[PATCH 2/2 v2] libsepol: Validate scope index class_perm_map array
James Carter <[email protected]> Thu, 23 Jul 2026 15:18:05 -0400
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
In addtion to the array of ebitmaps that shows which declarations are in scope for a given block, the scope index also contains an array of ebitmaps, class_perms_map, that shows which permissions are in scope for each class and it contains the length of that array. An optional block has a required scope. For a required scope validate that the array is long enough to contain all of the classes that are in scope for the block and that for each class in the array either the permission ebitmap is empty (the class is not required in the block) or contains at least one valid permission. [Older compilers could set all the bits if "*" was used.] For declared scopes, verify that the length of the class permissions ebitmap array is 0 and the array itself is NULL. Signed-off-by: James Carter <[email protected]> --- v2: Move assignment of class and map to after the validate_value() check to make sanitizers happy. libsepol/src/policydb_validate.c | 45 +++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 166e20a5..2d7c3e71 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -1690,10 +1690,9 @@ bad: static int validate_scope_index(sepol_handle_t *handle, const scope_index_t *scope_index, - validate_t flavors[]) + const policydb_t *p, validate_t flavors[], + bool required) { - uint32_t i; - if (!ebitmap_is_empty(&scope_index->scope[SYM_COMMONS])) goto bad; if (validate_ebitmap(&scope_index->p_classes_scope, @@ -1712,9 +1711,37 @@ static int validate_scope_index(sepol_handle_t *handle, if (validate_ebitmap(&scope_index->p_cat_scope, &flavors[SYM_CATS])) goto bad; - for (i = 0; i < scope_index->class_perms_len; i++) - if (validate_value(i + 1, &flavors[SYM_CLASSES])) + if (required) { + uint32_t i; + if (ebitmap_highest_set_bit(&scope_index->p_classes_scope) >= + scope_index->class_perms_len) + goto bad; + for (i = 0; i < scope_index->class_perms_len; i++) { + const ebitmap_t *map; + class_datum_t *class; + ebitmap_node_t *node; + unsigned int bit = 0; + if (validate_value(i + 1, &flavors[SYM_CLASSES])) + goto bad; + map = &scope_index->class_perms_map[i]; + class = p->class_val_to_struct[i]; + /* Either there are no perms */ + if (ebitmap_is_empty(map)) + continue; + /* Or at least one valid perm */ + ebitmap_for_each_positive_bit(map, node, bit) { + if (bit < class->permissions.nprim) + break; + } + if (bit >= class->permissions.nprim) + goto bad; + } + } else { + if (scope_index->class_perms_len != 0) + goto bad; + if (scope_index->class_perms_map != NULL) goto bad; + } return 0; @@ -1786,11 +1813,11 @@ static int validate_avrule_blocks(sepol_handle_t *handle, if (validate_range_trans_rules( handle, decl->range_tr_rules, flavors)) goto bad; - if (validate_scope_index(handle, &decl->required, - flavors)) + if (validate_scope_index(handle, &decl->required, p, + flavors, true)) goto bad; - if (validate_scope_index(handle, &decl->declared, - flavors)) + if (validate_scope_index(handle, &decl->declared, p, + flavors, false)) goto bad; if (validate_filename_trans_rules( handle, decl->filename_trans_rules, p, -- 2.55.0