A shift-out-of-bounds in minix_statfs in fs/minix/inode.c

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

 



Hi, there was a shift-out-bounds bug in minix_statfs in
fs/minix/inode.c founded by my custom syzkaller and reproduced in
linux-5.13.0-rc6+.

####
Simply analyze the vulnerability principle, First, mount a minix file
system by minix_fill_super() and initialize some custom basic data.

the code is as follows:
```
static int minix_fill_super(struct super_block *s, void *data, int silent)
{
struct buffer_head *bh;
struct buffer_head **map;
struct minix_super_block *ms;
struct minix3_super_block *m3s = NULL;
unsigned long i, block;
struct inode *root_inode;
struct minix_sb_info *sbi;
int ret = -EINVAL;

sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;

BUILD_BUG_ON(32 != sizeof (struct minix_inode));
BUILD_BUG_ON(64 != sizeof(struct minix2_inode));

if (!sb_set_blocksize(s, BLOCK_SIZE))
goto out_bad_hblock;

if (!(bh = sb_bread(s, 1)))    /// -----------------> get
minix_super_block's data from super_block
goto out_bad_sb;

ms = (struct minix_super_block *) bh->b_data; /// --------------> set
minix_super_block pointer
sbi->s_ms = ms;
sbi->s_sbh = bh;
sbi->s_mount_state = ms->s_state;
sbi->s_ninodes = ms->s_ninodes;
sbi->s_nzones = ms->s_nzones;
sbi->s_imap_blocks = ms->s_imap_blocks;
sbi->s_zmap_blocks = ms->s_zmap_blocks;
sbi->s_firstdatazone = ms->s_firstdatazone;
sbi->s_log_zone_size = ms->s_log_zone_size;  // ------------------>
set sbi->s_log_zone_size
s->s_maxbytes = ms->s_max_size;
s->s_magic = ms->s_magic;
```
Set bh->b_data to sbi. Initialize minix_sb_info by minix_super_block ’s data

After the file system is mounted, we can call the statfs syscall and
it could invoke the minix_statfs function. the code is as follows:
```
static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct minix_sb_info *sbi = minix_sb(sb);
u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) <<
sbi->s_log_zone_size;  // -----> shift left
buf->f_bfree = minix_count_free_blocks(sb);
buf->f_bavail = buf->f_bfree;
buf->f_files = sbi->s_ninodes;
buf->f_ffree = minix_count_free_inodes(sb);
buf->f_namelen = sbi->s_namelen;
buf->f_fsid = u64_to_fsid(id);

return 0;
}
```
if set sbi->s_log_zone_size as a lager num, the
(sbi->s_nzones-sbi->s_firstdatazone) will be shift left out of bounds
from the 64-bit type 'long unsigned int'.

####
crash logs is as follows:
```
[ 1512.826425][ T8010] loop0: detected capacity change from 0 to 16
[ 1512.829202][ T8010]
================================================================================
[ 1512.830892][ T8010] UBSAN: shift-out-of-bounds in fs/minix/inode.c:380:57
[ 1512.851019][ T8010] shift exponent 1024 is too large for 64-bit
type 'long unsigned int'
[ 1512.852875][ T8010] CPU: 0 PID: 8010 Comm: minix_statfs Not tainted
5.13.0-rc6+ #21
[ 1512.854333][ T8010] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.13.0-1ubuntu1 04/01/2014
[ 1512.856165][ T8010] Call Trace:
[ 1512.856809][ T8010]  dump_stack+0x7f/0xad
[ 1512.857629][ T8010]  ubsan_epilogue+0x5/0x40
[ 1512.858417][ T8010]  __ubsan_handle_shift_out_of_bounds.cold+0x61/0x10e
[ 1512.859634][ T8010]  ? __lock_acquire+0x3b6/0x2680
[ 1512.860566][ T8010]  minix_statfs.cold+0x16/0x1f
[ 1512.861453][ T8010]  statfs_by_dentry+0x48/0x70
[ 1512.862314][ T8010]  vfs_statfs+0x11/0xc0
[ 1512.863095][ T8010]  fd_statfs+0x29/0x60
[ 1512.863860][ T8010]  __do_sys_fstatfs+0x20/0x50
[ 1512.864733][ T8010]  do_syscall_64+0x3a/0xb0
[ 1512.865820][ T8010]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1512.866948][ T8010] RIP: 0033:0x44e74d
[ 1512.867804][ T8010] Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3
0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b
4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff 8
[ 1512.871739][ T8010] RSP: 002b:00007ffe06c55808 EFLAGS: 00000217
ORIG_RAX: 000000000000008a
[ 1512.873195][ T8010] RAX: ffffffffffffffda RBX: 0000000000400530
RCX: 000000000044e74d
[ 1512.874585][ T8010] RDX: 000000000044d9f7 RSI: 0000000000000000
RDI: 0000000000000005
[ 1512.875939][ T8010] RBP: 00007ffe06c55820 R08: 00007ffe06c55664
R09: 0000000000000000
[ 1512.877284][ T8010] R10: 00007ffe06c556e0 R11: 0000000000000217
R12: 0000000000403750
[ 1512.878665][ T8010] R13: 0000000000000000 R14: 00000000004c6018
R15: 0000000000000000
[ 1512.881676][ T8010]
================================================================================
[ 1512.883289][ T8010] Kernel panic - not syncing: panic_on_warn set ...
[ 1512.884457][ T8010] CPU: 0 PID: 8010 Comm: minix_statfs Not tainted
5.13.0-rc6+ #21
[ 1512.885851][ T8010] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.13.0-1ubuntu1 04/01/2014
[ 1512.887598][ T8010] Call Trace:
[ 1512.888186][ T8010]  dump_stack+0x7f/0xad
[ 1512.888935][ T8010]  panic+0x147/0x31a
[ 1512.889623][ T8010]  ubsan_epilogue+0x3f/0x40
[ 1512.890392][ T8010]  __ubsan_handle_shift_out_of_bounds.cold+0x61/0x10e
[ 1512.891527][ T8010]  ? __lock_acquire+0x3b6/0x2680
[ 1512.892353][ T8010]  minix_statfs.cold+0x16/0x1f
[ 1512.893202][ T8010]  statfs_by_dentry+0x48/0x70
[ 1512.894033][ T8010]  vfs_statfs+0x11/0xc0
[ 1512.894759][ T8010]  fd_statfs+0x29/0x60
[ 1512.895483][ T8010]  __do_sys_fstatfs+0x20/0x50
[ 1512.896298][ T8010]  do_syscall_64+0x3a/0xb0
[ 1512.897103][ T8010]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1512.898136][ T8010] RIP: 0033:0x44e74d
[ 1512.898823][ T8010] Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3
0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b
4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff 8
[ 1512.902284][ T8010] RSP: 002b:00007ffe06c55808 EFLAGS: 00000217
ORIG_RAX: 000000000000008a
[ 1512.903771][ T8010] RAX: ffffffffffffffda RBX: 0000000000400530
RCX: 000000000044e74d
[ 1512.905263][ T8010] RDX: 000000000044d9f7 RSI: 0000000000000000
RDI: 0000000000000005
[ 1512.906723][ T8010] RBP: 00007ffe06c55820 R08: 00007ffe06c55664
R09: 0000000000000000
[ 1512.908181][ T8010] R10: 00007ffe06c556e0 R11: 0000000000000217
R12: 0000000000403750
[ 1512.909661][ T8010] R13: 0000000000000000 R14: 00000000004c6018
R15: 0000000000000000
[ 1512.911356][ T8010] Kernel Offset: disabled
[ 1512.912216][ T8010] Rebooting in 86400 seconds..
```
The attachment is a reproduction.


Regards,
    butt3rflyh4ck

-- 
Active Defense Lab of Venustech

Attachment: repro.cprog
Description: Binary data


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux