[RFC PATCH v2 15/41] SUNRPC: name UUID and GUID users to gssd as uid_r=
From: Jan Koester
Date: Tue Oct 20 2026 - 23:38:05 EST
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@xxxxxxxxx>
---
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