diff options
| author | Stephen Smalley <stephen.smalley.work@gmail.com> | 2026-07-27 10:44:38 -0400 |
|---|---|---|
| committer | Paul Moore <paul@paul-moore.com> | 2026-07-27 17:17:33 -0400 |
| commit | fd6e2388a3ea55e58cbbbef840c1d8aa2067dbb3 (patch) | |
| tree | 37d67269be8e0757b35243d4af61cae018ea155c | |
| parent | c0b6a5b89d1aa31574ea68bfb1fed1dee46e5ec6 (diff) | |
| download | linux-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.c | 35 |
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; |
