summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Smalley <stephen.smalley.work@gmail.com>2026-07-27 10:44:38 -0400
committerPaul Moore <paul@paul-moore.com>2026-07-27 17:17:33 -0400
commitfd6e2388a3ea55e58cbbbef840c1d8aa2067dbb3 (patch)
tree37d67269be8e0757b35243d4af61cae018ea155c
parentc0b6a5b89d1aa31574ea68bfb1fed1dee46e5ec6 (diff)
downloadlinux-next-fd6e2388a3ea55e58cbbbef840c1d8aa2067dbb3.tar.gz
linux-next-fd6e2388a3ea55e58cbbbef840c1d8aa2067dbb3.zip
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>
-rw-r--r--security/selinux/ss/policydb.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index ba1c9bd9e29f..c4a81bd31e05 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -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;