From owner-freebsd-current Thu Mar 7 11:56:52 1996 Return-Path: owner-current Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id LAA03892 for current-outgoing; Thu, 7 Mar 1996 11:56:52 -0800 (PST) Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by freefall.freebsd.org (8.7.3/8.7.3) with SMTP id LAA03879 for ; Thu, 7 Mar 1996 11:56:38 -0800 (PST) Received: (from bde@localhost) by godzilla.zeta.org.au (8.6.12/8.6.9) id GAA05727; Fri, 8 Mar 1996 06:53:48 +1100 Date: Fri, 8 Mar 1996 06:53:48 +1100 From: Bruce Evans Message-Id: <199603071953.GAA05727@godzilla.zeta.org.au> To: current@freebsd.org, mark@linus.demon.co.uk Subject: Re: reproducible fatal trap 12 Sender: owner-current@freebsd.org Precedence: bulk >I can reliably reproduce a "Fatal trap 12: page fault while in kernel >mode" in a current kernel (up to date as of a few hours ago). I reproduce >it by mounting the FreeBSD 2.1 "live file system" CD and doing some file >name completion in the Xlib source tree (using bash), e.g. > $ more /cdrom/usr/X11R6/src/xc/lib/X11/ >The fault address on one instance was 0xf08aa001, and the fault code is >"supervisor read, page not present". The instruction pointer is at: > _cd9660_readdir+0x1a7: movzbl 0(%ecx),%esi >%ecx is the fault address. This is easy to reproduce and seems to be a bug in cd9660_readdir(). An invalid directory entry is accessed one statment before the check that finds it to be invalid. My fix delays the access and some other access until the reclen and namlen checks are done. Apparently it is OK to access the parts of the directory entry containing the reclen and the namlen, although there is no such thing as a partial struct in C. Skipping the faulting instructing in ddb happens to work safely. For some reason the bug wasn't reproducible after that (even after switching to another cdrom and back). Bruce *** cd9660_vnops.c~ Mon Dec 4 15:44:02 1995 --- cd9660_vnops.c Fri Mar 8 05:54:13 1996 *************** *** 559,562 **** --- 559,563 ---- struct iso_directory_record *ep; u_short elen; + int namlen; int reclen; int isoflags; *************** *** 620,625 **** reclen = isonum_711 (ep->length); - isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? - &ep->date[6]: ep->flags); if (reclen == 0) { /* skip to next block, if any */ --- 621,624 ---- *************** *** 641,648 **** } /* XXX: be more intelligent if we can */ idp->current.d_type = DT_UNKNOWN; ! idp->current.d_namlen = isonum_711 (ep->name_len); if (isoflags & 2) isodirino(&idp->current.d_fileno,ep,imp); --- 640,656 ---- } + namlen = isonum_711 (ep->name_len); + if (reclen < ISO_DIRECTORY_RECORD_SIZE + namlen) { + error = EINVAL; + /* illegal entry, stop */ + break; + } + /* XXX: be more intelligent if we can */ idp->current.d_type = DT_UNKNOWN; ! idp->current.d_namlen = namlen; ! isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? ! &ep->date[6]: ep->flags); if (isoflags & 2) isodirino(&idp->current.d_fileno,ep,imp); *************** *** 650,659 **** idp->current.d_fileno = dbtob(bp->b_blkno) + idp->curroff; - - if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { - error = EINVAL; - /* illegal entry, stop */ - break; - } idp->curroff += reclen; --- 658,661 ----