]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selinux: reject an unclaimed class value in security_get_classes()
authorBryam Vargas <hexlabsecurity@proton.me>
Fri, 31 Jul 2026 17:44:11 +0000 (12:44 -0500)
committerPaul Moore <paul@paul-moore.com>
Mon, 3 Aug 2026 20:03:56 +0000 (16:03 -0400)
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: 55fcf09b3fe4 ("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>
security/selinux/ss/services.c

index 90e81186cb2ee348b249273649194d995a900722..7afce975436e93c5b569327f73ee4a7fa410a0d4 100644 (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)