race condition in init (4.1BSD)
wls at astrovax.UUCP
wls at astrovax.UUCP
Tue Jul 26 12:11:06 AEST 1983
The following is a copy of a bug report I have just submitted to
ucbvax!4bsd-bugs.
William L. Sebok
Princeton Univ. Observatory
{allegra,cbosgd,ihnp4,knpo}!astrovax!wls
----------------------------------------------------
Date: Mon Jun 25 1983
From: allegra!astrovax!wls
Subject: race condition in init
Index: /usr/src/cmd/init.c 4.1 Fix
Description:
There is a race condition in /etc/init for 4.1 BSD. If a HUP signal is
sent to init, causing it to reread /etc/ttys, and at the same time
someone logs out, it is possible for init to lose track of the fact
that the logout occurred. If this happens no new process is created
for that port and the port is effectively dead. In this state
/etc/utmp is not updated so that the person still appears on the
list of users logged in, but without a process. The condition can be
cleared by disabling the port, then reenabling it.
The bug is in the fact that merge() is called and the branch out of
the loop is taken without checking that the pid returned by the wait
might be valid. On a loaded system it is quite possible for one of
init's children to die in the window between the HUP signal and init's
response to it.
We have a version of uucp that uses the same ports for dialing in and
dialing out. It regularly turns the dialin ports on and off, exposing
the existence of this bug.
Repeat-By:
Send a HUP to init and at the same time kill one of init's children
that is a process group header (not an orphan process). If the timing
is just right init will not know of the child's death. This is more
likely to occur on a heavily loaded system.
Fix:
the fix involves re-arranging the order of the operations in the main loop
of init. Here is a diff of that main loop:
diff init.c.old init.c
219,232c219
< for(EVER) {
< pid = wait((int *)0);
< if(mergflag) {
< merge();
< goto loop;
< }
< if(pid == -1)
< return;
< for(ALL)
< if(p->pid == pid || p->pid == -1) {
< rmut(p);
< dfork(p);
< }
< }
---
> for(EVER) {
> pid = wait((int *)0);
>
> if (pid=>0) for(ALL) { /* Bug Fix (WLS) July 7,1983 */
> if(p->pid == pid || p->pid == -1) {
> rmut(p);
> dfork(p);
> }
> }
>
> if(mergflag) {
> merge();
> goto loop;
> }
>
> if(pid == -1)
> return;
>
> }
More information about the Comp.unix.wizards
mailing list