[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-bugs
Subject:    kernel/811: Reading large file from ext2fs caused vm_fault.
From:       gluk () ecsc ! mipt ! ru
Date:       1999-04-24 11:23:05
[Download RAW message or body]


>Number:         811
>Category:       kernel
>Synopsis:       Reading large file from ext2fs caused vm_fault
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 24 06:00:02 MDT 1999
>Last-Modified:
>Originator:     Grigoriy Orlov
>Organization:

Network and Information Systems Laboratory at       
Moscow Institute of Physics and Technology (NISL/MIPT),
Grigoriy Orlov, System Administrator.                             
E-mail: gluk@ecsc.mipt.ru

>Release:        2.5-current
>Environment:
	
	System      : OpenBSD 2.4 ( with all patches )
	Architecture: OpenBSD.i386
	Machine     : i686
>Description:
Reading large file from ext2fs caused vm_fault, stack trace:
(gdb) bt
#0  0x100 in ?? ()
#1  0xf011e383 in panic (fmt=0xf01dce0e "trap")
    at ../../../../kern/subr_prf.c:202
#2  0xf01dd0d9 in trap (frame={tf_es = -257490928, tf_ds = -257556464, 
      tf_edi = -258970680, tf_esi = -250547708, tf_ebp = -39068368, 
      tf_ebx = 0, tf_edx = 0, tf_ecx = 0, tf_eax = -536821664, tf_trapno = 6, 
      tf_err = 0, tf_eip = -267163205, tf_cs = 8, tf_eflags = 66118, 
      tf_esp = 0, tf_ss = -39068348, tf_vm86_es = -267157750, tf_vm86_ds = 0, 
      tf_vm86_fs = -250547708, tf_vm86_gs = 0})
    at ../../../../arch/i386/i386/trap.c:257
#3  0xf0100b51 in ?? ()
#4  0xf0137f0a in bgetvp (vp=0x0, bp=0xf110f204)
    at ../../../../kern/vfs_subr.c:1949
#5  0xf0132a13 in getblk (vp=0x0, blkno=-65806, size=1024, slpflag=0, 
    slptimeo=0) at ../../../../kern/vfs_bio.c:597
#6  0xf01c1859 in ext2fs_bmaparray (vp=0x0, bn=65804, bnp=0xf110eef4, ap=0x0, 
    nump=0x0, runp=0x0) at ../../../../ufs/ext2fs/ext2fs_bmap.c:189
(gdb) 

Conditions: reading block with number >= 65804 ( 67383296 bytes for ext2 )
( 67383296 = (12 + 256 + 256*256) * 1024 )
 12 - direct blocks,
 256 - single indirect blocks,
 256*256 - double indirect blocks,
 1024 - block size.

For such a large block numbers the procedure "ufs_getlbns" fills in 
array "ap" beyond its allocated size and corrupts caller's stack frame. 
lines 282-298 at file /sys/ufs/ufs/ufs_bmap.c:
        ap++;
        for (++numlevels; i <= NIADDR; i++) {
                /* If searching for a meta-data block, quit when found. */
                if (metalbn == realbn)
                        break;

                blockcnt /= MNINDIR(ump);
                off = (bn / blockcnt) % MNINDIR(ump);

                ++numlevels;
                ap->in_lbn = metalbn;
                ap->in_off = off;
                ap->in_exists = 0;
                ++ap;

                metalbn -= -1 + off * blockcnt;
        }
at the beginning of this part of code:
numlevels=0,
i=1,
blockcnt=256*256*256,
bn=0,
realbn=65804,
metalbn=-65806,
NIADDR=3 , defined in /sys/ufs/ext2fs/ext2fs_dinode.h.
"ap" points to array of "struct indir" which is allocated
 in /sys/ufs/ext2fs_bmap.c: 123
       struct indir a[NIADDR], *xap;
Loop is executed 3 times so 4 "indir" items are written to "a".

Crash dosn't happen on ufs because, ufs does not use triple
indirect blocks. Default ufs block size is 8k, so crash would occur 
if file is 8*8*8 times larger then in ext2fs case. Even for
block size 4k triple indirect blocks aren't used for files of any
possible size.

Any user with read/write access to ext2fs can crash system.

>How-To-Repeat:
Read file with size > 67383296 from ext2fs
or, if there isn't enough disk space:
---------------------crash.c---------------------
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#define BLOCKSIZE 1024
#define DIRECT 12
#define INDIRECT 256

main()
{
int fd,count=BLOCKSIZE;
char buf[BLOCKSIZE];
char *text="xxxx";
int off=(DIRECT + INDIRECT + INDIRECT*INDIRECT)*BLOCKSIZE;

/* Create large file */
	fd=open("large",O_CREAT|O_RDWR,0600);
	lseek(fd,off + BLOCKSIZE,SEEK_SET);
	write(fd,text,sizeof(text));
	close(fd);

/* Read and crash... */
	fd=open("large",O_RDONLY,0);
	lseek(fd,off,SEEK_SET);
	while(count == BLOCKSIZE) {
		count = read(fd,buf,BLOCKSIZE);
	}
	close(fd);
}
-------------------------end-------------------
>Fix:
cd /sys/ufs/ext2fs
Patch0: 
--- ext2fs_bmap.c.orig	Fri Apr 23 14:36:20 1999
+++ ext2fs_bmap.c	Fri Apr 23 14:36:47 1999
@@ -120,7 +120,7 @@
 	struct ufsmount *ump;
 	struct mount *mp;
 	struct vnode *devvp;
-	struct indir a[NIADDR], *xap;
+	struct indir a[NIADDR + 1], *xap;
 	daddr_t daddr;
 	long metalbn;
 	int error, maxrun = 0, num;

cd /sys/ufs/ufs
Patch1:
--- ufs_bmap.c.orig	Fri Apr 23 06:11:20 1999
+++ ufs_bmap.c	Fri Apr 23 06:11:45 1999
@@ -114,7 +114,7 @@
 	struct ufsmount *ump;
 	struct mount *mp;
 	struct vnode *devvp;
-	struct indir a[NIADDR], *xap;
+	struct indir a[NIADDR + 1], *xap;
 	daddr_t daddr;
 	long metalbn;
 #ifdef	TRACE

>Audit-Trail:
>Unformatted:

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic