autofs-5.1.8 - dont use initgroups() at spawn From: Ian Kent The initgroups(3) function isn't safe to use between fork() and exec() in a threaded program. Using it this way often leads to a hang for even moderate work loads. But the getgrouplist()/setgroups() combination can be used safely in this case and this patch changes autofs to use these (the safety of using of setgroups() is yet to to be documented). A large portion of the work on this patch has been contributed by Roberto Bergantinos . Reported-by: Roberto Bergantinos Fixes: 6343a3292020 ("autofs-5.1.3 - fix ordering of seteuid/setegid in do_spawn()") Signed-off-by: Roberto Bergantinos Signed-off-by: Ian Kent --- CHANGELOG | 1 + daemon/spawn.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 72a5aa59..e1214323 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ - fix sysconf(3) return handling. - remove nonstrict parameter from tree_mapent_umount_offsets(). - fix handling of incorrect return from umount_ent(). +- dont use initgroups() at spawn. 19/10/2021 autofs-5.1.8 - add xdr_exports(). diff --git a/daemon/spawn.c b/daemon/spawn.c index 914e5288..6f8856a9 100644 --- a/daemon/spawn.c +++ b/daemon/spawn.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "automount.h" @@ -335,6 +336,10 @@ static int do_spawn(unsigned logopt, unsigned int wait, struct thread_stdenv_vars *tsv; pid_t euid = 0; gid_t egid = 0; + gid_t *groups = NULL; + gid_t *saved_groups = NULL; + int ngroups = 0; + int nsaved_groups = 0; if (open_pipe(pipefd)) return -1; @@ -357,6 +362,31 @@ static int do_spawn(unsigned logopt, unsigned int wait, } open_mutex_lock(); + + if (euid) { + struct passwd *pwd; + + pwd = getpwuid(getuid()); + if (!pwd) + fprintf(stderr, + "warning: getpwuid: can't get current username\n"); + else { + /* get number of groups for current gid */ + getgrouplist(pwd->pw_name, getgid(), NULL, &nsaved_groups); + saved_groups = malloc(nsaved_groups * sizeof(gid_t)); + + /* get current gid groups list */ + getgrouplist(pwd->pw_name, getgid(), saved_groups, &nsaved_groups); + } + + /* get number of groups of mount triggering process */ + getgrouplist(tsv->user, egid, NULL, &ngroups); + groups = malloc(ngroups * sizeof(gid_t)); + + /* get groups list of mount triggering process */ + getgrouplist(tsv->user, egid, groups, &ngroups); + } + f = fork(); if (f == 0) { char **pargv = (char **) argv; @@ -398,10 +428,13 @@ static int do_spawn(unsigned logopt, unsigned int wait, if (!tsv->user) fprintf(stderr, "warning: can't init groups\n"); - else if (initgroups(tsv->user, egid) == -1) - fprintf(stderr, - "warning: initgroups: %s\n", - strerror(errno)); + else if (groups) { + if (setgroups(ngroups, groups) == -1) + fprintf(stderr, + "warning: setgroups: %s\n", + strerror(errno)); + free(groups); + } if (setegid(egid) == -1) fprintf(stderr, @@ -436,6 +469,11 @@ static int do_spawn(unsigned logopt, unsigned int wait, strerror(errno)); if (pgrp >= 0) setpgid(0, pgrp); + /* Reset groups for trigger of trailing mount */ + if (euid && saved_groups) { + setgroups(nsaved_groups, saved_groups); + free(saved_groups); + } /* * The kernel leaves mount type autofs alone because @@ -474,6 +512,11 @@ done: pthread_sigmask(SIG_SETMASK, &tmpsig, NULL); open_mutex_unlock(); + if (groups) + free(groups); + if (saved_groups) + free(saved_groups); + close(pipefd[1]); if (f < 0) {