Re: [PATCH] selinux: reject a permission value exceeding the class permission count

[email protected] Fri, 24 Jul 2026 15:18:22 +0000
Newsgroups org.kernel.vger.selinux
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] The patch prevents an out-of-bounds write for class-specific permissions but fails to address the identical vulnerability when a class inherits permissions from a common. If a malicious policy declares a common with a large `nprim` and a class that inherits it but specifies a small `nprim`, the common permissions will bypass the patch's check and map to out-of-bounds indices in `security_get_permissions()`.
- [High] NULL pointer dereference in selinuxfs when a policy contains gaps in permission or class values. If a policy defines a sparse set of values (e.g., `nprim` is 3, but only values 1 and 3 are populated), `security_get_permissions()` leaves gaps in its allocated string array as NULL pointers. When `sel_make_perm_files()` iterates through these arrays, it passes the NULL pointers to `sel_attach_file()`, causing a kernel panic.
--

--- Patch [1]: [PATCH] selinux: reject a permission value exceeding the class permission count ---
commit eb44c136ba9338c4aa49d6ec88bea5f639bd151b
Author: Bryam Vargas <[email protected]>

selinux: reject a permission value exceeding the class permission count

This commit adds a bounds check in perm_read() to ensure a permission value
does not exceed the nprim value of its owning class or common. It attempts
to prevent an out-of-bounds heap write when security_get_permissions()
allocates an array sized by nprim and populates it.

> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
> index ead504a639e36..6973b68d9782a 100644
> --- a/security/selinux/ss/policydb.c
> +++ b/security/selinux/ss/policydb.c
> @@ -1175,6 +1175,9 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f
>  	rc = -EINVAL;
>  	if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX)
>  		goto bad;
> +	/* the value indexes an nprim-sized array in security_get_permissions() */
> +	if (perdatum->value > s->nprim)
> +		goto bad;

[Severity: High]
This is a pre-existing issue, but does this patch fully prevent the
out-of-bounds write if a class inherits permissions from a common?

While this check bounds the permission value against its immediate
symbol table's nprim, it seems a malicious policy could declare a
common with a large nprim and a class that inherits it with a small
nprim.

The parser sets the class's nprim without validating it against the
inherited common:

security/selinux/ss/policydb.c:class_read() {
    ...
    cladatum->permissions.nprim = le32_to_cpu(buf[3]);
    ...
}

Then security_get_permissions() allocates an array based solely on the
class's nprim:

security/selinux/ss/services.c:security_get_permissions() {
    ...
    *nperms = match->permissions.nprim;
    *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
    ...
    if (match->comdatum) {
        rc = hashtab_map(&match->comdatum->permissions.table,
                         get_permissions_callback, *perms);
    ...
}

Since the common permissions bypass this patch's symtab-specific bounds
check and are mapped into the undersized perms array, could this still
lead to a slab-out-of-bounds write in get_permissions_callback()?

[Severity: High]
This is a pre-existing issue, but could this sparse array allocation
lead to a null pointer dereference later on?

If a policy defines a sparse set of values (for instance, if nprim is 3
but only values 1 and 3 are populated), get_permissions_callback() maps
the present permissions:

security/selinux/ss/services.c:get_permissions_callback() {
    ...
    perms[value] = kstrdup(name, GFP_ATOMIC);
    ...
}

This leaves intermediate unpopulated indices as NULL in the array. When
sel_make_perm_files() iterates through this array:

security/selinux/selinuxfs.c:sel_make_perm_files() {
    ...
    for (i = 0; i < nperms; i++) {
        rc = sel_attach_file(dir, perms[i], inode);
    ...
}

It passes the NULL pointer to sel_attach_file(), which passes it to
d_alloc_name(), which requires a valid string for hashlen_string().

Can this cause a kernel panic when a process loads such a crafted policy?

>  
>  	rc = str_read(&key, GFP_KERNEL, fp, len);
>  	if (rc)

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1