On 12/08/26 4:49 am, Yehyeong Lee wrote:
> On a link whose device has max_recv_sge == 1 there is no shared v2 receive
> buffer, and smc_llc_save_add_link_rkeys() takes the v2 extension from 44
> bytes past the start of the queue entry's inline message:
> 
>   ext = (struct smc_llc_msg_add_link_v2_ext *)(llc_msg + SMC_WR_TX_SIZE);
> 
> The entry is a 72-byte allocation and the extension starts at offset 68, so
> ext->num_rkeys at offset 94 is already past it.  This happens on every

Extra whitespace

> SMC-Rv2 link addition, whatever the peer sends:
> 
>   [    2.490065] BUG: KASAN: slab-out-of-bounds in 
> smc_llc_save_add_link_rkeys+0x333/0x350
>   [    2.490431] Read of size 2 at addr ffff8880056406de by task smctest/106
>   [    2.490709] 
>   [    2.490792] CPU: 0 UID: 0 PID: 106 Comm: smctest Not tainted 
> 7.2.0-rc5-p1-g77a5d9d9c99f #32 PREEMPT(lazy) 
>   [    2.490795] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, 
> arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
>   [    2.490798] Call Trace:
>   [    2.490803]  <TASK>
>   [    2.490805]  dump_stack_lvl+0x53/0x70
>   [    2.490810]  print_report+0xd0/0x630
>   [    2.490828]  ? __pfx__raw_spin_lock_irqsave+0x10/0x10
>   [    2.490832]  ? smc_llc_save_add_link_rkeys+0x333/0x350
>   [    2.490834]  kasan_report+0xce/0x100
>   [    2.490836]  ? smc_llc_save_add_link_rkeys+0x333/0x350
>   [    2.490837]  smc_llc_save_add_link_rkeys+0x333/0x350
>   [    2.490839]  ? smcr_buf_map_lgr+0x1bf/0x2b0
>   [    2.490844]  smc_llc_cli_add_link+0xca7/0x1e80
>   [    2.490848]  ? smc_llc_wait+0x355/0x810
>   [    2.490850]  ? __pfx_smc_llc_wait+0x10/0x10
>   [    2.490851]  ? __pfx_smc_llc_cli_add_link+0x10/0x10
>   [    2.490853]  ? __pfx_autoremove_wake_function+0x10/0x10
>   [    2.490863]  __smc_connect+0x3f5c/0x4980
>   [    2.490873]  ? __pfx_kernel_connect+0x10/0x10
>   [    2.490888]  ? __pfx___smc_connect+0x10/0x10
>   [    2.490891]  ? release_sock+0x148/0x1d0
>   [    2.490894]  smc_connect+0x42c/0x580
>   [    2.490896]  __sys_connect+0xfc/0x130
>   [    2.490898]  ? __pfx___sys_connect+0x10/0x10
>   [    2.490900]  ? handle_mm_fault+0x1a1/0x430
>   [    2.490908]  __x64_sys_connect+0x6d/0xb0
>   [    2.490909]  ? fpregs_assert_state_consistent+0x56/0xe0
>   [    2.490917]  do_syscall_64+0xf9/0x540
>   [    2.490921]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
>   [    2.490924] RIP: 0033:0x421bb4
>   [    2.490927] Code: ff f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 
> 00 00 00 90 f3 0f 1e fa 80 3d ad 34 09 00 00 74 13 b8 2a 00 00 00 0f 05 <48> 
> 3d 00 f0 ff ff 77 4c c3 0f 1f 00 55 48 89 e5 48 83 ec 10 89 55
>   [    2.490929] RSP: 002b:00007ffd473b01a8 EFLAGS: 00000202 ORIG_RAX: 
> 000000000000002a
>   [    2.490935] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 
> 0000000000421bb4
>   [    2.490936] RDX: 0000000000000010 RSI: 00007ffd473b01d0 RDI: 
> 0000000000000003
>   [    2.490937] RBP: 0000000000003930 R08: 0000000000000004 R09: 
> 0000000000000000
>   [    2.490938] R10: 00007ffd473b0f98 R11: 0000000000000202 R12: 
> 0000000000000006
>   [    2.490939] R13: 00007ffd473b0f87 R14: 0000000000000003 R15: 
> 00007ffd473b0f90
>   [    2.490940]  </TASK>
>   [    2.490941] 
>   [    2.499545] Allocated by task 44:
>   [    2.499693]  kasan_save_stack+0x33/0x60
>   [    2.499860]  kasan_save_track+0x14/0x30
>   [    2.500026]  __kasan_kmalloc+0x8f/0xa0
>   [    2.500190]  __kmalloc_cache_noprof+0x158/0x370
>   [    2.500393]  smc_llc_enqueue+0x72/0x560
>   [    2.500559]  smc_wr_rx_tasklet_fn+0x474/0xa80
>   [    2.500747]  tasklet_action_common+0x20f/0x8a0
>   [    2.500945]  handle_softirqs+0x18e/0x590
>   [    2.501115]  do_softirq+0x3b/0x60
>   [    2.501266]  __local_bh_enable_ip+0x61/0x70
>   [    2.501446]  __alloc_skb+0x732/0x890
>   [    2.501604]  rxe_init_packet+0x16b/0x4f0
>   [    2.501783]  prepare_ack_packet+0xb8/0x830
>   [    2.501962]  rxe_receiver+0x495/0x96e0
>   [    2.502125]  do_work+0x144/0x470
>   [    2.502269]  process_one_work+0x633/0x1030
>   [    2.502450]  worker_thread+0x45b/0xd10
>   [    2.502617]  kthread+0x2c6/0x3b0
>   [    2.502762]  ret_from_fork+0x36e/0x5a0
>   [    2.502925]  ret_from_fork_asm+0x1a/0x30
>   [    2.503103] 
>   [    2.503177] The buggy address belongs to the object at ffff888005640680
>   [    2.503177]  which belongs to the cache kmalloc-96 of size 96
>   [    2.503692] The buggy address is located 22 bytes to the right of
>   [    2.503692]  allocated 72-byte region [ffff888005640680, 
> ffff8880056406c8)
>   [    2.504227] 
>   [    2.504300] The buggy address belongs to the physical page:
>   [    2.504535] page: refcount:0 mapcount:0 mapping:0000000000000000 
> index:0x0 pfn:0x5640
>   [    2.504865] flags: 0x100000000000000(node=0|zone=1)
>   [    2.505076] page_type: f5(slab)
>   [    2.505221] raw: 0100000000000000 ffff888001041280 dead000000000122 
> 0000000000000000
>   [    2.505544] raw: 0000000000000000 0000000000200020 00000000f5000000 
> 0000000000000000
>   [    2.505867] page dumped because: kasan: bad access detected
>   [    2.506102] 
>   [    2.506176] Memory state around the buggy address:
>   [    2.506380]  ffff888005640580: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc 
> fc fc
>   [    2.506683]  ffff888005640600: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc 
> fc fc
>   [    2.506987] >ffff888005640680: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc 
> fc fc
>   [    2.507291]                                                     ^
>   [    2.507548]  ffff888005640700: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc 
> fc fc
>   [    2.507850]  ffff888005640780: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc 
> fc fc
> 
> Whatever that read finds then bounds the ext->rt[] loop, so a peer that
> declares 255 rkeys reads much further.  smc_llc_rmt_delete_rkey() has the

Extra whitespace

> same shape for llcv2->rkey[].
> 
> Bound both loops by the buffer they read from, and skip the extension
> altogether when there is no shared v2 receive buffer.  The extension

Extra whitespace

> does arrive on the link, but smc_llc_enqueue() copies only
> sizeof(union smc_llc_msg) into the queue entry, so what that code read
> past the 44 inline bytes was heap and not peer data.
> 
> Fixes: 27ef6a9981fe ("net/smc: support SMC-R V2 for rdma devices with 
> max_recv_sge equals to 1")
> Cc: [email protected]
> Signed-off-by: Yehyeong Lee <[email protected]>
> ---
> v4 -> v5: corrected the reason given for skipping the extension.  It does
> arrive on the link; what is not there is the copy in the queue entry.  No
> functional change.
> 
> Measured over rxe with KASAN and max_recv_sge forced to 1, five test cells
> (plain 1-rkey delete, delete declaring 255, plain ADD_LINK v2, ADD_LINK
> declaring 255, and an SMC-Rv1 link group).  Without this patch four of the

Extra whitespace

> five report; with it none do.  With kasan_multi_shot the unpatched kernel

Extra whitespace

> reports 491 times in a single ADD_LINK run, the patched one not at all.
> 
> Changes since v5: none.
> 
>  net/smc/smc_llc.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
> index 055a03eee5b5..748d65186f68 100644
> --- a/net/smc/smc_llc.c
> +++ b/net/smc/smc_llc.c
> @@ -1000,13 +1000,21 @@ static void smc_llc_save_add_link_rkeys(struct 
> smc_link *link,
>                                       struct smc_link *link_new,
>                                       u8 *llc_msg)
>  {
> +     const u32 rt_off = offsetof(struct smc_llc_msg_add_link_v2_ext, rt);
>       struct smc_llc_msg_add_link_v2_ext *ext;
>       struct smc_link_group *lgr = link->lgr;
>       int max, i;
>  
> +     /* Without a shared v2 receive buffer the extension is not copied
> +      * into the queue entry, so not even ext->num_rkeys is there.
> +      */
> +     if (!smc_link_shared_v2_rxbuf(link))
> +             return;
>       ext = (struct smc_llc_msg_add_link_v2_ext *)(llc_msg +
>                                                    SMC_WR_TX_SIZE);
>       max = min_t(u8, ext->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2);
> +     max = min_t(u32, max, (SMC_WR_BUF_V2_SIZE - SMC_WR_TX_SIZE - rt_off) /
> +                           sizeof(ext->rt[0]));
>       down_write(&lgr->rmbs_lock);
>       for (i = 0; i < max; i++) {
>               smc_rtoken_set(lgr, link->link_idx, link_new->link_idx,
> @@ -1811,17 +1819,25 @@ static void smc_llc_rmt_delete_rkey(struct 
> smc_link_group *lgr)
>       link = qentry->link;
>  
>       if (lgr->smc_version == SMC_V2) {
> +             const u32 rkey_off =
> +                     offsetof(struct smc_llc_msg_delete_rkey_v2, rkey);
>               struct smc_llc_msg_delete_rkey_v2 *llcv2;
> +             u32 buf_len;
>  
>               if (smc_link_shared_v2_rxbuf(link)) {
>                       memcpy(lgr->wr_rx_buf_v2, llc, sizeof(*llc));
>                       llcv2 = (struct smc_llc_msg_delete_rkey_v2 
> *)lgr->wr_rx_buf_v2;
> +                     buf_len = SMC_WR_BUF_V2_SIZE;
>               } else {
>                       llcv2 = (struct smc_llc_msg_delete_rkey_v2 *)llc;
> +                     buf_len = sizeof(qentry->msg);
>               }
>               llcv2->num_inval_rkeys = 0;
>  
>               max = min_t(u8, llcv2->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2);
> +             /* bound by the buffer llcv2 points at */
> +             max = min_t(u32, max, (buf_len - rkey_off) /
> +                                   sizeof(llcv2->rkey[0]));
>               for (i = 0; i < max; i++) {
>                       if (smc_rtoken_delete(link, llcv2->rkey[i]))
>                               llcv2->num_inval_rkeys++;

Reviewed-by: Sidraya Jayagond <[email protected]>

Reply via email to