diff mbox series

btrfs: handle NULL as device path for btrfs_scan_one_device()

Message ID 330f0214f1d8150e25dc609477e89534e3da961a.1728527388.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: handle NULL as device path for btrfs_scan_one_device() | expand

Commit Message

Qu Wenruo Oct. 10, 2024, 2:30 a.m. UTC
[BUG]
Syzbot reports a crash when mounting a btrfs with NULL as @path for
btrfs_scan_one_device():

Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
CPU: 0 UID: 0 PID: 5235 Comm: syz-executor338 Not tainted 6.12.0-rc2-next-20241008-syzkaller #0
RIP: 0010:strlen+0x2c/0x70 lib/string.c:402
Call Trace:
 <TASK>
 getname_kernel+0x1d/0x2f0 fs/namei.c:232
 kern_path+0x1d/0x50 fs/namei.c:2716
 is_good_dev_path fs/btrfs/volumes.c:760 [inline]
 btrfs_scan_one_device+0x19e/0xd90 fs/btrfs/volumes.c:1484
 btrfs_get_tree_super fs/btrfs/super.c:1841 [inline]
 btrfs_get_tree+0x30e/0x1920 fs/btrfs/super.c:2114
 vfs_get_tree+0x90/0x2b0 fs/super.c:1800
 fc_mount+0x1b/0xb0 fs/namespace.c:1231
 btrfs_get_tree_subvol fs/btrfs/super.c:2077 [inline]
 btrfs_get_tree+0x652/0x1920 fs/btrfs/super.c:2115
 vfs_get_tree+0x90/0x2b0 fs/super.c:1800
 vfs_cmd_create+0xa0/0x1f0 fs/fsopen.c:225
 __do_sys_fsconfig fs/fsopen.c:472 [inline]
 __se_sys_fsconfig+0xa1f/0xf70 fs/fsopen.c:344
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fe8c78542a9
---[ end trace 0000000000000000 ]---

[CAUSE]
The reproducer passes NULL as the device path for
btrfs_scan_one_device().

Normally such case will be rejected by bdev_file_open_by_path(), which
will return -EINVAL and we reject the mount.

But since commit ("btrfs: avoid unnecessary device path update for the
same device") and commit ("btrfs: canonicalize the device path before
adding") will do extra kern_path() lookup before
bdev_file_open_by_path().

Unlike bdev_file_open_by_path(), kern_path() doesn't do the NULL pointer
check and triggers the above strlen() on NULL pointer.

[FIX]
For function is_good_dev_path() and get_canonical_dev_path(), do the
extra NULL pointer checks.

This will be folded into the two offending patches, and I hope this is
really the last fix I need to fold...

Reported-by: syzbot+cee29f5a48caf10cd475@syzkaller.appspotmail.com
Link: https://lore.kernel.org/linux-btrfs/670689a8.050a0220.67064.0046.GAE@google.com/
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/volumes.c | 8 ++++++++
 1 file changed, 8 insertions(+)

Comments

Johannes Thumshirn Oct. 10, 2024, 1:38 p.m. UTC | #1
Looks good to me,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
David Sterba Oct. 10, 2024, 5:11 p.m. UTC | #2
On Thu, Oct 10, 2024 at 01:00:57PM +1030, Qu Wenruo wrote:
> [BUG]
> Syzbot reports a crash when mounting a btrfs with NULL as @path for
> btrfs_scan_one_device():
> 
> Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN PTI
> KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
> CPU: 0 UID: 0 PID: 5235 Comm: syz-executor338 Not tainted 6.12.0-rc2-next-20241008-syzkaller #0
> RIP: 0010:strlen+0x2c/0x70 lib/string.c:402
> Call Trace:
>  <TASK>
>  getname_kernel+0x1d/0x2f0 fs/namei.c:232
>  kern_path+0x1d/0x50 fs/namei.c:2716
>  is_good_dev_path fs/btrfs/volumes.c:760 [inline]
>  btrfs_scan_one_device+0x19e/0xd90 fs/btrfs/volumes.c:1484
>  btrfs_get_tree_super fs/btrfs/super.c:1841 [inline]
>  btrfs_get_tree+0x30e/0x1920 fs/btrfs/super.c:2114
>  vfs_get_tree+0x90/0x2b0 fs/super.c:1800
>  fc_mount+0x1b/0xb0 fs/namespace.c:1231
>  btrfs_get_tree_subvol fs/btrfs/super.c:2077 [inline]
>  btrfs_get_tree+0x652/0x1920 fs/btrfs/super.c:2115
>  vfs_get_tree+0x90/0x2b0 fs/super.c:1800
>  vfs_cmd_create+0xa0/0x1f0 fs/fsopen.c:225
>  __do_sys_fsconfig fs/fsopen.c:472 [inline]
>  __se_sys_fsconfig+0xa1f/0xf70 fs/fsopen.c:344
>  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
>  do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7fe8c78542a9
> ---[ end trace 0000000000000000 ]---
> 
> [CAUSE]
> The reproducer passes NULL as the device path for
> btrfs_scan_one_device().
> 
> Normally such case will be rejected by bdev_file_open_by_path(), which
> will return -EINVAL and we reject the mount.
> 
> But since commit ("btrfs: avoid unnecessary device path update for the
> same device") and commit ("btrfs: canonicalize the device path before
> adding") will do extra kern_path() lookup before
> bdev_file_open_by_path().
> 
> Unlike bdev_file_open_by_path(), kern_path() doesn't do the NULL pointer
> check and triggers the above strlen() on NULL pointer.
> 
> [FIX]
> For function is_good_dev_path() and get_canonical_dev_path(), do the
> extra NULL pointer checks.
> 
> This will be folded into the two offending patches, and I hope this is
> really the last fix I need to fold...

After you fold it please manually close the syzbot reports as this won't
be done by the automatic detection of the reported-by links.
diff mbox series

Patch

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5f5748ab6f9d..dc9f54849f39 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -749,6 +749,9 @@  static bool is_good_dev_path(const char *dev_path)
 	bool is_good = false;
 	int ret;
 
+	if (!dev_path)
+		goto out;
+
 	path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
 	if (!path_buf)
 		goto out;
@@ -779,6 +782,11 @@  static int get_canonical_dev_path(const char *dev_path, char *canonical)
 	char *resolved_path;
 	int ret;
 
+	if (!dev_path) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
 	if (!path_buf) {
 		ret = -ENOMEM;