diff --git a/libselinux/include/selinux/label.h b/libselinux/include/selinux/label.h index 1a54307..f6eeb21 100644 --- a/libselinux/include/selinux/label.h +++ b/libselinux/include/selinux/label.h @@ -46,8 +46,10 @@ struct selabel_handle; #define SELABEL_OPT_PATH 3 /* select a subset of the search space as an optimization (file backend) */ #define SELABEL_OPT_SUBSET 4 +/* like subset, but an array of subsets */ +#define SELABEL_OPT_PREFIXES 5 /* total number of options */ -#define SELABEL_NOPT 5 +#define SELABEL_NOPT 6 /* * Label operations diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index 2985f6f..826ed71 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -139,7 +139,10 @@ struct av_decision { /* Structure for passing options, used by AVC and label subsystems */ struct selinux_opt { int type; - const char *value; + union { + const char *value; + const char **values; + }; }; /* Callback facilities */ @@ -410,6 +413,11 @@ extern int matchpathcon_init(const char *path); regexes that have stems that are prefixes of 'prefix'. */ extern int matchpathcon_init_prefix(const char *path, const char *prefix); +/* Same as matchpathcon_init, but only load entries with + * regexes that have stems that are prefixes of the 'prefixes' + * array of entries. The last entry must be NULL. */ +extern int matchpathcon_init_prefixes(const char *patch, const char **prefixes); + /* Free the memory allocated by matchpathcon_init. */ extern void matchpathcon_fini(void); diff --git a/libselinux/man/man3/matchpathcon.3 b/libselinux/man/man3/matchpathcon.3 index cdbb252..b6814ed 100644 --- a/libselinux/man/man3/matchpathcon.3 +++ b/libselinux/man/man3/matchpathcon.3 @@ -8,7 +8,9 @@ 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_init_prefixes(const char *" path ", const char **" prefixes ");" .BI "int matchpathcon_fini(void);" .sp @@ -50,6 +52,14 @@ by .I prefix. .sp +.B matchpathcon_init_prefixes +is the same as +.B matchpathcon_init_prefix +but takes an array of +.I prefixes +instead of a single prefix. The last entry in the array must be NULL. + +.sp .B matchpathcon_fini frees the memory allocated by a prior call to .B matchpathcon_init. 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/man8/setenforce.8 b/libselinux/man/man8/setenforce.8 index 8a010d6..639883e 100644 --- a/libselinux/man/man8/setenforce.8 +++ b/libselinux/man/man8/setenforce.8 @@ -6,18 +6,14 @@ setenforce \- modify the mode SELinux is running in. .SH "DESCRIPTION" Use Enforcing or 1 to put SELinux in enforcing mode. +.br Use Permissive or 0 to put SELinux in permissive mode. -You need to modify -.I /etc/grub.conf -or -.I /etc/selinux/config -to disable SELinux. + +If SELinux is disabled and you want to enable it, or SELinux is enabled and you want to disable it, please see +.B selinux(8). .SH AUTHOR Dan Walsh, .SH "SEE ALSO" selinux(8), getenforce(8), selinuxenabled(8) - -.SH FILES -/etc/grub.conf, /etc/selinux/config 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/label.c b/libselinux/src/label.c index f1c9a25..a9e0853 100644 --- a/libselinux/src/label.c +++ b/libselinux/src/label.c @@ -184,6 +184,12 @@ selabel_lookup_common(struct selabel_handle *rec, int translating, const char *key, int type) { struct selabel_lookup_rec *lr; + + if (key == NULL) { + errno = EINVAL; + return NULL; + } + char *ptr = selabel_sub(rec->subs, key); if (ptr) { lr = rec->func_lookup(rec, ptr, type); @@ -194,7 +200,7 @@ selabel_lookup_common(struct selabel_handle *rec, int translating, if (!lr) return NULL; - if (compat_validate(rec, lr, "file_contexts", 0)) + if (compat_validate(rec, lr, rec->spec_file, 0)) return NULL; if (translating && !lr->ctx_trans && @@ -234,6 +240,7 @@ void selabel_close(struct selabel_handle *rec) { selabel_subs_fini(rec->subs); rec->func_close(rec); + free(rec->spec_file); free(rec); } diff --git a/libselinux/src/label_db.c b/libselinux/src/label_db.c index 7afacf0..ab0696a 100644 --- a/libselinux/src/label_db.c +++ b/libselinux/src/label_db.c @@ -230,7 +230,7 @@ db_stats(struct selabel_handle *rec) * selabel_open() handler */ static catalog_t * -db_init(struct selinux_opt *opts, unsigned nopts) +db_init(struct selinux_opt *opts, unsigned nopts, struct selabel_handle *rec) { catalog_t *catalog; FILE *filp; @@ -275,6 +275,7 @@ db_init(struct selinux_opt *opts, unsigned nopts) free(catalog); return NULL; } + rec->spec_file = strdup(path); /* * Parse for each lines @@ -332,7 +333,7 @@ int selabel_db_init(struct selabel_handle *rec, rec->func_close = &db_close; rec->func_lookup = &db_lookup; rec->func_stats = &db_stats; - rec->data = db_init(opts, nopts); + rec->data = db_init(opts, nopts, rec); return !rec->data ? -1 : 0; } diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index ac11b37..82a608c 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 */ @@ -276,7 +277,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; @@ -310,12 +311,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) { @@ -397,7 +410,8 @@ 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 *static_prefix_array[2] = {NULL, }; + const char **prefix_array = static_prefix_array; FILE *fp; FILE *localfp = NULL; FILE *homedirfp = NULL; @@ -418,7 +432,10 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, path = opts[n].value; break; case SELABEL_OPT_SUBSET: - prefix = opts[n].value; + static_prefix_array[0] = opts[n].value; + break; + case SELABEL_OPT_PREFIXES: + prefix_array = opts[n].values; break; case SELABEL_OPT_BASEONLY: baseonly = !!opts[n].value; @@ -462,6 +479,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, if (localfp != NULL) __fsetlocking(localfp, FSETLOCKING_BYCALLER); } + rec->spec_file = strdup(path); /* * Perform two passes over the specification file. @@ -480,7 +498,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, while (getline(&line_buf, &line_len, fp) > 0) { if (data->nspec >= maxnspec) break; - status = process_line(rec, path, prefix, line_buf, pass, ++lineno); + status = process_line(rec, path, prefix_array, line_buf, pass, ++lineno); if (status) goto finish; } @@ -496,7 +514,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, while (getline(&line_buf, &line_len, homedirfp) > 0) { if (data->nspec >= maxnspec) break; - status = process_line(rec, homedir_path, prefix, line_buf, pass, ++lineno); + status = process_line(rec, homedir_path, prefix_array, line_buf, pass, ++lineno); if (status) goto finish; } @@ -506,7 +524,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, while (getline(&line_buf, &line_len, localfp) > 0) { if (data->nspec >= maxnspec) break; - status = process_line(rec, local_path, prefix, line_buf, pass, ++lineno); + status = process_line(rec, local_path, prefix_array, line_buf, pass, ++lineno); if (status) goto finish; } diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h index 02dbe73..79d5495 100644 --- a/libselinux/src/label_internal.h +++ b/libselinux/src/label_internal.h @@ -59,6 +59,12 @@ struct selabel_handle { /* supports backend-specific state information */ void *data; + /* + * The main spec file used. Note for file contexts the local and/or + * homedirs could also have been used to resolve a context. + */ + char *spec_file; + /* substitution support */ struct selabel_sub *subs; }; diff --git a/libselinux/src/label_media.c b/libselinux/src/label_media.c index f8986e4..227785f 100644 --- a/libselinux/src/label_media.c +++ b/libselinux/src/label_media.c @@ -100,6 +100,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, errno = EINVAL; return -1; } + rec->spec_file = strdup(path); /* * Perform two passes over the specification file. diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c index a9bfaa5..896ef02 100644 --- a/libselinux/src/label_x.c +++ b/libselinux/src/label_x.c @@ -127,6 +127,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, errno = EINVAL; return -1; } + rec->spec_file = strdup(path); /* * Perform two passes over the specification file. diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c index c396add..c625f55 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); } @@ -304,7 +305,7 @@ static void matchpathcon_init_once(void) destructor_key_initialized = 1; } -int matchpathcon_init_prefix(const char *path, const char *subset) +int matchpathcon_init_prefixes(const char *path, const char **prefixes) { if (!mycanoncon) mycanoncon = default_canoncon; @@ -312,15 +313,22 @@ int matchpathcon_init_prefix(const char *path, const char *subset) __selinux_once(once, matchpathcon_init_once); __selinux_setspecific(destructor_key, (void *)1); - options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; - options[SELABEL_OPT_SUBSET].value = subset; + options[SELABEL_OPT_PREFIXES].type = SELABEL_OPT_PREFIXES; + options[SELABEL_OPT_PREFIXES].values = prefixes; options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH; options[SELABEL_OPT_PATH].value = path; hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT); return hnd ? 0 : -1; } +hidden_def(matchpathcon_init_prefixes) +int matchpathcon_init_prefix(const char *path, const char *prefix) +{ + const char *prefixes[2] = { prefix, NULL }; + + return matchpathcon_init_prefixes(path, prefixes); +} hidden_def(matchpathcon_init_prefix) int matchpathcon_init(const char *path) @@ -531,9 +539,14 @@ int compat_validate(struct selabel_handle *rec, else { rc = selabel_validate(rec, contexts); if (rc < 0) { - COMPAT_LOG(SELINUX_WARNING, - "%s: line %d has invalid context %s\n", - path, lineno, *ctx); + if (lineno) { + COMPAT_LOG(SELINUX_WARNING, + "%s: line %d has invalid context %s\n", + path, lineno, *ctx); + } else { + COMPAT_LOG(SELINUX_WARNING, + "%s: has invalid context %s\n", path, *ctx); + } } } diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index 710396a..9a3fc14 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -80,6 +80,7 @@ hidden_proto(selinux_mkload_policy) hidden_proto(selinux_path) hidden_proto(selinux_check_passwd_access) hidden_proto(selinux_check_securetty_context) + hidden_proto(matchpathcon_init_prefixes) hidden_proto(matchpathcon_init_prefix) hidden_proto(selinux_users_path) hidden_proto(selinux_usersconf_path);