From 96e4e872e6df0836c75f1238639b552972f8c825 Mon Sep 17 00:00:00 2001 From: iefa m Date: Tue, 3 Nov 2026 20:28:06 +0530 Subject: [PATCH] running_as_user: compare the runas group by gid, not by name running_as_user() let "sudo -g group" skip authentication if the user was in the runas group, but it checked that with user_in_group() on the group's name. That matches against the names of the user's groups, case-insensitively by default, so a different group whose name only matches one of the user's groups (Staff vs. staff, or a second "admins" with another gid from a different NSS source) was treated as one the user already has. The command then ran with that group's gid without a password. Check the runas group-ID against the user's primary and supplementary group-IDs instead. --- plugins/sudoers/check.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c index 38fcc556cc..f555193e6f 100644 --- a/plugins/sudoers/check.c +++ b/plugins/sudoers/check.c @@ -82,15 +82,42 @@ get_authpw(struct sudoers_context *ctx, unsigned int mode) } /* - * Returns true if the user is running the command as themselves - * and no SELinux type/role, AppArmor profile, Solaris privilege - * or root directory was specified. + * Returns true if gid is the user's primary group-ID or one of + * the user's supplementary group-IDs. + */ +static bool +user_has_gid(const struct passwd *pw, gid_t gid) +{ + struct gid_list *gidlist; + bool matched = false; + int i; + debug_decl(user_has_gid, SUDOERS_DEBUG_AUTH); + + if (gid == pw->pw_gid) + debug_return_bool(true); + if ((gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY)) != NULL) { + for (i = 0; i < gidlist->ngids; i++) { + if (gidlist->gids[i] == gid) { + matched = true; + break; + } + } + sudo_gidlist_delref(gidlist); + } + debug_return_bool(matched); +} + +/* + * Returns true if the user is running the command as themselves, + * with one of their own groups, and no SELinux type/role, AppArmor + * profile, Solaris privilege or root directory was specified. + * The runas group is compared by group-ID, not by name. */ static bool running_as_user(struct sudoers_context *ctx) { return ctx->user.uid == ctx->runas.pw->pw_uid && (ctx->runas.gr == NULL || - user_in_group(ctx->user.pw, ctx->runas.gr->gr_name)) && + user_has_gid(ctx->user.pw, ctx->runas.gr->gr_gid)) && ctx->runas.role == NULL && ctx->runas.type == NULL && ctx->runas.apparmor_profile == NULL && ctx->runas.privs == NULL && ctx->runas.limitprivs == NULL &&