Subject: Re: Adaptec 2940 and `more than N DMA segs'
To: None <gnats-bugs@gnats.netbsd.org>
From: Johan Danielsson <joda@pdc.kth.se>
List: port-i386
Date: 06/08/1998 00:41:12
>Submitter-Id:	net
>Originator:	Johan Danielsson
>Organization:
>Confidential:	no
>Synopsis:	ahc_scsi_cmd gets called with too big datalen
>Severity:	serious
>Priority:	high
>Category:	kern
>Class:		sw-bug
>Release:	1.3.2
>Environment:
System: NetBSD buoy.pdc.kth.se 1.3.2 NetBSD 1.3.2 (BUOY) #4: Sat Jun  6 01:36:45 CEST 1998     root@buoy.pdc.kth.se:/usr/src/sys/arch/i386/compile/BUOY i386

>Description:

If you open a raw scsi disk-device, seek to a negative position,
ahc_scsi_cmd sometime gets called with a too big datalen. The call
chain is as follows:

In vn_read(), fp->f_offset is, say, -2135932928, and uio->uio_offset
gets this value also. Then in physio(), bp->b_blkno (which is an int)
gets set to uio->uio_offset >> 9, which is -4171744 (int). In
bounds_check_with_label(), the usual signed/unsigned comparison
breakage occurs, and bp->b_bcount gets set to 2134972928 (with
p->p_size == 8386733). This broken buf, is later picked up by
sdstart().

>How-To-Repeat:

Try this program on a raw scsi device attached to an Adaptec
controller (I have tried it on 2940AU/UW); read() will never
return. Running this on an (some) IDE controller, read returns EINVAL.

#include <fcntl.h>
#include <unistd.h>
#include <sys/param.h>
#include <err.h>

int
main(int argc, char **argv)
{
    char buf[DEV_BSIZE];
    int fd = open(argv[1], O_RDONLY);
    if(fd < 0)
	err(1, "open");
    /* doesn't work with any negative value here */
    if(lseek(fd, (off_t)0xffffffff80000000LL, SEEK_SET) == (off_t)-1)
	err(1, "lseek");
    if(read(fd, buf, sizeof(buf)) != sizeof(buf))
	err(1, "read");
    close(fd);
    exit(0);
}

>Fix:

Left as an ex[eo]rcise to the reader.