From owner-freebsd-fs@freebsd.org Sun Nov 15 15:29:24 2015 Return-Path: Delivered-To: freebsd-fs@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7A863A2FD9A for ; Sun, 15 Nov 2015 15:29:24 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from mail110.syd.optusnet.com.au (mail110.syd.optusnet.com.au [211.29.132.97]) by mx1.freebsd.org (Postfix) with ESMTP id 07DC41123 for ; Sun, 15 Nov 2015 15:29:23 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from c211-30-166-197.carlnfd1.nsw.optusnet.com.au (c211-30-166-197.carlnfd1.nsw.optusnet.com.au [211.30.166.197]) by mail110.syd.optusnet.com.au (Postfix) with ESMTPS id ED4277815DC for ; Mon, 16 Nov 2015 02:29:14 +1100 (AEDT) Date: Mon, 16 Nov 2015 02:29:09 +1100 (EST) From: Bruce Evans X-X-Sender: bde@besplex.bde.org cc: freebsd-fs@freebsd.org Subject: Re: [Bug 127270] fsck_msdosfs(8) may crash if BytesPerSec is zero In-Reply-To: Message-ID: <20151116021615.X932@besplex.bde.org> References: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed X-Optus-CM-Score: 0 X-Optus-CM-Analysis: v=2.1 cv=cK4dyQqN c=1 sm=1 tr=0 a=KA6XNC2GZCFrdESI5ZmdjQ==:117 a=PO7r1zJSAAAA:8 a=9cW_t1CCXrUA:10 a=JzwRw_2MAAAA:8 a=kj9zAlcOel0A:10 a=6I5d2MoRAAAA:8 a=Z8M1z4-aN0-FwmMLC9sA:9 a=CjuIK1q_8ugA:10 X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Nov 2015 15:29:24 -0000 On Sun, 15 Nov 2015 bugzilla-noreply@freebsd.org wrote: > https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=127270 > > NGie Cooper changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > Assignee|freebsd-fs@FreeBSD.org |ngie@FreeBSD.org > CC| |ngie@FreeBSD.org > > --- Comment #2 from NGie Cooper --- > This should avoid the divide by 0, but I'd need to verify that the behavior is > correct: > https://people.freebsd.org/~ngie/bug127270.patch > > This situation should occur if and when boot blocks 12 and 13 are 0, but there > might need to be some additional conditions that need to be tripped in order > for the divide by 0 to occur: > > 66 boot->bpbBytesPerSec = block[11] + (block[12] << 8); This is fixed as a side effect of other fixes in my version. (The sector size needs to be read from the media. Instead, a hard-coded sector size or a larger size is used in all fsck utilities and kernel code. Sometimes this size is too small or too large to work. ffs probes for some things but not the size.) X Index: boot.c X =================================================================== X RCS file: /home/ncvs/src/sbin/fsck_msdosfs/boot.c,v X retrieving revision 1.6 X diff -u -2 -r1.6 boot.c X --- boot.c 31 Jan 2008 13:16:29 -0000 1.6 X +++ boot.c 3 Jul 2010 16:53:33 -0000 X @@ -48,4 +48,6 @@ X #include "fsutil.h" X X +#define IOSIZE 65536 X + X int X readboot(dosfs, boot) X @@ -53,18 +55,48 @@ X struct bootblock *boot; X { X + u_char ioblock[IOSIZE]; X + u_char iofsinfo[IOSIZE]; X + u_char iobackup[IOSIZE]; X u_char block[DOSBOOTBLOCKSIZE]; X u_char fsinfo[2 * DOSBOOTBLOCKSIZE]; X u_char backup[DOSBOOTBLOCKSIZE]; X + u_char *infop; X + size_t iosize; X + u_int secsize; X int ret = FSOK; X X - if (read(dosfs, block, sizeof block) < sizeof block) { X + /* Search for an i/o size that works. */ X + for (iosize = IOSIZE; iosize >= DOSBOOTBLOCKSIZE; iosize >>= 1) { X + if (lseek(dosfs, (off_t)0, SEEK_SET) == 0 && X + read(dosfs, ioblock, iosize) == (ssize_t)iosize) X + break; X + } X + if (iosize < DOSBOOTBLOCKSIZE) { X perror("could not read boot block"); X return FSFATAL; X } X + memcpy(block, ioblock, sizeof block); X X - if (block[510] != 0x55 || block[511] != 0xaa) { X - pfatal("Invalid signature in boot block: %02x%02x", block[511], block[510]); X + /* X + * Preliminary decode to determine where the signature might be. X + * It is supposed to be at the end of a 512-block, but we used to X + * put it at the end of a sector. Accept the latter so as to fix X + * it someday. X + */ X + secsize = block[11] + (block[12] << 8); X + if (secsize < sizeof block || secsize > IOSIZE) { X + perror("Preposterous or unsupported sector size"); X return FSFATAL; X } A sector size of 0 and some other preposterous sizes are rejected here. Sizes that are not multiples of 512 are still allowed. The signature checks weed out most garbage. X + if (block[510] != 0x55 || block[511] != 0xaa) { X + if (ioblock[secsize - 2] != 0x55 || X + ioblock[secsize - 1] != 0xaa) { X + pfatal("Invalid signature in boot block: %02x%02x", X + block[511], block[510]); X + return FSFATAL; X + } X + pwarn( X + "Invalid primary signature in boot block -- using secondary\n"); X + } X X memset(boot, 0, sizeof *boot); X [... remainder of patch not included] Bruce