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 <[email protected]> --- 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

