Subject: kern/3748: bdwrite() can reference bdevsw with an invalid index
To: None <gnats-bugs@gnats.netbsd.org>
From: None <mhitch@gemini.oscs.montana.edu>
List: netbsd-bugs
Date: 06/13/1997 21:04:09
>Number:         3748
>Category:       kern
>Synopsis:       bdwrite() can access bdevsw with an invalid index
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 13 20:20:01 1997
>Last-Modified:
>Originator:     Michael L Hitch
>Organization:
	Montana State University
>Release:        NetBSD-current June 12, 1997
>Environment:
	
System: NetBSD news.oscs.montana.edu 1.2G NetBSD 1.2G (R4000) #970612TX-5: Fri Jun 13 20:18:41 MDT 1997 mhitch@news.oscs.montana.edu:/d/d/sys.new/arch/pmax/compile/R4000 pmax


>Description:
	It would appear that bdwrite() can be passed a buffer with NODEV in
	b_dev.  This can cause a bad index into bdevsw[] when bdwrite()
	makes the test to see if the device is a tape.  If you happen to
	be unlucky and the memory location contains D_TAPE [which is the
	case for pmax in -current], the buffer is written out.  This can
	cause a significant decrease in file write performance.
>How-To-Repeat:
	To demonstrate the file write degradation, bdevsw[255].d_type needs
	to be equal to D_TAPE.  The -current pmax GENERIC kernel meets this
	condition.  Inserting dummy data initialized to 1 at the correct
	location addressed by bdevsw[255].d_type can be used to demonstrate
	this as well.  Running iozone on a DECstation 5000 results in
	write rates 3 to 4 times slower than possible.

	Adding a printf() in bdwrite() to check for a invalid index by
	checking major(bp->b_dev) against nblkdev shows that bdwrite()
	gets called with 0xffffffff and 0x0000ff00 in b_dev.  I don't
	know enough about how bdwrite() is used to know if those values
	are valid, but they should not be used to index bdevsw.
>Fix:
	To prevent accessing bdevsw[] with a bad index, the index should
	be checked for a valid value (i.e. < nblkdev).

*** /c/work/src/sys/kern/vfs_bio.c	Sat May 17 22:43:33 1997
--- sys/kern/vfs_bio.c	Thu Jun 12 19:29:30 1997
***************
*** 357,363 ****
  	struct proc *p = (curproc != NULL ? curproc : &proc0);	/* XXX */
  
  	/* If this is a tape block, write the block now. */
! 	if (bdevsw[major(bp->b_dev)].d_type == D_TAPE) {
  		bawrite(bp);
  		return;
  	}
--- 357,364 ----
  	struct proc *p = (curproc != NULL ? curproc : &proc0);	/* XXX */
  
  	/* If this is a tape block, write the block now. */
! 	if (major(bp->b_dev) < nblkdev &&
! 	    bdevsw[major(bp->b_dev)].d_type == D_TAPE) {
  		bawrite(bp);
  		return;
  	}
>Audit-Trail:
>Unformatted: