selinux: reject an unclaimed class value in security_get_classes()

security_get_classes() sizes an array by p_classes.nprim and fills it at
value - 1, so a class value the policy never defines leaves a NULL.
sel_make_classes() passes every entry to sel_make_dir(), reaching the same
d_alloc_name() dereference as the permission array. The class symbol table
is allowed to be sparse (policydb_class_isvalid() exists to absorb that),
but this getter builds its own array straight from the hash table and has
no such predicate.

Fail the lookup when a value went unclaimed instead of handing out the
NULL. Conforming policies define every class they declare and are
unaffected.

Cc: stable@vger.kernel.org
Fixes: 55fcf09b3f ("selinux: add support for querying object classes and permissions from the running policy")
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Bryam Vargas 2026-07-31 12:44:11 -05:00 committed by Paul Moore
parent b98a8ac507
commit 22b05fec62

View File

@ -3304,6 +3304,7 @@ int security_get_classes(struct selinux_policy *policy,
char ***classes, u32 *nclasses)
{
struct policydb *policydb;
u32 i;
int rc;
policydb = &policy->policydb;
@ -3316,16 +3317,29 @@ int security_get_classes(struct selinux_policy *policy,
rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
*classes);
if (rc) {
u32 i;
if (rc)
goto err;
for (i = 0; i < *nclasses; i++)
kfree((*classes)[i]);
kfree(*classes);
/*
* The class symtab may be sparse, which policydb_class_isvalid() exists
* to absorb; the callback fills this array by value, so an unclaimed
* one leaves a NULL that sel_make_classes() hands to sel_make_dir().
*/
for (i = 0; i < *nclasses; i++) {
if (!(*classes)[i]) {
rc = -EINVAL;
goto err;
}
}
out:
return rc;
err:
for (i = 0; i < *nclasses; i++)
kfree((*classes)[i]);
kfree(*classes);
return rc;
}
static int get_permissions_callback(void *k, void *d, void *args)