From 043b991eed94aa8b59a59039108bb06014f0fcb5 Mon Sep 17 00:00:00 2001 From: wjiang Date: Mon, 17 Mar 2025 09:35:56 +0800 Subject: [PATCH] backport patches from upstream (cherry picked from commit 8d05d529161f16aa0b0edaf5ded4bc94d79fb4ce) --- ...k-the-right-bits-of-an-ibpkeycon-rul.patch | 36 +++ ...icy-Fix-MLS-users-in-optional-blocks.patch | 173 +++++++++++++ ...d-leak-of-identifier-on-required-att.patch | 45 ++++ ...avoid-memory-leaks-on-redeclarations.patch | 230 +++++++++++++++++ ...k-allocation-and-free-memory-on-erro.patch | 63 +++++ ...licy-check-identifier-before-copying.patch | 55 ++++ ...heckpolicy-clean-expression-on-error.patch | 237 ++++++++++++++++++ ...kpolicy-cleanup-identifiers-on-error.patch | 196 +++++++++++++++ ...icy-cleanup-resources-on-parse-error.patch | 86 +++++++ ...ee-complete-role_allow_rule-on-error.patch | 40 +++ ...rt-checkpolicy-free-ebitmap-on-error.patch | 57 +++++ ...ee-identifiers-on-invalid-typebounds.patch | 39 +++ ...eckpolicy-free-temporary-bounds-type.patch | 55 ++++ ...checkpolicy-handle-unprintable-token.patch | 50 ++++ ...policy-include-ctype.h-for-isprint-3.patch | 46 ++++ ...-return-YYerror-on-invalid-character.patch | 36 +++ ...licy-use-YYerror-only-when-available.patch | 59 +++++ checkpolicy.spec | 22 +- 18 files changed, 1524 insertions(+), 1 deletion(-) create mode 100644 backport-checkpolicy-Check-the-right-bits-of-an-ibpkeycon-rul.patch create mode 100644 backport-checkpolicy-Fix-MLS-users-in-optional-blocks.patch create mode 100644 backport-checkpolicy-avoid-leak-of-identifier-on-required-att.patch create mode 100644 backport-checkpolicy-avoid-memory-leaks-on-redeclarations.patch create mode 100644 backport-checkpolicy-check-allocation-and-free-memory-on-erro.patch create mode 100644 backport-checkpolicy-check-identifier-before-copying.patch create mode 100644 backport-checkpolicy-clean-expression-on-error.patch create mode 100644 backport-checkpolicy-cleanup-identifiers-on-error.patch create mode 100644 backport-checkpolicy-cleanup-resources-on-parse-error.patch create mode 100644 backport-checkpolicy-free-complete-role_allow_rule-on-error.patch create mode 100644 backport-checkpolicy-free-ebitmap-on-error.patch create mode 100644 backport-checkpolicy-free-identifiers-on-invalid-typebounds.patch create mode 100644 backport-checkpolicy-free-temporary-bounds-type.patch create mode 100644 backport-checkpolicy-handle-unprintable-token.patch create mode 100644 backport-checkpolicy-include-ctype.h-for-isprint-3.patch create mode 100644 backport-checkpolicy-return-YYerror-on-invalid-character.patch create mode 100644 backport-checkpolicy-use-YYerror-only-when-available.patch diff --git a/backport-checkpolicy-Check-the-right-bits-of-an-ibpkeycon-rul.patch b/backport-checkpolicy-Check-the-right-bits-of-an-ibpkeycon-rul.patch new file mode 100644 index 0000000..f3f09c1 --- /dev/null +++ b/backport-checkpolicy-Check-the-right-bits-of-an-ibpkeycon-rul.patch @@ -0,0 +1,36 @@ +From 84a33fb96b4876a49bfb739b9a2160d88e015209 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 8 Jul 2024 12:50:32 -0400 +Subject: [PATCH] checkpolicy: Check the right bits of an ibpkeycon rule subnet + prefix + +The lower 64 bits of the subnet prefix for an ibpkeycon rule should +all be 0's. Unfortunately the check uses the s6_addr macro which refers +to the 16 entry array of 8-bit values in the union and does not refer +to the correct bits. + +Use the s6_addr32 macro instead which refers to the 4 entry array of +32-bit values in the union and refers to the lower 64 bits. + +Signed-off-by: James Carter +Acked-by: Stephen Smalley +--- + policy_define.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/policy_define.c b/policy_define.c +index 4931f23d..bfeda86b 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -5092,7 +5092,7 @@ int define_ibpkey_context(unsigned int low, unsigned int high) + goto out; + } + +- if (subnet_prefix.s6_addr[2] || subnet_prefix.s6_addr[3]) { ++ if (subnet_prefix.s6_addr32[2] || subnet_prefix.s6_addr32[3]) { + yyerror("subnet prefix should be 0's in the low order 64 bits."); + rc = -1; + goto out; +-- +2.33.0 + diff --git a/backport-checkpolicy-Fix-MLS-users-in-optional-blocks.patch b/backport-checkpolicy-Fix-MLS-users-in-optional-blocks.patch new file mode 100644 index 0000000..3fba9e5 --- /dev/null +++ b/backport-checkpolicy-Fix-MLS-users-in-optional-blocks.patch @@ -0,0 +1,173 @@ +From 6f2b689f63ec7c3fe51ee420d0046a870bd5f496 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Aug 2024 10:29:44 -0400 +Subject: [PATCH] checkpolicy: Fix MLS users in optional blocks + +When a user is created in an optional block, a user datum is added +to both the avrule_decl's symtab and the policydb's symtab, but +the semantic MLS information is only added to the avrule_decl's +user datum. This causes an error to occur during policy expansion +when user_copy_callback() is called. If this error did not occur +then the policydb's user datum would be written without any MLS +info and the policy would fail validation when read later. + +When creating a user datum, search for a user datum with the same +key in the policydb's symtab. If that datum has no MLS information, +then copy the MLS information from the avrule_decl's datum. If it +does, then compare the default level, low level, and high level +sensitivities and give an error if they do not match. There is not +enough information to expand the categories for the high and low +levels, so merge the semantic categories. If the two category sets +are not equal an error will occur during the expansion phase. + +A minimum policy to demonstrate the bug: +class CLASS1 +sid kernel +class CLASS1 { PERM1 } +sensitivity SENS1; +dominance { SENS1 } +level SENS1; +mlsconstrain CLASS1 { PERM1 } ((h1 dom h2) and (l1 domby h1)); +type TYPE1; +allow TYPE1 self : CLASS1 PERM1; +role ROLE1; +role ROLE1 types TYPE1; +optional { + require { + role ROLE1; + } + user USER2 roles ROLE1 level SENS1 range SENS1; +} +user USER1 roles ROLE1 level SENS1 range SENS1; +sid kernel USER1:ROLE1:TYPE1:SENS1 + +Signed-off-by: James Carter +--- + policy_define.c | 72 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 71 insertions(+), 1 deletion(-) + +diff --git a/policy_define.c b/policy_define.c +index f8a10154..af30da90 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -4231,6 +4231,50 @@ static int parse_categories(char *id, level_datum_t * levdatum, ebitmap_t * cats + return 0; + } + ++static int mls_semantic_cats_merge(mls_semantic_cat_t ** dst, ++ const mls_semantic_cat_t * src) ++{ ++ mls_semantic_cat_t *new; ++ ++ while (src) { ++ new = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); ++ if (!new) ++ return -1; ++ ++ mls_semantic_cat_init(new); ++ new->low = src->low; ++ new->high = src->high; ++ new->next = *dst; ++ *dst = new; ++ ++ src = src->next; ++ } ++ ++ return 0; ++} ++ ++static int mls_add_or_check_level(mls_semantic_level_t *dst, const mls_semantic_level_t *src) ++{ ++ if (!dst->sens) { ++ if (mls_semantic_level_cpy(dst, src) < 0) { ++ yyerror("out of memory"); ++ return -1; ++ } ++ } else { ++ if (dst->sens != src->sens) { ++ return -1; ++ } ++ /* Duplicate cats won't cause problems, but different cats will ++ * result in an error during expansion */ ++ if (mls_semantic_cats_merge(&dst->cat, src->cat) < 0) { ++ yyerror("out of memory"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int parse_semantic_categories(char *id, level_datum_t * levdatum __attribute__ ((unused)), + mls_semantic_cat_t ** cats) + { +@@ -4289,7 +4333,7 @@ static int parse_semantic_categories(char *id, level_datum_t * levdatum __attrib + int define_user(void) + { + char *id; +- user_datum_t *usrdatum; ++ user_datum_t *usrdatum, *usr_global; + level_datum_t *levdatum; + int l; + +@@ -4314,10 +4358,16 @@ int define_user(void) + return 0; + } + ++ id = strdup(queue_head(id_queue)); ++ + if ((usrdatum = declare_user()) == NULL) { ++ free(id); + return -1; + } + ++ usr_global = hashtab_search(policydbp->p_users.table, (hashtab_key_t) id); ++ free(id); ++ + while ((id = queue_remove(id_queue))) { + if (set_user_roles(&usrdatum->roles, id)) + continue; +@@ -4344,6 +4394,7 @@ int define_user(void) + usrdatum->dfltlevel.sens = levdatum->level->sens; + + while ((id = queue_remove(id_queue))) { ++ /* This will add to any already existing categories */ + if (parse_semantic_categories(id, levdatum, + &usrdatum->dfltlevel.cat)) { + free(id); +@@ -4369,6 +4420,7 @@ int define_user(void) + usrdatum->range.level[l].sens = levdatum->level->sens; + + while ((id = queue_remove(id_queue))) { ++ /* This will add to any already existing categories */ + if (parse_semantic_categories(id, levdatum, + &usrdatum->range.level[l].cat)) { + free(id); +@@ -4389,6 +4441,24 @@ int define_user(void) + return -1; + } + } ++ ++ if (usr_global && usr_global != usrdatum) { ++ if (mls_add_or_check_level(&usr_global->dfltlevel, ++ &usrdatum->dfltlevel)) { ++ yyerror("Problem with user default level"); ++ return -1; ++ } ++ if (mls_add_or_check_level(&usr_global->range.level[0], ++ &usrdatum->range.level[0])) { ++ yyerror("Problem with user low level"); ++ return -1; ++ } ++ if (mls_add_or_check_level(&usr_global->range.level[1], ++ &usrdatum->range.level[1])) { ++ yyerror("Problem with user high level"); ++ return -1; ++ } ++ } + } + return 0; + } +-- +2.33.0 + diff --git a/backport-checkpolicy-avoid-leak-of-identifier-on-required-att.patch b/backport-checkpolicy-avoid-leak-of-identifier-on-required-att.patch new file mode 100644 index 0000000..4acda66 --- /dev/null +++ b/backport-checkpolicy-avoid-leak-of-identifier-on-required-att.patch @@ -0,0 +1,45 @@ +From 77747a36a9afd4b9e27af608301487b44d681b4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Wed, 6 Nov 2024 11:49:06 +0100 +Subject: [PATCH] checkpolicy: avoid leak of identifier on required attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Example policy generated by fuzzer: + + class s + sid k + class s { i } + optional{ + require{ + attribute i; + } + } + type m; + typealias m alias i; + + typeai + +Reported-by: oss-fuzz (issue 377576480) +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_define.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/policy_define.c b/policy_define.c +index dc404530..9ae8c4d4 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -1288,6 +1288,7 @@ static int add_aliases_to_type(type_datum_t * type) + aliasdatum->primary = type->s.value; + aliasdatum->flavor = TYPE_ALIAS; + ++ free(id); + break; + } + default:{ +-- +2.33.0 + diff --git a/backport-checkpolicy-avoid-memory-leaks-on-redeclarations.patch b/backport-checkpolicy-avoid-memory-leaks-on-redeclarations.patch new file mode 100644 index 0000000..f66dbe2 --- /dev/null +++ b/backport-checkpolicy-avoid-memory-leaks-on-redeclarations.patch @@ -0,0 +1,230 @@ +From beca1ee16b291e1556bc905498cc814898edc07d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 5 Nov 2024 22:06:18 +0100 +Subject: [PATCH] checkpolicy: avoid memory leaks on redeclarations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If declare_symbol() returns 1 the id and the datum are already defined +and not consumed by the function, so it they must be free'd by the +caller. + +Example policy (generated by fuzzer): + + class s sid e class s{i}optional{require{bool K;}bool K true; + +Reported-by: oss-fuzz (issue 377544445) +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + module_compiler.c | 2 +- + module_compiler.h | 2 +- + policy_define.c | 72 +++++++++++++++++++++++------------ + 3 files changed, 49 insertions(+), 27 deletions(-) + +diff --git a/module_compiler.c b/module_compiler.c +index 4efd77bf..3a7ad1bb 100644 +--- a/module_compiler.c ++++ b/module_compiler.c +@@ -195,7 +195,7 @@ static int create_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_ + * not be restricted pointers. */ + int declare_symbol(uint32_t symbol_type, + hashtab_key_t key, hashtab_datum_t datum, +- uint32_t * dest_value, uint32_t * datum_value) ++ uint32_t * dest_value, const uint32_t * datum_value) + { + avrule_decl_t *decl = stack_top->decl; + int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_DECL); +diff --git a/module_compiler.h b/module_compiler.h +index e43bc6c0..2fe3455d 100644 +--- a/module_compiler.h ++++ b/module_compiler.h +@@ -28,7 +28,7 @@ int define_policy(int pass, int module_header_given); + */ + int declare_symbol(uint32_t symbol_type, + hashtab_key_t key, hashtab_datum_t datum, +- uint32_t * dest_value, uint32_t * datum_value); ++ uint32_t * dest_value, const uint32_t * datum_value); + + role_datum_t *declare_role(unsigned char isattr); + type_datum_t *declare_type(unsigned char primary, unsigned char isattr); +diff --git a/policy_define.c b/policy_define.c +index af30da90..dc404530 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -148,9 +148,9 @@ static int id_has_dot(const char *id) + + int define_class(void) + { +- char *id = 0; +- class_datum_t *datum = 0; +- int ret; ++ char *id = NULL; ++ class_datum_t *datum = NULL; ++ int ret = -1; + uint32_t value; + + if (pass == 2) { +@@ -167,27 +167,29 @@ int define_class(void) + datum = (class_datum_t *) malloc(sizeof(class_datum_t)); + if (!datum) { + yyerror("out of memory"); +- goto bad; ++ goto cleanup; + } + memset(datum, 0, sizeof(class_datum_t)); + ret = declare_symbol(SYM_CLASSES, id, datum, &value, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); +- goto bad; ++ goto cleanup; + } + case -2:{ + yyerror2("duplicate declaration of class %s", id); +- goto bad; ++ goto cleanup; + } + case -1:{ + yyerror("could not declare class here"); +- goto bad; ++ goto cleanup; + } +- case 0: +- case 1:{ ++ case 0: { + break; + } ++ case 1:{ ++ goto cleanup; ++ } + default:{ + assert(0); /* should never get here */ + } +@@ -195,12 +197,10 @@ int define_class(void) + datum->s.value = value; + return 0; + +- bad: +- if (id) +- free(id); +- if (datum) +- free(datum); +- return -1; ++ cleanup: ++ free(id); ++ free(datum); ++ return ret == 1 ? 0 : -1; + } + + int define_permissive(void) +@@ -773,8 +773,13 @@ int define_sens(void) + yyerror("could not declare sensitivity level here"); + goto bad; + } +- case 0: ++ case 0: { ++ break; ++ } + case 1:{ ++ level_datum_destroy(datum); ++ free(datum); ++ free(id); + break; + } + default:{ +@@ -814,8 +819,13 @@ int define_sens(void) + ("could not declare sensitivity alias here"); + goto bad_alias; + } +- case 0: ++ case 0: { ++ break; ++ } + case 1:{ ++ level_datum_destroy(aliasdatum); ++ free(aliasdatum); ++ free(id); + break; + } + default:{ +@@ -944,15 +954,20 @@ int define_category(void) + yyerror("could not declare category here"); + goto bad; + } +- case 0: ++ case 0:{ ++ datum->s.value = value; ++ break; ++ } + case 1:{ ++ cat_datum_destroy(datum); ++ free(datum); ++ free(id); + break; + } + default:{ + assert(0); /* should never get here */ + } + } +- datum->s.value = value; + + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { +@@ -968,11 +983,11 @@ int define_category(void) + } + cat_datum_init(aliasdatum); + aliasdatum->isalias = TRUE; +- aliasdatum->s.value = datum->s.value; ++ aliasdatum->s.value = value; + + ret = + declare_symbol(SYM_CATS, id, aliasdatum, NULL, +- &datum->s.value); ++ &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); +@@ -988,8 +1003,13 @@ int define_category(void) + ("could not declare category aliases here"); + goto bad_alias; + } +- case 0: ++ case 0:{ ++ break; ++ } + case 1:{ ++ cat_datum_destroy(aliasdatum); ++ free(aliasdatum); ++ free(id); + break; + } + default:{ +@@ -1811,10 +1831,12 @@ int define_bool_tunable(int is_tunable) + yyerror("could not declare boolean here"); + goto cleanup; + } +- case 0: +- case 1:{ ++ case 0:{ + break; + } ++ case 1:{ ++ goto cleanup; ++ } + default:{ + assert(0); /* should never get here */ + } +@@ -1832,7 +1854,7 @@ int define_bool_tunable(int is_tunable) + return 0; + cleanup: + cond_destroy_bool(id, datum, NULL); +- return -1; ++ return ret == 1 ? 0 : -1; + } + + avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl) +-- +2.33.0 + diff --git a/backport-checkpolicy-check-allocation-and-free-memory-on-erro.patch b/backport-checkpolicy-check-allocation-and-free-memory-on-erro.patch new file mode 100644 index 0000000..994aa3d --- /dev/null +++ b/backport-checkpolicy-check-allocation-and-free-memory-on-erro.patch @@ -0,0 +1,63 @@ +From 770ad3ecac91f59c3e3296ac63a7001630f98d86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:54:57 +0100 +Subject: [PATCH] checkpolicy: check allocation and free memory on error at + type definition +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 +--- + policy_define.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/policy_define.c b/policy_define.c +index 053156df..ec19da9d 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -1400,7 +1400,7 @@ int define_typeattribute(void) + return 0; + } + +-static int define_typebounds_helper(char *bounds_id, char *type_id) ++static int define_typebounds_helper(const char *bounds_id, const char *type_id) + { + type_datum_t *bounds, *type; + +@@ -1483,15 +1483,26 @@ int define_type(int alias) + * old name based hierarchy. + */ + if ((id = queue_remove(id_queue))) { +- char *bounds, *delim; ++ const char *delim; ++ ++ if ((delim = strrchr(id, '.'))) { ++ int ret; ++ char *bounds = strdup(id); ++ if (!bounds) { ++ yyerror("out of memory"); ++ free(id); ++ return -1; ++ } + +- if ((delim = strrchr(id, '.')) +- && (bounds = strdup(id))) { + bounds[(size_t)(delim - id)] = '\0'; + +- if (define_typebounds_helper(bounds, id)) +- return -1; ++ ret = define_typebounds_helper(bounds, id); + free(bounds); ++ if (ret) { ++ free(id); ++ return -1; ++ } ++ + } + free(id); + } +-- +2.33.0 + diff --git a/backport-checkpolicy-check-identifier-before-copying.patch b/backport-checkpolicy-check-identifier-before-copying.patch new file mode 100644 index 0000000..14d9b26 --- /dev/null +++ b/backport-checkpolicy-check-identifier-before-copying.patch @@ -0,0 +1,55 @@ +From 158fb95ef28af13ccc8a6f1474aaa2e69620afd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Wed, 15 Jan 2025 14:13:25 +0100 +Subject: [PATCH] checkpolicy: check identifier before copying +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid calling strdup(3) with a NULL pointer, which can happen with an +invalid policy context, e.g.: + + class C + sid S + class C { P } + ; + user U roles j; + sid S s:l:q:q:q + +Fixes: 6f2b689f ("checkpolicy: Fix MLS users in optional blocks") +Reported-by: oss-fuzz (issue 390004173) +Signed-off-by: Christian Göttsche +--- + policy_define.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/policy_define.c b/policy_define.c +index 2f811b67..96a481f7 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -4355,6 +4355,7 @@ static int parse_semantic_categories(char *id, level_datum_t * levdatum __attrib + + int define_user(void) + { ++ const char *username; + char *id; + user_datum_t *usrdatum, *usr_global; + level_datum_t *levdatum; +@@ -4381,7 +4382,13 @@ int define_user(void) + return 0; + } + +- id = strdup(queue_head(id_queue)); ++ username = queue_head(id_queue); ++ if (!username) { ++ yyerror("no user name"); ++ return -1; ++ } ++ ++ id = strdup(username); + + if ((usrdatum = declare_user()) == NULL) { + free(id); +-- +2.33.0 + diff --git a/backport-checkpolicy-clean-expression-on-error.patch b/backport-checkpolicy-clean-expression-on-error.patch new file mode 100644 index 0000000..1db022d --- /dev/null +++ b/backport-checkpolicy-clean-expression-on-error.patch @@ -0,0 +1,237 @@ +From 187e75849e045636f02ff3a91ae5a67fa6855b92 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:54:58 +0100 +Subject: [PATCH] checkpolicy: clean expression on error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The passed expression needs to be transferred into the policy or free'd +by the sink functions define_constraint() and define_validatetrans(). + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_define.c | 68 ++++++++++++++++++++++--------------- + 1 file changed, 40 insertions(+), 28 deletions(-) + +diff --git a/policy_define.c b/policy_define.c +index ec19da9d..97582630 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -3529,20 +3529,22 @@ int define_constraint(constraint_expr_t * expr) + return 0; + } + ++ ebitmap_init(&classmap); ++ + depth = -1; + for (e = expr; e; e = e->next) { + switch (e->expr_type) { + case CEXPR_NOT: + if (depth < 0) { + yyerror("illegal constraint expression"); +- return -1; ++ goto bad; + } + break; + case CEXPR_AND: + case CEXPR_OR: + if (depth < 1) { + yyerror("illegal constraint expression"); +- return -1; ++ goto bad; + } + depth--; + break; +@@ -3550,51 +3552,48 @@ int define_constraint(constraint_expr_t * expr) + case CEXPR_NAMES: + if (e->attr & CEXPR_XTARGET) { + yyerror("illegal constraint expression"); +- return -1; /* only for validatetrans rules */ ++ goto bad; /* only for validatetrans rules */ + } + if (depth == (CEXPR_MAXDEPTH - 1)) { + yyerror("constraint expression is too deep"); +- return -1; ++ goto bad; + } + depth++; + break; + default: + yyerror("illegal constraint expression"); +- return -1; ++ goto bad; + } + } + if (depth != 0) { + yyerror("illegal constraint expression"); +- return -1; ++ goto bad; + } + +- ebitmap_init(&classmap); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + free(id); +- return -1; ++ goto bad; + } + cladatum = + (class_datum_t *) hashtab_search(policydbp->p_classes.table, + (hashtab_key_t) id); + if (!cladatum) { + yyerror2("class %s is not defined", id); +- ebitmap_destroy(&classmap); + free(id); +- return -1; ++ goto bad; + } + if (ebitmap_set_bit(&classmap, cladatum->s.value - 1, TRUE)) { + yyerror("out of memory"); +- ebitmap_destroy(&classmap); + free(id); +- return -1; ++ goto bad; + } + node = malloc(sizeof(struct constraint_node)); + if (!node) { + yyerror("out of memory"); + free(node); +- return -1; ++ goto bad; + } + memset(node, 0, sizeof(constraint_node_t)); + if (useexpr) { +@@ -3606,7 +3605,7 @@ int define_constraint(constraint_expr_t * expr) + if (!node->expr) { + yyerror("out of memory"); + free(node); +- return -1; ++ goto bad; + } + node->permissions = 0; + +@@ -3642,8 +3641,7 @@ int define_constraint(constraint_expr_t * expr) + yyerror2("permission %s is not" + " defined", id); + free(id); +- ebitmap_destroy(&classmap); +- return -1; ++ goto bad; + } + } + node->permissions |= (UINT32_C(1) << (perdatum->s.value - 1)); +@@ -3654,6 +3652,13 @@ int define_constraint(constraint_expr_t * expr) + ebitmap_destroy(&classmap); + + return 0; ++ ++bad: ++ ebitmap_destroy(&classmap); ++ if (useexpr) ++ constraint_expr_destroy(expr); ++ ++ return -1; + } + + int define_validatetrans(constraint_expr_t * expr) +@@ -3672,20 +3677,22 @@ int define_validatetrans(constraint_expr_t * expr) + return 0; + } + ++ ebitmap_init(&classmap); ++ + depth = -1; + for (e = expr; e; e = e->next) { + switch (e->expr_type) { + case CEXPR_NOT: + if (depth < 0) { + yyerror("illegal validatetrans expression"); +- return -1; ++ goto bad; + } + break; + case CEXPR_AND: + case CEXPR_OR: + if (depth < 1) { + yyerror("illegal validatetrans expression"); +- return -1; ++ goto bad; + } + depth--; + break; +@@ -3693,47 +3700,45 @@ int define_validatetrans(constraint_expr_t * expr) + case CEXPR_NAMES: + if (depth == (CEXPR_MAXDEPTH - 1)) { + yyerror("validatetrans expression is too deep"); +- return -1; ++ goto bad; + } + depth++; + break; + default: + yyerror("illegal validatetrans expression"); +- return -1; ++ goto bad; + } + } + if (depth != 0) { + yyerror("illegal validatetrans expression"); +- return -1; ++ goto bad; + } + +- ebitmap_init(&classmap); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + free(id); +- return -1; ++ goto bad; + } + cladatum = + (class_datum_t *) hashtab_search(policydbp->p_classes.table, + (hashtab_key_t) id); + if (!cladatum) { + yyerror2("class %s is not defined", id); +- ebitmap_destroy(&classmap); + free(id); +- return -1; ++ goto bad; + } + if (ebitmap_set_bit(&classmap, (cladatum->s.value - 1), TRUE)) { + yyerror("out of memory"); +- ebitmap_destroy(&classmap); + free(id); +- return -1; ++ goto bad; + } + + node = malloc(sizeof(struct constraint_node)); + if (!node) { + yyerror("out of memory"); +- return -1; ++ free(id); ++ goto bad; + } + memset(node, 0, sizeof(constraint_node_t)); + if (useexpr) { +@@ -3753,6 +3758,13 @@ int define_validatetrans(constraint_expr_t * expr) + ebitmap_destroy(&classmap); + + return 0; ++ ++bad: ++ ebitmap_destroy(&classmap); ++ if (useexpr) ++ constraint_expr_destroy(expr); ++ ++ return -1; + } + + uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) +-- +2.33.0 + diff --git a/backport-checkpolicy-cleanup-identifiers-on-error.patch b/backport-checkpolicy-cleanup-identifiers-on-error.patch new file mode 100644 index 0000000..2e8ccd9 --- /dev/null +++ b/backport-checkpolicy-cleanup-identifiers-on-error.patch @@ -0,0 +1,196 @@ +From b75bf48b42d93bf03211eeb176495dbc667d4e99 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:54:55 +0100 +Subject: [PATCH] checkpolicy: cleanup identifiers on error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Free identifiers removed from the queue but not yet owned by the policy +on errors. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_define.c | 32 ++++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/policy_define.c b/policy_define.c +index 260e609d..db7e9d0e 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -343,6 +343,7 @@ static int read_classes(ebitmap_t *e_classes) + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); ++ free(id); + return -1; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); +@@ -374,15 +375,18 @@ int define_default_user(int which) + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); ++ free(id); + return -1; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s", id); ++ free(id); + return -1; + } + if (cladatum->default_user && cladatum->default_user != which) { + yyerror2("conflicting default user information for class %s", id); ++ free(id); + return -1; + } + cladatum->default_user = which; +@@ -406,15 +410,18 @@ int define_default_role(int which) + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); ++ free(id); + return -1; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s", id); ++ free(id); + return -1; + } + if (cladatum->default_role && cladatum->default_role != which) { + yyerror2("conflicting default role information for class %s", id); ++ free(id); + return -1; + } + cladatum->default_role = which; +@@ -438,15 +445,18 @@ int define_default_type(int which) + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); ++ free(id); + return -1; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s", id); ++ free(id); + return -1; + } + if (cladatum->default_type && cladatum->default_type != which) { + yyerror2("conflicting default type information for class %s", id); ++ free(id); + return -1; + } + cladatum->default_type = which; +@@ -470,15 +480,18 @@ int define_default_range(int which) + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); ++ free(id); + return -1; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s", id); ++ free(id); + return -1; + } + if (cladatum->default_range && cladatum->default_range != which) { + yyerror2("conflicting default range information for class %s", id); ++ free(id); + return -1; + } + cladatum->default_range = which; +@@ -509,6 +522,7 @@ int define_common_perms(void) + comdatum = hashtab_search(policydbp->p_commons.table, id); + if (comdatum) { + yyerror2("duplicate declaration for common %s\n", id); ++ free(id); + return -1; + } + comdatum = (common_datum_t *) malloc(sizeof(common_datum_t)); +@@ -771,12 +785,14 @@ int define_sens(void) + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { + yyerror("sensitivity aliases may not contain periods"); +- goto bad_alias; ++ free(id); ++ return -1; + } + aliasdatum = (level_datum_t *) malloc(sizeof(level_datum_t)); + if (!aliasdatum) { + yyerror("out of memory"); +- goto bad_alias; ++ free(id); ++ return -1; + } + level_datum_init(aliasdatum); + aliasdatum->isalias = TRUE; +@@ -941,12 +957,14 @@ int define_category(void) + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { + yyerror("category aliases may not contain periods"); +- goto bad_alias; ++ free(id); ++ return -1; + } + aliasdatum = (cat_datum_t *) malloc(sizeof(cat_datum_t)); + if (!aliasdatum) { + yyerror("out of memory"); +- goto bad_alias; ++ free(id); ++ return -1; + } + cat_datum_init(aliasdatum); + aliasdatum->isalias = TRUE; +@@ -3807,6 +3825,7 @@ uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) + if (!is_id_in_scope(SYM_USERS, id)) { + yyerror2("user %s is not within scope", + id); ++ free(id); + constraint_expr_destroy(expr); + return 0; + } +@@ -3818,6 +3837,7 @@ uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) + id); + if (!user) { + yyerror2("unknown user %s", id); ++ free(id); + constraint_expr_destroy(expr); + return 0; + } +@@ -3827,6 +3847,7 @@ uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) + yyerror2("role %s is not within scope", + id); + constraint_expr_destroy(expr); ++ free(id); + return 0; + } + role = +@@ -3838,6 +3859,7 @@ uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) + if (!role) { + yyerror2("unknown role %s", id); + constraint_expr_destroy(expr); ++ free(id); + return 0; + } + val = role->s.value; +@@ -3850,11 +3872,13 @@ uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) + } else { + yyerror("invalid constraint expression"); + constraint_expr_destroy(expr); ++ free(id); + return 0; + } + if (ebitmap_set_bit(&expr->names, val - 1, TRUE)) { + yyerror("out of memory"); + ebitmap_destroy(&expr->names); ++ free(id); + constraint_expr_destroy(expr); + return 0; + } +-- +2.33.0 + diff --git a/backport-checkpolicy-cleanup-resources-on-parse-error.patch b/backport-checkpolicy-cleanup-resources-on-parse-error.patch new file mode 100644 index 0000000..0a4d2ae --- /dev/null +++ b/backport-checkpolicy-cleanup-resources-on-parse-error.patch @@ -0,0 +1,86 @@ +From c2fc48be68ee466207d870137681896b0b544691 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:54:54 +0100 +Subject: [PATCH] checkpolicy: cleanup resources on parse error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Close the input file and free all memory by the queue and lexer on a +syntax or parse error. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + parse_util.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/parse_util.c b/parse_util.c +index 8c1f393..5f92730 100644 +--- a/parse_util.c ++++ b/parse_util.c +@@ -26,6 +26,7 @@ extern FILE *yyin; + extern void init_parser(int); + extern int yyparse(void); + extern void yyrestart(FILE *); ++extern int yylex_destroy(void); + extern queue_t id_queue; + extern unsigned int policydb_errors; + extern policydb_t *policydbp; +@@ -34,6 +35,8 @@ extern void set_source_file(const char *name); + + int read_source_policy(policydb_t * p, const char *file, const char *progname) + { ++ int rc = -1; ++ + yyin = fopen(file, "r"); + if (!yyin) { + fprintf(stderr, "%s: unable to open %s: %s\n", progname, file, strerror(errno)); +@@ -41,20 +44,21 @@ int read_source_policy(policydb_t * p, const char *file, const char *progname) + } + set_source_file(file); + +- if ((id_queue = queue_create()) == NULL) { ++ id_queue = queue_create(); ++ if (id_queue == NULL) { + fprintf(stderr, "%s: out of memory!\n", progname); +- return -1; ++ goto cleanup; + } + +- policydbp = p; + mlspol = p->mls; ++ policydbp = p; + + init_parser(1); + if (yyparse() || policydb_errors) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + progname); +- return -1; ++ goto cleanup; + } + rewind(yyin); + init_parser(2); +@@ -64,11 +68,15 @@ int read_source_policy(policydb_t * p, const char *file, const char *progname) + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + progname); +- return -1; ++ goto cleanup; + } +- queue_destroy(id_queue); + ++ rc = 0; ++ ++cleanup: ++ queue_destroy(id_queue); + fclose(yyin); ++ yylex_destroy(); + +- return 0; ++ return rc; + } +-- +2.33.0 + diff --git a/backport-checkpolicy-free-complete-role_allow_rule-on-error.patch b/backport-checkpolicy-free-complete-role_allow_rule-on-error.patch new file mode 100644 index 0000000..ee0a607 --- /dev/null +++ b/backport-checkpolicy-free-complete-role_allow_rule-on-error.patch @@ -0,0 +1,40 @@ +From 652e28838c1af8adf442dee8a805a65c1e58353a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 2 Apr 2024 17:29:25 +0200 +Subject: [PATCH] checkpolicy: free complete role_allow_rule on error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Free the ebitmaps inside the rolesets on error. + +Reported-by: oss-fuzz (issue 67769) +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_define.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/policy_define.c b/policy_define.c +index 4fc6c417..1c019a3b 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -3301,6 +3301,7 @@ int define_role_allow(void) + + while ((id = queue_remove(id_queue))) { + if (set_roles(&ra->roles, id)) { ++ role_allow_rule_destroy(ra); + free(ra); + return -1; + } +@@ -3308,6 +3309,7 @@ int define_role_allow(void) + + while ((id = queue_remove(id_queue))) { + if (set_roles(&ra->new_roles, id)) { ++ role_allow_rule_destroy(ra); + free(ra); + return -1; + } +-- +2.33.0 + diff --git a/backport-checkpolicy-free-ebitmap-on-error.patch b/backport-checkpolicy-free-ebitmap-on-error.patch new file mode 100644 index 0000000..749370d --- /dev/null +++ b/backport-checkpolicy-free-ebitmap-on-error.patch @@ -0,0 +1,57 @@ +From 8b115c45ad116030d29bb2b84a268e4083d7548c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:54:56 +0100 +Subject: [PATCH] checkpolicy: free ebitmap on error +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 +--- + policy_define.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/policy_define.c b/policy_define.c +index db7e9d0e..053156df 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -2516,6 +2516,8 @@ static int define_te_avtab_helper(int which, avrule_t ** rule) + int add = 1, ret = 0; + int suppress = 0; + ++ ebitmap_init(&tclasses); ++ + avrule = (avrule_t *) malloc(sizeof(avrule_t)); + if (!avrule) { + yyerror("memory error"); +@@ -2562,7 +2564,6 @@ static int define_te_avtab_helper(int which, avrule_t ** rule) + } + } + +- ebitmap_init(&tclasses); + ret = read_classes(&tclasses); + if (ret) + goto out; +@@ -2639,8 +2640,6 @@ static int define_te_avtab_helper(int which, avrule_t ** rule) + free(id); + } + +- ebitmap_destroy(&tclasses); +- + avrule->perms = perms; + *rule = avrule; + +@@ -2649,6 +2648,9 @@ static int define_te_avtab_helper(int which, avrule_t ** rule) + avrule_destroy(avrule); + free(avrule); + } ++ ++ ebitmap_destroy(&tclasses); ++ + return ret; + + } +-- +2.33.0 + diff --git a/backport-checkpolicy-free-identifiers-on-invalid-typebounds.patch b/backport-checkpolicy-free-identifiers-on-invalid-typebounds.patch new file mode 100644 index 0000000..70a592c --- /dev/null +++ b/backport-checkpolicy-free-identifiers-on-invalid-typebounds.patch @@ -0,0 +1,39 @@ +From 9f2f9e28475abfaf9c2c756726f6f829c9183308 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Sat, 30 Mar 2024 14:35:01 +0100 +Subject: [PATCH] checkpolicy: free identifiers on invalid typebounds +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Free the two identifiers on an invalid typebounds in the error branch, +similar to the success branch. + +Reported-by: oss-fuzz (issue 67700) +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_define.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/policy_define.c b/policy_define.c +index 0cf938ea..92d1e5f2 100644 +--- a/policy_define.c ++++ b/policy_define.c +@@ -1462,8 +1462,12 @@ int define_typebounds(void) + } + + while ((id = queue_remove(id_queue))) { +- if (define_typebounds_helper(bounds, id)) ++ if (define_typebounds_helper(bounds, id)) { ++ free(bounds); ++ free(id); + return -1; ++ } ++ + free(id); + } + free(bounds); +-- +2.33.0 + diff --git a/backport-checkpolicy-free-temporary-bounds-type.patch b/backport-checkpolicy-free-temporary-bounds-type.patch new file mode 100644 index 0000000..31dfb39 --- /dev/null +++ b/backport-checkpolicy-free-temporary-bounds-type.patch @@ -0,0 +1,55 @@ +From 63207ce82e8ea515704731c908945e8a90fa6843 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 22 Jan 2024 14:55:05 +0100 +Subject: [PATCH] checkpolicy: free temporary bounds type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Free the temporary bounds type in the error branches. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + module_compiler.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/module_compiler.c b/module_compiler.c +index 119b7e36..464897cc 100644 +--- a/module_compiler.c ++++ b/module_compiler.c +@@ -233,6 +233,7 @@ static int role_implicit_bounds(hashtab_t roles_tab, + if (!bounds) { + yyerror2("role %s doesn't exist, is implicit bounds of %s", + bounds_id, role_id); ++ free(bounds_id); + return -1; + } + +@@ -242,6 +243,7 @@ static int role_implicit_bounds(hashtab_t roles_tab, + yyerror2("role %s has inconsistent bounds %s/%s", + role_id, bounds_id, + policydbp->p_role_val_to_name[role->bounds - 1]); ++ free(bounds_id); + return -1; + } + free(bounds_id); +@@ -478,6 +480,7 @@ static int user_implicit_bounds(hashtab_t users_tab, + if (!bounds) { + yyerror2("user %s doesn't exist, is implicit bounds of %s", + bounds_id, user_id); ++ free(bounds_id); + return -1; + } + +@@ -487,6 +490,7 @@ static int user_implicit_bounds(hashtab_t users_tab, + yyerror2("user %s has inconsistent bounds %s/%s", + user_id, bounds_id, + policydbp->p_role_val_to_name[user->bounds - 1]); ++ free(bounds_id); + return -1; + } + free(bounds_id); +-- +2.33.0 + diff --git a/backport-checkpolicy-handle-unprintable-token.patch b/backport-checkpolicy-handle-unprintable-token.patch new file mode 100644 index 0000000..6ceff14 --- /dev/null +++ b/backport-checkpolicy-handle-unprintable-token.patch @@ -0,0 +1,50 @@ +From 39b3cc51350a4ba670f9f38493311ec316e4d84d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 22 Mar 2024 15:50:49 +0100 +Subject: [PATCH] checkpolicy: handle unprintable token +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In case the erroneous token is unprintable, e.g. a control character, +print its hex value instead. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_scan.l | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/policy_scan.l b/policy_scan.l +index 5a6fbaa..30d081e 100644 +--- a/policy_scan.l ++++ b/policy_scan.l +@@ -314,6 +314,16 @@ GLBLUB { return(GLBLUB); } + %% + int yyerror(const char *msg) + { ++ const char *token; ++ char buf[8]; ++ ++ if (isprint((unsigned char)yytext[0])) { ++ token = yytext; ++ } else { ++ snprintf(buf, sizeof(buf), "%#x", yytext[0]); ++ token = buf; ++ } ++ + if (source_file[0]) + fprintf(stderr, "%s:%ld:", + source_file, source_lineno); +@@ -321,7 +331,7 @@ int yyerror(const char *msg) + fprintf(stderr, "(unknown source)::"); + fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n", + msg, +- yytext, ++ token, + policydb_lineno, + linebuf[0], linebuf[1]); + policydb_errors++; +-- +2.33.0 + diff --git a/backport-checkpolicy-include-ctype.h-for-isprint-3.patch b/backport-checkpolicy-include-ctype.h-for-isprint-3.patch new file mode 100644 index 0000000..2023839 --- /dev/null +++ b/backport-checkpolicy-include-ctype.h-for-isprint-3.patch @@ -0,0 +1,46 @@ +From 0ffe97479c8e4ac720526a368bb23f3e6ed9b71a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 2 Apr 2024 17:29:20 +0200 +Subject: [PATCH] checkpolicy: include for isprint(3) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Include the necessary header for isprint(3) to avoid an implicit +function declaration: + + policy_scan.l: In function ‘yyerror’: + policy_scan.l:342:13: warning: implicit declaration of function ‘isprint’ [-Wimplicit-function-declaration] + 342 | if (isprint((unsigned char)yytext[0])) { + | ^~~~~~~ + policy_scan.l:36:1: note: include ‘’ or provide a declaration of ‘isprint’ + 35 | #include "y.tab.h" + +++ |+#include + 36 | #endif + +This does not currently break the build cause -Werror is stripped for +the parsing code to avoid breakage on old flex/bison versions that might +not generate warning free code. + +Fixes: 39b3cc51350a ("checkpolicy: handle unprintable token") +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_scan.l | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/policy_scan.l b/policy_scan.l +index d7cf2896..62f28c11 100644 +--- a/policy_scan.l ++++ b/policy_scan.l +@@ -22,6 +22,7 @@ + + %{ + #include ++#include + #include + #include + #include +-- +2.33.0 + diff --git a/backport-checkpolicy-return-YYerror-on-invalid-character.patch b/backport-checkpolicy-return-YYerror-on-invalid-character.patch new file mode 100644 index 0000000..bfcfec1 --- /dev/null +++ b/backport-checkpolicy-return-YYerror-on-invalid-character.patch @@ -0,0 +1,36 @@ +From f4330d57705205b52ec117803bf8543a2e59bb00 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 11 Mar 2024 15:57:04 +0100 +Subject: [PATCH] checkpolicy: return YYerror on invalid character +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Inform bison about an invalid character by returning YYerror, so the +parser can cleanup internal state and return the failure via yyparse(). +Currently the error is only observable via the global variable +policydb_errors, which needs to be checked separately. + +Reported-by: oss-fuzz (issue #67270) +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_scan.l | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/policy_scan.l b/policy_scan.l +index 19c05a58..1926129c 100644 +--- a/policy_scan.l ++++ b/policy_scan.l +@@ -303,7 +303,7 @@ GLBLUB { return(GLBLUB); } + "]" | + "~" | + "*" { return(yytext[0]); } +-. { yyerror("unrecognized character");} ++. { yyerror("unrecognized character"); return YYerror; } + %% + int yyerror(const char *msg) + { +-- +2.33.0 + diff --git a/backport-checkpolicy-use-YYerror-only-when-available.patch b/backport-checkpolicy-use-YYerror-only-when-available.patch new file mode 100644 index 0000000..c63dd3c --- /dev/null +++ b/backport-checkpolicy-use-YYerror-only-when-available.patch @@ -0,0 +1,59 @@ +From ca77c5929905216fb1c0f70ed632664aa3ec85a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 22 Mar 2024 15:50:48 +0100 +Subject: [PATCH] checkpolicy: use YYerror only when available +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The special error value YYerror is only available since bison 3.6 +(released 2020). For example the version used by oss-fuzz does not +support it. + +Use a special token in case YYerror is not available. Only downside is +a duplicate error message, one from the manual yyerror() call and one +from within bison for the unexpected special token (which would be +omitted by using YYerror). + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + policy_parse.y | 1 + + policy_scan.l | 9 ++++++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/policy_parse.y b/policy_parse.y +index e0103502..1b275ebc 100644 +--- a/policy_parse.y ++++ b/policy_parse.y +@@ -155,6 +155,7 @@ typedef int (* require_func_t)(int pass); + %token FILESYSTEM + %token DEFAULT_USER DEFAULT_ROLE DEFAULT_TYPE DEFAULT_RANGE + %token LOW_HIGH LOW HIGH GLBLUB ++%token INVALID_CHAR + + %left OR + %left XOR +diff --git a/policy_scan.l b/policy_scan.l +index 1926129c..c4d8e937 100644 +--- a/policy_scan.l ++++ b/policy_scan.l +@@ -303,7 +303,14 @@ GLBLUB { return(GLBLUB); } + "]" | + "~" | + "*" { return(yytext[0]); } +-. { yyerror("unrecognized character"); return YYerror; } ++. { yyerror("unrecognized character"); ++/* Available since bison 3.6, avoids duplicate error message */ ++#ifdef YYerror ++ return YYerror; ++#else ++ return INVALID_CHAR; ++#endif ++ } + %% + int yyerror(const char *msg) + { +-- +2.33.0 + diff --git a/checkpolicy.spec b/checkpolicy.spec index d1b7176..bfb276c 100644 --- a/checkpolicy.spec +++ b/checkpolicy.spec @@ -1,6 +1,6 @@ Name: checkpolicy Version: 3.3 -Release: 3 +Release: 4 Summary: SELinux policy compiler License: GPLv2 URL: https://github.com/SELinuxProject/selinux @@ -8,6 +8,23 @@ Source0: https://github.com/SELinuxProject/selinux/releases/download/3.3/c Patch0: backport-checkpolicy-Improve-error-message-for-type-bounds.patch Patch1: backport-checkpolicy-delete-invalid-spaces.patch +Patch2: backport-checkpolicy-cleanup-resources-on-parse-error.patch +Patch3: backport-checkpolicy-cleanup-identifiers-on-error.patch +Patch4: backport-checkpolicy-free-ebitmap-on-error.patch +Patch5: backport-checkpolicy-check-allocation-and-free-memory-on-erro.patch +Patch6: backport-checkpolicy-clean-expression-on-error.patch +Patch7: backport-checkpolicy-free-temporary-bounds-type.patch +Patch8: backport-checkpolicy-return-YYerror-on-invalid-character.patch +Patch9: backport-checkpolicy-use-YYerror-only-when-available.patch +Patch10: backport-checkpolicy-handle-unprintable-token.patch +Patch11: backport-checkpolicy-free-identifiers-on-invalid-typebounds.patch +Patch12: backport-checkpolicy-include-ctype.h-for-isprint-3.patch +Patch13: backport-checkpolicy-free-complete-role_allow_rule-on-error.patch +Patch14: backport-checkpolicy-Check-the-right-bits-of-an-ibpkeycon-rul.patch +Patch15: backport-checkpolicy-Fix-MLS-users-in-optional-blocks.patch +Patch16: backport-checkpolicy-avoid-leak-of-identifier-on-required-att.patch +Patch17: backport-checkpolicy-avoid-memory-leaks-on-redeclarations.patch +Patch18: backport-checkpolicy-check-identifier-before-copying.patch BuildRequires: gcc byacc bison flex flex-static libsepol-static >= %{version} libselinux-devel >= %{version} git @@ -57,6 +74,9 @@ install test/dispol %{buildroot}%{_bindir}/sedispol %{_mandir}/*/* %changelog +* Fri Mar 14 2025 wangjiang - 3.3-4 +- backport patches from upstream + * Sat Mar 11 2023 zhangchenfeng - 3.3-3 - backport upstrem bugfix -- Gitee