lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250511173055.406906-14-cgoettsche@seltendoof.de>
Date: Sun, 11 May 2025 19:30:14 +0200
From: Christian Göttsche <cgoettsche@...tendoof.de>
To: selinux@...r.kernel.org
Cc: Christian Göttsche <cgzones@...glemail.com>,
	Paul Moore <paul@...l-moore.com>,
	Stephen Smalley <stephen.smalley.work@...il.com>,
	Ondrej Mosnacek <omosnace@...hat.com>,
	linux-kernel@...r.kernel.org,
	Thiébaud Weksteen <tweek@...gle.com>,
	Casey Schaufler <casey@...aufler-ca.com>,
	Canfeng Guo <guocanfeng@...ontech.com>,
	Takaya Saeki <takayas@...omium.org>
Subject: [PATCH v3 14/14] selinux: harden MLS context string generation against overflows

From: Christian Göttsche <cgzones@...glemail.com>

Check the length accumulator for the MLS component of security contexts
does not overflow in mls_compute_context_len() resulting in
out-of-buffer writes in mls_sid_to_context().

Signed-off-by: Christian Göttsche <cgzones@...glemail.com>
---
v3: add patch
---
 security/selinux/ss/mls.c      | 18 +++++++++-----
 security/selinux/ss/services.c | 43 +++++++++++++++++++++++++++++-----
 2 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 3cd36e2015fa..aa25724f0b0f 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -42,7 +42,8 @@ int mls_compute_context_len(struct policydb *p, struct context *context)
 	len = 1; /* for the beginning ":" */
 	for (l = 0; l < 2; l++) {
 		u32 index_sens = context->range.level[l].sens;
-		len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
+		if (check_add_overflow(len, strlen(sym_name(p, SYM_LEVELS, index_sens - 1)), &len))
+			return -EOVERFLOW;
 
 		/* categories */
 		head = -2;
@@ -54,24 +55,29 @@ int mls_compute_context_len(struct policydb *p, struct context *context)
 				/* one or more negative bits are skipped */
 				if (head != prev) {
 					nm = sym_name(p, SYM_CATS, prev);
-					len += strlen(nm) + 1;
+					if (check_add_overflow(len, strlen(nm) + 1, &len))
+						return -EOVERFLOW;
 				}
 				nm = sym_name(p, SYM_CATS, i);
-				len += strlen(nm) + 1;
+				if (check_add_overflow(len, strlen(nm) + 1, &len))
+					return -EOVERFLOW;
 				head = i;
 			}
 			prev = i;
 		}
 		if (prev != head) {
 			nm = sym_name(p, SYM_CATS, prev);
-			len += strlen(nm) + 1;
+			if (check_add_overflow(len, strlen(nm) + 1, &len))
+				return -EOVERFLOW;
 		}
 		if (l == 0) {
 			if (mls_level_eq(&context->range.level[0],
 					 &context->range.level[1]))
 				break;
-			else
-				len++;
+			else {
+				if (check_add_overflow(len, 1, &len))
+					return -EOVERFLOW;
+			}
 		}
 	}
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 464a4663c993..dc6dce2eb7d2 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1247,10 +1247,12 @@ static int context_struct_to_string(struct policydb *p,
 				    char **scontext, u32 *scontext_len)
 {
 	char *scontextp;
+	size_t len;
+	int mls_len;
 
 	if (scontext)
 		*scontext = NULL;
-	*scontext_len = 0;
+	len = 0;
 
 	if (context->len) {
 		*scontext_len = context->len;
@@ -1263,16 +1265,45 @@ static int context_struct_to_string(struct policydb *p,
 	}
 
 	/* Compute the size of the context. */
-	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
-	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
-	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
-	*scontext_len += mls_compute_context_len(p, context);
+	len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
+	len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
+	len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
+
+	mls_len = mls_compute_context_len(p, context);
+	if (unlikely(mls_len < 0)) {
+		pr_warn_ratelimited("SELinux: %s:  MLS security context component too large [%s:%s:%s[:[%s:%d]-[%s:%d]]]\n",
+				    __func__,
+				    sym_name(p, SYM_USERS, context->user - 1),
+				    sym_name(p, SYM_ROLES, context->role - 1),
+				    sym_name(p, SYM_TYPES, context->type - 1),
+				    sym_name(p, SYM_LEVELS, context->range.level[0].sens - 1),
+				    ebitmap_length(&context->range.level[0].cat),
+				    sym_name(p, SYM_LEVELS, context->range.level[1].sens - 1),
+				    ebitmap_length(&context->range.level[1].cat));
+		return -EOVERFLOW;
+	}
+
+	if (unlikely(check_add_overflow(len, mls_len, &len) || len > CONTEXT_MAXLENGTH)) {
+		pr_warn_ratelimited("SELinux: %s:  security context string of length %zu too large [%s:%s:%s[:[%s:%d]-[%s:%d]]]\n",
+				    __func__,
+				    len,
+				    sym_name(p, SYM_USERS, context->user - 1),
+				    sym_name(p, SYM_ROLES, context->role - 1),
+				    sym_name(p, SYM_TYPES, context->type - 1),
+				    sym_name(p, SYM_LEVELS, context->range.level[0].sens - 1),
+				    ebitmap_length(&context->range.level[0].cat),
+				    sym_name(p, SYM_LEVELS, context->range.level[1].sens - 1),
+				    ebitmap_length(&context->range.level[1].cat));
+		return -EOVERFLOW;
+	}
+
+	*scontext_len = len;
 
 	if (!scontext)
 		return 0;
 
 	/* Allocate space for the context; caller must free this space. */
-	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
+	scontextp = kmalloc(len, GFP_ATOMIC);
 	if (!scontextp)
 		return -ENOMEM;
 	*scontext = scontextp;
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ