diff --git a/BUILD.gn b/BUILD.gn index 95c7472c5ef78724a14bf447bf36fa86fb9a844c..aebce8b9244b7cdd23714e2581e2f446f45a6dd6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -114,6 +114,7 @@ ohos_shared_library("libsepol") { ] cflags = [ "-D_GNU_SOURCE", + "-DHAVE_REALLOCARRAY", "-w", ] install_enable = true diff --git a/OAT.xml b/OAT.xml index 77828b2c18866e29ca54eb5919fa2beb5124f3be..b77c05956d279d716639fc472d65b0147a5f8589 100644 --- a/OAT.xml +++ b/OAT.xml @@ -57,6 +57,7 @@ + @@ -230,17 +231,17 @@ " desc=""/> name); policydbp->name = id; if ((policydbp->version = queue_remove(id_queue)) == NULL) { diff --git a/checkpolicy/parse_util.c b/checkpolicy/parse_util.c index 8c1f393cec7e65cc90387669955f265fc1e61e65..f2d1e04d7e8ab1f7a1d13cae9a361575f41cab0b 100644 --- a/checkpolicy/parse_util.c +++ b/checkpolicy/parse_util.c @@ -47,6 +47,7 @@ int read_source_policy(policydb_t * p, const char *file, const char *progname) } policydbp = p; + policydbp->name = strdup(file); mlspol = p->mls; init_parser(1); diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index d3eb6111ead4b2be817816a9f11e00bb606eb669..8bf36859439c8444c884416e51f3408f05314412 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -1634,6 +1634,15 @@ static int define_compute_type_helper(int which, avrule_t ** rule) } add = 1; while ((id = queue_remove(id_queue))) { + if (strcmp(id, "self") == 0) { + free(id); + if (add == 0) { + yyerror("-self is not supported"); + goto bad; + } + avrule->flags |= RULE_SELF; + continue; + } if (set_types(&avrule->ttypes, id, &add, 0)) goto bad; } @@ -3300,7 +3309,7 @@ int define_filename_trans(void) type_datum_t *typdatum; uint32_t otype; unsigned int c, s, t; - int add, rc; + int add, self, rc; if (pass == 1) { /* stype */ @@ -3333,8 +3342,18 @@ int define_filename_trans(void) goto bad; } - add =1; + self = 0; + add = 1; while ((id = queue_remove(id_queue))) { + if (strcmp(id, "self") == 0) { + free(id); + if (add == 0) { + yyerror("-self is not supported"); + goto bad; + } + self = 1; + continue; + } if (set_types(&ttypes, id, &add, 0)) goto bad; } @@ -3396,6 +3415,24 @@ int define_filename_trans(void) goto bad; } } + if (self) { + rc = policydb_filetrans_insert( + policydbp, s+1, s+1, c+1, name, + NULL, otype, NULL + ); + if (rc != SEPOL_OK) { + if (rc == SEPOL_EEXIST) { + yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", + name, + policydbp->p_type_val_to_name[s], + policydbp->p_type_val_to_name[s], + policydbp->p_class_val_to_name[c]); + goto bad; + } + yyerror("out of memory"); + goto bad; + } + } } /* Now add the real rule since we didn't find any duplicates */ @@ -3418,6 +3455,7 @@ int define_filename_trans(void) } ftr->tclass = c + 1; ftr->otype = otype; + ftr->flags = self ? RULE_SELF : 0; } free(name); @@ -3477,6 +3515,8 @@ static constraint_expr_t *constraint_expr_clone(const constraint_expr_t * expr) return NULL; } +#define PERMISSION_MASK(nprim) ((nprim) == PERM_SYMTAB_SIZE ? (~UINT32_C(0)) : ((UINT32_C(1) << (nprim)) - 1)) + int define_constraint(constraint_expr_t * expr) { struct constraint_node *node; @@ -3590,6 +3630,22 @@ int define_constraint(constraint_expr_t * expr) cladatum = policydbp->class_val_to_struct[i]; node = cladatum->constraints; + if (strcmp(id, "*") == 0) { + node->permissions = PERMISSION_MASK(cladatum->permissions.nprim); + continue; + } + + if (strcmp(id, "~") == 0) { + node->permissions = ~node->permissions & PERMISSION_MASK(cladatum->permissions.nprim); + if (node->permissions == 0) { + yywarn("omitting constraint with no permission set"); + cladatum->constraints = node->next; + constraint_expr_destroy(node->expr); + free(node); + } + continue; + } + perdatum = (perm_datum_t *) hashtab_search(cladatum-> permissions. @@ -3609,7 +3665,7 @@ int define_constraint(constraint_expr_t * expr) } if (!perdatum) { yyerror2("permission %s is not" - " defined", id); + " defined for class %s", id, policydbp->p_class_val_to_name[i]); free(id); ebitmap_destroy(&classmap); return -1; @@ -5290,6 +5346,14 @@ int define_ipv4_node_context() goto out; } + if (mask.s_addr != 0 && ((~mask.s_addr + 1) & ~mask.s_addr) != 0) { + yywarn("ipv4 mask is not contiguous"); + } + + if ((~mask.s_addr & addr.s_addr) != 0) { + yywarn("host bits in ipv4 address set"); + } + newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); @@ -5325,6 +5389,40 @@ out: return rc; } +static int ipv6_is_mask_contiguous(const struct in6_addr *mask) +{ + int filled = 1; + unsigned i; + + for (i = 0; i < 16; i++) { + if ((((~mask->s6_addr[i] & 0xFF) + 1) & (~mask->s6_addr[i] & 0xFF)) != 0) { + return 0; + } + if (!filled && mask->s6_addr[i] != 0) { + return 0; + } + + if (filled && mask->s6_addr[i] != 0xFF) { + filled = 0; + } + } + + return 1; +} + +static int ipv6_has_host_bits_set(const struct in6_addr *addr, const struct in6_addr *mask) +{ + unsigned i; + + for (i = 0; i < 16; i++) { + if ((addr->s6_addr[i] & ~mask->s6_addr[i]) != 0) { + return 1; + } + } + + return 0; +} + int define_ipv6_node_context(void) { char *id; @@ -5376,6 +5474,14 @@ int define_ipv6_node_context(void) goto out; } + if (!ipv6_is_mask_contiguous(&mask)) { + yywarn("ipv6 mask is not contiguous"); + } + + if (ipv6_has_host_bits_set(&addr, &mask)) { + yywarn("host bits in ipv6 address set"); + } + newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l index 129a8a2a09263928b5c68f5bb0969e1a3cea05eb..9fefea7b207047e38987abbab7c6d0641e9c7783 100644 --- a/checkpolicy/policy_scan.l +++ b/checkpolicy/policy_scan.l @@ -60,7 +60,14 @@ hexval [0-9A-Fa-f] %% \n.* { +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif strncpy(linebuf[lno], yytext+1, 255); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif linebuf[lno][254] = 0; lno = 1 - lno; policydb_lineno++; @@ -308,11 +315,11 @@ GLBLUB { return(GLBLUB); } int yyerror(const char *msg) { if (source_file[0]) - fprintf(stderr, "%s:%ld:", + fprintf(stderr, "%s:%lu:", source_file, source_lineno); else fprintf(stderr, "(unknown source)::"); - fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n", + fprintf(stderr, "ERROR '%s' at token '%s' on line %lu:\n%s\n%s\n", msg, yytext, policydb_lineno, @@ -327,11 +334,11 @@ int yywarn(const char *msg) return yyerror(msg); if (source_file[0]) - fprintf(stderr, "%s:%ld:", + fprintf(stderr, "%s:%lu:", source_file, source_lineno); else fprintf(stderr, "(unknown source)::"); - fprintf(stderr, "WARNING '%s' at token '%s' on line %ld:\n%s\n%s\n", + fprintf(stderr, "WARNING '%s' at token '%s' on line %lu:\n%s\n%s\n", msg, yytext, policydb_lineno, diff --git a/libselinux/Makefile b/libselinux/Makefile index 439bc6a9b7fd35fdceb42daaa7ffac4b363ae690..6d9e27364192146edb0009cdfe4ecabd2a804ae3 100644 --- a/libselinux/Makefile +++ b/libselinux/Makefile @@ -23,7 +23,7 @@ ifeq ($(DISABLE_X11),y) endif export DISABLE_SETRANS DISABLE_RPM DISABLE_FLAGS ANDROID_HOST DISABLE_X11 LABEL_BACKEND_ANDROID -USE_PCRE2 ?= n +USE_PCRE2 ?= y ifeq ($(USE_PCRE2),y) PCRE_MODULE := libpcre2-8 PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 diff --git a/libselinux/VERSION b/libselinux/VERSION index eb39e5382f4f035e4d71c7f67712cdbfa6c0c335..2f4b60750dc3500b0e4cf08f316a960a7ca42b40 100644 --- a/libselinux/VERSION +++ b/libselinux/VERSION @@ -1 +1 @@ -3.3 +3.4 diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h index 466de39aac7284a85996054f87a937343ce1dc18..b10fe684eff91788a9d36b4e5529dfa3964a0d8e 100644 --- a/libselinux/include/selinux/restorecon.h +++ b/libselinux/include/selinux/restorecon.h @@ -2,6 +2,7 @@ #define _RESTORECON_H_ #include +#include #include #ifdef __cplusplus @@ -23,6 +24,19 @@ extern "C" { */ extern int selinux_restorecon(const char *pathname, unsigned int restorecon_flags); +/** + * selinux_restorecon_parallel - Relabel files, optionally use more threads. + * @pathname: specifies file/directory to relabel. + * @restorecon_flags: specifies the actions to be performed when relabeling. + * @nthreads: specifies the number of threads to use (0 = use number of CPUs + * currently online) + * + * Same as selinux_restorecon(3), but allows to use multiple threads to do + * the work. + */ +extern int selinux_restorecon_parallel(const char *pathname, + unsigned int restorecon_flags, + size_t nthreads); /* * restorecon_flags options */ @@ -107,6 +121,11 @@ extern int selinux_restorecon(const char *pathname, */ #define SELINUX_RESTORECON_CONFLICT_ERROR 0x10000 +/* + * Count, but otherwise ignore, errors during the file tree walk. + */ +#define SELINUX_RESTORECON_COUNT_ERRORS 0x20000 + /** * selinux_restorecon_set_sehandle - Set the global fc handle. * @hndl: specifies handle to set as the global fc handle. @@ -191,6 +210,16 @@ extern int selinux_restorecon_xattr(const char *pathname, /* Do not read /proc/mounts. */ #define SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS 0x0008 +/* selinux_restorecon_get_skipped_errors - Get the number of errors ignored + * during re-labeling. + * + * If SELINUX_RESTORECON_COUNT_ERRORS was passed to selinux_restorecon(3) or + * selinux_restorecon_parallel(3), and that function returned successfully + * (i.e., with a zero return value), then this function returns the number of + * errors ignored during the file tree walk. + */ +extern long unsigned selinux_restorecon_get_skipped_errors(void); + #ifdef __cplusplus } #endif diff --git a/libselinux/man/man3/getfilecon.3 b/libselinux/man/man3/getfilecon.3 index 5bb575b5fb1719caddd64daf64b7bd9de70cfe88..c3e92ba1566203ab29c061f5d4324dd26fe190b5 100644 --- a/libselinux/man/man3/getfilecon.3 +++ b/libselinux/man/man3/getfilecon.3 @@ -33,7 +33,9 @@ is identical to .BR getfilecon (), only the open file pointed to by filedes (as returned by .BR open (2)) -is interrogated in place of path. +is interrogated in place of path. Since libselinux 3.4 a file opened via +.I O_PATH +is supported. .BR getfilecon_raw (), .BR lgetfilecon_raw () diff --git a/libselinux/man/man3/selabel_open.3 b/libselinux/man/man3/selabel_open.3 index 971ebc1acd41fff50ac70588c88791647613c63b..0e03e1be111e06cbe914a0a7687394ab7272f4cb 100644 --- a/libselinux/man/man3/selabel_open.3 +++ b/libselinux/man/man3/selabel_open.3 @@ -10,7 +10,7 @@ selabel_open, selabel_close \- userspace SELinux labeling interface .br .B #include .sp -.BI "struct selabel_handle *selabel_open(int " backend , +.BI "struct selabel_handle *selabel_open(unsigned int " backend , .in +\w'struct selabel_handle *selabel_open('u .BI "const struct selinux_opt *" options , .br diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3 index ad637406a30dd7538607c4c8f8c381ad955aebf2..218aaf6d2ae59e6ab93f098809b3d4cbca1575b0 100644 --- a/libselinux/man/man3/selinux_restorecon.3 +++ b/libselinux/man/man3/selinux_restorecon.3 @@ -11,6 +11,14 @@ selinux_restorecon \- restore file(s) default SELinux security contexts .br .BI "unsigned int " restorecon_flags ");" .in +.sp +.BI "int selinux_restorecon_parallel(const char *" pathname , +.in +\w'int selinux_restorecon_parallel('u +.br +.BI "unsigned int " restorecon_flags "," +.br +.BI "size_t " nthreads ");" +.in . .SH "DESCRIPTION" .BR selinux_restorecon () @@ -70,7 +78,10 @@ specfile entries SHA1 digest. The specfile entries digest will be written to the .IR security.sehash extended attribute once relabeling has been completed successfully provided the .B SELINUX_RESTORECON_NOCHANGE -flag has not been set. +flag has not been set, and no errors have been skipped during the file tree walk +due to the +.B SELINUX_RESTORECON_COUNT_ERRORS +flag. .sp .B SELINUX_RESTORECON_NOCHANGE don't change any file labels (passive check) or update the digest in the @@ -156,6 +167,21 @@ on a directory below this. .B SELINUX_RESTORECON_CONFLICT_ERROR to treat conflicting specifications, such as where two hardlinks for the same inode have different contexts, as errors. +.sp +.B SELINUX_RESTORECON_COUNT_ERRORS +Count, but otherwise ignore, errors during the file tree walk. Only makes a +difference if the +.B SELINUX_RESTORECON_ABORT_ON_ERROR +flag is clear. Call +.BR selinux_restorecon_get_skipped_errors (3) +for fetching the ignored (skipped) error count after +.BR selinux_restorecon (3) +or +.BR selinux_restorecon_parallel (3) +completes with success. In case any errors were skipped during the file tree +walk, the specfile entries SHA1 digest will not have been written to the +.IR security.sehash +extended attribute. .RE .sp The behavior regarding the checking and updating of the SHA1 digest described @@ -187,6 +213,27 @@ unless the .B SELINUX_RESTORECON_IGNORE_MOUNTS flag has been set. .RE +.sp +.BR selinux_restorecon_parallel() +is similar to +.BR selinux_restorecon (3), +but accepts another parameter that allows to run relabeling over multiple +threads: +.sp +.RS +.IR nthreads +specifies the number of threads to use during relabeling. When set to 1, +the behavior is the same as calling +.BR selinux_restorecon (3). +When set to 0, the function will try to use as many threads as there are +online CPU cores. When set to any other number, the function will try to use +the given number of threads. +.sp +Note that to use the parallel relabeling capability, the calling process +must be linked with the +.B libpthread +library (either at compile time or dynamically at run time). Otherwise the +function will print a warning and fall back to the single threaded mode. . .SH "RETURN VALUE" On success, zero is returned. On error, \-1 is returned and @@ -250,6 +297,8 @@ option. .br .BR selinux_restorecon_default_handle (3), .br +.BR selinux_restorecon_get_skipped_errors (3), +.br .BR selinux_restorecon_set_exclude_list (3), .br .BR selinux_restorecon_set_alt_rootpath (3), diff --git a/libselinux/man/man3/selinux_restorecon_get_skipped_errors.3 b/libselinux/man/man3/selinux_restorecon_get_skipped_errors.3 new file mode 100644 index 0000000000000000000000000000000000000000..d1757b7612abe66dd9776101f24d4497a56c5275 --- /dev/null +++ b/libselinux/man/man3/selinux_restorecon_get_skipped_errors.3 @@ -0,0 +1,28 @@ +.TH "selinux_restorecon_get_skipped_errors" "3" "27 Apr 2022" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_get_skipped_errors \- get the number of errors ignored by +.BR selinux_restorecon (3) +or +.BR selinux_restorecon_parallel (3) +during the file tree walk +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "long unsigned selinux_restorecon_get_skipped_errors(void);" +.in +\w'long unsigned selinux_restorecon_get_skipped_errors('u +. +.SH "DESCRIPTION" +If +.B SELINUX_RESTORECON_COUNT_ERRORS +was passed to +.BR selinux_restorecon (3) +or +.BR selinux_restorecon_parallel (3) +and that function returned successfully (i.e., with a zero return value), then +.BR selinux_restorecon_get_skipped_errors () +returns the number of errors ignored during the file tree walk. +. +.SH "SEE ALSO" +.BR selinux_restorecon (3) diff --git a/libselinux/man/man3/selinux_restorecon_parallel.3 b/libselinux/man/man3/selinux_restorecon_parallel.3 new file mode 100644 index 0000000000000000000000000000000000000000..092d8412cc93fe750837429f6c82671c32ecc7d2 --- /dev/null +++ b/libselinux/man/man3/selinux_restorecon_parallel.3 @@ -0,0 +1 @@ +.so man3/selinux_restorecon.3 diff --git a/libselinux/man/man3/setfilecon.3 b/libselinux/man/man3/setfilecon.3 index 0e9a383ffb5900990b8d2d49bd4226bf3f48dc71..6c2ed3e0939e70d1fd1ea370e12ee6b1f87c2899 100644 --- a/libselinux/man/man3/setfilecon.3 +++ b/libselinux/man/man3/setfilecon.3 @@ -5,17 +5,17 @@ setfilecon, fsetfilecon, lsetfilecon \- set SELinux security context of a file .SH "SYNOPSIS" .B #include .sp -.BI "int setfilecon(const char *" path ", char *" con ); +.BI "int setfilecon(const char *" path ", const char *" con ); .sp -.BI "int setfilecon_raw(const char *" path ", char *" con ); +.BI "int setfilecon_raw(const char *" path ", const char *" con ); .sp -.BI "int lsetfilecon(const char *" path ", char *" con ); +.BI "int lsetfilecon(const char *" path ", const char *" con ); .sp -.BI "int lsetfilecon_raw(const char *" path ", char *" con ); +.BI "int lsetfilecon_raw(const char *" path ", const char *" con ); .sp -.BI "int fsetfilecon(int "fd ", char *" con ); +.BI "int fsetfilecon(int "fd ", const char *" con ); .sp -.BI "int fsetfilecon_raw(int "fd ", char *" con ); +.BI "int fsetfilecon_raw(int "fd ", const char *" con ); . .SH "DESCRIPTION" .BR setfilecon () @@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to. is identical to setfilecon, only the open file pointed to by filedes (as returned by .BR open (2)) -has it's context set in place of path. +has it's context set in place of path. Since libselinux 3.4 a file opened via +.I O_PATH +is supported. .BR setfilecon_raw (), .BR lsetfilecon_raw (), diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index 52c40f018f51502c9b95310e575e27950ceafa98..04bf4f240168e728af032ec1903b34c00c646c09 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -98,7 +98,6 @@ override LDFLAGS += -L/opt/local/lib -undefined dynamic_lookup LD_SONAME_FLAGS=-install_name,$(LIBSO) endif -PCRE_LDLIBS ?= -lpcre # override with -lfts when building on Musl libc to use fts-standalone FTS_LDLIBS ?= diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c index c18ccc54754ade964dbb4b5feb47ae75e68b184d..469c4055f4d72bc4bd231eb6233401475d5cc344 100644 --- a/libselinux/src/callbacks.c +++ b/libselinux/src/callbacks.c @@ -10,6 +10,8 @@ #include #include "callbacks.h" +pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; + /* default implementations */ static int __attribute__ ((format(printf, 2, 3))) default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) @@ -56,7 +58,7 @@ default_selinux_policyload(int seqno __attribute__((unused))) /* callback pointers */ int __attribute__ ((format(printf, 2, 3))) -(*selinux_log)(int, const char *, ...) = +(*selinux_log_direct)(int, const char *, ...) = default_selinux_log; int @@ -81,7 +83,7 @@ selinux_set_callback(int type, union selinux_callback cb) { switch (type) { case SELINUX_CB_LOG: - selinux_log = cb.func_log; + selinux_log_direct = cb.func_log; break; case SELINUX_CB_AUDIT: selinux_audit = cb.func_audit; @@ -106,7 +108,7 @@ selinux_get_callback(int type) switch (type) { case SELINUX_CB_LOG: - cb.func_log = selinux_log; + cb.func_log = selinux_log_direct; break; case SELINUX_CB_AUDIT: cb.func_audit = selinux_audit; diff --git a/libselinux/src/callbacks.h b/libselinux/src/callbacks.h index 03d87f0cbdfe5a8c32683f1cba3dcf86698190e6..5a4d0f8a85951f76bccef0c8f79e5104a7de72bf 100644 --- a/libselinux/src/callbacks.h +++ b/libselinux/src/callbacks.h @@ -5,14 +5,17 @@ #ifndef _SELINUX_CALLBACKS_H_ #define _SELINUX_CALLBACKS_H_ +#include #include #include #include #include +#include "selinux_internal.h" + /* callback pointers */ extern int __attribute__ ((format(printf, 2, 3))) -(*selinux_log) (int type, const char *, ...) ; +(*selinux_log_direct) (int type, const char *, ...) ; extern int (*selinux_audit) (void *, security_class_t, char *, size_t) ; @@ -26,4 +29,15 @@ extern int extern int (*selinux_netlink_policyload) (int seqno) ; +/* Thread-safe selinux_log() function */ +extern pthread_mutex_t log_mutex; + +#define selinux_log(type, ...) do { \ + int saved_errno__ = errno; \ + __pthread_mutex_lock(&log_mutex); \ + selinux_log_direct(type, __VA_ARGS__); \ + __pthread_mutex_unlock(&log_mutex); \ + errno = saved_errno__; \ +} while(0) + #endif /* _SELINUX_CALLBACKS_H_ */ diff --git a/libselinux/src/exception.sh b/libselinux/src/exception.sh old mode 100755 new mode 100644 diff --git a/libselinux/src/fgetfilecon.c b/libselinux/src/fgetfilecon.c index 8c748f8a2e6475568e948b2e04ddb7f61a938036..baf38ec1221f4623488609f959c2b3c8ce26d722 100644 --- a/libselinux/src/fgetfilecon.c +++ b/libselinux/src/fgetfilecon.c @@ -3,10 +3,32 @@ #include #include #include +#include #include #include "selinux_internal.h" #include "policy.h" +static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) { + char buf[40]; + int fd_flag, saved_errno = errno; + ssize_t ret; + + ret = fgetxattr(fd, name, value, size); + if (ret != -1 || errno != EBADF) + return ret; + + /* Emulate O_PATH support */ + fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd); + errno = saved_errno; + return getxattr(buf, name, value, size); +} + int fgetfilecon_raw(int fd, char ** context) { char *buf; @@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context) return -1; memset(buf, 0, size); - ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1); if (ret < 0 && errno == ERANGE) { char *newbuf; - size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0); + size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0); if (size < 0) goto out; @@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context) buf = newbuf; memset(buf, 0, size); - ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1); } out: if (ret == 0) { diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c index 5cf34e3fa5d047bc34d2e750b9924a05953a72c6..be821c7a6be25c599fb307ab1c92607e48500b6e 100644 --- a/libselinux/src/fsetfilecon.c +++ b/libselinux/src/fsetfilecon.c @@ -3,13 +3,34 @@ #include #include #include +#include #include #include "selinux_internal.h" #include "policy.h" +static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) { + char buf[40]; + int rc, fd_flag, saved_errno = errno; + + rc = fsetxattr(fd, name, value, size, flags); + if (rc == 0 || errno != EBADF) + return rc; + + /* Emulate O_PATH support */ + fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd); + errno = saved_errno; + return setxattr(buf, name, value, size, flags); +} + int fsetfilecon_raw(int fd, const char * context) { - int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, + int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); if (rc < 0 && errno == ENOTSUP) { char * ccontext = NULL; diff --git a/libselinux/src/is_customizable_type.c b/libselinux/src/is_customizable_type.c index 1b17860c362253e1fd4b6951701e556e8ca32faf..f83e1e83e944c49d90827195f74f61652606da9b 100644 --- a/libselinux/src/is_customizable_type.c +++ b/libselinux/src/is_customizable_type.c @@ -9,7 +9,10 @@ #include "selinux_internal.h" #include "context_internal.h" -static int get_customizable_type_list(char *** retlist) +static char **customizable_list = NULL; +static pthread_once_t customizable_once = PTHREAD_ONCE_INIT; + +static void customizable_init(void) { FILE *fp; char *buf; @@ -18,12 +21,12 @@ static int get_customizable_type_list(char *** retlist) fp = fopen(selinux_customizable_types_path(), "re"); if (!fp) - return -1; + return; buf = malloc(selinux_page_size); if (!buf) { fclose(fp); - return -1; + return; } while (fgets_unlocked(buf, selinux_page_size, fp) && ctr < UINT_MAX) { ctr++; @@ -54,23 +57,19 @@ static int get_customizable_type_list(char *** retlist) fclose(fp); free(buf); if (!list) - return -1; - *retlist = list; - return 0; + return; + customizable_list = list; } -static char **customizable_list = NULL; - int is_context_customizable(const char * scontext) { int i; const char *type; context_t c; - if (!customizable_list) { - if (get_customizable_type_list(&customizable_list) != 0) - return -1; - } + __selinux_once(customizable_once, customizable_init); + if (!customizable_list) + return -1; c = context_new(scontext); if (!c) diff --git a/libselinux/src/label.c b/libselinux/src/label.c index a03192e56f37ad8b57358c12d4a46ab08e8768c8..586e5e5e68c099bc360a1003e1bab1ccc5403076 100644 --- a/libselinux/src/label.c +++ b/libselinux/src/label.c @@ -226,6 +226,8 @@ struct selabel_handle *selabel_open(unsigned int backend, rec->digest = selabel_is_digest_set(opts, nopts, rec->digest); if ((*initfuncs[backend])(rec, opts, nopts)) { + if (rec->digest) + selabel_digest_fini(rec->digest); free(rec->spec_file); free(rec); rec = NULL; diff --git a/libselinux/src/label_backends_android.c b/libselinux/src/label_backends_android.c index 66d4df2d2895a10cd6f1045d084cc387abaf3037..c2d78360e2a0cc09fbe962c7054ee83e13633972 100644 --- a/libselinux/src/label_backends_android.c +++ b/libselinux/src/label_backends_android.c @@ -93,7 +93,6 @@ static int process_line(struct selabel_handle *rec, items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); if (items < 0) { - items = errno; if (errbuf) { selinux_log(SELINUX_ERROR, "%s: line %u error due to: %s\n", path, @@ -103,7 +102,6 @@ static int process_line(struct selabel_handle *rec, "%s: line %u error due to: %m\n", path, lineno); } - errno = items; return -1; } diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index 2e28d0474d731ddf4c6c219d4610cf05596a050b..74ae9b9feb70ff2accf6b253ec2bb35d24719ed2 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c @@ -951,7 +951,12 @@ static struct spec **lookup_all(struct selabel_handle *rec, rc = regex_match(spec->regex, key, partial); if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) { if (rc == REGEX_MATCH) { - spec->matches++; +#ifdef __ATOMIC_RELAXED + __atomic_store_n(&spec->any_matches, + true, __ATOMIC_RELAXED); +#else +#error "Please use a compiler that supports __atomic builtins" +#endif } if (strcmp(spec_arr[i].lr.ctx_raw, "<>") == 0) { @@ -1249,9 +1254,15 @@ static void stats(struct selabel_handle *rec) struct saved_data *data = (struct saved_data *)rec->data; unsigned int i, nspec = data->nspec; struct spec *spec_arr = data->spec_arr; + bool any_matches; for (i = 0; i < nspec; i++) { - if (spec_arr[i].matches == 0) { +#ifdef __ATOMIC_RELAXED + any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED); +#else +#error "Please use a compiler that supports __atomic builtins" +#endif + if (!any_matches) { if (spec_arr[i].type_str) { COMPAT_LOG(SELINUX_WARNING, "Warning! No matches for (%s, %s, %s)\n", diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h index 343ffc705e433ac2f92043e632202807814cbf4f..190bc1759cbea4049f17cf6f83adf1e0f42ee617 100644 --- a/libselinux/src/label_file.h +++ b/libselinux/src/label_file.h @@ -51,7 +51,7 @@ struct spec { bool regex_compiled; /* bool to indicate if the regex is compiled */ pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */ mode_t mode; /* mode format value */ - int matches; /* number of matching pathnames */ + bool any_matches; /* did any pathname match? */ int stem_id; /* indicates which stem-compression item */ char hasMetaChars; /* regular expression has meta-chars */ char from_mmap; /* this spec is from an mmap of the data */ @@ -444,7 +444,6 @@ static inline int process_line(struct selabel_handle *rec, items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context); if (items < 0) { - rc = errno; if (errbuf) { selinux_log(SELINUX_ERROR, "%s: line %u error due to: %s\n", path, @@ -454,7 +453,6 @@ static inline int process_line(struct selabel_handle *rec, "%s: line %u error due to: %m\n", path, lineno); } - errno = rc; return -1; } diff --git a/libselinux/src/label_media.c b/libselinux/src/label_media.c index eb27deaf510ead4ea43582acb27cf5fe8b659254..3137c18edc19271b7fcae8b7cde6fe0af3c0bf1f 100644 --- a/libselinux/src/label_media.c +++ b/libselinux/src/label_media.c @@ -95,10 +95,10 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts, __fsetlocking(fp, FSETLOCKING_BYCALLER); if (fstat(fileno(fp), &sb) < 0) - return -1; + goto finish; if (!S_ISREG(sb.st_mode)) { errno = EINVAL; - return -1; + goto finish; } rec->spec_file = strdup(path); diff --git a/libselinux/src/label_support.c b/libselinux/src/label_support.c index 94ed6e4273cbc27d92028bed9d26a3374f5c90bb..54fd49a5b7b9b40b41ba47b3f3cfa18adacd9e02 100644 --- a/libselinux/src/label_support.c +++ b/libselinux/src/label_support.c @@ -116,13 +116,25 @@ int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) void digest_gen_hash(struct selabel_digest *digest) { Sha1Context context; + size_t remaining_size; + const unsigned char *ptr; /* If SELABEL_OPT_DIGEST not set then just return */ if (!digest) return; Sha1Initialise(&context); - Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); + + /* Process in blocks of UINT32_MAX bytes */ + remaining_size = digest->hashbuf_size; + ptr = digest->hashbuf; + while (remaining_size > UINT32_MAX) { + Sha1Update(&context, ptr, UINT32_MAX); + remaining_size -= UINT32_MAX; + ptr += UINT32_MAX; + } + Sha1Update(&context, ptr, remaining_size); + Sha1Finalise(&context, (SHA1_HASH *)digest->digest); free(digest->hashbuf); digest->hashbuf = NULL; diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c index e9fa063fafffb42e3b329508f338bd5087bc4363..e6e8d9f60bffa9a04df0a18a3113ba421b8c342a 100644 --- a/libselinux/src/label_x.c +++ b/libselinux/src/label_x.c @@ -122,10 +122,10 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts, __fsetlocking(fp, FSETLOCKING_BYCALLER); if (fstat(fileno(fp), &sb) < 0) - return -1; + goto finish; if (!S_ISREG(sb.st_mode)) { errno = EINVAL; - return -1; + goto finish; } rec->spec_file = strdup(path); diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map index 2a368e93f9fd6e5971d58053e79d4cfd68a2731b..6e04eb61c0c5f85bf10c31c82390b429574f678c 100644 --- a/libselinux/src/libselinux.map +++ b/libselinux/src/libselinux.map @@ -240,3 +240,9 @@ LIBSELINUX_1.0 { local: *; }; + +LIBSELINUX_3.4 { + global: + selinux_restorecon_get_skipped_errors; + selinux_restorecon_parallel; +} LIBSELINUX_1.0; diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c index 1e7f8890c22e36d5301d08435bd911501208235b..ea78a23edc5a6736760110f31914632ebb2436af 100644 --- a/libselinux/src/matchpathcon.c +++ b/libselinux/src/matchpathcon.c @@ -356,7 +356,7 @@ int matchpathcon_init_prefix(const char *path, const char *subset) mycanoncon = default_canoncon; __selinux_once(once, matchpathcon_init_once); - __selinux_setspecific(destructor_key, (void *)1); + __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size); options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; options[SELABEL_OPT_SUBSET].value = subset; diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c index 72eb5efe922eea86ac3d4c7e92de01aae123326c..9896483e25f0fdadb73901b257c0ce1ca997009d 100644 --- a/libselinux/src/procattr.c +++ b/libselinux/src/procattr.c @@ -68,7 +68,7 @@ void __attribute__((destructor)) procattr_destructor(void) static inline void init_thread_destructor(void) { if (destructor_initialized == 0) { - __selinux_setspecific(destructor_key, (void *)1); + __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size); destructor_initialized = 1; } } diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c index 97f81a8b61ce18ec06c234889d7f2fb017413bbb..d2e49ee124bdbc811e87d6c8b1f6afb953cdc0d3 100644 --- a/libselinux/src/selinux_config.c +++ b/libselinux/src/selinux_config.c @@ -92,6 +92,7 @@ int selinux_getenforcemode(int *enforce) FILE *cfg = fopen(SELINUXCONFIG, "re"); if (cfg) { char *buf; + char *tag; int len = sizeof(SELINUXTAG) - 1; buf = malloc(selinux_page_size); if (!buf) { @@ -101,21 +102,24 @@ int selinux_getenforcemode(int *enforce) while (fgets_unlocked(buf, selinux_page_size, cfg)) { if (strncmp(buf, SELINUXTAG, len)) continue; + tag = buf+len; + while (isspace(*tag)) + tag++; if (!strncasecmp - (buf + len, "enforcing", sizeof("enforcing") - 1)) { + (tag, "enforcing", sizeof("enforcing") - 1)) { *enforce = 1; ret = 0; break; } else if (!strncasecmp - (buf + len, "permissive", + (tag, "permissive", sizeof("permissive") - 1)) { *enforce = 0; ret = 0; break; } else if (!strncasecmp - (buf + len, "disabled", + (tag, "disabled", sizeof("disabled") - 1)) { *enforce = -1; ret = 0; @@ -176,7 +180,10 @@ static void init_selinux_config(void) if (!strncasecmp(buf_p, SELINUXTYPETAG, sizeof(SELINUXTYPETAG) - 1)) { - type = strdup(buf_p + sizeof(SELINUXTYPETAG) - 1); + buf_p += sizeof(SELINUXTYPETAG) - 1; + while (isspace(*buf_p)) + buf_p++; + type = strdup(buf_p); if (!type) { free(line_buf); fclose(fp); @@ -199,6 +206,8 @@ static void init_selinux_config(void) } else if (!strncmp(buf_p, REQUIRESEUSERS, sizeof(REQUIRESEUSERS) - 1)) { value = buf_p + sizeof(REQUIRESEUSERS) - 1; + while (isspace(*value)) + value++; intptr = &require_seusers; } else { continue; diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index 27e9ac532c3f200fd239c38f0da01bb32def1bc6..297dcf26dee360168d0ac9586e20a28eb2929428 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -69,6 +69,22 @@ extern int selinux_page_size ; pthread_mutex_unlock(LOCK); \ } while (0) +#pragma weak pthread_create +#pragma weak pthread_join +#pragma weak pthread_cond_init +#pragma weak pthread_cond_signal +#pragma weak pthread_cond_destroy +#pragma weak pthread_cond_wait + +/* check if all functions needed to do parallel operations are available */ +#define __pthread_supported ( \ + pthread_create && \ + pthread_join && \ + pthread_cond_init && \ + pthread_cond_destroy && \ + pthread_cond_signal && \ + pthread_cond_wait \ +) #define SELINUXDIR "/etc/selinux/" #define SELINUXCONFIG SELINUXDIR "config" diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index e2553cdabeb54837190122680b390d7ebf41360d..dea3adbcb69198519ea6527ed456c5db998df631 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -44,7 +44,7 @@ static struct selabel_handle *fc_sehandle = NULL; static bool selabel_no_digest; static char *rootpath = NULL; -static int rootpathlen; +static size_t rootpathlen; /* Information on excluded fs and directories. */ struct edir { @@ -55,16 +55,20 @@ struct edir { }; #define CALLER_EXCLUDED true static bool ignore_mounts; -static int exclude_non_seclabel_mounts(void); +static uint64_t exclude_non_seclabel_mounts(void); static int exclude_count = 0; static struct edir *exclude_lst = NULL; static uint64_t fc_count = 0; /* Number of files processed so far */ static uint64_t efile_count; /* Estimated total number of files */ +static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER; /* Store information on directories with xattr's. */ static struct dir_xattr *dir_xattr_list; static struct dir_xattr *dir_xattr_last; +/* Number of errors ignored during the file tree walk. */ +static long unsigned skipped_errors; + /* restorecon_flags for passing to restorecon_sb() */ struct rest_flags { bool nochange; @@ -82,6 +86,7 @@ struct rest_flags { bool ignore_noent; bool warnonnomatch; bool conflicterror; + bool count_errors; }; static void restorecon_init(void) @@ -164,6 +169,12 @@ static int add_exclude(const char *directory, bool who) return -1; } + if (exclude_count >= INT_MAX - 1) { + selinux_log(SELINUX_ERROR, "Too many directory excludes: %d.\n", exclude_count); + errno = EOVERFLOW; + return -1; + } + tmp_list = realloc(exclude_lst, sizeof(struct edir) * (exclude_count + 1)); if (!tmp_list) @@ -206,10 +217,10 @@ static int check_excluded(const char *file) return 0; } -static int file_system_count(char *name) +static uint64_t file_system_count(const char *name) { struct statvfs statvfs_buf; - int nfile = 0; + uint64_t nfile = 0; memset(&statvfs_buf, 0, sizeof(statvfs_buf)); if (!statvfs(name, &statvfs_buf)) @@ -225,12 +236,13 @@ static int file_system_count(char *name) * that support security labels have the seclabel option, return * approximate total file count. */ -static int exclude_non_seclabel_mounts(void) +static uint64_t exclude_non_seclabel_mounts(void) { struct utsname uts; FILE *fp; size_t len; - int index = 0, found = 0, nfile = 0; + int index = 0, found = 0; + uint64_t nfile = 0; char *mount_info[4]; char *buf = NULL, *item; @@ -295,7 +307,8 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, { char *sha1_buf = NULL; size_t i, digest_len = 0; - int rc, digest_result; + int rc; + enum digest_result digest_result; bool match; struct dir_xattr *new_entry; uint8_t *xattr_digest = NULL; @@ -411,6 +424,7 @@ typedef struct file_spec { } file_spec_t; static file_spec_t *fl_head; +static pthread_mutex_t fl_mutex = PTHREAD_MUTEX_INITIALIZER; /* * Try to add an association between an inode and a context. If there is a @@ -424,11 +438,12 @@ static int filespec_add(ino_t ino, const char *con, const char *file, int h, ret; struct stat64 sb; + __pthread_mutex_lock(&fl_mutex); + if (!fl_head) { - fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t)); if (!fl_head) goto oom; - memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); } h = (ino + (ino >> HASH_BITS)) & HASH_MASK; @@ -445,11 +460,11 @@ static int filespec_add(ino_t ino, const char *con, const char *file, fl->con = strdup(con); if (!fl->con) goto oom; - return 1; + goto unlock_1; } if (strcmp(fl->con, con) == 0) - return 1; + goto unlock_1; selinux_log(SELINUX_ERROR, "conflicting specifications for %s and %s, using %s.\n", @@ -458,6 +473,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file, fl->file = strdup(file); if (!fl->file) goto oom; + + __pthread_mutex_unlock(&fl_mutex); + if (flags->conflicterror) { selinux_log(SELINUX_ERROR, "treating conflicting specifications as an error.\n"); @@ -479,16 +497,24 @@ static int filespec_add(ino_t ino, const char *con, const char *file, goto oom_freefl; fl->file = strdup(file); if (!fl->file) - goto oom_freefl; + goto oom_freeflcon; fl->next = prevfl->next; prevfl->next = fl; + + __pthread_mutex_unlock(&fl_mutex); return 0; +oom_freeflcon: + free(fl->con); oom_freefl: free(fl); oom: + __pthread_mutex_unlock(&fl_mutex); selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); return -1; +unlock_1: + __pthread_mutex_unlock(&fl_mutex); + return 1; } /* @@ -557,7 +583,7 @@ static void filespec_destroy(void) * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if * the type components differ, updating newtypecon if so. */ -static int compare_types(char *curcon, char *newcon, char **newtypecon) +static int compare_types(const char *curcon, const char *newcon, char **newtypecon) { int types_differ = 0; context_t cona; @@ -603,13 +629,13 @@ out: #define DATA_APP_EL4 "/data/app/el4/" #define DATA_ACCOUNTS_ACCOUNT_0 "/data/accounts/account_0/" -static int restorecon_sb(const char *pathname, const struct stat *sb, - struct rest_flags *flags) +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first) { char *newcon = NULL; char *curcon = NULL; char *newtypecon = NULL; - int rc; + int fd = -1, rc; + struct stat stat_buf; bool updated = false; const char *lookup_path = pathname; float pc; @@ -620,7 +646,6 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, !strncmp(pathname, DATA_ACCOUNTS_ACCOUNT_0, sizeof(DATA_ACCOUNTS_ACCOUNT_0) - 1)) { goto out; } - if (rootpath) { if (strncmp(rootpath, lookup_path, rootpathlen) != 0) { selinux_log(SELINUX_ERROR, @@ -631,24 +656,37 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, lookup_path += rootpathlen; } + fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL); + if (fd < 0) + goto err; + + rc = fstat(fd, &stat_buf); + if (rc < 0) + goto err; + if (rootpath != NULL && lookup_path[0] == '\0') /* this is actually the root dir of the alt root. */ rc = selabel_lookup_raw(fc_sehandle, &newcon, "/", - sb->st_mode); + stat_buf.st_mode); else rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path, - sb->st_mode); + stat_buf.st_mode); if (rc < 0) { - if (errno == ENOENT && flags->warnonnomatch) - selinux_log(SELINUX_INFO, - "Warning no default label for %s\n", - lookup_path); + if (errno == ENOENT) { + if (flags->warnonnomatch && first) + selinux_log(SELINUX_INFO, + "Warning no default label for %s\n", + lookup_path); - return 0; /* no match, but not an error */ + goto out; /* no match, but not an error */ + } + + goto err; } if (flags->progress) { + __pthread_mutex_lock(&progress_mutex); fc_count++; if (fc_count % STAR_COUNT == 0) { if (flags->mass_relabel && efile_count > 0) { @@ -660,22 +698,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } fflush(stdout); } + __pthread_mutex_unlock(&progress_mutex); } if (flags->add_assoc) { - rc = filespec_add(sb->st_ino, newcon, pathname, flags); + rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags); if (rc < 0) { selinux_log(SELINUX_ERROR, "filespec_add error: %s\n", pathname); - freecon(newcon); - return -1; + goto out1; } if (rc > 0) { /* Already an association and it took precedence. */ - freecon(newcon); - return 0; + goto out; } } @@ -683,7 +720,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, selinux_log(SELINUX_INFO, "%s matched by %s\n", pathname, newcon); - if (lgetfilecon_raw(pathname, &curcon) < 0) { + if (fgetfilecon_raw(fd, &curcon) < 0) { if (errno != ENODATA) goto err; @@ -716,7 +753,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (!flags->nochange) { - if (lsetfilecon(pathname, newcon) < 0) + if (fsetfilecon(fd, newcon) < 0) goto err; updated = true; } @@ -741,6 +778,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, out: rc = 0; out1: + if (fd >= 0) + close(fd); freecon(curcon); freecon(newcon); return rc; @@ -813,66 +852,224 @@ oom: goto free; } +struct rest_state { + struct rest_flags flags; + dev_t dev_num; + struct statfs sfsb; + bool ignore_digest; + bool setrestorecondigest; + bool parallel; -/* - * Public API - */ + FTS *fts; + FTSENT *ftsent_first; + struct dir_hash_node *head, *current; + bool abort; + int error; + long unsigned skipped_errors; + int saved_errno; + pthread_mutex_t mutex; +}; -/* selinux_restorecon(3) - Main function that is responsible for labeling */ -int selinux_restorecon(const char *pathname_orig, - unsigned int restorecon_flags) +static void *selinux_restorecon_thread(void *arg) { - struct rest_flags flags; + struct rest_state *state = arg; + FTS *fts = state->fts; + FTSENT *ftsent; + int error; + char ent_path[PATH_MAX]; + bool first = false; + + if (state->parallel) + pthread_mutex_lock(&state->mutex); + + if (state->ftsent_first) { + ftsent = state->ftsent_first; + state->ftsent_first = NULL; + first = true; + goto loop_body; + } + + while (((void)(errno = 0), ftsent = fts_read(fts)) != NULL) { +loop_body: + /* If the FTS_XDEV flag is set and the device is different */ + if (state->flags.set_xdev && + ftsent->fts_statp->st_dev != state->dev_num) + continue; + + switch (ftsent->fts_info) { + case FTS_DC: + selinux_log(SELINUX_ERROR, + "Directory cycle on %s.\n", + ftsent->fts_path); + errno = ELOOP; + state->error = -1; + state->abort = true; + goto finish; + case FTS_DP: + continue; + case FTS_DNR: + error = errno; + errno = ftsent->fts_errno; + selinux_log(SELINUX_ERROR, + "Could not read %s: %m.\n", + ftsent->fts_path); + errno = error; + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_NS: + error = errno; + errno = ftsent->fts_errno; + selinux_log(SELINUX_ERROR, + "Could not stat %s: %m.\n", + ftsent->fts_path); + errno = error; + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_ERR: + error = errno; + errno = ftsent->fts_errno; + selinux_log(SELINUX_ERROR, + "Error on %s: %m.\n", + ftsent->fts_path); + errno = error; + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_D: + if (state->sfsb.f_type == SYSFS_MAGIC && + !selabel_partial_match(fc_sehandle, + ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (check_excluded(ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (state->setrestorecondigest) { + struct dir_hash_node *new_node = NULL; + + if (check_context_match_for_dir(ftsent->fts_path, + &new_node, + state->error) && + !state->ignore_digest) { + selinux_log(SELINUX_INFO, + "Skipping restorecon on directory(%s)\n", + ftsent->fts_path); + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (new_node && !state->error) { + if (!state->current) { + state->current = new_node; + state->head = state->current; + } else { + state->current->next = new_node; + state->current = new_node; + } + } + } + /* fall through */ + default: + strcpy(ent_path, ftsent->fts_path); + + if (state->parallel) + pthread_mutex_unlock(&state->mutex); + + error = restorecon_sb(ent_path, &state->flags, + first); + + if (state->parallel) { + pthread_mutex_lock(&state->mutex); + if (state->abort) + goto unlock; + } + + first = false; + if (error) { + if (state->flags.abort_on_error) { + state->error = error; + state->abort = true; + goto finish; + } + if (state->flags.count_errors) + state->skipped_errors++; + else + state->error = error; + } + break; + } + } + +finish: + if (!state->saved_errno) + state->saved_errno = errno; +unlock: + if (state->parallel) + pthread_mutex_unlock(&state->mutex); + return NULL; +} - flags.nochange = (restorecon_flags & +static int selinux_restorecon_common(const char *pathname_orig, + unsigned int restorecon_flags, + size_t nthreads) +{ + struct rest_state state; + + state.flags.nochange = (restorecon_flags & SELINUX_RESTORECON_NOCHANGE) ? true : false; - flags.verbose = (restorecon_flags & + state.flags.verbose = (restorecon_flags & SELINUX_RESTORECON_VERBOSE) ? true : false; - flags.progress = (restorecon_flags & + state.flags.progress = (restorecon_flags & SELINUX_RESTORECON_PROGRESS) ? true : false; - flags.mass_relabel = (restorecon_flags & + state.flags.mass_relabel = (restorecon_flags & SELINUX_RESTORECON_MASS_RELABEL) ? true : false; - flags.recurse = (restorecon_flags & + state.flags.recurse = (restorecon_flags & SELINUX_RESTORECON_RECURSE) ? true : false; - flags.set_specctx = (restorecon_flags & + state.flags.set_specctx = (restorecon_flags & SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; - flags.userealpath = (restorecon_flags & + state.flags.userealpath = (restorecon_flags & SELINUX_RESTORECON_REALPATH) ? true : false; - flags.set_xdev = (restorecon_flags & + state.flags.set_xdev = (restorecon_flags & SELINUX_RESTORECON_XDEV) ? true : false; - flags.add_assoc = (restorecon_flags & + state.flags.add_assoc = (restorecon_flags & SELINUX_RESTORECON_ADD_ASSOC) ? true : false; - flags.abort_on_error = (restorecon_flags & + state.flags.abort_on_error = (restorecon_flags & SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false; - flags.syslog_changes = (restorecon_flags & + state.flags.syslog_changes = (restorecon_flags & SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false; - flags.log_matches = (restorecon_flags & + state.flags.log_matches = (restorecon_flags & SELINUX_RESTORECON_LOG_MATCHES) ? true : false; - flags.ignore_noent = (restorecon_flags & + state.flags.ignore_noent = (restorecon_flags & SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false; - flags.warnonnomatch = true; - flags.conflicterror = (restorecon_flags & + state.flags.warnonnomatch = true; + state.flags.conflicterror = (restorecon_flags & SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false; ignore_mounts = (restorecon_flags & SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false; - bool ignore_digest = (restorecon_flags & + state.ignore_digest = (restorecon_flags & SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; - bool setrestorecondigest = true; + state.flags.count_errors = (restorecon_flags & + SELINUX_RESTORECON_COUNT_ERRORS) ? true : false; + state.setrestorecondigest = true; + + state.head = NULL; + state.current = NULL; + state.abort = false; + state.error = 0; + state.skipped_errors = 0; + state.saved_errno = 0; struct stat sb; - struct statfs sfsb; - FTS *fts; - FTSENT *ftsent; char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; char *paths[2] = { NULL, NULL }; - int fts_flags, error, sverrno; - dev_t dev_num = 0; + int fts_flags, error; struct dir_hash_node *current = NULL; - struct dir_hash_node *head = NULL; - int errno_tmp; - if (flags.verbose && flags.progress) - flags.verbose = false; + if (state.flags.verbose && state.flags.progress) + state.flags.verbose = false; __selinux_once(fc_once, restorecon_init); @@ -885,13 +1082,31 @@ int selinux_restorecon(const char *pathname_orig, */ if (selabel_no_digest || (restorecon_flags & SELINUX_RESTORECON_SKIP_DIGEST)) - setrestorecondigest = false; + state.setrestorecondigest = false; + + if (!__pthread_supported) { + if (nthreads != 1) { + nthreads = 1; + selinux_log(SELINUX_WARNING, + "Threading functionality not available, falling back to 1 thread."); + } + } else if (nthreads == 0) { + long nproc = sysconf(_SC_NPROCESSORS_ONLN); + + if (nproc > 0) { + nthreads = nproc; + } else { + nthreads = 1; + selinux_log(SELINUX_WARNING, + "Unable to detect CPU count, falling back to 1 thread."); + } + } /* * Convert passed-in pathname to canonical pathname by resolving * realpath of containing dir, then appending last component name. */ - if (flags.userealpath) { + if (state.flags.userealpath) { char *basename_cpy = strdup(pathname_orig); if (!basename_cpy) goto realpatherr; @@ -936,7 +1151,7 @@ int selinux_restorecon(const char *pathname_orig, paths[0] = pathname; if (lstat(pathname, &sb) < 0) { - if (flags.ignore_noent && errno == ENOENT) { + if (state.flags.ignore_noent && errno == ENOENT) { free(pathdnamer); free(pathname); return 0; @@ -951,21 +1166,21 @@ int selinux_restorecon(const char *pathname_orig, /* Skip digest if not a directory */ if (!S_ISDIR(sb.st_mode)) - setrestorecondigest = false; + state.setrestorecondigest = false; - if (!flags.recurse) { + if (!state.flags.recurse) { if (check_excluded(pathname)) { error = 0; goto cleanup; } - error = restorecon_sb(pathname, &sb, &flags); + error = restorecon_sb(pathname, &state.flags, true); goto cleanup; } /* Obtain fs type */ - memset(&sfsb, 0, sizeof sfsb); - if (!S_ISLNK(sb.st_mode) && statfs(pathname, &sfsb) < 0) { + memset(&state.sfsb, 0, sizeof(state.sfsb)); + if (!S_ISLNK(sb.st_mode) && statfs(pathname, &state.sfsb) < 0) { selinux_log(SELINUX_ERROR, "statfs(%s) failed: %m\n", pathname); @@ -974,21 +1189,21 @@ int selinux_restorecon(const char *pathname_orig, } /* Skip digest on in-memory filesystems and /sys */ - if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC || - sfsb.f_type == SYSFS_MAGIC) - setrestorecondigest = false; + if (state.sfsb.f_type == RAMFS_MAGIC || state.sfsb.f_type == TMPFS_MAGIC || + state.sfsb.f_type == SYSFS_MAGIC) + state.setrestorecondigest = false; - if (flags.set_xdev) + if (state.flags.set_xdev) fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; else fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; - fts = fts_open(paths, fts_flags, NULL); - if (!fts) + state.fts = fts_open(paths, fts_flags, NULL); + if (!state.fts) goto fts_err; - ftsent = fts_read(fts); - if (!ftsent) + state.ftsent_first = fts_read(state.fts); + if (!state.ftsent_first) goto fts_err; /* @@ -1000,106 +1215,69 @@ int selinux_restorecon(const char *pathname_orig, * directories with a different device number when the FTS_XDEV flag * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2). */ - dev_num = ftsent->fts_statp->st_dev; + state.dev_num = state.ftsent_first->fts_statp->st_dev; - error = 0; - do { - /* If the FTS_XDEV flag is set and the device is different */ - if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num) - continue; + if (nthreads == 1) { + state.parallel = false; + selinux_restorecon_thread(&state); + } else { + size_t i; + pthread_t self = pthread_self(); + pthread_t *threads = NULL; - switch (ftsent->fts_info) { - case FTS_DC: - selinux_log(SELINUX_ERROR, - "Directory cycle on %s.\n", - ftsent->fts_path); - errno = ELOOP; - error = -1; - goto out; - case FTS_DP: - continue; - case FTS_DNR: - errno_tmp = errno; - errno = ftsent->fts_errno; - selinux_log(SELINUX_ERROR, - "Could not read %s: %m.\n", - ftsent->fts_path); - errno = errno_tmp; - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_NS: - errno_tmp = errno; - errno = ftsent->fts_errno; - selinux_log(SELINUX_ERROR, - "Could not stat %s: %m.\n", - ftsent->fts_path); - errno = errno_tmp; - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_ERR: - errno_tmp = errno; - errno = ftsent->fts_errno; - selinux_log(SELINUX_ERROR, - "Error on %s: %m.\n", - ftsent->fts_path); - errno = errno_tmp; - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_D: - if (sfsb.f_type == SYSFS_MAGIC && - !selabel_partial_match(fc_sehandle, - ftsent->fts_path)) { - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + pthread_mutex_init(&state.mutex, NULL); - if (check_excluded(ftsent->fts_path)) { - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + threads = calloc(nthreads - 1, sizeof(*threads)); + if (!threads) + goto oom; - if (setrestorecondigest) { - struct dir_hash_node *new_node = NULL; + state.parallel = true; + /* + * Start (nthreads - 1) threads - the main thread is going to + * take part, too. + */ + for (i = 0; i < nthreads - 1; i++) { + if (pthread_create(&threads[i], NULL, + selinux_restorecon_thread, &state)) { + /* + * If any thread fails to be created, just mark + * it as such and let the successfully created + * threads do the job. In the worst case the + * main thread will do everything, but that's + * still better than to give up. + */ + threads[i] = self; + } + } - if (check_context_match_for_dir(ftsent->fts_path, - &new_node, - error) && - !ignore_digest) { - selinux_log(SELINUX_INFO, - "Skipping restorecon on directory(%s)\n", - ftsent->fts_path); - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + /* Let's join in on the fun! */ + selinux_restorecon_thread(&state); - if (new_node && !error) { - if (!current) { - current = new_node; - head = current; - } else { - current->next = new_node; - current = current->next; - } - } - } - /* fall through */ - default: - error |= restorecon_sb(ftsent->fts_path, - ftsent->fts_statp, &flags); - if (flags.warnonnomatch) - flags.warnonnomatch = false; - if (error && flags.abort_on_error) - goto out; - break; + /* Now wait for all threads to finish. */ + for (i = 0; i < nthreads - 1; i++) { + /* Skip threads that failed to be created. */ + if (pthread_equal(threads[i], self)) + continue; + pthread_join(threads[i], NULL); } - } while ((ftsent = fts_read(fts)) != NULL); + free(threads); + + pthread_mutex_destroy(&state.mutex); + } + + error = state.error; + if (state.saved_errno) + goto out; /* * Labeling successful. Write partial match digests for subdirectories. * TODO: Write digest upon FTS_DP if no error occurs in its descents. + * Note: we can't ignore errors here that we've masked due to + * SELINUX_RESTORECON_COUNT_ERRORS. */ - if (setrestorecondigest && !flags.nochange && !error) { - current = head; + if (state.setrestorecondigest && !state.flags.nochange && !error && + state.skipped_errors == 0) { + current = state.head; while (current != NULL) { if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, @@ -1113,23 +1291,24 @@ int selinux_restorecon(const char *pathname_orig, } } + skipped_errors = state.skipped_errors; + out: - if (flags.progress && flags.mass_relabel) + if (state.flags.progress && state.flags.mass_relabel) fprintf(stdout, "\r%s 100.0%%\n", pathname); - sverrno = errno; - (void) fts_close(fts); - errno = sverrno; + (void) fts_close(state.fts); + errno = state.saved_errno; cleanup: - if (flags.add_assoc) { - if (flags.verbose) + if (state.flags.add_assoc) { + if (state.flags.verbose) filespec_eval(); filespec_destroy(); } free(pathdnamer); free(pathname); - current = head; + current = state.head; while (current != NULL) { struct dir_hash_node *next = current->next; @@ -1140,18 +1319,14 @@ cleanup: return error; oom: - sverrno = errno; selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); - errno = sverrno; error = -1; goto cleanup; realpatherr: - sverrno = errno; selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %m.\n", pathname_orig); - errno = sverrno; error = -1; goto cleanup; @@ -1163,6 +1338,26 @@ fts_err: goto cleanup; } + +/* + * Public API + */ + +/* selinux_restorecon(3) - Main function that is responsible for labeling */ +int selinux_restorecon(const char *pathname_orig, + unsigned int restorecon_flags) +{ + return selinux_restorecon_common(pathname_orig, restorecon_flags, 1); +} + +/* selinux_restorecon_parallel(3) - Parallel version of selinux_restorecon(3) */ +int selinux_restorecon_parallel(const char *pathname_orig, + unsigned int restorecon_flags, + size_t nthreads) +{ + return selinux_restorecon_common(pathname_orig, restorecon_flags, nthreads); +} + /* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ void selinux_restorecon_set_sehandle(struct selabel_handle *hndl) { @@ -1232,7 +1427,7 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list) /* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */ int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath) { - int len; + size_t len; /* This should be NULL on first use */ if (rootpath) @@ -1373,3 +1568,8 @@ cleanup: } return -1; } + +long unsigned selinux_restorecon_get_skipped_errors(void) +{ + return skipped_errors; +} diff --git a/libselinux/src/selinuxswig_python.i b/libselinux/src/selinuxswig_python.i index 4c73bf92df96bf5f62cec9513224459c30703b86..17e03b9e36a5f3d108274a8b5e550daefbbc5c97 100644 --- a/libselinux/src/selinuxswig_python.i +++ b/libselinux/src/selinuxswig_python.i @@ -20,7 +20,7 @@ DISABLED = -1 PERMISSIVE = 0 ENFORCING = 1 -def restorecon(path, recursive=False, verbose=False, force=False): +def restorecon(path, recursive=False, verbose=False, force=False, nthreads=1): """ Restore SELinux context on a given path Arguments: @@ -32,6 +32,8 @@ def restorecon(path, recursive=False, verbose=False, force=False): force -- Force reset of context to match file_context for customizable files, and the default file context, changing the user, role, range portion as well as the type (default False) + nthreads -- The number of threads to use during relabeling, or 0 to use as many + threads as there are online CPU cores (default 1) """ restorecon_flags = SELINUX_RESTORECON_IGNORE_DIGEST | SELINUX_RESTORECON_REALPATH @@ -41,7 +43,7 @@ def restorecon(path, recursive=False, verbose=False, force=False): restorecon_flags |= SELINUX_RESTORECON_VERBOSE if force: restorecon_flags |= SELINUX_RESTORECON_SET_SPECFILE_CTX - selinux_restorecon(os.path.expanduser(path), restorecon_flags) + selinux_restorecon_parallel(os.path.expanduser(path), restorecon_flags, nthreads) def chcon(path, context, recursive=False): """ Set the SELinux context on a given path """ diff --git a/libselinux/src/selinuxswig_python_exception.i b/libselinux/src/selinuxswig_python_exception.i index 237ea69ad5f5666a35aab748545ff2f264e82499..a02f4923a1e7a1d919e6d6444e8b2bc68ff5a172 100644 --- a/libselinux/src/selinuxswig_python_exception.i +++ b/libselinux/src/selinuxswig_python_exception.i @@ -1183,6 +1183,14 @@ } } +%exception selinux_restorecon_parallel { + $action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + SWIG_fail; + } +} + %exception selinux_restorecon_set_alt_rootpath { $action if (result < 0) { diff --git a/libselinux/src/setrans_client.c b/libselinux/src/setrans_client.c index 52a8ba78b2ad48d6b52d5b254ec658e58735daf7..faa126813a7755a88cc8acefb71f9f8574ea5b58 100644 --- a/libselinux/src/setrans_client.c +++ b/libselinux/src/setrans_client.c @@ -272,7 +272,7 @@ static inline void init_thread_destructor(void) if (!has_setrans) return; if (destructor_initialized == 0) { - __selinux_setspecific(destructor_key, (void *)1); + __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size); destructor_initialized = 1; } } diff --git a/libselinux/src/setup.py b/libselinux/src/setup.py index b79b2750748083387a37197207c60a6fed427de6..71e69a107f0194f0a5847ea46a56588c2eef678f 100644 --- a/libselinux/src/setup.py +++ b/libselinux/src/setup.py @@ -4,7 +4,7 @@ from distutils.core import Extension, setup setup( name="selinux", - version="3.3", + version="3.4", description="SELinux python 3 bindings", author="SELinux Project", author_email="selinux@vger.kernel.org", diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile index 3681615580332125c5a219faa685715f55ad1ad4..801066cb051a8a8b3e39fce02d82e4c91c5172e0 100644 --- a/libselinux/utils/Makefile +++ b/libselinux/utils/Makefile @@ -44,7 +44,6 @@ endif override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS) override LDFLAGS += -L../src override LDLIBS += -lselinux $(FTS_LDLIBS) -PCRE_LDLIBS ?= -lpcre ifeq ($(ANDROID_HOST),y) TARGETS=sefcontext_compile diff --git a/libselinux/utils/compute_av.c b/libselinux/utils/compute_av.c index df4a77e8b19600d15a5b299ff2b16714b052e5fa..cca407d6cb6654ba738757d5e04dbc7d304f3534 100644 --- a/libselinux/utils/compute_av.c +++ b/libselinux/utils/compute_av.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,16 @@ int main(int argc, char **argv) exit(1); } + if (security_check_context(argv[1])) { + fprintf(stderr, "%s: invalid source context '%s'\n", argv[0], argv[1]); + exit(4); + } + + if (security_check_context(argv[2])) { + fprintf(stderr, "%s: invalid target context '%s'\n", argv[0], argv[2]); + exit(5); + } + tclass = string_to_security_class(argv[3]); if (!tclass) { fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); @@ -25,7 +36,7 @@ int main(int argc, char **argv) ret = security_compute_av(argv[1], argv[2], tclass, 1, &avd); if (ret < 0) { - fprintf(stderr, "%s: security_compute_av failed\n", argv[0]); + fprintf(stderr, "%s: security_compute_av failed: %s\n", argv[0], strerror(errno)); exit(3); } diff --git a/libselinux/utils/compute_create.c b/libselinux/utils/compute_create.c index 449ccd90fff0451c2b2909bd231282ecbfddc2f2..c6481f4b01c18ea35cfa8ef32a9594da5e020a9b 100644 --- a/libselinux/utils/compute_create.c +++ b/libselinux/utils/compute_create.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -17,16 +18,26 @@ int main(int argc, char **argv) exit(1); } + if (security_check_context(argv[1])) { + fprintf(stderr, "%s: invalid source context '%s'\n", argv[0], argv[1]); + exit(4); + } + + if (security_check_context(argv[2])) { + fprintf(stderr, "%s: invalid target context '%s'\n", argv[0], argv[2]); + exit(5); + } + tclass = string_to_security_class(argv[3]); if (!tclass) { - fprintf(stderr, "Invalid class '%s'\n", argv[3]); + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); exit(2); } ret = security_compute_create(argv[1], argv[2], tclass, &buf); if (ret < 0) { - fprintf(stderr, "%s: security_compute_create failed\n", - argv[0]); + fprintf(stderr, "%s: security_compute_create failed: %s\n", + argv[0], strerror(errno)); exit(3); } diff --git a/libselinux/utils/compute_member.c b/libselinux/utils/compute_member.c index c6dad19e0dcc4449b3563c41fad2d1c54e4bfa6f..9fe790eeb45c43be2076512d1dc682490ee0b5ec 100644 --- a/libselinux/utils/compute_member.c +++ b/libselinux/utils/compute_member.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -17,16 +18,26 @@ int main(int argc, char **argv) exit(1); } + if (security_check_context(argv[1])) { + fprintf(stderr, "%s: invalid source context '%s'\n", argv[0], argv[1]); + exit(4); + } + + if (security_check_context(argv[2])) { + fprintf(stderr, "%s: invalid target context '%s'\n", argv[0], argv[2]); + exit(5); + } + tclass = string_to_security_class(argv[3]); if (!tclass) { - fprintf(stderr, "Invalid class '%s'\n", argv[3]); + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); exit(2); } ret = security_compute_member(argv[1], argv[2], tclass, &buf); if (ret < 0) { - fprintf(stderr, "%s: security_compute_member failed\n", - argv[0]); + fprintf(stderr, "%s: security_compute_member failed: %s\n", + argv[0], strerror(errno)); exit(3); } diff --git a/libselinux/utils/compute_relabel.c b/libselinux/utils/compute_relabel.c index 85c760bcb7ebfdf33c9b26098d62da3500b22e51..bdd39d0f03e63a3f5c13b47e161fc968e1c184fb 100644 --- a/libselinux/utils/compute_relabel.c +++ b/libselinux/utils/compute_relabel.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,16 @@ int main(int argc, char **argv) exit(1); } + if (security_check_context(argv[1])) { + fprintf(stderr, "%s: invalid source context '%s'\n", argv[0], argv[1]); + exit(4); + } + + if (security_check_context(argv[2])) { + fprintf(stderr, "%s: invalid target context '%s'\n", argv[0], argv[2]); + exit(5); + } + tclass = string_to_security_class(argv[3]); if (!tclass) { fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); @@ -25,8 +36,8 @@ int main(int argc, char **argv) ret = security_compute_relabel(argv[1], argv[2], tclass, &buf); if (ret < 0) { - fprintf(stderr, "%s: security_compute_relabel failed\n", - argv[0]); + fprintf(stderr, "%s: security_compute_relabel failed: %s\n", + argv[0], strerror(errno)); exit(3); } diff --git a/libselinux/utils/getconlist.c b/libselinux/utils/getconlist.c index 0bb2846937ca6aaae1e9c7b84e8fd3b3e17d593f..92f6a793212263f7e2ea78e4139048cd8118d06a 100644 --- a/libselinux/utils/getconlist.c +++ b/libselinux/utils/getconlist.c @@ -55,7 +55,7 @@ int main(int argc, char **argv) /* If a context wasn't passed, use the current context. */ if (((argc - optind) < 2)) { if (getcon(&cur_context) < 0) { - fprintf(stderr, "Couldn't get current context.\n"); + fprintf(stderr, "Couldn't get current context: %s\n", strerror(errno)); free(level); return 2; } diff --git a/libselinux/utils/getdefaultcon.c b/libselinux/utils/getdefaultcon.c index 957c1cb2e307fc0ea2b4b210ebd33b8ce95e7262..93102e5ef0542a05258100368640549dfb25c233 100644 --- a/libselinux/utils/getdefaultcon.c +++ b/libselinux/utils/getdefaultcon.c @@ -62,12 +62,17 @@ int main(int argc, char **argv) /* If a context wasn't passed, use the current context. */ if (((argc - optind) < 2)) { if (getcon(&cur_context) < 0) { - fprintf(stderr, "Couldn't get current context.\n"); + fprintf(stderr, "Couldn't get current context: %s\n", strerror(errno)); return 2; } } else cur_context = argv[optind + 1]; + if (security_check_context(cur_context)) { + fprintf(stderr, "%s: invalid from context '%s'\n", argv[0], cur_context); + return 3; + } + if ((ret = getseuser(user, service, &seuser, &dlevel)) == 0) { if (! level) level=dlevel; if (role != NULL && role[0]) diff --git a/libselinux/utils/getenforce.c b/libselinux/utils/getenforce.c index e5d19c544f15ddd1e94e9db4c5838e569feb5ec6..aeeb79a83450531447c0e0ab0bbf3317697ab323 100644 --- a/libselinux/utils/getenforce.c +++ b/libselinux/utils/getenforce.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include int main(int argc __attribute__ ((unused)), @@ -16,7 +18,7 @@ int main(int argc __attribute__ ((unused)), if (rc == 1) { rc = security_getenforce(); if (rc < 0) { - fputs("getenforce: getenforce() failed", stderr); + fprintf(stderr, "getenforce: security_getenforce() failed: %s\n", strerror(errno)); return 2; } diff --git a/libselinux/utils/getfilecon.c b/libselinux/utils/getfilecon.c index 6266ae1681a31ad661340a48b7a5319da6e5ce95..b823a1a1617003c4f4edb31a9dc489b5bb5f2342 100644 --- a/libselinux/utils/getfilecon.c +++ b/libselinux/utils/getfilecon.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include int main(int argc, char **argv) @@ -16,8 +18,8 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { rc = getfilecon(argv[i], &buf); if (rc < 0) { - fprintf(stderr, "%s: getfilecon(%s) failed\n", argv[0], - argv[i]); + fprintf(stderr, "%s: getfilecon(%s) failed: %s\n", argv[0], + argv[i], strerror(errno)); exit(2); } printf("%s\t%s\n", argv[i], buf); diff --git a/libselinux/utils/getpidcon.c b/libselinux/utils/getpidcon.c index ea6c274e18bfb55bb9d3d4f863a71f1eaa79214f..1a88fa6d9f712c5ff67ee9603c7c745e3ca7077c 100644 --- a/libselinux/utils/getpidcon.c +++ b/libselinux/utils/getpidcon.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include int main(int argc, char **argv) @@ -21,7 +23,7 @@ int main(int argc, char **argv) rc = getpidcon(pid, &buf); if (rc < 0) { - fprintf(stderr, "%s: getpidcon() failed\n", argv[0]); + fprintf(stderr, "%s: getpidcon() failed: %s\n", argv[0], strerror(errno)); exit(3); } diff --git a/libselinux/utils/policyvers.c b/libselinux/utils/policyvers.c index dd56f2c7efc515fb7173bd9197986034516e1d85..5230bcaf651955b6a7267c4ce8f53bde0a1eb8e0 100644 --- a/libselinux/utils/policyvers.c +++ b/libselinux/utils/policyvers.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include int main(int argc __attribute__ ((unused)), char **argv) @@ -9,7 +11,7 @@ int main(int argc __attribute__ ((unused)), char **argv) rc = security_policyvers(); if (rc < 0) { - fprintf(stderr, "%s: policyvers() failed\n", argv[0]); + fprintf(stderr, "%s: security_policyvers() failed: %s\n", argv[0], strerror(errno)); exit(2); } diff --git a/libselinux/utils/selabel_digest.c b/libselinux/utils/selabel_digest.c index 49408a0ba8d831e1ca6fb38dde0ebc951dfab685..6a8313a2c88d7700899290787faf57b05e8c4f2f 100644 --- a/libselinux/utils/selabel_digest.c +++ b/libselinux/utils/selabel_digest.c @@ -34,7 +34,7 @@ static int run_check_digest(char *cmd, char *selabel_digest) fp = popen(cmd, "r"); if (!fp) { - printf("Failed to run command line\n"); + fprintf(stderr, "Failed to run command '%s': %s\n", cmd, strerror(errno)); return -1; } diff --git a/libselinux/utils/selabel_get_digests_all_partial_matches.c b/libselinux/utils/selabel_get_digests_all_partial_matches.c index e28833d2ce970d3304ce9ed1716b20f4e0c8f391..c4e0f836b2607298dc10446b03a347fea501442d 100644 --- a/libselinux/utils/selabel_get_digests_all_partial_matches.c +++ b/libselinux/utils/selabel_get_digests_all_partial_matches.c @@ -77,7 +77,8 @@ int main(int argc, char **argv) hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2); if (!hnd) { fprintf(stderr, "ERROR: selabel_open - Could not obtain " - "handle.\n"); + "handle: %s\n", + strerror(errno)); return -1; } diff --git a/libselinux/utils/selabel_lookup.c b/libselinux/utils/selabel_lookup.c index 1aef64de8a0749ba3e0caaa63146fea1c647ec5c..112ffda108ac7c0630b1e43cb0065d60a1343b3c 100644 --- a/libselinux/utils/selabel_lookup.c +++ b/libselinux/utils/selabel_lookup.c @@ -91,7 +91,8 @@ int main(int argc, char **argv) hnd = selabel_open(backend, selabel_option, 2); if (!hnd) { fprintf(stderr, "ERROR: selabel_open - Could not obtain " - "handle.\n"); + "handle: %s\n", + strerror(errno)); return -1; } diff --git a/libselinux/utils/selabel_lookup_best_match.c b/libselinux/utils/selabel_lookup_best_match.c index 2cddc6cde0510ec8fdcf061dfad3805a9e3738ad..a4af0679807918008b0509abc36ffbaea74d6253 100644 --- a/libselinux/utils/selabel_lookup_best_match.c +++ b/libselinux/utils/selabel_lookup_best_match.c @@ -117,7 +117,8 @@ int main(int argc, char **argv) hnd = selabel_open(SELABEL_CTX_FILE, options, 2); if (!hnd) { fprintf(stderr, "ERROR: selabel_open - Could not obtain " - "handle.\n"); + "handle: %s\n", + strerror(errno)); rc = -1; goto out; } diff --git a/libselinux/utils/selabel_partial_match.c b/libselinux/utils/selabel_partial_match.c index c5932cb184eac6636ca4f7bc2adf8988386c8dd7..7bbd5777c7c030c2e9d333a1d3523feee8d0ec7e 100644 --- a/libselinux/utils/selabel_partial_match.c +++ b/libselinux/utils/selabel_partial_match.c @@ -61,7 +61,8 @@ int main(int argc, char **argv) hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2); if (!hnd) { fprintf(stderr, "ERROR: selabel_open - Could not obtain " - "handle.\n"); + "handle: %s\n", + strerror(errno)); return -1; } diff --git a/libselinux/utils/selinuxexeccon.c b/libselinux/utils/selinuxexeccon.c index b50e7886c32d608bdd10151864f3ab5d4c128bcd..66754b6a6396db87ff696cfdb3dc18eb45290e3f 100644 --- a/libselinux/utils/selinuxexeccon.c +++ b/libselinux/utils/selinuxexeccon.c @@ -16,7 +16,7 @@ static __attribute__ ((__noreturn__)) void usage(const char *name, const char *d exit(rc); } -static char * get_selinux_proc_context(const char *command, char * execcon) { +static char * get_selinux_proc_context(const char *command, const char * execcon) { char * fcon = NULL, *newcon = NULL; int ret = getfilecon(command, &fcon); @@ -43,6 +43,10 @@ int main(int argc, char **argv) } } else { con = strdup(argv[2]); + if (security_check_context(con)) { + fprintf(stderr, "%s: invalid from context '%s'\n", argv[0], con); + return -1; + } } proccon = get_selinux_proc_context(argv[1], con); diff --git a/libselinux/utils/setenforce.c b/libselinux/utils/setenforce.c index 60a20a4bcce71dbebfdfb5a40a2257114a33b023..67c13dcafb12f77ca3d3ea426fd57d918a281237 100644 --- a/libselinux/utils/setenforce.c +++ b/libselinux/utils/setenforce.c @@ -4,6 +4,7 @@ #include #include #include +#include #include static __attribute__ ((__noreturn__)) void usage(const char *progname) @@ -35,7 +36,7 @@ int main(int argc, char **argv) usage(argv[0]); } if (rc < 0) { - fprintf(stderr, "%s: setenforce() failed\n", argv[0]); + fprintf(stderr, "%s: security_setenforce() failed: %s\n", argv[0], strerror(errno)); return 2; } return 0; diff --git a/libselinux/utils/setfilecon.c b/libselinux/utils/setfilecon.c index 79af55dea380ff5b3c15e28c66859d960b35d8cf..a3fbc3eded51aae74659e811a91ebb32bdb86e45 100644 --- a/libselinux/utils/setfilecon.c +++ b/libselinux/utils/setfilecon.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include int main(int argc, char **argv) @@ -15,8 +17,8 @@ int main(int argc, char **argv) for (i = 2; i < argc; i++) { rc = setfilecon(argv[i], argv[1]); if (rc < 0) { - fprintf(stderr, "%s: setfilecon(%s,%s) failed\n", - argv[0], argv[i], argv[1]); + fprintf(stderr, "%s: setfilecon(%s,%s) failed: %s\n", + argv[0], argv[i], argv[1], strerror(errno)); exit(2); } } diff --git a/libselinux/utils/validatetrans.c b/libselinux/utils/validatetrans.c index 1db33e6613e7914509d4bdf0791d7de019cf7c28..9d642a93176088cd85eeddcae36fbac186db9756 100644 --- a/libselinux/utils/validatetrans.c +++ b/libselinux/utils/validatetrans.c @@ -17,12 +17,27 @@ int main(int argc, char **argv) exit(1); } + if (security_check_context(argv[1])) { + fprintf(stderr, "%s: invalid source context '%s'\n", argv[0], argv[1]); + exit(4); + } + + if (security_check_context(argv[2])) { + fprintf(stderr, "%s: invalid target context '%s'\n", argv[0], argv[2]); + exit(5); + } + tclass = string_to_security_class(argv[3]); if (!tclass) { fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); exit(2); } + if (security_check_context(argv[4])) { + fprintf(stderr, "%s: invalid new context '%s'\n", argv[0], argv[4]); + exit(6); + } + ret = security_validatetrans(argv[1], argv[2], tclass, argv[4]); printf("security_validatetrans returned %d errno: %s\n", ret, strerror(errno)); diff --git a/libsepol/.gitignore b/libsepol/.gitignore index 77bb5911c3f24371d977f5d0578d840430b61e50..abfb603b00fbb83e78fb9e1f1dee48ab29fc4237 100644 --- a/libsepol/.gitignore +++ b/libsepol/.gitignore @@ -1,2 +1,7 @@ utils/chkcon +utils/sepol_check_access +utils/sepol_compute_av +utils/sepol_compute_member +utils/sepol_compute_relabel +utils/sepol_validate_transition libsepol.map diff --git a/libsepol/VERSION b/libsepol/VERSION index eb39e5382f4f035e4d71c7f67712cdbfa6c0c335..2f4b60750dc3500b0e4cf08f316a960a7ca42b40 100644 --- a/libsepol/VERSION +++ b/libsepol/VERSION @@ -1 +1 @@ -3.3 +3.4 diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 4cc7f87fa9474802435cb10387b64475760df485..38edcf8e66378bb1116689d755851bf803167de4 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -1456,6 +1456,12 @@ int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size) buf_pos = snprintf(str_tmp, str_len, "user %s prefix %s;\n", user->datum.fqn, userprefix->prefix_str); + if (buf_pos < 0) { + free(str_tmp); + *size = 0; + *out = NULL; + goto exit; + } str_len -= buf_pos; str_tmp += buf_pos; } @@ -1765,6 +1771,9 @@ int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size) str_tmp += buf_pos; switch(filecon->type) { + case CIL_FILECON_ANY: + str_type = ""; + break; case CIL_FILECON_FILE: str_type = "\t--"; break; @@ -2530,7 +2539,7 @@ void cil_filecon_init(struct cil_filecon **filecon) *filecon = cil_malloc(sizeof(**filecon)); (*filecon)->path_str = NULL; - (*filecon)->type = 0; + (*filecon)->type = CIL_FILECON_ANY; (*filecon)->context_str = NULL; (*filecon)->context = NULL; } @@ -2574,6 +2583,7 @@ void cil_genfscon_init(struct cil_genfscon **genfscon) (*genfscon)->fs_str = NULL; (*genfscon)->path_str = NULL; + (*genfscon)->file_type = CIL_FILECON_ANY; (*genfscon)->context_str = NULL; (*genfscon)->context = NULL; } diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index d8aa495a487eb4c1c17c1c47152753789f019eaa..40615db29aabf9bf962183d349fda82273ee9cef 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -284,7 +284,7 @@ exit: return rc; } -int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) +static int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) { int rc = SEPOL_ERR; struct cil_list_item *curr_class; @@ -396,7 +396,7 @@ exit: return rc; } -int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role) +static int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role) { int rc = SEPOL_ERR; role_datum_t *sepol_role = NULL; @@ -479,7 +479,7 @@ exit: return rc; } -int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type) +static int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type) { int rc = SEPOL_ERR; type_datum_t *sepol_type = NULL; @@ -587,7 +587,7 @@ exit: return rc; } -int __cil_typeattr_bitmap_init(policydb_t *pdb) +static int __cil_typeattr_bitmap_init(policydb_t *pdb) { int rc = SEPOL_ERR; uint32_t i; @@ -698,7 +698,7 @@ exit: return rc; } -int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user) +static int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user) { int rc = SEPOL_ERR; user_datum_t *sepol_user = NULL; @@ -881,7 +881,7 @@ exit: return rc; } -int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) +static int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) { int rc = SEPOL_ERR; char *key = NULL; @@ -919,7 +919,7 @@ exit: return rc; } -int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_OK; avtab_ptr_t avtab_ptr = NULL; @@ -954,7 +954,7 @@ exit: return rc; } -avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list) +static avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list) { cond_av_list_t *cur_av; @@ -970,7 +970,7 @@ avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_li return NULL; } -int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_OK; avtab_key_t avtab_key; @@ -1063,24 +1063,53 @@ exit: return rc; } -int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_type_rule_to_avtab_helper(policydb_t *pdb, + type_datum_t *sepol_src, + type_datum_t *sepol_tgt, + struct cil_list *class_list, + type_datum_t *sepol_result, + struct cil_type_rule *cil_rule, + cond_node_t *cond_node, + enum cil_flavor cond_flavor) +{ + int rc; + class_datum_t *sepol_obj = NULL; + struct cil_list_item *c; + + cil_list_for_each(c, class_list) { + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) return rc; + + rc = __cil_insert_type_rule( + pdb, cil_rule->rule_kind, sepol_src->s.value, + sepol_tgt->s.value, sepol_obj->s.value, + sepol_result->s.value, cil_rule, cond_node, cond_flavor + ); + if (rc != SEPOL_OK) return rc; + } + return SEPOL_OK; +} + +static int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_ERR; - uint16_t kind = cil_rule->rule_kind; + struct cil_symtab_datum *src = NULL; + struct cil_symtab_datum *tgt = NULL; type_datum_t *sepol_src = NULL; type_datum_t *sepol_tgt = NULL; - class_datum_t *sepol_obj = NULL; struct cil_list *class_list = NULL; type_datum_t *sepol_result = NULL; ebitmap_t src_bitmap, tgt_bitmap; ebitmap_node_t *node1, *node2; unsigned int i, j; - struct cil_list_item *c; - rc = __cil_expand_type(cil_rule->src, &src_bitmap); - if (rc != SEPOL_OK) goto exit; + ebitmap_init(&src_bitmap); + ebitmap_init(&tgt_bitmap); + + src = cil_rule->src; + tgt = cil_rule->tgt; - rc = __cil_expand_type(cil_rule->tgt, &tgt_bitmap); + rc = __cil_expand_type(src, &src_bitmap); if (rc != SEPOL_OK) goto exit; class_list = cil_expand_class(cil_rule->obj); @@ -1088,19 +1117,34 @@ int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct ci rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_rule->result), &sepol_result); if (rc != SEPOL_OK) goto exit; - ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { - rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (tgt->fqn == CIL_KEY_SELF) { + ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_type_rule_to_avtab_helper( + pdb, sepol_src, sepol_src, class_list, + sepol_result, cil_rule, cond_node, cond_flavor + ); + if (rc != SEPOL_OK) goto exit; + } + } else { + rc = __cil_expand_type(tgt, &tgt_bitmap); if (rc != SEPOL_OK) goto exit; - ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { - rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); + ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); if (rc != SEPOL_OK) goto exit; - cil_list_for_each(c, class_list) { - rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); if (rc != SEPOL_OK) goto exit; - rc = __cil_insert_type_rule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, sepol_result->s.value, cil_rule, cond_node, cond_flavor); + rc = __cil_type_rule_to_avtab_helper( + pdb, sepol_src, sepol_tgt, class_list, + sepol_result, cil_rule, cond_node, + cond_flavor + ); if (rc != SEPOL_OK) goto exit; } } @@ -1120,19 +1164,57 @@ int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c return __cil_type_rule_to_avtab(pdb, db, cil_rule, NULL, CIL_FALSE); } -int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, + type_datum_t *sepol_src, + type_datum_t *sepol_tgt, + struct cil_list *class_list, + char *name, + type_datum_t *sepol_result) +{ + int rc; + class_datum_t *sepol_obj = NULL; + uint32_t otype; + struct cil_list_item *c; + + cil_list_for_each(c, class_list) { + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) return rc; + + rc = policydb_filetrans_insert( + pdb, sepol_src->s.value, sepol_tgt->s.value, + sepol_obj->s.value, name, NULL, + sepol_result->s.value, &otype + ); + if (rc != SEPOL_OK) { + if (rc == SEPOL_EEXIST) { + if (sepol_result->s.value!= otype) { + cil_log(CIL_ERR, "Conflicting name type transition rules\n"); + } else { + rc = SEPOL_OK; + } + } else { + cil_log(CIL_ERR, "Out of memory\n"); + } + if (rc != SEPOL_OK) { + return rc; + } + } + } + return SEPOL_OK; +} + +static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_ERR; + struct cil_symtab_datum *src = NULL; + struct cil_symtab_datum *tgt = NULL; type_datum_t *sepol_src = NULL; type_datum_t *sepol_tgt = NULL; - class_datum_t *sepol_obj = NULL; struct cil_list *class_list = NULL; type_datum_t *sepol_result = NULL; ebitmap_t src_bitmap, tgt_bitmap; ebitmap_node_t *node1, *node2; unsigned int i, j; - uint32_t otype; - struct cil_list_item *c; char *name = DATUM(typetrans->name)->name; if (name == CIL_KEY_STAR) { @@ -1149,10 +1231,13 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru return __cil_type_rule_to_avtab(pdb, db, &trans, cond_node, cond_flavor); } - rc = __cil_expand_type(typetrans->src, &src_bitmap); - if (rc != SEPOL_OK) goto exit; + ebitmap_init(&src_bitmap); + ebitmap_init(&tgt_bitmap); + + src = typetrans->src; + tgt = typetrans->tgt; - rc = __cil_expand_type(typetrans->tgt, &tgt_bitmap); + rc = __cil_expand_type(src, &src_bitmap); if (rc != SEPOL_OK) goto exit; class_list = cil_expand_class(typetrans->obj); @@ -1160,37 +1245,34 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru rc = __cil_get_sepol_type_datum(pdb, DATUM(typetrans->result), &sepol_result); if (rc != SEPOL_OK) goto exit; - ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { - rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (tgt->fqn == CIL_KEY_SELF) { + ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_typetransition_to_avtab_helper( + pdb, sepol_src, sepol_src, class_list, + name, sepol_result + ); + if (rc != SEPOL_OK) goto exit; + } + } else { + rc = __cil_expand_type(tgt, &tgt_bitmap); if (rc != SEPOL_OK) goto exit; - ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { - rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); + ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); if (rc != SEPOL_OK) goto exit; - cil_list_for_each(c, class_list) { - rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); if (rc != SEPOL_OK) goto exit; - rc = policydb_filetrans_insert( - pdb, sepol_src->s.value, sepol_tgt->s.value, - sepol_obj->s.value, name, NULL, - sepol_result->s.value, &otype + rc = __cil_typetransition_to_avtab_helper( + pdb, sepol_src, sepol_tgt, class_list, + name, sepol_result ); - if (rc != SEPOL_OK) { - if (rc == SEPOL_EEXIST) { - if (sepol_result->s.value!= otype) { - cil_log(CIL_ERR, "Conflicting name type transition rules\n"); - } else { - rc = SEPOL_OK; - } - } else { - cil_log(CIL_ERR, "Out of memory\n"); - } - if (rc != SEPOL_OK) { - goto exit; - } - } + if (rc != SEPOL_OK) goto exit; } } } @@ -1209,7 +1291,7 @@ int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, str return __cil_typetransition_to_avtab(pdb, db, typetrans, NULL, CIL_FALSE); } -int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum) +static int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum) { int rc; perm_datum_t *sepol_perm; @@ -1233,7 +1315,7 @@ exit: return rc; } -int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum) +static int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum) { int rc = SEPOL_ERR; char *key = NULL; @@ -1259,7 +1341,7 @@ exit: return rc; } -int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_OK; avtab_key_t avtab_key; @@ -1306,7 +1388,7 @@ exit: return rc; } -int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_ERR; type_datum_t *sepol_src = NULL; @@ -1347,7 +1429,7 @@ exit: } -int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_ERR; struct cil_list_item *curr; @@ -1402,7 +1484,7 @@ static int __cil_should_expand_attribute( const struct cil_db *db, struct cil_sy return !attr->keep || (ebitmap_cardinality(attr->types) < db->attrs_expand_size); } -int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor) +static int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor) { int rc = SEPOL_ERR; uint16_t kind = cil_avrule->rule_kind; @@ -1528,7 +1610,7 @@ int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_ #define XPERM_LOW(x) (x << 5) /* high value for this u32 */ #define XPERM_HIGH(x) (((x + 1) << 5) - 1) -void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_extended_perms *xperms) +static void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_extended_perms *xperms) { unsigned int i; uint16_t h = high + 1; @@ -1553,7 +1635,7 @@ void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_exten #define IOC_DRIV(x) (x >> 8) #define IOC_FUNC(x) (x & 0xff) -int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) +static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) { ebitmap_node_t *node; unsigned int i; @@ -1618,7 +1700,7 @@ int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list * return SEPOL_OK; } -int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) +static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) { int rc = SEPOL_OK; struct policydb *pdb; @@ -1668,7 +1750,7 @@ exit: return rc; } -int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) +static int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) { uint16_t specified; avtab_key_t *avtab_key; @@ -1725,7 +1807,7 @@ exit: return rc; } -int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args) +static int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args) { int rc = SEPOL_ERR; type_datum_t *sepol_src = NULL; @@ -1765,7 +1847,7 @@ exit: return rc; } -int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args) +static int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args) { int rc = SEPOL_ERR; uint16_t kind; @@ -1883,7 +1965,7 @@ static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, _ return SEPOL_OK; } -int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) +static int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) { int rc; enum cil_flavor flavor; @@ -2174,7 +2256,7 @@ static int __cil_cond_expr_to_sepol_expr(policydb_t *pdb, struct cil_list *cil_e return SEPOL_OK; } -int __cil_validate_cond_expr(cond_expr_t *cond_expr) +static int __cil_validate_cond_expr(cond_expr_t *cond_expr) { cond_expr_t *e; int depth = -1; @@ -2454,7 +2536,7 @@ exit: return rc; } -int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr) +static int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr) { int rc = SEPOL_ERR; @@ -2554,7 +2636,7 @@ exit: return SEPOL_ERR; } -int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr) +static int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr) { int rc = SEPOL_ERR; struct cil_list_item *l_item = op_item->next; @@ -2649,7 +2731,7 @@ exit: return rc; } -int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail) +static int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail) { int rc = SEPOL_ERR; struct cil_list_item *item; @@ -2747,7 +2829,7 @@ exit: return SEPOL_ERR; } -int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr) +static int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr) { int rc; constraint_expr_t *head, *tail; @@ -2762,7 +2844,7 @@ int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, return SEPOL_OK; } -int __cil_validate_constrain_expr(constraint_expr_t *sepol_expr) +static int __cil_validate_constrain_expr(constraint_expr_t *sepol_expr) { constraint_expr_t *e; int depth = -1; @@ -2805,7 +2887,7 @@ int __cil_validate_constrain_expr(constraint_expr_t *sepol_expr) return SEPOL_OK; } -int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr) +static int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr) { int rc = SEPOL_ERR; constraint_node_t *sepol_constrain = NULL; @@ -2823,6 +2905,12 @@ int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, s goto exit; } + if (sepol_constrain->permissions == 0) { + /* No permissions, so don't insert rule. */ + free(sepol_constrain); + return SEPOL_OK; + } + rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr); if (rc != SEPOL_OK) { goto exit; @@ -2845,7 +2933,7 @@ exit: return rc; } -int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr) +static int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr) { int rc = SEPOL_ERR; struct cil_list_item *curr; @@ -2899,7 +2987,7 @@ exit: return rc; } -int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans) +static int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans) { int rc = SEPOL_ERR; struct cil_list *expr = cil_validatetrans->datum_expr; @@ -2936,7 +3024,7 @@ exit: return rc; } -int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t *mls_level) +static int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t *mls_level) { int rc = SEPOL_ERR; struct cil_list_item *i; @@ -3029,7 +3117,7 @@ exit: return rc; } -int __cil_levelrange_to_mls_range(policydb_t *pdb, struct cil_levelrange *cil_lvlrange, mls_range_t *mls_range) +static int __cil_levelrange_to_mls_range(policydb_t *pdb, struct cil_levelrange *cil_lvlrange, mls_range_t *mls_range) { int rc = SEPOL_ERR; struct cil_level *low = cil_lvlrange->low; @@ -3056,7 +3144,7 @@ exit: return rc; } -int cil_userlevel_userrange_to_policydb(policydb_t *pdb, struct cil_user *cil_user) +static int cil_userlevel_userrange_to_policydb(policydb_t *pdb, struct cil_user *cil_user) { int rc = SEPOL_ERR; struct cil_level *cil_level = cil_user->dftlevel; @@ -3082,7 +3170,7 @@ exit: return rc; } -int __cil_context_to_sepol_context(policydb_t *pdb, struct cil_context *cil_context, context_struct_t *sepol_context) +static int __cil_context_to_sepol_context(policydb_t *pdb, struct cil_context *cil_context, context_struct_t *sepol_context) { int rc = SEPOL_ERR; struct cil_levelrange *cil_lvlrange = cil_context->range; @@ -3120,7 +3208,7 @@ exit: return rc; } -int cil_sidorder_to_policydb(policydb_t *pdb, const struct cil_db *db) +static int cil_sidorder_to_policydb(policydb_t *pdb, const struct cil_db *db) { int rc = SEPOL_ERR; struct cil_list_item *curr; @@ -3216,7 +3304,16 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st } else { cil_log(CIL_ERR, "Out of memory\n"); } +// TODO: add upper version bound once fixed in upstream GCC +#if defined(__GNUC__) && (__GNUC__ >= 12) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Warray-bounds" +# pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif mls_range_destroy(newdatum); +#if defined(__GNUC__) && (__GNUC__ >= 12) +# pragma GCC diagnostic pop +#endif free(newdatum); free(newkey); if (rc != SEPOL_OK) { @@ -3462,6 +3559,43 @@ int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons) new_ocon->u.name = cil_strdup(cil_genfscon->path_str); + if (cil_genfscon->file_type != CIL_FILECON_ANY) { + class_datum_t *class_datum; + const char *class_name; + switch (cil_genfscon->file_type) { + case CIL_FILECON_FILE: + class_name = "file"; + break; + case CIL_FILECON_DIR: + class_name = "dir"; + break; + case CIL_FILECON_CHAR: + class_name = "chr_file"; + break; + case CIL_FILECON_BLOCK: + class_name = "blk_file"; + break; + case CIL_FILECON_SOCKET: + class_name = "sock_file"; + break; + case CIL_FILECON_PIPE: + class_name = "fifo_file"; + break; + case CIL_FILECON_SYMLINK: + class_name = "lnk_file"; + break; + default: + rc = SEPOL_ERR; + goto exit; + } + class_datum = hashtab_search(pdb->p_classes.table, class_name); + if (!class_datum) { + rc = SEPOL_ERR; + goto exit; + } + new_ocon->v.sclass = class_datum->s.value; + } + rc = __cil_context_to_sepol_context(pdb, cil_genfscon->context, &new_ocon->context[0]); if (rc != SEPOL_OK) { goto exit; @@ -3572,7 +3706,7 @@ exit: return rc; } -int cil_devicetreecon_to_policydb(policydb_t *pdb, struct cil_sort *devicetreecons) +static int cil_devicetreecon_to_policydb(policydb_t *pdb, struct cil_sort *devicetreecons) { int rc = SEPOL_ERR; uint32_t i = 0; @@ -3596,7 +3730,7 @@ exit: return rc; } -int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def) +static int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def) { struct cil_list_item *curr; class_datum_t *sepol_class; @@ -3651,7 +3785,7 @@ exit: return SEPOL_ERR; } -int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def) +static int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def) { struct cil_list_item *curr; class_datum_t *sepol_class; @@ -3684,7 +3818,7 @@ exit: return SEPOL_ERR; } -int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) +static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) { int rc = SEPOL_OK; int pass; @@ -3866,7 +4000,7 @@ exit: return rc; } -int __cil_binary_create_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) +static int __cil_binary_create_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { int rc = SEPOL_ERR; @@ -3894,7 +4028,7 @@ exit: return rc; } -int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db) +static int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db) { int rc = SEPOL_ERR; @@ -3964,7 +4098,7 @@ exit: return rc; } -int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; common_datum_t *common = (common_datum_t *)datum; @@ -3977,7 +4111,7 @@ int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void return 0; } -int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; class_datum_t *class = (class_datum_t *)datum; @@ -3991,7 +4125,7 @@ int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void return 0; } -int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; role_datum_t *role = (role_datum_t *)datum; @@ -4005,7 +4139,7 @@ int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void * return 0; } -int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; type_datum_t *type = (type_datum_t *)datum; @@ -4019,7 +4153,7 @@ int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void * return 0; } -int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; user_datum_t *user = (user_datum_t *)datum; @@ -4033,7 +4167,7 @@ int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void * return 0; } -int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; cond_bool_datum_t *bool = (cond_bool_datum_t *)datum; @@ -4047,7 +4181,7 @@ int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void * return 0; } -int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; level_datum_t *level = (level_datum_t *)datum; @@ -4060,7 +4194,7 @@ int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void return 0; } -int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) +static int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) { policydb_t *pdb = data; cat_datum_t *cat = (cat_datum_t *)datum; @@ -4073,7 +4207,7 @@ int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *d return 0; } -int __cil_policydb_val_arrays_create(policydb_t *policydb) +static int __cil_policydb_val_arrays_create(policydb_t *policydb) { int rc = SEPOL_ERR; @@ -4168,7 +4302,7 @@ static void __cil_set_conditional_state_and_flags(policydb_t *pdb) } } -int __cil_policydb_create(const struct cil_db *db, struct sepol_policydb **spdb) +static int __cil_policydb_create(const struct cil_db *db, struct sepol_policydb **spdb) { int rc; struct policydb *pdb = NULL; @@ -4197,7 +4331,7 @@ exit: } -int __cil_policydb_init(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) +static int __cil_policydb_init(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) { int rc = SEPOL_ERR; @@ -4603,6 +4737,9 @@ static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tr char *neverallow_str; char *allow_str; enum cil_flavor avrule_flavor; + int num_matching = 0; + int count_matching = 0; + enum cil_log_level log_level = cil_get_log_level(); target.rule_kind = CIL_AVRULE_ALLOWED; target.is_extended = cil_rule->is_extended; @@ -4629,11 +4766,19 @@ static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tr goto exit; } + cil_list_for_each(i2, matching) { + num_matching++; + } cil_list_for_each(i2, matching) { n2 = i2->data; r2 = n2->data; __cil_print_parents(" ", n2); __cil_print_rule(" ", allow_str, r2); + count_matching++; + if (count_matching >= 4 && num_matching > 4 && log_level == CIL_ERR) { + cil_log(CIL_ERR, " Only first 4 of %d matching rules shown (use \"-v\" to show all)\n", num_matching); + break; + } } cil_log(CIL_ERR,"\n"); cil_list_destroy(&matching, CIL_FALSE); @@ -4826,6 +4971,7 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void struct cil_avrule target; struct cil_tree_node *n1 = NULL; int count_bad = 0; + enum cil_log_level log_level = cil_get_log_level(); *violation = CIL_TRUE; @@ -4872,16 +5018,16 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void __cil_print_rule(" ", "allow", r2); } count_matching++; - if (count_matching >= 2) { - cil_log(CIL_ERR, " Only first 2 of %d matching rules shown\n", num_matching); + if (count_matching >= 2 && num_matching > 2 && log_level == CIL_ERR) { + cil_log(CIL_ERR, " Only first 2 of %d matching rules shown (use \"-v\" to show all)\n", num_matching); break; } } cil_list_destroy(&matching, CIL_FALSE); cil_list_destroy(&target.perms.classperms, CIL_TRUE); count_bad++; - if (count_bad >= 2) { - cil_log(CIL_ERR, " Only first 2 of %d bad rules shown\n", numbad); + if (count_bad >= 4 && numbad > 4 && log_level == CIL_ERR) { + cil_log(CIL_ERR, " Only first 4 of %d bad rules shown (use \"-v\" to show all)\n", numbad); break; } } diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 9c34be2339984b763d7c376eaad7b33ae0172509..26fa79069b96fb590c014f2e7e86efd19cab8fd3 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -56,7 +56,7 @@ struct cil_args_build { struct cil_tree_node *boolif; }; -int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list) +static int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list) { int rc = SEPOL_ERR; struct cil_tree_node *curr; @@ -176,7 +176,7 @@ exit: return rc; } -void cil_clear_node(struct cil_tree_node *ast_node) +static void cil_clear_node(struct cil_tree_node *ast_node) { if (ast_node == NULL) { return; @@ -2141,7 +2141,7 @@ void cil_destroy_avrule(struct cil_avrule *rule) free(rule); } -int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx) +static int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx) { enum cil_syntax syntax[] = { CIL_SYN_STRING, @@ -2844,7 +2844,7 @@ exit: return rc; } -int cil_gen_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr) +static int cil_gen_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr) { int rc = SEPOL_ERR; @@ -3583,7 +3583,7 @@ void cil_destroy_category(struct cil_cat *cat) free(cat); } -int cil_gen_catset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node) +static int cil_gen_catset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node) { enum cil_syntax syntax[] = { CIL_SYN_STRING, @@ -4229,7 +4229,9 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru filecon->path_str = parse_current->next->data; - if (type == CIL_KEY_FILE) { + if (type == CIL_KEY_ANY) { + filecon->type = CIL_FILECON_ANY; + } else if (type == CIL_KEY_FILE) { filecon->type = CIL_FILECON_FILE; } else if (type == CIL_KEY_DIR) { filecon->type = CIL_FILECON_DIR; @@ -4243,8 +4245,6 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru filecon->type = CIL_FILECON_PIPE; } else if (type == CIL_KEY_SYMLINK) { filecon->type = CIL_FILECON_SYMLINK; - } else if (type == CIL_KEY_ANY) { - filecon->type = CIL_FILECON_ANY; } else { cil_log(CIL_ERR, "Invalid file type\n"); rc = SEPOL_ERR; @@ -4572,9 +4572,11 @@ int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, str CIL_SYN_STRING, CIL_SYN_STRING, CIL_SYN_STRING | CIL_SYN_LIST, + CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_END, CIL_SYN_END }; size_t syntax_len = sizeof(syntax)/sizeof(*syntax); + struct cil_tree_node *context_node; int rc = SEPOL_ERR; struct cil_genfscon *genfscon = NULL; @@ -4592,15 +4594,48 @@ int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, str genfscon->fs_str = parse_current->next->data; genfscon->path_str = parse_current->next->next->data; - if (parse_current->next->next->next->cl_head == NULL ) { - genfscon->context_str = parse_current->next->next->next->data; + if (parse_current->next->next->next->next) { + /* (genfscon ... */ + char *file_type = parse_current->next->next->next->data; + if (file_type == CIL_KEY_ANY) { + genfscon->file_type = CIL_FILECON_ANY; + } else if (file_type == CIL_KEY_FILE) { + genfscon->file_type = CIL_FILECON_FILE; + } else if (file_type == CIL_KEY_DIR) { + genfscon->file_type = CIL_FILECON_DIR; + } else if (file_type == CIL_KEY_CHAR) { + genfscon->file_type = CIL_FILECON_CHAR; + } else if (file_type == CIL_KEY_BLOCK) { + genfscon->file_type = CIL_FILECON_BLOCK; + } else if (file_type == CIL_KEY_SOCKET) { + genfscon->file_type = CIL_FILECON_SOCKET; + } else if (file_type == CIL_KEY_PIPE) { + genfscon->file_type = CIL_FILECON_PIPE; + } else if (file_type == CIL_KEY_SYMLINK) { + genfscon->file_type = CIL_FILECON_SYMLINK; + } else { + if (parse_current->next->next->next->cl_head) { + cil_log(CIL_ERR, "Expecting file type, but found a list\n"); + } else { + cil_log(CIL_ERR, "Invalid file type \"%s\"\n", file_type); + } + rc = SEPOL_ERR; + goto exit; + } + context_node = parse_current->next->next->next->next; } else { - cil_context_init(&genfscon->context); + /* (genfscon ... */ + context_node = parse_current->next->next->next; + } - rc = cil_fill_context(parse_current->next->next->next->cl_head, genfscon->context); + if (context_node->cl_head) { + cil_context_init(&genfscon->context); + rc = cil_fill_context(context_node->cl_head, genfscon->context); if (rc != SEPOL_OK) { goto exit; } + } else { + genfscon->context_str = context_node->data; } ast_node->data = genfscon; @@ -5668,10 +5703,10 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr) goto exit; } - if (strchr(addr_node->data, '.') != NULL) { - addr->family = AF_INET; - } else { + if (strchr(addr_node->data, ':') != NULL) { addr->family = AF_INET6; + } else { + addr->family = AF_INET; } rc = inet_pton(addr->family, addr_node->data, &addr->ip); @@ -5683,7 +5718,7 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr) return SEPOL_OK; exit: - cil_log(CIL_ERR, "Bad ip address or netmask\n"); + cil_log(CIL_ERR, "Bad ip address or netmask: %s\n", (addr_node && addr_node->data) ? (const char *)addr_node->data : "n/a"); return rc; } @@ -6441,7 +6476,7 @@ static struct cil_tree_node * parse_statement(struct cil_db *db, struct cil_tree return new_ast_node; } -int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args) +static int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args) { struct cil_args_build *args = extra_args; struct cil_tree_node *new_ast_node = NULL; @@ -6489,7 +6524,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f return SEPOL_OK; } -int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_node *parse_current, void *extra_args) +static int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_node *parse_current, void *extra_args) { struct cil_args_build *args = extra_args; struct cil_tree_node *ast = args->ast; @@ -6509,7 +6544,7 @@ int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_n return SEPOL_OK; } -int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) +static int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) { struct cil_args_build *args = extra_args; struct cil_tree_node *ast = args->ast; diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c index 2fad972c617bcfdbeb94b81eaf2316c0d0d7e477..17f05021f436e6cfaae8b6e99b781efa0923b005 100644 --- a/libsepol/cil/src/cil_copy_ast.c +++ b/libsepol/cil/src/cil_copy_ast.c @@ -85,7 +85,7 @@ void cil_copy_list(struct cil_list *data, struct cil_list **copy) *copy = new; } -int cil_copy_node(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_node(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { char *new = NULL; @@ -151,7 +151,7 @@ int cil_copy_blockinherit(__attribute__((unused)) struct cil_db *db, void *data, return SEPOL_OK; } -int cil_copy_policycap(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +static int cil_copy_policycap(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) { struct cil_policycap *orig = data; char *key = orig->datum.name; @@ -641,7 +641,7 @@ int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, __attr return SEPOL_OK; } -int cil_copy_expandtypeattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_expandtypeattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_expandtypeattribute *orig = data; struct cil_expandtypeattribute *new = NULL; @@ -663,7 +663,7 @@ int cil_copy_expandtypeattribute(__attribute__((unused)) struct cil_db *db, void return SEPOL_OK; } -int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +static int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) { struct cil_alias *orig = data; struct cil_alias *new = NULL; @@ -683,7 +683,7 @@ int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void * return SEPOL_OK; } -int cil_copy_aliasactual(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused))symtab_t *symtab) +static int cil_copy_aliasactual(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused))symtab_t *symtab) { struct cil_aliasactual *orig = data; struct cil_aliasactual *new = NULL; @@ -698,7 +698,7 @@ int cil_copy_aliasactual(__attribute__((unused)) struct cil_db *db, void *data, return SEPOL_OK; } -int cil_copy_roletransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_roletransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_roletransition *orig = data; struct cil_roletransition *new = NULL; @@ -777,7 +777,7 @@ int cil_copy_bool(__attribute__((unused)) struct cil_db *db, void *data, void ** return SEPOL_OK; } -int cil_copy_tunable(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +static int cil_copy_tunable(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) { struct cil_tunable *orig = data; struct cil_tunable *new = NULL; @@ -797,7 +797,7 @@ int cil_copy_tunable(__attribute__((unused)) struct cil_db *db, void *data, void return SEPOL_OK; } -void cil_copy_fill_permissionx(struct cil_db *db, struct cil_permissionx *orig, struct cil_permissionx *new) +static void cil_copy_fill_permissionx(struct cil_db *db, struct cil_permissionx *orig, struct cil_permissionx *new) { new->kind = orig->kind; new->obj_str = orig->obj_str; @@ -832,7 +832,7 @@ int cil_copy_avrule(struct cil_db *db, void *data, void **copy, __attribute__((u return SEPOL_OK; } -int cil_copy_permissionx(struct cil_db *db, void *data, void **copy, symtab_t *symtab) +static int cil_copy_permissionx(struct cil_db *db, void *data, void **copy, symtab_t *symtab) { struct cil_permissionx *orig = data; struct cil_permissionx *new = NULL; @@ -908,7 +908,7 @@ int cil_copy_cat(__attribute__((unused)) struct cil_db *db, void *data, void **c return SEPOL_OK; } -void cil_copy_cats(struct cil_db *db, struct cil_cats *orig, struct cil_cats **new) +static void cil_copy_cats(struct cil_db *db, struct cil_cats *orig, struct cil_cats **new) { cil_cats_init(new); cil_copy_expr(db, orig->str_expr, &(*new)->str_expr); @@ -1219,7 +1219,7 @@ int cil_copy_ibpkeycon(struct cil_db *db, void *data, void **copy, __attribute__ return SEPOL_OK; } -int cil_copy_ibendportcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_ibendportcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_ibendportcon *orig = data; struct cil_ibendportcon *new = NULL; @@ -1350,7 +1350,7 @@ int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, __attribut return SEPOL_OK; } -int cil_copy_devicetreecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_devicetreecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_devicetreecon *orig = data; struct cil_devicetreecon *new = NULL; @@ -1497,7 +1497,7 @@ exit: return rc; } -int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +static int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) { struct cil_macro *orig = data; char *key = orig->datum.name; @@ -1562,7 +1562,7 @@ int cil_copy_ipaddr(__attribute__((unused)) struct cil_db *db, void *data, void return SEPOL_OK; } -int cil_copy_condblock(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_condblock(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_condblock *orig = data; struct cil_condblock *new = *copy; @@ -1589,7 +1589,7 @@ int cil_copy_boolif(struct cil_db *db, void *data, void **copy, __attribute__((u return SEPOL_OK; } -int cil_copy_tunif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_tunif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_tunableif *orig = data; struct cil_tunableif *new = NULL; @@ -1604,7 +1604,7 @@ int cil_copy_tunif(struct cil_db *db, void *data, void **copy, __attribute__((un return SEPOL_OK; } -int cil_copy_default(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_default(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_default *orig = data; struct cil_default *new = NULL; @@ -1624,7 +1624,7 @@ int cil_copy_default(__attribute__((unused)) struct cil_db *db, void *data, void return SEPOL_OK; } -int cil_copy_defaultrange(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_defaultrange(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_defaultrange *orig = data; struct cil_defaultrange *new = NULL; @@ -1642,7 +1642,7 @@ int cil_copy_defaultrange(__attribute__((unused)) struct cil_db *db, void *data, return SEPOL_OK; } -int cil_copy_handleunknown(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_handleunknown(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_handleunknown *orig = data; struct cil_handleunknown *new = NULL; @@ -1654,7 +1654,7 @@ int cil_copy_handleunknown(__attribute__((unused)) struct cil_db *db, void *data return SEPOL_OK; } -int cil_copy_mls(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_mls(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_mls *orig = data; struct cil_mls *new = NULL; @@ -1666,7 +1666,7 @@ int cil_copy_mls(__attribute__((unused)) struct cil_db *db, void *data, void **c return SEPOL_OK; } -int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_bounds *orig = data; struct cil_bounds *new = NULL; @@ -1681,7 +1681,7 @@ int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void return SEPOL_OK; } -int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +static int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) { struct cil_src_info *orig = data; struct cil_src_info *new = NULL; @@ -1697,7 +1697,7 @@ int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, voi return SEPOL_OK; } -int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args) +static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args) { int rc = SEPOL_ERR; struct cil_tree_node *parent = NULL; @@ -1725,6 +1725,12 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void copy_func = &cil_copy_block; break; case CIL_BLOCKABSTRACT: + if (args->orig_dest->flavor == CIL_BLOCKINHERIT) { + /* When inheriting a block, don't copy any blockabstract + * statements. Inheriting a block from a block that was + * just inherited never worked. */ + return SEPOL_OK; + } copy_func = &cil_copy_blockabstract; break; case CIL_BLOCKINHERIT: @@ -2098,7 +2104,7 @@ exit: return rc; } -int __cil_copy_last_child_helper(__attribute__((unused)) struct cil_tree_node *orig, void *extra_args) +static int __cil_copy_last_child_helper(__attribute__((unused)) struct cil_tree_node *orig, void *extra_args) { struct cil_tree_node *node = NULL; struct cil_args_copy *args = NULL; diff --git a/libsepol/cil/src/cil_find.c b/libsepol/cil/src/cil_find.c index 3898725f18d5a7d7b7060a425907f8dd6ef1d876..8b755277ce1dfc326f5aa6bdd06929f1752b6e42 100644 --- a/libsepol/cil/src/cil_find.c +++ b/libsepol/cil/src/cil_find.c @@ -292,7 +292,7 @@ exit: return rc; } -int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self) +static int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self) { int rc = SEPOL_OK; struct cil_symtab_datum *s1 = avrule->src; diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h index 6f1d3cb51fae7161637e282fa38c08da3222700f..a76047628130e57bcf6e86f1ada30d504290f657 100644 --- a/libsepol/cil/src/cil_internal.h +++ b/libsepol/cil/src/cil_internal.h @@ -730,14 +730,14 @@ struct cil_context { }; enum cil_filecon_types { - CIL_FILECON_FILE = 1, + CIL_FILECON_ANY = 0, + CIL_FILECON_FILE, CIL_FILECON_DIR, CIL_FILECON_CHAR, CIL_FILECON_BLOCK, CIL_FILECON_SOCKET, CIL_FILECON_PIPE, CIL_FILECON_SYMLINK, - CIL_FILECON_ANY }; struct cil_filecon { @@ -791,6 +791,7 @@ struct cil_ipaddr { struct cil_genfscon { char *fs_str; char *path_str; + enum cil_filecon_types file_type; char *context_str; struct cil_context *context; }; diff --git a/libsepol/cil/src/cil_list.c b/libsepol/cil/src/cil_list.c index 8a426f1f5950e9aea54e1d8e8f306e3e0d030ff0..85446b4ca11ae096830ee1b0d3e4719edeb42313 100644 --- a/libsepol/cil/src/cil_list.c +++ b/libsepol/cil/src/cil_list.c @@ -35,7 +35,7 @@ #include "cil_log.h" #include "cil_mem.h" -__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_list_error(const char* msg, ...) +__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) static void cil_list_error(const char* msg, ...) { va_list ap; va_start(ap, msg); diff --git a/libsepol/cil/src/cil_log.c b/libsepol/cil/src/cil_log.c index a8e4d2e94a78c4a6f64ebeaef3379dcc98702b6f..f4c6e415e7876e7eeaa399f238af6cd6a872cb7b 100644 --- a/libsepol/cil/src/cil_log.c +++ b/libsepol/cil/src/cil_log.c @@ -37,12 +37,12 @@ static enum cil_log_level cil_log_level = CIL_ERR; -void cil_default_log_handler(__attribute__((unused)) int lvl, const char *msg) +static void cil_default_log_handler(__attribute__((unused)) int lvl, const char *msg) { fprintf(stderr, "%s", msg); } -void (*cil_log_handler)(int lvl, const char *msg) = &cil_default_log_handler; +static void (*cil_log_handler)(int lvl, const char *msg) = &cil_default_log_handler; void cil_set_log_handler(void (*handler)(int lvl, const char *msg)) { @@ -53,8 +53,13 @@ __attribute__ ((format (printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, co { if (cil_log_level >= lvl) { char buff[MAX_LOG_SIZE]; - vsnprintf(buff, MAX_LOG_SIZE, msg, args); - (*cil_log_handler)(cil_log_level, buff); + int n = vsnprintf(buff, MAX_LOG_SIZE, msg, args); + if (n > 0) { + (*cil_log_handler)(cil_log_level, buff); + if (n >= MAX_LOG_SIZE) { + (*cil_log_handler)(cil_log_level, " "); + } + } } } @@ -70,3 +75,8 @@ void cil_set_log_level(enum cil_log_level lvl) { cil_log_level = lvl; } + +enum cil_log_level cil_get_log_level(void) +{ + return cil_log_level; +} diff --git a/libsepol/cil/src/cil_log.h b/libsepol/cil/src/cil_log.h index 541569be616d577c71bf9a03bf680e16fcf0f706..442781fb77f4606868a66bd65da10abdedf26f99 100644 --- a/libsepol/cil/src/cil_log.h +++ b/libsepol/cil/src/cil_log.h @@ -38,4 +38,6 @@ __attribute__ ((format(printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args); __attribute__ ((format(printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...); +enum cil_log_level cil_get_log_level(void); + #endif // CIL_LOG_H_ diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c index 7e2c2b9a85c3545630b4c5554a2795e11c085605..714ce227e5f9f4b2b6f06245407bfb15219ffc52 100644 --- a/libsepol/cil/src/cil_post.c +++ b/libsepol/cil/src/cil_post.c @@ -366,7 +366,7 @@ int cil_post_nodecon_compare(const void *a, const void *b) } } -int cil_post_pirqcon_compare(const void *a, const void *b) +static int cil_post_pirqcon_compare(const void *a, const void *b) { int rc = SEPOL_ERR; struct cil_pirqcon *apirqcon = *(struct cil_pirqcon**)a; @@ -383,7 +383,7 @@ int cil_post_pirqcon_compare(const void *a, const void *b) return rc; } -int cil_post_iomemcon_compare(const void *a, const void *b) +static int cil_post_iomemcon_compare(const void *a, const void *b) { int rc = SEPOL_ERR; struct cil_iomemcon *aiomemcon = *(struct cil_iomemcon**)a; @@ -402,7 +402,7 @@ int cil_post_iomemcon_compare(const void *a, const void *b) return rc; } -int cil_post_ioportcon_compare(const void *a, const void *b) +static int cil_post_ioportcon_compare(const void *a, const void *b) { int rc = SEPOL_ERR; struct cil_ioportcon *aioportcon = *(struct cil_ioportcon**)a; @@ -421,7 +421,7 @@ int cil_post_ioportcon_compare(const void *a, const void *b) return rc; } -int cil_post_pcidevicecon_compare(const void *a, const void *b) +static int cil_post_pcidevicecon_compare(const void *a, const void *b) { int rc = SEPOL_ERR; struct cil_pcidevicecon *apcidevicecon = *(struct cil_pcidevicecon**)a; @@ -438,7 +438,7 @@ int cil_post_pcidevicecon_compare(const void *a, const void *b) return rc; } -int cil_post_devicetreecon_compare(const void *a, const void *b) +static int cil_post_devicetreecon_compare(const void *a, const void *b) { int rc = SEPOL_ERR; struct cil_devicetreecon *adevicetreecon = *(struct cil_devicetreecon**)a; @@ -466,35 +466,35 @@ int cil_post_fsuse_compare(const void *a, const void *b) return rc; } -int cil_post_filecon_context_compare(const void *a, const void *b) +static int cil_post_filecon_context_compare(const void *a, const void *b) { struct cil_filecon *a_filecon = *(struct cil_filecon**)a; struct cil_filecon *b_filecon = *(struct cil_filecon**)b; return context_compare(a_filecon->context, b_filecon->context); } -int cil_post_ibpkeycon_context_compare(const void *a, const void *b) +static int cil_post_ibpkeycon_context_compare(const void *a, const void *b) { struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a; struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b; return context_compare(a_ibpkeycon->context, b_ibpkeycon->context); } -int cil_post_portcon_context_compare(const void *a, const void *b) +static int cil_post_portcon_context_compare(const void *a, const void *b) { struct cil_portcon *a_portcon = *(struct cil_portcon**)a; struct cil_portcon *b_portcon = *(struct cil_portcon**)b; return context_compare(a_portcon->context, b_portcon->context); } -int cil_post_genfscon_context_compare(const void *a, const void *b) +static int cil_post_genfscon_context_compare(const void *a, const void *b) { struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a; struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b; return context_compare(a_genfscon->context, b_genfscon->context); } -int cil_post_netifcon_context_compare(const void *a, const void *b) +static int cil_post_netifcon_context_compare(const void *a, const void *b) { int rc; struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a; @@ -506,56 +506,56 @@ int cil_post_netifcon_context_compare(const void *a, const void *b) return context_compare(a_netifcon->packet_context, b_netifcon->packet_context); } -int cil_post_ibendportcon_context_compare(const void *a, const void *b) +static int cil_post_ibendportcon_context_compare(const void *a, const void *b) { struct cil_ibendportcon *a_ibendportcon = *(struct cil_ibendportcon **)a; struct cil_ibendportcon *b_ibendportcon = *(struct cil_ibendportcon **)b; return context_compare(a_ibendportcon->context, b_ibendportcon->context); } -int cil_post_nodecon_context_compare(const void *a, const void *b) +static int cil_post_nodecon_context_compare(const void *a, const void *b) { struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a; struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b; return context_compare(a_nodecon->context, b_nodecon->context); } -int cil_post_pirqcon_context_compare(const void *a, const void *b) +static int cil_post_pirqcon_context_compare(const void *a, const void *b) { struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a; struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b; return context_compare(a_pirqcon->context, b_pirqcon->context); } -int cil_post_iomemcon_context_compare(const void *a, const void *b) +static int cil_post_iomemcon_context_compare(const void *a, const void *b) { struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a; struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b; return context_compare(a_iomemcon->context, b_iomemcon->context); } -int cil_post_ioportcon_context_compare(const void *a, const void *b) +static int cil_post_ioportcon_context_compare(const void *a, const void *b) { struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a; struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b; return context_compare(a_ioportcon->context, b_ioportcon->context); } -int cil_post_pcidevicecon_context_compare(const void *a, const void *b) +static int cil_post_pcidevicecon_context_compare(const void *a, const void *b) { struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a; struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b; return context_compare(a_pcidevicecon->context, b_pcidevicecon->context); } -int cil_post_devicetreecon_context_compare(const void *a, const void *b) +static int cil_post_devicetreecon_context_compare(const void *a, const void *b) { struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a; struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b; return context_compare(a_devicetreecon->context, b_devicetreecon->context); } -int cil_post_fsuse_context_compare(const void *a, const void *b) +static int cil_post_fsuse_context_compare(const void *a, const void *b) { struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a; struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b; @@ -2280,8 +2280,10 @@ static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *fini static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str) { uint32_t count = sort->count; - uint32_t i, j = 0, removed = 0; + uint32_t i = 0, j, removed = 0; + int conflicting = 0; int rc = SEPOL_OK; + enum cil_log_level log_level = cil_get_log_level(); if (count < 2) { return SEPOL_OK; @@ -2289,36 +2291,43 @@ static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar) qsort(sort->array, sort->count, sizeof(sort->array), compar); - for (i=1; iarray[i], &sort->array[j]) != 0) { - j++; + i++; + if (conflicting >= 4) { + /* 2 rules were written when conflicting == 1 */ + cil_log(CIL_WARN, " Only first 4 of %d conflicting rules shown\n", conflicting); + } + conflicting = 0; } else { removed++; - if (!db->multiple_decls || - concompar(&sort->array[i], &sort->array[j]) != 0) { - struct cil_list_item li; - int rc2; - cil_log(CIL_WARN, "Found conflicting %s rules\n", - flavor_str); - rc = SEPOL_ERR; - li.flavor = flavor; - li.data = sort->array[i]; - rc2 = cil_tree_walk(db->ast->root, - __cil_post_report_conflict, - NULL, NULL, &li); - if (rc2 != SEPOL_OK) goto exit; - li.data = sort->array[j]; - rc2 = cil_tree_walk(db->ast->root, - __cil_post_report_conflict, - NULL, NULL, &li); - if (rc2 != SEPOL_OK) goto exit; + if (!db->multiple_decls || concompar(&sort->array[i], &sort->array[j]) != 0) { + conflicting++; + if (log_level >= CIL_WARN) { + struct cil_list_item li; + int rc2; + li.flavor = flavor; + if (conflicting == 1) { + cil_log(CIL_WARN, "Found conflicting %s rules\n", flavor_str); + rc = SEPOL_ERR; + li.data = sort->array[i]; + rc2 = cil_tree_walk(db->ast->root, __cil_post_report_conflict, + NULL, NULL, &li); + if (rc2 != SEPOL_OK) goto exit; + } + if (conflicting < 4 || log_level > CIL_WARN) { + li.data = sort->array[j]; + rc2 = cil_tree_walk(db->ast->root, __cil_post_report_conflict, + NULL, NULL, &li); + if (rc2 != SEPOL_OK) goto exit; + } + } } } - if (i != j) { - sort->array[j] = sort->array[i]; + if (i != j && !conflicting) { + sort->array[i] = sort->array[j]; } } - sort->count = count - removed; exit: @@ -2425,6 +2434,12 @@ static int cil_post_db(struct cil_db *db) goto exit; } + rc = __cil_post_process_context_rules(db->pirqcon, cil_post_pirqcon_compare, cil_post_pirqcon_context_compare, db, CIL_PIRQCON, CIL_KEY_IOMEMCON); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Problems processing pirqcon rules\n"); + goto exit; + } + rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Problems processing iomemcon rules\n"); diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c index 0ba075c840eee60c5f3facdc7bf52cc5881a42fc..0864d7ef01edc757f02e520af4acd4245bae5947 100644 --- a/libsepol/cil/src/cil_reset_ast.c +++ b/libsepol/cil/src/cil_reset_ast.c @@ -475,7 +475,7 @@ static void cil_reset_booleanif(struct cil_booleanif *bif) cil_list_destroy(&bif->datum_expr, CIL_FALSE); } -int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args) +static int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args) { switch (node->flavor) { case CIL_CLASS: diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index e97a9f46908d188626e532fa7f670efa6e2c7a9a..f5e22c97f37d01c9d4207427da42dfbf0487b937 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -65,6 +65,7 @@ struct cil_args_resolve { struct cil_list *sensitivityorder_lists; struct cil_list *in_list_before; struct cil_list *in_list_after; + struct cil_list *abstract_blocks; }; static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) @@ -190,7 +191,7 @@ exit: return rc; } -int cil_resolve_classperms_set(struct cil_tree_node *current, struct cil_classperms_set *cp_set, void *extra_args) +static int cil_resolve_classperms_set(struct cil_tree_node *current, struct cil_classperms_set *cp_set, void *extra_args) { int rc = SEPOL_ERR; struct cil_symtab_datum *datum = NULL; @@ -274,7 +275,7 @@ exit: return rc; } -void cil_type_used(struct cil_symtab_datum *datum, int used) +static void cil_type_used(struct cil_symtab_datum *datum, int used) { struct cil_typeattribute *attr = NULL; @@ -291,7 +292,7 @@ void cil_type_used(struct cil_symtab_datum *datum, int used) } } -int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args) +static int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args) { struct cil_symtab_datum *obj_datum = NULL; int rc = SEPOL_ERR; @@ -372,6 +373,7 @@ exit: int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args) { + struct cil_args_resolve *args = extra_args; struct cil_type_rule *rule = current->data; struct cil_symtab_datum *src_datum = NULL; struct cil_symtab_datum *tgt_datum = NULL; @@ -386,11 +388,15 @@ int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args) } rule->src = src_datum; - rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum); - if (rc != SEPOL_OK) { - goto exit; + if (rule->tgt_str == CIL_KEY_SELF) { + rule->tgt = args->db->selftype; + } else { + rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum); + if (rc != SEPOL_OK) { + goto exit; + } + rule->tgt = tgt_datum; } - rule->tgt = tgt_datum; rc = cil_resolve_name(current, rule->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum); if (rc != SEPOL_OK) { @@ -458,7 +464,7 @@ exit: return rc; } -int cil_resolve_expandtypeattribute(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_expandtypeattribute(struct cil_tree_node *current, void *extra_args) { struct cil_expandtypeattribute *expandattr = current->data; struct cil_symtab_datum *attr_datum = NULL; @@ -492,7 +498,7 @@ exit: return rc; } -int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor alias_flavor) +static int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor alias_flavor) { int rc = SEPOL_ERR; enum cil_sym_index sym_index; @@ -543,7 +549,7 @@ exit: return rc; } -int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor flavor) +static int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor flavor) { struct cil_alias *alias = current->data; struct cil_alias *a1 = current->data; @@ -637,11 +643,15 @@ int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar } nametypetrans->src = src_datum; - rc = cil_resolve_name(current, nametypetrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum); - if (rc != SEPOL_OK) { - goto exit; + if (nametypetrans->tgt_str == CIL_KEY_SELF) { + nametypetrans->tgt = args->db->selftype; + } else { + rc = cil_resolve_name(current, nametypetrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum); + if (rc != SEPOL_OK) { + goto exit; + } + nametypetrans->tgt = tgt_datum; } - nametypetrans->tgt = tgt_datum; rc = cil_resolve_name(current, nametypetrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum); if (rc != SEPOL_OK) { @@ -732,7 +742,7 @@ exit: return rc; } -int __class_update_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +static int __class_update_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) { struct cil_perm *perm = (struct cil_perm *)d; @@ -754,6 +764,11 @@ int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args) if (rc != SEPOL_OK) { goto exit; } + if (NODE(class_datum)->flavor != CIL_CLASS) { + cil_log(CIL_ERR, "Class %s is not a kernel class and cannot be associated with common %s\n", clscom->class_str, clscom->common_str); + rc = SEPOL_ERR; + goto exit; + } rc = cil_resolve_name(current, clscom->common_str, CIL_SYM_COMMONS, extra_args, &common_datum); if (rc != SEPOL_OK) { @@ -1172,7 +1187,7 @@ struct cil_ordered_list { struct cil_tree_node *node; }; -void __cil_ordered_list_init(struct cil_ordered_list **ordered) +static void __cil_ordered_list_init(struct cil_ordered_list **ordered) { *ordered = cil_malloc(sizeof(**ordered)); @@ -1181,7 +1196,7 @@ void __cil_ordered_list_init(struct cil_ordered_list **ordered) (*ordered)->node = NULL; } -void __cil_ordered_list_destroy(struct cil_ordered_list **ordered) +static void __cil_ordered_list_destroy(struct cil_ordered_list **ordered) { cil_list_destroy(&(*ordered)->list, CIL_FALSE); (*ordered)->node = NULL; @@ -1189,7 +1204,7 @@ void __cil_ordered_list_destroy(struct cil_ordered_list **ordered) *ordered = NULL; } -void __cil_ordered_lists_destroy(struct cil_list **ordered_lists) +static void __cil_ordered_lists_destroy(struct cil_list **ordered_lists) { struct cil_list_item *item = NULL; @@ -1209,13 +1224,13 @@ void __cil_ordered_lists_destroy(struct cil_list **ordered_lists) *ordered_lists = NULL; } -void __cil_ordered_lists_reset(struct cil_list **ordered_lists) +static void __cil_ordered_lists_reset(struct cil_list **ordered_lists) { __cil_ordered_lists_destroy(ordered_lists); cil_list_init(ordered_lists, CIL_LIST_ITEM); } -struct cil_list_item *__cil_ordered_item_insert(struct cil_list *old, struct cil_list_item *curr, struct cil_list_item *item) +static struct cil_list_item *__cil_ordered_item_insert(struct cil_list *old, struct cil_list_item *curr, struct cil_list_item *item) { if (item->flavor == CIL_SID) { struct cil_sid *sid = item->data; @@ -1250,7 +1265,7 @@ struct cil_list_item *__cil_ordered_item_insert(struct cil_list *old, struct cil return cil_list_insert(old, curr, item->flavor, item->data); } -int __cil_ordered_list_insert(struct cil_list *old, struct cil_list_item *ocurr, struct cil_list_item *nstart, struct cil_list_item *nstop) +static int __cil_ordered_list_insert(struct cil_list *old, struct cil_list_item *ocurr, struct cil_list_item *nstart, struct cil_list_item *nstop) { struct cil_list_item *ncurr = NULL; @@ -1263,7 +1278,7 @@ int __cil_ordered_list_insert(struct cil_list *old, struct cil_list_item *ocurr, return SEPOL_OK; } -struct cil_list_item *__cil_ordered_find_match(struct cil_list_item *t, struct cil_list_item *i) +static struct cil_list_item *__cil_ordered_find_match(struct cil_list_item *t, struct cil_list_item *i) { while (i) { if (i->data == t->data) { @@ -1274,7 +1289,7 @@ struct cil_list_item *__cil_ordered_find_match(struct cil_list_item *t, struct c return NULL; } -int __cil_ordered_lists_merge(struct cil_list *old, struct cil_list *new) +static int __cil_ordered_lists_merge(struct cil_list *old, struct cil_list *new) { struct cil_list_item *omatch = NULL; struct cil_list_item *ofirst = old->head; @@ -1403,7 +1418,7 @@ exit: return rc; } -struct cil_list *__cil_ordered_lists_merge_all(struct cil_list **ordered_lists, struct cil_list **unordered_lists) +static struct cil_list *__cil_ordered_lists_merge_all(struct cil_list **ordered_lists, struct cil_list **unordered_lists) { struct cil_list *composite = NULL; struct cil_list_item *curr = NULL; @@ -1550,7 +1565,7 @@ exit: return rc; } -void cil_set_cat_values(struct cil_list *ordered_cats, struct cil_db *db) +static void cil_set_cat_values(struct cil_list *ordered_cats, struct cil_db *db) { struct cil_list_item *curr; int v = 0; @@ -1646,7 +1661,7 @@ exit: return rc; } -int cil_resolve_cats(struct cil_tree_node *current, struct cil_cats *cats, void *extra_args) +static int cil_resolve_cats(struct cil_tree_node *current, struct cil_cats *cats, void *extra_args) { int rc = SEPOL_ERR; @@ -2218,7 +2233,7 @@ exit: return rc; } -int cil_resolve_devicetreecon(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_devicetreecon(struct cil_tree_node *current, void *extra_args) { struct cil_devicetreecon *devicetreecon = current->data; struct cil_symtab_datum *context_datum = NULL; @@ -2310,7 +2325,7 @@ exit: return rc; } -int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) { struct cil_blockinherit *inherit = current->data; struct cil_symtab_datum *block_datum = NULL; @@ -2343,7 +2358,7 @@ exit: return rc; } -int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) { struct cil_block *block = current->data; struct cil_args_resolve *args = extra_args; @@ -2379,11 +2394,25 @@ exit: return rc; } -int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) +static void cil_mark_subtree_abstract(struct cil_tree_node *node) +{ + struct cil_block *block = node->data; + + block->is_abstract = CIL_TRUE; + + for (node = node->cl_head; node; node = node->next) { + if (node->flavor == CIL_BLOCK) { + cil_mark_subtree_abstract(node); + } + } +} + +static int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) { struct cil_blockabstract *abstract = current->data; struct cil_symtab_datum *block_datum = NULL; struct cil_tree_node *block_node = NULL; + struct cil_args_resolve *args = extra_args; int rc = SEPOL_ERR; rc = cil_resolve_name(current, abstract->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum); @@ -2398,7 +2427,7 @@ int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) goto exit; } - ((struct cil_block*)block_datum)->is_abstract = CIL_TRUE; + cil_list_append(args->abstract_blocks, CIL_NODE, block_node); return SEPOL_OK; @@ -2449,7 +2478,7 @@ exit: return rc; } -int cil_resolve_in_list(struct cil_list *in_list, void *extra_args) +static int cil_resolve_in_list(struct cil_list *in_list, void *extra_args) { struct cil_list_item *curr = NULL; struct cil_tree_node *node = NULL; @@ -2503,7 +2532,7 @@ exit: } -int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor attr_flavor) +static int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor attr_flavor) { int rc = SEPOL_ERR; struct cil_bounds *bounds = current->data; @@ -2585,7 +2614,7 @@ exit: return rc; } -int cil_resolve_default(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_default(struct cil_tree_node *current, void *extra_args) { int rc = SEPOL_ERR; struct cil_default *def = current->data; @@ -2608,7 +2637,7 @@ exit: return rc; } -int cil_resolve_defaultrange(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_defaultrange(struct cil_tree_node *current, void *extra_args) { int rc = SEPOL_ERR; struct cil_defaultrange *def = current->data; @@ -2631,7 +2660,7 @@ exit: return rc; } -void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *terminating_node) +static void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *terminating_node) { struct cil_list *trace = NULL; struct cil_list_item * item = NULL; @@ -2666,7 +2695,7 @@ void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_n cil_list_destroy(&trace, CIL_FALSE); } -int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node) +static int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node) { struct cil_tree_node *curr = NULL; struct cil_call * call = NULL; @@ -3002,7 +3031,7 @@ exit: return rc; } -int cil_resolve_call(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_call(struct cil_tree_node *current, void *extra_args) { struct cil_call *call = current->data; struct cil_args_resolve *args = extra_args; @@ -3052,7 +3081,7 @@ exit: return rc; } -int cil_resolve_call_args(struct cil_tree_node *current, void *extra_args) +static int cil_resolve_call_args(struct cil_tree_node *current, void *extra_args) { struct cil_call *call = current->data; int rc = SEPOL_ERR; @@ -3583,7 +3612,7 @@ static int cil_check_for_bad_inheritance(struct cil_tree_node *node) return rc; } -int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) +static int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) { int rc = SEPOL_OK; struct cil_args_resolve *args = extra_args; @@ -3873,7 +3902,7 @@ exit: return rc; } -int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) +static int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { int rc = SEPOL_OK; struct cil_args_resolve *args = extra_args; @@ -3980,7 +4009,7 @@ exit: return rc; } -int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *extra_args) +static int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *extra_args) { int rc = SEPOL_ERR; struct cil_args_resolve *args = extra_args; @@ -4009,7 +4038,7 @@ exit: } -int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *extra_args) +static int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *extra_args) { int rc = SEPOL_ERR; struct cil_args_resolve *args = extra_args; @@ -4084,6 +4113,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) extra_args.sensitivityorder_lists = NULL; extra_args.in_list_before = NULL; extra_args.in_list_after = NULL; + extra_args.abstract_blocks = NULL; cil_list_init(&extra_args.to_destroy, CIL_NODE); cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); @@ -4093,6 +4123,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM); cil_list_init(&extra_args.in_list_before, CIL_IN); cil_list_init(&extra_args.in_list_after, CIL_IN); + cil_list_init(&extra_args.abstract_blocks, CIL_NODE); for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) { extra_args.pass = pass; @@ -4116,6 +4147,13 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) cil_list_destroy(&extra_args.in_list_after, CIL_FALSE); } + if (pass == CIL_PASS_BLKABS) { + struct cil_list_item *item; + cil_list_for_each(item, extra_args.abstract_blocks) { + cil_mark_subtree_abstract(item->data); + } + } + if (pass == CIL_PASS_BLKIN_LINK) { rc = cil_check_for_bad_inheritance(current); if (rc != SEPOL_OK) { @@ -4234,6 +4272,7 @@ exit: cil_list_destroy(&extra_args.to_destroy, CIL_FALSE); cil_list_destroy(&extra_args.in_list_before, CIL_FALSE); cil_list_destroy(&extra_args.in_list_after, CIL_FALSE); + cil_list_destroy(&extra_args.abstract_blocks, CIL_FALSE); return rc; } @@ -4255,9 +4294,13 @@ static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *nam case CIL_ROOT: goto exit; break; - case CIL_BLOCK: - symtab = &((struct cil_block*)node->data)->symtab[sym_index]; - rc = cil_symtab_get_datum(symtab, name, datum); + case CIL_BLOCK: { + struct cil_block *block = node->data; + if (!block->is_abstract) { + symtab = &block->symtab[sym_index]; + rc = cil_symtab_get_datum(symtab, name, datum); + } + } break; case CIL_BLOCKINHERIT: { struct cil_blockinherit *inherit = node->data; diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c index c195156071e1f0a6f5e9e58436fdf343abd2eaea..7e43a69028fc2c5fffb8f05e3bbdc6d971eab75b 100644 --- a/libsepol/cil/src/cil_symtab.c +++ b/libsepol/cil/src/cil_symtab.c @@ -42,7 +42,7 @@ #include "cil_strpool.h" #include "cil_log.h" -__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_symtab_error(const char* msg, ...) +__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) static void cil_symtab_error(const char* msg, ...) { va_list ap; va_start(ap, msg); @@ -149,7 +149,7 @@ void cil_symtab_destroy(symtab_t *symtab) } } -void cil_complex_symtab_hash(struct cil_complex_symtab_key *ckey, int mask, intptr_t *hash) +static void cil_complex_symtab_hash(struct cil_complex_symtab_key *ckey, int mask, intptr_t *hash) { intptr_t sum = ckey->key1 + ckey->key2 + ckey->key3 + ckey->key4; *hash = (intptr_t)((sum >> 2) & mask); diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c index aafc9dee39edf33e36ffd100e67eab07236b1d48..6376c208e960a8eb918958bc8e1c2efb976afe09 100644 --- a/libsepol/cil/src/cil_tree.c +++ b/libsepol/cil/src/cil_tree.c @@ -41,15 +41,6 @@ #include "cil_parser.h" #include "cil_strpool.h" -__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_error(const char* msg, ...) -{ - va_list ap; - va_start(ap, msg); - cil_vlog(CIL_ERR, msg, ap); - va_end(ap); - exit(1); -} - struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **info_kind, uint32_t *hll_line, char **path) { int rc; @@ -273,7 +264,7 @@ void cil_tree_node_destroy(struct cil_tree_node **node) extra_args: any additional data to be passed to the helper functions */ -int cil_tree_walk_core(struct cil_tree_node *node, +static int cil_tree_walk_core(struct cil_tree_node *node, int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), int (*first_child)(struct cil_tree_node *node, void *extra_args), int (*last_child)(struct cil_tree_node *node, void *extra_args), diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c index d994d717d52963fab38290ba125c91c21756d9d4..4640dc59def0bc862d6657f7f70d37a0af93d4fa 100644 --- a/libsepol/cil/src/cil_verify.c +++ b/libsepol/cil/src/cil_verify.c @@ -591,7 +591,7 @@ int __cil_verify_initsids(struct cil_list *sids) return rc; } -int __cil_is_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) +static int __cil_is_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) { struct cil_list_item *i; @@ -606,7 +606,7 @@ int __cil_is_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) } -int __cil_verify_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) +static int __cil_verify_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) { if (__cil_is_cat_in_cats(cat, cats) != CIL_TRUE) { cil_log(CIL_ERR, "Failed to find category %s in category list\n", cat->datum.name); @@ -616,7 +616,7 @@ int __cil_verify_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats) return SEPOL_OK; } -int __cil_verify_cats_associated_with_sens(struct cil_sens *sens, struct cil_cats *cats) +static int __cil_verify_cats_associated_with_sens(struct cil_sens *sens, struct cil_cats *cats) { int rc = SEPOL_OK; struct cil_list_item *i, *j; @@ -650,7 +650,7 @@ int __cil_verify_cats_associated_with_sens(struct cil_sens *sens, struct cil_cat return rc; } -int __cil_verify_levelrange_sensitivity(struct cil_db *db, struct cil_sens *low, struct cil_sens *high) +static int __cil_verify_levelrange_sensitivity(struct cil_db *db, struct cil_sens *low, struct cil_sens *high) { struct cil_list_item *curr; int found = CIL_FALSE; @@ -679,7 +679,7 @@ exit: } -int __cil_verify_levelrange_cats(struct cil_cats *low, struct cil_cats *high) +static int __cil_verify_levelrange_cats(struct cil_cats *low, struct cil_cats *high) { int rc = SEPOL_ERR; struct cil_list_item *item; @@ -707,7 +707,7 @@ exit: return rc; } -int __cil_verify_levelrange(struct cil_db *db, struct cil_levelrange *lr) +static int __cil_verify_levelrange(struct cil_db *db, struct cil_levelrange *lr) { int rc = SEPOL_ERR; @@ -739,7 +739,7 @@ exit: return rc; } -int __cil_verify_named_levelrange(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_named_levelrange(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_levelrange *lr = node->data; @@ -814,7 +814,7 @@ exit: return rc; } -int __cil_verify_role(struct cil_tree_node *node) +static int __cil_verify_role(struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_role *role = node->data; @@ -845,7 +845,7 @@ exit: return rc; } -int __cil_verify_type(struct cil_tree_node *node) +static int __cil_verify_type(struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_type *type = node->data; @@ -876,7 +876,7 @@ exit: return rc; } -int __cil_verify_context(struct cil_db *db, struct cil_context *ctx) +static int __cil_verify_context(struct cil_db *db, struct cil_context *ctx) { int rc = SEPOL_ERR; struct cil_user *user = ctx->user; @@ -954,7 +954,7 @@ exit: return rc; } -int __cil_verify_named_context(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_named_context(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_context *ctx = node->data; @@ -970,7 +970,8 @@ exit: return rc; } -int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *symtab) +/* +static int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *symtab) { int rc = SEPOL_ERR; @@ -1016,8 +1017,9 @@ exit: cil_tree_log(node, CIL_ERR, "Invalid rule"); return rc; } +*/ -int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args) +static int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args) { int rc = SEPOL_ERR; struct cil_tree_node *rule_node = node; @@ -1105,7 +1107,7 @@ exit: return rc; } -int __cil_verify_booleanif(struct cil_tree_node *node, struct cil_complex_symtab *symtab) +static int __cil_verify_booleanif(struct cil_tree_node *node, struct cil_complex_symtab *symtab) { int rc = SEPOL_ERR; struct cil_booleanif *bif = (struct cil_booleanif*)node->data; @@ -1129,7 +1131,7 @@ exit: return rc; } -int __cil_verify_netifcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_netifcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_netifcon *netif = node->data; @@ -1159,7 +1161,7 @@ exit: return rc; } -int __cil_verify_ibendportcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_ibendportcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_ibendportcon *ib_end_port = node->data; @@ -1179,7 +1181,7 @@ exit: return rc; } -int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_genfscon *genfs = node->data; @@ -1200,7 +1202,7 @@ exit: return rc; } -int __cil_verify_filecon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_filecon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_filecon *file = node->data; @@ -1226,7 +1228,7 @@ exit: return rc; } -int __cil_verify_nodecon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_nodecon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_nodecon *nodecon = node->data; @@ -1247,7 +1249,7 @@ exit: return rc; } -int __cil_verify_ibpkeycon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_ibpkeycon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_ibpkeycon *pkey = node->data; @@ -1267,7 +1269,7 @@ exit: return rc; } -int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_portcon *port = node->data; @@ -1288,7 +1290,7 @@ exit: return rc; } -int __cil_verify_pirqcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_pirqcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_pirqcon *pirq = node->data; @@ -1309,7 +1311,7 @@ exit: return rc; } -int __cil_verify_iomemcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_iomemcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_iomemcon *iomem = node->data; @@ -1330,7 +1332,7 @@ exit: return rc; } -int __cil_verify_ioportcon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_ioportcon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_ioportcon *ioport = node->data; @@ -1351,7 +1353,7 @@ exit: return rc; } -int __cil_verify_pcidevicecon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_pcidevicecon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_pcidevicecon *pcidev = node->data; @@ -1372,7 +1374,7 @@ exit: return rc; } -int __cil_verify_devicetreecon(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_devicetreecon(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_devicetreecon *dt = node->data; @@ -1393,7 +1395,7 @@ exit: return rc; } -int __cil_verify_fsuse(struct cil_db *db, struct cil_tree_node *node) +static int __cil_verify_fsuse(struct cil_db *db, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_fsuse *fsuse = node->data; @@ -1414,7 +1416,7 @@ exit: return rc; } -int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node *node) +static int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node *node) { int rc; struct cil_list *classes = NULL; @@ -1461,13 +1463,13 @@ exit: return rc; } -int __cil_verify_avrulex(struct cil_tree_node *node) +static int __cil_verify_avrulex(struct cil_tree_node *node) { struct cil_avrule *avrulex = node->data; return __cil_verify_permissionx(avrulex->perms.x.permx, node); } -int __cil_verify_class(struct cil_tree_node *node) +static int __cil_verify_class(struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_class *class = node->data; @@ -1503,7 +1505,7 @@ exit: return rc; } -int __cil_verify_policycap(struct cil_tree_node *node) +static int __cil_verify_policycap(struct cil_tree_node *node) { int rc; struct cil_policycap *polcap = node->data; diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c index d7f00bcc35d82ea00caf875acfde9ec43e77299c..b75784ef25dc6fc58c6f19b9d8cca6bbed786e60 100644 --- a/libsepol/cil/src/cil_write_ast.c +++ b/libsepol/cil/src/cil_write_ast.c @@ -546,7 +546,7 @@ static const char *macro_param_flavor_to_string(enum cil_flavor flavor) return str; } -void cil_write_src_info_node(FILE *out, struct cil_tree_node *node) +static void cil_write_src_info_node(FILE *out, struct cil_tree_node *node) { struct cil_src_info *info = node->data; if (info->kind == CIL_KEY_SRC_CIL || info->kind == CIL_KEY_SRC_HLL_LMS) { @@ -1232,24 +1232,34 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) struct cil_filecon *filecon = node->data; fprintf(out, "(filecon "); fprintf(out, "\"%s\" ", filecon->path_str); - if (filecon->type == CIL_FILECON_FILE) + switch (filecon->type) { + case CIL_FILECON_ANY: + fprintf(out, "%s ", CIL_KEY_ANY); + break; + case CIL_FILECON_FILE: fprintf(out, "%s ", CIL_KEY_FILE); - else if (filecon->type == CIL_FILECON_DIR) + break; + case CIL_FILECON_DIR: fprintf(out, "%s ", CIL_KEY_DIR); - else if (filecon->type == CIL_FILECON_CHAR) + break; + case CIL_FILECON_CHAR: fprintf(out, "%s ", CIL_KEY_CHAR); - else if (filecon->type == CIL_FILECON_BLOCK) + break; + case CIL_FILECON_BLOCK: fprintf(out, "%s ", CIL_KEY_BLOCK); - else if (filecon->type == CIL_FILECON_SOCKET) + break; + case CIL_FILECON_SOCKET: fprintf(out, "%s ", CIL_KEY_SOCKET); - else if (filecon->type == CIL_FILECON_PIPE) + break; + case CIL_FILECON_PIPE: fprintf(out, "%s ", CIL_KEY_PIPE); - else if (filecon->type == CIL_FILECON_SYMLINK) + break; + case CIL_FILECON_SYMLINK: fprintf(out, "%s ", CIL_KEY_SYMLINK); - else if (filecon->type == CIL_FILECON_ANY) - fprintf(out, "%s ", CIL_KEY_ANY); - else + break; + default: fprintf(out, " "); + } if (filecon->context) write_context(out, filecon->context, CIL_TRUE); else if (filecon->context_str) @@ -1318,6 +1328,33 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) struct cil_genfscon *genfscon = node->data; fprintf(out, "(genfscon "); fprintf(out, "%s \"%s\" ", genfscon->fs_str, genfscon->path_str); + if (genfscon->file_type != CIL_FILECON_ANY) { + switch (genfscon->file_type) { + case CIL_FILECON_FILE: + fprintf(out, "%s ", CIL_KEY_FILE); + break; + case CIL_FILECON_DIR: + fprintf(out, "%s ", CIL_KEY_DIR); + break; + case CIL_FILECON_CHAR: + fprintf(out, "%s ", CIL_KEY_CHAR); + break; + case CIL_FILECON_BLOCK: + fprintf(out, "%s ", CIL_KEY_BLOCK); + break; + case CIL_FILECON_SOCKET: + fprintf(out, "%s ", CIL_KEY_SOCKET); + break; + case CIL_FILECON_PIPE: + fprintf(out, "%s ", CIL_KEY_PIPE); + break; + case CIL_FILECON_SYMLINK: + fprintf(out, "%s ", CIL_KEY_SYMLINK); + break; + default: + fprintf(out, " "); + } + } if (genfscon->context) write_context(out, genfscon->context, CIL_TRUE); else diff --git a/libsepol/fuzz/binpolicy-fuzzer.c b/libsepol/fuzz/binpolicy-fuzzer.c new file mode 100644 index 0000000000000000000000000000000000000000..85c59645049c1e978087600e0722823f0e82b7ff --- /dev/null +++ b/libsepol/fuzz/binpolicy-fuzzer.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +static int write_binary_policy(policydb_t *p, FILE *outfp) +{ + struct policy_file pf; + + policy_file_init(&pf); + pf.type = PF_USE_STDIO; + pf.fp = outfp; + return policydb_write(p, &pf); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + policydb_t policydb = {}; + sidtab_t sidtab = {}; + struct policy_file pf; + FILE *devnull = NULL; + + sepol_debug(0); + + policy_file_init(&pf); + pf.type = PF_USE_MEMORY; + pf.data = (char *) data; + pf.len = size; + + if (policydb_init(&policydb)) + goto exit; + + if (policydb_read(&policydb, &pf, /*verbose=*/0)) + goto exit; + + if (policydb_load_isids(&policydb, &sidtab)) + goto exit; + + if (policydb.policy_type == POLICY_KERN) + (void) policydb_optimize(&policydb); + + devnull = fopen("/dev/null", "w"); + if (!devnull) + goto exit; + + (void) write_binary_policy(&policydb, devnull); + + (void) sepol_kernel_policydb_to_conf(devnull, &policydb); + + (void) sepol_kernel_policydb_to_cil(devnull, &policydb); + +exit: + if (devnull != NULL) + fclose(devnull); + + policydb_destroy(&policydb); + sepol_sidtab_destroy(&sidtab); + + /* Non-zero return values are reserved for future use. */ + return 0; +} diff --git a/libsepol/fuzz/policy.bin b/libsepol/fuzz/policy.bin new file mode 100644 index 0000000000000000000000000000000000000000..6f977ef34479daa9bf2e848c502ecea8d96f7912 Binary files /dev/null and b/libsepol/fuzz/policy.bin differ diff --git a/libsepol/fuzz/secilc-fuzzer.c b/libsepol/fuzz/secilc-fuzzer.c index 255b324187c8157974d8063e9619a76b4a58c903..9a1a16de98af8590aa1473c289e422908322a9b0 100644 --- a/libsepol/fuzz/secilc-fuzzer.c +++ b/libsepol/fuzz/secilc-fuzzer.c @@ -8,6 +8,10 @@ #include #include +static void log_handler(__attribute__((unused)) int lvl, __attribute__((unused)) const char *msg) { + /* be quiet */ +} + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { enum cil_log_level log_level = CIL_ERR; struct sepol_policy_file *pf = NULL; @@ -24,6 +28,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { sepol_policydb_t *pdb = NULL; cil_set_log_level(log_level); + cil_set_log_handler(log_handler); cil_db_init(&db); cil_set_disable_dontaudit(db, disable_dontaudit); diff --git a/libsepol/include/sepol/policydb/context.h b/libsepol/include/sepol/policydb/context.h index 37cdc591ce62d24a813d34d806afc347df7a024c..025c894fa03984c90049c52eda54b499d8718a49 100644 --- a/libsepol/include/sepol/policydb/context.h +++ b/libsepol/include/sepol/policydb/context.h @@ -43,7 +43,7 @@ static inline void mls_context_init(context_struct_t * c) } static inline int mls_context_cpy(context_struct_t * dst, - context_struct_t * src) + const context_struct_t * src) { if (mls_range_cpy(&dst->range, &src->range) < 0) @@ -55,7 +55,7 @@ static inline int mls_context_cpy(context_struct_t * dst, /* * Sets both levels in the MLS range of 'dst' to the low level of 'src'. */ -static inline int mls_context_cpy_low(context_struct_t *dst, context_struct_t *src) +static inline int mls_context_cpy_low(context_struct_t *dst, const context_struct_t *src) { int rc; @@ -75,7 +75,7 @@ out: /* * Sets both levels in the MLS range of 'dst' to the high level of 'src'. */ -static inline int mls_context_cpy_high(context_struct_t *dst, context_struct_t *src) +static inline int mls_context_cpy_high(context_struct_t *dst, const context_struct_t *src) { int rc; @@ -92,12 +92,12 @@ out: return rc; } -static inline int mls_context_glblub(context_struct_t *dst, context_struct_t *c1, context_struct_t *c2) +static inline int mls_context_glblub(context_struct_t *dst, const context_struct_t *c1, const context_struct_t *c2) { return mls_range_glblub(&dst->range, &c1->range, &c2->range); } -static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2) +static inline int mls_context_cmp(const context_struct_t * c1, const context_struct_t * c2) { return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) && mls_level_eq(&c1->range.level[1], &c2->range.level[1])); @@ -118,7 +118,7 @@ static inline void context_init(context_struct_t * c) memset(c, 0, sizeof(*c)); } -static inline int context_cpy(context_struct_t * dst, context_struct_t * src) +static inline int context_cpy(context_struct_t * dst, const context_struct_t * src) { dst->user = src->user; dst->role = src->role; @@ -135,7 +135,7 @@ static inline void context_destroy(context_struct_t * c) mls_context_destroy(c); } -static inline int context_cmp(context_struct_t * c1, context_struct_t * c2) +static inline int context_cmp(const context_struct_t * c1, const context_struct_t * c2) { return ((c1->user == c2->user) && (c1->role == c2->role) && diff --git a/libsepol/include/sepol/policydb/flask_types.h b/libsepol/include/sepol/policydb/flask_types.h index 7bec5129fe1d1da34b573601e0f243e39c356639..02c22eacf04a2c32d0514969c62f00bc66665ac6 100644 --- a/libsepol/include/sepol/policydb/flask_types.h +++ b/libsepol/include/sepol/policydb/flask_types.h @@ -27,6 +27,7 @@ extern "C" { * understanding of the security policy. */ typedef char *sepol_security_context_t; +typedef const char *sepol_const_security_context_t; /* * An access vector (AV) is a collection of related permissions diff --git a/libsepol/include/sepol/policydb/mls_types.h b/libsepol/include/sepol/policydb/mls_types.h index 0ba6d9defcb8fd7123cc261a5f379c3345edeec9..12990c69bbbc9ea3b989c98bd6092fb8c85e81cd 100644 --- a/libsepol/include/sepol/policydb/mls_types.h +++ b/libsepol/include/sepol/policydb/mls_types.h @@ -50,7 +50,7 @@ typedef struct mls_range { mls_level_t level[2]; /* low == level[0], high == level[1] */ } mls_range_t; -static inline int mls_range_glblub(struct mls_range *dst, struct mls_range *r1, struct mls_range *r2) +static inline int mls_range_glblub(struct mls_range *dst, const struct mls_range *r1, const struct mls_range *r2) { if (r1->level[1].sens < r2->level[0].sens || r2->level[1].sens < r1->level[0].sens) { /* These ranges have no common sensitivities */ @@ -74,7 +74,7 @@ static inline int mls_range_glblub(struct mls_range *dst, struct mls_range *r1, } -static inline int mls_level_cpy(struct mls_level *dst, struct mls_level *src) +static inline int mls_level_cpy(struct mls_level *dst, const struct mls_level *src) { dst->sens = src->sens; @@ -119,7 +119,7 @@ static inline int mls_level_dom(const struct mls_level *l1, const struct mls_lev (mls_level_dom(&(r2).level[0], &(r1).level[0]) && \ mls_level_dom(&(r1).level[1], &(r2).level[1])) -static inline int mls_range_cpy(mls_range_t * dst, mls_range_t * src) +static inline int mls_range_cpy(mls_range_t * dst, const mls_range_t * src) { if (mls_level_cpy(&dst->level[0], &src->level[0]) < 0) @@ -149,7 +149,7 @@ static inline void mls_range_destroy(struct mls_range *r) mls_level_destroy(&r->level[1]); } -static inline int mls_range_eq(struct mls_range *r1, struct mls_range *r2) +static inline int mls_range_eq(const struct mls_range *r1, const struct mls_range *r2) { return (mls_level_eq(&r1->level[0], &r2->level[0]) && mls_level_eq(&r1->level[1], &r2->level[1])); @@ -174,10 +174,10 @@ extern void mls_semantic_cat_init(mls_semantic_cat_t *c); extern void mls_semantic_cat_destroy(mls_semantic_cat_t *c); extern void mls_semantic_level_init(mls_semantic_level_t *l); extern void mls_semantic_level_destroy(mls_semantic_level_t *l); -extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, mls_semantic_level_t *src); +extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, const mls_semantic_level_t *src); extern void mls_semantic_range_init(mls_semantic_range_t *r); extern void mls_semantic_range_destroy(mls_semantic_range_t *r); -extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, mls_semantic_range_t *src); +extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, const mls_semantic_range_t *src); #ifdef __cplusplus } diff --git a/libsepol/include/sepol/policydb/polcaps.h b/libsepol/include/sepol/policydb/polcaps.h index 40669fb5147d2f62c0fe19cf2530c6786e6dfc5a..f5e32e60975d146a8af83f19c196083cd19031c3 100644 --- a/libsepol/include/sepol/policydb/polcaps.h +++ b/libsepol/include/sepol/policydb/polcaps.h @@ -7,16 +7,17 @@ extern "C" { /* Policy capabilities */ enum { - POLICYDB_CAPABILITY_NETPEER, - POLICYDB_CAPABILITY_OPENPERM, - POLICYDB_CAPABILITY_EXTSOCKCLASS, - POLICYDB_CAPABILITY_ALWAYSNETWORK, - POLICYDB_CAPABILITY_CGROUPSECLABEL, - POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION, - POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS, - __POLICYDB_CAPABILITY_MAX + POLICYDB_CAP_NETPEER, + POLICYDB_CAP_OPENPERM, + POLICYDB_CAP_EXTSOCKCLASS, + POLICYDB_CAP_ALWAYSNETWORK, + POLICYDB_CAP_CGROUPSECLABEL, + POLICYDB_CAP_NNP_NOSUID_TRANSITION, + POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS, + POLICYDB_CAP_IOCTL_SKIP_CLOEXEC, + __POLICYDB_CAP_MAX }; -#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) +#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1) /* Convert a capability name to number. */ extern int sepol_polcap_getnum(const char *name); diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index 4bf9f05ddd0a3442f033292ff0da0318f4a1a6b0..de0068a6c6f270cf3b18db3f3df2d7a1566cd99d 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -314,6 +314,7 @@ typedef struct role_allow_rule { } role_allow_rule_t; typedef struct filename_trans_rule { + uint32_t flags; /* may have RULE_SELF set */ type_set_t stypes; type_set_t ttypes; uint32_t tclass; @@ -781,9 +782,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define MOD_POLICYDB_VERSION_XPERMS_IOCTL 18 #define MOD_POLICYDB_VERSION_INFINIBAND 19 #define MOD_POLICYDB_VERSION_GLBLUB 20 +#define MOD_POLICYDB_VERSION_SELF_TYPETRANS 21 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_GLBLUB +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SELF_TYPETRANS #define POLICYDB_CONFIG_MLS 1 diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h index 048f8a5ac1d76a852c3b39c69f82ef3254e24f82..bcb0930fd425576f541aa6c1d6bb1fc1201af1fd 100644 --- a/libsepol/include/sepol/policydb/services.h +++ b/libsepol/include/sepol/policydb/services.h @@ -103,6 +103,15 @@ extern int sepol_string_to_av_perm(sepol_security_class_t tclass, const char *perm_name, sepol_access_vector_t *av); +/* + * Return a string representation of the permission av bit associated with + * tclass. + * Returns a pointer to an internal buffer, overridden by the next call to + * this function or sepol_av_to_string(). + */ + extern const char *sepol_av_perm_to_string(sepol_security_class_t tclass, + sepol_access_vector_t av); + /* * Compute a SID to use for labeling a new object in the * class `tclass' based on a SID pair. @@ -146,7 +155,7 @@ extern int sepol_sid_to_context(sepol_security_id_t sid, /* IN */ * Return a SID associated with the security context that * has the string representation specified by `scontext'. */ -extern int sepol_context_to_sid(const sepol_security_context_t scontext, /* IN */ +extern int sepol_context_to_sid(sepol_const_security_context_t scontext, /* IN */ size_t scontext_len, /* IN */ sepol_security_id_t * out_sid); /* OUT */ diff --git a/libsepol/src/Makefile b/libsepol/src/Makefile index dc8b1773d9749bd70651f69803761805d970e9ea..13410c6726c38d17e9e9bc201e2e4e7e32fa6fe0 100644 --- a/libsepol/src/Makefile +++ b/libsepol/src/Makefile @@ -29,6 +29,12 @@ LOBJS += $(sort $(patsubst %.c,%.lo,$(sort $(wildcard $(CILDIR)/src/*.c)) $(CIL_ override CFLAGS += -I$(CILDIR)/include endif +# check for reallocarray(3) availability +H := \# +ifeq (yes,$(shell printf '${H}define _GNU_SOURCE\n${H}include \nint main(void){void*p=reallocarray(NULL, 1, sizeof(char));return 0;}' | $(CC) -x c -o /dev/null - >/dev/null 2>&1 && echo yes)) +override CFLAGS += -DHAVE_REALLOCARRAY +endif + LD_SONAME_FLAGS=-soname,$(LIBSO),--version-script=$(LIBMAP),-z,defs LN=ln diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c index dd2749a09dc08dbddc3f130c961c8a10a514d296..161874c33a31266f83ec898a93236ef9cff13ca7 100644 --- a/libsepol/src/assertion.c +++ b/libsepol/src/assertion.c @@ -36,13 +36,21 @@ struct avtab_match_args { unsigned long errors; }; +static const char* policy_name(policydb_t *p) { + const char *policy_file = "policy.conf"; + if (p->name) { + policy_file = p->name; + } + return policy_file; +} + static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule, unsigned int stype, unsigned int ttype, const class_perm_node_t *curperm, uint32_t perms) { if (avrule->source_filename) { - ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };", - avrule->source_line, avrule->source_filename, avrule->line, + ERR(handle, "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };", + avrule->source_line, avrule->source_filename, avrule->line, policy_name(p), p->p_type_val_to_name[stype], p->p_type_val_to_name[ttype], p->p_class_val_to_name[curperm->tclass - 1], @@ -65,14 +73,11 @@ static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data) { for (; cp; cp = cp->next) { - if ((cp->tclass == class) && (cp->data & data)) { - break; - } + if ((cp->tclass == class) && (cp->data & data)) + return 1; } - if (!cp) - return 0; - return 1; + return 0; } static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) { @@ -151,15 +156,16 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle, ebitmap_t *tattr = &p->type_attr_map[ttype]; ebitmap_node_t *snode, *tnode; unsigned int i, j; - int rc = 1; - int ret = 0; + int rc; + int found_xperm = 0; + int errors = 0; memcpy(&tmp_key, k, sizeof(avtab_key_t)); tmp_key.specified = AVTAB_XPERMS_ALLOWED; ebitmap_for_each_positive_bit(sattr, snode, i) { + tmp_key.source_type = i + 1; ebitmap_for_each_positive_bit(tattr, tnode, j) { - tmp_key.source_type = i + 1; tmp_key.target_type = j + 1; for (node = avtab_search_node(avtab, &tmp_key); node; @@ -168,40 +174,39 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle, if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) continue; - + found_xperm = 1; rc = check_extended_permissions(avrule->xperms, xperms); /* failure on the extended permission check_extended_permissions */ if (rc) { extended_permissions_violated(&error, avrule->xperms, xperms); - ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n" + ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" "allowxperm %s %s:%s %s;", - avrule->source_line, avrule->source_filename, avrule->line, + avrule->source_line, avrule->source_filename, avrule->line, policy_name(p), p->p_type_val_to_name[i], p->p_type_val_to_name[j], p->p_class_val_to_name[curperm->tclass - 1], sepol_extended_perms_to_string(&error)); - rc = 0; - ret++; + errors++; } } } } /* failure on the regular permissions */ - if (rc) { - ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n" + if (!found_xperm) { + ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" "allow %s %s:%s {%s };", - avrule->source_line, avrule->source_filename, avrule->line, + avrule->source_line, avrule->source_filename, avrule->line, policy_name(p), p->p_type_val_to_name[stype], p->p_type_val_to_name[ttype], p->p_class_val_to_name[curperm->tclass - 1], sepol_av_to_string(p, curperm->tclass, perms)); - ret++; + errors++; } - return ret; + return errors; } static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args) @@ -214,9 +219,10 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void avrule_t *avrule = a->avrule; class_perm_node_t *cp; uint32_t perms; - ebitmap_t src_matches, tgt_matches, self_matches, matches; + ebitmap_t src_matches, tgt_matches, self_matches; ebitmap_node_t *snode, *tnode; unsigned int i, j; + const int is_avrule_self = (avrule->flags & RULE_SELF) != 0; if ((k->specified & AVTAB_ALLOWED) == 0) return 0; @@ -227,31 +233,27 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void ebitmap_init(&src_matches); ebitmap_init(&tgt_matches); ebitmap_init(&self_matches); - ebitmap_init(&matches); rc = ebitmap_and(&src_matches, &avrule->stypes.types, &p->attr_type_map[k->source_type - 1]); - if (rc) + if (rc < 0) goto oom; if (ebitmap_is_empty(&src_matches)) goto exit; rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]); - if (rc) + if (rc < 0) goto oom; - if (avrule->flags == RULE_SELF) { - rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]); - if (rc) - goto oom; - rc = ebitmap_and(&self_matches, &avrule->stypes.types, &matches); - if (rc) + if (is_avrule_self) { + rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]); + if (rc < 0) goto oom; if (!ebitmap_is_empty(&self_matches)) { rc = ebitmap_union(&tgt_matches, &self_matches); - if (rc) + if (rc < 0) goto oom; } } @@ -268,6 +270,8 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void ebitmap_for_each_positive_bit(&src_matches, snode, i) { ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { + if (is_avrule_self && i != j) + continue; if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) { a->errors += report_assertion_extended_permissions(handle,p, avrule, i, j, cp, perms, k, avtab); @@ -278,16 +282,12 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void } } } - goto exit; oom: - ERR(NULL, "Out of memory - unable to check neverallows"); - exit: ebitmap_destroy(&src_matches); ebitmap_destroy(&tgt_matches); ebitmap_destroy(&self_matches); - ebitmap_destroy(&matches); return rc; } @@ -301,12 +301,14 @@ static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avru args.avrule = avrule; args.errors = 0; + args.avtab = &p->te_avtab; rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args); - if (rc) + if (rc < 0) goto oom; + args.avtab = &p->te_cond_avtab; rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args); - if (rc) + if (rc < 0) goto oom; return args.errors; @@ -337,8 +339,8 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t tmp_key.specified = AVTAB_XPERMS_ALLOWED; ebitmap_for_each_positive_bit(sattr, snode, i) { + tmp_key.source_type = i + 1; ebitmap_for_each_positive_bit(tattr, tnode, j) { - tmp_key.source_type = i + 1; tmp_key.target_type = j + 1; for (node = avtab_search_node(avtab, &tmp_key); node; @@ -350,7 +352,7 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t continue; rc = check_extended_permissions(neverallow_xperms, xperms); if (rc) - break; + return rc; } } } @@ -377,125 +379,138 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab, avtab_key_t *k, policydb_t *p) { - ebitmap_t src_matches, tgt_matches, self_matches, matches; + ebitmap_t src_matches, tgt_matches, self_matches; unsigned int i, j; ebitmap_node_t *snode, *tnode; - class_perm_node_t *cp; + const int is_avrule_self = (avrule->flags & RULE_SELF) != 0; int rc; - int ret = 1; ebitmap_init(&src_matches); ebitmap_init(&tgt_matches); ebitmap_init(&self_matches); - ebitmap_init(&matches); rc = ebitmap_and(&src_matches, &avrule->stypes.types, &p->attr_type_map[k->source_type - 1]); - if (rc) + if (rc < 0) goto oom; - if (ebitmap_is_empty(&src_matches)) + if (ebitmap_is_empty(&src_matches)) { + rc = 0; goto exit; + } rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]); - if (rc) + if (rc < 0) goto oom; - if (avrule->flags == RULE_SELF) { - rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], - &p->attr_type_map[k->target_type - 1]); - if (rc) - goto oom; - rc = ebitmap_and(&self_matches, &avrule->stypes.types, &matches); - if (rc) + if (is_avrule_self) { + rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]); + if (rc < 0) goto oom; if (!ebitmap_is_empty(&self_matches)) { rc = ebitmap_union(&tgt_matches, &self_matches); - if (rc) + if (rc < 0) goto oom; } } - if (ebitmap_is_empty(&tgt_matches)) + if (ebitmap_is_empty(&tgt_matches)) { + rc = 0; goto exit; + } - for (cp = avrule->perms; cp; cp = cp->next) { - if (cp->tclass != k->target_class) - continue; - ebitmap_for_each_positive_bit(&src_matches, snode, i) { - ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { - ret = check_assertion_extended_permissions_avtab( - avrule, avtab, i, j, k, p); - if (ret) - goto exit; + ebitmap_for_each_positive_bit(&src_matches, snode, i) { + ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { + if (is_avrule_self && i != j) + continue; + if (check_assertion_extended_permissions_avtab(avrule, avtab, i, j, k, p)) { + rc = 1; + goto exit; } } } - goto exit; -oom: - ERR(NULL, "Out of memory - unable to check neverallows"); + rc = 0; +oom: exit: ebitmap_destroy(&src_matches); ebitmap_destroy(&tgt_matches); - ebitmap_destroy(&matches); - return ret; + ebitmap_destroy(&self_matches); + return rc; +} + +static int check_assertion_self_match(avtab_key_t *k, avrule_t *avrule, policydb_t *p) +{ + ebitmap_t src_matches; + int rc; + + /* The key's target must match something in the matches of the avrule's source + * and the key's source. + */ + + rc = ebitmap_and(&src_matches, &avrule->stypes.types, &p->attr_type_map[k->source_type - 1]); + if (rc < 0) + goto oom; + + if (!ebitmap_match_any(&src_matches, &p->attr_type_map[k->target_type - 1])) { + rc = 0; + goto nomatch; + } + + rc = 1; + +oom: +nomatch: + ebitmap_destroy(&src_matches); + return rc; } static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args) { - int rc, rc2 = 0; + int rc; struct avtab_match_args *a = (struct avtab_match_args *)args; policydb_t *p = a->p; avrule_t *avrule = a->avrule; avtab_t *avtab = a->avtab; if ((k->specified & AVTAB_ALLOWED) == 0) - goto exit; + goto nomatch; if (!match_any_class_permissions(avrule->perms, k->target_class, d->data)) - goto exit; + goto nomatch; - rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]); - if (rc == 0) - goto exit; + if (!ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1])) + goto nomatch; - if (avrule->flags == RULE_SELF) { - /* If the neverallow uses SELF, then it is not enough that the - * neverallow's source matches the src and tgt of the rule being checked. - * It must match the same thing in the src and tgt, so AND the source - * and target together and check for a match on the result. - */ - ebitmap_t match; - rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] ); - if (rc) { - ebitmap_destroy(&match); - goto oom; + /* neverallow may have tgts even if it uses SELF */ + if (!ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1])) { + if (avrule->flags == RULE_SELF) { + rc = check_assertion_self_match(k, avrule, p); + if (rc < 0) + goto oom; + if (rc == 0) + goto nomatch; + } else { + goto nomatch; } - rc2 = ebitmap_match_any(&avrule->stypes.types, &match); - ebitmap_destroy(&match); } - /* neverallow may have tgts even if it uses SELF */ - rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]); - if (rc == 0 && rc2 == 0) - goto exit; - if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) { rc = check_assertion_extended_permissions(avrule, avtab, k, p); + if (rc < 0) + goto oom; if (rc == 0) - goto exit; + goto nomatch; } return 1; -exit: +nomatch: return 0; oom: - ERR(NULL, "Out of memory - unable to check neverallows"); return rc; } @@ -538,6 +553,10 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p, if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))) continue; rc = check_assertion(p, a); + if (rc < 0) { + ERR(handle, "Error occurred while checking neverallows"); + return -1; + } if (rc) { rc = report_assertion_failures(handle, p, a); if (rc < 0) { diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 46e1e75d7751fa014f0870ac404870f668890fc4..7920b60a3a430277456382251c5db2550117a66f 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -503,6 +503,11 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { + if (items >= items2) { /* items is index, items2 is total number */ + ERR(fp->handle, "entry has too many items (%d/%d)", + items + 1, items2); + return -1; + } key.specified = spec_order[i] | enabled; datum.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); @@ -543,7 +548,7 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && (key.specified & AVTAB_XPERMS)) { ERR(fp->handle, "policy version %u does not support extended " - "permissions rules and one was specified\n", vers); + "permissions rules and one was specified", vers); return -1; } else if (key.specified & AVTAB_XPERMS) { rc = next_entry(&buf8, fp, sizeof(uint8_t)); diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c index 037dc7e2fcee6eb6be3c0a78e23481f2b4db9cfa..a620451d8bc512b17c45dccd2c540ca98c244acd 100644 --- a/libsepol/src/conditional.c +++ b/libsepol/src/conditional.c @@ -25,6 +25,7 @@ #include #include "private.h" +#include "debug.h" /* move all type rules to top of t/f lists to help kernel on evaluation */ static void cond_optimize(cond_av_list_t ** l) @@ -314,8 +315,7 @@ static int evaluate_cond_node(policydb_t * p, cond_node_t * node) if (new_state != node->cur_state) { node->cur_state = new_state; if (new_state == -1) - printf - ("expression result was undefined - disabling all rules.\n"); + WARN(NULL, "expression result was undefined - disabling all rules."); /* turn the rules on or off */ for (cur = node->true_list; cur != NULL; cur = cur->next) { if (new_state <= 0) { @@ -368,8 +368,7 @@ int cond_normalize_expr(policydb_t * p, cond_node_t * cn) if (ne) { ne->next = NULL; } else { /* ne should never be NULL */ - printf - ("Found expr with no bools and only a ! - this should never happen.\n"); + ERR(NULL, "Found expr with no bools and only a ! - this should never happen."); return -1; } /* swap the true and false lists */ @@ -421,9 +420,8 @@ int cond_normalize_expr(policydb_t * p, cond_node_t * cn) } k = cond_evaluate_expr(p, cn->expr); if (k == -1) { - printf - ("While testing expression, expression result " - "was undefined - this should never happen.\n"); + ERR(NULL, "While testing expression, expression result " + "was undefined - this should never happen."); return -1; } /* set the bit if expression evaluates true */ @@ -524,7 +522,7 @@ int cond_init_bool_indexes(policydb_t * p) if (p->bool_val_to_struct) free(p->bool_val_to_struct); p->bool_val_to_struct = (cond_bool_datum_t **) - malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *)); + calloc(p->p_bools.nprim, sizeof(cond_bool_datum_t *)); if (!p->bool_val_to_struct) return -1; return 0; @@ -635,9 +633,8 @@ static int cond_insertf(avtab_t * a */ if (k->specified & AVTAB_TYPE) { if (avtab_search(&p->te_avtab, k)) { - printf - ("security: type rule already exists outside of a conditional."); - goto err; + WARN(NULL, "security: type rule already exists outside of a conditional."); + return -1; } /* * If we are reading the false list other will be a pointer to @@ -652,9 +649,8 @@ static int cond_insertf(avtab_t * a if (node_ptr) { if (avtab_search_node_next (node_ptr, k->specified)) { - printf - ("security: too many conflicting type rules."); - goto err; + ERR(NULL, "security: too many conflicting type rules."); + return -1; } found = 0; for (cur = other; cur != NULL; cur = cur->next) { @@ -664,30 +660,28 @@ static int cond_insertf(avtab_t * a } } if (!found) { - printf - ("security: conflicting type rules.\n"); - goto err; + ERR(NULL, "security: conflicting type rules."); + return -1; } } } else { if (avtab_search(&p->te_cond_avtab, k)) { - printf - ("security: conflicting type rules when adding type rule for true.\n"); - goto err; + ERR(NULL, "security: conflicting type rules when adding type rule for true."); + return -1; } } } node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); if (!node_ptr) { - printf("security: could not insert rule."); - goto err; + ERR(NULL, "security: could not insert rule."); + return -1; } node_ptr->parse_context = (void *)1; list = malloc(sizeof(cond_av_list_t)); if (!list) - goto err; + return -1; memset(list, 0, sizeof(cond_av_list_t)); list->node = node_ptr; @@ -697,11 +691,6 @@ static int cond_insertf(avtab_t * a data->tail->next = list; data->tail = list; return 0; - - err: - cond_av_list_destroy(data->head); - data->head = NULL; - return -1; } static int cond_read_av_list(policydb_t * p, void *fp, @@ -730,8 +719,10 @@ static int cond_read_av_list(policydb_t * p, void *fp, for (i = 0; i < len; i++) { rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data); - if (rc) + if (rc) { + cond_av_list_destroy(data.head); return rc; + } } @@ -742,14 +733,12 @@ static int cond_read_av_list(policydb_t * p, void *fp, static int expr_isvalid(policydb_t * p, cond_expr_t * expr) { if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { - printf - ("security: conditional expressions uses unknown operator.\n"); + WARN(NULL, "security: conditional expressions uses unknown operator."); return 0; } if (expr->bool > p->p_bools.nprim) { - printf - ("security: conditional expressions uses unknown bool.\n"); + WARN(NULL, "security: conditional expressions uses unknown bool."); return 0; } return 1; diff --git a/libsepol/src/context.c b/libsepol/src/context.c index e81b28c61a8f011ba2eb4d80b0a0126b2a4fddef..5cc90afbfa1c080f3a8658b1dc2d92905cb537b8 100644 --- a/libsepol/src/context.c +++ b/libsepol/src/context.c @@ -22,7 +22,7 @@ int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c) int sepol_check_context(const char *context) { - return sepol_context_to_sid((const sepol_security_context_t)context, + return sepol_context_to_sid(context, strlen(context) + 1, NULL); } diff --git a/libsepol/src/context_record.c b/libsepol/src/context_record.c index 435f788058c47ace0200a0492452a1c6f8467f61..2bda121b539ce0f252b5be93de0da41963a16624 100644 --- a/libsepol/src/context_record.c +++ b/libsepol/src/context_record.c @@ -127,7 +127,7 @@ int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr) (sepol_context_t *) malloc(sizeof(sepol_context_t)); if (!con) { - ERR(handle, "out of memory, could not " "create context\n"); + ERR(handle, "out of memory, could not create context"); return STATUS_ERR; } diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c index 1de3816aec18fa7095641599ea87e369ac9a4f76..bd98c0f8cbea0e1063638420ebc92a064b783d4a 100644 --- a/libsepol/src/ebitmap.c +++ b/libsepol/src/ebitmap.c @@ -406,8 +406,7 @@ int ebitmap_read(ebitmap_t * e, void *fp) count = le32_to_cpu(buf[2]); if (mapsize != MAPSIZE) { - printf - ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n", + ERR(NULL, "security: ebitmap: map size %d does not match my size %zu (high bit was %d)", mapsize, MAPSIZE, e->highbit); goto bad; } @@ -416,8 +415,7 @@ int ebitmap_read(ebitmap_t * e, void *fp) goto ok; } if (e->highbit & (MAPSIZE - 1)) { - printf - ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n", + ERR(NULL, "security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)", e->highbit, MAPSIZE); goto bad; } @@ -429,12 +427,12 @@ int ebitmap_read(ebitmap_t * e, void *fp) for (i = 0; i < count; i++) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { - printf("security: ebitmap: truncated map\n"); + ERR(NULL, "security: ebitmap: truncated map"); goto bad; } n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t)); if (!n) { - printf("security: ebitmap: out of memory\n"); + ERR(NULL, "security: ebitmap: out of memory"); rc = -ENOMEM; goto bad; } @@ -443,34 +441,30 @@ int ebitmap_read(ebitmap_t * e, void *fp) n->startbit = le32_to_cpu(buf[0]); if (n->startbit & (MAPSIZE - 1)) { - printf - ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n", + ERR(NULL, "security: ebitmap start bit (%d) is not a multiple of the map size (%zu)", n->startbit, MAPSIZE); goto bad_free; } if (n->startbit > (e->highbit - MAPSIZE)) { - printf - ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n", + ERR(NULL, "security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)", n->startbit, (e->highbit - MAPSIZE)); goto bad_free; } rc = next_entry(&map, fp, sizeof(uint64_t)); if (rc < 0) { - printf("security: ebitmap: truncated map\n"); + ERR(NULL, "security: ebitmap: truncated map"); goto bad_free; } n->map = le64_to_cpu(map); if (!n->map) { - printf - ("security: ebitmap: null map in ebitmap (startbit %d)\n", + ERR(NULL, "security: ebitmap: null map in ebitmap (startbit %d)", n->startbit); goto bad_free; } if (l) { if (n->startbit <= l->startbit) { - printf - ("security: ebitmap: start bit %d comes after start bit %d\n", + ERR(NULL, "security: ebitmap: start bit %d comes after start bit %d", n->startbit, l->startbit); goto bad_free; } @@ -481,8 +475,7 @@ int ebitmap_read(ebitmap_t * e, void *fp) l = n; } if (count && l->startbit + MAPSIZE != e->highbit) { - printf - ("security: ebitmap: high bit %u has not the expected value %zu\n", + ERR(NULL, "security: ebitmap: high bit %u has not the expected value %zu", e->highbit, l->startbit + MAPSIZE); goto bad; } diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index a6a466f78ee410aaf43b16fe5fa4e6240770f082..8d19850eed5dfe490731996f66c509151f1858cb 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -166,7 +166,7 @@ static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum, if (new_type->flags & TYPE_FLAGS_PERMISSIVE) if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) { - ERR(state->handle, "Out of memory!\n"); + ERR(state->handle, "Out of memory!"); return -1; } @@ -929,11 +929,15 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, if (!sl->sens) return 0; + /* Invalid sensitivity */ + if (sl->sens > p->p_levels.nprim || !p->p_sens_val_to_name[sl->sens - 1]) + return -1; + l->sens = sl->sens; levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, p->p_sens_val_to_name[l->sens - 1]); if (!levdatum) { - ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n", + ERR(h, "%s: Impossible situation found, nothing in p_levels.table.", __func__); errno = ENOENT; return -1; @@ -1403,6 +1407,40 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) return 0; } +static int expand_filename_trans_helper(expand_state_t *state, + filename_trans_rule_t *rule, + unsigned int s, unsigned int t) +{ + uint32_t mapped_otype, present_otype; + int rc; + + mapped_otype = state->typemap[rule->otype - 1]; + + rc = policydb_filetrans_insert( + state->out, s + 1, t + 1, + rule->tclass, rule->name, + NULL, mapped_otype, &present_otype + ); + if (rc == SEPOL_EEXIST) { + /* duplicate rule, ignore */ + if (present_otype == mapped_otype) + return 0; + + ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s", + state->out->p_type_val_to_name[s], + state->out->p_type_val_to_name[t], + state->out->p_class_val_to_name[rule->tclass - 1], + rule->name, + state->out->p_type_val_to_name[present_otype - 1], + state->out->p_type_val_to_name[mapped_otype - 1]); + return -1; + } else if (rc < 0) { + ERR(state->handle, "Out of memory!"); + return -1; + } + return 0; +} + static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) { unsigned int i, j; @@ -1413,8 +1451,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r cur_rule = rules; while (cur_rule) { - uint32_t mapped_otype, present_otype; - ebitmap_init(&stypes); ebitmap_init(&ttypes); @@ -1430,32 +1466,21 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r return -1; } - mapped_otype = state->typemap[cur_rule->otype - 1]; ebitmap_for_each_positive_bit(&stypes, snode, i) { ebitmap_for_each_positive_bit(&ttypes, tnode, j) { - rc = policydb_filetrans_insert( - state->out, i + 1, j + 1, - cur_rule->tclass, cur_rule->name, - NULL, mapped_otype, &present_otype + rc = expand_filename_trans_helper( + state, cur_rule, i, j ); - if (rc == SEPOL_EEXIST) { - /* duplicate rule, ignore */ - if (present_otype == mapped_otype) - continue; - - ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s", - state->out->p_type_val_to_name[i], - state->out->p_type_val_to_name[j], - state->out->p_class_val_to_name[cur_rule->tclass - 1], - cur_rule->name, - state->out->p_type_val_to_name[present_otype - 1], - state->out->p_type_val_to_name[mapped_otype - 1]); - return -1; - } else if (rc < 0) { - ERR(state->handle, "Out of memory!"); - return -1; - } + if (rc) + return rc; + } + if (cur_rule->flags & RULE_SELF) { + rc = expand_filename_trans_helper( + state, cur_rule, i, i + ); + if (rc) + return rc; } } @@ -1690,7 +1715,7 @@ static int expand_terule_helper(sepol_handle_t * handle, uint32_t oldtype = 0; if (!(specified & (AVRULE_TRANSITION|AVRULE_MEMBER|AVRULE_CHANGE))) { - ERR(handle, "Invalid specification: %"PRIu32"\n", specified); + ERR(handle, "Invalid specification: %"PRIu32, specified); return EXPAND_RULE_ERROR; } @@ -1869,7 +1894,7 @@ static int expand_avrule_helper(sepol_handle_t * handle, return EXPAND_RULE_ERROR; break; default: - ERR(handle, "Unknown specification: %"PRIu32"\n", specified); + ERR(handle, "Unknown specification: %"PRIu32, specified); return EXPAND_RULE_ERROR; } @@ -2477,7 +2502,7 @@ int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t /* if role is to be complimented, invert the entire bitmap here */ if (x->flags & ROLE_COMP) { - for (i = 0; i < ebitmap_length(r); i++) { + for (i = 0; i < p->p_roles.nprim; i++) { if (ebitmap_get_bit(r, i)) { if (ebitmap_set_bit(r, i, 0)) return -1; @@ -2966,6 +2991,9 @@ int expand_module(sepol_handle_t * handle, state.out->policy_type = POLICY_KERN; state.out->policyvers = POLICYDB_VERSION_MAX; + if (state.base->name) { + state.out->name = strdup(state.base->name); + } /* Copy mls state from base to out */ out->mls = base->mls; @@ -3146,17 +3174,15 @@ int expand_module(sepol_handle_t * handle, goto cleanup; /* Build the type<->attribute maps and remove attributes. */ - state.out->attr_type_map = malloc(state.out->p_types.nprim * + state.out->attr_type_map = calloc(state.out->p_types.nprim, sizeof(ebitmap_t)); - state.out->type_attr_map = malloc(state.out->p_types.nprim * + state.out->type_attr_map = calloc(state.out->p_types.nprim, sizeof(ebitmap_t)); if (!state.out->attr_type_map || !state.out->type_attr_map) { ERR(handle, "Out of memory!"); goto cleanup; } for (i = 0; i < state.out->p_types.nprim; i++) { - ebitmap_init(&state.out->type_attr_map[i]); - ebitmap_init(&state.out->attr_type_map[i]); /* add the type itself as the degenerate case */ if (ebitmap_set_bit(&state.out->type_attr_map[i], i, 1)) { ERR(handle, "Out of memory!"); diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c index 21143b7699c08c2931d4a48e0977ad0dcbf72d42..922a8a4af3ea4f4ded15383311568f6cd41a96d8 100644 --- a/libsepol/src/hashtab.c +++ b/libsepol/src/hashtab.c @@ -32,6 +32,8 @@ #include #include +#include "private.h" + hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, const_hashtab_key_t key), int (*keycmp) (hashtab_t h, @@ -41,7 +43,6 @@ hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, { hashtab_t p; - unsigned int i; p = (hashtab_t) malloc(sizeof(hashtab_val_t)); if (p == NULL) @@ -52,13 +53,11 @@ hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, p->nel = 0; p->hash_value = hash_value; p->keycmp = keycmp; - p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size); + p->htable = (hashtab_ptr_t *) calloc(size, sizeof(hashtab_ptr_t)); if (p->htable == NULL) { free(p); return NULL; } - for (i = 0; i < size; i++) - p->htable[i] = (hashtab_ptr_t) NULL; return p; } @@ -222,8 +221,9 @@ int hashtab_map(hashtab_t h, int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args) { - unsigned int i, ret; + unsigned int i; hashtab_ptr_t cur; + int ret; if (!h) return SEPOL_OK; diff --git a/libsepol/src/hierarchy.c b/libsepol/src/hierarchy.c index 8919daa79e77919c89629f45dd897cf3d541a562..350443a86aef93248323a687b31d136a521a1841 100644 --- a/libsepol/src/hierarchy.c +++ b/libsepol/src/hierarchy.c @@ -237,7 +237,7 @@ oom: ERR(handle, "Insufficient memory"); exit: - ERR(handle,"Failed to expand parent rules\n"); + ERR(handle,"Failed to expand parent rules"); avtab_destroy(global_avtab); bounds_destroy_cond_info(*cond_info); *cond_info = NULL; diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index 305567a5ef1e2b1c3438274571242f9c667ae39d..9128ac553315939b3a31dfec4901dec045a7f03e 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -190,6 +190,10 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr } if (!names) { names = strdup("NO_IDENTIFIER"); + if (!names) { + sepol_log_err("Out of memory"); + goto exit; + } } if (strchr(names, ' ')) { new_val = create_str("(%s %s (%s))", 3, op, attr1, names); @@ -278,10 +282,13 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey, char *expr = NULL; int is_mls; char *perms; - const char *format_str; + const char *key_word; struct strs *strs; for (curr = constraint_rules; curr != NULL; curr = curr->next) { + if (curr->permissions == 0) { + continue; + } expr = constraint_expr_to_str(pdb, curr->expr, &is_mls); if (!expr) { rc = -1; @@ -291,14 +298,14 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey, perms = sepol_av_to_string(pdb, class->s.value, curr->permissions); if (is_mls) { - format_str = "(mlsconstrain (%s (%s)) %s)"; + key_word = "mlsconstrain"; strs = mls_list; } else { - format_str = "(constrain (%s (%s)) %s)"; + key_word = "constrain"; strs = non_mls_list; } - rc = strs_create_and_add(strs, format_str, 3, classkey, perms+1, expr); + rc = strs_create_and_add(strs, "(%s (%s (%s)) %s)", 4, key_word, classkey, perms+1, expr); free(expr); if (rc != 0) { goto exit; @@ -319,7 +326,7 @@ static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classke struct constraint_node *curr; char *expr = NULL; int is_mls; - const char *format_str; + const char *key_word; struct strs *strs; int rc = 0; @@ -331,14 +338,14 @@ static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classke } if (is_mls) { - format_str = "(mlsvalidatetrans %s %s)"; + key_word = "mlsvalidatetrans"; strs = mls_list; } else { - format_str = "(validatetrans %s %s)"; + key_word = "validatetrans"; strs = non_mls_list; } - rc = strs_create_and_add(strs, format_str, 2, classkey, expr); + rc = strs_create_and_add(strs, "(%s %s %s)", 3, key_word, classkey, expr); free(expr); if (rc != 0) { goto exit; @@ -358,6 +365,7 @@ static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->constraints) { name = pdb->p_class_val_to_name[i]; rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs); @@ -383,6 +391,7 @@ static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_st for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->validatetrans) { name = pdb->p_class_val_to_name[i]; rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs); @@ -461,6 +470,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb) /* class */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; name = pdb->p_class_val_to_name[i]; perms = class_or_common_perms_to_str(&class->permissions); if (perms) { @@ -488,6 +498,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb) /* classcommon */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; name = pdb->p_class_val_to_name[i]; if (class->comkey != NULL) { sepol_printf(out, "(classcommon %s %s)\n", name, class->comkey); @@ -503,6 +514,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb) } for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; name = class->comkey; if (name != NULL) { common = hashtab_search(pdb->p_commons.table, name); @@ -560,6 +572,11 @@ static int write_sids_to_cil(FILE *out, const char *const *sid_to_str, } else { snprintf(unknown, 18, "%s%u", "UNKNOWN", i); sid = strdup(unknown); + if (!sid) { + sepol_log_err("Out of memory"); + rc = -1; + goto exit; + } } rc = strs_add_at_index(strs, sid, i); if (rc != 0) { @@ -727,6 +744,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb) /* default_user */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_user != 0) { rc = write_default_user_to_cil(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -738,6 +756,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb) /* default_role */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_role != 0) { rc = write_default_role_to_cil(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -749,6 +768,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb) /* default_type */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_type != 0) { rc = write_default_type_to_cil(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -764,6 +784,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb) /* default_range */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_range) { rc = write_default_range_to_cil(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -1035,7 +1056,6 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) struct ebitmap_node *node; uint32_t i, start, range; char *catsbuf = NULL, *p; - const char *fmt; int len, remaining; remaining = (int)cats_ebitmap_len(cats, val_to_name); @@ -1063,9 +1083,15 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) continue; if (range > 1) { - fmt = (range == 2) ? "%s %s " : "(range %s %s) "; - len = snprintf(p, remaining, fmt, - val_to_name[start], val_to_name[i]); + if (range == 2) { + len = snprintf(p, remaining, "%s %s ", + val_to_name[start], + val_to_name[i]); + } else { + len = snprintf(p, remaining, "(range %s %s) ", + val_to_name[start], + val_to_name[i]); + } } else { len = snprintf(p, remaining, "%s ", val_to_name[start]); } @@ -1213,7 +1239,7 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_ATTRIB) { + if (type && type->flavor == TYPE_ATTRIB) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { goto exit; @@ -1343,7 +1369,7 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_TYPE && type->primary) { + if (type && type->flavor == TYPE_TYPE && type->primary) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { goto exit; @@ -1472,7 +1498,7 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_TYPE) { + if (type && type->flavor == TYPE_TYPE) { if (type->bounds > 0) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { @@ -1526,7 +1552,7 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { attr = pdb->type_val_to_struct[i]; - if (attr->flavor != TYPE_ATTRIB) continue; + if (!attr || attr->flavor != TYPE_ATTRIB) continue; name = pdb->p_type_val_to_name[i]; typemap = &pdb->attr_type_map[i]; if (ebitmap_is_empty(typemap)) continue; @@ -2259,7 +2285,7 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type_datum = pdb->type_val_to_struct[i]; - if (type_datum->flavor == TYPE_TYPE && type_datum->primary) { + if (type_datum && type_datum->flavor == TYPE_TYPE && type_datum->primary) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { goto exit; @@ -2383,6 +2409,7 @@ static int write_user_decl_rules_to_cil(FILE *out, struct policydb *pdb) } for (i=0; i < pdb->p_users.nprim; i++) { + if (!pdb->p_user_val_to_name[i]) continue; rc = strs_add(strs, pdb->p_user_val_to_name[i]); if (rc != 0) { goto exit; @@ -2640,6 +2667,8 @@ static int write_genfscon_rules_to_cil(FILE *out, struct policydb *pdb) struct ocontext *ocon; struct strs *strs; char *fstype, *name, *ctx; + uint32_t sclass; + const char *file_type; int rc; rc = strs_init(&strs, 32); @@ -2652,14 +2681,43 @@ static int write_genfscon_rules_to_cil(FILE *out, struct policydb *pdb) fstype = genfs->fstype; name = ocon->u.name; + sclass = ocon->v.sclass; + file_type = NULL; + if (sclass) { + const char *class_name = pdb->p_class_val_to_name[sclass-1]; + if (strcmp(class_name, "file") == 0) { + file_type = "file"; + } else if (strcmp(class_name, "dir") == 0) { + file_type = "dir"; + } else if (strcmp(class_name, "chr_file") == 0) { + file_type = "char"; + } else if (strcmp(class_name, "blk_file") == 0) { + file_type = "block"; + } else if (strcmp(class_name, "sock_file") == 0) { + file_type = "socket"; + } else if (strcmp(class_name, "fifo_file") == 0) { + file_type = "pipe"; + } else if (strcmp(class_name, "lnk_file") == 0) { + file_type = "symlink"; + } else { + rc = -1; + goto exit; + } + } + ctx = context_to_str(pdb, &ocon->context[0]); if (!ctx) { rc = -1; goto exit; } - rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s)", 3, - fstype, name, ctx); + if (file_type) { + rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s %s)", 4, + fstype, name, file_type, ctx); + } else { + rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s)", 3, + fstype, name, ctx); + } free(ctx); if (rc != 0) { goto exit; diff --git a/libsepol/src/kernel_to_common.c b/libsepol/src/kernel_to_common.c index a7453d3ce8268e958fc977bdd1ee27f545528c48..775703a922b60d0044b29b290397bb13b7114e39 100644 --- a/libsepol/src/kernel_to_common.c +++ b/libsepol/src/kernel_to_common.c @@ -18,6 +18,7 @@ #include #include +#include "private.h" #include "kernel_to_common.h" @@ -57,7 +58,7 @@ static char *create_str_helper(const char *fmt, int num, va_list vargs) va_list vargs2; char *str = NULL; char *s; - size_t len; + size_t len, s_len; int i, rc; va_copy(vargs2, vargs); @@ -66,7 +67,8 @@ static char *create_str_helper(const char *fmt, int num, va_list vargs) for (i=0; i 1 ? s_len - 2 : 0; /* -2 for each %s in fmt */ } str = malloc(len); @@ -106,6 +108,10 @@ int strs_init(struct strs **strs, size_t size) { struct strs *new; + if (size == 0) { + size = 1; + } + *strs = NULL; new = malloc(sizeof(struct strs)); @@ -114,7 +120,7 @@ int strs_init(struct strs **strs, size_t size) return -1; } - new->list = calloc(sizeof(char *), size); + new->list = calloc(size, sizeof(char *)); if (!new->list) { sepol_log_err("Out of memory"); free(new); @@ -159,9 +165,9 @@ int strs_add(struct strs *strs, char *s) { if (strs->num + 1 > strs->size) { char **new; - unsigned i = strs->size; + size_t i = strs->size; strs->size *= 2; - new = realloc(strs->list, sizeof(char *)*strs->size); + new = reallocarray(strs->list, strs->size, sizeof(char *)); if (!new) { sepol_log_err("Out of memory"); return -1; @@ -212,15 +218,15 @@ char *strs_remove_last(struct strs *strs) return strs->list[strs->num]; } -int strs_add_at_index(struct strs *strs, char *s, unsigned index) +int strs_add_at_index(struct strs *strs, char *s, size_t index) { if (index >= strs->size) { char **new; - unsigned i = strs->size; + size_t i = strs->size; while (index >= strs->size) { strs->size *= 2; } - new = realloc(strs->list, sizeof(char *)*strs->size); + new = reallocarray(strs->list, strs->size, sizeof(char *)); if (!new) { sepol_log_err("Out of memory"); return -1; @@ -237,7 +243,7 @@ int strs_add_at_index(struct strs *strs, char *s, unsigned index) return 0; } -char *strs_read_at_index(struct strs *strs, unsigned index) +char *strs_read_at_index(struct strs *strs, size_t index) { if (index >= strs->num) { return NULL; @@ -261,12 +267,12 @@ void strs_sort(struct strs *strs) qsort(strs->list, strs->num, sizeof(char *), strs_cmp); } -unsigned strs_num_items(struct strs *strs) +unsigned strs_num_items(const struct strs *strs) { return strs->num; } -size_t strs_len_items(struct strs *strs) +size_t strs_len_items(const struct strs *strs) { unsigned i; size_t len = 0; @@ -279,7 +285,7 @@ size_t strs_len_items(struct strs *strs) return len; } -char *strs_to_str(struct strs *strs) +char *strs_to_str(const struct strs *strs) { char *str = NULL; size_t len = 0; @@ -321,7 +327,7 @@ exit: return str; } -void strs_write_each(struct strs *strs, FILE *out) +void strs_write_each(const struct strs *strs, FILE *out) { unsigned i; @@ -333,7 +339,7 @@ void strs_write_each(struct strs *strs, FILE *out) } } -void strs_write_each_indented(struct strs *strs, FILE *out, int indent) +void strs_write_each_indented(const struct strs *strs, FILE *out, int indent) { unsigned i; @@ -354,13 +360,16 @@ int hashtab_ordered_to_strs(char *key, void *data, void *args) return strs_add_at_index(strs, key, datum->value-1); } -int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name) +int ebitmap_to_strs(const struct ebitmap *map, struct strs *strs, char **val_to_name) { struct ebitmap_node *node; uint32_t i; int rc; ebitmap_for_each_positive_bit(map, node, i) { + if (!val_to_name[i]) + continue; + rc = strs_add(strs, val_to_name[i]); if (rc != 0) { return -1; @@ -370,7 +379,7 @@ int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name) return 0; } -char *ebitmap_to_str(struct ebitmap *map, char **val_to_name, int sort) +char *ebitmap_to_str(const struct ebitmap *map, char **val_to_name, int sort) { struct strs *strs; char *str = NULL; @@ -418,7 +427,7 @@ char *strs_stack_pop(struct strs *stack) return strs_remove_last(stack); } -int strs_stack_empty(struct strs *stack) +int strs_stack_empty(const struct strs *stack) { return strs_num_items(stack) == 0; } diff --git a/libsepol/src/kernel_to_common.h b/libsepol/src/kernel_to_common.h index 8aa483fac70bc16aed5381ac18a50b91a3cf67ff..159c4289e929ed73546836710cbe71e9d98fcf1b 100644 --- a/libsepol/src/kernel_to_common.h +++ b/libsepol/src/kernel_to_common.h @@ -99,22 +99,22 @@ int strs_add(struct strs *strs, char *s); __attribute__ ((format(printf, 2, 4))) int strs_create_and_add(struct strs *strs, const char *fmt, int num, ...); char *strs_remove_last(struct strs *strs); -int strs_add_at_index(struct strs *strs, char *s, unsigned index); -char *strs_read_at_index(struct strs *strs, unsigned index); +int strs_add_at_index(struct strs *strs, char *s, size_t index); +char *strs_read_at_index(struct strs *strs, size_t index); void strs_sort(struct strs *strs); -unsigned strs_num_items(struct strs *strs); -size_t strs_len_items(struct strs *strs); -char *strs_to_str(struct strs *strs); -void strs_write_each(struct strs *strs, FILE *out); -void strs_write_each_indented(struct strs *strs, FILE *out, int indent); +unsigned strs_num_items(const struct strs *strs); +size_t strs_len_items(const struct strs *strs); +char *strs_to_str(const struct strs *strs); +void strs_write_each(const struct strs *strs, FILE *out); +void strs_write_each_indented(const struct strs *strs, FILE *out, int indent); int hashtab_ordered_to_strs(char *key, void *data, void *args); -int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name); -char *ebitmap_to_str(struct ebitmap *map, char **val_to_name, int sort); +int ebitmap_to_strs(const struct ebitmap *map, struct strs *strs, char **val_to_name); +char *ebitmap_to_str(const struct ebitmap *map, char **val_to_name, int sort); int strs_stack_init(struct strs **stack); void strs_stack_destroy(struct strs **stack); int strs_stack_push(struct strs *stack, char *s); char *strs_stack_pop(struct strs *stack); -int strs_stack_empty(struct strs *stack); +int strs_stack_empty(const struct strs *stack); int sort_ocontexts(struct policydb *pdb); diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index eb72e4ac983e09d6a31cb073d74fce3a563a3176..63dffd9b47f0ff565b235b8f977b23b16fa20f43 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -187,6 +187,10 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr } if (!names) { names = strdup("NO_IDENTIFIER"); + if (!names) { + sepol_log_err("Out of memory"); + goto exit; + } } if (strchr(names, ' ')) { new_val = create_str("%s %s { %s }", 3, attr1, op, names); @@ -271,12 +275,15 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey, { struct constraint_node *curr; struct strs *strs; - const char *format_str, *flavor; + const char *flavor, *perm_prefix, *perm_suffix; char *perms, *expr; int is_mls; int rc = 0; for (curr = constraint_rules; curr != NULL; curr = curr->next) { + if (curr->permissions == 0) { + continue; + } expr = constraint_expr_to_str(pdb, curr->expr, &is_mls); if (!expr) { rc = -1; @@ -285,9 +292,11 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey, perms = sepol_av_to_string(pdb, class->s.value, curr->permissions); if (strchr(perms, ' ')) { - format_str = "%s %s { %s } %s;"; + perm_prefix = "{ "; + perm_suffix = " }"; } else { - format_str = "%s %s %s %s"; + perm_prefix = ""; + perm_suffix = ""; } if (is_mls) { flavor = "mlsconstrain"; @@ -297,8 +306,10 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey, strs = non_mls_list; } - rc = strs_create_and_add(strs, format_str, 4, - flavor, classkey, perms+1, expr); + rc = strs_create_and_add(strs, "%s %s %s%s%s %s;", 6, + flavor, classkey, + perm_prefix, perms+1, perm_suffix, + expr); free(expr); if (rc != 0) { goto exit; @@ -358,7 +369,7 @@ static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; - if (class->constraints) { + if (class && class->constraints) { name = pdb->p_class_val_to_name[i]; rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs); if (rc != 0) { @@ -383,7 +394,7 @@ static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_st for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; - if (class->validatetrans) { + if (class && class->validatetrans) { name = pdb->p_class_val_to_name[i]; rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs); if (rc != 0) { @@ -551,6 +562,7 @@ static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb) } for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; name = class->comkey; if (!name) continue; common = hashtab_search(pdb->p_commons.table, name); @@ -577,6 +589,7 @@ static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb) /* class */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; name = pdb->p_class_val_to_name[i]; sepol_printf(out, "class %s", name); if (class->comkey) { @@ -702,6 +715,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb) /* default_user */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_user != 0) { rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -713,6 +727,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb) /* default_role */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_role != 0) { rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -724,6 +739,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb) /* default_type */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_type != 0) { rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -739,6 +755,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb) /* default_range */ for (i=0; i < pdb->p_classes.nprim; i++) { class = pdb->class_val_to_struct[i]; + if (!class) continue; if (class->default_range != 0) { rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class); if (rc != 0) { @@ -908,7 +925,7 @@ static int write_category_rules_to_conf(FILE *out, struct policydb *pdb) unsigned i, j, num; int rc = 0; - rc = strs_init(&strs, pdb->p_levels.nprim); + rc = strs_init(&strs, pdb->p_cats.nprim); if (rc != 0) { goto exit; } @@ -1026,7 +1043,6 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) struct ebitmap_node *node; uint32_t i, start, range, first; char *catsbuf = NULL, *p; - const char *fmt; char sep; int len, remaining; @@ -1054,12 +1070,12 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) if (range > 1) { sep = (range == 2) ? ',' : '.'; - fmt = first ? "%s%c%s" : ",%s%c%s"; - len = snprintf(p, remaining, fmt, + len = snprintf(p, remaining, "%s%s%c%s", + first ? "" : ",", val_to_name[start], sep, val_to_name[i]); } else { - fmt = first ? "%s" : ",%s"; - len = snprintf(p, remaining, fmt, val_to_name[start]); + len = snprintf(p, remaining, "%s%s", first ? "" : ",", + val_to_name[start]); } if (len < 0 || len >= remaining) { @@ -1201,7 +1217,7 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_ATTRIB) { + if (type && type->flavor == TYPE_ATTRIB) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { goto exit; @@ -1331,7 +1347,7 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_TYPE && type->primary) { + if (type && type->flavor == TYPE_TYPE && type->primary) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { goto exit; @@ -1451,7 +1467,7 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor == TYPE_TYPE) { + if (type && type->flavor == TYPE_TYPE) { if (type->bounds > 0) { rc = strs_add(strs, pdb->p_type_val_to_name[i]); if (rc != 0) { @@ -1574,7 +1590,7 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb) for (i=0; i < pdb->p_types.nprim; i++) { type = pdb->type_val_to_struct[i]; - if (type->flavor != TYPE_TYPE || !type->primary) continue; + if (!type || type->flavor != TYPE_TYPE || !type->primary) continue; if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue; rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]); @@ -2318,6 +2334,7 @@ static int write_user_decl_rules_to_conf(FILE *out, struct policydb *pdb) } for (i=0; i < pdb->p_users.nprim; i++) { + if (!pdb->p_user_val_to_name[i]) continue; rc = strs_add(strs, pdb->p_user_val_to_name[i]); if (rc != 0) { goto exit; @@ -2513,6 +2530,8 @@ static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb) struct ocontext *ocon; struct strs *strs; char *fstype, *name, *ctx; + uint32_t sclass; + const char *file_type; int rc; rc = strs_init(&strs, 32); @@ -2525,14 +2544,43 @@ static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb) fstype = genfs->fstype; name = ocon->u.name; + sclass = ocon->v.sclass; + file_type = NULL; + if (sclass) { + const char *class_name = pdb->p_class_val_to_name[sclass-1]; + if (strcmp(class_name, "file") == 0) { + file_type = "--"; + } else if (strcmp(class_name, "dir") == 0) { + file_type = "-d"; + } else if (strcmp(class_name, "chr_file") == 0) { + file_type = "-c"; + } else if (strcmp(class_name, "blk_file") == 0) { + file_type = "-b"; + } else if (strcmp(class_name, "sock_file") == 0) { + file_type = "-s"; + } else if (strcmp(class_name, "fifo_file") == 0) { + file_type = "-p"; + } else if (strcmp(class_name, "lnk_file") == 0) { + file_type = "-l"; + } else { + rc = -1; + goto exit; + } + } + ctx = context_to_str(pdb, &ocon->context[0]); if (!ctx) { rc = -1; goto exit; } - rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s", 3, - fstype, name, ctx); + if (file_type) { + rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s %s", 4, + fstype, name, file_type, ctx); + } else { + rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s", 3, + fstype, name, ctx); + } free(ctx); if (rc != 0) { goto exit; diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in index 0e05d606478945e93e6bf0ad8248349cc4e06435..844924fc866ea08309cb05c38cfaee3e7ff8d699 100644 --- a/libsepol/src/libsepol.map.in +++ b/libsepol/src/libsepol.map.in @@ -274,3 +274,18 @@ LIBSEPOL_3.0 { cil_write_resolve_ast; cil_set_qualified_names; } LIBSEPOL_1.1; + +LIBSEPOL_3.4 { + global: + sepol_av_perm_to_string; + sepol_change_sid; + sepol_compute_av; + sepol_compute_av_reason; + sepol_compute_av_reason_buffer; + sepol_context_to_sid; + sepol_member_sid; + sepol_sid_to_context; + sepol_string_to_av_perm; + sepol_string_to_security_class; + sepol_validate_transition_reason_buffer; +} LIBSEPOL_3.0; diff --git a/libsepol/src/link.c b/libsepol/src/link.c index 7512a4d927f9afec26444f18b3f4389c9a3102a2..7e8313cbc3912a9047f9e7a0889e3a4f0674d3b2 100644 --- a/libsepol/src/link.c +++ b/libsepol/src/link.c @@ -34,6 +34,7 @@ #include #include "debug.h" +#include "private.h" #undef min #define min(a,b) (((a) < (b)) ? (a) : (b)) @@ -164,7 +165,7 @@ static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum, (hashtab_datum_t) new_perm); if (ret) { ERR(state->handle, - "could not insert permission into class\n"); + "could not insert permission into class"); goto err; } new_perm->s.value = dest_class->permissions.nprim + 1; @@ -190,8 +191,9 @@ static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum, ERR(state->handle, "Out of memory!"); return -1; } - memcpy(newmap, mod->perm_map[sclassi], - mod->perm_map_len[sclassi] * sizeof(*newmap)); + if (mod->perm_map_len[sclassi] > 0) { + memcpy(newmap, mod->perm_map[sclassi], mod->perm_map_len[sclassi] * sizeof(*newmap)); + } free(mod->perm_map[sclassi]); mod->perm_map[sclassi] = newmap; mod->perm_map_len[sclassi] = perm->s.value; @@ -287,7 +289,7 @@ static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum, new_class = (class_datum_t *) calloc(1, sizeof(class_datum_t)); if (new_class == NULL) { - ERR(state->handle, "Memory error\n"); + ERR(state->handle, "Memory error"); ret = SEPOL_ERR; goto err; } @@ -298,7 +300,7 @@ static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum, } new_id = strdup(id); if (new_id == NULL) { - ERR(state->handle, "Memory error\n"); + ERR(state->handle, "Memory error"); symtab_destroy(&new_class->permissions); ret = SEPOL_ERR; goto err; @@ -694,7 +696,7 @@ static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum, return SEPOL_ENOTSUP; } else { ERR(state->handle, - "%s: has an unknown scope: %d\n", + "%s: has an unknown scope: %d", state->cur_mod_name, scope->scope); return SEPOL_ENOTSUP; } @@ -736,7 +738,7 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum, } else { /* unknown scope? malformed policy? */ ERR(state->handle, - "%s: has an unknown scope: %d\n", + "%s: has an unknown scope: %d", state->cur_mod_name, scope->scope); return SEPOL_ENOTSUP; } @@ -1480,6 +1482,7 @@ static int copy_filename_trans_list(filename_trans_rule_t * list, new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1]; new_rule->otype = module->map[SYM_TYPES][cur->otype - 1]; + new_rule->flags = cur->flags; cur = cur->next; } @@ -1679,14 +1682,10 @@ static int copy_scope_index(scope_index_t * src, scope_index_t * dest, } /* next copy the enabled permissions data */ - if ((dest->class_perms_map = malloc(largest_mapped_class_value * - sizeof(*dest->class_perms_map))) == - NULL) { + if ((dest->class_perms_map = calloc(largest_mapped_class_value, + sizeof(*dest->class_perms_map))) == NULL) { goto cleanup; } - for (i = 0; i < largest_mapped_class_value; i++) { - ebitmap_init(dest->class_perms_map + i); - } dest->class_perms_len = largest_mapped_class_value; for (i = 0; i < src->class_perms_len; i++) { ebitmap_t *srcmap = src->class_perms_map + i; @@ -1779,7 +1778,7 @@ static int copy_avrule_block(link_state_t * state, policy_module_t * module, if (module->policy->name != NULL) { new_decl->module_name = strdup(module->policy->name); if (new_decl->module_name == NULL) { - ERR(state->handle, "Out of memory\n"); + ERR(state->handle, "Out of memory"); avrule_decl_destroy(new_decl); ret = -1; goto cleanup; @@ -2206,7 +2205,7 @@ static int enable_avrules(link_state_t * state, policydb_t * pol) if (state->verbose) { const char *mod_name = decl->module_name ? decl->module_name : "BASE"; - INFO(state->handle, "check module %s decl %d\n", + INFO(state->handle, "check module %s decl %d", mod_name, decl->decl_id); } rc = is_decl_requires_met(state, decl, &req); @@ -2552,7 +2551,7 @@ int link_modules(sepol_handle_t * handle, if (mods[i]->policyvers > b->policyvers) { WARN(state.handle, - "Upgrading policy version from %u to %u\n", b->policyvers, mods[i]->policyvers); + "Upgrading policy version from %u to %u", b->policyvers, mods[i]->policyvers); b->policyvers = mods[i]->policyvers; } diff --git a/libsepol/src/mls.c b/libsepol/src/mls.c index 366a1114ce964db57e7156f128f446138bc86398..4ffe98142ca38d588bae2fc510c2b0fb8af524f2 100644 --- a/libsepol/src/mls.c +++ b/libsepol/src/mls.c @@ -451,7 +451,7 @@ int mls_context_to_sid(const policydb_t * policydb, * Copies the MLS range from `src' into `dst'. */ static inline int mls_copy_context(context_struct_t * dst, - context_struct_t * src) + const context_struct_t * src) { int l, rc = 0; @@ -471,7 +471,7 @@ static inline int mls_copy_context(context_struct_t * dst, * Copies the effective MLS range from `src' into `dst'. */ static inline int mls_scopy_context(context_struct_t * dst, - context_struct_t * src) + const context_struct_t * src) { int l, rc = 0; @@ -490,7 +490,7 @@ static inline int mls_scopy_context(context_struct_t * dst, /* * Copies the MLS range `range' into `context'. */ -static inline int mls_range_set(context_struct_t * context, mls_range_t * range) +static inline int mls_range_set(context_struct_t * context, const mls_range_t * range) { int l, rc = 0; @@ -601,8 +601,8 @@ int mls_convert_context(policydb_t * oldp, } int mls_compute_sid(policydb_t * policydb, - context_struct_t * scontext, - context_struct_t * tcontext, + const context_struct_t * scontext, + const context_struct_t * tcontext, sepol_security_class_t tclass, uint32_t specified, context_struct_t * newcontext) { @@ -755,9 +755,10 @@ void mls_semantic_level_destroy(mls_semantic_level_t * l) } int mls_semantic_level_cpy(mls_semantic_level_t * dst, - mls_semantic_level_t * src) + const mls_semantic_level_t * src) { - mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL; + const mls_semantic_cat_t *cat; + mls_semantic_cat_t *newcat, *lnewcat = NULL; mls_semantic_level_init(dst); dst->sens = src->sens; @@ -800,7 +801,7 @@ void mls_semantic_range_destroy(mls_semantic_range_t * r) } int mls_semantic_range_cpy(mls_semantic_range_t * dst, - mls_semantic_range_t * src) + const mls_semantic_range_t * src) { if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0) return -1; diff --git a/libsepol/src/mls.h b/libsepol/src/mls.h index 5ca3cd51c1adea8d1e39129dab86de1dde930337..eb4a1cb8b5228801e4d3ea4fbbd38d53bf636ae8 100644 --- a/libsepol/src/mls.h +++ b/libsepol/src/mls.h @@ -56,8 +56,8 @@ extern int mls_convert_context(policydb_t * oldp, policydb_t * newp, context_struct_t * context); extern int mls_compute_sid(policydb_t * policydb, - context_struct_t * scontext, - context_struct_t * tcontext, + const context_struct_t * scontext, + const context_struct_t * tcontext, sepol_security_class_t tclass, uint32_t specified, context_struct_t * newcontext); diff --git a/libsepol/src/module.c b/libsepol/src/module.c index 02a5de2ca5dd04606e3eb504b004a49be76c3bee..5246a59912d910790163132ae9122a5bc3986a73 100644 --- a/libsepol/src/module.c +++ b/libsepol/src/module.c @@ -293,11 +293,14 @@ static int link_netfilter_contexts(sepol_module_package_t * base, } base->netfilter_contexts = base_context; for (i = 0; i < num_modules; i++) { - memcpy(base->netfilter_contexts + base->netfilter_contexts_len, - modules[i]->netfilter_contexts, - modules[i]->netfilter_contexts_len); - base->netfilter_contexts_len += - modules[i]->netfilter_contexts_len; + if (modules[i]->netfilter_contexts_len > 0) { + memcpy(base->netfilter_contexts + base->netfilter_contexts_len, + modules[i]->netfilter_contexts, + modules[i]->netfilter_contexts_len); + base->netfilter_contexts_len += + modules[i]->netfilter_contexts_len; + } + } return 0; } @@ -406,14 +409,14 @@ static int module_package_read_offsets(sepol_module_package_t * mod, goto err; } - off = (size_t *) malloc((nsec + 1) * sizeof(size_t)); + off = (size_t *) calloc(nsec + 1, sizeof(size_t)); if (!off) { ERR(file->handle, "out of memory"); goto err; } free(buf); - buf = malloc(sizeof(uint32_t) * nsec); + buf = calloc(nsec, sizeof(uint32_t)); if (!buf) { ERR(file->handle, "out of memory"); goto err; diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c index 16e4004e3ae8670179c82a88e02173b355ad6693..b35bf055f07368d986e4dad27a7f705a08ead1a3 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -393,6 +393,8 @@ static int typealias_list_create(struct policydb *pdb) } typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists)); + if (!typealias_lists) + goto exit; typealias_lists_len = max_decl_id + 1; rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb); @@ -430,7 +432,7 @@ static int stack_init(struct stack **stack) goto exit; } - s->stack = malloc(sizeof(*s->stack) * STACK_SIZE); + s->stack = calloc(STACK_SIZE, sizeof(*s->stack)); if (s->stack == NULL) { goto exit; } @@ -453,7 +455,7 @@ static int stack_push(struct stack *stack, void *ptr) void *new_stack; if (stack->pos + 1 == stack->size) { - new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2)); + new_stack = reallocarray(stack->stack, stack->size * 2, sizeof(*stack->stack)); if (new_stack == NULL) { goto exit; } @@ -1008,7 +1010,7 @@ static int ebitmap_to_names(struct ebitmap *map, char **vals_to_names, char ***n goto exit; } - name_arr = malloc(sizeof(*name_arr) * num); + name_arr = calloc(num, sizeof(*name_arr)); if (name_arr == NULL) { log_err("Out of memory"); rc = -1; @@ -1259,7 +1261,7 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr * char *val2 = NULL; unsigned int num_params; const char *op; - const char *fmt_str; + const char *sep; const char *type; rc = stack_init(&stack); @@ -1308,11 +1310,11 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr * rc = -1; goto exit; } - fmt_str = "(%s %s)"; + sep = ""; } else { val2 = stack_pop(stack); val1 = stack_pop(stack); - fmt_str = "(%s %s %s)"; + sep = " "; } if (val1 == NULL || val2 == NULL) { @@ -1334,10 +1336,7 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr * goto exit; } - // although we always supply val2 and there isn't always a 2nd - // value, it should only be used when there are actually two values - // in the format strings - rlen = snprintf(new_val, len, fmt_str, op, val1, val2); + rlen = snprintf(new_val, len, "(%s %s%s%s)", op, val1, sep, val2); if (rlen < 0 || rlen >= len) { log_err("Failed to generate conditional expression"); rc = -1; @@ -1623,6 +1622,13 @@ static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filena rule->name, pdb->p_type_val_to_name[rule->otype - 1]); } + if (rule->flags & RULE_SELF) { + cil_println(indent, "(typetransition %s self %s \"%s\" %s)", + stypes[stype], + pdb->p_class_val_to_name[rule->tclass - 1], + rule->name, + pdb->p_type_val_to_name[rule->otype - 1]); + } } names_destroy(&stypes, &num_stypes); @@ -1711,7 +1717,7 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp char *val2 = NULL; uint32_t num_params; const char *op; - const char *fmt_str; + const char *sep; const char *attr1; const char *attr2; char *names = NULL; @@ -1795,6 +1801,10 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp } if (num_names == 0) { names = strdup("NO_IDENTIFIER"); + if (!names) { + rc = -1; + goto exit; + } } else { rc = name_list_to_string(name_list, num_names, &names); if (rc != 0) { @@ -1849,11 +1859,11 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp rc = -1; goto exit; } - fmt_str = "(%s %s)"; + sep = ""; } else { val2 = stack_pop(stack); val1 = stack_pop(stack); - fmt_str = "(%s %s %s)"; + sep = " "; } if (val1 == NULL || val2 == NULL) { @@ -1875,10 +1885,7 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp goto exit; } - // although we always supply val2 and there isn't always a 2nd - // value, it should only be used when there are actually two values - // in the format strings - rlen = snprintf(new_val, len, fmt_str, op, val1, val2); + rlen = snprintf(new_val, len, "(%s %s%s%s)", op, val1, sep, val2); if (rlen < 0 || rlen >= len) { log_err("Failed to generate constraint expression"); rc = -1; @@ -2562,6 +2569,11 @@ static int ocontext_isid_to_cil(struct policydb *pdb, const char *const *sid_to_ goto exit; } item->sid_key = strdup(sid); + if (!item->sid_key) { + log_err("Out of memory"); + rc = -1; + goto exit; + } item->next = head; head = item; } @@ -2961,10 +2973,35 @@ static int genfscon_to_cil(struct policydb *pdb) { struct genfs *genfs; struct ocontext *ocon; + uint32_t sclass; for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) { for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) { - cil_printf("(genfscon %s \"%s\" ", genfs->fstype, ocon->u.name); + sclass = ocon->v.sclass; + if (sclass) { + const char *file_type; + const char *class_name = pdb->p_class_val_to_name[sclass-1]; + if (strcmp(class_name, "file") == 0) { + file_type = "file"; + } else if (strcmp(class_name, "dir") == 0) { + file_type = "dir"; + } else if (strcmp(class_name, "chr_file") == 0) { + file_type = "char"; + } else if (strcmp(class_name, "blk_file") == 0) { + file_type = "block"; + } else if (strcmp(class_name, "sock_file") == 0) { + file_type = "socket"; + } else if (strcmp(class_name, "fifo_file") == 0) { + file_type = "pipe"; + } else if (strcmp(class_name, "lnk_file") == 0) { + file_type = "symlink"; + } else { + return -1; + } + cil_printf("(genfscon %s \"%s\" %s ", genfs->fstype, ocon->u.name, file_type); + } else { + cil_printf("(genfscon %s \"%s\" ", genfs->fstype, ocon->u.name); + } context_to_cil(pdb, &ocon->context[0]); cil_printf(")\n"); } @@ -4123,7 +4160,7 @@ exit: static int fp_to_buffer(FILE *fp, char **data, size_t *data_len) { int rc = -1; - char *d = NULL; + char *d = NULL, *d_tmp; size_t d_len = 0; size_t read_len = 0; size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files @@ -4139,12 +4176,13 @@ static int fp_to_buffer(FILE *fp, char **data, size_t *data_len) d_len += read_len; if (d_len == max_len) { max_len *= 2; - d = realloc(d, max_len); - if (d == NULL) { + d_tmp = realloc(d, max_len); + if (d_tmp == NULL) { log_err("Out of memory"); rc = -1; goto exit; } + d = d_tmp; } } diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c index 6826155c5128c5087678f258501b0a1086097c04..a38025ecae8361dfd53502db8256c78a345e93ad 100644 --- a/libsepol/src/optimize.c +++ b/libsepol/src/optimize.c @@ -31,6 +31,9 @@ #include #include +#include "debug.h" +#include "private.h" + #define TYPE_VEC_INIT_SIZE 16 struct type_vec { @@ -42,7 +45,7 @@ static int type_vec_init(struct type_vec *v) { v->capacity = TYPE_VEC_INIT_SIZE; v->count = 0; - v->types = malloc(v->capacity * sizeof(*v->types)); + v->types = calloc(v->capacity, sizeof(*v->types)); if (!v->types) return -1; return 0; @@ -57,8 +60,9 @@ static int type_vec_append(struct type_vec *v, uint32_t type) { if (v->capacity == v->count) { unsigned int new_capacity = v->capacity * 2; - uint32_t *new_types = realloc(v->types, - new_capacity * sizeof(*v->types)); + uint32_t *new_types = reallocarray(v->types, + new_capacity, + sizeof(*v->types)); if (!new_types) return -1; @@ -93,7 +97,7 @@ static struct type_vec *build_type_map(const policydb_t *p) { unsigned int i, k; ebitmap_node_t *n; - struct type_vec *map = malloc(p->p_types.nprim * sizeof(*map)); + struct type_vec *map = calloc(p->p_types.nprim, sizeof(*map)); if (!map) return NULL; @@ -101,6 +105,9 @@ static struct type_vec *build_type_map(const policydb_t *p) if (type_vec_init(&map[i])) goto err; + if (!p->type_val_to_struct[i]) + continue; + if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) { ebitmap_for_each_positive_bit(&p->type_attr_map[i], n, k) { @@ -111,11 +118,13 @@ static struct type_vec *build_type_map(const policydb_t *p) ebitmap_t *types_i = &p->attr_type_map[i]; for (k = 0; k < p->p_types.nprim; k++) { - ebitmap_t *types_k = &p->attr_type_map[k]; + const ebitmap_t *types_k; - if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB) + if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB) continue; + types_k = &p->attr_type_map[k]; + if (ebitmap_contains(types_k, types_i)) { if (type_vec_append(&map[i], k)) goto err; @@ -435,6 +444,17 @@ int policydb_optimize(policydb_t *p) if (p->policy_type != POLICY_KERN) return -1; + if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) { + /* + * For policy versions between 20 and 23, attributes exist in the policy, + * but only in the type_attr_map. This means that there are gaps in both + * the type_val_to_struct and p_type_val_to_name arrays and policy rules + * can refer to those gaps. + */ + ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported"); + return -1; + } + type_map = build_type_map(p); if (!type_map) return -1; diff --git a/libsepol/src/polcaps.c b/libsepol/src/polcaps.c index 6a74ec7d3c3af8ad073158d305b1328fe8bc4cad..687e971c6f35aab01950b3eb40d0d3c799239c09 100644 --- a/libsepol/src/polcaps.c +++ b/libsepol/src/polcaps.c @@ -6,13 +6,14 @@ #include static const char * const polcap_names[] = { - "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */ - "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */ - "extended_socket_class", /* POLICYDB_CAPABILITY_EXTSOCKCLASS */ - "always_check_network", /* POLICYDB_CAPABILITY_ALWAYSNETWORK */ - "cgroup_seclabel", /* POLICYDB_CAPABILITY_SECLABEL */ - "nnp_nosuid_transition", /* POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION */ - "genfs_seclabel_symlinks", /* POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS */ + "network_peer_controls", /* POLICYDB_CAP_NETPEER */ + "open_perms", /* POLICYDB_CAP_OPENPERM */ + "extended_socket_class", /* POLICYDB_CAP_EXTSOCKCLASS */ + "always_check_network", /* POLICYDB_CAP_ALWAYSNETWORK */ + "cgroup_seclabel", /* POLICYDB_CAP_SECLABEL */ + "nnp_nosuid_transition", /* POLICYDB_CAP_NNP_NOSUID_TRANSITION */ + "genfs_seclabel_symlinks", /* POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS */ + "ioctl_skip_cloexec", /* POLICYDB_CAP_IOCTL_SKIP_CLOEXEC */ NULL }; @@ -20,7 +21,7 @@ int sepol_polcap_getnum(const char *name) { int capnum; - for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) { + for (capnum = 0; capnum <= POLICYDB_CAP_MAX; capnum++) { if (polcap_names[capnum] == NULL) continue; if (strcasecmp(polcap_names[capnum], name) == 0) @@ -31,7 +32,7 @@ int sepol_polcap_getnum(const char *name) const char *sepol_polcap_getname(unsigned int capnum) { - if (capnum > POLICYDB_CAPABILITY_MAX) + if (capnum > POLICYDB_CAP_MAX) return NULL; return polcap_names[capnum]; diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index 587ba64a5dbe7726a1b51801dff2e8e12e67691d..fc260eb664b1c7eb5c9733393dbe60312c6a679c 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -327,6 +327,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_IBENDPORT + 1, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_BASE, + .version = MOD_POLICYDB_VERSION_SELF_TYPETRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_IBENDPORT + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BASE, @@ -446,7 +453,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, - + { + .type = POLICY_MOD, + .version = MOD_POLICYDB_VERSION_SELF_TYPETRANS, + .sym_num = SYM_NUM, + .ocon_num = 0, + .target_platform = SEPOL_TARGET_SELINUX, + }, }; #if 0 @@ -1252,7 +1265,8 @@ int policydb_index_others(sepol_handle_t * handle, if (!p->type_val_to_struct) return -1; - cond_init_bool_indexes(p); + if (cond_init_bool_indexes(p)) + return -1; for (i = SYM_ROLES; i < SYM_NUM; i++) { free(p->sym_val_to_name[i]); @@ -2103,6 +2117,8 @@ static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp) if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) goto bad; comdatum->permissions.nprim = le32_to_cpu(buf[2]); + if (comdatum->permissions.nprim > PERM_SYMTAB_SIZE) + goto bad; nel = le32_to_cpu(buf[3]); key = malloc(len + 1); @@ -2251,6 +2267,8 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp) if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) goto bad; cladatum->permissions.nprim = le32_to_cpu(buf[3]); + if (cladatum->permissions.nprim > PERM_SYMTAB_SIZE) + goto bad; nel = le32_to_cpu(buf[4]); ncons = le32_to_cpu(buf[5]); @@ -2679,7 +2697,10 @@ static int filename_trans_read_one_compat(policydb_t *p, struct policy_file *fp) if (rc < 0) goto err; - stype = le32_to_cpu(buf[0]); + stype = le32_to_cpu(buf[0]); + if (stype == 0) + goto err; + ttype = le32_to_cpu(buf[1]); tclass = le32_to_cpu(buf[2]); otype = le32_to_cpu(buf[3]); @@ -2773,6 +2794,7 @@ static int filename_trans_read_one(policydb_t *p, struct policy_file *fp) if (!datum) goto err; + datum->next = NULL; *dst = datum; /* ebitmap_read() will at least init the bitmap */ @@ -2790,7 +2812,6 @@ static int filename_trans_read_one(policydb_t *p, struct policy_file *fp) dst = &datum->next; } - *dst = NULL; if (ndatum > 1 && filename_trans_check_datum(first)) goto err; @@ -2879,6 +2900,8 @@ static int ocontext_read_xen(const struct policydb_compat_info *info, if (rc < 0) return -1; c->sid[0] = le32_to_cpu(buf[0]); + if (is_saturated(c->sid[0])) + return -1; if (context_read_and_validate (&c->context[0], p, fp)) return -1; @@ -2990,6 +3013,8 @@ static int ocontext_read_selinux(const struct policydb_compat_info *info, if (rc < 0) return -1; c->sid[0] = le32_to_cpu(buf[0]); + if (is_saturated(c->sid[0])) + return -1; if (context_read_and_validate (&c->context[0], p, fp)) return -1; @@ -3810,10 +3835,11 @@ static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp) return 0; } -static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_file *fp) +static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r, + struct policy_file *fp) { - uint32_t buf[2], nel; - unsigned int i, len; + uint32_t buf[3], nel, i, len; + unsigned int entries; filename_trans_rule_t *ftr, *lftr; int rc; @@ -3858,11 +3884,18 @@ static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_fi if (type_set_read(&ftr->ttypes, fp)) return -1; - rc = next_entry(buf, fp, sizeof(uint32_t) * 2); + if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) + entries = 3; + else + entries = 2; + + rc = next_entry(buf, fp, sizeof(uint32_t) * entries); if (rc < 0) return -1; ftr->tclass = le32_to_cpu(buf[0]); ftr->otype = le32_to_cpu(buf[1]); + if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) + ftr->flags = le32_to_cpu(buf[2]); } return 0; @@ -3926,6 +3959,8 @@ static int scope_index_read(scope_index_t * scope_index, if (rc < 0) return -1; scope_index->class_perms_len = le32_to_cpu(buf[0]); + if (is_saturated(scope_index->class_perms_len)) + return -1; if (scope_index->class_perms_len == 0) { scope_index->class_perms_map = NULL; return 0; @@ -3963,7 +3998,7 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && - filename_trans_rule_read(&decl->filename_trans_rules, fp)) + filename_trans_rule_read(p, &decl->filename_trans_rules, fp)) return -1; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && @@ -3980,6 +4015,8 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl, if (rc < 0) return -1; nprim = le32_to_cpu(buf[0]); + if (is_saturated(nprim)) + return -1; nel = le32_to_cpu(buf[1]); for (j = 0; j < nel; j++) { if (read_f[i] (p, decl->symtab[i].table, fp)) { @@ -4106,12 +4143,12 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp) goto cleanup; scope->scope = le32_to_cpu(buf[0]); scope->decl_ids_len = le32_to_cpu(buf[1]); - if (scope->decl_ids_len == 0) { + if (zero_or_saturated(scope->decl_ids_len)) { ERR(fp->handle, "invalid scope with no declaration"); goto cleanup; } if ((scope->decl_ids = - malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) { + calloc(scope->decl_ids_len, sizeof(uint32_t))) == NULL) { goto cleanup; } rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len); @@ -4144,7 +4181,7 @@ static sepol_security_class_t policydb_string_to_security_class( class_datum_t *tclass_datum; tclass_datum = hashtab_search(policydb->p_classes.table, - (hashtab_key_t) class_name); + class_name); if (!tclass_datum) return 0; return tclass_datum->s.value; @@ -4164,7 +4201,7 @@ static sepol_access_vector_t policydb_string_to_av_perm( perm_datum = (perm_datum_t *) hashtab_search(tclass_datum->permissions.table, - (hashtab_key_t)perm_name); + perm_name); if (perm_datum != NULL) return UINT32_C(1) << (perm_datum->s.value - 1); @@ -4173,7 +4210,7 @@ static sepol_access_vector_t policydb_string_to_av_perm( perm_datum = (perm_datum_t *) hashtab_search(tclass_datum->comdatum->permissions.table, - (hashtab_key_t)perm_name); + perm_name); if (perm_datum != NULL) return UINT32_C(1) << (perm_datum->s.value - 1); @@ -4396,6 +4433,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) if (rc < 0) goto bad; nprim = le32_to_cpu(buf[0]); + if (is_saturated(nprim)) + goto bad; nel = le32_to_cpu(buf[1]); if (nel && !nprim) { ERR(fp->handle, "unexpected items in symbol table with no symbol"); @@ -4500,14 +4539,10 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) } if (policy_type == POLICY_KERN) { - p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t)); - p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t)); + p->type_attr_map = calloc(p->p_types.nprim, sizeof(ebitmap_t)); + p->attr_type_map = calloc(p->p_types.nprim, sizeof(ebitmap_t)); if (!p->type_attr_map || !p->attr_type_map) goto bad; - for (i = 0; i < p->p_types.nprim; i++) { - ebitmap_init(&p->type_attr_map[i]); - ebitmap_init(&p->attr_type_map[i]); - } for (i = 0; i < p->p_types.nprim; i++) { if (r_policyvers >= POLICYDB_VERSION_AVTAB) { if (ebitmap_read(&p->type_attr_map[i], fp)) diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 5804d24742995577abca56c4f592d7beb31d2fc0..da18282bafc87a6a5a7e0bce83ead8092395b7ec 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -2,15 +2,24 @@ #include #include #include +#include #include "debug.h" #include "policydb_validate.h" +#define bool_xor(a, b) (!(a) != !(b)) +#define bool_xnor(a, b) !bool_xor(a, b) + typedef struct validate { uint32_t nprim; ebitmap_t gaps; } validate_t; +typedef struct map_arg { + validate_t *flavors; + sepol_handle_t *handle; + int mls; +} map_arg_t; static int create_gap_ebitmap(char **val_to_name, uint32_t nprim, ebitmap_t *gaps) { @@ -115,6 +124,30 @@ static int validate_type_set(type_set_t *type_set, validate_t *type) if (validate_ebitmap(&type_set->negset, type)) goto bad; + switch (type_set->flags) { + case 0: + case TYPE_STAR: + case TYPE_COMP: + break; + default: + goto bad; + } + + return 0; + +bad: + return -1; +} + +static int validate_empty_type_set(type_set_t *type_set) +{ + if (!ebitmap_is_empty(&type_set->types)) + goto bad; + if (!ebitmap_is_empty(&type_set->negset)) + goto bad; + if (type_set->flags != 0) + goto bad; + return 0; bad: @@ -124,9 +157,21 @@ bad: static int validate_role_set(role_set_t *role_set, validate_t *role) { if (validate_ebitmap(&role_set->roles, role)) - return -1; + goto bad; + + switch (role_set->flags) { + case 0: + case ROLE_STAR: + case ROLE_COMP: + break; + default: + goto bad; + } return 0; + +bad: + return -1; } static int validate_scope(__attribute__ ((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) @@ -135,12 +180,23 @@ static int validate_scope(__attribute__ ((unused)) hashtab_key_t k, hashtab_datu uint32_t *nprim = (uint32_t *)args; unsigned int i; + switch (scope_datum->scope) { + case SCOPE_REQ: + case SCOPE_DECL: + break; + default: + goto bad; + } + for (i = 0; i < scope_datum->decl_ids_len; i++) { if (!value_isvalid(scope_datum->decl_ids[i], *nprim)) - return -1; + goto bad; } return 0; + +bad: + return -1; } static int validate_scopes(sepol_handle_t *handle, symtab_t scopes[], avrule_block_t *block) @@ -167,22 +223,110 @@ bad: return -1; } -static int validate_constraint_nodes(sepol_handle_t *handle, constraint_node_t *cons, validate_t flavors[]) +static int validate_constraint_nodes(sepol_handle_t *handle, unsigned int nperms, constraint_node_t *cons, validate_t flavors[]) { constraint_expr_t *cexp; for (; cons; cons = cons->next) { + if (nperms == 0 && cons->permissions != 0) + goto bad; + if (nperms > 0 && cons->permissions == 0) + goto bad; + if (nperms > 0 && nperms != PERM_SYMTAB_SIZE && cons->permissions >= (UINT32_C(1) << nperms)) + goto bad; + for (cexp = cons->expr; cexp; cexp = cexp->next) { - if (cexp->attr & CEXPR_USER) { - if (validate_ebitmap(&cexp->names, &flavors[SYM_USERS])) + if (cexp->expr_type == CEXPR_NAMES) { + if (cexp->attr & CEXPR_XTARGET && nperms != 0) + goto bad; + if (!(cexp->attr & CEXPR_TYPE)) { + if (validate_empty_type_set(cexp->type_names)) + goto bad; + } + + switch (cexp->op) { + case CEXPR_EQ: + case CEXPR_NEQ: + break; + default: + goto bad; + } + + switch (cexp->attr) { + case CEXPR_USER: + case CEXPR_USER | CEXPR_TARGET: + case CEXPR_USER | CEXPR_XTARGET: + if (validate_ebitmap(&cexp->names, &flavors[SYM_USERS])) + goto bad; + break; + case CEXPR_ROLE: + case CEXPR_ROLE | CEXPR_TARGET: + case CEXPR_ROLE | CEXPR_XTARGET: + if (validate_ebitmap(&cexp->names, &flavors[SYM_ROLES])) + goto bad; + break; + case CEXPR_TYPE: + case CEXPR_TYPE | CEXPR_TARGET: + case CEXPR_TYPE | CEXPR_XTARGET: + if (validate_ebitmap(&cexp->names, &flavors[SYM_TYPES])) + goto bad; + if (validate_type_set(cexp->type_names, &flavors[SYM_TYPES])) + goto bad; + break; + default: + goto bad; + } + } else if (cexp->expr_type == CEXPR_ATTR) { + if (!ebitmap_is_empty(&cexp->names)) + goto bad; + if (validate_empty_type_set(cexp->type_names)) + goto bad; + + switch (cexp->op) { + case CEXPR_EQ: + case CEXPR_NEQ: + break; + case CEXPR_DOM: + case CEXPR_DOMBY: + case CEXPR_INCOMP: + if ((cexp->attr & CEXPR_USER) || (cexp->attr & CEXPR_TYPE)) + goto bad; + break; + default: goto bad; - } else if (cexp->attr & CEXPR_ROLE) { - if (validate_ebitmap(&cexp->names, &flavors[SYM_ROLES])) + } + + switch (cexp->attr) { + case CEXPR_USER: + case CEXPR_ROLE: + case CEXPR_TYPE: + case CEXPR_L1L2: + case CEXPR_L1H2: + case CEXPR_H1L2: + case CEXPR_H1H2: + case CEXPR_L1H1: + case CEXPR_L2H2: + break; + default: goto bad; - } else if (cexp->attr & CEXPR_TYPE) { - if (validate_ebitmap(&cexp->names, &flavors[SYM_TYPES])) + } + } else { + switch (cexp->expr_type) { + case CEXPR_NOT: + case CEXPR_AND: + case CEXPR_OR: + break; + default: + goto bad; + } + + if (cexp->op != 0) goto bad; - if (validate_type_set(cexp->type_names, &flavors[SYM_TYPES])) + if (cexp->attr != 0) + goto bad; + if (!ebitmap_is_empty(&cexp->names)) + goto bad; + if (validate_empty_type_set(cexp->type_names)) goto bad; } } @@ -199,11 +343,54 @@ static int validate_class_datum(sepol_handle_t *handle, class_datum_t *class, va { if (validate_value(class->s.value, &flavors[SYM_CLASSES])) goto bad; - if (validate_constraint_nodes(handle, class->constraints, flavors)) + if (class->permissions.nprim > PERM_SYMTAB_SIZE) + goto bad; + if (validate_constraint_nodes(handle, class->permissions.nprim, class->constraints, flavors)) goto bad; - if (validate_constraint_nodes(handle, class->validatetrans, flavors)) + if (validate_constraint_nodes(handle, 0, class->validatetrans, flavors)) goto bad; + switch (class->default_user) { + case 0: + case DEFAULT_SOURCE: + case DEFAULT_TARGET: + break; + default: + goto bad; + } + + switch (class->default_role) { + case 0: + case DEFAULT_SOURCE: + case DEFAULT_TARGET: + break; + default: + goto bad; + } + + switch (class->default_type) { + case 0: + case DEFAULT_SOURCE: + case DEFAULT_TARGET: + break; + default: + goto bad; + } + + switch (class->default_range) { + case 0: + case DEFAULT_SOURCE_LOW: + case DEFAULT_SOURCE_HIGH: + case DEFAULT_SOURCE_LOW_HIGH: + case DEFAULT_TARGET_LOW: + case DEFAULT_TARGET_HIGH: + case DEFAULT_TARGET_LOW_HIGH: + case DEFAULT_GLBLUB: + break; + default: + goto bad; + } + return 0; bad: @@ -211,6 +398,32 @@ bad: return -1; } +static int validate_class_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_class_datum(margs->handle, d, margs->flavors); +} + +static int validate_common_datum(sepol_handle_t *handle, common_datum_t *common) +{ + if (common->permissions.nprim > PERM_SYMTAB_SIZE) + goto bad; + + return 0; + +bad: + ERR(handle, "Invalid common class datum"); + return -1; +} + +static int validate_common_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_common_datum(margs->handle, d); +} + static int validate_role_datum(sepol_handle_t *handle, role_datum_t *role, validate_t flavors[]) { if (validate_value(role->s.value, &flavors[SYM_ROLES])) @@ -227,10 +440,17 @@ static int validate_role_datum(sepol_handle_t *handle, role_datum_t *role, valid return 0; bad: - ERR(handle, "Invalid class datum"); + ERR(handle, "Invalid role datum"); return -1; } +static int validate_role_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_role_datum(margs->handle, d, margs->flavors); +} + static int validate_type_datum(sepol_handle_t *handle, type_datum_t *type, validate_t flavors[]) { if (validate_value(type->s.value, &flavors[SYM_TYPES])) @@ -240,6 +460,26 @@ static int validate_type_datum(sepol_handle_t *handle, type_datum_t *type, valid if (type->bounds && validate_value(type->bounds, &flavors[SYM_TYPES])) goto bad; + switch (type->flavor) { + case TYPE_TYPE: + case TYPE_ATTRIB: + case TYPE_ALIAS: + break; + default: + goto bad; + } + + switch (type->flags) { + case 0: + case TYPE_FLAGS_PERMISSIVE: + case TYPE_FLAGS_EXPAND_ATTR_TRUE: + case TYPE_FLAGS_EXPAND_ATTR_FALSE: + case TYPE_FLAGS_EXPAND_ATTR: + break; + default: + goto bad; + } + return 0; bad: @@ -247,6 +487,13 @@ bad: return -1; } +static int validate_type_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_type_datum(margs->handle, d, margs->flavors); +} + static int validate_mls_semantic_cat(mls_semantic_cat_t *cat, validate_t *cats) { for (; cat; cat = cat->next) { @@ -290,7 +537,41 @@ bad: return -1; } -static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, validate_t flavors[]) +static int validate_mls_level(mls_level_t *level, validate_t *sens, validate_t *cats) +{ + if (validate_value(level->sens, sens)) + goto bad; + if (validate_ebitmap(&level->cat, cats)) + goto bad; + + return 0; + + bad: + return -1; +} + +static int validate_level_datum(__attribute__ ((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + level_datum_t *level = d; + validate_t *flavors = args; + + return validate_mls_level(level->level, &flavors[SYM_LEVELS], &flavors[SYM_CATS]); +} + +static int validate_mls_range(mls_range_t *range, validate_t *sens, validate_t *cats) +{ + if (validate_mls_level(&range->level[0], sens, cats)) + goto bad; + if (validate_mls_level(&range->level[1], sens, cats)) + goto bad; + + return 0; + + bad: + return -1; +} + +static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, validate_t flavors[], int mls) { if (validate_value(user->s.value, &flavors[SYM_USERS])) goto bad; @@ -300,6 +581,10 @@ static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, valid goto bad; if (validate_mls_semantic_level(&user->dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS])) goto bad; + if (mls && validate_mls_range(&user->exp_range, &flavors[SYM_LEVELS], &flavors[SYM_CATS])) + goto bad; + if (mls && validate_mls_level(&user->exp_dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS])) + goto bad; if (user->bounds && validate_value(user->bounds, &flavors[SYM_USERS])) goto bad; @@ -310,32 +595,60 @@ bad: return -1; } -static int validate_datum_arrays(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) +static int validate_user_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_user_datum(margs->handle, d, margs->flavors, margs->mls); +} + +static int validate_bool_datum(sepol_handle_t *handle, cond_bool_datum_t *boolean, validate_t flavors[]) +{ + if (validate_value(boolean->s.value, &flavors[SYM_BOOLS])) + goto bad; + + switch (boolean->state) { + case 0: + case 1: + break; + default: + goto bad; + } + + switch (boolean->flags) { + case 0: + case COND_BOOL_FLAGS_TUNABLE: + break; + default: + goto bad; + } + + return 0; + +bad: + ERR(handle, "Invalid bool datum"); + return -1; +} + +static int validate_bool_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) +{ + map_arg_t *margs = args; + + return validate_bool_datum(margs->handle, d, margs->flavors); +} + +static int validate_datum_array_gaps(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) { unsigned int i; for (i = 0; i < p->p_classes.nprim; i++) { - if (p->class_val_to_struct[i]) { - if (ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i)) - goto bad; - if (validate_class_datum(handle, p->class_val_to_struct[i], flavors)) - goto bad; - } else { - if (!ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i)) - goto bad; - } + if (bool_xnor(p->class_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i))) + goto bad; } for (i = 0; i < p->p_roles.nprim; i++) { - if (p->role_val_to_struct[i]) { - if (ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i)) - goto bad; - if (validate_role_datum(handle, p->role_val_to_struct[i], flavors)) - goto bad; - } else { - if (!ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i)) - goto bad; - } + if (bool_xnor(p->role_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i))) + goto bad; } /* @@ -344,34 +657,68 @@ static int validate_datum_arrays(sepol_handle_t *handle, policydb_t *p, validate */ if (p->policyvers < POLICYDB_VERSION_AVTAB || p->policyvers > POLICYDB_VERSION_PERMISSIVE) { for (i = 0; i < p->p_types.nprim; i++) { - if (p->type_val_to_struct[i]) { - if (ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i)) - goto bad; - if (validate_type_datum(handle, p->type_val_to_struct[i], flavors)) - goto bad; - } else { - if (!ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i)) - goto bad; - } + if (bool_xnor(p->type_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i))) + goto bad; } } for (i = 0; i < p->p_users.nprim; i++) { - if (p->user_val_to_struct[i]) { - if (ebitmap_get_bit(&flavors[SYM_USERS].gaps, i)) - goto bad; - if (validate_user_datum(handle, p->user_val_to_struct[i], flavors)) - goto bad; - } else { - if (!ebitmap_get_bit(&flavors[SYM_USERS].gaps, i)) - goto bad; - } + if (bool_xnor(p->user_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_USERS].gaps, i))) + goto bad; + } + + for (i = 0; i < p->p_bools.nprim; i++) { + if (bool_xnor(p->bool_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_BOOLS].gaps, i))) + goto bad; } return 0; bad: - ERR(handle, "Invalid datum arrays"); + ERR(handle, "Invalid datum array gaps"); + return -1; +} + +static int validate_datum(__attribute__ ((unused))hashtab_key_t k, hashtab_datum_t d, void *args) +{ + symtab_datum_t *s = d; + uint32_t *nprim = (uint32_t *)args; + + return !value_isvalid(s->value, *nprim); +} + +static int validate_datum_array_entries(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) +{ + map_arg_t margs = { flavors, handle, p->mls }; + + if (hashtab_map(p->p_commons.table, validate_common_datum_wrapper, &margs)) + goto bad; + + if (hashtab_map(p->p_classes.table, validate_class_datum_wrapper, &margs)) + goto bad; + + if (hashtab_map(p->p_roles.table, validate_role_datum_wrapper, &margs)) + goto bad; + + if (hashtab_map(p->p_types.table, validate_type_datum_wrapper, &margs)) + goto bad; + + if (hashtab_map(p->p_users.table, validate_user_datum_wrapper, &margs)) + goto bad; + + if (p->mls && hashtab_map(p->p_levels.table, validate_level_datum, flavors)) + goto bad; + + if (hashtab_map(p->p_cats.table, validate_datum, &flavors[SYM_CATS])) + goto bad; + + if (hashtab_map(p->p_bools.table, validate_bool_datum_wrapper, &margs)) + goto bad; + + return 0; + +bad: + ERR(handle, "Invalid datum array entries"); return -1; } @@ -379,7 +726,7 @@ bad: * Functions to validate a kernel policydb */ -static int validate_avtab_key(avtab_key_t *key, validate_t flavors[]) +static int validate_avtab_key(avtab_key_t *key, int conditional, validate_t flavors[]) { if (validate_value(key->source_type, &flavors[SYM_TYPES])) goto bad; @@ -387,6 +734,23 @@ static int validate_avtab_key(avtab_key_t *key, validate_t flavors[]) goto bad; if (validate_value(key->target_class, &flavors[SYM_CLASSES])) goto bad; + switch (0xFFF & key->specified) { + case AVTAB_ALLOWED: + case AVTAB_AUDITALLOW: + case AVTAB_AUDITDENY: + case AVTAB_TRANSITION: + case AVTAB_MEMBER: + case AVTAB_CHANGE: + break; + case AVTAB_XPERMS_ALLOWED: + case AVTAB_XPERMS_AUDITALLOW: + case AVTAB_XPERMS_DONTAUDIT: + if (conditional) + goto bad; + break; + default: + goto bad; + } return 0; @@ -394,15 +758,22 @@ bad: return -1; } -static int validate_avtab_key_wrapper(avtab_key_t *k, __attribute__ ((unused)) avtab_datum_t *d, void *args) +static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void *args) { validate_t *flavors = (validate_t *)args; - return validate_avtab_key(k, flavors); + + if (validate_avtab_key(k, 0, flavors)) + return -1; + + if ((k->specified & AVTAB_TYPE) && validate_value(d->data, &flavors[SYM_TYPES])) + return -1; + + return 0; } static int validate_avtab(sepol_handle_t *handle, avtab_t *avtab, validate_t flavors[]) { - if (avtab_map(avtab, validate_avtab_key_wrapper, flavors)) { + if (avtab_map(avtab, validate_avtab_key_and_datum, flavors)) { ERR(handle, "Invalid avtab"); return -1; } @@ -416,7 +787,7 @@ static int validate_cond_av_list(sepol_handle_t *handle, cond_av_list_t *cond_av for (; cond_av; cond_av = cond_av->next) { for (avtab_ptr = cond_av->node; avtab_ptr; avtab_ptr = avtab_ptr->next) { - if (validate_avtab_key(&avtab_ptr->key, flavors)) { + if (validate_avtab_key(&avtab_ptr->key, 1, flavors)) { ERR(handle, "Invalid cond av list"); return -1; } @@ -426,7 +797,7 @@ static int validate_cond_av_list(sepol_handle_t *handle, cond_av_list_t *cond_av return 0; } -static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, validate_t flavors[]) +static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, int conditional, validate_t flavors[]) { class_perm_node_t *class; @@ -440,6 +811,48 @@ static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, validate_t if (validate_value(class->tclass, &flavors[SYM_CLASSES])) goto bad; } + + switch(avrule->specified) { + case AVRULE_ALLOWED: + case AVRULE_AUDITALLOW: + case AVRULE_AUDITDENY: + case AVRULE_DONTAUDIT: + case AVRULE_TRANSITION: + case AVRULE_MEMBER: + case AVRULE_CHANGE: + break; + case AVRULE_NEVERALLOW: + case AVRULE_XPERMS_ALLOWED: + case AVRULE_XPERMS_AUDITALLOW: + case AVRULE_XPERMS_DONTAUDIT: + case AVRULE_XPERMS_NEVERALLOW: + if (conditional) + goto bad; + break; + default: + goto bad; + } + + if (avrule->specified & AVRULE_XPERMS) { + if (!avrule->xperms) + goto bad; + switch (avrule->xperms->specified) { + case AVRULE_XPERMS_IOCTLFUNCTION: + case AVRULE_XPERMS_IOCTLDRIVER: + break; + default: + goto bad; + } + } else if (avrule->xperms) + goto bad; + + switch(avrule->flags) { + case 0: + case RULE_SELF: + break; + default: + goto bad; + } } return 0; @@ -468,16 +881,59 @@ bad: return -1; } +static int validate_cond_expr(sepol_handle_t *handle, struct cond_expr *expr, validate_t *bool) +{ + int depth = -1; + + for (; expr; expr = expr->next) { + switch(expr->expr_type) { + case COND_BOOL: + if (validate_value(expr->bool, bool)) + goto bad; + if (depth == (COND_EXPR_MAXDEPTH - 1)) + goto bad; + depth++; + break; + case COND_NOT: + if (depth < 0) + goto bad; + break; + case COND_OR: + case COND_AND: + case COND_XOR: + case COND_EQ: + case COND_NEQ: + if (depth < 1) + goto bad; + depth--; + break; + default: + goto bad; + } + } + + if (depth != 0) + goto bad; + + return 0; + +bad: + ERR(handle, "Invalid cond expression"); + return -1; +} + static int validate_cond_list(sepol_handle_t *handle, cond_list_t *cond, validate_t flavors[]) { for (; cond; cond = cond->next) { + if (validate_cond_expr(handle, cond->expr, &flavors[SYM_BOOLS])) + goto bad; if (validate_cond_av_list(handle, cond->true_list, flavors)) goto bad; if (validate_cond_av_list(handle, cond->false_list, flavors)) goto bad; - if (validate_avrules(handle, cond->avtrue_list, flavors)) + if (validate_avrules(handle, cond->avtrue_list, 1, flavors)) goto bad; - if (validate_avrules(handle, cond->avfalse_list, flavors)) + if (validate_avrules(handle, cond->avfalse_list, 1, flavors)) goto bad; if (validate_bool_id_array(handle, cond->bool_ids, cond->nbools, &flavors[SYM_BOOLS])) goto bad; @@ -559,6 +1015,77 @@ static int validate_filename_trans_hashtab(sepol_handle_t *handle, hashtab_t fil return 0; } +static int validate_context(context_struct_t *con, validate_t flavors[], int mls) +{ + if (validate_value(con->user, &flavors[SYM_USERS])) + return -1; + if (validate_value(con->role, &flavors[SYM_ROLES])) + return -1; + if (validate_value(con->type, &flavors[SYM_TYPES])) + return -1; + if (mls && validate_mls_range(&con->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS])) + return -1; + + return 0; +} + +static int validate_ocontexts(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) +{ + ocontext_t *octx; + unsigned int i; + + for (i = 0; i < OCON_NUM; i++) { + for (octx = p->ocontexts[i]; octx; octx = octx->next) { + if (validate_context(&octx->context[0], flavors, p->mls)) + goto bad; + + if (p->target_platform == SEPOL_TARGET_SELINUX) { + switch (i) { + case OCON_FS: + case OCON_NETIF: + if (validate_context(&octx->context[1], flavors, p->mls)) + goto bad; + break; + case OCON_FSUSE: + switch (octx->v.behavior) { + case SECURITY_FS_USE_XATTR: + case SECURITY_FS_USE_TRANS: + case SECURITY_FS_USE_TASK: + break; + default: + goto bad; + } + } + } + } + } + + return 0; + +bad: + ERR(handle, "Invalid ocontext"); + return -1; +} + +static int validate_genfs(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) +{ + genfs_t *genfs; + ocontext_t *octx; + + for (genfs = p->genfs; genfs; genfs = genfs->next) { + for (octx = genfs->head; octx; octx = octx->next) { + if (validate_context(&octx->context[0], flavors, p->mls)) + goto bad; + } + } + + return 0; + +bad: + ERR(handle, "Invalid genfs"); + return -1; +} + /* * Functions to validate a module policydb */ @@ -657,6 +1184,10 @@ static int validate_filename_trans_rules(sepol_handle_t *handle, filename_trans_ goto bad; if (validate_value(filename_trans->otype, &flavors[SYM_TYPES])) goto bad; + + /* currently only the RULE_SELF flag can be set */ + if ((filename_trans->flags & ~RULE_SELF) != 0) + goto bad; } return 0; @@ -666,14 +1197,6 @@ bad: return -1; } -static int validate_datum(__attribute__ ((unused))hashtab_key_t k, hashtab_datum_t d, void *args) -{ - symtab_datum_t *s = d; - uint32_t *nprim = (uint32_t *)args; - - return !value_isvalid(s->value, *nprim); -} - static int validate_symtabs(sepol_handle_t *handle, symtab_t symtabs[], validate_t flavors[]) { unsigned int i; @@ -696,7 +1219,7 @@ static int validate_avrule_blocks(sepol_handle_t *handle, avrule_block_t *avrule for (decl = avrule_block->branch_list; decl != NULL; decl = decl->next) { if (validate_cond_list(handle, decl->cond_list, flavors)) goto bad; - if (validate_avrules(handle, decl->avrules, flavors)) + if (validate_avrules(handle, decl->avrules, 0, flavors)) goto bad; if (validate_role_trans_rules(handle, decl->role_tr_rules, flavors)) goto bad; @@ -713,6 +1236,14 @@ static int validate_avrule_blocks(sepol_handle_t *handle, avrule_block_t *avrule if (validate_symtabs(handle, decl->symtab, flavors)) goto bad; } + + switch (avrule_block->flags) { + case 0: + case AVRULE_OPTIONAL: + break; + default: + goto bad; + } } return 0; @@ -722,6 +1253,71 @@ bad: return -1; } +static int validate_permissives(sepol_handle_t *handle, policydb_t *p, validate_t flavors[]) +{ + ebitmap_node_t *node; + unsigned i; + + ebitmap_for_each_positive_bit(&p->permissive_map, node, i) { + if (validate_value(i, &flavors[SYM_TYPES])) + goto bad; + } + + return 0; + +bad: + ERR(handle, "Invalid permissive type"); + return -1; +} + +static int validate_properties(sepol_handle_t *handle, policydb_t *p) +{ + switch (p->policy_type) { + case POLICY_KERN: + if (p->policyvers < POLICYDB_VERSION_MIN || p->policyvers > POLICYDB_VERSION_MAX) + goto bad; + break; + case POLICY_BASE: + case POLICY_MOD: + if (p->policyvers < MOD_POLICYDB_VERSION_MIN || p->policyvers > MOD_POLICYDB_VERSION_MAX) + goto bad; + break; + default: + goto bad; + } + + switch (p->target_platform) { + case SEPOL_TARGET_SELINUX: + case SEPOL_TARGET_XEN: + break; + default: + goto bad; + } + + switch (p->mls) { + case 0: + case 1: + break; + default: + goto bad; + } + + switch (p->handle_unknown) { + case SEPOL_DENY_UNKNOWN: + case SEPOL_REJECT_UNKNOWN: + case SEPOL_ALLOW_UNKNOWN: + break; + default: + goto bad; + } + + return 0; + +bad: + ERR(handle, "Invalid policy property"); + return -1; +} + static void validate_array_destroy(validate_t flavors[]) { unsigned int i; @@ -741,6 +1337,9 @@ int validate_policydb(sepol_handle_t *handle, policydb_t *p) if (validate_array_init(p, flavors)) goto bad; + if (validate_properties(handle, p)) + goto bad; + if (p->policy_type == POLICY_KERN) { if (validate_avtab(handle, &p->te_avtab, flavors)) goto bad; @@ -759,10 +1358,22 @@ int validate_policydb(sepol_handle_t *handle, policydb_t *p) goto bad; } + if (validate_ocontexts(handle, p, flavors)) + goto bad; + + if (validate_genfs(handle, p, flavors)) + goto bad; + if (validate_scopes(handle, p->scope, p->global)) goto bad; - if (validate_datum_arrays(handle, p, flavors)) + if (validate_datum_array_gaps(handle, p, flavors)) + goto bad; + + if (validate_datum_array_entries(handle, p, flavors)) + goto bad; + + if (validate_permissives(handle, p, flavors)) goto bad; validate_array_destroy(flavors); diff --git a/libsepol/src/private.h b/libsepol/src/private.h index 71287282fbc0670aecd2b570a16eb9a49520ec9e..1833b497857ccf974bac39f49104d44b02f05260 100644 --- a/libsepol/src/private.h +++ b/libsepol/src/private.h @@ -44,7 +44,12 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) -#define is_saturated(x) (x == (typeof(x))-1) +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# define is_saturated(x) (x == (typeof(x))-1 || (x) > (1U << 16)) +#else +# define is_saturated(x) (x == (typeof(x))-1) +#endif + #define zero_or_saturated(x) ((x == 0) || is_saturated(x)) #define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b))) @@ -78,3 +83,14 @@ extern int next_entry(void *buf, struct policy_file *fp, size_t bytes); extern size_t put_entry(const void *ptr, size_t size, size_t n, struct policy_file *fp); extern int str_read(char **strp, struct policy_file *fp, size_t len); + +#ifndef HAVE_REALLOCARRAY +static inline void* reallocarray(void *ptr, size_t nmemb, size_t size) { + if (size && nmemb > (size_t)-1 / size) { + errno = ENOMEM; + return NULL; + } + + return realloc(ptr, nmemb * size); +} +#endif diff --git a/libsepol/src/services.c b/libsepol/src/services.c index 3407058fd446915e1cb311eb92bd8a202040ad47..d7510e9dae510a36cfcd6ff9339bf52669dabe64 100644 --- a/libsepol/src/services.c +++ b/libsepol/src/services.c @@ -94,7 +94,7 @@ static void push(char *expr_ptr) else new_stack_len = stack_len * 2; - new_stack = realloc(stack, new_stack_len * sizeof(*stack)); + new_stack = reallocarray(stack, new_stack_len, sizeof(*stack)); if (!new_stack) { ERR(NULL, "unable to allocate stack space"); return; @@ -449,8 +449,8 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, else new_expr_list_len = expr_list_len * 2; - new_expr_list = realloc(expr_list, - new_expr_list_len * sizeof(*expr_list)); + new_expr_list = reallocarray(expr_list, + new_expr_list_len, sizeof(*expr_list)); if (!new_expr_list) { ERR(NULL, "failed to allocate expr buffer stack"); rc = -ENOMEM; @@ -712,7 +712,7 @@ mls_ops: * Generate the same number of answer buffer entries as expression * buffers (as there will never be more). */ - answer_list = malloc(expr_count * sizeof(*answer_list)); + answer_list = calloc(expr_count, sizeof(*answer_list)); if (!answer_list) { ERR(NULL, "failed to allocate answer stack"); rc = -ENOMEM; @@ -797,13 +797,13 @@ mls_ops: for (x = 0; buffers[x] != NULL; x++) { while (1) { - p = *r_buf + reason_buf_used; + p = *r_buf ? (*r_buf + reason_buf_used) : NULL; len = snprintf(p, reason_buf_len - reason_buf_used, "%s", buffers[x]); if (len < 0 || len >= reason_buf_len - reason_buf_used) { new_buf_len = reason_buf_len + REASON_BUF_SIZE; *new_buf = realloc(*r_buf, new_buf_len); - if (!new_buf) { + if (!*new_buf) { ERR(NULL, "failed to realloc reason buffer"); goto out1; } @@ -1233,6 +1233,12 @@ out: return STATUS_ERR; } + const char *sepol_av_perm_to_string(sepol_security_class_t tclass, + sepol_access_vector_t av) +{ + return sepol_av_to_string(policydb, tclass, av); +} + /* * Write the security context string representation of * the context associated with `sid' into a dynamically @@ -1263,7 +1269,7 @@ int sepol_sid_to_context(sepol_security_id_t sid, * Return a SID associated with the security context that * has the string representation specified by `scontext'. */ -int sepol_context_to_sid(const sepol_security_context_t scontext, +int sepol_context_to_sid(sepol_const_security_context_t scontext, size_t scontext_len, sepol_security_id_t * sid) { @@ -1553,7 +1559,7 @@ static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p) cladatum2->comdatum->permissions.table)) { ERR(NULL, " in the access vector definition " - "for class %s\n", key); + "for class %s", key); return -1; } } @@ -2163,12 +2169,11 @@ int sepol_get_user_sids(sepol_security_id_t fromsid, } usercon.user = user->s.value; - mysids = malloc(maxnel * sizeof(sepol_security_id_t)); + mysids = calloc(maxnel, sizeof(sepol_security_id_t)); if (!mysids) { rc = -ENOMEM; goto out; } - memset(mysids, 0, maxnel * sizeof(sepol_security_id_t)); ebitmap_for_each_positive_bit(&user->roles.roles, rnode, i) { role = policydb->role_val_to_struct[i]; @@ -2198,17 +2203,12 @@ int sepol_get_user_sids(sepol_security_id_t fromsid, mysids[mynel++] = sid; } else { maxnel += SIDS_NEL; - mysids2 = - malloc(maxnel * - sizeof(sepol_security_id_t)); - + mysids2 = calloc(maxnel, sizeof(sepol_security_id_t)); if (!mysids2) { rc = -ENOMEM; free(mysids); goto out; } - memset(mysids2, 0, - maxnel * sizeof(sepol_security_id_t)); memcpy(mysids2, mysids, mynel * sizeof(sepol_security_id_t)); free(mysids); diff --git a/libsepol/src/sidtab.c b/libsepol/src/sidtab.c index 255e072524124304d1dbb303d7128d1c3a0f4f6c..0cec41d2aad80fe1286ad331decd9b50be7afe0d 100644 --- a/libsepol/src/sidtab.c +++ b/libsepol/src/sidtab.c @@ -15,6 +15,7 @@ #include #include "flask.h" +#include "private.h" #define SIDTAB_HASH(sid) \ (sid & SIDTAB_HASH_MASK) @@ -25,13 +26,9 @@ int sepol_sidtab_init(sidtab_t * s) { - int i; - - s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE); + s->htable = calloc(SIDTAB_SIZE, sizeof(sidtab_ptr_t)); if (!s->htable) return -ENOMEM; - for (i = 0; i < SIDTAB_SIZE; i++) - s->htable[i] = (sidtab_ptr_t) NULL; s->nel = 0; s->next_sid = 1; s->shutdown = 0; diff --git a/libsepol/src/user_record.c b/libsepol/src/user_record.c index ac5200604091d9904a382adc7fdf0ed98ce958c6..dddd23b9e5447e14f6bba997cc1c55196b08b0e1 100644 --- a/libsepol/src/user_record.c +++ b/libsepol/src/user_record.c @@ -4,6 +4,7 @@ #include "user_internal.h" #include "debug.h" +#include "private.h" struct sepol_user { /* This user's name */ @@ -182,8 +183,9 @@ int sepol_user_add_role(sepol_handle_t * handle, if (!role_cp) goto omem; - roles_realloc = realloc(user->roles, - sizeof(char *) * (user->num_roles + 1)); + roles_realloc = reallocarray(user->roles, + user->num_roles + 1, + sizeof(char *)); if (!roles_realloc) goto omem; @@ -265,7 +267,7 @@ int sepol_user_get_roles(sepol_handle_t * handle, unsigned int i; const char **tmp_roles = - (const char **)malloc(sizeof(char *) * user->num_roles); + (const char **)calloc(user->num_roles, sizeof(char *)); if (!tmp_roles) goto omem; diff --git a/libsepol/src/users.c b/libsepol/src/users.c index b895b7f56b2ac858af3824deb1867dd89db216f1..a7406214a26151a548d7c20c6d964af09e0d2077 100644 --- a/libsepol/src/users.c +++ b/libsepol/src/users.c @@ -226,17 +226,17 @@ int sepol_user_modify(sepol_handle_t * handle, void *tmp_ptr; /* Ensure reverse lookup array has enough space */ - tmp_ptr = realloc(policydb->user_val_to_struct, - (policydb->p_users.nprim + - 1) * sizeof(user_datum_t *)); + tmp_ptr = reallocarray(policydb->user_val_to_struct, + policydb->p_users.nprim + 1, + sizeof(user_datum_t *)); if (!tmp_ptr) goto omem; policydb->user_val_to_struct = tmp_ptr; policydb->user_val_to_struct[policydb->p_users.nprim] = NULL; - tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS], - (policydb->p_users.nprim + - 1) * sizeof(char *)); + tmp_ptr = reallocarray(policydb->sym_val_to_name[SYM_USERS], + policydb->p_users.nprim + 1, + sizeof(char *)); if (!tmp_ptr) goto omem; policydb->sym_val_to_name[SYM_USERS] = tmp_ptr; diff --git a/libsepol/src/util.c b/libsepol/src/util.c index 902c63c5b18267fabd3b28b2b40b8043f2ad023c..1cd1308d1687aaf819619f285a89cebcf04b229d 100644 --- a/libsepol/src/util.c +++ b/libsepol/src/util.c @@ -28,6 +28,8 @@ #include #include +#include "private.h" + struct val_to_name { unsigned int val; char *name; @@ -40,6 +42,8 @@ struct val_to_name { * 0). Return 0 on success, -1 on out of memory. */ int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a) { + uint32_t *new; + if (cnt == NULL || a == NULL) return -1; @@ -48,17 +52,18 @@ int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a) * than be smart about it, for now we realloc() the array each * time a new uint32_t is added! */ if (*a != NULL) - *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t)); + new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t)); else { /* empty list */ *cnt = 0; - *a = (uint32_t *) malloc(sizeof(uint32_t)); + new = (uint32_t *) malloc(sizeof(uint32_t)); } - if (*a == NULL) { + if (new == NULL) { return -1; } - (*a)[*cnt] = i; + new[*cnt] = i; (*cnt)++; + *a = new; return 0; } diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 3bd034d65cb1b8fb9339691d1e69f1ce46295824..48ed21ea683a28aee6a762f7a1c470157356579b 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -1745,6 +1745,14 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, uint32_t buf[32], len; class_perm_node_t *cur; + if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS && + (avrule->specified & AVRULE_TYPE) && + (avrule->flags & RULE_SELF)) { + ERR(fp->handle, + "Module contains a self rule not supported by the target module policy version"); + return POLICYDB_ERROR; + } + items = 0; buf[items++] = cpu_to_le32(avrule->specified); buf[items++] = cpu_to_le32(avrule->flags); @@ -1929,11 +1937,12 @@ static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp) return POLICYDB_SUCCESS; } -static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_file *fp) +static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t, + struct policy_file *fp) { int nel = 0; - size_t items; - uint32_t buf[2], len; + size_t items, entries; + uint32_t buf[3], len; filename_trans_rule_t *ftr; for (ftr = t; ftr; ftr = ftr->next) @@ -1962,9 +1971,20 @@ static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_fi buf[0] = cpu_to_le32(ftr->tclass); buf[1] = cpu_to_le32(ftr->otype); + buf[2] = cpu_to_le32(ftr->flags); - items = put_entry(buf, sizeof(uint32_t), 2, fp); - if (items != 2) + if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) { + entries = 3; + } else if (!(ftr->flags & RULE_SELF)) { + entries = 2; + } else { + ERR(fp->handle, + "Module contains a self rule not supported by the target module policy version"); + return POLICYDB_ERROR; + } + + items = put_entry(buf, sizeof(uint32_t), entries, fp); + if (items != entries) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; @@ -2039,7 +2059,7 @@ static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && - filename_trans_rule_write(decl->filename_trans_rules, fp)) + filename_trans_rule_write(p, decl->filename_trans_rules, fp)) return POLICYDB_ERROR; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && @@ -2117,7 +2137,7 @@ static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) * buffer. this would have been easier with C99's * dynamic arrays... */ rc = POLICYDB_ERROR; - dyn_buf = malloc(items * sizeof(*dyn_buf)); + dyn_buf = calloc(items, sizeof(*dyn_buf)); if (!dyn_buf) goto err; buf = dyn_buf; diff --git a/libsepol/tests/Makefile b/libsepol/tests/Makefile index fc9bd1a303be50e51a67598302902befa57e646a..a72c327dee9a7dbf6d958dd432a76cfe6e6d111f 100644 --- a/libsepol/tests/Makefile +++ b/libsepol/tests/Makefile @@ -1,3 +1,4 @@ +ENV ?= env M4 ?= m4 MKDIR ?= mkdir EXE ?= libsepol-tests @@ -44,10 +45,15 @@ clean: rm -f $(objs) $(EXE) rm -f $(policies) rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo - +# mkdir is run in a clean environment created by env -i to avoid failing under ASan with: +# +# ASan runtime does not come first in initial library list; +# you should either link runtime to your application or manually preload it with LD_PRELOAD +# +# when the source code is built with ASan test: $(EXE) $(policies) - $(MKDIR) -p policies/test-downgrade + $(ENV) -i $(MKDIR) -p policies/test-downgrade ../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi ./$(EXE) diff --git a/libsepol/tests/policies/test-deps/base-metreq.conf b/libsepol/tests/policies/test-deps/base-metreq.conf index 3e2f8407bfaef0285e1bee57dcdcf04e7fe76084..b7528dde5e269f4df5dca5177c915abcd32f28b2 100644 --- a/libsepol/tests/policies/test-deps/base-metreq.conf +++ b/libsepol/tests/policies/test-deps/base-metreq.conf @@ -516,7 +516,7 @@ genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:net_foo_t, s0) diff --git a/libsepol/tests/policies/test-deps/base-notmetreq.conf b/libsepol/tests/policies/test-deps/base-notmetreq.conf index 8ff3d2042f63a3d45a6f41aeb0a91efbfd8d93a3..eee36dcaf43d120ef9a8c052b94897fddf1463de 100644 --- a/libsepol/tests/policies/test-deps/base-notmetreq.conf +++ b/libsepol/tests/policies/test-deps/base-notmetreq.conf @@ -503,7 +503,7 @@ genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:net_foo_t, s0) diff --git a/libsepol/tests/policies/test-deps/small-base.conf b/libsepol/tests/policies/test-deps/small-base.conf index 1411e62430cd1496ef86ac7ead259a472a2de8b0..98f49c23e33d5d6b43d696855728d5337324ee21 100644 --- a/libsepol/tests/policies/test-deps/small-base.conf +++ b/libsepol/tests/policies/test-deps/small-base.conf @@ -504,7 +504,7 @@ genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:net_foo_t, s0) diff --git a/libsepol/tests/policies/test-expander/alias-base.conf b/libsepol/tests/policies/test-expander/alias-base.conf index 57d4520ebb9c54c79d281ca9388fe3a7175e5e56..b950039df185127b52a35371f07d1dfb340d605f 100644 --- a/libsepol/tests/policies/test-expander/alias-base.conf +++ b/libsepol/tests/policies/test-expander/alias-base.conf @@ -494,7 +494,7 @@ genfscon proc / gen_context(system_u:object_r:system_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:system_t, s0) diff --git a/libsepol/tests/policies/test-expander/role-base.conf b/libsepol/tests/policies/test-expander/role-base.conf index a603390b12e937a0297b6df2e4e7df0dda09e47f..8e88b4be80d80060ec1562350456b78b8efecc9b 100644 --- a/libsepol/tests/policies/test-expander/role-base.conf +++ b/libsepol/tests/policies/test-expander/role-base.conf @@ -476,7 +476,7 @@ genfscon proc / gen_context(system_u:object_r:system_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:system_t, s0) diff --git a/libsepol/tests/policies/test-expander/small-base.conf b/libsepol/tests/policies/test-expander/small-base.conf index 20005e3f2f170799571d0985d5d408601f871a33..055ea0544885ea0d09ce6ad2d9bedf32f51fc893 100644 --- a/libsepol/tests/policies/test-expander/small-base.conf +++ b/libsepol/tests/policies/test-expander/small-base.conf @@ -714,7 +714,7 @@ genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:net_foo_t, s0) diff --git a/libsepol/tests/policies/test-expander/user-base.conf b/libsepol/tests/policies/test-expander/user-base.conf index 1f84fd7689ad46283a9b5b3db885b3b316545cd5..b31ee8cd2043e163212195cffe1cc310bf1f5991 100644 --- a/libsepol/tests/policies/test-expander/user-base.conf +++ b/libsepol/tests/policies/test-expander/user-base.conf @@ -480,7 +480,7 @@ genfscon proc / gen_context(system_u:object_r:system_t, s0) # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(system_u:object_r:system_t, s0) diff --git a/libsepol/tests/policies/test-hooks/cmp_policy.conf b/libsepol/tests/policies/test-hooks/cmp_policy.conf index 1eccf4a8af21ec20a05c85523c9f6d1e8a28791f..9082b333dc800b977870f374a525009329858e12 100644 --- a/libsepol/tests/policies/test-hooks/cmp_policy.conf +++ b/libsepol/tests/policies/test-hooks/cmp_policy.conf @@ -464,7 +464,7 @@ genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(g_b_user_1:object_r:g_b_type_1, s0) diff --git a/libsepol/tests/policies/test-hooks/small-base.conf b/libsepol/tests/policies/test-hooks/small-base.conf index 1eccf4a8af21ec20a05c85523c9f6d1e8a28791f..9082b333dc800b977870f374a525009329858e12 100644 --- a/libsepol/tests/policies/test-hooks/small-base.conf +++ b/libsepol/tests/policies/test-hooks/small-base.conf @@ -464,7 +464,7 @@ genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(g_b_user_1:object_r:g_b_type_1, s0) diff --git a/libsepol/tests/policies/test-linker/small-base.conf b/libsepol/tests/policies/test-linker/small-base.conf index 2bc14656a3d2c5a30dbe11a57dc4fa411742702e..890ebbebc8e3e4f8216cd987caafddd5032c90a2 100644 --- a/libsepol/tests/policies/test-linker/small-base.conf +++ b/libsepol/tests/policies/test-linker/small-base.conf @@ -593,7 +593,7 @@ genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 -nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) +nodecon ::1 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF gen_context(g_b_user_1:object_r:g_b_type_1, s0) diff --git a/libsepol/tests/test-common.c b/libsepol/tests/test-common.c index f690635eee27d832ef82d892e885766bcd5de469..8f2807b26e1bf05982fd04ee8543aa8461ee8608 100644 --- a/libsepol/tests/test-common.c +++ b/libsepol/tests/test-common.c @@ -26,6 +26,7 @@ #include +#include "test-common.h" #include "helpers.h" void test_sym_presence(policydb_t * p, const char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len) diff --git a/libsepol/tests/test-expander.c b/libsepol/tests/test-expander.c index ee70e220918ca675593c15f52eaf08abcae0e3f2..a9e66ed8dde894dee539c7a51c27f3ceffd26d6e 100644 --- a/libsepol/tests/test-expander.c +++ b/libsepol/tests/test-expander.c @@ -67,7 +67,7 @@ extern int mls; /* Takes base, some number of modules, links them, and expands them reads source from myfiles array, which has the base string followed by each module string */ -int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, const char *const *myfiles) +static int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, const char *const *myfiles) { char *filename[num_modules + 1]; int i; diff --git a/libsepol/tests/test-linker-cond-map.c b/libsepol/tests/test-linker-cond-map.c index b02e78818aadebac55d22280ffa191edde970a42..694a73469c4635b03bb50466fa5ba208bc138e68 100644 --- a/libsepol/tests/test-linker-cond-map.c +++ b/libsepol/tests/test-linker-cond-map.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "test-linker-cond-map.h" #include "parse_util.h" #include "helpers.h" #include "test-common.h" @@ -54,7 +55,7 @@ typedef struct test_cond_expr { uint32_t expr_type; } test_cond_expr_t; -void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len) +static void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len) { int i; cond_expr_t *expr; @@ -75,7 +76,7 @@ void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t } } -void test_bool_state(policydb_t * p, const char *bool, int state) +static void test_bool_state(policydb_t * p, const char *bool, int state) { cond_bool_datum_t *b; diff --git a/libsepol/tests/test-linker-cond-map.h b/libsepol/tests/test-linker-cond-map.h index 148c6f62e1577796ca853c305419ef1584328241..740a722e7a3fca3d274dac20c9badb22c16f8a04 100644 --- a/libsepol/tests/test-linker-cond-map.h +++ b/libsepol/tests/test-linker-cond-map.h @@ -21,6 +21,8 @@ #ifndef __TEST_LINKER_COND_MAP_H__ #define __TEST_LINKER_COND_MAP_H__ +#include + extern void base_cond_tests(policydb_t * base); extern void module_cond_tests(policydb_t * base); diff --git a/libsepol/tests/test-linker-roles.c b/libsepol/tests/test-linker-roles.c index 6843252bbe1b1884b39db00be0f92008685e44c1..2b17dffd50432fc023740379f34ac3b1c0f760f0 100644 --- a/libsepol/tests/test-linker-roles.c +++ b/libsepol/tests/test-linker-roles.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "test-linker-roles.h" #include "parse_util.h" #include "helpers.h" #include "test-common.h" diff --git a/libsepol/tests/test-linker-types.c b/libsepol/tests/test-linker-types.c index b41e08e0099c007aac1b5996a71d8663eb66539d..048dd4223e69723f0cbd4e9771279f45efb52549 100644 --- a/libsepol/tests/test-linker-types.c +++ b/libsepol/tests/test-linker-types.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "test-linker-types.h" #include "parse_util.h" #include "helpers.h" #include "test-common.h" diff --git a/libsepol/tests/test-linker-types.h b/libsepol/tests/test-linker-types.h index 0c860ebf980c67ec7e7f66511d80911d66ba1ce7..acad5e0e7ebce27a4179f50ad4cc4f720d434d73 100644 --- a/libsepol/tests/test-linker-types.h +++ b/libsepol/tests/test-linker-types.h @@ -21,6 +21,8 @@ #ifndef __TEST_LINKER_TYPES_H__ #define __TEST_LINKER_TYPES_H__ +#include + extern void base_type_tests(policydb_t * base); extern void module_type_tests(policydb_t * base); diff --git a/libsepol/utils/sepol_check_access.c b/libsepol/utils/sepol_check_access.c new file mode 100644 index 0000000000000000000000000000000000000000..bd2ea89600f366840bd61037d9aefde1eb01c5bb --- /dev/null +++ b/libsepol/utils/sepol_check_access.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *fp; + sepol_security_id_t ssid, tsid; + sepol_security_class_t tclass; + const char *permlist; + sepol_access_vector_t av; + struct sepol_av_decision avd; + unsigned int reason; + char *reason_buf; + int i; + + if (argc != 6) { + printf("usage: %s policy source_context target_context class permission[,permission2[,...]]\n", argv[0]); + return 1; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Can't open policy %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (sepol_set_policydb_from_file(fp) < 0) { + fprintf(stderr, "Error while processing policy %s: %s\n", argv[1], strerror(errno)); + fclose(fp); + return 1; + } + fclose(fp); + + if (sepol_context_to_sid(argv[2], strlen(argv[2]), &ssid) < 0) { + fprintf(stderr, "Invalid source context %s\n", argv[2]); + return 1; + } + + if (sepol_context_to_sid(argv[3], strlen(argv[3]), &tsid) < 0) { + fprintf(stderr, "Invalid target context %s\n", argv[3]); + return 1; + } + + if (sepol_string_to_security_class(argv[4], &tclass) < 0) { + fprintf(stderr, "Invalid security class %s\n", argv[4]); + return 1; + } + + permlist = argv[5]; + do { + char *tmp = NULL; + const char *perm; + const char *delim = strchr(permlist, ','); + + if (delim) { + tmp = strndup(permlist, delim - permlist); + if (!tmp) { + fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); + return 1; + } + } + + perm = tmp ? tmp : permlist; + + if (sepol_string_to_av_perm(tclass, perm, &av) < 0) { + fprintf(stderr, "Invalid permission %s for security class %s: %s\n", perm, argv[4], strerror(errno)); + free(tmp); + return 1; + } + + free(tmp); + + permlist = strchr(permlist, ','); + } while (permlist++); + + if (av == 0) { + fprintf(stderr, "Empty permission set computed from %s\n", argv[5]); + return 1; + } + + if (sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0) < 0) { + fprintf(stderr, "Failed to compute av decision: %s\n", strerror(errno)); + return 1; + } + + if ((avd.allowed & av) == av) { + printf("requested permission %s allowed\n", argv[5]); + free(reason_buf); + return 0; + } + + printf("requested permission %s denied by ", argv[5]); + i = 0; + if (reason & SEPOL_COMPUTEAV_TE) { + printf("te-rule"); + i++; + } + if (reason & SEPOL_COMPUTEAV_CONS) { + if (i > 0) + printf(", "); + printf("constraint"); + i++; + } + if (reason & SEPOL_COMPUTEAV_RBAC) { + if (i > 0) + printf(", "); + printf("transition-constraint"); + i++; + } + if (reason & SEPOL_COMPUTEAV_BOUNDS) { + if (i > 0) + printf(", "); + printf("type-bound"); + //i++; + } + + if ((reason & SEPOL_COMPUTEAV_CONS) && reason_buf) + printf("; reason:\n%s", reason_buf); + + free(reason_buf); + + printf("\n"); + + return 7; +} diff --git a/libsepol/utils/sepol_compute_av.c b/libsepol/utils/sepol_compute_av.c new file mode 100644 index 0000000000000000000000000000000000000000..d64dc31dea883452d143e2c2239064bb136983f2 --- /dev/null +++ b/libsepol/utils/sepol_compute_av.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *fp; + sepol_security_id_t ssid, tsid; + sepol_security_class_t tclass; + struct sepol_av_decision avd; + int rc; + + if (argc != 5) { + printf("usage: %s policy scontext tcontext tclass\n", argv[0]); + return 1; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Can't open policy %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (sepol_set_policydb_from_file(fp) < 0) { + fprintf(stderr, "Error while processing policy %s: %s\n", argv[1], strerror(errno)); + fclose(fp); + return 1; + } + fclose(fp); + + if (sepol_context_to_sid(argv[2], strlen(argv[2]), &ssid) < 0) { + fprintf(stderr, "Invalid source context %s\n", argv[2]); + return 1; + } + + if (sepol_context_to_sid(argv[3], strlen(argv[3]), &tsid) < 0) { + fprintf(stderr, "Invalid target context %s\n", argv[3]); + return 1; + } + + if (sepol_string_to_security_class(argv[4], &tclass) < 0) { + fprintf(stderr, "Invalid security class %s\n", argv[4]); + return 1; + } + + rc = sepol_compute_av(ssid, tsid, tclass, 0, &avd); + switch (rc) { + case 0: + printf("allowed: %s\n", sepol_av_perm_to_string(tclass, avd.allowed)); + printf("decided: %s\n", sepol_av_perm_to_string(tclass, avd.decided)); + printf("auditallow: %s\n", sepol_av_perm_to_string(tclass, avd.auditallow)); + printf("auditdeny: %s\n", sepol_av_perm_to_string(tclass, avd.auditdeny)); + break; + case -EINVAL: + printf("Invalid request\n"); + break; + default: + printf("Failed to compute av decision: %d\n", rc); + } + + return rc != 0; +} diff --git a/libsepol/utils/sepol_compute_member.c b/libsepol/utils/sepol_compute_member.c new file mode 100644 index 0000000000000000000000000000000000000000..69481055436e0c7c2e9487a7813f0527f20fd0d1 --- /dev/null +++ b/libsepol/utils/sepol_compute_member.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *fp; + sepol_security_id_t ssid, tsid, out_sid; + sepol_security_class_t tclass; + char *context; + size_t context_len; + + if (argc != 5) { + printf("usage: %s policy scontext tcontext tclass\n", argv[0]); + return 1; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Can't open policy %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (sepol_set_policydb_from_file(fp) < 0) { + fprintf(stderr, "Error while processing policy %s: %s\n", argv[1], strerror(errno)); + fclose(fp); + return 1; + } + fclose(fp); + + if (sepol_context_to_sid(argv[2], strlen(argv[2]), &ssid) < 0) { + fprintf(stderr, "Invalid source context %s\n", argv[2]); + return 1; + } + + if (sepol_context_to_sid(argv[3], strlen(argv[3]), &tsid) < 0) { + fprintf(stderr, "Invalid target context %s\n", argv[3]); + return 1; + } + + if (sepol_string_to_security_class(argv[4], &tclass) < 0) { + fprintf(stderr, "Invalid security class %s\n", argv[4]); + return 1; + } + + if (sepol_member_sid(ssid, tsid, tclass, &out_sid) < 0) { + fprintf(stderr, "Failed to compute member sid: %s\n", strerror(errno)); + return 1; + } + + if (sepol_sid_to_context(out_sid, &context, &context_len) < 0) { + fprintf(stderr, "Failed to convert sid %u: %s\n", out_sid, strerror(errno)); + return 1; + } + + printf("%s\n", context); + free(context); + + return 0; +} diff --git a/libsepol/utils/sepol_compute_relabel.c b/libsepol/utils/sepol_compute_relabel.c new file mode 100644 index 0000000000000000000000000000000000000000..2465753015e971d9f2b673ab1ec255f38022aaa8 --- /dev/null +++ b/libsepol/utils/sepol_compute_relabel.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *fp; + sepol_security_id_t ssid, tsid, out_sid; + sepol_security_class_t tclass; + char *context; + size_t context_len; + + if (argc != 5) { + printf("usage: %s policy scontext tcontext tclass\n", argv[0]); + return 1; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Can't open policy %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (sepol_set_policydb_from_file(fp) < 0) { + fprintf(stderr, "Error while processing policy %s: %s\n", argv[1], strerror(errno)); + fclose(fp); + return 1; + } + fclose(fp); + + if (sepol_context_to_sid(argv[2], strlen(argv[2]), &ssid) < 0) { + fprintf(stderr, "Invalid source context %s\n", argv[2]); + return 1; + } + + if (sepol_context_to_sid(argv[3], strlen(argv[3]), &tsid) < 0) { + fprintf(stderr, "Invalid target context %s\n", argv[3]); + return 1; + } + + if (sepol_string_to_security_class(argv[4], &tclass) < 0) { + fprintf(stderr, "Invalid security class %s\n", argv[4]); + return 1; + } + + if (sepol_change_sid(ssid, tsid, tclass, &out_sid) < 0) { + fprintf(stderr, "Failed to compute changed sid: %s\n", strerror(errno)); + return 1; + } + + if (sepol_sid_to_context(out_sid, &context, &context_len) < 0) { + fprintf(stderr, "Failed to convert sid %u: %s\n", out_sid, strerror(errno)); + return 1; + } + + printf("%s\n", context); + free(context); + + return 0; +} diff --git a/libsepol/utils/sepol_validate_transition.c b/libsepol/utils/sepol_validate_transition.c new file mode 100644 index 0000000000000000000000000000000000000000..621b5e22d19f56b353c096dcd9df22e934f578c0 --- /dev/null +++ b/libsepol/utils/sepol_validate_transition.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *fp; + sepol_security_id_t oldsid, newsid, tasksid; + sepol_security_class_t tclass; + char *reason = NULL; + int ret; + + if (argc != 6) { + printf("usage: %s policy oldcontext newcontext tclass taskcontext\n", argv[0]); + return 1; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Can't open policy %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (sepol_set_policydb_from_file(fp) < 0) { + fprintf(stderr, "Error while processing policy %s: %s\n", argv[1], strerror(errno)); + fclose(fp); + return 1; + } + fclose(fp); + + if (sepol_context_to_sid(argv[2], strlen(argv[2]), &oldsid) < 0) { + fprintf(stderr, "Invalid old context %s\n", argv[2]); + return 1; + } + + if (sepol_context_to_sid(argv[3], strlen(argv[3]), &newsid) < 0) { + fprintf(stderr, "Invalid new context %s\n", argv[3]); + return 1; + } + + if (sepol_string_to_security_class(argv[4], &tclass) < 0) { + fprintf(stderr, "Invalid security class %s\n", argv[4]); + return 1; + } + + if (sepol_context_to_sid(argv[5], strlen(argv[5]), &tasksid) < 0) { + fprintf(stderr, "Invalid task context %s\n", argv[5]); + return 1; + } + + ret = sepol_validate_transition_reason_buffer(oldsid, newsid, tasksid, tclass, &reason, SHOW_GRANTED); + switch (ret) { + case 0: + printf("allowed\n"); + ret = 0; + break; + case -EPERM: + printf("denied\n"); + printf("%s\n", reason ? reason : "unknown - possible BUG()"); + ret = 7; + break; + default: + printf("sepol_validate_transition_reason_buffer returned %d errno: %s\n", ret, strerror(errno)); + ret = 1; + } + + free(reason); + + return ret; +} diff --git a/secilc/VERSION b/secilc/VERSION index eb39e5382f4f035e4d71c7f67712cdbfa6c0c335..2f4b60750dc3500b0e4cf08f316a960a7ca42b40 100644 --- a/secilc/VERSION +++ b/secilc/VERSION @@ -1 +1 @@ -3.3 +3.4 diff --git a/secilc/docs/cil_file_labeling_statements.md b/secilc/docs/cil_file_labeling_statements.md index ed7b7bf9ba5c84f9b70f86291da2e01ed96313d0..73f7388539dee89095a5144824240af3b0c64ae8 100644 --- a/secilc/docs/cil_file_labeling_statements.md +++ b/secilc/docs/cil_file_labeling_statements.md @@ -36,11 +36,13 @@ Define entries for labeling files. The compiler will produce these entries in a - +

keyword

file_contexts entry

+ +

file

--

@@ -185,7 +187,7 @@ Used to allocate a security context to filesystems that cannot support any of th **Statement definition:** ```secil - (genfscon fsname path context_id) + (genfscon fsname path [file_type] context_id) ``` **Where:** @@ -209,6 +211,10 @@ Used to allocate a security context to filesystems that cannot support any of th

If fsname is proc, then the partial path (see examples). For all other types this must be ‘/’.

+

file_type

+

Optional keyword representing a file type. Valid values are the same as in [`filecon`](cil_file_labeling_statements.md#filecon) rules.

+ +

context_id

A previously declared context identifier or an anonymous security context (user role type levelrange), the range MUST be defined whether the policy is MLS/MCS enabled or not.

diff --git a/secilc/docs/cil_reference_guide.md b/secilc/docs/cil_reference_guide.md index 1e63e680e350e78964444c3ff635d435057bc950..ac800b122907fb38cc72b2741d6d8243613eabf1 100644 --- a/secilc/docs/cil_reference_guide.md +++ b/secilc/docs/cil_reference_guide.md @@ -189,7 +189,7 @@ Expressions Expressions may occur in the following CIL statements: [`booleanif`](cil_conditional_statements.md#booleanif), [`tunableif`](cil_conditional_statements.md#tunableif), [`classpermissionset`](cil_class_and_permission_statements.md#classpermissionset), [`typeattributeset`](cil_type_statements.md#typeattributeset), [`roleattributeset`](cil_role_statements.md#roleattributeset), [`categoryset`](cil_mls_labeling_statements.md#categoryset), [`constrain`](cil_constraint_statements.md#constrain), [`mlsconstrain`](cil_constraint_statements.md#mlsconstrain), [`validatetrans`](cil_constraint_statements.md#validatetrans), [`mlsvalidatetrans`](cil_constraint_statements.md#mlsvalidatetrans) -CIL expressions use the [prefix](http://www.cs.man.ac.uk/~pjj/cs212/fix.html) or Polish notation and may be nested (note that the kernel policy language uses postfix or reverse Polish notation). The syntax is as follows, where the parenthesis are part of the syntax: +CIL expressions use the [prefix](http://www.cs.man.ac.uk/~pjj/cs212/fix.html) or Polish notation and may be nested (note that the kernel policy language uses infix notation). The syntax is as follows, where the parenthesis are part of the syntax: ``` expr_set = (name ... | expr ...)