Linux-CIFS Archive mirror
 help / color / mirror / Atom feed
From: Ruikai Peng <ruikai@pwno.io>
To: linkinjeon@kernel.org, sfrench@samba.org,
	senozhatsky@chromium.org,  tom@talpey.com
Cc: security@kernel.org, metze@samba.org, pc@manguebit.org,
	 linux-cifs@vger.kernel.org
Subject: [SECURITY] SMB Direct: double-free of send_io on ib_post_send failure in batch flush path
Date: Wed, 8 Apr 2026 07:29:26 -0400	[thread overview]
Message-ID: <CAFD3drNOSJ05y3A+jNXSDxW-2w09KHQ0DivhxQ_pcc7immVVOQ@mail.gmail.com> (raw)

Hi,

The send batching logic introduced in the v7.0 merge window has a
double-free of mempool-backed send message objects when ib_post_send()
fails during a batch flush. The bug affects both the client
(fs/smb/client/smbdirect.c) and server (fs/smb/server/transport_rdma.c)
SMB Direct implementations. It is present on current upstream HEAD
(v7.0-rc7+).

The batch flush helpers (smbd_send_batch_flush and
smb_direct_flush_send_list) take ownership of the batched send
messages and free them on ib_post_send() failure:

  fs/smb/server/transport_rdma.c, smb_direct_flush_send_list():

    ret = smb_direct_post_send(sc, &first->wr);
    if (ret) {
        list_for_each_entry_safe(sibling, ...) {
            smb_direct_free_sendmsg(sc, sibling);
        }
        smb_direct_free_sendmsg(sc, last);
    }

However, the callers (smb_direct_post_send_data and
smbd_post_send_iter) have a generic error path that frees the same
message unconditionally:

  fs/smb/server/transport_rdma.c, smb_direct_post_send_data():

    ret = smb_direct_flush_send_list(sc, send_ctx, true);
    if (ret)
        goto err;
    ...
  err:
    smb_direct_free_sendmsg(sc, msg);

This double-free occurs specifically when using the stack-allocated
local batch for single-message sends, since in that case the caller
immediately flushes and then falls through to the same err label.

The same pattern exists on the client side:

  fs/smb/client/smbdirect.c, smbd_post_send_iter():

    rc = smbd_send_batch_flush(sc, batch, true);
    if (!rc)
        return 0;
    ...
  err_dma:
    smbd_free_send_io(request);

A remote peer can trigger ib_post_send() failures by tearing down the
RDMA connection or forcing the QP into an error state during active
sending. This results in:

  - Kernel heap double-free of mempool-backed send_io objects
  - Use-after-free from subsequent RDMA completion processing
  - Potential memory corruption

This requires an SMB Direct (RDMA) configuration and an attacker
capable of disrupting the RDMA connection.

I reproduced this deterministically using paired QEMU guests with
RXE soft-RDMA, a ksmbd share mounted over SMB Direct, and a
kretprobe-based fault injection module that forces
smb_direct_post_send() to return -EIO. KASAN reports a double-free
in mempool_free_slab and follow-on slab-use-after-free splats.

The first splat is a use-after-free when the caller's error path
touches the object that the flush helper already freed:

  [   14.352449] BUG: KASAN: slab-use-after-free in
smb_direct_free_sendmsg+0x31f/0x380
  [   14.352449] Read of size 8 at addr ffff888009dc72f8 by task kworker/1:0H/25
  [   14.352449]
  [   14.352449] CPU: 1 UID: 0 PID: 25 Comm: kworker/1:0H Tainted: G
        O        7.0.0-rc7-00059-g3036cd0d3328 #10 PREEMPT(lazy)
  [   14.352449] Workqueue: ksmbd-smb_direct-wq smb_direct_send_immediate_work
  [   14.352449] Call Trace:
  [   14.352449]  <TASK>
  [   14.352449]  dump_stack_lvl+0x5f/0x80
  [   14.352449]  print_report+0xd1/0x640
  [   14.352449]  kasan_report+0xe5/0x120
  [   14.352449]  smb_direct_free_sendmsg+0x31f/0x380
  [   14.352449]  smb_direct_post_send_data+0xf77/0x2cf0
  [   14.352449]  smb_direct_send_immediate_work+0x55/0x70
  [   14.352449]  process_one_work+0x635/0x10a0
  [   14.352449]  worker_thread+0x45b/0xc90
  [   14.352449]  kthread+0x2d7/0x3c0
  [   14.352449]  ret_from_fork+0x39f/0x5d0
  [   14.352449]  </TASK>
  [   14.352449]
  [   14.352449] Allocated by task 25:
  [   14.352449]  kmem_cache_alloc_noprof+0x109/0x380
  [   14.352449]  mempool_alloc_slab+0x14/0x20
  [   14.352449]  mempool_alloc_noprof+0x127/0x210
  [   14.352449]  smb_direct_post_send_data+0x308/0x2cf0
  [   14.352449]  smb_direct_send_immediate_work+0x55/0x70
  [   14.352449]
  [   14.352449] Freed by task 25:
  [   14.352449]  kmem_cache_free+0xb5/0x3b0
  [   14.352449]  mempool_free_slab+0x16/0x20
  [   14.352449]  mempool_free+0xbe/0x110
  [   14.352449]  smb_direct_free_sendmsg+0xa0/0x380
  [   14.352449]  smb_direct_flush_send_list+0x411/0x660      <--
first free here
  [   14.352449]  smb_direct_post_send_data+0x1abb/0x2cf0
  [   14.352449]  smb_direct_send_immediate_work+0x55/0x70
  [   14.352449]
  [   14.352449] The buggy address belongs to the object at ffff888009dc7280
  [   14.352449]  which belongs to the cache
smbdirect_send_io_pool_(____ptrval____) of size 208

This is immediately followed by the explicit double-free when the
caller attempts to return the same object to the mempool:

  [   14.382870] BUG: KASAN: double-free in mempool_free_slab+0x16/0x20
  [   14.382949] Free of addr ffff888009dc7280 by task kworker/1:0H/25
  [   14.383097]
  [   14.383097] CPU: 1 UID: 0 PID: 25 Comm: kworker/1:0H Tainted: G
 B      O        7.0.0-rc7-00059-g3036cd0d3328 #10 PREEMPT(lazy)
  [   14.383143] Workqueue: ksmbd-smb_direct-wq smb_direct_send_immediate_work
  [   14.383171] Call Trace:
  [   14.383181]  <TASK>
  [   14.383192]  dump_stack_lvl+0x5f/0x80
  [   14.383211]  print_report+0xd1/0x640
  [   14.383278]  kasan_report_invalid_free+0xa4/0xd0
  [   14.383387]  check_slab_allocation+0xe2/0x110
  [   14.383387]  __kasan_slab_pre_free+0xd/0x20
  [   14.383387]  kmem_cache_free+0x90/0x3b0
  [   14.383387]  mempool_free_slab+0x16/0x20
  [   14.383387]  mempool_free+0xbe/0x110
  [   14.383387]  smb_direct_free_sendmsg+0xa0/0x380           <--
second free here
  [   14.383387]  smb_direct_post_send_data+0xf77/0x2cf0       <--
caller err path
  [   14.383387]  smb_direct_send_immediate_work+0x55/0x70
  [   14.383387]  process_one_work+0x635/0x10a0
  [   14.383387]  worker_thread+0x45b/0xc90
  [   14.383387]  kthread+0x2d7/0x3c0
  [   14.383387]  ret_from_fork+0x39f/0x5d0
  [   14.383387]  </TASK>
  [   14.383387]
  [   14.383387] Allocated by task 25:
  [   14.383387]  kmem_cache_alloc_noprof+0x109/0x380
  [   14.383387]  mempool_alloc_slab+0x14/0x20
  [   14.383387]  mempool_alloc_noprof+0x127/0x210
  [   14.383387]  smb_direct_post_send_data+0x308/0x2cf0
  [   14.383387]  smb_direct_send_immediate_work+0x55/0x70
  [   14.383387]
  [   14.383387] Freed by task 25:
  [   14.383387]  kmem_cache_free+0xb5/0x3b0
  [   14.383387]  mempool_free_slab+0x16/0x20
  [   14.383387]  mempool_free+0xbe/0x110
  [   14.383387]  smb_direct_free_sendmsg+0xa0/0x380
  [   14.383387]  smb_direct_flush_send_list+0x411/0x660       <--
flush freed it
  [   14.383387]  smb_direct_post_send_data+0x1abb/0x2cf0
  [   14.383387]  smb_direct_send_immediate_work+0x55/0x70

The "Freed by" stacks confirm the first free comes from
smb_direct_flush_send_list() and the second from the caller
smb_direct_post_send_data() at a different offset (+0xf77 vs +0x1abb),
matching the two distinct free sites described above.

Best,
- Ruikai Peng

             reply	other threads:[~2026-04-08 11:29 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-08 11:29 Ruikai Peng [this message]
2026-04-08 11:58 ` [SECURITY] SMB Direct: double-free of send_io on ib_post_send failure in batch flush path Stefan Metzmacher
2026-04-08 13:10 ` Stefan Metzmacher
2026-04-08 13:36   ` Ruikai Peng
2026-04-08 15:18     ` Stefan Metzmacher

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=CAFD3drNOSJ05y3A+jNXSDxW-2w09KHQ0DivhxQ_pcc7immVVOQ@mail.gmail.com \
    --to=ruikai@pwno.io \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=pc@manguebit.org \
    --cc=security@kernel.org \
    --cc=senozhatsky@chromium.org \
    --cc=sfrench@samba.org \
    --cc=tom@talpey.com \
    /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
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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 read-only IMAP folder(s) and NNTP newsgroup(s).