public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Henrique Carvalho <henrique.carvalho@suse.com>,
	Steve French <stfrench@microsoft.com>,
	Sasha Levin <sashal@kernel.org>,
	sfrench@samba.org, linux-cifs@vger.kernel.org,
	samba-technical@lists.samba.org
Subject: [PATCH AUTOSEL 6.19-6.1] smb: client: add proper locking around ses->iface_last_update
Date: Tue, 10 Feb 2026 18:31:07 -0500	[thread overview]
Message-ID: <20260210233123.2905307-22-sashal@kernel.org> (raw)
In-Reply-To: <20260210233123.2905307-1-sashal@kernel.org>

From: Henrique Carvalho <henrique.carvalho@suse.com>

[ Upstream commit e97dcac3dc0bd37e4b56aaa6874b572a3a461102 ]

There is a missing ses->iface_lock in cifs_setup_session,
around ses->iface_last_update.

Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

The locking infrastructure and documentation are identical in the stable
branch. Now I have all the information needed for a thorough analysis.

---

## Complete Analysis

### 1. COMMIT MESSAGE ANALYSIS

The commit subject is "smb: client: add proper locking around
ses->iface_last_update". The body explains that there is a "missing
ses->iface_lock in cifs_setup_session, around ses->iface_last_update."
This is a direct, clear statement of a locking bug fix. The commit is
authored by Henrique Carvalho (SUSE employee) and accepted by Steve
French (the SMB/CIFS maintainer).

### 2. CODE CHANGE ANALYSIS

The patch is minimal — exactly 2 lines added:

```c
+               spin_lock(&ses->iface_lock);
                ses->iface_last_update = 0;
+               spin_unlock(&ses->iface_lock);
```

This wraps the write to `ses->iface_last_update` (which forces an
interface list refresh) with the `ses->iface_lock` spinlock.

### 3. BUG MECHANISM — THE DATA RACE

**The documentation is unambiguous.** In `fs/smb/client/cifsglob.h`:

```1111:1123:fs/smb/client/cifsglob.h
 - iface_lock should be taken when accessing any of these fields
 */
spinlock_t iface_lock;
/* ========= begin: protected by iface_lock ======== */
struct list_head iface_list;
size_t iface_count;
unsigned long iface_last_update; /* jiffies */
/* ========= end: protected by iface_lock ======== */
```

And in the locking documentation at lines 2000-2002:

```2000:2002:fs/smb/client/cifsglob.h
 - cifs_ses->iface_lock            cifs_ses->iface_list
   sesInfoAlloc
 - ->iface_count
 - ->iface_last_update
```

`iface_last_update` is explicitly documented as protected by
`iface_lock`. The buggy code at `connect.c:4273` writes to this field
without holding the lock.

**Concurrent access paths that create the race:**

1. **Writer (buggy, in `cifs_setup_session`):** Sets
   `ses->iface_last_update = 0` during session reconnect — called from
   `smb2_reconnect()`, `cifs_reconnect_tcon()`, `cifs_get_smb_ses()`,
   and `cifs_ses_add_channel()`.

2. **Reader (in `SMB3_request_interfaces`, smb2ops.c:828):** Reads
   `iface_last_update` as an optimization check before performing an
   expensive ioctl. This is called from the
   `smb2_query_server_interfaces` delayed work that runs periodically
   every `SMB_INTERFACE_POLL_INTERVAL` seconds.

3. **Reader/Writer (in `parse_server_interfaces`, smb2ops.c:641):**
   Reads `iface_last_update` with `iface_lock` held, writes
   `iface_last_update` at lines 669 and 798.

**The concrete race scenario:** Thread A is doing a session reconnect
and calls `cifs_setup_session()` which writes `iface_last_update = 0`
without the lock. Concurrently, Thread B (the periodic delayed work
`smb2_query_server_interfaces`) calls
`SMB3_request_interfaces`/`parse_server_interfaces` which reads
`iface_last_update` under `iface_lock`. This is a classic data race
where a writer and reader access shared data without consistent
synchronization.

On weakly-ordered architectures (ARM64), this can lead to the reader
seeing a torn or stale value of `iface_last_update`, potentially causing
the interface list not to be refreshed when it should be (or vice
versa). Even on x86-64 where `unsigned long` writes are naturally
atomic, this violates the documented locking discipline and could
confuse KCSAN (Kernel Concurrency Sanitizer).

### 4. SCOPE AND RISK ASSESSMENT

- **Size:** 2 lines added — the smallest possible fix
- **Files touched:** 1 (`fs/smb/client/connect.c`)
- **Risk of regression:** Extremely low. The added
  `spin_lock/spin_unlock` pair is properly nested inside the already-
  held `ses_lock`. Looking at the locking hierarchy documented in
  `cifsglob.h`, `ses_lock` and `iface_lock` are independent spinlocks
  (no nested ordering requirement documented). The critical section is
  one `unsigned long` assignment — negligible contention.
- **Subsystem:** SMB client — a filesystem used by many enterprise users
  for networked file access

### 5. USER IMPACT

This affects all users of the SMB/CIFS client who use multichannel
sessions (Azure files, enterprise NAS). The race occurs during session
reconnect — a critical recovery path that fires when a server connection
drops. The race could cause:
- **Missed interface refresh:** If the write to `iface_last_update = 0`
  tears or is lost due to the race, the client might not refresh the
  interface list during reconnect, potentially connecting secondary
  channels to stale/wrong IP addresses
- **Incorrect reconnection behavior:** After a server failover (common
  with Azure files), secondary channels might connect to the wrong
  server

### 6. AFFECTED VERSIONS

The buggy commit `d9a6d78096056a3cb5c5f07a730ab92f2f9ac4e6` was
introduced in v6.7-rc1 and was already backported to stable branches:
- 6.1.y (as `c9569bfd2868`)
- 6.6.y (as `aabf4851d160`)
- 6.12.y (as `d9a6d78096056`)

The code context is identical in all these branches — the fix applies
cleanly.

### 7. DEPENDENCY CHECK

This fix is completely self-contained. It requires only:
- `ses->iface_lock` spinlock to exist (present since the multichannel
  feature was added)
- The `iface_last_update` field to be in the `iface_lock`-protected
  region (documented since its introduction)

No other commits are needed.

### 8. CLASSIFICATION

This is a **race condition fix** (data race on a shared variable
accessed without proper synchronization). It falls squarely into the
"synchronization changes" category of stable-worthy fixes. The fix is:
- Obviously correct (adds documented required locking)
- Tested (accepted by maintainer)
- Small (2 lines)
- Fixes a real bug (data race during reconnect)
- Contained (no side effects)
- Does not introduce new features or APIs

**YES**

 fs/smb/client/connect.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index ce620503e9f70..60c76375f0f50 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -4270,7 +4270,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 		ses->ses_status = SES_IN_SETUP;
 
 		/* force iface_list refresh */
+		spin_lock(&ses->iface_lock);
 		ses->iface_last_update = 0;
+		spin_unlock(&ses->iface_lock);
 	}
 	spin_unlock(&ses->ses_lock);
 
-- 
2.51.0


  parent reply	other threads:[~2026-02-10 23:31 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-10 23:30 [PATCH AUTOSEL 6.19-6.12] i3c: mipi-i3c-hci: Reset RING_OPERATION1 fields during init Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-5.15] gfs2: fiemap page fault fix Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.18] dlm: fix recovery pending middle conversion Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.6] smb: client: prevent races in ->query_interfaces() Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.12] i3c: mipi-i3c-hci: Ensure proper bus clean-up Sasha Levin
2026-02-11  7:56   ` Adrian Hunter
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-5.10] audit: add fchmodat2() to change attributes class Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.12] btrfs: fallback to buffered IO if the data profile has duplication Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19] btrfs: don't BUG() on unexpected delayed ref type in run_one_delayed_ref() Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.12] i3c: mipi-i3c-hci-pci: Add System Suspend support Sasha Levin
2026-02-11  7:57   ` Adrian Hunter
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.18] hfsplus: fix volume corruption issue for generic/480 Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.18] kselftest/kublk: include message in _Static_assert for C11 compatibility Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.12] dlm: validate length in dlm_search_rsb_tree Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.18] i3c: mipi-i3c-hci: Stop reading Extended Capabilities if capability ID is 0 Sasha Levin
2026-02-10 23:30 ` [PATCH AUTOSEL 6.19-6.1] fs/buffer: add alert in try_to_free_buffers() for folios without buffers Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-5.15] i3c: master: svc: Initialize 'dev' to NULL in svc_i3c_master_ibi_isr() Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-6.12] statmount: permission check should return EPERM Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-5.10] audit: add missing syscalls to read class Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-5.10] hfsplus: pretend special inodes as regular files Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-5.10] hfsplus: fix volume corruption issue for generic/498 Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-6.18] netfs: when subreq is marked for retry, do not check if it faced an error Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19] hfs: Replace BUG_ON with error handling for CNID count checks Sasha Levin
2026-02-10 23:31 ` Sasha Levin [this message]
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-6.6] btrfs: handle user interrupt properly in btrfs_trim_fs() Sasha Levin
2026-02-10 23:31 ` [PATCH AUTOSEL 6.19-5.10] minix: Add required sanity checking to minix_check_superblock() Sasha Levin
2026-02-11  7:56 ` [PATCH AUTOSEL 6.19-6.12] i3c: mipi-i3c-hci: Reset RING_OPERATION1 fields during init Adrian Hunter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260210233123.2905307-22-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=henrique.carvalho@suse.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=patches@lists.linux.dev \
    --cc=samba-technical@lists.samba.org \
    --cc=sfrench@samba.org \
    --cc=stable@vger.kernel.org \
    --cc=stfrench@microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox