Package: libpam-modules Version: 1.1.8-3.6 Severity: normal Dear Maintainer,
pam_exec is currently not handling SIGCHLD in the same way that other pam modules do when using fork (see for example how pam_unix reset SIGCHLD to default before fork and restore SIGCHLD to the old value after wait). By not resetting SIGCHLD, you might encounter a race conditions when the process that is calling pam actually sets up a signal handler that runs wait (to retrieve pids of its children). I was able to always reproduce this behaviour with a fresh Debian installation (minimal set of packages) and: - install a trivial pam_exec line, for example append in /etc/pam.d/common-account - sets up an at job for the near future - verify the behaviour of the atd process - you should see that it fails and in the log: /var/log/auth.log: Oct 13 21:47:00 d9test atd[766]: pam_exec(atd:account): waitpid returns with -1: No child processes and a strace of atd reveals what happens (atd has pid 487, the new process that is generated at 21:47 has pid 766) (see the output of "strace -tt -f -p 487") - atd (pid=487) forks at exactly 21:47 (it's the job that has been setup) producing pid=766 - pam stack runs, pam_exec fork/exec the process that is defined in /etc/pam.d (in this example /bin/true), pid=767 - pid=767 exits immediately with exit=0 - pid=766 receives SIGCHLD and you can clearly see that there's a signal handler that collects pid=767 - after the signal handler, there's another wait call (pam_exec's) that cannot find this child and therefore exit with exit=1 487 21:46:24.691254 restart_syscall(<... resuming interrupted nanosleep ...>) = 0 487 21:47:00.039083 stat(".", {st_mode=S_IFDIR|S_ISVTX|0770, st_size=4096, ...}) = 0 [...] 487 21:47:00.040078 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fad11926f50) = 766 766 21:47:00.040313 set_robust_list(0x7fad11926f60, 24) = 0 [...] 766 21:47:00.060342 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fad11926f50) = 767 767 21:47:00.060535 set_robust_list(0x7fad11926f60, 24 <unfinished ...> [...] 767 21:47:00.158848 execve("/bin/true", ["/bin/true"], [/* 3 vars */]) = 0 [...] 767 21:47:00.160283 exit_group(0) = ? 767 21:47:00.160345 +++ exited with 0 +++ 766 21:47:00.160366 <... read resumed> "", 4096) = 0 766 21:47:00.160412 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=767, si_uid=1, si_status=0, si_utime=0, si_stime=0} --- 766 21:47:00.160462 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 767 766 21:47:00.160549 wait4(-1, 0x7ffe3a24a914, WNOHANG, NULL) = -1 ECHILD (No child processes) 766 21:47:00.160607 rt_sigreturn({mask=[]}) = 0 766 21:47:00.160668 close(7) = 0 766 21:47:00.160719 wait4(767, 0x7ffe3a24aff8, 0, NULL) = -1 ECHILD (No child processes) [...] 766 21:47:00.163397 exit_group(1) = ? 766 21:47:00.163533 +++ exited with 1 +++ [...] A simple fix (that works for me) could be to do what pam_unix does: reset to SIG_DFL before fork and then restore the signal at wait. (in pam_unix there's also a check of option UNIX_NOREAP, it might be a good idea to also introduce this in pam_exec). --- pam_exec.c.orig +++ pam_exec.c @@ -48,6 +48,7 @@ #include <sys/wait.h> #include <sys/stat.h> #include <sys/types.h> +#include <signal.h> #define PAM_SM_AUTH @@ -212,6 +213,10 @@ return PAM_SERVICE_ERR; } + memset(&newsa, '\0', sizeof(newsa)); + newsa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &newsa, &oldsa); + pid = fork(); if (pid == -1) return PAM_SYSTEM_ERR; @@ -258,6 +263,7 @@ while ((retval = waitpid (pid, &status, 0)) == -1 && errno == EINTR); + sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */ if (retval == (pid_t)-1) { pam_syslog (pamh, LOG_ERR, "waitpid returns with -1: %m"); Regards, Leonardo. -- System Information: Debian Release: 9.5 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 4.9.0-8-amd64 (SMP w/6 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE=en_GB:en (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages libpam-modules depends on: ii debconf [debconf-2.0] 1.5.61 ii libaudit1 1:2.6.7-2 ii libc6 2.24-11+deb9u3 ii libdb5.3 5.3.28-12+deb9u1 ii libpam-modules-bin 1.1.8-3.6 ii libpam0g 1.1.8-3.6 ii libselinux1 2.6-3+b3 libpam-modules recommends no packages. libpam-modules suggests no packages. -- debconf information: libpam-modules/disable-screensaver: