From 80f49404968d680f07f33f57ed9a9a1ddd2f2418 Mon Sep 17 00:00:00 2001 From: Enzo Matsumiya Date: Thu, 8 Oct 2026 15:26:09 -0300 Subject: [PATCH 01/61] smb: client: fast fail sends if need to reconnect smb_send_kvec() keeps retrying when server needs to reconnect, which makes no sense as cifs_reconnect() will never run in parallel (because both need server mutex). IOW, retrying will never succeed, but only delay reconnects further. Bail out early from smb_send_kvec() when need to reconnect. Also shutdown socket queues when CifsNeedReconnect is first detected, so any sends/receives fails immediately (and don't wait for socket to timeout). Add TCP_Server_Info::need_sock_shutdown to ensure socket is shutdown only once -- even though socket/TCP API will prevent multiple shutdowns, we need to prevent, from cifs side, concurrent tasks from accidentally shutting down the socket again in case cifs_reconnect() is successful. kernel_sock_shutdown() will be called from whichever task detects it first; cifsd (cifs_tcp_ses_needs_reconnect()), or sending tasks, through cifs_call_async() or compound_send_recv(). Signed-off-by: Enzo Matsumiya Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifsglob.h | 1 + fs/smb/client/connect.c | 25 +++++++++++++++++++++++-- fs/smb/client/transport.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 5c5b76a9e9fe..d74cc9e8c413 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -802,6 +802,7 @@ struct TCP_Server_Info { bool posix_ext_supported; struct delayed_work reconnect; /* reconnect workqueue job */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ + bool need_sock_shutdown; /* shutdown socket when need to reconnect */ unsigned long echo_interval; /* diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 28e1ddeb6182..ff8637301fa9 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -130,8 +130,11 @@ void smb2_query_server_interfaces(struct work_struct *work) #define set_need_reco(server) \ do { \ spin_lock(&server->srv_lock); \ - if (server->tcpStatus != CifsExiting) \ + if (server->tcpStatus != CifsExiting) { \ + if (server->tcpStatus != CifsNeedReconnect) \ + server->need_sock_shutdown = true; \ server->tcpStatus = CifsNeedReconnect; \ + } \ spin_unlock(&server->srv_lock); \ } while (0) @@ -353,6 +356,8 @@ cifs_abort_connection(struct TCP_Server_Info *server) static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets) { + bool shutdown; + spin_lock(&server->srv_lock); server->nr_targets = num_targets; if (server->tcpStatus == CifsExiting) { @@ -365,9 +370,25 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); trace_smb3_reconnect(server->current_mid, server->conn_id, server->hostname); - server->tcpStatus = CifsNeedReconnect; + /* + * Cover cases where sender tasks didn't manage to shutdown the socket + * for some reason. + */ + shutdown = server->tcpStatus != CifsNeedReconnect || + server->need_sock_shutdown; + server->need_sock_shutdown = false; + server->tcpStatus = CifsNeedReconnect; spin_unlock(&server->srv_lock); + + if (shutdown) { + cifs_server_lock(server); + if (server->ssocket) + /* Don't release it here/yet! */ + kernel_sock_shutdown(server->ssocket, SHUT_RDWR); + cifs_server_unlock(server); + } + return true; } diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 6e21b5f8754a..cf11af490b0d 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -179,6 +179,17 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, * to avoid unnecessary reconnects. */ rc = sock_sendmsg(ssocket, smb_msg); + + /* + * If need to reconnect, blame it for any non-interrupt error + * and bail out early, even if -EAGAIN; reconnect will never + * happen in parallel as cifs_reconnect() needs server mutex + * (which we're already holding), so it's pointless to retry. + */ + if (unlikely(rc <= 0 && !is_interrupt_error(rc) && + READ_ONCE(server->tcpStatus) == CifsNeedReconnect)) + return -ECONNRESET; + if (rc == -EAGAIN || unlikely(rc == -EINTR && task_work_pending(current))) { retries++; if (retries >= 14 || @@ -654,6 +665,26 @@ int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *mid) return 0; } +static void cond_sock_shutdown(struct TCP_Server_Info *server) +{ + bool shutdown; + + lockdep_assert_held(&server->_srv_mutex); + + spin_lock(&server->srv_lock); + /* + * No need to check status, ->need_sock_shutdown is only set when it's + * CifsNeedReconnect. + */ + shutdown = server->need_sock_shutdown && server->ssocket; + server->need_sock_shutdown = false; + spin_unlock(&server->srv_lock); + + if (shutdown) + /* Don't release it here/yet! */ + kernel_sock_shutdown(server->ssocket, SHUT_RDWR); +} + /* * Send a SMB request and set the callback function in the mid to handle * the result. Caller is responsible for dealing with timeouts. @@ -724,6 +755,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, revert_current_mid(server, mid->credits); server->sequence_number -= 2; delete_mid(server, mid); + cond_sock_shutdown(server); } cifs_server_unlock(server); @@ -982,6 +1014,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, delete_mid(server, mid[i]); cancelled_mid[i] = true; } + cond_sock_shutdown(server); } cifs_server_unlock(server); From 031278577380e7875d95aed81a2b2bcac39be923 Mon Sep 17 00:00:00 2001 From: Henry Martin Date: Sat, 10 Oct 2026 11:28:56 +0800 Subject: [PATCH 02/61] smb: client: fix use-after-free in cifs_ses_add_channel() The error path of cifs_ses_add_channel() calls cifs_put_tcp_session() before cifs_chan_clear_need_reconnect(). The latter reaches cifs_ses_get_chan_index(), which dereferences server->terminate; if the put was the final reference, TCP_Server_Info is already freed and this is a use-after-free. Same put-then-use pattern as the recently fixed sibling in commit 717e0a25036b ("cifs: Fix server use-after-free in cifs_chan_skip_or_disable()"). Move the put last, but do not read chan->server after dropping chan_lock: chan points into ses->chans[], and once chan_count is decremented a concurrent add_channel can reuse the slot and overwrite the pointer, so the put would act on the new channel's server. Cache the pointer under chan_lock, clear the reconnect bit and decrement chan_count while still holding the reference, and release it after the unlock. This issue was discovered by Tencent CodeBuddy Security. Fixes: ee1d21794e55a ("cifs: handle when server stops supporting multichannel") Signed-off-by: Henry Martin Cc: stable@vger.kernel.org Reviewed-by: Namjae Jeon Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/sess.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index e095f41b5882..0ab3f37d4809 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -626,12 +626,13 @@ cifs_ses_add_channel(struct cifs_ses *ses, out: if (rc && chan->server) { - cifs_put_tcp_session(chan->server, 0); + struct TCP_Server_Info *pserver; spin_lock(&ses->chan_lock); + pserver = chan->server; /* we rely on all bits beyond chan_count to be clear */ - cifs_chan_clear_need_reconnect(ses, chan->server); + cifs_chan_clear_need_reconnect(ses, pserver); ses->chan_count--; /* * chan_count should never reach 0 as at least the primary @@ -639,6 +640,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, */ WARN_ON(ses->chan_count < 1); spin_unlock(&ses->chan_lock); + cifs_put_tcp_session(pserver, 0); } kfree(ctx->UNC); From 59131dd72f62b198fc9ea1489ad9d3573154f684 Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:30 +0100 Subject: [PATCH 03/61] smb: client: fix use-after-free infoleak via the readdir resume name CIFSFindNext() copies the resume name that cifs_save_resume_key() recorded from the last entry of the previous response into its request; psrch_inf->presume_name points into the response buffer that entry came from, and nothing ever clears it. find_cifs_entry() records a new name only from a response with a usable last entry, and cifs_readdir() only from an entry it walks to, so a response that carries no entries and leaves last_entry NULL, because CIFSFindFirst() or CIFSFindNext() rejected LastNameOffset, refreshes neither and presume_name keeps pointing into the previous response. That buffer has already been released: by CIFSFindNext() before it installs the new response, or by find_cifs_entry() when it rewinds the search, which does not drop the name either and can then fail in initiate_cifs_search() before a new response replaces it. The next CIFSFindNext() then copies up to PATH_MAX - 1 bytes of the resume name out of the released buffer into its request and sends them to the server: a use-after-free read that leaks kernel memory to a malicious or compromised server, which can provoke it with a single FindNext response that carries no entries and a LastNameOffset above CIFSMaxBufSize, which is all the existing check rejects. With KASAN enabled, a server that answers a listing that way gives: CIFS: VFS: ignoring corrupt resume name ================================================================== BUG: KASAN: slab-use-after-free in CIFSFindNext+0x8ca/0x14c0 Read of size 4080 at addr ffff88807c823f98 by task ls/83 CPU: 0 UID: 0 PID: 83 Comm: ls Tainted: G B 7.3.0-rc4-00457-gf14572c203d5 #69 PREEMPT(lazy) Tainted: [B]=BAD_PAGE Call Trace: kasan_report+0xdf/0x1a0 kasan_check_range+0x10f/0x1e0 __asan_memcpy+0x23/0x60 CIFSFindNext+0x8ca/0x14c0 cifs_readdir+0xf51/0x29c0 iterate_dir+0x1c0/0x570 __x64_sys_getdents64+0x133/0x270 do_syscall_64+0x109/0x5d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 83 on cpu 1 at 13.497119s: cifs_buf_get+0x36/0x90 smb_init+0x4f/0x110 CIFSFindNext+0xf7/0x14c0 cifs_readdir+0xf51/0x29c0 Freed by task 83 on cpu 0 at 13.584018s: cifs_buf_release+0x41/0x80 CIFSFindNext+0xfce/0x14c0 cifs_readdir+0xf51/0x29c0 The buggy address is located 16280 bytes inside of freed 16588-byte region [ffff88807c820000, ffff88807c8240cc) ================================================================== The same memcpy() first reads past the end of that object while it is still live, a slab-out-of-bounds read that the following patches bound; that is the taint the report above carries. SMB1 is not negotiated by default; reaching this code requires an explicit vers=1.0 mount. Clear presume_name and resume_name_len whenever a new response is installed and when the rewind path releases the search buffer, so that the name never outlives the buffer it points into, and reset resume_key with them, since it was taken from the same entry and would otherwise be sent with an empty name. A response without a usable last entry then continues the search with an empty resume name rather than a stale one; CIFSFindNext() skips the copy of a zero-length name so that it never runs on the NULL pointer. The next patch in the series leaves last_entry NULL for a response that carries no entries, and bounds LastNameOffset against the received response rather than against CIFSMaxBufSize. Responses that are given a last entry today then take the path fixed here, so that patch must not be applied without this one. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Fixes: b77d753c413e ("[CIFS] Check that last search entry resume key is valid") Cc: stable@vger.kernel.org Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifssmb.c | 11 ++++++++++- fs/smb/client/readdir.c | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 6dddbd84b93b..95f339f48ad7 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4543,6 +4543,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->entries_in_buffer; + psrch_inf->presume_name = NULL; + psrch_inf->resume_name_len = 0; + psrch_inf->resume_key = 0; lnoff = le16_to_cpu(parms->LastNameOffset); if (CIFSMaxBufSize < lnoff) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); @@ -4607,7 +4610,10 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, name_len = psrch_inf->resume_name_len; params += name_len; if (name_len < PATH_MAX) { - memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); + if (name_len) { + memcpy(pSMB->ResumeFileName, + psrch_inf->presume_name, name_len); + } byte_count += name_len; /* 14 byte parm len above enough for 2 byte null terminator */ pSMB->ResumeFileName[name_len] = 0; @@ -4662,6 +4668,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->endOfSearch = !!parms->EndofSearch; psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer; + psrch_inf->presume_name = NULL; + psrch_inf->resume_name_len = 0; + psrch_inf->resume_key = 0; lnoff = le16_to_cpu(parms->LastNameOffset); if (CIFSMaxBufSize < lnoff) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 9530e5b01564..6ab4e687c3e4 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -752,6 +752,9 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, cfile->srch_inf.ntwrk_buf_start = NULL; cfile->srch_inf.srch_entries_start = NULL; cfile->srch_inf.last_entry = NULL; + cfile->srch_inf.presume_name = NULL; + cfile->srch_inf.resume_name_len = 0; + cfile->srch_inf.resume_key = 0; } rc = initiate_cifs_search(xid, file, full_path); if (rc) { From 570c783a96f054dd3ac409a92772e9afb705d21c Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:31 +0100 Subject: [PATCH 04/61] smb: client: fix OOB last_entry pointer from unbounded LastNameOffset CIFSFindFirst() and CIFSFindNext() locate the last entry of a TRANS2_FIND_FIRST2 or TRANS2_FIND_NEXT2 response by adding the LastNameOffset of the response parameters to the start of the data area, and store the result in psrch_inf->last_entry. MS-CIFS 2.2.6.2.2 defines that offset as the offset of the entry's file name; the client follows the reading of NT and Samba servers, which point it at the entry. LastNameOffset is only checked against CIFSMaxBufSize, which says nothing about the response actually received: validate_t2() lets the data area start up to 1024 bytes into the buffer, and SendReceive() copies at most CIFSMaxBufSize + MAX_CIFS_HDR_SIZE bytes of a response, 16468 by default, into a cifs_request allocation of CIFSMaxBufSize + MAX_SMB2_HDR_SIZE bytes, 16588 by default. The pointer itself can therefore be placed anywhere from the end of the received data to 820 bytes past the end of the allocation. The read through that pointer is far larger than its displacement. find_cifs_entry() hands last_entry to cifs_save_resume_key() after every FindNext and after the FindFirst of a search rewind, and cifs_fill_dirent() takes the length of the name from the entry itself: a __le32 FileNameLength for most levels, a __u8 for SMB_FIND_FILE_INFO_STANDARD, and for SMB_FIND_FILE_UNIX the result of a scan for the terminating NUL over up to PATH_MAX + 1 UTF-16 units. The name is recorded as the resume name of the search, and the next CIFSFindNext() rejects only a recorded length of PATH_MAX or more before copying the name into the ResumeFileName of its request and sending it with the resume key taken from the same entry: up to 4 KiB of memory from past the end of the allocation leaks to the server, and for SMB_FIND_FILE_UNIX the NUL scan runs about twice as far before the length is even known. The entry does not have to lie outside the response for that either: a maximal response ends about 120 bytes before the end of the allocation, so an entry in its last bytes with a name just under PATH_MAX has nearly all of that name copied from past the allocation. It needs nothing unusual from the client: a FindNext response that reports no entries and does not end the search makes find_cifs_entry() send the next FindNext at once, carrying whatever was parsed at LastNameOffset, and a search rewind can do the same after its FindFirst. SMB1 is not negotiated by default: this takes a malicious or compromised server, a mount of it with an explicit vers=1.0, which CONFIG_CIFS_ALLOW_INSECURE_LEGACY (default y) permits, and a directory listing on that mount. With KASAN enabled, a response that places the last entry past the buffer, with a large DataOffset and a LastNameOffset near the end of its range, gives: ================================================================== BUG: KASAN: slab-out-of-bounds in cifs_save_resume_key.isra.0+0x7aa/0x7f0 Read of size 4 at addr ffff88807b55c33b by task ls/83 CPU: 1 UID: 0 PID: 83 Comm: ls Not tainted 7.3.0-rc4-00457-gf14572c203d5 #69 PREEMPT(lazy) Call Trace: kasan_report+0xdf/0x1a0 cifs_save_resume_key.isra.0+0x7aa/0x7f0 cifs_readdir+0x1ed6/0x29c0 iterate_dir+0x1c0/0x570 __x64_sys_getdents64+0x133/0x270 do_syscall_64+0x109/0x5d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 83 on cpu 0 at 19.317556s: cifs_buf_get+0x36/0x90 smb_init+0x4f/0x110 CIFSFindNext+0xf7/0x14c0 cifs_readdir+0xf51/0x29c0 The buggy address belongs to the object at ffff88807b558000 which belongs to the cache cifs_request of size 16588 The buggy address is located 623 bytes to the right of allocated 16588-byte region [ffff88807b558000, ffff88807b55c0cc) ================================================================== The four bytes read there are the FileNameLength of the entry, which cifs_fill_dirent() takes before anything checks where the entry lies. Ignore the last entry when it does not start inside the received response or the response holds no entries; for a response without entries, last_entry pointed into or past its empty data area and cifs_save_resume_key() parsed whatever the buffer held there. The entry is bounded by the response that was received, which is what the buffer holds, rather than by the data area the response declares, which a later patch checks against the received length. Record the search handle before the last entry is examined, since a response without a usable last entry still carries the handle that the search is continued and closed with; leaving the assignment in the else branch would drop the handle of every response without entries. This bounds where the last entry starts, not how far it is parsed: an entry that starts within the final bytes of the response still has its fixed part read past the end of the received data and its name, up to 4095 bytes, copied from past the end of the allocation, until the following patch bounds the parse itself. A response without a usable last entry continues the search with an empty resume name, since the preceding patch, "smb: client: fix use-after-free infoleak via the readdir resume name", drops the recorded name whenever a new response is installed. This patch applies on top of that one and relies on it: without it, every response rejected here would leave the previous name in place, pointing into a buffer that has been released. A conforming server is not affected: the last entry lies inside the data area of the response. Fixes: 0752f1522a91 ("[CIFS] make sure we have the right resume info before calling CIFSFindNext") Fixes: b77d753c413e ("[CIFS] Check that last search entry resume key is valid") Cc: stable@vger.kernel.org Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifssmb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 95f339f48ad7..d8b1740b50fa 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4546,14 +4546,17 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->presume_name = NULL; psrch_inf->resume_name_len = 0; psrch_inf->resume_key = 0; + if (pnetfid) + *pnetfid = parms->SearchHandle; lnoff = le16_to_cpu(parms->LastNameOffset); - if (CIFSMaxBufSize < lnoff) { + if (!psrch_inf->entries_in_buffer) { + psrch_inf->last_entry = NULL; + } else if (psrch_inf->srch_entries_start + lnoff >= + psrch_inf->ntwrk_buf_start + bytes_returned) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; } else { psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff; - if (pnetfid) - *pnetfid = parms->SearchHandle; } return 0; } @@ -4672,7 +4675,10 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->resume_name_len = 0; psrch_inf->resume_key = 0; lnoff = le16_to_cpu(parms->LastNameOffset); - if (CIFSMaxBufSize < lnoff) { + if (!psrch_inf->entries_in_buffer) { + psrch_inf->last_entry = NULL; + } else if (psrch_inf->srch_entries_start + lnoff >= + psrch_inf->ntwrk_buf_start + bytes_returned) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; } else { From f8171804a39ee89a11cd462f67862899de9c6b10 Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:32 +0100 Subject: [PATCH 05/61] smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2 cifs_fill_dirent() reads the fixed part of a directory entry and the name length it holds, or for SMB_FIND_FILE_UNIX scans the name for its terminating NUL, without knowing where the response ends. cifs_save_resume_key() calls it for the entry at the LastNameOffset the server chose, after every FindNext and after the FindFirst of a search rewind, and records the name it returns as the resume name of the search without bounding it; the next CIFSFindNext() copies up to PATH_MAX - 1 bytes from that name into its request and sends them to the server. cifs_filldir() bounds the name against the end of the response since commit f8cf09a53a0d ("smb: client: bound dirent name against end of SMB response in cifs_filldir"), but only after cifs_fill_dirent() has read the entry, and nxt_dir_entry() checks the entries it walks only against sizeof(FILE_DIRECTORY_INFO), for every level but SMB_FIND_FILE_INFO_STANDARD, and never sees the first entry of a response. Bounding where last_entry starts, as the preceding patch does, does not bound the read. A last entry that starts within the final bytes of the response still has its fixed part read past the end of the received data, and the name length it declares, a __le32 for every level but SMB_FIND_FILE_INFO_STANDARD and SMB_FIND_FILE_UNIX, is recorded without being checked against anything. CIFSFindNext() rejects only a length of PATH_MAX or more, then copies the name, up to 4095 bytes, into its request and sends it, and as the report below shows that copy can run past the end of the cifs_request allocation that holds the response. For SMB_FIND_FILE_UNIX the name is in addition scanned for its terminating NUL over up to PATH_MAX + 1 UTF-16 units, or PATH_MAX bytes, before any check. The FindNext that carries the name is only sent by the SMB1 dialect, which is not negotiated by default; reaching it requires an explicit vers=1.0 mount. With KASAN enabled, a response whose last entry declares a name longer than the bytes that follow it gives: ================================================================== BUG: KASAN: slab-out-of-bounds in CIFSFindNext+0x8ca/0x14c0 Read of size 4080 at addr ffff88807c823f98 by task ls/83 CPU: 0 UID: 0 PID: 83 Comm: ls Not tainted 7.3.0-rc4-00457-gf14572c203d5 #69 PREEMPT(lazy) Call Trace: kasan_report+0xdf/0x1a0 kasan_check_range+0x10f/0x1e0 __asan_memcpy+0x23/0x60 CIFSFindNext+0x8ca/0x14c0 cifs_readdir+0xf51/0x29c0 iterate_dir+0x1c0/0x570 __x64_sys_getdents64+0x133/0x270 do_syscall_64+0x109/0x5d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 83 on cpu 1 at 13.497119s: cifs_buf_get+0x36/0x90 smb_init+0x4f/0x110 CIFSFindNext+0xf7/0x14c0 cifs_readdir+0xf51/0x29c0 The buggy address belongs to the object at ffff88807c820000 which belongs to the cache cifs_request of size 16588 The buggy address is located 16280 bytes inside of allocated 16588-byte region [ffff88807c820000, ffff88807c8240cc) ================================================================== The read is the memcpy() that copies the recorded name into the next request, so those bytes go to the server. Pass the end of the response to cifs_fill_dirent() and have it reject an entry whose fixed part does not fit or whose name extends past the end, before either is used, so that both callers are covered; cifs_save_resume_key() computes the end the same way cifs_readdir() does. The name bound compares the bytes left between the name and the end with the name length rather than adding the length to the name pointer, since the length is a 32-bit value taken from the entry and the sum could wrap on 32-bit systems. cifs_fill_dirent() is also used on the SMB2 readdir path; there smb2_parse_query_directory() has already checked every entry against the end of the response, so a valid SMB2 response is not rejected by the new checks. The check cifs_filldir() applies after the parse is left in place. The NUL scan for SMB_FIND_FILE_UNIX names is capped by a separate patch. An entry and its name lie inside the data area of the response, so a server that points LastNameOffset at the entry is not affected. One that points it at the file name, as MS-CIFS 2.2.6.2.2 describes, has its last entry rejected here; the listing is unaffected, because cifs_readdir() records the resume name from an entry it emitted, and before this series such a response could instead end the listing early, since a name length read from the wrong place is usually PATH_MAX or more, which CIFSFindNext() rejects with -EINVAL. On trees before v6.19 the type for the level 0x105 fixed part is spelled SEARCH_ID_FULL_DIR_INFO; adjust when backporting. Fixes: 0752f1522a91 ("[CIFS] make sure we have the right resume info before calling CIFSFindNext") Cc: stable@vger.kernel.org # 6.1.x: f8cf09a53a0d: smb: client: bound dirent name against end of SMB response in cifs_filldir Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/readdir.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 6ab4e687c3e4..441cafcdc889 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -586,30 +586,46 @@ static void cifs_fill_dirent_std(struct cifs_dirent *de, } static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, - u16 level, bool is_unicode) + const char *end, u16 level, bool is_unicode) { + size_t len = end > (const char *)info ? end - (const char *)info : 0; + memset(de, 0, sizeof(*de)); switch (level) { case SMB_FIND_FILE_POSIX_INFO: + if (len < sizeof(struct smb2_posix_info)) + goto too_short; cifs_fill_dirent_posix(de, info); break; case SMB_FIND_FILE_UNIX: + if (len < offsetof(FILE_UNIX_INFO, FileName)) + goto too_short; cifs_fill_dirent_unix(de, info, is_unicode); break; case SMB_FIND_FILE_DIRECTORY_INFO: + if (len < offsetof(FILE_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_dir(de, info); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + if (len < offsetof(FILE_FULL_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_full(de, info); break; case SMB_FIND_FILE_ID_FULL_DIR_INFO: + if (len < offsetof(FILE_ID_FULL_DIR_INFO, FileName)) + goto too_short; cifs_fill_dirent_search(de, info); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + if (len < offsetof(FILE_BOTH_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_both(de, info); break; case SMB_FIND_FILE_INFO_STANDARD: + if (len < offsetof(FIND_FILE_STANDARD_INFO, FileName)) + goto too_short; cifs_fill_dirent_std(de, info); break; default: @@ -617,7 +633,19 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, return -EINVAL; } + if (de->name && + (end < de->name || (size_t)(end - de->name) < de->namelen)) { + cifs_dbg(VFS, "%s: search entry name extends past end of SMB\n", + __func__); + return -EINVAL; + } + return 0; + +too_short: + cifs_dbg(VFS, "%s: search entry extends past end of SMB\n", + __func__); + return -EINVAL; } #define UNICODE_DOT cpu_to_le16(0x2e) @@ -672,10 +700,14 @@ static int is_dir_changed(struct file *file) static int cifs_save_resume_key(const char *current_entry, struct cifsFileInfo *file_info) { + struct TCP_Server_Info *server = tlink_tcon(file_info->tlink)->ses->server; + char *buf = file_info->srch_inf.ntwrk_buf_start; + const char *end = buf + server->ops->calc_smb_size(buf); struct cifs_dirent de; int rc; - rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level, + rc = cifs_fill_dirent(&de, current_entry, end, + file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (!rc) { file_info->srch_inf.presume_name = de.name; @@ -977,7 +1009,8 @@ static int cifs_filldir(char *find_entry, struct file *file, struct qstr name; int rc = 0; - rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, + rc = cifs_fill_dirent(&de, find_entry, end_of_smb, + file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (rc) return rc; From fa0c2f082946917c3f07d2475c8ce73a8c96d0e2 Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:33 +0100 Subject: [PATCH 06/61] smb: client: fix OOB read in the SMB_FIND_FILE_UNIX name scan cifs_fill_dirent_unix() finds the length of an SMB_FIND_FILE_UNIX entry name by scanning for its terminating NUL, over up to PATH_MAX + 1 UTF-16 units in cifs_unicode_bytelen() or PATH_MAX bytes in strnlen(). Neither scan knows where the response ends. cifs_fill_dirent() only requires the fixed part of the entry to fit, so the name can start exactly at the end of the received data, and a name that holds no terminator is then scanned for 8194 bytes, or 4096 bytes without unicode, past the end of the received data. SendReceive() copies at most 16468 bytes into the 16588-byte cifs_request allocation, so for a response of that length up to 8074 of the bytes scanned lie past the end of the allocation. Before the preceding patches bounded where the entry starts, the entry itself could start up to 820 bytes past the end of the allocation at the default CIFSMaxBufSize, and its name 928 bytes past it, so all 8194 scanned bytes would lie outside. cifs_fill_dirent() rejects the name afterwards because it extends past the end of the response, so nothing of what was read is used, but the out-of-bounds read itself remains. SMB_FIND_FILE_UNIX is only used with SMB1 servers that offer the Unix extensions; SMB1 is not negotiated by default and requires an explicit vers=1.0 mount. Before the preceding patches, an entry placed past the buffer left the scan out of bounds from its first read. They bound where the entry starts, but nothing bounds the scan, so a name that holds no terminator still runs off the end of the allocation. Reproduced on the unpatched tree with KASAN enabled, for an entry that starts inside the response, which is the case the preceding patches leave open: ================================================================== BUG: KASAN: slab-out-of-bounds in cifs_save_resume_key.isra.0+0x75c/0x7f0 Read of size 2 at addr ffff88807ee640cc by task ls/84 CPU: 0 UID: 0 PID: 84 Comm: ls Not tainted 7.3.0-rc4-00457-gf14572c203d5 #69 PREEMPT(lazy) Call Trace: kasan_report+0xdf/0x1a0 cifs_save_resume_key.isra.0+0x75c/0x7f0 cifs_readdir+0x1ed6/0x29c0 iterate_dir+0x1c0/0x570 __x64_sys_getdents64+0x133/0x270 do_syscall_64+0x109/0x5d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 84 on cpu 1 at 15.751078s: cifs_buf_get+0x36/0x90 smb_init+0x4f/0x110 CIFSFindNext+0xf7/0x14c0 cifs_readdir+0xf51/0x29c0 The buggy address belongs to the object at ffff88807ee60000 which belongs to the cache cifs_request of size 16588 The buggy address is located 0 bytes to the right of allocated 16588-byte region [ffff88807ee60000, ffff88807ee640cc) ================================================================== The two bytes read there are one UTF-16 unit of the scan, at the first byte past the end of the object. The scan carries on from there, reported again 2, 4 and 6 bytes to the right. Pass the number of bytes that follow the fixed part of the entry to cifs_fill_dirent_unix() and stop both scans there. A scan that reaches the end of the response without finding a terminator now fails: it returns a name that ends exactly at the end of the response and would otherwise pass the bound, so cifs_fill_dirent() requires the position of the terminator of an SMB_FIND_FILE_UNIX name to lie inside the response as well. Accepting such a name truncated at the end of the response would turn a malformed entry into a directory entry, or a resume name, that no server sent. A name longer than the PATH_MAX cap of the scans is still truncated there, as before, when the response extends past the cap. The message cifs_unicode_bytelen() logs when it finds no terminator now covers both limits. This patch depends on "smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2", which adds the end argument of cifs_fill_dirent() and the length it derives from it; the backport note in that patch applies to this one as well. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/readdir.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 441cafcdc889..1667bba40e44 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -456,17 +456,20 @@ initiate_cifs_search(const unsigned int xid, struct file *file, } /* return length of unicode string in bytes */ -static int cifs_unicode_bytelen(const char *str) +static size_t cifs_unicode_bytelen(const char *str, size_t maxlen) { - int len; const __le16 *ustr = (const __le16 *)str; + size_t len; - for (len = 0; len <= PATH_MAX; len++) { + maxlen = umin(PATH_MAX + 1, maxlen / sizeof(__le16)); + for (len = 0; len < maxlen; len++) { if (ustr[len] == 0) - return len << 1; + return len * sizeof(__le16); } - cifs_dbg(FYI, "Unicode string longer than PATH_MAX found\n"); - return len << 1; + len *= sizeof(__le16); + cifs_dbg(FYI, "%s: Unicode string not terminated within %zu bytes\n", + __func__, len); + return len; } static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) @@ -532,13 +535,13 @@ static void cifs_fill_dirent_posix(struct cifs_dirent *de, } static void cifs_fill_dirent_unix(struct cifs_dirent *de, - const FILE_UNIX_INFO *info, bool is_unicode) + const FILE_UNIX_INFO *info, bool is_unicode, size_t maxlen) { de->name = &info->FileName[0]; if (is_unicode) - de->namelen = cifs_unicode_bytelen(de->name); + de->namelen = cifs_unicode_bytelen(de->name, maxlen); else - de->namelen = strnlen(de->name, PATH_MAX); + de->namelen = strnlen(de->name, min_t(size_t, maxlen, PATH_MAX)); de->resume_key = info->ResumeKey; de->ino = le64_to_cpu(info->basic.UniqueId); } @@ -589,6 +592,7 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, const char *end, u16 level, bool is_unicode) { size_t len = end > (const char *)info ? end - (const char *)info : 0; + size_t nul_len = 0; memset(de, 0, sizeof(*de)); @@ -601,7 +605,9 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, case SMB_FIND_FILE_UNIX: if (len < offsetof(FILE_UNIX_INFO, FileName)) goto too_short; - cifs_fill_dirent_unix(de, info, is_unicode); + cifs_fill_dirent_unix(de, info, is_unicode, + len - offsetof(FILE_UNIX_INFO, FileName)); + nul_len = is_unicode ? sizeof(__le16) : sizeof(__u8); break; case SMB_FIND_FILE_DIRECTORY_INFO: if (len < offsetof(FILE_DIRECTORY_INFO, FileName)) @@ -634,7 +640,8 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, } if (de->name && - (end < de->name || (size_t)(end - de->name) < de->namelen)) { + (end < de->name || + (size_t)(end - de->name) < de->namelen + nul_len)) { cifs_dbg(VFS, "%s: search entry name extends past end of SMB\n", __func__); return -EINVAL; From 29bd6773187cb5c1bbbdf90d677c6add7d58af26 Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:34 +0100 Subject: [PATCH 07/61] smb: client: reject FIND data areas that run past the received response CIFSFindFirst() and CIFSFindNext() take the directory entries of a TRANS2_FIND_FIRST2 or TRANS2_FIND_NEXT2 response from DataOffset for DataCount bytes. validate_t2() bounds DataOffset at 1024 and ParameterCount + DataCount by the byte count, and nothing compares DataOffset + DataCount with the number of bytes SendReceive() copied into the buffer. smb_init() places the request and the response in the same cifs_request allocation and cifs_buf_get() clears only the start of it, so a short response whose data area extends past its end has srch_entries_start point at bytes of the request that was just sent, or at whatever the allocation held before, and those bytes are parsed as directory entries. cifs_readdir() and find_cifs_entry() walk the entries with nxt_dir_entry(), which checks every entry but the first of a response against the end of the SMB; cifs_query_path_info() and cifs_backup_query_path_info() read the first entry with no check at all. Those reads stay inside the allocation, but what they return is not part of the response. The last entry, which LastNameOffset locates relative to the data area, is bounded against the received response by an earlier patch of this series, as is every entry that cifs_fill_dirent() parses; the walk itself and the two query functions are not. SMB1 is not negotiated by default; reaching this code requires an explicit vers=1.0 mount. Reject a response whose data area extends past the received length, with the -EINVAL that validate_t2() returns for the other malformed transaction responses. cifs_query_path_info() and cifs_backup_query_path_info() still read a whole entry from a data area that may be smaller than one; that is not changed here. A conforming server is not affected. The data block of a transaction response is part of the SMB, so DataOffset + DataCount cannot exceed the smbCalcSize() bytes that SendReceive() copies; coalesce_t2() appends each secondary response to the data area and adds its length to both DataCount and the byte count, which keeps that relation. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifssmb.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index d8b1740b50fa..bb71fed940a5 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4410,8 +4410,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, /* level 257 SMB_ */ TRANSACTION2_FFIRST_REQ *pSMB = NULL; TRANSACTION2_FFIRST_RSP *pSMBr = NULL; - T2_FFIRST_RSP_PARMS *parms; + unsigned int data_off, data_count; struct nls_table *nls_codepage; + T2_FFIRST_RSP_PARMS *parms; unsigned int in_len, lnoff; __u16 params, byte_count; int bytes_returned = 0; @@ -4530,11 +4531,19 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + data_off = le16_to_cpu(pSMBr->t2.DataOffset); + data_count = le16_to_cpu(pSMBr->t2.DataCount); + if (data_off + data_count > (unsigned int)bytes_returned) { + cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n", + __func__, data_off, data_count, bytes_returned); + cifs_buf_release(pSMB); + return -EINVAL; + } + psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); psrch_inf->ntwrk_buf_start = (char *)pSMBr; psrch_inf->smallBuf = false; - psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.DataOffset); + psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + data_off; parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset)); @@ -4567,8 +4576,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, { TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; - T2_FNEXT_RSP_PARMS *parms; + unsigned int data_off, data_count; unsigned int name_len, in_len; + T2_FNEXT_RSP_PARMS *parms; unsigned int lnoff; __u16 params, byte_count; char *response_data; @@ -4652,13 +4662,22 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, cifs_buf_release(pSMB); return rc; } + + data_off = le16_to_cpu(pSMBr->t2.DataOffset); + data_count = le16_to_cpu(pSMBr->t2.DataCount); + if (data_off + data_count > (unsigned int)bytes_returned) { + cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n", + __func__, data_off, data_count, bytes_returned); + cifs_buf_release(pSMB); + return -EINVAL; + } + /* BB fixme add lock for file (srch_info) struct here */ psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); response_data = (char *)&pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset); parms = (T2_FNEXT_RSP_PARMS *)response_data; - response_data = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.DataOffset); + response_data = (char *)&pSMBr->hdr.Protocol + data_off; if (psrch_inf->smallBuf) cifs_small_buf_release(psrch_inf->ntwrk_buf_start); From 531aa4239b0d80d7146b102b98f7aa7da989ccdd Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:35 +0100 Subject: [PATCH 08/61] smb: client: reject short or out-of-range FIND response parameters CIFSFindFirst() and CIFSFindNext() read the SearchHandle, SearchCount, EndofSearch and LastNameOffset of a TRANS2_FIND_FIRST2 or TRANS2_FIND_NEXT2 response at ParameterOffset. validate_t2() bounds the offset at 1024 and ParameterCount below 512, and nothing compares them with the number of bytes SendReceive() copied into the buffer or with the size of the response parameters. smb_init() places the request and the response in the same cifs_request allocation and cifs_buf_get() clears only the start of it, so a short response with a ParameterOffset past its end has the search handle, the entry count, the end-of-search flag and the last-entry offset read out of the request that was just sent, or out of whatever the allocation held before, and a ParameterCount smaller than the parameters has them read past the end of the parameter block. The reads stay inside the allocation, but what they return is not part of the response, and CIFSFindFirst() then hands back a search handle the server never sent. That handle is sent back to the server in the next FIND_NEXT2 or FIND_CLOSE2, so two bytes of the buffer leak at an offset the server picks. SMB1 is not negotiated by default; reaching this code requires an explicit vers=1.0 mount. Reject a response whose parameter area is smaller than the response parameters or extends past the received length, returning smb_EIO2() with a new smb_eio_traces value for each of the two responses, like the other response checks this file gained since v6.19. Backports to trees before v6.19 need smb_EIO2() replaced with -EINVAL and the trace.h hunk dropped. A conforming server is not affected. The parameter block of a transaction response is part of the SMB, so ParameterOffset + ParameterCount cannot exceed the smbCalcSize() bytes that SendReceive() copies, and the response parameters are 10 bytes for FIND_FIRST2 and 8 bytes for FIND_NEXT2, which is what T2_FFIRST_RSP_PARMS and T2_FNEXT_RSP_PARMS hold. This patch depends on "smb: client: reject FIND data areas that run past the received response", whose declarations it extends. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org # 6.19.x Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifssmb.c | 34 ++++++++++++++++++++++++++++------ fs/smb/client/trace.h | 2 ++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index bb71fed940a5..94ed6a2d3541 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4408,9 +4408,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_search_info *psrch_inf, bool msearch) { /* level 257 SMB_ */ + unsigned int parm_off, parm_count, data_off, data_count; TRANSACTION2_FFIRST_REQ *pSMB = NULL; TRANSACTION2_FFIRST_RSP *pSMBr = NULL; - unsigned int data_off, data_count; struct nls_table *nls_codepage; T2_FFIRST_RSP_PARMS *parms; unsigned int in_len, lnoff; @@ -4531,6 +4531,18 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + parm_off = le16_to_cpu(pSMBr->t2.ParameterOffset); + parm_count = le16_to_cpu(pSMBr->t2.ParameterCount); + if (parm_count < sizeof(*parms) || + parm_off + parm_count > (unsigned int)bytes_returned) { + cifs_dbg(FYI, "%s: bad parameter area offset %u count %u for response of %d\n", + __func__, parm_off, parm_count, bytes_returned); + rc = smb_EIO2(smb_eio_trace_ffirst_param_area, + parm_off, parm_count); + cifs_buf_release(pSMB); + return rc; + } + data_off = le16_to_cpu(pSMBr->t2.DataOffset); data_count = le16_to_cpu(pSMBr->t2.DataCount); if (data_off + data_count > (unsigned int)bytes_returned) { @@ -4545,8 +4557,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->smallBuf = false; psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + data_off; - parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.ParameterOffset)); + parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + parm_off); psrch_inf->endOfSearch = !!parms->EndofSearch; psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); @@ -4574,9 +4585,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, __u16 searchHandle, __u16 search_flags, struct cifs_search_info *psrch_inf) { + unsigned int parm_off, parm_count, data_off, data_count; TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; - unsigned int data_off, data_count; unsigned int name_len, in_len; T2_FNEXT_RSP_PARMS *parms; unsigned int lnoff; @@ -4663,6 +4674,18 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + parm_off = le16_to_cpu(pSMBr->t2.ParameterOffset); + parm_count = le16_to_cpu(pSMBr->t2.ParameterCount); + if (parm_count < sizeof(*parms) || + parm_off + parm_count > (unsigned int)bytes_returned) { + cifs_dbg(FYI, "%s: bad parameter area offset %u count %u for response of %d\n", + __func__, parm_off, parm_count, bytes_returned); + rc = smb_EIO2(smb_eio_trace_fnext_param_area, + parm_off, parm_count); + cifs_buf_release(pSMB); + return rc; + } + data_off = le16_to_cpu(pSMBr->t2.DataOffset); data_count = le16_to_cpu(pSMBr->t2.DataCount); if (data_off + data_count > (unsigned int)bytes_returned) { @@ -4674,8 +4697,7 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, /* BB fixme add lock for file (srch_info) struct here */ psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); - response_data = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.ParameterOffset); + response_data = (char *)&pSMBr->hdr.Protocol + parm_off; parms = (T2_FNEXT_RSP_PARMS *)response_data; response_data = (char *)&pSMBr->hdr.Protocol + data_off; diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index bb8d0197cb54..2708bedb49ab 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -30,6 +30,8 @@ EM(smb_eio_trace_ea_next_offset, "ea_next_offset") \ EM(smb_eio_trace_ea_overrun, "ea_overrun") \ EM(smb_eio_trace_extract_will_pin, "extract_will_pin") \ + EM(smb_eio_trace_ffirst_param_area, "ffirst_param_area") \ + EM(smb_eio_trace_fnext_param_area, "fnext_param_area") \ EM(smb_eio_trace_forced_shutdown, "forced_shutdown") \ EM(smb_eio_trace_getacl_bcc_too_small, "getacl_bcc_too_small") \ EM(smb_eio_trace_getcifsacl_param_count, "getcifsacl_param_count") \ From 276dcdc55b5dd238b2ec5b5db6c16ee37792a118 Mon Sep 17 00:00:00 2001 From: Diego Oliva Date: Tue, 29 Sep 2026 10:16:36 +0100 Subject: [PATCH 09/61] smb: client: drop the redundant name bounds in cifs_filldir() cifs_fill_dirent() rejects an entry whose name extends past the end of the response before it returns, for both of its callers. The two checks cifs_filldir() applies after the parse can no longer fail: the one that commit f8cf09a53a0d ("smb: client: bound dirent name against end of SMB response in cifs_filldir") added tests the same name against the same end, and the older one, which compares the name length with the length of the response, is implied by it because the name starts inside the response. Remove both. This patch depends on "smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2", which added the check to cifs_fill_dirent(). No functional change intended. Assisted-by: Bynario AI Signed-off-by: Diego Oliva Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/readdir.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 1667bba40e44..525f99181485 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -1022,17 +1022,6 @@ static int cifs_filldir(char *find_entry, struct file *file, if (rc) return rc; - if (de.namelen > max_len) { - cifs_dbg(VFS, "bad search response length %zd past smb end\n", - de.namelen); - return -EINVAL; - } - - if (de.name + de.namelen > end_of_smb) { - cifs_dbg(VFS, "search entry name extends past end of SMB\n"); - return -EINVAL; - } - /* skip . and .. since we added them first */ if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) return 0; From 689ab4c8d1597360064cddc0299089ab19ff7e3d Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 17:08:52 -0300 Subject: [PATCH 10/61] smb: client: rename mfsymlink helpers to the smb2_ prefix smb3_query_mf_symlink() and smb3_create_mf_symlink() are installed from smb20_operations through smb311_operations, so they serve every SMB2 dialect rather than only SMB3. Rename them with the smb2_ prefix to match. No functional change. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/link.c | 4 ++-- fs/smb/client/smb2ops.c | 16 ++++++++-------- fs/smb/client/smb2proto.h | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index 8d5d6aca742a..694de8864db7 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -309,7 +309,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, * SMB 2.1/SMB3 Protocol specific functions */ int -smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +smb2_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_read) { @@ -363,7 +363,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, } int -smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +smb2_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written) { diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 583ab4c4d773..c441b6d9a693 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -5810,8 +5810,8 @@ struct smb_version_operations smb20_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -5913,8 +5913,8 @@ struct smb_version_operations smb21_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -6020,8 +6020,8 @@ struct smb_version_operations smb30_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -6136,8 +6136,8 @@ struct smb_version_operations smb311_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 2e9f70096825..2425ad4beeea 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -91,11 +91,11 @@ int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb); -int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int smb2_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written); -int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int smb2_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_read); From 54a53dd9b6d987d887aa29e2aaf7e89860bb496b Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 17:08:52 -0300 Subject: [PATCH 11/61] smb: client: set lease_granted before revalidating inode in cifs_nt_open() cifs_new_fileinfo() -> set_fid() sets CIFS_I(inode)->lease_granted only after cifs_get_inode_info() has run. Opens that cifs_get_inode_info() issues for the inode -- such as the Minshall+French symlink probe or an open compounded in smb2_compound_op() -- therefore find lease_granted clear, go out leaseless, and make the server break the lease just granted to the file. Set lease_granted right after the open succeeds, before cifs_get_inode_info(), so those opens reuse the inode's lease key. Only raise it: lease_granted is kept set for the inode's lifetime, so lowering it here could clobber a lease still held through another open. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 11355d6bf89d..e08ed5072c29 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -622,6 +622,10 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_ if (rdwr_for_fscache == 2) cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); + if (server->vals->protocol_id > SMB20_PROT_ID && + *oplock != SMB2_OPLOCK_LEVEL_NONE) + CIFS_I(inode)->lease_granted = true; + /* TODO: Add support for calling posix query info but with passing in fid */ if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, From 7c4bf530aefad8b5b47ffb464daa90b3f0662930 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 17:08:52 -0300 Subject: [PATCH 12/61] smb: client: avoid breaking the file lease when probing mfsymlinks cifs_check_mf_symlink() probes any file whose size matches CIFS_MF_SYMLINK_FILE_SIZE as a possible Minshall+French symlink. smb2_query_mf_symlink() did so with a fresh leaseless SMB2_open, so the server saw a second conflicting opener and broke the RWH lease the client had just been granted on the same file, needlessly churning the cache. Rework smb2_query_mf_symlink() to issue a single OPEN/READ/CLOSE compound that either reuses an already open handle via cifs_get_readable_path() or, failing that, opens with the inode's lease key so the server treats it as the same lease holder. Thread the inode down to the ->query_mf_symlink() handlers, rename check_mf_symlink() to cifs_check_mf_symlink(), and validate the read payload against the response buffer before copying it. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 9 +- fs/smb/client/cifsproto.h | 13 +- fs/smb/client/inode.c | 22 ++-- fs/smb/client/link.c | 271 ++++++++++++++++++++++++++++---------- fs/smb/client/smb2glob.h | 8 ++ fs/smb/client/smb2inode.c | 3 - fs/smb/client/smb2pdu.c | 13 +- fs/smb/client/smb2proto.h | 10 +- 8 files changed, 245 insertions(+), 104 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index d74cc9e8c413..a3f54dd19fb0 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -543,9 +543,12 @@ struct smb_version_operations { struct cifsFileInfo *src_file, void __user *); int (*notify)(const unsigned int xid, struct file *pfile, void __user *pbuf, bool return_changes); - int (*query_mf_symlink)(unsigned int, struct cifs_tcon *, - struct cifs_sb_info *, const unsigned char *, - char *, unsigned int *); + int (*query_mf_symlink)(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read); int (*create_mf_symlink)(unsigned int, struct cifs_tcon *, struct cifs_sb_info *, const unsigned char *, char *, unsigned int *); diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 00168839c123..582cd182c616 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -319,9 +319,10 @@ int generate_smb311signingkey(struct cifs_ses *ses, #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb, const char *reason, int rc); bool couldbe_mf_symlink(const struct cifs_fattr *fattr); -int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - const unsigned char *path); +int cifs_check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, struct inode *inode, + struct cifs_fattr *fattr); int E_md4hash(const unsigned char *passwd, unsigned char *p16, const struct nls_table *codepage); @@ -337,9 +338,11 @@ struct cifs_ses *cifs_get_smb_ses(struct TCP_Server_Info *server, int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); -int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int cifs_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, - const unsigned char *path, char *pbuf, + const char *full_path, + struct inode *inode, char *pbuf, unsigned int *pbytes_read); int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index f29555f3c7d0..00dbf5342c10 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -456,7 +456,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path, FILE_UNIX_BASIC_INFO find_data; struct cifs_tcon *tcon; struct tcon_link *tlink; - int rc, tmprc; + int rc; cifs_dbg(FYI, "Getting info on %s\n", full_path); @@ -486,8 +486,10 @@ static int cifs_get_unix_fattr(const unsigned char *full_path, /* check for Minshall+French symlinks */ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + *pinode, fattr); + if (rc) + return rc; } if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { @@ -1437,8 +1439,8 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, /* check for Minshall+French symlinks */ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + *inode, fattr); } out: @@ -1475,6 +1477,7 @@ int cifs_get_inode_info(struct inode **inode, static int smb311_posix_get_fattr(struct cifs_open_info_data *data, struct cifs_fattr *fattr, const char *full_path, + struct inode *inode, struct super_block *sb, const unsigned int xid) { @@ -1483,7 +1486,6 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_tcon *tcon; struct tcon_link *tlink; - int tmprc; int rc = 0; tlink = cifs_sb_tlink(cifs_sb); @@ -1537,8 +1539,8 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, */ /* check for Minshall+French symlinks */ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + inode, fattr); } out: @@ -1561,7 +1563,7 @@ int smb311_posix_get_inode_info(struct inode **inode, return 0; } - rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid); + rc = smb311_posix_get_fattr(data, &fattr, full_path, *inode, sb, xid); if (rc) goto out; @@ -1713,7 +1715,7 @@ struct inode *cifs_root_iget(struct super_block *sb) convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); if (tcon->posix_extensions) - rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid); + rc = smb311_posix_get_fattr(NULL, &fattr, path, inode, sb, xid); else rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index 694de8864db7..034c9174018d 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -17,6 +17,7 @@ #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "smb2proto.h" +#include "smb2glob.h" #include "cifs_ioctl.h" #include "fs_context.h" #include "reparse.h" @@ -166,30 +167,34 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - const unsigned char *path) +int cifs_check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, struct inode *inode, + struct cifs_fattr *fattr) { - int rc; - u8 *buf = NULL; - unsigned int link_len = 0; + struct TCP_Server_Info *server = tcon->ses->server; + char *buf __free(kfree) = NULL; unsigned int bytes_read = 0; + unsigned int link_len = 0; char *symlink = NULL; + int rc = 0; if (!couldbe_mf_symlink(fattr)) - /* it's not a symlink */ - return 0; + goto out; buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + rc = -ENOMEM; + goto out; + } - if (tcon->ses->server->ops->query_mf_symlink) - rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, - cifs_sb, path, buf, &bytes_read); - else + if (server->ops->query_mf_symlink) { + rc = server->ops->query_mf_symlink(xid, tcon, + cifs_sb, full_path, + inode, buf, &bytes_read); + } else { rc = -ENOSYS; + } if (rc) goto out; @@ -214,19 +219,17 @@ check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, fattr->cf_dtype = DT_LNK; fattr->cf_symlink_target = symlink; out: - kfree(buf); - return rc; + cifs_dbg(FYI, "%s: rc = %d\n", __func__, rc); + return rc == -ENOMEM ? rc : 0; } #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY -/* - * SMB 1.0 Protocol specific functions - */ - -int -cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, const unsigned char *path, - char *pbuf, unsigned int *pbytes_read) +int cifs_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read) { int rc; int oplock = 0; @@ -242,7 +245,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, .desired_access = GENERIC_READ, .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), .disposition = FILE_OPEN, - .path = path, + .path = full_path, .fid = &fid, }; @@ -305,60 +308,184 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -/* - * SMB 2.1/SMB3 Protocol specific functions - */ -int -smb2_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, const unsigned char *path, - char *pbuf, unsigned int *pbytes_read) +int smb2_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read) { - int rc; + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; + struct kvec read_iov[2], close_iov; + struct cifsFileInfo *cfile = NULL; + struct smb2_read_rsp *read_rsp; + struct TCP_Server_Info *server; + int retries = 0, cur_sleep = 0; + struct cifs_io_parms io_parms; + struct smb2_read_req *req; + struct smb_rqst rqst[3]; + unsigned int total_len; + struct kvec rsp_iov[3]; struct cifs_fid fid; - struct cifs_open_parms oparms; - struct cifs_io_parms io_parms = {0}; - int buf_type = CIFS_NO_BUFFER; - __le16 *utf16_path; - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; - struct cifs_open_info_data data = {}; + int rsp_buftype[3]; + struct kvec *riov; + int num_rqst; + __u8 oplock; + int flags; + u32 dlen; + int rc; - oparms = (struct cifs_open_parms) { - .tcon = tcon, - .cifs_sb = cifs_sb, - .path = path, - .desired_access = GENERIC_READ, - .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), - .disposition = FILE_OPEN, - .fid = &fid, - }; + cifs_get_readable_path(tcon, full_path, &cfile); + *pbytes_read = 0; +again: + flags = 0; + num_rqst = 0; + req = NULL; + oplock = SMB2_OPLOCK_LEVEL_NONE; + server = cifs_pick_channel(tcon->ses); - utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (utf16_path == NULL) - return -ENOMEM; + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, &data, NULL, - NULL, NULL); - if (rc) - goto qmf_out_open_fail; + for (int i = 0; i < ARRAY_SIZE(rsp_buftype); i++) + rsp_buftype[i] = CIFS_NO_BUFFER; - if (data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { - /* it's not a symlink */ - rc = -ENOENT; /* Is there a better rc to return? */ - goto qmf_out; + memset(rqst, 0, sizeof(rqst)); + memset(rsp_iov, 0, sizeof(rsp_iov)); + + if (!cfile) { + __le16 *utf16_path __free(kfree) = NULL; + struct cifs_open_parms oparms; + + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); + if (!utf16_path) { + rc = -ENOMEM; + goto out; + } + + if (inode && CIFS_I(inode)->lease_granted && + server->ops->get_lease_key) { + oplock = SMB2_OPLOCK_LEVEL_LEASE; + server->ops->get_lease_key(inode, &fid); + } + + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, GENERIC_READ, + FILE_OPEN, CREATE_NOT_DIR, ACL_NO_MODE); + oparms.fid = &fid; + + memset(open_iov, 0, sizeof(open_iov)); + rqst[num_rqst].rq_iov = open_iov; + rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; + + rc = SMB2_open_init(tcon, server, &rqst[num_rqst], + &oplock, &oparms, utf16_path); + if (rc) + goto out; + smb2_set_next_command(tcon, &rqst[num_rqst++]); } - io_parms.netfid = fid.netfid; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; - io_parms.offset = 0; - io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; - io_parms.persistent_fid = fid.persistent_fid; - io_parms.volatile_fid = fid.volatile_fid; - rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type); -qmf_out: - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); -qmf_out_open_fail: - kfree(utf16_path); + io_parms = (struct cifs_io_parms) { + .pid = current->tgid, + .tcon = tcon, + .length = CIFS_MF_SYMLINK_FILE_SIZE, + .server = server, + .persistent_fid = COMP_PID(cfile), + .volatile_fid = COMP_VID(cfile), + }; + + rc = smb2_new_read_req((void **)&req, &total_len, + &io_parms, NULL, 0, 0); + if (rc) + goto out; + + read_iov[0].iov_base = req; + read_iov[0].iov_len = total_len; + rqst[num_rqst].rq_iov = read_iov; + rqst[num_rqst].rq_nvec = 1; + if (!cfile) { + smb2_set_next_command(tcon, &rqst[num_rqst]); + smb2_set_related(&rqst[num_rqst]); + } + num_rqst++; + + if (!cfile) { + flags |= CIFS_CP_CREATE_CLOSE_OP; + memset(&close_iov, 0, sizeof(close_iov)); + rqst[num_rqst].rq_iov = &close_iov; + rqst[num_rqst].rq_nvec = 1; + rc = SMB2_close_init(tcon, server, &rqst[num_rqst], + COMPOUND_FID, COMPOUND_FID, false); + smb2_set_related(&rqst[num_rqst++]); + if (rc) + goto out; + } + + if (retries) { + if (cur_sleep) + msleep(cur_sleep); + for (int i = 0; i < num_rqst; i++) + smb2_set_replay(server, &rqst[i]); + } + + rc = compound_send_recv(xid, tcon->ses, server, flags, + num_rqst, rqst, rsp_buftype, rsp_iov); + if (rc) { + if (rc != -ENODATA) { + if (rc != -ENOENT) + cifs_stats_fail_inc(tcon, SMB2_READ_HE); + cifs_dbg(FYI, "%s: failed to read file: %d\n", + __func__, rc); + trace_smb3_read_err(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, io_parms.length, + rc); + } else { + trace_smb3_read_done(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, 0); + } + rc = rc == -ENODATA ? 0 : rc; + goto out; + } + trace_smb3_read_done(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, io_parms.length); + + riov = &rsp_iov[!cfile ? 1 : 0]; + read_rsp = riov->iov_base; + dlen = le32_to_cpu(read_rsp->DataLength); + if (dlen > CIFS_MAX_MSGSIZE || dlen > io_parms.length) { + cifs_dbg(FYI, "%s: bad length %u for count %u\n", + __func__, dlen, io_parms.length); + rc = smb_EIO2(smb_eio_trace_read_overlarge, + dlen, io_parms.length); + } else if (dlen != CIFS_MF_SYMLINK_FILE_SIZE) { + rc = -ENOENT; + } else { + rc = smb2_validate_iov(read_rsp->DataOffset, dlen, riov, + CIFS_MF_SYMLINK_FILE_SIZE); + } + + if (!rc) { + memcpy(pbuf, (u8 *)read_rsp + read_rsp->DataOffset, dlen); + *pbytes_read = dlen; + } + +out: + if (!cfile) { + SMB2_open_free(&rqst[0]); + SMB2_close_free(&rqst[2]); + } + cifs_small_buf_release(req); + for (int i = 0; i < ARRAY_SIZE(rsp_buftype); i++) + free_rsp_buf(rsp_buftype[i], rsp_iov[i].iov_base); + + if (is_replayable_error(rc) && + smb2_should_replay(tcon, &retries, &cur_sleep)) + goto again; + + if (cfile) + cifsFileInfo_put(cfile); return rc; } diff --git a/fs/smb/client/smb2glob.h b/fs/smb/client/smb2glob.h index 19da74b1edab..99c6f5a635fc 100644 --- a/fs/smb/client/smb2glob.h +++ b/fs/smb/client/smb2glob.h @@ -13,6 +13,14 @@ #ifndef _SMB2_GLOB_H #define _SMB2_GLOB_H +#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID) +#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID) + +static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) +{ + cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); +} + /* ***************************************************************** * Constants go here diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index f46a62eae659..7c1472fe5b9a 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -200,9 +200,6 @@ static void set_next_compound(struct cifs_tcon *tcon, (*num_rqst)++; } -#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID) -#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID) - /* * note: If cfile is passed, the reference to it is dropped here. * So make sure that you do not reuse cfile after return from this func. diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index cfe3c4b4abe7..d7479418b94f 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2113,11 +2113,6 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) return rc; } -static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) -{ - cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); -} - #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) /* These are similar values to what Windows uses */ @@ -4581,10 +4576,10 @@ static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms) * To form a chain of read requests, any read requests after the first should * have the end_of_chain boolean set to true. */ -static int -smb2_new_read_req(void **buf, unsigned int *total_len, - struct cifs_io_parms *io_parms, struct cifs_io_subrequest *rdata, - unsigned int remaining_bytes, int request_type) +int smb2_new_read_req(void **buf, unsigned int *total_len, + struct cifs_io_parms *io_parms, + struct cifs_io_subrequest *rdata, + unsigned int remaining_bytes, int request_type) { int rc = -EACCES; struct smb2_read_req *req = NULL; diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 2425ad4beeea..69a32f8311ca 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -95,9 +95,11 @@ int smb2_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written); -int smb2_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int smb2_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, - const unsigned char *path, char *pbuf, + const char *full_path, + struct inode *inode, char *pbuf, unsigned int *pbytes_read); int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb); @@ -172,6 +174,10 @@ int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, struct cifs_tcon *tcon, struct TCP_Server_Info *server, u64 persistent_fid, u64 volatile_fid); void SMB2_flush_free(struct smb_rqst *rqst); +int smb2_new_read_req(void **buf, unsigned int *total_len, + struct cifs_io_parms *io_parms, + struct cifs_io_subrequest *rdata, + unsigned int remaining_bytes, int request_type); int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data); From a4111beeade900346726acb2746f22a6313aeaf0 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 17:39:11 -0300 Subject: [PATCH 13/61] smb: client: log the selected security type on session setup failure When mounting without an explicit sec= option, ses->sectype stays Unspecified while the real mechanism is chosen later through ->select_sectype(), so a failed session setup logs a useless name: CIFS: VFS: \\server failed to create a new SMB session with Unknown: -13 Resolve the mechanism through ->select_sectype() before formatting it, as cifs_debug.c already does, so the message names the actual security type. Fixes: a8fce7c807b1 ("smb: client: improve error message when creating SMB session") Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/connect.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index ff8637301fa9..90eda91d9da9 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -4195,8 +4195,12 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, if (rc) { if (new_ses) { + enum securityEnum sectype; + + sectype = server->ops->select_sectype(server, + ses->sectype); cifs_server_dbg(VFS, "failed to create a new SMB session with %s: %d\n", - get_security_type_str(ses->sectype), rc); + get_security_type_str(sectype), rc); } spin_lock(&ses->ses_lock); if (ses->ses_status == SES_IN_SETUP) From 2bcbf169f311776dfc100d6fdb935da864cdd485 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 14/61] smb: client: remove commented-out ntlmv2_support definition Drop this leftover commented-out definition. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 98b610b2a114..e774ae0a3465 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -71,7 +71,6 @@ bool enable_gcm_256 = true; bool require_gcm_256; /* false by default */ bool enable_negotiate_signing; /* false by default */ unsigned int global_secflags = CIFSSEC_DEF; -/* unsigned int ntlmv2_support = 0; */ /* * Global transaction id (XID) information From fe3fc9f7797145d9962091557973e96187386b36 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 15/61] smb: client: remove commented-out i_flags assignment Drop this leftover commented-out assignment. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index e774ae0a3465..e705b7255b35 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -463,7 +463,6 @@ cifs_alloc_inode(struct super_block *sb) * Can not set i_flags here - they get immediately overwritten to zero * by the VFS. */ - /* cifs_inode->netfs.inode.i_flags = S_NOATIME | S_NOCMTIME; */ INIT_LIST_HEAD(&cifs_inode->openFileList); INIT_LIST_HEAD(&cifs_inode->llist); INIT_LIST_HEAD(&cifs_inode->deferred_closes); From a40b17cc9ecaaa85c3615963ec21cfed1c734340 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 16/61] smb: client: remove commented-out cancel_*_requests() calls Drop these leftover commented-out calls. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index e705b7255b35..ac9e3155c3f7 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -856,8 +856,6 @@ static void cifs_umount_begin(struct super_block *sb) spin_unlock(&tcon->tc_lock); spin_unlock(&cifs_tcp_ses_lock); - /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ - /* cancel_notify_requests(tcon); */ if (tcon->ses && tcon->ses->server) { cifs_dbg(FYI, "wake up tasks now - umount begin not complete\n"); wake_up_all(&tcon->ses->server->request_q); From 775bf158872f875e887d1ab4c2a52de8e40b53e8 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 17/61] smb: client: remove commented-out oplock assignment Drop this leftover commented-out assignment. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 94ed6a2d3541..8e648097cf16 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1308,9 +1308,6 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(FYI, "Error in Open = %d\n", rc); } else { /* BB verify if wct == 15 */ - -/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/ - *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Let caller know file was created so we can set the mode. */ /* Do we care about the CreateAction in any other cases? */ From 1e0e189998c0018d45485b2dfcf7d6be599f8e89 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 18/61] smb: client: remove commented-out write debug message Drop this leftover commented-out debug message. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 8e648097cf16..cd4e119c8f4e 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1793,7 +1793,6 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, *nbytes = 0; - /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/ if (tcon->ses == NULL) return -ECONNABORTED; From a59aeb074cacd14388f0489f3c52f29fb956a567 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 19/61] smb: client: remove commented-out LOCK_RSP declaration Drop this leftover commented-out declaration. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index cd4e119c8f4e..ddb6301f9c07 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -2225,7 +2225,6 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, { int rc = 0; LOCK_REQ *pSMB = NULL; -/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ unsigned int in_len; int bytes_returned; int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT; From bdf9ccc58bc6e64ccf1302f8c9f0f204bd185777 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:34 -0300 Subject: [PATCH 20/61] smb: client: remove commented-out QPathInfo debug message Drop this leftover commented-out debug message. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index ddb6301f9c07..f09a29fc3533 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4151,7 +4151,6 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, int name_len; __u16 params, byte_count; - /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */ QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); From 5c2824d98b30cb649bb2b5a0abde83c8a8b30077 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:35 -0300 Subject: [PATCH 21/61] smb: client: remove commented-out CIFSSMBWinSetPerms() call Drop this leftover commented-out call. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/dir.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c index 1a56fa4d0e89..26c8adbb8e4e 100644 --- a/fs/smb/client/dir.c +++ b/fs/smb/client/dir.c @@ -419,7 +419,6 @@ static int __cifs_do_create(struct inode *dir, struct dentry *direntry, * BB implement mode setting via Windows security * descriptors e.g. */ - /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/ /* Could set r/o dos attribute if mode & 0222 == 0 */ } From e4a1508b8b3f2f4d72795ff2a68c95c24d38941c Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:02:35 -0300 Subject: [PATCH 22/61] smb: client: remove commented-out time conversion debug message Drop this leftover commented-out debug message. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/netmisc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/smb/client/netmisc.c b/fs/smb/client/netmisc.c index bddadee82d0c..cf737ede1ab3 100644 --- a/fs/smb/client/netmisc.c +++ b/fs/smb/client/netmisc.c @@ -204,9 +204,6 @@ struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) sec += 24 * 60 * 60 * days; ts.tv_sec = sec + offset; - - /* cifs_dbg(FYI, "sec after cnvrt dos to unix time %d\n",sec); */ - ts.tv_nsec = 0; return ts; } From bb274d81559771e292a517180c327993604f6111 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:03:02 -0300 Subject: [PATCH 23/61] smb: client: remove commented-out Unix caps assignment Drop this leftover commented-out assignment. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/ioctl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c index 2f152d76be7d..71f92ebb3432 100644 --- a/fs/smb/client/ioctl.c +++ b/fs/smb/client/ioctl.c @@ -513,7 +513,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) if (pSMBFile == NULL) break; tcon = tlink_tcon(pSMBFile->tlink); - /* caps = le64_to_cpu(tcon->fsUnixInfo.Capability); */ if (get_user(ExtAttrBits, (int __user *)arg)) { rc = -EFAULT; From 5dce507a8ba4ac3c5d7a065659f44b8732969e3e Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:03:02 -0300 Subject: [PATCH 24/61] smb: client: clean up cifs_buf_release() Remove the leftover commented-out debug message, drop the now-unnecessary braces around the single return, and test !buf_to_free instead of comparing against NULL. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/misc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index 05168284f205..ec28f102ea08 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -215,10 +215,8 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { - /* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/ + if (!buf_to_free) return; - } mempool_free(buf_to_free, cifs_req_poolp); atomic_dec(&buf_alloc_count); From c684280717a8e044ca99d594427cfb85be9d8d39 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:24:02 -0300 Subject: [PATCH 25/61] smb: client: remove the internal CIFS version number CIFS carried a hand-maintained internal version (CIFS_VERSION and SMB3_PRODUCT_BUILD) that had to be bumped by hand on every change. The kernel version already identifies which features and fixes are present, so drop it. Remove MODULE_VERSION() and the "CIFS Version" line in DebugData, and send LINUX_VERSION_SUBLEVEL in the NTLMSSP ProductBuild field so the advertised version is derived entirely from the kernel version -- its major and minor were already taken from there. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifs_debug.c | 1 - fs/smb/client/cifsfs.c | 1 - fs/smb/client/cifsfs.h | 3 --- fs/smb/client/ntlmssp.h | 2 +- fs/smb/client/sess.c | 4 ++-- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 3761d3ad6088..577f0ddede90 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -450,7 +450,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_puts(m, "Display Internal CIFS Data Structures for Debugging\n" "---------------------------------------------------\n"); - seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); seq_printf(m, "Features:"); #ifdef CONFIG_CIFS_DFS_UPCALL seq_printf(m, " DFS"); diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index ac9e3155c3f7..5d7c786d1801 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -2249,7 +2249,6 @@ MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ MODULE_DESCRIPTION ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and " "also older servers complying with the SNIA CIFS Specification)"); -MODULE_VERSION(CIFS_VERSION); MODULE_SOFTDEP("nls"); MODULE_SOFTDEP("aes"); MODULE_SOFTDEP("aead2"); diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index e3d820c9778b..0b064236b4dc 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -167,7 +167,4 @@ char *cifs_silly_fullpath(struct dentry *dentry); extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -/* when changing internal version - update following two lines at same time */ -#define SMB3_PRODUCT_BUILD 61 -#define CIFS_VERSION "2.61" #endif /* _CIFSFS_H */ diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index be0365f08396..7d68153985f8 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -93,7 +93,7 @@ typedef struct _NEGOTIATE_MESSAGE { struct ntlmssp_version { __u8 ProductMajorVersion; __u8 ProductMinorVersion; - __le16 ProductBuild; /* we send the cifs.ko module version here */ + __le16 ProductBuild; /* we send the kernel sublevel here */ __u8 Reserved[3]; __u8 NTLMRevisionCurrent; /* currently 0x0F */ } __packed; diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 0ab3f37d4809..fc105308226c 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -890,7 +890,7 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR; sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD); + sec_blob->Version.ProductBuild = cpu_to_le16(LINUX_VERSION_SUBLEVEL); sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; tmp = *pbuffer + sizeof(struct negotiate_message); @@ -956,7 +956,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR; sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD); + sec_blob->Version.ProductBuild = cpu_to_le16(LINUX_VERSION_SUBLEVEL); sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE); From 1f0cd146ba93133cbee9b7202f9fd092078cd273 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:45:56 -0300 Subject: [PATCH 26/61] smb: client: remove unused overrideSecFlg from struct cifs_ses overrideSecFlg has no readers or writers anywhere in the tree; drop it. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index a3f54dd19fb0..d80853008f90 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1070,7 +1070,6 @@ struct cifs_ses { struct TCP_Server_Info *server; /* pointer to server info */ int ses_count; /* reference counter */ enum ses_status_enum ses_status; /* updates protected by cifs_tcp_ses_lock */ - unsigned int overrideSecFlg; /* if non-zero override global sec flags */ char *serverOS; /* name of operating system underlying server */ char *serverNOS; /* name of network operating system of server */ char *serverDomain; /* security realm of server */ From 5be685f3516c3ffe8a005285a465cf3de23b1a83 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:53:24 -0300 Subject: [PATCH 27/61] smb: client: remove write-only max_rw from TCP_Server_Info max_rw is assigned from the SMB1 negotiate response but never read, so drop it. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 3 --- fs/smb/client/cifssmb.c | 1 - 2 files changed, 4 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index d80853008f90..7c2ab3f56fae 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -733,9 +733,6 @@ struct TCP_Server_Info { /* message size the server can send or receive for non-raw SMBs */ /* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */ /* when socket is setup (and during reconnect) before NegProt sent */ - unsigned int max_rw; /* maxRw specifies the maximum */ - /* message size the server can send or receive for */ - /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ unsigned int capabilities; /* selective disabling of caps by smb sess */ int timeAdj; /* Adjust for difference in server time zone in sec */ __u64 current_mid; /* multiplex id - rotating counter, protected by mid_counter_lock */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index f09a29fc3533..31695f1efe89 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -502,7 +502,6 @@ CIFSSMBNegotiate(const unsigned int xid, server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); /* set up max_read for readahead check */ server->max_read = server->maxBuf; - server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->session_key_id = pSMBr->SessionKey; From 6b56bb27466f1908462bc06bd06e3fc1848e5373 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:53:46 -0300 Subject: [PATCH 28/61] smb: client: remove write-only sec_kerberosu2u from TCP_Server_Info sec_kerberosu2u is set when the krb5 user-to-user OID is seen but is never read, so the OID branch that sets it has no effect. Drop both. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/asn1.c | 2 -- fs/smb/client/cifsglob.h | 1 - 2 files changed, 3 deletions(-) diff --git a/fs/smb/client/asn1.c b/fs/smb/client/asn1.c index 214a44509e7b..b610780c6802 100644 --- a/fs/smb/client/asn1.c +++ b/fs/smb/client/asn1.c @@ -46,8 +46,6 @@ int cifs_neg_token_init_mech_type(void *context, size_t hdrlen, oid = look_up_OID(value, vlen); if (oid == OID_mskrb5) server->sec_mskerberos = true; - else if (oid == OID_krb5u2u) - server->sec_kerberosu2u = true; else if (oid == OID_krb5) server->sec_kerberos = true; else if (oid == OID_ntlmssp) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 7c2ab3f56fae..65ed7a8fb574 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -752,7 +752,6 @@ struct TCP_Server_Info { char negflavor; /* NEGOTIATE response flavor */ /* extended security flavors that server supports */ bool sec_ntlmssp; /* supports NTLMSSP */ - bool sec_kerberosu2u; /* supports U2U Kerberos */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_iakerb; /* supports pass-through auth for Kerberos (krb5 proxy) */ From 5ef569b5b78913e8dfda4bbd2c49fe1d1366ca19 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:54:08 -0300 Subject: [PATCH 29/61] smb: client: remove write-only signing_negotiated from TCP_Server_Info signing_negotiated is set when a signing context is received but never read; drop it. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 1 - fs/smb/client/smb2pdu.c | 1 - 2 files changed, 2 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 65ed7a8fb574..96b464cf8bc9 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -797,7 +797,6 @@ struct TCP_Server_Info { __le16 cipher_type; /* save initial negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; - bool signing_negotiated; /* true if valid signing context rcvd from server */ bool posix_ext_supported; struct delayed_work reconnect; /* reconnect workqueue job */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index d7479418b94f..71d44c6da4b5 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -960,7 +960,6 @@ static void decode_signing_ctx(struct TCP_Server_Info *server, return; } - server->signing_negotiated = true; server->signing_algorithm = le16_to_cpu(pctxt->SigningAlgorithms[0]); cifs_dbg(FYI, "signing algorithm %d chosen\n", server->signing_algorithm); From 62d973b788e05c3c428bd328e68dd48f45492eaf Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 18:54:30 -0300 Subject: [PATCH 30/61] smb: client: remove unused num_acl_set stat from cifs_tcon num_acl_set is only ever reset to 0 -- never incremented or reported -- so drop the dead counter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 1 - fs/smb/client/smb1ops.c | 1 - 2 files changed, 2 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 96b464cf8bc9..7bf8f372697d 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1231,7 +1231,6 @@ struct cifs_tcon { atomic_t num_symlinks; atomic_t num_locks; atomic_t num_acl_get; - atomic_t num_acl_set; } cifs_stats; struct { atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS]; diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 3ac4126267f6..7d2ddf2dcad9 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -815,7 +815,6 @@ cifs_clear_stats(struct cifs_tcon *tcon) atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0); atomic_set(&tcon->stats.cifs_stats.num_locks, 0); atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0); - atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0); } static void From 273913b7c33a591e1747ffdc2bfc4daaf88bbb88 Mon Sep 17 00:00:00 2001 From: Huiwen He Date: Wed, 5 Aug 2026 09:54:46 +0800 Subject: [PATCH 31/61] smb: client: implement fileattr_set for compression flags CIFS handles FS_IOC_SETFLAGS in cifs_ioctl() because it does not implement ->fileattr_set. This causes the request to fall back from the generic fileattr path and bypass its permission and serialization checks. Implement ->fileattr_set for regular files and directories and use the existing compression helper for FS_COMPR_FL. Accept an unchanged FS_CASEFOLD_FL reported by fileattr_get so chattr can update compression on case-insensitive shares. Tested chattr +c and -c on files and directories against Samba. Non-owner and read-only mount requests were rejected by the VFS checks. Signed-off-by: Huiwen He Reviewed-by: ChenXiaoSong Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifsfs.c | 4 +- fs/smb/client/cifsfs.h | 2 + fs/smb/client/ioctl.c | 89 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 5d7c786d1801..f65141e64adf 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1194,7 +1194,7 @@ int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) u32 attrs; /* Preserve FS_COMPR_FL previously reported by cifs_ioctl(). */ - if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) + if (READ_ONCE(CIFS_I(inode)->cifsAttrs) & ATTR_COMPRESSED) fa->flags |= FS_COMPR_FL; /* @@ -1255,6 +1255,7 @@ const struct inode_operations cifs_dir_inode_ops = { .get_acl = cifs_get_acl, .set_acl = cifs_set_acl, .fileattr_get = cifs_fileattr_get, + .fileattr_set = cifs_fileattr_set, }; const struct inode_operations cifs_file_inode_ops = { @@ -1266,6 +1267,7 @@ const struct inode_operations cifs_file_inode_ops = { .get_acl = cifs_get_acl, .set_acl = cifs_set_acl, .fileattr_get = cifs_fileattr_get, + .fileattr_set = cifs_fileattr_set, }; const char *cifs_get_link(struct dentry *dentry, struct inode *inode, diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 0b064236b4dc..3c96521513cb 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -91,6 +91,8 @@ extern const struct inode_operations cifs_namespace_inode_operations; struct file_kattr; int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); +int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa); /* Functions related to files and directories */ diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c index 71f92ebb3432..eb5cf580628d 100644 --- a/fs/smb/client/ioctl.c +++ b/fs/smb/client/ioctl.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -67,11 +68,11 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, return rc; } -static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, +static int cifs_set_compression_by_path(unsigned int xid, struct dentry *dentry, struct cifs_tcon *tcon, __u16 compression_state) { - struct inode *inode = file_inode(filep); + struct inode *inode = d_inode(dentry); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct TCP_Server_Info *server = tcon->ses->server; struct cifs_open_parms oparms; @@ -92,11 +93,11 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, cifs_sb->mnt_cifs_serverino_autodisabled) return -EOPNOTSUPP; - if (d_unhashed(filep->f_path.dentry)) + if (d_unhashed(dentry)) return -ESTALE; page = alloc_dentry_path(); - full_path = build_path_from_dentry(filep->f_path.dentry, page); + full_path = build_path_from_dentry(dentry, page); if (IS_ERR(full_path)) { free_dentry_path(page); return PTR_ERR(full_path); @@ -123,6 +124,10 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, goto close; uniqueid = le64_to_cpu(data.fi.IndexNumber); + if (!uniqueid) { + rc = -EOPNOTSUPP; + goto close; + } if (uniqueid != CIFS_I(inode)->uniqueid) { rc = -ESTALE; goto close; @@ -140,14 +145,14 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, return rc; } -static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep, - struct cifs_tcon *tcon, - struct cifsFileInfo *cfile, - __u16 compression_state) +static int cifs_set_compression(unsigned int xid, struct dentry *dentry, + struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, + __u16 compression_state) { struct cifsFileInfo *wfile; struct cifs_tcon *wtcon; - struct inode *inode = file_inode(filep); + struct inode *inode = d_inode(dentry); int rc; if (!tcon->ses->server->ops->set_compression) @@ -172,10 +177,68 @@ static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep, return rc; } - return cifs_set_compression_by_path(xid, filep, tcon, + return cifs_set_compression_by_path(xid, dentry, tcon, compression_state); } +int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry); + struct inode *inode = d_inode(dentry); + struct file_kattr current_fa = {}; + u32 allowed = FS_COMPR_FL; + struct tcon_link *tlink; + __u16 compression_state; + bool enable_compression; + struct cifs_tcon *tcon; + unsigned int xid; + int rc; + + if (!fa->flags_valid) + return -EOPNOTSUPP; + + /* + * chattr writes back all flags returned by fileattr_get(). Accept + * FS_CASEFOLD_FL only when it reflects the share's casefold state. + */ + if (fa->flags & FS_CASEFOLD_FL) { + rc = cifs_fileattr_get(dentry, ¤t_fa); + if (rc) + return rc; + if (current_fa.flags & FS_CASEFOLD_FL) + allowed |= FS_CASEFOLD_FL; + } + if (fa->flags & ~allowed) + return -EOPNOTSUPP; + + enable_compression = fa->flags & FS_COMPR_FL; + compression_state = enable_compression ? COMPRESSION_FORMAT_DEFAULT : + COMPRESSION_FORMAT_NONE; + + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + xid = get_xid(); + rc = cifs_set_compression(xid, dentry, tcon, NULL, compression_state); + free_xid(xid); + cifs_put_tlink(tlink); + + if (!rc) { + spin_lock(&inode->i_lock); + if (enable_compression) + CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_COMPRESSED; + else + CIFS_I(inode)->cifsAttrs &= ~FILE_ATTRIBUTE_COMPRESSED; + spin_unlock(&inode->i_lock); + } + + cifs_dbg(FYI, "set compress flag rc %d\n", rc); + return rc; +} + static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, unsigned long srcfd) { @@ -540,9 +603,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE; - rc = cifs_ioctl_set_compression(xid, filep, tcon, - pSMBFile, - compression_state); + rc = cifs_set_compression(xid, filep->f_path.dentry, + tcon, pSMBFile, + compression_state); if (rc == 0) { spin_lock(&inode->i_lock); if (enable_compression) From c38f4e84c9356a9e14d602a00c4afca09c79dc7a Mon Sep 17 00:00:00 2001 From: Huiwen He Date: Wed, 5 Aug 2026 09:54:47 +0800 Subject: [PATCH 32/61] smb: client: remove unused file flags ioctl handlers FS_IOC_GETFLAGS and FS_IOC_SETFLAGS are now handled by the generic VFS fileattr path, so their cifs_ioctl() handlers are unreachable. Remove the handlers and associated state. Signed-off-by: Huiwen He Reviewed-by: ChenXiaoSong Reviewed-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/cifsfs.c | 2 +- fs/smb/client/ioctl.c | 81 ------------------------------------------ 2 files changed, 1 insertion(+), 82 deletions(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index f65141e64adf..f4743b463ebd 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1193,7 +1193,7 @@ int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) struct inode *inode = d_inode(dentry); u32 attrs; - /* Preserve FS_COMPR_FL previously reported by cifs_ioctl(). */ + /* Report the cached SMB compressed attribute as FS_COMPR_FL. */ if (READ_ONCE(CIFS_I(inode)->cifsAttrs) & ATTR_COMPRESSED) fa->flags |= FS_COMPR_FL; diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c index eb5cf580628d..af4664f5b120 100644 --- a/fs/smb/client/ioctl.c +++ b/fs/smb/client/ioctl.c @@ -527,14 +527,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) struct cifs_tcon *tcon; struct tcon_link *tlink; struct cifs_sb_info *cifs_sb; - __u64 ExtAttrBits = 0; - bool enable_compression; - __u16 compression_state; -#ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - __u64 caps; -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -#endif /* CONFIG_CIFS_POSIX */ xid = get_xid(); @@ -545,79 +537,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) trace_smb3_ioctl(xid, pSMBFile->fid.persistent_fid, command); switch (command) { - case FS_IOC_GETFLAGS: - if (pSMBFile == NULL) - break; - tcon = tlink_tcon(pSMBFile->tlink); -#ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - caps = le64_to_cpu(tcon->fsUnixInfo.Capability); - if (CIFS_UNIX_EXTATTR_CAP & caps) { - __u64 ExtAttrMask = 0; - rc = CIFSGetExtAttr(xid, tcon, - pSMBFile->fid.netfid, - &ExtAttrBits, &ExtAttrMask); - if (rc == 0) - rc = put_user(ExtAttrBits & - FS_FL_USER_VISIBLE, - (int __user *)arg); - if (rc != -EOPNOTSUPP) - break; - } -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -#endif /* CONFIG_CIFS_POSIX */ - if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) - ExtAttrBits |= FS_COMPR_FL; - - rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE, - (int __user *)arg); - break; - case FS_IOC_SETFLAGS: - if (pSMBFile == NULL) - break; - tcon = tlink_tcon(pSMBFile->tlink); - - if (get_user(ExtAttrBits, (int __user *)arg)) { - rc = -EFAULT; - break; - } - - /* - * if (CIFS_UNIX_EXTATTR_CAP & caps) - * rc = CIFSSetExtAttr(xid, tcon, - * pSMBFile->fid.netfid, - * extAttrBits, - * &ExtAttrMask); - * if (rc != -EOPNOTSUPP) - * break; - */ - - /* Currently only flag we can set or clear is compressed. */ - if (ExtAttrBits & ~FS_COMPR_FL) { - rc = -EOPNOTSUPP; - break; - } - - enable_compression = ExtAttrBits & FS_COMPR_FL; - compression_state = enable_compression ? - COMPRESSION_FORMAT_DEFAULT : - COMPRESSION_FORMAT_NONE; - - rc = cifs_set_compression(xid, filep->f_path.dentry, - tcon, pSMBFile, - compression_state); - if (rc == 0) { - spin_lock(&inode->i_lock); - if (enable_compression) - CIFS_I(inode)->cifsAttrs |= - FILE_ATTRIBUTE_COMPRESSED; - else - CIFS_I(inode)->cifsAttrs &= - ~FILE_ATTRIBUTE_COMPRESSED; - spin_unlock(&inode->i_lock); - } - cifs_dbg(FYI, "set compress flag rc %d\n", rc); - break; case CIFS_IOC_COPYCHUNK_FILE: rc = cifs_ioctl_copychunk(xid, filep, arg); break; From 740619915257969048c5fd3b94c6a55b5be11032 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:08:54 -0300 Subject: [PATCH 33/61] smb: client: size smb2_compound_vars.qi_iov for the padding iov A non-last, non-encrypted compound request gets an 8-byte alignment padding iov appended by smb2_set_next_command() at rq_iov[rq_nvec]. qi_iov was a single struct kvec used for the query_info link of such chains, so with rq_nvec == 1 the padding was written into the adjacent io_iov[0] member. That write stays within struct smb2_compound_vars and io_iov is unused on the query_info paths, so it is harmless today, but it relies on field ordering and would corrupt a live member if that changed. Add SMB2_QUERY_INFO_IOV_SIZE and make qi_iov an array so the padding iov gets its own slot. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 2 +- fs/smb/client/smb2inode.c | 4 ++-- fs/smb/client/smb2ops.c | 4 ++-- fs/smb/client/smb2pdu.h | 3 +++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 7bf8f372697d..3199dec9a5b2 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -2256,7 +2256,7 @@ struct smb2_compound_vars { struct kvec rsp_iov[MAX_COMPOUND]; struct smb_rqst rqst[MAX_COMPOUND]; struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; - struct kvec qi_iov; + struct kvec qi_iov[SMB2_QUERY_INFO_IOV_SIZE]; struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; struct kvec hl_iov[SMB2_SET_INFO_IOV_SIZE]; diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 7c1472fe5b9a..cc29ff042c56 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -317,7 +317,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, /* Operation */ switch (cmds[i]) { case SMB2_OP_QUERY_INFO: - rqst[num_rqst].rq_iov = &vars->qi_iov; + rqst[num_rqst].rq_iov = vars->qi_iov; rqst[num_rqst].rq_nvec = 1; rc = SMB2_query_info_init(tcon, server, @@ -334,7 +334,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ses->Suid, full_path); break; case SMB2_OP_POSIX_QUERY_INFO: - rqst[num_rqst].rq_iov = &vars->qi_iov; + rqst[num_rqst].rq_iov = vars->qi_iov; rqst[num_rqst].rq_nvec = 1; /* TBD: fix following to allow for longer SIDs */ diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index c441b6d9a693..d969f1a98b69 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1728,7 +1728,7 @@ smb2_ioctl_query_info(const unsigned int xid, SMB2_O_INFO_FILE, 0, data, size); free_req1_func = SMB2_set_info_free; } else if (qi.flags == PASSTHRU_QUERY_INFO) { - rqst[1].rq_iov = &vars->qi_iov; + rqst[1].rq_iov = vars->qi_iov; rqst[1].rq_nvec = 1; rc = SMB2_query_info_init(tcon, server, @@ -3026,7 +3026,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, goto qic_exit; smb2_set_next_command(tcon, &rqst[0]); - rqst[1].rq_iov = &vars->qi_iov; + rqst[1].rq_iov = vars->qi_iov; rqst[1].rq_nvec = 1; if (cfid) { diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index b37a1e3941a1..04e755d2cdd8 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -178,6 +178,9 @@ struct network_resiliency_req { */ #define SMB2_IOCTL_IOV_SIZE 2 +/* extra iov for the alignment padding smb2_set_next_command() may add */ +#define SMB2_QUERY_INFO_IOV_SIZE 2 + /* * PDU query infolevel structure definitions * BB consider moving to a different header From 78abbc67787d22328c14ba6f477c7e33ba496127 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:33:26 -0300 Subject: [PATCH 34/61] smb: client: drop redundant nls_table arg from SMBSetInformation() SMBSetInformation() already gets the cifs_sb whose local_nls the caller passes separately as nls_codepage, and that is the same table as tcon->ses->local_nls. Derive it from the session and drop the redundant parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 11 +++++------ fs/smb/client/smb1ops.c | 6 +++--- fs/smb/client/smb1proto.h | 3 +-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 31695f1efe89..77c10bb7353e 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -5728,11 +5728,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __le32 attributes, __le64 write_time, - const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __le32 attributes, + __le64 write_time, struct cifs_sb_info *cifs_sb) { SETATTR_REQ *pSMB; SETATTR_RSP *pSMBr; @@ -5754,7 +5752,8 @@ SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, - fileName, PATH_MAX, nls_codepage, + fileName, PATH_MAX, + tcon->ses->local_nls, cifs_remap(cifs_sb)); name_len++; /* trailing null */ name_len *= 2; diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 7d2ddf2dcad9..85548e8a6012 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -873,7 +873,7 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path, rc = SMBSetInformation(xid, tcon, full_path, info.Attributes, 0 /* do not change write time */, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) cifsInode->cifsAttrs = dosattrs; } @@ -1072,7 +1072,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, rc = SMBSetInformation(xid, tcon, full_path, buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs), write_time, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) cinode->cifsAttrs = le32_to_cpu(buf->Attributes); else @@ -1111,7 +1111,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, SMBSetInformation(xid, tcon, full_path, buf->Attributes, 0 /* do not change write time */, - cifs_sb->local_nls, cifs_sb); + cifs_sb); } out: if (tlink != NULL) diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 80eaeb3dd2ec..bb4efc7c1094 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -186,8 +186,7 @@ int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, bool set_allocation); int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, __le32 attributes, - __le64 write_time, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb); + __le64 write_time, struct cifs_sb_info *cifs_sb); int CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener); From cd040ff11dae8f6ba3a97cd0cee583d84d6a9be3 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:37:21 -0300 Subject: [PATCH 35/61] smb: client: drop redundant nls_table arg from CIFSSMBSetPathInfo() CIFSSMBSetPathInfo() already gets the cifs_sb whose local_nls the caller passes separately as nls_codepage, and that is the same table as tcon->ses->local_nls. Derive it from the session and drop the redundant parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 10 ++++------ fs/smb/client/smb1ops.c | 6 ++---- fs/smb/client/smb1proto.h | 1 - 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 77c10bb7353e..4ab5f8ad3c58 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -5914,11 +5914,9 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const FILE_BASIC_INFO *data, - const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const FILE_BASIC_INFO *data, + struct cifs_sb_info *cifs_sb) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -5942,7 +5940,7 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 85548e8a6012..313ef84ec22f 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -867,8 +867,7 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path, cifsInode = CIFS_I(inode); dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; info.Attributes = cpu_to_le32(dosattrs); - rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, - cifs_sb); + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb); if (rc == -EOPNOTSUPP || rc == -EINVAL) rc = SMBSetInformation(xid, tcon, full_path, info.Attributes, @@ -1022,8 +1021,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, if (open_file) goto set_via_filehandle; - rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, - cifs_sb); + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb); if (rc == 0) { cinode->cifsAttrs = le32_to_cpu(buf->Attributes); goto out; diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index bb4efc7c1094..fc9e1191c3cb 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -195,7 +195,6 @@ int CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, __u32 pid_of_opener); int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const FILE_BASIC_INFO *data, - const struct nls_table *nls_codepage, struct cifs_sb_info *cifs_sb); int CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const struct cifs_unix_set_info_args *args, u16 fid, From 64fd7c38697b07a75537670c5dad19fd041001f4 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:42:09 -0300 Subject: [PATCH 36/61] smb: client: drop redundant nls_table arg from ->set_EA() The ->set_EA() operation already receives the cifs_sb whose local_nls the callers pass separately, and that is the same table as ses->local_nls (the session match requires an identical iocharset). The SMB2 implementation never used it. Drop the parameter: CIFSSMBSetEA() derives the codepage from tcon->ses->local_nls and smb2_set_ea() no longer takes it. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 2 +- fs/smb/client/cifssmb.c | 12 +++++------- fs/smb/client/smb1proto.h | 1 - fs/smb/client/smb2ops.c | 9 ++++----- fs/smb/client/xattr.c | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 3199dec9a5b2..14865bdbf3fd 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -574,7 +574,7 @@ struct smb_version_operations { size_t, struct cifs_sb_info *); int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *, const char *, const void *, const __u16, - const struct nls_table *, struct cifs_sb_info *); + struct cifs_sb_info *); struct smb_ntsd * (*get_acl)(struct cifs_sb_info *cifssb, struct inode *ino, const char *patch, u32 *plen, u32 info); struct smb_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *cifssmb, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 4ab5f8ad3c58..e1ef04c93fab 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -3163,7 +3163,6 @@ struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data, &ea->ea_data[0], &ea->ea_data[ea->ea_name_length+1], le16_to_cpu(ea->ea_value_length), - cifs_sb->local_nls, cifs_sb); if (rc) goto out_close; @@ -6383,11 +6382,10 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, return (ssize_t)rc; } -int -CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const char *ea_name, const void *ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const char *ea_name, + const void *ea_value, const __u16 ea_value_len, + struct cifs_sb_info *cifs_sb) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -6412,7 +6410,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index fc9e1191c3cb..ebb2cf396b8f 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -210,7 +210,6 @@ ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const char *ea_name, const void *ea_value, const __u16 ea_value_len, - const struct nls_table *nls_codepage, struct cifs_sb_info *cifs_sb); /* diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index d969f1a98b69..207aa2c6acf4 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1186,11 +1186,10 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static int -smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, - const char *path, const char *ea_name, const void *ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +static int smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, + const char *path, const char *ea_name, + const void *ea_value, const __u16 ea_value_len, + struct cifs_sb_info *cifs_sb) { struct smb2_compound_vars *vars; struct cifs_ses *ses = tcon->ses; diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c index 5091f6c0d7fe..86c778650d22 100644 --- a/fs/smb/client/xattr.c +++ b/fs/smb/client/xattr.c @@ -155,7 +155,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler, if (pTcon->ses->server->ops->set_EA) { rc = pTcon->ses->server->ops->set_EA(xid, pTcon, full_path, name, value, (__u16)size, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) inode_set_ctime_current(inode); } From b07c7b781f89d400692763e6c45e48bd75d5f629 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:45:43 -0300 Subject: [PATCH 37/61] smb: client: drop redundant nls_table arg from build_avpair_blob() The nls codepage passed to build_avpair_blob() is always the session's ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsencrypt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index 71a2a59123f5..fad3fd5e4f69 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -100,8 +100,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, * and client time (total five av pairs and + one end of fields indicator. * Allocate domain name which gets freed when session struct is deallocated. */ -static int -build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) +static int build_avpair_blob(struct cifs_ses *ses) { unsigned int dlen; unsigned int size = 2 * sizeof(struct ntlmssp2_name); @@ -141,7 +140,8 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); attrptr->length = cpu_to_le16(2 * dlen); blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); - cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp); + cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, + ses->local_nls); return 0; } @@ -414,7 +414,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) if (rc) goto setup_ntlmv2_rsp_ret; } else { - rc = build_avpair_blob(ses, nls_cp); + rc = build_avpair_blob(ses); if (rc) { cifs_dbg(VFS, "error %d building av pair blob\n", rc); goto setup_ntlmv2_rsp_ret; From 71098da2195fa242a99f8b1ef3f152d259025106 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:47:42 -0300 Subject: [PATCH 38/61] smb: client: drop redundant nls_table arg from calc_ntlmv2_hash() The nls codepage passed to calc_ntlmv2_hash() is always ses->local_nls; derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsencrypt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index fad3fd5e4f69..7ce0c38cfbb9 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -235,8 +235,7 @@ static __le64 find_timestamp(struct cifs_ses *ses) return cpu_to_le64(cifs_UnixTimeToNT(ts)); } -static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, - const struct nls_table *nls_cp) +static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash) { int len; char nt_hash[CIFS_NTHASH_SIZE]; @@ -246,7 +245,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, wchar_t *server; /* calculate md4 hash of password */ - E_md4hash(ses->password, nt_hash, nls_cp); + E_md4hash(ses->password, nt_hash, ses->local_nls); hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE); memzero_explicit(nt_hash, sizeof(nt_hash)); @@ -258,7 +257,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, goto out_nomem; if (len) { - len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp); + len = cifs_strtoUTF16(user, ses->user_name, len, + ses->local_nls); UniStrupr(user); } else { *(u16 *)user = 0; @@ -276,7 +276,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, goto out_nomem; len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, - nls_cp); + ses->local_nls); hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len); kfree(domain); } else { @@ -287,7 +287,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, if (server == NULL) goto out_nomem; - len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp); + len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, + ses->local_nls); hmac_md5_update(&hmac_ctx, (const u8 *)server, 2 * len); kfree(server); } @@ -452,7 +453,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) } /* calculate ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); + rc = calc_ntlmv2_hash(ses, ntlmv2_hash); if (rc) { cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc); goto unlock; From 6d16358ac43d2f784f9e0ac0c12b372bf76fb41c Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:50:04 -0300 Subject: [PATCH 39/61] smb: client: drop redundant nls_table arg from setup_ntlmv2_rsp() The nls codepage passed to setup_ntlmv2_rsp() is always ses->local_nls, which is never NULL, so derive it from @ses and drop both the parameter and the now-dead NULL check. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsencrypt.c | 8 +------- fs/smb/client/cifsproto.h | 2 +- fs/smb/client/sess.c | 2 +- fs/smb/client/smb1session.c | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index 7ce0c38cfbb9..c0bd4049f65f 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -373,8 +373,7 @@ static int set_auth_key_response(struct cifs_ses *ses) return rc; } -int -setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) +int setup_ntlmv2_rsp(struct cifs_ses *ses) { unsigned char *tiblob = NULL; /* target info blob */ struct ntlmv2_resp *ntlmv2; @@ -383,11 +382,6 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) __u64 cc; int rc; - if (nls_cp == NULL) { - cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); - return -EINVAL; - } - if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (!ses->domainName) { if (ses->domainAuto) { diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 582cd182c616..46b7ac2885f2 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -307,7 +307,7 @@ struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace); void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace); -int setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp); +int setup_ntlmv2_rsp(struct cifs_ses *ses); void cifs_crypto_secmech_release(struct TCP_Server_Info *server); int calc_seckey(struct cifs_ses *ses); int generate_smb30signingkey(struct cifs_ses *ses, diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index fc105308226c..06a894794741 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -929,7 +929,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, unsigned char *tmp; int len; - rc = setup_ntlmv2_rsp(ses, nls_cp); + rc = setup_ntlmv2_rsp(ses); if (rc) { cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); *buflen = 0; diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 83bfbf0c068e..9673ecd87f86 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -443,7 +443,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) if (ses->user_name != NULL) { /* calculate nlmv2 response and session key */ - rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp); + rc = setup_ntlmv2_rsp(ses); if (rc) { cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc); goto out; From a8ef7f94f90136c1650fad5f748949f75ee44778 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:59:03 -0300 Subject: [PATCH 40/61] smb: client: drop redundant nls_table arg from build_ntlmssp_negotiate_blob() The nls codepage passed to build_ntlmssp_negotiate_blob() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/ntlmssp.h | 3 +-- fs/smb/client/sess.c | 7 +++---- fs/smb/client/smb1session.c | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index 7d68153985f8..658d7795db3e 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -146,8 +146,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, struct TCP_Server_Info *server, diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 06a894794741..01f73e540d89 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -794,8 +794,7 @@ static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf, int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc = 0; NEGOTIATE_MESSAGE *sec_blob; @@ -835,13 +834,13 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, NULL, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, NULL, CIFS_MAX_WORKSTATION_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); *buflen = tmp - *pbuffer; setup_ntlm_neg_ret: diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 9673ecd87f86..b4a334d89cb1 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -741,8 +741,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) /* Build security blob before we assemble the request */ rc = build_ntlmssp_negotiate_blob(&ntlmsspblob, - &blob_len, ses, server, - sess_data->nls_cp); + &blob_len, ses, server); if (rc) goto out_free_ntlmsspblob; From aadcd752e34b8afde1becd07fac4bd471dc66b5d Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 11 Oct 2026 23:59:45 -0300 Subject: [PATCH 41/61] smb: client: drop redundant nls_table arg from build_ntlmssp_smb3_negotiate_blob() The nls codepage passed to build_ntlmssp_smb3_negotiate_blob() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/ntlmssp.h | 3 +-- fs/smb/client/sess.c | 7 +++---- fs/smb/client/smb2pdu.c | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index 658d7795db3e..1f8c33835110 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -149,8 +149,7 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct TCP_Server_Info *server); int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, struct TCP_Server_Info *server, diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 01f73e540d89..86662a4dd9fa 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -855,8 +855,7 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc = 0; struct negotiate_message *sec_blob; @@ -901,13 +900,13 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, NULL, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, NULL, CIFS_MAX_WORKSTATION_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); *buflen = tmp - *pbuffer; setup_ntlm_smb3_neg_ret: diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 71d44c6da4b5..d117d61cb8c2 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1833,8 +1833,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) goto out_err; rc = build_ntlmssp_smb3_negotiate_blob(&ntlmssp_blob, - &blob_length, ses, server, - sess_data->nls_cp); + &blob_length, ses, server); if (rc) goto out; From 4acec99c4c1ad31234f4eb9c3508886443d73b11 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:00:47 -0300 Subject: [PATCH 42/61] smb: client: drop redundant nls_table arg from build_ntlmssp_auth_blob() The nls codepage passed to build_ntlmssp_auth_blob() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/ntlmssp.h | 3 +-- fs/smb/client/sess.c | 9 ++++----- fs/smb/client/smb1session.c | 3 +-- fs/smb/client/smb2pdu.c | 3 +-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index 1f8c33835110..0957b4002b9c 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -152,5 +152,4 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct TCP_Server_Info *server); int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 86662a4dd9fa..f86a7a8cd1f7 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -918,8 +918,7 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc; AUTHENTICATE_MESSAGE *sec_blob; @@ -988,19 +987,19 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, ses->domainName, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->UserName, ses->user_name, CIFS_MAX_USERNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, ses->workstation_name, ntlmssp_workstation_name_size(ses), *pbuffer, &tmp, - nls_cp); + ses->local_nls); if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) && diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index b4a334d89cb1..68eabde27ac8 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -835,8 +835,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; smb_buf = (struct smb_hdr *)pSMB; rc = build_ntlmssp_auth_blob(&ntlmsspblob, - &blob_len, ses, server, - sess_data->nls_cp); + &blob_len, ses, server); if (rc) goto out_free_ntlmsspblob; sess_data->iov[1].iov_len = blob_len; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index d117d61cb8c2..5c06f9d42fc6 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1917,8 +1917,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) req->hdr.SessionId = cpu_to_le64(ses->Suid); rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, - ses, server, - sess_data->nls_cp); + ses, server); if (rc) { cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc); goto out; From 6b3884e9d0acbaf6f7ed6e2cca49308d298b0e29 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:02:41 -0300 Subject: [PATCH 43/61] smb: client: drop unused nls_table arg from ascii_oslm_strings() ascii_oslm_strings() never uses the nls codepage, so drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 68eabde27ac8..74b1e9683ba4 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -106,8 +106,7 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) *pbcc_area = bcc_ptr; } -static void -ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) +static void ascii_oslm_strings(char **pbcc_area) { char *bcc_ptr = *pbcc_area; @@ -213,7 +212,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* BB check for overflow here */ ascii_domain_string(&bcc_ptr, ses, nls_cp); - ascii_oslm_strings(&bcc_ptr, nls_cp); + ascii_oslm_strings(&bcc_ptr); *pbcc_area = bcc_ptr; } @@ -595,7 +594,7 @@ sess_auth_kerberos(struct sess_data *sess_data) unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); } else { - ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); + ascii_oslm_strings(&bcc_ptr); ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); } @@ -694,7 +693,7 @@ _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) } unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); } else { - ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); + ascii_oslm_strings(&bcc_ptr); } sess_data->iov[2].iov_len = (long) bcc_ptr - From 40c21e0e41ba3cc199ea088b9dde9651145909d8 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:03:36 -0300 Subject: [PATCH 44/61] smb: client: drop redundant nls_table arg from unicode_domain_string() The nls codepage passed to unicode_domain_string() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 74b1e9683ba4..c00d3e6e17cb 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -121,8 +121,7 @@ static void ascii_oslm_strings(char **pbcc_area) *pbcc_area = bcc_ptr; } -static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int bytes_ret = 0; @@ -138,7 +137,8 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, bytes_ret = 0; } else bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, - CIFS_MAX_DOMAINNAME_LEN, nls_cp); + CIFS_MAX_DOMAINNAME_LEN, + ses->local_nls); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null terminator */ @@ -184,7 +184,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ - unicode_domain_string(&bcc_ptr, ses, nls_cp); + unicode_domain_string(&bcc_ptr, ses); unicode_oslm_strings(&bcc_ptr, nls_cp); *pbcc_area = bcc_ptr; @@ -592,7 +592,7 @@ sess_auth_kerberos(struct sess_data *sess_data) bcc_ptr++; } unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); - unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + unicode_domain_string(&bcc_ptr, ses); } else { ascii_oslm_strings(&bcc_ptr); ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); From 40e439b61fd96204a5163c149b00bd348dd8abf6 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:03:59 -0300 Subject: [PATCH 45/61] smb: client: drop unused nls_table arg from ascii_domain_string() ascii_domain_string() never uses the nls codepage, so drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index c00d3e6e17cb..8c8b42b2704d 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -145,8 +145,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses) *pbcc_area = bcc_ptr; } -static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int len; @@ -211,7 +210,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* BB check for overflow here */ - ascii_domain_string(&bcc_ptr, ses, nls_cp); + ascii_domain_string(&bcc_ptr, ses); ascii_oslm_strings(&bcc_ptr); *pbcc_area = bcc_ptr; @@ -595,7 +594,7 @@ sess_auth_kerberos(struct sess_data *sess_data) unicode_domain_string(&bcc_ptr, ses); } else { ascii_oslm_strings(&bcc_ptr); - ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + ascii_domain_string(&bcc_ptr, ses); } sess_data->iov[2].iov_len = (long) bcc_ptr - From f945ba31422ca963666dd16e6e3207cc5f4f12b1 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:04:38 -0300 Subject: [PATCH 46/61] smb: client: drop redundant nls_table arg from unicode_ssetup_strings() The nls codepage passed to unicode_ssetup_strings() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 8c8b42b2704d..db7ce16b140b 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -163,8 +163,7 @@ static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses) *pbcc_area = bcc_ptr; } -static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int bytes_ret = 0; @@ -178,13 +177,14 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, *(bcc_ptr+1) = 0; } else { bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name, - CIFS_MAX_USERNAME_LEN, nls_cp); + CIFS_MAX_USERNAME_LEN, + ses->local_nls); } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ unicode_domain_string(&bcc_ptr, ses); - unicode_oslm_strings(&bcc_ptr, nls_cp); + unicode_oslm_strings(&bcc_ptr, ses->local_nls); *pbcc_area = bcc_ptr; } @@ -465,7 +465,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); + unicode_ssetup_strings(&bcc_ptr, ses); } else { ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); } From 34e037c98a5de07559ec2693a1e4998762f0c00d Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:05:01 -0300 Subject: [PATCH 47/61] smb: client: drop unused nls_table arg from ascii_ssetup_strings() ascii_ssetup_strings() no longer uses the nls codepage, so drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index db7ce16b140b..df2d3eea898d 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -189,8 +189,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) *pbcc_area = bcc_ptr; } -static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int len; @@ -467,7 +466,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) } unicode_ssetup_strings(&bcc_ptr, ses); } else { - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); + ascii_ssetup_strings(&bcc_ptr, ses); } From ea0261b23fa5baedbfef1c8d45aeeb2627c0330a Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:06:53 -0300 Subject: [PATCH 48/61] smb: client: drop redundant nls_table arg from decode_unicode_ssetup() The nls codepage passed to decode_unicode_ssetup() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index df2d3eea898d..d1ea7e0b2d58 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -215,9 +215,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) *pbcc_area = bcc_ptr; } -static void -decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void decode_unicode_ssetup(char **pbcc_area, int bleft, + struct cifs_ses *ses) { int len; char *data = *pbcc_area; @@ -225,7 +224,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, cifs_dbg(FYI, "bleft %d\n", bleft); kfree(ses->serverOS); - ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverOS=%s\n", ses->serverOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -234,7 +234,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverNOS); - ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverNOS=%s\n", ses->serverNOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -243,7 +244,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverDomain); - ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverDomain=%s\n", ses->serverDomain); return; @@ -504,8 +506,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, sess_data->nls_cp); @@ -640,8 +641,7 @@ sess_auth_kerberos(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, sess_data->nls_cp); @@ -891,8 +891,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, sess_data->nls_cp); From 9f9ab02ddfcbac6174de72745e09dcb460b28c68 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:07:15 -0300 Subject: [PATCH 49/61] smb: client: drop unused nls_table arg from decode_ascii_ssetup() decode_ascii_ssetup() never uses the nls codepage, so drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index d1ea7e0b2d58..2f6eb57dd179 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -252,8 +252,7 @@ static void decode_unicode_ssetup(char **pbcc_area, int bleft, } static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, - struct cifs_ses *ses, - const struct nls_table *nls_cp) + struct cifs_ses *ses) { int len; char *bcc_ptr = *pbcc_area; @@ -508,8 +507,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) } decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } rc = sess_establish_session(sess_data); @@ -643,8 +641,7 @@ sess_auth_kerberos(struct sess_data *sess_data) } decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } rc = sess_establish_session(sess_data); @@ -893,8 +890,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) } decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } out_free_ntlmsspblob: From ca67b7abefda27f8e898efc2c7e4e0ade65ab58f Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:10:57 -0300 Subject: [PATCH 50/61] smb: client: drop redundant nls_table arg from ->sess_setup() The nls codepage threaded through ->sess_setup() and stored in sess_data->nls_cp is always ses->local_nls, so derive it from @ses and drop both the parameter and the now-dead sess_data->nls_cp member. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 3 +-- fs/smb/client/connect.c | 2 +- fs/smb/client/smb1proto.h | 3 +-- fs/smb/client/smb1session.c | 9 +++------ fs/smb/client/smb2pdu.c | 8 ++------ fs/smb/client/smb2proto.h | 3 +-- 6 files changed, 9 insertions(+), 19 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 14865bdbf3fd..6a345ffd51d4 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -373,8 +373,7 @@ struct smb_version_operations { unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); /* setup smb sessionn */ int (*sess_setup)(const unsigned int, struct cifs_ses *, - struct TCP_Server_Info *server, - const struct nls_table *); + struct TCP_Server_Info *server); /* close smb session */ int (*logoff)(const unsigned int, struct cifs_ses *); /* connect to a server share */ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 90eda91d9da9..067330fa0069 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -4188,7 +4188,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, if (!rc) { if (server->ops->sess_setup) - rc = server->ops->sess_setup(xid, ses, server, nls_info); + rc = server->ops->sess_setup(xid, ses, server); else rc = -ENOSYS; } diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index ebb2cf396b8f..adaa3fd1ef16 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -271,8 +271,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, * smb1session.c */ int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); /* * smb1transport.c diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 2f6eb57dd179..c45d3254dfac 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -20,7 +20,6 @@ struct sess_data { unsigned int xid; struct cifs_ses *ses; struct TCP_Server_Info *server; - struct nls_table *nls_cp; void (*func)(struct sess_data *); int result; unsigned int in_len; @@ -588,7 +587,7 @@ sess_auth_kerberos(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); + unicode_oslm_strings(&bcc_ptr, sess_data->ses->local_nls); unicode_domain_string(&bcc_ptr, ses); } else { ascii_oslm_strings(&bcc_ptr); @@ -686,7 +685,7 @@ _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); + unicode_oslm_strings(&bcc_ptr, sess_data->ses->local_nls); } else { ascii_oslm_strings(&bcc_ptr); } @@ -948,8 +947,7 @@ static int select_sec(struct sess_data *sess_data) } int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc = 0; struct sess_data *sess_data; @@ -967,7 +965,6 @@ int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, sess_data->ses = ses; sess_data->server = server; sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->nls_cp = (struct nls_table *) nls_cp; rc = select_sec(sess_data); if (rc) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 5c06f9d42fc6..cb72735a4553 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1529,7 +1529,6 @@ struct SMB2_sess_data { unsigned int xid; struct cifs_ses *ses; struct TCP_Server_Info *server; - struct nls_table *nls_cp; void (*func)(struct SMB2_sess_data *); int result; u64 previous_session; @@ -2002,10 +2001,8 @@ SMB2_select_sec(struct SMB2_sess_data *sess_data) return 0; } -int -SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) +int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) { int rc = 0; struct SMB2_sess_data *sess_data; @@ -2025,7 +2022,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, sess_data->ses = ses; sess_data->server = server; sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->nls_cp = (struct nls_table *) nls_cp; sess_data->previous_session = ses->Suid; rc = SMB2_select_sec(sess_data); diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 69a32f8311ca..aa1340fec27b 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -131,8 +131,7 @@ bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries, int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *cp); From 172cbcd178c876113b29df2b33c53fa2ddeb393a Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:11:58 -0300 Subject: [PATCH 51/61] smb: client: drop redundant nls_table arg from cifs_setup_session() The nls codepage passed to cifs_setup_session() is always ses->local_nls and, now that ->sess_setup() no longer takes it, is unused, so drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsproto.h | 3 +-- fs/smb/client/cifssmb.c | 2 +- fs/smb/client/connect.c | 11 ++++------- fs/smb/client/sess.c | 2 +- fs/smb/client/smb2pdu.c | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 46b7ac2885f2..7b9eca22281f 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -290,8 +290,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon); int cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct nls_table *nls_info); + struct TCP_Server_Info *server); int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required); diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index e1ef04c93fab..06438d3fff90 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -163,7 +163,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) return -EHOSTDOWN; goto again; } - rc = cifs_setup_session(0, ses, server, ses->local_nls); + rc = cifs_setup_session(0, ses, server); if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) { /* * Try alternate password for next reconnect if an alternate diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 067330fa0069..fba926347682 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -2403,8 +2403,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) return ERR_PTR(rc); } - rc = cifs_setup_session(xid, ses, server, - ctx->local_nls); + rc = cifs_setup_session(xid, ses, server); if (rc) { if (((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) && !retries && ses->password2) { @@ -2521,7 +2520,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses, server); if (!rc) - rc = cifs_setup_session(xid, ses, server, ctx->local_nls); + rc = cifs_setup_session(xid, ses, server); mutex_unlock(&ses->session_mutex); /* each channel uses a different signing key */ @@ -4093,10 +4092,8 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, return rc; } -int -cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct nls_table *nls_info) +int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) { int rc = 0; struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index f86a7a8cd1f7..c1fc90726e2d 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -620,7 +620,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, rc = cifs_negotiate_protocol(xid, ses, chan->server); if (!rc) - rc = cifs_setup_session(xid, ses, chan->server, ses->local_nls); + rc = cifs_setup_session(xid, ses, chan->server); mutex_unlock(&ses->session_mutex); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index cb72735a4553..41ca08538316 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -395,7 +395,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, } } - rc = cifs_setup_session(0, ses, server, ses->local_nls); + rc = cifs_setup_session(0, ses, server); if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) { /* * Try alternate password for next reconnect (key rotation From fd8ac150455df9b5a08f67c2fb628465f28c4f33 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:14:15 -0300 Subject: [PATCH 52/61] smb: client: drop redundant nls_table arg from ->tree_connect() The nls codepage passed to ->tree_connect() is always ses->local_nls, so derive it from @ses and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifsglob.h | 2 +- fs/smb/client/cifssmb.c | 11 +++++------ fs/smb/client/connect.c | 8 +++----- fs/smb/client/dfs.c | 6 +++--- fs/smb/client/smb1proto.h | 2 +- fs/smb/client/smb2pdu.c | 8 ++++---- fs/smb/client/smb2proto.h | 2 +- 7 files changed, 18 insertions(+), 21 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 6a345ffd51d4..73b49dcb5215 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -378,7 +378,7 @@ struct smb_version_operations { int (*logoff)(const unsigned int, struct cifs_ses *); /* connect to a server share */ int (*tree_connect)(const unsigned int, struct cifs_ses *, const char *, - struct cifs_tcon *, const struct nls_table *); + struct cifs_tcon *); /* close tree connection */ int (*tree_disconnect)(const unsigned int, struct cifs_tcon *); /* get DFS referrals */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 06438d3fff90..910f454fabfa 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -536,10 +536,8 @@ CIFSSMBNegotiate(const unsigned int xid, /* * Issue a TREE_CONNECT request. */ -int -CIFSTCon(const unsigned int xid, struct cifs_ses *ses, - const char *tree, struct cifs_tcon *tcon, - const struct nls_table *nls_codepage) +int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, const char *tree, + struct cifs_tcon *tcon) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; @@ -590,7 +588,8 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, length = cifs_strtoUTF16((__le16 *) bcc_ptr, tree, 6 /* max utf8 char length in bytes */ * - (/* server len*/ + 256 /* share len */), nls_codepage); + (/* server len*/ + 256 /* share len */), + ses->local_nls); bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ @@ -648,7 +647,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, bytes_left, is_unicode, - nls_codepage); + ses->local_nls); cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index fba926347682..550e687a1b15 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -2085,7 +2085,7 @@ struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal) tcon->ses = ses; tcon->ipc = true; tcon->seal = seal; - rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls); + rc = server->ops->tree_connect(xid, ses, unc, tcon); free_xid(xid); if (rc) { @@ -2815,8 +2815,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) } xid = get_xid(); - rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon, - ctx->local_nls); + rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon); free_xid(xid); cifs_dbg(FYI, "Tcon rc = %d\n", rc); if (rc) @@ -4561,8 +4560,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) tcon->status = TID_IN_TCON; spin_unlock(&tcon->tc_lock); - rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, - tcon, tcon->ses->local_nls); + rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon); if (rc) { spin_lock(&tcon->tc_lock); if (tcon->status == TID_IN_TCON) diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c index f65a8a90ba27..b7143335d70a 100644 --- a/fs/smb/client/dfs.c +++ b/fs/smb/client/dfs.c @@ -371,7 +371,7 @@ static int tree_connect_dfs_target(const unsigned int xid, dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit); scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); rc = ops->tree_connect(xid, tcon->ses, tree, - tcon, tcon->ses->local_nls); + tcon); if (islink && !rc && cifs_sb) rc = cifs_update_super_prepath(cifs_sb, prefix); break; @@ -426,7 +426,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); cifs_server_unlock(server); rc = ops->tree_connect(xid, tcon->ses, tree, - tcon, tcon->ses->local_nls); + tcon); goto out; } @@ -438,7 +438,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) if (!server->leaf_fullpath || dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) { rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, - tcon, tcon->ses->local_nls); + tcon); goto out; } diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index adaa3fd1ef16..12a9e35ad423 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -33,7 +33,7 @@ int small_smb_init_no_tc(const int smb_command, const int wct, int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *nls_codepage); + struct cifs_tcon *tcon); int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon); int CIFSSMBEcho(struct TCP_Server_Info *server); int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 41ca08538316..f10feec98b38 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2116,9 +2116,8 @@ static inline void init_copy_chunk_defaults(struct cifs_tcon *tcon) tcon->max_bytes_copy = 16777216; } -int -SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *cp) +int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, + struct cifs_tcon *tcon) { struct smb_rqst rqst; struct smb2_tree_connect_req *req; @@ -2142,7 +2141,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, if (unc_path == NULL) return -ENOMEM; - unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp); + unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), + ses->local_nls); if (unc_path_len <= 0) { rc = -EINVAL; goto free_unc_path; diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index aa1340fec27b..c79e5cb2ce26 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -134,7 +134,7 @@ int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *cp); + struct cifs_tcon *tcon); int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct cifs_open_info_data *buf, From 8552a75e219ccedc377bc14cbc4225644de04ae7 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:17:37 -0300 Subject: [PATCH 53/61] smb: client: drop redundant nls_table arg from CIFSPOSIXDelFile() The nls codepage passed to CIFSPOSIXDelFile() is always tcon->ses->local_nls, so derive it from @tcon and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 8 +++----- fs/smb/client/inode.c | 3 +-- fs/smb/client/smb1proto.h | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 910f454fabfa..67273e7adbeb 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -836,10 +836,8 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) return rc; } -int -CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __u16 type, - const struct nls_table *nls_codepage, int remap) +int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __u16 type, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -861,7 +859,7 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 00dbf5342c10..b104135888fa 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -2019,8 +2019,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { rc = CIFSPOSIXDelFile(xid, tcon, full_path, - SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, - cifs_remap(cifs_sb)); + SMB_POSIX_UNLINK_FILE_TARGET, cifs_remap(cifs_sb)); cifs_dbg(FYI, "posix del rc %d\n", rc); if ((rc == 0) || (rc == -ENOENT)) goto psx_del_no_retry; diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 12a9e35ad423..d953dc82144a 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -38,8 +38,7 @@ int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon); int CIFSSMBEcho(struct TCP_Server_Info *server); int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses); int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __u16 type, - const struct nls_table *nls_codepage, int remap); + const char *fileName, __u16 type, int remap); int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, struct cifs_sb_info *cifs_sb, struct dentry *dentry); From b2c49578d3423c81eb1e6ac4c506d57ea4c3a87c Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:18:18 -0300 Subject: [PATCH 54/61] smb: client: drop redundant nls_table arg from CIFSPOSIXCreate() The nls codepage passed to CIFSPOSIXCreate() is always tcon->ses->local_nls, so derive it from @tcon and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 12 +++++------- fs/smb/client/file.c | 3 +-- fs/smb/client/inode.c | 2 +- fs/smb/client/smb1proto.h | 3 +-- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 67273e7adbeb..5ee659287f57 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1047,12 +1047,10 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, return rc; } -int -CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, - __u32 posix_flags, __u64 mode, __u16 *netfid, - FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, - const char *name, const struct nls_table *nls_codepage, - int remap) +int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, + __u32 posix_flags, __u64 mode, __u16 *netfid, + FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, + const char *name, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -1075,7 +1073,7 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, name, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index e08ed5072c29..0767eb5f4687 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -516,8 +516,7 @@ int cifs_posix_open(const char *full_path, struct inode **pinode, posix_flags = cifs_posix_convert_flags(f_flags); rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, - poplock, full_path, cifs_sb->local_nls, - cifs_remap(cifs_sb)); + poplock, full_path, cifs_remap(cifs_sb)); cifs_put_tlink(tlink); if (rc) diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index b104135888fa..79e7f252641c 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -2240,7 +2240,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, mode &= ~current_umask(); rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, info, &oplock, full_path, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); if (rc == -EOPNOTSUPP) goto posix_mkdir_out; else if (rc) { diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index d953dc82144a..cd0966164db9 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -50,8 +50,7 @@ int CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, __u32 posix_flags, __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, - const char *name, const struct nls_table *nls_codepage, - int remap); + const char *name, int remap); int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, From 34c6fdb03b0560c5942945086201bd4caaaa46f8 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:19:14 -0300 Subject: [PATCH 55/61] smb: client: drop redundant nls_table arg from SMBLegacyOpen() The nls codepage passed to SMBLegacyOpen() is always tcon->ses->local_nls, so derive it from @tcon and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 14 +++++++------- fs/smb/client/smb1ops.c | 1 - fs/smb/client/smb1proto.h | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 5ee659287f57..dee7c0958284 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1229,12 +1229,11 @@ access_flags_to_smbopen_mode(const int access_flags) return SMBOPEN_READ; } -int -SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const int openDisposition, - const int access_flags, const int create_options, __u16 *netfid, - int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap) +int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const int openDisposition, + const int access_flags, const int create_options, + __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info, + int remap) { int rc; OPENX_REQ *pSMB = NULL; @@ -1257,7 +1256,8 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, count = 1; /* account for one byte pad to word boundary */ name_len = cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); + fileName, PATH_MAX, + tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 313ef84ec22f..c0d0eb0cdd2c 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -890,7 +890,6 @@ static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms oparms->desired_access, oparms->create_options, &oparms->fid->netfid, oplock, &fi, - oparms->cifs_sb->local_nls, cifs_remap(oparms->cifs_sb)); else rc = CIFS_open(xid, oparms, oplock, &fi); diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index cd0966164db9..3dfabff9533e 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -55,7 +55,7 @@ int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap); + int remap); int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, FILE_ALL_INFO *buf); int cifs_async_readv(struct cifs_io_subrequest *rdata); From b012ffcd45b0c5bb9eeb57ec1e7e2a71d3f36e06 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 00:20:13 -0300 Subject: [PATCH 56/61] smb: client: drop redundant nls_table arg from CIFSSMBRenameOpenFile() The nls codepage passed to CIFSSMBRenameOpenFile() is always pTcon->ses->local_nls, so derive it from @pTcon and drop the parameter. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/cifssmb.c | 10 +++++----- fs/smb/client/inode.c | 5 ++--- fs/smb/client/smb1proto.h | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index dee7c0958284..50ca062a22bf 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -2545,8 +2545,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, } int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, - int netfid, const char *target_name, - const struct nls_table *nls_codepage, int remap) + int netfid, const char *target_name, int remap) { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; @@ -2595,12 +2594,13 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); len_of_str = cifsConvertToUTF16((__le16 *)rename_info->target_name, - dummy_string, 24, nls_codepage, remap); + dummy_string, 24, + pTcon->ses->local_nls, remap); } else { len_of_str = cifsConvertToUTF16((__le16 *)rename_info->target_name, - target_name, PATH_MAX, nls_codepage, - remap); + target_name, PATH_MAX, + pTcon->ses->local_nls, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); count = sizeof(struct set_file_rename) + (2 * len_of_str); diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 79e7f252641c..43a2d7982488 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -1889,7 +1889,6 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, /* rename the file */ rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, - cifs_sb->local_nls, cifs_remap(cifs_sb)); if (rc != 0) { rc = -EBUSY; @@ -1931,7 +1930,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, */ undo_rename: CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); undo_setattr: if (dosattr != origattr) { info_buf->Attributes = cpu_to_le32(origattr); @@ -2522,7 +2521,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, if (rc == 0) { rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, (const char *) to_dentry->d_name.name, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); CIFSSMBClose(xid, tcon, fid.netfid); } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 3dfabff9533e..7175b458724c 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -88,8 +88,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb); int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, - int netfid, const char *target_name, - const struct nls_table *nls_codepage, int remap); + int netfid, const char *target_name, int remap); int CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage, int remap); From f13208f26c052d06a10c53eda4c78c930f2b9c47 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 01:52:46 -0300 Subject: [PATCH 57/61] smb: client: allocate struct sess_data on the stack CIFS_SessSetup() kzalloc()s struct sess_data only to run a synchronous state machine and free it before returning; the object never escapes the function. At 96 bytes it fits comfortably on the stack even under CONFIG_FRAME_WARN=1024, so drop the allocation and its failure path. memzero_explicit() preserves the kfree_sensitive() scrubbing. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb1session.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index c45d3254dfac..5f469b4d70f7 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -949,34 +949,31 @@ static int select_sec(struct sess_data *sess_data) int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { + struct sess_data sess_data; int rc = 0; - struct sess_data *sess_data; if (ses == NULL) { WARN(1, "%s: ses == NULL!", __func__); return -EINVAL; } - sess_data = kzalloc_obj(struct sess_data); - if (!sess_data) - return -ENOMEM; + sess_data = (struct sess_data) { + .xid = xid, + .ses = ses, + .server = server, + .buf0_type = CIFS_NO_BUFFER, + }; - sess_data->xid = xid; - sess_data->ses = ses; - sess_data->server = server; - sess_data->buf0_type = CIFS_NO_BUFFER; - - rc = select_sec(sess_data); + rc = select_sec(&sess_data); if (rc) goto out; - while (sess_data->func) - sess_data->func(sess_data); + while (sess_data.func) + sess_data.func(&sess_data); - /* Store result before we free sess_data */ - rc = sess_data->result; + rc = sess_data.result; out: - kfree_sensitive(sess_data); + memzero_explicit(&sess_data, sizeof(sess_data)); return rc; } From cafbf020e437365beaeacc682fecd50450dff669 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 12 Oct 2026 01:53:14 -0300 Subject: [PATCH 58/61] smb: client: allocate struct SMB2_sess_data on the stack SMB2_sess_setup() kzalloc()s struct SMB2_sess_data only to run a synchronous state machine and free it before returning; the object never escapes the function. At 88 bytes it fits comfortably on the stack even under CONFIG_FRAME_WARN=1024, so drop the allocation and its failure path. memzero_explicit() preserves the kfree_sensitive() scrubbing. Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM --- fs/smb/client/smb2pdu.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index f10feec98b38..b140ec0a71a8 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2004,8 +2004,8 @@ SMB2_select_sec(struct SMB2_sess_data *sess_data) int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { + struct SMB2_sess_data sess_data; int rc = 0; - struct SMB2_sess_data *sess_data; cifs_dbg(FYI, "Session Setup\n"); @@ -2014,17 +2014,15 @@ int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, return smb_EIO(smb_eio_trace_null_pointers); } - sess_data = kzalloc_obj(struct SMB2_sess_data); - if (!sess_data) - return -ENOMEM; + sess_data = (struct SMB2_sess_data) { + .xid = xid, + .ses = ses, + .server = server, + .buf0_type = CIFS_NO_BUFFER, + .previous_session = ses->Suid, + }; - sess_data->xid = xid; - sess_data->ses = ses; - sess_data->server = server; - sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->previous_session = ses->Suid; - - rc = SMB2_select_sec(sess_data); + rc = SMB2_select_sec(&sess_data); if (rc) goto out; @@ -2034,14 +2032,14 @@ int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, memcpy(ses->preauth_sha_hash, server->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); - while (sess_data->func) - sess_data->func(sess_data); + while (sess_data.func) + sess_data.func(&sess_data); if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign)) cifs_server_dbg(VFS, "signing requested but authenticated as guest\n"); - rc = sess_data->result; + rc = sess_data.result; out: - kfree_sensitive(sess_data); + memzero_explicit(&sess_data, sizeof(sess_data)); return rc; } From 8667061cf99394526dd9c0ea2662e6bbc7ae7848 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Tue, 13 Oct 2026 10:33:41 -0300 Subject: [PATCH 59/61] smb: client: require stable pages for SMB compression Like signing, SMB compression builds the write payload from the pagecache folios: should_compress() lets a write request through and smb_compress() compresses those folios on the way to the socket. If a buffered write mutates a folio while a write subrequest is still in flight, the compressed bytes no longer correspond to a consistent view of the data, and the server silently stores corrupted contents - worse than the signed case, which at least fails loudly with STATUS_ACCESS_DENIED. Mark the mapping for stable writes when a write may be compressed, i.e. the same condition should_compress() tests (compression negotiated and the share allows compressed data), so netfs_perform_write() waits for writeback to complete before modifying an in-flight folio. Fixes: f046d71e84e1 ("smb: client: insert compression check/call on write requests") Suggested-by: David Howells Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM Cc: stable@vger.kernel.org --- fs/smb/client/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 43a2d7982488..d94007deb548 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -88,7 +88,9 @@ static void cifs_set_ops(struct inode *inode) else inode->i_data.a_ops = &cifs_addr_ops; mapping_set_large_folios(inode->i_mapping); - if (tcon->ses->server->sign) + if (tcon->ses->server->sign || + (tcon->ses->server->compression.enabled && + (tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA))) mapping_set_stable_writes(inode->i_mapping); break; case S_IFDIR: From 2225ab306575e424b3dad2ee1be2521c89249d15 Mon Sep 17 00:00:00 2001 From: Zikang Gao <2715417602@qq.com> Date: Wed, 14 Oct 2026 04:19:44 -0400 Subject: [PATCH 60/61] smb: client: do not pass a NULL buf to is_oplock_break() receive_encrypted_read() sets *num_mids = 1 and never writes the caller's bufs[]. Offload returns -1 with *num_mids = 0, so the demultiplex thread skips the frame. The inline decrypt path returns 0 even when smb2_find_mid() fails. cifs_demultiplex_thread() then treats mids[i] == NULL as an oplock break and calls is_oplock_break(bufs[i], server) with bufs[i] still NULL. smb2_is_valid_oplock_break() reads hdr.Command at offset 12 and oopses. A large encrypted READ whose MessageId does not match is enough to panic cifsd. Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] CPU: 0 PID: 100 Comm: cifsd RIP: smb2_is_valid_oplock_break+0xc8/0x2270 [cifs] cifs_demultiplex_thread Kernel panic - not syncing: Fatal exception Return -1 when inline decrypt finds no mid, and skip is_oplock_break() plus the unknown-frame dump when bufs[i] is NULL. receive_encrypted_standard() already assigns bufs[*num_mids]. Fixes: c42a6abe3012 ("CIFS: Add capability to decrypt big read responses") Assisted-by: LLM Signed-off-by: Zikang Gao <2715417602@qq.com> Reviewed-by: David Howells Signed-off-by: Paulo Alcantara Cc: stable@vger.kernel.org --- fs/smb/client/connect.c | 4 +++- fs/smb/client/smb2ops.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 550e687a1b15..f46c37e9b3c7 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1422,12 +1422,14 @@ cifs_demultiplex_thread(void *p) mid_execute_callback(server, mids[i]); release_mid(server, mids[i]); - } else if (server->ops->is_oplock_break && + } else if (bufs[i] && server->ops->is_oplock_break && server->ops->is_oplock_break(bufs[i], server)) { smb2_add_credits_from_hdr(bufs[i], server); cifs_dbg(FYI, "Received oplock break\n"); } else { + if (!bufs[i]) + continue; cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", atomic_read(&mid_count)); cifs_dump_mem("Received Data is: ", bufs[i], diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 207aa2c6acf4..a0b9363ba89d 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -5396,6 +5396,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, *mid = smb2_find_mid(server, buf); if (*mid == NULL) { cifs_dbg(FYI, "mid not found\n"); + rc = -1; } else { cifs_dbg(FYI, "mid found\n"); (*mid)->decrypted = true; From 78f73985846465a25a7bd1d89904053661f3ca92 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Thu, 15 Oct 2026 15:53:32 -0300 Subject: [PATCH 61/61] smb: client: reclaim credits for decrypted reads with no matching mid When a decrypted SMB2 READ response carries a MessageId that matches no outstanding request, both the inline receive_encrypted_read() and the offloaded smb2_decrypt_offload() paths drop the frame without accounting the credits the server granted in it. The plaintext unknown-frame path in cifs_demultiplex_thread() already reclaims them with smb2_add_credits_from_hdr(), so encrypted reads leak credits that the plaintext path would not. This also happens for legitimate frames - e.g. a reply that arrives after the client has timed out and dropped the mid - so over a long-lived connection the client's credit count drifts down and can eventually starve it of the ability to issue requests. The frame is AEAD-authenticated, so the granted credits in the decrypted header come from the real server and are safe to apply. Reclaim the credits from the decrypted header before dropping the frame, and export smb2_add_credits_from_hdr() so the SMB2 receive paths can use it. Fixes: c42a6abe3012 ("CIFS: Add capability to decrypt big read responses") Fixes: 35cf94a39728 ("smb3: allow parallelizing decryption of reads") Signed-off-by: Paulo Alcantara Reviewed-by: David Howells Cc: Namjae Jeon Cc: Ronnie Sahlberg Cc: Shyam Prasad N Cc: Tom Talpey Cc: Bharath SM Cc: stable@vger.kernel.org --- fs/smb/client/cifsproto.h | 1 + fs/smb/client/connect.c | 3 +-- fs/smb/client/smb2ops.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 7b9eca22281f..9c44d1d2ae20 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -131,6 +131,7 @@ void cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); +void smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server); bool backup_cred(struct cifs_sb_info *cifs_sb); bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file, bool from_readdir); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index f46c37e9b3c7..c3614c077746 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1249,8 +1249,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) return 0; } -static void -smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) +void smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) { struct smb2_hdr *shdr = (struct smb2_hdr *)buffer; int scredits, in_flight; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index a0b9363ba89d..83d5c6a05ef6 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -5263,9 +5263,10 @@ static void smb2_decrypt_offload(struct work_struct *work) dw->server->lstrp = jiffies; mid = smb2_find_dequeue_mid(dw->server, dw->buf); - if (mid == NULL) + if (mid == NULL) { cifs_dbg(FYI, "mid not found\n"); - else { + smb2_add_credits_from_hdr(dw->buf, dw->server); + } else { mid->decrypted = true; rc = handle_read_data(dw->server, mid, dw->buf, dw->server->vals->read_rsp_size, @@ -5396,6 +5397,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, *mid = smb2_find_mid(server, buf); if (*mid == NULL) { cifs_dbg(FYI, "mid not found\n"); + smb2_add_credits_from_hdr(buf, server); rc = -1; } else { cifs_dbg(FYI, "mid found\n");