diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index d29b0c1..792e68e 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -500,6 +500,25 @@ extern const char *selinux_colors_path(void); extern const char *selinux_netfilter_context_path(void); extern const char *selinux_path(void); +/** + * selinux_check_access - Check permissions and perform appropriate auditing. + * @scon: source security context + * @tcon: target security context + * @tclass: target security class string + * @perm: requested permissions string, interpreted based on @tclass + * @auditdata: auxiliary audit data + * + * Check the AVC to determine whether the @perm permissions are granted + * for the SID pair (@scon, @tcon), interpreting the permissions + * based on @tclass. + * Return %0 if all @perm permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied or to another + * value upon other errors. + * If auditing or logging is configured the appropriate callbacks will be called + * and passed the auditdata field + */ +extern int selinux_check_access(const security_context_t scon, const security_context_t tcon, const char *tclass, const char *perm, void *auditdata); + /* Check a permission in the passwd class. Return 0 if granted or -1 otherwise. */ extern int selinux_check_passwd_access(access_vector_t requested); diff --git a/libselinux/man/man3/matchpathcon.3 b/libselinux/man/man3/matchpathcon.3 index cdbb252..e2a4371 100644 --- a/libselinux/man/man3/matchpathcon.3 +++ b/libselinux/man/man3/matchpathcon.3 @@ -8,7 +8,7 @@ matchpathcon, matchpathcon_index \- get the default SELinux security context for .BI "int matchpathcon_init(const char *" path ");" -.BI "int matchpathcon_init_prefix(const char *" path ", const char *" subset ");" +.BI "int matchpathcon_init_prefix(const char *" path ", const char *" prefix ");" .BI "int matchpathcon_fini(void);" .sp @@ -48,7 +48,7 @@ is the same as but only loads entries with regular expressions that have stems prefixed by .I prefix. - +prefix can have multiple paths separated by ":", for example "/dev:/var/run:/tmp" .sp .B matchpathcon_fini frees the memory allocated by a prior call to diff --git a/libselinux/man/man3/security_compute_av.3 b/libselinux/man/man3/security_compute_av.3 index f2d9f30..1e36952 100644 --- a/libselinux/man/man3/security_compute_av.3 +++ b/libselinux/man/man3/security_compute_av.3 @@ -24,6 +24,8 @@ the SELinux policy database in the kernel. .BI "int security_get_initial_context(const char *" name ", security_context_t "con ); .sp +.BI "int selinux_check_access(const security_context_t " scon, " const security_context_t " tcon, " const char *" class, " const char *" perm, "void *" auditdata); +.sp .BI "int selinux_check_passwd_access(access_vector_t " requested ); .sp .BI "int checkPasswdAccess(access_vector_t " requested ); @@ -74,6 +76,9 @@ source context. It is mainly used by is used to get the context of a kernel initial security identifier specified by .I name +.B selinux_check_access +is used to check if the source context has the access permission for the specified class on the target context. + .B selinux_check_passwd_access is used to check for a permission in the .I passwd diff --git a/libselinux/man/man3/selabel_open.3 b/libselinux/man/man3/selabel_open.3 index 8674e37..89bb4d3 100644 --- a/libselinux/man/man3/selabel_open.3 +++ b/libselinux/man/man3/selabel_open.3 @@ -66,6 +66,13 @@ A non-null value for this option enables context validation. By default, is used; a custom validation function can be provided via .BR selinux_set_callback (3). Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation. +.TP +.B SELABEL_OPT_SUBSET +A ":" separates string of path prefixes that tell the system to only loads entries with regular expressions that could match this strings. For example "/dev:/var/run:/tmp". This option can cause the system to use less memory and work faster, but you should only use paths that begin with a prefix. +.TP +.B SELABEL_OPT_PATH +A string representing an alternate path the the regular expressions. +.sp .SH "BACKENDS" @@ -99,4 +106,3 @@ Eamon Walsh .BR selabel_stats (3), .BR selinux_set_callback (3), .BR selinux (8) - diff --git a/libselinux/man/man3/selinux_check_access.3 b/libselinux/man/man3/selinux_check_access.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/libselinux/man/man3/selinux_check_access.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c index 74591b4..e7ad31d 100644 --- a/libselinux/src/avc.c +++ b/libselinux/src/avc.c @@ -165,6 +165,9 @@ int avc_init(const char *prefix, struct avc_node *new; int i, rc = 0; + if (avc_running) + return 0; + if (prefix) strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1); 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/checkAccess.c b/libselinux/src/checkAccess.c index c1982c7..37ccc15 100644 --- a/libselinux/src/checkAccess.c +++ b/libselinux/src/checkAccess.c @@ -4,8 +4,40 @@ #include #include "selinux_internal.h" #include +#include #include +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static void avc_init_once(void) +{ + avc_open(NULL, 0); +} + +int selinux_check_access(const security_context_t scon, const security_context_t tcon, const char *class, const char *perm, void *aux) { + int status = -1; + int rc = -1; + security_id_t scon_id; + security_id_t tcon_id; + security_class_t sclass; + access_vector_t av; + + if (is_selinux_enabled() == 0) + return 0; + + __selinux_once(once, avc_init_once); + + if ((rc = avc_context_to_sid(scon, &scon_id)) < 0) return rc; + + if ((rc = avc_context_to_sid(tcon, &tcon_id)) < 0) return rc; + + if ((sclass = string_to_security_class(class)) == 0) return status; + + if ((av = string_to_av_perm(sclass, perm)) == 0) return status; + + return (avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); +} + int selinux_check_passwd_access(access_vector_t requested) { int status = -1; diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index 3b8346d..02f3f98 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c @@ -27,6 +27,7 @@ * Internals, mostly moved over from matchpathcon.c */ +#define MAX_PREFIX 100 /* A file security context specification. */ typedef struct spec { struct selabel_lookup_rec lr; /* holds contexts for lookup result */ @@ -279,7 +280,7 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf) static int process_line(struct selabel_handle *rec, - const char *path, const char *prefix, + const char *path, const char **prefix_array, char *line_buf, int pass, unsigned lineno) { int items, len; @@ -313,12 +314,24 @@ static int process_line(struct selabel_handle *rec, } len = get_stem_from_spec(regex); - if (len && prefix && strncmp(prefix, regex, len)) { - /* Stem of regex does not match requested prefix, discard. */ - free(regex); - free(type); - free(context); - return 0; + if (len && prefix_array[0]) { + int i = 0; + int found = 0; + while (i < MAX_PREFIX && prefix_array[i]) { + if (strncmp(prefix_array[i], regex, len) == 0) { + found = 1; + break; + } + i++; + } + + if (! found) { + /* Stem of regex does not match requested prefix, discard. */ + free(regex); + free(type); + free(context); + return 0; + } } if (pass == 1) { @@ -400,7 +413,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, { struct saved_data *data = (struct saved_data *)rec->data; const char *path = NULL; - const char *prefix = NULL; + const char *prefix_array[MAX_PREFIX] = {NULL,}; FILE *fp; FILE *localfp = NULL; FILE *homedirfp = NULL; @@ -421,8 +434,19 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, path = opts[n].value; break; case SELABEL_OPT_SUBSET: - prefix = opts[n].value; + { + char *ptr; + i = 0; + if (opts[n].value) { + prefix_array[i] = strtok_r((char *)opts[n].value, ":", &ptr); + while ((prefix_array[i] != NULL) && i < MAX_PREFIX - 1) { + i++; + prefix_array[i] = strtok_r(NULL, ":", &ptr); + } + } + break; + } case SELABEL_OPT_BASEONLY: baseonly = !!opts[n].value; break; @@ -481,7 +505,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, data->ncomp = 0; while (getline(&line_buf, &line_len, fp) > 0 && data->nspec < maxnspec) { - if (process_line(rec, path, prefix, line_buf, + if (process_line(rec, path, prefix_array, line_buf, pass, ++lineno) != 0) goto finish; } @@ -495,7 +519,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, while (getline(&line_buf, &line_len, homedirfp) > 0 && data->nspec < maxnspec) { if (process_line - (rec, homedir_path, prefix, + (rec, homedir_path, prefix_array, line_buf, pass, ++lineno) != 0) goto finish; } @@ -505,7 +529,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, while (getline(&line_buf, &line_len, localfp) > 0 && data->nspec < maxnspec) { if (process_line - (rec, local_path, prefix, line_buf, + (rec, local_path, prefix_array, line_buf, pass, ++lineno) != 0) goto finish; } diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c index 868660f..7fa6383 100644 --- a/libselinux/src/load_policy.c +++ b/libselinux/src/load_policy.c @@ -380,7 +380,7 @@ int selinux_init_load_policy(int *enforce) } if (! mntpoint ) { - if (errno == ENODEV) { + if (errno == ENODEV || errno == ENOENT) { /* * SELinux was disabled in the kernel, either * omitted entirely or disabled at boot via selinux=0. diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c index 5914afa..df83b30 100644 --- a/libselinux/src/matchpathcon.c +++ b/libselinux/src/matchpathcon.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "selinux_internal.h" #include "label_internal.h" #include "callbacks.h" @@ -62,7 +63,7 @@ static void { va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + vsyslog(LOG_ERR, fmt, ap); va_end(ap); }