commit 836feec54d58f145d34b14baee7cb0ff677cbd26
parent c282965520a0d8bcc2b8c2f010fd96ad063a25c3
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Thu, 7 Aug 2014 14:52:19 +0200
Avoid race conditions between fork and wait
If some signal arrives to the parent between these two points
then it is possible to have dirty entries in utmp.
Diffstat:
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/utmp.c b/utmp.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
@@ -39,6 +40,7 @@ main(int argc, char *argv[])
{
int status;
uid_t uid;
+ sigset_t set;
extern void addutmp(void), delutmp(void);
egid = getegid();
@@ -54,8 +56,12 @@ main(int argc, char *argv[])
setenv("SHELL", pass->pw_shell, 0);
setenv("HOME", pass->pw_dir, 0);
+ sigfillset(&set);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+
switch (fork()) {
case 0:
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
argv[0] = getenv("SHELL");
execv(argv[0], argv);
die("error executing shell:%s", strerror(errno));
@@ -63,10 +69,13 @@ main(int argc, char *argv[])
die("error spawning child:%s", strerror(errno));
default:
addutmp();
- if (wait(&status) == -1) {
- fprintf(stderr, "error waiting child:%s\n",
- strerror(errno));
- }
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+
+ if (wait(&status) == -1)
+ perror("error waiting child");
delutmp();
}
return 0;