summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
6 daysksmbd: limit sessions on each connectionNamjae Jeon
The pending setup limit only counts InProgress sessions. A client can complete authentication repeatedly and retain an unbounded number of Valid sessions on one connection. Reserve a connection slot before allocating a session and retain a connection reference while authentication is in progress. The first SMB3 channel takes over that reservation; binding to another connection reserves one slot there. Reauthentication and authentication continuation reuse the existing reservation. Return slots on allocation or insertion failure, channel removal, and final session destruction. Accept max_sessions_per_connection in reserved startup-request space and default to 64 when older tools leave it zero. Keep the request size and existing field offsets unchanged. Expose the configured limit in procfs. The existing connection limits bound the aggregate number of sessions without a separate global session allocation limit. Fixes: d7fd1f98607f ("ksmbd: follow SMB2 session expiration semantics") Cc: stable@vger.kernel.org Reported-by: Abdifatah Suruur <suruurism@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: hold a connection reference for each session channelNamjae Jeon
ksmbd_session_unregister() removes a session from the global and per- connection tables before dropping the table reference. A concurrent reference holder can keep the session and its channel list alive after those removals. Connection cleanup can no longer find the unpublished session to remove its channels. Since a channel only stores a raw conn pointer, the connection can be freed while another session reference holder is still accessing it, for example during SMB3.1.1 binding or a procfs read. Take a connection reference when registering a channel and release it on insertion failure, channel removal, or final session destruction. Keep the channels and signing keys until the session is destroyed so a response can still be signed after the session has been unregistered. Fixes: d7fd1f98607f ("ksmbd: follow SMB2 session expiration semantics") Cc: stable@vger.kernel.org Reported-by: Abdifatah Suruur <suruurism@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: defer connection scavenging while session locks are busyNamjae Jeon
The expiration worker holds conn_list_lock for reading while checking for authenticated sessions. Without this change, the check can wait for conn->session_lock or sessions_table_lock. In destroy_previous_session(), the status updates after ksmbd_conn_wait_idle_sess() run with both session locks held for writing. Both the KSMBD_SESS_GOOD error path and the KSMBD_SESS_NEED_SETUP success path call ksmbd_all_conn_set_status(), which takes conn_list_lock for reading. A writer queued on conn_list_lock can block these new read acquisitions. The worker then waits for a session lock held by destroy_previous_session(), which waits behind the writer. The writer cannot proceed until the worker releases conn_list_lock. Try both session locks instead of waiting in the scavenging check. Keep the connection when either lock is busy and let the periodic worker retry later. Fixes: d7fd1f98607f ("ksmbd: follow SMB2 session expiration semantics") Cc: stable@vger.kernel.org Reported-by: Abdifatah Suruur <suruurism@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: accept share config responses from ksmbd-tools before 3.5.3Michail Andreas Michalopoulos
ksmbd-tools releases before 3.5.2 do not have the payload_sz field in struct ksmbd_share_config_response; the field occupies the last word of their reserved[] area, so the kernel always sees payload_sz == 0 from them. ipc_validate_msg() and share_config_request() used to treat payload_sz == 0 as "legacy userspace" and skip the payload size checks. That case was removed by commit f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses"). With payload_sz == 0: - the IPC$ (pipe) response fails the final message size comparison: these tools always send a one-byte payload, so msg_sz is sizeof(*resp) + 1, but the expected size is now computed as sizeof(*resp) + 0; - every other share fails "payload_sz <= veto_list_sz". In addition, ksmbd-tools before 3.5.3 copy a global "veto files" setting into the IPC$ response, so with such a configuration IPC$ also fails the now unconditional "veto_list_sz > payload_sz" check, even though pipe shares never use a veto list. ksmbd_ipc_share_config_request() then returns NULL and every tree connect fails with STATUS_BAD_NETWORK_NAME, so ksmbd cannot serve any share when used with these ksmbd-tools releases, for example the 3.5.1 package shipped by Ubuntu 24.04. Login still works, which makes the failure look like a configuration problem: CIFS: VFS: BAD_NETWORK_NAME: \\127.0.0.1\IPC$ CIFS: VFS: \\127.0.0.1 failed to connect to IPC (rc=-2) When payload_sz is zero, derive it from the size of the message actually received and store it back in the response, so that the checks in ipc_validate_msg() and the path and veto list parsing in share_config_request() all use the same bound. The response is the kernel's own copy made by handle_response(), and msg_sz has already been checked to be at least sizeof(*resp), so this cannot underflow. All checks added by that commit then apply unchanged, bounded by the bytes that really arrived, and newer ksmbd-tools that fill in payload_sz are unaffected. Also skip the veto list size check for pipe shares: share_config_request() reads neither the path nor the veto list for them. Tested in QEMU with ksmbd-tools 3.5.1 and 3.5.7 and the in-kernel SMB client over loopback, with and without a global "veto files" setting. Fixes: f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Michail Andreas Michalopoulos <mike.michalo@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: round SetAllocation to the advertised allocation unitDaeMyung Kang
SetAllocation rounds requests to 512-byte blocks, although FS_SIZE_INFORMATION advertises the filesystem's f_bsize as its allocation unit. For example, on a filesystem with a 4 KiB unit, a 1000-byte request can truncate an 8 KiB file to 1024 bytes instead of 4 KiB. Round the request to the advertised unit and use the same result for the block-count decision, fallocate, truncate, and the size stored on the open handle. Validate the unit and rounded size before either operation. Use DIV_ROUND_UP_ULL() so the calculation works on 32-bit kernels. This does not change the existing block-count decision for whether to call fallocate. In particular, success does not yet guarantee reservation of holes within the requested range on a sparse file. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: avoid restoring only in-memory EOF after allocation changeDaeMyung Kang
When SetAllocation requests a size below the allocated block count but above EOF, ksmbd truncates the file to that size and restores only the in-memory i_size. The larger EOF remains on disk and reappears after a reboot. A 3-byte file preallocated to 64 KiB can acquire a 4 KiB EOF after reducing its allocation to 4 KiB. Extending EOF this way is not a reliable way to reclaim the preallocation beyond the old EOF either. Only use this truncate path when the requested allocation is at or below the observed EOF. A truncate to the existing EOF still lets filesystems release preallocated blocks beyond EOF. Remove the in-memory-only i_size restoration. The size check still precedes vfs_truncate() taking the inode lock, so a concurrent shrink can make the truncate extend EOF; that race also existed in the original path. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: inherit FileIds in related compound requestsNamjae Jeon
MS-SMB2 specifies that subsequent related operations use the FileId from the preceding operation. Track FileIds from handle-bearing requests so related requests that use the all-ones placeholder resolve to the inherited handle. Return STATUS_INVALID_HANDLE when a related request refers to a FileId but the preceding operation neither contained nor generated one. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Reported-by: Ronnie Sahlberg <ronniesahlberg@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: reserve space for the UTF-16 terminator in stream infoAbdifatah Suruur
smb_strtoUTF16() always writes a terminating zero UTF-16 unit after the converted characters, but get_file_stream_info() budgets only sizeof(struct smb2_file_stream_info) + streamlen * 2 for a stream entry and sizeof(struct smb2_file_stream_info) + 7 * 2 for the trailing "::$DATA" entry. When an entry exactly fills the 448-byte small response buffer, the terminator is written two bytes past the allocation. Reserve one extra UTF-16 unit in both budget checks. The terminator is not part of the wire format, so the reported lengths are unchanged. Cc: stable@vger.kernel.org Signed-off-by: Abdifatah Suruur <suruurism@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: reject FSCTL_SET_ZERO_DATA on a directory handleLee Seong Hyeon
An authenticated client with a writable tree connection can open a directory with FILE_WRITE_DATA and send FSCTL_SET_ZERO_DATA on that handle. The handler only checks fp->daccess & FILE_WRITE_DATA_LE, but on a directory FILE_WRITE_DATA is the legitimate add-file right, so the check passes. ksmbd_vfs_zero_data() then calls kernel_write() on the directory file, which has no FMODE_WRITE, and __kernel_write_iter() hits WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE)), panicking a panic_on_warn kernel. Before commit 25e414db7033 ("ksmbd: report holes in allocated range queries") the dense-file path used vfs_fallocate(), which rejects directories with -EISDIR. The kernel_write() loop that replaced it has no such check. Reject a directory handle in ksmbd_vfs_zero_data() before writing, as ksmbd_vfs_write() already does for SMB2_WRITE. WARNING: fs/read_write.c:608 at __kernel_write_iter+0x74b/0x8c0 Workqueue: ksmbd-io handle_ksmbd_work Call Trace: kernel_write+0x1ef/0x4d0 ksmbd_vfs_zero_data+0x413/0x590 smb2_ioctl+0x21fa/0x66a0 handle_ksmbd_work+0x61b/0x1ff0 Fixes: 25e414db7033 ("ksmbd: report holes in allocated range queries") Signed-off-by: Lee Seong Hyeon <ihopenre@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: correct POSIX filesystem block size and response lengthNamjae Jeon
POSIX filesystem information uses f_bsize for BlockSize even when the filesystem reports a distinct fragment size for its block counts. Use f_frsize when available, falling back to f_bsize. Keep f_bsize as the optimal transfer size and derive the response length from the information structure instead of a hard-coded value. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: query POSIX filesystem info through the open fileNamjae Jeon
POSIX filesystem queries use the share root for statfs and do not validate the requested file handle. This can report the wrong filesystem for files below a mount point within the share. Require SMB3.1.1 POSIX extensions and a valid POSIX open. Resolve the requested handle, including compound file IDs, and use its referenced path for the filesystem query. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: require POSIX opens for file and directory queriesNamjae Jeon
POSIX file information queries only check the tree's extension flag, while directory queries do not verify that the directory was opened with a POSIX create context. Require SMB3.1.1, negotiated POSIX tree extensions and a POSIX open for both file and directory POSIX information requests. Return STATUS_INVALID_INFO_CLASS when these conditions are not met. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: include filenames in POSIX query infoNamjae Jeon
The POSIX file query response ends after the owner and group SIDs, omitting the filename length and filename. Append the path relative to the share in UTF-16, without a leading separator, and include its byte length in the response. Check both the fixed fields and the converted filename against the available output buffer before writing the response. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: correct POSIX file metadata in responsesNamjae Jeon
POSIX responses omit special permission bits, and the create response reports a file identifier as its reparse tag without encoding the file type. Directory and file queries also report rdev as the filesystem device identifier. Report the POSIX mode and file type in create responses, include special permission bits in all three response paths, and use the special-file reparse tag consistently. Set the corresponding DOS attribute in directory and file queries, report the filesystem device identifier and initialize reserved fields. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: apply POSIX mode ACEs in security updatesNamjae Jeon
Explicit modes carried by NFS mode ACEs can be overwritten by the DACL permission fallback, and security updates discard special mode bits. Track modes supplied by ACCESS_ALLOWED NFS mode ACEs and bypass the permission fallback for them. Apply both permission and special bits when setting an explicit POSIX mode. For SET_INFO, require a POSIX open for explicit mode changes and apply the mode only when DACL security information is requested. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: use requested mode in POSIX createsNamjae Jeon
The share mode helpers treat a requested POSIX mode of zero as an unspecified mode, replacing it with the share's default permissions. Use the requested mode, including zero, before applying the share masks and forced modes. Pass an explicit default-mode sentinel for non-POSIX creates to keep their existing mode selection. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: apply byte-range lock checks per openNamjae Jeon
Using the tree's POSIX extension flag to skip byte-range lock checks also skips them for ordinary opens on a POSIX-enabled tree. Base the read and write lock checks on each file's POSIX create context instead. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: enforce POSIX append-only writesNamjae Jeon
POSIX append-only opens do not set O_APPEND, and the SMB append sentinel is rejected as a negative write offset. Track append-only POSIX opens, set O_APPEND and require the U64_MAX offset sentinel for their writes. Accept FILE_WRITE_DATA or FILE_APPEND_DATA for WRITE requests, preserving ordinary SMB write permissions. Use the POSIX append flag and offset check to prevent POSIX append-only opens from overwriting existing data. For synchronous writes, derive the fsync range from the completed write position so append writes flush the range actually written. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: validate POSIX create contextsNamjae Jeon
POSIX create contexts are only examined when the tree has POSIX extensions enabled, and IPC requests bypass this validation. Examine POSIX contexts before selecting the IPC create path. Reject duplicate contexts and require an SMB3.1.1 connection, a POSIX-enabled tree and a non-IPC share for POSIX creates. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: validate POSIX negotiate contextsNamjae Jeon
The POSIX negotiate context currently enables extensions without checking its payload, and duplicate contexts are accepted. Reject duplicate contexts and invalid payload lengths. Enable POSIX extensions only for the published tag, and use the same tag constant when building the negotiate response. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: expire unacknowledged lease breaksNamjae Jeon
Arm a lease break acknowledgment timer once the common notification path accepts an ACK-required notification for transmission. Keep the deadline on the lease across channel retries and scan every lease in the global lease tables when the timer expires. Set timed-out leases and all their opens to NONE, then rearm for the next deadline. Serialize client acknowledgments, notification state and timer expiry under the lease lock, taking each open's state lock after it. Update every open before publishing break completion so a late acknowledgment cannot restore an expired lease. Wake blocked opens on timeout, send failure and global lease-table teardown, and cancel the timer at teardown. Keep the existing connection-independent lease-table lifetime and use the notifier's opinfo reference to retain the lease. Stop after selecting one open during lease-key lookup. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: expire unacknowledged oplock breaksNamjae Jeon
Arm the oplock break acknowledgment timer once the common notification path accepts a classic break for transmission. Preserve its shared retry deadline when another channel is tried. Store a deadline per open and scan the global open table when the earliest deadline expires. Drop expired breaks to NONE and restart the timer while other breaks remain. Serialize timer expiry with client acknowledgments and close using the oplock state lock. Wake blocked requests when a break expires or sending the notification fails, and invalidate durable reconnect for the open. Use wake_up_all() for acknowledgment, timeout, close and send failure. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: track SMB2 locks above OFFSET_MAX in server lock tableNamjae Jeon
SMB2 lock ranges use unsigned 64-bit offsets, but file_lock stores signed loff_t values. Track valid ranges above OFFSET_MAX in ksmbd's inode-based lock index and arbitrate conflicts there. Keep these offsets out of file_lock, and handle blocking requests, unlocks, rollback, close cleanup and cancellation in the SMB layer. Reserve large ranges under the index spinlock until the full request commits. Keep lookup and ownership independent of the connection so channel removal and hard-link opens use the same conflict checks. Finish large-range unlocks in the SMB layer after unlocking any VFS portion. Wake large-range lock waiters when normal locks are removed by unlock or close. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: rebind completed CREATE replays without draining the old channelNamjae Jeon
A completed DurableHandleReqV2 CREATE can be replayed through another channel while its original channel is exiting. The existing replay path returns the open but leaves its connection and oplock references pointing at the old channel. Its open count also stays on that channel, and a later CLOSE through the surviving channel decrements the wrong counter. After checking the owner, lease key and persistent flag, verify that an active open is still published in the requesting session's file table. Do this even when no oplock was granted, and before processing a consumed replay. Do not read a borrowed opinfo session pointer for this check. Keep a healthy original binding. If the original channel is exiting or releasing, move the open and its own oplock references to the requesting channel. Serialize this with CLOSE using the session file-table lock, and with detach, reconnect and notification snapshots using m_lock. The earlier lock index and lease-table changes make their lifetimes independent of this connection change. No old-channel r_count wait is needed, including when an unrelated request remains active there. Account final close against fp->conn in one place, balance durable detach and reconnect, and transfer the count with a replay binding change. A final global lookup put may run after CLOSE has removed the volatile id; unlink the open from the inode list on that final close as well. A live completed CREATE replay may follow a break that lowered the durable open's batch oplock. Apply the batch eligibility check only to detached reconnects, while retaining the owner, lease key and persistent flag checks for active replays. Fixes: bb8bf7eb13b5 ("ksmbd: add SMB3 request replay support") Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: index byte-range locks independently of their connectionNamjae Jeon
SMB locks belong to an open, but the lock conflict and UNLOCK scan only visits connections in conn_list. When a channel is removed, its locks remain attached to live opens and become invisible to another channel. An exact UNLOCK returns STATUS_RANGE_NOT_LOCKED, and zero-byte lock conflicts are no longer detected. A request finishing on the old channel after it is removed can publish another invisible lock. Index granted SMB locks by VFS inode, with the open's lock_list retaining ownership. Protect lookup, publication and removal with one spinlock. Use the inode rather than the dentry-based ksmbd_inode so hard-link opens still participate in the same conflict checks. Keep these entries through durable detach and reconnect. Publish a batch only after the existing LOCK handler commits it, and remove every entry before final close drops the file reference. Drop the per-lock connection references and connection-local lists; channel changes no longer require moving lock entries or waiting for unrelated requests to finish. Prefer an exclusive lock when several locks on an open match an UNLOCK. This preserves stacked zero-byte lock behavior despite the inode hash inserting newer locks before older entries. Fixes: d63528eb0d43 ("ksmbd: free ksmbd_lock when file is closed") Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: keep lease tables until their last lease is closedNamjae Jeon
Disconnecting one channel destroys the lease table for its ClientGuid, even when another channel still uses the same opens. A lease break ACK on the surviving channel can no longer find the lease. Detached durable opens also lose their lease lookup entries before reconnect or expiry. Tie a client table to its lease entries instead of the connection which created it. Remove the table when its last lease is removed, and release any remaining entries at server shutdown. Do not destroy client tables from connection teardown or keep a connection reference in each table. For a detached lease, collect break candidates using the table's ClientGuid directly. The existing notification retry path takes its own references on matching live connections. Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: retry break notifications on another connectionNamjae Jeon
An oplock or lease break belongs to an open that can outlive its original channel. A draining channel or stalled TCP writer can otherwise leave the break pending until timeout or invalidate a durable open. Snapshot the owner's live channels and try eligible connections with the same notification. Track TCP delivery separately from the SMB ACK, retry when a channel stops progressing, and share one break deadline. Run ordinary break waits on a dedicated workqueue so blocked request responses do not stall breaks. Publish NONE before sending a level II break, which requires no ACK, so an unsolicited ACK observes the completed level while TCP delivery is pending. Keep the first rename lease notification in the request context and enqueue the interim writer only after the notification is accepted. Join that work before returning so a blocked interim response does not stop notification retries or release the request early. Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: track delivery of queued TCP writesNamjae Jeon
A nonblocking break send must distinguish a PDU accepted by TCP from one still queued in ksmbd. Retrying an accepted PDU can send duplicates, while abandoning a partial send can corrupt the stream. Queue owned PDU bytes when TCP cannot accept the full message. Track the stream position through socket delivery and TCP ACK, and expose it to break retries. Bound retained data and stop queued writes during teardown. Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: serialize oplock break ACK state updatesNamjae Jeon
ACK handling updates lease or oplock levels and wakes break waiters. Without state_lock across validation and publication, timeout or break completion can observe a partially updated state. Serialize ACK validation and state changes under state_lock. Publish NONE after lease levels are updated, then wake waiters after unlocking. Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: release connection lock while draining old sessionNamjae Jeon
Previous-session teardown waits for requests on the old channels. Holding srv_mutex during that wait can block their responses and prevent the drain from completing. Record the previous session ID during authentication, finish using the request's authentication state, and release srv_mutex while the old session drains. Keep the response binding decision in the work item because signing and preauthentication hashing run after the drain. Reported-by: Pan Guihua <pan.guihua@datatom.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: validate security descriptor offsets before pointer arithmeticNamjae Jeon
parse_sec_desc() constructs SID and DACL pointers by adding untrusted 32-bit offsets to the security descriptor before checking their bounds. The existing checks reject offsets into the descriptor header, but do not reject offsets beyond the descriptor's length. On a 32-bit kernel, a large offset can wrap the pointer before the descriptor. The end-only checks in parse_sid() and parse_dacl() can then accept it, allowing an authenticated SMB2 SET_INFO request to access memory outside the security descriptor and fault the kernel. Check each nonzero offset against acl_len before constructing its pointer. Initialize the optional owner and group SID pointers to NULL so an omitted SID remains absent when parsing the DACL. Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") Cc: stable@vger.kernel.org Reported-by: Ratnaker Gautam <ratnaker.gautam@kuleuven.be> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 dayssmb: smbdirect: don't WARN on an unexpected receive opcodeStefan Metzmacher
The receive completion handlers smbdirect_connection_recv_io_done(), smbdirect_accept_negotiate_recv_done() and smbdirect_connect_negotiate_recv_done() verify that the completion is a regular receive with WARN_ON_ONCE(wc->opcode != IB_WC_RECV). But wc->opcode is controlled by the remote peer: a posted receive work request is consumed not only by an incoming SEND, but also by an RDMA Write with Immediate, which completes as IB_WC_RECV_RDMA_WITH_IMM. An unauthenticated peer can transmit such a message, even before the negotiate completes, so it reaches the accept/connect negotiate handlers as well. With panic_on_warn set this is a remote denial of service, and otherwise it still taints the kernel and spams the log for something a peer can trigger at will. The opcode check itself was inherited from the original client and server recv_done() handlers (fs/smb/client/smbdirect.c and fs/smb/server/transport_rdma.c), where an unexpected opcode was simply logged and the connection was torn down. Only the WARN_ON_ONCE() was added on top during the socketization rework. Drop the WARN_ON_ONCE() and keep the existing graceful error path, which logs the unexpected opcode (unless the status is IB_WC_WR_FLUSH_ERR) and tears the connection down. Fixes: ea4151222a93 ("smb: smbdirect: introduce smbdirect_connection_recv_io_done()") Fixes: eb3ed1e9048c ("smb: smbdirect: introduce smbdirect_accept_connect_request()") Fixes: d1f187656797 ("smb: smbdirect: introduce smbdirect_connect[_sync]()") Reported-by: Sashiko <sashiko-bot+sashiko@kernel.org> Closes: https://sashiko.dev/#/bug/linux-5341a0c0-7b00-4eef-915c-91e099649d3e Cc: Namjae Jeon <linkinjeon@kernel.org> Cc: Paulo Alcantara <pc@manguebit.org> Cc: Tom Talpey <tom@talpey.com> Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 dayssmb: smbdirect: don't hand out already failed sockets in ↵Stefan Metzmacher
smbdirect_socket_accept() A socket on the ready list is in SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, but it may fail before smbdirect_socket_accept() picks it up, e.g. RDMA_CM_EVENT_DISCONNECTED already moved it to SMBDIRECT_SOCKET_DISCONNECTED. smbdirect_socket_accept() unconditionally overwrote the status with SMBDIRECT_SOCKET_CONNECTED and handed out the already disconnected socket. smbdirect_socket_cleanup_work() then called rdma_disconnect() on it again, and before the recent commit smbdirect_socket_destroy_sync() waited forever for an RDMA_CM_EVENT_DISCONNECTED that already happened. Now we check first_error and change the status to SMBDIRECT_SOCKET_CONNECTED only via cmpxchg() from SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, while we still hold listen.lock. If the socket already failed, we move it to the orphaned list and queue purge_orphaned_work, like smbdirect_listen_orphan_socket() does, and try the next one. If we only found failed sockets, we wait for the next one. Fixes: dc691b91ad16 ("smb: smbdirect: introduce smbdirect_socket_{listen,accept}()") Reported-by: Sashiko <sashiko-bot+sashiko@kernel.org> Closes: https://sashiko.dev/#/patchset/cover.1791224972.git.metze%40samba.org Closes: https://sashiko.dev/#/bug/linux-f9dbca09-30a7-4145-9bdb-4676759982c8 Cc: Namjae Jeon <linkinjeon@kernel.org> Cc: Paulo Alcantara <pc@manguebit.org> Cc: Tom Talpey <tom@talpey.com> Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 dayssmb: smbdirect: release failed pending sockets of a listenerStefan Metzmacher
A child of a listener only left the listen.pending or listen.ready list via smbdirect_socket_accept() or when the listener was destroyed. So every connection that failed before it was accepted (negotiate timeout, peer disconnect, invalid negotiate request, ...) stayed on the list and counted against the backlog until the listener was destroyed. After about backlog (10 for ksmbd) such connections smbdirect_listen_connect_request() rejected every new connection with -EBUSY, so an unauthenticated peer was able to permanently stop ksmbd from accepting SMB-Direct connections. Now a failed child moves itself to a new listen.orphaned list at the end of smbdirect_socket_cleanup_work(), after the disconnect was started, and queues listen.purge_orphaned_work, which releases it with smbdirect_socket_release(), without holding the listener's rdma_lock_handler() lock, in the same way smbdirect_socket_destroy() does for the remaining children. Orphaned sockets still count against the backlog until they are released. sc->accept.listener is now only changed under listener->listen.lock and whoever clears it is responsible for releasing the socket: smbdirect_socket_accept(), purge_orphaned_work or the destroy of the listener. In order to make that work: - a struct smbdirect_socket that is a listener is now freed via kfree_rcu(), so that a child can dereference sc->accept.listener under rcu_read_lock(), even if the listener is released concurrently. - smbdirect_listen_connect_request() adds nsc to the listen.pending list and sets nsc->accept.listener before it calls smbdirect_accept_connect_request(), and always returns 0 so the rdma_cm core keeps the connection id and nsc owns it. On a non-zero return it schedules nsc's teardown with smbdirect_socket_schedule_cleanup(), which orphans it off the listener so that purge_orphaned_work releases it; nsc destroys its own connection id with rdma_destroy_id() in that teardown. The teardown has to be deferred because the rdma_cm core holds nsc's id_priv->handler_mutex across the handler, so nsc->rdma.cm_id must not be destroyed synchronously from here. That same handler_mutex (and the listener's) also guarantees nsc can't go away under us, so setting the listener before the call is safe and lets a failure orphan nsc. - smbdirect_accept_negotiate_recv_work() no longer moves a socket to the ready list if it already failed or no longer belongs to the listener. Every accepting socket has a listener, so if sc->accept.listener is already cleared, it no longer sends a negotiate response, as the socket is about to be released. - smbdirect_socket_destroy() of the listener disables purge_orphaned_work and also releases the orphaned sockets. Fixes: dc691b91ad16 ("smb: smbdirect: introduce smbdirect_socket_{listen,accept}()") Reported-by: Lee Seong Hyeon <ihopenre@gmail.com> Closes: https://lore.kernel.org/linux-cifs/CANTrAmxL5sWU8Sn29JAGZvSq5PBB2OA+VKA0MHsZJMesagtfzA@mail.gmail.com/ Reported-by: Sashiko <sashiko-bot+sashiko@kernel.org> Closes: https://sashiko.dev/#/patchset/cover.1791224972.git.metze%40samba.org Closes: https://sashiko.dev/#/patchset/cover.1791229120.git.metze%40samba.org Cc: Namjae Jeon <linkinjeon@kernel.org> Cc: Paulo Alcantara <pc@manguebit.org> Cc: Tom Talpey <tom@talpey.com> Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 dayssmb: smbdirect: don't wait for RDMA_CM_EVENT_DISCONNECTED in ↵Stefan Metzmacher
smbdirect_socket_destroy_sync() smbdirect_socket_destroy_sync() waited for RDMA_CM_EVENT_DISCONNECTED after smbdirect_socket_cleanup_work() called rdma_disconnect(). That can take very long, e.g. if the peer just disappeared, until the rdma cm gives up, or forever if the event already happened, but the status was overwritten afterwards. This is not needed: smbdirect_socket_destroy() drains the qp under rdma_lock_handler(), destroys it and calls rdma_destroy_id(), which only waits for a currently running event handler and makes sure no further events are delivered. The rest of the disconnect protocol (DREQ/DREP and timewait for IB, abrupt close for iWarp) is handled by the rdma core asynchronously. drivers/nvme/host/rdma.c also just calls rdma_disconnect() and ib_drain_qp() before rdma_destroy_id(). So smbdirect_socket_destroy() now also accepts SMBDIRECT_SOCKET_DISCONNECTING and changes the status to SMBDIRECT_SOCKET_DISCONNECTED itself under rdma_lock_handler(). We could still get RDMA_CM_EVENT_DISCONNECTED in the small windows between rdma_unlock_handler() and rdma_destroy_id(), but in that case smbdirect_connection_rdma_event_handler() is basically a no-op. Fixes: 422a2436697d ("smb: smbdirect: introduce smbdirect_socket_destroy[_sync]()") Cc: Namjae Jeon <linkinjeon@kernel.org> Cc: Paulo Alcantara <pc@manguebit.org> Cc: Tom Talpey <tom@talpey.com> Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Cc: linux-rdma@vger.kernel.org Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: preserve unreadable named streams on openDaeMyung Kang
A write-only client can open an existing named stream with FILE_OPEN_IF without permission to read the underlying file. The case-insensitive lookup finds the xattr name, but querying its value length then fails with -EACCES. smb2_set_stream_name_xattr() treats every negative result as a missing stream and replaces the existing xattr with an empty value. A failed xattr list is not proof that the stream is absent either: for example, -ENOMEM can lead to the same empty replacement. Preserve listing errors and create a stream only for -ENOENT or -ENODATA. The latter can occur if the xattr is removed between listing its name and querying its value. Return other lookup errors without changing the stream. A write-only FILE_OPEN now reports access denied instead of name not found. FILE_OVERWRITE_IF and FILE_SUPERSEDE on an unreadable stream also fail instead of appearing to replace it. Stream writes and EOF changes already need to read the old value, so such handles cannot update the stream after opening either. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: use the existing xattr name for a named streamDaeMyung Kang
SMB stream names are case-insensitive, but ksmbd stores each named stream in an xattr whose name is case-sensitive. Opening an existing stream finds its xattr with a case-insensitive match, yet the handle keeps the name as the client spelled it, and every later operation that needs an exact name uses that spelling: - a WRITE or an end-of-file change creates a second xattr, so a stream created as "Foo" and written through "foo" ends up stored twice, and which value a later lookup returns depends on xattr list order; - delete-on-close and delete-pending removal can fail with -ENODATA, or remove only a case-variant copy and leave the original; - the share mode check compares stream names with strcmp(), so two opens of the same stream that differ only in case do not conflict. Have ksmbd_vfs_casexattr_len() copy the matching xattr's name into the handle when the stream is opened, so later operations use the name already on disk. The match must have the same length as the name it replaces; the stream lookup passes a length that includes the terminating NUL, which already guarantees that, and the check makes the copy safe for any caller. A stream that does not exist yet keeps the client's spelling, as before. smb2_rename() compares and looks up fp->stream.name case-insensitively, so it behaves the same with either spelling. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: return end of file for reads past a named stream's dataDaeMyung Kang
A READ on a non-empty named stream at or beyond its end fails with STATUS_INVALID_PARAMETER. ksmbd_vfs_stream_read() returns -EINVAL when the offset is not below the stream length, and smb2_read() maps -EINVAL to that status. smb2_read() already turns a zero-byte read into STATUS_END_OF_FILE, the status a regular file returns at its end, and an empty stream already takes that path. Return 0 instead of -EINVAL so that non-empty streams do the same. Clients that read a stream until end of file otherwise get an error once they have read all of its data. The buffered copychunk path converts a zero-byte source read to -EIO, as it does for a regular file that shrinks during copying. Fixes: 2ae1a6cc4302 ("cifsd: fix potential read overflow in ksmbd_vfs_stream_read()") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: validate AppInstanceId takeover targetSung Byeongchan
AppInstanceId lookup currently selects the first open with the matching identifier. CREATE for an unrelated share or path can therefore force-close another session's open before authorization of the new target. Matching only the base path also conflates alternate data streams with the unnamed stream. MS-SMB2 requires the old open to match the share and path, belong to a different ClientGuid, and be closed only when the requester has GENERIC_READ access. Search all opens with the ID and match share, resolved path, stream, and the current connection's client GUID. Retain a share configuration reference in ksmbd_file and reuse its name instead of allocating a name for every open. This keeps matching safe during tree connection teardown and preserves name-based matching across configuration updates. Refresh the share reference on durable reconnect and restore the old reference if reopening fails. Serialize connection and share comparisons with durable disconnect/reconnect, and recheck the target before closing it. Keep the original ClientGuid for durable replay and lease checks. Check AppInstanceVersion before querying access, even when GENERIC_READ is absent, and before disconnected delete-on-close cleanup. Rejected CREATE must leave other durable opens untouched. Calculate maximal access on the matched open's referenced path so a rename cannot substitute another file's authorization. Require read access with the effective VFS credentials as well as the NT DACL before takeover. Access denial only skips takeover and leaves CREATE to its normal access checks. Restore filesystem credentials before returning a takeover error. Handle takeover before checking FILE_CREATE collisions, and re-resolve the path after closing the old open. This lets delete-on-close remove the old file before a new one is created. Include SYNCHRONIZE in the baseline maximal-access mask so read-only files report GENERIC_READ correctly. Fixes: 16c30649709d ("ksmbd: handle durable v2 app instance id") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Sung Byeongchan <tjdqudcks0424@naver.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: fix named stream write and EOF handlingDaeMyung Kang
An SMB WRITE to an existing named stream can silently discard data after its written range. ksmbd stores streams as xattr values, but the write path passes offset + count as the length of the replacement xattr even when the old stream is longer. Writing 26 bytes at offset 0 to a 60-byte stream reports 26 bytes written while discarding the remaining 34 bytes. Keep the existing xattr length when an in-place write ends before EOF. Reject writes that cross XATTR_SIZE_MAX rather than storing only the portion that fits while reporting the full requested count. Commit 4ea0bb8aaedf ("ksmbd: handle set/get info file for streamed file") intentionally skipped ordinary inode truncation for stream handles: an EOF SetInfo on an ADS had truncated the base file. That fixed the base file corruption but left stream EOF changes reporting success without resizing the stream. Handle these requests by resizing only the stream xattr; the base file size remains untouched. Zero-fill stream extensions. This is needed alongside the write fix: a short write's accidental truncation previously masked an ignored explicit EOF change. The stream resize helper returns xattr errors directly rather than using the base-file truncate path's EBADF conversion. Fixes: f44158485826 ("cifsd: add file operations") Fixes: 4ea0bb8aaedf ("ksmbd: handle set/get info file for streamed file") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: fix extended session security negotiation for raw NTLMSSPNamjae Jeon
ksmbd_build_ntlmssp_challenge_blob() only advertises extended session security when conn->use_spnego is true. As a result, raw NTLMSSP negotiation drops NTLMSSP_NEGOTIATE_EXTENDED_SEC from the challenge even when the client requested it. A Windows capture shows an initial SPNEGO authentication succeeding, followed by a raw NTLMSSP negotiation on the same TCP connection. The raw challenge omits extended session security, and the client does not send an AUTHENTICATE message. The unfinished session then occupies the pending session slot, causing subsequent SESSION_SETUP requests to fail with STATUS_INSUFFICIENT_RESOURCES. Set NTLMSSP_NEGOTIATE_EXTENDED_SEC whenever the client requests it, independently of the SPNEGO wrapper, as required by [MS-NLMP]. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Reported-by: Tea La Forgia <tealaforgia+alias@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: fix durable reconnects for root sharesNamjae Jeon
When a share exports "/", ksmbd_validate_name_reconnect() expects another slash after the share path. For a file at /foo, this rejects the valid reconnect name "foo" even though the file is in the share. Compare the requested name with the rendered file path after its leading slash when the resolved share root is "/". Keep the exact-root/empty-name check and reject rendered paths without an initial slash. Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") Reported-by: Dairui Zhang <zhangdairui@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: cache the resolved share path for durable reconnectsNamjae Jeon
A share configured as /a/link/b, with /a/link pointing to /real, is opened relative to share->vfs_path at /real/b. However, ksmbd_validate_name_reconnect() compares the file's d_path() result against the original /a/link/b string and rejects a valid reconnect. Render share->vfs_path with d_path() after the existing kern_path() lookup and cache a copy in real_path along with its length. Use the resolved string for durable reconnect name validation. Keep path and path_sz as the configured spelling for existing consumers, including the volume serial calculation and path lookups. Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") Reported-by: Dairui Zhang <zhangdairui@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: use u8 for SMB2 oplock level valuesKarl Mehltretter
The SMB2 oplock level is an unsigned 8-bit wire value, but smb20_oplock_break_ack() stores it in a plain char. On architectures where plain char is signed, the value 0xff becomes -1 and cannot compare equal to SMB2_OPLOCK_LEVEL_LEASE (0xff). The acknowledgment is consequently rejected with STATUS_INVALID_OPLOCK_PROTOCOL instead of the intended STATUS_INVALID_PARAMETER. Use u8 for the request and response oplock-level variables. This preserves all wire values in their original representation. Fixes: 80a56d4a826c ("ksmbd: align SMB2 oplock break ack handling") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: support FileIdAllExtdDirectoryInformationNamjae Jeon
Handle FileIdAllExtdDirectoryInformation (0x50) in SMB2 QUERY_DIRECTORY. Add the packed wire layout specified by MS-FSCC 2.4.21 and support this class in entry reservation, filename lookup and response encoding. Use the VFS inode number for the 64-bit file ID and retain the existing Apple extension behavior of returning a zero ID. Zero the 128-bit file ID because the VFS provides only a 64-bit inode number, as permitted by the specification. Report reparse tags separately from the EA size, set the reparse flag without changing other file attributes, and initialize entry padding. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: support FileId64ExtdBothDirectoryInformationNamjae Jeon
Handle FileId64ExtdBothDirectoryInformation (0x4f) in SMB2 QUERY_DIRECTORY. Add the packed wire layout specified by MS-FSCC 2.4.18 and support this class in entry reservation, filename lookup and response encoding. Use the VFS inode number for the 64-bit file ID and retain the existing Apple extension behavior of returning a zero ID. Return an empty short name and zero its storage and the reserved byte. Report reparse tags separately from the EA size, set the reparse flag without changing other file attributes, and initialize entry padding. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: support FileId64ExtdDirectoryInformationNamjae Jeon
Handle FileId64ExtdDirectoryInformation (0x4e) in SMB2 QUERY_DIRECTORY. Add the packed wire layout specified by MS-FSCC 2.4.19 and support this class in entry reservation, filename lookup and response encoding. Use the VFS inode number for the 64-bit file ID and retain the existing Apple extension behavior of returning a zero ID. Report reparse tags separately from the EA size, set the reparse flag without changing other file attributes, and initialize entry padding. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: support FileIdExtdDirectoryInformationNamjae Jeon
Handle FileIdExtdDirectoryInformation (0x3c) in SMB2 QUERY_DIRECTORY. Add the packed wire layout specified by MS-FSCC 2.4.23 and support this class in entry reservation, filename lookup and response encoding. Return reparse tags separately from the EA size and set the reparse flag without changing other file attributes. Zero the 128-bit file ID because the VFS provides only a 64-bit inode number, as permitted by the specification, and initialize entry padding. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: support FileIdAllExtdBothDirectoryInformationNamjae Jeon
Windows SMB clients can request FileIdAllExtdBothDirectoryInformation (0x51) when enumerating a directory. ksmbd does not implement this format, requiring the client to retry with an older information class. Add the packed FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION wire layout from MS-FSCC section 2.4.20 and support it throughout directory entry reservation, name retrieval and response encoding. Include the reparse tag separately from EaSize and retain the file attributes when marking special files as reparse points. Use the inode number for the 64-bit file ID, as for existing directory classes. Set the 128-bit ID to zero because the VFS stat data does not provide one, as required by MS-FSCC. Return no short name and zero reserved fields and alignment padding. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
6 daysksmbd: use clear_and_wake_up_bit() directlyDaijiamu
clear_and_wake_up_bit() was introduced by commit 8236b0ae31c8 ("bdi: wake up concurrent wb_shutdown() callers.") to replace the open-coded clear_bit_unlock() + smp_mb__after_atomic() + wake_up_bit() sequence. Replace the sequence and drop the now-trivial wake_up_oplock_break() wrapper, calling the helper directly at each call site. Suggested-by: ChenXiaoSong <chenxiaosong@chenxiaosong.com> Signed-off-by: Daijiamu <3058704216@qq.com> Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>