lkml.org 
[lkml]   [2021]   [Jul]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    Date
    SubjectA shift-out-of-bounds in minix_statfs in fs/minix/inode.c
    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
    [unhandled content-type:application/octet-stream]
    \
     
     \ /
      Last update: 2021-07-21 19:15    [W:2.825 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site