From f0dc24b7aa7c4817f6f03b40615ecfa4a3b8ac80 Mon Sep 17 00:00:00 2001 From: Jason Colapietro Date: Fri, 21 Aug 2026 16:48:00 -0400 Subject: [PATCH] internal/as_user: drop supplementary groups set_eids() switched the effective gid and uid to the target user but never touched the supplementary group list, so the privilege-dropped thread kept the caller's group memberships while acting as that user. A directory reachable only through one of root's supplementary groups stayed reachable for the duration of the switch. Drop the list with setgroups(0, NULL) before relinquishing the gid and uid, while the thread still holds the privilege required to make that call, following the revocation order described in CERT POS36-C. Fixes #2242 Signed-off-by: Jason Colapietro --- docs/release-notes.md | 2 ++ internal/as_user/as_user.c | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index b9020a1e8d..4bda965383 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -19,6 +19,8 @@ nav_order: 9 ### Bug fixes +- Drop supplementary groups when dropping privileges to write files as a user ([#2242](https://github.com/coreos/ignition/issues/2242)) + ## Upcoming Ignition 2.27.0 (unreleased) diff --git a/internal/as_user/as_user.c b/internal/as_user/as_user.c index f84b464803..386f998ba7 100644 --- a/internal/as_user/as_user.c +++ b/internal/as_user/as_user.c @@ -15,6 +15,7 @@ #define _GNU_SOURCE #include #include +#include #include #include #include @@ -54,7 +55,9 @@ typedef struct au_thread_ctxt { int err; } au_thread_ctxt_t; -/* set_eids() sets the effective gid and uid of the calling thread to ids */ +/* set_eids() drops the supplementary groups and sets the effective gid and + * uid of the calling thread to ids + */ static int set_eids(au_ids_t *ids) { uid_t cu; gid_t cg; @@ -64,6 +67,14 @@ static int set_eids(au_ids_t *ids) { cu = geteuid(); cg = getegid(); + /* Drop the supplementary groups inherited from the caller before + * relinquishing the gid and uid, while we still have the privilege + * required to do so. Otherwise the thread would keep root's group + * memberships while acting as the target user. + */ + if(setgroups(0, NULL) == -1) + return -1; + if(cg != ids->gid && setregid(-1, ids->gid) == -1) return -1;