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.