[PATCH] selinux: validate constraint expression attr and op at load time
Stephen Smalley <[email protected]> Mon, 27 Jul 2026 10:44:38 -0400
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- security/selinux/ss/policydb.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) 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; -- 2.55.0