From 6498a0c2cc19361526aad0a0aa01f309aba4293a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Nov 2023 17:45:06 +0100 Subject: [PATCH] user-util: add new helper fully_set_uid_gid() Usually when we do setresuid() we also do setesgid() and setgroups(). Let's add a common helper that does all three, and use it everywhere. --- src/basic/user-util.c | 19 ++++++++++++++----- src/basic/user-util.h | 5 ++++- src/core/exec-invoke.c | 8 ++------ src/home/homed-home.c | 18 +++--------------- src/home/homework-fscrypt.c | 18 +++--------------- src/nspawn/nspawn-setuid.c | 13 +++++-------- src/test/test-socket-util.c | 5 +---- 7 files changed, 32 insertions(+), 54 deletions(-) diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 9ae8577238..8aaffe8d04 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -661,17 +661,26 @@ int get_shell(char **ret) { return path_simplify_alloc(e, ret); } -int reset_uid_gid(void) { +int fully_set_uid_gid(uid_t uid, gid_t gid, const gid_t supplementary_gids[], size_t n_supplementary_gids) { int r; - r = maybe_setgroups(0, NULL); + assert(supplementary_gids || n_supplementary_gids == 0); + + /* Sets all UIDs and all GIDs to the specified ones. Drops all auxiliary GIDs */ + + r = maybe_setgroups(n_supplementary_gids, supplementary_gids); if (r < 0) return r; - if (setresgid(0, 0, 0) < 0) - return -errno; + if (gid_is_valid(gid)) + if (setresgid(gid, gid, gid) < 0) + return -errno; + + if (uid_is_valid(uid)) + if (setresuid(uid, uid, uid) < 0) + return -errno; - return RET_NERRNO(setresuid(0, 0, 0)); + return 0; } int take_etc_passwd_lock(const char *root) { diff --git a/src/basic/user-util.h b/src/basic/user-util.h index f394f6251d..b3e254662e 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -57,7 +57,10 @@ int getgroups_alloc(gid_t** gids); int get_home_dir(char **ret); int get_shell(char **ret); -int reset_uid_gid(void); +int fully_set_uid_gid(uid_t uid, gid_t gid, const gid_t supplementary_gids[], size_t n_supplementary_gids); +static inline int reset_uid_gid(void) { + return fully_set_uid_gid(0, 0, NULL, 0); +} int take_etc_passwd_lock(const char *root); diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 74c910fc12..e44eacd8ed 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -1220,13 +1220,9 @@ static int setup_pam( * PR_SET_PDEATHSIG work in most cases. If this fails, ignore the error - but expect sd-pam * threads to fail to exit normally */ - r = maybe_setgroups(0, NULL); + r = fully_set_uid_gid(uid, gid, /* supplementary_gids= */ NULL, /* n_supplementary_gids= */ 0); if (r < 0) - log_warning_errno(r, "Failed to setgroups() in sd-pam: %m"); - if (setresgid(gid, gid, gid) < 0) - log_warning_errno(errno, "Failed to setresgid() in sd-pam: %m"); - if (setresuid(uid, uid, uid) < 0) - log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m"); + log_warning_errno(r, "Failed to drop privileges in sd-pam: %m"); (void) ignore_signals(SIGPIPE); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 37b3270841..7673e50435 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -2085,23 +2085,11 @@ int home_killall(Home *h) { if (r < 0) return r; if (r == 0) { - gid_t gid; - /* Child */ - gid = user_record_gid(h->record); - if (setresgid(gid, gid, gid) < 0) { - log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); - _exit(EXIT_FAILURE); - } - - if (setgroups(0, NULL) < 0) { - log_error_errno(errno, "Failed to reset auxiliary groups list: %m"); - _exit(EXIT_FAILURE); - } - - if (setresuid(h->uid, h->uid, h->uid) < 0) { - log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", h->uid); + r = fully_set_uid_gid(h->uid, user_record_gid(h->record), /* supplementary_gids= */ NULL, /* n_supplementary_gids= */ 0); + if (r < 0) { + log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m", h->uid, user_record_gid(h->record)); _exit(EXIT_FAILURE); } diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c index 6aae1d2626..ad0b69b021 100644 --- a/src/home/homework-fscrypt.c +++ b/src/home/homework-fscrypt.c @@ -319,23 +319,11 @@ int home_setup_fscrypt( if (r < 0) return log_error_errno(r, "Failed install encryption key in user's keyring: %m"); if (r == 0) { - gid_t gid; - /* Child */ - gid = user_record_gid(h); - if (setresgid(gid, gid, gid) < 0) { - log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); - _exit(EXIT_FAILURE); - } - - if (setgroups(0, NULL) < 0) { - log_error_errno(errno, "Failed to reset auxiliary groups list: %m"); - _exit(EXIT_FAILURE); - } - - if (setresuid(h->uid, h->uid, h->uid) < 0) { - log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", h->uid); + r = fully_set_uid_gid(h->uid, user_record_gid(h), /* supplementary_gids= */ NULL, /* n_supplementary_gids= */ 0); + if (r < 0) { + log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m", h->uid, user_record_gid(h)); _exit(EXIT_FAILURE); } diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c index 2d67c3d9de..e350b22806 100644 --- a/src/nspawn/nspawn-setuid.c +++ b/src/nspawn/nspawn-setuid.c @@ -56,6 +56,8 @@ int change_uid_gid_raw( size_t n_supplementary_gids, bool chown_stdio) { + int r; + if (!uid_is_valid(uid)) uid = 0; if (!gid_is_valid(gid)) @@ -67,14 +69,9 @@ int change_uid_gid_raw( (void) fchown(STDERR_FILENO, uid, gid); } - if (setgroups(n_supplementary_gids, supplementary_gids) < 0) - return log_error_errno(errno, "Failed to set auxiliary groups: %m"); - - if (setresgid(gid, gid, gid) < 0) - return log_error_errno(errno, "setresgid() failed: %m"); - - if (setresuid(uid, uid, uid) < 0) - return log_error_errno(errno, "setresuid() failed: %m"); + r = fully_set_uid_gid(uid, gid, supplementary_gids, n_supplementary_gids); + if (r < 0) + return log_error_errno(r, "Changing privileges failed: %m"); return 0; } diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index e9c776a8c5..4233ca6527 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -176,10 +176,7 @@ TEST(getpeercred_getpeergroups) { test_gids = (gid_t*) gids; n_test_gids = ELEMENTSOF(gids); - assert_se(setgroups(n_test_gids, test_gids) >= 0); - assert_se(setresgid(test_gid, test_gid, test_gid) >= 0); - assert_se(setresuid(test_uid, test_uid, test_uid) >= 0); - + assert_se(fully_set_uid_gid(test_uid, test_gid, test_gids, n_test_gids) >= 0); } else { long ngroups_max; -- 2.25.1