linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Qu Wenruo <quwenruo.btrfs@gmx.com>
To: butt3rflyh4ck <butterflyhuangxx@gmail.com>,
	clm@fb.com, Josef Bacik <josef@toxicpanda.com>,
	dsterba@suse.com
Cc: linux-btrfs@vger.kernel.org
Subject: Re: A null-ptr-dereference bug in btrfs_rm_device in fs/btrfs/volumes.c
Date: Fri, 6 Aug 2021 17:59:12 +0800	[thread overview]
Message-ID: <30a749de-8228-05ad-13bc-15d6ac010e40@gmx.com> (raw)
In-Reply-To: <CAFcO6XPOB7xPibhbRaUrJ3fJUvH1m=9wVY-yA_Ytj6hXW0cqXA@mail.gmail.com>



On 2021/8/6 下午5:52, butt3rflyh4ck wrote:
> Hello, there is a null pointer dereference bug in the btrfs_rm_device
> function in fs/btrfs/volumes.c.
> When a user invokes a BTRFS_IOC_RM_DEV_V2 ioctl to remove a volume device,
> it would call btrfs_ioctl_rm_dev_v2 function to implement. And
> btrfs_ioctl_rm_dev_v2 would call btrfs_rm_device,
> if the id of the volume device is illegal, it would trigger a
> null-ptr-deref bug to cause DoS.
> Fortunately, invoking this function requires ‘CAP_SYS_ADMIN’ advanced
> permissions.
>
> Ok, let us see the code as follows:
> btrfs_ioctl_rm_dev_v2
> ``````
> static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
> {
>          struct inode *inode = file_inode(file);
>          struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
>          struct btrfs_ioctl_vol_args_v2 *vol_args;
>          int ret;
>          bool cancel = false;
>
>          if (!capable(CAP_SYS_ADMIN))   ///------------>  ‘CAP_SYS_ADMIN’  need
>                  return -EPERM;
>
>           ...
>
>          vol_args = memdup_user(arg, sizeof(*vol_args));  //
> -------------> copy a user data from 'arg' to vol_args.
>          if (IS_ERR(vol_args)) {
>                  ret = PTR_ERR(vol_args);
>                  goto err_drop;
>          }
>
>         ...
>
>                 if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
> //---------------> here would judge vol_args->flags
>                  ret = btrfs_rm_device(fs_info, NULL, vol_args->devid);
>   // ------------->call btrfs_rm_device
>          else
>                  ret = btrfs_rm_device(fs_info, vol_args->name, 0);
>
> ````
>   if the vol_args->flags is  BTRFS_DEVICE_SPEC_BY_ID, it would  also
> call  btrfs_rm_device function,
> the second arg type is a pointer,but the second arg is NULL, the third
> arg is a id of volome device.
>
> Let us see the code as follows:
> btrfs_rm_device
> ````
> int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
>                      u64 devid)
> {
>          struct btrfs_device *device;
>          struct btrfs_fs_devices *cur_devices;
>          struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
>          u64 num_devices;
>          int ret = 0;
>
>          mutex_lock(&uuid_mutex);
>
>          num_devices = btrfs_num_devices(fs_info);
>
>          ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1);
>          if (ret)
>                  goto out;
>
>          device = btrfs_find_device_by_devspec(fs_info, devid,
> device_path); // ------------>  this function would get a volume
> device by devid.
>
>          if (IS_ERR(device)) {
>                  if (PTR_ERR(device) == -ENOENT &&
>                      strcmp(device_path, "missing") == 0)
> //-----------------> use device_path pointer,  but device_patch is
> NULL.
>                          ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
>                  else
>                          ret = PTR_ERR(device);
>                  goto out;
>          }
> ````
> btrfs_find_device_by_devspec would lookup  a volume device by devid,
> ```
>   * Lookup a device given by device id, or the path if the id is 0.
>   */
> struct btrfs_device *btrfs_find_device_by_devspec(
>                  struct btrfs_fs_info *fs_info, u64 devid,
>                  const char *device_path)
> {
>          struct btrfs_device *device;
>
>          if (devid) {
>                  device = btrfs_find_device(fs_info->fs_devices, devid, NULL,
>                                             NULL);
>                  if (!device)
>                          return ERR_PTR(-ENOENT);  // -----> if not
> lookup a device, it return -ENOENT error.
>                   return device;
>          }
>
>        ....
>
> ```
> After returning an -ENOENT error, it would call strcmp to compare
> device_path with 'missing'.
> As our previous analysis, device_path is NULL, it would  trigger a
> null-ptr-deref bug.
>
> crash log:
> root@syzkaller:/home/user# ./btrfs_rm_device
> [   46.204657][ T8385] loop0: detected capacity change from 0 to 32768
> [   46.218173][ T8385] BTRFS: device fsid
> 195aeaee-03bd-442f-8f6e-93f8f339d194 devid 1 transid 7 /dev/loop0
> scanned by btrfs_rm_device (8385)
> [   46.238597][ T8385] BTRFS info (device loop0): disabling tree log
> [   46.239838][ T8385] BTRFS info (device loop0): disk space caching is enabled
> [   46.241198][ T8385] BTRFS info (device loop0): has skinny extents
> [   46.253597][ T8385] BTRFS info (device loop0): enabling ssd optimizations
> [   46.286692][ T8385] BUG: kernel NULL pointer dereference, address:
> 0000000000000000
> [   46.288135][ T8385] #PF: supervisor read access in kernel mode
> [   46.289222][ T8385] #PF: error_code(0x0000) - not-present page
> [   46.290308][ T8385] PGD 4618d067 P4D 4618d067 PUD 4616b067 PMD 0
> [   46.291469][ T8385] Oops: 0000 [#1] PREEMPT SMP
> [   46.292247][ T8385] CPU: 0 PID: 8385 Comm: btrfs_rm_device Not
> tainted 5.14.0-rc4+ #4
> [   46.293485][ T8385] Hardware name: QEMU Standard PC (i440FX + PIIX,
> 1996), BIOS 1.13.0-1ubuntu1 04/01/2014
> [   46.295205][ T8385] RIP: 0010:btrfs_rm_device+0x487/0x6d0
> [   46.296136][ T8385] Code: fe 74 18 45 89 f4 e9 91 fd ff ff 48 89 df
> 45 89 ec e8 bd e3 f9 ff e9 2f ff ff ff 48 c7 c7 6a d1 a2 84 b9 08 00
> 00 00 4c 89 ee <f3>b
> [   46.299535][ T8385] RSP: 0018:ffffc9000560bd90 EFLAGS: 00010246
> [   46.300588][ T8385] RAX: fffffffffffffffe RBX: 0000000000000000
> RCX: 0000000000000008
> [   46.301961][ T8385] RDX: fffffffffffffffe RSI: 0000000000000000
> RDI: ffffffff84a2d16a
> [   46.303374][ T8385] RBP: ffff88804939c000 R08: ffff888013010600
> R09: 0000000000000001
> [   46.304793][ T8385] R10: 0000000000000001 R11: 00000000001357f7
> R12: 0000000000000008
> [   46.306238][ T8385] R13: 0000000000000000 R14: fffffffffffffffe
> R15: ffffffff83d8c123
> [   46.307614][ T8385] FS:  000000000214a880(0000)
> GS:ffff88803ec00000(0000) knlGS:0000000000000000
> [   46.308999][ T8385] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   46.310141][ T8385] CR2: 0000000000000000 CR3: 0000000046200000
> CR4: 00000000000006f0
> [   46.311604][ T8385] Call Trace:
> [   46.312123][ T8385]  btrfs_ioctl+0xba8/0x31b0
> [   46.312821][ T8385]  ? __x64_sys_ioctl+0x7b/0xb0
> [   46.313655][ T8385]  __x64_sys_ioctl+0x7b/0xb0
> [   46.314460][ T8385]  do_syscall_64+0x35/0xb0
> [   46.315454][ T8385]  entry_SYSCALL_64_after_hwframe+0x44/0xae
> [   46.316501][ T8385] RIP: 0033:0x44f51d
> [   46.317178][ T8385] 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>8
> [   46.320656][ T8385] RSP: 002b:00007ffc361763e8 EFLAGS: 00000283
> ORIG_RAX: 0000000000000010
> [   46.321991][ T8385] RAX: ffffffffffffffda RBX: 0000000000400530
> RCX: 000000000044f51d
> [   46.323410][ T8385] RDX: 0000000020001d80 RSI: 000000005000943a
> RDI: 0000000000000005
> [   46.324773][ T8385] RBP: 00007ffc36176400 R08: 0000000020001db0
> R09: 0000000000000000
> [   46.326029][ T8385] R10: 0000000000000000 R11: 0000000000000283
> R12: 00000000004042a0
> [   46.327388][ T8385] R13: 0000000000000000 R14: 00000000004ca018
> R15: 0000000000000000
> [   46.328775][ T8385] Modules linked in:
> [   46.329458][ T8385] CR2: 0000000000000000
> [   46.330389][ T8385] ---[ end trace 1cb21b999dbc3d91 ]---
> [   46.331249][ T8385] RIP: 0010:btrfs_rm_device+0x487/0x6d0
> [   46.332180][ T8385] Code: fe 74 18 45 89 f4 e9 91 fd ff ff 48 89 df
> 45 89 ec e8 bd e3 f9 ff e9 2f ff ff ff 48 c7 c7 6a d1 a2 84 b9 08 00
> 00 00 4c 89 ee <f3>b
> [   46.335928][ T8385] RSP: 0018:ffffc9000560bd90 EFLAGS: 00010246
> [   46.337120][ T8385] RAX: fffffffffffffffe RBX: 0000000000000000
> RCX: 0000000000000008
> [   46.338710][ T8385] RDX: fffffffffffffffe RSI: 0000000000000000
> RDI: ffffffff84a2d16a
> [   46.340164][ T8385] RBP: ffff88804939c000 R08: ffff888013010600
> R09: 0000000000000001
> [   46.341611][ T8385] R10: 0000000000000001 R11: 00000000001357f7
> R12: 0000000000000008
> [   46.343055][ T8385] R13: 0000000000000000 R14: fffffffffffffffe
> R15: ffffffff83d8c123
> [   46.344521][ T8385] FS:  000000000214a880(0000)
> GS:ffff88803ec00000(0000) knlGS:0000000000000000
> [   46.346265][ T8385] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   46.347470][ T8385] CR2: 0000000000000000 CR3: 0000000046200000
> CR4: 00000000000006f0
> [   46.348918][ T8385] Kernel panic - not syncing: Fatal exception
> [   46.350160][ T8385] Kernel Offset: disabled
> [   46.350978][ T8385] Rebooting in 86400 seconds..
>
> the attachment is reproduce.

Awesome analyse and reproducer.

>
> Regards,
>     butt3rflyh4ck.
>
BTW, would you like us to use "butt3rflyh4ck" as reported-by user name?

Normally we use real names for reported-by, not sure if "butt3rflyh4ck"
would work here.
(Awesome hacky ID though)

Thanks,
Qu

  reply	other threads:[~2021-08-06  9:59 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-06  9:52 butt3rflyh4ck
2021-08-06  9:59 ` Qu Wenruo [this message]
2021-08-07  6:00   ` butt3rflyh4ck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=30a749de-8228-05ad-13bc-15d6ac010e40@gmx.com \
    --to=quwenruo.btrfs@gmx.com \
    --cc=butterflyhuangxx@gmail.com \
    --cc=clm@fb.com \
    --cc=dsterba@suse.com \
    --cc=josef@toxicpanda.com \
    --cc=linux-btrfs@vger.kernel.org \
    --subject='Re: A null-ptr-dereference bug in btrfs_rm_device in fs/btrfs/volumes.c' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).