[RFC PATCH v2 05/41] af_unix: keep sender ids in skb->cb only when they are classic ids

Jan Koester jan.koester at tuxist.de
Wed Oct 21 03:15:25 UTC 2026


unix_skb_parms has to fit into the 48 bytes of skb->cb. With kuid_t and
kgid_t growing to hold UUIDs and GUIDs the two of them alone would take
40 bytes.

Store classic ids as 32 bit values as before, and only for a UUID or
GUID allocate a small struct unix_skb_ids for both, freed together with
the pid reference in unix_destruct_scm(). AF_UNIX skbs carrying a pid
reference are never cloned, so the pointer has a single owner.
Senders with classic ids see no change and no allocation.

Assisted-by: Claude:claude-opus-5-5

Signed-off-by: Jan Koester <jan.koester at tuxist.de>
---
 net/unix/af_unix.c | 50 +++++++++++++++++++++++++++++++++++++++-------
 net/unix/af_unix.h | 11 ++++++++--
 2 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 42cffeafc8..2b17310534 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1969,11 +1969,46 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
 	unix_peek_fpl(scm->fp);
 }
 
+/*
+ * The sender's ids, in the skb itself for legacy ids; UUIDs and GUIDs don't
+ * fit in skb->cb and come from an allocation, freed with the pid reference
+ * in unix_destruct_scm().
+ */
+static int unix_skb_set_ids(struct sk_buff *skb, kuid_t uid, kgid_t gid)
+{
+	struct unix_skb_ids *ids = NULL;
+
+	if (!uid_is_legacy(uid) || !gid_is_legacy(gid)) {
+		ids = kmalloc_obj(*ids, GFP_KERNEL_ACCOUNT);
+		if (!ids)
+			return -ENOMEM;
+		ids->uid = uid;
+		ids->gid = gid;
+	}
+	kfree(UNIXCB(skb).ids);
+	UNIXCB(skb).ids = ids;
+	UNIXCB(skb).uid = __kuid_val(uid);
+	UNIXCB(skb).gid = __kgid_val(gid);
+	return 0;
+}
+
+static kuid_t unix_skb_uid(const struct sk_buff *skb)
+{
+	return UNIXCB(skb).ids ? UNIXCB(skb).ids->uid : KUIDT_INIT(UNIXCB(skb).uid);
+}
+
+static kgid_t unix_skb_gid(const struct sk_buff *skb)
+{
+	return UNIXCB(skb).ids ? UNIXCB(skb).ids->gid : KGIDT_INIT(UNIXCB(skb).gid);
+}
+
 static void unix_destruct_scm(struct sk_buff *skb)
 {
 	struct scm_cookie scm = {};
 
 	swap(scm.pid, UNIXCB(skb).pid);
+	kfree(UNIXCB(skb).ids);
+	UNIXCB(skb).ids = NULL;
 
 	if (UNIXCB(skb).fp)
 		unix_detach_fds(&scm, skb);
@@ -1992,20 +2027,21 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
 	int err = 0;
 
 	UNIXCB(skb).pid = get_pid(scm->pid);
-	UNIXCB(skb).uid = scm->creds.uid;
-	UNIXCB(skb).gid = scm->creds.gid;
 	UNIXCB(skb).fp = NULL;
+	skb->destructor = unix_wfree;
+	err = unix_skb_set_ids(skb, scm->creds.uid, scm->creds.gid);
+	if (err)
+		return err;
 	unix_get_secdata(scm, skb);
 	if (scm->fp && send_fds)
 		err = unix_attach_fds(scm, skb);
 
-	skb->destructor = unix_wfree;
 	return err;
 }
 
 static void unix_skb_to_scm(struct sk_buff *skb, struct scm_cookie *scm)
 {
-	scm_set_cred(scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+	scm_set_cred(scm, UNIXCB(skb).pid, unix_skb_uid(skb), unix_skb_gid(skb));
 	unix_set_secdata(scm, skb);
 }
 
@@ -2039,7 +2075,7 @@ static int unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
 			return err;
 
 		UNIXCB(skb).pid = get_pid(pid);
-		current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
+		return unix_skb_set_ids(skb, current_uid(), current_gid());
 	}
 
 	return 0;
@@ -2049,8 +2085,8 @@ static bool unix_skb_scm_eq(struct sk_buff *skb,
 			    struct scm_cookie *scm)
 {
 	return UNIXCB(skb).pid == scm->pid &&
-	       uid_eq(UNIXCB(skb).uid, scm->creds.uid) &&
-	       gid_eq(UNIXCB(skb).gid, scm->creds.gid) &&
+	       uid_eq(unix_skb_uid(skb), scm->creds.uid) &&
+	       gid_eq(unix_skb_gid(skb), scm->creds.gid) &&
 	       unix_secdata_eq(scm, skb);
 }
 
diff --git a/net/unix/af_unix.h b/net/unix/af_unix.h
index 8119dbeef3..e861a430cf 100644
--- a/net/unix/af_unix.h
+++ b/net/unix/af_unix.h
@@ -10,10 +10,17 @@
 
 struct sock *unix_peer_get(struct sock *sk);
 
-struct unix_skb_parms {
-	struct pid		*pid;		/* skb credentials	*/
+/* The sender's ids, when either is a UUID or GUID */
+struct unix_skb_ids {
 	kuid_t			uid;
 	kgid_t			gid;
+};
+
+struct unix_skb_parms {
+	struct pid		*pid;		/* skb credentials	*/
+	struct unix_skb_ids	*ids;		/* uid and gid, or NULL	*/
+	uid_t			uid;		/* for ids NULL: legacy	*/
+	gid_t			gid;		/* uid and gid		*/
 	struct scm_fp_list	*fp;		/* Passed files		*/
 #ifdef CONFIG_SECURITY_NETWORK
 	u32			secid;		/* Security ID		*/
-- 
2.56.0




More information about the Linux-security-module-archive mailing list