[RFC PATCH 06/41] netlink: keep classic sender ids in skb->cb

From: Jan Koester

Date: Sun Oct 18 2026 - 14:04:41 EST


netlink_skb_parms has to fit into skb->cb, and netlink skbs are cloned
together with it for broadcasts, so there is neither room for kuid_t
and kgid_t holding UUIDs nor a single owner for an allocation.

Store the sender ids as classic kernel ids: a UUID or GUID becomes -1,
which reaches the receiver of SCM_CREDENTIALS as the overflow id. The
kernel's own permission checks on netlink messages use the socket's
file credentials, not these.

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

Signed-off-by: Jan Koester <jan.koester@xxxxxxx>
---
include/linux/netlink.h | 2 +-
include/net/scm.h | 28 ++++++++++++++++++++++++++++
lib/kobject_uevent.c | 8 ++++----
net/netlink/af_netlink.c | 4 ++--
4 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 882e9c1b6c..999c7a352e 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -23,7 +23,7 @@ enum netlink_skb_flags {
};

struct netlink_skb_parms {
- struct scm_creds creds; /* Skb credentials */
+ struct scm_creds_classic creds; /* Skb credentials */
__u32 portid;
__u32 dst_group;
__u32 flags;
diff --git a/include/net/scm.h b/include/net/scm.h
index 86ae6bc109..daa52e3d44 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -23,6 +23,34 @@ struct scm_creds {
kgid_t gid;
};

+/*
+ * Sender credentials for skb->cb of skbs that get cloned along with it
+ * (netlink, bluetooth): no room for kuid_t and kgid_t, and no single owner
+ * for an allocation. The ids are classic kernel ids; a UUID or GUID becomes
+ * -1, which the receiver of SCM_CREDENTIALS sees as the overflow id.
+ */
+struct scm_creds_classic {
+ u32 pid;
+ uid_t uid;
+ gid_t gid;
+};
+
+static inline void scm_creds_to_classic(struct scm_creds_classic *classic,
+ const struct scm_creds *creds)
+{
+ classic->pid = creds->pid;
+ classic->uid = __kuid_val(creds->uid);
+ classic->gid = __kgid_val(creds->gid);
+}
+
+static inline void scm_creds_from_classic(struct scm_creds *creds,
+ const struct scm_creds_classic *classic)
+{
+ creds->pid = classic->pid;
+ creds->uid = KUIDT_INIT(classic->uid);
+ creds->gid = KGIDT_INIT(classic->gid);
+}
+
#ifdef CONFIG_UNIX
struct unix_edge;
#endif
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index ddbc4d7482..8b63044881 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -297,8 +297,8 @@ static struct sk_buff *alloc_uevent_skb(struct kobj_uevent_env *env,
skb_put_data(skb, env->buf, env->buflen);

parms = &NETLINK_CB(skb);
- parms->creds.uid = GLOBAL_ROOT_UID;
- parms->creds.gid = GLOBAL_ROOT_GID;
+ parms->creds.uid = __kuid_val(GLOBAL_ROOT_UID);
+ parms->creds.gid = __kgid_val(GLOBAL_ROOT_GID);
parms->dst_group = 1;
parms->portid = 0;

@@ -362,12 +362,12 @@ static int uevent_net_broadcast_tagged(struct sock *usk,
/* fix uid */
root_uid = make_kuid(owning_user_ns, 0);
if (uid_valid(root_uid))
- parms->creds.uid = root_uid;
+ parms->creds.uid = __kuid_val(root_uid);

/* fix gid */
root_gid = make_kgid(owning_user_ns, 0);
if (gid_valid(root_gid))
- parms->creds.gid = root_gid;
+ parms->creds.gid = __kgid_val(root_gid);
}

ret = netlink_broadcast(usk, skb, 0, 1, GFP_KERNEL);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3029894eda..282a5d0da4 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1901,7 +1901,7 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)

NETLINK_CB(skb).portid = nlk->portid;
NETLINK_CB(skb).dst_group = dst_group;
- NETLINK_CB(skb).creds = scm.creds;
+ scm_creds_to_classic(&NETLINK_CB(skb).creds, &scm.creds);
NETLINK_CB(skb).flags = netlink_skb_flags;

err = -EFAULT;
@@ -1994,7 +1994,7 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
netlink_cmsg_listen_all_nsid(sk, msg, skb);

memset(&scm, 0, sizeof(scm));
- scm.creds = *NETLINK_CREDS(skb);
+ scm_creds_from_classic(&scm.creds, NETLINK_CREDS(skb));
if (flags & MSG_TRUNC)
copied = data_skb->len;

--
2.56.0