diff options
| author | Henrique Carvalho <henrique.carvalho@suse.com> | 2026-01-27 13:01:28 -0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-02-16 10:17:47 +0100 |
| commit | 4386f6af8aaedd0c5ad6f659b40cadcc8f423828 (patch) | |
| tree | 97bbd6166b7fc4d1c0327cb6e61b290afbcbc22f | |
| parent | 1b4ef5214f17e671cc13f2da4a678574ce91d151 (diff) | |
| download | linux-4386f6af8aaedd0c5ad6f659b40cadcc8f423828.tar.gz linux-4386f6af8aaedd0c5ad6f659b40cadcc8f423828.tar.bz2 linux-4386f6af8aaedd0c5ad6f659b40cadcc8f423828.zip | |
smb: client: split cached_fid bitfields to avoid shared-byte RMW races
commit ec306600d5ba7148c9dbf8f5a8f1f5c1a044a241 upstream.
is_open, has_lease and on_list are stored in the same bitfield byte in
struct cached_fid but are updated in different code paths that may run
concurrently. Bitfield assignments generate byte read–modify–write
operations (e.g. `orb $mask, addr` on x86_64), so updating one flag can
restore stale values of the others.
A possible interleaving is:
CPU1: load old byte (has_lease=1, on_list=1)
CPU2: clear both flags (store 0)
CPU1: RMW store (old | IS_OPEN) -> reintroduces cleared bits
To avoid this class of races, convert these flags to separate bool
fields.
Cc: stable@vger.kernel.org
Fixes: ebe98f1447bbc ("cifs: enable caching of directories for which a lease is held")
Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | fs/smb/client/cached_dir.h | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h index bc8a812ff95f..96697c78b3a6 100644 --- a/fs/smb/client/cached_dir.h +++ b/fs/smb/client/cached_dir.h @@ -34,10 +34,10 @@ struct cached_fid { struct list_head entry; struct cached_fids *cfids; const char *path; - bool has_lease:1; - bool is_open:1; - bool on_list:1; - bool file_all_info_is_valid:1; + bool has_lease; + bool is_open; + bool on_list; + bool file_all_info_is_valid; unsigned long time; /* jiffies of when lease was taken */ struct kref refcount; struct cifs_fid fid; |
