Linux CIFS filesystem development
 help / color / mirror / Atom feed
* Subject: [RESEND][PATCH] ksmbd: add rwsem locking for iface_list to fix UAF during server reset
@ 2026-09-23 13:19 朱浩
  2026-09-23 13:22 ` Greg KH
  0 siblings, 1 reply; 2+ messages in thread
From: 朱浩 @ 2026-09-23 13:19 UTC (permalink / raw)
  To: Greg KH
  Cc: 朱浩, security, linkinjeon, linkinjeon, smfrench,
	sfrench, linux-cifs


[-- Attachment #1.1: Type: text/plain, Size: 7333 bytes --]

Hi,
Thank you for the feedback on formatting. I have repackaged the fix as a proper git format-patch patch (plain text, no HTML), so it applies cleanly.



-------------------------------------------------------------------
Fix
-------------------------------------------------------------------

You can find it in ksmbd_iface_list_uaf_fix/patches/0001-ksmbd-add-rwsem-locking-for-iface_list.patch in my uploading tar file.



-------------------------------------------------------------------
Summary
-------------------------------------------------------------------
ksmbd frees the global interface list (iface_list) without any lock during server
reset / hard-kill, *before* stop_sessions() is invoked. Meanwhile the
FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl handler traverses that same list while holding
only rtnl_lock (a lock the free path does not take), dereferencing freed iface nodes.
A remote authenticated SMB client that floods FSCTL_QUERY_NETWORK_INTERFACE_INFO while the
server is being reset can trigger a use-after-free read, producing a KASAN
slab-use-after-free report and a general protection fault (kernel oops / DoS).
-------------------------------------------------------------------
Affected component and versions
-------------------------------------------------------------------
Component: Linux kernel, fs/smb/server (ksmbd)
Confirmed present:
  - Snapshot at commit af5226abb4 (6.15.0-rc3 era), where I reproduced it with KASAN.
  - Current upstream master (checked 2026-09): ksmbd_tcp_destroy() still frees iface_list
    without any lock, and ksmbd_find_netdev_name_iface_list() still traverses it holding
    only rtnl_lock. No fix is present upstream as far as I can tell.
-------------------------------------------------------------------
Root cause (code references)
-------------------------------------------------------------------
1) The shared object:
   fs/smb/server/transport_tcp.c
     static LIST_HEAD(iface_list);            // plain LIST_HEAD, no lock, no refcount
2) Freeing side (no lock):
   fs/smb/server/transport_tcp.c : ksmbd_tcp_destroy()
     unregister_netdevice_notifier(&ksmbd_netdev_notifier);   // rtnl taken+released internally
     list_for_each_entry_safe(iface, tmp, &iface_list, entry) {
         list_del(&iface->entry);        // entry->next becomes LIST_POISON under DEBUG_LIST
         kfree(iface->name);
         kfree(iface);
     }
   Call ordering (fs/smb/server/connection.c : ksmbd_conn_transport_destroy):
     mutex_lock(&init_lock);
     ksmbd_tcp_destroy();      // (A) frees iface_list
     stop_sessions();          // (B) only afterwards stops the connection worker threads
     mutex_unlock(&init_lock);
   Because (A) runs before (B), the ksmbd-io workqueue workers that service in-flight SMB
   requests are still active while iface_list is being freed.
3) Use side (unlocked traversal, holds only rtnl_lock):
   fs/smb/server/smb2pdu.c : fsctl_query_iface_info_ioctl()
     rtnl_lock();
     for_each_netdev(&init_net, netdev) {
         if (!ksmbd_find_netdev_name_iface_list(netdev->name))   // boolean gate
             continue;
         ...
     }
     rtnl_unlock();
   fs/smb/server/transport_tcp.c : ksmbd_find_netdev_name_iface_list()
     list_for_each_entry(iface, &iface_list, entry)
         if (!strcmp(iface->name, netdev_name))   // dereferences iface->name / walks iface->entry.next
             return iface;
   The traversal holds rtnl_lock; the free path does not take rtnl_lock. They are different
   lock domains, so the free can proceed concurrently with the traversal.
-------------------------------------------------------------------
Trigger / reachability
-------------------------------------------------------------------
- Read side (attacker-controlled): any authenticated SMB session can issue
  FSCTL_QUERY_NETWORK_INTERFACE_INFO (no_fileid_ioctl, FID = SMB2_NO_FID). No admin, no
  open file, and (if the server allows guest) even weaker credentials suffice. Flooding this
  ioctl from multiple connections keeps workers traversing iface_list.
- Free side (trigger): the server reset path runs when
    (a) root writes "hard" to /sys/class/ksmbd-control/kill_server (kill_server_store), or
    (b) the ksmbd userspace daemon heartbeat times out (server_queue_ctrl_reset_work).
  These correspond to an administrator restarting / hard-killing the service.
- The race: a worker iterating iface_list (or mid-strcmp on a node) while the reset frees
  that node -> use-after-free read of iface->name, or walking the list into LIST_POISON.
-------------------------------------------------------------------
Impact
-------------------------------------------------------------------
- KASAN reports "slab-use-after-free in ksmbd_find_netdev_name_iface_list".
- A subsequent general protection fault (non-canonical LIST_POISON dereference) -> kernel oops.
- Denial of service: with panic_on_oops the machine panics; otherwise the worker is killed.
  The list_del + kfree of the name and the node can also leave a dangling name pointer.
- This is a read-only UAF (no write primitive, no function-pointer in struct interface),
  so the practical impact is kernel DoS rather than privilege escalation.
-------------------------------------------------------------------
Evidence
-------------------------------------------------------------------
Reproduced on the vulnerable kernel (6.15.0-rc3, KASAN enabled) with:
  - a userspace SMB client flooding FSCTL_QUERY_NETWORK_INTERFACE_INFO (12 threads,
    authenticated session, no open file), and
  - a VM-side root writing "hard" to /sys/class/ksmbd-control/kill_server (reset loop).
KASAN report (abridged):
  BUG: KASAN: slab-use-after-free in ksmbd_find_netdev_name_iface_list+0x64/0x90
  Read of size 8 ... by task kworker/...
  Call Trace:
    fsctl_query_iface_info_ioctl.isra.0
    smb2_ioctl
    handle_ksmbd_work
  Freed by task 1:
    kfree
    ksmbd_tcp_destroy
    ksmbd_conn_transport_destroy
    server_ctrl_handle_reset
    kill_server_store        <- the sysfs write that triggers the reset
  The buggy address belongs to the object at ffff... which belongs to the cache kmalloc-96
  ...
  Oops: general protection fault, probably for non-canonical address 0xdead...:
  RIP: ksmbd_find_netdev_name_iface_list+0x48
I also have a self-contained userspace reproducer (python, SMB2 client) and the full KASAN
splat available; happy to share them on request.
-------------------------------------------------------------------
Suggested fix
-------------------------------------------------------------------
Any of:
  1. Protect iface_list with a dedicated lock shared by ksmbd_tcp_destroy() and
     ksmbd_find_netdev_name_iface_list() (and all other traversers);
  2. Free the nodes via RCU and traverse under rcu_read_lock();
  3. Reorder ksmbd_conn_transport_destroy() to run stop_sessions() before freeing iface_list.
-------------------------------------------------------------------
Credit
-------------------------------------------------------------------

Discovered and reported by:
  Hao Zhu
  Peking University


Thank you for maintaining ksmbd. Please let me know if you need any additional detail or the reproducer. I am happy to follow your embargo/disclosure timeline.
Best regards,
Hao Zhu




 朱浩
2401112100@stu.pku.edu.cn





[-- Attachment #1.2: Type: text/html, Size: 20065 bytes --]

[-- Attachment #2: ksmbd_iface_list_uaf_fix.tar-zhuhao.gz --]
[-- Type: application/x-gzip, Size: 12922 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-23 13:35 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 13:19 Subject: [RESEND][PATCH] ksmbd: add rwsem locking for iface_list to fix UAF during server reset 朱浩
2026-09-23 13:22 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox