summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-08-17landlock: Decouple the per-denial logging decision from CONFIG_AUDITMickaël Salaün
Until now, whether a denial is logged was decided inside landlock_audit_denial(): a per-execution flag check (log_same_exec or log_new_exec, selected by the credential's domain_exec bitmask), preceded by a LANDLOCK_LOG_DISABLED early return in landlock_log_denial() for domains an ancestor fully quieted. Factor that decision into a single is_denial_logged() helper called once by landlock_log_denial(), and pass its result to landlock_audit_denial() as a "logged" boolean. A following commit passes the same boolean to the deny tracepoints, so audit and tracing share one decision that stays correct as new log state is added, and a tracepoints-only build (CONFIG_AUDIT=n) computes it identically. Computing the logged verdict once in the shared helper makes audit and tracing apply identical filtering, so they cannot report different logged= values for the same denial as log controls grow. Move the LANDLOCK_LOG_DISABLED gate out of landlock_log_denial() into the decision so num_denials counts every denial, including those a domain quiets. This was previously masked: the only reader of num_denials is the audit "domain deallocated" record, emitted only for domains that reached LANDLOCK_LOG_RECORDED; a fully quieted domain never records, so its undercount was never observable. A following commit adds a free_domain tracepoint that reports num_denials, which needs the full count. This is not a functional change for audit: the logged decision and the audit_enabled gate are preserved, so the emitted records are identical. Cc: Günther Noack <gnoack@google.com> Link: https://patch.msgid.link/20260811094338.288094-6-mic@digikod.net Reviewed-by: Tingmao Wang <m@maowtm.org> [mic: Update copyright] Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-08-17landlock: Split denial logging from audit into common frameworkMickaël Salaün
Tracepoint emission requires the denial framework (layer identification, request validation) without depending on CONFIG_AUDIT. Separate the denial logging infrastructure from the audit-specific code by introducing a common log framework. Create CONFIG_SECURITY_LANDLOCK_LOG, enabled by default when CONFIG_AUDIT is set; a following commit extends it to CONFIG_TRACEPOINTS when the first tracepoint consumer is added. Move the common framework (the request types, the layer identification and request validation, and the landlock_log_denial() and landlock_log_free_domain() entry points) into log.c and log.h, and keep the audit-specific record formatting in audit.c. log.o is built for CONFIG_SECURITY_LANDLOCK_LOG and audit.o for CONFIG_AUDIT, so the common framework is available to a tracepoints-only build. The entry points dispatch to no-op static inline audit stubs without CONFIG_AUDIT, so the call sites stay unconditional. Rename the former landlock_log_drop_domain() to landlock_log_free_domain() to match the landlock_free_domain tracepoint added in a following commit. landlock_log_denial() counts denials even without audit, so its declaration and no-op stub are guarded by CONFIG_SECURITY_LANDLOCK_LOG, not CONFIG_AUDIT; a CONFIG_AUDIT guard would expose the stub and clash with log.c's definition in a tracepoints-only build. Widen the ID allocation (id.o and the landlock_init_id() / landlock_get_id_range() declarations) and the log-state representation (the domain_exec and log_subdomains_off credential fields, the landlock_hierarchy log fields, and the code that maintains them) from CONFIG_AUDIT to CONFIG_SECURITY_LANDLOCK_LOG, so each field and its writer share one guard and are available to tracing without audit support. Widen the denial-path state that feeds the per-denial logging decision the same way, so the "logged" verdict is computed identically whether or not CONFIG_AUDIT is set. Widening fown_layer is what keeps the file-owner-signal path valid without audit: otherwise hook_file_send_sigiotask() would leave layer_plus_one at zero, tripping the is_valid_request() canary and dropping the LANDLOCK_SCOPE_SIGNAL denial from tracing. The ruleset-level quiet_masks stays on no CONFIG guard: it is builder state validated and stored from user input, kept available so LANDLOCK_ADD_RULE_QUIET flags are accepted and ignored, not rejected, when CONFIG_SECURITY_LANDLOCK_LOG is disabled. Cc: Günther Noack <gnoack@google.com> Link: https://patch.msgid.link/20260811094338.288094-5-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-08-17landlock: Split struct landlock_domain from struct landlock_rulesetMickaël Salaün
Switch all domain users to the new struct landlock_domain type introduced by a previous commit, eliminating the conflation between mutable rulesets and immutable domains. landlock_merge_ruleset() now returns and allocates a struct landlock_domain, and the merge and inherit helpers move next to it; the former static insert_rule() is exported as landlock_store_rule() for its new caller across the translation-unit boundary. The merge destination is now a private struct landlock_domain still under construction (owned by the calling thread, not yet shared), so the merge and inherit helpers lock only the source ruleset: the previous lock of both destination and source collapses to a single mutex_lock(&src->lock). Rename the per-layer access-mask field from access_masks to handled_masks, naming it by the role it plays (the rights each layer handles) rather than by its type, paralleling the struct access_masks quiet_masks field. Drop the now domain-only fields (hierarchy, work_free, num_layers) from struct landlock_ruleset. The new struct landlock_domain field in cred.h pulls in domain.h, which includes audit.h, which previously included cred.h, forming an include cycle. Break it by having audit.h forward-declare the struct landlock_cred_security and struct landlock_hierarchy it uses instead of including cred.h. Cc: Günther Noack <gnoack@google.com> Cc: Tingmao Wang <m@maowtm.org> Link: https://patch.msgid.link/20260811094338.288094-4-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-08-17landlock: Move domain query functions to domain.cMickaël Salaün
Grouping domain-specific code in one compilation unit reduces coupling between domain and ruleset implementations. Move the access-check functions that only operate on a domain (rule lookup, layer unmasking, layer-mask init, access-mask union) from ruleset.[ch] to domain.[ch]. They evaluate whether a domain grants a requested access during the pathwalk and network checks and do not modify the domain. The merge and inherit chain stays in ruleset.c for now because it calls the static create_ruleset() allocator; a following commit moves it once the domain type switch eliminates that dependency. No behavioral change. The functions move with unchanged signatures and bodies. Cc: Günther Noack <gnoack@google.com> Cc: Tingmao Wang <m@maowtm.org> Link: https://patch.msgid.link/20260811094338.288094-3-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-08-17landlock: Prepare ruleset and domain type splitMickaël Salaün
Rulesets and domains serve fundamentally different purposes: a ruleset is mutable and user-facing, created by landlock_create_ruleset(), while a domain is immutable after construction and enforced on tasks via landlock_restrict_self(). Today both are represented by struct landlock_ruleset, which conflates mutable and immutable state in a single type: the lock field is unused by domains, the hierarchy field is unused by rulesets, and lifecycle functions must handle both cases. Prepare for a clean type split by introducing two new structures: - struct landlock_rules: the red-black tree roots and rule count, shared by both rulesets and domains. Decoupling rule storage from the domain API lets the backing data structure change independently (e.g. to a hash table, cf. [1]). - struct landlock_domain: the immutable domain enforced on tasks, with no lock field because its rules and access masks are fixed once construction completes. The name reflects the role, not the internal data structure. Add the domain lifecycle helpers (landlock_get_domain(), landlock_put_domain(), landlock_put_domain_deferred()) and move domain.o from landlock-$(CONFIG_AUDIT) to landlock-y, because these are needed unconditionally, not just for audit logging. No behavioral change. The new types and lifecycle functions are not yet used by any caller. Cc: Günther Noack <gnoack@google.com> Link: https://patch.msgid.link/20250523165741.693976-1-mic@digikod.net [1] Link: https://patch.msgid.link/20260811094338.288094-2-mic@digikod.net Reviewed-by: Tingmao Wang <m@maowtm.org> [mic: Update copyright] Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-08-17erofs: guard on-disk algorithm IDs against Z_EROFS_COMPRESSION_MAXGao Xiang
All on-disk algorithm IDs should be validated against supported Z_EROFS_COMPRESSION_MAX. This includes a partial revert of a previous commit and also adds validation for encoded extents. Fixes: 131897c65e2b ("erofs: fix invalid algorithm for encoded extents") Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Gao Xiang <xiang@kernel.org>
2026-08-17erofs: fix interlaced ztailpacking pclustersGao Xiang
On-disk sizes of interlaced pclusters should be block-aligned, and ztailpacking interlaced pclusters should be invalid at all. Currently, mkfs.erofs won't generate any interlaced pcluster with ztailpacking enabled, so this doesn't affect any existing valid filesystems. However, crafted images can contain invalid interlaced ztailpacking pclusters, resulting in an out-of-bounds read from a kmap'd page and copying irrelevant kernel memory into userspace-visible page cache. Reported-by: Haiyang Huang <huanghaiyang83@gmail.com> Closes: https://lore.kernel.org/r/20260806065253.1083865-1-huanghaiyang83@gmail.com Fixes: fdffc091e6f9 ("erofs: support interlaced uncompressed data for compressed files") Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Gao Xiang <xiang@kernel.org>
2026-08-17bpf: Rewrite any fault prone load out of a mem or btf_id pointerDaniel Borkmann
bpf_convert_ctx_accesses() turns a BPF_LDX into a BPF_PROBE_MEM one by matching the type recorded for the insn against a list of exact pointer types. The list cannot keep up with the flag combinations the verifier produces, and a type which is missing from it ends up as a plain load without an exception table entry, so a bad address panics the kernel instead of being handled. Two such types exist today and are reachable: - PTR_TO_BTF_ID | PTR_UNTRUSTED | MEM_ALLOC | NON_OWN_REF - PTR_TO_BTF_ID | PTR_UNTRUSTED | MEM_RCU Rather than adding the two, just drop the list and state the property itself in the default case of the switch. This is a superset of what the list matched, the untrusted PTR_TO_MEM does not have to carry MEM_RDONLY for it anymore, and it stays in sync with the verifier side which uses the same match in save_aux_ptr_type() and reg_type_mismatch_ok(). Assert that a fault prone type which does not get the rewrite for whatever reason is rejected at load time rather than left to fault at runtime to catch any future cases. Fixes: 1b12171533a9 ("bpf: Mark direct ld of stashed bpf_{rb,list}_node as non-owning ref") Fixes: 6fcd486b3a0a ("bpf: Refactor RCU enforcement in the verifier.") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260814215301.709827-4-daniel@iogearbox.net
2026-08-17bpf: Reject a store through a fault prone pointerDaniel Borkmann
check_ptr_to_btf_access() allows the program to store before the default BTF access path gets to reject a non read access. ac65c710cc64 ("bpf: Reject writes through untrusted BTF pointers") closed that for a PTR_UNTRUSTED pointer, but a bare PTR_TO_BTF_ID may fault on a dereference just the same and is let through. A BPF_LDX gets the BPF_PROBE_MEM rewrite in bpf_convert_ctx_accesses() and a bad address is handled, but a BPF_STX does not and cannot, there is no probed store to rewrite. The store is emitted as a plain one without an exception table entry and a bad address panics the kernel. A bpf_qdisc program can reach this, bpf_qdisc_btf_struct_access() permits a write to Qdisc::limit and Qdisc::next_sched is a plain struct Qdisc pointer which the walk turns into the compat type: struct Qdisc *next = sch->next_sched; next->limit = 1000; BUG: kernel NULL pointer dereference, address: 0000000000000014 RIP: 0010:bpf_prog_c6e14e7f32c8e325_bpf_fifo_enqueue+0x3a/0x12b Code: [...] bf e8 03 00 00 <89> 7e 14 41 8b 7f 14 [...] Kernel panic - not syncing: Fatal exception in interrupt Fix by widen the check to bpf_may_fault_on_deref() so that it covers both. Fixes: 27ae7997a661 ("bpf: Introduce BPF_PROG_TYPE_STRUCT_OPS") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260814215301.709827-3-daniel@iogearbox.net
2026-08-17bpf: Treat a fault prone PTR_TO_MEM as a pointer type mismatchDaniel Borkmann
reg_type_mismatch_ok() enumerates the pointer types which must not silently share a BPF_LDX with a different one, since the type recorded for the insn drives a rewrite in bpf_convert_ctx_accesses(). f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()") added PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED as another type in need of one, namely the BPF_PROBE_MEM rewrite, but did not add it there. Fix it by adding the missing case to reg_type_mismatch_ok(), so that a PTR_TO_MEM which may fault on deref is not mismatch ok anymore. The triage in save_aux_ptr_type() then merges them. Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260814215301.709827-2-daniel@iogearbox.net
2026-08-17bpf: Keep fault protection when merging pointer typesDaniel Borkmann
When the same BPF_LDX instruction is reached through paths that yield different pointer types, save_aux_ptr_type() merges them into a single type which is later used by bpf_convert_ctx_accesses() to decide whether the load has to be rewritten into a BPF_PROBE_MEM one. Before f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()") the merge only accepted two PTR_TO_BTF_ID pointers and unconditionally fell back to PTR_TO_BTF_ID | PTR_UNTRUSTED, so the merged type was always one that gets the BPF_PROBE_MEM rewrite. However, the mentioned commit widened the merge to also cover a PTR_TO_MEM base and replaced the fallback by a union of the PTR_UNTRUSTED and MEM_RDONLY flags. A union of flags though cannot express the property the later rewrite is built upon, some examples: - PTR_TO_MEM merged with PTR_TO_BTF_ID | PTR_UNTRUSTED gets PTR_TO_MEM | PTR_UNTRUSTED but only the MEM_RDONLY variant is valid - PTR_TO_MEM merged with a plain PTR_TO_BTF_ID gets PTR_TO_MEM dropping the rewrite the latter type would have gotten - PTR_TO_MEM | MEM_RDONLY merged with a plain PTR_TO_BTF_ID gets PTR_TO_MEM | MEM_RDONLY which is not rewritten either since only its PTR_UNTRUSTED variant is In all three cases a program can take the unsafe path at runtime with a NULL or otherwise bad pointer and panic the kernel on the faulting load: BUG: kernel NULL pointer dereference, address: 0000000000000038 RIP: 0010:bpf_prog_77531a87032eeaf1_mixed_mem_btf_id_type+0x4b/0x65 Call Trace: <TASK> bpf_test_run+0x20b/0x460 bpf_prog_test_run_skb+0x650/0xbe0 __sys_bpf+0xb96/0x3140 __x64_sys_bpf+0x2c/0x40 do_syscall_64+0xba/0x590 Kernel panic - not syncing: Fatal exception in interrupt Note that the last two shapes have to be fixed right here, otherwise the merged type retains nothing which marks the load as fault prone, thus no rule in bpf_convert_ctx_accesses() can recover it. Fix it by normalizing the merged type instead. Reuse it in is_load_acq_unsafe() to avoid open coding, and trim the overly verbose comment which is more of an implementation detail of bpf_convert_ctx_accesses() anyway. Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260814215301.709827-1-daniel@iogearbox.net
2026-08-17ALSA: hda/tas2781: Add hardware stabilization delay during firmware load retriesZeliang Li
During runtime resume transitions, loading calibration data blocks to the tas2781 amplifier may intermittently trigger transmission failures or block checksum mismatches (-EAGAIN) due to un-stabilized power rails or I2C bus glitches. The loop in tasdev_load_blk() decrements block->nr_retry and attempts an immediate re-transmission upon receiving -EAGAIN. However, without any inter-retry delay, all available retry slots are exhausted within less than a microsecond—long before the hardware can physically settle. This leads to permanent "ERROR_PRAM_CRCCHK" deadlocks and silent speakers on modern laptops after resuming media. Fix this cleanly by introducing a 2ms usleep_range() delay directly inside the tasdev_load_blk() retry paths prior to each 'continue' statement. This grants the chip sufficient time to stabilize before the next transmission attempt without introducing unnecessary latency on final failures. Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com> Link: https://patch.msgid.link/20260815-master-v2-1-b4ea03c8b59e@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-17ALSA: hda/realtek: Fix mute LED for HP Victus 15-fa1xxx (MB 8C3F)Yashraj Ghule
The HP Victus 15-fa1xxx with motherboard 8C3F is missing the existing mute LED quirk for ALC245 codecs. Add the 103c:8c3f subsystem ID to the existing ALC245_FIXUP_HP_MUTE_LED_COEFBIT quirk. Tested on HP Victus 15-fa1xxx (MB 8C3F). The mute LED works as intended. Signed-off-by: Yashraj Ghule <yashrajghule.221@gmail.com> Link: https://patch.msgid.link/20260816110655.11592-1-yashrajghule.221@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-17ALSA: hda/realtek: Add micmute LED quirk for Acer Aspire A515-57Giulio Gualtierotti
The Acer Aspire A515-57 with subsystem ID 1025:1616 and Realtek ALC256 uses GPIO2 (0x04) for the microphone mute LED. Without a quirk, the GPIO mask and direction are not configured and the LED does not follow the microphone mute state. Reuse ALC256_FIXUP_ACER_SFG16_MICMUTE_LED, which configures GPIO2 as the microphone mute LED. Tested on an Acer Aspire A515-57 with ALC256 (10ec:0256, subsystem 1025:1616). GPIO mask and direction are 0x04 and GPIO data switches between 0x00 and 0x04; the LED device is registered and follows the microphone mute state. Signed-off-by: Giulio Gualtierotti <ggualtierotti.dev@mailbox.org> Link: https://patch.msgid.link/20260816094223.36617-1-ggualtierotti.dev@mailbox.org Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-17Merge branch 'for-next' into for-linusTakashi Iwai
2026-08-17auxdisplay: charlcd: cancel backlight work on registration failureHongyan Xu
With CONFIG_CHARLCD_BL_FLASH, charlcd_init() schedules bl_work before charlcd_register() calls misc_register(). If registration fails, the caller frees the charlcd object while delayed work still contains its address. Add charlcd_deinit() to cancel the delayed work and turn the backlight off. Use it for both registration rollback and normal unregistration. Fixes: 39f8ea46724e ("auxdisplay: charlcd: Extract character LCD core from misc/panel") Cc: stable@vger.kernel.org Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Hongyan Xu <getshell@seu.edu.cn> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2026-08-17exfat: replace truncate_lock with inode_lockChi Zhiling
Remove the per-inode truncate_lock and rely on inode_lock instead. exfat_setattr() truncates under inode_lock (held exclusively by the VFS callers), and exfat_aop_bmap() now takes inode_lock shared to exclude a concurrent truncate, providing the same mutual exclusion with a single lock. Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb/server: fix posix state check for directory renameChenXiaoSong
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: c841bd3d8dec ("ksmbd: deny renaming directory with open children") Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: exempt FSCTL_PIPE_TRANSCEIVE from the generic file-id lookupGael Blivet
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-17ksmbd: defer publishing granted locks to prevent UAF/double-free raceIlan Dudnik
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: e2f34481b24d ("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-17ksmbd: fix use-after-free in lease break notificationNamjae Jeon
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: 2145945feb2c ("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-17smb/server: preserve error status in smb2_handle_negotiate()ZhangGuoDong
smb2_handle_negotiate() records specific failures such as STATUS_INVALID_PARAMETER or STATUS_NOT_SUPPORTED. Fixes: e2b76ab8b5c9 ("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-17smb/server: call ksmbd_proc_cleanup() on module init failureZhangGuoDong
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: b38f99c1217a ("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-17smb/server: abort initialization when proc setup failsZhangGuoDong
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: b38f99c1217a ("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-17smb/server: fix invalid pointer dereference in ksmbd_stop_durable_scavenger()ZhangGuoDong
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: d484d621d40f ("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-17smb/server: fix memory leak in ksmbd_vfs_set_durable_owner()ZhangGuoDong
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-17smb/server: fix null-ptr-deref in ksmbd_ipc_tree_connect_request()ZhangGuoDong
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: e2f34481b24d ("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-17ksmbd: remove extra byte from ipc_msg_alloc() size calculationsRosen Penev
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-17ksmbd: reject blocking compound lock requestsNamjae Jeon
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-17ksmbd: safely discard unregistered deferred locksNamjae Jeon
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-17ksmbd: recognize replayed SMB2 lock sequencesNamjae Jeon
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-17ksmbd: fix SMB2 byte-range lock end offsetNamjae Jeon
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-17ksmbd: serialize oplock close with pending break ownershipNamjae Jeon
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: e2f34481b24d ("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-17smb/server: fix unbuffered file position alignment checkChenXiaoSong
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-17ksmbd: expire SMB sessions when Kerberos tickets expireNamjae Jeon
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-17ksmbd: stabilize allocation size after buffered writesNamjae Jeon
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-17ksmbd: report holes in allocated range queriesNamjae Jeon
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-17ksmbd: only rebind the reopened file's own oplock on durable reconnectAldo Ariel Panzardo
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: f363a0fb134a ("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-17ksmbd: free preauth sessions on connection teardownNamjae Jeon
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: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb/server: avoid registering async requests during connection closeChenXiaoSong
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-17smb/server: cancel async requests when closing connectionChenXiaoSong
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-17smb/server: fix signing when a response uses more than one iovChenXiaoSong
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-17ksmbd: validate ipc response length before dereferencing its fieldsYunseong Kim
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: d6a6aa81eac2 ("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-17smb: smbdirect: release pending child sockets outside the handler lockYunseong Kim
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: dc691b91ad16 ("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-17smb: smbdirect: avoid recursive listen.lock during cleanupYunseong Kim
__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: dc691b91ad16 ("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-17smb: smbdirect: destroy QP before mem pools on accept failureYunseong Kim
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: eb3ed1e9048c ("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-17smb: smbdirect: free completion queues with ib_free_cq()Yunseong Kim
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: 6073eb3e3175 ("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-17ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user()Yunseong Kim
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: e2f34481b24d ("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-17ksmbd: implement the command sequence windowNamjae Jeon
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-17ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel responseGael Blivet
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>