[dev] [utmp][PATH] Avoid race conditions between fork and wait

From: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
Date: Thu, 7 Aug 2014 15:35:21 +0200

If some signal arrives to the parent between these two points
then it is possible to have dirty entries in utmp.
---
 utmp.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/utmp.c b/utmp.c
index c893ae1..6cdc5d2 100644
--- a/utmp.c
+++ b/utmp.c
_AT_@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <signal.h>
 
 #include <sys/types.h>
 #include <unistd.h>
_AT_@ -40,6 +41,7 @@ main(int argc, char *argv[])
 	int status;
 	uid_t uid;
 	extern void addutmp(void), delutmp(void);
+	sigset_t set;
 
 	egid = getegid();
 	gid = getgid();
_AT_@ -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));
_AT_@ -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;
-- 
1.9.3
Received on Thu Aug 07 2014 - 15:35:21 CEST

This archive was generated by hypermail 2.3.0 : Thu Aug 07 2014 - 15:48:03 CEST