Linux CIFS filesystem development
 help / color / mirror / Atom feed
From: Jarkko Sakkinen <jarkko@kernel.org>
To: David Howells <dhowells@redhat.com>
Cc: keyrings@vger.kernel.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Jarkko Sakkinen <jarkko@kernel.org>,
	Paulo Alcantara <pc@manguebit.org>,
	Namjae Jeon <linkinjeon@kernel.org>,
	Ronnie Sahlberg <ronniesahlberg@gmail.com>,
	Shyam Prasad N <sprasad@microsoft.com>,
	Tom Talpey <tom@talpey.com>, Bharath SM <bharathsm@microsoft.com>,
	Paul Moore <paul@paul-moore.com>,
	James Morris <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	linux-cifs@vger.kernel.org (open list:COMMON INTERNET FILE
	SYSTEM CLIENT (CIFS and SMB3)),
	samba-technical@lists.samba.org (moderated list:COMMON INTERNET
	FILE SYSTEM CLIENT (CIFS and SMB3)),
	linux-kernel@vger.kernel.org (open list),
	linux-security-module@vger.kernel.org (open list:SECURITY
	SUBSYSTEM)
Subject: [RFC PATCH 1/6] keys: prevent quota overflow and widen quotalen and datalen to 32 bits
Date: Sat, 17 Oct 2026 00:52:59 +0300	[thread overview]
Message-ID: <20261016215326.4110064-2-jarkko@kernel.org> (raw)
In-Reply-To: <20261016215326.4110064-1-jarkko@kernel.org>

In struct key, quotalen and datalen are 16-bit unsigned shorts, limiting
payload and quota tracking to 64 KiB. With large descriptions or payload
updates, addition and difference calculations can truncate or overflow,
corrupting user quota accounting.

Additionally, existing quota checks rely on undefined signed overflow
checks (e.g. user->qnbytes + quotalen < user->qnbytes) and do not guard
against user->qnkeys or user->qnbytes reaching INT_MAX.

Widen quotalen and datalen to unsigned 32-bit integers in struct key.
Validate description lengths against INT_MAX in key_alloc(), and check
quota headroom using safe subtraction across key_alloc(),
key_payload_reserve(), and keyctl_chown_key().

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: LLM
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 fs/smb/client/cifsacl.c |  6 +++---
 include/linux/key.h     |  4 ++--
 security/keys/key.c     | 25 ++++++++++++++++++++-----
 security/keys/keyctl.c  |  9 +++++----
 4 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index c5e47a835f99..de2acc7234be 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -385,7 +385,7 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
 		goto out_revert_creds;
 	} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
 		rc = smb_EIO1(smb_eio_trace_malformed_sid_key, sidkey->datalen);
-		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
+		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%u)\n",
 			 __func__, sidkey->datalen);
 		goto invalidate_key;
 	}
@@ -403,7 +403,7 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
 	if (ksid_size > sidkey->datalen) {
 		rc = smb_EIO2(smb_eio_trace_malformed_ksid_key,
 			      ksid_size, sidkey->datalen);
-		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
+		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%u, ksid_size=%u)\n",
 			 __func__, sidkey->datalen, ksid_size);
 		goto invalidate_key;
 	}
@@ -498,7 +498,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
 	 */
 	BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
 	if (sidkey->datalen != sizeof(uid_t)) {
-		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
+		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%u)\n",
 			 __func__, sidkey->datalen);
 		key_invalidate(sidkey);
 		goto out_key_put;
diff --git a/include/linux/key.h b/include/linux/key.h
index e40b5267658f..26139c3adf62 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -216,8 +216,8 @@ struct key {
 	kuid_t			uid;
 	kgid_t			gid;
 	key_perm_t		perm;		/* access permissions */
-	unsigned short		quotalen;	/* length added to quota */
-	unsigned short		datalen;	/* payload data length
+	unsigned int		quotalen;	/* length added to quota */
+	unsigned int		datalen;	/* payload data length
 						 * - may not match RCU dereferenced payload
 						 * - payload should contain own length
 						 */
diff --git a/security/keys/key.c b/security/keys/key.c
index 6ebb8691551f..144745684334 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -245,6 +245,10 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 	}
 
 	desclen = strlen(desc);
+	if (desclen >= INT_MAX || type->def_datalen > INT_MAX - desclen - 1) {
+		key = ERR_PTR(-EINVAL);
+		goto error;
+	}
 	quotalen = desclen + 1 + type->def_datalen;
 
 	/* get hold of the key tracking for this user */
@@ -261,10 +265,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 			key_quota_root_maxbytes : key_quota_maxbytes;
 
 		spin_lock_irqsave(&user->lock, irqflags);
+		if (user->qnkeys == INT_MAX ||
+		    quotalen > INT_MAX - user->qnbytes)
+			goto no_quota;
+
 		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
 			if (user->qnkeys + 1 > maxkeys ||
-			    user->qnbytes + quotalen > maxbytes ||
-			    user->qnbytes + quotalen < user->qnbytes)
+			    quotalen > maxbytes ||
+			    user->qnbytes > maxbytes - quotalen)
 				goto no_quota;
 		}
 
@@ -373,11 +381,16 @@ EXPORT_SYMBOL(key_alloc);
  */
 int key_payload_reserve(struct key *key, size_t datalen)
 {
-	int delta = (int)datalen - key->datalen;
+	int delta;
 	int ret = 0;
 
 	key_check(key);
 
+	if (datalen > INT_MAX)
+		return -EINVAL;
+
+	delta = (int)datalen - (int)key->datalen;
+
 	/* contemplate the quota adjustment */
 	if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
 		unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
@@ -387,8 +400,10 @@ int key_payload_reserve(struct key *key, size_t datalen)
 		spin_lock_irqsave(&key->user->lock, flags);
 
 		if (delta > 0 &&
-		    (key->user->qnbytes + delta > maxbytes ||
-		     key->user->qnbytes + delta < key->user->qnbytes)) {
+		    (delta > INT_MAX - key->user->qnbytes ||
+		     delta > INT_MAX - key->quotalen ||
+		     delta > maxbytes ||
+		     key->user->qnbytes > maxbytes - delta)) {
 			ret = -EDQUOT;
 		}
 		else {
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 5a5efa26ed0e..6b528faab1a7 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1014,10 +1014,11 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
 				key_quota_root_maxbytes : key_quota_maxbytes;
 
 			spin_lock_irqsave(&newowner->lock, flags);
-			if (newowner->qnkeys + 1 > maxkeys ||
-			    newowner->qnbytes + key->quotalen > maxbytes ||
-			    newowner->qnbytes + key->quotalen <
-			    newowner->qnbytes)
+			if (newowner->qnkeys == INT_MAX ||
+			    newowner->qnkeys + 1 > maxkeys ||
+			    key->quotalen > INT_MAX - newowner->qnbytes ||
+			    key->quotalen > maxbytes ||
+			    newowner->qnbytes > maxbytes - key->quotalen)
 				goto quota_overrun;
 
 			newowner->qnkeys++;
-- 
2.47.3


       reply	other threads:[~2026-10-16 21:53 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20261016215326.4110064-1-jarkko@kernel.org>
2026-10-16 21:52 ` Jarkko Sakkinen [this message]
2026-10-17  5:28   ` [RFC PATCH 1/6] keys: prevent quota overflow and widen quotalen and datalen to 32 bits Eric Biggers

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=20261016215326.4110064-2-jarkko@kernel.org \
    --to=jarkko@kernel.org \
    --cc=bharathsm@microsoft.com \
    --cc=dhowells@redhat.com \
    --cc=jmorris@namei.org \
    --cc=keyrings@vger.kernel.org \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=paul@paul-moore.com \
    --cc=pc@manguebit.org \
    --cc=ronniesahlberg@gmail.com \
    --cc=samba-technical@lists.samba.org \
    --cc=serge@hallyn.com \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    --cc=torvalds@linux-foundation.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