Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Jun 2002 10:37:12 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Brooks Davis <brooks@one-eyed-alien.net>
Cc:        current@FreeBSD.ORG
Subject:   Re: dump (via amanda) causing panics
Message-ID:  <20020606100455.N9476-100000@gamplex.bde.org>
In-Reply-To: <20020605161454.A22201@Odin.AC.HMC.Edu>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 5 Jun 2002, Brooks Davis wrote:

> For the last week or so I've had my laptop panic every time amanda did
> a dump of it.  This happens with a kernel as of yesterday so it probably
> wasn't just a bad update.
>
> Before the crash I see the following in dmesg:
>
> ad0: count 6359632 size transfers not supported
> bus_dmamap_load: Too many segs! buf_len = 0xc204abb0
> ad0: READ command tiemotu tag=0 serv=0 - resetting
> ad0: resetting devices .. done
> [the above repeated twice more]
> ad0: count 6359632 size transfers not supported
> bus_dmamap_load: Too many segs! buf_len = 0xc204abb0
> ad0: READ command tiemotu tag=0 serv=0 - resetting
> ad0: trying to fall back to PIO mode
> ad0: resetting devices .. done
> ad0: count 6359632 size transfers not supported
> PANIC

This is caused by:
(1) amanda attempting to read from a bad offset on the device.  Almost
    any offset that causes a block number of >= 2GB or 4GB will trigger
    the kernel bug.
(2) the bounds checking in dscheck() being 64-bit daddr_t casualty
    (*blush*).

I just committed this fix which I had been sitting on this fix for
too long:

%%%
Index: subr_diskslice.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/subr_diskslice.c,v
retrieving revision 1.103
diff -u -2 -r1.103 subr_diskslice.c
--- subr_diskslice.c	12 May 2002 20:49:41 -0000	1.103
+++ subr_diskslice.c	23 May 2002 14:10:26 -0000
@@ -57,4 +57,5 @@
 #include <sys/malloc.h>
 #include <sys/stat.h>
+#include <sys/stdint.h>
 #include <sys/syslog.h>
 #include <sys/vnode.h>
@@ -225,5 +226,5 @@

 	/* beyond partition? */
-	if (secno + nsec > endsecno) {
+	if ((uintmax_t)secno + nsec > endsecno) {
 		/* if exactly at end of disk, return an EOF */
 		if (secno == endsecno) {
@@ -232,10 +233,9 @@
 		}
 		/* or truncate if part of it fits */
-		nsec = endsecno - secno;
-		if (nsec <= 0) {
+		if (secno > endsecno) {
 			bp->bio_error = EINVAL;
 			goto bad;
 		}
-		bp->bio_bcount = nsec * ssp->dss_secsize;
+		bp->bio_bcount = (endsecno - secno) * ssp->dss_secsize;
 	}

%%%

This fixes 2 overflow bugs.  The main one is in the second hunk.  Offsets
way beyond the end of the disk caused "truncation" to actually expand the
block to a huge one.  (`nsec = endsecno - secno' subtracts a daddr_t that
is known to be positive from a u_long and stores the result in a long, so
overflow used to be only possible (for the assignment only) for physical
disks with more than 2GB sectors, but it is now possible for byte offsets
larger than 1TB which are much cheaper than 1TB disks.)

Device drivers that check the bounds directly probably have variants of this
bug.  Ones that use the deprecated bounds_check_with_label() (mainly ccd and
drivers for ancient cdroms) certainly do.

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020606100455.N9476-100000>