Module Name: src Committed By: mlelstv Date: Sun Feb 24 19:06:40 UTC 2019
Modified Files: src/sys/ufs/ufs: ufs_vnops.c Log Message: Reading a directory may trigger a panic when the buffer is too small. Adjust necessary checks. While here, also check for arithmetic overflow. Reported-by: syzbot+88ecace8bff241690...@syzkaller.appspotmail.com To generate a diff of this commit: cvs rdiff -u -r1.242 -r1.243 src/sys/ufs/ufs/ufs_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/ufs/ufs/ufs_vnops.c diff -u src/sys/ufs/ufs/ufs_vnops.c:1.242 src/sys/ufs/ufs/ufs_vnops.c:1.243 --- src/sys/ufs/ufs/ufs_vnops.c:1.242 Tue Jan 1 10:06:55 2019 +++ src/sys/ufs/ufs/ufs_vnops.c Sun Feb 24 19:06:40 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_vnops.c,v 1.242 2019/01/01 10:06:55 hannken Exp $ */ +/* $NetBSD: ufs_vnops.c,v 1.243 2019/02/24 19:06:40 mlelstv Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.242 2019/01/01 10:06:55 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.243 2019/02/24 19:06:40 mlelstv Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -1268,19 +1268,28 @@ ufs_readdir(void *v) } /* round start and end down to block boundaries */ - physstart = startoffset & ~(off_t)(ump->um_dirblksiz - 1); - physend = endoffset & ~(off_t)(ump->um_dirblksiz - 1); + physstart = rounddown2(startoffset, ump->um_dirblksiz); + physend = rounddown2(endoffset, ump->um_dirblksiz); + + if (physstart >= physend) { + /* Need at least one block */ + return EINVAL; + } + skipstart = startoffset - physstart; dropend = endoffset - physend; - if (callerbytes - dropend < _DIRENT_MINSIZE(rawdp)) { + /* how much to actually read */ + rawbufmax = callerbytes + skipstart; + if (rawbufmax < callerbytes) + return EINVAL; + rawbuf -= dropend; + + if (rawbufmax < _DIRENT_MINSIZE(rawdp)) { /* no room for even one struct direct */ return EINVAL; } - /* how much to actually read */ - rawbufmax = callerbytes + skipstart - dropend; - /* read it */ rawbuf = kmem_alloc(rawbufmax, KM_SLEEP); rawiov.iov_base = rawbuf;