]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Fix potential 2**32-1 overflow problems by ext2fs_div_ceil()
authorTheodore Ts'o <tytso@mit.edu>
Wed, 30 Aug 2006 05:57:00 +0000 (01:57 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 30 Aug 2006 05:57:00 +0000 (01:57 -0400)
Add a new function, ext2fs_div_ceil(), which correctly calculates a division
of two unsigned integer where the result is always rounded up the next
largest integer.   This is used everywhere where we might have
previously caused an overflow when the number of blocks
or inodes is too close to 2**32-1.

Based on patches from Eric Sandeen, but generalized to use this new function

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Eric Sandeen <esandeen@redhat.com>
ext2ed/ChangeLog
ext2ed/init.c
lib/ext2fs/ChangeLog
lib/ext2fs/ext2fs.h
lib/ext2fs/initialize.c
lib/ext2fs/openfs.c
misc/ChangeLog
misc/filefrag.c
misc/mke2fs.c
resize/ChangeLog
resize/resize2fs.c

index fa59c2413773612d333059ae56e59eedce9ffdfe..2756490650add5003bdc4ecf5d0d979c5915bd0a 100644 (file)
@@ -1,3 +1,8 @@
+2006-08-30  Theodore Tso  <tytso@mit.edu>
+
+       * init.c (div_ceil, set_file_system_info): Fix potential overflow
+               for really big filesystems.
+
 2006-06-30  Theodore Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs 1.38
index f89d8934b9b398f1415a18adc0d3cd017b507ce0..7ab2e28c8fe8c7a30fc5cfeb231b27b416e967d2 100644 (file)
@@ -370,6 +370,13 @@ void add_user_command (struct struct_commands *ptr,char *name,char *description,
        ptr->callback [num]=callback;
 }
 
+static unsigned int div_ceil(unsigned int a, unsigned int b)
+{
+       if (!a)
+               return 0;
+       return ((a - 1) / b) + 1;
+}
+
 int set_file_system_info (void)
 
 {
@@ -415,8 +422,8 @@ int set_file_system_info (void)
                        file_system_info.first_group_desc_offset=2*EXT2_MIN_BLOCK_SIZE;
                else
                        file_system_info.first_group_desc_offset=file_system_info.block_size;
-               file_system_info.groups_count=( sb->s_blocks_count-sb->s_first_data_block+sb->s_blocks_per_group-1) /
-                                               sb->s_blocks_per_group;
+               file_system_info.groups_count = div_ceil(sb->s_blocks_count, 
+                                                sb->s_blocks_per_group);
        
                file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode);
                file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block;
index abd188f2db97862db43e9802210ee88491a74a42..6a2c8bdfc3cdd62fe2efb7e51ecbcad0aa8a7ff7 100644 (file)
@@ -1,3 +1,14 @@
+2006-08-30  Theodore Tso  <tytso@mit.edu>
+
+       * ext2fs.h (ext2fs_div_ceil): Add new function which safely
+               calculates an integer division where the result is always
+               rounded up while avoiding overflow errors.
+
+       * initialize.c (calc_reserved_gdt_blocks, ext2fs_initialize):
+       * openfs.c (ext2fs_open2): Use ext2fs_div_ceil() instead of a 
+               using an open-coded expression which was subject to 
+               overflows.
+
 2006-08-06  Andreas Dilger <adilger@clusterfs.com>
 
        * bitops.h (ext2fs_cpu_to_le32, ext2fs_le64_to_cpu,
index b3c2f656f28ad50c921eda44a24c050be8f3d831..8ca5723fc7651cb324c036305ad8c8c8177d2576 100644 (file)
@@ -965,6 +965,7 @@ extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
 extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
 extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
                                      struct ext2_inode *inode);
+extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b);
 
 /*
  * The actual inlined functions definitions themselves...
@@ -1132,6 +1133,16 @@ _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
        return inode->i_blocks -
               (inode->i_file_acl ? fs->blocksize >> 9 : 0);
 }
+
+/*
+ * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
+ */
+_INLINE_ unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b)
+{
+       if (!a)
+               return 0;
+       return ((a - 1) / b) + 1;
+}
 #undef _INLINE_
 #endif
 
index 05ba8c8a3e2ef8b1396c9ef0ace80604d25621ff..6b476d9809add3020f5726b47f8829893655e6ba 100644 (file)
@@ -77,8 +77,8 @@ static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs)
         */
        if (sb->s_blocks_count < max_blocks / 1024)
                max_blocks = sb->s_blocks_count * 1024;
-       rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
-       rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
+       rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg);
+       rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks;
        if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
                rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
 #ifdef RES_GDT_DEBUG
@@ -205,17 +205,15 @@ errcode_t ext2fs_initialize(const char *name, int flags,
        }
 
 retry:
-       fs->group_desc_count = (super->s_blocks_count -
-                               super->s_first_data_block +
-                               EXT2_BLOCKS_PER_GROUP(super) - 1)
-               / EXT2_BLOCKS_PER_GROUP(super);
+       fs->group_desc_count = ext2fs_div_ceil(super->s_blocks_count -
+                                              super->s_first_data_block,
+                                              EXT2_BLOCKS_PER_GROUP(super));
        if (fs->group_desc_count == 0) {
                retval = EXT2_ET_TOOSMALL;
                goto cleanup;
        }
-       fs->desc_blocks = (fs->group_desc_count +
-                          EXT2_DESC_PER_BLOCK(super) - 1)
-               / EXT2_DESC_PER_BLOCK(super);
+       fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
+                                         EXT2_DESC_PER_BLOCK(super));
 
        i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
        set_field(s_inodes_count, super->s_blocks_count / i);
@@ -233,8 +231,7 @@ retry:
         * should be.  But make sure that we don't allocate more than
         * one bitmap's worth of inodes each group.
         */
-       ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
-               fs->group_desc_count;
+       ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
        if (ipg > fs->blocksize * 8) {
                if (super->s_blocks_per_group >= 256) {
                        /* Try again with slightly different parameters */
index 00149c80bdf5633e8968b059e4125aa2bba8c46a..f09484fcf59712d830b1044c8ced7a6a9acfd400 100644 (file)
@@ -258,12 +258,11 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
-       fs->group_desc_count = (fs->super->s_blocks_count -
-                               fs->super->s_first_data_block +
-                               blocks_per_group - 1) / blocks_per_group;
-       fs->desc_blocks = (fs->group_desc_count +
-                          EXT2_DESC_PER_BLOCK(fs->super) - 1)
-               / EXT2_DESC_PER_BLOCK(fs->super);
+       fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
+                                              fs->super->s_first_data_block,
+                                              blocks_per_group);
+       fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
+                                         EXT2_DESC_PER_BLOCK(fs->super));
        retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
                                &fs->group_desc);
        if (retval)
index 86254330188e736429a604b94965097ead3085e5..0cecaa436405a69c009eaacbb1653a393b9de7ac 100644 (file)
@@ -1,3 +1,12 @@
+2006-08-30  Theodore Tso  <tytso@mit.edu>
+
+       * mke2fs.c (parse_extended_opts): Use ext2fs_div_ceil() instead of
+               a using an open-coded expression which was subject to
+               overflows.
+
+       * filefrag.c (div_ceil, frag_report): Fix potential overflow for
+               really big filesystems.
+
 2006-08-06  Theodore Tso  <tytso@mit.edu>
 
        * findsuper.c (main): Improve findsuper program by printing the
index 0719d4cef5b0c2b8a04b5c09773b4105372fc847..df900602c1707e87bb865021a8d9db3e848109ee 100644 (file)
@@ -47,6 +47,13 @@ int verbose = 0;
 #define EXT4_EXTENTS_FL                        0x00080000 /* Inode uses extents */
 #define        EXT3_IOC_GETFLAGS               _IOR('f', 1, long)
 
+static unsigned int div_ceil(unsigned int a, unsigned int b)
+{
+       if (!a)
+               return 0;
+       return ((a - 1) / b) + 1;
+}
+
 static unsigned long get_bmap(int fd, unsigned long block)
 {
        int     ret;
@@ -105,7 +112,7 @@ static void frag_report(const char *filename)
        if (verbose) {
                printf("Filesystem type is: %x\n", fsinfo.f_type);
        }
-       cylgroups = (fsinfo.f_blocks + fsinfo.f_bsize*8-1) / fsinfo.f_bsize*8;
+       cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize*8);
        if (verbose) {
                printf("Filesystem cylinder groups is approximately %ld\n", 
                       cylgroups);
index 677c5140a20aff3e8c3d411237c51edd5568e088..a581ef09c28d09598d2add28da15eebadc901780 100644 (file)
@@ -820,12 +820,12 @@ static void parse_extended_opts(struct ext2_super_block *param,
                        if (!bpg)
                                bpg = blocksize * 8;
                        gdpb = blocksize / sizeof(struct ext2_group_desc);
-                       group_desc_count = (param->s_blocks_count +
-                                           bpg - 1) / bpg;
+                       group_desc_count = 
+                               ext2fs_div_ceil(param->s_blocks_count, bpg);
                        desc_blocks = (group_desc_count +
                                       gdpb - 1) / gdpb;
-                       rsv_groups = (resize + bpg - 1) / bpg;
-                       rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - 
+                       rsv_groups = ext2fs_div_ceil(resize, bpg);
+                       rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - 
                                desc_blocks;
                        if (rsv_gdb > (int) EXT2_ADDR_PER_BLOCK(param))
                                rsv_gdb = EXT2_ADDR_PER_BLOCK(param);
index db770ce510bce811429ddaeeb94fb41dfb23a01a..32f116bc5df679ca165aa6286c9af33cb4f236a8 100644 (file)
@@ -1,3 +1,9 @@
+2006-08-30  Theodore Tso  <tytso@mit.edu>
+
+       * resize2fs.c (adjust_fs_info): Use ext2fs_div_ceil() instead of a
+               using an open-coded expression which was subject to
+               overflows.
+
 2006-05-22  Theodore Tso  <tytso@mit.edu>
 
        * resize2fs.8.in: Fixed spelling mistake (Addresses Debian Bug:
index de8f00dcd5a902ba7d0e8bad3cfc9681f8b72f6a..f6c3ede8efdb3b39599d78b0a77ee6fd92da1238 100644 (file)
@@ -190,15 +190,13 @@ errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, blk_t new_size)
        fs->super->s_blocks_count = new_size;
 
 retry:
-       fs->group_desc_count = (fs->super->s_blocks_count -
-                               fs->super->s_first_data_block +
-                               EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
-               / EXT2_BLOCKS_PER_GROUP(fs->super);
+       fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
+                                      fs->super->s_first_data_block,
+                                      EXT2_BLOCKS_PER_GROUP(fs->super));
        if (fs->group_desc_count == 0)
                return EXT2_ET_TOOSMALL;
-       fs->desc_blocks = (fs->group_desc_count +
-                          EXT2_DESC_PER_BLOCK(fs->super) - 1)
-               / EXT2_DESC_PER_BLOCK(fs->super);
+       fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, 
+                                         EXT2_DESC_PER_BLOCK(fs->super));
 
        /*
         * Overhead is the number of bookkeeping blocks per group.  It