Re: Latent undefined behaviour in fs/ext4/mballoc.c (seen in v4.5-rc3)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Feb 8, 2016, at 7:45 AM, Mark Rutland <mark.rutland@xxxxxxx> wrote:
> 
> Hi,
> 
> While trying UBSAN on arm64, I hit a couple of splats at boot in the
> ext4 mballoc code [1] (duplicated below), on v4.5-rc3. In both cases a
> dynamically-computed shift amount underflows before it is applied,
> leading to a too-large shift in one case and a negative shift in the
> other.
> 
> The code in question seems largely unchanged since 2008 judging by git
> blame, and I didn't spot any relevant changes in linux-next today
> (next-20160208), so I assume I'm the first to report this.

Are you running with an uncommon configuration (e.g. 64KB PAGE_SIZE or
blocksize > 8192)?  That might trigger problems in this code.

Cheers, Andreas

> I've had a quick look at figuring out what's happening below, but I'm
> not familiar with the code and I'm not sure what the intended results
> are. Any help would be appreciated.
> 
> The first splat looks like:
> 
> [    3.804750] ================================================================================
> [    3.813176] UBSAN: Undefined behaviour in fs/ext4/mballoc.c:2612:15
> [    3.819431] shift exponent 4294967295 is too large for 32-bit type 'int'
> [    3.826121] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.5.0-rc2+ #48
> [    3.832463] Hardware name: AMD Overdrive/Supercharger/Default string, BIOS ROD0085E 11/23/2015
> [    3.841060] Call trace:
> [    3.843499] [<ffffffc00008d7b8>] dump_backtrace+0x0/0x298
> [    3.848887] [<ffffffc00008da64>] show_stack+0x14/0x20
> [    3.853929] [<ffffffc00056e0f0>] dump_stack+0xe0/0x178
> [    3.859056] [<ffffffc0005b734c>] ubsan_epilogue+0x14/0x50
> [    3.864444] [<ffffffc0005b7748>] __ubsan_handle_shift_out_of_bounds+0xe0/0x138
> [    3.871655] [<ffffffc0003e1734>] ext4_mb_init+0x84c/0x920
> [    3.877043] [<ffffffc0003ba294>] ext4_fill_super+0x2eac/0x4958
> [    3.882866] [<ffffffc0002c1008>] mount_bdev+0x180/0x1e8
> [    3.888079] [<ffffffc0003adf8c>] ext4_mount+0x14/0x20
> [    3.893118] [<ffffffc0002c23f4>] mount_fs+0x44/0x1c8
> [    3.898073] [<ffffffc0002ed9c0>] vfs_kern_mount+0x50/0x1a8
> [    3.903547] [<ffffffc0002f3d90>] do_mount+0x240/0x1478
> [    3.908673] [<ffffffc0002f54d0>] SyS_mount+0x90/0xf8
> [    3.913627] [<ffffffc000eb2750>] mount_block_root+0x22c/0x3c4
> [    3.919361] [<ffffffc000eb2a08>] mount_root+0x120/0x138
> [    3.924574] [<ffffffc000eb2b5c>] prepare_namespace+0x13c/0x184
> [    3.930396] [<ffffffc000eb21bc>] kernel_init_freeable+0x390/0x3b4
> [    3.936479] [<ffffffc000bb4a78>] kernel_init+0x10/0xe0
> [    3.941606] [<ffffffc000086cd0>] ret_from_fork+0x10/0x40
> [    3.946905] ================================================================================
> 
> Which corresponds to the following loop:
> 
> 2606         i = 1;
> 2607         offset = 0;
> 2608         max = sb->s_blocksize << 2;
> 2609         do {
> 2610                 sbi->s_mb_offsets[i] = offset;
> 2611                 sbi->s_mb_maxs[i] = max;
> 2612                 offset += 1 << (sb->s_blocksize_bits - i);
> 2613                 max = max >> 1;
> 2614                 i++;
> 2615         } while (i <= sb->s_blocksize_bits + 1);
> 
> The loop condition permits an iteration where i == sb->s_blocksize_bits + 1, as
> sb->s_blocksize_bits is an unsigned char and i is an unsigned, the result is an
> unsigned underflow value (4294967295). This leads us to try to left shift 1 by
> an insanely large value.
> 
> The second splat looks like:
> 
> [    5.566166] ================================================================================
> [    5.574596] UBSAN: Undefined behaviour in fs/ext4/mballoc.c:1274:11
> [    5.580851] shift exponent -1 is negative
> [    5.584851] CPU: 4 PID: 1028 Comm: mount Not tainted 4.5.0-rc2+ #48
> [    5.591105] Hardware name: AMD Overdrive/Supercharger/Default string, BIOS ROD0085E 11/23/2015
> [    5.599702] Call trace:
> [    5.602142] [<ffffffc00008d7b8>] dump_backtrace+0x0/0x298
> [    5.607530] [<ffffffc00008da64>] show_stack+0x14/0x20
> [    5.612572] [<ffffffc00056e0f0>] dump_stack+0xe0/0x178
> [    5.617700] [<ffffffc0005b734c>] ubsan_epilogue+0x14/0x50
> [    5.623088] [<ffffffc0005b7748>] __ubsan_handle_shift_out_of_bounds+0xe0/0x138
> [    5.630300] [<ffffffc0003d2a04>] mb_find_order_for_block+0x154/0x1b0
> [    5.636641] [<ffffffc0003d2b2c>] mb_find_extent+0xcc/0x548
> [    5.642116] [<ffffffc0003de6a8>] ext4_mb_complex_scan_group+0xe8/0x4e8
> [    5.648632] [<ffffffc0003ded7c>] ext4_mb_regular_allocator+0x2d4/0x648
> [    5.655148] [<ffffffc0003e2b4c>] ext4_mb_new_blocks+0x344/0x7e0
> [    5.661056] [<ffffffc0003cbf54>] ext4_ext_map_blocks+0x684/0xf68
> [    5.667052] [<ffffffc000393664>] ext4_map_blocks+0x12c/0x500
> [    5.672699] [<ffffffc000398df4>] ext4_writepages+0x47c/0xe38
> [    5.678348] [<ffffffc00020da20>] do_writepages+0x48/0xc8
> [    5.683649] [<ffffffc0001f9100>] __filemap_fdatawrite_range+0x70/0xe8
> [    5.690078] [<ffffffc0001f91b0>] filemap_flush+0x18/0x20
> [    5.695378] [<ffffffc000394b64>] ext4_alloc_da_blocks+0x3c/0x78
> [    5.701285] [<ffffffc0003ac1c8>] ext4_rename+0x690/0xe38
> [    5.706585] [<ffffffc0003ac98c>] ext4_rename2+0x1c/0x40
> [    5.711800] [<ffffffc0002d0510>] vfs_rename+0x2c0/0xa90
> [    5.717013] [<ffffffc0002d661c>] SyS_renameat2+0x464/0x5c0
> [    5.722486] [<ffffffc0002d6788>] SyS_renameat+0x10/0x18
> [    5.727700] [<ffffffc000086d30>] el0_svc_naked+0x24/0x28
> [    5.732998] ================================================================================
> 
> Which corresponds to:
> 
> 1259 static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
> 1260 {
> 1261         int order = 1;
> 1262         void *bb;
> 1263
> 1264         BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
> 1265         BUG_ON(block >= (1 << (e4b->bd_blkbits + 3)));
> 1266
> 1267         bb = e4b->bd_buddy;
> 1268         while (order <= e4b->bd_blkbits + 1) {
> 1269                 block = block >> 1;
> 1270                 if (!mb_test_bit(block, bb)) {
> 1271                         /* this block is part of buddy of order 'order' */
> 1272                         return order;
> 1273                 }
> 1274                 bb += 1 << (e4b->bd_blkbits - order);
> 1275                 order++;
> 1276         }
> 1277         return 0;
> 1278 }
> 
> We allow an iteration when order == e4b->bd_blkbits + 1 and so we calculate a
> shift amount of -1.
> 
> Any idea of what should be done in these cases?
> 
> Thanks,
> Mark.
> 
> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-February/405825.html


Cheers, Andreas





Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail


[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux