selinux: require every boolean value to be defined

p_bools.nprim comes from the policy image independently of how many
booleans follow it, and cond_index_bool() fills bool_val_to_struct[] at
value - 1, so a count larger than the values present leaves NULL entries.
Every user of that array then walks it by index and dereferences each
entry: cond_evaluate_expr() on the access-vector path,
security_get_bools() and security_get_bool_value() behind selinuxfs, and
security_set_bools(). A sparse class value is absorbed by
policydb_class_isvalid() and its siblings; booleans have no such
predicate, and no consumer that could use one.

Reject a boolean value that no boolean defines, once, where the array is
built. Conforming policies define every boolean they declare and are
unaffected.

Cc: stable@vger.kernel.org
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
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:12 -05:00
committed by Paul Moore
parent 22b05fec62
commit a93d37a09b

View File

@@ -719,6 +719,7 @@ static inline void symtab_hash_eval(struct symtab *s)
static int policydb_index(struct policydb *p)
{
int i, rc;
u32 v;
if (p->mls_enabled)
pr_debug(
@@ -769,6 +770,24 @@ static int policydb_index(struct policydb *p)
if (rc)
goto out;
}
/*
* A sparse class value is absorbed by policydb_class_isvalid() and
* its siblings, but no such predicate exists for booleans: every
* user of bool_val_to_struct[] walks it by index and dereferences
* each entry -- cond_evaluate_expr(), the two getters and
* security_set_bools() -- so an unclaimed one has no consumer that
* can tolerate it.
*/
for (v = 0; v < p->p_bools.nprim; v++) {
if (!p->bool_val_to_struct[v]) {
pr_err("SELinux: boolean %u is declared but not defined\n",
v + 1);
rc = -EINVAL;
goto out;
}
}
rc = 0;
out:
return rc;