diff mbox series

btrfs: send: fix buffer overflow when reversing path that is full

Message ID fbbc0efa2ad81b3dcc00c6dcb15af8189d343af3.1726692825.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: send: fix buffer overflow when reversing path that is full | expand

Commit Message

Filipe Manana Sept. 18, 2024, 8:54 p.m. UTC
From: Filipe Manana <fdmanana@suse.com>

When unreversing a path we are doing a memmove() for a length that
corresponds to the length of the path's content plus 1. This is incorrect
as we shouldn't add the extra 1, that is, the length of our content is
the difference between the path's end offset and the path's start offset,
and there's no NULL termination as we always use the length for all
operations. Most of the time this ends up being harmless because the
path's content is less than the path's buffer length, however when the
content's length matches the size of the buffer, we end up doing a buffer
overflow, which results in a crash like the following on a fortified
kernel:

   Sep 15 23:32:17 sdslinux1 kernel: ------------[ cut here ]------------
   Sep 15 23:32:17 sdslinux1 kernel: strcpy: detected buffer overflow: 20
   byte write of buffer size 19
   Sep 15 23:32:17 sdslinux1 kernel: WARNING: CPU: 3 PID: 3310 at
   __fortify_report+0x45/0x50
   Sep 15 23:32:17 sdslinux1 kernel: Modules linked in: nfsd auth_rpcgss
   lockd grace nfs_acl bridge stp llc bonding tls vfat fat binfmt_misc
   snd_hda_codec_hdmi intel_rapl_msr intel_rapl_common x8
   6_pkg_temp_thermal intel_powerclamp kvm_intel iTCO_wdt intel_pmc_bxt
   spi_intel_platform kvm at24 mei_wdt spi_intel mei_pxp
   iTCO_vendor_support mei_hdcp btusb snd_hda_codec_realtek btbcm btinte
   l snd_hda_scodec_component i915 rapl iwlwifi snd_hda_codec_generic btrtl
   intel_cstate btmtk cec snd_hda_intel intel_uncore cfg80211
   snd_intel_dspcfg drm_buddy coretemp snd_intel_sdw_acpi bluet
   ooth ttm pcspkr snd_hda_codec rfkill snd_hda_core snd_hwdep intel_vbtn
   snd_pcm mei_me drm_display_helper snd_timer sparse_keymap i2c_i801 mei
   snd i2c_smbus lpc_ich soundcore cdc_mbim cdc_wdm cdc_ncm cdc_ether
   usbnet crct10dif_pclmul crc32_pclmul crc32c_intel polyval_clmulni
   polyval_generic ghash_clmulni_intel sha512_ssse3 sha256_ssse3 sha1_ssse3
   igb r8152 serio_raw i2c_algo_bit mii dca e1000e video wmi sunrpc
   Sep 15 23:32:17 sdslinux1 kernel: CPU: 3 UID: 0 PID: 3310 Comm: btrfs
   Not tainted 6.11.0-prnet #1
   Sep 15 23:32:17 sdslinux1 kernel: Hardware name: CompuLab Ltd.
   sbc-ihsw/Intense-PC2 (IPC2), BIOS IPC2_3.330.7 X64 03/15/2018
   Sep 15 23:32:17 sdslinux1 kernel: RIP: 0010:__fortify_report+0x45/0x50
   Sep 15 23:32:17 sdslinux1 kernel: Code: 48 8b 34 (...)
   Sep 15 23:32:17 sdslinux1 kernel: RSP: 0018:ffff97ebc0d6f650 EFLAGS:
   00010246
   Sep 15 23:32:17 sdslinux1 kernel: RAX: 7749924ef60fa600 RBX:
   ffff8bf5446a521a RCX: 0000000000000027
   Sep 15 23:32:17 sdslinux1 kernel: RDX: 00000000ffffdfff RSI:
   ffff97ebc0d6f548 RDI: ffff8bf84e7a1cc8
   Sep 15 23:32:17 sdslinux1 kernel: RBP: ffff8bf548574080 R08:
   ffffffffa8c40e10 R09: 0000000000005ffd
   Sep 15 23:32:17 sdslinux1 kernel: R10: 0000000000000004 R11:
   ffffffffa8c70e10 R12: ffff8bf551eef400
   Sep 15 23:32:17 sdslinux1 kernel: R13: 0000000000000000 R14:
   0000000000000013 R15: 00000000000003a8
   Sep 15 23:32:17 sdslinux1 kernel: FS:  00007fae144de8c0(0000)
   GS:ffff8bf84e780000(0000) knlGS:0000000000000000
   Sep 15 23:32:17 sdslinux1 kernel: CS:  0010 DS: 0000 ES: 0000 CR0:
   0000000080050033
   Sep 15 23:32:17 sdslinux1 kernel: CR2: 00007fae14691690 CR3:
   00000001027a2003 CR4: 00000000001706f0
   Sep 15 23:32:17 sdslinux1 kernel: Call Trace:
   Sep 15 23:32:17 sdslinux1 kernel:  <TASK>
   Sep 15 23:32:17 sdslinux1 kernel:  ? __warn+0x12a/0x1d0
   Sep 15 23:32:17 sdslinux1 kernel:  ? __fortify_report+0x45/0x50
   Sep 15 23:32:17 sdslinux1 kernel:  ? report_bug+0x154/0x1c0
   Sep 15 23:32:17 sdslinux1 kernel:  ? handle_bug+0x42/0x70
   Sep 15 23:32:17 sdslinux1 kernel:  ? exc_invalid_op+0x1a/0x50
   Sep 15 23:32:17 sdslinux1 kernel:  ? asm_exc_invalid_op+0x1a/0x20
   Sep 15 23:32:17 sdslinux1 kernel:  ? __fortify_report+0x45/0x50
   Sep 15 23:32:17 sdslinux1 kernel:  __fortify_panic+0x9/0x10
   Sep 15 23:32:17 sdslinux1 kernel: __get_cur_name_and_parent+0x3bc/0x3c0
   Sep 15 23:32:17 sdslinux1 kernel:  get_cur_path+0x207/0x3b0
   Sep 15 23:32:17 sdslinux1 kernel:  send_extent_data+0x709/0x10d0
   Sep 15 23:32:17 sdslinux1 kernel:  ? find_parent_nodes+0x22df/0x25d0
   Sep 15 23:32:17 sdslinux1 kernel:  ? mas_nomem+0x13/0x90
   Sep 15 23:32:17 sdslinux1 kernel:  ? mtree_insert_range+0xa5/0x110
   Sep 15 23:32:17 sdslinux1 kernel:  ? btrfs_lru_cache_store+0x5f/0x1e0
   Sep 15 23:32:17 sdslinux1 kernel:  ? iterate_extent_inodes+0x52d/0x5a0
   Sep 15 23:32:17 sdslinux1 kernel:  process_extent+0xa96/0x11a0
   Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_lookup_backref_cache+0x10/0x10
   Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_store_backref_cache+0x10/0x10
   Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_iterate_backrefs+0x10/0x10
   Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_check_extent_item+0x10/0x10
   Sep 15 23:32:17 sdslinux1 kernel:  changed_cb+0x6fa/0x930
   Sep 15 23:32:17 sdslinux1 kernel:  ? tree_advance+0x362/0x390
   Sep 15 23:32:17 sdslinux1 kernel:  ? memcmp_extent_buffer+0xd7/0x160
   Sep 15 23:32:17 sdslinux1 kernel:  send_subvol+0xf0a/0x1520
   Sep 15 23:32:17 sdslinux1 kernel:  btrfs_ioctl_send+0x106b/0x11d0
   Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx___clone_root_cmp_sort+0x10/0x10
   Sep 15 23:32:17 sdslinux1 kernel:  _btrfs_ioctl_send+0x1ac/0x240
   Sep 15 23:32:17 sdslinux1 kernel:  btrfs_ioctl+0x75b/0x850
   Sep 15 23:32:17 sdslinux1 kernel:  __se_sys_ioctl+0xca/0x150
   Sep 15 23:32:17 sdslinux1 kernel:  do_syscall_64+0x85/0x160
   Sep 15 23:32:17 sdslinux1 kernel:  ? __count_memcg_events+0x69/0x100
   Sep 15 23:32:17 sdslinux1 kernel:  ? handle_mm_fault+0x1327/0x15c0
   Sep 15 23:32:17 sdslinux1 kernel:  ? __se_sys_rt_sigprocmask+0xf1/0x180
   Sep 15 23:32:17 sdslinux1 kernel:  ? syscall_exit_to_user_mode+0x75/0xa0
   Sep 15 23:32:17 sdslinux1 kernel:  ? do_syscall_64+0x91/0x160
   Sep 15 23:32:17 sdslinux1 kernel:  ? do_user_addr_fault+0x21d/0x630
   Sep 15 23:32:17 sdslinux1 kernel: entry_SYSCALL_64_after_hwframe+0x76/0x7e
   Sep 15 23:32:17 sdslinux1 kernel: RIP: 0033:0x7fae145eeb4f
   Sep 15 23:32:17 sdslinux1 kernel: Code: 00 48 89 (...)
   Sep 15 23:32:17 sdslinux1 kernel: RSP: 002b:00007ffdf1cb09b0 EFLAGS:
   00000246 ORIG_RAX: 0000000000000010
   Sep 15 23:32:17 sdslinux1 kernel: RAX: ffffffffffffffda RBX:
   0000000000000004 RCX: 00007fae145eeb4f
   Sep 15 23:32:17 sdslinux1 kernel: RDX: 00007ffdf1cb0ad0 RSI:
   0000000040489426 RDI: 0000000000000004
   Sep 15 23:32:17 sdslinux1 kernel: RBP: 00000000000078fe R08:
   00007fae144006c0 R09: 00007ffdf1cb0927
   Sep 15 23:32:17 sdslinux1 kernel: R10: 0000000000000008 R11:
   0000000000000246 R12: 00007ffdf1cb1ce8
   Sep 15 23:32:17 sdslinux1 kernel: R13: 0000000000000003 R14:
   000055c499fab2e0 R15: 0000000000000004
   Sep 15 23:32:17 sdslinux1 kernel:  </TASK>
   Sep 15 23:32:17 sdslinux1 kernel: ---[ end trace 0000000000000000 ]---
   Sep 15 23:32:17 sdslinux1 kernel: ------------[ cut here ]------------

Fix this passing the actual length to memmove(), not summing 1.

Reported-by: David Arendt <admin@prnet.org>
Link: https://lore.kernel.org/linux-btrfs/cee4591a-3088-49ba-99b8-d86b4242b8bd@prnet.org/
Fixes: 31db9f7c23fb ("Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/send.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Filipe Manana Sept. 19, 2024, 4:46 p.m. UTC | #1
On Wed, Sep 18, 2024 at 9:57 PM <fdmanana@kernel.org> wrote:
>
> From: Filipe Manana <fdmanana@suse.com>
>
> When unreversing a path we are doing a memmove() for a length that
> corresponds to the length of the path's content plus 1. This is incorrect
> as we shouldn't add the extra 1, that is, the length of our content is
> the difference between the path's end offset and the path's start offset,
> and there's no NULL termination as we always use the length for all
> operations. Most of the time this ends up being harmless because the
> path's content is less than the path's buffer length, however when the
> content's length matches the size of the buffer, we end up doing a buffer
> overflow, which results in a crash like the following on a fortified
> kernel:
>
>    Sep 15 23:32:17 sdslinux1 kernel: ------------[ cut here ]------------
>    Sep 15 23:32:17 sdslinux1 kernel: strcpy: detected buffer overflow: 20
>    byte write of buffer size 19
>    Sep 15 23:32:17 sdslinux1 kernel: WARNING: CPU: 3 PID: 3310 at
>    __fortify_report+0x45/0x50
>    Sep 15 23:32:17 sdslinux1 kernel: Modules linked in: nfsd auth_rpcgss
>    lockd grace nfs_acl bridge stp llc bonding tls vfat fat binfmt_misc
>    snd_hda_codec_hdmi intel_rapl_msr intel_rapl_common x8
>    6_pkg_temp_thermal intel_powerclamp kvm_intel iTCO_wdt intel_pmc_bxt
>    spi_intel_platform kvm at24 mei_wdt spi_intel mei_pxp
>    iTCO_vendor_support mei_hdcp btusb snd_hda_codec_realtek btbcm btinte
>    l snd_hda_scodec_component i915 rapl iwlwifi snd_hda_codec_generic btrtl
>    intel_cstate btmtk cec snd_hda_intel intel_uncore cfg80211
>    snd_intel_dspcfg drm_buddy coretemp snd_intel_sdw_acpi bluet
>    ooth ttm pcspkr snd_hda_codec rfkill snd_hda_core snd_hwdep intel_vbtn
>    snd_pcm mei_me drm_display_helper snd_timer sparse_keymap i2c_i801 mei
>    snd i2c_smbus lpc_ich soundcore cdc_mbim cdc_wdm cdc_ncm cdc_ether
>    usbnet crct10dif_pclmul crc32_pclmul crc32c_intel polyval_clmulni
>    polyval_generic ghash_clmulni_intel sha512_ssse3 sha256_ssse3 sha1_ssse3
>    igb r8152 serio_raw i2c_algo_bit mii dca e1000e video wmi sunrpc
>    Sep 15 23:32:17 sdslinux1 kernel: CPU: 3 UID: 0 PID: 3310 Comm: btrfs
>    Not tainted 6.11.0-prnet #1
>    Sep 15 23:32:17 sdslinux1 kernel: Hardware name: CompuLab Ltd.
>    sbc-ihsw/Intense-PC2 (IPC2), BIOS IPC2_3.330.7 X64 03/15/2018
>    Sep 15 23:32:17 sdslinux1 kernel: RIP: 0010:__fortify_report+0x45/0x50
>    Sep 15 23:32:17 sdslinux1 kernel: Code: 48 8b 34 (...)
>    Sep 15 23:32:17 sdslinux1 kernel: RSP: 0018:ffff97ebc0d6f650 EFLAGS:
>    00010246
>    Sep 15 23:32:17 sdslinux1 kernel: RAX: 7749924ef60fa600 RBX:
>    ffff8bf5446a521a RCX: 0000000000000027
>    Sep 15 23:32:17 sdslinux1 kernel: RDX: 00000000ffffdfff RSI:
>    ffff97ebc0d6f548 RDI: ffff8bf84e7a1cc8
>    Sep 15 23:32:17 sdslinux1 kernel: RBP: ffff8bf548574080 R08:
>    ffffffffa8c40e10 R09: 0000000000005ffd
>    Sep 15 23:32:17 sdslinux1 kernel: R10: 0000000000000004 R11:
>    ffffffffa8c70e10 R12: ffff8bf551eef400
>    Sep 15 23:32:17 sdslinux1 kernel: R13: 0000000000000000 R14:
>    0000000000000013 R15: 00000000000003a8
>    Sep 15 23:32:17 sdslinux1 kernel: FS:  00007fae144de8c0(0000)
>    GS:ffff8bf84e780000(0000) knlGS:0000000000000000
>    Sep 15 23:32:17 sdslinux1 kernel: CS:  0010 DS: 0000 ES: 0000 CR0:
>    0000000080050033
>    Sep 15 23:32:17 sdslinux1 kernel: CR2: 00007fae14691690 CR3:
>    00000001027a2003 CR4: 00000000001706f0
>    Sep 15 23:32:17 sdslinux1 kernel: Call Trace:
>    Sep 15 23:32:17 sdslinux1 kernel:  <TASK>
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __warn+0x12a/0x1d0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __fortify_report+0x45/0x50
>    Sep 15 23:32:17 sdslinux1 kernel:  ? report_bug+0x154/0x1c0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? handle_bug+0x42/0x70
>    Sep 15 23:32:17 sdslinux1 kernel:  ? exc_invalid_op+0x1a/0x50
>    Sep 15 23:32:17 sdslinux1 kernel:  ? asm_exc_invalid_op+0x1a/0x20
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __fortify_report+0x45/0x50
>    Sep 15 23:32:17 sdslinux1 kernel:  __fortify_panic+0x9/0x10
>    Sep 15 23:32:17 sdslinux1 kernel: __get_cur_name_and_parent+0x3bc/0x3c0
>    Sep 15 23:32:17 sdslinux1 kernel:  get_cur_path+0x207/0x3b0
>    Sep 15 23:32:17 sdslinux1 kernel:  send_extent_data+0x709/0x10d0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? find_parent_nodes+0x22df/0x25d0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? mas_nomem+0x13/0x90
>    Sep 15 23:32:17 sdslinux1 kernel:  ? mtree_insert_range+0xa5/0x110
>    Sep 15 23:32:17 sdslinux1 kernel:  ? btrfs_lru_cache_store+0x5f/0x1e0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? iterate_extent_inodes+0x52d/0x5a0
>    Sep 15 23:32:17 sdslinux1 kernel:  process_extent+0xa96/0x11a0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_lookup_backref_cache+0x10/0x10
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_store_backref_cache+0x10/0x10
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_iterate_backrefs+0x10/0x10
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx_check_extent_item+0x10/0x10
>    Sep 15 23:32:17 sdslinux1 kernel:  changed_cb+0x6fa/0x930
>    Sep 15 23:32:17 sdslinux1 kernel:  ? tree_advance+0x362/0x390
>    Sep 15 23:32:17 sdslinux1 kernel:  ? memcmp_extent_buffer+0xd7/0x160
>    Sep 15 23:32:17 sdslinux1 kernel:  send_subvol+0xf0a/0x1520
>    Sep 15 23:32:17 sdslinux1 kernel:  btrfs_ioctl_send+0x106b/0x11d0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __pfx___clone_root_cmp_sort+0x10/0x10
>    Sep 15 23:32:17 sdslinux1 kernel:  _btrfs_ioctl_send+0x1ac/0x240
>    Sep 15 23:32:17 sdslinux1 kernel:  btrfs_ioctl+0x75b/0x850
>    Sep 15 23:32:17 sdslinux1 kernel:  __se_sys_ioctl+0xca/0x150
>    Sep 15 23:32:17 sdslinux1 kernel:  do_syscall_64+0x85/0x160
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __count_memcg_events+0x69/0x100
>    Sep 15 23:32:17 sdslinux1 kernel:  ? handle_mm_fault+0x1327/0x15c0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? __se_sys_rt_sigprocmask+0xf1/0x180
>    Sep 15 23:32:17 sdslinux1 kernel:  ? syscall_exit_to_user_mode+0x75/0xa0
>    Sep 15 23:32:17 sdslinux1 kernel:  ? do_syscall_64+0x91/0x160
>    Sep 15 23:32:17 sdslinux1 kernel:  ? do_user_addr_fault+0x21d/0x630
>    Sep 15 23:32:17 sdslinux1 kernel: entry_SYSCALL_64_after_hwframe+0x76/0x7e
>    Sep 15 23:32:17 sdslinux1 kernel: RIP: 0033:0x7fae145eeb4f
>    Sep 15 23:32:17 sdslinux1 kernel: Code: 00 48 89 (...)
>    Sep 15 23:32:17 sdslinux1 kernel: RSP: 002b:00007ffdf1cb09b0 EFLAGS:
>    00000246 ORIG_RAX: 0000000000000010
>    Sep 15 23:32:17 sdslinux1 kernel: RAX: ffffffffffffffda RBX:
>    0000000000000004 RCX: 00007fae145eeb4f
>    Sep 15 23:32:17 sdslinux1 kernel: RDX: 00007ffdf1cb0ad0 RSI:
>    0000000040489426 RDI: 0000000000000004
>    Sep 15 23:32:17 sdslinux1 kernel: RBP: 00000000000078fe R08:
>    00007fae144006c0 R09: 00007ffdf1cb0927
>    Sep 15 23:32:17 sdslinux1 kernel: R10: 0000000000000008 R11:
>    0000000000000246 R12: 00007ffdf1cb1ce8
>    Sep 15 23:32:17 sdslinux1 kernel: R13: 0000000000000003 R14:
>    000055c499fab2e0 R15: 0000000000000004
>    Sep 15 23:32:17 sdslinux1 kernel:  </TASK>
>    Sep 15 23:32:17 sdslinux1 kernel: ---[ end trace 0000000000000000 ]---
>    Sep 15 23:32:17 sdslinux1 kernel: ------------[ cut here ]------------
>
> Fix this passing the actual length to memmove(), not summing 1.
>
> Reported-by: David Arendt <admin@prnet.org>
> Link: https://lore.kernel.org/linux-btrfs/cee4591a-3088-49ba-99b8-d86b4242b8bd@prnet.org/
> Fixes: 31db9f7c23fb ("Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>  fs/btrfs/send.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
> index 7f48ba6c1c77..0c5a62da802d 100644
> --- a/fs/btrfs/send.c
> +++ b/fs/btrfs/send.c
> @@ -620,7 +620,7 @@ static void fs_path_unreverse(struct fs_path *p)
>         len = p->end - p->start;
>         p->start = p->buf;
>         p->end = p->start + len;
> -       memmove(p->start, tmp, len + 1);
> +       memmove(p->start, tmp, len);

Scratch this, the problem is elsewhere, reversed paths always end with
a nul terminator.

>         p->reversed = 0;
>  }
>
> --
> 2.43.0
>
>
diff mbox series

Patch

diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 7f48ba6c1c77..0c5a62da802d 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -620,7 +620,7 @@  static void fs_path_unreverse(struct fs_path *p)
 	len = p->end - p->start;
 	p->start = p->buf;
 	p->end = p->start + len;
-	memmove(p->start, tmp, len + 1);
+	memmove(p->start, tmp, len);
 	p->reversed = 0;
 }