[RFC PATCH v2 15/41] SUNRPC: name UUID and GUID users to gssd as uid_r=

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


gssd learns the user of an upcall as a 32 bit uid. UUID and GUID users
would all reach it as the overflow uid and share its credentials.

In the text (v1) upcall, name such a user as uid_r= with the text form
of the id instead of uid=. gssd versions that don't know uid_r= find no
uid= and refuse the upcall, so nobody ends up with the overflow uid's
credentials; where gssd's user namespace can't see the user, the upcall
names no user at all and fails the same way.

A downcall for such a user starts with uid -1, which is never valid,
followed by the user as __kernel_uid_r_t; downcalls for classic uids are
unchanged.

The binary (v0) upcall has room for a 32 bit uid only: fail it with
-EACCES for UUID and GUID users.

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

Signed-off-by: Jan Koester <jan.koester at tuxist.de>
---
 net/sunrpc/auth_gss/auth_gss.c | 44 +++++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 8ddc65e894..5e9e2cf4e9 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/uidgid_r.h>
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/auth_gss.h>
 #include <linux/sunrpc/gss_krb5.h>
@@ -438,10 +439,23 @@ static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
 	struct gss_api_mech *mech = gss_msg->auth->mech;
 	char *p = gss_msg->databuf;
 	size_t buflen = sizeof(gss_msg->databuf);
+	char idbuf[KID_STR_LEN];
 	int len;
 
-	len = scnprintf(p, buflen, "mech=%s uid=%d", mech->gm_name,
-			from_kuid_munged(userns, gss_msg->uid));
+	/*
+	 * A UUID or GUID user is uid_r= in its text form instead of uid=,
+	 * which gssd versions that don't know it reject rather than taking
+	 * an overflow uid. Where gssd can't see the user at all, there is
+	 * neither, and the upcall fails.
+	 */
+	if (uid_is_legacy(gss_msg->uid))
+		len = scnprintf(p, buflen, "mech=%s uid=%d", mech->gm_name,
+				from_kuid_munged(userns, gss_msg->uid));
+	else if (kuid_has_mapping(userns, gss_msg->uid))
+		len = scnprintf(p, buflen, "mech=%s uid_r=%s", mech->gm_name,
+				kuid_str(gss_msg->uid, idbuf));
+	else
+		len = scnprintf(p, buflen, "mech=%s", mech->gm_name);
 	buflen -= len;
 	p += len;
 	gss_msg->msg.len = len;
@@ -536,6 +550,15 @@ gss_alloc_msg(struct gss_auth *gss_auth,
 	err = vers;
 	if (err < 0)
 		goto err_free_msg;
+	/*
+	 * The binary v0 upcall is a 32 bit uid: UUID and GUID users would
+	 * all be the overflow uid there and share its credentials.
+	 */
+	if (vers == 0 && !uid_is_legacy(uid)) {
+		put_pipe_version(gss_auth->net);
+		err = -EACCES;
+		goto err_free_msg;
+	}
 	gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
 	INIT_LIST_HEAD(&gss_msg->list);
 	rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
@@ -752,7 +775,22 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 		goto err;
 	}
 
-	uid = make_kuid(current_user_ns(), id);
+	/*
+	 * A uid of -1, never valid, is followed by a __kernel_uid_r_t: the
+	 * reply to a uid_r= upcall of a UUID or GUID user.
+	 */
+	if (id == (uid_t)-1) {
+		struct __kernel_uid_r id_r;
+
+		p = simple_get_bytes(p, end, &id_r, sizeof(id_r));
+		if (IS_ERR(p)) {
+			err = PTR_ERR(p);
+			goto err;
+		}
+		uid = make_kuid_r(current_user_ns(), &id_r);
+	} else {
+		uid = make_kuid(current_user_ns(), id);
+	}
 	if (!uid_valid(uid)) {
 		err = -EINVAL;
 		goto err;
-- 
2.56.0




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