diff options
author | bde <bde@FreeBSD.org> | 1997-11-24 16:33:03 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1997-11-24 16:33:03 +0000 |
commit | f48794b9f592747b49a561fac3392de4ae98657b (patch) | |
tree | 709ce072877f8755d18b58d51759ab3dc8b14eff /sys/gnu/ext2fs/ext2_bmap.c | |
parent | 17589a04675b24622c64547b408d6243800feff0 (diff) | |
download | FreeBSD-src-f48794b9f592747b49a561fac3392de4ae98657b.zip FreeBSD-src-f48794b9f592747b49a561fac3392de4ae98657b.tar.gz |
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 <mckusick@McKusick.COM>
Diffstat (limited to 'sys/gnu/ext2fs/ext2_bmap.c')
-rw-r--r-- | sys/gnu/ext2fs/ext2_bmap.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/sys/gnu/ext2fs/ext2_bmap.c b/sys/gnu/ext2fs/ext2_bmap.c index c85cc37..84df148 100644 --- a/sys/gnu/ext2fs/ext2_bmap.c +++ b/sys/gnu/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 <sys/param.h> @@ -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; |