From f48794b9f592747b49a561fac3392de4ae98657b Mon Sep 17 00:00:00 2001 From: bde Date: Mon, 24 Nov 1997 16:33:03 +0000 Subject: Fixed overflow in ufs_getblns(). For ufs on systems with 32-bit ints, triple indirect blocks only worked for block sizes of 4K, since MNINDIR(ump)**3 overflows for larger block sizes (e.g., (8192/4)**3 = 2**33 > INT_MAX). This fix is not the obvious one of changing some types to 64 bits. It rearranges the code to avoid some unnecessary 64-bit calculations. Reviewed by: Kirk McKusick --- sys/gnu/fs/ext2fs/ext2_bmap.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'sys/gnu/fs/ext2fs/ext2_bmap.c') diff --git a/sys/gnu/fs/ext2fs/ext2_bmap.c b/sys/gnu/fs/ext2fs/ext2_bmap.c index c85cc37..84df148 100644 --- a/sys/gnu/fs/ext2fs/ext2_bmap.c +++ b/sys/gnu/fs/ext2fs/ext2_bmap.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 - * $Id: ufs_bmap.c,v 1.15 1997/03/09 06:10:31 mpp Exp $ + * $Id: ufs_bmap.c,v 1.16 1997/09/02 20:06:56 bde Exp $ */ #include @@ -248,9 +248,10 @@ ufs_getlbns(vp, bn, ap, nump) struct indir *ap; int *nump; { - long metalbn, realbn; + long blockcnt, metalbn, realbn; struct ufsmount *ump; - int blockcnt, i, numlevels, off; + int i, numlevels, off; + int64_t qblockcnt; ump = VFSTOUFS(vp->v_mount); if (nump) @@ -267,15 +268,21 @@ ufs_getlbns(vp, bn, ap, nump) /* * Determine the number of levels of indirection. After this loop * is done, blockcnt indicates the number of data blocks possible - * at the given level of indirection, and NIADDR - i is the number + * at the previous level of indirection, and NIADDR - i is the number * of levels of indirection needed to locate the requested block. */ for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { if (i == 0) return (EFBIG); - blockcnt *= MNINDIR(ump); - if (bn < blockcnt) + /* + * Use int64_t's here to avoid overflow for triple indirect + * blocks when longs have 32 bits and the block size is more + * than 4K. + */ + qblockcnt = (int64_t)blockcnt * MNINDIR(ump); + if (bn < qblockcnt) break; + blockcnt = qblockcnt; } /* Calculate the address of the first meta-block. */ @@ -299,7 +306,6 @@ ufs_getlbns(vp, bn, ap, nump) if (metalbn == realbn) break; - blockcnt /= MNINDIR(ump); off = (bn / blockcnt) % MNINDIR(ump); ++numlevels; @@ -309,6 +315,7 @@ ufs_getlbns(vp, bn, ap, nump) ++ap; metalbn -= -1 + off * blockcnt; + blockcnt /= MNINDIR(ump); } if (nump) *nump = numlevels; -- cgit v1.1