00e063e5f5
2.1.4 2011-0817 * mapping fix for invalid class/perms after selinux_set_mapping * audit2why: work around python bug not defining * resolv symlinks and dot directories before matching
478 lines
12 KiB
Diff
478 lines
12 KiB
Diff
diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
|
|
index f110dcf..d29b0c1 100644
|
|
--- a/libselinux/include/selinux/selinux.h
|
|
+++ b/libselinux/include/selinux/selinux.h
|
|
@@ -566,7 +566,7 @@ extern int selinux_file_context_cmp(const security_context_t a,
|
|
|
|
/*
|
|
* Verify the context of the file 'path' against policy.
|
|
- * Return 0 if correct.
|
|
+ * Return 1 if match, 0 if not and -1 on error.
|
|
*/
|
|
extern int selinux_file_context_verify(const char *path, mode_t mode);
|
|
|
|
diff --git a/libselinux/man/man3/selinux_file_context_cmp.3 b/libselinux/man/man3/selinux_file_context_cmp.3
|
|
index 51e8c20..cd67188 100644
|
|
--- a/libselinux/man/man3/selinux_file_context_cmp.3
|
|
+++ b/libselinux/man/man3/selinux_file_context_cmp.3
|
|
@@ -1,25 +1,75 @@
|
|
-.TH "selinux_file_context_cmp" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation"
|
|
+.TH "selinux_file_context_cmp" "3" "08 March 2011" "SELinux API documentation"
|
|
+
|
|
.SH "NAME"
|
|
-selinux_file_context_cmp, selinux_file_context_verify \- comparison of two file contexts.
|
|
+selinux_file_context_cmp \- Compare two SELinux security contexts excluding the 'user' component.
|
|
|
|
.SH "SYNOPSIS"
|
|
.B #include <selinux/selinux.h>
|
|
.sp
|
|
-
|
|
-.BI "int selinux_file_context_cmp(const security_context_t " a ", const security_context_t " b ");"
|
|
-
|
|
-.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");"
|
|
+.BI "int selinux_file_context_cmp(const security_context_t " a ", "
|
|
+.RS
|
|
+.BI "const security_context_t " b ");"
|
|
+.RE
|
|
|
|
.SH "DESCRIPTION"
|
|
.B selinux_file_context_cmp
|
|
-compares two file contexts to see if their differences are "significant", the function runs the strcmp function ignoring the user componant of the file context.
|
|
-.sp
|
|
-.B selinux_file_context_verify
|
|
-compares the file context on disk to the system default.
|
|
+compares two context strings excluding the user component with
|
|
+.B strcmp(3)
|
|
+as shown in the
|
|
+.B EXAMPLE
|
|
+section.
|
|
.sp
|
|
+This is useful as for most object contexts, the user component is not relevant.
|
|
|
|
.SH "RETURN VALUE"
|
|
-Returns zero on success or \-1 otherwise.
|
|
+The return values follow the
|
|
+.B strcmp(3)
|
|
+function, where:
|
|
+.RS
|
|
+0 if they are equal.
|
|
+.RE
|
|
+.RS
|
|
+1 if
|
|
+.I a
|
|
+is greater than
|
|
+.I b
|
|
+.RE
|
|
+.RS
|
|
+\-1 if
|
|
+.I a
|
|
+is less than
|
|
+.I b
|
|
+.RE
|
|
+
|
|
+.SH "ERRORS"
|
|
+None.
|
|
+
|
|
+.SH "NOTES"
|
|
+The contexts being compared do not specifically need to be file contexts.
|
|
+
|
|
+.SH "EXAMPLE"
|
|
+If context
|
|
+.I a
|
|
+is:
|
|
+.RS
|
|
+user_u:user_r:user_t:s0
|
|
+.RE
|
|
+.sp
|
|
+and context
|
|
+.I b
|
|
+is:
|
|
+.RS
|
|
+root:user_r:user_t:s0
|
|
+.RE
|
|
+.sp
|
|
+then the actual strings compared are:
|
|
+.RS
|
|
+:user_r:user_t:s0 and :user_r:user_t:s0
|
|
+.RE
|
|
+.sp
|
|
+Therefore they will match and
|
|
+.B selinux_file_context_cmp
|
|
+will return zero.
|
|
|
|
.SH "SEE ALSO"
|
|
-.BR selinux "(8), " selinux_lsetfilecon "(3), " matchpathcon "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
|
|
+.BR selinux "(8)"
|
|
diff --git a/libselinux/man/man3/selinux_file_context_verify.3 b/libselinux/man/man3/selinux_file_context_verify.3
|
|
index d777547..e22be70 100644
|
|
--- a/libselinux/man/man3/selinux_file_context_verify.3
|
|
+++ b/libselinux/man/man3/selinux_file_context_verify.3
|
|
@@ -1 +1,98 @@
|
|
-.so man3/selinux_file_context_cmp.3
|
|
+.TH "selinux_file_context_verify" "3" "08 March 2011" "SELinux API documentation"
|
|
+
|
|
+.SH "NAME"
|
|
+selinux_file_context_verify \- Compare the SELinux security context on disk to the default security context required by the policy file contexts file.
|
|
+
|
|
+.SH "SYNOPSIS"
|
|
+.B #include <selinux/selinux.h>
|
|
+.sp
|
|
+.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");"
|
|
+
|
|
+.SH "DESCRIPTION"
|
|
+.B selinux_file_context_verify
|
|
+compares the context of the specified
|
|
+.I path
|
|
+that is held on disk (in the extended attribute), to the system default entry held in the file contexts series of files.
|
|
+.sp
|
|
+The
|
|
+.I mode
|
|
+may be zero.
|
|
+.sp
|
|
+Note that the two contexts are compared for "significant" differences (i.e. the user component of the contexts are ignored) as shown in the
|
|
+.B EXAMPLE
|
|
+section.
|
|
+
|
|
+.SH "RETURN VALUE"
|
|
+If the contexts significantly match, 1 (one) is returned.
|
|
+.sp
|
|
+If the contexts do not match 0 (zero) is returned and
|
|
+.I errno
|
|
+is set to either
|
|
+.B ENOENT
|
|
+or
|
|
+.B EINVAL
|
|
+for the reasons listed in the
|
|
+.B ERRORS
|
|
+section, or if
|
|
+.I errno
|
|
+= 0 then the contexts did not match.
|
|
+.sp
|
|
+On failure \-1 is returned and
|
|
+.I errno
|
|
+set appropriately.
|
|
+
|
|
+.SH "ERRORS"
|
|
+.TP
|
|
+.B ENOTSUP
|
|
+if extended attributes are not supported by the file system.
|
|
+.TP
|
|
+.B ENOENT
|
|
+if there is no entry in the file contexts series of files or
|
|
+.I path
|
|
+does not exist.
|
|
+.TP
|
|
+.B EINVAL
|
|
+if the entry in the file contexts series of files or
|
|
+.I path
|
|
+are invalid, or the returned context fails validation.
|
|
+.TP
|
|
+.B ENOMEM
|
|
+if attempt to allocate memory failed.
|
|
+
|
|
+.SH "FILES"
|
|
+The following configuration files (the file contexts series of files) supporting the active policy will be used (should they exist) to determine the
|
|
+.I path
|
|
+default context:
|
|
+.sp
|
|
+.RS
|
|
+contexts/files/file_contexts - This file must exist.
|
|
+.sp
|
|
+contexts/files/file_contexts.local - If exists has local customizations.
|
|
+.sp
|
|
+contexts/files/file_contexts.homedirs - If exists has users home directory customizations.
|
|
+.sp
|
|
+contexts/files/file_contexts.subs - If exists has substitutions that are then applied to the 'in memory' version of the file contexts files.
|
|
+.RE
|
|
+
|
|
+.SH "EXAMPLE"
|
|
+If the files context is:
|
|
+.RS
|
|
+unconfined_u:object_r:admin_home_t:s0
|
|
+.RE
|
|
+.sp
|
|
+and the default context defined in the file contexts file is:
|
|
+.RS
|
|
+system_u:object_r:admin_home_t:s0
|
|
+.RE
|
|
+.sp
|
|
+then the actual strings compared are:
|
|
+.RS
|
|
+:object_r:admin_home_t:s0 and :object_r:admin_home_t:s0
|
|
+.RE
|
|
+.sp
|
|
+Therefore they will match and
|
|
+.B selinux_file_context_verify
|
|
+will return 1.
|
|
+
|
|
+.SH "SEE ALSO"
|
|
+.BR selinux "(8)"
|
|
diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c
|
|
index b245364..7c47222 100644
|
|
--- a/libselinux/src/callbacks.c
|
|
+++ b/libselinux/src/callbacks.c
|
|
@@ -16,6 +16,7 @@ default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
|
|
{
|
|
int rc;
|
|
va_list ap;
|
|
+ if (is_selinux_enabled() == 0) return 0;
|
|
va_start(ap, fmt);
|
|
rc = vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
|
|
index 5fd8fe4..410dd9d 100644
|
|
--- a/libselinux/src/matchpathcon.c
|
|
+++ b/libselinux/src/matchpathcon.c
|
|
@@ -2,9 +2,11 @@
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
+#include <syslog.h>
|
|
#include "selinux_internal.h"
|
|
#include "label_internal.h"
|
|
#include "callbacks.h"
|
|
+#include <limits.h>
|
|
|
|
static __thread struct selabel_handle *hnd;
|
|
|
|
@@ -61,7 +63,7 @@ static void
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
- vfprintf(stderr, fmt, ap);
|
|
+ vsyslog(LOG_ERR, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
@@ -337,14 +339,82 @@ void matchpathcon_fini(void)
|
|
}
|
|
}
|
|
|
|
-int matchpathcon(const char *name, mode_t mode, security_context_t * con)
|
|
+/*
|
|
+ * We do not want to resolve a symlink to a real path if it is the final
|
|
+ * component of the name. Thus we split the pathname on the last "/" and
|
|
+ * determine a real path component of the first portion. We then have to
|
|
+ * copy the last part back on to get the final real path. Wheww.
|
|
+ */
|
|
+static int symlink_realpath(const char *name, char *resolved_path)
|
|
+{
|
|
+ char *last_component;
|
|
+ char *tmp_path, *p;
|
|
+ size_t len = 0;
|
|
+ int rc = 0;
|
|
+
|
|
+ tmp_path = strdup(name);
|
|
+ if (!tmp_path) {
|
|
+ fprintf(stderr, "symlink_realpath(%s) strdup() failed: %s\n",
|
|
+ name, strerror(errno));
|
|
+ rc = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ last_component = strrchr(tmp_path, '/');
|
|
+
|
|
+ if (last_component == tmp_path) {
|
|
+ last_component++;
|
|
+ p = strcpy(resolved_path, "/");
|
|
+ } else if (last_component) {
|
|
+ *last_component = '\0';
|
|
+ last_component++;
|
|
+ p = realpath(tmp_path, resolved_path);
|
|
+ } else {
|
|
+ last_component = tmp_path;
|
|
+ p = realpath("./", resolved_path);
|
|
+ }
|
|
+
|
|
+ if (!p) {
|
|
+ fprintf(stderr, "symlink_realpath(%s) realpath() failed: %s\n",
|
|
+ name, strerror(errno));
|
|
+ rc = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ len = strlen(p);
|
|
+ if (len + strlen(last_component) + 1 > PATH_MAX) {
|
|
+ fprintf(stderr, "symlink_realpath(%s) failed: Filename too long \n",
|
|
+ name);
|
|
+ rc = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ resolved_path += len;
|
|
+ strcpy(resolved_path, last_component);
|
|
+out:
|
|
+ free(tmp_path);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int matchpathcon(const char *path, mode_t mode, security_context_t * con)
|
|
{
|
|
+ char stackpath[PATH_MAX + 1];
|
|
+ char *p = NULL;
|
|
if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
|
|
return -1;
|
|
|
|
+ if (S_ISLNK(mode)) {
|
|
+ if (!symlink_realpath(path, stackpath))
|
|
+ path = stackpath;
|
|
+ } else {
|
|
+ p = realpath(path, stackpath);
|
|
+ if (p)
|
|
+ path = p;
|
|
+ }
|
|
+
|
|
return notrans ?
|
|
- selabel_lookup_raw(hnd, con, name, mode) :
|
|
- selabel_lookup(hnd, con, name, mode);
|
|
+ selabel_lookup_raw(hnd, con, path, mode) :
|
|
+ selabel_lookup(hnd, con, path, mode);
|
|
}
|
|
|
|
int matchpathcon_index(const char *name, mode_t mode, security_context_t * con)
|
|
@@ -394,7 +464,7 @@ int selinux_file_context_verify(const char *path, mode_t mode)
|
|
rc = lgetfilecon_raw(path, &con);
|
|
if (rc == -1) {
|
|
if (errno != ENOTSUP)
|
|
- return 1;
|
|
+ return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
@@ -404,11 +474,18 @@ int selinux_file_context_verify(const char *path, mode_t mode)
|
|
|
|
if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) {
|
|
if (errno != ENOENT)
|
|
- rc = 1;
|
|
+ rc = -1;
|
|
else
|
|
rc = 0;
|
|
- } else
|
|
+ } else {
|
|
+ /*
|
|
+ * Need to set errno to 0 as it can be set to ENOENT if the
|
|
+ * file_contexts.subs file does not exist (see selabel_open in
|
|
+ * label.c), thus causing confusion if errno is checked on return.
|
|
+ */
|
|
+ errno = 0;
|
|
rc = (selinux_file_context_cmp(fcontext, con) == 0);
|
|
+ }
|
|
|
|
freecon(con);
|
|
freecon(fcontext);
|
|
diff --git a/libselinux/utils/matchpathcon.c b/libselinux/utils/matchpathcon.c
|
|
index 3ecd52f..5f0a4c2 100644
|
|
--- a/libselinux/utils/matchpathcon.c
|
|
+++ b/libselinux/utils/matchpathcon.c
|
|
@@ -43,63 +43,6 @@ int printmatchpathcon(char *path, int header, int mode)
|
|
return 0;
|
|
}
|
|
|
|
-/*
|
|
- * We do not want to resolve a symlink to a real path if it is the final
|
|
- * component of the name. Thus we split the pathname on the last "/" and
|
|
- * determine a real path component of the first portion. We then have to
|
|
- * copy the last part back on to get the final real path. Wheww.
|
|
- */
|
|
-static int symlink_realpath(char *name, char *resolved_path)
|
|
-{
|
|
- char *last_component;
|
|
- char *tmp_path, *p;
|
|
- size_t len = 0;
|
|
- int rc = 0;
|
|
-
|
|
- tmp_path = strdup(name);
|
|
- if (!tmp_path) {
|
|
- fprintf(stderr, "symlink_realpath(%s) strdup() failed: %s\n",
|
|
- name, strerror(errno));
|
|
- rc = -1;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- last_component = strrchr(tmp_path, '/');
|
|
-
|
|
- if (last_component == tmp_path) {
|
|
- last_component++;
|
|
- p = strcpy(resolved_path, "/");
|
|
- } else if (last_component) {
|
|
- *last_component = '\0';
|
|
- last_component++;
|
|
- p = realpath(tmp_path, resolved_path);
|
|
- } else {
|
|
- last_component = tmp_path;
|
|
- p = realpath("./", resolved_path);
|
|
- }
|
|
-
|
|
- if (!p) {
|
|
- fprintf(stderr, "symlink_realpath(%s) realpath() failed: %s\n",
|
|
- name, strerror(errno));
|
|
- rc = -1;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- len = strlen(p);
|
|
- if (len + strlen(last_component) + 1 > PATH_MAX) {
|
|
- fprintf(stderr, "symlink_realpath(%s) failed: Filename too long \n",
|
|
- name);
|
|
- rc = -1;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- resolved_path += len;
|
|
- strcpy(resolved_path, last_component);
|
|
-out:
|
|
- free(tmp_path);
|
|
- return rc;
|
|
-}
|
|
-
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i, init = 0;
|
|
@@ -166,8 +109,7 @@ int main(int argc, char **argv)
|
|
for (i = optind; i < argc; i++) {
|
|
int rc, mode = 0;
|
|
struct stat buf;
|
|
- char *p, *path = argv[i];
|
|
- char stackpath[PATH_MAX + 1];
|
|
+ char *path = argv[i];
|
|
int len = strlen(path);
|
|
if (len > 1 && path[len - 1 ] == '/')
|
|
path[len - 1 ] = '\0';
|
|
@@ -175,31 +117,23 @@ int main(int argc, char **argv)
|
|
if (lstat(path, &buf) == 0)
|
|
mode = buf.st_mode;
|
|
|
|
- if (S_ISLNK(mode)) {
|
|
- rc = symlink_realpath(path, stackpath);
|
|
- if (!rc)
|
|
- path = stackpath;
|
|
- } else {
|
|
- p = realpath(path, stackpath);
|
|
- if (p)
|
|
- path = p;
|
|
- }
|
|
-
|
|
if (verify) {
|
|
rc = selinux_file_context_verify(path, mode);
|
|
|
|
if (quiet) {
|
|
- if (rc)
|
|
+ if (rc == 1)
|
|
continue;
|
|
else
|
|
exit(1);
|
|
}
|
|
|
|
- if (rc) {
|
|
+ if (rc == -1) {
|
|
+ printf("%s error: %s\n", path, strerror(errno));
|
|
+ exit(1);
|
|
+ } else if (rc == 1) {
|
|
printf("%s verified.\n", path);
|
|
} else {
|
|
security_context_t con;
|
|
- int rc;
|
|
error = 1;
|
|
if (notrans)
|
|
rc = lgetfilecon_raw(path, &con);
|