[PATCH 3/5] init: fix race with utmp and children

Mike Frysinger vapier at gentoo.org
Sun Oct 18 08:49:36 UTC 2009


From: Gil Kloepfer <gbz at kloepfer.org>

A race condition in sysvinit exists where the utmp entry that getty needs
to update may not be written by sysvinit by the time getty accesses it.
This happens more often (and almost exclusively) on uniprocessor systems
due to the way time-slicing is done by the kernel.

This race condition exists because when the getty is spawned from init, it
is assumed that the return from the function that spawns the getty will
happen faster than it takes for getty to start and update the utmp file.
On a multiprocessor system, this is likely to happen because init and getty
will run in parallel.  However, on a uniprocessor system, due to the way
that Linux schedules subprocesses, getty will have the processor for enough
of a timeslice that the function return in init will not happen until after
getty has proceeded to update utmp.  Because getty expects that init has
written the initial utmp entry, and the entry doesn't exist, getty creates
another entry.

These bogus extra entries are seen as extra logins by "uptime" and "top" and
so the number of logins becomes incorrect as a result.

URL: https://bugs.gentoo.org/188262
Signed-off-by: Gil Kloepfer <gbz at kloepfer.org>
Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
 src/init.c |   29 ++++++++++++++++++++---------
 1 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/init.c b/src/init.c
index cffd5dd..a6e666b 100644
--- a/src/init.c
+++ b/src/init.c
@@ -958,6 +958,25 @@ int spawn(CHILD *ch, int *res)
   		sigprocmask(SIG_SETMASK, &omask, NULL);
 
 		/*
+		 * Update utmp/wtmp file prior to starting
+		 * any child.  This MUST be done right here in
+		 * the child process in order to prevent a race
+		 * condition that occurs when the child
+		 * process' time slice executes before the
+		 * parent (can and does happen in a uniprocessor
+		 * environment).  If the child is a getty and
+		 * the race condition happens, then init's utmp
+		 * update will happen AFTER the getty runs
+		 * and expects utmp to be updated already!
+		 *
+		 * Do NOT log if process field starts with '+'
+		 * FIXME: that's for compatibility with *very*
+		 * old getties - probably it can be taken out.
+		 */
+		if (ch->action == RESPAWN && ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
+
+		/*
 		 *	In sysinit, boot, bootwait or single user mode:
 		 *	for any wait-type subprocess we _force_ the console
 		 *	to be its controlling tty.
@@ -1099,15 +1118,7 @@ void startup(CHILD *ch)
 		case ONDEMAND:
 		case RESPAWN:
   			ch->flags |= RUNNING;
-  			if (spawn(ch, &(ch->pid)) < 0) break;
-			/*
-			 *	Do NOT log if process field starts with '+'
-			 *	FIXME: that's for compatibility with *very*
-			 *	old getties - probably it can be taken out.
-			 */
-  			if (ch->process[0] != '+')
-				write_utmp_wtmp("", ch->id, ch->pid,
-					INIT_PROCESS, "");
+  			(void)spawn(ch, &(ch->pid));
   			break;
 	}
 }
-- 
1.6.5.rc2




More information about the initscripts-ng-devel mailing list