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

