From 71cd553b4cdb58c5fe665f29bd2fec086e187a63 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 04 2021 00:52:02 +0000 Subject: import libsepol-3.2-4.el9 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c5faa5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/libsepol-3.2.tar.gz diff --git a/.libsepol.metadata b/.libsepol.metadata new file mode 100644 index 0000000..ee7313d --- /dev/null +++ b/.libsepol.metadata @@ -0,0 +1 @@ +9ce0e7c9772a17e5bad6479d80e6bf3b24db5f0c SOURCES/libsepol-3.2.tar.gz diff --git a/SOURCES/0001-libsepol-Expand-role-attributes-in-constraint-expres.patch b/SOURCES/0001-libsepol-Expand-role-attributes-in-constraint-expres.patch new file mode 100644 index 0000000..43f5370 --- /dev/null +++ b/SOURCES/0001-libsepol-Expand-role-attributes-in-constraint-expres.patch @@ -0,0 +1,79 @@ +From f7431d0e0ed9f695a6a8af74c3f239f80649a167 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 10 Mar 2021 14:30:12 -0500 +Subject: [PATCH] libsepol: Expand role attributes in constraint expressions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When creating the kernel binary policy, role attributes in constraint +expressions are not expanded. This causes the constraint expression +to refer to a non-existent role in the kernel policy. This can lead +to a segfault when converting the binary policy back to conf or CIL +source or when using policy tools such as seinfo. + +Expand role attributes in constraint expressions when creating the +kernel binary policy. + +Reported-by: Christian Göttsche +Signed-off-by: James Carter +--- + libsepol/src/expand.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c +index eac7e4507d02..2d9cb566fe1e 100644 +--- a/libsepol/src/expand.c ++++ b/libsepol/src/expand.c +@@ -71,6 +71,38 @@ static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map) + return 0; + } + ++static int ebitmap_expand_roles(policydb_t *p, ebitmap_t *roles) ++{ ++ ebitmap_node_t *node; ++ unsigned int bit; ++ role_datum_t *role; ++ ebitmap_t tmp; ++ ++ ebitmap_init(&tmp); ++ ebitmap_for_each_positive_bit(roles, node, bit) { ++ role = p->role_val_to_struct[bit]; ++ assert(role); ++ if (role->flavor != ROLE_ATTRIB) { ++ if (ebitmap_set_bit(&tmp, bit, 1)) { ++ ebitmap_destroy(&tmp); ++ return -1; ++ } ++ } else { ++ if (ebitmap_union(&tmp, &role->roles)) { ++ ebitmap_destroy(&tmp); ++ return -1; ++ } ++ } ++ } ++ ebitmap_destroy(roles); ++ if (ebitmap_cpy(roles, &tmp)) { ++ ebitmap_destroy(&tmp); ++ return -1; ++ } ++ ebitmap_destroy(&tmp); ++ return 0; ++} ++ + static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum, + void *data) + { +@@ -333,6 +365,9 @@ static int constraint_node_clone(constraint_node_t ** dst, + if (map_ebitmap(&expr->names, &new_expr->names, state->rolemap)) { + goto out_of_mem; + } ++ if (ebitmap_expand_roles(state->out, &new_expr->names)) { ++ goto out_of_mem; ++ } + } else if (new_expr->attr & CEXPR_USER) { + if (map_ebitmap(&expr->names, &new_expr->names, state->usermap)) { + goto out_of_mem; +-- +2.32.0 + diff --git a/SOURCES/0002-libsepol-Properly-handle-types-associated-to-role-at.patch b/SOURCES/0002-libsepol-Properly-handle-types-associated-to-role-at.patch new file mode 100644 index 0000000..97d94d2 --- /dev/null +++ b/SOURCES/0002-libsepol-Properly-handle-types-associated-to-role-at.patch @@ -0,0 +1,70 @@ +From 6015b05d068515201f5d053910c6587fff8407d4 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 9 Mar 2021 16:36:40 -0500 +Subject: [PATCH] libsepol: Properly handle types associated to role attributes + +Types associated to role attributes in optional blocks are not +associated with the roles that have that attribute. The problem +is that role_fix_callback is called before the avrule_decls are +walked. + +Example/ + class CLASS1 + sid kernel + class CLASS1 { PERM1 } + type TYPE1; + type TYPE1A; + allow TYPE1 self : CLASS1 PERM1; + attribute_role ROLE_ATTR1A; + role ROLE1; + role ROLE1A; + roleattribute ROLE1A ROLE_ATTR1A; + role ROLE1 types TYPE1; + optional { + require { + class CLASS1 PERM1; + } + role ROLE_ATTR1A types TYPE1A; + } + user USER1 roles ROLE1; + sid kernel USER1:ROLE1:TYPE1 + +In this example ROLE1A will not have TYPE1A associated to it. + +Call role_fix_callback() after the avrule_decls are walked. + +Signed-off-by: James Carter +--- + libsepol/src/expand.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c +index 2d9cb566fe1e..a656ffad3a71 100644 +--- a/libsepol/src/expand.c ++++ b/libsepol/src/expand.c +@@ -3052,10 +3052,6 @@ int expand_module(sepol_handle_t * handle, + if (hashtab_map(state.base->p_roles.table, + role_bounds_copy_callback, &state)) + goto cleanup; +- /* escalate the type_set_t in a role attribute to all regular roles +- * that belongs to it. */ +- if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state)) +- goto cleanup; + + /* copy MLS's sensitivity level and categories - this needs to be done + * before expanding users (they need to be indexed too) */ +@@ -3121,6 +3117,11 @@ int expand_module(sepol_handle_t * handle, + goto cleanup; + } + ++ /* escalate the type_set_t in a role attribute to all regular roles ++ * that belongs to it. */ ++ if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state)) ++ goto cleanup; ++ + if (copy_and_expand_avrule_block(&state) < 0) { + ERR(handle, "Error during expand"); + goto cleanup; +-- +2.32.0 + diff --git a/SOURCES/0003-libsepol-Remove-unnecessary-copying-of-declarations-.patch b/SOURCES/0003-libsepol-Remove-unnecessary-copying-of-declarations-.patch new file mode 100644 index 0000000..058df23 --- /dev/null +++ b/SOURCES/0003-libsepol-Remove-unnecessary-copying-of-declarations-.patch @@ -0,0 +1,58 @@ +From 859857def94bd6c8ad9e9ecce88c85d19dc19933 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 11 Mar 2021 11:56:44 -0500 +Subject: [PATCH] libsepol: Remove unnecessary copying of declarations from + link.c + +At one point link_modules() might have needed this initial copying, +but now it serves no purpose, so remove it. + +Signed-off-by: James Carter +--- + libsepol/src/link.c | 30 ------------------------------ + 1 file changed, 30 deletions(-) + +diff --git a/libsepol/src/link.c b/libsepol/src/link.c +index 83bbc8a5c7d1..bdc1fcbf59d3 100644 +--- a/libsepol/src/link.c ++++ b/libsepol/src/link.c +@@ -2573,36 +2573,6 @@ int link_modules(sepol_handle_t * handle, + goto cleanup; + } + +- /* copy all types, declared and required */ +- for (i = 0; i < len; i++) { +- state.cur = modules[i]; +- state.cur_mod_name = modules[i]->policy->name; +- ret = +- hashtab_map(modules[i]->policy->p_types.table, +- type_copy_callback, &state); +- if (ret) { +- retval = ret; +- goto cleanup; +- } +- } +- +- /* then copy everything else, including aliases, and fixup attributes */ +- for (i = 0; i < len; i++) { +- state.cur = modules[i]; +- state.cur_mod_name = modules[i]->policy->name; +- ret = +- copy_identifiers(&state, modules[i]->policy->symtab, NULL); +- if (ret) { +- retval = ret; +- goto cleanup; +- } +- } +- +- if (policydb_index_others(state.handle, state.base, 0)) { +- ERR(state.handle, "Error while indexing others"); +- goto cleanup; +- } +- + /* copy and remap the module's data over to base */ + for (i = 0; i < len; i++) { + state.cur = modules[i]; +-- +2.32.0 + diff --git a/SOURCES/0004-libsepol-Check-kernel-to-CIL-and-Conf-functions-for-.patch b/SOURCES/0004-libsepol-Check-kernel-to-CIL-and-Conf-functions-for-.patch new file mode 100644 index 0000000..b584858 --- /dev/null +++ b/SOURCES/0004-libsepol-Check-kernel-to-CIL-and-Conf-functions-for-.patch @@ -0,0 +1,91 @@ +From 43c5ed469c2f3bc1beed9110b72bcc29c367ecfb Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 15 Mar 2021 11:09:38 -0400 +Subject: [PATCH] libsepol: Check kernel to CIL and Conf functions for + supported versions + +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 which can lead to NULL +dereferences when using sepol_kernel_policydb_to_conf() and +sepol_kernel_policydb_to_cil(). + +This can be seen with the following policy: + class CLASS1 + sid SID1 + class CLASS1 { PERM1 } + attribute TYPE_ATTR1; + type TYPE1; + typeattribute TYPE1 TYPE_ATTR1; + allow TYPE_ATTR1 self : CLASS1 PERM1; + role ROLE1; + role ROLE1 types TYPE1; + user USER1 roles ROLE1; + sid SID1 USER1:ROLE1:TYPE1 + +Compile the policy: + checkpolicy -c 23 -o policy.bin policy.conf +Converting back to a policy.conf causes a segfault: + checkpolicy -F -b -o policy.bin.conf policy.bin + +Have both sepol_kernel_policydb_to_conf() and +sepol_kernel_policydb_to_cil() exit with an error if the kernel +policy version is between 20 and 23. + +Acked-by: Nicolas Iooss +Signed-off-by: James Carter +--- + libsepol/src/kernel_to_cil.c | 12 ++++++++++++ + libsepol/src/kernel_to_conf.c | 12 ++++++++++++ + 2 files changed, 24 insertions(+) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index a146ac514018..edfebeafe283 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -3164,6 +3164,18 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb) + goto exit; + } + ++ if (pdb->policyvers >= POLICYDB_VERSION_AVTAB && pdb->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. ++ */ ++ sepol_log_err("Writing policy versions between 20 and 23 as CIL is not supported"); ++ rc = -1; ++ goto exit; ++ } ++ + rc = constraint_rules_to_strs(pdb, mls_constraints, non_mls_constraints); + if (rc != 0) { + goto exit; +diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c +index a22f196df9e9..ea58a026501f 100644 +--- a/libsepol/src/kernel_to_conf.c ++++ b/libsepol/src/kernel_to_conf.c +@@ -3041,6 +3041,18 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb) + goto exit; + } + ++ if (pdb->policyvers >= POLICYDB_VERSION_AVTAB && pdb->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. ++ */ ++ sepol_log_err("Writing policy versions between 20 and 23 as a policy.conf is not supported"); ++ rc = -1; ++ goto exit; ++ } ++ + rc = constraint_rules_to_strs(pdb, mls_constraints, non_mls_constraints); + if (rc != 0) { + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0005-libsepol-cil-make-cil_post_fc_fill_data-static.patch b/SOURCES/0005-libsepol-cil-make-cil_post_fc_fill_data-static.patch new file mode 100644 index 0000000..9aebb86 --- /dev/null +++ b/SOURCES/0005-libsepol-cil-make-cil_post_fc_fill_data-static.patch @@ -0,0 +1,77 @@ +From ba5fb7a41bb481cb870da273dd2faea4f2343c6d Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 16:58:44 +0100 +Subject: [PATCH] libsepol/cil: make cil_post_fc_fill_data static + +cil_post_fc_fill_data() is not used outside of cil_post.c, and is not +exported in libsepol.so. Make it static, in order to ease the analysis +of static analyzers. + +While at it, make its path argument "const char*" and the fields of +"struct fc_data" "unsigned int" or "size_t", in order to make the types +better match the values. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_post.c | 11 +++++++++-- + libsepol/cil/src/cil_post.h | 7 ------- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index a55df1ea5bb0..d2ecbd430aa3 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -27,6 +27,7 @@ + * either expressed or implied, of Tresys Technology, LLC. + */ + ++#include + #include + #include + #include +@@ -50,6 +51,12 @@ + #define GEN_REQUIRE_ATTR "cil_gen_require" /* Also in libsepol/src/module_to_cil.c */ + #define TYPEATTR_INFIX "_typeattr_" /* Also in libsepol/src/module_to_cil.c */ + ++struct fc_data { ++ unsigned int meta; ++ size_t stem_len; ++ size_t str_len; ++}; ++ + static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db); + static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db); + +@@ -156,9 +163,9 @@ static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor) + return CIL_TRUE; + } + +-void cil_post_fc_fill_data(struct fc_data *fc, char *path) ++static void cil_post_fc_fill_data(struct fc_data *fc, const char *path) + { +- int c = 0; ++ size_t c = 0; + fc->meta = 0; + fc->stem_len = 0; + fc->str_len = 0; +diff --git a/libsepol/cil/src/cil_post.h b/libsepol/cil/src/cil_post.h +index 3d5415486b77..b1d2206f9ef6 100644 +--- a/libsepol/cil/src/cil_post.h ++++ b/libsepol/cil/src/cil_post.h +@@ -30,13 +30,6 @@ + #ifndef CIL_POST_H_ + #define CIL_POST_H_ + +-struct fc_data { +- int meta; +- int stem_len; +- int str_len; +-}; +- +-void cil_post_fc_fill_data(struct fc_data *fc, char *path); + int cil_post_filecon_compare(const void *a, const void *b); + int cil_post_ibpkeycon_compare(const void *a, const void *b); + int cil_post_portcon_compare(const void *a, const void *b); +-- +2.32.0 + diff --git a/SOURCES/0006-libsepol-cil-remove-stray-printf.patch b/SOURCES/0006-libsepol-cil-remove-stray-printf.patch new file mode 100644 index 0000000..2a204dd --- /dev/null +++ b/SOURCES/0006-libsepol-cil-remove-stray-printf.patch @@ -0,0 +1,28 @@ +From fba672edfbe3fef4969c947eb3f7d62f5da6be2f Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 17:58:01 +0100 +Subject: [PATCH] libsepol/cil: remove stray printf + +printf("%i\n", node->flavor); looks very much like a statement which was +added for debugging purpose and was unintentionally left. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 0e07856133e5..47cdf0e7c0b9 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -1088,7 +1088,6 @@ int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args) + node = NODE(result_datum); + if (node->flavor != CIL_ROLE) { + rc = SEPOL_ERR; +- printf("%i\n", node->flavor); + cil_log(CIL_ERR, "roletransition must result in a role, but %s is a %s\n", roletrans->result_str, cil_node_to_string(node)); + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0007-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch b/SOURCES/0007-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch new file mode 100644 index 0000000..8cbd686 --- /dev/null +++ b/SOURCES/0007-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch @@ -0,0 +1,39 @@ +From 68e8871cfcbe1267ff0234a0dc78b207acc26af8 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 18:04:04 +0100 +Subject: [PATCH] libsepol/cil: replace printf with proper cil_tree_log + +All functions of the CIL compiler use cil_log or cil_tree_log to report +errors, but in two places which still uses printf. Replace these printf +invocation with cil_tree_log. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 47cdf0e7c0b9..2ea106d63505 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2497,7 +2497,7 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args) + + rc = cil_copy_ast(db, current, block_node); + if (rc != SEPOL_OK) { +- printf("Failed to copy in, rc: %d\n", rc); ++ cil_tree_log(current, CIL_ERR, "Failed to copy in-statement"); + goto exit; + } + +@@ -2788,7 +2788,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + macro_node = NODE(macro_datum); + + if (macro_node->flavor != CIL_MACRO) { +- printf("Failed to resolve %s to a macro\n", new_call->macro_str); ++ cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", new_call->macro_str); + rc = SEPOL_ERR; + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0008-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch b/SOURCES/0008-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch new file mode 100644 index 0000000..d87eb8c --- /dev/null +++ b/SOURCES/0008-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch @@ -0,0 +1,42 @@ +From c5e6153720e713e72a65614f625a51ad44d1fc07 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 19:25:58 +0100 +Subject: [PATCH] libsepol/cil: fix NULL pointer dereference in + __cil_insert_name + +OSS-Fuzz found a Null-dereference in __cil_insert_name when trying to +compile the following policy: + + (macro MACRO () + (classmap CLASS (PERM)) + (type TYPE) + (typetransition TYPE TYPE CLASS "name" TYPE) + ) + (call MACRO) + +When using a macro with no argument, macro->params is NULL and +cil_list_for_each(item, macro->params) dereferenced a NULL pointer. +Fix this by checking that macro->params is not NULL before using it. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28565 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 2ea106d63505..63beed9230b9 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -82,7 +82,7 @@ static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, + } else if (parent->flavor == CIL_MACRO) { + macro = parent->data; + } +- if (macro != NULL) { ++ if (macro != NULL && macro->params != NULL) { + struct cil_list_item *item; + cil_list_for_each(item, macro->params) { + if (((struct cil_param*)item->data)->str == key) { +-- +2.32.0 + diff --git a/SOURCES/0009-libsepol-cil-do-not-leak-avrulex_ioctl_table-memory-.patch b/SOURCES/0009-libsepol-cil-do-not-leak-avrulex_ioctl_table-memory-.patch new file mode 100644 index 0000000..8c7fb87 --- /dev/null +++ b/SOURCES/0009-libsepol-cil-do-not-leak-avrulex_ioctl_table-memory-.patch @@ -0,0 +1,173 @@ +From 78d458d16393d8f2dd2cd2a7b066222da4e87975 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 19:53:25 +0100 +Subject: [PATCH] libsepol/cil: do not leak avrulex_ioctl_table memory when an + error occurs + +OSS-Fuzz found a memory leak when trying to compile the following +policy: + + (class CLASS (PERM ioctl)) + (classorder (CLASS)) + (sid SID) + (sidorder (SID)) + (user USER) + (role ROLE) + (type TYPE) + (category CAT) + (categoryorder (CAT)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (sensitivitycategory SENS (CAT)) + (allow TYPE self (CLASS (PERM))) + (roletype ROLE TYPE) + (userrole USER ROLE) + (userlevel USER (SENS)) + (userrange USER ((SENS)(SENS (CAT)))) + (sidcontext SID (USER ROLE TYPE ((SENS)(SENS)))) + + (permissionx ioctl_test (ioctl CLASS (and (range 0x1600 0x19FF) (not (range 0x1750 0x175F))))) + (allowx TYPE TYPE ioctl_test) + + (boolean BOOLEAN false) + + (booleanif (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (not (xor (eq BOOLEAN BOOLEAN) + (and (eq BOOLEAN BOOLEAN) BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + BOOLEAN ) ) ) + (true + (allow TYPE TYPE (CLASS (PERM))) + ) + ) + +When the CIL compiler reports "Conditional expression exceeded max +allowable depth" because of the loooooong expression in the booleanif +statement, cil_binary_create_allocated_pdb returns without freeing the +memory which was allocated to store the keys and values of hash table +avrulex_ioctl_table. + +Fix this by moving the freeing logic to a dedicated destructor function +and calling it in the exit block of cil_binary_create_allocated_pdb. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28618 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_binary.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index f80d84679f85..18532aad9801 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -1668,14 +1668,6 @@ exit: + } + cil_list_destroy(&xperms_list, CIL_FALSE); + } +- +- // hashtab_t does not have a way to free keys or datum since it doesn't +- // know what they are. We won't need the keys/datum after this function, so +- // clean them up here. +- free(avtab_key); +- ebitmap_destroy(datum); +- free(datum); +- + return rc; + } + +@@ -1885,6 +1877,15 @@ exit: + return rc; + } + ++static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) ++{ ++ free(k); ++ ebitmap_destroy(datum); ++ free(datum); ++ ++ return SEPOL_OK; ++} ++ + int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) + { + int rc; +@@ -5037,6 +5038,7 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p + + exit: + hashtab_destroy(role_trans_table); ++ hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL); + hashtab_destroy(avrulex_ioctl_table); + free(type_value_to_cil); + free(class_value_to_cil); +-- +2.32.0 + diff --git a/SOURCES/0010-libsepol-make-num_-unsigned-int-in-module_to_cil.patch b/SOURCES/0010-libsepol-make-num_-unsigned-int-in-module_to_cil.patch new file mode 100644 index 0000000..4b6cc88 --- /dev/null +++ b/SOURCES/0010-libsepol-make-num_-unsigned-int-in-module_to_cil.patch @@ -0,0 +1,234 @@ +From 13eaba21ef523325f226c14c4c792ce404b58970 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Tue, 16 Mar 2021 23:23:13 +0100 +Subject: [PATCH] libsepol: make num_* unsigned int in module_to_cil +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Using signed integer to represent counts can troube some gcc +optimisation passes, for example in +https://github.com/fishilico/selinux/runs/2125501324?check_suite_focus=true#step:9:107 + + In function ‘name_list_to_string’, + inlined from ‘constraint_expr_to_string’ at module_to_cil.c:1799:11: + module_to_cil.c:1156:8: error: argument 1 range + [18446744071562067968, 18446744073709551615] exceeds maximum + object size 9223372036854775807 [-Werror=alloc-size-larger-than=] + 1156 | str = malloc(len); + | ^~~~~~~~~~~ + In file included from module_to_cil.c:39: + module_to_cil.c: In function ‘constraint_expr_to_string’: + /usr/include/stdlib.h:539:14: note: in a call to allocation + function ‘malloc’ declared here + 539 | extern void *malloc (size_t __size) __THROW __attribute_malloc__ + | ^~~~~~ + +The wide range (from 18446744071562067968 = 0xffffffff80000000 to +18446744073709551615 = 0xffffffffffffffff) was caused by num_names being +a signed int used in "len += num_names;", even though it should always +be non-negative. + +Prevent such issues from occurring by using "unsigned int" where +appropriate. + +Signed-off-by: Nicolas Iooss +--- + libsepol/src/module_to_cil.c | 62 ++++++++++++++++++------------------ + 1 file changed, 31 insertions(+), 31 deletions(-) + +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index a87bc15e7610..cb1069caffdf 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -717,9 +717,9 @@ exit: + return rc; + } + +-static int num_digits(int n) ++static unsigned int num_digits(unsigned int n) + { +- int num = 1; ++ unsigned int num = 1; + while (n >= 10) { + n /= 10; + num++; +@@ -945,7 +945,7 @@ static char *search_attr_list(struct list *attr_list, int is_type, void *set) + return NULL; + } + +-static int set_to_names(struct policydb *pdb, int is_type, void *set, struct list *attr_list, char ***names, int *num_names) ++static int set_to_names(struct policydb *pdb, int is_type, void *set, struct list *attr_list, char ***names, unsigned int *num_names) + { + char *attr_name = NULL; + int rc = 0; +@@ -982,12 +982,12 @@ exit: + return rc; + } + +-static int ebitmap_to_names(struct ebitmap *map, char **vals_to_names, char ***names, int *num_names) ++static int ebitmap_to_names(struct ebitmap *map, char **vals_to_names, char ***names, unsigned int *num_names) + { + int rc = 0; + struct ebitmap_node *node; + uint32_t i; +- uint32_t num; ++ unsigned int num; + char **name_arr; + + num = 0; +@@ -1026,7 +1026,7 @@ exit: + return rc; + } + +-static int process_roleset(struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***names, int *num_names) ++static int process_roleset(struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***names, unsigned int *num_names) + { + int rc = 0; + +@@ -1049,7 +1049,7 @@ exit: + return rc; + } + +-static int process_typeset(struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***names, int *num_names) ++static int process_typeset(struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***names, unsigned int *num_names) + { + int rc = 0; + +@@ -1072,7 +1072,7 @@ exit: + return rc; + } + +-static void names_destroy(char ***names, int *num_names) ++static void names_destroy(char ***names, unsigned int *num_names) + { + free(*names); + *names = NULL; +@@ -1083,7 +1083,7 @@ static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack * + { + struct list_node *curr; + char **tnames = NULL; +- int num_tnames, i; ++ unsigned int num_tnames, i; + struct role_list_node *role_node = NULL; + int rc; + struct type_set *ts; +@@ -1124,12 +1124,12 @@ exit: + } + + +-static int name_list_to_string(char **names, int num_names, char **string) ++static int name_list_to_string(char **names, unsigned int num_names, char **string) + { + // create a space separated string of the names + int rc = -1; + size_t len = 0; +- int i; ++ unsigned int i; + char *str; + char *strpos; + +@@ -1184,7 +1184,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a + struct avrule *avrule; + char **snames = NULL; + char **tnames = NULL; +- int s, t, num_snames, num_tnames; ++ unsigned int s, t, num_snames, num_tnames; + struct type_set *ts; + + for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) { +@@ -1257,7 +1257,7 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr * + char *new_val = NULL; + char *val1 = NULL; + char *val2 = NULL; +- int num_params; ++ unsigned int num_params; + const char *op; + const char *fmt_str; + const char *type; +@@ -1432,11 +1432,11 @@ static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans + int rc = 0; + struct role_trans_rule *rule; + char **role_names = NULL; +- int num_role_names = 0; +- int role; ++ unsigned int num_role_names = 0; ++ unsigned int role; + char **type_names = NULL; +- int num_type_names = 0; +- int type; ++ unsigned int num_type_names = 0; ++ unsigned int type; + uint32_t i; + struct ebitmap_node *node; + struct type_set *ts; +@@ -1482,10 +1482,10 @@ static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allo + int rc = -1; + struct role_allow_rule *rule; + char **roles = NULL; +- int num_roles = 0; ++ unsigned int num_roles = 0; + char **new_roles = NULL; +- int num_new_roles = 0; +- int i,j; ++ unsigned int num_new_roles = 0; ++ unsigned int i, j; + struct role_set *rs; + + for (rule = rules; rule != NULL; rule = rule->next) { +@@ -1525,11 +1525,11 @@ static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_tra + int rc = -1; + struct range_trans_rule *rule; + char **stypes = NULL; +- int num_stypes = 0; +- int stype; ++ unsigned int num_stypes = 0; ++ unsigned int stype; + char **ttypes = NULL; +- int num_ttypes = 0; +- int ttype; ++ unsigned int num_ttypes = 0; ++ unsigned int ttype; + struct ebitmap_node *node; + uint32_t i; + struct type_set *ts; +@@ -1594,11 +1594,11 @@ static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filena + { + int rc = -1; + char **stypes = NULL; +- int num_stypes = 0; +- int stype; ++ unsigned int num_stypes = 0; ++ unsigned int stype; + char **ttypes = NULL; +- int num_ttypes = 0; +- int ttype; ++ unsigned int num_ttypes = 0; ++ unsigned int ttype; + struct type_set *ts; + struct filename_trans_rule *rule; + +@@ -1716,7 +1716,7 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp + const char *attr2; + char *names = NULL; + char **name_list = NULL; +- int num_names = 0; ++ unsigned int num_names = 0; + struct type_set *ts; + + rc = stack_init(&stack); +@@ -2090,9 +2090,9 @@ static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UN + int rc = -1; + struct ebitmap_node *node; + uint32_t i; +- int j; ++ unsigned int j; + char **types = NULL; +- int num_types = 0; ++ unsigned int num_types = 0; + struct role_datum *role = datum; + struct type_set *ts; + struct list *attr_list = NULL; +-- +2.32.0 + diff --git a/SOURCES/0011-libsepol-Write-NO_IDENTIFIER-for-empty-constraint-ex.patch b/SOURCES/0011-libsepol-Write-NO_IDENTIFIER-for-empty-constraint-ex.patch new file mode 100644 index 0000000..416d189 --- /dev/null +++ b/SOURCES/0011-libsepol-Write-NO_IDENTIFIER-for-empty-constraint-ex.patch @@ -0,0 +1,37 @@ +From d4d0955c67f5b928ef134ee7e7e23a9c40a266ea Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 14:30:02 -0400 +Subject: [PATCH] libsepol: Write "NO_IDENTIFIER" for empty constraint + expression + +If a role attribute with no roles associated with it is used in a +constraint expression, then the role bitmap will be empty. This is +not a problem for the kernel, but does cause problems when +converting a kernel policy to policy.conf. + +When creating a policy.conf from a kernel policy, if an empty bitmap +is encountered, use the string "NO_IDENTIFIER". An error will occur +if an attempt is made to compile the resulting policy, but this is +better than exiting with an error without creating a policy.conf. + +Signed-off-by: James Carter +--- + libsepol/src/kernel_to_conf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c +index ea58a026501f..cd5a517abb59 100644 +--- a/libsepol/src/kernel_to_conf.c ++++ b/libsepol/src/kernel_to_conf.c +@@ -186,7 +186,7 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr + names = ebitmap_to_str(&curr->names, pdb->p_role_val_to_name, 1); + } + if (!names) { +- goto exit; ++ names = strdup("NO_IDENTIFIER"); + } + new_val = create_str("%s %s %s", 3, attr1, op, names); + free(names); +-- +2.32.0 + diff --git a/SOURCES/0012-libsepol-Enclose-identifier-lists-in-constraint-expr.patch b/SOURCES/0012-libsepol-Enclose-identifier-lists-in-constraint-expr.patch new file mode 100644 index 0000000..2a7eed3 --- /dev/null +++ b/SOURCES/0012-libsepol-Enclose-identifier-lists-in-constraint-expr.patch @@ -0,0 +1,38 @@ +From dbe890ab9f74c9514a0f8839591eb3c4c70a6e03 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 14:42:36 -0400 +Subject: [PATCH] libsepol: Enclose identifier lists in constraint expressions + +When writing a policy.conf from a kernel policy, if there are +multiple users, roles, or types, then the list needs to be enclosed +by "{" and "}". + +When writing a constraint expression, check to see if there are +multiple identifiers in the names string and enclose the list +with "{" and "}" if there are. + +Signed-off-by: James Carter +--- + libsepol/src/kernel_to_conf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c +index cd5a517abb59..5db47fe4f567 100644 +--- a/libsepol/src/kernel_to_conf.c ++++ b/libsepol/src/kernel_to_conf.c +@@ -188,7 +188,11 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr + if (!names) { + names = strdup("NO_IDENTIFIER"); + } +- new_val = create_str("%s %s %s", 3, attr1, op, names); ++ if (strchr(names, ' ')) { ++ new_val = create_str("%s %s { %s }", 3, attr1, op, names); ++ } else { ++ new_val = create_str("%s %s %s", 3, attr1, op, names); ++ } + free(names); + } + } else { +-- +2.32.0 + diff --git a/SOURCES/0013-libsepol-cil-Allow-lists-in-constraint-expressions.patch b/SOURCES/0013-libsepol-cil-Allow-lists-in-constraint-expressions.patch new file mode 100644 index 0000000..df6f5b9 --- /dev/null +++ b/SOURCES/0013-libsepol-cil-Allow-lists-in-constraint-expressions.patch @@ -0,0 +1,40 @@ +From 48ca44c8bc3bffd276fae0e7cc8c5b04af4f8736 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 15:18:31 -0400 +Subject: [PATCH] libsepol/cil: Allow lists in constraint expressions + +The expectation in CIL was to use user, role, or type attributes in +constraint expressions. The problem is that neither user nor role +attributes are part of the kernel binary policy, so when converting +from a kernel policy to CIL, that would require the creation of a +role or user attribute. The better solution is to just allow a list +to be used. In fact, the only thing preventing a list to be used +is a check in cil_verify_constraint_leaf_expr_syntax(). + +Remove the check and allow lists in constraint expressions. + +The following is now allowed: + (constrain (CLASS1 (PERM1)) (eq r1 (ROLE1 ROLE2 ROLE_ATTR3))) + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_verify.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 6706e21921fe..09e3daf94cc7 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -225,9 +225,6 @@ int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_fl + cil_log(CIL_ERR, "u3, r3, and t3 can only be used with (mls)validatetrans rules\n"); + goto exit; + } +- } else if (r_flavor == CIL_LIST) { +- cil_log(CIL_ERR, "t1, t2, r1, r2, u1, u2 cannot be used on the left side with a list on the right side\n"); +- goto exit; + } + } else { + if (r_flavor == CIL_CONS_U2) { +-- +2.32.0 + diff --git a/SOURCES/0014-libsepol-Enclose-identifier-lists-in-CIL-constraint-.patch b/SOURCES/0014-libsepol-Enclose-identifier-lists-in-CIL-constraint-.patch new file mode 100644 index 0000000..1574a51 --- /dev/null +++ b/SOURCES/0014-libsepol-Enclose-identifier-lists-in-CIL-constraint-.patch @@ -0,0 +1,66 @@ +From 6758addf8592d950cba489703abedd4a3430602f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 15:24:14 -0400 +Subject: [PATCH] libsepol: Enclose identifier lists in CIL constraint + expressions + +When writing CIL policy from a kernel policy or module, if there are +multiple users, roles, or types, then the list needs to be enclosed +by "(" and ")". + +When writing a constraint expression, check to see if there are +multiple identifiers in the names string and enclose the list with +"(" and ")" if there are. + +Signed-off-by: James Carter +--- + libsepol/src/kernel_to_cil.c | 6 +++++- + libsepol/src/module_to_cil.c | 9 ++++++++- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index edfebeafe283..101cb61240f5 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -191,7 +191,11 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr + if (!names) { + goto exit; + } +- new_val = create_str("(%s %s %s)", 3, op, attr1, names); ++ if (strchr(names, ' ')) { ++ new_val = create_str("(%s %s (%s))", 3, op, attr1, names); ++ } else { ++ new_val = create_str("(%s %s %s)", 3, op, attr1, names); ++ } + free(names); + } + } else { +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index cb1069caffdf..fdf56b701e2c 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -1800,13 +1800,20 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp + + // length of values/oper + 2 spaces + 2 parens + null terminator + len = strlen(op) + strlen(attr1) + strlen(names) + 2 + 2 + 1; ++ if (num_names > 1) { ++ len += 2; // 2 more parens ++ } + new_val = malloc(len); + if (new_val == NULL) { + log_err("Out of memory"); + rc = -1; + goto exit; + } +- rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names); ++ if (num_names > 1) { ++ rlen = snprintf(new_val, len, "(%s %s (%s))", op, attr1, names); ++ } else { ++ rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names); ++ } + if (rlen < 0 || rlen >= len) { + log_err("Failed to generate constraint expression"); + rc = -1; +-- +2.32.0 + diff --git a/SOURCES/0015-libsepol-Write-NO_IDENTIFIER-for-empty-CIL-constrain.patch b/SOURCES/0015-libsepol-Write-NO_IDENTIFIER-for-empty-CIL-constrain.patch new file mode 100644 index 0000000..75e6302 --- /dev/null +++ b/SOURCES/0015-libsepol-Write-NO_IDENTIFIER-for-empty-CIL-constrain.patch @@ -0,0 +1,60 @@ +From b839e9a1cb78d67c18df8b2e75e2fa53cca74392 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 15:31:06 -0400 +Subject: [PATCH] libsepol: Write "NO_IDENTIFIER" for empty CIL constraint + expression + +If a role or user attribute with nothing associated with it is used +in a constraint expression, then the bitmap will be empty. This is +not a problem for the kernel, but does cause problems when converting +a kernel policy or module to CIL. + +When creating a CIL policy from a kernel policy or module, if an +empty bitmap is encountered, use the string "NO_IDENTIFIER". An +error will occur if an attempt is made to compile the resulting +policy, but a valid policy was not being produced before anyway. +Treat types the same way even though empty bitmaps are not expected. + +Signed-off-by: James Carter +--- + libsepol/src/kernel_to_cil.c | 2 +- + libsepol/src/module_to_cil.c | 10 +++++++--- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 101cb61240f5..989aacde8a12 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -189,7 +189,7 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr + names = ebitmap_to_str(&curr->names, pdb->p_role_val_to_name, 1); + } + if (!names) { +- goto exit; ++ names = strdup("NO_IDENTIFIER"); + } + if (strchr(names, ' ')) { + new_val = create_str("(%s %s (%s))", 3, op, attr1, names); +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index fdf56b701e2c..58df0d4f6d77 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -1793,9 +1793,13 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp + goto exit; + } + } +- rc = name_list_to_string(name_list, num_names, &names); +- if (rc != 0) { +- goto exit; ++ if (num_names == 0) { ++ names = strdup("NO_IDENTIFIER"); ++ } else { ++ rc = name_list_to_string(name_list, num_names, &names); ++ if (rc != 0) { ++ goto exit; ++ } + } + + // length of values/oper + 2 spaces + 2 parens + null terminator +-- +2.32.0 + diff --git a/SOURCES/0016-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch b/SOURCES/0016-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch new file mode 100644 index 0000000..1c0427f --- /dev/null +++ b/SOURCES/0016-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch @@ -0,0 +1,163 @@ +From d155b410d4bbc90d28f361b966f0429598da8188 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 10:26:28 -0400 +Subject: [PATCH] libsepol/cil: Check for duplicate blocks, optionals, and + macros + +In CIL, blocks, optionals, and macros share the same symbol table so +that the targets of "in" statements can be located. Because of this, +they cannot have the same name in the same namespace, but, because +they do not show up in the final policy, they can have the same name +as long as they are in different namespaces. Unfortunately, when +copying from one namespace to another, no check was being done to see +if there was a conflict. + +When copying blocks, optionals, and macros, if a datum is found in +the destination namespace, then there is a conflict with a previously +declared block, optional, or macro, so exit with an error. + +Reported-by: Nicolas Iooss +Reported-by: Evgeny Vereshchagin +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_copy_ast.c | 89 +++++++++------------------------ + 1 file changed, 25 insertions(+), 64 deletions(-) + +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index c9aada9db348..ed96786115d3 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -100,16 +100,17 @@ int cil_copy_block(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_block *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_block *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_block *new; +- cil_block_init(&new); +- *copy = new; +- } else { +- *copy = datum;; ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; + } + ++ cil_block_init(&new); ++ *copy = new; ++ + return SEPOL_OK; + } + +@@ -1509,64 +1510,22 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_macro *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_macro *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_macro *new; +- cil_macro_init(&new); +- if (orig->params != NULL) { +- cil_copy_list(orig->params, &new->params); +- } +- +- *copy = new; +- +- } else { +- struct cil_list_item *curr_orig = NULL; +- struct cil_list_item *curr_new = NULL; +- struct cil_param *param_orig = NULL; +- struct cil_param *param_new = NULL; +- +- if (((struct cil_macro*)datum)->params != NULL) { +- curr_new = ((struct cil_macro*)datum)->params->head; +- } +- +- if (orig->params != NULL) { +- curr_orig = orig->params->head; +- } +- +- if (curr_orig != NULL && curr_new != NULL) { +- while (curr_orig != NULL) { +- if (curr_new == NULL) { +- goto exit; +- } +- +- param_orig = (struct cil_param*)curr_orig->data; +- param_new = (struct cil_param*)curr_new->data; +- if (param_orig->str != param_new->str) { +- goto exit; +- } else if (param_orig->flavor != param_new->flavor) { +- goto exit; +- } +- +- curr_orig = curr_orig->next; +- curr_new = curr_new->next; +- } +- +- if (curr_new != NULL) { +- goto exit; +- } +- } else if (!(curr_orig == NULL && curr_new == NULL)) { +- goto exit; +- } ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; ++ } + +- *copy = datum; ++ cil_macro_init(&new); ++ if (orig->params != NULL) { ++ cil_copy_list(orig->params, &new->params); + } + +- return SEPOL_OK; ++ *copy = new; + +-exit: +- cil_log(CIL_INFO, "cil_copy_macro: macro cannot be redefined\n"); +- return SEPOL_ERR; ++ return SEPOL_OK; + } + + int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +@@ -1574,16 +1533,17 @@ int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, voi + struct cil_optional *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_optional *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_optional *new; +- cil_optional_init(&new); +- *copy = new; +- } else { +- *copy = datum; ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; + } + ++ cil_optional_init(&new); ++ *copy = new; ++ + return SEPOL_OK; + } + +@@ -2122,6 +2082,7 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + args->dest = new; + } + } else { ++ cil_tree_log(orig, CIL_ERR, "Problem copying %s node", cil_node_to_string(orig)); + goto exit; + } + +-- +2.32.0 + diff --git a/SOURCES/0017-libsepol-cil-Fix-out-of-bound-read-of-file-context-p.patch b/SOURCES/0017-libsepol-cil-Fix-out-of-bound-read-of-file-context-p.patch new file mode 100644 index 0000000..045e67f --- /dev/null +++ b/SOURCES/0017-libsepol-cil-Fix-out-of-bound-read-of-file-context-p.patch @@ -0,0 +1,50 @@ +From e13c8162656665f9ec1c76a033cae5b011b8c658 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:24:29 -0400 +Subject: [PATCH] libsepol/cil: Fix out-of-bound read of file context pattern + ending with "\" + +Based on patch by Nicolas Iooss, who writes: + OSS-Fuzz found a Heap-buffer-overflow in the CIL compiler when trying + to compile the following policy: + + (sid SID) + (sidorder(SID)) + (filecon "\" any ()) + (filecon "" any ()) + + When cil_post_fc_fill_data() processes "\", it goes beyond the NUL + terminator of the string. Fix this by returning when '\0' is read + after a backslash. + +To be consistent with the function compute_diffdata() in +refpolicy/support/fc_sort.py, also increment str_len in this case. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28484 +Reported-by: Nicolas Iooss +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_post.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index d2ecbd430aa3..fd4758dc580e 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -186,6 +186,13 @@ static void cil_post_fc_fill_data(struct fc_data *fc, const char *path) + break; + case '\\': + c++; ++ if (path[c] == '\0') { ++ if (!fc->meta) { ++ fc->stem_len++; ++ } ++ fc->str_len++; ++ return; ++ } + /* FALLTHRU */ + default: + if (!fc->meta) { +-- +2.32.0 + diff --git a/SOURCES/0018-libsepol-cil-Destroy-classperms-list-when-resetting-.patch b/SOURCES/0018-libsepol-cil-Destroy-classperms-list-when-resetting-.patch new file mode 100644 index 0000000..cdb15b8 --- /dev/null +++ b/SOURCES/0018-libsepol-cil-Destroy-classperms-list-when-resetting-.patch @@ -0,0 +1,97 @@ +From f34d3d30c8325e4847a6b696fe7a3936a8a361f3 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:01 -0400 +Subject: [PATCH] libsepol/cil: Destroy classperms list when resetting + classpermission + +Nicolas Iooss reports: + A few months ago, OSS-Fuzz found a crash in the CIL compiler, which + got reported as + https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28648 (the title + is misleading, or is caused by another issue that conflicts with the + one I report in this message). Here is a minimized CIL policy which + reproduces the issue: + + (class CLASS (PERM)) + (classorder (CLASS)) + (sid SID) + (sidorder (SID)) + (user USER) + (role ROLE) + (type TYPE) + (category CAT) + (categoryorder (CAT)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (sensitivitycategory SENS (CAT)) + (allow TYPE self (CLASS (PERM))) + (roletype ROLE TYPE) + (userrole USER ROLE) + (userlevel USER (SENS)) + (userrange USER ((SENS)(SENS (CAT)))) + (sidcontext SID (USER ROLE TYPE ((SENS)(SENS)))) + + (classpermission CLAPERM) + + (optional OPT + (roletype nonexistingrole nonexistingtype) + (classpermissionset CLAPERM (CLASS (PERM))) + ) + + The CIL policy fuzzer (which mimics secilc built with clang Address + Sanitizer) reports: + + ==36541==ERROR: AddressSanitizer: heap-use-after-free on address + 0x603000004f98 at pc 0x56445134c842 bp 0x7ffe2a256590 sp + 0x7ffe2a256588 + READ of size 8 at 0x603000004f98 thread T0 + #0 0x56445134c841 in __cil_verify_classperms + /selinux/libsepol/src/../cil/src/cil_verify.c:1620:8 + #1 0x56445134a43e in __cil_verify_classpermission + /selinux/libsepol/src/../cil/src/cil_verify.c:1650:9 + #2 0x56445134a43e in __cil_pre_verify_helper + /selinux/libsepol/src/../cil/src/cil_verify.c:1715:8 + #3 0x5644513225ac in cil_tree_walk_core + /selinux/libsepol/src/../cil/src/cil_tree.c:272:9 + #4 0x564451322ab1 in cil_tree_walk + /selinux/libsepol/src/../cil/src/cil_tree.c:316:7 + #5 0x5644513226af in cil_tree_walk_core + /selinux/libsepol/src/../cil/src/cil_tree.c:284:9 + #6 0x564451322ab1 in cil_tree_walk + /selinux/libsepol/src/../cil/src/cil_tree.c:316:7 + #7 0x5644512b88fd in cil_pre_verify + /selinux/libsepol/src/../cil/src/cil_post.c:2510:7 + #8 0x5644512b88fd in cil_post_process + /selinux/libsepol/src/../cil/src/cil_post.c:2524:7 + #9 0x5644511856ff in cil_compile + /selinux/libsepol/src/../cil/src/cil.c:564:7 + +The classperms list of a classpermission rule is created and filled +in when classpermissionset rules are processed, so it doesn't own any +part of the list and shouldn't retain any of it when it is reset. + +Destroy the classperms list (without destroying the data in it) when +resetting a classpermission rule. + +Reported-by: Nicolas Iooss +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 3da1b9a64167..db70a535bd42 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -54,7 +54,7 @@ static void cil_reset_classpermission(struct cil_classpermission *cp) + return; + } + +- cil_reset_classperms_list(cp->classperms); ++ cil_list_destroy(&cp->classperms, CIL_FALSE); + } + + static void cil_reset_classperms_set(struct cil_classperms_set *cp_set) +-- +2.32.0 + diff --git a/SOURCES/0019-libsepol-cil-Destroy-classperm-list-when-resetting-m.patch b/SOURCES/0019-libsepol-cil-Destroy-classperm-list-when-resetting-m.patch new file mode 100644 index 0000000..85b7b6f --- /dev/null +++ b/SOURCES/0019-libsepol-cil-Destroy-classperm-list-when-resetting-m.patch @@ -0,0 +1,36 @@ +From 2d35fcc7e9e976a2346b1de20e54f8663e8a6cba Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:04 -0400 +Subject: [PATCH] libsepol/cil: Destroy classperm list when resetting map perms + +Map perms share the same struct as regular perms, but only the +map perms use the classperms field. This field is a pointer to a +list of classperms that is created and added to when resolving +classmapping rules, so the map permission doesn't own any of the +data in the list and this list should be destroyed when the AST is +reset. + +When resetting a perm, destroy the classperms list without destroying +the data in the list. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index db70a535bd42..89f91e568d0e 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -36,7 +36,7 @@ static void cil_reset_class(struct cil_class *class) + + static void cil_reset_perm(struct cil_perm *perm) + { +- cil_reset_classperms_list(perm->classperms); ++ cil_list_destroy(&perm->classperms, CIL_FALSE); + } + + static inline void cil_reset_classperms(struct cil_classperms *cp) +-- +2.32.0 + diff --git a/SOURCES/0020-libsepol-cil-cil_reset_classperms_set-should-not-res.patch b/SOURCES/0020-libsepol-cil-cil_reset_classperms_set-should-not-res.patch new file mode 100644 index 0000000..e43a330 --- /dev/null +++ b/SOURCES/0020-libsepol-cil-cil_reset_classperms_set-should-not-res.patch @@ -0,0 +1,39 @@ +From c49a8ea09501ad66e799ea41b8154b6770fec2c8 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:06 -0400 +Subject: [PATCH] libsepol/cil: cil_reset_classperms_set() should not reset + classpermission + +In struct cil_classperms_set, the set field is a pointer to a +struct cil_classpermission which is looked up in the symbol table. +Since the cil_classperms_set does not create the cil_classpermission, +it should not reset it. + +Set the set field to NULL instead of resetting the classpermission +that it points to. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 89f91e568d0e..1d9ca704e3ea 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -59,7 +59,11 @@ static void cil_reset_classpermission(struct cil_classpermission *cp) + + static void cil_reset_classperms_set(struct cil_classperms_set *cp_set) + { +- cil_reset_classpermission(cp_set->set); ++ if (cp_set == NULL) { ++ return; ++ } ++ ++ cp_set->set = NULL; + } + + static inline void cil_reset_classperms_list(struct cil_list *cp_list) +-- +2.32.0 + diff --git a/SOURCES/0021-libsepol-cil-Set-class-field-to-NULL-when-resetting-.patch b/SOURCES/0021-libsepol-cil-Set-class-field-to-NULL-when-resetting-.patch new file mode 100644 index 0000000..38ea226 --- /dev/null +++ b/SOURCES/0021-libsepol-cil-Set-class-field-to-NULL-when-resetting-.patch @@ -0,0 +1,32 @@ +From a7a80ef51b915071f0339e5e0262f06d84112874 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:08 -0400 +Subject: [PATCH] libsepol/cil: Set class field to NULL when resetting struct + cil_classperms + +The class field of a struct cil_classperms points to the class looked +up in the symbol table, so that field should be set to NULL when +the cil_classperms is reset. + +Set the class field to NULL when resetting the struct cil_classperms. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 1d9ca704e3ea..76405aba6194 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -45,6 +45,7 @@ static inline void cil_reset_classperms(struct cil_classperms *cp) + return; + } + ++ cp->class = NULL; + cil_list_destroy(&cp->perms, CIL_FALSE); + } + +-- +2.32.0 + diff --git a/SOURCES/0022-libsepol-cil-More-strict-verification-of-constraint-.patch b/SOURCES/0022-libsepol-cil-More-strict-verification-of-constraint-.patch new file mode 100644 index 0000000..0048ed8 --- /dev/null +++ b/SOURCES/0022-libsepol-cil-More-strict-verification-of-constraint-.patch @@ -0,0 +1,42 @@ +From e978e7692e16d6d8b801700d1dc5129ca31dfbad Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:11 -0400 +Subject: [PATCH] libsepol/cil: More strict verification of constraint leaf + expressions + +In constraint expressions u1, u3, r1, r3, t1, and t3 are never +allowed on the right side of an expression, but there were no checks +to verify that they were not used on the right side. The result was +that the expression "(eq t1 t1)" would be silently turned into +"(eq t1 t2)" when the binary policy was created. + +Verify that u1, u3, r1, r3, t1, and t3 are not used on the right +side of a constraint expression. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_verify.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 09e3daf94cc7..2707b6c97d15 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -227,7 +227,13 @@ int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_fl + } + } + } else { +- if (r_flavor == CIL_CONS_U2) { ++ if (r_flavor == CIL_CONS_U1 || r_flavor == CIL_CONS_R1 || r_flavor == CIL_CONS_T1) { ++ cil_log(CIL_ERR, "u1, r1, and t1 are not allowed on the right side\n"); ++ goto exit; ++ } else if (r_flavor == CIL_CONS_U3 || r_flavor == CIL_CONS_R3 || r_flavor == CIL_CONS_T3) { ++ cil_log(CIL_ERR, "u3, r3, and t3 are not allowed on the right side\n"); ++ goto exit; ++ } else if (r_flavor == CIL_CONS_U2) { + if (op != CIL_EQ && op != CIL_NEQ) { + cil_log(CIL_ERR, "u2 on the right side must be used with eq or neq as the operator\n"); + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0023-libsepol-cil-Exit-with-an-error-if-declaration-name-.patch b/SOURCES/0023-libsepol-cil-Exit-with-an-error-if-declaration-name-.patch new file mode 100644 index 0000000..9e12278 --- /dev/null +++ b/SOURCES/0023-libsepol-cil-Exit-with-an-error-if-declaration-name-.patch @@ -0,0 +1,194 @@ +From 532469a251607cfd8bd5e9299d3bba3764345ab6 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:12 -0400 +Subject: [PATCH] libsepol/cil: Exit with an error if declaration name is a + reserved word + +When CIL parses sets or conditional expressions, any identifier that +matches an operator name will always be taken as an operator. If a +declaration has the same name as an operator, then there is the +possibility of causing either confusion or a syntax error if it is +used in an expression. The potential for problems is much greater +than any possible advantage in allowing a declaration to share the +name of a reserved word. + +Create a new function, __cil_is_reserved_name() that is called when +an identifier is declared and its name is being validated. In this +function, check if the declaration has the same name as a reserved +word for an expression operator that can be used with the identifer's +flavor and exit with an error if it does. + +Also, move the check for types, type aliases, and type attributes +matching the reserved word "self" to this new function. + +Finally, change the name of the function __cil_verify_name() to +cil_verify_name(), since this function is neither static nor a +helper function. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 28 ++--------------- + libsepol/cil/src/cil_verify.c | 52 +++++++++++++++++++++++++++++++- + libsepol/cil/src/cil_verify.h | 2 +- + 3 files changed, 54 insertions(+), 28 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 4e53f06a98f4..e57de662dbd9 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -114,7 +114,7 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + symtab_t *symtab = NULL; + struct cil_symtab_datum *prev; + +- rc = __cil_verify_name((const char*)key); ++ rc = cil_verify_name((const char*)key, nflavor); + if (rc != SEPOL_OK) { + goto exit; + } +@@ -1953,12 +1953,6 @@ int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current + goto exit; + } + +- if (parse_current->next->data == CIL_KEY_SELF) { +- cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF); +- rc = SEPOL_ERR; +- goto exit; +- } +- + cil_roleattribute_init(&attr); + + key = parse_current->next->data; +@@ -2337,12 +2331,6 @@ int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct + goto exit; + } + +- if (parse_current->next->data == CIL_KEY_SELF) { +- cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF); +- rc = SEPOL_ERR; +- goto exit; +- } +- + cil_type_init(&type); + + key = parse_current->next->data; +@@ -2391,12 +2379,6 @@ int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current + goto exit; + } + +- if (parse_current->next->data == CIL_KEY_SELF) { +- cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF); +- rc = SEPOL_ERR; +- goto exit; +- } +- + cil_typeattribute_init(&attr); + + key = parse_current->next->data; +@@ -3048,12 +3030,6 @@ int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct + goto exit; + } + +- if (flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) { +- cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF); +- rc = SEPOL_ERR; +- goto exit; +- } +- + cil_alias_init(&alias); + + key = parse_current->next->data; +@@ -5278,7 +5254,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + + param->str = current_item->cl_head->next->data; + +- rc = __cil_verify_name(param->str); ++ rc = cil_verify_name(param->str, param->flavor); + if (rc != SEPOL_OK) { + cil_destroy_param(param); + goto exit; +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 2707b6c97d15..8fd54360698d 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -47,7 +47,51 @@ + + #include "cil_verify.h" + +-int __cil_verify_name(const char *name) ++static int __cil_is_reserved_name(const char *name, enum cil_flavor flavor) ++{ ++ switch (flavor) { ++ case CIL_BOOL: ++ case CIL_TUNABLE: ++ if ((name == CIL_KEY_EQ) || (name == CIL_KEY_NEQ)) ++ return CIL_TRUE; ++ break; ++ case CIL_PERM: ++ case CIL_MAP_PERM: ++ case CIL_USER: ++ case CIL_USERATTRIBUTE: ++ case CIL_ROLE: ++ case CIL_ROLEATTRIBUTE: ++ if (name == CIL_KEY_ALL) ++ return CIL_TRUE; ++ break; ++ case CIL_TYPE: ++ case CIL_TYPEATTRIBUTE: ++ case CIL_TYPEALIAS: ++ if ((name == CIL_KEY_ALL) || (name == CIL_KEY_SELF)) ++ return CIL_TRUE; ++ break; ++ case CIL_CAT: ++ case CIL_CATSET: ++ case CIL_CATALIAS: ++ case CIL_PERMISSIONX: ++ if ((name == CIL_KEY_ALL) || (name == CIL_KEY_RANGE)) ++ return CIL_TRUE; ++ break; ++ default: ++ /* All of these are not used in expressions */ ++ return CIL_FALSE; ++ break; ++ } ++ ++ /* Everything not under the default case is also checked for these */ ++ if ((name == CIL_KEY_AND) || (name == CIL_KEY_OR) || (name == CIL_KEY_NOT) || (name == CIL_KEY_XOR)) { ++ return CIL_TRUE; ++ } ++ ++ return CIL_FALSE; ++} ++ ++int cil_verify_name(const char *name, enum cil_flavor flavor) + { + int rc = SEPOL_ERR; + int len; +@@ -77,6 +121,12 @@ int __cil_verify_name(const char *name) + goto exit; + } + } ++ ++ if (__cil_is_reserved_name(name, flavor)) { ++ cil_log(CIL_ERR, "Name %s is a reserved word\n", name); ++ goto exit; ++ } ++ + return SEPOL_OK; + + exit: +diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h +index 905761b0a19c..1887ae3f13a1 100644 +--- a/libsepol/cil/src/cil_verify.h ++++ b/libsepol/cil/src/cil_verify.h +@@ -56,7 +56,7 @@ struct cil_args_verify { + int *pass; + }; + +-int __cil_verify_name(const char *name); ++int cil_verify_name(const char *name, enum cil_flavor flavor); + int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len); + int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor); + int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor); +-- +2.32.0 + diff --git a/SOURCES/0024-libsepol-cil-Allow-permission-expressions-when-using.patch b/SOURCES/0024-libsepol-cil-Allow-permission-expressions-when-using.patch new file mode 100644 index 0000000..c6a0f8b --- /dev/null +++ b/SOURCES/0024-libsepol-cil-Allow-permission-expressions-when-using.patch @@ -0,0 +1,75 @@ +From 22fb6f477bf10e834ece9eff84438fcaebf7d2ec Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:14 -0400 +Subject: [PATCH] libsepol/cil: Allow permission expressions when using map + classes + +The following policy will cause a segfault: + (class CLASS (PERM)) + (class C (P1 P2 P3)) + (classorder (CLASS C)) + (sid SID) + (sidorder (SID)) + (user USER) + (role ROLE) + (type TYPE) + (category CAT) + (categoryorder (CAT)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (sensitivitycategory SENS (CAT)) + (allow TYPE self (CLASS (PERM))) + (roletype ROLE TYPE) + (userrole USER ROLE) + (userlevel USER (SENS)) + (userrange USER ((SENS)(SENS (CAT)))) + (sidcontext SID (USER ROLE TYPE ((SENS)(SENS)))) + + (classmap CM (PM1 PM2 PM3)) + (classmapping CM PM1 (C (P1))) + (classmapping CM PM2 (C (P2))) + (classmapping CM PM3 (C (P3))) + (allow TYPE self (CM (and (all) (not PM2)))) + +The problem is that, while permission expressions are allowed for +normal classes, map classes are expected to only have permission +lists and no check is done to verify that only a permission list +is being used. + +When the above policy is parsed, the "and" and "all" are seen as +expression operators, but when the map permissions are converted to +normal class and permissions, the permission expression is assumed +to be a list of datums and since the operators are not datums a +segfault is the result. + +There is no reason to limit map classes to only using a list of +permissions and, in fact, it would be better to be able to use them +in the same way normal classes are used. + +Allow permissions expressions to be used for map classes by first +evaluating the permission expression and then converting the +resulting list to normal classes and permissions. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_post.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index fd4758dc580e..05842b644807 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -2137,6 +2137,10 @@ static int __evaluate_classperms_list(struct cil_list *classperms, struct cil_db + } + } else { /* MAP */ + struct cil_list_item *i = NULL; ++ rc = __evaluate_classperms(cp, db); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } + cil_list_for_each(i, cp->perms) { + struct cil_perm *cmp = i->data; + rc = __evaluate_classperms_list(cmp->classperms, db); +-- +2.32.0 + diff --git a/SOURCES/0025-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch b/SOURCES/0025-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch new file mode 100644 index 0000000..953ff91 --- /dev/null +++ b/SOURCES/0025-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch @@ -0,0 +1,74 @@ +From 63ce05ba07fc3517900fac22efe1c761d856762f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:16 -0400 +Subject: [PATCH] libsepol/cil: Refactor helper function for cil_gen_node() + +Change the name of cil_is_datum_multiple_decl() to +cil_allow_multiple_decls() and make it static. The new function +takes the CIL db and the flavors of the old and new datum as +arguments. Also, put all of the logic of determining if multiple +declarations are allowed into the new function. Finally, update +the call from cil_gen_node(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 27 ++++++++++----------------- + 1 file changed, 10 insertions(+), 17 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index e57de662dbd9..14cdce1482a0 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -82,30 +82,24 @@ exit: + return rc; + } + +-/* +- * Determine whether or not multiple declarations of the same key can share a +- * datum, given the new datum and the one already present in a given symtab. +- */ +-int cil_is_datum_multiple_decl(__attribute__((unused)) struct cil_symtab_datum *cur, +- struct cil_symtab_datum *old, +- enum cil_flavor f) ++static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, enum cil_flavor f_old) + { +- int rc = CIL_FALSE; ++ if (f_new != f_old) { ++ return CIL_FALSE; ++ } + +- switch (f) { ++ switch (f_new) { + case CIL_TYPE: + case CIL_TYPEATTRIBUTE: +- if (!old || f != FLAVOR(old)) { +- rc = CIL_FALSE; +- } else { +- /* type and typeattribute statements insert empty datums */ +- rc = CIL_TRUE; ++ if (db->multiple_decls) { ++ return CIL_TRUE; + } + break; + default: + break; + } +- return rc; ++ ++ return CIL_FALSE; + } + + int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor) +@@ -135,8 +129,7 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + cil_log(CIL_ERR, "Re-declaration of %s %s, but previous declaration could not be found\n",cil_node_to_string(ast_node), key); + goto exit; + } +- if (!db->multiple_decls || +- !cil_is_datum_multiple_decl(datum, prev, nflavor)) { ++ if (!cil_allow_multiple_decls(db, nflavor, FLAVOR(prev))) { + /* multiple_decls not ok, ret error */ + struct cil_tree_node *node = NODE(prev); + cil_log(CIL_ERR, "Re-declaration of %s %s\n", +-- +2.32.0 + diff --git a/SOURCES/0026-libsepol-cil-Create-function-cil_add_decl_to_symtab-.patch b/SOURCES/0026-libsepol-cil-Create-function-cil_add_decl_to_symtab-.patch new file mode 100644 index 0000000..7912be9 --- /dev/null +++ b/SOURCES/0026-libsepol-cil-Create-function-cil_add_decl_to_symtab-.patch @@ -0,0 +1,141 @@ +From 0d4e568afe5a28edc5fcdcff8e925d4ec1d0d3d0 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:19 -0400 +Subject: [PATCH] libsepol/cil: Create function cil_add_decl_to_symtab() and + refactor + +The functionality of adding a declaration to a symbol table is also +needed in __cil_copy_node_helper() and not just cil_gen_node(). + +Create a new function called cil_add_decl_to_symtab() to add a +declaration to a symtab and refactor cil_gen_node() and +__cil_copy_node_helper() to use the new function. + +By using the new function, __cil_copy_node_helper() will now allow +duplicate declarations when appropriate. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 63 +++++++++++++++++++------------- + libsepol/cil/src/cil_build_ast.h | 2 + + libsepol/cil/src/cil_copy_ast.c | 6 ++- + 3 files changed, 45 insertions(+), 26 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 14cdce1482a0..ec81db554b22 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -102,11 +102,45 @@ static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, en + return CIL_FALSE; + } + ++int cil_add_decl_to_symtab(struct cil_db *db, symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node) ++{ ++ int rc; ++ ++ if (symtab == NULL || datum == NULL || node == NULL) { ++ return SEPOL_ERR; ++ } ++ ++ rc = cil_symtab_insert(symtab, key, datum, node); ++ if (rc == SEPOL_EEXIST) { ++ struct cil_symtab_datum *prev; ++ rc = cil_symtab_get_datum(symtab, key, &prev); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Re-declaration of %s %s, but previous declaration could not be found\n",cil_node_to_string(node), key); ++ return SEPOL_ERR; ++ } ++ if (!cil_allow_multiple_decls(db, node->flavor, FLAVOR(prev))) { ++ /* multiple_decls not ok, ret error */ ++ struct cil_tree_node *n = NODE(prev); ++ cil_log(CIL_ERR, "Re-declaration of %s %s\n", ++ cil_node_to_string(node), key); ++ cil_tree_log(node, CIL_ERR, "Previous declaration of %s", ++ cil_node_to_string(n)); ++ return SEPOL_ERR; ++ } ++ /* multiple_decls is enabled and works for this datum type, add node */ ++ cil_list_append(prev->nodes, CIL_NODE, node); ++ node->data = prev; ++ cil_symtab_datum_destroy(datum); ++ free(datum); ++ } ++ ++ return SEPOL_OK; ++} ++ + int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor) + { + int rc = SEPOL_ERR; + symtab_t *symtab = NULL; +- struct cil_symtab_datum *prev; + + rc = cil_verify_name((const char*)key, nflavor); + if (rc != SEPOL_OK) { +@@ -121,30 +155,9 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + ast_node->data = datum; + ast_node->flavor = nflavor; + +- if (symtab != NULL) { +- rc = cil_symtab_insert(symtab, (hashtab_key_t)key, datum, ast_node); +- if (rc == SEPOL_EEXIST) { +- rc = cil_symtab_get_datum(symtab, (hashtab_key_t)key, &prev); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Re-declaration of %s %s, but previous declaration could not be found\n",cil_node_to_string(ast_node), key); +- goto exit; +- } +- if (!cil_allow_multiple_decls(db, nflavor, FLAVOR(prev))) { +- /* multiple_decls not ok, ret error */ +- struct cil_tree_node *node = NODE(prev); +- cil_log(CIL_ERR, "Re-declaration of %s %s\n", +- cil_node_to_string(ast_node), key); +- cil_tree_log(node, CIL_ERR, "Previous declaration of %s", +- cil_node_to_string(node)); +- rc = SEPOL_ERR; +- goto exit; +- } +- /* multiple_decls is enabled and works for this datum type, add node */ +- cil_list_append(prev->nodes, CIL_NODE, ast_node); +- ast_node->data = prev; +- cil_symtab_datum_destroy(datum); +- free(datum); +- } ++ rc = cil_add_decl_to_symtab(db, symtab, key, datum, ast_node); ++ if (rc != SEPOL_OK) { ++ goto exit; + } + + if (ast_node->parent->flavor == CIL_MACRO) { +diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h +index 8153e51e3a97..fd9053ce55ca 100644 +--- a/libsepol/cil/src/cil_build_ast.h ++++ b/libsepol/cil/src/cil_build_ast.h +@@ -37,6 +37,8 @@ + #include "cil_tree.h" + #include "cil_list.h" + ++int cil_add_decl_to_symtab(struct cil_db *db, symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node); ++ + int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor); + int cil_parse_to_list(struct cil_tree_node *parse_cl_head, struct cil_list *ast_cl, enum cil_flavor flavor); + +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index ed96786115d3..12bc553c6594 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -2031,7 +2031,11 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + rc = SEPOL_ERR; + goto exit; + } +- rc = cil_symtab_insert(symtab, ((struct cil_symtab_datum*)orig->data)->name, ((struct cil_symtab_datum*)data), new); ++ ++ rc = cil_add_decl_to_symtab(db, symtab, DATUM(orig->data)->name, DATUM(data), new); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } + + namespace = new; + while (namespace->flavor != CIL_MACRO && namespace->flavor != CIL_BLOCK && namespace->flavor != CIL_ROOT) { +-- +2.32.0 + diff --git a/SOURCES/0027-libsepol-cil-Move-check-for-the-shadowing-of-macro-p.patch b/SOURCES/0027-libsepol-cil-Move-check-for-the-shadowing-of-macro-p.patch new file mode 100644 index 0000000..cb31501 --- /dev/null +++ b/SOURCES/0027-libsepol-cil-Move-check-for-the-shadowing-of-macro-p.patch @@ -0,0 +1,140 @@ +From e65cf030b784dbb1ff4415e0b63a3bdf0158ccf6 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:23 -0400 +Subject: [PATCH] libsepol/cil: Move check for the shadowing of macro + parameters + +In cil_gen_node(), after the declaration is added to the symbol +table, if the parent is a macro, then a check is made to ensure +the declaration does not shadow any of the macro's parameters. +This check also needs to be done when copying the AST. + +Move the check for the shadowing of macro parameters to its own +function, cil_verify_decl_does_not_shadow_macro_parameter(), and +refactor cil_gen_node() and __cil_copy_node_helper() to use the +new function. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 16 +++------------- + libsepol/cil/src/cil_copy_ast.c | 20 ++++---------------- + libsepol/cil/src/cil_verify.c | 18 ++++++++++++++++++ + libsepol/cil/src/cil_verify.h | 1 + + 4 files changed, 26 insertions(+), 29 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index ec81db554b22..a4a2baa0f53b 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -161,19 +161,9 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + } + + if (ast_node->parent->flavor == CIL_MACRO) { +- struct cil_list_item *item; +- struct cil_list *param_list = ((struct cil_macro*)ast_node->parent->data)->params; +- if (param_list != NULL) { +- cil_list_for_each(item, param_list) { +- struct cil_param *param = item->data; +- if (param->flavor == ast_node->flavor) { +- if (param->str == key) { +- cil_log(CIL_ERR, "%s %s shadows a macro parameter in macro declaration\n", cil_node_to_string(ast_node), key); +- rc = SEPOL_ERR; +- goto exit; +- } +- } +- } ++ rc = cil_verify_decl_does_not_shadow_macro_parameter(ast_node->parent->data, ast_node, key); ++ if (rc != SEPOL_OK) { ++ goto exit; + } + } + +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index 12bc553c6594..954eab330340 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -40,6 +40,7 @@ + #include "cil_copy_ast.h" + #include "cil_build_ast.h" + #include "cil_strpool.h" ++#include "cil_verify.h" + + struct cil_args_copy { + struct cil_tree_node *dest; +@@ -1716,7 +1717,6 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + struct cil_db *db = NULL; + struct cil_args_copy *args = NULL; + struct cil_tree_node *namespace = NULL; +- struct cil_param *param = NULL; + enum cil_sym_index sym_index = CIL_SYM_UNKNOWN; + symtab_t *symtab = NULL; + void *data = NULL; +@@ -2043,21 +2043,9 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + } + + if (namespace->flavor == CIL_MACRO) { +- struct cil_macro *macro = namespace->data; +- struct cil_list *param_list = macro->params; +- if (param_list != NULL) { +- struct cil_list_item *item; +- cil_list_for_each(item, param_list) { +- param = item->data; +- if (param->flavor == new->flavor) { +- if (param->str == ((struct cil_symtab_datum*)new->data)->name) { +- cil_tree_log(orig, CIL_ERR, "%s %s shadows a macro parameter", cil_node_to_string(new), ((struct cil_symtab_datum*)orig->data)->name); +- cil_tree_log(namespace, CIL_ERR, "Note: macro declaration"); +- rc = SEPOL_ERR; +- goto exit; +- } +- } +- } ++ rc = cil_verify_decl_does_not_shadow_macro_parameter(namespace->data, orig, DATUM(orig->data)->name); ++ if (rc != SEPOL_OK) { ++ goto exit; + } + } + } +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 8fd54360698d..5a37dd2f76bc 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -412,6 +412,24 @@ int cil_verify_conditional_blocks(struct cil_tree_node *current) + return SEPOL_OK; + } + ++int cil_verify_decl_does_not_shadow_macro_parameter(struct cil_macro *macro, struct cil_tree_node *node, const char *name) ++{ ++ struct cil_list_item *item; ++ struct cil_list *param_list = macro->params; ++ if (param_list != NULL) { ++ cil_list_for_each(item, param_list) { ++ struct cil_param *param = item->data; ++ if (param->flavor == node->flavor) { ++ if (param->str == name) { ++ cil_log(CIL_ERR, "%s %s shadows a macro parameter in macro declaration\n", cil_node_to_string(node), name); ++ return SEPOL_ERR; ++ } ++ } ++ } ++ } ++ return SEPOL_OK; ++} ++ + int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list) + { + struct cil_list_item *i; +diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h +index 1887ae3f13a1..c497018f8a95 100644 +--- a/libsepol/cil/src/cil_verify.h ++++ b/libsepol/cil/src/cil_verify.h +@@ -62,6 +62,7 @@ int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, en + int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor); + int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op); + int cil_verify_conditional_blocks(struct cil_tree_node *current); ++int cil_verify_decl_does_not_shadow_macro_parameter(struct cil_macro *macro, struct cil_tree_node *node, const char *name); + int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list); + int __cil_verify_ranges(struct cil_list *list); + int __cil_verify_ordered_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args); +-- +2.32.0 + diff --git a/SOURCES/0028-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch b/SOURCES/0028-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch new file mode 100644 index 0000000..52f266d --- /dev/null +++ b/SOURCES/0028-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch @@ -0,0 +1,219 @@ +From 69bfe64cdf659cc47c544e6b376f0a653ff06f6f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:12 -0400 +Subject: [PATCH] libsepol/cil: Reorder checks for invalid rules when building + AST + +Reorder checks for invalid rules in the blocks of tunableifs, +in-statements, macros, and booleanifs when building the AST for +consistency. + +Order the checks in the same order the blocks will be resolved in, +so tuanbleif, in-statement, macro, booleanif, and then non-block +rules. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 100 +++++++++++++++---------------- + 1 file changed, 50 insertions(+), 50 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index a4a2baa0f53b..eee21086bba8 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -49,10 +49,10 @@ + struct cil_args_build { + struct cil_tree_node *ast; + struct cil_db *db; +- struct cil_tree_node *macro; +- struct cil_tree_node *boolif; + struct cil_tree_node *tunif; + struct cil_tree_node *in; ++ struct cil_tree_node *macro; ++ struct cil_tree_node *boolif; + }; + + int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list) +@@ -6069,10 +6069,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + struct cil_tree_node *ast_current = NULL; + struct cil_db *db = NULL; + struct cil_tree_node *ast_node = NULL; +- struct cil_tree_node *macro = NULL; +- struct cil_tree_node *boolif = NULL; + struct cil_tree_node *tunif = NULL; + struct cil_tree_node *in = NULL; ++ struct cil_tree_node *macro = NULL; ++ struct cil_tree_node *boolif = NULL; + int rc = SEPOL_ERR; + + if (parse_current == NULL || finished == NULL || extra_args == NULL) { +@@ -6082,10 +6082,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + args = extra_args; + ast_current = args->ast; + db = args->db; +- macro = args->macro; +- boolif = args->boolif; + tunif = args->tunif; + in = args->in; ++ macro = args->macro; ++ boolif = args->boolif; + + if (parse_current->parent->cl_head != parse_current) { + /* ignore anything that isn't following a parenthesis */ +@@ -6102,13 +6102,31 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + goto exit; + } + ++ if (tunif != NULL) { ++ if (parse_current->data == CIL_KEY_TUNABLE) { ++ rc = SEPOL_ERR; ++ cil_tree_log(parse_current, CIL_ERR, "Found tunable"); ++ cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); ++ goto exit; ++ } ++ } ++ ++ if (in != NULL) { ++ if (parse_current->data == CIL_KEY_IN) { ++ rc = SEPOL_ERR; ++ cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); ++ cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); ++ goto exit; ++ } ++ } ++ + if (macro != NULL) { +- if (parse_current->data == CIL_KEY_MACRO || +- parse_current->data == CIL_KEY_TUNABLE || ++ if (parse_current->data == CIL_KEY_TUNABLE || + parse_current->data == CIL_KEY_IN || + parse_current->data == CIL_KEY_BLOCK || + parse_current->data == CIL_KEY_BLOCKINHERIT || +- parse_current->data == CIL_KEY_BLOCKABSTRACT) { ++ parse_current->data == CIL_KEY_BLOCKABSTRACT || ++ parse_current->data == CIL_KEY_MACRO) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macros", (char *)parse_current->data); + goto exit; +@@ -6116,15 +6134,15 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + } + + if (boolif != NULL) { +- if (parse_current->data != CIL_KEY_CONDTRUE && ++ if (parse_current->data != CIL_KEY_TUNABLEIF && ++ parse_current->data != CIL_KEY_CALL && ++ parse_current->data != CIL_KEY_CONDTRUE && + parse_current->data != CIL_KEY_CONDFALSE && +- parse_current->data != CIL_KEY_AUDITALLOW && +- parse_current->data != CIL_KEY_TUNABLEIF && + parse_current->data != CIL_KEY_ALLOW && + parse_current->data != CIL_KEY_DONTAUDIT && ++ parse_current->data != CIL_KEY_AUDITALLOW && + parse_current->data != CIL_KEY_TYPETRANSITION && +- parse_current->data != CIL_KEY_TYPECHANGE && +- parse_current->data != CIL_KEY_CALL) { ++ parse_current->data != CIL_KEY_TYPECHANGE) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { +@@ -6138,24 +6156,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + } + } + +- if (tunif != NULL) { +- if (parse_current->data == CIL_KEY_TUNABLE) { +- rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "Found tunable"); +- cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); +- goto exit; +- } +- } +- +- if (in != NULL) { +- if (parse_current->data == CIL_KEY_IN) { +- rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); +- cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); +- goto exit; +- } +- } +- + cil_tree_node_init(&ast_node); + + ast_node->parent = ast_current; +@@ -6441,14 +6441,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + + if (rc == SEPOL_OK) { + if (ast_current->cl_head == NULL) { +- if (ast_current->flavor == CIL_MACRO) { +- args->macro = ast_current; +- } +- +- if (ast_current->flavor == CIL_BOOLEANIF) { +- args->boolif = ast_current; +- } +- + if (ast_current->flavor == CIL_TUNABLEIF) { + args->tunif = ast_current; + } +@@ -6457,6 +6449,14 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + args->in = ast_current; + } + ++ if (ast_current->flavor == CIL_MACRO) { ++ args->macro = ast_current; ++ } ++ ++ if (ast_current->flavor == CIL_BOOLEANIF) { ++ args->boolif = ast_current; ++ } ++ + ast_current->cl_head = ast_node; + } else { + ast_current->cl_tail->next = ast_node; +@@ -6492,14 +6492,6 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void + + args->ast = ast->parent; + +- if (ast->flavor == CIL_MACRO) { +- args->macro = NULL; +- } +- +- if (ast->flavor == CIL_BOOLEANIF) { +- args->boolif = NULL; +- } +- + if (ast->flavor == CIL_TUNABLEIF) { + args->tunif = NULL; + } +@@ -6508,6 +6500,14 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void + args->in = NULL; + } + ++ if (ast->flavor == CIL_MACRO) { ++ args->macro = NULL; ++ } ++ ++ if (ast->flavor == CIL_BOOLEANIF) { ++ args->boolif = NULL; ++ } ++ + // At this point we no longer have any need for parse_current or any of its + // siblings; they have all been converted to the appropriate AST node. The + // full parse tree will get deleted elsewhere, but in an attempt to +@@ -6532,10 +6532,10 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci + + extra_args.ast = ast; + extra_args.db = db; +- extra_args.macro = NULL; +- extra_args.boolif = NULL; + extra_args.tunif = NULL; + extra_args.in = NULL; ++ extra_args.macro = NULL; ++ extra_args.boolif = NULL; + + rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args); + if (rc != SEPOL_OK) { +-- +2.32.0 + diff --git a/SOURCES/0029-libsepol-cil-Cleanup-build-AST-helper-functions.patch b/SOURCES/0029-libsepol-cil-Cleanup-build-AST-helper-functions.patch new file mode 100644 index 0000000..74c56d6 --- /dev/null +++ b/SOURCES/0029-libsepol-cil-Cleanup-build-AST-helper-functions.patch @@ -0,0 +1,91 @@ +From f043078f1debeb1c84d4f6943aa689c33dd9cefc Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:13 -0400 +Subject: [PATCH] libsepol/cil: Cleanup build AST helper functions + +Since parse_current, finished, and extra_args can never be NULL, +remove the useless check and directly assign local variables from +extra_args. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 44 ++++++++------------------------ + 1 file changed, 10 insertions(+), 34 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index eee21086bba8..0d6d91a7dc34 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6065,28 +6065,16 @@ void cil_destroy_src_info(struct cil_src_info *info) + + int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args) + { +- struct cil_args_build *args = NULL; +- struct cil_tree_node *ast_current = NULL; +- struct cil_db *db = NULL; ++ struct cil_args_build *args = extra_args; ++ struct cil_db *db = args->db; ++ struct cil_tree_node *ast_current = args->ast; ++ struct cil_tree_node *tunif = args->tunif; ++ struct cil_tree_node *in = args->in; ++ struct cil_tree_node *macro = args->macro; ++ struct cil_tree_node *boolif = args->boolif; + struct cil_tree_node *ast_node = NULL; +- struct cil_tree_node *tunif = NULL; +- struct cil_tree_node *in = NULL; +- struct cil_tree_node *macro = NULL; +- struct cil_tree_node *boolif = NULL; + int rc = SEPOL_ERR; + +- if (parse_current == NULL || finished == NULL || extra_args == NULL) { +- goto exit; +- } +- +- args = extra_args; +- ast_current = args->ast; +- db = args->db; +- tunif = args->tunif; +- in = args->in; +- macro = args->macro; +- boolif = args->boolif; +- + if (parse_current->parent->cl_head != parse_current) { + /* ignore anything that isn't following a parenthesis */ + rc = SEPOL_OK; +@@ -6474,20 +6462,11 @@ exit: + + int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) + { +- int rc = SEPOL_ERR; +- struct cil_tree_node *ast = NULL; +- struct cil_args_build *args = NULL; +- +- if (extra_args == NULL) { +- goto exit; +- } +- +- args = extra_args; +- ast = args->ast; ++ struct cil_args_build *args = extra_args; ++ struct cil_tree_node *ast = args->ast; + + if (ast->flavor == CIL_ROOT) { +- rc = SEPOL_OK; +- goto exit; ++ return SEPOL_OK; + } + + args->ast = ast->parent; +@@ -6516,9 +6495,6 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void + cil_tree_children_destroy(parse_current->parent); + + return SEPOL_OK; +- +-exit: +- return rc; + } + + int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast) +-- +2.32.0 + diff --git a/SOURCES/0030-libsepol-cil-Create-new-first-child-helper-function-.patch b/SOURCES/0030-libsepol-cil-Create-new-first-child-helper-function-.patch new file mode 100644 index 0000000..4a6f6e0 --- /dev/null +++ b/SOURCES/0030-libsepol-cil-Create-new-first-child-helper-function-.patch @@ -0,0 +1,98 @@ +From ab90cb46abd4cfc5927f48c7b61782aa97e2561f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:14 -0400 +Subject: [PATCH] libsepol/cil: Create new first child helper function for + building AST + +In order to find statements not allowed in tunableifs, in-statements, +macros, and booleanifs, there are tree node pointers that point to +each of these kinds of statements when its block is being parsed. +If the pointer is non-NULL, then the rule being parsed is in the block +of that kind of statement. + +The tree node pointers were being updated at the wrong point which +prevented an invalid statement from being found if it was the first +statement in the block of a tunableif, in-statement, macro, or +booleanif. + +Create a first child helper function for walking the parse tree and +in that function set the appropriate tree node pointer if the +current AST node is a tunableif, in-statement, macro, or booleanif. +This also makes the code symmetrical with the last child helper +where the tree node pointers are set to NULL. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 42 +++++++++++++++++++------------- + 1 file changed, 25 insertions(+), 17 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 0d6d91a7dc34..9836f044553c 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6429,22 +6429,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + + if (rc == SEPOL_OK) { + if (ast_current->cl_head == NULL) { +- if (ast_current->flavor == CIL_TUNABLEIF) { +- args->tunif = ast_current; +- } +- +- if (ast_current->flavor == CIL_IN) { +- args->in = ast_current; +- } +- +- if (ast_current->flavor == CIL_MACRO) { +- args->macro = ast_current; +- } +- +- if (ast_current->flavor == CIL_BOOLEANIF) { +- args->boolif = ast_current; +- } +- + ast_current->cl_head = ast_node; + } else { + ast_current->cl_tail->next = ast_node; +@@ -6460,6 +6444,30 @@ exit: + return rc; + } + ++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; ++ ++ if (ast->flavor == CIL_TUNABLEIF) { ++ args->tunif = ast; ++ } ++ ++ if (ast->flavor == CIL_IN) { ++ args->in = ast; ++ } ++ ++ if (ast->flavor == CIL_MACRO) { ++ args->macro = ast; ++ } ++ ++ if (ast->flavor == CIL_BOOLEANIF) { ++ args->boolif = ast; ++ } ++ ++ return SEPOL_OK; ++} ++ + int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) + { + struct cil_args_build *args = extra_args; +@@ -6513,7 +6521,7 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci + extra_args.macro = NULL; + extra_args.boolif = NULL; + +- rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args); ++ rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, __cil_build_ast_first_child_helper, __cil_build_ast_last_child_helper, &extra_args); + if (rc != SEPOL_OK) { + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0031-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch b/SOURCES/0031-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch new file mode 100644 index 0000000..2cdaa58 --- /dev/null +++ b/SOURCES/0031-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch @@ -0,0 +1,249 @@ +From 525f0312d51d3afd48f5e0cd8a58cced3532cfdf Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:15 -0400 +Subject: [PATCH] libsepol/cil: Use AST to track blocks and optionals when + resolving + +When resolving the AST, block and optional stacks are used to +determine if the current rule being resolved is in a block or +an optional. There is no need to do this since the parent node +pointers can be used when exiting a block or an optional to +determine if resolution is still within a block or an optional. + +When entering either a block or an optional, update the appropriate +tree node pointer. When finished with the last child of a block or +optional, set the appropriate pointer to NULL. If a parent of the +same kind is found when the parent node pointers are followed back +to the root node, then set the pointer to that tree node. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 107 +++++++++-------------------- + 1 file changed, 32 insertions(+), 75 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 63beed9230b9..a61462d0eb31 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -52,10 +52,10 @@ struct cil_args_resolve { + enum cil_pass pass; + uint32_t *changed; + struct cil_list *disabled_optionals; +- struct cil_tree_node *optstack; ++ struct cil_tree_node *optional; + struct cil_tree_node *boolif; + struct cil_tree_node *macro; +- struct cil_tree_node *blockstack; ++ struct cil_tree_node *block; + struct cil_list *sidorder_lists; + struct cil_list *classorder_lists; + struct cil_list *unordered_classorder_lists; +@@ -3777,16 +3777,16 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + int rc = SEPOL_ERR; + struct cil_args_resolve *args = extra_args; + enum cil_pass pass = args->pass; +- struct cil_tree_node *optstack = args->optstack; ++ struct cil_tree_node *optional = args->optional; + struct cil_tree_node *boolif = args->boolif; +- struct cil_tree_node *blockstack = args->blockstack; ++ struct cil_tree_node *block = args->block; + struct cil_tree_node *macro = args->macro; + + if (node == NULL) { + goto exit; + } + +- if (optstack != NULL) { ++ if (optional != NULL) { + if (node->flavor == CIL_TUNABLE || node->flavor == CIL_MACRO) { + /* tuanbles and macros are not allowed in optionals*/ + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); +@@ -3795,7 +3795,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + } + } + +- if (blockstack != NULL) { ++ if (block != NULL) { + if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); + rc = SEPOL_ERR; +@@ -3849,11 +3849,11 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + if (rc == SEPOL_ENOENT) { + enum cil_log_level lvl = CIL_ERR; + +- if (optstack != NULL) { ++ if (optional != NULL) { + lvl = CIL_INFO; + +- struct cil_optional *opt = (struct cil_optional *)optstack->data; +- struct cil_tree_node *opt_node = opt->datum.nodes->head->data; ++ struct cil_optional *opt = (struct cil_optional *)optional->data; ++ struct cil_tree_node *opt_node = NODE(opt);; + /* disable an optional if something failed to resolve */ + opt->enabled = CIL_FALSE; + cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); +@@ -3876,39 +3876,18 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex + { + int rc = SEPOL_ERR; + struct cil_args_resolve *args = extra_args; +- struct cil_tree_node *optstack = NULL; + struct cil_tree_node *parent = NULL; +- struct cil_tree_node *blockstack = NULL; +- struct cil_tree_node *new = NULL; + + if (current == NULL || extra_args == NULL) { + goto exit; + } + +- optstack = args->optstack; + parent = current->parent; +- blockstack = args->blockstack; + +- if (parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) { +- /* push this node onto a stack */ +- cil_tree_node_init(&new); +- +- new->data = parent->data; +- new->flavor = parent->flavor; +- +- if (parent->flavor == CIL_OPTIONAL) { +- if (optstack != NULL) { +- optstack->parent = new; +- new->cl_head = optstack; +- } +- args->optstack = new; +- } else if (parent->flavor == CIL_BLOCK) { +- if (blockstack != NULL) { +- blockstack->parent = new; +- new->cl_head = blockstack; +- } +- args->blockstack = new; +- } ++ if (parent->flavor == CIL_BLOCK) { ++ args->block = parent; ++ } else if (parent->flavor == CIL_OPTIONAL) { ++ args->optional = parent; + } else if (parent->flavor == CIL_BOOLEANIF) { + args->boolif = parent; + } else if (parent->flavor == CIL_MACRO) { +@@ -3927,7 +3906,6 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + int rc = SEPOL_ERR; + struct cil_args_resolve *args = extra_args; + struct cil_tree_node *parent = NULL; +- struct cil_tree_node *blockstack = NULL; + + if (current == NULL || extra_args == NULL) { + goto exit; +@@ -3938,30 +3916,31 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + if (parent->flavor == CIL_MACRO) { + args->macro = NULL; + } else if (parent->flavor == CIL_OPTIONAL) { +- struct cil_tree_node *optstack; +- ++ struct cil_tree_node *n = parent->parent; + if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) { + *(args->changed) = CIL_TRUE; + cil_list_append(args->disabled_optionals, CIL_NODE, parent); + } +- +- /* pop off the stack */ +- optstack = args->optstack; +- args->optstack = optstack->cl_head; +- if (optstack->cl_head) { +- optstack->cl_head->parent = NULL; ++ args->optional = NULL; ++ while (n && n->flavor != CIL_ROOT) { ++ if (n->flavor == CIL_OPTIONAL) { ++ args->optional = n; ++ break; ++ } ++ n = n->parent; + } +- free(optstack); + } else if (parent->flavor == CIL_BOOLEANIF) { + args->boolif = NULL; + } else if (parent->flavor == CIL_BLOCK) { +- /* pop off the stack */ +- blockstack = args->blockstack; +- args->blockstack = blockstack->cl_head; +- if (blockstack->cl_head) { +- blockstack->cl_head->parent = NULL; ++ struct cil_tree_node *n = parent->parent; ++ args->block = NULL; ++ while (n && n->flavor != CIL_ROOT) { ++ if (n->flavor == CIL_BLOCK) { ++ args->block = n; ++ break; ++ } ++ n = n->parent; + } +- free(blockstack); + } + + return SEPOL_OK; +@@ -3970,16 +3949,6 @@ exit: + return rc; + } + +-static void cil_destroy_tree_node_stack(struct cil_tree_node *curr) +-{ +- struct cil_tree_node *next; +- while (curr != NULL) { +- next = curr->cl_head; +- free(curr); +- curr = next; +- } +-} +- + int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + { + int rc = SEPOL_ERR; +@@ -3994,7 +3963,8 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.db = db; + extra_args.pass = pass; + extra_args.changed = &changed; +- extra_args.optstack = NULL; ++ extra_args.block = NULL; ++ extra_args.optional = NULL; + extra_args.boolif= NULL; + extra_args.macro = NULL; + extra_args.sidorder_lists = NULL; +@@ -4003,7 +3973,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.catorder_lists = NULL; + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; +- extra_args.blockstack = NULL; + + cil_list_init(&extra_args.disabled_optionals, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); +@@ -4107,17 +4076,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + } + cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); + cil_list_init(&extra_args.disabled_optionals, CIL_NODE); +- } +- +- /* reset the arguments */ +- changed = 0; +- while (extra_args.optstack != NULL) { +- cil_destroy_tree_node_stack(extra_args.optstack); +- extra_args.optstack = NULL; +- } +- while (extra_args.blockstack!= NULL) { +- cil_destroy_tree_node_stack(extra_args.blockstack); +- extra_args.blockstack = NULL; ++ changed = 0; + } + } + +@@ -4128,8 +4087,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + + rc = SEPOL_OK; + exit: +- cil_destroy_tree_node_stack(extra_args.optstack); +- cil_destroy_tree_node_stack(extra_args.blockstack); + __cil_ordered_lists_destroy(&extra_args.sidorder_lists); + __cil_ordered_lists_destroy(&extra_args.classorder_lists); + __cil_ordered_lists_destroy(&extra_args.catorder_lists); +-- +2.32.0 + diff --git a/SOURCES/0032-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch b/SOURCES/0032-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch new file mode 100644 index 0000000..91492f0 --- /dev/null +++ b/SOURCES/0032-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch @@ -0,0 +1,175 @@ +From ef533c8fd941bfb0c9a729b757d8a5b68fe3d080 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:16 -0400 +Subject: [PATCH] libsepol/cil: Reorder checks for invalid rules when resolving + AST + +Reorder checks for invalid rules in the blocks of tunableifs, +in-statements, macros, and booleanifs when resolving the AST for +consistency. + +Order the checks in the same order the blocks will be resolved in, +so tuanbleif, in-statement, macro, booleanif, and then non-block +rules. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 76 +++++++++++++++--------------- + 1 file changed, 39 insertions(+), 37 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index a61462d0eb31..93fc0d633cc7 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -52,10 +52,10 @@ struct cil_args_resolve { + enum cil_pass pass; + uint32_t *changed; + struct cil_list *disabled_optionals; ++ struct cil_tree_node *block; ++ struct cil_tree_node *macro; + struct cil_tree_node *optional; + struct cil_tree_node *boolif; +- struct cil_tree_node *macro; +- struct cil_tree_node *block; + struct cil_list *sidorder_lists; + struct cil_list *classorder_lists; + struct cil_list *unordered_classorder_lists; +@@ -3777,50 +3777,52 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + int rc = SEPOL_ERR; + struct cil_args_resolve *args = extra_args; + enum cil_pass pass = args->pass; +- struct cil_tree_node *optional = args->optional; +- struct cil_tree_node *boolif = args->boolif; + struct cil_tree_node *block = args->block; + struct cil_tree_node *macro = args->macro; ++ struct cil_tree_node *optional = args->optional; ++ struct cil_tree_node *boolif = args->boolif; + + if (node == NULL) { + goto exit; + } + +- if (optional != NULL) { +- if (node->flavor == CIL_TUNABLE || node->flavor == CIL_MACRO) { +- /* tuanbles and macros are not allowed in optionals*/ +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); ++ if (block != NULL) { ++ if (node->flavor == CIL_CAT || ++ node->flavor == CIL_SENS) { ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } + } + +- if (block != NULL) { +- if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); ++ if (macro != NULL) { ++ if (node->flavor == CIL_BLOCK || ++ node->flavor == CIL_BLOCKINHERIT || ++ node->flavor == CIL_BLOCKABSTRACT || ++ node->flavor == CIL_MACRO) { ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } + } + +- if (macro != NULL) { +- if (node->flavor == CIL_BLOCKINHERIT || +- node->flavor == CIL_BLOCK || +- node->flavor == CIL_BLOCKABSTRACT || +- node->flavor == CIL_MACRO) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); ++ if (optional != NULL) { ++ if (node->flavor == CIL_TUNABLE || ++ node->flavor == CIL_MACRO) { ++ /* tuanbles and macros are not allowed in optionals*/ ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } + } + + if (boolif != NULL) { +- if (!(node->flavor == CIL_CONDBLOCK || +- node->flavor == CIL_AVRULE || +- node->flavor == CIL_TYPE_RULE || +- node->flavor == CIL_CALL || +- node->flavor == CIL_TUNABLEIF || +- node->flavor == CIL_NAMETYPETRANSITION)) { ++ if (!(node->flavor == CIL_TUNABLEIF || ++ node->flavor == CIL_CALL || ++ node->flavor == CIL_CONDBLOCK || ++ node->flavor == CIL_AVRULE || ++ node->flavor == CIL_TYPE_RULE || ++ node->flavor == CIL_NAMETYPETRANSITION)) { + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); + } else { +@@ -3886,12 +3888,12 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex + + if (parent->flavor == CIL_BLOCK) { + args->block = parent; ++ } else if (parent->flavor == CIL_MACRO) { ++ args->macro = parent; + } else if (parent->flavor == CIL_OPTIONAL) { + args->optional = parent; + } else if (parent->flavor == CIL_BOOLEANIF) { + args->boolif = parent; +- } else if (parent->flavor == CIL_MACRO) { +- args->macro = parent; + } + + return SEPOL_OK; +@@ -3913,7 +3915,17 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + + parent = current->parent; + +- if (parent->flavor == CIL_MACRO) { ++ if (parent->flavor == CIL_BLOCK) { ++ struct cil_tree_node *n = parent->parent; ++ args->block = NULL; ++ while (n && n->flavor != CIL_ROOT) { ++ if (n->flavor == CIL_BLOCK) { ++ args->block = n; ++ break; ++ } ++ n = n->parent; ++ } ++ } else if (parent->flavor == CIL_MACRO) { + args->macro = NULL; + } else if (parent->flavor == CIL_OPTIONAL) { + struct cil_tree_node *n = parent->parent; +@@ -3931,16 +3943,6 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + } + } else if (parent->flavor == CIL_BOOLEANIF) { + args->boolif = NULL; +- } else if (parent->flavor == CIL_BLOCK) { +- struct cil_tree_node *n = parent->parent; +- args->block = NULL; +- while (n && n->flavor != CIL_ROOT) { +- if (n->flavor == CIL_BLOCK) { +- args->block = n; +- break; +- } +- n = n->parent; +- } + } + + return SEPOL_OK; +@@ -3964,9 +3966,9 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.pass = pass; + extra_args.changed = &changed; + extra_args.block = NULL; ++ extra_args.macro = NULL; + extra_args.optional = NULL; + extra_args.boolif= NULL; +- extra_args.macro = NULL; + extra_args.sidorder_lists = NULL; + extra_args.classorder_lists = NULL; + extra_args.unordered_classorder_lists = NULL; +-- +2.32.0 + diff --git a/SOURCES/0033-libsepol-cil-Sync-checks-for-invalid-rules-in-boolea.patch b/SOURCES/0033-libsepol-cil-Sync-checks-for-invalid-rules-in-boolea.patch new file mode 100644 index 0000000..c55a8fa --- /dev/null +++ b/SOURCES/0033-libsepol-cil-Sync-checks-for-invalid-rules-in-boolea.patch @@ -0,0 +1,86 @@ +From 8a74c05b97050bd226d61fc162e04dcdf8e91247 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:17 -0400 +Subject: [PATCH] libsepol/cil: Sync checks for invalid rules in booleanifs + +When building the AST, typemember rules in a booleanif block will +be incorrectly called invalid. They are allowed in the kernel +policy and should be allowed in CIL. + +When resolving the AST, if a neverallow rule is copied into a +booleanif block, it will not be considered an invalid rule, even +though this is not allowed in the kernel policy. + +Update the booleanif checks to allow typemember rules and to not +allow neverallow rules in booleanifs. Also use the same form of +conditional for the checks when building and resolving the AST. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 3 ++- + libsepol/cil/src/cil_resolve_ast.c | 23 +++++++++++++++-------- + 2 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 9836f044553c..96c944975def 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6130,7 +6130,8 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data != CIL_KEY_DONTAUDIT && + parse_current->data != CIL_KEY_AUDITALLOW && + parse_current->data != CIL_KEY_TYPETRANSITION && +- parse_current->data != CIL_KEY_TYPECHANGE) { ++ parse_current->data != CIL_KEY_TYPECHANGE && ++ parse_current->data != CIL_KEY_TYPEMEMBER) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 93fc0d633cc7..56295a047ba2 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3774,7 +3774,7 @@ exit: + + int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) + { +- int rc = SEPOL_ERR; ++ int rc = SEPOL_OK; + struct cil_args_resolve *args = extra_args; + enum cil_pass pass = args->pass; + struct cil_tree_node *block = args->block; +@@ -3817,18 +3817,25 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + } + + if (boolif != NULL) { +- if (!(node->flavor == CIL_TUNABLEIF || +- node->flavor == CIL_CALL || +- node->flavor == CIL_CONDBLOCK || +- node->flavor == CIL_AVRULE || +- node->flavor == CIL_TYPE_RULE || +- node->flavor == CIL_NAMETYPETRANSITION)) { ++ if (node->flavor != CIL_TUNABLEIF && ++ node->flavor != CIL_CALL && ++ node->flavor != CIL_CONDBLOCK && ++ node->flavor != CIL_AVRULE && ++ node->flavor != CIL_TYPE_RULE && ++ node->flavor != CIL_NAMETYPETRANSITION) { ++ rc = SEPOL_ERR; ++ } else if (node->flavor == CIL_AVRULE) { ++ struct cil_avrule *rule = node->data; ++ if (rule->rule_kind == CIL_AVRULE_NEVERALLOW) { ++ rc = SEPOL_ERR; ++ } ++ } ++ if (rc == SEPOL_ERR) { + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); + } else { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node)); + } +- rc = SEPOL_ERR; + goto exit; + } + } +-- +2.32.0 + diff --git a/SOURCES/0034-libsepol-cil-Check-for-statements-not-allowed-in-opt.patch b/SOURCES/0034-libsepol-cil-Check-for-statements-not-allowed-in-opt.patch new file mode 100644 index 0000000..88ff656 --- /dev/null +++ b/SOURCES/0034-libsepol-cil-Check-for-statements-not-allowed-in-opt.patch @@ -0,0 +1,151 @@ +From 340f0eb7f3673e8aacaf0a96cbfcd4d12a405521 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:18 -0400 +Subject: [PATCH] libsepol/cil: Check for statements not allowed in optional + blocks + +While there are some checks for invalid statements in an optional +block when resolving the AST, there are no checks when building the +AST. + +OSS-Fuzz found the following policy which caused a null dereference +in cil_tree_get_next_path(). + (blockinherit b3) + (sid SID) + (sidorder(SID)) + (optional o + (ibpkeycon :(1 0)s) + (block b3 + (filecon""block()) + (filecon""block()))) + +The problem is that the blockinherit copies block b3 before +the optional block is disabled. When the optional is disabled, +block b3 is deleted along with everything else in the optional. +Later, when filecon statements with the same path are found an +error message is produced and in trying to find out where the block +was copied from, the reference to the deleted block is used. The +error handling code assumes (rightly) that if something was copied +from a block then that block should still exist. + +It is clear that in-statements, blocks, and macros cannot be in an +optional, because that allows nodes to be copied from the optional +block to somewhere outside even though the optional could be disabled +later. When optionals are disabled the AST is reset and the +resolution is restarted at the point of resolving macro calls, so +anything resolved before macro calls will never be re-resolved. +This includes tunableifs, in-statements, blockinherits, +blockabstracts, and macro definitions. Tunable declarations also +cannot be in an optional block because they are needed to resolve +tunableifs. It should be fine to allow blockinherit statements in +an optional, because that is copying nodes from outside the optional +to the optional and if the optional is later disabled, everything +will be deleted anyway. + +Check and quit with an error if a tunable declaration, in-statement, +block, blockabstract, or macro definition is found within an +optional when either building or resolving the AST. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 32 ++++++++++++++++++++++++++++++ + libsepol/cil/src/cil_resolve_ast.c | 4 +++- + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 96c944975def..8825485855f6 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -52,6 +52,7 @@ struct cil_args_build { + struct cil_tree_node *tunif; + struct cil_tree_node *in; + struct cil_tree_node *macro; ++ struct cil_tree_node *optional; + struct cil_tree_node *boolif; + }; + +@@ -6071,6 +6072,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + struct cil_tree_node *tunif = args->tunif; + struct cil_tree_node *in = args->in; + struct cil_tree_node *macro = args->macro; ++ struct cil_tree_node *optional = args->optional; + struct cil_tree_node *boolif = args->boolif; + struct cil_tree_node *ast_node = NULL; + int rc = SEPOL_ERR; +@@ -6121,6 +6123,18 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + } + } + ++ if (optional != NULL) { ++ if (parse_current->data == CIL_KEY_TUNABLE || ++ parse_current->data == CIL_KEY_IN || ++ parse_current->data == CIL_KEY_BLOCK || ++ parse_current->data == CIL_KEY_BLOCKABSTRACT || ++ parse_current->data == CIL_KEY_MACRO) { ++ rc = SEPOL_ERR; ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in optionals", (char *)parse_current->data); ++ goto exit; ++ } ++ } ++ + if (boolif != NULL) { + if (parse_current->data != CIL_KEY_TUNABLEIF && + parse_current->data != CIL_KEY_CALL && +@@ -6462,6 +6476,10 @@ int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_n + args->macro = ast; + } + ++ if (ast->flavor == CIL_OPTIONAL) { ++ args->optional = ast; ++ } ++ + if (ast->flavor == CIL_BOOLEANIF) { + args->boolif = ast; + } +@@ -6492,6 +6510,19 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void + args->macro = NULL; + } + ++ if (ast->flavor == CIL_OPTIONAL) { ++ struct cil_tree_node *n = ast->parent; ++ args->optional = NULL; ++ /* Optionals can be nested */ ++ while (n && n->flavor != CIL_ROOT) { ++ if (n->flavor == CIL_OPTIONAL) { ++ args->optional = n; ++ break; ++ } ++ n = n->parent; ++ } ++ } ++ + if (ast->flavor == CIL_BOOLEANIF) { + args->boolif = NULL; + } +@@ -6520,6 +6551,7 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci + extra_args.tunif = NULL; + extra_args.in = NULL; + extra_args.macro = NULL; ++ extra_args.optional = NULL; + extra_args.boolif = NULL; + + rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, __cil_build_ast_first_child_helper, __cil_build_ast_last_child_helper, &extra_args); +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 56295a047ba2..efff0f2ec49d 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3808,8 +3808,10 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + + if (optional != NULL) { + if (node->flavor == CIL_TUNABLE || ++ node->flavor == CIL_IN || ++ node->flavor == CIL_BLOCK || ++ node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { +- /* tuanbles and macros are not allowed in optionals*/ + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0035-libsepol-cil-Sync-checks-for-invalid-rules-in-macros.patch b/SOURCES/0035-libsepol-cil-Sync-checks-for-invalid-rules-in-macros.patch new file mode 100644 index 0000000..e96ec87 --- /dev/null +++ b/SOURCES/0035-libsepol-cil-Sync-checks-for-invalid-rules-in-macros.patch @@ -0,0 +1,35 @@ +From f38b7ea300e83d4b14d817c35f4ff24071e4990e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:19 -0400 +Subject: [PATCH] libsepol/cil: Sync checks for invalid rules in macros + +When resolving the AST, tunable and in-statements are not considered +to be invalid in macros. This is inconsistent with the checks when +building the AST. + +Add checks to make tunable and in-statments invalid in macros when +resolving the AST. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index efff0f2ec49d..7229a3b4e990 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3796,7 +3796,9 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + } + + if (macro != NULL) { +- if (node->flavor == CIL_BLOCK || ++ if (node->flavor == CIL_TUNABLE || ++ node->flavor == CIL_IN || ++ node->flavor == CIL_BLOCK || + node->flavor == CIL_BLOCKINHERIT || + node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { +-- +2.32.0 + diff --git a/SOURCES/0036-libsepol-cil-Do-not-allow-tunable-declarations-in-in.patch b/SOURCES/0036-libsepol-cil-Do-not-allow-tunable-declarations-in-in.patch new file mode 100644 index 0000000..144a167 --- /dev/null +++ b/SOURCES/0036-libsepol-cil-Do-not-allow-tunable-declarations-in-in.patch @@ -0,0 +1,35 @@ +From ea34dbf041f0c75f2b0261ddf6fa014121d69a1a Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:20 -0400 +Subject: [PATCH] libsepol/cil: Do not allow tunable declarations in + in-statements + +Since tunableifs are resolved before in-statements, do not allow +tuanble declarations in in-statements. + +Since in-statements are the first flavor of statement that causes +part of the AST to be copied to another part, there is no need to +check the in-statements when resolving the AST. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 8825485855f6..3f83c228fec1 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6102,7 +6102,8 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + } + + if (in != NULL) { +- if (parse_current->data == CIL_KEY_IN) { ++ if (parse_current->data == CIL_KEY_TUNABLE || ++ parse_current->data == CIL_KEY_IN) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); + cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); +-- +2.32.0 + diff --git a/SOURCES/0037-libsepol-cil-Make-invalid-statement-error-messages-c.patch b/SOURCES/0037-libsepol-cil-Make-invalid-statement-error-messages-c.patch new file mode 100644 index 0000000..7485154 --- /dev/null +++ b/SOURCES/0037-libsepol-cil-Make-invalid-statement-error-messages-c.patch @@ -0,0 +1,120 @@ +From ca339eb49da6fe5b191de5c3ee7196453fa14e23 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:40:01 -0400 +Subject: [PATCH] libsepol/cil: Make invalid statement error messages + consistent + +Use a consistent style for the error messages when an invalid +statement is found within tunableif, in-statement, block, macro, +optional, and booleanif blocks. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 17 ++++++----------- + libsepol/cil/src/cil_resolve_ast.c | 10 +++++----- + 2 files changed, 11 insertions(+), 16 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 3f83c228fec1..5b1e28246b2e 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6095,8 +6095,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (tunif != NULL) { + if (parse_current->data == CIL_KEY_TUNABLE) { + rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "Found tunable"); +- cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in tunableif", (char *)parse_current->data); + goto exit; + } + } +@@ -6105,8 +6104,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (parse_current->data == CIL_KEY_TUNABLE || + parse_current->data == CIL_KEY_IN) { + rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); +- cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in in-statement", (char *)parse_current->data); + goto exit; + } + } +@@ -6119,7 +6117,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data == CIL_KEY_BLOCKABSTRACT || + parse_current->data == CIL_KEY_MACRO) { + rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macros", (char *)parse_current->data); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macro", (char *)parse_current->data); + goto exit; + } + } +@@ -6131,7 +6129,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data == CIL_KEY_BLOCKABSTRACT || + parse_current->data == CIL_KEY_MACRO) { + rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in optionals", (char *)parse_current->data); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in optional", (char *)parse_current->data); + goto exit; + } + } +@@ -6148,13 +6146,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data != CIL_KEY_TYPECHANGE && + parse_current->data != CIL_KEY_TYPEMEMBER) { + rc = SEPOL_ERR; +- cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { +- cil_log(CIL_ERR, "%s cannot be defined within tunableif statement (treated as a booleanif due to preserve-tunables)\n", +- (char*)parse_current->data); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in tunableif being treated as a booleanif", (char *)parse_current->data); + } else { +- cil_log(CIL_ERR, "%s cannot be defined within booleanif statement\n", +- (char*)parse_current->data); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in booleanif", (char *)parse_current->data); + } + goto exit; + } +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 7229a3b4e990..872b6799b0bf 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3789,7 +3789,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + if (block != NULL) { + if (node->flavor == CIL_CAT || + node->flavor == CIL_SENS) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); ++ cil_tree_log(node, CIL_ERR, "%s is not allowed in block", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3802,7 +3802,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + node->flavor == CIL_BLOCKINHERIT || + node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); ++ cil_tree_log(node, CIL_ERR, "%s is not allowed in macro", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3814,7 +3814,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + node->flavor == CIL_BLOCK || + node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); ++ cil_tree_log(node, CIL_ERR, "%s is not allowed in optional", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3836,9 +3836,9 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + } + if (rc == SEPOL_ERR) { + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); ++ cil_tree_log(node, CIL_ERR, "%s is not allowed in tunableif being treated as a booleanif", cil_node_to_string(node)); + } else { +- cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node)); ++ cil_tree_log(node, CIL_ERR, "%s is not allowed in booleanif", cil_node_to_string(node)); + } + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0038-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch b/SOURCES/0038-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch new file mode 100644 index 0000000..ba05f81 --- /dev/null +++ b/SOURCES/0038-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch @@ -0,0 +1,58 @@ +From 8314076cd9cd71ee7ee3c5e668c1f0472ea8b815 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:40:02 -0400 +Subject: [PATCH] libsepol/cil: Use CIL_ERR for error messages in cil_compile() + +In cil_compile(), CIL_INFO is being used as the priority for +error messages. This can make it difficult to tell when the error +occurred. + +Instead, use CIL_ERR as the priority for the error messages in +cil_compile(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 99c8e288912c..b971922c70b5 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -539,7 +539,7 @@ int cil_compile(struct cil_db *db) + cil_log(CIL_INFO, "Building AST from Parse Tree\n"); + rc = cil_build_ast(db, db->parse->root, db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to build ast\n"); ++ cil_log(CIL_ERR, "Failed to build AST\n"); + goto exit; + } + +@@ -549,21 +549,21 @@ int cil_compile(struct cil_db *db) + cil_log(CIL_INFO, "Resolving AST\n"); + rc = cil_resolve_ast(db, db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to resolve ast\n"); ++ cil_log(CIL_ERR, "Failed to resolve AST\n"); + goto exit; + } + + cil_log(CIL_INFO, "Qualifying Names\n"); + rc = cil_fqn_qualify(db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to qualify names\n"); ++ cil_log(CIL_ERR, "Failed to qualify names\n"); + goto exit; + } + + cil_log(CIL_INFO, "Compile post process\n"); + rc = cil_post_process(db); + if (rc != SEPOL_OK ) { +- cil_log(CIL_INFO, "Post process failed\n"); ++ cil_log(CIL_ERR, "Post process failed\n"); + goto exit; + } + +-- +2.32.0 + diff --git a/SOURCES/0039-libsepol-cil-Create-functions-to-write-the-CIL-AST.patch b/SOURCES/0039-libsepol-cil-Create-functions-to-write-the-CIL-AST.patch new file mode 100644 index 0000000..c5784dc --- /dev/null +++ b/SOURCES/0039-libsepol-cil-Create-functions-to-write-the-CIL-AST.patch @@ -0,0 +1,3162 @@ +From 0b31424ac714ccff963defe8401f20357fc6bcce Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 21 Apr 2021 13:21:10 -0400 +Subject: [PATCH] libsepol/cil: Create functions to write the CIL AST + +The function cil_print_tree() has existed in cil_tree.c since the +beginning of the development of CIL and secilc. Unfortunately, it +used cil_log() at log level CIL_INFO to print out the AST and +has suffered greatly from bit rot. + +Move the functions to write the CIL AST to cil_write_ast.c, update +the functions, and write the AST to the FILE pointer passed in as +an argument. + +The function cil_write_ast() supports writing the CIL AST at three +different phases of the compiling a CIL policy. After parsing has +been done and the parse tree has been created, after the CIL AST +has been built, and after the CIL AST has been resolved. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_tree.c | 1471 ---------------------------- + libsepol/cil/src/cil_tree.h | 2 - + libsepol/cil/src/cil_write_ast.c | 1573 ++++++++++++++++++++++++++++++ + libsepol/cil/src/cil_write_ast.h | 46 + + 4 files changed, 1619 insertions(+), 1473 deletions(-) + create mode 100644 libsepol/cil/src/cil_write_ast.c + create mode 100644 libsepol/cil/src/cil_write_ast.h + +diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c +index 3da972e9cf4e..067268eb897c 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" + +-void cil_tree_print_perms_list(struct cil_tree_node *current_perm); +-void cil_tree_print_classperms(struct cil_classperms *cp); +-void cil_tree_print_level(struct cil_level *level); +-void cil_tree_print_levelrange(struct cil_levelrange *lvlrange); +-void cil_tree_print_context(struct cil_context *context); +-void cil_tree_print_expr_tree(struct cil_tree_node *expr_root); +-void cil_tree_print_constrain(struct cil_constrain *cons); +-void cil_tree_print_node(struct cil_tree_node *node); +- + __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_error(const char* msg, ...) + { + va_list ap; +@@ -328,1465 +319,3 @@ int cil_tree_walk(struct cil_tree_node *node, + + return SEPOL_OK; + } +- +- +-/* Copied from cil_policy.c, but changed to prefix -- Need to refactor */ +-static int cil_expr_to_string(struct cil_list *expr, char **out) +-{ +- int rc = SEPOL_ERR; +- struct cil_list_item *curr; +- char *stack[COND_EXPR_MAXDEPTH] = {}; +- int pos = 0; +- +- cil_list_for_each(curr, expr) { +- if (pos >= COND_EXPR_MAXDEPTH) { +- rc = SEPOL_ERR; +- goto exit; +- } +- switch (curr->flavor) { +- case CIL_LIST: +- rc = cil_expr_to_string(curr->data, &stack[pos]); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- pos++; +- break; +- case CIL_STRING: +- stack[pos] = curr->data; +- pos++; +- break; +- case CIL_DATUM: +- stack[pos] = ((struct cil_symtab_datum *)curr->data)->name; +- pos++; +- break; +- case CIL_OP: { +- int len; +- char *expr_str; +- enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data); +- char *op_str = NULL; +- +- if (pos == 0) { +- rc = SEPOL_ERR; +- goto exit; +- } +- switch (op_flavor) { +- case CIL_AND: +- op_str = CIL_KEY_AND; +- break; +- case CIL_OR: +- op_str = CIL_KEY_OR; +- break; +- case CIL_NOT: +- op_str = CIL_KEY_NOT; +- break; +- case CIL_ALL: +- op_str = CIL_KEY_ALL; +- break; +- case CIL_EQ: +- op_str = CIL_KEY_EQ; +- break; +- case CIL_NEQ: +- op_str = CIL_KEY_NEQ; +- break; +- case CIL_XOR: +- op_str = CIL_KEY_XOR; +- break; +- case CIL_RANGE: +- op_str = CIL_KEY_RANGE; +- break; +- case CIL_CONS_DOM: +- op_str = CIL_KEY_CONS_DOM; +- break; +- case CIL_CONS_DOMBY: +- op_str = CIL_KEY_CONS_DOMBY; +- break; +- case CIL_CONS_INCOMP: +- op_str = CIL_KEY_CONS_INCOMP; +- break; +- default: +- cil_log(CIL_ERR, "Unknown operator in expression\n"); +- goto exit; +- break; +- } +- if (op_flavor == CIL_NOT) { +- len = strlen(stack[pos-1]) + strlen(op_str) + 4; +- expr_str = cil_malloc(len); +- snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]); +- free(stack[pos-1]); +- stack[pos-1] = NULL; +- pos--; +- } else { +- if (pos < 2) { +- rc = SEPOL_ERR; +- goto exit; +- } +- len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5; +- expr_str = cil_malloc(len); +- snprintf(expr_str, len, "(%s %s %s)", op_str, stack[pos-1], stack[pos-2]); +- free(stack[pos-2]); +- free(stack[pos-1]); +- stack[pos-2] = NULL; +- stack[pos-1] = NULL; +- pos -= 2; +- } +- stack[pos] = expr_str; +- pos++; +- break; +- } +- case CIL_CONS_OPERAND: { +- enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data); +- char *operand_str = NULL; +- switch (operand_flavor) { +- case CIL_CONS_U1: +- operand_str = CIL_KEY_CONS_U1; +- break; +- case CIL_CONS_U2: +- operand_str = CIL_KEY_CONS_U2; +- break; +- case CIL_CONS_U3: +- operand_str = CIL_KEY_CONS_U3; +- break; +- case CIL_CONS_T1: +- operand_str = CIL_KEY_CONS_T1; +- break; +- case CIL_CONS_T2: +- operand_str = CIL_KEY_CONS_T2; +- break; +- case CIL_CONS_T3: +- operand_str = CIL_KEY_CONS_T3; +- break; +- case CIL_CONS_R1: +- operand_str = CIL_KEY_CONS_R1; +- break; +- case CIL_CONS_R2: +- operand_str = CIL_KEY_CONS_R2; +- break; +- case CIL_CONS_R3: +- operand_str = CIL_KEY_CONS_R3; +- break; +- case CIL_CONS_L1: +- operand_str = CIL_KEY_CONS_L1; +- break; +- case CIL_CONS_L2: +- operand_str = CIL_KEY_CONS_L2; +- break; +- case CIL_CONS_H1: +- operand_str = CIL_KEY_CONS_H1; +- break; +- case CIL_CONS_H2: +- operand_str = CIL_KEY_CONS_H2; +- break; +- default: +- cil_log(CIL_ERR, "Unknown operand in expression\n"); +- goto exit; +- break; +- } +- stack[pos] = operand_str; +- pos++; +- break; +- } +- default: +- cil_log(CIL_ERR, "Unknown flavor in expression\n"); +- goto exit; +- break; +- } +- } +- +- *out = stack[0]; +- +- return SEPOL_OK; +- +-exit: +- return rc; +-} +- +-void cil_tree_print_expr(struct cil_list *datum_expr, struct cil_list *str_expr) +-{ +- char *expr_str; +- int rc; +- +- cil_log(CIL_INFO, "("); +- +- if (datum_expr != NULL) { +- rc = cil_expr_to_string(datum_expr, &expr_str); +- } else { +- rc = cil_expr_to_string(str_expr, &expr_str); +- } +- if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "ERROR)"); +- return; +- } +- cil_log(CIL_INFO, "%s)", expr_str); +- free(expr_str); +-} +- +-void cil_tree_print_perms_list(struct cil_tree_node *current_perm) +-{ +- while (current_perm != NULL) { +- if (current_perm->flavor == CIL_PERM) { +- cil_log(CIL_INFO, " %s", ((struct cil_perm *)current_perm->data)->datum.name); +- } else if (current_perm->flavor == CIL_MAP_PERM) { +- cil_log(CIL_INFO, " %s", ((struct cil_perm*)current_perm->data)->datum.name); +- } else { +- cil_log(CIL_INFO, "\n\n perms list contained unexpected data type: %d\n", current_perm->flavor); +- break; +- } +- current_perm = current_perm->next; +- } +-} +- +-void cil_tree_print_cats(struct cil_cats *cats) +-{ +- cil_tree_print_expr(cats->datum_expr, cats->str_expr); +-} +- +-void cil_tree_print_perm_strs(struct cil_list *perm_strs) +-{ +- struct cil_list_item *curr; +- +- if (perm_strs == NULL) { +- return; +- } +- +- cil_log(CIL_INFO, " ("); +- +- cil_list_for_each(curr, perm_strs) { +- cil_log(CIL_INFO, " %s", (char*)curr->data); +- } +- +- cil_log(CIL_INFO, " )"); +-} +- +- +-void cil_tree_print_classperms(struct cil_classperms *cp) +-{ +- if (cp == NULL) { +- return; +- } +- +- cil_log(CIL_INFO, " class: %s", cp->class_str); +- cil_log(CIL_INFO, ", perm_strs:"); +- cil_tree_print_perm_strs(cp->perm_strs); +-} +- +-void cil_tree_print_classperms_set(struct cil_classperms_set *cp_set) +-{ +- if (cp_set == NULL) { +- return; +- } +- +- cil_log(CIL_INFO, " %s", cp_set->set_str); +-} +- +-void cil_tree_print_classperms_list(struct cil_list *cp_list) +-{ +- struct cil_list_item *i; +- +- if (cp_list == NULL) { +- return; +- } +- +- cil_list_for_each(i, cp_list) { +- if (i->flavor == CIL_CLASSPERMS) { +- cil_tree_print_classperms(i->data); +- } else { +- cil_tree_print_classperms_set(i->data); +- } +- } +-} +- +-void cil_tree_print_level(struct cil_level *level) +-{ +- if (level->sens != NULL) { +- cil_log(CIL_INFO, " %s", level->sens->datum.name); +- } else if (level->sens_str != NULL) { +- cil_log(CIL_INFO, " %s", level->sens_str); +- } +- +- cil_tree_print_cats(level->cats); +- +- return; +-} +- +-void cil_tree_print_levelrange(struct cil_levelrange *lvlrange) +-{ +- cil_log(CIL_INFO, " ("); +- if (lvlrange->low != NULL) { +- cil_log(CIL_INFO, " ("); +- cil_tree_print_level(lvlrange->low); +- cil_log(CIL_INFO, " )"); +- } else if (lvlrange->low_str != NULL) { +- cil_log(CIL_INFO, " %s", lvlrange->low_str); +- } +- +- if (lvlrange->high != NULL) { +- cil_log(CIL_INFO, " ("); +- cil_tree_print_level(lvlrange->high); +- cil_log(CIL_INFO, " )"); +- } else if (lvlrange->high_str != NULL) { +- cil_log(CIL_INFO, " %s", lvlrange->high_str); +- } +- cil_log(CIL_INFO, " )"); +-} +- +-void cil_tree_print_context(struct cil_context *context) +-{ +- cil_log(CIL_INFO, " ("); +- if (context->user != NULL) { +- cil_log(CIL_INFO, " %s", context->user->datum.name); +- } else if (context->user_str != NULL) { +- cil_log(CIL_INFO, " %s", context->user_str); +- } +- +- if (context->role != NULL) { +- cil_log(CIL_INFO, " %s", context->role->datum.name); +- } else if (context->role_str != NULL) { +- cil_log(CIL_INFO, " %s", context->role_str); +- } +- +- if (context->type != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)context->type)->name); +- } else if (context->type_str != NULL) { +- cil_log(CIL_INFO, " %s", context->type_str); +- } +- +- if (context->range != NULL) { +- cil_tree_print_levelrange(context->range); +- } else if (context->range_str != NULL) { +- cil_log(CIL_INFO, " %s", context->range_str); +- } +- +- cil_log(CIL_INFO, " )"); +- +- return; +-} +- +-void cil_tree_print_constrain(struct cil_constrain *cons) +-{ +- cil_tree_print_classperms_list(cons->classperms); +- +- cil_tree_print_expr(cons->datum_expr, cons->str_expr); +- +- cil_log(CIL_INFO, "\n"); +-} +- +-void cil_tree_print_node(struct cil_tree_node *node) +-{ +- if (node->data == NULL) { +- cil_log(CIL_INFO, "FLAVOR: %d", node->flavor); +- return; +- } else { +- switch( node->flavor ) { +- case CIL_BLOCK: { +- struct cil_block *block = node->data; +- cil_log(CIL_INFO, "BLOCK: %s\n", block->datum.name); +- return; +- } +- case CIL_BLOCKINHERIT: { +- struct cil_blockinherit *inherit = node->data; +- cil_log(CIL_INFO, "BLOCKINHERIT: %s\n", inherit->block_str); +- return; +- } +- case CIL_BLOCKABSTRACT: { +- struct cil_blockabstract *abstract = node->data; +- cil_log(CIL_INFO, "BLOCKABSTRACT: %s\n", abstract->block_str); +- return; +- } +- case CIL_IN: { +- struct cil_in *in = node->data; +- cil_log(CIL_INFO, "IN: %s\n", in->block_str); +- return; +- } +- case CIL_USER: { +- struct cil_user *user = node->data; +- cil_log(CIL_INFO, "USER: %s\n", user->datum.name); +- return; +- } +- case CIL_TYPE: { +- struct cil_type *type = node->data; +- cil_log(CIL_INFO, "TYPE: %s\n", type->datum.name); +- return; +- } +- case CIL_EXPANDTYPEATTRIBUTE: { +- struct cil_expandtypeattribute *attr = node->data; +- +- cil_log(CIL_INFO, "(EXPANDTYPEATTRIBUTE "); +- cil_tree_print_expr(attr->attr_datums, attr->attr_strs); +- cil_log(CIL_INFO, "%s)\n",attr->expand ? +- CIL_KEY_CONDTRUE : CIL_KEY_CONDFALSE); +- +- return; +- } +- case CIL_TYPEATTRIBUTESET: { +- struct cil_typeattributeset *attr = node->data; +- +- cil_log(CIL_INFO, "(TYPEATTRIBUTESET %s ", attr->attr_str); +- +- cil_tree_print_expr(attr->datum_expr, attr->str_expr); +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_TYPEATTRIBUTE: { +- struct cil_typeattribute *attr = node->data; +- cil_log(CIL_INFO, "TYPEATTRIBUTE: %s\n", attr->datum.name); +- return; +- } +- case CIL_ROLE: { +- struct cil_role *role = node->data; +- cil_log(CIL_INFO, "ROLE: %s\n", role->datum.name); +- return; +- } +- case CIL_USERROLE: { +- struct cil_userrole *userrole = node->data; +- cil_log(CIL_INFO, "USERROLE:"); +- struct cil_symtab_datum *datum = NULL; +- +- if (userrole->user != NULL) { +- datum = userrole->user; +- cil_log(CIL_INFO, " %s", datum->name); +- } else if (userrole->user_str != NULL) { +- cil_log(CIL_INFO, " %s", userrole->user_str); +- } +- +- if (userrole->role != NULL) { +- datum = userrole->role; +- cil_log(CIL_INFO, " %s", datum->name); +- } else if (userrole->role_str != NULL) { +- cil_log(CIL_INFO, " %s", userrole->role_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_USERLEVEL: { +- struct cil_userlevel *usrlvl = node->data; +- cil_log(CIL_INFO, "USERLEVEL:"); +- +- if (usrlvl->user_str != NULL) { +- cil_log(CIL_INFO, " %s", usrlvl->user_str); +- } +- +- if (usrlvl->level != NULL) { +- cil_log(CIL_INFO, " ("); +- cil_tree_print_level(usrlvl->level); +- cil_log(CIL_INFO, " )"); +- } else if (usrlvl->level_str != NULL) { +- cil_log(CIL_INFO, " %s", usrlvl->level_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_USERRANGE: { +- struct cil_userrange *userrange = node->data; +- cil_log(CIL_INFO, "USERRANGE:"); +- +- if (userrange->user_str != NULL) { +- cil_log(CIL_INFO, " %s", userrange->user_str); +- } +- +- if (userrange->range != NULL) { +- cil_log(CIL_INFO, " ("); +- cil_tree_print_levelrange(userrange->range); +- cil_log(CIL_INFO, " )"); +- } else if (userrange->range_str != NULL) { +- cil_log(CIL_INFO, " %s", userrange->range_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_USERBOUNDS: { +- struct cil_bounds *bnds = node->data; +- cil_log(CIL_INFO, "USERBOUNDS: user: %s, bounds: %s\n", bnds->parent_str, bnds->child_str); +- return; +- } +- case CIL_ROLETYPE: { +- struct cil_roletype *roletype = node->data; +- struct cil_symtab_datum *datum = NULL; +- cil_log(CIL_INFO, "ROLETYPE:"); +- +- if (roletype->role != NULL) { +- datum = roletype->role; +- cil_log(CIL_INFO, " %s", datum->name); +- } else if (roletype->role_str != NULL) { +- cil_log(CIL_INFO, " %s", roletype->role_str); +- } +- +- if (roletype->type != NULL) { +- datum = roletype->type; +- cil_log(CIL_INFO, " %s", datum->name); +- } else if (roletype->type_str != NULL) { +- cil_log(CIL_INFO, " %s", roletype->type_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_ROLETRANSITION: { +- struct cil_roletransition *roletrans = node->data; +- cil_log(CIL_INFO, "ROLETRANSITION:"); +- +- if (roletrans->src != NULL) { +- cil_log(CIL_INFO, " %s", roletrans->src->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", roletrans->src_str); +- } +- +- if (roletrans->tgt != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)roletrans->tgt)->name); +- } else { +- cil_log(CIL_INFO, " %s", roletrans->tgt_str); +- } +- +- if (roletrans->obj != NULL) { +- cil_log(CIL_INFO, " %s", roletrans->obj->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", roletrans->obj_str); +- } +- +- if (roletrans->result != NULL) { +- cil_log(CIL_INFO, " %s\n", roletrans->result->datum.name); +- } else { +- cil_log(CIL_INFO, " %s\n", roletrans->result_str); +- } +- +- return; +- } +- case CIL_ROLEALLOW: { +- struct cil_roleallow *roleallow = node->data; +- cil_log(CIL_INFO, "ROLEALLOW:"); +- +- if (roleallow->src != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->src)->name); +- } else { +- cil_log(CIL_INFO, " %s", roleallow->src_str); +- } +- +- if (roleallow->tgt != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->tgt)->name); +- } else { +- cil_log(CIL_INFO, " %s", roleallow->tgt_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_ROLEATTRIBUTESET: { +- struct cil_roleattributeset *attr = node->data; +- +- cil_log(CIL_INFO, "(ROLEATTRIBUTESET %s ", attr->attr_str); +- +- cil_tree_print_expr(attr->datum_expr, attr->str_expr); +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_ROLEATTRIBUTE: { +- struct cil_roleattribute *attr = node->data; +- cil_log(CIL_INFO, "ROLEATTRIBUTE: %s\n", attr->datum.name); +- return; +- } +- case CIL_USERATTRIBUTESET: { +- struct cil_userattributeset *attr = node->data; +- +- cil_log(CIL_INFO, "(USERATTRIBUTESET %s ", attr->attr_str); +- +- cil_tree_print_expr(attr->datum_expr, attr->str_expr); +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_USERATTRIBUTE: { +- struct cil_userattribute *attr = node->data; +- cil_log(CIL_INFO, "USERATTRIBUTE: %s\n", attr->datum.name); +- return; +- } +- case CIL_ROLEBOUNDS: { +- struct cil_bounds *bnds = node->data; +- cil_log(CIL_INFO, "ROLEBOUNDS: role: %s, bounds: %s\n", bnds->parent_str, bnds->child_str); +- return; +- } +- case CIL_CLASS: { +- struct cil_class *cls = node->data; +- cil_log(CIL_INFO, "CLASS: %s ", cls->datum.name); +- +- if (cls->common != NULL) { +- cil_log(CIL_INFO, "inherits: %s ", cls->common->datum.name); +- } +- cil_log(CIL_INFO, "("); +- +- cil_tree_print_perms_list(node->cl_head); +- +- cil_log(CIL_INFO, " )"); +- return; +- } +- case CIL_CLASSORDER: { +- struct cil_classorder *classorder = node->data; +- struct cil_list_item *class; +- +- if (classorder->class_list_str == NULL) { +- cil_log(CIL_INFO, "CLASSORDER: ()\n"); +- return; +- } +- +- cil_log(CIL_INFO, "CLASSORDER: ("); +- cil_list_for_each(class, classorder->class_list_str) { +- cil_log(CIL_INFO, " %s", (char*)class->data); +- } +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_COMMON: { +- struct cil_class *common = node->data; +- cil_log(CIL_INFO, "COMMON: %s (", common->datum.name); +- +- cil_tree_print_perms_list(node->cl_head); +- +- cil_log(CIL_INFO, " )"); +- return; +- } +- case CIL_CLASSCOMMON: { +- struct cil_classcommon *clscom = node->data; +- +- cil_log(CIL_INFO, "CLASSCOMMON: class: %s, common: %s\n", clscom->class_str, clscom->common_str); +- +- return; +- } +- case CIL_CLASSPERMISSION: { +- struct cil_classpermission *cp = node->data; +- +- cil_log(CIL_INFO, "CLASSPERMISSION: %s", cp->datum.name); +- +- cil_log(CIL_INFO, "\n"); +- +- return; +- } +- case CIL_CLASSPERMISSIONSET: { +- struct cil_classpermissionset *cps = node->data; +- +- cil_log(CIL_INFO, "CLASSPERMISSIONSET: %s", cps->set_str); +- +- cil_tree_print_classperms_list(cps->classperms); +- +- cil_log(CIL_INFO, "\n"); +- +- return; +- } +- case CIL_MAP_CLASS: { +- struct cil_class *cm = node->data; +- cil_log(CIL_INFO, "MAP_CLASS: %s", cm->datum.name); +- +- cil_log(CIL_INFO, " ("); +- cil_tree_print_perms_list(node->cl_head); +- cil_log(CIL_INFO, " )\n"); +- +- return; +- } +- case CIL_MAP_PERM: { +- struct cil_perm *cmp = node->data; +- +- cil_log(CIL_INFO, "MAP_PERM: %s", cmp->datum.name); +- +- if (cmp->classperms == NULL) { +- cil_log(CIL_INFO, " perms: ()"); +- return; +- } +- +- cil_log(CIL_INFO, " kernel class perms: ("); +- +- cil_tree_print_classperms_list(cmp->classperms); +- +- cil_log(CIL_INFO, " )\n"); +- +- return; +- } +- case CIL_CLASSMAPPING: { +- struct cil_classmapping *mapping = node->data; +- +- cil_log(CIL_INFO, "CLASSMAPPING: map class: %s, map perm: %s,", mapping->map_class_str, mapping->map_perm_str); +- +- cil_log(CIL_INFO, " ("); +- +- cil_tree_print_classperms_list(mapping->classperms); +- +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_BOOL: { +- struct cil_bool *boolean = node->data; +- cil_log(CIL_INFO, "BOOL: %s, value: %d\n", boolean->datum.name, boolean->value); +- return; +- } +- case CIL_TUNABLE: { +- struct cil_tunable *tunable = node->data; +- cil_log(CIL_INFO, "TUNABLE: %s, value: %d\n", tunable->datum.name, tunable->value); +- return; +- } +- case CIL_BOOLEANIF: { +- struct cil_booleanif *bif = node->data; +- +- cil_log(CIL_INFO, "(BOOLEANIF "); +- +- cil_tree_print_expr(bif->datum_expr, bif->str_expr); +- +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_TUNABLEIF: { +- struct cil_tunableif *tif = node->data; +- +- cil_log(CIL_INFO, "(TUNABLEIF "); +- +- cil_tree_print_expr(tif->datum_expr, tif->str_expr); +- +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_CONDBLOCK: { +- struct cil_condblock *cb = node->data; +- if (cb->flavor == CIL_CONDTRUE) { +- cil_log(CIL_INFO, "true\n"); +- } else if (cb->flavor == CIL_CONDFALSE) { +- cil_log(CIL_INFO, "false\n"); +- } +- return; +- } +- case CIL_ALL: +- cil_log(CIL_INFO, "all"); +- return; +- case CIL_AND: +- cil_log(CIL_INFO, "&&"); +- return; +- case CIL_OR: +- cil_log(CIL_INFO, "|| "); +- return; +- case CIL_NOT: +- cil_log(CIL_INFO, "!"); +- return; +- case CIL_EQ: +- cil_log(CIL_INFO, "=="); +- return; +- case CIL_NEQ: +- cil_log(CIL_INFO, "!="); +- return; +- case CIL_TYPEALIAS: { +- struct cil_alias *alias = node->data; +- cil_log(CIL_INFO, "TYPEALIAS: %s\n", alias->datum.name); +- return; +- } +- case CIL_TYPEALIASACTUAL: { +- struct cil_aliasactual *aliasactual = node->data; +- cil_log(CIL_INFO, "TYPEALIASACTUAL: type: %s, alias: %s\n", aliasactual->alias_str, aliasactual->actual_str); +- return; +- } +- case CIL_TYPEBOUNDS: { +- struct cil_bounds *bnds = node->data; +- cil_log(CIL_INFO, "TYPEBOUNDS: type: %s, bounds: %s\n", bnds->parent_str, bnds->child_str); +- return; +- } +- case CIL_TYPEPERMISSIVE: { +- struct cil_typepermissive *typeperm = node->data; +- +- if (typeperm->type != NULL) { +- cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", ((struct cil_symtab_datum *)typeperm->type)->name); +- } else { +- cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", typeperm->type_str); +- } +- +- return; +- } +- case CIL_NAMETYPETRANSITION: { +- struct cil_nametypetransition *nametypetrans = node->data; +- cil_log(CIL_INFO, "TYPETRANSITION:"); +- +- if (nametypetrans->src != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->src)->name); +- } else { +- cil_log(CIL_INFO, " %s", nametypetrans->src_str); +- } +- +- if (nametypetrans->tgt != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->tgt)->name); +- } else { +- cil_log(CIL_INFO, " %s", nametypetrans->tgt_str); +- } +- +- if (nametypetrans->obj != NULL) { +- cil_log(CIL_INFO, " %s", nametypetrans->obj->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", nametypetrans->obj_str); +- } +- +- cil_log(CIL_INFO, " %s\n", nametypetrans->name_str); +- +- if (nametypetrans->result != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->result)->name); +- } else { +- cil_log(CIL_INFO, " %s", nametypetrans->result_str); +- } +- +- return; +- } +- case CIL_RANGETRANSITION: { +- struct cil_rangetransition *rangetrans = node->data; +- cil_log(CIL_INFO, "RANGETRANSITION:"); +- +- if (rangetrans->src != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->src)->name); +- } else { +- cil_log(CIL_INFO, " %s", rangetrans->src_str); +- } +- +- if (rangetrans->exec != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->exec)->name); +- } else { +- cil_log(CIL_INFO, " %s", rangetrans->exec_str); +- } +- +- if (rangetrans->obj != NULL) { +- cil_log(CIL_INFO, " %s", rangetrans->obj->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", rangetrans->obj_str); +- } +- +- if (rangetrans->range != NULL) { +- cil_log(CIL_INFO, " ("); +- cil_tree_print_levelrange(rangetrans->range); +- cil_log(CIL_INFO, " )"); +- } else { +- cil_log(CIL_INFO, " %s", rangetrans->range_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_AVRULE: { +- struct cil_avrule *rule = node->data; +- switch (rule->rule_kind) { +- case CIL_AVRULE_ALLOWED: +- cil_log(CIL_INFO, "ALLOW:"); +- break; +- case CIL_AVRULE_AUDITALLOW: +- cil_log(CIL_INFO, "AUDITALLOW:"); +- break; +- case CIL_AVRULE_DONTAUDIT: +- cil_log(CIL_INFO, "DONTAUDIT:"); +- break; +- case CIL_AVRULE_NEVERALLOW: +- cil_log(CIL_INFO, "NEVERALLOW:"); +- break; +- } +- +- if (rule->src != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->src)->name); +- } else { +- cil_log(CIL_INFO, " %s", rule->src_str); +- } +- +- if (rule->tgt != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->tgt)->name); +- } else { +- cil_log(CIL_INFO, " %s", rule->tgt_str); +- } +- +- cil_tree_print_classperms_list(rule->perms.classperms); +- +- cil_log(CIL_INFO, "\n"); +- +- return; +- } +- case CIL_TYPE_RULE: { +- struct cil_type_rule *rule = node->data; +- switch (rule->rule_kind) { +- case CIL_TYPE_TRANSITION: +- cil_log(CIL_INFO, "TYPETRANSITION:"); +- break; +- case CIL_TYPE_MEMBER: +- cil_log(CIL_INFO, "TYPEMEMBER:"); +- break; +- case CIL_TYPE_CHANGE: +- cil_log(CIL_INFO, "TYPECHANGE:"); +- break; +- } +- +- if (rule->src != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->src)->name); +- } else { +- cil_log(CIL_INFO, " %s", rule->src_str); +- } +- +- if (rule->tgt != NULL) { +- cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->tgt)->name); +- } else { +- cil_log(CIL_INFO, " %s", rule->tgt_str); +- } +- +- if (rule->obj != NULL) { +- cil_log(CIL_INFO, " %s", rule->obj->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", rule->obj_str); +- } +- +- if (rule->result != NULL) { +- cil_log(CIL_INFO, " %s\n", ((struct cil_symtab_datum *)rule->result)->name); +- } else { +- cil_log(CIL_INFO, " %s\n", rule->result_str); +- } +- +- return; +- } +- case CIL_SENS: { +- struct cil_sens *sens = node->data; +- cil_log(CIL_INFO, "SENSITIVITY: %s\n", sens->datum.name); +- return; +- } +- case CIL_SENSALIAS: { +- struct cil_alias *alias = node->data; +- cil_log(CIL_INFO, "SENSITIVITYALIAS: %s\n", alias->datum.name); +- return; +- } +- case CIL_SENSALIASACTUAL: { +- struct cil_aliasactual *aliasactual = node->data; +- cil_log(CIL_INFO, "SENSITIVITYALIAS: alias: %s, sensitivity: %s\n", aliasactual->alias_str, aliasactual->actual_str); +- +- return; +- } +- case CIL_CAT: { +- struct cil_cat *cat = node->data; +- cil_log(CIL_INFO, "CATEGORY: %s\n", cat->datum.name); +- return; +- } +- case CIL_CATALIAS: { +- struct cil_alias *alias = node->data; +- cil_log(CIL_INFO, "CATEGORYALIAS: %s\n", alias->datum.name); +- return; +- } +- case CIL_CATALIASACTUAL: { +- struct cil_aliasactual *aliasactual = node->data; +- cil_log(CIL_INFO, "CATEGORYALIAS: alias %s, category: %s\n", aliasactual->alias_str, aliasactual->actual_str); +- return; +- } +- case CIL_CATSET: { +- struct cil_catset *catset = node->data; +- +- cil_log(CIL_INFO, "CATSET: %s ",catset->datum.name); +- +- cil_tree_print_cats(catset->cats); +- +- return; +- } +- case CIL_CATORDER: { +- struct cil_catorder *catorder = node->data; +- struct cil_list_item *cat; +- +- if (catorder->cat_list_str == NULL) { +- cil_log(CIL_INFO, "CATORDER: ()\n"); +- return; +- } +- +- cil_log(CIL_INFO, "CATORDER: ("); +- cil_list_for_each(cat, catorder->cat_list_str) { +- cil_log(CIL_INFO, " %s", (char*)cat->data); +- } +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_SENSCAT: { +- struct cil_senscat *senscat = node->data; +- +- cil_log(CIL_INFO, "SENSCAT: sens:"); +- +- if (senscat->sens_str != NULL) { +- cil_log(CIL_INFO, " %s ", senscat->sens_str); +- } else { +- cil_log(CIL_INFO, " [processed]"); +- } +- +- cil_tree_print_cats(senscat->cats); +- +- return; +- } +- case CIL_SENSITIVITYORDER: { +- struct cil_sensorder *sensorder = node->data; +- struct cil_list_item *sens; +- +- cil_log(CIL_INFO, "SENSITIVITYORDER: ("); +- +- if (sensorder->sens_list_str != NULL) { +- cil_list_for_each(sens, sensorder->sens_list_str) { +- if (sens->flavor == CIL_LIST) { +- struct cil_list_item *sub; +- cil_log(CIL_INFO, " ("); +- cil_list_for_each(sub, (struct cil_list*)sens->data) { +- cil_log(CIL_INFO, " %s", (char*)sub->data); +- } +- cil_log(CIL_INFO, " )"); +- } else { +- cil_log(CIL_INFO, " %s", (char*)sens->data); +- } +- } +- } +- +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_LEVEL: { +- struct cil_level *level = node->data; +- cil_log(CIL_INFO, "LEVEL %s:", level->datum.name); +- cil_tree_print_level(level); +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_LEVELRANGE: { +- struct cil_levelrange *lvlrange = node->data; +- cil_log(CIL_INFO, "LEVELRANGE %s:", lvlrange->datum.name); +- cil_tree_print_levelrange(lvlrange); +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_CONSTRAIN: { +- struct cil_constrain *cons = node->data; +- cil_log(CIL_INFO, "CONSTRAIN: ("); +- cil_tree_print_constrain(cons); +- return; +- } +- case CIL_MLSCONSTRAIN: { +- struct cil_constrain *cons = node->data; +- cil_log(CIL_INFO, "MLSCONSTRAIN: ("); +- cil_tree_print_constrain(cons); +- return; +- } +- case CIL_VALIDATETRANS: { +- struct cil_validatetrans *vt = node->data; +- +- cil_log(CIL_INFO, "(VALIDATETRANS "); +- +- if (vt->class != NULL) { +- cil_log(CIL_INFO, "%s ", vt->class->datum.name); +- } else if (vt->class_str != NULL) { +- cil_log(CIL_INFO, "%s ", vt->class_str); +- } +- +- cil_tree_print_expr(vt->datum_expr, vt->str_expr); +- +- cil_log(CIL_INFO, ")\n"); +- return; +- } +- case CIL_MLSVALIDATETRANS: { +- struct cil_validatetrans *vt = node->data; +- +- cil_log(CIL_INFO, "(MLSVALIDATETRANS "); +- +- if (vt->class != NULL) { +- cil_log(CIL_INFO, "%s ", vt->class->datum.name); +- } else if (vt->class_str != NULL) { +- cil_log(CIL_INFO, "%s ", vt->class_str); +- } +- +- cil_tree_print_expr(vt->datum_expr, vt->str_expr); +- +- cil_log(CIL_INFO, ")\n"); +- return; +- } +- case CIL_CONTEXT: { +- struct cil_context *context = node->data; +- cil_log(CIL_INFO, "CONTEXT %s:", context->datum.name); +- cil_tree_print_context(context); +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_FILECON: { +- struct cil_filecon *filecon = node->data; +- cil_log(CIL_INFO, "FILECON:"); +- cil_log(CIL_INFO, " %s %d", filecon->path_str, filecon->type); +- +- if (filecon->context != NULL) { +- cil_tree_print_context(filecon->context); +- } else if (filecon->context_str != NULL) { +- cil_log(CIL_INFO, " %s", filecon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- +- } +- case CIL_IBPKEYCON: { +- struct cil_ibpkeycon *ibpkeycon = node->data; +- +- cil_log(CIL_INFO, "IBPKEYCON: %s", ibpkeycon->subnet_prefix_str); +- cil_log(CIL_INFO, " (%d %d) ", ibpkeycon->pkey_low, ibpkeycon->pkey_high); +- +- if (ibpkeycon->context) +- cil_tree_print_context(ibpkeycon->context); +- else if (ibpkeycon->context_str) +- cil_log(CIL_INFO, " %s", ibpkeycon->context_str); +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_PORTCON: { +- struct cil_portcon *portcon = node->data; +- cil_log(CIL_INFO, "PORTCON:"); +- if (portcon->proto == CIL_PROTOCOL_UDP) { +- cil_log(CIL_INFO, " udp"); +- } else if (portcon->proto == CIL_PROTOCOL_TCP) { +- cil_log(CIL_INFO, " tcp"); +- } else if (portcon->proto == CIL_PROTOCOL_DCCP) { +- cil_log(CIL_INFO, " dccp"); +- } else if (portcon->proto == CIL_PROTOCOL_SCTP) { +- cil_log(CIL_INFO, " sctp"); +- } +- cil_log(CIL_INFO, " (%d %d)", portcon->port_low, portcon->port_high); +- +- if (portcon->context != NULL) { +- cil_tree_print_context(portcon->context); +- } else if (portcon->context_str != NULL) { +- cil_log(CIL_INFO, " %s", portcon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_NODECON: { +- struct cil_nodecon *nodecon = node->data; +- char buf[256]; +- +- cil_log(CIL_INFO, "NODECON:"); +- +- if (nodecon->addr) { +- inet_ntop(nodecon->addr->family, &nodecon->addr->ip, buf, 256); +- cil_log(CIL_INFO, " %s", buf); +- } else { +- cil_log(CIL_INFO, " %s", nodecon->addr_str); +- } +- +- if (nodecon->mask) { +- inet_ntop(nodecon->mask->family, &nodecon->mask->ip, buf, 256); +- cil_log(CIL_INFO, " %s", buf); +- } else { +- cil_log(CIL_INFO, " %s", nodecon->mask_str); +- } +- +- if (nodecon->context != NULL) { +- cil_tree_print_context(nodecon->context); +- } else if (nodecon->context_str != NULL) { +- cil_log(CIL_INFO, " %s", nodecon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_GENFSCON: { +- struct cil_genfscon *genfscon = node->data; +- cil_log(CIL_INFO, "GENFSCON:"); +- cil_log(CIL_INFO, " %s %s", genfscon->fs_str, genfscon->path_str); +- +- if (genfscon->context != NULL) { +- cil_tree_print_context(genfscon->context); +- } else if (genfscon->context_str != NULL) { +- cil_log(CIL_INFO, " %s", genfscon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_NETIFCON: { +- struct cil_netifcon *netifcon = node->data; +- cil_log(CIL_INFO, "NETIFCON %s", netifcon->interface_str); +- +- if (netifcon->if_context != NULL) { +- cil_tree_print_context(netifcon->if_context); +- } else if (netifcon->if_context_str != NULL) { +- cil_log(CIL_INFO, " %s", netifcon->if_context_str); +- } +- +- if (netifcon->packet_context != NULL) { +- cil_tree_print_context(netifcon->packet_context); +- } else if (netifcon->packet_context_str != NULL) { +- cil_log(CIL_INFO, " %s", netifcon->packet_context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_IBENDPORTCON: { +- struct cil_ibendportcon *ibendportcon = node->data; +- +- cil_log(CIL_INFO, "IBENDPORTCON: %s %u ", ibendportcon->dev_name_str, ibendportcon->port); +- +- if (ibendportcon->context) +- cil_tree_print_context(ibendportcon->context); +- else if (ibendportcon->context_str) +- cil_log(CIL_INFO, " %s", ibendportcon->context_str); +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_PIRQCON: { +- struct cil_pirqcon *pirqcon = node->data; +- +- cil_log(CIL_INFO, "PIRQCON %d", pirqcon->pirq); +- if (pirqcon->context != NULL) { +- cil_tree_print_context(pirqcon->context); +- } else { +- cil_log(CIL_INFO, " %s", pirqcon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_IOMEMCON: { +- struct cil_iomemcon *iomemcon = node->data; +- +- cil_log(CIL_INFO, "IOMEMCON ( %"PRId64" %"PRId64" )", iomemcon->iomem_low, iomemcon->iomem_high); +- if (iomemcon->context != NULL) { +- cil_tree_print_context(iomemcon->context); +- } else { +- cil_log(CIL_INFO, " %s", iomemcon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_IOPORTCON: { +- struct cil_ioportcon *ioportcon = node->data; +- +- cil_log(CIL_INFO, "IOPORTCON ( %d %d )", ioportcon->ioport_low, ioportcon->ioport_high); +- if (ioportcon->context != NULL) { +- cil_tree_print_context(ioportcon->context); +- } else { +- cil_log(CIL_INFO, " %s", ioportcon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_PCIDEVICECON: { +- struct cil_pcidevicecon *pcidevicecon = node->data; +- +- cil_log(CIL_INFO, "PCIDEVICECON %d", pcidevicecon->dev); +- if (pcidevicecon->context != NULL) { +- cil_tree_print_context(pcidevicecon->context); +- } else { +- cil_log(CIL_INFO, " %s", pcidevicecon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_DEVICETREECON: { +- struct cil_devicetreecon *devicetreecon = node->data; +- +- cil_log(CIL_INFO, "DEVICETREECON %s", devicetreecon->path); +- if (devicetreecon->context != NULL) { +- cil_tree_print_context(devicetreecon->context); +- } else { +- cil_log(CIL_INFO, " %s", devicetreecon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_FSUSE: { +- struct cil_fsuse *fsuse = node->data; +- cil_log(CIL_INFO, "FSUSE: "); +- +- if (fsuse->type == CIL_FSUSE_XATTR) { +- cil_log(CIL_INFO, "xattr "); +- } else if (fsuse->type == CIL_FSUSE_TASK) { +- cil_log(CIL_INFO, "task "); +- } else if (fsuse->type == CIL_FSUSE_TRANS) { +- cil_log(CIL_INFO, "trans "); +- } else { +- cil_log(CIL_INFO, "unknown "); +- } +- +- cil_log(CIL_INFO, "%s ", fsuse->fs_str); +- +- if (fsuse->context != NULL) { +- cil_tree_print_context(fsuse->context); +- } else { +- cil_log(CIL_INFO, " %s", fsuse->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_SID: { +- struct cil_sid *sid = node->data; +- cil_log(CIL_INFO, "SID: %s\n", sid->datum.name); +- return; +- } +- case CIL_SIDCONTEXT: { +- struct cil_sidcontext *sidcon = node->data; +- cil_log(CIL_INFO, "SIDCONTEXT: %s", sidcon->sid_str); +- +- if (sidcon->context != NULL) { +- cil_tree_print_context(sidcon->context); +- } else { +- cil_log(CIL_INFO, " %s", sidcon->context_str); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_SIDORDER: { +- struct cil_sidorder *sidorder = node->data; +- struct cil_list_item *sid; +- +- if (sidorder->sid_list_str == NULL) { +- cil_log(CIL_INFO, "SIDORDER: ()\n"); +- return; +- } +- +- cil_log(CIL_INFO, "SIDORDER: ("); +- cil_list_for_each(sid, sidorder->sid_list_str) { +- cil_log(CIL_INFO, " %s", (char*)sid->data); +- } +- cil_log(CIL_INFO, " )\n"); +- return; +- } +- case CIL_POLICYCAP: { +- struct cil_policycap *polcap = node->data; +- cil_log(CIL_INFO, "POLICYCAP: %s\n", polcap->datum.name); +- return; +- } +- case CIL_MACRO: { +- struct cil_macro *macro = node->data; +- cil_log(CIL_INFO, "MACRO %s:", macro->datum.name); +- +- if (macro->params != NULL && macro->params->head != NULL) { +- struct cil_list_item *curr_param; +- cil_log(CIL_INFO, " parameters: ("); +- cil_list_for_each(curr_param, macro->params) { +- cil_log(CIL_INFO, " flavor: %d, string: %s;", ((struct cil_param*)curr_param->data)->flavor, ((struct cil_param*)curr_param->data)->str); +- +- } +- cil_log(CIL_INFO, " )"); +- } +- cil_log(CIL_INFO, "\n"); +- +- return; +- } +- case CIL_CALL: { +- struct cil_call *call = node->data; +- cil_log(CIL_INFO, "CALL: macro name:"); +- +- if (call->macro != NULL) { +- cil_log(CIL_INFO, " %s", call->macro->datum.name); +- } else { +- cil_log(CIL_INFO, " %s", call->macro_str); +- } +- +- if (call->args != NULL) { +- cil_log(CIL_INFO, ", args: ( "); +- struct cil_list_item *item; +- cil_list_for_each(item, call->args) { +- struct cil_symtab_datum *datum = ((struct cil_args*)item->data)->arg; +- if (datum != NULL) { +- if (datum->nodes != NULL && datum->nodes->head != NULL) { +- cil_tree_print_node(NODE(datum)); +- } +- } else if (((struct cil_args*)item->data)->arg_str != NULL) { +- switch (item->flavor) { +- case CIL_TYPE: cil_log(CIL_INFO, "type:"); break; +- case CIL_USER: cil_log(CIL_INFO, "user:"); break; +- case CIL_ROLE: cil_log(CIL_INFO, "role:"); break; +- case CIL_SENS: cil_log(CIL_INFO, "sensitivity:"); break; +- case CIL_CAT: cil_log(CIL_INFO, "category:"); break; +- case CIL_CATSET: cil_log(CIL_INFO, "categoryset:"); break; +- case CIL_LEVEL: cil_log(CIL_INFO, "level:"); break; +- case CIL_CLASS: cil_log(CIL_INFO, "class:"); break; +- default: break; +- } +- cil_log(CIL_INFO, "%s ", ((struct cil_args*)item->data)->arg_str); +- } +- } +- cil_log(CIL_INFO, ")"); +- } +- +- cil_log(CIL_INFO, "\n"); +- return; +- } +- case CIL_OPTIONAL: { +- struct cil_optional *optional = node->data; +- cil_log(CIL_INFO, "OPTIONAL: %s\n", optional->datum.name); +- return; +- } +- case CIL_IPADDR: { +- struct cil_ipaddr *ipaddr = node->data; +- char buf[256]; +- +- inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256); +- cil_log(CIL_INFO, "IPADDR %s: %s\n", ipaddr->datum.name, buf); +- +- break; +- } +- default : { +- cil_log(CIL_INFO, "CIL FLAVOR: %d\n", node->flavor); +- return; +- } +- } +- } +-} +- +-void cil_tree_print(struct cil_tree_node *tree, uint32_t depth) +-{ +- struct cil_tree_node *current = NULL; +- current = tree; +- uint32_t x = 0; +- +- if (current != NULL) { +- if (current->cl_head == NULL) { +- if (current->flavor == CIL_NODE) { +- if (current->parent->cl_head == current) { +- cil_log(CIL_INFO, "%s", (char*)current->data); +- } else { +- cil_log(CIL_INFO, " %s", (char*)current->data); +- } +- } else if (current->flavor != CIL_PERM) { +- for (x = 0; xparent != NULL) { +- cil_log(CIL_INFO, "\n"); +- for (x = 0; xflavor != CIL_NODE) { +- cil_tree_print_node(current); +- } +- } +- cil_tree_print(current->cl_head, depth + 1); +- } +- +- if (current->next == NULL) { +- if ((current->parent != NULL) && (current->parent->cl_tail == current) && (current->parent->parent != NULL)) { +- if (current->flavor == CIL_PERM) { +- cil_log(CIL_INFO, ")\n"); +- } else if (current->flavor != CIL_NODE) { +- for (x = 0; xparent != NULL) && (current->parent->parent == NULL)) +- cil_log(CIL_INFO, "\n\n"); +- } else { +- cil_tree_print(current->next, depth); +- } +- } else { +- cil_log(CIL_INFO, "Tree is NULL\n"); +- } +-} +diff --git a/libsepol/cil/src/cil_tree.h b/libsepol/cil/src/cil_tree.h +index aeded5608239..bac9f1e47f2c 100644 +--- a/libsepol/cil/src/cil_tree.h ++++ b/libsepol/cil/src/cil_tree.h +@@ -62,8 +62,6 @@ void cil_tree_children_destroy(struct cil_tree_node *node); + void cil_tree_node_init(struct cil_tree_node **node); + void cil_tree_node_destroy(struct cil_tree_node **node); + +-void cil_tree_print(struct cil_tree_node *tree, uint32_t depth); +- + //finished values + #define CIL_TREE_SKIP_NOTHING 0 + #define CIL_TREE_SKIP_NEXT 1 +diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c +new file mode 100644 +index 000000000000..4871f7045e19 +--- /dev/null ++++ b/libsepol/cil/src/cil_write_ast.c +@@ -0,0 +1,1573 @@ ++/* ++ * Copyright 2011 Tresys Technology, LLC. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO ++ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ++ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation are those ++ * of the authors and should not be interpreted as representing official policies, ++ * either expressed or implied, of Tresys Technology, LLC. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "cil_internal.h" ++#include "cil_flavor.h" ++#include "cil_list.h" ++#include "cil_log.h" ++#include "cil_symtab.h" ++#include "cil_tree.h" ++#include "cil_write_ast.h" ++ ++ ++static inline const char *datum_or_str(struct cil_symtab_datum *datum, const char *str) ++{ ++ return datum ? datum->fqn : str; ++} ++ ++static inline const char *datum_to_str(struct cil_symtab_datum *datum) ++{ ++ return datum ? datum->fqn : ""; ++} ++ ++static void write_expr(FILE *out, struct cil_list *expr) ++{ ++ struct cil_list_item *curr; ++ int notfirst = 0; ++ ++ fprintf(out, "("); ++ cil_list_for_each(curr, expr) { ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ switch (curr->flavor) { ++ case CIL_LIST: ++ write_expr(out, curr->data); ++ break; ++ case CIL_STRING: ++ fprintf(out, "%s", (char *)curr->data); ++ break; ++ case CIL_DATUM: ++ case CIL_TYPE: ++ case CIL_ROLE: ++ case CIL_USER: ++ case CIL_SENS: ++ case CIL_CAT: ++ case CIL_BOOL: ++ case CIL_CLASS: ++ case CIL_MAP_CLASS: ++ case CIL_NAME: ++ fprintf(out, "%s", datum_to_str(curr->data)); ++ break; ++ case CIL_OP: { ++ const char *op_str; ++ enum cil_flavor op_flavor = (enum cil_flavor)curr->data; ++ switch (op_flavor) { ++ case CIL_AND: ++ op_str = CIL_KEY_AND; ++ break; ++ case CIL_OR: ++ op_str = CIL_KEY_OR; ++ break; ++ case CIL_NOT: ++ op_str = CIL_KEY_NOT; ++ break; ++ case CIL_ALL: ++ op_str = CIL_KEY_ALL; ++ break; ++ case CIL_EQ: ++ op_str = CIL_KEY_EQ; ++ break; ++ case CIL_NEQ: ++ op_str = CIL_KEY_NEQ; ++ break; ++ case CIL_XOR: ++ op_str = CIL_KEY_XOR; ++ break; ++ case CIL_RANGE: ++ op_str = CIL_KEY_RANGE; ++ break; ++ case CIL_CONS_DOM: ++ op_str = CIL_KEY_CONS_DOM; ++ break; ++ case CIL_CONS_DOMBY: ++ op_str = CIL_KEY_CONS_DOMBY; ++ break; ++ case CIL_CONS_INCOMP: ++ op_str = CIL_KEY_CONS_INCOMP; ++ break; ++ default: ++ op_str = ""; ++ break; ++ } ++ fprintf(out, "%s", op_str); ++ break; ++ } ++ case CIL_CONS_OPERAND: { ++ const char *operand_str; ++ enum cil_flavor operand_flavor = (enum cil_flavor)curr->data; ++ switch (operand_flavor) { ++ case CIL_CONS_U1: ++ operand_str = CIL_KEY_CONS_U1; ++ break; ++ case CIL_CONS_U2: ++ operand_str = CIL_KEY_CONS_U2; ++ break; ++ case CIL_CONS_U3: ++ operand_str = CIL_KEY_CONS_U3; ++ break; ++ case CIL_CONS_T1: ++ operand_str = CIL_KEY_CONS_T1; ++ break; ++ case CIL_CONS_T2: ++ operand_str = CIL_KEY_CONS_T2; ++ break; ++ case CIL_CONS_T3: ++ operand_str = CIL_KEY_CONS_T3; ++ break; ++ case CIL_CONS_R1: ++ operand_str = CIL_KEY_CONS_R1; ++ break; ++ case CIL_CONS_R2: ++ operand_str = CIL_KEY_CONS_R2; ++ break; ++ case CIL_CONS_R3: ++ operand_str = CIL_KEY_CONS_R3; ++ break; ++ case CIL_CONS_L1: ++ operand_str = CIL_KEY_CONS_L1; ++ break; ++ case CIL_CONS_L2: ++ operand_str = CIL_KEY_CONS_L2; ++ break; ++ case CIL_CONS_H1: ++ operand_str = CIL_KEY_CONS_H1; ++ break; ++ case CIL_CONS_H2: ++ operand_str = CIL_KEY_CONS_H2; ++ break; ++ default: ++ operand_str = ""; ++ break; ++ } ++ fprintf(out, "%s", operand_str); ++ break; ++ } ++ default: ++ fprintf(out, ""); ++ break; ++ } ++ } ++ fprintf(out, ")"); ++} ++ ++static void write_node_list(FILE *out, struct cil_tree_node *current) ++{ ++ int notfirst = 0; ++ ++ fprintf(out, "("); ++ while (current) { ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ ++ fprintf(out, "%s", datum_to_str(current->data)); ++ current = current->next; ++ } ++ fprintf(out, ")"); ++} ++ ++static void write_string_list(FILE *out, struct cil_list *list) ++{ ++ struct cil_list_item *curr; ++ int notfirst = 0; ++ ++ if (!list) { ++ fprintf(out, "()"); ++ return; ++ } ++ ++ fprintf(out, "("); ++ cil_list_for_each(curr, list) { ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ fprintf(out, "%s", (char*)curr->data); ++ } ++ fprintf(out, ")"); ++} ++ ++static void write_datum_list(FILE *out, struct cil_list *list) ++{ ++ struct cil_list_item *curr; ++ int notfirst = 0; ++ ++ if (!list) { ++ fprintf(out, "()"); ++ return; ++ } ++ ++ fprintf(out, "("); ++ cil_list_for_each(curr, list) { ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ fprintf(out, "%s", datum_to_str(curr->data)); ++ } ++ fprintf(out, ")"); ++} ++ ++static void write_classperms(FILE *out, struct cil_classperms *cp) ++{ ++ if (!cp) { ++ fprintf(out, "()"); ++ return; ++ } ++ ++ fprintf(out, "(%s ", datum_or_str(DATUM(cp->class), cp->class_str)); ++ if (cp->perms) ++ write_expr(out, cp->perms); ++ else ++ write_expr(out, cp->perm_strs); ++ fprintf(out, ")"); ++} ++ ++static void write_classperms_list(FILE *out, struct cil_list *cp_list) ++{ ++ struct cil_list_item *curr; ++ int notfirst = 0; ++ int num = 0; ++ ++ if (!cp_list) { ++ fprintf(out, "()"); ++ return; ++ } ++ ++ cil_list_for_each(curr, cp_list) { ++ num++; ++ } ++ if (num > 1) ++ fprintf(out, "("); ++ cil_list_for_each(curr, cp_list) { ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ if (curr->flavor == CIL_CLASSPERMS) { ++ write_classperms(out, curr->data); ++ } else { ++ struct cil_classperms_set *cp_set = curr->data; ++ struct cil_classpermission *cp = cp_set->set; ++ if (cp) { ++ if (cp->datum.name) ++ fprintf(out, "%s", datum_to_str(DATUM(cp))); ++ else ++ write_classperms_list(out,cp->classperms); ++ } else { ++ fprintf(out, "%s", cp_set->set_str); ++ } ++ } ++ } ++ if (num > 1) ++ fprintf(out, ")"); ++} ++ ++static void write_permx(FILE *out, struct cil_permissionx *permx) ++{ ++ if (permx->datum.name) { ++ fprintf(out, "%s", datum_to_str(DATUM(permx))); ++ } else { ++ fprintf(out, "("); ++ fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : ""); ++ fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); ++ write_expr(out, permx->expr_str); ++ fprintf(out, ")"); ++ } ++} ++ ++static void write_cats(FILE *out, struct cil_cats *cats) ++{ ++ if (cats->datum_expr) { ++ write_expr(out, cats->datum_expr); ++ } else { ++ write_expr(out, cats->str_expr); ++ } ++} ++ ++static void write_level(FILE *out, struct cil_level *level, int print_name) ++{ ++ if (print_name && level->datum.name) { ++ fprintf(out, "%s", datum_to_str(DATUM(level))); ++ } else { ++ fprintf(out, "("); ++ fprintf(out, "%s", datum_or_str(DATUM(level->sens), level->sens_str)); ++ if (level->cats) { ++ fprintf(out, " "); ++ write_cats(out, level->cats); ++ } ++ fprintf(out, ")"); ++ } ++} ++ ++static void write_range(FILE *out, struct cil_levelrange *range, int print_name) ++{ ++ if (print_name && range->datum.name) { ++ fprintf(out, "%s", datum_to_str(DATUM(range))); ++ } else { ++ fprintf(out, "("); ++ if (range->low) ++ write_level(out, range->low, CIL_TRUE); ++ else ++ fprintf(out, "%s", range->low_str); ++ fprintf(out, " "); ++ if (range->high) ++ write_level(out, range->high, CIL_TRUE); ++ else ++ fprintf(out, "%s", range->high_str); ++ fprintf(out, ")"); ++ } ++} ++ ++static void write_context(FILE *out, struct cil_context *context, int print_name) ++{ ++ if (print_name && context->datum.name) { ++ fprintf(out, "%s", datum_to_str(DATUM(context))); ++ } else { ++ fprintf(out, "("); ++ fprintf(out, "%s ", datum_or_str(DATUM(context->user), context->user_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(context->role), context->role_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(context->type), context->type_str)); ++ if (context->range) ++ write_range(out, context->range, CIL_TRUE); ++ else ++ fprintf(out, "%s", context->range_str); ++ fprintf(out, ")"); ++ } ++} ++ ++static void write_ipaddr(FILE *out, struct cil_ipaddr *ipaddr) ++{ ++ if (ipaddr->datum.name) { ++ fprintf(out, "%s", datum_to_str(DATUM(ipaddr))); ++ } else { ++ char buf[256]; ++ if (inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256) == NULL) ++ strcpy(buf, ""); ++ fprintf(out, "(%s)", buf); ++ } ++} ++ ++static void write_constrain(FILE *out, struct cil_constrain *cons) ++{ ++ write_classperms_list(out, cons->classperms); ++ fprintf(out, " "); ++ if (cons->datum_expr) ++ write_expr(out, cons->datum_expr); ++ else ++ write_expr(out, cons->str_expr); ++} ++ ++static void write_call_args(FILE *out, struct cil_list *args) ++{ ++ struct cil_list_item *item; ++ int notfirst = 0; ++ ++ fprintf(out, "("); ++ cil_list_for_each(item, args) { ++ struct cil_args* arg = item->data; ++ enum cil_flavor arg_flavor = arg->flavor; ++ if (notfirst) ++ fprintf(out, " "); ++ else ++ notfirst = 1; ++ switch (arg_flavor) { ++ case CIL_TYPE: ++ case CIL_ROLE: ++ case CIL_USER: ++ case CIL_SENS: ++ case CIL_CAT: ++ case CIL_BOOL: ++ case CIL_CLASS: ++ case CIL_MAP_CLASS: ++ case CIL_NAME: { ++ fprintf(out, "%s", datum_or_str(arg->arg, arg->arg_str)); ++ break; ++ } ++ case CIL_CATSET: { ++ if (arg->arg) { ++ struct cil_catset *catset = (struct cil_catset *)arg->arg; ++ write_cats(out, catset->cats); ++ } else { ++ fprintf(out, "%s", arg->arg_str); ++ } ++ break; ++ } ++ case CIL_LEVEL: { ++ if (arg->arg) { ++ struct cil_level *level = (struct cil_level *)arg->arg; ++ write_level(out, level, CIL_TRUE); ++ } else { ++ fprintf(out, "%s", arg->arg_str); ++ } ++ break; ++ } ++ case CIL_LEVELRANGE: { ++ if (arg->arg) { ++ struct cil_levelrange *range = (struct cil_levelrange *)arg->arg; ++ write_range(out, range, CIL_TRUE); ++ } else { ++ fprintf(out, "%s", arg->arg_str); ++ } ++ break; ++ } ++ case CIL_IPADDR: { ++ if (arg->arg) { ++ struct cil_ipaddr *addr = (struct cil_ipaddr *)arg->arg; ++ write_ipaddr(out, addr); ++ } else { ++ fprintf(out, "%s", arg->arg_str); ++ } ++ break; ++ } ++ case CIL_CLASSPERMISSION: { ++ if (arg->arg) { ++ struct cil_classpermission *cp = (struct cil_classpermission *)arg->arg; ++ if (cp->datum.name) ++ fprintf(out, "%s", datum_to_str(DATUM(cp))); ++ else ++ write_classperms_list(out, cp->classperms); ++ } else { ++ fprintf(out, "%s", arg->arg_str); ++ } ++ break; ++ } ++ default: ++ fprintf(out, "", datum_or_str(arg->arg, arg->arg_str)); ++ break; ++ } ++ } ++ fprintf(out, ")"); ++} ++ ++static void write_call_args_tree(FILE *out, struct cil_tree_node *arg_node) ++{ ++ while (arg_node) { ++ if (arg_node->data) { ++ fprintf(out, "%s", (char *)arg_node->data); ++ } else if (arg_node->cl_head) { ++ fprintf(out, "("); ++ write_call_args_tree(out, arg_node->cl_head); ++ fprintf(out, ")"); ++ } ++ if (arg_node->next) ++ fprintf(out, " "); ++ arg_node = arg_node->next; ++ } ++} ++ ++static const char *macro_param_flavor_to_string(enum cil_flavor flavor) ++{ ++ const char *str; ++ switch(flavor) { ++ case CIL_TYPE: ++ str = CIL_KEY_TYPE; ++ break; ++ case CIL_ROLE: ++ str = CIL_KEY_ROLE; ++ break; ++ case CIL_USER: ++ str = CIL_KEY_USER; ++ break; ++ case CIL_SENS: ++ str = CIL_KEY_SENSITIVITY; ++ break; ++ case CIL_CAT: ++ str = CIL_KEY_CATEGORY; ++ break; ++ case CIL_CATSET: ++ str = CIL_KEY_CATSET; ++ break; ++ case CIL_LEVEL: ++ str = CIL_KEY_LEVEL; ++ break; ++ case CIL_LEVELRANGE: ++ str = CIL_KEY_LEVELRANGE; ++ break; ++ case CIL_CLASS: ++ str = CIL_KEY_CLASS; ++ break; ++ case CIL_IPADDR: ++ str = CIL_KEY_IPADDR; ++ break; ++ case CIL_MAP_CLASS: ++ str = CIL_KEY_MAP_CLASS; ++ break; ++ case CIL_CLASSPERMISSION: ++ str = CIL_KEY_CLASSPERMISSION; ++ break; ++ case CIL_BOOL: ++ str = CIL_KEY_BOOL; ++ break; ++ case CIL_STRING: ++ str = CIL_KEY_STRING; ++ break; ++ case CIL_NAME: ++ str = CIL_KEY_NAME; ++ break; ++ default: ++ str = ""; ++ break; ++ } ++ return str; ++} ++ ++void cil_write_ast_node(FILE *out, struct cil_tree_node *node) ++{ ++ if (!node->data) { ++ return; ++ } ++ ++ switch(node->flavor) { ++ case CIL_NODE: { ++ fprintf(out, "%s\n", (char *)node->data); ++ break; ++ } ++ case CIL_BLOCK: { ++ struct cil_block *block = node->data; ++ fprintf(out, "(block %s", datum_to_str(DATUM(block))); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_BLOCKINHERIT: { ++ struct cil_blockinherit *inherit = node->data; ++ fprintf(out, "(blockinherit %s)\n", datum_or_str(DATUM(inherit->block), inherit->block_str)); ++ break; ++ } ++ case CIL_IN: { ++ struct cil_in *in = node->data; ++ fprintf(out, "(in %s", in->block_str); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_OPTIONAL: { ++ struct cil_optional *optional = node->data; ++ fprintf(out, "(optional %s", datum_to_str(DATUM(optional))); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_BOOLEANIF: { ++ struct cil_booleanif *bif = node->data; ++ fprintf(out, "(booleanif "); ++ if (bif->datum_expr) ++ write_expr(out, bif->datum_expr); ++ else ++ write_expr(out, bif->str_expr); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_TUNABLEIF: { ++ struct cil_tunableif *tif = node->data; ++ fprintf(out, "(tunableif "); ++ if (tif->datum_expr) ++ write_expr(out, tif->datum_expr); ++ else ++ write_expr(out, tif->str_expr); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_CONDBLOCK: { ++ struct cil_condblock *cb = node->data; ++ fprintf(out, "(%s", cb->flavor == CIL_CONDTRUE ? "true" : "false"); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_MACRO: { ++ struct cil_macro *macro = node->data; ++ struct cil_list_item *curr; ++ fprintf(out, "(macro %s (", datum_to_str(DATUM(macro))); ++ if (macro->params) { ++ cil_list_for_each(curr, macro->params) { ++ struct cil_param *param = curr->data; ++ fprintf(out, "(%s %s)", macro_param_flavor_to_string(param->flavor), param->str); ++ } ++ } ++ fprintf(out, ")"); ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_CALL: { ++ struct cil_call *call = node->data; ++ fprintf(out, "(call %s", datum_or_str(DATUM(call->macro), call->macro_str)); ++ if (call->args) { ++ fprintf(out, " "); ++ write_call_args(out, call->args); ++ } else if (call->args_tree) { ++ fprintf(out, " "); ++ write_call_args_tree(out, call->args_tree->root); ++ } ++ if (!node->cl_head) ++ fprintf(out, ")"); ++ fprintf(out, "\n"); ++ break; ++ } ++ case CIL_BLOCKABSTRACT: { ++ struct cil_blockabstract *abstract = node->data; ++ fprintf(out, "(blockabstract %s)\n", abstract->block_str); ++ break; ++ } ++ case CIL_MLS: { ++ struct cil_mls *mls = node->data; ++ fprintf(out, "(mls %s)\n", mls->value ? "true" : "false"); ++ break; ++ } ++ case CIL_HANDLEUNKNOWN: { ++ struct cil_handleunknown *unknown = node->data; ++ fprintf(out, "(handleunknown "); ++ if (unknown->handle_unknown == SEPOL_ALLOW_UNKNOWN) ++ fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_ALLOW); ++ else if (unknown->handle_unknown == SEPOL_DENY_UNKNOWN) ++ fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_DENY); ++ else if (unknown->handle_unknown == SEPOL_REJECT_UNKNOWN) ++ fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_REJECT); ++ else ++ fprintf(out, ""); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_DEFAULTUSER: { ++ struct cil_default *def = node->data; ++ fprintf(out, "(defaultuser "); ++ if (def->class_datums) ++ write_datum_list(out, def->class_datums); ++ else ++ write_string_list(out, def->class_strs); ++ if (def->object == CIL_DEFAULT_SOURCE) ++ fprintf(out, " source"); ++ else if (def->object == CIL_DEFAULT_TARGET) ++ fprintf(out, " target"); ++ else ++ fprintf(out, " "); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_DEFAULTROLE: { ++ struct cil_default *def = node->data; ++ fprintf(out, "(defaultrole "); ++ if (def->class_datums) ++ write_datum_list(out, def->class_datums); ++ else ++ write_string_list(out, def->class_strs); ++ if (def->object == CIL_DEFAULT_SOURCE) ++ fprintf(out, " source"); ++ else if (def->object == CIL_DEFAULT_TARGET) ++ fprintf(out, " target"); ++ else ++ fprintf(out, " "); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_DEFAULTTYPE: { ++ struct cil_default *def = node->data; ++ fprintf(out, "(defaulttype "); ++ if (def->class_datums) ++ write_datum_list(out, def->class_datums); ++ else ++ write_string_list(out, def->class_strs); ++ if (def->object == CIL_DEFAULT_SOURCE) ++ fprintf(out, " source"); ++ else if (def->object == CIL_DEFAULT_TARGET) ++ fprintf(out, " target"); ++ else ++ fprintf(out, " "); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_DEFAULTRANGE: { ++ struct cil_defaultrange *def = node->data; ++ fprintf(out, "(defaultrange "); ++ if (def->class_datums) ++ write_datum_list(out, def->class_datums); ++ else ++ write_string_list(out, def->class_strs); ++ if (def->object_range == CIL_DEFAULT_SOURCE_LOW) ++ fprintf(out, " source low"); ++ else if (def->object_range == CIL_DEFAULT_SOURCE_HIGH) ++ fprintf(out, " source high"); ++ else if (def->object_range == CIL_DEFAULT_SOURCE_LOW_HIGH) ++ fprintf(out, " source low-high"); ++ else if (def->object_range == CIL_DEFAULT_TARGET_LOW) ++ fprintf(out, " target low"); ++ else if (def->object_range == CIL_DEFAULT_TARGET_HIGH) ++ fprintf(out, " target high"); ++ else if (def->object_range == CIL_DEFAULT_TARGET_LOW_HIGH) ++ fprintf(out, " target low-high"); ++ else ++ fprintf(out, " "); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CLASS: { ++ struct cil_class *class = node->data; ++ fprintf(out, "(class %s ", datum_to_str(DATUM(class))); ++ write_node_list(out, node->cl_head); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CLASSORDER: { ++ struct cil_classorder *classorder = node->data; ++ fprintf(out, "(classorder "); ++ write_string_list(out, classorder->class_list_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_COMMON: { ++ struct cil_class *common = node->data; ++ fprintf(out, "(common %s ", datum_to_str(DATUM(common))); ++ write_node_list(out, node->cl_head); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CLASSCOMMON: { ++ struct cil_classcommon *cc = node->data; ++ fprintf(out, "(classcommon %s %s)\n", cc->class_str, cc->common_str); ++ break; ++ } ++ case CIL_CLASSPERMISSION: { ++ struct cil_classpermission *cp = node->data; ++ fprintf(out, "(classpermission %s)\n", datum_to_str(DATUM(cp))); ++ break; ++ } ++ case CIL_CLASSPERMISSIONSET: { ++ struct cil_classpermissionset *cps = node->data; ++ fprintf(out, "(classpermissionset %s ", cps->set_str); ++ write_classperms_list(out, cps->classperms); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_MAP_CLASS: { ++ struct cil_class *map = node->data; ++ fprintf(out, "(classmap %s ", datum_to_str(DATUM(map))); ++ write_node_list(out, node->cl_head); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CLASSMAPPING: { ++ struct cil_classmapping *mapping = node->data; ++ fprintf(out, "(classmapping %s %s ", mapping->map_class_str, mapping->map_perm_str); ++ write_classperms_list(out, mapping->classperms); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_PERMISSIONX: { ++ struct cil_permissionx *permx = node->data; ++ fprintf(out, "(permissionx %s (", datum_to_str(DATUM(permx))); ++ fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : ""); ++ fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); ++ write_expr(out, permx->expr_str); ++ fprintf(out, "))\n"); ++ break; ++ } ++ case CIL_SID: { ++ struct cil_sid *sid = node->data; ++ fprintf(out, "(sid %s)\n", datum_to_str(DATUM(sid))); ++ break; ++ } ++ case CIL_SIDCONTEXT: { ++ struct cil_sidcontext *sidcon = node->data; ++ fprintf(out, "(sidcontext %s ", sidcon->sid_str); ++ if (sidcon->context) ++ write_context(out, sidcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", sidcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_SIDORDER: { ++ struct cil_sidorder *sidorder = node->data; ++ fprintf(out, "(sidorder "); ++ write_string_list(out, sidorder->sid_list_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_BOOL: { ++ struct cil_bool *boolean = node->data; ++ fprintf(out, "(boolean %s %s)\n", datum_to_str(DATUM(boolean)), boolean->value ? "true" : "false"); ++ break; ++ } ++ case CIL_TUNABLE: { ++ struct cil_tunable *tunable = node->data; ++ fprintf(out, "(tunable %s %s)\n", datum_to_str(DATUM(tunable)), tunable->value ? "true" : "false"); ++ break; ++ } ++ case CIL_SENS: { ++ struct cil_sens *sens = node->data; ++ fprintf(out, "(sensitivity %s)\n", datum_to_str(DATUM(sens))); ++ break; ++ } ++ case CIL_SENSALIAS: { ++ struct cil_alias *alias = node->data; ++ fprintf(out, "(sensitivityalias %s)\n", datum_to_str(DATUM(alias))); ++ break; ++ } ++ case CIL_SENSALIASACTUAL: { ++ struct cil_aliasactual *aliasactual = node->data; ++ fprintf(out, "(sensitivityaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str); ++ break; ++ } ++ case CIL_CAT: { ++ struct cil_cat *cat = node->data; ++ fprintf(out, "(category %s)\n", datum_to_str(DATUM(cat))); ++ break; ++ } ++ case CIL_CATALIAS: { ++ struct cil_alias *alias = node->data; ++ fprintf(out, "(categoryalias %s)\n", datum_to_str(DATUM(alias))); ++ break; ++ } ++ case CIL_CATALIASACTUAL: { ++ struct cil_aliasactual *aliasactual = node->data; ++ fprintf(out, "(categoryaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str); ++ break; ++ } ++ case CIL_CATSET: { ++ struct cil_catset *catset = node->data; ++ fprintf(out, "(categoryset %s ", datum_to_str(DATUM(catset))); ++ write_cats(out, catset->cats); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CATORDER: { ++ struct cil_catorder *catorder = node->data; ++ fprintf(out, "(categoryorder "); ++ write_string_list(out, catorder->cat_list_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_SENSCAT: { ++ struct cil_senscat *senscat = node->data; ++ fprintf(out, "(sensitivitycategory "); ++ fprintf(out, "%s ", senscat->sens_str); ++ write_cats(out, senscat->cats); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_SENSITIVITYORDER: { ++ struct cil_sensorder *sensorder = node->data; ++ fprintf(out, "(sensitivityorder "); ++ write_string_list(out, sensorder->sens_list_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_LEVEL: { ++ struct cil_level *level = node->data; ++ fprintf(out, "(level %s ", datum_to_str(&level->datum)); ++ write_level(out, level, CIL_FALSE); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_LEVELRANGE: { ++ struct cil_levelrange *lvlrange = node->data; ++ fprintf(out, "(levelrange %s ", datum_to_str(DATUM(lvlrange))); ++ write_range(out, lvlrange, CIL_FALSE); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_USER: { ++ struct cil_user *user = node->data; ++ fprintf(out, "(user %s)\n", datum_to_str(DATUM(user))); ++ break; ++ } ++ case CIL_USERATTRIBUTE: { ++ struct cil_userattribute *attr = node->data; ++ fprintf(out, "(userattribute %s)\n", datum_to_str(DATUM(attr))); ++ break; ++ } ++ case CIL_USERATTRIBUTESET: { ++ struct cil_userattributeset *attr = node->data; ++ fprintf(out, "(userattributeset %s ", attr->attr_str); ++ if (attr->datum_expr) ++ write_expr(out, attr->datum_expr); ++ else ++ write_expr(out, attr->str_expr); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_USERROLE: { ++ struct cil_userrole *userrole = node->data; ++ fprintf(out, "(userrole "); ++ fprintf(out, "%s ", datum_or_str(userrole->user, userrole->user_str)); ++ fprintf(out, "%s", datum_or_str(userrole->role, userrole->role_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_USERLEVEL: { ++ struct cil_userlevel *userlevel = node->data; ++ fprintf(out, "(userlevel %s ", userlevel->user_str); ++ if (userlevel->level) ++ write_level(out, userlevel->level, CIL_TRUE); ++ else ++ fprintf(out, "%s", userlevel->level_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_USERRANGE: { ++ struct cil_userrange *userrange = node->data; ++ fprintf(out, "(userrange %s ", userrange->user_str); ++ if (userrange->range) ++ write_range(out, userrange->range, CIL_TRUE); ++ else ++ fprintf(out, "%s", userrange->range_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_USERBOUNDS: { ++ struct cil_bounds *bounds = node->data; ++ fprintf(out, "(userbounds %s %s)\n", bounds->parent_str, bounds->child_str); ++ break; ++ } ++ case CIL_USERPREFIX: { ++ struct cil_userprefix *prefix = node->data; ++ fprintf(out, "(userprefix "); ++ fprintf(out, "%s ", datum_or_str(DATUM(prefix->user), prefix->user_str)); ++ fprintf(out, "%s)\n", prefix->prefix_str); ++ break; ++ } ++ case CIL_SELINUXUSER: { ++ struct cil_selinuxuser *selinuxuser = node->data; ++ fprintf(out, "(selinuxuser %s ", selinuxuser->name_str); ++ fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str)); ++ if (selinuxuser->range) ++ write_range(out, selinuxuser->range, CIL_TRUE); ++ else ++ fprintf(out, "%s", selinuxuser->range_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_SELINUXUSERDEFAULT: { ++ struct cil_selinuxuser *selinuxuser = node->data; ++ fprintf(out, "(selinuxuserdefault "); ++ fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str)); ++ if (selinuxuser->range) ++ write_range(out, selinuxuser->range, CIL_TRUE); ++ else ++ fprintf(out, "%s", selinuxuser->range_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_ROLE: { ++ fprintf(out, "(role %s)\n", datum_to_str(node->data)); ++ break; ++ } ++ case CIL_ROLEATTRIBUTE: { ++ fprintf(out, "(roleattribute %s)\n", datum_to_str(node->data)); ++ break; ++ } ++ case CIL_ROLEATTRIBUTESET: { ++ struct cil_roleattributeset *attr = node->data; ++ fprintf(out, "(roleattributeset %s ", attr->attr_str); ++ if (attr->datum_expr) ++ write_expr(out, attr->datum_expr); ++ else ++ write_expr(out, attr->str_expr); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_ROLETYPE: { ++ struct cil_roletype *roletype = node->data; ++ fprintf(out, "(roletype "); ++ fprintf(out, "%s ", datum_or_str(DATUM(roletype->role), roletype->role_str)); ++ fprintf(out, "%s", datum_or_str(DATUM(roletype->type), roletype->type_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_ROLEBOUNDS: { ++ struct cil_bounds *bnds = node->data; ++ fprintf(out, "(rolebounds %s %s)\n", bnds->parent_str, bnds->child_str); ++ break; ++ } ++ case CIL_TYPE: { ++ fprintf(out, "(type %s)\n", datum_to_str(node->data)); ++ break; ++ } ++ case CIL_TYPEALIAS: { ++ fprintf(out, "(typealias %s)\n", datum_to_str(node->data)); ++ break; ++ } ++ case CIL_TYPEALIASACTUAL: { ++ struct cil_aliasactual *aliasactual = node->data; ++ fprintf(out, "(typealiasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str); ++ break; ++ } ++ case CIL_TYPEATTRIBUTE: { ++ fprintf(out, "(typeattribute %s)\n", datum_to_str(node->data)); ++ break; ++ } ++ case CIL_TYPEATTRIBUTESET: { ++ struct cil_typeattributeset *attr = node->data; ++ fprintf(out, "(typeattributeset %s ", attr->attr_str); ++ if (attr->datum_expr) ++ write_expr(out, attr->datum_expr); ++ else ++ write_expr(out, attr->str_expr); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_EXPANDTYPEATTRIBUTE: { ++ struct cil_expandtypeattribute *attr = node->data; ++ fprintf(out, "(expandtypeattribute "); ++ if (attr->attr_datums) ++ write_expr(out, attr->attr_datums); ++ else ++ write_expr(out, attr->attr_strs); ++ fprintf(out, " %s)\n", attr->expand ? "true" : "false"); ++ break; ++ } ++ case CIL_TYPEPERMISSIVE: { ++ struct cil_typepermissive *tp = node->data; ++ fprintf(out, "(typepermissive "); ++ fprintf(out, "%s", datum_or_str(DATUM(tp->type), tp->type_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_TYPEBOUNDS: { ++ struct cil_bounds *bounds = node->data; ++ fprintf(out, "(typebounds %s %s)\n", bounds->parent_str, bounds->child_str); ++ break; ++ } ++ case CIL_ROLEALLOW: { ++ struct cil_roleallow *roleallow = node->data; ++ fprintf(out, "(roleallow "); ++ fprintf(out, "%s ", datum_or_str(DATUM(roleallow->src), roleallow->src_str)); ++ fprintf(out, "%s", datum_or_str(DATUM(roleallow->tgt), roleallow->tgt_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_ROLETRANSITION: { ++ struct cil_roletransition *roletrans = node->data; ++ fprintf(out, "(roletransition "); ++ fprintf(out, "%s ", datum_or_str(DATUM(roletrans->src), roletrans->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(roletrans->tgt), roletrans->tgt_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(roletrans->obj), roletrans->obj_str)); ++ fprintf(out, "%s", datum_or_str(DATUM(roletrans->result), roletrans->result_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_AVRULE: { ++ struct cil_avrule *rule = node->data; ++ if (rule->rule_kind == AVRULE_ALLOWED) ++ fprintf(out, "(allow "); ++ else if (rule->rule_kind == AVRULE_AUDITALLOW) ++ fprintf(out, "(auditallow "); ++ else if (rule->rule_kind == AVRULE_DONTAUDIT) ++ fprintf(out, "(dontaudit "); ++ else if (rule->rule_kind == AVRULE_NEVERALLOW) ++ fprintf(out, "(neverallow "); ++ else ++ fprintf(out, "( "); ++ ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str)); ++ write_classperms_list(out, rule->perms.classperms); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_AVRULEX: { ++ struct cil_avrule *rule = node->data; ++ if (rule->rule_kind == AVRULE_ALLOWED) ++ fprintf(out, "(allowx "); ++ else if (rule->rule_kind == AVRULE_AUDITALLOW) ++ fprintf(out, "(auditallowx "); ++ else if (rule->rule_kind == AVRULE_DONTAUDIT) ++ fprintf(out, "(dontauditx "); ++ else if (rule->rule_kind == AVRULE_NEVERALLOW) ++ fprintf(out, "(neverallowx "); ++ else ++ fprintf(out, "( "); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str)); ++ if (rule->perms.x.permx_str) { ++ fprintf(out, "%s",rule->perms.x.permx_str); ++ } else { ++ write_permx(out, rule->perms.x.permx); ++ } ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_TYPE_RULE: { ++ struct cil_type_rule *rule = node->data; ++ if (rule->rule_kind == AVRULE_TRANSITION) ++ fprintf(out, "(typetransition "); ++ else if (rule->rule_kind == AVRULE_MEMBER) ++ fprintf(out, "(typemember "); ++ else if (rule->rule_kind == AVRULE_CHANGE) ++ fprintf(out, "(typechange "); ++ else ++ fprintf(out, "( "); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str)); ++ fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_NAMETYPETRANSITION: { ++ struct cil_nametypetransition *rule = node->data; ++ fprintf(out, "(typetransition "); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str)); ++ fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str)); ++ fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str)); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_RANGETRANSITION: { ++ struct cil_rangetransition *rule = node->data; ++ fprintf(out, "(rangetransition "); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->exec), rule->exec_str)); ++ fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str)); ++ if (rule->range) ++ write_range(out, rule->range, CIL_TRUE); ++ else ++ fprintf(out, "%s", rule->range_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CONSTRAIN: { ++ struct cil_constrain *cons = node->data; ++ fprintf(out, "(constrain "); ++ write_constrain(out, cons); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_MLSCONSTRAIN: { ++ struct cil_constrain *cons = node->data; ++ fprintf(out, "(mlsconstrain "); ++ write_constrain(out, cons); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_VALIDATETRANS: { ++ struct cil_validatetrans *vt = node->data; ++ fprintf(out, "(validatetrans "); ++ fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str)); ++ if (vt->datum_expr) ++ write_expr(out, vt->datum_expr); ++ else ++ write_expr(out, vt->str_expr); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_MLSVALIDATETRANS: { ++ struct cil_validatetrans *vt = node->data; ++ fprintf(out, "(mlsvalidatetrans "); ++ fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str)); ++ if (vt->datum_expr) ++ write_expr(out, vt->datum_expr); ++ else ++ write_expr(out, vt->str_expr); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_CONTEXT: { ++ struct cil_context *context = node->data; ++ fprintf(out, "(context %s ", datum_to_str(DATUM(context))); ++ write_context(out, context, CIL_FALSE); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_FILECON: { ++ struct cil_filecon *filecon = node->data; ++ fprintf(out, "(filecon "); ++ fprintf(out, "\"%s\" ", filecon->path_str); ++ if (filecon->type == CIL_FILECON_FILE) ++ fprintf(out, "%s ", CIL_KEY_FILE); ++ else if (filecon->type == CIL_FILECON_DIR) ++ fprintf(out, "%s ", CIL_KEY_DIR); ++ else if (filecon->type == CIL_FILECON_CHAR) ++ fprintf(out, "%s ", CIL_KEY_CHAR); ++ else if (filecon->type == CIL_FILECON_BLOCK) ++ fprintf(out, "%s ", CIL_KEY_BLOCK); ++ else if (filecon->type == CIL_FILECON_SOCKET) ++ fprintf(out, "%s ", CIL_KEY_SOCKET); ++ else if (filecon->type == CIL_FILECON_PIPE) ++ fprintf(out, "%s ", CIL_KEY_PIPE); ++ else if (filecon->type == CIL_FILECON_SYMLINK) ++ fprintf(out, "%s ", CIL_KEY_SYMLINK); ++ else if (filecon->type == CIL_FILECON_ANY) ++ fprintf(out, "%s ", CIL_KEY_ANY); ++ else ++ fprintf(out, " "); ++ if (filecon->context) ++ write_context(out, filecon->context, CIL_TRUE); ++ else if (filecon->context_str) ++ fprintf(out, "%s", filecon->context_str); ++ else ++ fprintf(out, "()"); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_IBPKEYCON: { ++ struct cil_ibpkeycon *ibpkeycon = node->data; ++ fprintf(out, "(ibpkeycon %s ", ibpkeycon->subnet_prefix_str); ++ fprintf(out, "(%d %d) ", ibpkeycon->pkey_low, ibpkeycon->pkey_high); ++ if (ibpkeycon->context) ++ write_context(out, ibpkeycon->context, CIL_TRUE); ++ else if (ibpkeycon->context_str) ++ fprintf(out, "%s", ibpkeycon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_PORTCON: { ++ struct cil_portcon *portcon = node->data; ++ fprintf(out, "(portcon "); ++ if (portcon->proto == CIL_PROTOCOL_UDP) ++ fprintf(out, " udp "); ++ else if (portcon->proto == CIL_PROTOCOL_TCP) ++ fprintf(out, " tcp "); ++ else if (portcon->proto == CIL_PROTOCOL_DCCP) ++ fprintf(out, "dccp "); ++ else if (portcon->proto == CIL_PROTOCOL_SCTP) ++ fprintf(out, "sctp "); ++ else ++ fprintf(out, " "); ++ if (portcon->port_low == portcon->port_high) ++ fprintf(out, "%d ", portcon->port_low); ++ else ++ fprintf(out, "(%d %d) ", portcon->port_low, portcon->port_high); ++ if (portcon->context) ++ write_context(out, portcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", portcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_NODECON: { ++ struct cil_nodecon *nodecon = node->data; ++ fprintf(out, "(nodecon "); ++ if (nodecon->addr) ++ write_ipaddr(out, nodecon->addr); ++ else ++ fprintf(out, "%s ", nodecon->addr_str); ++ fprintf(out, " "); ++ if (nodecon->mask) ++ write_ipaddr(out, nodecon->mask); ++ else ++ fprintf(out, "%s ", nodecon->mask_str); ++ fprintf(out, " "); ++ if (nodecon->context) ++ write_context(out, nodecon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", nodecon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_GENFSCON: { ++ struct cil_genfscon *genfscon = node->data; ++ fprintf(out, "(genfscon "); ++ fprintf(out, "%s \"%s\" ", genfscon->fs_str, genfscon->path_str); ++ if (genfscon->context) ++ write_context(out, genfscon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", genfscon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_NETIFCON: { ++ struct cil_netifcon *netifcon = node->data; ++ fprintf(out, "(netifcon %s ", netifcon->interface_str); ++ if (netifcon->if_context) ++ write_context(out, netifcon->if_context, CIL_TRUE); ++ else ++ fprintf(out, "%s", netifcon->if_context_str); ++ fprintf(out, " "); ++ if (netifcon->packet_context) ++ write_context(out, netifcon->packet_context, CIL_TRUE); ++ else ++ fprintf(out, "%s", netifcon->packet_context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_IBENDPORTCON: { ++ struct cil_ibendportcon *ibendportcon = node->data; ++ fprintf(out, "(ibendportcon %s %u ", ibendportcon->dev_name_str, ibendportcon->port); ++ if (ibendportcon->context) ++ write_context(out, ibendportcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", ibendportcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_PIRQCON: { ++ struct cil_pirqcon *pirqcon = node->data; ++ fprintf(out, "(pirqcon %d ", pirqcon->pirq); ++ if (pirqcon->context) ++ write_context(out, pirqcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", pirqcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_IOMEMCON: { ++ struct cil_iomemcon *iomemcon = node->data; ++ fprintf(out, "(iomemcon (%"PRId64" %"PRId64") ", iomemcon->iomem_low, iomemcon->iomem_high); ++ if (iomemcon->context) ++ write_context(out, iomemcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", iomemcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_IOPORTCON: { ++ struct cil_ioportcon *ioportcon = node->data; ++ fprintf(out, "(ioportcon "); ++ if (ioportcon->ioport_low == ioportcon->ioport_high) ++ fprintf(out, "%d ", ioportcon->ioport_low); ++ else ++ fprintf(out, "(%d %d) ", ioportcon->ioport_low, ioportcon->ioport_high); ++ ++ if (ioportcon->context) ++ write_context(out, ioportcon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", ioportcon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_PCIDEVICECON: { ++ struct cil_pcidevicecon *pcidevicecon = node->data; ++ fprintf(out, "(pcidevicecon %d ", pcidevicecon->dev); ++ if (pcidevicecon->context) ++ write_context(out, pcidevicecon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", pcidevicecon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_DEVICETREECON: { ++ struct cil_devicetreecon *devicetreecon = node->data; ++ fprintf(out, "(devicetreecon \"%s\" ", devicetreecon->path); ++ if (devicetreecon->context) ++ write_context(out, devicetreecon->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", devicetreecon->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_FSUSE: { ++ struct cil_fsuse *fsuse = node->data; ++ fprintf(out, "(fsuse "); ++ if (fsuse->type == CIL_FSUSE_XATTR) ++ fprintf(out, "xattr "); ++ else if (fsuse->type == CIL_FSUSE_TASK) ++ fprintf(out, "task "); ++ else if (fsuse->type == CIL_FSUSE_TRANS) ++ fprintf(out, "trans "); ++ else ++ fprintf(out, " "); ++ fprintf(out, "%s ", fsuse->fs_str); ++ if (fsuse->context) ++ write_context(out, fsuse->context, CIL_TRUE); ++ else ++ fprintf(out, "%s", fsuse->context_str); ++ fprintf(out, ")\n"); ++ break; ++ } ++ case CIL_POLICYCAP: { ++ struct cil_policycap *polcap = node->data; ++ fprintf(out, "(policycap %s)\n", polcap->datum.name); ++ break; ++ } ++ case CIL_IPADDR: { ++ struct cil_ipaddr *ipaddr = node->data; ++ char buf[256]; ++ if (inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256) == NULL) ++ strcpy(buf, ""); ++ fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf); ++ break; ++ } ++ default : ++ fprintf(out, "()\n", cil_node_to_string(node)); ++ break; ++ } ++} ++ ++/* ++ * Tree walk data and helper functions for writing the AST of the various phases ++ */ ++ ++struct cil_write_ast_args { ++ FILE *out; ++ int depth; ++}; ++ ++/* ++ * Helper functions for writing the parse AST ++ */ ++ ++static int __write_parse_ast_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ ++ fprintf(args->out, "%*s", args->depth*4, ""); ++ if (!node->data) { ++ if (node->cl_head) ++ fprintf(args->out, "(\n"); ++ else ++ fprintf(args->out, "()\n"); ++ } else { ++ char *str = (char *)node->data; ++ size_t len = strlen(str); ++ size_t i; ++ ++ for (i = 0; i < len; i++) { ++ if (isspace(str[i])) { ++ fprintf(args->out, "\"%s\"\n", str); ++ return SEPOL_OK; ++ } ++ } ++ ++ fprintf(args->out, "%s\n", (char *)node->data); ++ } ++ ++ return SEPOL_OK; ++} ++ ++static int __write_parse_ast_first_child_helper(struct cil_tree_node *node, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ struct cil_tree_node *parent = node->parent; ++ ++ if (parent->flavor != CIL_ROOT) { ++ args->depth++; ++ } ++ ++ return SEPOL_OK; ++} ++ ++static int __write_parse_ast_last_child_helper(struct cil_tree_node *node, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ struct cil_tree_node *parent = node->parent; ++ ++ if (parent->flavor == CIL_ROOT) { ++ return SEPOL_OK; ++ } ++ ++ args->depth--; ++ fprintf(args->out, "%*s", args->depth*4, ""); ++ fprintf(args->out, ")\n"); ++ ++ return SEPOL_OK; ++} ++ ++/* ++ * Helper functions for writing the CIL AST for the build and resolve phases ++ */ ++ ++static int __write_cil_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ ++ if (node->flavor == CIL_SRC_INFO) ++ return SEPOL_OK; ++ ++ fprintf(args->out, "%*s", args->depth*4, ""); ++ ++ cil_write_ast_node(args->out, node); ++ ++ if (node->flavor == CIL_CLASS || node->flavor == CIL_COMMON || node->flavor == CIL_MAP_CLASS) { ++ *finished = CIL_TREE_SKIP_HEAD; ++ } ++ ++ return SEPOL_OK; ++} ++ ++static int __write_cil_ast_first_child_helper(struct cil_tree_node *node, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ struct cil_tree_node *parent = node->parent; ++ ++ if (parent->flavor != CIL_SRC_INFO && parent->flavor != CIL_ROOT) { ++ args->depth++; ++ } ++ ++ return SEPOL_OK; ++} ++ ++static int __write_cil_ast_last_child_helper(struct cil_tree_node *node, void *extra_args) ++{ ++ struct cil_write_ast_args *args = extra_args; ++ struct cil_tree_node *parent = node->parent; ++ ++ if (parent->flavor == CIL_SRC_INFO || parent->flavor == CIL_ROOT) { ++ return SEPOL_OK; ++ } ++ ++ args->depth--; ++ fprintf(args->out, "%*s", args->depth*4, ""); ++ fprintf(args->out, ")\n"); ++ ++ return SEPOL_OK; ++} ++ ++int cil_write_ast(FILE *out, enum cil_write_ast_phase phase, struct cil_tree_node *node) ++{ ++ struct cil_write_ast_args extra_args; ++ int rc; ++ ++ extra_args.out = out; ++ extra_args.depth = 0; ++ ++ if (phase == CIL_WRITE_AST_PHASE_PARSE) { ++ rc = cil_tree_walk(node, __write_parse_ast_node_helper, __write_parse_ast_first_child_helper, __write_parse_ast_last_child_helper, &extra_args); ++ } else { ++ rc = cil_tree_walk(node, __write_cil_ast_node_helper, __write_cil_ast_first_child_helper, __write_cil_ast_last_child_helper, &extra_args); ++ } ++ ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to write AST\n"); ++ return SEPOL_ERR; ++ } ++ ++ return SEPOL_OK; ++} +diff --git a/libsepol/cil/src/cil_write_ast.h b/libsepol/cil/src/cil_write_ast.h +new file mode 100644 +index 000000000000..3f4b9d95ca1a +--- /dev/null ++++ b/libsepol/cil/src/cil_write_ast.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright 2011 Tresys Technology, LLC. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO ++ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ++ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation are those ++ * of the authors and should not be interpreted as representing official policies, ++ * either expressed or implied, of Tresys Technology, LLC. ++ */ ++ ++#ifndef CIL_WRITE_AST_H_ ++#define CIL_WRITE_AST_H_ ++ ++#include ++ ++#include "cil_tree.h" ++ ++enum cil_write_ast_phase { ++ CIL_WRITE_AST_PHASE_PARSE = 0, ++ CIL_WRITE_AST_PHASE_BUILD, ++ CIL_WRITE_AST_PHASE_RESOLVE, ++}; ++ ++void cil_write_ast_node(FILE *out, struct cil_tree_node *node); ++int cil_write_ast(FILE *out, enum cil_write_ast_phase phase, struct cil_tree_node *node); ++ ++#endif /* CIL_WRITE_AST_H_ */ +-- +2.32.0 + diff --git a/SOURCES/0040-libsepol-cil-Add-functions-to-make-use-of-cil_write_.patch b/SOURCES/0040-libsepol-cil-Add-functions-to-make-use-of-cil_write_.patch new file mode 100644 index 0000000..ca8d7c6 --- /dev/null +++ b/SOURCES/0040-libsepol-cil-Add-functions-to-make-use-of-cil_write_.patch @@ -0,0 +1,158 @@ +From 86ec04cfded8b2a76953ca2682d2a32bf6b24721 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 21 Apr 2021 13:21:11 -0400 +Subject: [PATCH] libsepol/cil: Add functions to make use of cil_write_ast() + +Add the functions cil_write_parse_ast(), cil_write_build_ast(), +and cil_write_resolve_ast() that can be used outside of libsepol. + +These functions take a FILE pointer and CIL db, do the CIL build +through the desired phase, and then call cil_write_ast() to write +the CIL AST at that point. + +Signed-off-by: James Carter +--- + libsepol/cil/include/cil/cil.h | 3 ++ + libsepol/cil/src/cil.c | 92 ++++++++++++++++++++++++++++++++++ + libsepol/src/libsepol.map.in | 3 ++ + 3 files changed, 98 insertions(+) + +diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h +index e6f4503eb33a..92fac6e1619a 100644 +--- a/libsepol/cil/include/cil/cil.h ++++ b/libsepol/cil/include/cil/cil.h +@@ -60,6 +60,9 @@ extern void cil_set_attrs_expand_size(struct cil_db *db, unsigned attrs_expand_s + extern void cil_set_target_platform(cil_db_t *db, int target_platform); + extern void cil_set_policy_version(cil_db_t *db, int policy_version); + extern void cil_write_policy_conf(FILE *out, struct cil_db *db); ++extern int cil_write_parse_ast(FILE *out, cil_db_t *db); ++extern int cil_write_build_ast(FILE *out, cil_db_t *db); ++extern int cil_write_resolve_ast(FILE *out, cil_db_t *db); + + enum cil_log_level { + CIL_ERR = 1, +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index b971922c70b5..0d351b491c2c 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -50,6 +50,7 @@ + #include "cil_binary.h" + #include "cil_policy.h" + #include "cil_strpool.h" ++#include "cil_write_ast.h" + + int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = { + {64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, +@@ -572,6 +573,97 @@ exit: + return rc; + } + ++int cil_write_parse_ast(FILE *out, cil_db_t *db) ++{ ++ int rc = SEPOL_ERR; ++ ++ if (db == NULL) { ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Writing Parse AST\n"); ++ rc = cil_write_ast(out, CIL_WRITE_AST_PHASE_PARSE, db->parse->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to write parse ast\n"); ++ goto exit; ++ } ++ ++exit: ++ return rc; ++} ++ ++int cil_write_build_ast(FILE *out, cil_db_t *db) ++{ ++ int rc = SEPOL_ERR; ++ ++ if (db == NULL) { ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Building AST from Parse Tree\n"); ++ rc = cil_build_ast(db, db->parse->root, db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to build ast\n"); ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Destroying Parse Tree\n"); ++ cil_tree_destroy(&db->parse); ++ ++ cil_log(CIL_INFO, "Writing Build AST\n"); ++ rc = cil_write_ast(out, CIL_WRITE_AST_PHASE_BUILD, db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to write build ast\n"); ++ goto exit; ++ } ++ ++exit: ++ return rc; ++} ++ ++int cil_write_resolve_ast(FILE *out, cil_db_t *db) ++{ ++ int rc = SEPOL_ERR; ++ ++ if (db == NULL) { ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Building AST from Parse Tree\n"); ++ rc = cil_build_ast(db, db->parse->root, db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to build ast\n"); ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Destroying Parse Tree\n"); ++ cil_tree_destroy(&db->parse); ++ ++ cil_log(CIL_INFO, "Resolving AST\n"); ++ rc = cil_resolve_ast(db, db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to resolve ast\n"); ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Qualifying Names\n"); ++ rc = cil_fqn_qualify(db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to qualify names\n"); ++ goto exit; ++ } ++ ++ cil_log(CIL_INFO, "Writing Resolve AST\n"); ++ rc = cil_write_ast(out, CIL_WRITE_AST_PHASE_RESOLVE, db->ast->root); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to write resolve ast\n"); ++ goto exit; ++ } ++ ++exit: ++ return rc; ++} ++ + int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db) + { + int rc; +diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in +index eb5721257638..2e503bd1b453 100644 +--- a/libsepol/src/libsepol.map.in ++++ b/libsepol/src/libsepol.map.in +@@ -269,4 +269,7 @@ LIBSEPOL_1.1 { + LIBSEPOL_3.0 { + global: + sepol_policydb_optimize; ++ cil_write_parse_ast; ++ cil_write_build_ast; ++ cil_write_resolve_ast; + } LIBSEPOL_1.1; +-- +2.32.0 + diff --git a/SOURCES/0041-libsepol-use-checked-arithmetic-builtin-to-perform-s.patch b/SOURCES/0041-libsepol-use-checked-arithmetic-builtin-to-perform-s.patch new file mode 100644 index 0000000..82dca14 --- /dev/null +++ b/SOURCES/0041-libsepol-use-checked-arithmetic-builtin-to-perform-s.patch @@ -0,0 +1,103 @@ +From 0744fa4f533c765d0a704fe8aa7174a0f93eb7bc Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Thu, 22 Apr 2021 08:46:04 +0200 +Subject: [PATCH] libsepol: use checked arithmetic builtin to perform safe + addition + +Checking whether an overflow occurred after adding two values can be +achieved using checked arithmetic builtin functions such as: + + bool __builtin_add_overflow(type1 x, type2 y, type3 *sum); + +This function is available at least in clang +(at least since clang 3.8.0, +https://releases.llvm.org/3.8.0/tools/clang/docs/LanguageExtensions.html#checked-arithmetic-builtins) +and gcc +(https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html, +since gcc 5 according to https://gcc.gnu.org/gcc-5/changes.html) + +Signed-off-by: Nicolas Iooss +--- + libsepol/src/context_record.c | 29 ++++++----------------------- + libsepol/src/module_to_cil.c | 6 ++---- + 2 files changed, 8 insertions(+), 27 deletions(-) + +diff --git a/libsepol/src/context_record.c b/libsepol/src/context_record.c +index 317a42133884..435f788058c4 100644 +--- a/libsepol/src/context_record.c ++++ b/libsepol/src/context_record.c +@@ -267,31 +267,13 @@ int sepol_context_from_string(sepol_handle_t * handle, + return STATUS_ERR; + } + +- +-static inline int safe_sum(size_t *sum, const size_t augends[], const size_t cnt) { +- +- size_t a, i; +- +- *sum = 0; +- for(i=0; i < cnt; i++) { +- /* sum should not be smaller than the addend */ +- a = augends[i]; +- *sum += a; +- if (*sum < a) { +- return i; +- } +- } +- +- return 0; +-} +- + int sepol_context_to_string(sepol_handle_t * handle, + const sepol_context_t * con, char **str_ptr) + { + + int rc; + char *str = NULL; +- size_t total_sz, err; ++ size_t total_sz = 0, i; + const size_t sizes[] = { + strlen(con->user), /* user length */ + strlen(con->role), /* role length */ +@@ -300,10 +282,11 @@ int sepol_context_to_string(sepol_handle_t * handle, + ((con->mls) ? 3 : 2) + 1 /* mls has extra ":" also null byte */ + }; + +- err = safe_sum(&total_sz, sizes, ARRAY_SIZE(sizes)); +- if (err) { +- ERR(handle, "invalid size, overflow at position: %zu", err); +- goto err; ++ for (i = 0; i < ARRAY_SIZE(sizes); i++) { ++ if (__builtin_add_overflow(total_sz, sizes[i], &total_sz)) { ++ ERR(handle, "invalid size, overflow at position: %zu", i); ++ goto err; ++ } + } + + str = (char *)malloc(total_sz); +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index 58df0d4f6d77..496693f4616e 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -1134,16 +1134,14 @@ static int name_list_to_string(char **names, unsigned int num_names, char **stri + char *strpos; + + for (i = 0; i < num_names; i++) { +- len += strlen(names[i]); +- if (len < strlen(names[i])) { ++ if (__builtin_add_overflow(len, strlen(names[i]), &len)) { + log_err("Overflow"); + return -1; + } + } + + // add spaces + null terminator +- len += num_names; +- if (len < (size_t)num_names) { ++ if (__builtin_add_overflow(len, (size_t)num_names, &len)) { + log_err("Overflow"); + return -1; + } +-- +2.32.0 + diff --git a/SOURCES/0042-libsepol-cil-Properly-reset-an-anonymous-classperm-s.patch b/SOURCES/0042-libsepol-cil-Properly-reset-an-anonymous-classperm-s.patch new file mode 100644 index 0000000..2a1c6b5 --- /dev/null +++ b/SOURCES/0042-libsepol-cil-Properly-reset-an-anonymous-classperm-s.patch @@ -0,0 +1,51 @@ +From 2d2c76fc613ba338476a3a1741c2a3af5e04d154 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 26 Apr 2021 15:22:05 -0400 +Subject: [PATCH] libsepol/cil: Properly reset an anonymous classperm set + +In struct cil_classperms_set, the "set" field is a pointer to a +struct cil_classpermission. Normally the classpermission is created +in a classpermissionset rule with a name declared in a +classpermission rule and stored in a symbol table. Commit c49a8ea0 +("libsepol/cil: cil_reset_classperms_set() should not reset +classpermission") fixed the resetting of classperms sets by setting +the "set" field to NULL rather than resetting the classpermission +that it pointed to. + +But this fix mixed the special case where an anonymous classperm +set is passed as an argument to a call. In this case the +classpermission is not named and not stored in a symtab, it is +created just for the classperms set and its classperms list needs +to be reset. + +Reset the classperms list if the classperms set is anonymous (which +is when the datum name is NULL). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 76405aba6194..d24d4f8159a3 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -60,10 +60,14 @@ static void cil_reset_classpermission(struct cil_classpermission *cp) + + static void cil_reset_classperms_set(struct cil_classperms_set *cp_set) + { +- if (cp_set == NULL) { ++ if (cp_set == NULL || cp_set->set == NULL) { + return; + } + ++ if (cp_set->set->datum.name == NULL) { ++ cil_reset_classperms_list(cp_set->set->classperms); ++ } ++ + cp_set->set = NULL; + } + +-- +2.32.0 + diff --git a/SOURCES/0043-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch b/SOURCES/0043-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch new file mode 100644 index 0000000..77dcc9b --- /dev/null +++ b/SOURCES/0043-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch @@ -0,0 +1,80 @@ +From 5681c6275b5ad9cf3d84af243a66b900a0628f72 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:06:58 -0400 +Subject: [PATCH] libsepol/cil: Fix instances where an error returns SEPOL_OK + +There are six instances when the CIL policy is being built or +resolved where an error can be detected, but SEPOL_OK is returned +instead of SEPOL_ERR. This causes the policy compiler to continue +when it should exit with an error. + +Return SEPOL_ERR in these cases, so the compiler exits with an +error. + +Two of the instances were found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 3 +++ + libsepol/cil/src/cil_resolve_ast.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 5b1e28246b2e..87043a8fa183 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -444,6 +444,7 @@ int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct + } + if (class->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in class '%s'", class->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -1018,6 +1019,7 @@ int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struc + } + if (common->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in common '%s'", common->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -3209,6 +3211,7 @@ int cil_gen_expandtypeattribute(struct cil_db *db, struct cil_tree_node *parse_c + expandattr->expand = CIL_FALSE; + } else { + cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'"); ++ rc = SEPOL_ERR; + goto exit; + } + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 872b6799b0bf..5389df43fed7 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -772,6 +772,7 @@ int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args) + class->num_perms += common->num_perms; + if (class->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(current, CIL_ERR, "Too many permissions in class '%s' when including common permissions", class->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -1484,6 +1485,7 @@ int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args) + rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to resolve class %s in classorder\n", (char *)curr->data); ++ rc = SEPOL_ERR; + goto exit; + } + cil_list_append(new, CIL_CLASS, datum); +@@ -2464,6 +2466,7 @@ int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) + block_node = NODE(block_datum); + if (block_node->flavor != CIL_BLOCK) { + cil_log(CIL_ERR, "Failed to resolve blockabstract to a block, rc: %d\n", rc); ++ rc = SEPOL_ERR; + goto exit; + } + +-- +2.32.0 + diff --git a/SOURCES/0044-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch b/SOURCES/0044-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch new file mode 100644 index 0000000..d979cd3 --- /dev/null +++ b/SOURCES/0044-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch @@ -0,0 +1,136 @@ +From 74d00a8decebf940d95064ff60042dcb2cbcc2c0 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:07:02 -0400 +Subject: [PATCH] libsepol/cil: Detect degenerate inheritance and exit with an + error + +A CIL policy with inheritance of the form +... +(blockinherit ba) +(block ba + (block b1 + (blockinherit bb) + ) + (block bb + (block b2 + (blockinherit bc) + ) + (block bc + (block b3 + (blockinherit bd) + ) + (block bd + (block b4 + (blockinherit be) + ) + (block be + ... +will require creating 2^depth copies of the block at the bottom of +the inheritance chain. This pattern can quickly consume all the +memory of the system compiling this policy. + +The depth of the inheritance chain can be found be walking the +tree up through the parents and noting how many of the parent +blocks have been inherited. The number of times a block will be +copied is found by counting the list of nodes in the "bi_nodes" +list of the block. To minimize legitimate policies from being +falsely detected as being degenerate, both the depth and breadth +(number of copies) are checked and an error is given only if both +exceed the limits (depth >= 12 and breadth >= 4096). + +This problem was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_internal.h | 2 ++ + libsepol/cil/src/cil_resolve_ast.c | 54 ++++++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 9bdcbdd013c0..74e0b34d6cbd 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -48,6 +48,8 @@ + + #define CIL_MAX_NAME_LENGTH 2048 + ++#define CIL_DEGENERATE_INHERITANCE_DEPTH 12 ++#define CIL_DEGENERATE_INHERITANCE_BREADTH (0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH) + + enum cil_pass { + CIL_PASS_INIT = 0, +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 5389df43fed7..6890964728cb 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2410,6 +2410,55 @@ exit: + return rc; + } + ++/* ++ * Detect degenerate inheritance of the form: ++ * ... ++ * (blockinherit ba) ++ * (block ba ++ * (block b1 ++ * (blockinherit bb) ++ * ) ++ * (block bb ++ * (block b2 ++ * (blockinherit bc) ++ * ) ++ * (block bc ++ * ... ++ */ ++static int cil_check_for_degenerate_inheritance(struct cil_tree_node *current) ++{ ++ struct cil_block *block = current->data; ++ struct cil_tree_node *node; ++ struct cil_list_item *item; ++ unsigned depth; ++ unsigned breadth = 0; ++ ++ cil_list_for_each(item, block->bi_nodes) { ++ breadth++; ++ } ++ ++ if (breadth >= CIL_DEGENERATE_INHERITANCE_BREADTH) { ++ node = current->parent; ++ depth = 0; ++ while (node && node->flavor != CIL_ROOT) { ++ if (node->flavor == CIL_BLOCK) { ++ block = node->data; ++ if (block->bi_nodes != NULL) { ++ depth++; ++ } ++ } ++ node = node->parent; ++ } ++ ++ if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { ++ cil_tree_log(current, CIL_ERR, "Degenerate inheritance detected (depth=%u, breadth=%u)", depth, breadth); ++ return SEPOL_ERR; ++ } ++ } ++ ++ return SEPOL_OK; ++} ++ + int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) + { + struct cil_block *block = current->data; +@@ -2426,6 +2475,11 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + + db = args->db; + ++ rc = cil_check_for_degenerate_inheritance(current); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ + // Make sure this is the original block and not a merged block from a blockinherit + if (current != block->datum.nodes->head->data) { + rc = SEPOL_OK; +-- +2.32.0 + diff --git a/SOURCES/0045-libsepol-cil-Check-datum-in-ordered-list-for-expecte.patch b/SOURCES/0045-libsepol-cil-Check-datum-in-ordered-list-for-expecte.patch new file mode 100644 index 0000000..26ce37b --- /dev/null +++ b/SOURCES/0045-libsepol-cil-Check-datum-in-ordered-list-for-expecte.patch @@ -0,0 +1,69 @@ +From d438b6cfb3d4b60cd9ced49be817f67902910912 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:07:03 -0400 +Subject: [PATCH] libsepol/cil: Check datum in ordered list for expected flavor + +The secilc-fuzzer found an out of bounds memory access occurs +when building the binary policy if a map class is included in a +classorder statement. + +The order statements in CIL (sidorder, classorder, categoryorder, +and sensitivityorder) are used to specify an ordering for sids, +classes, categories, and sensitivities. When the order statments +are resolved and merged, only in the case of the category order +list is the datum resolved checked to see if it is the expected +flavor. + +When resolving the sid, class, and sensitivity order statements, +check that each name resolved to a datum of the expected flavor +and return an error if it does not. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 6890964728cb..b081d45d4cb5 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -1488,6 +1488,11 @@ int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args) + rc = SEPOL_ERR; + goto exit; + } ++ if (FLAVOR(datum) != CIL_CLASS) { ++ cil_log(CIL_ERR, "%s is not a class. Only classes are allowed in classorder statements\n", datum->name); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + cil_list_append(new, CIL_CLASS, datum); + } + +@@ -1526,6 +1531,12 @@ int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args) + cil_log(CIL_ERR, "Failed to resolve sid %s in sidorder\n", (char *)curr->data); + goto exit; + } ++ if (FLAVOR(datum) != CIL_SID) { ++ cil_log(CIL_ERR, "%s is not a sid. Only sids are allowed in sidorder statements\n", datum->name); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ + cil_list_append(new, CIL_SID, datum); + } + +@@ -1617,6 +1628,11 @@ int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args + cil_log(CIL_ERR, "Failed to resolve sensitivty %s in sensitivityorder\n", (char *)curr->data); + goto exit; + } ++ if (FLAVOR(datum) != CIL_SENS) { ++ cil_log(CIL_ERR, "%s is not a sensitivity. Only sensitivities are allowed in sensitivityorder statements\n", datum->name); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + cil_list_append(new, CIL_SENS, datum); + } + +-- +2.32.0 + diff --git a/SOURCES/0046-libsepol-cil-Return-an-error-if-a-call-argument-fail.patch b/SOURCES/0046-libsepol-cil-Return-an-error-if-a-call-argument-fail.patch new file mode 100644 index 0000000..717260e --- /dev/null +++ b/SOURCES/0046-libsepol-cil-Return-an-error-if-a-call-argument-fail.patch @@ -0,0 +1,40 @@ +From d9433692c782b65e5397234950c6d9993fbcaa70 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:07:09 -0400 +Subject: [PATCH] libsepol/cil: Return an error if a call argument fails to + resolve + +Return an error if a call argument fails to resolve so that +the resolution phase stops and returns an error. + +This problem was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index b081d45d4cb5..f251ed1582fc 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3277,6 +3277,7 @@ int cil_resolve_call2(struct cil_tree_node *current, void *extra_args) + if (sym_index != CIL_SYM_UNKNOWN) { + rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &(arg->arg)); + if (rc != SEPOL_OK) { ++ cil_tree_log(current, CIL_ERR, "Failed to resolve %s in call argument list", arg->arg_str); + goto exit; + } + } +@@ -3308,7 +3309,7 @@ int cil_resolve_name_call_args(struct cil_call *call, char *name, enum cil_sym_i + if (param_index == sym_index) { + if (name == arg->param_str) { + *datum = arg->arg; +- rc = SEPOL_OK; ++ rc = *datum ? SEPOL_OK : SEPOL_ERR; + goto exit; + } + } +-- +2.32.0 + diff --git a/SOURCES/0047-libsepol-cil-Check-for-self-referential-loops-in-set.patch b/SOURCES/0047-libsepol-cil-Check-for-self-referential-loops-in-set.patch new file mode 100644 index 0000000..9c4ebf3 --- /dev/null +++ b/SOURCES/0047-libsepol-cil-Check-for-self-referential-loops-in-set.patch @@ -0,0 +1,244 @@ +From 61fbdce666f24c4a118b249ece6b014d54b65074 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 4 May 2021 16:14:55 -0400 +Subject: [PATCH] libsepol/cil: Check for self-referential loops in sets + +The secilc-fuzzer found a self-referential loop using category sets. +Any set declaration in CIL that allows sets in it is susceptible to +the creation of a self-referential loop. There is a check, but only +for the name of the set being declared being used in the set +declaration. + +Check for self-refential loops in user, role, and type attributes +and in category sets. Since all of the sets need to be declared, +this check has to be done when verifying the CIL db before doing +the post phase. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 31 +--------- + libsepol/cil/src/cil_verify.c | 97 +++++++++++++++++++++--------- + libsepol/cil/src/cil_verify.h | 1 - + 3 files changed, 71 insertions(+), 58 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index f251ed1582fc..5368ae80ede9 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -438,11 +438,6 @@ int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args + goto exit; + } + +- rc = cil_verify_no_self_reference(attr_datum, attrtypes->datum_expr); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + if (attr->expr_list == NULL) { + cil_list_init(&attr->expr_list, CIL_TYPEATTRIBUTE); + } +@@ -1151,11 +1146,6 @@ int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args + goto exit; + } + +- rc = cil_verify_no_self_reference(attr_datum, attrroles->datum_expr); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + if (attr->expr_list == NULL) { + cil_list_init(&attr->expr_list, CIL_ROLEATTRIBUTE); + } +@@ -1666,21 +1656,7 @@ exit: + + int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args) + { +- int rc = SEPOL_ERR; +- +- rc = cil_resolve_cats(current, catset->cats, extra_args); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- +- rc = cil_verify_no_self_reference((struct cil_symtab_datum *)catset, catset->cats->datum_expr); +- if (rc != SEPOL_OK) { +- cil_list_destroy(&catset->cats->datum_expr, CIL_FALSE); +- goto exit; +- } +- +-exit: +- return rc; ++ return cil_resolve_cats(current, catset->cats, extra_args); + } + + int cil_resolve_senscat(struct cil_tree_node *current, void *extra_args) +@@ -3545,11 +3521,6 @@ int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args + goto exit; + } + +- rc = cil_verify_no_self_reference(attr_datum, attrusers->datum_expr); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + if (attr->expr_list == NULL) { + cil_list_init(&attr->expr_list, CIL_USERATTRIBUTE); + } +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 5a37dd2f76bc..8e15a0e68a69 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -430,28 +430,71 @@ int cil_verify_decl_does_not_shadow_macro_parameter(struct cil_macro *macro, str + return SEPOL_OK; + } + +-int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list) ++static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_symtab_datum *orig); ++ ++static int __verify_no_self_reference_in_expr(struct cil_list *expr, struct cil_symtab_datum *orig) + { +- struct cil_list_item *i; ++ struct cil_list_item *item; ++ int rc = SEPOL_OK; + +- cil_list_for_each(i, datum_list) { +- if (i->flavor == CIL_DATUM) { +- struct cil_symtab_datum *d = i->data; +- if (d == datum) { +- cil_log(CIL_ERR,"Self-reference found for %s\n",datum->name); +- return SEPOL_ERR; +- } +- } else if (i->flavor == CIL_LIST) { +- int rc = cil_verify_no_self_reference(datum, i->data); +- if (rc != SEPOL_OK) { +- return SEPOL_ERR; +- } ++ if (!expr) { ++ return SEPOL_OK; ++ } ++ ++ cil_list_for_each(item, expr) { ++ if (item->flavor == CIL_DATUM) { ++ struct cil_symtab_datum* datum = item->data; ++ rc = cil_verify_no_self_reference(FLAVOR(datum), datum, orig); ++ } else if (item->flavor == CIL_LIST) { ++ rc = __verify_no_self_reference_in_expr(item->data, orig); ++ } ++ if (rc != SEPOL_OK) { ++ return SEPOL_ERR; + } + } + + return SEPOL_OK; + } + ++static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_symtab_datum *orig) ++{ ++ int rc = SEPOL_OK; ++ ++ if (datum == orig) { ++ cil_tree_log(NODE(orig), CIL_ERR, "Self-reference found for %s", orig->name); ++ return SEPOL_ERR; ++ } else if (orig == NULL) { ++ orig = datum; ++ } ++ ++ switch (flavor) { ++ case CIL_USERATTRIBUTE: { ++ struct cil_userattribute *attr = (struct cil_userattribute *)datum; ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ break; ++ } ++ case CIL_ROLEATTRIBUTE: { ++ struct cil_roleattribute *attr = (struct cil_roleattribute *)datum; ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ break; ++ } ++ case CIL_TYPEATTRIBUTE: { ++ struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ break; ++ } ++ case CIL_CATSET: { ++ struct cil_catset *set = (struct cil_catset *)datum; ++ rc = __verify_no_self_reference_in_expr(set->cats->datum_expr, orig); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return rc; ++} ++ + int __cil_verify_ranges(struct cil_list *list) + { + int rc = SEPOL_ERR; +@@ -1757,27 +1800,22 @@ static int __cil_verify_map_class(struct cil_tree_node *node) + + int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __attribute__((unused)) void *extra_args) + { +- int rc = SEPOL_ERR; ++ int rc = SEPOL_OK; + +- if (node->flavor == CIL_MACRO) { ++ switch (node->flavor) { ++ case CIL_MACRO: { + *finished = CIL_TREE_SKIP_HEAD; +- rc = SEPOL_OK; +- goto exit; +- } else if (node->flavor == CIL_BLOCK) { ++ break; ++ } ++ case CIL_BLOCK: { + struct cil_block *blk = node->data; + if (blk->is_abstract == CIL_TRUE) { + *finished = CIL_TREE_SKIP_HEAD; + } +- rc = SEPOL_OK; +- goto exit; ++ break; + } +- +- switch (node->flavor) { + case CIL_USER: + rc = __cil_verify_user_pre_eval(node); +- if (rc != SEPOL_OK) { +- goto exit; +- } + break; + case CIL_MAP_CLASS: + rc = __cil_verify_map_class(node); +@@ -1785,11 +1823,16 @@ int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __at + case CIL_CLASSPERMISSION: + rc = __cil_verify_classpermission(node); + break; ++ case CIL_USERATTRIBUTE: ++ case CIL_ROLEATTRIBUTE: ++ case CIL_TYPEATTRIBUTE: ++ case CIL_CATSET: ++ rc = cil_verify_no_self_reference(node->flavor, node->data, NULL); ++ break; + default: + rc = SEPOL_OK; + break; + } + +-exit: + return rc; + } +diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h +index c497018f8a95..4ea14f5b0a9a 100644 +--- a/libsepol/cil/src/cil_verify.h ++++ b/libsepol/cil/src/cil_verify.h +@@ -63,7 +63,6 @@ int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_fl + int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op); + int cil_verify_conditional_blocks(struct cil_tree_node *current); + int cil_verify_decl_does_not_shadow_macro_parameter(struct cil_macro *macro, struct cil_tree_node *node, const char *name); +-int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list); + int __cil_verify_ranges(struct cil_list *list); + int __cil_verify_ordered_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args); + int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor); +-- +2.32.0 + diff --git a/SOURCES/0048-libsepol-cil-Fix-name-resolution-involving-inherited.patch b/SOURCES/0048-libsepol-cil-Fix-name-resolution-involving-inherited.patch new file mode 100644 index 0000000..74df5f4 --- /dev/null +++ b/SOURCES/0048-libsepol-cil-Fix-name-resolution-involving-inherited.patch @@ -0,0 +1,74 @@ +From 0d6e95cfb24fd0bc5405ecea0b3ebac3462b5312 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 6 May 2021 13:05:36 -0400 +Subject: [PATCH] libsepol/cil: Fix name resolution involving inherited blocks + +When resolving a name in a block that has been inherited. First, +a search is done in the parent namespaces (if any) of the +blockinherit rule with the exception of the global namespace. If +the name is not found, then a search is done in the namespaces of +the original block (starting with that block's namespace) with +the exception of the global namespace. Finally, if it still has +not been found, the global namespace is searched. + +This does not work if a declaration is in the block being +inherited. + +For example: + (block b + (typeattribute a) + (allow a self (CLASS (PERM))) + ) + (blockinherit b) + +This will result in a policy with the following identical allow +rules: + (allow b.a self (CLASS (PERM))) + (allow b.a self (CLASS (PERM))) +rather than the expected: + (allow b.a self (CLASS (PERM))) + (allow a self (CLASS (PERM))) +This is because when the typeattribute is copied while resolving +the inheritance, the new datum is added to the global namespace +and, since that is searched last, the typeattribute in block b is +found first. + +This behavior means that no declaration that is inherited into the +global namespace will actually be used. + +Instead, if the name is not found in the parent namespaces (if any) +where the blockinherit is located with the exception of the global +namespace, start the next search in the namespace of the parent of +the original block (instead of the original block itself). Now if +a declaration is inherited from the original block, the new +declaration will be used. This behavior seems to be the originally +intended behavior because there is a comment in the code that says, +"Continue search in original block's parent". + +This issue was found by secilc-fuzzer. If the original block +is made to be abstract, then the type attribute declaration +in the original block is not in the policy and a segfault +occurs when creating the binary because the copied allow rule +refers to a non-existent type attribute. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 5368ae80ede9..5684b8da0f76 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4182,7 +4182,7 @@ static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *nam + rc = __cil_resolve_name_with_parents(node->parent, name, sym_index, datum); + if (rc != SEPOL_OK) { + /* Continue search in original block's parent */ +- rc = __cil_resolve_name_with_parents(NODE(inherit->block), name, sym_index, datum); ++ rc = __cil_resolve_name_with_parents(NODE(inherit->block)->parent, name, sym_index, datum); + goto exit; + } + } +-- +2.32.0 + diff --git a/SOURCES/0049-libsepol-cil-Make-name-resolution-in-macros-work-as-.patch b/SOURCES/0049-libsepol-cil-Make-name-resolution-in-macros-work-as-.patch new file mode 100644 index 0000000..e8165ee --- /dev/null +++ b/SOURCES/0049-libsepol-cil-Make-name-resolution-in-macros-work-as-.patch @@ -0,0 +1,75 @@ +From 788d40b0e61f352524660d0965d5e86f6e1e0718 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 11 May 2021 09:43:22 -0400 +Subject: [PATCH] libsepol/cil: Make name resolution in macros work as + documented + +The CIL Reference Guide specifies how name resolution is suppose +to work within an expanded macro. + 1. Items defined inside the macro + 2. Items passed into the macro as arguments + 3. Items defined in the same namespace of the macro + 4. Items defined in the caller's namespace + 5. Items defined in the global namespace + +But Lorenzo Ceragioli found +that the first step is not done. + +So the following policy: + (block A + (type a) + (macro m () + (type a) + (allow a self (CLASS (PERM))) + ) + ) + (block B + (call A.m) + ) +will result in: + (allow A.a self (CLASS (PERM))) +instead of the expected: + (allow B.a self (CLASS (PERM))) + +Now when an expanded call is found, the macro's namespace is +checked first. If the name is found, then the name was declared +in the macro and it is declared in the expanded call, so only the +namespace of the call up to and including the global namespace +will be searched. If the name is not found in the macro's namespace +then name resolution continues with steps 2-5 above. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 5684b8da0f76..ae6743f92f4c 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4195,10 +4195,18 @@ static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *nam + break; + case CIL_CALL: { + struct cil_call *call = node->data; +- rc = cil_resolve_name_call_args(call, name, sym_index, datum); +- if (rc != SEPOL_OK) { +- /* Continue search in macro's parent */ +- rc = __cil_resolve_name_with_parents(NODE(call->macro)->parent, name, sym_index, datum); ++ struct cil_macro *macro = call->macro; ++ symtab = ¯o->symtab[sym_index]; ++ rc = cil_symtab_get_datum(symtab, name, datum); ++ if (rc == SEPOL_OK) { ++ /* If the name was declared in the macro, just look on the call side */ ++ rc = SEPOL_ERR; ++ } else { ++ rc = cil_resolve_name_call_args(call, name, sym_index, datum); ++ if (rc != SEPOL_OK) { ++ /* Continue search in macro's parent */ ++ rc = __cil_resolve_name_with_parents(NODE(call->macro)->parent, name, sym_index, datum); ++ } + } + } + break; +-- +2.32.0 + diff --git a/SOURCES/0050-libsepol-cil-Do-not-add-NULL-node-when-inserting-key.patch b/SOURCES/0050-libsepol-cil-Do-not-add-NULL-node-when-inserting-key.patch new file mode 100644 index 0000000..147fd9f --- /dev/null +++ b/SOURCES/0050-libsepol-cil-Do-not-add-NULL-node-when-inserting-key.patch @@ -0,0 +1,45 @@ +From a1952af7c0346f3cd60a362e43fc90a7d799cffe Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 11 May 2021 09:43:43 -0400 +Subject: [PATCH] libsepol/cil: Do not add NULL node when inserting key into + symtab + +Allow inserting a key without providing a node. + +This will make it easier to properly resolve call arguments where +a key might need to be temporarily removed to search for a datum +that is not declared within the call. Since the node is already +in the node list, re-inserting the key without this option would +add another link to the node and cause problems. + +Also, do not add the node to the datum's node list if the result +of the call to hashtab_insert() is SEPOL_EEXIST because the datum +is a duplicate and will be destroyed. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_symtab.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c +index 579a888e5785..c195156071e1 100644 +--- a/libsepol/cil/src/cil_symtab.c ++++ b/libsepol/cil/src/cil_symtab.c +@@ -93,10 +93,10 @@ int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_dat + datum->fqn = key; + datum->symtab = symtab; + symtab->nprim++; +- cil_list_append(datum->nodes, CIL_NODE, node); +- } else if (rc == SEPOL_EEXIST) { +- cil_list_append(datum->nodes, CIL_NODE, node); +- } else { ++ if (node) { ++ cil_list_append(datum->nodes, CIL_NODE, node); ++ } ++ } else if (rc != SEPOL_EEXIST) { + cil_symtab_error("Failed to insert datum into hashtab\n"); + } + +-- +2.32.0 + diff --git a/SOURCES/0051-libsepo-cil-Refactor-macro-call-resolution.patch b/SOURCES/0051-libsepo-cil-Refactor-macro-call-resolution.patch new file mode 100644 index 0000000..575e1e8 --- /dev/null +++ b/SOURCES/0051-libsepo-cil-Refactor-macro-call-resolution.patch @@ -0,0 +1,738 @@ +From bccec36a7694e8eee03ab0d592c3b0d8ddfff36e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 11 May 2021 12:34:27 -0400 +Subject: [PATCH] libsepo/cil: Refactor macro call resolution + +Rename cil_resolve_call1() as cil resolve_call() and rename +cil_resolve_call2() as cil_resolve_call_args() to make it clearer +what is being done in each function. + +Move code to build call arguments out of cil_resolve_call() and into +the new function called cil_build_call_args() so that the logic of +cil_resolve_call() can be seen. + +Exit cil_resolve_call() immediately if the call has already been +copied. + +In __cil_resolve_ast_node(), only resolve calls outside of macros. +This results in more calls to cil_copy_ast(), but slightly less +rules copied overall (since no rules are copied into a macro). This +also means that the CIL_PASS_MACRO pass is not needed and can be +eliminated. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_internal.h | 1 - + libsepol/cil/src/cil_resolve_ast.c | 599 +++++++++++++++-------------- + 2 files changed, 303 insertions(+), 297 deletions(-) + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 74e0b34d6cbd..a77c95201fb7 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -59,7 +59,6 @@ enum cil_pass { + CIL_PASS_BLKIN_LINK, + CIL_PASS_BLKIN_COPY, + CIL_PASS_BLKABS, +- CIL_PASS_MACRO, + CIL_PASS_CALL1, + CIL_PASS_CALL2, + CIL_PASS_ALIAS1, +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index ae6743f92f4c..258fdb1bb69f 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2816,359 +2816,371 @@ exit: + return rc; + } + +-int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) ++static int cil_build_call_args(struct cil_tree_node *call_node, struct cil_call *call, struct cil_macro *macro, void *extra_args) + { +- struct cil_call *new_call = current->data; + struct cil_args_resolve *args = extra_args; +- struct cil_db *db = NULL; +- struct cil_tree_node *macro_node = NULL; +- struct cil_symtab_datum *macro_datum = NULL; ++ struct cil_list_item *item; ++ struct cil_args *arg = NULL; ++ struct cil_tree_node *arg_node = NULL; + int rc = SEPOL_ERR; + +- if (args != NULL) { +- db = args->db; ++ if (macro->params == NULL) { ++ if (call->args_tree == NULL) { ++ return SEPOL_OK; ++ } else { ++ cil_tree_log(call_node, CIL_ERR, "Unexpected arguments"); ++ return SEPOL_ERR;; ++ } + } +- +- rc = cil_resolve_name(current, new_call->macro_str, CIL_SYM_BLOCKS, extra_args, ¯o_datum); +- if (rc != SEPOL_OK) { +- goto exit; ++ if (call->args_tree == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Missing arguments"); ++ return SEPOL_ERR; + } + +- macro_node = NODE(macro_datum); ++ arg_node = call->args_tree->root->cl_head; + +- if (macro_node->flavor != CIL_MACRO) { +- cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", new_call->macro_str); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_call->macro = (struct cil_macro*)macro_datum; ++ cil_list_init(&call->args, CIL_LIST_ITEM); + +- if (new_call->macro->params != NULL ) { ++ cil_list_for_each(item, macro->params) { ++ enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor; + +- struct cil_list_item *item; +- struct cil_args *new_arg = NULL; +- struct cil_tree_node *pc = NULL; +- +- if (new_call->args_tree == NULL) { +- cil_tree_log(current, CIL_ERR, "Missing arguments"); ++ if (arg_node == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Missing arguments"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ if (item->flavor != CIL_PARAM) { + rc = SEPOL_ERR; + goto exit; + } + +- pc = new_call->args_tree->root->cl_head; +- +- cil_list_init(&new_call->args, CIL_LIST_ITEM); +- +- cil_list_for_each(item, new_call->macro->params) { +- enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor; ++ cil_args_init(&arg); + +- if (pc == NULL) { +- cil_tree_log(current, CIL_ERR, "Missing arguments"); ++ switch (flavor) { ++ case CIL_NAME: { ++ struct cil_name *name; ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); + rc = SEPOL_ERR; + goto exit; + } +- if (item->flavor != CIL_PARAM) { ++ name = __cil_insert_name(args->db, arg_node->data, call_node); ++ if (name != NULL) { ++ arg->arg = (struct cil_symtab_datum *)name; ++ } else { ++ arg->arg_str = arg_node->data; ++ } ++ } ++ break; ++ case CIL_TYPE: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); + rc = SEPOL_ERR; + goto exit; + } +- +- cil_args_init(&new_arg); +- +- switch (flavor) { +- case CIL_NAME: { +- struct cil_name *name; +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- name = __cil_insert_name(args->db, pc->data, current); +- if (name != NULL) { +- new_arg->arg = (struct cil_symtab_datum *)name; +- } else { +- new_arg->arg_str = pc->data; +- } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_ROLE: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; + } +- break; +- case CIL_TYPE: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_ROLE: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_USER: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_SENS: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_CAT: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_BOOL: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_CATSET: { +- if (pc->cl_head != NULL) { +- struct cil_catset *catset = NULL; +- struct cil_tree_node *cat_node = NULL; +- cil_catset_init(&catset); +- rc = cil_fill_cats(pc, &catset->cats); +- if (rc != SEPOL_OK) { +- cil_destroy_catset(catset); +- cil_destroy_args(new_arg); +- goto exit; +- } +- cil_tree_node_init(&cat_node); +- cat_node->flavor = CIL_CATSET; +- cat_node->data = catset; +- cil_list_append(((struct cil_symtab_datum*)catset)->nodes, +- CIL_LIST_ITEM, cat_node); +- new_arg->arg = (struct cil_symtab_datum*)catset; +- } else if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_USER: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_SENS: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_CAT: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_BOOL: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_CATSET: { ++ if (arg_node->cl_head != NULL) { ++ struct cil_catset *catset = NULL; ++ struct cil_tree_node *cat_node = NULL; ++ cil_catset_init(&catset); ++ rc = cil_fill_cats(arg_node, &catset->cats); ++ if (rc != SEPOL_OK) { ++ cil_destroy_catset(catset); ++ cil_destroy_args(arg); + goto exit; +- } else { +- new_arg->arg_str = pc->data; + } +- +- break; ++ cil_tree_node_init(&cat_node); ++ cat_node->flavor = CIL_CATSET; ++ cat_node->data = catset; ++ cil_list_append(((struct cil_symtab_datum*)catset)->nodes, ++ CIL_LIST_ITEM, cat_node); ++ arg->arg = (struct cil_symtab_datum*)catset; ++ } else if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } else { ++ arg->arg_str = arg_node->data; + } +- case CIL_LEVEL: { +- if (pc->cl_head != NULL) { +- struct cil_level *level = NULL; +- struct cil_tree_node *lvl_node = NULL; +- cil_level_init(&level); +- +- rc = cil_fill_level(pc->cl_head, level); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc); +- cil_destroy_level(level); +- cil_destroy_args(new_arg); +- goto exit; +- } +- cil_tree_node_init(&lvl_node); +- lvl_node->flavor = CIL_LEVEL; +- lvl_node->data = level; +- cil_list_append(((struct cil_symtab_datum*)level)->nodes, +- CIL_LIST_ITEM, lvl_node); +- new_arg->arg = (struct cil_symtab_datum*)level; +- } else if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; ++ ++ break; ++ } ++ case CIL_LEVEL: { ++ if (arg_node->cl_head != NULL) { ++ struct cil_level *level = NULL; ++ struct cil_tree_node *lvl_node = NULL; ++ cil_level_init(&level); ++ ++ rc = cil_fill_level(arg_node->cl_head, level); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc); ++ cil_destroy_level(level); ++ cil_destroy_args(arg); + goto exit; +- } else { +- new_arg->arg_str = pc->data; + } +- +- break; ++ cil_tree_node_init(&lvl_node); ++ lvl_node->flavor = CIL_LEVEL; ++ lvl_node->data = level; ++ cil_list_append(((struct cil_symtab_datum*)level)->nodes, ++ CIL_LIST_ITEM, lvl_node); ++ arg->arg = (struct cil_symtab_datum*)level; ++ } else if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } else { ++ arg->arg_str = arg_node->data; + } +- case CIL_LEVELRANGE: { +- if (pc->cl_head != NULL) { +- struct cil_levelrange *range = NULL; +- struct cil_tree_node *range_node = NULL; +- cil_levelrange_init(&range); +- +- rc = cil_fill_levelrange(pc->cl_head, range); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc); +- cil_destroy_levelrange(range); +- cil_destroy_args(new_arg); +- goto exit; +- } +- cil_tree_node_init(&range_node); +- range_node->flavor = CIL_LEVELRANGE; +- range_node->data = range; +- cil_list_append(((struct cil_symtab_datum*)range)->nodes, +- CIL_LIST_ITEM, range_node); +- new_arg->arg = (struct cil_symtab_datum*)range; +- } else if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; ++ ++ break; ++ } ++ case CIL_LEVELRANGE: { ++ if (arg_node->cl_head != NULL) { ++ struct cil_levelrange *range = NULL; ++ struct cil_tree_node *range_node = NULL; ++ cil_levelrange_init(&range); ++ ++ rc = cil_fill_levelrange(arg_node->cl_head, range); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc); ++ cil_destroy_levelrange(range); ++ cil_destroy_args(arg); + goto exit; +- } else { +- new_arg->arg_str = pc->data; + } +- +- break; ++ cil_tree_node_init(&range_node); ++ range_node->flavor = CIL_LEVELRANGE; ++ range_node->data = range; ++ cil_list_append(((struct cil_symtab_datum*)range)->nodes, ++ CIL_LIST_ITEM, range_node); ++ arg->arg = (struct cil_symtab_datum*)range; ++ } else if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } else { ++ arg->arg_str = arg_node->data; + } +- case CIL_IPADDR: { +- if (pc->cl_head != NULL) { +- struct cil_ipaddr *ipaddr = NULL; +- struct cil_tree_node *addr_node = NULL; +- cil_ipaddr_init(&ipaddr); +- +- rc = cil_fill_ipaddr(pc->cl_head, ipaddr); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc); +- cil_destroy_ipaddr(ipaddr); +- cil_destroy_args(new_arg); +- goto exit; +- } +- cil_tree_node_init(&addr_node); +- addr_node->flavor = CIL_IPADDR; +- addr_node->data = ipaddr; +- cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes, +- CIL_LIST_ITEM, addr_node); +- new_arg->arg = (struct cil_symtab_datum*)ipaddr; +- } else if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; ++ ++ break; ++ } ++ case CIL_IPADDR: { ++ if (arg_node->cl_head != NULL) { ++ struct cil_ipaddr *ipaddr = NULL; ++ struct cil_tree_node *addr_node = NULL; ++ cil_ipaddr_init(&ipaddr); ++ ++ rc = cil_fill_ipaddr(arg_node->cl_head, ipaddr); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc); ++ cil_destroy_ipaddr(ipaddr); ++ cil_destroy_args(arg); + goto exit; +- } else { +- new_arg->arg_str = pc->data; + } ++ cil_tree_node_init(&addr_node); ++ addr_node->flavor = CIL_IPADDR; ++ addr_node->data = ipaddr; ++ cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes, ++ CIL_LIST_ITEM, addr_node); ++ arg->arg = (struct cil_symtab_datum*)ipaddr; ++ } else if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } else { ++ arg->arg_str = arg_node->data; ++ } + +- break; ++ break; ++ } ++ case CIL_CLASS: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; + } +- case CIL_CLASS: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_MAP_CLASS: +- if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; +- goto exit; +- } +- new_arg->arg_str = pc->data; +- break; +- case CIL_CLASSPERMISSION: { +- if (pc->cl_head != NULL) { +- struct cil_classpermission *cp = NULL; +- struct cil_tree_node *cp_node = NULL; +- +- cil_classpermission_init(&cp); +- rc = cil_fill_classperms_list(pc, &cp->classperms); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to create anonymous classpermission\n"); +- cil_destroy_classpermission(cp); +- cil_destroy_args(new_arg); +- goto exit; +- } +- cil_tree_node_init(&cp_node); +- cp_node->flavor = CIL_CLASSPERMISSION; +- cp_node->data = cp; +- cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node); +- new_arg->arg = (struct cil_symtab_datum*)cp; +- } else if (pc->data == NULL) { +- cil_tree_log(current, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(new_arg); +- rc = SEPOL_ERR; ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_MAP_CLASS: ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ arg->arg_str = arg_node->data; ++ break; ++ case CIL_CLASSPERMISSION: { ++ if (arg_node->cl_head != NULL) { ++ struct cil_classpermission *cp = NULL; ++ struct cil_tree_node *cp_node = NULL; ++ ++ cil_classpermission_init(&cp); ++ rc = cil_fill_classperms_list(arg_node, &cp->classperms); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to create anonymous classpermission\n"); ++ cil_destroy_classpermission(cp); ++ cil_destroy_args(arg); + goto exit; +- } else { +- new_arg->arg_str = pc->data; + } +- break; +- } +- default: +- cil_log(CIL_ERR, "Unexpected flavor: %d\n", +- (((struct cil_param*)item->data)->flavor)); +- cil_destroy_args(new_arg); ++ cil_tree_node_init(&cp_node); ++ cp_node->flavor = CIL_CLASSPERMISSION; ++ cp_node->data = cp; ++ cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node); ++ arg->arg = (struct cil_symtab_datum*)cp; ++ } else if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); + rc = SEPOL_ERR; + goto exit; ++ } else { ++ arg->arg_str = arg_node->data; + } +- new_arg->param_str = ((struct cil_param*)item->data)->str; +- new_arg->flavor = flavor; +- +- cil_list_append(new_call->args, CIL_ARGS, new_arg); +- +- pc = pc->next; ++ break; + } +- +- if (pc != NULL) { +- cil_tree_log(current, CIL_ERR, "Unexpected arguments"); ++ default: ++ cil_log(CIL_ERR, "Unexpected flavor: %d\n", ++ (((struct cil_param*)item->data)->flavor)); ++ cil_destroy_args(arg); + rc = SEPOL_ERR; + goto exit; + } +- } else if (new_call->args_tree != NULL) { +- cil_tree_log(current, CIL_ERR, "Unexpected arguments"); ++ arg->param_str = ((struct cil_param*)item->data)->str; ++ arg->flavor = flavor; ++ ++ cil_list_append(call->args, CIL_ARGS, arg); ++ ++ arg_node = arg_node->next; ++ } ++ ++ if (arg_node != NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Unexpected arguments"); + rc = SEPOL_ERR; + goto exit; + } + +- if (new_call->copied == 0) { +- new_call->copied = 1; ++ return SEPOL_OK; + +- rc = cil_check_recursive_call(current, macro_node); +- if (rc != SEPOL_OK) { +- goto exit; +- } ++exit: ++ return rc; ++} + +- rc = cil_copy_ast(db, macro_node, current); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc); +- goto exit; +- } ++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; ++ struct cil_tree_node *macro_node = NULL; ++ struct cil_symtab_datum *macro_datum = NULL; ++ int rc = SEPOL_ERR; ++ ++ if (call->copied) { ++ return SEPOL_OK; ++ } ++ ++ rc = cil_resolve_name(current, call->macro_str, CIL_SYM_BLOCKS, extra_args, ¯o_datum); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ macro_node = NODE(macro_datum); ++ ++ if (macro_node->flavor != CIL_MACRO) { ++ cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", call->macro_str); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ call->macro = (struct cil_macro*)macro_datum; ++ ++ rc = cil_build_call_args(current, call, call->macro, extra_args); ++ if (rc != SEPOL_OK) { ++ goto exit; + } + ++ rc = cil_check_recursive_call(current, macro_node); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ rc = cil_copy_ast(args->db, macro_node, current); ++ if (rc != SEPOL_OK) { ++ cil_tree_log(current, CIL_ERR, "Failed to copy macro %s to call", macro_datum->name); ++ goto exit; ++ } ++ ++ call->copied = 1; ++ + return SEPOL_OK; + + exit: + return rc; + } + +-int cil_resolve_call2(struct cil_tree_node *current, void *extra_args) ++int cil_resolve_call_args(struct cil_tree_node *current, void *extra_args) + { +- struct cil_call *new_call = current->data; ++ struct cil_call *call = current->data; + int rc = SEPOL_ERR; + enum cil_sym_index sym_index = CIL_SYM_UNKNOWN; + struct cil_list_item *item; + +- if (new_call->args == NULL) { ++ if (call->args == NULL) { + rc = SEPOL_OK; + goto exit; + } + +- cil_list_for_each(item, new_call->args) { ++ cil_list_for_each(item, call->args) { + struct cil_args *arg = item->data; + if (arg->arg == NULL && arg->arg_str == NULL) { + cil_log(CIL_ERR, "Arguments not created correctly\n"); +@@ -3574,19 +3586,14 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) + rc = cil_resolve_blockabstract(node, args); + } + break; +- case CIL_PASS_MACRO: +- if (node->flavor == CIL_CALL && args->macro != NULL) { +- rc = cil_resolve_call1(node, args); +- } +- break; + case CIL_PASS_CALL1: +- if (node->flavor == CIL_CALL) { +- rc = cil_resolve_call1(node, args); ++ if (node->flavor == CIL_CALL && args->macro == NULL) { ++ rc = cil_resolve_call(node, args); + } + break; + case CIL_PASS_CALL2: +- if (node->flavor == CIL_CALL) { +- rc = cil_resolve_call2(node, args); ++ if (node->flavor == CIL_CALL && args->macro == NULL) { ++ rc = cil_resolve_call_args(node, args); + } + break; + case CIL_PASS_ALIAS1: +@@ -3890,7 +3897,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + } + + if (node->flavor == CIL_MACRO) { +- if (pass != CIL_PASS_TIF && pass != CIL_PASS_MACRO) { ++ if (pass != CIL_PASS_TIF) { + *finished = CIL_TREE_SKIP_HEAD; + rc = SEPOL_OK; + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0052-libsepol-cil-Do-not-resolve-arguments-to-declaration.patch b/SOURCES/0052-libsepol-cil-Do-not-resolve-arguments-to-declaration.patch new file mode 100644 index 0000000..07904fa --- /dev/null +++ b/SOURCES/0052-libsepol-cil-Do-not-resolve-arguments-to-declaration.patch @@ -0,0 +1,83 @@ +From aa8ac8ffafb9e4121b95a721341371042a3b2994 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 11 May 2021 14:22:53 -0400 +Subject: [PATCH] libsepol/cil: Do not resolve arguments to declarations in the + call + +Lorenzo Ceragioli noted that the +following policy: + (type a) + (block A + (macro m ((type x)) + (type a) + (allow x x (file (read)))) + ) + (block B + (call A.m(a)) + ) +results in the allow rule (allow B.a B.a (file(read))). This makes +no sense because the "a" being passed as an argument has to be the +global "a" and not the "a" defined in the macro. + +This behavior occurs because the call arguments are resolved AFTER +the macro body has been copied and the declaration of "a" in the +macro has been added to block B's namespace, so this is the "a" +that the call argument resolves to, rather than the one in the +global namespace. + +When resolving call arguments, check if the datum found belongs to +a declaration in the call. If it does, then remove the datum from +the symbol table, re-resolve the argument, and add the datum back +into the symbol table. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 258fdb1bb69f..74e5b78f9325 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3263,11 +3263,37 @@ int cil_resolve_call_args(struct cil_tree_node *current, void *extra_args) + } + + if (sym_index != CIL_SYM_UNKNOWN) { +- rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &(arg->arg)); ++ struct cil_symtab_datum *datum; ++ struct cil_tree_node *n; ++ rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &datum); + if (rc != SEPOL_OK) { + cil_tree_log(current, CIL_ERR, "Failed to resolve %s in call argument list", arg->arg_str); + goto exit; + } ++ arg->arg = datum; ++ n = NODE(datum); ++ while (n && n->flavor != CIL_ROOT) { ++ if (n == current) { ++ symtab_t *s = datum->symtab; ++ /* Call arg should not resolve to declaration in the call ++ * Need to remove datum temporarily to resolve to a datum outside ++ * the call. ++ */ ++ cil_symtab_remove_datum(datum); ++ rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &(arg->arg)); ++ if (rc != SEPOL_OK) { ++ cil_tree_log(current, CIL_ERR, "Failed to resolve %s in call argument list", arg->arg_str); ++ goto exit; ++ } ++ rc = cil_symtab_insert(s, datum->name, datum, NULL); ++ if (rc != SEPOL_OK) { ++ cil_tree_log(current, CIL_ERR, "Failed to re-insert datum while resolving %s in call argument list", arg->arg_str); ++ goto exit; ++ } ++ break; ++ } ++ n = n->parent; ++ } + } + } + +-- +2.32.0 + diff --git a/SOURCES/0053-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch b/SOURCES/0053-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch new file mode 100644 index 0000000..34c174b --- /dev/null +++ b/SOURCES/0053-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch @@ -0,0 +1,94 @@ +From 5661efd459e7aa998390ab70e3ec50125a35e9e9 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:30:37 -0400 +Subject: [PATCH] libsepol/cil: Handle disabled optional blocks in earlier + passes + +A failed tunable resolution in a tunableif can cause an optional +to be disabled before the CIL_PASS_CALL1 phase. If this occurs, the +optional block and its subtree should be destroyed, but no reset +will be required since tunables are not allowed inside an optional +block. + +Anytime there are optional blocks in the disabled_optionals list +(changed == 1), destroy the optional block and its subtree even if +in a pass before CIL_PASS_CALL1. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 54 ++++++++++++++++-------------- + 1 file changed, 28 insertions(+), 26 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 74e5b78f9325..328add0421c5 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4132,35 +4132,37 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + } + } + +- if (changed && (pass > CIL_PASS_CALL1)) { ++ if (changed) { + struct cil_list_item *item; +- /* Need to re-resolve because an optional was disabled that contained +- * one or more declarations. We only need to reset to the call1 pass +- * because things done in the preceding passes aren't allowed in +- * optionals, and thus can't be disabled. +- * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment +- * it to CIL_PASS_CALL2 +- */ +- cil_log(CIL_INFO, "Resetting declarations\n"); +- +- if (pass >= CIL_PASS_MISC1) { +- __cil_ordered_lists_reset(&extra_args.sidorder_lists); +- __cil_ordered_lists_reset(&extra_args.classorder_lists); +- __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); +- __cil_ordered_lists_reset(&extra_args.catorder_lists); +- __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); +- cil_list_destroy(&db->sidorder, CIL_FALSE); +- cil_list_destroy(&db->classorder, CIL_FALSE); +- cil_list_destroy(&db->catorder, CIL_FALSE); +- cil_list_destroy(&db->sensitivityorder, CIL_FALSE); +- } ++ if (pass > CIL_PASS_CALL1) { ++ /* Need to re-resolve because an optional was disabled that contained ++ * one or more declarations. We only need to reset to the call1 pass ++ * because things done in the preceding passes aren't allowed in ++ * optionals, and thus can't be disabled. ++ * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment ++ * it to CIL_PASS_CALL2 ++ */ ++ cil_log(CIL_INFO, "Resetting declarations\n"); ++ ++ if (pass >= CIL_PASS_MISC1) { ++ __cil_ordered_lists_reset(&extra_args.sidorder_lists); ++ __cil_ordered_lists_reset(&extra_args.classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.catorder_lists); ++ __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); ++ cil_list_destroy(&db->sidorder, CIL_FALSE); ++ cil_list_destroy(&db->classorder, CIL_FALSE); ++ cil_list_destroy(&db->catorder, CIL_FALSE); ++ cil_list_destroy(&db->sensitivityorder, CIL_FALSE); ++ } + +- pass = CIL_PASS_CALL1; ++ pass = CIL_PASS_CALL1; + +- rc = cil_reset_ast(current); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to reset declarations\n"); +- goto exit; ++ rc = cil_reset_ast(current); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to reset declarations\n"); ++ goto exit; ++ } + } + cil_list_for_each(item, extra_args.disabled_optionals) { + cil_tree_children_destroy(item->data); +-- +2.32.0 + diff --git a/SOURCES/0054-libsepol-cil-Destroy-the-permission-nodes-when-exiti.patch b/SOURCES/0054-libsepol-cil-Destroy-the-permission-nodes-when-exiti.patch new file mode 100644 index 0000000..6e9c55e --- /dev/null +++ b/SOURCES/0054-libsepol-cil-Destroy-the-permission-nodes-when-exiti.patch @@ -0,0 +1,39 @@ +From 29d6a3ee4a958607fdf7c01a78b6d389ba6e8612 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:36:44 -0400 +Subject: [PATCH] libsepol/cil: Destroy the permission nodes when exiting with + an error + +When exiting with an error because a class or common has too many +permissions, destroy the permission nodes. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 87043a8fa183..71f14e20e25e 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -444,6 +444,7 @@ int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct + } + if (class->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in class '%s'", class->datum.name); ++ cil_tree_children_destroy(ast_node); + rc = SEPOL_ERR; + goto exit; + } +@@ -1019,6 +1020,7 @@ int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struc + } + if (common->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in common '%s'", common->datum.name); ++ cil_tree_children_destroy(ast_node); + rc = SEPOL_ERR; + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0055-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch b/SOURCES/0055-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch new file mode 100644 index 0000000..6df8498 --- /dev/null +++ b/SOURCES/0055-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch @@ -0,0 +1,48 @@ +From 69fc31d1fb5d3bc1d4a919285284d1fb9d679a6e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:37:59 -0400 +Subject: [PATCH] libsepol/cil: Limit the number of open parenthesis allowed + +When parsing a CIL policy, the number of open parenthesis is tracked +to verify that each has a matching close parenthesis. If there are +too many open parenthesis, a stack overflow could occur during later +processing. + +Exit with an error if the number of open parenthesis exceeds 4096 +(which should be enough for any policy.) + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_parser.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_parser.c b/libsepol/cil/src/cil_parser.c +index a93062180ff8..fb95f401f1c7 100644 +--- a/libsepol/cil/src/cil_parser.c ++++ b/libsepol/cil/src/cil_parser.c +@@ -42,6 +42,8 @@ + #include "cil_strpool.h" + #include "cil_stack.h" + ++#define CIL_PARSER_MAX_EXPR_DEPTH (0x1 << 12) ++ + char *CIL_KEY_HLL_LMS; + char *CIL_KEY_HLL_LMX; + char *CIL_KEY_HLL_LME; +@@ -245,7 +247,10 @@ int cil_parser(const char *_path, char *buffer, uint32_t size, struct cil_tree * + break; + case OPAREN: + paren_count++; +- ++ if (paren_count > CIL_PARSER_MAX_EXPR_DEPTH) { ++ cil_log(CIL_ERR, "Number of open parenthesis exceeds limit of %d at line %d of %s\n", CIL_PARSER_MAX_EXPR_DEPTH, tok.line, path); ++ goto exit; ++ } + create_node(&node, current, tok.line, hll_lineno, NULL); + insert_node(node, current); + current = node; +-- +2.32.0 + diff --git a/SOURCES/0056-libsepol-cil-Resolve-anonymous-class-permission-sets.patch b/SOURCES/0056-libsepol-cil-Resolve-anonymous-class-permission-sets.patch new file mode 100644 index 0000000..fc3f0a1 --- /dev/null +++ b/SOURCES/0056-libsepol-cil-Resolve-anonymous-class-permission-sets.patch @@ -0,0 +1,44 @@ +From a8dcf4d57bad3e531e44855ccfa22d234a2a7e56 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:51:44 -0400 +Subject: [PATCH] libsepol/cil: Resolve anonymous class permission sets only + once + +Anonymous class permission sets can be passed as call arguments. +Anonymous call arguments are resolved when they are used in a +rule. [This is because all the information might not be present +(like common permissions being added to a class) when the call +itself is resolved.] If there is more than one rule using an +anonymous class permission set, then a memory leak will occur +when a new list for the permission datum expression is created +without destroying the old one. + +When resolving the class and permissions, check if the class has +already been resolved. If it has, then the permissions have been +as well. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 328add0421c5..c504e60b7c58 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -158,6 +158,10 @@ int cil_resolve_classperms(struct cil_tree_node *current, struct cil_classperms + symtab_t *common_symtab = NULL; + struct cil_class *class; + ++ if (cp->class) { ++ return SEPOL_OK; ++ } ++ + rc = cil_resolve_name(current, cp->class_str, CIL_SYM_CLASSES, extra_args, &datum); + if (rc != SEPOL_OK) { + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0057-libsepol-cil-Pointers-to-datums-should-be-set-to-NUL.patch b/SOURCES/0057-libsepol-cil-Pointers-to-datums-should-be-set-to-NUL.patch new file mode 100644 index 0000000..5a598a0 --- /dev/null +++ b/SOURCES/0057-libsepol-cil-Pointers-to-datums-should-be-set-to-NUL.patch @@ -0,0 +1,232 @@ +From 73d991abdc41b8e1380bfe05f031c822bfa0b515 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:53:54 -0400 +Subject: [PATCH] libsepol/cil: Pointers to datums should be set to NULL when + resetting + +Set the pointer to the sensitivity in levels, the pointers to the low +and high levels in levelranges, the pointer to the level in userlevels, +the pointer to the range in userranges, and the pointers to contexts +in ocontexts to NULL. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 56 ++++++++++++++++++++++++++++++-- + 1 file changed, 53 insertions(+), 3 deletions(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index d24d4f8159a3..6d1d2da77c89 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -140,8 +140,11 @@ static void cil_reset_userattributeset(struct cil_userattributeset *uas) + + static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser) + { ++ selinuxuser->user = NULL; + if (selinuxuser->range_str == NULL) { + cil_reset_levelrange(selinuxuser->range); ++ } else { ++ selinuxuser->range = NULL; + } + } + +@@ -214,6 +217,8 @@ static void cil_reset_rangetransition(struct cil_rangetransition *rangetrans) + { + if (rangetrans->range_str == NULL) { + cil_reset_levelrange(rangetrans->range); ++ } else { ++ rangetrans->range = NULL; + } + } + +@@ -251,6 +256,7 @@ static void cil_reset_catset(struct cil_catset *catset) + + static inline void cil_reset_level(struct cil_level *level) + { ++ level->sens = NULL; + cil_reset_cats(level->cats); + } + +@@ -258,10 +264,14 @@ static inline void cil_reset_levelrange(struct cil_levelrange *levelrange) + { + if (levelrange->low_str == NULL) { + cil_reset_level(levelrange->low); ++ } else { ++ levelrange->low = NULL; + } + + if (levelrange->high_str == NULL) { + cil_reset_level(levelrange->high); ++ } else { ++ levelrange->high = NULL; + } + } + +@@ -269,6 +279,8 @@ static inline void cil_reset_userlevel(struct cil_userlevel *userlevel) + { + if (userlevel->level_str == NULL) { + cil_reset_level(userlevel->level); ++ } else { ++ userlevel->level = NULL; + } + } + +@@ -276,13 +288,20 @@ static inline void cil_reset_userrange(struct cil_userrange *userrange) + { + if (userrange->range_str == NULL) { + cil_reset_levelrange(userrange->range); ++ } else { ++ userrange->range = NULL; + } + } + + static inline void cil_reset_context(struct cil_context *context) + { ++ if (!context) { ++ return; ++ } + if (context->range_str == NULL) { + cil_reset_levelrange(context->range); ++ } else { ++ context->range = NULL; + } + } + +@@ -290,26 +309,35 @@ static void cil_reset_sidcontext(struct cil_sidcontext *sidcontext) + { + if (sidcontext->context_str == NULL) { + cil_reset_context(sidcontext->context); ++ } else { ++ sidcontext->context = NULL; + } + } + + static void cil_reset_filecon(struct cil_filecon *filecon) + { +- if (filecon->context_str == NULL && filecon->context != NULL) { ++ if (filecon->context_str == NULL) { + cil_reset_context(filecon->context); ++ } else { ++ filecon->context = NULL; + } + } + + static void cil_reset_ibpkeycon(struct cil_ibpkeycon *ibpkeycon) + { +- if (!ibpkeycon->context_str) ++ if (ibpkeycon->context_str == NULL) { + cil_reset_context(ibpkeycon->context); ++ } else { ++ ibpkeycon->context = NULL; ++ } + } + + static void cil_reset_portcon(struct cil_portcon *portcon) + { + if (portcon->context_str == NULL) { + cil_reset_context(portcon->context); ++ } else { ++ portcon->context = NULL; + } + } + +@@ -317,6 +345,8 @@ static void cil_reset_nodecon(struct cil_nodecon *nodecon) + { + if (nodecon->context_str == NULL) { + cil_reset_context(nodecon->context); ++ } else { ++ nodecon->context = NULL; + } + } + +@@ -324,6 +354,8 @@ static void cil_reset_genfscon(struct cil_genfscon *genfscon) + { + if (genfscon->context_str == NULL) { + cil_reset_context(genfscon->context); ++ } else { ++ genfscon->context = NULL; + } + } + +@@ -331,17 +363,23 @@ static void cil_reset_netifcon(struct cil_netifcon *netifcon) + { + if (netifcon->if_context_str == NULL) { + cil_reset_context(netifcon->if_context); ++ } else { ++ netifcon->if_context = NULL; + } + + if (netifcon->packet_context_str == NULL) { + cil_reset_context(netifcon->packet_context); ++ } else { ++ netifcon->packet_context = NULL; + } + } + + static void cil_reset_ibendportcon(struct cil_ibendportcon *ibendportcon) + { +- if (!ibendportcon->context_str) { ++ if (ibendportcon->context_str == NULL) { + cil_reset_context(ibendportcon->context); ++ } else { ++ ibendportcon->context = NULL; + } + } + +@@ -349,6 +387,8 @@ static void cil_reset_pirqcon(struct cil_pirqcon *pirqcon) + { + if (pirqcon->context_str == NULL) { + cil_reset_context(pirqcon->context); ++ } else { ++ pirqcon->context = NULL; + } + } + +@@ -356,6 +396,8 @@ static void cil_reset_iomemcon(struct cil_iomemcon *iomemcon) + { + if (iomemcon->context_str == NULL) { + cil_reset_context(iomemcon->context); ++ } else { ++ iomemcon->context = NULL; + } + } + +@@ -363,6 +405,8 @@ static void cil_reset_ioportcon(struct cil_ioportcon *ioportcon) + { + if (ioportcon->context_str == NULL) { + cil_reset_context(ioportcon->context); ++ } else { ++ ioportcon->context = NULL; + } + } + +@@ -370,6 +414,8 @@ static void cil_reset_pcidevicecon(struct cil_pcidevicecon *pcidevicecon) + { + if (pcidevicecon->context_str == NULL) { + cil_reset_context(pcidevicecon->context); ++ } else { ++ pcidevicecon->context = NULL; + } + } + +@@ -377,6 +423,8 @@ static void cil_reset_devicetreecon(struct cil_devicetreecon *devicetreecon) + { + if (devicetreecon->context_str == NULL) { + cil_reset_context(devicetreecon->context); ++ } else { ++ devicetreecon->context = NULL; + } + } + +@@ -384,6 +432,8 @@ static void cil_reset_fsuse(struct cil_fsuse *fsuse) + { + if (fsuse->context_str == NULL) { + cil_reset_context(fsuse->context); ++ } else { ++ fsuse->context = NULL; + } + } + +-- +2.32.0 + diff --git a/SOURCES/0058-libsepol-cil-Resolve-anonymous-levels-only-once.patch b/SOURCES/0058-libsepol-cil-Resolve-anonymous-levels-only-once.patch new file mode 100644 index 0000000..f353049 --- /dev/null +++ b/SOURCES/0058-libsepol-cil-Resolve-anonymous-levels-only-once.patch @@ -0,0 +1,39 @@ +From d8b90f8ad1bc9dbff09312e628b48ac439ef4ef0 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 13:23:57 -0400 +Subject: [PATCH] libsepol/cil: Resolve anonymous levels only once + +Anonymous levels can be passed as call arguments and they can +appear in anonymous levelranges as well. + +Anonymous call arguments are resolved when they are used in a rule. +If more than one rule uses the anonymous level, then a memory leak +will occur when a new list for the category datum expression is +created without destroying the old one. + +When resolving a level, check if the sensitivity datum has already +been resolved. If it has, then the categories have been as well. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index c504e60b7c58..77ffe0ffd22b 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -1700,6 +1700,10 @@ int cil_resolve_level(struct cil_tree_node *current, struct cil_level *level, vo + struct cil_symtab_datum *sens_datum = NULL; + int rc = SEPOL_ERR; + ++ if (level->sens) { ++ return SEPOL_OK; ++ } ++ + rc = cil_resolve_name(current, (char*)level->sens_str, CIL_SYM_SENS, extra_args, &sens_datum); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to find sensitivity\n"); +-- +2.32.0 + diff --git a/SOURCES/0059-libsepol-quote-paths-in-CIL-conversion.patch b/SOURCES/0059-libsepol-quote-paths-in-CIL-conversion.patch new file mode 100644 index 0000000..193d3a7 --- /dev/null +++ b/SOURCES/0059-libsepol-quote-paths-in-CIL-conversion.patch @@ -0,0 +1,58 @@ +From 644c5bbbc4c71f6636c939cb7748dd2dfa50e638 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 21:39:02 +0200 +Subject: [PATCH] libsepol: quote paths in CIL conversion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When generating CIL policy from kernel or module policy quote paths, +which are allowed to contain spaces, in the statements `genfscon` and +`devicetreecon`. + +Reported by LuK1337 while building policy for Android via IRC. + +Signed-off-by: Christian Göttsche +--- + libsepol/src/kernel_to_cil.c | 4 ++-- + libsepol/src/module_to_cil.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 989aacde8a12..30a27bf527d5 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -2654,7 +2654,7 @@ static int write_genfscon_rules_to_cil(FILE *out, struct policydb *pdb) + goto exit; + } + +- rc = strs_create_and_add(strs, "(genfscon %s %s %s)", 3, ++ rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s)", 3, + fstype, name, ctx); + free(ctx); + if (rc != 0) { +@@ -3115,7 +3115,7 @@ static int write_xen_devicetree_rules_to_cil(FILE *out, struct policydb *pdb) + goto exit; + } + +- sepol_printf(out, "(devicetreecon %s %s)\n", name, ctx); ++ sepol_printf(out, "(devicetreecon \"%s\" %s)\n", name, ctx); + + free(ctx); + } +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index 496693f4616e..19c7c65c6382 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -2963,7 +2963,7 @@ static int genfscon_to_cil(struct policydb *pdb) + + 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); ++ cil_printf("(genfscon %s \"%s\" ", genfs->fstype, ocon->u.name); + context_to_cil(pdb, &ocon->context[0]); + cil_printf(")\n"); + } +-- +2.32.0 + diff --git a/SOURCES/0060-libsepol-cil-Fix-anonymous-IP-address-call-arguments.patch b/SOURCES/0060-libsepol-cil-Fix-anonymous-IP-address-call-arguments.patch new file mode 100644 index 0000000..4a6ce68 --- /dev/null +++ b/SOURCES/0060-libsepol-cil-Fix-anonymous-IP-address-call-arguments.patch @@ -0,0 +1,93 @@ +From 9ac9d2dab40826abe049fd07d21a20386fe5b38b Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 14 Jun 2021 12:53:25 -0400 +Subject: [PATCH] libsepol/cil: Fix anonymous IP address call arguments + +A named IP address (using an ipaddr rule) could be passed as an +argument, but trying to pass an actual IP address caused an error. + +As an exmample, consider the following portion of a policy. + (macro m4 ((ipaddr ip)(ipaddr nm)) + (nodecon ip nm (USER ROLE TYPE ((s0) (s0)))) + ) + (ipaddr nm1 255.255.255.0) + (ipaddr ip1 1.2.3.4) + (call m4 (ip1 nm1)) ; This works + (call m4 (1.2.3.4 255.255.255.0)) ; This doesn't + +Allow actual IP addresses to be passed as a call argument. Now the +second call works as well. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 4 ---- + libsepol/cil/src/cil_resolve_ast.c | 23 ++++++++++------------- + 2 files changed, 10 insertions(+), 17 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 71f14e20e25e..538df2794ade 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5642,10 +5642,6 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr) + goto exit; + } + +- if (addr_node->cl_head != NULL || addr_node->next != NULL) { +- goto exit; +- } +- + if (strchr(addr_node->data, '.') != NULL) { + addr->family = AF_INET; + } else { +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 77ffe0ffd22b..16c8c7533ce3 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3024,14 +3024,18 @@ static int cil_build_call_args(struct cil_tree_node *call_node, struct cil_call + break; + } + case CIL_IPADDR: { +- if (arg_node->cl_head != NULL) { ++ if (arg_node->data == NULL) { ++ cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); ++ cil_destroy_args(arg); ++ rc = SEPOL_ERR; ++ goto exit; ++ } else if (strchr(arg_node->data, '.') || strchr(arg_node->data, ':')) { + struct cil_ipaddr *ipaddr = NULL; + struct cil_tree_node *addr_node = NULL; + cil_ipaddr_init(&ipaddr); +- +- rc = cil_fill_ipaddr(arg_node->cl_head, ipaddr); ++ rc = cil_fill_ipaddr(arg_node, ipaddr); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc); ++ cil_tree_log(call_node, CIL_ERR, "Failed to create anonymous ip address"); + cil_destroy_ipaddr(ipaddr); + cil_destroy_args(arg); + goto exit; +@@ -3039,18 +3043,11 @@ static int cil_build_call_args(struct cil_tree_node *call_node, struct cil_call + cil_tree_node_init(&addr_node); + addr_node->flavor = CIL_IPADDR; + addr_node->data = ipaddr; +- cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes, +- CIL_LIST_ITEM, addr_node); +- arg->arg = (struct cil_symtab_datum*)ipaddr; +- } else if (arg_node->data == NULL) { +- cil_tree_log(call_node, CIL_ERR, "Invalid macro parameter"); +- cil_destroy_args(arg); +- rc = SEPOL_ERR; +- goto exit; ++ cil_list_append(DATUM(ipaddr)->nodes, CIL_LIST_ITEM, addr_node); ++ arg->arg = DATUM(ipaddr); + } else { + arg->arg_str = arg_node->data; + } +- + break; + } + case CIL_CLASS: +-- +2.32.0 + diff --git a/SOURCES/0061-libsepol-cil-Account-for-anonymous-category-sets-in-.patch b/SOURCES/0061-libsepol-cil-Account-for-anonymous-category-sets-in-.patch new file mode 100644 index 0000000..8b7983e --- /dev/null +++ b/SOURCES/0061-libsepol-cil-Account-for-anonymous-category-sets-in-.patch @@ -0,0 +1,90 @@ +From 982ec302b67f3c7f8df667dadb67352b1e4a6d18 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 15 Jun 2021 10:40:20 -0400 +Subject: [PATCH] libsepol/cil: Account for anonymous category sets in an + expression + +It is possible for anonymous category sets to be in a category +expression if the expression has a macro parameter in it. +Unfortunately, anonymous category sets are not looked for when +resolving category expressions and a segfault will occur during +later processing if there was one. + +As an example, consider the following portion of a policy. + (macro m1 ((categoryset cs)) + (userlevel USER (s0 (cs))) + ) + (call m1 ((c0 c1))) +This policy will cause a segault, because the categoryset datum +for the parameter cs is not seen as a categoryset and is treated +as a plain category. + +When resolving an expression, check whether or not the datum that +is found is actually an anonymous category set associated with a +macro parameter. If it is, then resolve the category set if it +has not already been resolved and treat its categories as a sub +expression. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 16c8c7533ce3..42a58468ed36 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3346,6 +3346,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + struct cil_list_item *curr; + struct cil_symtab_datum *res_datum = NULL; + enum cil_sym_index sym_index = CIL_SYM_UNKNOWN; ++ struct cil_list *datum_sub_expr; + + switch (str_expr->flavor) { + case CIL_BOOL: +@@ -3379,18 +3380,26 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + if (rc != SEPOL_OK) { + goto exit; + } +- +- if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) { +- cil_type_used(res_datum, CIL_ATTR_CONSTRAINT); ++ if (sym_index == CIL_SYM_CATS && NODE(res_datum)->flavor == CIL_CATSET) { ++ struct cil_catset *catset = (struct cil_catset *)res_datum; ++ if (!catset->cats->datum_expr) { ++ rc = cil_resolve_expr(expr_type, catset->cats->str_expr, &catset->cats->datum_expr, parent, extra_args); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ } ++ cil_copy_list(catset->cats->datum_expr, &datum_sub_expr); ++ cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr); ++ } else { ++ if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) { ++ cil_type_used(res_datum, CIL_ATTR_CONSTRAINT); ++ } ++ cil_list_append(*datum_expr, CIL_DATUM, res_datum); + } +- +- cil_list_append(*datum_expr, CIL_DATUM, res_datum); + break; + case CIL_LIST: { +- struct cil_list *datum_sub_expr; + rc = cil_resolve_expr(expr_type, curr->data, &datum_sub_expr, parent, extra_args); + if (rc != SEPOL_OK) { +- cil_list_destroy(&datum_sub_expr, CIL_TRUE); + goto exit; + } + cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr); +@@ -3404,6 +3413,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + return SEPOL_OK; + + exit: ++ cil_list_destroy(datum_expr, CIL_FALSE); + return rc; + } + +-- +2.32.0 + diff --git a/SOURCES/0062-libsepol-Quote-paths-when-generating-policy.conf-fro.patch b/SOURCES/0062-libsepol-Quote-paths-when-generating-policy.conf-fro.patch new file mode 100644 index 0000000..e8a5e53 --- /dev/null +++ b/SOURCES/0062-libsepol-Quote-paths-when-generating-policy.conf-fro.patch @@ -0,0 +1,46 @@ +From ce1025bf9ccd2e34a0c12d9a1d8eee19eb415573 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 15 Jun 2021 16:31:01 -0400 +Subject: [PATCH] libsepol: Quote paths when generating policy.conf from binary + policy +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Christian Göttsche submitted a similar patch +to quote paths when generating CIL policy from a binary policy. + +Since genfscon and devicetreecon rules have paths which are allowed +to contain spaces, always quote the path when writing out these rules. + +Signed-off-by: James Carter +Acked-by: Petr Lautrbach +--- + libsepol/src/kernel_to_conf.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c +index 5db47fe4f567..ffdf179a71f3 100644 +--- a/libsepol/src/kernel_to_conf.c ++++ b/libsepol/src/kernel_to_conf.c +@@ -2527,7 +2527,7 @@ static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb) + goto exit; + } + +- rc = strs_create_and_add(strs, "genfscon %s %s %s", 3, ++ rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s", 3, + fstype, name, ctx); + free(ctx); + if (rc != 0) { +@@ -2992,7 +2992,7 @@ static int write_xen_devicetree_rules_to_conf(FILE *out, struct policydb *pdb) + goto exit; + } + +- sepol_printf(out, "devicetreecon %s %s\n", name, ctx); ++ sepol_printf(out, "devicetreecon \"%s\" %s\n", name, ctx); + + free(ctx); + } +-- +2.32.0 + diff --git a/SOURCES/0063-libsepol-fix-typos.patch b/SOURCES/0063-libsepol-fix-typos.patch new file mode 100644 index 0000000..75716ca --- /dev/null +++ b/SOURCES/0063-libsepol-fix-typos.patch @@ -0,0 +1,72 @@ +From 2cb6bacddcd6957a8f28ce51a089e8514af3d574 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:50 +0200 +Subject: [PATCH] libsepol: fix typos +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + libsepol/src/module_to_cil.c | 2 +- + libsepol/src/policydb_validate.c | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 538df2794ade..96c97263d8c8 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -3692,7 +3692,7 @@ int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_curr + + cil_list_for_each(curr, sensorder->sens_list_str) { + if (curr->data == CIL_KEY_UNORDERED) { +- cil_log(CIL_ERR, "Sensitivy order cannot be unordered.\n"); ++ cil_log(CIL_ERR, "Sensitivity order cannot be unordered.\n"); + rc = SEPOL_ERR; + goto exit; + } +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 42a58468ed36..92a4d29700e9 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -1619,7 +1619,7 @@ int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args + cil_list_for_each(curr, sensorder->sens_list_str) { + rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SENS, extra_args, &datum); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to resolve sensitivty %s in sensitivityorder\n", (char *)curr->data); ++ cil_log(CIL_ERR, "Failed to resolve sensitivity %s in sensitivityorder\n", (char *)curr->data); + goto exit; + } + if (FLAVOR(datum) != CIL_SENS) { +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index 19c7c65c6382..60290da2a75f 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -3972,7 +3972,7 @@ int sepol_module_policydb_to_cil(FILE *fp, struct policydb *pdb, int linked) + + if (pdb->policy_type != SEPOL_POLICY_BASE && + pdb->policy_type != SEPOL_POLICY_MOD) { +- log_err("Policy pakcage is not a base or module"); ++ log_err("Policy package is not a base or module"); + rc = -1; + goto exit; + } +diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c +index b2891ddd64f3..246aa6e398f3 100644 +--- a/libsepol/src/policydb_validate.c ++++ b/libsepol/src/policydb_validate.c +@@ -641,7 +641,7 @@ static int validate_scope_index(sepol_handle_t *handle, scope_index_t *scope_ind + return 0; + + bad: +- ERR(handle, "Invalide scope"); ++ ERR(handle, "Invalid scope"); + return -1; + } + +-- +2.32.0 + diff --git a/SOURCES/0064-libsepol-resolve-missing-prototypes.patch b/SOURCES/0064-libsepol-resolve-missing-prototypes.patch new file mode 100644 index 0000000..f2f096e --- /dev/null +++ b/SOURCES/0064-libsepol-resolve-missing-prototypes.patch @@ -0,0 +1,203 @@ +From 9ec061b61c97878ac4d2626803dfbdd3fcbe0c87 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:51 +0200 +Subject: [PATCH] libsepol: resolve missing prototypes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Declare the functions as static or include the corresponding header +file. + +assertion.c:294:5: error: no previous prototype for function 'report_assertion_failures' [-Werror,-Wmissing-prototypes] +int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule) + ^ + +context.c:23:5: error: no previous prototype for function 'sepol_check_context' [-Werror,-Wmissing-prototypes] +int sepol_check_context(const char *context) + ^ + +expand.c:3377:5: error: no previous prototype for function 'expand_cond_av_node' [-Werror,-Wmissing-prototypes] +int expand_cond_av_node(policydb_t * p, + ^ + +policydb.c:638:6: error: no previous prototype for function 'role_trans_rule_destroy' [-Werror,-Wmissing-prototypes] +void role_trans_rule_destroy(role_trans_rule_t * x) + ^ + +policydb.c:1169:5: error: no previous prototype for function 'policydb_index_decls' [-Werror,-Wmissing-prototypes] +int policydb_index_decls(sepol_handle_t * handle, policydb_t * p) + ^ + +policydb.c:1429:6: error: no previous prototype for function 'ocontext_selinux_free' [-Werror,-Wmissing-prototypes] +void ocontext_selinux_free(ocontext_t **ocontexts) + ^ + +policydb.c:1451:6: error: no previous prototype for function 'ocontext_xen_free' [-Werror,-Wmissing-prototypes] +void ocontext_xen_free(ocontext_t **ocontexts) + ^ + +policydb.c:1750:5: error: no previous prototype for function 'type_set_or' [-Werror,-Wmissing-prototypes] +int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) + ^ + +policydb.c:2524:5: error: no previous prototype for function 'role_trans_read' [-Werror,-Wmissing-prototypes] +int role_trans_read(policydb_t *p, struct policy_file *fp) + ^ + +policydb.c:2567:5: error: no previous prototype for function 'role_allow_read' [-Werror,-Wmissing-prototypes] +int role_allow_read(role_allow_t ** r, struct policy_file *fp) + ^ + +policydb.c:2842:5: error: no previous prototype for function 'filename_trans_read' [-Werror,-Wmissing-prototypes] +int filename_trans_read(policydb_t *p, struct policy_file *fp) + ^ + +services.c:1027:5: error: no previous prototype for function 'sepol_validate_transition' [-Werror,-Wmissing-prototypes] +int sepol_validate_transition(sepol_security_id_t oldsid, + ^ + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/assertion.c | 2 +- + libsepol/src/context_internal.h | 1 + + libsepol/src/expand.c | 6 +++--- + libsepol/src/policydb.c | 16 ++++++++-------- + libsepol/src/services.c | 2 +- + 5 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c +index 266f67d74c56..dd2749a09dc0 100644 +--- a/libsepol/src/assertion.c ++++ b/libsepol/src/assertion.c +@@ -291,7 +291,7 @@ exit: + return rc; + } + +-int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule) ++static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule) + { + int rc; + struct avtab_match_args args; +diff --git a/libsepol/src/context_internal.h b/libsepol/src/context_internal.h +index 3cae28cc1c67..3dc9cd156a9c 100644 +--- a/libsepol/src/context_internal.h ++++ b/libsepol/src/context_internal.h +@@ -1,6 +1,7 @@ + #ifndef _SEPOL_CONTEXT_INTERNAL_H_ + #define _SEPOL_CONTEXT_INTERNAL_H_ + ++#include + #include + + #endif +diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c +index a656ffad3a71..84bfcfa36d0a 100644 +--- a/libsepol/src/expand.c ++++ b/libsepol/src/expand.c +@@ -3374,9 +3374,9 @@ static int expand_cond_insert(cond_av_list_t ** l, + return 0; + } + +-int expand_cond_av_node(policydb_t * p, +- avtab_ptr_t node, +- cond_av_list_t ** newl, avtab_t * expa) ++static int expand_cond_av_node(policydb_t * p, ++ avtab_ptr_t node, ++ cond_av_list_t ** newl, avtab_t * expa) + { + avtab_key_t *k = &node->key; + avtab_datum_t *d = &node->datum; +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index ffa279715686..3f7ddb11a236 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -635,7 +635,7 @@ void role_trans_rule_init(role_trans_rule_t * x) + ebitmap_init(&x->classes); + } + +-void role_trans_rule_destroy(role_trans_rule_t * x) ++static void role_trans_rule_destroy(role_trans_rule_t * x) + { + if (x != NULL) { + role_set_destroy(&x->roles); +@@ -1166,7 +1166,7 @@ int policydb_index_bools(policydb_t * p) + return 0; + } + +-int policydb_index_decls(sepol_handle_t * handle, policydb_t * p) ++static int policydb_index_decls(sepol_handle_t * handle, policydb_t * p) + { + avrule_block_t *curblock; + avrule_decl_t *decl; +@@ -1426,7 +1426,7 @@ static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum, + return 0; + } + +-void ocontext_selinux_free(ocontext_t **ocontexts) ++static void ocontext_selinux_free(ocontext_t **ocontexts) + { + ocontext_t *c, *ctmp; + int i; +@@ -1448,7 +1448,7 @@ void ocontext_selinux_free(ocontext_t **ocontexts) + } + } + +-void ocontext_xen_free(ocontext_t **ocontexts) ++static void ocontext_xen_free(ocontext_t **ocontexts) + { + ocontext_t *c, *ctmp; + int i; +@@ -1747,7 +1747,7 @@ int symtab_insert(policydb_t * pol, uint32_t sym, + return retval; + } + +-int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) ++static int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) + { + type_set_init(dst); + +@@ -2521,7 +2521,7 @@ static int type_read(policydb_t * p, hashtab_t h, struct policy_file *fp) + return -1; + } + +-int role_trans_read(policydb_t *p, struct policy_file *fp) ++static int role_trans_read(policydb_t *p, struct policy_file *fp) + { + role_trans_t **t = &p->role_tr; + unsigned int i; +@@ -2564,7 +2564,7 @@ int role_trans_read(policydb_t *p, struct policy_file *fp) + return 0; + } + +-int role_allow_read(role_allow_t ** r, struct policy_file *fp) ++static int role_allow_read(role_allow_t ** r, struct policy_file *fp) + { + unsigned int i; + uint32_t buf[2], nel; +@@ -2839,7 +2839,7 @@ err: + return -1; + } + +-int filename_trans_read(policydb_t *p, struct policy_file *fp) ++static int filename_trans_read(policydb_t *p, struct policy_file *fp) + { + unsigned int i; + uint32_t buf[1], nel; +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index 6596431c38e2..39fbd979b095 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -1024,7 +1024,7 @@ static int context_struct_compute_av(context_struct_t * scontext, + return 0; + } + +-int sepol_validate_transition(sepol_security_id_t oldsid, ++static int sepol_validate_transition(sepol_security_id_t oldsid, + sepol_security_id_t newsid, + sepol_security_id_t tasksid, + sepol_security_class_t tclass) +-- +2.32.0 + diff --git a/SOURCES/0065-libsepol-remove-unused-functions.patch b/SOURCES/0065-libsepol-remove-unused-functions.patch new file mode 100644 index 0000000..508a16a --- /dev/null +++ b/SOURCES/0065-libsepol-remove-unused-functions.patch @@ -0,0 +1,151 @@ +From 42f3d7cceb1e15f10eb8e886e6f07ee3c3c6130f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:52 +0200 +Subject: [PATCH] libsepol: remove unused functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The functions `role_set_get_role`, `sepol_validate_transition` and +`sepol_sidtab_remove` seem to be unused since the initial import. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/policydb.c | 18 ---------------- + libsepol/src/services.c | 47 ----------------------------------------- + libsepol/src/sidtab.c | 31 --------------------------- + 3 files changed, 96 deletions(-) + +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index 3f7ddb11a236..fc1d07112efb 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -1791,24 +1791,6 @@ int type_set_or_eq(type_set_t * dst, type_set_t * other) + return ret; + } + +-int role_set_get_role(role_set_t * x, uint32_t role) +-{ +- if (x->flags & ROLE_STAR) +- return 1; +- +- if (ebitmap_get_bit(&x->roles, role - 1)) { +- if (x->flags & ROLE_COMP) +- return 0; +- else +- return 1; +- } else { +- if (x->flags & ROLE_COMP) +- return 1; +- else +- return 0; +- } +-} +- + /***********************************************************************/ + /* everything below is for policy reads */ + +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index 39fbd979b095..ff91f7d2fdfc 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -1024,53 +1024,6 @@ static int context_struct_compute_av(context_struct_t * scontext, + return 0; + } + +-static int sepol_validate_transition(sepol_security_id_t oldsid, +- sepol_security_id_t newsid, +- sepol_security_id_t tasksid, +- sepol_security_class_t tclass) +-{ +- context_struct_t *ocontext; +- context_struct_t *ncontext; +- context_struct_t *tcontext; +- class_datum_t *tclass_datum; +- constraint_node_t *constraint; +- +- if (!tclass || tclass > policydb->p_classes.nprim) { +- ERR(NULL, "unrecognized class %d", tclass); +- return -EINVAL; +- } +- tclass_datum = policydb->class_val_to_struct[tclass - 1]; +- +- ocontext = sepol_sidtab_search(sidtab, oldsid); +- if (!ocontext) { +- ERR(NULL, "unrecognized SID %d", oldsid); +- return -EINVAL; +- } +- +- ncontext = sepol_sidtab_search(sidtab, newsid); +- if (!ncontext) { +- ERR(NULL, "unrecognized SID %d", newsid); +- return -EINVAL; +- } +- +- tcontext = sepol_sidtab_search(sidtab, tasksid); +- if (!tcontext) { +- ERR(NULL, "unrecognized SID %d", tasksid); +- return -EINVAL; +- } +- +- constraint = tclass_datum->validatetrans; +- while (constraint) { +- if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext, +- 0, constraint, NULL, 0)) { +- return -EPERM; +- } +- constraint = constraint->next; +- } +- +- return 0; +-} +- + /* + * sepol_validate_transition_reason_buffer - the reason buffer is realloc'd + * in the constraint_expr_eval_reason() function. +diff --git a/libsepol/src/sidtab.c b/libsepol/src/sidtab.c +index e6bf57161e52..255e07252412 100644 +--- a/libsepol/src/sidtab.c ++++ b/libsepol/src/sidtab.c +@@ -84,37 +84,6 @@ int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid, + return 0; + } + +-int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid) +-{ +- int hvalue; +- sidtab_node_t *cur, *last; +- +- if (!s || !s->htable) +- return -ENOENT; +- +- hvalue = SIDTAB_HASH(sid); +- last = NULL; +- cur = s->htable[hvalue]; +- while (cur != NULL && sid > cur->sid) { +- last = cur; +- cur = cur->next; +- } +- +- if (cur == NULL || sid != cur->sid) +- return -ENOENT; +- +- if (last == NULL) +- s->htable[hvalue] = cur->next; +- else +- last->next = cur->next; +- +- context_destroy(&cur->context); +- +- free(cur); +- s->nel--; +- return 0; +-} +- + context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid) + { + int hvalue; +-- +2.32.0 + diff --git a/SOURCES/0066-libsepol-avoid-unsigned-integer-overflow.patch b/SOURCES/0066-libsepol-avoid-unsigned-integer-overflow.patch new file mode 100644 index 0000000..9846153 --- /dev/null +++ b/SOURCES/0066-libsepol-avoid-unsigned-integer-overflow.patch @@ -0,0 +1,47 @@ +From 1537ea8412e4af832b53ac48b7d85eac00426a92 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:55 +0200 +Subject: [PATCH] libsepol: avoid unsigned integer overflow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Unsigned integer overflow is well-defined and not undefined behavior. +But it is still useful to enable undefined behavior sanitizer checks on +unsigned arithmetic to detect possible issues on counters or variables +with similar purpose. + +Use a spaceship operator like comparison instead of subtraction. + +Modern compilers will generate a single comparison instruction instead +of actually perform the subtraction. + +policydb.c:826:17: runtime error: unsigned integer overflow: 24 - 1699 cannot be represented in type 'unsigned int' + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/policydb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index fc1d07112efb..e0b072e1938f 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -817,11 +817,11 @@ static int filenametr_cmp(hashtab_t h __attribute__ ((unused)), + const filename_trans_key_t *ft2 = (const filename_trans_key_t *)k2; + int v; + +- v = ft1->ttype - ft2->ttype; ++ v = (ft1->ttype > ft2->ttype) - (ft1->ttype < ft2->ttype); + if (v) + return v; + +- v = ft1->tclass - ft2->tclass; ++ v = (ft1->tclass > ft2->tclass) - (ft1->tclass < ft2->tclass); + if (v) + return v; + +-- +2.32.0 + diff --git a/SOURCES/0067-libsepol-follow-declaration-after-statement.patch b/SOURCES/0067-libsepol-follow-declaration-after-statement.patch new file mode 100644 index 0000000..9f83eba --- /dev/null +++ b/SOURCES/0067-libsepol-follow-declaration-after-statement.patch @@ -0,0 +1,335 @@ +From 8f50b45320f715aa7ab883fe3540017bdc097e20 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:56 +0200 +Subject: [PATCH] libsepol: follow declaration-after-statement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Follow the project style of no declaration after statement. + +Found by the gcc warning -Wdeclaration-after-statement + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/booleans.c | 6 ++-- + libsepol/src/debug.c | 2 +- + libsepol/src/ebitmap.c | 11 ++++--- + libsepol/src/module_to_cil.c | 10 +++--- + libsepol/src/nodes.c | 6 ++-- + libsepol/src/services.c | 59 ++++++++++++++++++------------------ + libsepol/src/util.c | 2 +- + 7 files changed, 50 insertions(+), 46 deletions(-) + +diff --git a/libsepol/src/booleans.c b/libsepol/src/booleans.c +index 30fcf29d892b..716da6b487a9 100644 +--- a/libsepol/src/booleans.c ++++ b/libsepol/src/booleans.c +@@ -19,6 +19,7 @@ static int bool_update(sepol_handle_t * handle, + const char *cname; + char *name; + int value; ++ cond_bool_datum_t *datum; + + sepol_bool_key_unpack(key, &cname); + name = strdup(cname); +@@ -27,8 +28,7 @@ static int bool_update(sepol_handle_t * handle, + if (!name) + goto omem; + +- cond_bool_datum_t *datum = +- hashtab_search(policydb->p_bools.table, name); ++ datum = hashtab_search(policydb->p_bools.table, name); + if (!datum) { + ERR(handle, "boolean %s no longer in policy", name); + goto err; +@@ -84,10 +84,10 @@ int sepol_bool_set(sepol_handle_t * handle, + const sepol_bool_key_t * key, const sepol_bool_t * data) + { + ++ policydb_t *policydb = &p->p; + const char *name; + sepol_bool_key_unpack(key, &name); + +- policydb_t *policydb = &p->p; + if (bool_update(handle, policydb, key, data) < 0) + goto err; + +diff --git a/libsepol/src/debug.c b/libsepol/src/debug.c +index 0458e3538884..f6a59ae701ed 100644 +--- a/libsepol/src/debug.c ++++ b/libsepol/src/debug.c +@@ -44,6 +44,7 @@ void sepol_msg_default_handler(void *varg __attribute__ ((unused)), + { + + FILE *stream = NULL; ++ va_list ap; + + switch (sepol_msg_get_level(handle)) { + +@@ -60,7 +61,6 @@ void sepol_msg_default_handler(void *varg __attribute__ ((unused)), + fprintf(stream, "%s.%s: ", + sepol_msg_get_channel(handle), sepol_msg_get_fname(handle)); + +- va_list ap; + va_start(ap, fmt); + vfprintf(stream, fmt, ap); + va_end(ap); +diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c +index 7f425349c229..522e14a68a94 100644 +--- a/libsepol/src/ebitmap.c ++++ b/libsepol/src/ebitmap.c +@@ -113,9 +113,10 @@ int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit) + + int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit) + { ++ int rc; + ebitmap_t e3; + ebitmap_init(dst); +- int rc = ebitmap_not(&e3, e2, maxbit); ++ rc = ebitmap_not(&e3, e2, maxbit); + if (rc < 0) + return rc; + rc = ebitmap_and(dst, e1, &e3); +@@ -138,13 +139,15 @@ unsigned int ebitmap_cardinality(ebitmap_t *e1) + + int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2) + { ++ int rc; ++ ebitmap_t tmp; ++ int distance; + if (ebitmap_cmp(e1, e2)) + return 0; +- ebitmap_t tmp; +- int rc = ebitmap_xor(&tmp, e1, e2); ++ rc = ebitmap_xor(&tmp, e1, e2); + if (rc < 0) + return -1; +- int distance = ebitmap_cardinality(&tmp); ++ distance = ebitmap_cardinality(&tmp); + ebitmap_destroy(&tmp); + return distance; + } +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index 60290da2a75f..580ba06a95b0 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -107,8 +107,8 @@ static void cil_printf(const char *fmt, ...) { + __attribute__ ((format(printf, 2, 3))) + static void cil_println(int indent, const char *fmt, ...) + { +- cil_indent(indent); + va_list argptr; ++ cil_indent(indent); + va_start(argptr, fmt); + if (vfprintf(out_file, fmt, argptr) < 0) { + log_err("Failed to write to output"); +@@ -235,12 +235,14 @@ static void role_list_destroy(void) + + static void attr_list_destroy(struct list **attr_list) + { ++ struct list_node *curr; ++ struct attr_list_node *attr; ++ + if (attr_list == NULL || *attr_list == NULL) { + return; + } + +- struct list_node *curr = (*attr_list)->head; +- struct attr_list_node *attr; ++ curr = (*attr_list)->head; + + while (curr != NULL) { + attr = curr->data; +@@ -3525,12 +3527,12 @@ exit: + static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack) + { + int rc = -1; ++ struct avrule_decl *decl = stack_peek(decl_stack); + struct map_args args; + args.pdb = pdb; + args.block = block; + args.decl_stack = decl_stack; + args.indent = indent; +- struct avrule_decl *decl = stack_peek(decl_stack); + + for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) { + if (func_to_cil[args.sym_index] == NULL) { +diff --git a/libsepol/src/nodes.c b/libsepol/src/nodes.c +index 820346d0f5df..97a0f959c7ca 100644 +--- a/libsepol/src/nodes.c ++++ b/libsepol/src/nodes.c +@@ -19,20 +19,20 @@ static int node_from_record(sepol_handle_t * handle, + ocontext_t *tmp_node = NULL; + context_struct_t *tmp_con = NULL; + char *addr_buf = NULL, *mask_buf = NULL; ++ size_t addr_bsize, mask_bsize; ++ int proto; + + tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t)); + if (!tmp_node) + goto omem; + +- size_t addr_bsize, mask_bsize; +- + /* Address and netmask */ + if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0) + goto err; + if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0) + goto err; + +- int proto = sepol_node_get_proto(data); ++ proto = sepol_node_get_proto(data); + + switch (proto) { + case SEPOL_PROTO_IP4: +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index ff91f7d2fdfc..d647c8f57300 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -290,6 +290,19 @@ static char *get_class_info(sepol_security_class_t tclass, + { + constraint_expr_t *e; + int mls, state_num; ++ /* Determine statement type */ ++ const char *statements[] = { ++ "constrain ", /* 0 */ ++ "mlsconstrain ", /* 1 */ ++ "validatetrans ", /* 2 */ ++ "mlsvalidatetrans ", /* 3 */ ++ 0 }; ++ size_t class_buf_len = 0; ++ size_t new_class_buf_len; ++ size_t buf_used; ++ int len; ++ char *class_buf = NULL, *p; ++ char *new_class_buf = NULL; + + /* Find if MLS statement or not */ + mls = 0; +@@ -300,26 +313,11 @@ static char *get_class_info(sepol_security_class_t tclass, + } + } + +- /* Determine statement type */ +- const char *statements[] = { +- "constrain ", /* 0 */ +- "mlsconstrain ", /* 1 */ +- "validatetrans ", /* 2 */ +- "mlsvalidatetrans ", /* 3 */ +- 0 }; +- + if (xcontext == NULL) + state_num = mls + 0; + else + state_num = mls + 2; + +- size_t class_buf_len = 0; +- size_t new_class_buf_len; +- size_t buf_used; +- int len; +- char *class_buf = NULL, *p; +- char *new_class_buf = NULL; +- + while (1) { + new_class_buf_len = class_buf_len + EXPR_BUF_SIZE; + new_class_buf = realloc(class_buf, new_class_buf_len); +@@ -417,6 +415,8 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + char *tgt = NULL; + int rc = 0, x; + char *class_buf = NULL; ++ int expr_list_len = 0; ++ int expr_count; + + /* + * The array of expression answer buffer pointers and counter. +@@ -424,6 +424,11 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + char **answer_list = NULL; + int answer_counter = 0; + ++ /* The pop operands */ ++ char *a; ++ char *b; ++ int a_len, b_len; ++ + class_buf = get_class_info(tclass, constraint, xcontext); + if (!class_buf) { + ERR(NULL, "failed to allocate class buffer"); +@@ -431,7 +436,6 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + } + + /* Original function but with buffer support */ +- int expr_list_len = 0; + expr_counter = 0; + expr_list = NULL; + for (e = constraint->expr; e; e = e->next) { +@@ -701,7 +705,7 @@ mls_ops: + * expr_list malloc's. Normally they are released by the RPN to + * infix code. + */ +- int expr_count = expr_counter; ++ expr_count = expr_counter; + expr_counter = 0; + + /* +@@ -715,11 +719,6 @@ mls_ops: + goto out; + } + +- /* The pop operands */ +- char *a; +- char *b; +- int a_len, b_len; +- + /* Convert constraint from RPN to infix notation. */ + for (x = 0; x != expr_count; x++) { + if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x], +@@ -778,14 +777,6 @@ mls_ops: + xcontext ? "Validatetrans" : "Constraint", + s[0] ? "GRANTED" : "DENIED"); + +- int len, new_buf_len; +- char *p, **new_buf = r_buf; +- /* +- * These contain the constraint components that are added to the +- * callers reason buffer. +- */ +- const char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 }; +- + /* + * This will add the constraints to the callers reason buffer (who is + * responsible for freeing the memory). It will handle any realloc's +@@ -796,6 +787,14 @@ mls_ops: + + if (r_buf && ((s[0] == 0) || ((s[0] == 1 && + (flags & SHOW_GRANTED) == SHOW_GRANTED)))) { ++ int len, new_buf_len; ++ char *p, **new_buf = r_buf; ++ /* ++ * These contain the constraint components that are added to the ++ * callers reason buffer. ++ */ ++ const char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 }; ++ + for (x = 0; buffers[x] != NULL; x++) { + while (1) { + p = *r_buf + reason_buf_used; +diff --git a/libsepol/src/util.c b/libsepol/src/util.c +index d51750af3fa1..a47cae87bfed 100644 +--- a/libsepol/src/util.c ++++ b/libsepol/src/util.c +@@ -129,9 +129,9 @@ char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms) + unsigned int bit; + unsigned int in_range = 0; + static char xpermsbuf[2048]; +- xpermsbuf[0] = '\0'; + char *p; + int len, xpermslen = 0; ++ xpermsbuf[0] = '\0'; + p = xpermsbuf; + + if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) +-- +2.32.0 + diff --git a/SOURCES/0068-libsepol-cil-follow-declaration-after-statement.patch b/SOURCES/0068-libsepol-cil-follow-declaration-after-statement.patch new file mode 100644 index 0000000..4a7b05d --- /dev/null +++ b/SOURCES/0068-libsepol-cil-follow-declaration-after-statement.patch @@ -0,0 +1,189 @@ +From 852c4398a9a227e0eb4de42d45c0c2845ed92bc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:57 +0200 +Subject: [PATCH] libsepol/cil: follow declaration-after-statement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Follow the project style of no declaration after statement. + +Found by the gcc warning -Wdeclaration-after-statement + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_binary.c | 5 +++-- + libsepol/cil/src/cil_build_ast.c | 5 +++-- + libsepol/cil/src/cil_fqn.c | 3 ++- + libsepol/cil/src/cil_list.c | 7 ++++--- + libsepol/cil/src/cil_post.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 6 +++--- + libsepol/cil/src/cil_strpool.c | 3 ++- + 7 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 18532aad9801..85094b01ef9d 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -593,11 +593,11 @@ exit: + int __cil_typeattr_bitmap_init(policydb_t *pdb) + { + int rc = SEPOL_ERR; ++ uint32_t i; + + pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + +- uint32_t i = 0; + for (i = 0; i < pdb->p_types.nprim; i++) { + ebitmap_init(&pdb->type_attr_map[i]); + ebitmap_init(&pdb->attr_type_map[i]); +@@ -2657,6 +2657,7 @@ int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_ + int rc = SEPOL_ERR; + struct cil_list_item *item; + enum cil_flavor flavor; ++ enum cil_flavor cil_op; + constraint_expr_t *op, *h1, *h2, *t1, *t2; + int is_leaf = CIL_FALSE; + +@@ -2673,7 +2674,7 @@ int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_ + goto exit; + } + +- enum cil_flavor cil_op = (enum cil_flavor)(uintptr_t)item->data; ++ cil_op = (enum cil_flavor)(uintptr_t)item->data; + switch (cil_op) { + case CIL_NOT: + op->expr_type = CEXPR_NOT; +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 96c97263d8c8..908b0336d1dd 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5173,6 +5173,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + char *key = NULL; + struct cil_macro *macro = NULL; + struct cil_tree_node *macro_content = NULL; ++ struct cil_tree_node *current_item; + enum cil_syntax syntax[] = { + CIL_SYN_STRING, + CIL_SYN_STRING, +@@ -5195,7 +5196,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + + key = parse_current->next->data; + +- struct cil_tree_node *current_item = parse_current->next->next->cl_head; ++ current_item = parse_current->next->next->cl_head; + while (current_item != NULL) { + enum cil_syntax param_syntax[] = { + CIL_SYN_STRING, +@@ -5205,6 +5206,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax); + char *kind = NULL; + struct cil_param *param = NULL; ++ struct cil_list_item *curr_param; + + rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len); + if (rc != SEPOL_OK) { +@@ -5263,7 +5265,6 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + } + + //walk current list and check for duplicate parameters +- struct cil_list_item *curr_param; + cil_list_for_each(curr_param, macro->params) { + if (param->str == ((struct cil_param*)curr_param->data)->str) { + cil_log(CIL_ERR, "Duplicate parameter\n"); +diff --git a/libsepol/cil/src/cil_fqn.c b/libsepol/cil/src/cil_fqn.c +index 097222a83da9..46db069b254a 100644 +--- a/libsepol/cil/src/cil_fqn.c ++++ b/libsepol/cil/src/cil_fqn.c +@@ -78,12 +78,13 @@ static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, has + struct cil_tree_node *node = NODE(datum); + int i; + int rc = SEPOL_OK; ++ int newlen; + + if (node->flavor != CIL_BLOCK) { + goto exit; + } + +- int newlen = fqn_args->len + strlen(datum->name) + 1; ++ newlen = fqn_args->len + strlen(datum->name) + 1; + if (newlen >= CIL_MAX_NAME_LENGTH) { + cil_log(CIL_INFO, "Fully qualified name for block %s is too long\n", datum->name); + rc = SEPOL_ERR; +diff --git a/libsepol/cil/src/cil_list.c b/libsepol/cil/src/cil_list.c +index 4e7843cb01ef..8a426f1f5950 100644 +--- a/libsepol/cil/src/cil_list.c ++++ b/libsepol/cil/src/cil_list.c +@@ -55,15 +55,16 @@ void cil_list_init(struct cil_list **list, enum cil_flavor flavor) + + void cil_list_destroy(struct cil_list **list, unsigned destroy_data) + { ++ struct cil_list_item *item; ++ + if (*list == NULL) { + return; + } + +- struct cil_list_item *item = (*list)->head; +- struct cil_list_item *next = NULL; ++ item = (*list)->head; + while (item != NULL) + { +- next = item->next; ++ struct cil_list_item *next = item->next; + if (item->flavor == CIL_LIST) { + cil_list_destroy((struct cil_list**)&(item->data), destroy_data); + free(item); +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index 05842b644807..7bca0834ad39 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -213,8 +213,8 @@ int cil_post_filecon_compare(const void *a, const void *b) + struct fc_data *a_data = cil_malloc(sizeof(*a_data)); + struct fc_data *b_data = cil_malloc(sizeof(*b_data)); + char *a_path = cil_malloc(strlen(a_filecon->path_str) + 1); +- a_path[0] = '\0'; + char *b_path = cil_malloc(strlen(b_filecon->path_str) + 1); ++ a_path[0] = '\0'; + b_path[0] = '\0'; + strcat(a_path, a_filecon->path_str); + strcat(b_path, b_filecon->path_str); +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 92a4d29700e9..b5199bad35e2 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3956,10 +3956,10 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + enum cil_log_level lvl = CIL_ERR; + + if (optional != NULL) { +- lvl = CIL_INFO; +- + struct cil_optional *opt = (struct cil_optional *)optional->data; +- struct cil_tree_node *opt_node = NODE(opt);; ++ struct cil_tree_node *opt_node = NODE(opt); ++ ++ lvl = CIL_INFO; + /* disable an optional if something failed to resolve */ + opt->enabled = CIL_FALSE; + cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); +diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c +index 2598bbf3d80e..70bca3630220 100644 +--- a/libsepol/cil/src/cil_strpool.c ++++ b/libsepol/cil/src/cil_strpool.c +@@ -75,9 +75,10 @@ char *cil_strpool_add(const char *str) + + strpool_ref = hashtab_search(cil_strpool_tab, (hashtab_key_t)str); + if (strpool_ref == NULL) { ++ int rc; + strpool_ref = cil_malloc(sizeof(*strpool_ref)); + strpool_ref->str = cil_strdup(str); +- int rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref); ++ rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref); + if (rc != SEPOL_OK) { + pthread_mutex_unlock(&cil_strpool_mutex); + cil_log(CIL_ERR, "Failed to allocate memory\n"); +-- +2.32.0 + diff --git a/SOURCES/0069-libsepol-remove-dead-stores.patch b/SOURCES/0069-libsepol-remove-dead-stores.patch new file mode 100644 index 0000000..e99c4fd --- /dev/null +++ b/SOURCES/0069-libsepol-remove-dead-stores.patch @@ -0,0 +1,92 @@ +From a53a845b76f674f2a11cd178222042bc9c3fdae6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:58 +0200 +Subject: [PATCH] libsepol: remove dead stores +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +conditional.c:391:4: warning: Value stored to 'i' is never read [deadcode.DeadStores] + i = 0; + ^ ~ +conditional.c:718:2: warning: Value stored to 'len' is never read [deadcode.DeadStores] + len = 0; + ^ ~ +conditional.c:772:2: warning: Value stored to 'len' is never read [deadcode.DeadStores] + len = 0; + ^ ~ + +services.c:89:10: warning: Value stored to 'new_stack' during its initialization is never read [deadcode.DeadStores] + char **new_stack = stack; + ^~~~~~~~~ ~~~~~ + +services.c:440:11: warning: Value stored to 'new_expr_list' during its initialization is never read [deadcode.DeadStores] + char **new_expr_list = expr_list; + ^~~~~~~~~~~~~ ~~~~~~~~~ + +../cil/src/cil_binary.c:2230:24: warning: Value stored to 'cb_node' during its initialization is never read [deadcode.DeadStores] + struct cil_tree_node *cb_node = node->cl_head; + ^~~~~~~ ~~~~~~~~~~~~~ + +Found by clang-analyzer + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/conditional.c | 3 --- + libsepol/src/services.c | 4 ++-- + 2 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c +index 823b649a9163..e3ede694e59f 100644 +--- a/libsepol/src/conditional.c ++++ b/libsepol/src/conditional.c +@@ -388,7 +388,6 @@ int cond_normalize_expr(policydb_t * p, cond_node_t * cn) + for (e = cn->expr; e != NULL; e = e->next) { + switch (e->expr_type) { + case COND_BOOL: +- i = 0; + /* see if we've already seen this bool */ + if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) { + /* count em all but only record up to COND_MAX_BOOLS */ +@@ -715,7 +714,6 @@ static int cond_read_av_list(policydb_t * p, void *fp, + + *ret_list = NULL; + +- len = 0; + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + return -1; +@@ -769,7 +767,6 @@ static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp) + + node->cur_state = le32_to_cpu(buf[0]); + +- len = 0; + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + goto err; +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index d647c8f57300..c34bb9667fbc 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -86,7 +86,7 @@ static int next_stack_entry; + static void push(char *expr_ptr) + { + if (next_stack_entry >= stack_len) { +- char **new_stack = stack; ++ char **new_stack; + int new_stack_len; + + if (stack_len == 0) +@@ -441,7 +441,7 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + for (e = constraint->expr; e; e = e->next) { + /* Allocate a stack to hold expression buffer entries */ + if (expr_counter >= expr_list_len) { +- char **new_expr_list = expr_list; ++ char **new_expr_list; + int new_expr_list_len; + + if (expr_list_len == 0) +-- +2.32.0 + diff --git a/SOURCES/0070-libsepol-mark-read-only-parameters-of-ebitmap-interf.patch b/SOURCES/0070-libsepol-mark-read-only-parameters-of-ebitmap-interf.patch new file mode 100644 index 0000000..5504b7f --- /dev/null +++ b/SOURCES/0070-libsepol-mark-read-only-parameters-of-ebitmap-interf.patch @@ -0,0 +1,135 @@ +From 390ec54d278a14d9c29b80cc4fc5cb9ba504ed13 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:59 +0200 +Subject: [PATCH] libsepol: mark read-only parameters of ebitmap interfaces + const +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make it more obvious which parameters are read-only and not being +modified and allow callers to pass const pointers. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/include/sepol/policydb/ebitmap.h | 16 ++++++++-------- + libsepol/src/ebitmap.c | 18 +++++++++--------- + 2 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/libsepol/include/sepol/policydb/ebitmap.h b/libsepol/include/sepol/policydb/ebitmap.h +index 634436f6c30b..81d0c7a67347 100644 +--- a/libsepol/include/sepol/policydb/ebitmap.h ++++ b/libsepol/include/sepol/policydb/ebitmap.h +@@ -67,7 +67,7 @@ static inline unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit) + return (bit + 1); + } + +-static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit) ++static inline int ebitmap_node_get_bit(const ebitmap_node_t * n, unsigned int bit) + { + if (n->map & (MAPBIT << (bit - n->startbit))) + return 1; +@@ -83,18 +83,18 @@ static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit) + extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2); + extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2); + extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1); +-extern int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2); +-extern int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2); +-extern int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit); +-extern int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit); +-extern unsigned int ebitmap_cardinality(ebitmap_t *e1); +-extern int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2); ++extern int ebitmap_and(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2); ++extern int ebitmap_xor(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2); ++extern int ebitmap_not(ebitmap_t *dst, const ebitmap_t *e1, unsigned int maxbit); ++extern int ebitmap_andnot(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2, unsigned int maxbit); ++extern unsigned int ebitmap_cardinality(const ebitmap_t *e1); ++extern int ebitmap_hamming_distance(const ebitmap_t * e1, const ebitmap_t * e2); + extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src); + extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2); + extern int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2); + extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit); + extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value); +-extern unsigned int ebitmap_highest_set_bit(ebitmap_t * e); ++extern unsigned int ebitmap_highest_set_bit(const ebitmap_t * e); + extern void ebitmap_destroy(ebitmap_t * e); + extern int ebitmap_read(ebitmap_t * e, void *fp); + +diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c +index 522e14a68a94..4e9acdf868a2 100644 +--- a/libsepol/src/ebitmap.c ++++ b/libsepol/src/ebitmap.c +@@ -71,7 +71,7 @@ int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1) + return 0; + } + +-int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) ++int ebitmap_and(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2) + { + unsigned int i, length = min(ebitmap_length(e1), ebitmap_length(e2)); + ebitmap_init(dst); +@@ -85,7 +85,7 @@ int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) + return 0; + } + +-int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) ++int ebitmap_xor(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2) + { + unsigned int i, length = max(ebitmap_length(e1), ebitmap_length(e2)); + ebitmap_init(dst); +@@ -98,7 +98,7 @@ int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) + return 0; + } + +-int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit) ++int ebitmap_not(ebitmap_t *dst, const ebitmap_t *e1, unsigned int maxbit) + { + unsigned int i; + ebitmap_init(dst); +@@ -111,7 +111,7 @@ int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit) + return 0; + } + +-int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit) ++int ebitmap_andnot(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2, unsigned int maxbit) + { + int rc; + ebitmap_t e3; +@@ -126,10 +126,10 @@ int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int ma + return 0; + } + +-unsigned int ebitmap_cardinality(ebitmap_t *e1) ++unsigned int ebitmap_cardinality(const ebitmap_t *e1) + { + unsigned int count = 0; +- ebitmap_node_t *n; ++ const ebitmap_node_t *n; + + for (n = e1->node; n; n = n->next) { + count += __builtin_popcountll(n->map); +@@ -137,7 +137,7 @@ unsigned int ebitmap_cardinality(ebitmap_t *e1) + return count; + } + +-int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2) ++int ebitmap_hamming_distance(const ebitmap_t * e1, const ebitmap_t * e2) + { + int rc; + ebitmap_t tmp; +@@ -347,9 +347,9 @@ int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value) + return 0; + } + +-unsigned int ebitmap_highest_set_bit(ebitmap_t * e) ++unsigned int ebitmap_highest_set_bit(const ebitmap_t * e) + { +- ebitmap_node_t *n; ++ const ebitmap_node_t *n; + MAPTYPE map; + unsigned int pos = 0; + +-- +2.32.0 + diff --git a/SOURCES/0071-libsepol-mark-read-only-parameters-of-type_set_-inte.patch b/SOURCES/0071-libsepol-mark-read-only-parameters-of-type_set_-inte.patch new file mode 100644 index 0000000..2d3f283 --- /dev/null +++ b/SOURCES/0071-libsepol-mark-read-only-parameters-of-type_set_-inte.patch @@ -0,0 +1,68 @@ +From 8eec1bb50230c78faaeb9ccc0decb83cad205bf2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:00 +0200 +Subject: [PATCH] libsepol: mark read-only parameters of type_set_ interfaces + const +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make it more obvious which parameters are read-only and not being +modified and allow callers to pass const pointers. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/include/sepol/policydb/policydb.h | 4 ++-- + libsepol/src/policydb.c | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h +index 9ef43abc2f12..6976ef4831ef 100644 +--- a/libsepol/include/sepol/policydb/policydb.h ++++ b/libsepol/include/sepol/policydb/policydb.h +@@ -667,8 +667,8 @@ extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p); + extern void class_perm_node_init(class_perm_node_t * x); + extern void type_set_init(type_set_t * x); + extern void type_set_destroy(type_set_t * x); +-extern int type_set_cpy(type_set_t * dst, type_set_t * src); +-extern int type_set_or_eq(type_set_t * dst, type_set_t * other); ++extern int type_set_cpy(type_set_t * dst, const type_set_t * src); ++extern int type_set_or_eq(type_set_t * dst, const type_set_t * other); + extern void role_set_init(role_set_t * x); + extern void role_set_destroy(role_set_t * x); + extern void avrule_init(avrule_t * x); +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index e0b072e1938f..b4e427af05c8 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -1747,7 +1747,7 @@ int symtab_insert(policydb_t * pol, uint32_t sym, + return retval; + } + +-static int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) ++static int type_set_or(type_set_t * dst, const type_set_t * a, const type_set_t * b) + { + type_set_init(dst); + +@@ -1764,7 +1764,7 @@ static int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) + return 0; + } + +-int type_set_cpy(type_set_t * dst, type_set_t * src) ++int type_set_cpy(type_set_t * dst, const type_set_t * src) + { + type_set_init(dst); + +@@ -1777,7 +1777,7 @@ int type_set_cpy(type_set_t * dst, type_set_t * src) + return 0; + } + +-int type_set_or_eq(type_set_t * dst, type_set_t * other) ++int type_set_or_eq(type_set_t * dst, const type_set_t * other) + { + int ret; + type_set_t tmp; +-- +2.32.0 + diff --git a/SOURCES/0072-libsepol-do-not-allocate-memory-of-size-0.patch b/SOURCES/0072-libsepol-do-not-allocate-memory-of-size-0.patch new file mode 100644 index 0000000..16e4c45 --- /dev/null +++ b/SOURCES/0072-libsepol-do-not-allocate-memory-of-size-0.patch @@ -0,0 +1,63 @@ +From 19a6ebfa895ce3baa6bd07cb5227556c82f20cb6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:01 +0200 +Subject: [PATCH] libsepol: do not allocate memory of size 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In case cats_ebitmap_len() returns 0, do not allocate but quit. + +Found by clang-analyzer + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/kernel_to_cil.c | 5 ++++- + libsepol/src/kernel_to_conf.c | 5 ++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 30a27bf527d5..5aaee6288565 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -1034,11 +1034,14 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) + { + struct ebitmap_node *node; + uint32_t i, start, range; +- char *catsbuf, *p; ++ char *catsbuf = NULL, *p; + const char *fmt; + int len, remaining; + + remaining = (int)cats_ebitmap_len(cats, val_to_name); ++ if (remaining == 0) { ++ goto exit; ++ } + catsbuf = malloc(remaining); + if (!catsbuf) { + goto exit; +diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c +index ffdf179a71f3..cb8e13809d52 100644 +--- a/libsepol/src/kernel_to_conf.c ++++ b/libsepol/src/kernel_to_conf.c +@@ -1025,12 +1025,15 @@ 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, *p; ++ char *catsbuf = NULL, *p; + const char *fmt; + char sep; + int len, remaining; + + remaining = (int)cats_ebitmap_len(cats, val_to_name); ++ if (remaining == 0) { ++ goto exit; ++ } + catsbuf = malloc(remaining); + if (!catsbuf) { + goto exit; +-- +2.32.0 + diff --git a/SOURCES/0073-libsepol-remove-dead-stores.patch b/SOURCES/0073-libsepol-remove-dead-stores.patch new file mode 100644 index 0000000..652db56 --- /dev/null +++ b/SOURCES/0073-libsepol-remove-dead-stores.patch @@ -0,0 +1,41 @@ +From 1076a07288f527ac64dcd421ec01e424ee85474d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:03 +0200 +Subject: [PATCH] libsepol: remove dead stores +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Found by Infer + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/services.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index c34bb9667fbc..f7c31d80f954 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -175,7 +175,7 @@ static int expr_buf_len; + static void cat_expr_buf(char *e_buf, const char *string) + { + int len, new_buf_len; +- char *p, *new_buf = e_buf; ++ char *p, *new_buf; + + while (1) { + p = e_buf + expr_buf_used; +@@ -406,7 +406,7 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + #define TARGET 2 + #define XTARGET 3 + +- int s_t_x_num = SOURCE; ++ int s_t_x_num; + + /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */ + int u_r_t = 0; +-- +2.32.0 + diff --git a/SOURCES/0074-libsepol-cil-silence-cast-warning.patch b/SOURCES/0074-libsepol-cil-silence-cast-warning.patch new file mode 100644 index 0000000..dbb4b9a --- /dev/null +++ b/SOURCES/0074-libsepol-cil-silence-cast-warning.patch @@ -0,0 +1,51 @@ +From de3b96a158c60147703dc5d49c227a596d4ae165 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:04 +0200 +Subject: [PATCH] libsepol/cil: silence cast warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../cil/src/cil_write_ast.c:86:32: error: cast to smaller integer type 'enum cil_flavor' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast] + enum cil_flavor op_flavor = (enum cil_flavor)curr->data; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +../cil/src/cil_write_ast.c:130:37: error: cast to smaller integer type 'enum cil_flavor' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast] + enum cil_flavor operand_flavor = (enum cil_flavor)curr->data; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Silence this warning by casting the pointer to an integer the cast to +enum cil_flavor. + +See 32f8ed3d6b0b ("libsepol/cil: introduce intermediate cast to silence -Wvoid-pointer-to-enum-cast") + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_write_ast.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c +index 4871f7045e19..186070c1783a 100644 +--- a/libsepol/cil/src/cil_write_ast.c ++++ b/libsepol/cil/src/cil_write_ast.c +@@ -83,7 +83,7 @@ static void write_expr(FILE *out, struct cil_list *expr) + break; + case CIL_OP: { + const char *op_str; +- enum cil_flavor op_flavor = (enum cil_flavor)curr->data; ++ enum cil_flavor op_flavor = (enum cil_flavor)(uintptr_t)curr->data; + switch (op_flavor) { + case CIL_AND: + op_str = CIL_KEY_AND; +@@ -127,7 +127,7 @@ static void write_expr(FILE *out, struct cil_list *expr) + } + case CIL_CONS_OPERAND: { + const char *operand_str; +- enum cil_flavor operand_flavor = (enum cil_flavor)curr->data; ++ enum cil_flavor operand_flavor = (enum cil_flavor)(uintptr_t)curr->data; + switch (operand_flavor) { + case CIL_CONS_U1: + operand_str = CIL_KEY_CONS_U1; +-- +2.32.0 + diff --git a/SOURCES/0075-libsepol-cil-drop-extra-semicolon.patch b/SOURCES/0075-libsepol-cil-drop-extra-semicolon.patch new file mode 100644 index 0000000..62c59ab --- /dev/null +++ b/SOURCES/0075-libsepol-cil-drop-extra-semicolon.patch @@ -0,0 +1,30 @@ +From 261b655ac20e8a4d21cd420ef70468309dedb097 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:05 +0200 +Subject: [PATCH] libsepol/cil: drop extra semicolon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 908b0336d1dd..71ddada226df 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -4153,7 +4153,7 @@ void cil_destroy_context(struct cil_context *context) + return; + } + +- cil_symtab_datum_destroy(&context->datum);; ++ cil_symtab_datum_destroy(&context->datum); + + if (context->range_str == NULL && context->range != NULL) { + cil_destroy_levelrange(context->range); +-- +2.32.0 + diff --git a/SOURCES/0076-libsepol-cil-drop-dead-store.patch b/SOURCES/0076-libsepol-cil-drop-dead-store.patch new file mode 100644 index 0000000..1cabde7 --- /dev/null +++ b/SOURCES/0076-libsepol-cil-drop-dead-store.patch @@ -0,0 +1,36 @@ +From 0bb89514eba0f34685c87278d600b152b28ea76e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:06 +0200 +Subject: [PATCH] libsepol/cil: drop dead store +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../cil/src/cil_binary.c:2230:24: warning: Value stored to 'cb_node' during its initialization is never read [deadcode.DeadStores] + struct cil_tree_node *cb_node = node->cl_head; + ^~~~~~~ ~~~~~~~~~~~~~ + +Found by clang-analyzer + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_binary.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 85094b01ef9d..601fe8d10ab1 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -2227,7 +2227,7 @@ int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c + int rc = SEPOL_ERR; + struct cil_args_booleanif bool_args; + struct cil_booleanif *cil_boolif = (struct cil_booleanif*)node->data; +- struct cil_tree_node *cb_node = node->cl_head; ++ struct cil_tree_node *cb_node; + struct cil_tree_node *true_node = NULL; + struct cil_tree_node *false_node = NULL; + struct cil_tree_node *tmp_node = NULL; +-- +2.32.0 + diff --git a/SOURCES/0077-libsepol-cil-drop-unnecessary-casts.patch b/SOURCES/0077-libsepol-cil-drop-unnecessary-casts.patch new file mode 100644 index 0000000..b67d201 --- /dev/null +++ b/SOURCES/0077-libsepol-cil-drop-unnecessary-casts.patch @@ -0,0 +1,68 @@ +From 2723b8ec2a84488f00199687d27d1aae5a76c33b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:07 +0200 +Subject: [PATCH] libsepol/cil: drop unnecessary casts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +`const_hashtab_key_t` is a typedef of `const char *`, so these casts are +not needed. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_strpool.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c +index 70bca3630220..e32ee4e90f34 100644 +--- a/libsepol/cil/src/cil_strpool.c ++++ b/libsepol/cil/src/cil_strpool.c +@@ -47,14 +47,13 @@ static hashtab_t cil_strpool_tab = NULL; + + static unsigned int cil_strpool_hash(hashtab_t h, const_hashtab_key_t key) + { +- const char *p, *keyp; ++ const char *p; + size_t size; + unsigned int val; + + val = 0; +- keyp = (const char*)key; +- size = strlen(keyp); +- for (p = keyp; ((size_t) (p - keyp)) < size; p++) ++ size = strlen(key); ++ for (p = key; ((size_t) (p - key)) < size; p++) + val = + (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); + return val & (h->size - 1); +@@ -62,9 +61,7 @@ static unsigned int cil_strpool_hash(hashtab_t h, const_hashtab_key_t key) + + static int cil_strpool_compare(hashtab_t h __attribute__ ((unused)), const_hashtab_key_t key1, const_hashtab_key_t key2) + { +- const char *keyp1 = (const char*)key1; +- const char *keyp2 = (const char*)key2; +- return strcmp(keyp1, keyp2); ++ return strcmp(key1, key2); + } + + char *cil_strpool_add(const char *str) +@@ -73,12 +70,12 @@ char *cil_strpool_add(const char *str) + + pthread_mutex_lock(&cil_strpool_mutex); + +- strpool_ref = hashtab_search(cil_strpool_tab, (hashtab_key_t)str); ++ strpool_ref = hashtab_search(cil_strpool_tab, str); + if (strpool_ref == NULL) { + int rc; + strpool_ref = cil_malloc(sizeof(*strpool_ref)); + strpool_ref->str = cil_strdup(str); +- rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref); ++ rc = hashtab_insert(cil_strpool_tab, strpool_ref->str, strpool_ref); + if (rc != SEPOL_OK) { + pthread_mutex_unlock(&cil_strpool_mutex); + cil_log(CIL_ERR, "Failed to allocate memory\n"); +-- +2.32.0 + diff --git a/SOURCES/0078-libsepol-cil-avoid-using-maybe-uninitialized-variabl.patch b/SOURCES/0078-libsepol-cil-avoid-using-maybe-uninitialized-variabl.patch new file mode 100644 index 0000000..9837b1d --- /dev/null +++ b/SOURCES/0078-libsepol-cil-avoid-using-maybe-uninitialized-variabl.patch @@ -0,0 +1,78 @@ +From 5324a9ab1bf5e6d0dd931ee2342f32193341c601 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:08 +0200 +Subject: [PATCH] libsepol/cil: avoid using maybe uninitialized variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initialize variables, as they are set after goto statements, which jump +to cleanup code using them. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_binary.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 601fe8d10ab1..54d13f2f3945 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -1073,7 +1073,7 @@ int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct ci + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + type_datum_t *sepol_result = NULL; + ebitmap_t src_bitmap, tgt_bitmap; + ebitmap_node_t *node1, *node2; +@@ -1129,7 +1129,7 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + type_datum_t *sepol_result = NULL; + ebitmap_t src_bitmap, tgt_bitmap; + ebitmap_node_t *node1, *node2; +@@ -2338,7 +2338,7 @@ int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c + role_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + role_datum_t *sepol_result = NULL; + role_trans_t *new = NULL; + uint32_t *new_role = NULL; +@@ -3166,7 +3166,7 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_class = NULL; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + range_trans_t *newkey = NULL; + struct mls_range *newdatum = NULL; + ebitmap_t src_bitmap, tgt_bitmap; +@@ -3603,7 +3603,7 @@ int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def) + { + struct cil_list_item *curr; + class_datum_t *sepol_class; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + + cil_list_for_each(curr, def->class_datums) { + struct cil_list_item *c; +@@ -3658,7 +3658,7 @@ int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def) + { + struct cil_list_item *curr; + class_datum_t *sepol_class; +- struct cil_list *class_list; ++ struct cil_list *class_list = NULL; + + cil_list_for_each(curr, def->class_datums) { + struct cil_list_item *c; +-- +2.32.0 + diff --git a/SOURCES/0079-libsepol-drop-repeated-semicolons.patch b/SOURCES/0079-libsepol-drop-repeated-semicolons.patch new file mode 100644 index 0000000..d364cc8 --- /dev/null +++ b/SOURCES/0079-libsepol-drop-repeated-semicolons.patch @@ -0,0 +1,44 @@ +From 811185648af2ec8a6b11b54484cbe9d19ba452fa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:09 +0200 +Subject: [PATCH] libsepol: drop repeated semicolons +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/kernel_to_cil.c | 2 +- + libsepol/src/module.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 5aaee6288565..336d53b09ff9 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -1050,7 +1050,7 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name) + p = catsbuf; + + *p++ = '('; +- remaining--;; ++ remaining--; + + range = 0; + ebitmap_for_each_positive_bit(cats, node, i) { +diff --git a/libsepol/src/module.c b/libsepol/src/module.c +index 836da308f8d3..9b53bc470952 100644 +--- a/libsepol/src/module.c ++++ b/libsepol/src/module.c +@@ -82,7 +82,7 @@ static int policy_file_length(struct policy_file *fp, size_t *out) + break; + case PF_USE_MEMORY: + *out = fp->size; +- break;; ++ break; + default: + *out = 0; + break; +-- +2.32.0 + diff --git a/SOURCES/0080-libsepol-drop-unnecessary-casts.patch b/SOURCES/0080-libsepol-drop-unnecessary-casts.patch new file mode 100644 index 0000000..9e6f68c --- /dev/null +++ b/SOURCES/0080-libsepol-drop-unnecessary-casts.patch @@ -0,0 +1,52 @@ +From 4fbc018a279a39160f17e257017b503194a7f44d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:10 +0200 +Subject: [PATCH] libsepol: drop unnecessary casts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +`hashtab_search()` does take `const_hashtab_key_t` as second parameter, +which is a typedef for `const char *`. +Drop the unnecessary and const-violating cast. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/services.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index f7c31d80f954..47a3dc1419db 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -1182,7 +1182,7 @@ int sepol_string_to_security_class(const char *class_name, + class_datum_t *tclass_datum; + + tclass_datum = hashtab_search(policydb->p_classes.table, +- (hashtab_key_t) class_name); ++ class_name); + if (!tclass_datum) { + ERR(NULL, "unrecognized class %s", class_name); + return STATUS_ERR; +@@ -1211,7 +1211,7 @@ int sepol_string_to_av_perm(sepol_security_class_t tclass, + /* Check for unique perms then the common ones (if any) */ + perm_datum = (perm_datum_t *) + hashtab_search(tclass_datum->permissions.table, +- (hashtab_key_t)perm_name); ++ perm_name); + if (perm_datum != NULL) { + *av = 0x1 << (perm_datum->s.value - 1); + return STATUS_SUCCESS; +@@ -1222,7 +1222,7 @@ int sepol_string_to_av_perm(sepol_security_class_t tclass, + + perm_datum = (perm_datum_t *) + hashtab_search(tclass_datum->comdatum->permissions.table, +- (hashtab_key_t)perm_name); ++ perm_name); + + if (perm_datum != NULL) { + *av = 0x1 << (perm_datum->s.value - 1); +-- +2.32.0 + diff --git a/SOURCES/0081-libsepol-declare-file-local-variable-static.patch b/SOURCES/0081-libsepol-declare-file-local-variable-static.patch new file mode 100644 index 0000000..971c3d5 --- /dev/null +++ b/SOURCES/0081-libsepol-declare-file-local-variable-static.patch @@ -0,0 +1,36 @@ +From 4572bf254a8242898467a41811c8e235209ebdfa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:11 +0200 +Subject: [PATCH] libsepol: declare file local variable static +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Clang issues: + + module_to_cil.c:65:7: warning: no previous extern declaration for non-static variable 'out_file' [-Wmissing-variable-declarations] + FILE *out_file; + ^ + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/module_to_cil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index 580ba06a95b0..21d8e5dbcc39 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -62,7 +62,7 @@ + # define UNUSED(x) UNUSED_ ## x + #endif + +-FILE *out_file; ++static FILE *out_file; + + #define STACK_SIZE 16 + #define DEFAULT_LEVEL "systemlow" +-- +2.32.0 + diff --git a/SOURCES/0082-libsepol-declare-read-only-arrays-const.patch b/SOURCES/0082-libsepol-declare-read-only-arrays-const.patch new file mode 100644 index 0000000..9f79ae6 --- /dev/null +++ b/SOURCES/0082-libsepol-declare-read-only-arrays-const.patch @@ -0,0 +1,225 @@ +From 9fb8df7f1675cef89f32e3dd1a187cc5d53e08e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:59:12 +0200 +Subject: [PATCH] libsepol: declare read-only arrays const +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make it more apparent that those data does not change and enforce it. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/avrule_block.c | 2 +- + libsepol/src/avtab.c | 2 +- + libsepol/src/link.c | 2 +- + libsepol/src/polcaps.c | 2 +- + libsepol/src/policydb.c | 22 +++++++++++----------- + libsepol/src/policydb_internal.h | 2 +- + libsepol/src/private.h | 6 +++--- + libsepol/src/write.c | 8 ++++---- + 8 files changed, 23 insertions(+), 23 deletions(-) + +diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c +index a9832d0d118f..dcfce8b8492c 100644 +--- a/libsepol/src/avrule_block.c ++++ b/libsepol/src/avrule_block.c +@@ -30,7 +30,7 @@ + /* It is anticipated that there be less declarations within an avrule + * block than the global policy. Thus the symbol table sizes are + * smaller than those listed in policydb.c */ +-static unsigned int symtab_sizes[SYM_NUM] = { ++static const unsigned int symtab_sizes[SYM_NUM] = { + 2, + 4, + 8, +diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c +index 257f051a86ec..88e9d510f981 100644 +--- a/libsepol/src/avtab.c ++++ b/libsepol/src/avtab.c +@@ -418,7 +418,7 @@ void avtab_hash_eval(avtab_t * h, char *tag) + } + + /* Ordering of datums in the original avtab format in the policy file. */ +-static uint16_t spec_order[] = { ++static const uint16_t spec_order[] = { + AVTAB_ALLOWED, + AVTAB_AUDITDENY, + AVTAB_AUDITALLOW, +diff --git a/libsepol/src/link.c b/libsepol/src/link.c +index bdc1fcbf59d3..461d2feb8190 100644 +--- a/libsepol/src/link.c ++++ b/libsepol/src/link.c +@@ -78,7 +78,7 @@ typedef struct missing_requirement { + uint32_t perm_value; + } missing_requirement_t; + +-static const char *symtab_names[SYM_NUM] = { ++static const char * const symtab_names[SYM_NUM] = { + "common", "class", "role", "type/attribute", "user", + "bool", "level", "category" + }; +diff --git a/libsepol/src/polcaps.c b/libsepol/src/polcaps.c +index 67ed5786db16..6a74ec7d3c3a 100644 +--- a/libsepol/src/polcaps.c ++++ b/libsepol/src/polcaps.c +@@ -5,7 +5,7 @@ + #include + #include + +-static const char *polcap_names[] = { ++static const char * const polcap_names[] = { + "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */ + "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */ + "extended_socket_class", /* POLICYDB_CAPABILITY_EXTSOCKCLASS */ +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index b4e427af05c8..ef2217c28c91 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -57,10 +57,10 @@ + #include "policydb_validate.h" + + #define POLICYDB_TARGET_SZ ARRAY_SIZE(policydb_target_strings) +-const char *policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING }; ++const char * const policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING }; + + /* These need to be updated if SYM_NUM or OCON_NUM changes */ +-static struct policydb_compat_info policydb_compat[] = { ++static const struct policydb_compat_info policydb_compat[] = { + { + .type = POLICY_KERN, + .version = POLICYDB_VERSION_BOUNDARY, +@@ -460,7 +460,7 @@ static char *symtab_name[SYM_NUM] = { + }; + #endif + +-static unsigned int symtab_sizes[SYM_NUM] = { ++static const unsigned int symtab_sizes[SYM_NUM] = { + 2, + 32, + 16, +@@ -471,12 +471,12 @@ static unsigned int symtab_sizes[SYM_NUM] = { + 16, + }; + +-struct policydb_compat_info *policydb_lookup_compat(unsigned int version, +- unsigned int type, +- unsigned int target_platform) ++const struct policydb_compat_info *policydb_lookup_compat(unsigned int version, ++ unsigned int type, ++ unsigned int target_platform) + { + unsigned int i; +- struct policydb_compat_info *info = NULL; ++ const struct policydb_compat_info *info = NULL; + + for (i = 0; i < sizeof(policydb_compat) / sizeof(*info); i++) { + if (policydb_compat[i].version == version && +@@ -2848,7 +2848,7 @@ static int filename_trans_read(policydb_t *p, struct policy_file *fp) + return 0; + } + +-static int ocontext_read_xen(struct policydb_compat_info *info, ++static int ocontext_read_xen(const struct policydb_compat_info *info, + policydb_t *p, struct policy_file *fp) + { + unsigned int i, j; +@@ -2957,7 +2957,7 @@ static int ocontext_read_xen(struct policydb_compat_info *info, + } + return 0; + } +-static int ocontext_read_selinux(struct policydb_compat_info *info, ++static int ocontext_read_selinux(const struct policydb_compat_info *info, + policydb_t * p, struct policy_file *fp) + { + unsigned int i, j; +@@ -3135,7 +3135,7 @@ static int ocontext_read_selinux(struct policydb_compat_info *info, + return 0; + } + +-static int ocontext_read(struct policydb_compat_info *info, ++static int ocontext_read(const struct policydb_compat_info *info, + policydb_t *p, struct policy_file *fp) + { + int rc = -1; +@@ -4192,7 +4192,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) + uint32_t buf[5]; + size_t len, nprim, nel; + char *policydb_str; +- struct policydb_compat_info *info; ++ const struct policydb_compat_info *info; + unsigned int policy_type, bufindex; + ebitmap_node_t *tnode; + int rc; +diff --git a/libsepol/src/policydb_internal.h b/libsepol/src/policydb_internal.h +index 06ba5c8be144..dd8f25d0fc74 100644 +--- a/libsepol/src/policydb_internal.h ++++ b/libsepol/src/policydb_internal.h +@@ -3,5 +3,5 @@ + + #include + +-extern const char *policydb_target_strings[]; ++extern const char * const policydb_target_strings[]; + #endif +diff --git a/libsepol/src/private.h b/libsepol/src/private.h +index f5b5277f183a..72f212628314 100644 +--- a/libsepol/src/private.h ++++ b/libsepol/src/private.h +@@ -56,9 +56,9 @@ struct policydb_compat_info { + unsigned int target_platform; + }; + +-extern struct policydb_compat_info *policydb_lookup_compat(unsigned int version, +- unsigned int type, +- unsigned int target_platform); ++extern const struct policydb_compat_info *policydb_lookup_compat(unsigned int version, ++ unsigned int type, ++ unsigned int target_platform); + + /* Reading from a policy "file". */ + extern int next_entry(void *buf, struct policy_file *fp, size_t bytes); +diff --git a/libsepol/src/write.c b/libsepol/src/write.c +index 84bcaf3f57ca..3bd034d65cb1 100644 +--- a/libsepol/src/write.c ++++ b/libsepol/src/write.c +@@ -1345,7 +1345,7 @@ static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, + common_write, class_write, role_write, type_write, user_write, + cond_write_bool, sens_write, cat_write,}; + +-static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p, ++static int ocontext_write_xen(const struct policydb_compat_info *info, policydb_t *p, + struct policy_file *fp) + { + unsigned int i, j; +@@ -1453,7 +1453,7 @@ static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p, + return POLICYDB_SUCCESS; + } + +-static int ocontext_write_selinux(struct policydb_compat_info *info, ++static int ocontext_write_selinux(const struct policydb_compat_info *info, + policydb_t *p, struct policy_file *fp) + { + unsigned int i, j; +@@ -1583,7 +1583,7 @@ static int ocontext_write_selinux(struct policydb_compat_info *info, + return POLICYDB_SUCCESS; + } + +-static int ocontext_write(struct policydb_compat_info *info, policydb_t * p, ++static int ocontext_write(const struct policydb_compat_info *info, policydb_t * p, + struct policy_file *fp) + { + int rc = POLICYDB_ERROR; +@@ -2179,7 +2179,7 @@ int policydb_write(policydb_t * p, struct policy_file *fp) + unsigned int i, num_syms; + uint32_t buf[32], config; + size_t items, items2, len; +- struct policydb_compat_info *info; ++ const struct policydb_compat_info *info; + struct policy_data pd; + const char *policydb_str; + +-- +2.32.0 + diff --git a/SOURCES/0083-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch b/SOURCES/0083-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch new file mode 100644 index 0000000..e7c7736 --- /dev/null +++ b/SOURCES/0083-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch @@ -0,0 +1,276 @@ +From 67a8dc8117e0c3887c39f7add8932e4ad23c1d9c Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 16 Jun 2021 17:04:00 -0400 +Subject: [PATCH] libsepol/cil: Allow duplicate optional blocks in most cases + +The commit d155b410d4bbc90d28f361b966f0429598da8188 (libsepol/cil: +Check for duplicate blocks, optionals, and macros) fixed a bug +that allowed duplicate blocks, optionals, and macros with the same +name in the same namespace. For blocks and macros, a duplicate +is always a problem, but optional block names are only used for +in-statement resolution. If no in-statement refers to an optional +block, then it does not matter if more than one with same name +exists. + +One easy way to generate multiple optional blocks with the same +name declaration is to call a macro with an optional block multiple +times in the same namespace. + +As an example, here is a portion of CIL policy + (macro m1 ((type t)) + (optional op1 + (allow t self (CLASS (PERM))) + ) + ) + (type t1) + (call m1 (t1)) + (type t2) + (call m1 (t2)) +This will result in two optional blocks with the name op1. + +There are three parts to allowing multiple optional blocks with +the same name declaration. + +1) Track an optional block's enabled status in a different way. + + One hinderance to allowing multiple optional blocks with the same + name declaration is that they cannot share the same datum. This is + because the datum is used to get the struct cil_optional which has + the enabled field and each block's enabled status is independent of + the others. + + Remove the enabled field from struct cil_optional, so it only contains + the datum. Use a stack to track which optional blocks are being + disabled, so they can be deleted in the right order. + +2) Allow multiple declarations of optional blocks. + + Update cil_allow_multiple_decls() so that a flavor of CIL_OPTIONAL + will return CIL_TRUE. Also remove the check in cil_copy_optional(). + +3) Check if an in-statement refers to an optional with multiple + declarations and exit with an error if it does. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil.c | 1 - + libsepol/cil/src/cil_build_ast.c | 3 ++ + libsepol/cil/src/cil_copy_ast.c | 11 +----- + libsepol/cil/src/cil_internal.h | 1 - + libsepol/cil/src/cil_resolve_ast.c | 55 ++++++++++++++++++------------ + 5 files changed, 37 insertions(+), 34 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 0d351b491c2c..671b5ec6e183 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -2752,7 +2752,6 @@ void cil_call_init(struct cil_call **call) + void cil_optional_init(struct cil_optional **optional) + { + *optional = cil_malloc(sizeof(**optional)); +- (*optional)->enabled = CIL_TRUE; + cil_symtab_datum_init(&(*optional)->datum); + } + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 71ddada226df..ea665a323f78 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -96,6 +96,9 @@ static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, en + return CIL_TRUE; + } + break; ++ case CIL_OPTIONAL: ++ return CIL_TRUE; ++ break; + default: + break; + } +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index 954eab330340..9c0231f294e3 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -1529,19 +1529,10 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void * + return SEPOL_OK; + } + +-int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) ++int cil_copy_optional(__attribute__((unused)) struct cil_db *db, __attribute__((unused)) void *data, void **copy, __attribute__((unused)) symtab_t *symtab) + { +- struct cil_optional *orig = data; +- char *key = orig->datum.name; +- struct cil_symtab_datum *datum = NULL; + struct cil_optional *new; + +- cil_symtab_get_datum(symtab, key, &datum); +- if (datum != NULL) { +- cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); +- return SEPOL_ERR; +- } +- + cil_optional_init(&new); + *copy = new; + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index a77c95201fb7..24be09aa33d8 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -358,7 +358,6 @@ struct cil_in { + + struct cil_optional { + struct cil_symtab_datum datum; +- int enabled; + }; + + struct cil_perm { +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index b5199bad35e2..6d13544c80f7 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -46,12 +46,13 @@ + #include "cil_verify.h" + #include "cil_strpool.h" + #include "cil_symtab.h" ++#include "cil_stack.h" + + struct cil_args_resolve { + struct cil_db *db; + enum cil_pass pass; + uint32_t *changed; +- struct cil_list *disabled_optionals; ++ struct cil_list *to_destroy; + struct cil_tree_node *block; + struct cil_tree_node *macro; + struct cil_tree_node *optional; +@@ -62,6 +63,7 @@ struct cil_args_resolve { + struct cil_list *catorder_lists; + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; ++ struct cil_stack *disabled_optionals; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2552,6 +2554,15 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args) + + block_node = NODE(block_datum); + ++ if (block_node->flavor == CIL_OPTIONAL) { ++ if (block_datum->nodes && block_datum->nodes->head != block_datum->nodes->tail) { ++ cil_tree_log(current, CIL_ERR, "Multiple optional blocks referred to by in-statement"); ++ cil_tree_log(block_node, CIL_ERR, "First optional block"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ } ++ + rc = cil_copy_ast(db, current, block_node); + if (rc != SEPOL_OK) { + cil_tree_log(current, CIL_ERR, "Failed to copy in-statement"); +@@ -3874,6 +3885,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + struct cil_tree_node *macro = args->macro; + struct cil_tree_node *optional = args->optional; + struct cil_tree_node *boolif = args->boolif; ++ struct cil_stack *disabled_optionals = args->disabled_optionals; + + if (node == NULL) { + goto exit; +@@ -3953,22 +3965,14 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + + rc = __cil_resolve_ast_node(node, extra_args); + if (rc == SEPOL_ENOENT) { +- enum cil_log_level lvl = CIL_ERR; +- +- if (optional != NULL) { +- struct cil_optional *opt = (struct cil_optional *)optional->data; +- struct cil_tree_node *opt_node = NODE(opt); +- +- lvl = CIL_INFO; +- /* disable an optional if something failed to resolve */ +- opt->enabled = CIL_FALSE; +- cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); +- cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name); ++ if (optional == NULL) { ++ cil_tree_log(node, CIL_ERR, "Failed to resolve %s statement", cil_node_to_string(node)); ++ } else { ++ cil_stack_push(disabled_optionals, CIL_NODE, optional); ++ cil_tree_log(node, CIL_INFO, "Failed to resolve %s statement", cil_node_to_string(node)); ++ cil_tree_log(optional, CIL_INFO, "Disabling optional '%s'", DATUM(optional->data)->name); + rc = SEPOL_OK; +- goto exit; + } +- +- cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); + goto exit; + } + +@@ -4011,6 +4015,7 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + { + int rc = SEPOL_ERR; + struct cil_args_resolve *args = extra_args; ++ struct cil_stack *disabled_optionals = args->disabled_optionals; + struct cil_tree_node *parent = NULL; + + if (current == NULL || extra_args == NULL) { +@@ -4033,9 +4038,11 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + args->macro = NULL; + } else if (parent->flavor == CIL_OPTIONAL) { + struct cil_tree_node *n = parent->parent; +- if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) { ++ struct cil_stack_item *item = cil_stack_peek(disabled_optionals); ++ if (item && item->data == parent) { ++ cil_stack_pop(disabled_optionals); + *(args->changed) = CIL_TRUE; +- cil_list_append(args->disabled_optionals, CIL_NODE, parent); ++ cil_list_append(args->to_destroy, CIL_NODE, parent); + } + args->optional = NULL; + while (n && n->flavor != CIL_ROOT) { +@@ -4079,14 +4086,17 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.catorder_lists = NULL; + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; ++ extra_args.disabled_optionals = NULL; + +- cil_list_init(&extra_args.disabled_optionals, CIL_NODE); ++ cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.in_list, CIL_IN); ++ cil_stack_init(&extra_args.disabled_optionals); ++ + for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) { + extra_args.pass = pass; + rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args); +@@ -4179,11 +4189,11 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + goto exit; + } + } +- cil_list_for_each(item, extra_args.disabled_optionals) { ++ cil_list_for_each(item, extra_args.to_destroy) { + cil_tree_children_destroy(item->data); + } +- cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); +- cil_list_init(&extra_args.disabled_optionals, CIL_NODE); ++ cil_list_destroy(&extra_args.to_destroy, CIL_FALSE); ++ cil_list_init(&extra_args.to_destroy, CIL_NODE); + changed = 0; + } + } +@@ -4200,8 +4210,9 @@ exit: + __cil_ordered_lists_destroy(&extra_args.catorder_lists); + __cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists); + __cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists); +- cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); ++ cil_list_destroy(&extra_args.to_destroy, CIL_FALSE); + cil_list_destroy(&extra_args.in_list, CIL_FALSE); ++ cil_stack_destroy(&extra_args.disabled_optionals); + + return rc; + } +-- +2.32.0 + diff --git a/SOURCES/0084-libsepol-cil-Properly-check-for-loops-in-sets.patch b/SOURCES/0084-libsepol-cil-Properly-check-for-loops-in-sets.patch new file mode 100644 index 0000000..ce31d00 --- /dev/null +++ b/SOURCES/0084-libsepol-cil-Properly-check-for-loops-in-sets.patch @@ -0,0 +1,136 @@ +From c28525a26fa145cb5fd911fd2a3b9125a275677f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:34:30 -0400 +Subject: [PATCH] libsepol/cil: Properly check for loops in sets + +Commit 61fbdce666f24c4a118b249ece6b014d54b65074 (ibsepol/cil: Check +for self-referential loops in sets) added checks for self-referential +loops in user, role, type, and category sets. Unfortunately, this +check ends up in an infinite loop if the set with the self-referential +loop is used in a different set that is checked before the bad set. + +The problem with the old check is that only the initial datum is used +for the check. Instead, use a stack to track all of the set datums +that are currently involved as the check is made. A self-referential +loop occurs if a duplicate datum is found for any of the datums in the +stack. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_verify.c | 48 +++++++++++++++++++++++------------ + 1 file changed, 32 insertions(+), 16 deletions(-) + +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 8e15a0e68a69..59397f70f2ea 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -44,6 +44,7 @@ + #include "cil_tree.h" + #include "cil_list.h" + #include "cil_find.h" ++#include "cil_stack.h" + + #include "cil_verify.h" + +@@ -430,9 +431,9 @@ int cil_verify_decl_does_not_shadow_macro_parameter(struct cil_macro *macro, str + return SEPOL_OK; + } + +-static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_symtab_datum *orig); ++static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_stack *stack); + +-static int __verify_no_self_reference_in_expr(struct cil_list *expr, struct cil_symtab_datum *orig) ++static int __verify_no_self_reference_in_expr(struct cil_list *expr, struct cil_stack *stack) + { + struct cil_list_item *item; + int rc = SEPOL_OK; +@@ -444,9 +445,9 @@ static int __verify_no_self_reference_in_expr(struct cil_list *expr, struct cil_ + cil_list_for_each(item, expr) { + if (item->flavor == CIL_DATUM) { + struct cil_symtab_datum* datum = item->data; +- rc = cil_verify_no_self_reference(FLAVOR(datum), datum, orig); ++ rc = cil_verify_no_self_reference(FLAVOR(datum), datum, stack); + } else if (item->flavor == CIL_LIST) { +- rc = __verify_no_self_reference_in_expr(item->data, orig); ++ rc = __verify_no_self_reference_in_expr(item->data, stack); + } + if (rc != SEPOL_OK) { + return SEPOL_ERR; +@@ -456,36 +457,47 @@ static int __verify_no_self_reference_in_expr(struct cil_list *expr, struct cil_ + return SEPOL_OK; + } + +-static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_symtab_datum *orig) ++static int cil_verify_no_self_reference(enum cil_flavor flavor, struct cil_symtab_datum *datum, struct cil_stack *stack) + { ++ struct cil_stack_item *item; ++ int i = 0; + int rc = SEPOL_OK; + +- if (datum == orig) { +- cil_tree_log(NODE(orig), CIL_ERR, "Self-reference found for %s", orig->name); +- return SEPOL_ERR; +- } else if (orig == NULL) { +- orig = datum; ++ cil_stack_for_each(stack, i, item) { ++ struct cil_symtab_datum *prev = item->data; ++ if (datum == prev) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Self-reference found for %s", datum->name); ++ return SEPOL_ERR; ++ } + } + + switch (flavor) { + case CIL_USERATTRIBUTE: { + struct cil_userattribute *attr = (struct cil_userattribute *)datum; +- rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ cil_stack_push(stack, CIL_DATUM, datum); ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, stack); ++ cil_stack_pop(stack); + break; + } + case CIL_ROLEATTRIBUTE: { + struct cil_roleattribute *attr = (struct cil_roleattribute *)datum; +- rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ cil_stack_push(stack, CIL_DATUM, datum); ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, stack); ++ cil_stack_pop(stack); + break; + } + case CIL_TYPEATTRIBUTE: { + struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; +- rc = __verify_no_self_reference_in_expr(attr->expr_list, orig); ++ cil_stack_push(stack, CIL_DATUM, datum); ++ rc = __verify_no_self_reference_in_expr(attr->expr_list, stack); ++ cil_stack_pop(stack); + break; + } + case CIL_CATSET: { + struct cil_catset *set = (struct cil_catset *)datum; +- rc = __verify_no_self_reference_in_expr(set->cats->datum_expr, orig); ++ cil_stack_push(stack, CIL_DATUM, datum); ++ rc = __verify_no_self_reference_in_expr(set->cats->datum_expr, stack); ++ cil_stack_pop(stack); + break; + } + default: +@@ -1826,9 +1838,13 @@ int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __at + case CIL_USERATTRIBUTE: + case CIL_ROLEATTRIBUTE: + case CIL_TYPEATTRIBUTE: +- case CIL_CATSET: +- rc = cil_verify_no_self_reference(node->flavor, node->data, NULL); ++ case CIL_CATSET: { ++ struct cil_stack *stack; ++ cil_stack_init(&stack); ++ rc = cil_verify_no_self_reference(node->flavor, node->data, stack); ++ cil_stack_destroy(&stack); + break; ++ } + default: + rc = SEPOL_OK; + break; +-- +2.32.0 + diff --git a/SOURCES/0085-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch b/SOURCES/0085-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch new file mode 100644 index 0000000..0771ee3 --- /dev/null +++ b/SOURCES/0085-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch @@ -0,0 +1,55 @@ +From ac8b35d910750b56d38d54f312a712a73c95749c Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:34:33 -0400 +Subject: [PATCH] libsepol/cil: Fix syntax checking of defaultrange rule + +When "glblub" was added as a default for the defaultrange rule, the +syntax array was updated because the "glblub" default does not need +to specify a range of "low", "high", or "low-high". Unfortunately, +additional checking was not added for the "source" and "target" +defaults to make sure they specified a range. This means that using +the "source" or "target" defaults without specifying the range will +result in a segfault. + +When the "source" or "target" defaults are used, check that the rule +specifies a range as well. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index ea665a323f78..baed3e581be4 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5886,6 +5886,11 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no + + object = parse_current->next->next->data; + if (object == CIL_KEY_SOURCE) { ++ if (!parse_current->next->next->next) { ++ cil_log(CIL_ERR, "Missing 'low', 'high', or 'low-high'\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + range = parse_current->next->next->next->data; + if (range == CIL_KEY_LOW) { + def->object_range = CIL_DEFAULT_SOURCE_LOW; +@@ -5899,6 +5904,11 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no + goto exit; + } + } else if (object == CIL_KEY_TARGET) { ++ if (!parse_current->next->next->next) { ++ cil_log(CIL_ERR, "Missing 'low', 'high', or 'low-high'\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + range = parse_current->next->next->next->data; + if (range == CIL_KEY_LOW) { + def->object_range = CIL_DEFAULT_TARGET_LOW; +-- +2.32.0 + diff --git a/SOURCES/0086-libsepol-cil-Check-for-empty-list-when-marking-never.patch b/SOURCES/0086-libsepol-cil-Check-for-empty-list-when-marking-never.patch new file mode 100644 index 0000000..b8a43db --- /dev/null +++ b/SOURCES/0086-libsepol-cil-Check-for-empty-list-when-marking-never.patch @@ -0,0 +1,35 @@ +From f33745a22b4133c59059356a23dbbc229067e3c1 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:56:43 -0400 +Subject: [PATCH] libsepol/cil: Check for empty list when marking neverallow + attributes + +When marking a type attribute as used in a neverallow (to help determine +whether or not it should be expanded), check if the attribute's expression +list is empty (no attributes are associated with it) before iterating +over the list. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_post.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index 7bca0834ad39..7e2c2b9a85c3 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -1494,6 +1494,10 @@ static void __mark_neverallow_attrs(struct cil_list *expr_list) + { + struct cil_list_item *curr; + ++ if (!expr_list) { ++ return; ++ } ++ + cil_list_for_each(curr, expr_list) { + if (curr->flavor == CIL_DATUM) { + if (FLAVOR(curr->data) == CIL_TYPEATTRIBUTE) { +-- +2.32.0 + diff --git a/SOURCES/0087-libsepol-cil-Reduce-the-initial-symtab-sizes-for-blo.patch b/SOURCES/0087-libsepol-cil-Reduce-the-initial-symtab-sizes-for-blo.patch new file mode 100644 index 0000000..3cc8a15 --- /dev/null +++ b/SOURCES/0087-libsepol-cil-Reduce-the-initial-symtab-sizes-for-blo.patch @@ -0,0 +1,36 @@ +From 36e494573d7071f9b56670b4777ed14637025d9e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:56:49 -0400 +Subject: [PATCH] libsepol/cil: Reduce the initial symtab sizes for blocks + +It is possible to create bad behaving policy that can consume all +of a system's memory (one way is through the use of inheritance). +Analyzing these policies shows that most of the memory usage is for +the block symtabs. + +Most of the nineteen symtabs will most likely never be used, so give +these symtabs an initial size of 1. The others are given more +appropriate sizes. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 671b5ec6e183..9d5038d91add 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -54,7 +54,7 @@ + + int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = { + {64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, +- {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, ++ {8, 8, 8, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} +-- +2.32.0 + diff --git a/SOURCES/0088-libsepol-cil-Improve-degenerate-inheritance-check.patch b/SOURCES/0088-libsepol-cil-Improve-degenerate-inheritance-check.patch new file mode 100644 index 0000000..db35a64 --- /dev/null +++ b/SOURCES/0088-libsepol-cil-Improve-degenerate-inheritance-check.patch @@ -0,0 +1,362 @@ +From 37863b0b1444c85a1ddc6c333c8bfea0c678c592 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:56:55 -0400 +Subject: [PATCH] libsepol/cil: Improve degenerate inheritance check + +The commit 74d00a8decebf940d95064ff60042dcb2cbcc2c0 (libsepol/cil: +Detect degenerate inheritance and exit with an error) detects the +use of inheritance (mostly by the secilc-fuzzer and not in any real +policies) that results in the exponential growth of the policy through +the copying of blocks that takes place with inheritance in CIL. +Unfortunately, the check takes place during the pass when all the +blocks are being copied, so it is possible to consume all of a system's +memory before an error is produced. + +The new check happens in two parts. First, a check is made while the +block inheritance is being linked to the block it will inherit. In +this check, all of the parent nodes of the inheritance rule up to the +root node are checked and if enough of these blocks are being inherited +(>= CIL_DEGENERATE_INHERITANCE_DEPTH), then a flag is set for a more +in-depth check after the pass. This in-depth check will determine the +number of potential inheritances that will occur when resolving the +all of the inheritance rules. If this value is greater than +CIL_DEGENERATE_INHERITANCE_GROWTH * the original number of inheritance +rules and greater than CIL_DEGENERATE_INHERITANCE_MINIMUM (which is +set to 0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH), then degenerate +inheritance is determined to have occurred and an error result will +be returned. + +Since the potential number of inheritances can quickly be an extremely +large number, the count of potential inheritances is aborted as soon +as the threshold for degenerate inheritance has been exceeded. + +Normal policies should rarely, if ever, have the in-depth check occur. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_internal.h | 5 +- + libsepol/cil/src/cil_resolve_ast.c | 226 +++++++++++++++++++---------- + 2 files changed, 151 insertions(+), 80 deletions(-) + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 24be09aa33d8..8b9aeabf66e4 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -48,8 +48,9 @@ + + #define CIL_MAX_NAME_LENGTH 2048 + +-#define CIL_DEGENERATE_INHERITANCE_DEPTH 12 +-#define CIL_DEGENERATE_INHERITANCE_BREADTH (0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH) ++#define CIL_DEGENERATE_INHERITANCE_DEPTH 10UL ++#define CIL_DEGENERATE_INHERITANCE_MINIMUM (0x01 << CIL_DEGENERATE_INHERITANCE_DEPTH) ++#define CIL_DEGENERATE_INHERITANCE_GROWTH 10UL + + enum cil_pass { + CIL_PASS_INIT = 0, +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 6d13544c80f7..5245cc1556bd 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -64,6 +64,7 @@ struct cil_args_resolve { + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; + struct cil_stack *disabled_optionals; ++ int *inheritance_check; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2308,40 +2309,7 @@ exit: + return rc; + } + +-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; +- struct cil_tree_node *node = NULL; +- int rc = SEPOL_ERR; +- +- rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- +- node = NODE(block_datum); +- +- if (node->flavor != CIL_BLOCK) { +- cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node)); +- rc = SEPOL_ERR; +- goto exit; +- } +- +- inherit->block = (struct cil_block *)block_datum; +- +- if (inherit->block->bi_nodes == NULL) { +- cil_list_init(&inherit->block->bi_nodes, CIL_NODE); +- } +- cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); +- +- return SEPOL_OK; +- +-exit: +- return rc; +-} +- +-void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) ++static void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) + { + struct cil_list *trace = NULL; + struct cil_list_item *item = NULL; +@@ -2379,7 +2347,7 @@ void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_ + cil_list_destroy(&trace, CIL_FALSE); + } + +-int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) ++static int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) + { + struct cil_tree_node *curr = NULL; + struct cil_blockinherit *bi = NULL; +@@ -2412,53 +2380,67 @@ exit: + return rc; + } + +-/* +- * Detect degenerate inheritance of the form: +- * ... +- * (blockinherit ba) +- * (block ba +- * (block b1 +- * (blockinherit bb) +- * ) +- * (block bb +- * (block b2 +- * (blockinherit bc) +- * ) +- * (block bc +- * ... +- */ +-static int cil_check_for_degenerate_inheritance(struct cil_tree_node *current) ++static int cil_possible_degenerate_inheritance(struct cil_tree_node *node) + { +- struct cil_block *block = current->data; +- struct cil_tree_node *node; +- struct cil_list_item *item; +- unsigned depth; +- unsigned breadth = 0; ++ unsigned depth = 1; + +- cil_list_for_each(item, block->bi_nodes) { +- breadth++; +- } +- +- if (breadth >= CIL_DEGENERATE_INHERITANCE_BREADTH) { +- node = current->parent; +- depth = 0; +- while (node && node->flavor != CIL_ROOT) { +- if (node->flavor == CIL_BLOCK) { +- block = node->data; +- if (block->bi_nodes != NULL) { +- depth++; ++ node = node->parent; ++ while (node && node->flavor != CIL_ROOT) { ++ if (node->flavor == CIL_BLOCK) { ++ if (((struct cil_block *)(node->data))->bi_nodes != NULL) { ++ depth++; ++ if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { ++ return CIL_TRUE; + } + } +- node = node->parent; + } ++ node = node->parent; ++ } + +- if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { +- cil_tree_log(current, CIL_ERR, "Degenerate inheritance detected (depth=%u, breadth=%u)", depth, breadth); +- return SEPOL_ERR; +- } ++ return CIL_FALSE; ++} ++ ++int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) ++{ ++ struct cil_args_resolve *args = extra_args; ++ struct cil_blockinherit *inherit = current->data; ++ struct cil_symtab_datum *block_datum = NULL; ++ struct cil_tree_node *node = NULL; ++ int rc = SEPOL_ERR; ++ ++ rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ node = NODE(block_datum); ++ ++ if (node->flavor != CIL_BLOCK) { ++ cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node)); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ ++ inherit->block = (struct cil_block *)block_datum; ++ ++ rc = cil_check_recursive_blockinherit(current); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ if (inherit->block->bi_nodes == NULL) { ++ cil_list_init(&inherit->block->bi_nodes, CIL_NODE); ++ } ++ cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); ++ ++ if (*(args->inheritance_check) == CIL_FALSE) { ++ *(args->inheritance_check) = cil_possible_degenerate_inheritance(node); + } + + return SEPOL_OK; ++ ++exit: ++ return rc; + } + + int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) +@@ -2477,11 +2459,6 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + + db = args->db; + +- rc = cil_check_for_degenerate_inheritance(current); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + // Make sure this is the original block and not a merged block from a blockinherit + if (current != block->datum.nodes->head->data) { + rc = SEPOL_OK; +@@ -3597,6 +3574,88 @@ exit: + return rc; + } + ++/* ++ * Degenerate inheritance leads to exponential growth of the policy ++ * It can take many forms, but here is one example. ++ * ... ++ * (blockinherit ba) ++ * (block b0 ++ * (block b1 ++ * (block b2 ++ * (block b3 ++ * ... ++ * ) ++ * (blockinherit b3) ++ * ) ++ * (blockinherit b2) ++ * ) ++ * (blockinherit b1) ++ * ) ++ * (blockinherit b0) ++ * ... ++ * This leads to 2^4 copies of the content of block b3, 2^3 copies of the ++ * contents of block b2, etc. ++ */ ++static unsigned cil_count_actual(struct cil_tree_node *node) ++{ ++ unsigned count = 0; ++ ++ if (node->flavor == CIL_BLOCKINHERIT) { ++ count += 1; ++ } ++ ++ for (node = node->cl_head; node; node = node->next) { ++ count += cil_count_actual(node); ++ } ++ ++ return count; ++} ++ ++static unsigned cil_count_potential(struct cil_tree_node *node, unsigned max) ++{ ++ unsigned count = 0; ++ ++ if (node->flavor == CIL_BLOCKINHERIT) { ++ struct cil_blockinherit *bi = node->data; ++ count += 1; ++ if (bi->block) { ++ count += cil_count_potential(NODE(bi->block), max); ++ if (count > max) { ++ return count; ++ } ++ } ++ } ++ ++ for (node = node->cl_head; node; node = node->next) { ++ count += cil_count_potential(node, max); ++ if (count > max) { ++ return count; ++ } ++ } ++ ++ return count; ++} ++ ++static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) ++{ ++ uint64_t num_actual, num_potential, max; ++ ++ num_actual = cil_count_actual(node); ++ ++ max = num_actual * CIL_DEGENERATE_INHERITANCE_GROWTH; ++ if (max < CIL_DEGENERATE_INHERITANCE_MINIMUM) { ++ max = CIL_DEGENERATE_INHERITANCE_MINIMUM; ++ } ++ ++ num_potential = cil_count_potential(node, max); ++ ++ if (num_potential > max) { ++ return SEPOL_ERR; ++ } ++ ++ return SEPOL_OK; ++} ++ + int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) + { + int rc = SEPOL_OK; +@@ -4068,6 +4127,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + struct cil_args_resolve extra_args; + enum cil_pass pass = CIL_PASS_TIF; + uint32_t changed = 0; ++ int inheritance_check = 0; + + if (db == NULL || current == NULL) { + return rc; +@@ -4087,6 +4147,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; + extra_args.disabled_optionals = NULL; ++ extra_args.inheritance_check = &inheritance_check; + + cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); +@@ -4113,6 +4174,15 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + cil_list_destroy(&extra_args.in_list, CIL_FALSE); + } + ++ if (pass == CIL_PASS_BLKIN_LINK && inheritance_check == CIL_TRUE) { ++ rc = cil_check_for_degenerate_inheritance(current); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Degenerate inheritance detected\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ } ++ + if (pass == CIL_PASS_MISC1) { + db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL); + if (db->sidorder == NULL) { +-- +2.32.0 + diff --git a/SOURCES/0089-libsepol-cil-Add-function-to-determine-if-a-subtree-.patch b/SOURCES/0089-libsepol-cil-Add-function-to-determine-if-a-subtree-.patch new file mode 100644 index 0000000..066403e --- /dev/null +++ b/SOURCES/0089-libsepol-cil-Add-function-to-determine-if-a-subtree-.patch @@ -0,0 +1,58 @@ +From 20271849d5e16fd3a3dd9c0db7d19fae18cf1f4c Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 24 Jun 2021 15:58:14 -0400 +Subject: [PATCH] libsepol/cil: Add function to determine if a subtree has a + declaration + +Create the function cil_tree_subtree_has_decl() that returns CIL_TRUE +if the subtree has a declaration in it and CIL_FALSE otherwise. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_tree.c | 16 ++++++++++++++++ + libsepol/cil/src/cil_tree.h | 2 ++ + 2 files changed, 18 insertions(+) + +diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c +index 067268eb897c..4cf8dcc8b280 100644 +--- a/libsepol/cil/src/cil_tree.c ++++ b/libsepol/cil/src/cil_tree.c +@@ -136,6 +136,22 @@ __attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *n + cil_log(lvl,"\n"); + } + ++int cil_tree_subtree_has_decl(struct cil_tree_node *node) ++{ ++ while (node) { ++ if (node->flavor >= CIL_MIN_DECLARATIVE) { ++ return CIL_TRUE; ++ } ++ if (node->cl_head != NULL) { ++ if (cil_tree_subtree_has_decl(node->cl_head)) ++ return CIL_TRUE; ++ } ++ node = node->next; ++ } ++ ++ return CIL_FALSE; ++} ++ + int cil_tree_init(struct cil_tree **tree) + { + struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree)); +diff --git a/libsepol/cil/src/cil_tree.h b/libsepol/cil/src/cil_tree.h +index bac9f1e47f2c..f4d2207153ce 100644 +--- a/libsepol/cil/src/cil_tree.h ++++ b/libsepol/cil/src/cil_tree.h +@@ -54,6 +54,8 @@ struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char ** + char *cil_tree_get_cil_path(struct cil_tree_node *node); + __attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...); + ++int cil_tree_subtree_has_decl(struct cil_tree_node *node); ++ + int cil_tree_init(struct cil_tree **tree); + void cil_tree_destroy(struct cil_tree **tree); + void cil_tree_subtree_destroy(struct cil_tree_node *node); +-- +2.32.0 + diff --git a/SOURCES/0090-libsepol-cil-Only-reset-AST-if-optional-has-a-declar.patch b/SOURCES/0090-libsepol-cil-Only-reset-AST-if-optional-has-a-declar.patch new file mode 100644 index 0000000..784d9e8 --- /dev/null +++ b/SOURCES/0090-libsepol-cil-Only-reset-AST-if-optional-has-a-declar.patch @@ -0,0 +1,92 @@ +From 4ff514a33e2442ba7dac7e96fc7e371898eed316 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 24 Jun 2021 15:58:15 -0400 +Subject: [PATCH] libsepol/cil: Only reset AST if optional has a declaration + +When disabling optionals, the AST needs to be reset only if one +of the optional blocks being disabled contains a declaration. + +Call the function cil_tree_subtree_has_decl() for each optional +block being disabled and only reset the AST if one of them has +a declaration in it. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 58 +++++++++++++++++------------- + 1 file changed, 34 insertions(+), 24 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 5245cc1556bd..0ea5b1697dd2 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4230,33 +4230,43 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + if (changed) { + struct cil_list_item *item; + if (pass > CIL_PASS_CALL1) { +- /* Need to re-resolve because an optional was disabled that contained +- * one or more declarations. We only need to reset to the call1 pass +- * because things done in the preceding passes aren't allowed in +- * optionals, and thus can't be disabled. +- * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment +- * it to CIL_PASS_CALL2 +- */ +- cil_log(CIL_INFO, "Resetting declarations\n"); +- +- if (pass >= CIL_PASS_MISC1) { +- __cil_ordered_lists_reset(&extra_args.sidorder_lists); +- __cil_ordered_lists_reset(&extra_args.classorder_lists); +- __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); +- __cil_ordered_lists_reset(&extra_args.catorder_lists); +- __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); +- cil_list_destroy(&db->sidorder, CIL_FALSE); +- cil_list_destroy(&db->classorder, CIL_FALSE); +- cil_list_destroy(&db->catorder, CIL_FALSE); +- cil_list_destroy(&db->sensitivityorder, CIL_FALSE); ++ int has_decls = CIL_FALSE; ++ ++ cil_list_for_each(item, extra_args.to_destroy) { ++ has_decls = cil_tree_subtree_has_decl(item->data); ++ if (has_decls) { ++ break; ++ } + } + +- pass = CIL_PASS_CALL1; ++ if (has_decls) { ++ /* Need to re-resolve because an optional was disabled that ++ * contained one or more declarations. ++ * Everything that needs to be reset comes after the ++ * CIL_PASS_CALL2 pass. We set pass to CIL_PASS_CALL1 because ++ * the pass++ will increment it to CIL_PASS_CALL2 ++ */ ++ cil_log(CIL_INFO, "Resetting declarations\n"); ++ ++ if (pass >= CIL_PASS_MISC1) { ++ __cil_ordered_lists_reset(&extra_args.sidorder_lists); ++ __cil_ordered_lists_reset(&extra_args.classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.catorder_lists); ++ __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); ++ cil_list_destroy(&db->sidorder, CIL_FALSE); ++ cil_list_destroy(&db->classorder, CIL_FALSE); ++ cil_list_destroy(&db->catorder, CIL_FALSE); ++ cil_list_destroy(&db->sensitivityorder, CIL_FALSE); ++ } + +- rc = cil_reset_ast(current); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to reset declarations\n"); +- goto exit; ++ pass = CIL_PASS_CALL1; ++ ++ rc = cil_reset_ast(current); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to reset declarations\n"); ++ goto exit; ++ } + } + } + cil_list_for_each(item, extra_args.to_destroy) { +-- +2.32.0 + diff --git a/SOURCES/0091-libsepol-cil-make-array-cil_sym_sizes-const.patch b/SOURCES/0091-libsepol-cil-make-array-cil_sym_sizes-const.patch new file mode 100644 index 0000000..5b8780e --- /dev/null +++ b/SOURCES/0091-libsepol-cil-make-array-cil_sym_sizes-const.patch @@ -0,0 +1,60 @@ +From af75f64194c0f81c61f84305ddc8eb494de30e95 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sat, 26 Jun 2021 14:34:43 +0200 +Subject: [PATCH] libsepol/cil: make array cil_sym_sizes const + +The values of this table are never modified. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil.c | 4 ++-- + libsepol/cil/src/cil_internal.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 9d5038d91add..32e8b3cf419e 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -52,7 +52,7 @@ + #include "cil_strpool.h" + #include "cil_write_ast.h" + +-int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = { ++const int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = { + {64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, + {8, 8, 8, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, +@@ -1882,7 +1882,7 @@ void cil_set_policy_version(struct cil_db *db, int policy_version) + db->policy_version = policy_version; + } + +-void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM]) ++void cil_symtab_array_init(symtab_t symtab[], const int symtab_sizes[CIL_SYM_NUM]) + { + uint32_t i = 0; + for (i = 0; i < CIL_SYM_NUM; i++) { +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 8b9aeabf66e4..3211fc355ec9 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -275,7 +275,7 @@ enum cil_sym_array { + CIL_SYM_ARRAY_NUM + }; + +-extern int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM]; ++extern const int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM]; + + #define CIL_CLASS_SYM_SIZE 256 + #define CIL_PERMS_PER_CLASS (sizeof(sepol_access_vector_t) * 8) +@@ -981,7 +981,7 @@ int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size); + int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size); + int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size); + +-void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM]); ++void cil_symtab_array_init(symtab_t symtab[], const int symtab_sizes[CIL_SYM_NUM]); + void cil_symtab_array_destroy(symtab_t symtab[]); + void cil_destroy_ast_symtabs(struct cil_tree_node *root); + int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index); +-- +2.32.0 + diff --git a/SOURCES/0092-libsepol-cil-Provide-option-to-allow-qualified-names.patch b/SOURCES/0092-libsepol-cil-Provide-option-to-allow-qualified-names.patch new file mode 100644 index 0000000..3c9c28f --- /dev/null +++ b/SOURCES/0092-libsepol-cil-Provide-option-to-allow-qualified-names.patch @@ -0,0 +1,244 @@ +From a0914acf2a128bdfd30ca0ee964a1e88ddb6439e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 29 Jun 2021 11:13:59 -0400 +Subject: [PATCH] libsepol/cil: Provide option to allow qualified names in + declarations + +Qualified names have "dots" in them. They are generated when a CIL +policy is compiled and come from declarations in blocks. If a kernel +policy is decompiled into a CIL policy, the resulting policy could +have declarations that use qualified names. Compiling this policy would +result in an error because "dots" in declarations are not allowed. + +Qualified names in a policy are normally used to refer to the name of +identifiers, blocks, macros, or optionals that are declared in a +different block (that is not a parent). Name resolution is based on +splitting a name based on the "dots", searching the parents up to the +global namespace for the first block using the first part of the name, +using the second part of the name to lookup the next block using the +first block's symbol tables, looking up the third block in the second's +symbol tables, and so on. + +To allow the option of using qualified names in declarations: + +1) Create a field in the struct cil_db called "qualified_names" which +is set to CIL_TRUE when qualified names are to be used. This field is +checked in cil_verify_name() and "dots" are allowed if qualified names +are being allowed. + +2) Only allow the direct lookup of the whole name in the global symbol +table. This means that blocks, blockinherits, blockabstracts, and in- +statements cannot be allowed. Use the "qualified_names" field of the +cil_db to know when using one of these should result in an error. + +3) Create the function cil_set_qualified_names() that is used to set +the "qualified_names" field. Export the function in libsepol. + +Signed-off-by: James Carter +--- + libsepol/cil/include/cil/cil.h | 1 + + libsepol/cil/src/cil.c | 6 ++++++ + libsepol/cil/src/cil_build_ast.c | 24 ++++++++++++++++++++++-- + libsepol/cil/src/cil_internal.h | 1 + + libsepol/cil/src/cil_resolve_ast.c | 4 ++-- + libsepol/cil/src/cil_verify.c | 19 ++++++++++++++----- + libsepol/cil/src/cil_verify.h | 2 +- + libsepol/src/libsepol.map.in | 1 + + 8 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h +index 92fac6e1619a..482ca522277b 100644 +--- a/libsepol/cil/include/cil/cil.h ++++ b/libsepol/cil/include/cil/cil.h +@@ -51,6 +51,7 @@ extern int cil_selinuxusers_to_string(cil_db_t *db, char **out, size_t *size); + extern int cil_filecons_to_string(cil_db_t *db, char **out, size_t *size); + extern void cil_set_disable_dontaudit(cil_db_t *db, int disable_dontaudit); + extern void cil_set_multiple_decls(cil_db_t *db, int multiple_decls); ++extern void cil_set_qualified_names(struct cil_db *db, int qualified_names); + extern void cil_set_disable_neverallow(cil_db_t *db, int disable_neverallow); + extern void cil_set_preserve_tunables(cil_db_t *db, int preserve_tunables); + extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown); +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 32e8b3cf419e..d24c81c89337 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -440,6 +440,7 @@ void cil_db_init(struct cil_db **db) + (*db)->handle_unknown = -1; + (*db)->mls = -1; + (*db)->multiple_decls = CIL_FALSE; ++ (*db)->qualified_names = CIL_FALSE; + (*db)->target_platform = SEPOL_TARGET_SELINUX; + (*db)->policy_version = POLICYDB_VERSION_MAX; + } +@@ -1872,6 +1873,11 @@ void cil_set_multiple_decls(struct cil_db *db, int multiple_decls) + db->multiple_decls = multiple_decls; + } + ++void cil_set_qualified_names(struct cil_db *db, int qualified_names) ++{ ++ db->qualified_names = qualified_names; ++} ++ + void cil_set_target_platform(struct cil_db *db, int target_platform) + { + db->target_platform = target_platform; +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index baed3e581be4..9da90883e85a 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -146,7 +146,7 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + int rc = SEPOL_ERR; + symtab_t *symtab = NULL; + +- rc = cil_verify_name((const char*)key, nflavor); ++ rc = cil_verify_name(db, (const char*)key, nflavor); + if (rc != SEPOL_OK) { + goto exit; + } +@@ -204,6 +204,11 @@ int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct + goto exit; + } + ++ if (db->qualified_names) { ++ cil_log(CIL_ERR, "Blocks are not allowed when the option for qualified names is used\n"); ++ goto exit; ++ } ++ + rc = __cil_verify_syntax(parse_current, syntax, syntax_len); + if (rc != SEPOL_OK) { + goto exit; +@@ -274,6 +279,11 @@ int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, + goto exit; + } + ++ if (db->qualified_names) { ++ cil_log(CIL_ERR, "Block inherit rules are not allowed when the option for qualified names is used\n"); ++ goto exit; ++ } ++ + rc = __cil_verify_syntax(parse_current, syntax, syntax_len); + if (rc != SEPOL_OK) { + goto exit; +@@ -331,6 +341,11 @@ int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current + goto exit; + } + ++ if (db->qualified_names) { ++ cil_log(CIL_ERR, "Block abstract rules are not allowed when the option for qualified names is used\n"); ++ goto exit; ++ } ++ + rc = __cil_verify_syntax(parse_current, syntax, syntax_len); + if (rc != SEPOL_OK) { + goto exit; +@@ -376,6 +391,11 @@ int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct ci + goto exit; + } + ++ if (db->qualified_names) { ++ cil_log(CIL_ERR, "In-statements are not allowed when the option for qualified names is used\n"); ++ goto exit; ++ } ++ + rc = __cil_verify_syntax(parse_current, syntax, syntax_len); + if (rc != SEPOL_OK) { + goto exit; +@@ -5261,7 +5281,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + + param->str = current_item->cl_head->next->data; + +- rc = cil_verify_name(param->str, param->flavor); ++ rc = cil_verify_name(db, param->str, param->flavor); + if (rc != SEPOL_OK) { + cil_destroy_param(param); + goto exit; +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 3211fc355ec9..98e303d14e84 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -321,6 +321,7 @@ struct cil_db { + int handle_unknown; + int mls; + int multiple_decls; ++ int qualified_names; + int target_platform; + int policy_version; + }; +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 0ea5b1697dd2..32ea64e39b21 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4419,8 +4419,8 @@ int cil_resolve_name_keep_aliases(struct cil_tree_node *ast_node, char *name, en + + *datum = NULL; + +- if (strchr(name,'.') == NULL) { +- /* No '.' in name */ ++ if (db->qualified_names || strchr(name,'.') == NULL) { ++ /* Using qualified names or No '.' in name */ + rc = __cil_resolve_name_helper(db, ast_node->parent, name, sym_index, datum); + if (rc != SEPOL_OK) { + goto exit; +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 59397f70f2ea..ce3fcd8c81c9 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -92,7 +92,7 @@ static int __cil_is_reserved_name(const char *name, enum cil_flavor flavor) + return CIL_FALSE; + } + +-int cil_verify_name(const char *name, enum cil_flavor flavor) ++int cil_verify_name(const struct cil_db *db, const char *name, enum cil_flavor flavor) + { + int rc = SEPOL_ERR; + int len; +@@ -116,10 +116,19 @@ int cil_verify_name(const char *name, enum cil_flavor flavor) + goto exit; + } + +- for (i = 1; i < len; i++) { +- if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') { +- cil_log(CIL_ERR, "Invalid character \"%c\" in %s\n", name[i], name); +- goto exit; ++ if (db->qualified_names == CIL_FALSE) { ++ for (i = 1; i < len; i++) { ++ if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') { ++ cil_log(CIL_ERR, "Invalid character \"%c\" in %s\n", name[i], name); ++ goto exit; ++ } ++ } ++ } else { ++ for (i = 1; i < len; i++) { ++ if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-' && name[i] != '.') { ++ cil_log(CIL_ERR, "Invalid character \"%c\" in %s\n", name[i], name); ++ goto exit; ++ } + } + } + +diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h +index 4ea14f5b0a9a..26e195a94c7e 100644 +--- a/libsepol/cil/src/cil_verify.h ++++ b/libsepol/cil/src/cil_verify.h +@@ -56,7 +56,7 @@ struct cil_args_verify { + int *pass; + }; + +-int cil_verify_name(const char *name, enum cil_flavor flavor); ++int cil_verify_name(const struct cil_db *db, const char *name, enum cil_flavor flavor); + int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len); + int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor); + int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor); +diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in +index 2e503bd1b453..0e05d6064789 100644 +--- a/libsepol/src/libsepol.map.in ++++ b/libsepol/src/libsepol.map.in +@@ -272,4 +272,5 @@ LIBSEPOL_3.0 { + cil_write_parse_ast; + cil_write_build_ast; + cil_write_resolve_ast; ++ cil_set_qualified_names; + } LIBSEPOL_1.1; +-- +2.32.0 + diff --git a/SOURCES/0093-libsepol-cil-do-not-override-previous-results-of-__c.patch b/SOURCES/0093-libsepol-cil-do-not-override-previous-results-of-__c.patch new file mode 100644 index 0000000..b030e47 --- /dev/null +++ b/SOURCES/0093-libsepol-cil-do-not-override-previous-results-of-__c.patch @@ -0,0 +1,51 @@ +From fd705df050f916add396954218a67fb8a4fd7cad Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Fri, 2 Jul 2021 13:07:05 +0200 +Subject: [PATCH] libsepol/cil: do not override previous results of + __cil_verify_classperms + +When __cil_verify_map_class() verifies a classpermission, it calls +__verify_map_perm_classperms() on each item. If the first item reports a +failure and the next one succeeds, the failure is overwritten in +map_args->rc. This is a bug which causes a NULL pointer dereference in +the CIL compiler when compiling the following policy: + + (sid SID) + (sidorder (SID)) + + (class CLASS (PERM1)) + (classorder (CLASS)) + + (classpermission CLSPERM) + (classpermissionset CLSPERM (CLASS (PERM1))) + (classmap files (CLAMAPxx x)) + (classmapping files CLAMAPxx CLSPERM) + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=30286 + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_verify.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index ce3fcd8c81c9..fc8a8a406a15 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -1795,8 +1795,12 @@ static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, + { + struct cil_verify_map_args *map_args = args; + struct cil_perm *cmp = (struct cil_perm *)d; ++ int rc; + +- map_args->rc = __cil_verify_classperms(cmp->classperms, &cmp->datum, &map_args->class->datum, &cmp->datum, CIL_MAP_PERM, 0, 2); ++ rc = __cil_verify_classperms(cmp->classperms, &cmp->datum, &map_args->class->datum, &cmp->datum, CIL_MAP_PERM, 0, 2); ++ if (rc != SEPOL_OK) { ++ map_args->rc = rc; ++ } + + return SEPOL_OK; + } +-- +2.32.0 + diff --git a/SOURCES/0094-libsepol-silence-Wextra-semi-stmt-warning.patch b/SOURCES/0094-libsepol-silence-Wextra-semi-stmt-warning.patch new file mode 100644 index 0000000..bd3cecd --- /dev/null +++ b/SOURCES/0094-libsepol-silence-Wextra-semi-stmt-warning.patch @@ -0,0 +1,132 @@ +From 9d85aa60d12e468e7fd510c2b5475b5299b71622 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sat, 3 Jul 2021 16:31:17 +0200 +Subject: [PATCH] libsepol: silence -Wextra-semi-stmt warning + +On Ubuntu 20.04, when building with clang -Werror -Wextra-semi-stmt +(which is not the default build configuration), the compiler reports: + + ../cil/src/cil_binary.c:4293:22: error: empty expression statement + has no effect; remove unnecessary ';' to silence this warning + [-Werror,-Wextra-semi-stmt] + mix(k->target_class); + ^ + ../cil/src/cil_binary.c:4294:21: error: empty expression statement + has no effect; remove unnecessary ';' to silence this warning + [-Werror,-Wextra-semi-stmt] + mix(k->target_type); + ^ + ../cil/src/cil_binary.c:4295:21: error: empty expression statement + has no effect; remove unnecessary ';' to silence this warning + [-Werror,-Wextra-semi-stmt] + mix(k->source_type); + ^ + ../cil/src/cil_binary.c:4296:19: error: empty expression statement + has no effect; remove unnecessary ';' to silence this warning + [-Werror,-Wextra-semi-stmt] + mix(k->specified); + ^ + +Use a do { ... } while (0) construction to silence this warning. + +Moreover the same warning appears when using two semicolons to end a +statement. Remove such occurrences, like what was already done in commit +811185648af2 ("libsepol: drop repeated semicolons"). + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_binary.c | 4 ++-- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + libsepol/src/avtab.c | 4 ++-- + libsepol/tests/libsepol-tests.c | 18 +++++++++++------- + 4 files changed, 16 insertions(+), 12 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 54d13f2f3945..41105c122bc3 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -4277,7 +4277,7 @@ static unsigned int avrulex_hash(__attribute__((unused)) hashtab_t h, const_hash + + uint32_t hash = 0; + +-#define mix(input) { \ ++#define mix(input) do { \ + uint32_t v = input; \ + v *= c1; \ + v = (v << r1) | (v >> (32 - r1)); \ +@@ -4285,7 +4285,7 @@ static unsigned int avrulex_hash(__attribute__((unused)) hashtab_t h, const_hash + hash ^= v; \ + hash = (hash << r2) | (hash >> (32 - r2)); \ + hash = hash * m + n; \ +-} ++} while (0) + + mix(k->target_class); + mix(k->target_type); +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 32ea64e39b21..9a02e3867659 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2825,7 +2825,7 @@ static int cil_build_call_args(struct cil_tree_node *call_node, struct cil_call + return SEPOL_OK; + } else { + cil_tree_log(call_node, CIL_ERR, "Unexpected arguments"); +- return SEPOL_ERR;; ++ return SEPOL_ERR; + } + } + if (call->args_tree == NULL) { +diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c +index 88e9d510f981..5e16a0e9899e 100644 +--- a/libsepol/src/avtab.c ++++ b/libsepol/src/avtab.c +@@ -63,7 +63,7 @@ static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask) + + uint32_t hash = 0; + +-#define mix(input) { \ ++#define mix(input) do { \ + uint32_t v = input; \ + v *= c1; \ + v = (v << r1) | (v >> (32 - r1)); \ +@@ -71,7 +71,7 @@ static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask) + hash ^= v; \ + hash = (hash << r2) | (hash >> (32 - r2)); \ + hash = hash * m + n; \ +-} ++} while (0) + + mix(keyp->target_class); + mix(keyp->target_type); +diff --git a/libsepol/tests/libsepol-tests.c b/libsepol/tests/libsepol-tests.c +index 544c792d2ab5..dc8fd5ce5f6c 100644 +--- a/libsepol/tests/libsepol-tests.c ++++ b/libsepol/tests/libsepol-tests.c +@@ -36,13 +36,17 @@ + int mls; + + #define DECLARE_SUITE(name) \ +- suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \ +- if (NULL == suite) { \ +- CU_cleanup_registry(); \ +- return CU_get_error(); } \ +- if (name##_add_tests(suite)) { \ +- CU_cleanup_registry(); \ +- return CU_get_error(); } ++ do { \ ++ suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \ ++ if (NULL == suite) { \ ++ CU_cleanup_registry(); \ ++ return CU_get_error(); \ ++ } \ ++ if (name##_add_tests(suite)) { \ ++ CU_cleanup_registry(); \ ++ return CU_get_error(); \ ++ } \ ++ } while (0) + + static void usage(char *progname) + { +-- +2.32.0 + diff --git a/SOURCES/0095-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch b/SOURCES/0095-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch new file mode 100644 index 0000000..4e86d6b --- /dev/null +++ b/SOURCES/0095-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch @@ -0,0 +1,315 @@ +From 9af91692416d01814f4b2ac22e39d3b57993af4f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 30 Jun 2021 15:12:16 -0400 +Subject: [PATCH] libsepol/cil: Improve checking for bad inheritance patterns + +commits 37863b0b1444c85a1ddc6c333c8bfea0c678c592 (libsepol/cil: +Improve degenerate inheritance check) and +74d00a8decebf940d95064ff60042dcb2cbcc2c0 (libsepol/cil: Detect +degenerate inheritance and exit with an error) attempted to detect +and exit with an error when compiling policies that have degenerate +inheritances. These policies result in the exponential growth of memory +usage while copying the blocks that are inherited. + +There were two problems with the previous attempts to detect this +bad inheritance problem. The first is that the quick check using +cil_possible_degenerate_inheritance() did not detect all patterns +of degenerate inheritance. The second problem is that the detection +of inheritance loops during the CIL_PASS_BLKIN_LINK pass did not +detect all inheritance loops which made it possible for the full +degenerate inheritance checking done with +cil_check_for_degenerate_inheritance() to have a stack overflow +when encountering the inheritance loops. Both the degenerate and +loop inheritance checks need to be done at the same time and done +after the CIL_PASS_BLKIN_LINK pass. Otherwise, if loops are being +detected first, then a degenerate policy can cause the consumption +of all system memory and if degenerate policy is being detected +first, then an inheritance loop can cause a stack overflow. + +With the new approach, the quick check is eliminated and the full +check is always done after the CIL_PASS_BLKIN_LINK pass. Because +of this the "inheritance_check" field in struct cil_resolve_args +is not needed and removed and the functions +cil_print_recursive_blockinherit(), cil_check_recursive_blockinherit(), +and cil_possible_degenerate_inheritance() have been deleted. The +function cil_count_potential() is renamed cil_check_inheritances() +and has checks for both degenerate inheritance and inheritance loops. +The inheritance checking is improved and uses an approach similar +to commit c28525a26fa145cb5fd911fd2a3b9125a275677f (libsepol/cil: +Properly check for loops in sets). + +As has been the case with these degenerate inheritance patches, +these issues were discovered by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 172 +++++++---------------------- + 1 file changed, 42 insertions(+), 130 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 9a02e3867659..145d4e7452dd 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -64,7 +64,6 @@ struct cil_args_resolve { + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; + struct cil_stack *disabled_optionals; +- int *inheritance_check; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2309,100 +2308,8 @@ exit: + return rc; + } + +-static void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) +-{ +- struct cil_list *trace = NULL; +- struct cil_list_item *item = NULL; +- struct cil_tree_node *curr = NULL; +- +- cil_list_init(&trace, CIL_NODE); +- +- for (curr = bi_node; curr != terminating_node; curr = curr->parent) { +- if (curr->flavor == CIL_BLOCK) { +- cil_list_prepend(trace, CIL_NODE, curr); +- } else if (curr->flavor == CIL_BLOCKINHERIT) { +- if (curr != bi_node) { +- cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block)); +- } +- cil_list_prepend(trace, CIL_NODE, curr); +- } else { +- cil_list_prepend(trace, CIL_NODE, curr); +- } +- } +- cil_list_prepend(trace, CIL_NODE, terminating_node); +- +- cil_list_for_each(item, trace) { +- curr = item->data; +- if (curr->flavor == CIL_BLOCK) { +- cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name); +- } else if (curr->flavor == CIL_BLOCKINHERIT) { +- cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str); +- } else if (curr->flavor == CIL_OPTIONAL) { +- cil_tree_log(curr, CIL_ERR, "optional %s", DATUM(curr->data)->name); +- } else { +- cil_tree_log(curr, CIL_ERR, "%s", cil_node_to_string(curr)); +- } +- } +- +- cil_list_destroy(&trace, CIL_FALSE); +-} +- +-static int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) +-{ +- struct cil_tree_node *curr = NULL; +- struct cil_blockinherit *bi = NULL; +- struct cil_block *block = NULL; +- int rc = SEPOL_ERR; +- +- bi = bi_node->data; +- +- for (curr = bi_node->parent; curr != NULL; curr = curr->parent) { +- if (curr->flavor != CIL_BLOCK) { +- continue; +- } +- +- block = curr->data; +- +- if (block != bi->block) { +- continue; +- } +- +- cil_log(CIL_ERR, "Recursive blockinherit found:\n"); +- cil_print_recursive_blockinherit(bi_node, curr); +- +- rc = SEPOL_ERR; +- goto exit; +- } +- +- rc = SEPOL_OK; +- +-exit: +- return rc; +-} +- +-static int cil_possible_degenerate_inheritance(struct cil_tree_node *node) +-{ +- unsigned depth = 1; +- +- node = node->parent; +- while (node && node->flavor != CIL_ROOT) { +- if (node->flavor == CIL_BLOCK) { +- if (((struct cil_block *)(node->data))->bi_nodes != NULL) { +- depth++; +- if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { +- return CIL_TRUE; +- } +- } +- } +- node = node->parent; +- } +- +- return CIL_FALSE; +-} +- + int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) + { +- struct cil_args_resolve *args = extra_args; + struct cil_blockinherit *inherit = current->data; + struct cil_symtab_datum *block_datum = NULL; + struct cil_tree_node *node = NULL; +@@ -2423,20 +2330,11 @@ int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_arg + + inherit->block = (struct cil_block *)block_datum; + +- rc = cil_check_recursive_blockinherit(current); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + if (inherit->block->bi_nodes == NULL) { + cil_list_init(&inherit->block->bi_nodes, CIL_NODE); + } + cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); + +- if (*(args->inheritance_check) == CIL_FALSE) { +- *(args->inheritance_check) = cil_possible_degenerate_inheritance(node); +- } +- + return SEPOL_OK; + + exit: +@@ -2466,11 +2364,6 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + } + + cil_list_for_each(item, block->bi_nodes) { +- rc = cil_check_recursive_blockinherit(item->data); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + rc = cil_copy_ast(db, current, item->data); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n"); +@@ -3611,34 +3504,58 @@ static unsigned cil_count_actual(struct cil_tree_node *node) + return count; + } + +-static unsigned cil_count_potential(struct cil_tree_node *node, unsigned max) ++static int cil_check_inheritances(struct cil_tree_node *node, unsigned max, unsigned *count, struct cil_stack *stack, unsigned *loop) + { +- unsigned count = 0; ++ int rc; + + if (node->flavor == CIL_BLOCKINHERIT) { + struct cil_blockinherit *bi = node->data; +- count += 1; ++ *count += 1; ++ if (*count > max) { ++ cil_tree_log(node, CIL_ERR, "Degenerate inheritance detected"); ++ return SEPOL_ERR; ++ } + if (bi->block) { +- count += cil_count_potential(NODE(bi->block), max); +- if (count > max) { +- return count; ++ struct cil_tree_node *block_node = NODE(bi->block); ++ struct cil_stack_item *item; ++ int i = 0; ++ cil_stack_for_each(stack, i, item) { ++ if (block_node == (struct cil_tree_node *)item->data) { ++ *loop = CIL_TRUE; ++ cil_tree_log(block_node, CIL_ERR, "Block inheritance loop found"); ++ cil_tree_log(node, CIL_ERR, " blockinherit"); ++ return SEPOL_ERR; ++ } ++ } ++ cil_stack_push(stack, CIL_BLOCK, block_node); ++ rc = cil_check_inheritances(block_node, max, count, stack, loop); ++ cil_stack_pop(stack); ++ if (rc != SEPOL_OK) { ++ if (*loop == CIL_TRUE) { ++ cil_tree_log(node, CIL_ERR, " blockinherit"); ++ } ++ return SEPOL_ERR; + } + } + } + + for (node = node->cl_head; node; node = node->next) { +- count += cil_count_potential(node, max); +- if (count > max) { +- return count; ++ rc = cil_check_inheritances(node, max, count, stack, loop); ++ if (rc != SEPOL_OK) { ++ return SEPOL_ERR; + } + } + +- return count; ++ return SEPOL_OK; + } + +-static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) ++static int cil_check_for_bad_inheritance(struct cil_tree_node *node) + { +- uint64_t num_actual, num_potential, max; ++ unsigned num_actual, max; ++ unsigned num_potential = 0; ++ unsigned loop = CIL_FALSE; ++ struct cil_stack *stack; ++ int rc; + + num_actual = cil_count_actual(node); + +@@ -3647,13 +3564,11 @@ static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) + max = CIL_DEGENERATE_INHERITANCE_MINIMUM; + } + +- num_potential = cil_count_potential(node, max); ++ cil_stack_init(&stack); ++ rc = cil_check_inheritances(node, max, &num_potential, stack, &loop); ++ cil_stack_destroy(&stack); + +- if (num_potential > max) { +- return SEPOL_ERR; +- } +- +- return SEPOL_OK; ++ return rc; + } + + int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) +@@ -4127,7 +4042,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + struct cil_args_resolve extra_args; + enum cil_pass pass = CIL_PASS_TIF; + uint32_t changed = 0; +- int inheritance_check = 0; + + if (db == NULL || current == NULL) { + return rc; +@@ -4147,7 +4061,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; + extra_args.disabled_optionals = NULL; +- extra_args.inheritance_check = &inheritance_check; + + cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); +@@ -4174,10 +4087,9 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + cil_list_destroy(&extra_args.in_list, CIL_FALSE); + } + +- if (pass == CIL_PASS_BLKIN_LINK && inheritance_check == CIL_TRUE) { +- rc = cil_check_for_degenerate_inheritance(current); ++ if (pass == CIL_PASS_BLKIN_LINK) { ++ rc = cil_check_for_bad_inheritance(current); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Degenerate inheritance detected\n"); + rc = SEPOL_ERR; + goto exit; + } +-- +2.32.0 + diff --git a/SOURCES/0096-libsepol-avoid-unsigned-integer-overflow.patch b/SOURCES/0096-libsepol-avoid-unsigned-integer-overflow.patch new file mode 100644 index 0000000..1fc9e77 --- /dev/null +++ b/SOURCES/0096-libsepol-avoid-unsigned-integer-overflow.patch @@ -0,0 +1,79 @@ +From 44d56761bed0a394cceb4b0c57fee4fc0e4d9a85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 6 Jul 2021 19:36:29 +0200 +Subject: [PATCH] libsepol: avoid unsigned integer overflow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Unsigned integer overflow is well-defined and not undefined behavior. +It is commonly used for hashing or pseudo random number generation. +But it is still useful to enable undefined behavior sanitizer checks on +unsigned arithmetic to detect possible issues on counters or variables +with similar purpose or missed overflow checks on user input. + +Use a spaceship operator like comparison instead of subtraction. + + policydb.c:851:24: runtime error: unsigned integer overflow: 801 - 929 cannot be represented in type 'unsigned int' + +Follow-up of: 1537ea8412e4 ("libsepol: avoid unsigned integer overflow") + +Signed-off-by: Christian Göttsche +--- + libsepol/src/policydb.c | 10 +++++----- + libsepol/src/private.h | 2 ++ + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index ef2217c28c91..0398ceed2574 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -817,11 +817,11 @@ static int filenametr_cmp(hashtab_t h __attribute__ ((unused)), + const filename_trans_key_t *ft2 = (const filename_trans_key_t *)k2; + int v; + +- v = (ft1->ttype > ft2->ttype) - (ft1->ttype < ft2->ttype); ++ v = spaceship_cmp(ft1->ttype, ft2->ttype); + if (v) + return v; + +- v = (ft1->tclass > ft2->tclass) - (ft1->tclass < ft2->tclass); ++ v = spaceship_cmp(ft1->tclass, ft2->tclass); + if (v) + return v; + +@@ -843,15 +843,15 @@ static int rangetr_cmp(hashtab_t h __attribute__ ((unused)), + const struct range_trans *key2 = (const struct range_trans *)k2; + int v; + +- v = key1->source_type - key2->source_type; ++ v = spaceship_cmp(key1->source_type, key2->source_type); + if (v) + return v; + +- v = key1->target_type - key2->target_type; ++ v = spaceship_cmp(key1->target_type, key2->target_type); + if (v) + return v; + +- v = key1->target_class - key2->target_class; ++ v = spaceship_cmp(key1->target_class, key2->target_class); + + return v; + } +diff --git a/libsepol/src/private.h b/libsepol/src/private.h +index 72f212628314..c63238abe5f3 100644 +--- a/libsepol/src/private.h ++++ b/libsepol/src/private.h +@@ -47,6 +47,8 @@ + #define is_saturated(x) (x == (typeof(x))-1) + #define zero_or_saturated(x) ((x == 0) || is_saturated(x)) + ++#define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b))) ++ + /* Policy compatibility information. */ + struct policydb_compat_info { + unsigned int type; +-- +2.32.0 + diff --git a/SOURCES/0097-libsepol-ignore-UBSAN-false-positives.patch b/SOURCES/0097-libsepol-ignore-UBSAN-false-positives.patch new file mode 100644 index 0000000..7597ba7 --- /dev/null +++ b/SOURCES/0097-libsepol-ignore-UBSAN-false-positives.patch @@ -0,0 +1,99 @@ +From 09405ba91c40e4e08f2212c946a432fa001d04bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 1 Jul 2021 20:06:22 +0200 +Subject: [PATCH] libsepol: ignore UBSAN false-positives +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Unsigned integer overflow is well-defined and not undefined behavior. +But it is still useful to enable undefined behavior sanitizer checks on +unsigned arithmetic to detect possible issues on counters or variables +with similar purpose. + +Annotate functions, in which unsigned overflows are expected to happen, +with the respective Clang function attribute[1]. +GCC does not support sanitizing unsigned integer arithmetic[2]. + + avtab.c:76:2: runtime error: unsigned integer overflow: 6 * 3432918353 cannot be represented in type 'unsigned int' + policydb.c:795:42: runtime error: unsigned integer overflow: 8160943042179512010 * 11 cannot be represented in type 'unsigned long' + symtab.c:25:12: runtime error: left shift of 1766601759 by 4 places cannot be represented in type 'unsigned int' + +[1]: https://clang.llvm.org/docs/AttributeReference.html#no-sanitize +[2]: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html + +Signed-off-by: Christian Göttsche +--- + libsepol/src/avtab.c | 1 + + libsepol/src/policydb.c | 1 + + libsepol/src/private.h | 11 +++++++++++ + libsepol/src/symtab.c | 4 ++++ + 4 files changed, 17 insertions(+) + +diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c +index 5e16a0e9899e..93505b20e4c0 100644 +--- a/libsepol/src/avtab.c ++++ b/libsepol/src/avtab.c +@@ -52,6 +52,7 @@ + /* Based on MurmurHash3, written by Austin Appleby and placed in the + * public domain. + */ ++ignore_unsigned_overflow_ + static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask) + { + static const uint32_t c1 = 0xcc9e2d51; +diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c +index 0398ceed2574..7093d9b7028a 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -789,6 +789,7 @@ static int roles_init(policydb_t * p) + goto out; + } + ++ignore_unsigned_overflow_ + static inline unsigned long + partial_name_hash(unsigned long c, unsigned long prevhash) + { +diff --git a/libsepol/src/private.h b/libsepol/src/private.h +index c63238abe5f3..71287282fbc0 100644 +--- a/libsepol/src/private.h ++++ b/libsepol/src/private.h +@@ -49,6 +49,17 @@ + + #define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b))) + ++/* Use to ignore intentional unsigned under- and overflows while running under UBSAN. */ ++#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 4) ++#if (__clang_major__ >= 12) ++#define ignore_unsigned_overflow_ __attribute__((no_sanitize("unsigned-integer-overflow", "unsigned-shift-base"))) ++#else ++#define ignore_unsigned_overflow_ __attribute__((no_sanitize("unsigned-integer-overflow"))) ++#endif ++#else ++#define ignore_unsigned_overflow_ ++#endif ++ + /* Policy compatibility information. */ + struct policydb_compat_info { + unsigned int type; +diff --git a/libsepol/src/symtab.c b/libsepol/src/symtab.c +index 9a417ca24b53..a60618510bd3 100644 +--- a/libsepol/src/symtab.c ++++ b/libsepol/src/symtab.c +@@ -8,9 +8,13 @@ + */ + + #include ++ ++#include "private.h" ++ + #include + #include + ++ignore_unsigned_overflow_ + static unsigned int symhash(hashtab_t h, const_hashtab_key_t key) + { + const char *p, *keyp; +-- +2.32.0 + diff --git a/SOURCES/0098-libsepol-avoid-implicit-conversions.patch b/SOURCES/0098-libsepol-avoid-implicit-conversions.patch new file mode 100644 index 0000000..a19c894 --- /dev/null +++ b/SOURCES/0098-libsepol-avoid-implicit-conversions.patch @@ -0,0 +1,70 @@ +From e1491388d570a83f6b005d7dc1906765a02b922e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 1 Jul 2021 20:06:45 +0200 +Subject: [PATCH] libsepol: avoid implicit conversions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid implicit conversions from signed to unsigned values, found by +UB sanitizers, by using unsigned values in the first place. + + expand.c:1644:18: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'uint32_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned) + + expand.c:2892:24: runtime error: implicit conversion from type 'int' of value -2 (32-bit, signed) to type 'unsigned int' changed the value to 4294967294 (32-bit, unsigned) + + policy_define.c:2344:4: runtime error: implicit conversion from type 'int' of value -1048577 (32-bit, signed) to type 'unsigned int' changed the value to 4293918719 (32-bit, unsigned) + +Signed-off-by: Christian Göttsche +--- + libsepol/include/sepol/policydb/conditional.h | 2 +- + libsepol/include/sepol/policydb/policydb.h | 6 +++--- + libsepol/src/expand.c | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libsepol/include/sepol/policydb/conditional.h b/libsepol/include/sepol/policydb/conditional.h +index 9c3df3ef488e..49c0d76631c4 100644 +--- a/libsepol/include/sepol/policydb/conditional.h ++++ b/libsepol/include/sepol/policydb/conditional.h +@@ -90,7 +90,7 @@ typedef struct cond_node { + uint32_t expr_pre_comp; + struct cond_node *next; + /* a tunable conditional, calculated and used at expansion */ +-#define COND_NODE_FLAGS_TUNABLE 0x01 ++#define COND_NODE_FLAGS_TUNABLE UINT32_C(0x01) + uint32_t flags; + } cond_node_t; + +diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h +index 6976ef4831ef..4bf9f05ddd0a 100644 +--- a/libsepol/include/sepol/policydb/policydb.h ++++ b/libsepol/include/sepol/policydb/policydb.h +@@ -251,9 +251,9 @@ typedef struct class_perm_node { + struct class_perm_node *next; + } class_perm_node_t; + +-#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f))) +-#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f))) +-#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) ++#define xperm_test(x, p) (UINT32_C(1) & (p[x >> 5] >> (x & 0x1f))) ++#define xperm_set(x, p) (p[x >> 5] |= (UINT32_C(1) << (x & 0x1f))) ++#define xperm_clear(x, p) (p[x >> 5] &= ~(UINT32_C(1) << (x & 0x1f))) + #define EXTENDED_PERMS_LEN 8 + + typedef struct av_extended_perms { +diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c +index 84bfcfa36d0a..aac5b35f7bd1 100644 +--- a/libsepol/src/expand.c ++++ b/libsepol/src/expand.c +@@ -1641,7 +1641,7 @@ static avtab_ptr_t find_avtab_node(sepol_handle_t * handle, + * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for + * others. Initialize the data accordingly. + */ +- avdatum.data = key->specified == AVTAB_AUDITDENY ? ~0 : 0; ++ avdatum.data = key->specified == AVTAB_AUDITDENY ? ~UINT32_C(0) : UINT32_C(0); + /* this is used to get the node - insertion is actually unique */ + node = avtab_insert_nonunique(avtab, key, &avdatum); + if (!node) { +-- +2.32.0 + diff --git a/SOURCES/0099-libsepol-assure-string-NUL-termination-of-ibdev_name.patch b/SOURCES/0099-libsepol-assure-string-NUL-termination-of-ibdev_name.patch new file mode 100644 index 0000000..b578976 --- /dev/null +++ b/SOURCES/0099-libsepol-assure-string-NUL-termination-of-ibdev_name.patch @@ -0,0 +1,89 @@ +From 07d6f1cea5a8ec0251606636189bc519d80b0729 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 1 Jul 2021 20:07:07 +0200 +Subject: [PATCH] libsepol: assure string NUL-termination of ibdev_name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Clang complains: + + ibendport_record.c: In function ‘sepol_ibendport_get_ibdev_name’: + ibendport_record.c:169:2: error: ‘strncpy’ specified bound 64 equals destination size [-Werror=stringop-truncation] + 169 | strncpy(tmp_ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ibendport_record.c: In function ‘sepol_ibendport_set_ibdev_name’: + ibendport_record.c:189:2: error: ‘strncpy’ specified bound 64 equals destination size [-Werror=stringop-truncation] + 189 | strncpy(tmp, ibdev_name, IB_DEVICE_NAME_MAX); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +strncpy(3) does not NUL-terminate the destination if the source is of +the same length or longer then the specified size. +The source of these copies are retrieved from +sepol_ibendport_alloc_ibdev_name(), which allocates a fixed amount of +IB_DEVICE_NAME_MAX bytes. +Reduce the size to copy by 1 of all memory regions allocated by +sepol_ibendport_alloc_ibdev_name(). + +Signed-off-by: Christian Göttsche +--- + libsepol/src/ibendport_record.c | 8 ++++---- + libsepol/src/ibendports.c | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libsepol/src/ibendport_record.c b/libsepol/src/ibendport_record.c +index adf671615e5c..1eb50914b8c0 100644 +--- a/libsepol/src/ibendport_record.c ++++ b/libsepol/src/ibendport_record.c +@@ -62,7 +62,7 @@ int sepol_ibendport_key_create(sepol_handle_t *handle, + if (sepol_ibendport_alloc_ibdev_name(handle, &tmp_key->ibdev_name) < 0) + goto err; + +- strncpy(tmp_key->ibdev_name, ibdev_name, IB_DEVICE_NAME_MAX); ++ strncpy(tmp_key->ibdev_name, ibdev_name, IB_DEVICE_NAME_MAX - 1); + tmp_key->port = port; + + *key_ptr = tmp_key; +@@ -166,7 +166,7 @@ int sepol_ibendport_get_ibdev_name(sepol_handle_t *handle, + if (sepol_ibendport_alloc_ibdev_name(handle, &tmp_ibdev_name) < 0) + goto err; + +- strncpy(tmp_ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX); ++ strncpy(tmp_ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX - 1); + *ibdev_name = tmp_ibdev_name; + return STATUS_SUCCESS; + +@@ -186,7 +186,7 @@ int sepol_ibendport_set_ibdev_name(sepol_handle_t *handle, + if (sepol_ibendport_alloc_ibdev_name(handle, &tmp) < 0) + goto err; + +- strncpy(tmp, ibdev_name, IB_DEVICE_NAME_MAX); ++ strncpy(tmp, ibdev_name, IB_DEVICE_NAME_MAX - 1); + free(ibendport->ibdev_name); + ibendport->ibdev_name = tmp; + return STATUS_SUCCESS; +@@ -230,7 +230,7 @@ int sepol_ibendport_clone(sepol_handle_t *handle, + if (sepol_ibendport_alloc_ibdev_name(handle, &new_ibendport->ibdev_name) < 0) + goto omem; + +- strncpy(new_ibendport->ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX); ++ strncpy(new_ibendport->ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX - 1); + new_ibendport->port = ibendport->port; + + if (ibendport->con && +diff --git a/libsepol/src/ibendports.c b/libsepol/src/ibendports.c +index 6d56c9a1793f..ee5cb1930f31 100644 +--- a/libsepol/src/ibendports.c ++++ b/libsepol/src/ibendports.c +@@ -34,7 +34,7 @@ static int ibendport_from_record(sepol_handle_t *handle, + &ibdev_name) < 0) + goto err; + +- strncpy(tmp_ibendport->u.ibendport.dev_name, ibdev_name, IB_DEVICE_NAME_MAX); ++ strncpy(tmp_ibendport->u.ibendport.dev_name, ibdev_name, IB_DEVICE_NAME_MAX - 1); + + free(ibdev_name); + ibdev_name = NULL; +-- +2.32.0 + diff --git a/SOURCES/0100-libsepol-cil-Fix-handling-category-sets-in-an-expres.patch b/SOURCES/0100-libsepol-cil-Fix-handling-category-sets-in-an-expres.patch new file mode 100644 index 0000000..e02d849 --- /dev/null +++ b/SOURCES/0100-libsepol-cil-Fix-handling-category-sets-in-an-expres.patch @@ -0,0 +1,108 @@ +From 8470058934e89d1876b8e034d1ea818bde62b994 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 12 Jul 2021 09:50:38 -0400 +Subject: [PATCH] libsepol/cil: Fix handling category sets in an expression + +There are two problems that need to be addressed when resolving an +expression with category sets. + +1. Only expand anonymous category sets in an expression. + +Commit 982ec302b67f3c7f8df667dadb67352b1e4a6d18 (libsepol/cil: +Account for anonymous category sets in an expression) attempted to +properly handle anonymous category sets when resolving category +expressions. Unfortunately, it did not check whether a category set +was actually an anonymous category set and expanded all category +sets in an expression. If a category set refers to itself in the +expression, then everything from the name of the category set to the +end of the expression is ignored. + +For example, the rule "(categoryset cs (c0 cs c1 c2))", would be +equivalent to the rule "(categoryset cs (c0))" as everything from +"cs" to the end would be dropped. The secilc-fuzzer found that the +rule "(categoryset cat (not cat))" would cause a segfault since +"(not)" is not a valid expression and it is assumed to be valid +during later evaluation because syntax checking has already been +done. + +Instead, check whether or not the category set is anonymous before +expanding it when resolving an expression. + +2. Category sets cannot be used in a category range + +A category range can be used to specify a large number of categories. +The range "(range c0 c1023)" refers to 1024 categories. Only categories +and category aliases can be used in a range. Determining if an +identifier is a category, an alias, or a set can only be done after +resolving the identifer. + +Keep track of the current operator as an expression is being resolved +and if the expression involves categories and a category set is +encountered, then return an error if the expression is a category +range. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 145d4e7452dd..180073247617 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3228,6 +3228,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + struct cil_symtab_datum *res_datum = NULL; + enum cil_sym_index sym_index = CIL_SYM_UNKNOWN; + struct cil_list *datum_sub_expr; ++ enum cil_flavor op = CIL_NONE; + + switch (str_expr->flavor) { + case CIL_BOOL: +@@ -3263,14 +3264,24 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + } + if (sym_index == CIL_SYM_CATS && NODE(res_datum)->flavor == CIL_CATSET) { + struct cil_catset *catset = (struct cil_catset *)res_datum; +- if (!catset->cats->datum_expr) { +- rc = cil_resolve_expr(expr_type, catset->cats->str_expr, &catset->cats->datum_expr, parent, extra_args); +- if (rc != SEPOL_OK) { +- goto exit; ++ if (op == CIL_RANGE) { ++ cil_tree_log(parent, CIL_ERR, "Category set not allowed in category range"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ if (!res_datum->name) { ++ /* Anonymous category sets need to be resolved when encountered */ ++ if (!catset->cats->datum_expr) { ++ rc = cil_resolve_expr(expr_type, catset->cats->str_expr, &catset->cats->datum_expr, parent, extra_args); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } + } ++ cil_copy_list(catset->cats->datum_expr, &datum_sub_expr); ++ cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr); ++ } else { ++ cil_list_append(*datum_expr, CIL_DATUM, res_datum); + } +- cil_copy_list(catset->cats->datum_expr, &datum_sub_expr); +- cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr); + } else { + if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) { + cil_type_used(res_datum, CIL_ATTR_CONSTRAINT); +@@ -3287,9 +3298,12 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc + break; + } + default: ++ if (curr->flavor == CIL_OP) { ++ op = (enum cil_flavor)(uintptr_t)curr->data; ++ } + cil_list_append(*datum_expr, curr->flavor, curr->data); + break; +- } ++ } + } + return SEPOL_OK; + +-- +2.32.0 + diff --git a/SOURCES/0101-libsepol-cil-do-not-allow-0-in-quoted-strings.patch b/SOURCES/0101-libsepol-cil-do-not-allow-0-in-quoted-strings.patch new file mode 100644 index 0000000..d6cadba --- /dev/null +++ b/SOURCES/0101-libsepol-cil-do-not-allow-0-in-quoted-strings.patch @@ -0,0 +1,41 @@ +From af29a235531f66882e5a027e1348658b8d8c1e68 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Mon, 12 Jul 2021 10:44:28 +0200 +Subject: [PATCH] libsepol/cil: do not allow \0 in quoted strings + +Using the '\0' character in strings in a CIL policy is not expected to +happen, and makes the flex tokenizer very slow. For example when +generating a file with: + + python -c 'print("\"" + "\0"*100000 + "\"")' > policy.cil + +secilc fails after 26 seconds, on my desktop computer. Increasing the +numbers of \0 makes this time increase significantly. But replacing \0 +with another character makes secilc fail in only few milliseconds. + +Fix this "possible denial of service" issue by forbidding \0 in strings +in CIL policies. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=36016 + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_lexer.l | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_lexer.l b/libsepol/cil/src/cil_lexer.l +index e28c33ecb9f1..8bf2b6e7765a 100644 +--- a/libsepol/cil/src/cil_lexer.l ++++ b/libsepol/cil/src/cil_lexer.l +@@ -49,7 +49,7 @@ spec_char [\[\]\.\@\=\/\*\-\_\$\%\+\-\!\|\&\^\:\~\`\#\{\}\'\<\>\?\,] + symbol ({digit}|{alpha}|{spec_char})+ + white [ \t] + newline [\n\r] +-qstring \"[^"\n]*\" ++qstring \"[^"\n\0]*\" + hll_lm ^;;\* + comment ; + +-- +2.32.0 + diff --git a/SPECS/libsepol.spec b/SPECS/libsepol.spec new file mode 100644 index 0000000..2194d97 --- /dev/null +++ b/SPECS/libsepol.spec @@ -0,0 +1,1449 @@ +Summary: SELinux binary policy manipulation library +Name: libsepol +Version: 3.2 +Release: 4%{?dist} +License: LGPLv2+ +Source0: https://github.com/SELinuxProject/selinux/releases/download/3.2/libsepol-3.2.tar.gz +URL: https://github.com/SELinuxProject/selinux/wiki +# $ git clone https://github.com/fedora-selinux/selinux.git +# $ cd selinux +# $ git format-patch -N libsepol-3.2 -- libsepol +# $ i=1; for j in 0*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done +# Patch list start +Patch0001: 0001-libsepol-Expand-role-attributes-in-constraint-expres.patch +Patch0002: 0002-libsepol-Properly-handle-types-associated-to-role-at.patch +Patch0003: 0003-libsepol-Remove-unnecessary-copying-of-declarations-.patch +Patch0004: 0004-libsepol-Check-kernel-to-CIL-and-Conf-functions-for-.patch +Patch0005: 0005-libsepol-cil-make-cil_post_fc_fill_data-static.patch +Patch0006: 0006-libsepol-cil-remove-stray-printf.patch +Patch0007: 0007-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch +Patch0008: 0008-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch +Patch0009: 0009-libsepol-cil-do-not-leak-avrulex_ioctl_table-memory-.patch +Patch0010: 0010-libsepol-make-num_-unsigned-int-in-module_to_cil.patch +Patch0011: 0011-libsepol-Write-NO_IDENTIFIER-for-empty-constraint-ex.patch +Patch0012: 0012-libsepol-Enclose-identifier-lists-in-constraint-expr.patch +Patch0013: 0013-libsepol-cil-Allow-lists-in-constraint-expressions.patch +Patch0014: 0014-libsepol-Enclose-identifier-lists-in-CIL-constraint-.patch +Patch0015: 0015-libsepol-Write-NO_IDENTIFIER-for-empty-CIL-constrain.patch +Patch0016: 0016-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch +Patch0017: 0017-libsepol-cil-Fix-out-of-bound-read-of-file-context-p.patch +Patch0018: 0018-libsepol-cil-Destroy-classperms-list-when-resetting-.patch +Patch0019: 0019-libsepol-cil-Destroy-classperm-list-when-resetting-m.patch +Patch0020: 0020-libsepol-cil-cil_reset_classperms_set-should-not-res.patch +Patch0021: 0021-libsepol-cil-Set-class-field-to-NULL-when-resetting-.patch +Patch0022: 0022-libsepol-cil-More-strict-verification-of-constraint-.patch +Patch0023: 0023-libsepol-cil-Exit-with-an-error-if-declaration-name-.patch +Patch0024: 0024-libsepol-cil-Allow-permission-expressions-when-using.patch +Patch0025: 0025-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch +Patch0026: 0026-libsepol-cil-Create-function-cil_add_decl_to_symtab-.patch +Patch0027: 0027-libsepol-cil-Move-check-for-the-shadowing-of-macro-p.patch +Patch0028: 0028-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch +Patch0029: 0029-libsepol-cil-Cleanup-build-AST-helper-functions.patch +Patch0030: 0030-libsepol-cil-Create-new-first-child-helper-function-.patch +Patch0031: 0031-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch +Patch0032: 0032-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch +Patch0033: 0033-libsepol-cil-Sync-checks-for-invalid-rules-in-boolea.patch +Patch0034: 0034-libsepol-cil-Check-for-statements-not-allowed-in-opt.patch +Patch0035: 0035-libsepol-cil-Sync-checks-for-invalid-rules-in-macros.patch +Patch0036: 0036-libsepol-cil-Do-not-allow-tunable-declarations-in-in.patch +Patch0037: 0037-libsepol-cil-Make-invalid-statement-error-messages-c.patch +Patch0038: 0038-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch +Patch0039: 0039-libsepol-cil-Create-functions-to-write-the-CIL-AST.patch +Patch0040: 0040-libsepol-cil-Add-functions-to-make-use-of-cil_write_.patch +Patch0041: 0041-libsepol-use-checked-arithmetic-builtin-to-perform-s.patch +Patch0042: 0042-libsepol-cil-Properly-reset-an-anonymous-classperm-s.patch +Patch0043: 0043-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch +Patch0044: 0044-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch +Patch0045: 0045-libsepol-cil-Check-datum-in-ordered-list-for-expecte.patch +Patch0046: 0046-libsepol-cil-Return-an-error-if-a-call-argument-fail.patch +Patch0047: 0047-libsepol-cil-Check-for-self-referential-loops-in-set.patch +Patch0048: 0048-libsepol-cil-Fix-name-resolution-involving-inherited.patch +Patch0049: 0049-libsepol-cil-Make-name-resolution-in-macros-work-as-.patch +Patch0050: 0050-libsepol-cil-Do-not-add-NULL-node-when-inserting-key.patch +Patch0051: 0051-libsepo-cil-Refactor-macro-call-resolution.patch +Patch0052: 0052-libsepol-cil-Do-not-resolve-arguments-to-declaration.patch +Patch0053: 0053-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch +Patch0054: 0054-libsepol-cil-Destroy-the-permission-nodes-when-exiti.patch +Patch0055: 0055-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch +Patch0056: 0056-libsepol-cil-Resolve-anonymous-class-permission-sets.patch +Patch0057: 0057-libsepol-cil-Pointers-to-datums-should-be-set-to-NUL.patch +Patch0058: 0058-libsepol-cil-Resolve-anonymous-levels-only-once.patch +Patch0059: 0059-libsepol-quote-paths-in-CIL-conversion.patch +Patch0060: 0060-libsepol-cil-Fix-anonymous-IP-address-call-arguments.patch +Patch0061: 0061-libsepol-cil-Account-for-anonymous-category-sets-in-.patch +Patch0062: 0062-libsepol-Quote-paths-when-generating-policy.conf-fro.patch +Patch0063: 0063-libsepol-fix-typos.patch +Patch0064: 0064-libsepol-resolve-missing-prototypes.patch +Patch0065: 0065-libsepol-remove-unused-functions.patch +Patch0066: 0066-libsepol-avoid-unsigned-integer-overflow.patch +Patch0067: 0067-libsepol-follow-declaration-after-statement.patch +Patch0068: 0068-libsepol-cil-follow-declaration-after-statement.patch +Patch0069: 0069-libsepol-remove-dead-stores.patch +Patch0070: 0070-libsepol-mark-read-only-parameters-of-ebitmap-interf.patch +Patch0071: 0071-libsepol-mark-read-only-parameters-of-type_set_-inte.patch +Patch0072: 0072-libsepol-do-not-allocate-memory-of-size-0.patch +Patch0073: 0073-libsepol-remove-dead-stores.patch +Patch0074: 0074-libsepol-cil-silence-cast-warning.patch +Patch0075: 0075-libsepol-cil-drop-extra-semicolon.patch +Patch0076: 0076-libsepol-cil-drop-dead-store.patch +Patch0077: 0077-libsepol-cil-drop-unnecessary-casts.patch +Patch0078: 0078-libsepol-cil-avoid-using-maybe-uninitialized-variabl.patch +Patch0079: 0079-libsepol-drop-repeated-semicolons.patch +Patch0080: 0080-libsepol-drop-unnecessary-casts.patch +Patch0081: 0081-libsepol-declare-file-local-variable-static.patch +Patch0082: 0082-libsepol-declare-read-only-arrays-const.patch +Patch0083: 0083-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch +Patch0084: 0084-libsepol-cil-Properly-check-for-loops-in-sets.patch +Patch0085: 0085-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch +Patch0086: 0086-libsepol-cil-Check-for-empty-list-when-marking-never.patch +Patch0087: 0087-libsepol-cil-Reduce-the-initial-symtab-sizes-for-blo.patch +Patch0088: 0088-libsepol-cil-Improve-degenerate-inheritance-check.patch +Patch0089: 0089-libsepol-cil-Add-function-to-determine-if-a-subtree-.patch +Patch0090: 0090-libsepol-cil-Only-reset-AST-if-optional-has-a-declar.patch +Patch0091: 0091-libsepol-cil-make-array-cil_sym_sizes-const.patch +Patch0092: 0092-libsepol-cil-Provide-option-to-allow-qualified-names.patch +Patch0093: 0093-libsepol-cil-do-not-override-previous-results-of-__c.patch +Patch0094: 0094-libsepol-silence-Wextra-semi-stmt-warning.patch +Patch0095: 0095-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch +Patch0096: 0096-libsepol-avoid-unsigned-integer-overflow.patch +Patch0097: 0097-libsepol-ignore-UBSAN-false-positives.patch +Patch0098: 0098-libsepol-avoid-implicit-conversions.patch +Patch0099: 0099-libsepol-assure-string-NUL-termination-of-ibdev_name.patch +Patch0100: 0100-libsepol-cil-Fix-handling-category-sets-in-an-expres.patch +Patch0101: 0101-libsepol-cil-do-not-allow-0-in-quoted-strings.patch +# Patch list end +BuildRequires: make +BuildRequires: gcc +BuildRequires: flex +Obsoletes: %{name}-compat = 3.1-4 + +%description +Security-enhanced Linux is a feature of the Linux® kernel and a number +of utilities with enhanced security functionality designed to add +mandatory access controls to Linux. The Security-enhanced Linux +kernel contains new architectural components originally developed to +improve the security of the Flask operating system. These +architectural components provide general support for the enforcement +of many kinds of mandatory access control policies, including those +based on the concepts of Type Enforcement®, Role-based Access +Control, and Multi-level Security. + +libsepol provides an API for the manipulation of SELinux binary policies. +It is used by checkpolicy (the policy compiler) and similar tools, as well +as by programs like load_policy that need to perform specific transformations +on binary policies such as customizing policy boolean settings. + +%package devel +Summary: Header files and libraries used to build policy manipulation tools +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The libsepol-devel package contains the libraries and header files +needed for developing applications that manipulate binary policies. + +%package static +Summary: static libraries used to build policy manipulation tools +Requires: %{name}-devel%{?_isa} = %{version}-%{release} + +%description static +The libsepol-static package contains the static libraries and header files +needed for developing applications that manipulate binary policies. + +%prep +%autosetup -p 2 -n libsepol-%{version} + +# sparc64 is an -fPIC arch, so we need to fix it here +%ifarch sparc64 +sed -i 's/fpic/fPIC/g' src/Makefile +%endif + +%build +%set_build_flags +CFLAGS="$CFLAGS -fno-semantic-interposition" +%make_build + +%install +mkdir -p ${RPM_BUILD_ROOT}%{_libdir} +mkdir -p ${RPM_BUILD_ROOT}%{_includedir} +mkdir -p ${RPM_BUILD_ROOT}%{_bindir} +mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man3 +mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8 +%make_install LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" +rm -f ${RPM_BUILD_ROOT}%{_bindir}/genpolbools +rm -f ${RPM_BUILD_ROOT}%{_bindir}/genpolusers +rm -f ${RPM_BUILD_ROOT}%{_bindir}/chkcon +rm -rf ${RPM_BUILD_ROOT}%{_mandir}/man8 +rm -rf ${RPM_BUILD_ROOT}%{_mandir}/ru/man8 + +%files static +%{_libdir}/libsepol.a + +%files devel +%{_libdir}/libsepol.so +%{_libdir}/pkgconfig/libsepol.pc +%{_includedir}/sepol/*.h +%{_mandir}/man3/*.3.gz +%dir %{_includedir}/sepol +%dir %{_includedir}/sepol/policydb +%{_includedir}/sepol/policydb/*.h +%dir %{_includedir}/sepol/cil +%{_includedir}/sepol/cil/*.h + +%files +%license COPYING +%{_libdir}/libsepol.so.2 + +%changelog +* Mon Aug 09 2021 Mohan Boddu - 3.2-4 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Wed Jul 28 2021 Petr Lautrbach - 3.2-3 +- Rebase on upstream commit 32611aea6543 + +* Fri Apr 16 2021 Mohan Boddu - 3.2-2 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Mon Mar 8 2021 Petr Lautrbach - 3.2-1 +- SELinux userspace 3.2 release + +* Fri Feb 5 2021 Petr Lautrbach - 3.2-0.rc2.1 +- SELinux userspace 3.2-rc2 release + +* Tue Jan 26 2021 Fedora Release Engineering - 3.2-0.rc1.1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Wed Jan 20 2021 Petr Lautrbach - 3.2-0.rc1.1 +- SELinux userspace 3.2-rc1 release + +* Fri Nov 20 2020 Petr Lautrbach - 3.1-5 +- Drop and obsolete libsepol-compat subpackage +- cil: Give error for more than one true or false block + +* Fri Oct 23 2020 Petr Lautrbach - 3.1-4 +- Drop deprecated functions and duplicated symbols +- Dange library version to libsepol.so.2 +- temporary ship -compat with libsepol.so.1 +- Re-enable LTO flags + +* Mon Jul 27 2020 Petr Lautrbach - 3.1-3 +- Disable LTO cflags +- Drop telinit from % post sciptlet + +* Mon Jul 13 2020 Tom Stellard - 3.1-2 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro +- Use set_build_flags and -fno-semantic-interposition + +* Fri Jul 10 2020 Petr Lautrbach - 3.1-1 +- SELinux userspace 3.1 release + +* Wed Jan 29 2020 Fedora Release Engineering - 3.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Tue Jan 28 2020 Petr Lautrbach - 3.0-2 +- Fix -fno-common issues discovered by GCC 10 + +* Fri Dec 6 2019 Petr Lautrbach - 3.0-1 +- SELinux userspace 3.0 release + +* Mon Nov 11 2019 Petr Lautrbach - 3.0-0.rc.1 +- SELinux userspace 3.0-rc1 release + +* Thu Jul 25 2019 Fedora Release Engineering - 2.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Mon Mar 18 2019 Petr Lautrbach - 2.9-1 +- SELinux userspace 2.9 release + +* Wed Mar 6 2019 Petr Lautrbach - 2.9-0.rc2.1 +- SELinux userspace 2.9-rc2 release + +* Fri Feb 01 2019 Fedora Release Engineering - 2.9-0.rc1.1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Fri Jan 25 2019 Petr Lautrbach - 2.9-0.rc1.1 +- SELinux userspace 2.9-rc1 release + +* Tue Nov 13 2018 Petr Lautrbach - 2.8-3 +- Fix RESOURCE_LEAK coverity scan defects + +* Fri Jul 13 2018 Fedora Release Engineering - 2.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Fri May 25 2018 Petr Lautrbach - 2.8-1 +- SELinux userspace 2.8 release + +* Mon May 14 2018 Petr Lautrbach - 2.8-0.rc3.1 +- SELinux userspace 2.8-rc1 release candidate + +* Mon Apr 23 2018 Petr Lautrbach - 2.0-0.rc1.1 +- SELinux userspace 2.8-rc1 release candidate + +* Wed Mar 21 2018 Petr Lautrbach - 2.7-6 +- Prevent freeing unitialized value in ibendport handling +- Add support for the SCTP portcon keyword +- Export sepol_polcap_getnum/name functions + +* Tue Mar 13 2018 Petr Lautrbach - 2.7-5 +- cil: Create new keep field for type attribute sets +- build: follow standard semantics for DESTDIR and PREFIX +- cil: show an error when cil_expr_to_string() fails + +* Wed Feb 07 2018 Fedora Release Engineering - 2.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Wed Nov 22 2017 Petr Lautrbach - 2.7-3 +- free ibendport device names + +* Fri Oct 20 2017 Petr Lautrbach - 2.7-2 +- reset pointer after free in cil_strpool_destroy() +- cil: Add ability to redeclare types[attributes] +- cil: Keep attributes used by generated attributes in neverallow rules +- use IN6ADDR_ANY_INIT to initialize IPv6 addresses +- fix memory leak in sepol_bool_query() +- cil: drop wrong unused attribute +- cil: fix -Wwrite-strings warning +- cil: __cil_post_db_neverallow_attr_helper() does not use extra_args + +* Mon Aug 07 2017 Petr Lautrbach - 2.7-1 +- Update to upstream release 2017-08-04 + +* Thu Aug 03 2017 Fedora Release Engineering - 2.6-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Sun Jul 30 2017 Florian Weimer - 2.6-4 +- Rebuild with binutils fix for ppc64le (#1475636) + +* Fri Jul 28 2017 Petr Lautrbach - 2.6-3 +- Fix neverallow bug when checking conditional policy +- Destroy the expanded level when mls_semantic_level_expand() fails +- Do not seg fault on sepol_*_key_free(NULL) + +* Wed Jul 26 2017 Fedora Release Engineering - 2.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sun Feb 12 2017 Petr Lautrbach - 2.6-1 +- Update to upstream release 2016-10-14 + +* Fri Feb 10 2017 Fedora Release Engineering - 2.5-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Oct 03 2016 Petr Lautrbach 2.5-10 +- Check for too many permissions in classes and commons in CIL +- Fix xperm mapping between avrule and avtab +- tests: Fix mispelling of optimization option +- Fix unused/uninitialized variables on mac build +- Produce more meaningful error messages for conflicting type rules in CIL +- make "make test" fail when a CUnit test fails +- tests: fix g_b_role_2 test +- Change which attributes CIL keeps in the binary policy +- Port str_read() from kernel and remove multiple occurances of similar code +- Use calloc instead of malloc for all the *_to_val_structs +- Fix bugs found by AFL +- Fix memory leak in expand.c +- Fix invalid read when policy file is corrupt +- Fix possible use of uninitialized variables + +* Mon Aug 01 2016 Petr Lautrbach 2.5-9 +- Warn instead of fail if permission is not resolved +- Ignore object_r when adding userrole mappings to policydb + +* Thu Jul 14 2016 Petr Lautrbach - 2.5-8 +- Add missing return to sepol_node_query() +- Add missing include + +* Thu Jun 23 2016 Petr Lautrbach - 2.5-7 +- Correctly detect unknown classes in sepol_string_to_security_class +- Sort object files for deterministic linking order +- Fix neverallowxperm checking on attributes +- Remove libsepol.map when cleaning +- Add high-level language line marking support to CIL + +* Fri May 06 2016 Petr Lautrbach - 2.5-6 +- Change logic of bounds checking to match change in kernel +- Fix multiple spelling errors + +* Mon May 02 2016 Petr Lautrbach - 2.5-5 +- Only apply bounds checking to source types in rules +- Fix CIL and not add an attribute as a type in the attr_type_map + +* Fri Apr 29 2016 Petr Lautrbach - 2.5-4 +- Build policy on systems not supporting DCCP protocol +- Fix extended permissions neverallow checking +- Fix CIL neverallow and bounds checking +- Android.mk: Add -D_GNU_SOURCE to common_cflags + +* Fri Apr 08 2016 Petr Lautrbach - 2.5-3 +- Fix bug in CIL when resetting classes +- Add support for portcon dccp protocol + +* Sun Feb 28 2016 Petr Lautrbach 2.5-2 +- Use fully versioned arch-specific requires + +* Tue Feb 23 2016 Petr Lautrbach 2.5-1 +- Update to upstream release 2016-02-23 + +* Sun Feb 21 2016 Petr Lautrbach 2.5-0.1.rc1 +- Update to upstream rc1 release 2016-01-07 + +* Thu Feb 04 2016 Fedora Release Engineering - 2.4-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Aug 25 2015 Michal Srb - 2.4-3 +- Improve compatibility with Python 3 SWIG bindings +- Resolves: rhbz#1247714 + +* Fri Aug 14 2015 Adam Jackson 2.4-2 +- Pass ldflags to make so hardening works + +* Mon Apr 13 2015 Petr Lautrbach 2.4-0.1 +- Update to upstream release 2.4 + +* Sun Aug 17 2014 Fedora Release Engineering - 2.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Jul 18 2014 Tom Callaway - 2.3-3 +- fix license handling + +* Sat Jun 07 2014 Fedora Release Engineering - 2.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue May 6 2014 Dan Walsh - 2.3-1 +- Update to upstream + * Improve error message for name-based transition conflicts. + * Revert libsepol: filename_trans: use some better sorting to compare and merge. + * Report source file and line information for neverallow failures. + * Fix valgrind errors in constraint_expr_eval_reason from Richard Haines. + * Add sepol_validate_transition_reason_buffer function from Richard Haines. + +* Thu Oct 31 2013 Dan Walsh - 2.2-1 +- Update to upstream +- Richard Haines patch V1 Allow constraint denials to be determined. +- Add separate role declarations as required by modern checkpolicy. + +* Sat Aug 03 2013 Fedora Release Engineering - 2.1.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu Feb 7 2013 Dan Walsh - 2.1.9-1 +- Update to upstream +- filename_trans: use some better sorting to compare and merge +- coverity fixes +- implement default type policy syntax +- Fix memory leak issues found by Klocwork +- Add CONTRAINT_NAMES to the kernel + +* Sun Jan 27 2013 Dan Walsh - 2.1.8-8 +- Update to latest patches from eparis/Upstream + +* Fri Jan 25 2013 Dan Walsh - 2.1.8-7 +- Update to latest patches from eparis/Upstream + +* Tue Jan 8 2013 Dan Walsh - 2.1.8-6 +- Fix libsepol.stack messages in audit2allow/audit2why + +* Fri Jan 4 2013 Dan Walsh - 2.1.8-5 +- Update to latest patches from eparis/Upstream + +* Tue Nov 27 2012 Dan Walsh - 2.1.8-4 +- Update Richard Haines patch to show constraint information + +* Mon Nov 19 2012 Dan Walsh - 2.1.8-3 +- Add sepol_compute_av_reason_buffer patch from Richard Haines + +* Wed Sep 19 2012 Dan Walsh - 2.1.8-2 +- Revert patch that was attempting to expand filetrans attributes, but is breaking filetrans rules + +* Thu Sep 13 2012 Dan Walsh - 2.1.8-1 +- Update to upstream + * fix neverallow checking on attributes + * Move context_copy() after switch block in ocontext_copy_*(). + * check for missing initial SID labeling statement. + * Add always_check_network policy capability + * role_fix_callback skips out-of-scope roles during expansion. + +* Mon Jul 30 2012 Dan Walsh - 2.1.7-4 +- Try new patches + +* Tue Jul 24 2012 Dan Walsh - 2.1.7-3 +- Revert patches + +* Thu Jul 19 2012 Fedora Release Engineering - 2.1.7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Wed Jul 4 2012 Dan Walsh - 2.1.7-1 +- Update to upstream + * reserve policycapability for redhat testing of ptrace child + * cosmetic changes to make the source easier to read + * prepend instead of append to filename_trans list + * Android/MacOS X build support + * allocate enough space to hold filename in trans rules + +* Mon Apr 23 2012 Dan Walsh - 2.1.5-3 +- Fix off by one error that is causing file_name transition rules to be expanded- incorrectly on i686 machines + +* Tue Apr 17 2012 Dan Walsh - 2.1.5-2 +- Add support for ptrace_child + +* Thu Mar 29 2012 Dan Walsh - 2.1.5-1 +- Update to upstream + * checkpolicy: implement new default labeling behaviors + +* Fri Jan 13 2012 Fedora Release Engineering - 2.1.4-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Dec 21 2011 Dan Walsh - 2.1.4-5 +- Update to match eparis pool + +* Thu Dec 15 2011 Dan Walsh - 2.1.4-4 +- Additional fix for default transitioning labeling for semodule + +* Thu Dec 15 2011 Dan Walsh - 2.1.4-3 +- Add Eparis patch for handling of default transition labeling + +* Mon Dec 5 2011 Dan Walsh - 2.1.4-2 +- Allow policy to specify the source of target for generating the default user,role +- or mls label for a new target. + +* Fri Nov 4 2011 Dan Walsh - 2.1.4-1 +- Update to upstream + * regenerate .pc on VERSION change + * Move ebitmap_* functions from mcstrans to libsepol + * expand: do filename_trans type comparison on mapped representation + +* Mon Oct 31 2011 Dan Walsh - 2.1.3-2 +-The filename_trans code had a bug where duplicate detection was being +done between the unmapped type value of a new rule and the type value of +rules already in policy. This meant that duplicates were not being +silently dropped and were instead outputting a message that there was a +problem. It made things hard because the message WAS using the mapped +type to convert to the string representation, so it didn't look like a +dup! + +* Mon Sep 19 2011 Dan Walsh - 2.1.3-1 +-Update to upstream + * Skip writing role attributes for policy.X and + * Indicate when boolean is indeed a tunable. + * Separate tunable from boolean during compile. + * Write and read TUNABLE flags in related + * Copy and check the cond_bool_datum_t.flags during link. + * Permanently discard disabled branches of tunables in + * Skip tunable identifier and cond_node_t in expansion. + * Create a new preserve_tunables flag + * Preserve tunables when required by semodule program. + * setools expects expand_module_avrules to be an exported + * tree: default make target to all not + +* Thu Sep 15 2011 Dan Walsh - 2.1.2-3 +- Add patch to handle preserving tunables + +* Thu Sep 1 2011 Dan Walsh - 2.1.2-2 +- export expand_module_avrules + +* Thu Aug 18 2011 Dan Walsh - 2.1.2-0 +- Update to upstream + * Only call role_fix_callback for base.p_roles during expansion. + * use mapped role number instead of module role number + +* Mon Aug 1 2011 Dan Walsh 2.1.1-1 +- Update to upstream + * Minor fix to reading policy with filename transition rules + +* Wed Jul 27 2011 Dan Walsh 2.1.0-1 +- Update to upstream + * Release, minor version bump + +* Tue May 3 2011 Dan Walsh 2.0.45-1 +- Update to upstream + * Warn if filename_trans rules are dropped by Steve Lawrence. + +* Thu Apr 21 2011 Dan Walsh 2.0.44-2 +- Fixes for new role_transition class field by Eric Paris. + +* Thu Apr 14 2011 Dan Walsh 2.0.44-1 +-Update to upstream + * Fixes for new role_transition class field by Eric Paris. + * Add libsepol support for filename_trans rules by Eric Paris. + +* Tue Apr 12 2011 Dan Walsh 2.0.43-3 +- re-add Erics patch for filename transitions + +* Tue Apr 12 2011 Dan Walsh 2.0.43-1 +-Update to upstream + * Add new class field in role_transition by Harry Ciao. + +* Tue Mar 29 2011 Dan Walsh 2.0.42-3 +- Apply Eparis Patch + This patch add libsepol support for filename_trans rules. These rules +allow on to make labeling decisions for new objects based partially on +the last path component. They are stored in a list. If we find that +the number of rules grows to an significant size I will likely choose to +store these in a hash, both in libsepol and in the kernel. But as long +as the number of such rules stays small, this should be good. + +* Tue Feb 08 2011 Fedora Release Engineering - 2.0.42-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Dec 21 2010 Dan Walsh 2.0.42-1 +- Upgrade to latest from NSA + * Fix compliation under GCC 4.6 by Justin Mattock + +* Thu Feb 18 2010 Dan Walsh 2.0.41-3 +- Fix libsepol.pc file + +* Thu Jan 28 2010 Dan Walsh 2.0.41-2 +- Resolve specfile problems +Resolves: #555835 + +* Wed Nov 18 2009 Dan Walsh 2.0.41-1 +- Upgrade to latest from NSA + * Fixed typo in error message from Manoj Srivastava. + +* Mon Nov 2 2009 Dan Walsh 2.0.40-1 +- Upgrade to latest from NSA + * Add pkgconfig file from Eamon Walsh. + +* Wed Oct 14 2009 Dan Walsh 2.0.39-1 +- Upgrade to latest from NSA + * Add support for building Xen policies from Paul Nuzzi. + +* Tue Sep 8 2009 Dan Walsh 2.0.38-1 +- Upgrade to latest from NSA + * Check last offset in the module package against the file size. + Reported by Manoj Srivastava for bug filed by Max Kellermann. + +* Sat Jul 25 2009 Fedora Release Engineering - 2.0.37-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jul 7 2009 Dan Walsh 2.0.37-1 +- Upgrade to latest from NSA + * Add method to check disable dontaudit flag from Christopher Pardy. + +* Wed Mar 25 2009 Dan Walsh 2.0.36-1 +- Upgrade to latest from NSA + * Fix boolean state smashing from Joshua Brindle. + +* Thu Mar 5 2009 Dan Walsh 2.0.35-3 +- Fix license specification to be LGPL instead of GPL + +* Wed Feb 25 2009 Fedora Release Engineering - 2.0.35-2 + +* Wed Feb 18 2009 Dan Walsh 2.0.35-1 +- Upgrade to latest from NSA + * Fix alias field in module format, caused by boundary format change + from Caleb Case. + +* Tue Oct 14 2008 Dan Walsh 2.0.34-1 +- Upgrade to latest from NSA + * Add bounds support from KaiGai Kohei. + * Fix invalid aliases bug from Joshua Brindle. + +* Tue Sep 30 2008 Dan Walsh 2.0.33-1 +- Upgrade to latest from NSA + * Revert patch that removed expand_rule. + +* Mon Jul 7 2008 Dan Walsh 2.0.32-1 +- Upgrade to latest from NSA + * Allow require then declare in the source policy from Joshua Brindle. + +* Sun Jun 22 2008 Dan Walsh 2.0.31-1 +- Upgrade to latest from NSA + * Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley. + +* Wed Jun 11 2008 Dan Walsh 2.0.30-1 +- Upgrade to latest from NSA + * Fix endianness bug in the handling of network node addresses from Stephen Smalley. + Only affects big endian platforms. + Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc. + +* Wed May 28 2008 Dan Walsh 2.0.29-1 +- Upgrade to latest from NSA + * Merge user and role mapping support from Joshua Brindle. + +* Mon May 19 2008 Dan Walsh 2.0.28-1 +- Upgrade to latest from NSA + * Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley. + * Belatedly merge test for policy downgrade from Todd Miller. + +* Thu Mar 27 2008 Dan Walsh 2.0.26-1 +- Upgrade to latest from NSA + * Add permissive domain support from Eric Paris. + +* Thu Mar 13 2008 Dan Walsh 2.0.25-1 +- Upgrade to latest from NSA + * Drop unused ->buffer field from struct policy_file. + * Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller. + + +* Thu Feb 28 2008 Dan Walsh 2.0.23-1 +- Upgrade to latest from NSA + * Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley. + * Add support for open_perms policy capability from Eric Paris. + +* Wed Feb 20 2008 Dan Walsh 2.0.21-1 +- Upgrade to latest from NSA + * Fix invalid memory allocation in policydb_index_others() from Jason Tang. + +* Mon Feb 4 2008 Dan Walsh 2.0.20-1 +- Upgrade to latest from NSA + * Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley. + +* Sat Feb 2 2008 Dan Walsh 2.0.19-1 +- Upgrade to latest from NSA + * Add support for consuming avrule_blocks during expansion to reduce + peak memory usage. + +* Mon Jan 21 2008 Dan Walsh 2.0.18-2 +- Fixed for spec review + +* Fri Jan 11 2008 Dan Walsh 2.0.18-1 +- Upgrade to latest from NSA + * Added support for policy capabilities from Todd Miller. + * Prevent generation of policy.18 with MLS enabled from Todd Miller. + +* Mon Dec 10 2007 Dan Walsh 2.0.16-1 +- Upgrade to latest from NSA + * print module magic number in hex on mismatch, from Todd Miller. + +* Fri Nov 30 2007 Dan Walsh 2.0.15-1 +- Upgrade to latest from NSA + * clarify and reduce neverallow error reporting from Stephen Smalley. + +* Tue Nov 6 2007 Dan Walsh 2.0.14-1 +- Upgrade to latest from NSA + * Reject self aliasing at link time from Stephen Smalley. + * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley. + * Fixed bug in require checking from Stephen Smalley. + * Added user hierarchy checking from Todd Miller. + +* Wed Sep 26 2007 Dan Walsh 2.0.11-1 + * Pass CFLAGS to CC even on link command, per Dennis Gilmore. + +* Tue Sep 18 2007 Dan Walsh 2.0.10-1 +- Upgrade to latest from NSA + * Merged support for the handle_unknown policydb flag from Eric Paris. + +* Fri Aug 31 2007 Dan Walsh 2.0.9-1 +- Upgrade to latest from NSA + * Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper. + * Fixed module_package_read_offsets bug introduced by the prior patch. + +* Thu Aug 23 2007 Dan Walsh 2.0.7-1 +- Upgrade to latest from NSA + * Eliminate unaligned accesses from policy reading code from Stephen Smalley. + +* Mon Aug 20 2007 Dan Walsh 2.0.6-1 +- Upgrade to latest from NSA + * Allow dontaudits to be turned off during policy expansion + + +* Fri Aug 10 2007 Dan Walsh 2.0.5-1 +- Upgrade to latest from NSA + * Fix sepol_context_clone to handle a NULL context correctly. + This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL) + to set the file context entry to "<>". +- Apply patch from Joshua Brindle to disable dontaudit rules + + +* Thu Jun 21 2007 Dan Walsh 2.0.4-1 +- Upgrade to latest from NSA + * Merged error handling patch from Eamon Walsh. + +* Tue Apr 17 2007 Dan Walsh 2.0.3-1 +- Upgrade to latest from NSA + * Merged add boolmap argument to expand_module_avrules() from Chris PeBenito. + +* Fri Mar 30 2007 Dan Walsh 2.0.2-1 +- Upgrade to latest from NSA + * Merged fix from Karl to remap booleans at expand time to + avoid holes in the symbol table. + +* Wed Feb 7 2007 Dan Walsh 2.0.1-1 +- Upgrade to latest from NSA + * Merged libsepol segfault fix from Stephen Smalley for when + sensitivities are required but not present in the base. + * Merged patch to add errcodes.h to libsepol by Karl MacMillan. + +* Fri Jan 19 2007 Dan Walsh 1.16.0-1 +- Upgrade to latest from NSA + * Updated version for stable branch. + +* Tue Dec 12 2006 Adam Jackson 1.15.3-1 +- Add dist tag and rebuild, fixes 6 to 7 upgrades. + +* Tue Nov 28 2006 Dan Walsh 1.15.3-1 +- Upgrade to latest from NSA + * Merged patch to compile wit -fPIC instead of -fpic from + Manoj Srivastava to prevent hitting the global offest table + limit. Patch changed to include libselinux and libsemanage in + addition to libselinux. + +* Wed Nov 1 2006 Dan Walsh 1.15.2-1 +- Upgrade to latest from NSA + * Merged fix from Karl MacMillan for a segfault when linking + non-MLS modules with users in them. + +* Tue Oct 24 2006 Dan Walsh 1.15.1-1 +- Upgrade to latest from NSA + * Merged fix for version comparison that was preventing range + transition rules from being written for a version 5 base policy + from Darrel Goeddel. + +* Tue Oct 17 2006 Dan Walsh 1.14-1 +- NSA Released version - Same as previous but changed release number + +* Tue Oct 17 2006 Dan Walsh 1.12.28-1 +- Upgrade to latest from NSA + * Build libsepol's static object files with -fpic + +* Thu Sep 28 2006 Dan Walsh 1.12.27-1 +- Upgrade to latest from NSA + * Merged mls user and range_transition support in modules + from Darrel Goeddel + +* Wed Sep 6 2006 Dan Walsh 1.12.26-1 +- Upgrade to latest from NSA + * Merged range transition enhancements and user format changes + Darrel Goeddel + +* Fri Aug 25 2006 Dan Walsh 1.12.25-3 +- Fix location of include directory to devel package + +* Fri Aug 25 2006 Dan Walsh 1.12.25-2 +- Remove invalid Requires + +* Thu Aug 24 2006 Dan Walsh 1.12.25-1 +- Upgrade to latest from NSA + * Merged conditionally expand neverallows patch from Jeremy Mowery. + * Merged refactor expander patch from Jeremy Mowery. + +* Thu Aug 3 2006 Dan Walsh 1.12.24-1 +- Upgrade to latest from NSA + * Merged libsepol unit tests from Joshua Brindle. + * Merged symtab datum patch from Karl MacMillan. + * Merged netfilter contexts support from Chris PeBenito. + +* Tue Aug 1 2006 Dan Walsh 1.12.21-1 +- Upgrade to latest from NSA + * Merged helpful hierarchy check errors patch from Joshua Brindle. + * Merged semodule_deps patch from Karl MacMillan. + This adds source module names to the avrule decls. + +* Wed Jul 12 2006 Jesse Keating - 1.12.19-1.1 +- rebuild + +* Tue Jul 4 2006 Dan Walsh 1.12.19-1 +- Upgrade to latest from NSA + * Lindent. + * Merged optionals in base take 2 patch set from Joshua Brindle. + +* Tue Jun 13 2006 Bill Nottingham 1.12.17-2 +- bump so it's newer than the FC5 version + +* Mon Jun 5 2006 Dan Walsh 1.12.17-1 +- Upgrade to latest from NSA + * Revert 1.12.16. + * Merged cleaner fix for bool_ids overflow from Karl MacMillan, + replacing the prior patch. + * Merged fixes for several memory leaks in the error paths during + policy read from Serge Hallyn. + +* Tue May 30 2006 Dan Walsh 1.12.14-1 +- Upgrade to latest from NSA + * Fixed bool_ids overflow bug in cond_node_find and cond_copy_list, + based on bug report and suggested fix by Cedric Roux. + * Merged sens_copy_callback, check_role_hierarchy_callback, + and node_from_record fixes from Serge Hallyn. + +* Tue May 23 2006 Dan Walsh 1.12.12-1 +- Upgrade to latest from NSA + * Added sepol_policydb_compat_net() interface for testing whether + a policy requires the compatibility support for network checks + to be enabled in the kernel. + +* Thu May 18 2006 Dan Walsh 1.12.11-1 +- Upgrade to latest from NSA + * Merged patch to initialize sym_val_to_name arrays from Kevin Carr. + Reworked to use calloc in the first place, and converted some other + malloc/memset pairs to calloc calls. + +* Mon May 15 2006 Dan Walsh 1.12.10-1 +- Upgrade to latest from NSA + * Merged patch to revert role/user decl upgrade from Karl MacMillan. + +* Thu May 11 2006 Steve Grubb 1.12.9 +- Couple minor spec file clean ups + +* Mon May 8 2006 Dan Walsh 1.12.9-1 +- Upgrade to latest from NSA + * Dropped tests from all Makefile target. + * Merged fix warnings patch from Karl MacMillan. + * Merged libsepol test framework patch from Karl MacMillan. + +* Mon May 1 2006 Dan Walsh 1.12.6-1 +- Upgrade to latest from NSA + * Fixed cond_normalize to traverse the entire cond list at link time. + +* Wed Apr 5 2006 Dan Walsh 1.12.5-1 +- Upgrade to latest from NSA + * Merged fix for leak of optional package sections from Ivan Gyurdiev. + +* Wed Mar 29 2006 Dan Walsh 1.12.4-1 +- Upgrade to latest from NSA + * Generalize test for bitmap overflow in ebitmap_set_bit. + +* Mon Mar 27 2006 Dan Walsh 1.12.3-1 +- Upgrade to latest from NSA + * Fixed attr_convert_callback and expand_convert_type_set + typemap bug. + +* Fri Mar 24 2006 Dan Walsh 1.12.2-1 +- Upgrade to latest from NSA + * Fixed avrule_block_write num_decls endian bug. + +* Fri Mar 17 2006 Dan Walsh 1.12.1-1 +- Upgrade to latest from NSA + * Fixed sepol_module_package_write buffer overflow bug. + +* Fri Mar 10 2006 Dan Walsh 1.12-2 +- Upgrade to latest from NSA + * Updated version for release. + * Merged cond_evaluate_expr fix from Serge Hallyn (IBM). + * Fixed bug in copy_avrule_list reported by Ivan Gyurdiev. + * Merged sepol_policydb_mls_enabled interface and error handling + changes from Ivan Gyurdiev. + +* Mon Feb 20 2006 Dan Walsh 1.11.18-2 +- Rebuild for fc5-head + +* Fri Feb 17 2006 Dan Walsh 1.11.18-1 +- Upgrade to latest from NSA + * Merged node_expand_addr bugfix and node_compare* change from + Ivan Gyurdiev. + +* Thu Feb 16 2006 Dan Walsh 1.11.17-1 +- Upgrade to latest from NSA + * Merged nodes, ports: always prepend patch from Ivan Gyurdiev. + * Merged bug fix patch from Ivan Gyurdiev. + * Added a defined flag to level_datum_t for use by checkpolicy. + * Merged nodecon support patch from Ivan Gyurdiev. + * Merged cleanups patch from Ivan Gyurdiev. + +* Mon Feb 13 2006 Dan Walsh 1.11.14-2 +- Fix post install not to fire if /dev/initctr does not exist + +* Mon Feb 13 2006 Dan Walsh 1.11.14-1 +- Upgrade to latest from NSA + * Merged optionals in base patch from Joshua Brindle. + +* Fri Feb 10 2006 Jesse Keating - 1.11.13-1.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 7 2006 Dan Walsh 1.11.13-1 +- Upgrade to latest from NSA + * Merged seuser/user_extra support patch from Joshua Brindle. + * Merged fix patch from Ivan Gyurdiev. + +* Tue Feb 07 2006 Jesse Keating - 1.11.12-1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Thu Feb 2 2006 Dan Walsh 1.11.12-1 +- Upgrade to latest from NSA + * Merged assertion copying bugfix from Joshua Brindle. + * Merged sepol_av_to_string patch from Joshua Brindle. + * Merged clone record on set_con patch from Ivan Gyurdiev. + +* Mon Jan 30 2006 Dan Walsh 1.11.10-1 +- Upgrade to latest from NSA + * Merged cond_expr mapping and package section count bug fixes + from Joshua Brindle. + * Merged improve port/fcontext API patch from Ivan Gyurdiev. + * Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev. + +* Fri Jan 13 2006 Dan Walsh 1.11.9-1 +- Upgrade to latest from NSA + * Merged size_t -> unsigned int patch from Ivan Gyurdiev. + +* Tue Jan 10 2006 Dan Walsh 1.11.8-1 +- Upgrade to latest from NSA + * Merged 2nd const in APIs patch from Ivan Gyurdiev. + +* Fri Jan 6 2006 Dan Walsh 1.11.7-1 +- Upgrade to latest from NSA + * Merged const in APIs patch from Ivan Gyurdiev. + * Merged compare2 function patch from Ivan Gyurdiev. + * Fixed hierarchy checker to only check allow rules. + +* Thu Jan 5 2006 Dan Walsh 1.11.5-1 +- Upgrade to latest from NSA + * Merged further fixes from Russell Coker, specifically: + - av_to_string overflow checking + - sepol_context_to_string error handling + - hierarchy checking memory leak fixes and optimizations + - avrule_block_read variable initialization + * Marked deprecated code in genbools and genusers. + +* Thu Jan 5 2006 Dan Walsh 1.11.4-1 +- Upgrade to latest from NSA + * Merged bugfix for sepol_port_modify from Russell Coker. + * Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev. + * Merged port ordering patch from Ivan Gyurdiev. + +* Wed Jan 4 2006 Dan Walsh 1.11.2-2 +- Upgrade to latest from NSA + * Merged patch series from Ivan Gyurdiev. + This includes patches to: + - support ordering of records in compare function + - enable port interfaces + - add interfaces for context validity and range checks + - add include guards + +* Tue Dec 27 2005 Dan Walsh 1.11.1-2 +- Add Ivans patch to make ports work + +* Fri Dec 16 2005 Dan Walsh 1.11.1-1 +- Upgrade to latest from NSA + * Fixed mls_range_cpy bug. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Wed Dec 7 2005 Dan Walsh 1.10-1 +- Upgrade to latest from NSA + +* Mon Dec 5 2005 Dan Walsh 1.9.42-1 +- Upgrade to latest from NSA + * Dropped handle from user_del_role interface. + +* Mon Nov 28 2005 Dan Walsh 1.9.41-1 +- Upgrade to latest from NSA + * Merged remove defrole from sepol patch from Ivan Gyurdiev. + +* Wed Nov 16 2005 Dan Walsh 1.9.40-1 +- Upgrade to latest from NSA + * Merged module function and map file cleanup from Ivan Gyurdiev. + * Merged MLS and genusers cleanups from Ivan Gyurdiev. + +* Wed Nov 9 2005 Dan Walsh 1.9.39-1 +- Upgrade to latest from NSA + Prepare for removal of booleans* and *.users files. + * Cleaned up sepol_genbools to not regenerate the image if + there were no changes in the boolean values, including the + degenerate case where there are no booleans or booleans.local + files. + * Cleaned up sepol_genusers to not warn on missing local.users. + +* Tue Nov 8 2005 Dan Walsh 1.9.38-1 +- Upgrade to latest from NSA + * Removed sepol_port_* from libsepol.map, as the port interfaces + are not yet stable. + +* Mon Nov 7 2005 Dan Walsh 1.9.37-1 +- Upgrade to latest from NSA + * Merged context destroy cleanup patch from Ivan Gyurdiev. + +* Thu Nov 3 2005 Dan Walsh 1.9.36-1 +- Upgrade to latest from NSA + * Merged context_to_string interface change patch from Ivan Gyurdiev. + +* Thu Nov 3 2005 Dan Walsh 1.9.35-1 +- Upgrade to latest from NSA + * Added src/dso.h and src/*_internal.h. + Added hidden_def for exported symbols used within libsepol. + Added hidden for symbols that should not be exported by + the wildcards in libsepol.map. + +* Mon Oct 31 2005 Dan Walsh 1.9.34-1 +- Upgrade to latest from NSA + * Merged record interface, record bugfix, and set_roles patches + from Ivan Gyurdiev. + +* Fri Oct 28 2005 Dan Walsh 1.9.33-1 +- Upgrade to latest from NSA + * Merged count specification change from Ivan Gyurdiev. + +* Wed Oct 26 2005 Dan Walsh 1.9.32-1 +- Upgrade to latest from NSA + * Added further checking and error reporting to + sepol_module_package_read and _info. + * Merged sepol handle passing, DEBUG conversion, and memory leak + fix patches from Ivan Gyurdiev. + +* Tue Oct 25 2005 Dan Walsh 1.9.30-1 +- Upgrade to latest from NSA + * Removed processing of system.users from sepol_genusers and + dropped delusers logic. + * Removed policydb_destroy from error path of policydb_read, + since create/init/destroy/free of policydb is handled by the + caller now. + * Fixed sepol_module_package_read to handle a failed policydb_read + properly. + * Merged query/exists and count patches from Ivan Gyurdiev. + * Merged fix for pruned types in expand code from Joshua Brindle. + * Merged new module package format code from Joshua Brindle. + + +* Mon Oct 24 2005 Dan Walsh 1.9.26-1 +- Upgrade to latest from NSA + * Merged context interface cleanup, record conversion code, + key passing, and bug fix patches from Ivan Gyurdiev. + +* Fri Oct 21 2005 Dan Walsh 1.9.25-1 +- Upgrade to latest from NSA + * Merged users cleanup patch from Ivan Gyurdiev. + * Merged user record memory leak fix from Ivan Gyurdiev. + * Merged reorganize users patch from Ivan Gyurdiev. + +- Need to check for /sbin/telinit + +* Tue Oct 18 2005 Dan Walsh 1.9.23-1 +- Upgrade to latest from NSA + * Added check flag to expand_module() to control assertion + and hierarchy checking on expansion. + * Reworked check_assertions() and hierarchy_check_constraints() + to take handles and use callback-based error reporting. + * Changed expand_module() to call check_assertions() and + hierarchy_check_constraints() prior to returning the expanded + policy. + +* Tue Oct 18 2005 Dan Walsh 1.9.21-1 +- Upgrade to latest from NSA + * Changed sepol_module_package_set_file_contexts to copy the + file contexts data since it is internally managed. + * Added sepol_policy_file_set_handle interface to associate + a handle with a policy file. + * Added handle argument to policydb_from_image/to_image. + * Added sepol_module_package_set_file_contexts interface. + * Dropped sepol_module_package_create_file interface. + * Reworked policydb_read/write, policydb_from_image/to_image, + and sepol_module_package_read/write to use callback-based error + reporting system rather than DEBUG. + +* Tue Oct 18 2005 Dan Walsh 1.9.19-1 +- Upgrade to latest from NSA + * Reworked link_packages, link_modules, and expand_module to use + callback-based error reporting system rather than error buffering. + +* Sat Oct 15 2005 Dan Walsh 1.9.18-1 +- Upgrade to latest from NSA + * Merged conditional expression mapping fix in the module linking + code from Joshua Brindle. + +* Fri Oct 14 2005 Dan Walsh 1.9.17-2 +- Tell init to reexec itself in post script + +* Mon Oct 10 2005 Dan Walsh 1.9.17-1 +- Upgrade to latest from NSA + * Hid sepol_module_package type definition, and added get interfaces. + * Merged new callback-based error reporting system from Ivan + Gyurdiev. + * Merged support for require blocks inside conditionals from + Joshua Brindle (Tresys). + +* Mon Oct 10 2005 Dan Walsh 1.9.14.1-1 +- Upgrade to latest from NSA + * Fixed use of policydb_from_image/to_image to ensure proper + init of policydb. + * Isolated policydb internal headers under . + These headers should only be used by users of the static libsepol. + Created new with new public types and interfaces + for shared libsepol. + Created new with public types and interfaces moved + or wrapped from old module.h, link.h, and expand.h, adjusted for + new public types for policydb and policy_file. + Added public interfaces to libsepol.map. + Some implementation changes visible to users of the static libsepol: + 1) policydb_read no longer calls policydb_init. + Caller must do so first. + 2) policydb_init no longer takes policy_type argument. + Caller must set policy_type separately. + 3) expand_module automatically enables the global branch. + Caller no longer needs to do so. + 4) policydb_write uses the policy_type and policyvers from the + policydb itself, and sepol_set_policyvers() has been removed. + +* Fri Oct 7 2005 Dan Walsh 1.9.12-1 +- Upgrade to latest from NSA + * Merged function renaming and static cleanup from Ivan Gyurdiev. + +* Thu Oct 6 2005 Dan Walsh 1.9.11-1 +- Upgrade to latest from NSA + * Merged bug fix for check_assertions handling of no assertions + from Joshua Brindle (Tresys). + +* Tue Oct 4 2005 Dan Walsh 1.9.10-1 +- Upgrade to latest from NSA + * Merged iterate patch from Ivan Gyurdiev. + * Merged MLS in modules patch from Joshua Brindle (Tresys). + +* Mon Oct 3 2005 Dan Walsh 1.9.8-1 +- Upgrade to latest from NSA + * Merged pointer typedef elimination patch from Ivan Gyurdiev. + * Merged user list function, new mls functions, and bugfix patch + from Ivan Gyurdiev. + +* Wed Sep 28 2005 Dan Walsh 1.9.7-1 +- Upgrade to latest from NSA + * Merged sepol_get_num_roles fix from Karl MacMillan (Tresys). + +* Fri Sep 23 2005 Dan Walsh 1.9.6-1 +- Upgrade to latest from NSA + * Merged bug fix patches from Joshua Brindle (Tresys). + +* Wed Sep 21 2005 Dan Walsh 1.9.5-1 +- Upgrade to latest from NSA + * Merged boolean record and memory leak fix patches from Ivan + Gyurdiev. + +* Tue Sep 20 2005 Dan Walsh 1.9.4-1 +- Upgrade to latest from NSA + * Merged interface record patch from Ivan Gyurdiev. + +* Thu Sep 15 2005 Dan Walsh 1.9.3-1 +- Upgrade to latest from NSA + * Merged fix for sepol_enable/disable_debug from Ivan + Gyurdiev. + +* Wed Sep 14 2005 Dan Walsh 1.9.1-2 +- Upgrade to latest from NSA + * Merged stddef.h patch and debug conversion patch from + Ivan Gyurdiev. + +* Mon Sep 12 2005 Dan Walsh 1.9.1-1 +- Upgrade to latest from NSA + * Fixed expand_avtab and expand_cond_av_list to keep separate + entries with identical keys but different enabled flags. + * Updated version for release. + +* Thu Sep 1 2005 Dan Walsh 1.7.24-1 +- Upgrade to latest from NSA + * Fixed symtab_insert return value for duplicate declarations. + * Merged fix for memory error in policy_module_destroy from + Jason Tang (Tresys). + +* Mon Aug 29 2005 Dan Walsh 1.7.22-1 +- Upgrade to latest from NSA + * Merged fix for memory leak in sepol_context_to_sid from + Jason Tang (Tresys). + * Merged fixes for resource leaks on error paths and + change to scope_destroy from Joshua Brindle (Tresys). + +* Tue Aug 23 2005 Dan Walsh 1.7.20-1 +- Upgrade to latest from NSA + * Merged more fixes for resource leaks on error paths + from Serge Hallyn (IBM). Bugs found by Coverity. + +* Fri Aug 19 2005 Dan Walsh 1.7.19-1 +- Upgrade to latest from NSA + * Changed to treat all type conflicts as fatal errors. + * Merged several error handling fixes from + Serge Hallyn (IBM). Bugs found by Coverity. + +* Mon Aug 15 2005 Dan Walsh 1.7.17-1 +- Upgrade to latest from NSA + * Fixed several memory leaks found by valgrind. + +* Sun Aug 14 2005 Dan Walsh 1.7.15-1 +- Upgrade to latest from NSA + * Fixed empty list test in cond_write_av_list. Bug found by + Coverity, reported by Serge Hallyn (IBM). + * Merged patch to policydb_write to check errors + when writing the type->attribute reverse map from + Serge Hallyn (IBM). Bug found by Coverity. + * Fixed policydb_destroy to properly handle NULL type_attr_map + or attr_type_map. + +* Sat Aug 13 2005 Dan Walsh 1.7.14-1 +- Upgrade to latest from NSA + * Fixed empty list test in cond_write_av_list. Bug found by + Coverity, reported by Serge Hallyn (IBM). + * Merged patch to policydb_write to check errors + when writing the type->attribute reverse map from + Serge Hallyn (IBM). Bug found by Coverity. + * Fixed policydb_destroy to properly handle NULL type_attr_map + or attr_type_map. + + +* Thu Aug 11 2005 Dan Walsh 1.7.13-1 +- Upgrade to latest from NSA + * Improved memory use by SELinux by both reducing the avtab + node size and reducing the number of avtab nodes (by not + expanding attributes in TE rules when possible). Added + expand_avtab and expand_cond_av_list functions for use by + assertion checker, hierarchy checker, compatibility code, + and dispol. Added new inline ebitmap operators and converted + existing users of ebitmaps to the new operators for greater + efficiency. + Note: The binary policy format version has been incremented to + version 20 as a result of these changes. + +* Thu Aug 11 2005 Dan Walsh 1.7.12-1 +- Upgrade to latest from NSA + * Fixed bug in constraint_node_clone handling of name sets. + +* Wed Aug 10 2005 Dan Walsh 1.7.11-1 +- Upgrade to latest from NSA + * Fix range_trans_clone to map the type values properly. + +* Fri Aug 5 2005 Dan Walsh 1.7.10-1 +- Upgrade to latest from NSA + * Merged patch to move module read/write code from libsemanage + to libsepol from Jason Tang (Tresys). + +* Tue Aug 2 2005 Dan Walsh 1.7.9-1 +- Upgrade to latest from NSA + * Enabled further compiler warning flags and fixed them. + * Merged user, context, port records patch from Ivan Gyurdiev. + * Merged key extract function patch from Ivan Gyurdiev. + * Merged mls_context_to_sid bugfix from Ivan Gyurdiev. + +* Wed Jul 27 2005 Dan Walsh 1.7.6-2 +- Fix MLS Free + +* Mon Jul 25 2005 Dan Walsh 1.7.6-1 +- Upgrade to latest from NSA + * Merged context reorganization, memory leak fixes, + port and interface loading, replacements for genusers and + genbools, debug traceback, and bugfix patches from Ivan Gyurdiev. + * Merged uninitialized variable bugfix from Dan Walsh. + +* Mon Jul 25 2005 Dan Walsh 1.7.5-2 +- Fix unitialized variable problem + +* Mon Jul 18 2005 Dan Walsh 1.7.5-1 +- Upgrade to latest from NSA + * Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat). + * Removed genpolbools and genpolusers utilities. + * Merged hierarchy check fix from Joshua Brindle (Tresys). + + + +* Thu Jul 14 2005 Dan Walsh 1.7.3-1 +- Upgrade to latest from NSA + * Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat). + * Merged genbools debugging message cleanup from Red Hat. + +* Thu Jul 7 2005 Dan Walsh 1.7-2 +- Remove genpolbools and genpoluser + +* Thu Jul 7 2005 Dan Walsh 1.7-1 +- Upgrade to latest from NSA + * Merged loadable module support from Tresys Technology. + +* Wed Jun 29 2005 Dan Walsh 1.6-1 +- Upgrade to latest from NSA + * Updated version for release. + +* Tue May 17 2005 Dan Walsh 1.5.10-1 +- Fix reset booleans warning message +- Upgrade to latest from NSA + * License changed to LGPL v2.1, see COPYING. + +* Tue May 17 2005 Dan Walsh 1.5.9-2 +- Upgrade to latest from NSA + * Added sepol_genbools_policydb and sepol_genusers_policydb for + audit2why. + +* Mon May 16 2005 Dan Walsh 1.5.8-2 +- export sepol_context_to_sid + +* Mon May 16 2005 Dan Walsh 1.5.8-1 +- Upgrade to latest from NSA + * Added sepol_ prefix to Flask types to avoid + namespace collision with libselinux. + +* Fri May 13 2005 Dan Walsh 1.5.7-1 +- Upgrade to latest from NSA + * Added sepol_compute_av_reason() for audit2why. + +* Tue Apr 26 2005 Dan Walsh 1.5.6-1 +- Upgrade to latest from NSA + * Fixed bug in role hierarchy checker. + +* Mon Apr 25 2005 Dan Walsh 1.5.5-2 +- Fixes found via intel compiler + +* Thu Apr 14 2005 Dan Walsh 1.5.5-1 +- Update from NSA + +* Tue Mar 29 2005 Dan Walsh 1.5.3-1 +- Update from NSA + +* Thu Mar 24 2005 Dan Walsh 1.5.2-2 +- Handle booleans.local + +* Thu Mar 17 2005 Dan Walsh 1.5.2-1 +- Update to latest from NSA + * Added man page for sepol_check_context. + * Added man page for sepol_genusers function. + * Merged man pages for genpolusers and chkcon from Manoj Srivastava. + +* Thu Mar 10 2005 Dan Walsh 1.4-1 +- Update to latest from NSA + +* Tue Mar 8 2005 Dan Walsh 1.3.8-1 +- Update to latest from NSA + * Cleaned up error handling in sepol_genusers and sepol_genbools. + +* Tue Mar 1 2005 Dan Walsh 1.3.7-1 +- Update to latest from NSA + * Merged sepol_debug and fclose patch from Dan Walsh. + +* Fri Feb 18 2005 Dan Walsh 1.3.6-3 +- Make sure local_files file pointer is closed +- Stop outputing error messages + +* Thu Feb 17 2005 Dan Walsh 1.3.6-1 +- Update to latest from NSA + * Changed sepol_genusers to also use getline and correctly handle + EOL. +* Thu Feb 17 2005 Dan Walsh 1.3.5-1 +- Update to latest from NSA + * Merged endianness and compute_av patches from Darrel Goeddel (TCS). + * Merged range_transition support from Darrel Goeddel (TCS). + * Added sepol_genusers function. + +* Thu Feb 10 2005 Dan Walsh 1.3.2-1 +- Update to latest from NSA + * Changed relabel Makefile target to use restorecon. + +* Mon Feb 7 2005 Dan Walsh 1.3.1-1 +- Update to latest from NSA + * Merged enhanced MLS support from Darrel Goeddel (TCS). + +* Thu Jan 20 2005 Dan Walsh 1.2.1.1-1 +- Update to latest from NSA + * Merged build fix patch from Manoj Srivastava. + +* Thu Nov 4 2004 Dan Walsh 1.2.1-1 +- Update to latest from NSA + +* Mon Aug 30 2004 Dan Walsh 1.1.1-2 +- Add optargs for build + +* Sun Aug 22 2004 Dan Walsh 1.1.1-1 +- New version from NSA + +* Fri Aug 20 2004 Colin Walters 1.0-2 +- Apply Stephen's chkcon patch + +* Thu Aug 19 2004 Colin Walters 1.0-1 +- New upstream version + +* Mon Aug 16 2004 Dan Walsh 0.4.2-1 +- Newversion from upstream implementing stringcase compare + +* Fri Aug 13 2004 Bill Nottingham 0.4.1-2 +- ldconfig tweaks + +* Thu Aug 12 2004 Dan Walsh 0.4.1-1 +- Ignore case of true/false + +* Wed Aug 11 2004 Dan Walsh 0.4.1-1 +- New version from NSA + +* Tue Aug 10 2004 Dan Walsh 0.3.1-1 +- Initial version +- Created by Stephen Smalley + +