SELinux Security Module development
 help / color / mirror / Atom feed
From: James Carter <jwcart2@gmail.com>
To: selinux@vger.kernel.org
Cc: James Carter <jwcart2@gmail.com>
Subject: [PATCH 1/3] libsepol: Tighten checks on MLS range and level when validating
Date: Thu, 22 Jan 2026 11:06:00 -0500	[thread overview]
Message-ID: <20260122160602.65567-1-jwcart2@gmail.com> (raw)

Because of various corner cases, the checks for MLS semantic
levels and ranges and the checks for MLS levels and ranges do not
give an error when the value for the sensitivity is 0 (which occurs
because it has not been set).

The corner cases only apply to users and, even then, not to all
policy types, so user's MLS portions are not being checked as
strictly as possible. Range transitions are also not getting checked
as strictly as they could be either.

For user datums:
- Only check the MLS portions for MLS policies.
- Do not allow unset sensitivities in semantic levels and ranges for
a modular policy.
- Do not allow unset sensitivities in levels and ranges for a
kernel policy.

For range transitions:
- Never allow unset sensitivities.

Reported-by: oss-fuzz (issues 471456886 and 471525113)
Signed-off-by: James Carter <jwcart2@gmail.com>
---
 libsepol/src/policydb_validate.c | 50 +++++++++++++++++---------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c
index 5afbfa49..9ee71bf2 100644
--- a/libsepol/src/policydb_validate.c
+++ b/libsepol/src/policydb_validate.c
@@ -661,9 +661,9 @@ bad:
 	return -1;
 }
 
-static int validate_mls_semantic_level(const mls_semantic_level_t *level, const validate_t *sens, const validate_t *cats)
+static int validate_mls_semantic_level(const mls_semantic_level_t *level, const validate_t *sens, const validate_t *cats, int allow_unset)
 {
-	if (level->sens == 0)
+	if (allow_unset && level->sens == 0)
 		return 0;
 	if (validate_value(level->sens, sens))
 		goto bad;
@@ -676,11 +676,11 @@ bad:
 	return -1;
 }
 
-static int validate_mls_semantic_range(const mls_semantic_range_t *range, const validate_t *sens, const validate_t *cats)
+static int validate_mls_semantic_range(const mls_semantic_range_t *range, const validate_t *sens, const validate_t *cats, int allow_unset)
 {
-	if (validate_mls_semantic_level(&range->level[0], sens, cats))
+	if (validate_mls_semantic_level(&range->level[0], sens, cats, allow_unset))
 		goto bad;
-	if (validate_mls_semantic_level(&range->level[1], sens, cats))
+	if (validate_mls_semantic_level(&range->level[1], sens, cats, allow_unset))
 		goto bad;
 
 	return 0;
@@ -689,9 +689,9 @@ bad:
 	return -1;
 }
 
-static int validate_mls_level(const mls_level_t *level, const validate_t *sens, const validate_t *cats)
+static int validate_mls_level(const mls_level_t *level, const validate_t *sens, const validate_t *cats, int allow_unset)
 {
-	if (level->sens == 0)
+	if (allow_unset && level->sens == 0)
 		return 0;
 	if (validate_value(level->sens, sens))
 		goto bad;
@@ -712,7 +712,7 @@ static int validate_level_datum(sepol_handle_t *handle, const level_datum_t *lev
 	if (level->level->sens == 0)
 		goto bad;
 
-	if (validate_mls_level(level->level, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+	if (validate_mls_level(level->level, &flavors[SYM_LEVELS], &flavors[SYM_CATS], 0))
 		goto bad;
 
 	if (level->isalias) {
@@ -740,11 +740,11 @@ static int validate_level_datum_wrapper(__attribute__ ((unused)) hashtab_key_t k
 	return validate_level_datum(margs->handle, d, margs->flavors, margs->policy);
 }
 
-static int validate_mls_range(const mls_range_t *range, const validate_t *sens, const validate_t *cats)
+static int validate_mls_range(const mls_range_t *range, const validate_t *sens, const validate_t *cats, int allow_unset)
 {
-	if (validate_mls_level(&range->level[0], sens, cats))
+	if (validate_mls_level(&range->level[0], sens, cats, allow_unset))
 		goto bad;
-	if (validate_mls_level(&range->level[1], sens, cats))
+	if (validate_mls_level(&range->level[1], sens, cats, allow_unset))
 		goto bad;
 
 	return 0;
@@ -759,14 +759,19 @@ static int validate_user_datum(sepol_handle_t *handle, const user_datum_t *user,
 		goto bad;
 	if (validate_role_set(&user->roles, &flavors[SYM_ROLES]))
 		goto bad;
-	if (validate_mls_semantic_range(&user->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
-		goto bad;
-	if (validate_mls_semantic_level(&user->dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
-		goto bad;
-	if (p->mls && p->policy_type != POLICY_MOD && validate_mls_range(&user->exp_range, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
-		goto bad;
-	if (p->mls && p->policy_type != POLICY_MOD && validate_mls_level(&user->exp_dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
-		goto bad;
+	if (p->mls) {
+		int allow_unset = (p->policy_type != POLICY_MOD);
+		if (validate_mls_semantic_range(&user->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS], allow_unset))
+			goto bad;
+		if (validate_mls_semantic_level(&user->dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS], allow_unset))
+			goto bad;
+
+		allow_unset = (p->policy_type != POLICY_KERN);
+		if (validate_mls_range(&user->exp_range, &flavors[SYM_LEVELS], &flavors[SYM_CATS], allow_unset))
+			goto bad;
+		if (validate_mls_level(&user->exp_dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS], allow_unset))
+			goto bad;
+	}
 	if (user->bounds && validate_value(user->bounds, &flavors[SYM_USERS]))
 		goto bad;
 
@@ -1323,7 +1328,7 @@ static int validate_context(const context_struct_t *con, validate_t flavors[], i
 		return -1;
 	if (validate_value(con->type, &flavors[SYM_TYPES]))
 		return -1;
-	if (mls && validate_mls_range(&con->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+	if (mls && validate_mls_range(&con->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS], 0))
 		return -1;
 
 	return 0;
@@ -1484,7 +1489,7 @@ static int validate_range_trans_rules(sepol_handle_t *handle, const range_trans_
 			goto bad;
 		if (validate_ebitmap(&range_trans->tclasses, &flavors[SYM_CLASSES]))
 			goto bad;
-		if (validate_mls_semantic_range(&range_trans->trange, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+		if (validate_mls_semantic_range(&range_trans->trange, &flavors[SYM_LEVELS], &flavors[SYM_CATS], 0))
 			goto bad;
 	}
 
@@ -1663,8 +1668,7 @@ static int validate_range_transition(hashtab_key_t key, hashtab_datum_t data, vo
 		goto bad;
 	if (validate_value(rt->target_class, &flavors[SYM_CLASSES]))
 		goto bad;
-
-	if (validate_mls_range(r, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+	if (validate_mls_range(r, &flavors[SYM_LEVELS], &flavors[SYM_CATS], 0))
 		goto bad;
 
 	return 0;
-- 
2.52.0


             reply	other threads:[~2026-01-22 16:06 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-22 16:06 James Carter [this message]
2026-01-22 16:06 ` [PATCH 2/3] libsepol: Check for an unset sensitivity in module_to_cil James Carter
2026-01-22 16:06 ` [PATCH 3/3] libsepol: Handled required users " James Carter
2026-01-26  1:48 ` [PATCH 1/3] libsepol: Tighten checks on MLS range and level when validating Jason Zaman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260122160602.65567-1-jwcart2@gmail.com \
    --to=jwcart2@gmail.com \
    --cc=selinux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox