selinux: validate constraint expression attr and op at load time

read_cons_helper() validates the expression type and stack depth
of each constraint node but leaves e->attr and e->op unchecked,
so a policy with an invalid operator or attribute value is
accepted at load and only detected when the constraint is evaluated.
constraint_expr_eval() handles such unrecognized cases with BUG()
so the first permission check that reaches such a node oopses in
the context of the checking process or panics with panic_on_oops.

Reject these expresssions when the policy is loaded, matching what
the libsepol validator already does.

Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Stephen Smalley 2026-07-27 10:44:38 -04:00 committed by Paul Moore
parent c0b6a5b89d
commit fd6e2388a3

View File

@ -1332,6 +1332,27 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
if (depth == (CEXPR_MAXDEPTH - 1))
return -EINVAL;
depth++;
switch (e->attr) {
case CEXPR_USER:
case CEXPR_TYPE:
if (e->op != CEXPR_EQ &&
e->op != CEXPR_NEQ)
return -EINVAL;
break;
case CEXPR_ROLE:
case CEXPR_L1L2:
case CEXPR_L1H2:
case CEXPR_H1L2:
case CEXPR_H1H2:
case CEXPR_L1H1:
case CEXPR_L2H2:
if (e->op < CEXPR_EQ ||
e->op > CEXPR_INCOMP)
return -EINVAL;
break;
default:
return -EINVAL;
}
break;
case CEXPR_NAMES:
if (!allowxtarget && (e->attr & CEXPR_XTARGET))
@ -1339,6 +1360,20 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
if (depth == (CEXPR_MAXDEPTH - 1))
return -EINVAL;
depth++;
switch (e->attr &
~(CEXPR_TARGET|CEXPR_XTARGET)) {
case CEXPR_USER:
case CEXPR_ROLE:
case CEXPR_TYPE:
break;
default:
return -EINVAL;
}
if ((e->attr & (CEXPR_TARGET|CEXPR_XTARGET)) ==
(CEXPR_TARGET|CEXPR_XTARGET))
return -EINVAL;
if (e->op != CEXPR_EQ && e->op != CEXPR_NEQ)
return -EINVAL;
rc = ebitmap_read(&e->names, fp);
if (rc)
return rc;