[net.bugs.v7] A severe bug in V7 exece

olson@fortune.UUCP (Dave Olson) (12/07/84)

There is a severe bug in the V7 exece() in sys1.c, IF it has been
modified to use bdwrite(), without adding the code at the end of this
article (or equivalent code).  (It is ok in S5 and 4.1BSD, and
possibly others).  The problem definitely occurs if you have modified
it to use bdwrite();  if it is stock and uses bawrite(), the problem
might still occur, but probably will not (and the fix below will not
help).

The problem occurs when getxfile() fails.  (This most frequently
happens with shell scripts on our system.)  In this case,  the
accumulated argument list and environment remain in the buffer cache
(due to the bdwrite(bp) ).  Unfortunately, the swap space that was
allocated is freed.  Since bp is 0'ed just before the call to
getxfile(), you won't even release the latest buffer used.

Typically, exece() ends up getting the same swap
blocks on each call (or the write actually occurs and the buffer is
released).  In this case, there is no problem.  However, if the system
becomes loaded enough that the swap space is reallocated to another
process (and the process swaps) BEFORE the write completes, the
swapped process will be partially overwritten.

If the portion overwritten happens to be the upage, disastrous things
can happen.  (If the overwrite is in the text, data, or stack segment
of a process, bizzare behaviour may occur IF the overwritten info is
referenced by the process after it is swapped in.)

If you are running on a 68000 machine, you will typically
get a double bus error in resume().  You therefore get a 'silent hang'
where the CPU simply shuts down.  I'm not sure what would happen on 
other machines.

With the modification to use bdwrite(), instead of bawrite()
in order to reduce disk i/o, the problem is much more severe,
as the chance of the write completing after the swap space is
reallocated is much greater.

The fix is relatively simple:
Change the lines:
	if (getxfile(ip, nc) || u.u_error)
		goto bad;
To:
	if(getxfile(ip, nc) || u.u_error) {
		for(c = 0; c < nc; c += BSIZE) {
			bp = (incore(swapdev, dbtofsb(bno+swplo)+(c>>BSHIFT))) ?
				bread(swapdev,dbtofsb(bno+swplo)+(c>>BSHIFT)) : 0;
			if(bp) {	/* if the buffer has not yet been written */
				bp->b_flags |= B_AGE;		/* throw it away */
				bp->b_flags &= ~B_DELWRI;	/* cancel the I/O */
				brelse(bp);
				bp = 0;	/* prevent brelse() at bad: */
			}
		}
		goto bad;
	}


Dave Olson at Fortune Systems.  UUCP: {ihnp4,ucbvax!dual}!fortune!olson