Commit graph

1,465,279 commits

Author SHA1 Message Date
Ze Tan
39f2032096 smb/server: fix tree connection leak in smb2_tree_connect()
See the procedure below:

  smb2_tree_connect
    ksmbd_tree_conn_connect
      xa_store(&sess->tree_conns, tree_conn->id, tree_conn)
      ksmbd_counter_inc(KSMBD_COUNTER_TREE_CONNS)
      ksmbd_share_tree_conn_inc(sc)
    ksmbd_iov_pin_rsp // fail
    status.ret = KSMBD_TREE_CONN_STATUS_NOMEM
    // do not disconnect tree_conn

Disconnect the new tree connection if ksmbd_iov_pin_rsp() fails.

Fixes: e2b76ab8b5 ("ksmbd: add support for read compound")
Signed-off-by: Ze Tan <tanze@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:23 +09:00
Namjae Jeon
4818df5aaa ksmbd: wait for deferred notify cancellation
A cancelled SMB2 CHANGE_NOTIFY request is completed from system_wq. The
deferred work keeps a reference to the connection, but it is not included
in the connection's r_count. During connection teardown,
ksmbd_conn_transport_destroy() can therefore finish the connection handler
and destroy session proc entries before the deferred response runs.

Account for the deferred cancellation work in r_count. The connection
handler now waits for the deferred response to finish before it
deregisters sessions and removes their proc entries.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:22 +09:00
ChenXiaoSong
93a3cda161 smb/server: fix use-after-free in ksmbd_conn_transport_destroy()
Reproducer (Link[1]):

  1. Build kernel with CONFIG_KASAN=y
  2. server: systemctl start ksmbd
  3. client: mount -t cifs //localhost/export /mnt
  4. client: umount /mnt
  5. server: modprobe -r ksmbd

The error message is as follows:

  ==================================================================
  BUG: KASAN: slab-use-after-free in proc_remove+0x3e/0x80
  Read of size 8 at addr ffff88810654e098 by task modprobe/785
  ...
  Call Trace:
   <TASK>
   __dump_stack+0x19/0x30
   dump_stack_lvl+0x49/0x60
   print_address_description+0x7b/0x200
   print_report+0x5b/0x70
   kasan_report+0xed/0x130
   __asan_report_load8_noabort+0x18/0x20
   proc_remove+0x3e/0x80
   ksmbd_conn_transport_destroy+0x2b/0x320 [ksmbd]
   cleanup_module+0x33/0xe00 [ksmbd]
   __se_sys_delete_module+0x276/0x400
   __x64_sys_delete_module+0x5f/0x70
   x64_sys_call+0x2675/0x3030
   do_syscall_64+0xf0/0x3b0
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
  RIP: 0033:0x7f5b56d2b02b
  ...
   </TASK>

  Allocated by task 159:
   kasan_save_track+0x2f/0x70
   kasan_save_alloc_info+0x40/0x50
   __kasan_slab_alloc+0x52/0x70
   kmem_cache_alloc_noprof+0x168/0x3e0
   __proc_create+0x20b/0x710
   proc_create_single_data+0x78/0x150
   ksmbd_proc_create+0x24/0x30 [ksmbd]
   ksmbd_conn_transport_init+0x4f/0x80 [ksmbd]
   server_ctrl_handle_work+0x64/0x2c0 [ksmbd]
   process_scheduled_works+0x788/0xec0
   worker_thread+0x894/0xc10
   kthread+0x2e5/0x3c0
   ret_from_fork+0x168/0x4f0
   ret_from_fork_asm+0x1a/0x30

  Freed by task 785:
   kasan_save_track+0x2f/0x70
   kasan_save_free_info+0x4a/0x60
   __kasan_slab_free+0x47/0x70
   kmem_cache_free+0x122/0x410
   pde_put+0xfd/0x160
   remove_proc_subtree+0x365/0x540
   proc_remove+0x6a/0x80
   ksmbd_proc_cleanup+0x1f/0x60 [ksmbd]
   cleanup_module+0x18/0xe00 [ksmbd]
   __se_sys_delete_module+0x276/0x400
   __x64_sys_delete_module+0x5f/0x70
   x64_sys_call+0x2675/0x3030
   do_syscall_64+0xf0/0x3b0
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
  ==================================================================

Reported-by: Kyenghwan Hwang <obnred@gmail.com>
Link[1]: https://lore.kernel.org/linux-cifs/8ea028f5-90f4-4d21-b1ac-a343f0f04d88@chenxiaosong.com/
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:22 +09:00
Namjae Jeon
215e8816b1 ksmbd: detach blocked lock requests before freeing
A file_lock retained by ksmbd for byte-range lock bookkeeping can still
be part of the VFS blocked-request graph. In particular, the VFS can
chain a new waiter below an already blocked request through
flc_blocked_requests. The ksmbd_file reference count does not cover that
graph.

Both __ksmbd_close_fd() and the cross-request unlock path free these
retained file_lock objects directly. If a dependent waiter is still
attached, locks_release_private() hits
BUG_ON(!list_empty(&flc->flc_blocked_requests)). The same lifetime
mismatch can leave a freed ksmbd_lock reachable through its request-local
llist.

Detach the file_lock from the blocked-request graph before freeing it in
the close, cross-request unlock, and rollback paths. locks_delete_block()
also wakes requests chained below the object. Remove llist when a
completed lock is published so a globally visible ksmbd_lock no longer
points into the submitting worker's stack.

Fixes: d63528eb0d ("ksmbd: free ksmbd_lock when file is closed")
Reported-by: Kyenghwan Hwang <obnred@gmail.com>
Tested-by: Kyenghwan Hwang <obnred@gmail.com>
Tested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:22 +09:00
Thomas Huth
5b90f78dc2 smb: server: Clear Preauth_HashValue in smb2pdu.c with kfree_sensitive()
struct preauth_session contains the Preauth_HashValue[] array that
might contain sensitive data. Use kfree_sensitive() to clear it
before returning the memory to the heap.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:22 +09:00
Thomas Huth
0cb81ed8b5 smb: server: Free sensitive data in connection.c with kfree_sensitive()
struct ksmbd_conn contains an embedded struct ntlmssp_auth with the
ciphertext[] and cryptkey[] arrays, so to avoid leaking this information
via the heap, it should be freed with kfree_sensitive().

While we're at it, also use kfree_sensitive() for freeing preauth_info
in ksmbd_conn_free() to avoid that the Preauth_HashValue[] could leak
via the heap here, too.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:22 +09:00
Thomas Huth
9a4bd6507c smb: server: Free session data in user_session.c with kfree_sensitive()
struct ksmbd_session contains some arrays with sensitive information, like
sess_key, smb3encryptionkey, smb3decryptionkey and smb3signingkey. Thus
let's make sure that this information cannot leak via the heap and use
kfree_sensitive() to free it.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:21 +09:00
Thomas Huth
2c5a176882 smb: server: Make sure that passkey is not leaked on the heap in user_config.c
Use kfree_sensitive() to free the user->passkey (and the struct
ksmbd_login_response in ksmbd_login_user() that contains the same
information) to avoid that this information could leak somewhere
else via the heap.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:21 +09:00
Thomas Huth
9a9f1342da smb: server: Clear sensitive stack and heap data in auth.c
Sensitive data like keys that are stored in stack-local arrays could be
leaked via the stack to the calling functions, or via the heap when using
only normal kfree() functions. There is no known vulnaribility for this
right now, but it's good security style to explicitly zeroize this
sensitive matieral as soon as possible to avoid that it could be exploited
together with other bugs later.

In calc_ntlmv2_hash(), the struct hmac_md5_ctx is normally cleared during
hmac_md5_final() already, but in case of errors, this function is skipped
and ctx is never zeroized, so add a memzero_explicit(&ctx, sizeof(ctx))
there to fix the problem.

In ksmbd_krb5_authenticate(), the ksmbd_spnego_authen_response contains
the session key in the payload. It's currently freed with plain kvfree().
Let's better use kvfree_sensitive() instead.

In generate_key(), the prfhash[] array is used to calculate the key,
but it's never cleared, so it leaks on the stack. Thus clear this with
a memzero_explicit(), too.

In ksmbd_crypt_message(), the sign[] and key[] arrays are leaked via
the stack, too. Make sure to clear them via memzero_explicit() at the
end.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:21 +09:00
Ilan Dudnik
23a0be6a84 ksmbd: fix heap out-of-bounds write in krb5_authenticate()
In krb5_authenticate(), out_len is calculated to determine available
headroom in response_buf for the incoming Kerberos AP-REP token. However,
when SMB2_SESSION_SETUP is processed as a non-first element of a compounded
SMB2 request, the calculation omits work->next_smb2_rsp_hdr_off.

This causes out_len to overstate remaining buffer headroom by
the cumulative size of prior responses in the compound chain. Consequently,
the length check in ksmbd_krb5_authenticate()
(*out_len <= resp->spnego_blob_len) passes erroneously, allowing memcpy()
to write the AP-REP blob past the end of response_buf into adjacent kernel
heap memory.

Fix this by subtracting work->next_smb2_rsp_hdr_off when computing out_len,
ensuring it accurately reflects physical remaining buffer space.

Signed-off-by: Ilan Dudnik <ilan.dudnik@safebreach.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:21 +09:00
ChenXiaoSong
6a8292d379 smb/server: deny overwriting targets with non-POSIX opens
Reproducer:

  1. server: systemctl start ksmbd
  2. client: mount without `posix` option
     mount -t cifs //${server_ip}/export /mnt
  3. client: touch /mnt/file1 /mnt/file2
  4. client: C program: int fd = open("/mnt/file2", O_RDONLY);
  5. client: C program: rename("/mnt/file1", "/mnt/file2");
  6. client: C program: struct stat stbuf; fstat(fd, &stbuf);
                        stbuf.st_nlink is 1, should be 0

This patch fixes xfstests generic/035 when mounted without `posix` option.

Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:20 +09:00
ChenXiaoSong
1e3b4b4f77 smb/server: rename to ksmbd_has_nonposix_open_child()
The original function name `ksmbd_has_open_files()` could be confused with
the function name introduced in the next patch, and it does not accurately
describe what this function does.

Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 22:38:03 +09:00
ChenXiaoSong
2d99fbd7ad smb/server: fix posix state check for directory rename
Pass the source ksmbd_file to the rename helpers and use the per-handle
POSIX create-context state when deciding whether open children block a
directory rename.

work->tcon->posix_extensions only records whether POSIX extensions were
negotiated on the connection.  It does not indicate that the handles were
opened with POSIX create contexts.

Reproducer:

  1. server: systemctl start ksmbd
  2. client: mount -t cifs //${server_ip}/export /mnt
     # without posix option
  3. client: mkdir /mnt/dir1/; touch /mnt/dir1/file
  4. client: tail -f /mnt/dir1/file # open file
  5. client: mv /mnt/dir1 /mnt/dir2

Without this fix, the rename can succeed when it should fail with
"Permission denied".

Fixes: c841bd3d8d ("ksmbd: deny renaming directory with open children")
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:01:00 +09:00
Gael Blivet
a3bcea7c81 ksmbd: exempt FSCTL_PIPE_TRANSCEIVE from the generic file-id lookup
smb2_ioctl() rejects FSCTL_PIPE_TRANSCEIVE with
STATUS_OBJECT_NAME_NOT_FOUND before fsctl_pipe_transceive() runs. RPC
pipe IDs live in sess->rpc_handle_list, a separate namespace from the
ksmbd_file table the generic ksmbd_lookup_fd_slow() gate searches, so
the lookup always misses.

Found while testing generic SMB browsing (Finder's "Connect to
Server"): every DCE/RPC bind over a named pipe (SRVSVC, WKSSVC, SAMR,
LSARPC) failed right after CREATE. Adding FSCTL_PIPE_TRANSCEIVE to the
same no_fileid_ioctl exemption as FSCTL_PIPE_WAIT fixes it, confirmed
by testing a build with and without the change.

Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Tested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:01:00 +09:00
Ilan Dudnik
29f74f0f2e ksmbd: defer publishing granted locks to prevent UAF/double-free race
In smb2_lock(), mid-batch granted locks are published to connection-wide
(conn->lock_list) and file-wide (fp->lock_list) lists immediately upon
vfs_lock_file() success, while also remaining tracked on the stack-local
rollback_list.

If a subsequent element in the same SMB2_LOCK request array fails
validation or execution, the thread jumps to out: and walks
rollback_list to undo previously granted locks. However, because the
granted lock was already published to conn->lock_list, a concurrent
UNLOCK request on the same connection can find the lock object and
kfree() it before the rollback loop executes.

When the granting thread subsequently walks rollback_list, it
dereferences and frees the already-freed ksmbd_lock structure, resulting
in a Use-After-Free and Double-Free (on both ksmbd_lock and struct
file_lock).

Fix this by deferring the publication of granted locks to
conn->lock_list and fp->lock_list until after the entire array of lock
elements has been processed without error. Mid-batch grants remain
tracked exclusively on the request-local rollback_list until the whole
batch succeeds, eliminating the race window.

Fixes: e2f34481b2 ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Ilan Dudnik <ilan.dudnik@safebreach.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:59 +09:00
Namjae Jeon
3a98de41b0 ksmbd: fix use-after-free in lease break notification
smb2_lease_break_noti() selects a connection from a shared lease table,
but reads lease->l_lb without lease_list_lock. Connection teardown can
free the table before the notification takes a reference to the selected
connection.

Select and pin the connection while holding the lock protecting its
lifetime, before the allocations that may sleep. Also protect the owner
connection lookup with ci->m_lock, since session reconnect can clear
opinfo->conn under that lock. Transfer the reference to the notification
work and release it on allocation failures or in the existing work cleanup
path.

Fixes: 2145945feb ("ksmbd: route v2 lease breaks on the client lease channel")
Reported-by: Jinpyo Lee <bint4b13@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:59 +09:00
ZhangGuoDong
73541bd2ba smb/server: preserve error status in smb2_handle_negotiate()
smb2_handle_negotiate() records specific failures such as
STATUS_INVALID_PARAMETER or STATUS_NOT_SUPPORTED.

Fixes: e2b76ab8b5 ("ksmbd: add support for read compound")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:59 +09:00
ZhangGuoDong
f43cbe3b58 smb/server: call ksmbd_proc_cleanup() on module init failure
When a later initializer fails, the unwind chain releases resources
created after procfs and then jumps directly to class_unregister().
Returning an error from module_init() leaves the proc tree and its
per-CPU counters allocated.

Fixes: b38f99c121 ("ksmbd: add procfs interface for runtime monitoring and statistics")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:59 +09:00
ZhangGuoDong
db97f37637 smb/server: abort initialization when proc setup fails
ksmbd_server_init() calls ksmbd_proc_init() before creating the
remaining proc entries and server subsystems. ksmbd_proc_init() tears
down partial state on a procfs or percpu_counter allocation failure,
but returns void, so ksmbd_server_init() continues as if the counters
were usable.

Once userspace starts the server, server_ctrl_handle_init() calls
ksmbd_proc_reset(), which reaches percpu_counter_set() with a NULL
per-CPU counters pointer on SMP systems. The later ksmbd_proc_create()
calls also receive a NULL parent and may create entries in the /proc
root; ksmbd_proc_cleanup() cannot remove those entries because
ksmbd_proc_fs is NULL.

Fixes: b38f99c121 ("ksmbd: add procfs interface for runtime monitoring and statistics")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:58 +09:00
ZhangGuoDong
bef46b6047 smb/server: fix invalid pointer dereference in ksmbd_stop_durable_scavenger()
See the procedure below:

  ksmbd_launch_ksmbd_durable_scavenger
    durable_scavenger_running = true
    server_conf.dh_task = kthread_run() // fail, dh_task is an ERR_PTR()

  server_ctrl_handle_reset
    ksmbd_stop_durable_scavenger
    kthread_stop(server_conf.dh_task) // invalid pointer

Fixes: d484d621d4 ("ksmbd: add durable scavenger timer")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:58 +09:00
ZhangGuoDong
3ce2f94919 smb/server: fix memory leak in ksmbd_vfs_set_durable_owner()
See the procedure below:

  smb2_open
    ksmbd_vfs_set_durable_owner
      fp->owner.name = name

  // When the connection goes away
  ksmbd_sessions_deregister
    ksmbd_session_destroy
      ksmbd_destroy_file_table
        __close_file_table_ids
          session_fd_check // skip()
            ksmbd_vfs_set_durable_owner
              fp->owner.name = name // memory leak

Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:58 +09:00
ZhangGuoDong
d2ccf905f4 smb/server: fix null-ptr-deref in ksmbd_ipc_tree_connect_request()
See the procedure below:

  ksmbd_tree_conn_connect
    ksmbd_share_config_get
      share->name = kstrdup() // fail
      if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) // false
      // do not check `share->name`
    ksmbd_ipc_tree_connect_request
      strlen(share->name) // null-ptr-deref

Fixes: e2f34481b2 ("cifsd: add server-side procedures for SMB3")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:57 +09:00
Rosen Penev
6eac877e0e ksmbd: remove extra byte from ipc_msg_alloc() size calculations
Three ipc_msg_alloc() calls in transport_ipc.c allocate
sizeof(struct) + payload_len + 1, but the extra byte is
unnecessary. The payload data is binary and copied with
memcpy() to the exact size; no null terminator is needed.

This was present in the original commit that introduced the
file, where the structs already used [0] zero-length arrays,
so the +1 was never correct.

Assisted-by: Opencode:Big-Pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:57 +09:00
Namjae Jeon
16a7f7c2ec ksmbd: reject blocking compound lock requests
Clients set SMB2_LOCKFLAG_FAIL_IMMEDIATELY when a LOCK request contains
multiple lock elements, and servers reject requests that omit it.
Accepting such a request can leave earlier elements locked while a later
element waits asynchronously, enabling prolonged partial lock ownership
and avoidable deadlocks.

Return STATUS_INVALID_PARAMETER before processing any element when a
multi-element lock request contains a blocking lock. Unlock arrays remain
unaffected.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:57 +09:00
Namjae Jeon
054bcca4cd ksmbd: safely discard unregistered deferred locks
When vfs_lock_file() defers a lock, smb2_lock() puts its ksmbd_lock on
rollback_list before allocating and registering the asynchronous work.
If either operation fails, rollback assumes that smb_lock->conn is
initialized and dereferences NULL. The deferred file_lock also remains
linked into the VFS blocked-lock state while it is freed.

Keep the lock off rollback_list until async setup succeeds. On setup
failures, explicitly unblock and wake the deferred lock before freeing it
and its ksmbd wrapper.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:56 +09:00
Namjae Jeon
5ce5227cd6 ksmbd: recognize replayed SMB2 lock sequences
A server returns success without processing a lock request when a valid
LockSequenceArray entry contains the same sequence number. The current
verifier only invalidates mismatched entries, so matching requests are
submitted to the VFS again and recorded as duplicate locks.

Make the verifier report matching sequences and skip lock processing for
those replays. Also correct the field comment to describe the sequence
and index bit layout used by the implementation and the protocol. Use
the capabilities advertised by the server when deciding whether lock
sequence verification applies to a multichannel connection.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:56 +09:00
Namjae Jeon
54d90311f9 ksmbd: fix SMB2 byte-range lock end offset
SMB2 describes a byte-range lock using an offset and a length, while
Linux file_lock uses an inclusive end offset. smb2_lock() currently sets
fl_end to start + length and consequently locks one extra byte for every
nonzero-length request.

Translate nonzero lengths to start + length - 1 and reject ranges that
cannot be represented by loff_t instead of silently truncating them at
OFFSET_MAX. Track zero-length locks from the request length so one-byte
ranges are not mistaken for zero-length locks after endpoint conversion.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:56 +09:00
Namjae Jeon
b0148dc562 ksmbd: serialize oplock close with pending break ownership
close may abort an in-flight oplock break while another breaker already
holds an opinfo reference. Releasing pending_break wakes that waiter, but
without serializing the close transition with bit acquisition it can become
a new break owner through the test_and_set_bit() fast path. It can then
overwrite OPLOCK_CLOSING with OPLOCK_ACK_WAIT and continue a break for
a dying opinfo.

Make OPLOCK_CLOSING terminal once the opinfo is removed from the inode
list. Serialize that transition, pending_break acquisition, and
OPLOCK_ACK_WAIT setup with an opinfo state lock. A breaker which loses
the race releases its ownership and returns -ENOENT. Explicitly wake
pending_break waiters during close so they can observe the terminal state.

Also prevent ACK and timeout paths from replacing OPLOCK_CLOSING with
OPLOCK_STATE_NONE.

Fixes: e2f34481b2 ("cifsd: add server-side procedures for SMB3")
Co-developed-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:55 +09:00
ChenXiaoSong
f39ec312c3 smb/server: fix unbuffered file position alignment check
FILE_NO_INTERMEDIATE_BUFFERING is a CreateOptions flag and can be
combined with other flags, such as FILE_NON_DIRECTORY_FILE.

Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:55 +09:00
Namjae Jeon
a47634cd72 ksmbd: expire SMB sessions when Kerberos tickets expire
Store the expiry time from the Kerberos authentication response in
the session and reject requests after that time with
STATUS_NETWORK_SESSION_EXPIRED.

Allow an expired Kerberos session to be reauthenticated. Keep the old SMB
signing key until its SESSION_SETUP response has been signed, then install
the new session key and regenerate the SMB3 keys.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:54 +09:00
Namjae Jeon
84c41b731b ksmbd: stabilize allocation size after buffered writes
Ordinary opens initialize their allocation size from stat.blocks.
Buffered writes can leave delayed allocation pending, so separate handles
can cache different block counts for the same file.

This makes generic/568 fail when a zero write used for fallocate
emulation is followed by an overwrite of the same range. The first query
can report the pre-writeback block count, while the second query reports
the block count after delayed allocation is completed.

Complete writeback and refresh the cached block count before returning
allocation information for ordinary opens. Track client-specified
allocation sizes separately so CREATE allocation contexts and
FILE_ALLOCATION_INFORMATION continue to return the requested value.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:54 +09:00
Namjae Jeon
25e414db70 ksmbd: report holes in allocated range queries
FSCTL_QUERY_ALLOCATED_RANGES treated every range in a file without the
sparse attribute as allocated. Files can have holes after an ordinary write
beyond EOF, so CIFS FIEMAP reported extents for those holes.

SEEK_DATA and SEEK_HOLE are insufficient because unwritten extents
look like holes. Use zero writes for FSCTL_SET_ZERO_DATA on dense files.
Sparse files still use hole punching, and allocated-range queries can use
SEEK_DATA and SEEK_HOLE for both file types.

When clearing the sparse attribute, materialize holes with zero writes
before updating the attribute. This keeps the file fully allocated without
relying on unwritten extents that SEEK_DATA would still report as holes.

Return STATUS_BUFFER_OVERFLOW when another allocated range does not fit in
the SMB response so the client continues the query.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:53 +09:00
Aldo Ariel Panzardo
3f220a0a62 ksmbd: only rebind the reopened file's own oplock on durable reconnect
ksmbd_reopen_durable_fd() walks the inode's m_op_list and rebinds every
detached oplock to the reconnecting session:

	list_for_each_entry_rcu(op, &ci->m_op_list, op_entry,
				lockdep_is_held(&ci->m_lock)) {
		if (op->conn)
			continue;
		op->conn = ksmbd_conn_get(fp->conn);
		op->sess = work->sess;
	}

The only key is op->conn == NULL, which every detached durable handle on
that inode matches, not just the one owned by fp.  When two sessions hold
durable handles on the same file and both disconnect, reconnecting one of
them adopts the other session's oplock: op->sess is overwritten with the
reconnecting session without taking a reference on it, while op->conn
pins the connection.

The sibling teardown path, session_fd_check(), keys on the identity of
the connection being torn down (op->conn == conn) rather than on shared
state, and so does not have this problem.

Once the adopting session is destroyed, ksmbd_session_destroy() frees it
while the foreign oplock still points at it.  The reader in
ksmbd_close_fd_app_instance_id() validates only opinfo->conn, which is
still live thanks to the reference taken above, and then dereferences the
stale session:

	if (!opinfo->conn) {
		up_read(&fp->f_ci->m_lock);
		goto out;
	}

	ft = &opinfo->sess->file_table;
	write_lock(&ft->lock);

  BUG: KASAN: slab-use-after-free in _raw_write_lock+0x74/0xd0
  Write of size 4 at addr ffff88810a970528 by task kworker/0:0/9
  Workqueue: ksmbd-io handle_ksmbd_work
  Call Trace:
   _raw_write_lock+0x74/0xd0
   ksmbd_close_fd_app_instance_id+0x183/0x410
   smb2_open+0x1346/0x4430
   handle_ksmbd_work+0x2bb/0x7b0

Reached from an authenticated session against a share with the default
durable-handle and oplock configuration: two sessions open the same file
with a durable-v2 handle and an RH lease under distinct AppInstanceIds,
both log off, one reconnects with DH2C, and a later durable-v2 create
carrying the other AppInstanceId walks into the freed session.

Constrain the loop to the oplock owned by the file being reopened.

Fixes: f363a0fb13 ("ksmbd: fix app-instance durable supersede session UAF")
Cc: stable@vger.kernel.org
Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:53 +09:00
Namjae Jeon
06c7b1d731 ksmbd: free preauth sessions on connection teardown
SMB3.1.1 multichannel binding preserves the preauthentication hash in a
preauth_session between the NTLM negotiate and authenticate requests.
The binding NTLM negotiate allocates this object and returns
STATUS_MORE_PROCESSING_REQUIRED. If the client disconnects before it sends
the authenticate request, neither the authenticate nor error cleanup paths
free the object.

Release any remaining preauthentication sessions when tearing down the
connection. Initialize the list when allocating the connection so that this
cleanup is safe regardless of the negotiated dialect.

Reported-by: Runa Takemoto <takemotoruna223@gmail.com>
Fixes: f5a544e3ba ("ksmbd: add support for SMB3 multichannel")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:53 +09:00
ChenXiaoSong
528af7cf69 smb/server: avoid registering async requests during connection close
A connection-close scan can miss the synthetic CHANGE_NOTIFY work item
because smb2_notify() registers it directly after setup_async_work()
has returned. Link both regular and synthetic async work through one
helper that checks the connection state under request_lock.

If the connection is already closing, release a newly allocated async
ID or complete the synthetic notify work immediately.

Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Co-developed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:52 +09:00
ChenXiaoSong
4fd5bad647 smb/server: cancel async requests when closing connection
An async request may still be waiting when a connection is closed.
This can stop the connection from closing.

Cancel active async requests before waiting for them to finish.

Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:52 +09:00
ChenXiaoSong
df3e2150f3 smb/server: fix signing when a response uses more than one iov
Some SMB responses keep their data in another buffer. The SMB header
and the data are then in different iovs.

The old code only handled this for SMB2 READ. For other commands, it
signed only the last iov. QUERY_INFO and CHANGE_NOTIFY can also use
another iov for their data. Their SMB header was not signed, so Windows
will client rejected the response.

Find the iov that starts with the current SMB header. Sign this iov and
all iovs after it.

Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:52 +09:00
Yunseong Kim
e9b33376bd ksmbd: validate ipc response length before dereferencing its fields
ipc_validate_msg() computes the expected message size by reading length
fields out of the response buffer supplied by the userspace ksmbd daemon
(payload_sz, session_key_len, ngroups, ...).  Those fields are read before
the buffer is verified to be large enough to contain the struct they belong
to, so a short response makes the read land past the end of the allocation.

handle_response() sizes entry->response purely from the netlink attribute
length (nla_len()) and only guards the leading handle read, so the daemon
can install a response as small as the kmalloc-8 object seen below.  When
ipc_msg_send_request() then calls ipc_validate_msg() for a
KSMBD_EVENT_RPC_REQUEST, the cast to struct ksmbd_rpc_command reads
resp->payload_sz at offset 8 of an 8-byte allocation:

[ 3697.841381] ==================================================================
[ 3697.844099] BUG: KASAN: slab-out-of-bounds in ipc_msg_send_request+0x763/0x800
[ 3697.846604] Read of size 4 at addr ffff888105f95910 by task kworker/4:3/20682
[ 3697.849061]
[ 3697.849801] CPU: 4 UID: 0 PID: 20682 Comm: kworker/4:3 Not tainted 7.2.0-rc3-next-20260717-virtme #117 PREEMPT(lazy)
[ 3697.850077] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3697.850303] Workqueue: ksmbd-io handle_ksmbd_work
[ 3697.850592] Call Trace:
[ 3697.850794]  <TASK>
[ 3697.850952]  __dump_stack+0x21/0x60
[ 3697.851239]  dump_stack_lvl+0xc2/0x100
[ 3697.851528]  print_address_description+0x77/0x200
[ 3697.851816]  ? ipc_msg_send_request+0x763/0x800
[ 3697.852024]  print_report+0x58/0x70
[ 3697.852316]  kasan_report+0x117/0x150
[ 3697.852585]  ? down_write+0x146/0x1f0
[ 3697.852809]  ? ipc_msg_send_request+0x763/0x800
[ 3697.853082]  ipc_msg_send_request+0x763/0x800
[ 3697.853385]  ? __pfx_ipc_msg_send_request+0x10/0x10
[ 3697.853604]  ? kasan_unpoison+0x48/0x70
[ 3697.853936]  ? __pfx___up_read+0x10/0x10
[ 3697.854221]  ksmbd_rpc_ioctl+0x380/0x520
[ 3697.854542]  ? __pfx_ksmbd_rpc_ioctl+0x10/0x10
[ 3697.854757]  ? kasan_unpoison+0x48/0x70
[ 3697.854962]  ? copy_from_kernel_nofault+0x32c/0x4e0
[ 3697.855166]  ? kasan_unpoison+0x48/0x70
[ 3697.855416]  fsctl_pipe_transceive+0x139/0x7a0
[ 3697.855705]  ? __pfx_copy_from_kernel_nofault+0x10/0x10
[ 3697.855937]  ? __pfx_fsctl_pipe_transceive+0x10/0x10
[ 3697.856388]  ? __sanitizer_cov_trace_switch+0x7b/0x140
[ 3697.856620]  smb2_ioctl+0x1141/0x3420
[ 3697.856994]  ? __pfx_smb2_ioctl+0x10/0x10
[ 3697.857182]  ? get_smb2_cmd_val+0xe3/0x1c0
[ 3697.857655]  handle_ksmbd_work+0x9ad/0x15e0
[ 3697.858034]  ? __pfx_handle_ksmbd_work+0x10/0x10
[ 3697.858251]  ? lock_release+0xf7/0x360
[ 3697.858466]  ? process_scheduled_works+0x954/0x1600
[ 3697.858698]  ? process_scheduled_works+0x954/0x1600
[ 3697.858905]  process_scheduled_works+0xc22/0x1600
[ 3697.859368]  ? __pfx_process_scheduled_works+0x10/0x10
[ 3697.859637]  ? __pfx_assign_work+0x10/0x10
[ 3697.859896]  ? lock_is_held_type+0x7b/0x110
[ 3697.860146]  worker_thread+0x975/0xee0
[ 3697.860524]  ? __pfx_do_raw_spin_lock+0x10/0x10
[ 3697.860830]  ? __kthread_parkme+0x21e/0x260
[ 3697.861105]  kthread+0x3a6/0x490
[ 3697.861423]  ? __pfx_worker_thread+0x10/0x10
[ 3697.861643]  ? __pfx_kthread+0x10/0x10
[ 3697.861878]  ret_from_fork+0x55a/0xa20
[ 3697.862194]  ? __pfx_ret_from_fork+0x10/0x10
[ 3697.862480]  ? __pfx_kthread+0x10/0x10
[ 3697.862714]  ret_from_fork_asm+0x1a/0x30
[ 3697.862965]  </TASK>
[ 3697.863039]
[ 3697.938882] Allocated by task 20761:
[ 3697.940257]  kasan_save_track+0x3e/0x80
[ 3697.941782]  __kasan_kmalloc+0x72/0x90
[ 3697.943228]  __kvmalloc_node_noprof+0x3e9/0x6a0
[ 3697.944948]  handle_generic_event+0x59b/0x750
[ 3697.946592]  genl_family_rcv_msg_doit+0x3d6/0x560
[ 3697.946977]  genl_rcv_msg+0x67c/0x900
[ 3697.947224]  netlink_rcv_skb+0x286/0x580
[ 3697.947488]  genl_rcv+0x2d/0x80
[ 3697.947706]  netlink_unicast+0x937/0xb70
[ 3697.947993]  netlink_sendmsg+0x977/0xc10
[ 3697.948268]  __sock_sendmsg+0x264/0x2d0
[ 3697.948536]  __sys_sendto+0x4de/0x690
[ 3697.948789]  __x64_sys_sendto+0x173/0x380
[ 3697.949069]  do_syscall_64+0x13d/0x420
[ 3697.949328]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3697.949662]
[ 3697.949779] The buggy address belongs to the object at ffff888105f95908
[ 3697.949779]  which belongs to the cache kmalloc-8 of size 8
[ 3697.950550] The buggy address is located 0 bytes to the right of
[ 3697.950550]  allocated 8-byte region [ffff888105f95908, ffff888105f95910)
[ 3697.951455]
[ 3697.951574] The buggy address belongs to the physical page:
[ 3697.951958] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888105f951b8 pfn:0x105f95
[ 3697.952571] flags: 0x100000000000200(workingset|node=0|zone=2)
[ 3697.952973] page_type: f5(slab)
[ 3697.953198] raw: 0100000000000200 ffff888100042640 ffffea0004063610 ffff888100040588
[ 3697.953707] raw: ffff888105f951b8 00000000001c000e 00000000f5000000 0000000000000000
[ 3697.954240] page dumped because: kasan: bad access detected
[ 3697.954616]
[ 3697.954734] Memory state around the buggy address:
[ 3697.955063]  ffff888105f95800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fa
[ 3697.955534]  ffff888105f95880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 3697.956006] >ffff888105f95900: fc 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 3697.956477]                          ^
[ 3697.956728]  ffff888105f95980: fc fc fc fa fc fc fc fc fc fc fc fc fc fc fc fc
[ 3697.957202]  ffff888105f95a00: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc
[ 3697.957671] ==================================================================

The final "entry->msg_sz != msg_sz" comparison cannot help: the offending
read has already happened by the time it runs.  Every case in the switch
shares this pattern.

Floor entry->msg_sz against the base struct of each event type before
dereferencing any of its length fields.  On failure ipc_msg_send_request()
already frees the response and returns NULL, so callers stay safe.

The malformed message originates from the ksmbd.mountd daemon over genl
netlink rather than a remote SMB client, so triggering it requires a buggy
or compromised daemon; it is still an out-of-bounds read the validator is
meant to prevent.

Fixes: d6a6aa81ea ("ksmbd: validate response sizes in ipc_validate_msg()")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:52 +09:00
Yunseong Kim
db82fbe4bb smb: smbdirect: release pending child sockets outside the handler lock
smbdirect_socket_destroy() releases the listener's pending/ready child
sockets while still holding the listener's handler lock, the
&id_priv->handler_mutex taken via rdma_lock_handler(), not
sc->listen.lock, and before the listener's own rdma_destroy_id().
That ordering has one real consequence and one cosmetic one.

The real one: smbdirect_socket_release() drops the child's last
reference, which destroys the child's cm_id.  Doing that before the
listener's rdma_destroy_id() lets _cma_cancel_listens(), running from
the listener's _destroy_id(), walk an already freed child id_priv,
which KASAN catches as a slab-use-after-free during listener shutdown:

[ 4758.909130] BUG: KASAN: slab-use-after-free in __mutex_lock+0x1469/0x1560
[ 4758.911450] Read of size 1 at addr ffff88821c381db4 by task ksmbd.control/1652
[ 4758.913262] Call Trace:
[ 4758.913267]  <TASK>
[ 4758.913299]  __mutex_lock+0x1469/0x1560
[ 4758.913408]  _cma_cancel_listens+0x312/0x3b0
[ 4758.913413]  _destroy_id+0x363/0xee0
[ 4758.913417]  smbdirect_socket_destroy_sync+0x17d5/0x2440
[ 4758.913443]  smbdirect_socket_release+0x124/0x230
[ 4758.913451]  ksmbd_rdma_stop_listening+0x9f/0x190
[ 4758.913457]  ksmbd_conn_transport_destroy+0x65/0x3c0
[ 4758.913463]  kill_server_store+0x1fb/0x2b0
[ 4758.913501]  kernfs_fop_write_iter+0x349/0x4d0
[ 4758.913507]  vfs_write+0x5e7/0xc70
[ 4758.913528]  ksys_write+0x12a/0x210
[ 4758.913541]  do_syscall_64+0x135/0x460
[ 4758.913555]  entry_SYSCALL_64_after_hwframe+0x77/0x7f

The cosmetic one: releasing a child recurses into
smbdirect_socket_destroy(), which takes the child's own
rdma_lock_handler() lock nested under the listener's.  The listener's
and the child's cm_id are always different instances, so this cannot
deadlock for real; the CM core itself nests a new connection id's
handler_mutex under the listening id's in cma_ib_req_handler().  But
lockdep only sees one lock class, reports possible recursive locking,
and then disables itself, hiding real locking bugs for the rest of the
run:

[ 2424.579653] WARNING: possible recursive locking detected
[ 2424.581180] 7.1.0-next-20260623+ #89 Not tainted
[ 2424.582548] --------------------------------------------
[ 2424.584500] ksmbd.control/8854 is trying to acquire lock:
[ 2424.586817] ffff888102303c20 (&id_priv->handler_mutex){+.+.}-{4:4}, at: smbdirect_socket_destroy_sync+0xc39/0x2440
[ 2424.590590]
[ 2424.590590] but task is already holding lock:
[ 2424.591601] ffff888102046c20 (&id_priv->handler_mutex){+.+.}-{4:4}, at: smbdirect_socket_destroy_sync+0xc39/0x2440
[ 2424.594178]
[ 2424.594178] other info that might help us debug this:
[ 2424.596634]  Possible unsafe locking scenario:
[ 2424.596634]
[ 2424.598841]        CPU0
[ 2424.599765]        ----
[ 2424.600695]   lock(&id_priv->handler_mutex);
[ 2424.601836]   lock(&id_priv->handler_mutex);
[ 2424.602590]
[ 2424.602590]  *** DEADLOCK ***
[ 2424.602590]
[ 2424.604512]  May be due to missing lock nesting notation

Splice the pending/ready children onto a local list under the
listener's listen.lock, while the handler lock is held so a concurrent
CM CONNECT_REQUEST cannot add more, but defer the actual
smbdirect_socket_release() calls until after the listener's cm_id has
been destroyed and its handler lock dropped.  The children are
independent sockets whose teardown needs neither the listener's
handler lock nor its cm_id.

Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.

[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow

Fixes: dc691b91ad ("smb: smbdirect: introduce smbdirect_socket_{listen,accept}()")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:51 +09:00
Yunseong Kim
76fa42c004 smb: smbdirect: avoid recursive listen.lock during cleanup
__smbdirect_socket_schedule_cleanup() and smbdirect_socket_cleanup_work()
take sc->listen.lock and walk the listener's pending list, recursing
into smbdirect_socket_schedule_cleanup() for each child, and every
child takes its own listen.lock inside that walk.

This cannot deadlock for real: the nesting is strictly listener into
child, a child never listens, so the outer and the inner lock are
always different instances.  lockdep only tracks lock classes, though;
it sees the same class acquired twice and reports a possible recursive
locking deadlock.  This change therefore works around a lockdep
limitation rather than fixing a real hang, but the report is still
worth avoiding: lockdep disables itself after the first splat and then
hides real locking bugs for the rest of the run.

Only a socket that was a listener owns a populated listen.ready/pending
list; a child has empty lists and nothing to do in these blocks.  Guard
both of them with sc->listen.backlog != -1, the "was a listener" marker
that smbdirect_socket_destroy() already uses: listen.backlog leaves its
initial -1 exactly once, when smbdirect_socket_listen() succeeds.  The
alternative !sc->accept.listener test reads as "not a listener" while
meaning the opposite, and it is also true for an accepted child, whose
accept.listener has been cleared on hand-over.  With the guard the walk
only runs for a listener and never nests a child's listen.lock under
it; a pending child stays on its listener's list for the free path
(smbdirect_socket_destroy) to reap.

[  741.705044] WARNING: possible recursive locking detected
[  741.705403] 7.1.0-next-20260623+ #75 Not tainted
[  741.705695] --------------------------------------------
[  741.706022] ksmbd.control/18502 is trying to acquire lock:
[  741.706379] ffff888108d612f8 (&sc->listen.lock){....}-{3:3}, at: __smbdirect_socket_schedule_cleanup+0x719/0xd70
[  741.707008]
[  741.707008] but task is already holding lock:
[  741.707396] ffff8881087642f8 (&sc->listen.lock){....}-{3:3}, at: __smbdirect_socket_schedule_cleanup+0x719/0xd70
[  741.708025]
[  741.708025] other info that might help us debug this:
[  741.708448]  Possible unsafe locking scenario:
[  741.708448]
[  741.708845]        CPU0
[  741.709016]        ----
[  741.709186]   lock(&sc->listen.lock);
[  741.709453]   lock(&sc->listen.lock);
[  741.709705]
[  741.709705]  *** DEADLOCK ***
[  741.709705]
[  741.710095]  May be due to missing lock nesting notation
[  741.710095]
[  741.710663] 6 locks held by ksmbd.control/18502:
[  741.710975]  #0: ffff888109e51420 (sb_writers#7){.+.+}-{0:0}, at: vfs_write+0x1e7/0xc70
[  741.711561]  #1: ffff888126ec3880 (&of->mutex){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x1be/0x4d0
[  741.712147]  #2: ffff888102af17b0 (kn->active#45){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x205/0x4d0
[  741.712803]  #3: ffffffff85ad1e00 (ctrl_lock){+.+.}-{4:4}, at: kill_server_store+0x1e0/0x2b0
[  741.713381]  #4: ffffffff85ad41a0 (init_lock){+.+.}-{4:4}, at: ksmbd_conn_transport_destroy+0x5b/0x3c0
[  741.713995]  #5: ffff8881087642f8 (&sc->listen.lock){....}-{3:3}, at: __smbdirect_socket_schedule_cleanup+0x719/0xd70
[  741.714736]
[  741.714736] stack backtrace:
[  741.715038] CPU: 4 UID: 0 PID: 18502 Comm: ksmbd.control Not tainted 7.1.0-next-20260623+ #75 PREEMPT(lazy)
[  741.715043] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[  741.715046] Call Trace:
[  741.715049]  <TASK>
[  741.715052]  dump_stack_lvl+0x77/0xa0
[  741.715058]  print_deadlock_bug+0x279/0x290
[  741.715065]  __lock_acquire+0x272a/0x2e30
[  741.715070]  ? stack_trace_save+0xae/0x100
[  741.715075]  ? smb_direct_logging_vaprintf+0x1a0/0x230
[  741.715079]  ? __pfx_smb_direct_logging_vaprintf+0x10/0x10
[  741.715082]  ? __timer_delete+0x58/0x320
[  741.715087]  lock_acquire+0xd3/0x270
[  741.715091]  ? __smbdirect_socket_schedule_cleanup+0x719/0xd70
[  741.715095]  ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[  741.715099]  _raw_spin_lock_irqsave+0x42/0x60
[  741.715105]  ? __smbdirect_socket_schedule_cleanup+0x719/0xd70

Note the two addresses above: ffff888108d612f8 is the child's lock,
ffff8881087642f8 the listener's, always distinct objects.

Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.

[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow

Fixes: dc691b91ad ("smb: smbdirect: introduce smbdirect_socket_{listen,accept}()")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:51 +09:00
Yunseong Kim
383a9480f5 smb: smbdirect: destroy QP before mem pools on accept failure
On the rdma_accept_failed error path of
smbdirect_accept_connect_request(), the receive io posted just above is
owned by the QP (recv_io is set to NULL after a successful post).  The
error path fell through to smbdirect_connection_destroy_mem_pools()
before smbdirect_connection_destroy_qp(), so the mem pools and the
recv_io slab cache were destroyed while that recv_io was still
outstanding on the QP.

The drain in smbdirect_connection_destroy_qp() (ib_drain_qp()) is what
runs the recv completion that returns the recv_io to the free list, so
destroying the pools first leaves the object outstanding at
kmem_cache_destroy() time ("Slab cache still has objects") and later
frees it into an already-destroyed mempool (mempool_free_bulk
NULL-pointer dereference).

Give rdma_accept_failed its own teardown that drains the QP first, then
destroys the mem pools, and returns.  The remaining labels
(post_recv_io_failed onward) run before the recv_io was ever posted, so
they keep the mem-pools-then-qp order.

The outstanding recv_io at kmem_cache_destroy() time:

[ 3487.344647] =============================================================================
[ 3487.349942] BUG smbdirect_recv_io_cache_ffff88811ba99000 (Not tainted): Objects remaining on __kmem_cache_shutdown()
[ 3487.356078] -----------------------------------------------------------------------------
[ 3487.356078]
[ 3487.356738] Object 0xffff8881511c3440 @offset=13376
[ 3487.358464] Allocated in mempool_alloc_noprof+0x18c/0x290 age=1194 cpu=6 pid=22254
[ 3487.361197]  mempool_alloc_noprof+0x18c/0x290
[ 3487.361542]  smbdirect_connection_create_mem_pools+0x405/0x780
[ 3487.361972]  smbdirect_accept_connect_request+0x5a8/0x1b80
[ 3487.362359]  smbdirect_listen_rdma_event_handler+0x1579/0x1b90
[ 3487.362779]  cma_cm_event_handler+0x9c/0x230
[ 3487.363096]  cma_ib_req_handler+0x2682/0x45d0
[ 3487.363414]  cm_process_work+0x56/0x3d0
[ 3487.363676]  cm_work_handler+0x8a0e/0xd000
[ 3487.367496]  process_scheduled_works+0xa07/0x13a0
[ 3487.367859]  worker_thread+0x7c9/0xc80
[ 3487.368148]  kthread+0x341/0x430
[ 3487.368407]  ret_from_fork+0x3a8/0x7a0
[ 3487.368704]  ret_from_fork_asm+0x1a/0x30
[ 3487.370307] Slab 0xffffea0005447000 objects=19 used=1 fp=0xffff8881511c0040 flags=0x100000000000240(workingset|head|node=0|zone=2)
[ 3487.372840] ------------[ cut here ]------------
[ 3487.373195] WARNING: mm/slub.c:1244 at __slab_err+0x1a/0x30, CPU#6: kworker/6:84/22254
[ 3487.373759] Modules linked in:
[ 3487.373993] CPU: 6 UID: 0 PID: 22254 Comm: kworker/6:84 Tainted: G    B               7.1.0-next-20260623+ #88 PREEMPT(lazy)
[ 3487.374778] Tainted: [B]=BAD_PAGE
[ 3487.377830] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3487.378515] Workqueue: ib_cm cm_work_handler
[ 3487.378820] RIP: 0010:__slab_err+0x1a/0x30
[ 3487.379129] Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 e8 36 00 00 00 bf 05 00 00 00 be 01 00 00 00 e8 f7 75 45 00 90 <0f> 0b 90 c3 cc cc cc cc cc 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
[ 3487.383255] RSP: 0018:ffff888220fc7050 EFLAGS: 00010093
[ 3487.383643] RAX: ffffffff8168e60a RBX: ffff88810955e640 RCX: ffff88821c381d80
[ 3487.384158] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffffffff870fa080
[ 3487.384662] RBP: ffff888220fc7068 R08: ffffffff870fa087 R09: 1ffffffff0e1f410
[ 3487.385192] R10: dffffc0000000000 R11: fffffbfff0e1f411 R12: ffffea0005447210
[ 3487.385674] R13: ffffea0005447000 R14: ffff888220fc7068 R15: ffff88812a8ab300
[ 3487.388932] FS:  0000000000000000(0000) GS:ffff888427e76000(0000) knlGS:0000000000000000
[ 3487.389529] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3487.389934] CR2: 00007ffcf2d84fd8 CR3: 0000000111d64006 CR4: 0000000000f72ef0
[ 3487.390440] PKRU: 55555554
[ 3487.390641] Call Trace:
[ 3487.390826]  <TASK>
[ 3487.391209]  __kmem_cache_shutdown+0x1aa/0x2b0
[ 3487.392062]  ? smbdirect_connection_destroy_mem_pools+0x239/0x300
[ 3487.393565]  kmem_cache_destroy+0x9d/0x180
[ 3487.398663]  smbdirect_connection_destroy_mem_pools+0x239/0x300
[ 3487.403534]  ? __pfx_smb_direct_logging_needed+0x10/0x10
[ 3487.407562]  smbdirect_accept_connect_request+0x95c/0x1b80
[ 3487.412391]  ? __pfx_smbdirect_accept_connect_request+0x10/0x10
[ 3487.416753]  ? do_raw_spin_lock+0x130/0x300
[ 3487.420623]  ? smbdirect_socket_set_initial_parameters+0x28b/0x6a0
[ 3487.424322]  ? lock_acquire+0x4c/0x270
[ 3487.424409] ksmbd: can't change a file to a directory
[ 3487.426321]  ? trace_irq_enable+0x36/0x120
[ 3487.429144]  smbdirect_listen_rdma_event_handler+0x1579/0x1b90
[ 3487.432606]  ? __pfx_smbdirect_listen_rdma_event_handler+0x10/0x10
[ 3487.433595]  ? trace_cm_event_handler+0x51/0x170
[ 3487.435183]  ? __pfx_smbdirect_listen_rdma_event_handler+0x10/0x10
[ 3487.435646]  ? cma_listen_handler+0xf6/0x150
[ 3487.435975]  cma_cm_event_handler+0x9c/0x230
[ 3487.436288]  cma_ib_req_handler+0x2682/0x45d0
[ 3487.439039]  ? __pfx_cma_ib_req_handler+0x10/0x10
[ 3487.439540]  ? __pfx_roce_resolve_route_from_path+0x10/0x10
[ 3487.439972]  ? stack_depot_save_flags+0x34/0x840
[ 3487.440374]  ? __xas_nomem+0xa9/0x410
[ 3487.443356]  ? xas_clear_mark+0x26c/0x4a0
[ 3487.443673]  cm_process_work+0x56/0x3d0
[ 3487.443969]  ? _raw_spin_unlock_irq+0x28/0x50
[ 3487.444317]  cm_work_handler+0x8a0e/0xd000
[ 3487.444624]  ? __pfx_cm_work_handler+0x10/0x10
[ 3487.444971]  ? pwq_dec_nr_in_flight+0xa73/0xdf0
[ 3487.445344]  ? __pfx_pwq_dec_nr_in_flight+0x10/0x10
[ 3487.445737]  ? lock_acquire+0x4c/0x270
[ 3487.448833]  ? process_scheduled_works+0x995/0x13a0
[ 3487.449230]  ? process_scheduled_works+0x995/0x13a0
[ 3487.449588]  process_scheduled_works+0xa07/0x13a0
[ 3487.449938]  ? __pfx_process_scheduled_works+0x10/0x10
[ 3487.450334]  ? do_raw_spin_lock+0x130/0x300
[ 3487.450639]  ? assign_work+0x3bb/0x5c0
[ 3487.450916]  worker_thread+0x7c9/0xc80
[ 3487.451211]  kthread+0x341/0x430
[ 3487.451453]  ? __pfx_worker_thread+0x10/0x10
[ 3487.451756]  ? __pfx_kthread+0x10/0x10
[ 3487.454814]  ret_from_fork+0x3a8/0x7a0
[ 3487.455114]  ? __pfx_ret_from_fork+0x10/0x10
[ 3487.455450]  ? __switch_to+0xb76/0x1110
[ 3487.455772]  ? __pfx_kthread+0x10/0x10
[ 3487.456081]  ret_from_fork_asm+0x1a/0x30
[ 3487.456384]  </TASK>
[ 3487.456549] irq event stamp: 0
[ 3487.456767] hardirqs last  enabled at (0): [<0000000000000000>] 0x0
[ 3487.460124] hardirqs last disabled at (0): [<ffffffff81684648>] copy_process+0xa08/0x3a10
[ 3487.460726] softirqs last  enabled at (0): [<ffffffff81684648>] copy_process+0xa08/0x3a10
[ 3487.461328] softirqs last disabled at (0): [<0000000000000000>] 0x0
[ 3487.461778] ---[ end trace 0000000000000000 ]---
[ 3487.543875] ksmbd: can't change a file to a directory
[ 3487.599675] ksmbd: can't change a file to a directory
[ 3487.626694] ksmbd: can't change a file to a directory
[ 3487.824687] ksmbd: can't change a file to a directory
[ 3487.871840] ksmbd: can't change a file to a directory
[ 3487.986207] ------------[ cut here ]------------
[ 3487.987157] kmem_cache_destroy smbdirect_recv_io_cache_ffff88811ba99000: Slab cache still has objects when called from smbdirect_connection_destroy_mem_pools+0x239/0x300
[ 3487.987183] WARNING: mm/slab_common.c:572 at kmem_cache_destroy+0x15c/0x180, CPU#6: kworker/6:84/22254
[ 3487.999821] Modules linked in:
[ 3488.001902] CPU: 6 UID: 0 PID: 22254 Comm: kworker/6:84 Tainted: G    B   W           7.1.0-next-20260623+ #88 PREEMPT(lazy)
[ 3488.008289] Tainted: [B]=BAD_PAGE, [W]=WARN
[ 3488.010459] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3488.014502] Workqueue: ib_cm cm_work_handler
[ 3488.017790] RIP: 0010:kmem_cache_destroy+0x16a/0x180
[ 3488.020662] Code: fd ff 48 8b 3d 2f c0 9c 06 48 89 de 5b 41 5e 5d e9 5b a3 0e 00 48 8d 3d a4 07 12 04 48 8b 53 58 48 c7 c6 91 9d 3e 85 4c 89 f1 <67> 48 0f b9 3a e9 33 ff ff ff 66 66 66 2e 0f 1f 84 00 00 00 00 00
[ 3488.028077] RSP: 0018:ffff888220fc70b8 EFLAGS: 00010202
[ 3488.032038] RAX: 0000000000000001 RBX: ffff88810955e640 RCX: ffffffff822bc079
[ 3488.035742] RDX: ffff88812404ec40 RSI: ffffffff853e9d91 RDI: ffffffff85f7ac50
[ 3488.037830] RBP: 0000000000000001 R08: ffff8883aef3e843 R09: 1ffff11075de7d08
[ 3488.041076] R10: dffffc0000000000 R11: ffffed1075de7d09 R12: 1ffff11024fa6c3c
[ 3488.045376] R13: ffff888127d361e8 R14: ffffffff822bc079 R15: ffff88811ba99538
[ 3488.049073] FS:  0000000000000000(0000) GS:ffff888427e76000(0000) knlGS:0000000000000000
[ 3488.052515] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3488.054934] CR2: 00007ffcf2d84fd8 CR3: 0000000111d64006 CR4: 0000000000f72ef0
[ 3488.058529] PKRU: 55555554
[ 3488.060542] Call Trace:
[ 3488.061595]  <TASK>
[ 3488.062006]  smbdirect_connection_destroy_mem_pools+0x239/0x300
[ 3488.066041]  ? __pfx_smb_direct_logging_needed+0x10/0x10
[ 3488.068620]  smbdirect_accept_connect_request+0x95c/0x1b80
[ 3488.071594]  ? __pfx_smbdirect_accept_connect_request+0x10/0x10
[ 3488.073218] ksmbd: not allow base filename in rename
[ 3488.074751]  ? do_raw_spin_lock+0x130/0x300
[ 3488.076792] ksmbd: can't change a file to a directory
[ 3488.077942]  ? smbdirect_socket_set_initial_parameters+0x28b/0x6a0
[ 3488.080143]  ? lock_acquire+0x4c/0x270
[ 3488.080747]  ? trace_irq_enable+0x36/0x120
[ 3488.081400]  smbdirect_listen_rdma_event_handler+0x1579/0x1b90
[ 3488.085089]  ? __pfx_smbdirect_listen_rdma_event_handler+0x10/0x10
[ 3488.089333]  ? trace_cm_event_handler+0x51/0x170
[ 3488.092637]  ? __pfx_smbdirect_listen_rdma_event_handler+0x10/0x10
[ 3488.095741]  ? cma_listen_handler+0xf6/0x150
[ 3488.099638]  cma_cm_event_handler+0x9c/0x230
[ 3488.101552]  cma_ib_req_handler+0x2682/0x45d0
[ 3488.104571]  ? __pfx_cma_ib_req_handler+0x10/0x10
[ 3488.106790]  ? __pfx_roce_resolve_route_from_path+0x10/0x10
[ 3488.109799]  ? stack_depot_save_flags+0x34/0x840
[ 3488.112174]  ? __xas_nomem+0xa9/0x410
[ 3488.114217]  ? xas_clear_mark+0x26c/0x4a0
[ 3488.116854]  cm_process_work+0x56/0x3d0
[ 3488.118179]  ? _raw_spin_unlock_irq+0x28/0x50
[ 3488.120034]  cm_work_handler+0x8a0e/0xd000
[ 3488.121677]  ? __pfx_cm_work_handler+0x10/0x10
[ 3488.123682]  ? pwq_dec_nr_in_flight+0xa73/0xdf0
[ 3488.126928]  ? __pfx_pwq_dec_nr_in_flight+0x10/0x10
[ 3488.129390]  ? lock_acquire+0x4c/0x270
[ 3488.131432]  ? process_scheduled_works+0x995/0x13a0
[ 3488.132694] ksmbd: can't change a file to a directory
[ 3488.136702]  ? process_scheduled_works+0x995/0x13a0
[ 3488.140060]  process_scheduled_works+0xa07/0x13a0
[ 3488.143379]  ? __pfx_process_scheduled_works+0x10/0x10
[ 3488.147221]  ? do_raw_spin_lock+0x130/0x300
[ 3488.150790]  ? assign_work+0x3bb/0x5c0
[ 3488.154259]  worker_thread+0x7c9/0xc80
[ 3488.155730]  kthread+0x341/0x430
[ 3488.158309]  ? __pfx_worker_thread+0x10/0x10
[ 3488.160865]  ? __pfx_kthread+0x10/0x10
[ 3488.164384]  ret_from_fork+0x3a8/0x7a0
[ 3488.167020]  ? __pfx_ret_from_fork+0x10/0x10
[ 3488.170050]  ? __switch_to+0xb76/0x1110
[ 3488.171809]  ? __pfx_kthread+0x10/0x10
[ 3488.174955]  ret_from_fork_asm+0x1a/0x30
[ 3488.175605]  </TASK>
[ 3488.176206] irq event stamp: 0
[ 3488.179360] hardirqs last  enabled at (0): [<0000000000000000>] 0x0
[ 3488.186521] hardirqs last disabled at (0): [<ffffffff81684648>] copy_process+0xa08/0x3a10
[ 3488.191889] softirqs last  enabled at (0): [<ffffffff81684648>] copy_process+0xa08/0x3a10
[ 3488.196853] softirqs last disabled at (0): [<0000000000000000>] 0x0
[ 3488.200870] ---[ end trace 0000000000000000 ]---

Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.

[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow

Fixes: eb3ed1e904 ("smb: smbdirect: introduce smbdirect_accept_connect_request()")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Acked-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:51 +09:00
Yunseong Kim
fe2c0cacbc smb: smbdirect: free completion queues with ib_free_cq()
smbdirect_connection_destroy_qp() creates the send and receive completion
queues with ib_alloc_cq_any(), which for IB_POLL_WORKQUEUE arms an
internal completion handler that runs ib_cq_poll_work() on a workqueue.
Tearing those CQs down with ib_destroy_cq() frees them without first
cancelling that poll work.

If the provider posts a completion late -- for example Soft-RoCE (rxe)
posting an RNR error from rxe_receiver() after rdma_destroy_qp() -- the
handler re-queues ib_cq_poll_work() on the already-freed CQ, and a
follow-on access faults in rxe_req_notify_cq().

Use ib_free_cq(), which cancel_work_sync()es the poll work before freeing
the CQ, so no completion handler can run against a freed queue.

[ 1236.599526] ==================================================================
[ 1236.602142] BUG: KASAN: slab-use-after-free in ib_cq_poll_work+0xd0/0x1a0
[ 1236.605524] Read of size 8 at addr ffff888111865800 by task kworker/4:1H/82
[ 1236.609017]
[ 1236.609270] CPU: 4 UID: 0 PID: 82 Comm: kworker/4:1H Not tainted 7.2.0-rc3-next-20260717-virtme #110 PREEMPT(lazy)
[ 1236.609287] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 1236.609498] Workqueue: ib-comp-wq ib_cq_poll_work
[ 1236.609525] Call Trace:
[ 1236.609536]  <TASK>
[ 1236.609545]  __dump_stack+0x21/0x60
[ 1236.609562]  dump_stack_lvl+0xc2/0x100
[ 1236.609573]  print_address_description+0x77/0x200
[ 1236.609587]  ? ib_cq_poll_work+0xd0/0x1a0
[ 1236.609597]  print_report+0x58/0x70
[ 1236.609607]  kasan_report+0x117/0x150
[ 1236.609623]  ? ib_cq_poll_work+0xd0/0x1a0
[ 1236.609636]  ? process_scheduled_works+0x954/0x1600
[ 1236.609650]  ib_cq_poll_work+0xd0/0x1a0
[ 1236.609662]  ? process_scheduled_works+0x954/0x1600
[ 1236.609674]  process_scheduled_works+0xc22/0x1600
[ 1236.609698]  ? __pfx_process_scheduled_works+0x10/0x10
[ 1236.609713]  ? __pfx_assign_work+0x10/0x10
[ 1236.609726]  ? lock_is_held_type+0x7b/0x110
[ 1236.609741]  worker_thread+0x975/0xee0
[ 1236.609757]  ? __pfx_do_raw_spin_lock+0x10/0x10
[ 1236.609775]  ? __kthread_parkme+0x21e/0x260
[ 1236.609789]  kthread+0x3a6/0x490
[ 1236.609800]  ? __pfx_worker_thread+0x10/0x10
[ 1236.609809]  ? __pfx_kthread+0x10/0x10
[ 1236.609820]  ret_from_fork+0x55a/0xa20
[ 1236.609835]  ? __pfx_ret_from_fork+0x10/0x10
[ 1236.609850]  ? __pfx_kthread+0x10/0x10
[ 1236.609861]  ret_from_fork_asm+0x1a/0x30
[ 1236.609880]  </TASK>
[ 1236.609886]
[ 1236.661292] Allocated by task 5076:
[ 1236.662640]  kasan_save_track+0x3e/0x80
[ 1236.663842]  __kasan_kmalloc+0x72/0x90
[ 1236.664763]  __kmalloc_noprof+0x2b0/0x5d0
[ 1236.665356]  __ib_alloc_cq+0x284/0x1000
[ 1236.666573]  __ib_alloc_cq_any+0x23e/0x340
[ 1236.668654]  smbdirect_connection_create_qp+0x6f7/0x1070
[ 1236.669757]  smbdirect_accept_connect_request+0x500/0x1ca0
[ 1236.672625]  smbdirect_listen_rdma_event_handler+0x1655/0x1c50
[ 1236.673930]  cma_listen_handler+0x1bf/0x260
[ 1236.674923]  cma_cm_event_handler+0x128/0x380
[ 1236.676926]  cma_ib_req_handler+0x2d3d/0x4de0
[ 1236.678368]  cm_process_work+0xb0/0x530
[ 1236.680454]  cm_queue_work_unlock+0xb1/0x230
[ 1236.681673]  cm_work_handler+0x969f/0xdca0
[ 1236.682704]  process_scheduled_works+0xc22/0x1600
[ 1236.683447]  worker_thread+0x975/0xee0
[ 1236.685901]  kthread+0x3a6/0x490
[ 1236.688164]  ret_from_fork+0x55a/0xa20
[ 1236.689522]  ret_from_fork_asm+0x1a/0x30
[ 1236.690073]
[ 1236.690378] Freed by task 5137:
[ 1236.692242]  kasan_save_track+0x3e/0x80
[ 1236.694272]  kasan_save_free_info+0x40/0x50
[ 1236.695514]  __kasan_slab_free+0x3a/0x60
[ 1236.696773]  kfree+0x14e/0x4e0
[ 1236.697216]  ib_destroy_cq_user+0x18d/0x250
[ 1236.699817]  smbdirect_connection_destroy_qp+0xf2/0x280
[ 1236.702115]  smbdirect_socket_destroy_sync+0x1607/0x2720
[ 1236.704062]  smbdirect_socket_release+0x140/0x280
[ 1236.705286]  smb_direct_free_transport+0x3b/0x90
[ 1236.707241]  __ksmbd_conn_release_work+0x99/0xf0
[ 1236.709287]  process_scheduled_works+0xc22/0x1600
[ 1236.710763]  worker_thread+0x975/0xee0
[ 1236.711262]  kthread+0x3a6/0x490
[ 1236.711720]  ret_from_fork+0x55a/0xa20
[ 1236.712232]  ret_from_fork_asm+0x1a/0x30
[ 1236.712762]
[ 1236.712992] Last potentially related work creation:
[ 1236.715157]  kasan_save_stack+0x3e/0x60
[ 1236.716993]  kasan_record_aux_stack+0x99/0xb0
[ 1236.718864]  insert_work+0xb2/0x4a0
[ 1236.720916]  __queue_work+0xebb/0x1260
[ 1236.722397]  queue_work_on+0x23b/0x350
[ 1236.723809]  ib_cq_completion_workqueue+0xac/0x160
[ 1236.724895]  rxe_cq_post+0x433/0x7c0
[ 1236.726273]  rxe_receiver+0xa41/0xd0d0
[ 1236.727754]  do_work+0x272/0x860
[ 1236.728896]  process_scheduled_works+0xc22/0x1600
[ 1236.730026]  worker_thread+0x975/0xee0
[ 1236.731499]  kthread+0x3a6/0x490
[ 1236.732132]  ret_from_fork+0x55a/0xa20
[ 1236.733171]  ret_from_fork_asm+0x1a/0x30
[ 1236.734224]
[ 1236.734871] Second to last potentially related work creation:
[ 1236.736001]  kasan_save_stack+0x3e/0x60
[ 1236.737161]  kasan_record_aux_stack+0x99/0xb0
[ 1236.739074]  insert_work+0xb2/0x4a0
[ 1236.740414]  __queue_work+0xebb/0x1260
[ 1236.740932]  queue_work_on+0x23b/0x350
[ 1236.741849]  ib_cq_completion_workqueue+0xac/0x160
[ 1236.744099]  rxe_cq_post+0x433/0x7c0
[ 1236.745514]  rxe_receiver+0xa41/0xd0d0
[ 1236.746091]  do_work+0x272/0x860
[ 1236.747187]  process_scheduled_works+0xc22/0x1600
[ 1236.749060]  worker_thread+0x975/0xee0
[ 1236.750224]  kthread+0x3a6/0x490
[ 1236.751480]  ret_from_fork+0x55a/0xa20
[ 1236.751989]  ret_from_fork_asm+0x1a/0x30
[ 1236.752974]
[ 1236.753627] The buggy address belongs to the object at ffff888111865800
[ 1236.753627]  which belongs to the cache kmalloc-1k of size 1024
[ 1236.757729] The buggy address is located 0 bytes inside of
[ 1236.757729]  freed 1024-byte region [ffff888111865800, ffff888111865c00)
[ 1236.760816]
[ 1236.761373] The buggy address belongs to the physical page:
[ 1236.762599] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x111860
[ 1236.764306] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 1236.765281] flags: 0x100000000000040(head|node=0|zone=2)
[ 1236.765979] page_type: f5(slab)
[ 1236.766410] raw: 0100000000000040 ffff8881000430c0 ffffea0004a7e210 ffffea0004586210
[ 1236.770418] raw: 0000000000000000 00000000000a000a 00000000f5000000 0000000000000000
[ 1236.775899] head: 0100000000000040 ffff8881000430c0 ffffea0004a7e210 ffffea0004586210
[ 1236.782823] head: 0000000000000000 00000000000a000a 00000000f5000000 0000000000000000
[ 1236.786239] head: 0100000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
[ 1236.790658] head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[ 1236.794132] page dumped because: kasan: bad access detected
[ 1236.798301]
[ 1236.799640] Memory state around the buggy address:
[ 1236.802028]  ffff888111865700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 1236.806254]  ffff888111865780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 1236.809036] >ffff888111865800: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 1236.813968]                    ^
[ 1236.816416]  ffff888111865880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 1236.819454]  ffff888111865900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 1236.823143] ==================================================================
[ 1236.830365] Disabling lock debugging due to kernel taint
[ 1236.831136] BUG: unable to handle page fault for address: ffffc90006dc8080
[ 1236.838157] #PF: supervisor read access in kernel mode
[ 1236.843686] #PF: error_code(0x0000) - not-present page
[ 1236.849393] PGD 100000067 P4D 100000067 PUD 100366067 PMD 12913e067 PTE 0
[ 1236.854156] Oops: Oops: 0000 [#1] SMP KASAN NOPTI
[ 1236.857893] CPU: 4 UID: 0 PID: 82 Comm: kworker/4:1H Tainted: G    B               7.2.0-rc3-next-20260717-virtme #110 PREEMPT(lazy)
[ 1236.860893] ksmbd: smb_direct: smbdirect_connection_recv_io_refill() failed -ECONNRESET
[ 1236.864209] Tainted: [B]=BAD_PAGE
[ 1236.864220] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 1236.864233] Workqueue: ib-comp-wq ib_cq_poll_work
[ 1236.878314] RIP: 0010:rxe_req_notify_cq+0x13a/0x350
[ 1236.881683] Code: 20 87 fd 4c 89 fe 48 ba 00 00 00 00 00 fc ff df 4c 8b 3e 49 83 ef 80 4c 89 f8 48 c1 e8 03 0f b6 04 10 84 c0 0f 85 9b 01 00 00 <45> 8b 2f 41 80 3c 16 00 74 18 49 89 f6 48 89 f7 e8 71 20 87 fd 4c
[ 1236.886819] ksmbd: smb_direct: smbdirect_connection_recv_io_refill() failed -ECONNRESET
[ 1236.890671] RSP: 0018:ffff88810222f920 EFLAGS: 00010046
[ 1236.890705] RAX: 0000000000000000 RBX: ffff88810222f920 RCX: ffffffff84c92863
[ 1236.901613] RDX: dffffc0000000000 RSI: ffff888120456d48 RDI: ffff888120456d48
[ 1236.903979] RBP: ffff88810222fa20 R08: 0000000000000003 R09: 0000000000000004
[ 1236.908958] R10: dffffc0000000000 R11: ffffed1020445f10 R12: ffff888120456d40
[ 1236.914473] R13: dffffc0000000000 R14: 1ffff1102408ada9 R15: ffffc90006dc8080
[ 1236.918946] FS:  0000000000000000(0000) GS:ffff88842600d000(0000) knlGS:0000000000000000
[ 1236.921600] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1236.925779] CR2: ffffc90006dc8080 CR3: 000000012b35f003 CR4: 0000000000f72ef0
[ 1236.926809] ksmbd: smb_direct: smbdirect_connection_recv_io_refill() failed -ECONNRESET
[ 1236.928302] PKRU: 55555554
[ 1236.928328] Call Trace:
[ 1236.928338]  <TASK>
[ 1236.928352]  ? ib_cq_poll_work+0xd0/0x1a0
[ 1236.928374]  ? __pfx_rxe_req_notify_cq+0x10/0x10
[ 1236.941601]  ? ib_cq_poll_work+0xd0/0x1a0
[ 1236.943306]  ib_cq_poll_work+0xfe/0x1a0
[ 1236.943961]  ? process_scheduled_works+0x954/0x1600
[ 1236.947036]  process_scheduled_works+0xc22/0x1600
[ 1236.951626]  ? __pfx_process_scheduled_works+0x10/0x10
[ 1236.954316]  ? __pfx_assign_work+0x10/0x10
[ 1236.958110]  ? lock_is_held_type+0x7b/0x110
[ 1236.960042]  worker_thread+0x975/0xee0
[ 1236.962668]  ? __pfx_do_raw_spin_lock+0x10/0x10
[ 1236.965334]  ? __kthread_parkme+0x21e/0x260
[ 1236.966058]  kthread+0x3a6/0x490
[ 1236.968115]  ? __pfx_worker_thread+0x10/0x10
[ 1236.971020]  ? __pfx_kthread+0x10/0x10
[ 1236.974488]  ret_from_fork+0x55a/0xa20
[ 1236.977419]  ? __pfx_ret_from_fork+0x10/0x10
[ 1236.979846]  ? __pfx_kthread+0x10/0x10
[ 1236.981238]  ret_from_fork_asm+0x1a/0x30
[ 1236.984086]  </TASK>
[ 1236.986181] Modules linked in:
[ 1236.989048] CR2: ffffc90006dc8080
[ 1236.990412] ---[ end trace 0000000000000000 ]---
[ 1236.994119] RIP: 0010:rxe_req_notify_cq+0x13a/0x350
[ 1236.998482] Code: 20 87 fd 4c 89 fe 48 ba 00 00 00 00 00 fc ff df 4c 8b 3e 49 83 ef 80 4c 89 f8 48 c1 e8 03 0f b6 04 10 84 c0 0f 85 9b 01 00 00 <45> 8b 2f 41 80 3c 16 00 74 18 49 89 f6 48 89 f7 e8 71 20 87 fd 4c
[ 1237.006635] RSP: 0018:ffff88810222f920 EFLAGS: 00010046
[ 1237.008513] RAX: 0000000000000000 RBX: ffff88810222f920 RCX: ffffffff84c92863
[ 1237.014100] RDX: dffffc0000000000 RSI: ffff888120456d48 RDI: ffff888120456d48
[ 1237.021058] RBP: ffff88810222fa20 R08: 0000000000000003 R09: 0000000000000004
[ 1237.024939] R10: dffffc0000000000 R11: ffffed1020445f10 R12: ffff888120456d40
[ 1237.030203] R13: dffffc0000000000 R14: 1ffff1102408ada9 R15: ffffc90006dc8080
[ 1237.034299] FS:  0000000000000000(0000) GS:ffff88842600d000(0000) knlGS:0000000000000000
[ 1237.037311] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1237.042838] CR2: ffffc90006dc8080 CR3: 000000012b35f003 CR4: 0000000000f72ef0

Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.

[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow

Fixes: 6073eb3e31 ("smb: smbdirect: introduce smbdirect_connection_{create,destroy}_qp()")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Acked-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:50 +09:00
Yunseong Kim
7405d0ba29 ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user()
ksmbd_alloc_user() copies resp->hash_sz bytes out of the mountd IPC
login response with

	user->passkey_sz = resp->hash_sz;
	user->passkey = kmalloc(resp->hash_sz, KSMBD_DEFAULT_GFP);
	if (user->passkey)
		memcpy(user->passkey, resp->hash, resp->hash_sz);

resp->hash_sz is a __u16 supplied by the response, but resp->hash[] is
only KSMBD_REQ_MAX_HASH_SZ bytes.  A malformed or malicious login
response can set hash_sz well beyond that (up to 65535), so the memcpy()
reads past the end of the response object.  ipc_validate_msg() does not
bound hash_sz, so reject any response whose hash_sz exceeds the on-stack
hash[] buffer before allocating and copying.

[ 2030.238706] BUG: KASAN: slab-out-of-bounds in ksmbd_alloc_user+0x278/0x680
[ 2030.240549] Read of size 65535 at addr ffff888121bb6680 by task kworker/4:1/18611
[ 2030.242296]
[ 2030.242710] CPU: 4 UID: 0 PID: 18611 Comm: kworker/4:1 Not tainted 7.1.0-next-20260623-virtme #96 PREEMPT(lazy)
[ 2030.242732] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 2030.242743] Workqueue: ksmbd-io handle_ksmbd_work
[ 2030.242763] Call Trace:
[ 2030.242769]  <TASK>
[ 2030.242776]  dump_stack_lvl+0xa2/0xd0
[ 2030.242794]  print_address_description+0x77/0x200
[ 2030.242815]  ? ksmbd_alloc_user+0x278/0x680
[ 2030.242831]  print_report+0x58/0x70
[ 2030.242848]  kasan_report+0x117/0x150
[ 2030.242869]  ? ksmbd_alloc_user+0x278/0x680
[ 2030.242888]  kasan_check_range+0x3c7/0x3f0
[ 2030.242908]  ? ksmbd_alloc_user+0x278/0x680
[ 2030.242925]  __asan_memcpy+0x29/0x70
[ 2030.242942]  ksmbd_alloc_user+0x278/0x680
[ 2030.242960]  ksmbd_login_user+0xc3/0x120
[ 2030.242978]  ntlm_authenticate+0x5e6/0x1b00
[ 2030.243017]  ? __pfx_ntlm_authenticate+0x10/0x10
[ 2030.243035]  ? ksmbd_session_lookup+0x188/0x1d0
[ 2030.243054]  ? __pfx_ksmbd_session_lookup+0x10/0x10
[ 2030.243090]  ? __sanitizer_cov_trace_switch+0x7b/0x140
[ 2030.243108]  smb2_sess_setup+0x1e4a/0x27b0
[ 2030.243126]  ? copy_from_kernel_nofault+0x199/0x300
[ 2030.243156]  ? __pfx_smb2_sess_setup+0x10/0x10
[ 2030.243173]  ? get_smb2_cmd_val+0xe3/0x1c0
[ 2030.243208]  handle_ksmbd_work+0x954/0x1280
[ 2030.243230]  ? __pfx_handle_ksmbd_work+0x10/0x10
[ 2030.243249]  ? process_scheduled_works+0xa07/0x1490
[ 2030.243270]  ? process_scheduled_works+0xa07/0x1490
[ 2030.243291]  process_scheduled_works+0xa70/0x1490
[ 2030.243320]  ? __pfx_process_scheduled_works+0x10/0x10
[ 2030.243340]  ? do_raw_spin_lock+0x130/0x300
[ 2030.243358]  ? lock_is_held_type+0x7b/0x110
[ 2030.243388]  worker_thread+0x932/0xe20
[ 2030.243415]  kthread+0x38a/0x470
[ 2030.243431]  ? __pfx_worker_thread+0x10/0x10
[ 2030.243451]  ? __pfx_kthread+0x10/0x10
[ 2030.243467]  ret_from_fork+0x484/0x910
[ 2030.243485]  ? __pfx_ret_from_fork+0x10/0x10
[ 2030.243501]  ? __switch_to+0xc77/0x12c0
[ 2030.243523]  ? __pfx_kthread+0x10/0x10
[ 2030.243540]  ret_from_fork_asm+0x1a/0x30
[ 2030.243564]  </TASK>
[ 2030.243570]
[ 2030.290164] Allocated by task 19279:
[ 2030.290911]  kasan_save_track+0x3e/0x80
[ 2030.292179]  __kasan_kmalloc+0x72/0x90
[ 2030.293217]  __kvmalloc_node_noprof+0x3ff/0x6b0
[ 2030.294467]  handle_generic_event+0x59b/0x750
[ 2030.295345]  genl_family_rcv_msg_doit+0x238/0x340
[ 2030.296553]  genl_rcv_msg+0x606/0x7b0
[ 2030.297129]  netlink_rcv_skb+0x22b/0x4a0
[ 2030.298500]  genl_rcv+0x2d/0x40
[ 2030.299273]  netlink_unicast+0x7ba/0x930
[ 2030.300019]  netlink_sendmsg+0x8c3/0xb00
[ 2030.301073]  __sock_sendmsg+0xec/0x140
[ 2030.301579]  __sys_sendto+0x357/0x470
[ 2030.302255]  __x64_sys_sendto+0xe3/0x100
[ 2030.303425]  do_syscall_64+0x135/0x460
[ 2030.304763]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 2030.305594]
[ 2030.305819] The buggy address belongs to the object at ffff888121bb6640
[ 2030.305819]  which belongs to the cache kmalloc-192 of size 192
[ 2030.309595] The buggy address is located 64 bytes inside of
[ 2030.309595]  allocated 166-byte region [ffff888121bb6640, ffff888121bb66e6)
[ 2030.312484]
[ 2030.312719] The buggy address belongs to the physical page:
[ 2030.314315] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x121bb6
[ 2030.316481] head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 2030.318248] flags: 0x100000000000040(head|node=0|zone=2)
[ 2030.319662] page_type: f5(slab)
[ 2030.320242] raw: 0100000000000040 ffff8881000424c0 ffffea00047c1510 ffff888100040468
[ 2030.321911] raw: 0000000000000000 0000000000150015 00000000f5000000 0000000000000000
[ 2030.324413] head: 0100000000000040 ffff8881000424c0 ffffea00047c1510 ffff888100040468
[ 2030.326150] head: 0000000000000000 0000000000150015 00000000f5000000 0000000000000000
[ 2030.327960] head: 0100000000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
[ 2030.329615] head: ffff888121bb7ab0 0000000000000000 00000000ffffffff 0000000000000000
[ 2030.331861] page dumped because: kasan: bad access detected
[ 2030.332946]
[ 2030.333502] Memory state around the buggy address:
[ 2030.334698]  ffff888121bb6580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 2030.336475]  ffff888121bb6600: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00
[ 2030.338143] >ffff888121bb6680: 00 00 00 00 00 00 00 00 00 00 00 00 06 fc fc fc
[ 2030.339116]                                                        ^
[ 2030.341315]  ffff888121bb6700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 2030.342801]  ffff888121bb6780: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
[ 2030.344643] ==================================================================

Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.

[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow

Fixes: e2f34481b2 ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:50 +09:00
Namjae Jeon
fd8c97d7c1 ksmbd: implement the command sequence window
ksmbd tracked only credit counts (total_credits/outstanding_credits) and
never validated the MessageId of an incoming request. As a result a
request carrying a MessageId outside the granted range was accepted, a
MessageId could be replayed, and a 64-bit sequence wrap was not detected.

Maintain a command sequence window per connection:

  - [seq_low, seq_high) is the range of granted sequence numbers and
    seq_bitmap records which of them have been granted but not yet
    consumed. The window starts as { 0 } at connection setup.
  - smb2_set_rsp_credits() extends seq_high by the number of credits it
    grants (setting the corresponding bits), capped so the window never
    spans more than KSMBD_CMD_SEQ_WINDOW (== SMB2_MAX_CREDITS) sequence
    numbers. This implements the "limit the range of acceptable
    sequence numbers" allowance and keeps seq_bitmap usable as a ring.
  - smb2_check_sequence_number(), run for every SMB2 request from
    ksmbd_smb2_check_message(), verifies that the CreditCharge
    consecutive sequence numbers starting at MessageId lie within the
    window and have not already been consumed, then removes them and
    slides seq_low forward. CANCEL consumes nothing. A violation
    (out of window, replay, or wrap) tears the connection down.

The legacy SMB1 multi-protocol negotiate occupies sequence number 0 but
does not pass through ksmbd_smb2_check_message(), so it consumes that
sequence number explicitly; otherwise seq_low would stay pinned at 0
after the upgrade to SMB2 and eventually stall credit grants.

For an in-order client seq_high - seq_low equals total_credits, so the
window-room cap never reduces the number of credits granted. it only
engages for a client that withholds low sequence numbers.
init_smb2_max_credits() now clamps the configured maximum to
SMB2_MAX_CREDITS so the window (and its bitmap) can always represent
every outstanding sequence number.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:50 +09:00
Gael Blivet
7b46161088 ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel response
release_async_work() zeroes work->async_id before the CANCELLED path
calls smb2_send_interim_resp(work, STATUS_CANCELLED), which reads
work->async_id to build the response's AsyncId field. The cancellation
response for a cancelled blocked-lock request is sent with AsyncId=0
instead of the id the client received in the original STATUS_PENDING
response for this request.

Checked against every other release_async_work() call site in this
file: smb2_read()/smb2_write() don't send a further async response
afterward (their status goes out on the synchronous path instead), and
smb2_notify()'s two async paths already transfer the id to a separate
struct before releasing, so this reordering is scoped to smb2_lock()
only.

Send the STATUS_CANCELLED response while work->async_id is still valid,
then release the async work afterward.

Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:50 +09:00
Gael Blivet
08f41323f5 ksmbd: fix maximal access leak when object has no NT ACL
smb2_open()'s maximal-access handling sets maximal_access to the
FILE_MAXIMAL_ACCESS_LE request sentinel, then calls
smb_check_perm_dacl() to compute the real access mask from the
object's DACL.

smb_check_perm_dacl() returns success without touching *pdaccess when
the object has no stored NT ACL xattr (ksmbd_vfs_get_sd_xattr() fails,
taking an early goto err_out with rc still 0). This leaves
maximal_access holding the raw FILE_MAXIMAL_ACCESS_LE sentinel instead
of a real access mask.

Observed live: a freshly-created share root shows macOS's "no entry"
(prohibited-access) badge on connect, even though POSIX permissions
clearly allow access -- macOS requests maximal access via the MxAc
create context on every share-root open, not via DesiredAccess, so it
trusts the leaked sentinel verbatim instead of falling through to the
correct POSIX-based path.

Fall back to ksmbd_vfs_query_maximal_access() -- the same POSIX-based
computation already used for the DesiredAccess-requested-maximal-access
case below -- whenever the sentinel comes back unmodified.

Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:49 +09:00
Namjae Jeon
eebdd3f115 ksmbd: do not advertise unimplemented CA support
ksmbd durable handles are currently in-memory state. There is no persistent
open recovery, cluster ownership epoch, fencing, or failover implementation
behind the continuous-availability share flag.

Do not advertise SMB2 persistent-handle or continuous-availability
capabilities until those guarantees exist. A client requesting DH2Q then
falls back to the existing durable V2 behavior rather than being promised a
persistent handle that cannot survive a server failure.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:49 +09:00
Namjae Jeon
d6bf101da7 ksmbd: fix durable V2 persistent handle handling
Correct the durable-handle V2 response context layout and use the V2
context size when chaining a following CREATE response context. Validate
the only defined DH2Q/DH2C flag, require the reconnect request type to
match the saved open type, and process the application instance identifier
before durable V2 state.

Persistent opens are durable opens as required by MS-SMB2. Permit the
durable reconnect path to rebind either type of disconnected open.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:49 +09:00
Namjae Jeon
bc2f3f3dd6 ksmbd: honor client signing-required in all modes
The SMB2 NEGOTIATE request's SMB2_NEGOTIATE_SIGNING_REQUIRED bit requires
the server to set Connection.ShouldSign. KSMBD represents that state with
conn->sign, but previously set it only when its signing configuration was
auto or disabled.

Set conn->sign whenever the client requires signing, independently of the
server's signing mode. Keep the mandatory server-mode handling unchanged.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:48 +09:00
Namjae Jeon
4c670ccd57 ksmbd: extend procfs server statistics
The server proc entry does not expose configured limits or enough outcome
data to distinguish protocol errors from transport stalls.

Report the server state, listener and signing configuration, connection
limits, timeout values, current client and open-file totals, IPC activity,
and durable scavenger state. Classify processed SMB2 response statuses by
NTSTATUS severity and provide counters for common error groups while
retaining the per-command counters.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17 15:00:48 +09:00