7.0.2-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainercover 7.0.2-rc1 review
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-7.0.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 7.0.2-rc1
Naman Jain <[email protected]>
mshv_vtl: Fix vmemmap_shift exceeding MAX_FOLIO_ORDER
Anderson Nascimento <[email protected]>
rxrpc: Fix missing validation of ticket length in non-XDR key preparsing
Sean Christopherson <[email protected]>
crypto: ccp: Don't attempt to copy ID to userspace if PSP command failed
Sean Christopherson <[email protected]>
crypto: ccp: Don't attempt to copy PDH cert to userspace if PSP command failed
Sean Christopherson <[email protected]>
crypto: ccp: Don't attempt to copy CSR to userspace if PSP command failed
Bingquan Chen <[email protected]>
net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
Berk Cem Goksel <[email protected]>
ALSA: caiaq: take a reference on the USB device in create_card()
Eric Naim <[email protected]>
ALSA: hda/realtek: Add quirk for Legion S7 15IMH
Cryolitia PukNgae <[email protected]>
ALSA: usb-audio: apply quirk for MOONDROP JU Jiu
George Saad <[email protected]>
f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
Jan Kara <[email protected]>
writeback: Fix use after free in inode_switch_wbs_work_fn()
DaeMyung Kang <[email protected]>
ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()
Tristan Madani <[email protected]>
ksmbd: use check_add_overflow() to prevent u16 DACL size overflow
Tristan Madani <[email protected]>
ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment
Michael Bommarito <[email protected]>
ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl()
Michael Bommarito <[email protected]>
ksmbd: validate response sizes in ipc_validate_msg()
Michael Bommarito <[email protected]>
smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
Michael Bommarito <[email protected]>
smb: client: validate the whole DACL before rewriting it in cifsacl
Michael Bommarito <[email protected]>
smb: client: require a full NFS mode SID before reading mode bits
DaeMyung Kang <[email protected]>
smb: server: fix max_connections off-by-one in tcp accept path
Paulo Alcantara <[email protected]>
smb: client: fix dir separator in SMB1 UNIX mounts
Michael Bommarito <[email protected]>
smb: server: fix active_num_conn leak on transport allocation failure
Michael Bommarito <[email protected]>
ksmbd: require minimum ACE size in smb_check_perm_dacl()
Miklos Szeredi <[email protected]>
fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized
Darrick J. Wong <[email protected]>
fuse: quiet down complaints in fuse_conn_limit_write
Bernd Schubert <[email protected]>
fuse: Check for large folio with SPLICE_F_MOVE
Miklos Szeredi <[email protected]>
fuse: abort on fatal signal during sync init
Samuel Page <[email protected]>
fuse: reject oversized dirents in page cache
Chao Yu <[email protected]>
f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer
Chao Yu <[email protected]>
f2fs: fix to avoid memory leak in f2fs_rename()
Yongpeng Yang <[email protected]>
f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
Chao Yu <[email protected]>
f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
Greg Kroah-Hartman <[email protected]>
fs/ntfs3: validate rec->used in journal-replay file record check
Nathan Chancellor <[email protected]>
scripts/dtc: Remove unused dts_version in dtc-lexer.l
Tamir Duberstein <[email protected]>
scripts: generate_rust_analyzer.py: define scripts
Namjae Jeon <[email protected]>
ksmbd: validate owner of durable handle on reconnect
Namjae Jeon <[email protected]>
ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger
Dudu Lu <[email protected]>
crypto: krb5enc - fix async decrypt skipping hash verification
Wesley Atwell <[email protected]>
crypto: krb5enc - fix sleepable flag handling in encrypt dispatch
Mikhail Gavrilov <[email protected]>
drm/amdgpu: replace PASID IDR with XArray
Miguel Ojeda <[email protected]>
pwm: th1520: fix `CLIPPY=1` warning
Herbert Xu <[email protected]>
crypto: authencesn - Fix src offset when decrypting in-place
-------------
Diffstat:
Makefile | 4 +- crypto/authencesn.c | 6 +- crypto/krb5enc.c | 51 ++++++++----- drivers/crypto/ccp/sev-dev.c | 19 ++++- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 39 +++++----- drivers/hv/mshv_vtl_main.c | 12 ++- drivers/pwm/pwm_th1520.rs | 5 +- fs/f2fs/compress.c | 14 +++- fs/f2fs/data.c | 7 +- fs/f2fs/f2fs.h | 2 +- fs/f2fs/namei.c | 1 + fs/f2fs/segment.c | 6 +- fs/f2fs/super.c | 11 ++- fs/fs-writeback.c | 36 ++++----- fs/fuse/control.c | 4 +- fs/fuse/dev.c | 30 +++++--- fs/fuse/fuse_i.h | 1 + fs/fuse/inode.c | 1 + fs/fuse/readdir.c | 4 + fs/ntfs3/fslog.c | 12 ++- fs/smb/client/cifsacl.c | 117 +++++++++++++++++++++-------- fs/smb/client/connect.c | 10 +-- fs/smb/client/smb1ops.c | 19 ++--- fs/smb/client/smb2ops.c | 6 ++ fs/smb/server/connection.c | 5 +- fs/smb/server/mgmt/user_config.c | 6 -- fs/smb/server/mgmt/user_session.c | 8 +- fs/smb/server/oplock.c | 7 ++ fs/smb/server/oplock.h | 1 + fs/smb/server/smb2pdu.c | 5 +- fs/smb/server/smbacl.c | 61 +++++++++++---- fs/smb/server/transport_ipc.c | 16 +++- fs/smb/server/transport_tcp.c | 4 +- fs/smb/server/vfs_cache.c | 128 +++++++++++++++++++++++++++----- fs/smb/server/vfs_cache.h | 12 ++- include/uapi/linux/mshv.h | 2 +- net/packet/af_packet.c | 21 ++++-- net/rxrpc/key.c | 4 + scripts/dtc/dtc-lexer.l | 3 - scripts/generate_rust_analyzer.py | 14 +++- sound/hda/codecs/realtek/alc269.c | 1 + sound/usb/caiaq/device.c | 4 +- sound/usb/mixer.c | 7 ++ 43 files changed, 513 insertions(+), 213 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/42 crypto: authencesn - Fix src offset when decrypting in-place
7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herbert Xu <[email protected]>
commit 1f48ad3b19a9dfc947868edda0bb8e48e5b5a8fa upstream.
The src SG list offset wasn't set properly when decrypting in-place, fix it.
--- crypto/authencesn.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
crypto/authencesn.c +4 -2
@@ -228,9 +228,11 @@ static int crypto_authenc_esn_decrypt_ta decrypt: -if (src != dst) - src =scatterwalk_ffwd (areq_ctx->src, src, assoclen); dst =scatterwalk_ffwd (areq_ctx->dst, dst, assoclen); +if (req->src == req->dst) + src = dst; +else + src =scatterwalk_ffwd (areq_ctx->src, src, assoclen);skcipher_request_set_tfm (skreq, ctx->enc); skcipher_request_set_callback(skreq, flags,
Greg Kroah-Hartman
maintainerPATCH 2/42 pwm: th1520: fix `CLIPPY=1` warning
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
[ Upstream commit aa8f35172ab66c57d4355a8c4e28d05b44c938e3 ]
The Rust kernel code should be kept CLIPPY=1-clean [1].
Clippy reports:
error: this pattern reimplements `Option::unwrap_or`
--> drivers/pwm/pwm_th1520.rs:64:5
|
64 | / (match ns.checked_mul(rate_hz) {
65 | | Some(product) => product,
66 | | None => u64::MAX,
67 | | }) / NSEC_PER_SEC_U64
| |______^ help: replace with: `ns.checked_mul(rate_hz).unwrap_or(u64::MAX)`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#manual_unwrap_or
= note: `-D clippy::manual-unwrap-or` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or)]`Applying the suggestion then triggers:
error: manual saturating arithmetic
--> drivers/pwm/pwm_th1520.rs:64:5
|
64 | ns.checked_mul(rate_hz).unwrap_or(u64::MAX) / NSEC_PER_SEC_U64
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `ns.saturating_mul(rate_hz)`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#manual_saturating_arithmetic
= note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]`Thus fix it by using saturating arithmetic, which simplifies the code as well.
--- drivers/pwm/pwm_th1520.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/pwm/pwm_th1520.rs +1 -4
@@ -64,10 +64,7 @@ const fn th1520_pwm_fp(n: u32) -> usize {fn ns_to_cycles (ns:u64 , rate_hz:u64 ) ->u64 {const NSEC_PER_SEC_U64 :u64 = time::NSEC_PER_SEC as u64 ; - (match ns.checked_mul (rate_hz) { -Some (product) => product, -None => u64::MAX , - }) /NSEC_PER_SEC_U64 + ns.saturating_mul (rate_hz) /NSEC_PER_SEC_U64 }fn cycles_to_ns (cycles:u64 , rate_hz:u64 ) ->u64 {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 3/42 drm/amdgpu: replace PASID IDR with XArray
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit 3c863ff920b45fa7a9b7d4cb932f466488a87a58 upstream.
Replace the PASID IDR + spinlock with XArray as noted in the TODO left by commit ea56aa262570 ("drm/amdgpu: fix the idr allocation flags").
The IDR conversion still has an IRQ safety issue:amdgpu_pasid_free() can be called from hardirq context via the fence signal path, but amdgpu_pasid_idr_lock is taken with plain spin_lock() in process context, creating a potential deadlock:
CPU0
----
spin_lock(&amdgpu_pasid_idr_lock) // process context, IRQs on
<Interrupt>
spin_lock(&amdgpu_pasid_idr_lock) // deadlock
The hardirq call chain is:
sdma_v6_0_process_trap_irq
-> amdgpu_fence_process
-> dma_fence_signal
-> drm_sched_job_done
-> dma_fence_signal
-> amdgpu_pasid_free_cb
-> amdgpu_pasid_freeUse XArray with XA_FLAGS_LOCK_IRQ (all xa operations use IRQ-safe locking internally) and XA_FLAGS_ALLOC1 (zero is not a valid PASID). Both xa_alloc_cyclic() and xa_erase() then handle locking consistently, fixing the IRQ safety issue and removing the need for an explicit spinlock.
v8: squash in irq safe fix
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 39 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +19 -20
@@ -22,7 +22,7 @@*/ #include "amdgpu_ids.h" -#include <linux/idr.h> +#include <linux/xarray.h> #include <linux/dma-fence-array.h>
@@ -40,8 +40,8 @@* VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDR (amdgpu_pasid_idr); -static DEFINE_SPINLOCK (amdgpu_pasid_idr_lock); +static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1); +static u32 amdgpu_pasid_xa_next;/* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb {
@@ -62,36 +62,37 @@ struct amdgpu_pasid_cb {*/ int amdgpu_pasid_alloc (unsigned int bits) { -int pasid; +u32 pasid; +int r;if (bits ==0 )return -EINVAL ; -spin_lock (&amdgpu_pasid_idr_lock); -/* TODO: Need to replace the idr with an xarry, and then -* handle the internal locking with ATOMIC safe paths. -*/ - pasid =idr_alloc_cyclic (&amdgpu_pasid_idr,NULL ,1 , -1U << bits,GFP_ATOMIC ); -spin_unlock (&amdgpu_pasid_idr_lock); - -if (pasid >=0 ) -trace_amdgpu_pasid_allocated (pasid); + r =xa_alloc_cyclic_irq (&amdgpu_pasid_xa, &pasid,xa_mk_value (0 ), +XA_LIMIT (1 , (1U << bits) -1 ), + &amdgpu_pasid_xa_next,GFP_KERNEL ); +if (r <0 ) +return r; +trace_amdgpu_pasid_allocated (pasid);return pasid; }/** * amdgpu_pasid_free - Free a PASID * @pasid: PASID to free +* +* Called in IRQ context. */ void amdgpu_pasid_free (u32 pasid) { +unsigned long flags; +trace_amdgpu_pasid_freed (pasid); -spin_lock (&amdgpu_pasid_idr_lock); -idr_remove (&amdgpu_pasid_idr, pasid); -spin_unlock (&amdgpu_pasid_idr_lock); +xa_lock_irqsave (&amdgpu_pasid_xa, flags); +__xa_erase (&amdgpu_pasid_xa, pasid); +xa_unlock_irqrestore (&amdgpu_pasid_xa, flags); } static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -634,7 +635,5 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_*/ void amdgpu_pasid_mgr_cleanup (void ) { -spin_lock (&amdgpu_pasid_idr_lock); -idr_destroy (&amdgpu_pasid_idr); -spin_unlock (&amdgpu_pasid_idr_lock); +xa_destroy (&amdgpu_pasid_xa); }
Greg Kroah-Hartman
maintainerPATCH 4/42 crypto: krb5enc - fix sleepable flag handling in encrypt dispatch
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wesley Atwell <[email protected]>
commit 2ef3bac16fb5e9eee4fb1d722578a79b751ea58a upstream.
krb5enc_encrypt_ahash_done() continues encryption from an ahash completion callback by calling krb5enc_dispatch_encrypt().
That helper takes a flags argument for this continuation path, but it ignored that argument and reused aead_request_flags(req) when setting up the skcipher subrequest callback. This can incorrectly preserve CRYPTO_TFM_REQ_MAY_SLEEP when the encrypt step is started from callback context.
Preserve the original request flags but clear CRYPTO_TFM_REQ_MAY_SLEEP for the callback continuation path, and use the caller-supplied flags when setting up the skcipher subrequest.
--- crypto/krb5enc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
crypto/krb5enc.c +3 -2
@@ -154,7 +154,7 @@ static int krb5enc_dispatch_encrypt(stru dst =scatterwalk_ffwd (areq_ctx->dst, req->dst, req->assoclen);skcipher_request_set_tfm (skreq, enc); -skcipher_request_set_callback (skreq,aead_request_flags (req), +skcipher_request_set_callback (skreq, flags, krb5enc_encrypt_done, req);skcipher_request_set_crypt (skreq, src, dst, req->cryptlen, req->iv);
@@ -192,7 +192,8 @@ static void krb5enc_encrypt_ahash_done(vkrb5enc_insert_checksum (req, ahreq->result); - err =krb5enc_dispatch_encrypt (req,0 ); + err =krb5enc_dispatch_encrypt (req, +aead_request_flags (req) & ~CRYPTO_TFM_REQ_MAY_SLEEP );if (err != -EINPROGRESS )aead_request_complete (req, err); }
Greg Kroah-Hartman
maintainerPATCH 5/42 crypto: krb5enc - fix async decrypt skipping hash verification
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dudu Lu <[email protected]>
commit 3bfbf5f0a99c991769ec562721285df7ab69240b upstream.
krb5enc_dispatch_decrypt() sets req->base.complete as the skcipher callback, which is the caller's own completion handler. When the skcipher completes asynchronously, this signals "done" to the caller without executing krb5enc_dispatch_decrypt_hash(), completely bypassing the integrity verification (hash check).
Compare with the encrypt path which correctly uses krb5enc_encrypt_done as an intermediate callback to chain into the hash computation on async completion.
Fix by adding krb5enc_decrypt_done as an intermediate callback that chains into krb5enc_dispatch_decrypt_hash() upon async skcipher completion, matching the encrypt path's callback pattern.
Also fix EBUSY/EINPROGRESS handling throughout: remove krb5enc_request_complete() which incorrectly swallowed EINPROGRESS notifications that must be passed up to callers waiting on backlogged requests, and add missing EBUSY checks in krb5enc_encrypt_ahash_done for the dispatch_encrypt return value.
Unset MAY_BACKLOG on the async completion path so the user won't see back-to-back EINPROGRESS notifications.
--- crypto/krb5enc.c | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-)
crypto/krb5enc.c +31 -21
@@ -39,12 +39,6 @@ struct krb5enc_request_ctx {char tail[]; }; -static void krb5enc_request_complete (struct aead_request *req,int err) -{ -if (err != -EINPROGRESS ) -aead_request_complete (req, err); -} -/** * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob. * @keys: Where to put the key sizes and pointers
@@ -127,7 +121,7 @@ static void krb5enc_encrypt_done(void *d {struct aead_request *req = data; -krb5enc_request_complete (req, err); +aead_request_complete (req, err); }/*
@@ -188,14 +182,16 @@ static void krb5enc_encrypt_ahash_done(vstruct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);if (err) -return krb5enc_request_complete (req, err); + goto out;krb5enc_insert_checksum (req, ahreq->result); - err =krb5enc_dispatch_encrypt (req, -aead_request_flags (req) & ~CRYPTO_TFM_REQ_MAY_SLEEP ); -if (err != -EINPROGRESS ) -aead_request_complete (req, err); + err =krb5enc_dispatch_encrypt (req,0 ); +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); }/*
@@ -265,17 +261,16 @@ static void krb5enc_decrypt_hash_done(vo {struct aead_request *req = data; -if (err) -return krb5enc_request_complete (req, err); - - err =krb5enc_verify_hash (req); -krb5enc_request_complete (req, err); +if (!err) + err =krb5enc_verify_hash (req); +aead_request_complete (req, err); }/* * Dispatch the hashing of the plaintext after we've done the decryption. */ -static int krb5enc_dispatch_decrypt_hash (struct aead_request *req) +static int krb5enc_dispatch_decrypt_hash (struct aead_request *req, +unsigned int flags) {struct crypto_aead *krb5enc =crypto_aead_reqtfm (req);struct aead_instance *inst =aead_alg_instance (krb5enc);
@@ -291,7 +286,7 @@ static int krb5enc_dispatch_decrypt_hashahash_request_set_tfm (ahreq, auth);ahash_request_set_crypt (ahreq, req->dst, hash, req->assoclen + req->cryptlen - authsize); -ahash_request_set_callback (ahreq,aead_request_flags (req), +ahash_request_set_callback (ahreq, flags, krb5enc_decrypt_hash_done, req); err =crypto_ahash_digest (ahreq);
@@ -301,6 +296,21 @@ static int krb5enc_dispatch_decrypt_hashreturn krb5enc_verify_hash (req); } +static void krb5enc_decrypt_done (void *data,int err) +{ +struct aead_request *req = data; + +if (err) + goto out; + + err =krb5enc_dispatch_decrypt_hash (req,0 ); +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); +} +/* * Dispatch the decryption of the ciphertext. */
@@ -324,7 +334,7 @@ static int krb5enc_dispatch_decrypt(struskcipher_request_set_tfm (skreq, ctx->enc);skcipher_request_set_callback (skreq,aead_request_flags (req), - req->base.complete, req->base.data); + krb5enc_decrypt_done, req);skcipher_request_set_crypt (skreq, src, dst, req->cryptlen - authsize, req->iv);
@@ -339,7 +349,7 @@ static int krb5enc_decrypt(struct aead_rif (err <0 )return err; -return krb5enc_dispatch_decrypt_hash (req); +return krb5enc_dispatch_decrypt_hash (req,aead_request_flags (req)); }static int krb5enc_init_tfm (struct crypto_aead *tfm)
Greg Kroah-Hartman
maintainerPATCH 6/42 ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 235e32320a470fcd3998fb3774f2290a0eb302a1 ]
When a durable file handle survives session disconnect (TCP close without SMB2_LOGOFF), session_fd_check() sets fp->conn = NULL to preserve the handle for later reconnection. However, it did not clean up the byte-range locks on fp->lock_list.
Later, when the durable scavenger thread times out and calls __ksmbd_close_fd(NULL, fp), the lock cleanup loop did:
spin_lock(&fp->conn->llist_lock);
This caused a slab use-after-free because fp->conn was NULL and the original connection object had already been freed by ksmbd_tcp_disconnect().
The root cause is asymmetric cleanup: lock entries (smb_lock->clist) were left dangling on the freed conn->lock_list while fp->conn was nulled out.
To fix this issue properly, we need to handle the lifetime of smb_lock->clist across three paths:
- Safely skip clist deletion when list is empty and fp->conn is NULL.
- Remove the lock from the old connection's lock_list in session_fd_check()
- Re-add the lock to the new connection's lock_list in ksmbd_reopen_durable_fd().
Stable-dep-of: 49110a8ce654 ("ksmbd: validate owner of durable handle on reconnect")
--- fs/smb/server/vfs_cache.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-)
fs/smb/server/vfs_cache.c +30 -11
@@ -463,9 +463,11 @@ static void __ksmbd_close_fd(struct ksmb* there are not accesses to fp->lock_list. */ list_for_each_entry_safe (smb_lock, tmp_lock, &fp->lock_list, flist) { -spin_lock (&fp->conn->llist_lock); -list_del (&smb_lock->clist); -spin_unlock (&fp->conn->llist_lock); +if (!list_empty (&smb_lock->clist) && fp->conn) { +spin_lock (&fp->conn->llist_lock); +list_del (&smb_lock->clist); +spin_unlock (&fp->conn->llist_lock); + }list_del (&smb_lock->flist);locks_free_lock (smb_lock->fl);
@@ -995,6 +997,7 @@ static bool session_fd_check(struct ksmbstruct ksmbd_inode *ci;struct oplock_info *op;struct ksmbd_conn *conn; +struct ksmbd_lock *smb_lock, *tmp_lock;if (!is_reconnectable (fp))return false;
@@ -1011,6 +1014,12 @@ static bool session_fd_check(struct ksmb }up_write (&ci->m_lock); +list_for_each_entry_safe (smb_lock, tmp_lock, &fp->lock_list, flist) { +spin_lock (&fp->conn->llist_lock); +list_del_init (&smb_lock->clist); +spin_unlock (&fp->conn->llist_lock); + } + fp->conn =NULL ; fp->tcon =NULL ; fp->volatile_id =KSMBD_NO_FID ;
@@ -1090,6 +1099,9 @@ int ksmbd_reopen_durable_fd(struct ksmbd {struct ksmbd_inode *ci;struct oplock_info *op; +struct ksmbd_conn *conn = work->conn; +struct ksmbd_lock *smb_lock; +unsigned int old_f_state;if (!fp->is_durable || fp->conn || fp->tcon) {pr_err ("Invalid durable fd [%p:%p]\n" , fp->conn, fp->tcon);
@@ -1101,9 +1113,23 @@ int ksmbd_reopen_durable_fd(struct ksmbdreturn -EBADF ; } - fp->conn = work->conn; + old_f_state = fp->f_state; + fp->f_state =FP_NEW ; +__open_id (&work->sess->file_table, fp,OPEN_ID_TYPE_VOLATILE_ID ); +if (!has_file_id (fp->volatile_id)) { + fp->f_state = old_f_state; +return -EBADF ; + } + + fp->conn = conn; fp->tcon = work->tcon; +list_for_each_entry (smb_lock, &fp->lock_list, flist) { +spin_lock (&conn->llist_lock); +list_add_tail (&smb_lock->clist, &conn->lock_list); +spin_unlock (&conn->llist_lock); + } + ci = fp->f_ci;down_write (&ci->m_lock);list_for_each_entry_rcu (op, &ci->m_op_list, op_entry) {
@@ -1114,13 +1140,6 @@ int ksmbd_reopen_durable_fd(struct ksmbd }up_write (&ci->m_lock); - fp->f_state =FP_NEW ; -__open_id (&work->sess->file_table, fp,OPEN_ID_TYPE_VOLATILE_ID ); -if (!has_file_id (fp->volatile_id)) { - fp->conn =NULL ; - fp->tcon =NULL ; -return -EBADF ; - }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 7/42 ksmbd: validate owner of durable handle on reconnect
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 49110a8ce654bbe56bef7c5e44cce31f4b102b8a ]
Currently, ksmbd does not verify if the user attempting to reconnect to a durable handle is the same user who originally opened the file. This allows any authenticated user to hijack an orphaned durable handle by predicting or brute-forcing the persistent ID.
According to MS-SMB2, the server MUST verify that the SecurityContext of the reconnect request matches the SecurityContext associated with the existing open.
Add a durable_owner structure to ksmbd_file to store the original opener's UID, GID, and account name. and catpure the owner information when a file handle becomes orphaned. and implementing ksmbd_vfs_compare_durable_owner() to validate the identity of the requester during SMB2_CREATE (DHnC).
--- fs/smb/server/mgmt/user_session.c | 8 +-- fs/smb/server/oplock.c | 7 +++ fs/smb/server/oplock.h | 1 fs/smb/server/smb2pdu.c | 3 - fs/smb/server/vfs_cache.c | 87 ++++++++++++++++++++++++++++++++++---- fs/smb/server/vfs_cache.h | 12 ++++- 6 files changed, 102 insertions(+), 16 deletions(-)
fs/smb/server/mgmt/user_session.c +3 -5
@@ -382,12 +382,10 @@ void ksmbd_session_destroy(struct ksmbd_return ;delete_proc_session (sess); - +ksmbd_tree_conn_session_logoff (sess); +ksmbd_destroy_file_table (sess);if (sess->user)ksmbd_free_user (sess->user); - -ksmbd_tree_conn_session_logoff (sess); -ksmbd_destroy_file_table (&sess->file_table);ksmbd_launch_ksmbd_durable_scavenger ();ksmbd_session_rpc_clear_list (sess);free_channel_list (sess);
@@ -618,7 +616,7 @@ void destroy_previous_session(struct ksm goto out; } -ksmbd_destroy_file_table (&prev_sess->file_table); +ksmbd_destroy_file_table (prev_sess); prev_sess->state =SMB2_SESSION_EXPIRED ;ksmbd_all_conn_set_status (id,KSMBD_SESS_NEED_SETUP );ksmbd_launch_ksmbd_durable_scavenger ();
fs/smb/server/oplock.c +7 -0
@@ -1841,6 +1841,7 @@ int smb2_check_durable_oplock(struct ksmstruct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name) { struct oplock_info *opinfo = opinfo_get(fp);
@@ -1849,6 +1850,12 @@ int smb2_check_durable_oplock(struct ksmif (!opinfo)return 0 ; +if (ksmbd_vfs_compare_durable_owner (fp, user) == false) { +ksmbd_debug (SMB ,"Durable handle reconnect failed: owner mismatch\n" ); + ret = -EBADF ; + goto out; + } +if (opinfo->is_lease == false) {if (lctx) {pr_err ("create context include lease\n" );
fs/smb/server/oplock.h +1 -0
@@ -126,5 +126,6 @@ int smb2_check_durable_oplock(struct ksmstruct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name);#endif /* __KSMBD_OPLOCK_H */
fs/smb/server/smb2pdu.c +2 -1
@@ -3013,7 +3013,8 @@ int smb2_open(struct ksmbd_work *work) }if (dh_info.reconnected == true) { - rc =smb2_check_durable_oplock (conn, share, dh_info.fp, lc, name); + rc =smb2_check_durable_oplock (conn, share, dh_info.fp, + lc, sess->user, name);if (rc) {ksmbd_put_durable_fd (dh_info.fp); goto err_out2;
fs/smb/server/vfs_cache.c +78 -9
161 lines not on this page · raw message
fs/smb/server/vfs_cache.h +11 -1
@@ -68,6 +68,13 @@ enum {FP_CLOSED }; +/* Owner information for durable handle reconnect */ +struct durable_owner { +unsigned int uid; +unsigned int gid; +char *name; +}; +struct ksmbd_file {struct file *filp;u64 persistent_id;
@@ -114,6 +121,7 @@ struct ksmbd_file {bool is_resilient;bool is_posix_ctxt; +struct durable_owner owner; }; static inline void set_ctx_actor(struct dir_context *ctx,
@@ -140,7 +148,7 @@ static inline bool ksmbd_stream_fd(struc }int ksmbd_init_file_table (struct ksmbd_file_table *ft); -void ksmbd_destroy_file_table (struct ksmbd_file_table *ft); +void ksmbd_destroy_file_table (struct ksmbd_session *sess);int ksmbd_close_fd (struct ksmbd_work *work,u64 id);struct ksmbd_file *ksmbd_lookup_fd_fast (struct ksmbd_work *work,u64 id);struct ksmbd_file *ksmbd_lookup_foreign_fd (struct ksmbd_work *work,u64 id);
@@ -166,6 +174,8 @@ void ksmbd_free_global_file_table(void);void ksmbd_set_fd_limit (unsigned long limit);void ksmbd_update_fstate (struct ksmbd_file_table *ft,struct ksmbd_file *fp,unsigned int state); +bool ksmbd_vfs_compare_durable_owner (struct ksmbd_file *fp, +struct ksmbd_user *user);/* * INODE hash
Greg Kroah-Hartman
maintainerPATCH 8/42 scripts: generate_rust_analyzer.py: define scripts
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tamir Duberstein <[email protected]>
[ Upstream commit 36c619f6bd793493294becb10a02fea370b67a91 ]
Add IDE support for host-side scripts written in Rust. This support has been missing since these scripts were initially added in commit 9a8ff24ce584 ("scripts: add generate_rust_target.rs"), thus add it.
Change the existing instance of extension stripping to pathlib.Path.stem to maintain code consistency.
--- scripts/generate_rust_analyzer.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
scripts/generate_rust_analyzer.py +13 -1
@@ -188,6 +188,18 @@ def generate_crates(srctree, objtree, sy append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"]) + scripts = srctree / "scripts" + makefile = (scripts / "Makefile").read_text() + for path in scripts.glob("*.rs"): + name = path.stem + if f"{name}-rust" not in makefile: + continue + append_crate( + name, + path, + ["std"], + ) + def is_root_crate(build_file, target): try: contents = build_file.read_text()
@@ -204,7 +216,7 @@ def generate_crates(srctree, objtree, sy for folder in extra_dirs: for path in folder.rglob("*.rs"): logging.info("Checking %s", path) - name = path.name.replace(".rs", "") + name = path.stem # Skip those that are not crate roots. if not is_root_crate(path.parent / "Makefile", name) and \
Greg Kroah-Hartman
maintainerPATCH 9/42 scripts/dtc: Remove unused dts_version in dtc-lexer.l
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
This patch is for stable only. Commit 5a09df20872c ("scripts/dtc: Update to upstream version v1.7.2-69-g53373d135579") upstream applied it as part of a regular scripts/dtc sync, which may be unsuitable for older versions of stable where the warning it fixes is present.
A recent strengthening of -Wunused-but-set-variable (enabled with -Wall) in clang under a new subwarning, -Wunused-but-set-global, points out an unused static global variable in dtc-lexer.lex.c (compiled from dtc-lexer.l):
scripts/dtc/dtc-lexer.lex.c:641:12: warning: variable 'dts_version' set but not used [-Wunused-but-set-global]
641 | static int dts_version = 1;
| ^Remove it to clear up the warning, as it is truly unused.
---
This should apply cleanly to all supported stable branches.
--- scripts/dtc/dtc-lexer.l | 3 --- 1 file changed, 3 deletions(-)
scripts/dtc/dtc-lexer.l +0 -3
@@ -39,8 +39,6 @@ extern bool treesource_error; #define DPRINT(fmt, ...) do { } while (0) #endif -static int dts_version = 1; - #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \ BEGIN(V1); \
@@ -101,7 +99,6 @@ static void PRINTF(1, 2) lexical_error(c <*>"/dts-v1/" { DPRINT("Keyword: /dts-v1/\n"); - dts_version = 1; BEGIN_DEFAULT(); return DT_V1; }
Greg Kroah-Hartman
maintainerPATCH 10/42 fs/ntfs3: validate rec->used in journal-replay file record check
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 0ca0485e4b2e837ebb6cbd4f2451aba665a03e4b upstream.
check_file_record() validates rec->total against the record size but never validates rec->used. The do_action() journal-replay handlers read rec->used from disk and use it to compute memmove lengths:
DeleteAttribute: memmove(attr, ..., used - asize - roff) CreateAttribute: memmove(..., attr, used - roff) change_attr_size: memmove(..., used - PtrOffset(rec, next))
When rec->used is smaller than the offset of a validated attribute, or larger than the record size, these subtractions can underflow allowing us to copy huge amounts of memory in to a 4kb buffer, generally considered a bad idea overall.
This requires a corrupted filesystem, which isn't a threat model the kernel really needs to worry about, but checking for such an obvious out-of-bounds value is good to keep things robust, especially on journal replay
Fix this up by bounding rec->used correctly.
This is much like commit b2bc7c44ed17 ("fs/ntfs3: Fix slab-out-of-bounds read in DeleteIndexEntryRoot") which checked different values in this same switch statement.
--- fs/ntfs3/fslog.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
fs/ntfs3/fslog.c +11 -1
@@ -2791,13 +2791,14 @@ static inline bool check_file_record(conu16 fn =le16_to_cpu (rec->rhdr.fix_num);u16 ao =le16_to_cpu (rec->attr_off);u32 rs = sbi->record_size; +u32 used =le32_to_cpu (rec->used);/* Check the file record header for consistency. */ if (rec->rhdr.sign !=NTFS_FILE_SIGNATURE || fo > (SECTOR_SIZE - ((rs >>SECTOR_SHIFT ) +1 ) *sizeof (short )) || (fn -1 ) *SECTOR_SIZE != rs || ao <MFTRECORD_FIXUP_OFFSET_1 || ao > sbi->record_size -SIZEOF_RESIDENT || !is_rec_inuse (rec) || -le32_to_cpu (rec->total) != rs) { +le32_to_cpu (rec->total) != rs || used > rs || used < ao) {return false; }
@@ -2809,6 +2810,15 @@ static inline bool check_file_record(conreturn false; } +/* +* The do_action() handlers compute memmove lengths as +* "rec->used - <offset of validated attr>", which underflows when +* rec->used is smaller than the attribute walk reached. At this +* point attr is the ATTR_END marker; rec->used must cover it. +*/ +if (used <PtrOffset (rec, attr) +sizeof (attr->type)) +return false; +return true; }
Greg Kroah-Hartman
maintainerPATCH 11/42 f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit 6af249c996f7d73a3435f9e577956fa259347d18 upstream.
Syzbot reported a f2fs bug as below:
------------[ cut here ]------------
kernel BUG at fs/f2fs/segment.c:1900!
Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 6527 Comm: syz.5.110 Not tainted syzkaller #0 PREEMPT_{RT,(full)}
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
RIP: 0010:f2fs_issue_discard_timeout+0x59b/0x5a0 fs/f2fs/segment.c:1900
Code: d9 80 e1 07 80 c1 03 38 c1 0f 8c d6 fe ff ff 48 89 df e8 a8 5e fa fd e9 c9 fe ff ff e8 4e 46 94 fd 90 0f 0b e8 46 46 94 fd 90 <0f> 0b 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3
RSP: 0018:ffffc9000494f940 EFLAGS: 00010283
RAX: ffffffff843009ca RBX: 0000000000000001 RCX: 0000000000080000
RDX: ffffc9001ca78000 RSI: 00000000000029f3 RDI: 00000000000029f4
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: dffffc0000000000 R11: ffffed100893a431 R12: 1ffff1100893a430
R13: 1ffff1100c2b702c R14: dffffc0000000000 R15: ffff8880449d2160
FS: 00007ffa35fed6c0(0000) GS:ffff88812643d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f2b68634000 CR3: 0000000039f62000 CR4: 00000000003526f0
Call Trace:
<TASK>
__f2fs_remount fs/f2fs/super.c:2960 [inline]
f2fs_reconfigure+0x108a/0x1710 fs/f2fs/super.c:5443
reconfigure_super+0x227/0x8a0 fs/super.c:1080
do_remount fs/namespace.c:3391 [inline]
path_mount+0xdc5/0x10e0 fs/namespace.c:4151
do_mount fs/namespace.c:4172 [inline]
__do_sys_mount fs/namespace.c:4361 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4338
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ffa37dbda0aThe root cause is there will be race condition in between f2fs_ioc_fitrim() and f2fs_remount():
- f2fs_remount - f2fs_ioc_fitrim
- f2fs_issue_discard_timeout
- __issue_discard_cmd
- __drop_discard_cmd
- __wait_all_discard_cmd
- f2fs_trim_fs
- f2fs_write_checkpoint
- f2fs_clear_prefree_segments
- f2fs_issue_discard
- __issue_discard_async
- __queue_discard_cmd
- __update_discard_tree_range
- __insert_discard_cmd
- __create_discard_cmd
: atomic_inc(&dcc->discard_cmd_cnt);
- sanity check on dcc->discard_cmd_cnt (expect discard_cmd_cnt to be zero)
This will only happen when fitrim races w/ remount rw, if we remount to readonly filesystem, remount will wait until mnt_pcp.mnt_writers to zero, that means fitrim is not in process at that time.
--- fs/f2fs/f2fs.h | 2 +- fs/f2fs/segment.c | 6 +++--- fs/f2fs/super.c | 11 ++++++++--- 3 files changed, 12 insertions(+), 7 deletions(-)
fs/f2fs/f2fs.h +1 -1
@@ -3989,7 +3989,7 @@ bool f2fs_is_checkpointed_data(struct f2int f2fs_start_discard_thread (struct f2fs_sb_info *sbi);void f2fs_drop_discard_cmd (struct f2fs_sb_info *sbi);void f2fs_stop_discard_thread (struct f2fs_sb_info *sbi); -bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi); +bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi,bool need_check);void f2fs_clear_prefree_segments (struct f2fs_sb_info *sbi,struct cp_control *cpc);void f2fs_dirty_to_prefree (struct f2fs_sb_info *sbi);
fs/f2fs/segment.c +3 -3
@@ -1880,7 +1880,7 @@ void f2fs_stop_discard_thread(struct f2f* * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false. */ -bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi) +bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi,bool need_check) {struct discard_cmd_control *dcc =SM_I (sbi)->dcc_info;struct discard_policy dpolicy;
@@ -1897,7 +1897,7 @@ bool f2fs_issue_discard_timeout(struct f/* just to make sure there is no pending discard commands */ __wait_all_discard_cmd (sbi,NULL ); -f2fs_bug_on (sbi,atomic_read (&dcc->discard_cmd_cnt)); +f2fs_bug_on (sbi, need_check &&atomic_read (&dcc->discard_cmd_cnt));return !dropped; }
@@ -2367,7 +2367,7 @@ static void destroy_discard_cmd_control(* Recovery can cache discard commands, so in error path of * fill_super(), it needs to give a chance to handle them. */ -f2fs_issue_discard_timeout (sbi); +f2fs_issue_discard_timeout (sbi, true);kfree (dcc);SM_I (sbi)->dcc_info =NULL ;
fs/f2fs/super.c +8 -3
@@ -2009,7 +2009,7 @@ static void f2fs_put_super(struct super_ }/* be sure to wait for any on-going discard commands */ - done =f2fs_issue_discard_timeout (sbi); + done =f2fs_issue_discard_timeout (sbi, true);if (f2fs_realtime_discard_enable (sbi) && !sbi->discard_blks && done) {struct cp_control cpc = { .reason =CP_UMOUNT |CP_TRIMMED ,
@@ -2152,7 +2152,7 @@ static int f2fs_unfreeze(struct super_bl* will recover after removal of snapshot. */ if (test_opt (sbi,DISCARD ) && !f2fs_hw_support_discard (sbi)) -f2fs_issue_discard_timeout (sbi); +f2fs_issue_discard_timeout (sbi, true);clear_sbi_flag (F2FS_SB (sb),SBI_IS_FREEZING );return 0 ;
@@ -2957,7 +2957,12 @@ static int __f2fs_remount(struct fs_cont need_stop_discard = true; }else {f2fs_stop_discard_thread (sbi); -f2fs_issue_discard_timeout (sbi); +/* +* f2fs_ioc_fitrim() won't race w/ "remount ro" +* so it's safe to check discard_cmd_cnt in +* f2fs_issue_discard_timeout(). +*/ +f2fs_issue_discard_timeout (sbi, flags &SB_RDONLY ); need_restart_discard = true; } }
Greg Kroah-Hartman
maintainerPATCH 12/42 f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <[email protected]>
commit 2d9c4a4ed4eef1f82c5b16b037aee8bad819fd53 upstream.
The xfstests case "generic/107" and syzbot have both reported a NULL pointer dereference.
The concurrent scenario that triggers the panic is as follows:
F2FS_WB_CP_DATA write callback umount
- f2fs_write_checkpoint
- f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA)
- blk_mq_end_request
- bio_endio
- f2fs_write_end_io
: dec_page_count(sbi, F2FS_WB_CP_DATA)
: wake_up(&sbi->cp_wait)
- kill_f2fs_super
- kill_block_super
- f2fs_put_super
: iput(sbi->node_inode)
: sbi->node_inode = NULL
: f2fs_in_warm_node_list
- is_node_folio // sbi->node_inode is NULL and panic
The root cause is that f2fs_put_super() calls iput(sbi->node_inode) and sets sbi->node_inode to NULL after sbi->nr_pages[F2FS_WB_CP_DATA] is decremented to zero. As a result, f2fs_in_warm_node_list() may dereference a NULL node_inode when checking whether a folio belongs to the node inode, leading to a panic.
This patch fixes the issue by calling f2fs_in_warm_node_list() before decrementing sbi->nr_pages[F2FS_WB_CP_DATA], thus preventing the use-after-free condition.
--- fs/f2fs/data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -2
@@ -386,6 +386,8 @@ static void f2fs_write_end_io(struct bio folio->index, NODE_TYPE_REGULAR, true);f2fs_bug_on (sbi, folio->index !=nid_of_node (folio)); } +if (f2fs_in_warm_node_list (sbi, folio)) +f2fs_del_fsync_node_entry (sbi, folio);dec_page_count (sbi, type);
@@ -397,8 +399,6 @@ static void f2fs_write_end_io(struct bio wq_has_sleeper(&sbi->cp_wait))wake_up (&sbi->cp_wait); -if (f2fs_in_warm_node_list (sbi, folio)) -f2fs_del_fsync_node_entry (sbi, folio);folio_clear_f2fs_gcing (folio);folio_end_writeback (folio); }
Greg Kroah-Hartman
maintainerPATCH 13/42 f2fs: fix to avoid memory leak in f2fs_rename()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit 3cf11e6f36c170050c12171dd6fd3142711478fc upstream.
syzbot reported a f2fs bug as below:
BUG: memory leak
unreferenced object 0xffff888127f70830 (size 16):
comm "syz.0.23", pid 6144, jiffies 4294943712
hex dump (first 16 bytes):
3c af 57 72 5b e6 8f ad 6e 8e fd 33 42 39 03 ff <.Wr[...n..3B9..
backtrace (crc 925f8a80):
kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline]
slab_post_alloc_hook mm/slub.c:4520 [inline]
slab_alloc_node mm/slub.c:4844 [inline]
__do_kmalloc_node mm/slub.c:5237 [inline]
__kmalloc_noprof+0x3bd/0x560 mm/slub.c:5250
kmalloc_noprof include/linux/slab.h:954 [inline]
fscrypt_setup_filename+0x15e/0x3b0 fs/crypto/fname.c:364
f2fs_setup_filename+0x52/0xb0 fs/f2fs/dir.c:143
f2fs_rename+0x159/0xca0 fs/f2fs/namei.c:961
f2fs_rename2+0xd5/0xf20 fs/f2fs/namei.c:1308
vfs_rename+0x7ff/0x1250 fs/namei.c:6026
filename_renameat2+0x4f4/0x660 fs/namei.c:6144
__do_sys_renameat2 fs/namei.c:6173 [inline]
__se_sys_renameat2 fs/namei.c:6168 [inline]
__x64_sys_renameat2+0x59/0x80 fs/namei.c:6168
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7fThe root cause is in commit 40b2d55e0452 ("f2fs: fix to create selinux label during whiteout initialization"), we added a call to f2fs_setup_filename() without a matching call to f2fs_free_filename(), fix it.
--- fs/f2fs/namei.c | 1 + 1 file changed, 1 insertion(+)
fs/f2fs/namei.c +1 -0
@@ -964,6 +964,7 @@ static int f2fs_rename(struct mnt_idmapreturn err; err =f2fs_create_whiteout (idmap, old_dir, &whiteout, &fname); +f2fs_free_filename (&fname);if (err)return err; }
Greg Kroah-Hartman
maintainerPATCH 14/42 f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit 7b9161a605e91d0987e2596a245dc1f21621b23f upstream.
syzbot reported a f2fs bug as below:
BUG: KMSAN: uninit-value in f2fs_sanity_check_node_footer+0x374/0xa20 fs/f2fs/node.c:1520 f2fs_sanity_check_node_footer+0x374/0xa20 fs/f2fs/node.c:1520 f2fs_finish_read_bio+0xe1e/0x1d60 fs/f2fs/data.c:177 f2fs_read_end_io+0x6ab/0x2220 fs/f2fs/data.c:-1 bio_endio+0x1006/0x1160 block/bio.c:1792 submit_bio_noacct+0x533/0x2960 block/blk-core.c:891 submit_bio+0x57a/0x620 block/blk-core.c:926 blk_crypto_submit_bio include/linux/blk-crypto.h:203 [inline] f2fs_submit_read_bio+0x12c/0x360 fs/f2fs/data.c:557 f2fs_submit_page_bio+0xee2/0x1450 fs/f2fs/data.c:775 read_node_folio+0x384/0x4b0 fs/f2fs/node.c:1481 __get_node_folio+0x5db/0x15d0 fs/f2fs/node.c:1576 f2fs_get_inode_folio+0x40/0x50 fs/f2fs/node.c:1623 do_read_inode fs/f2fs/inode.c:425 [inline] f2fs_iget+0x1209/0x9380 fs/f2fs/inode.c:596 f2fs_fill_super+0x8f5a/0xb2e0 fs/f2fs/super.c:5184 get_tree_bdev_flags+0x6e6/0x920 fs/super.c:1694 get_tree_bdev+0x38/0x50 fs/super.c:1717 f2fs_get_tree+0x35/0x40 fs/f2fs/super.c:5436 vfs_get_tree+0xb3/0x5d0 fs/super.c:1754 fc_mount fs/namespace.c:1193 [inline] do_new_mount_fc fs/namespace.c:3763 [inline] do_new_mount+0x885/0x1dd0 fs/namespace.c:3839 path_mount+0x7a2/0x20b0 fs/namespace.c:4159 do_mount fs/namespace.c:4172 [inline] __do_sys_mount fs/namespace.c:4361 [inline] __se_sys_mount+0x704/0x7f0 fs/namespace.c:4338 __x64_sys_mount+0xe4/0x150 fs/namespace.c:4338 x64_sys_call+0x39f0/0x3ea0 arch/x86/include/generated/asm/syscalls_64.h:166 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x134/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
The root cause is: in f2fs_finish_read_bio(), we may access uninit data in folio if we failed to read the data from device into folio, let's add a check condition to avoid such issue.
--- fs/f2fs/data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/f2fs/data.c +2 -1
@@ -173,7 +173,8 @@ static void f2fs_finish_read_bio(structwhile (nr_pages--)dec_page_count (F2FS_F_SB (folio),__read_io_type (folio)); -if (F2FS_F_SB (folio)->node_inode &&is_node_folio (folio) && +if (bio->bi_status ==BLK_STS_OK && +F2FS_F_SB (folio)->node_inode &&is_node_folio (folio) &&f2fs_sanity_check_node_footer (F2FS_F_SB (folio), folio, folio->index,NODE_TYPE_REGULAR , true)) bio->bi_status =BLK_STS_IOERR ;
Greg Kroah-Hartman
maintainerPATCH 15/42 fuse: reject oversized dirents in page cache
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Page <[email protected]>
commit 51a8de6c50bf947c8f534cd73da4c8f0a13e7bed upstream.
fuse_add_dirent_to_cache() computes a serialized dirent size from the server-controlled namelen field and copies the dirent into a single page-cache page. The existing logic only checks whether the dirent fits in the remaining space of the current page and advances to a fresh page if not. It never checks whether the dirent itself exceeds PAGE_SIZE.
As a result, a malicious FUSE server can return a dirent with namelen=4095, producing a serialized record size of 4120 bytes. On 4 KiB page systems this causes memcpy() to overflow the cache page by 24 bytes into the following kernel page.
Reject dirents that cannot fit in a single page before copying them into the readdir cache.
--- fs/fuse/readdir.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/fuse/readdir.c +4 -0
@@ -41,6 +41,10 @@ static void fuse_add_dirent_to_cache(strunsigned int offset;void *addr; +/* Dirent doesn't fit in readdir cache page? Skip caching. */ +if (reclen >PAGE_SIZE ) +return ; +spin_lock (&fi->rdc.lock);/* * Is cache already completed? Or this entry does not go at the end of
Greg Kroah-Hartman
maintainerPATCH 16/42 fuse: abort on fatal signal during sync init
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miklos Szeredi <[email protected]>
commit 204aa22a686bfee48daca7db620c1e017615f2ff upstream.
When sync init is used and the server exits for some reason (error, crash) while processing FUSE_INIT, the filesystem creation will hang. The reason is that while all other threads will exit, the mounting thread (or process) will keep the device fd open, which will prevent an abort from happening.
This is a regression from the async mount case, where the mount was done first, and the FUSE_INIT processing afterwards, in which case there's no such recursive syscall keeping the fd open.
--- fs/fuse/dev.c | 8 +++++++- fs/fuse/fuse_i.h | 1 + fs/fuse/inode.c | 1 + 3 files changed, 9 insertions(+), 1 deletion(-)
fs/fuse/dev.c +7 -1
@@ -570,6 +570,11 @@ static void request_wait_answer(struct fif (!err)return ; +if (req->args->abort_on_kill) { +fuse_abort_conn (fc); +return ; + } +if (test_bit (FR_URING , &req->flags)) removed =fuse_uring_remove_pending_req (req);else
@@ -676,7 +681,8 @@ ssize_t __fuse_simple_request(struct mntfuse_force_creds (req);__set_bit (FR_WAITING , &req->flags); -__set_bit (FR_FORCE , &req->flags); +if (!args->abort_on_kill) +__set_bit (FR_FORCE , &req->flags); }else {WARN_ON (args->nocreds); req =fuse_get_req (idmap, fm, false);
fs/fuse/fuse_i.h +1 -0
@@ -345,6 +345,7 @@ struct fuse_args { bool is_ext:1; bool is_pinned:1; bool invalidate_vmap:1; + bool abort_on_kill:1;struct fuse_in_arg in_args[4 ];struct fuse_arg out_args[2 ];void (*end)(struct fuse_mount *fm,struct fuse_args *args,int error);
fs/fuse/inode.c +1 -0
@@ -1551,6 +1551,7 @@ int fuse_send_init(struct fuse_mount *fmint err;if (fm->fc->sync_init) { + ia->args.abort_on_kill = true; err =fuse_simple_request (fm, &ia->args);/* Ignore size of init reply */ if (err >0 )
Greg Kroah-Hartman
maintainerPATCH 17/42 fuse: Check for large folio with SPLICE_F_MOVE
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Schubert <[email protected]>
commit 59ba47b6be9cd0146ef9a55c6e32e337e11e7625 upstream.
xfstest generic/074 and generic/075 complain result in kernel warning messages / page dumps.
This is easily reproducible (on 6.19) with CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ALWAYS=y CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ALWAYS=y
This just adds a test for large folios fuse_try_move_folio with the same page copy fallback, but to avoid the warnings from fuse_check_folio().
--- fs/fuse/dev.c | 3 +++ 1 file changed, 3 insertions(+)
fs/fuse/dev.c +3 -0
@@ -1017,6 +1017,9 @@ static int fuse_try_move_folio(struct fufolio_clear_uptodate (newfolio);folio_clear_mappedtodisk (newfolio); +if (folio_test_large (newfolio)) + goto out_fallback_unlock; +if (fuse_check_folio (newfolio) !=0 ) goto out_fallback_unlock;
Greg Kroah-Hartman
maintainerPATCH 18/42 fuse: quiet down complaints in fuse_conn_limit_write
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 129a45f9755a89f573c6a513a6b9e3d234ce89b0 upstream.
gcc 15 complains about an uninitialized variable val that is passed by reference into fuse_conn_limit_write:
control.c: In function ‘fuse_conn_congestion_threshold_write’:
include/asm-generic/rwonce.h:55:37: warning: ‘val’ may be used uninitialized [-Wmaybe-uninitialized]
55 | *(volatile typeof(x) *)&(x) = (val); \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
include/asm-generic/rwonce.h:61:9: note: in expansion of macro ‘__WRITE_ONCE’
61 | __WRITE_ONCE(x, val); \
| ^~~~~~~~~~~~
control.c:178:9: note: in expansion of macro ‘WRITE_ONCE’
178 | WRITE_ONCE(fc->congestion_threshold, val);
| ^~~~~~~~~~ control.c:166:18: note: ‘val’ was declared here
166 | unsigned val;
| ^~~
Unfortunately there's enough macro spew involved in kstrtoul_from_user that I think gcc gives up on its analysis and sprays the above warning. AFAICT it's not actually a bug, but we could just zero-initialize the variable to enable using -Wmaybe-uninitialized to find real problems.
Previously we would use some weird uninitialized_var annotation to quiet down the warnings, so clearly this code has been like this for quite some time.
--- fs/fuse/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/fuse/control.c +2 -2
@@ -121,7 +121,7 @@ static ssize_t fuse_conn_max_background_const char __user *buf, size_t count, loff_t *ppos) { - unsigned val; + unsigned int val = 0;ssize_t ret; ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
@@ -163,7 +163,7 @@ static ssize_t fuse_conn_congestion_threconst char __user *buf, size_t count, loff_t *ppos) { - unsigned val; + unsigned int val = 0;struct fuse_conn *fc;ssize_t ret;
Greg Kroah-Hartman
maintainerPATCH 19/42 fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miklos Szeredi <[email protected]>
commit da6fcc6dbddbef80e603d2f0c1554a9f2ac03742 upstream.
Use fuse_get_dev() not __fuse_get_dev() on the old fd, since in the case of synchronous INIT the caller will want to wait for the device file to be available for cloning, just like I/O wants to wait instead of returning an error.
--- fs/fuse/dev.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
fs/fuse/dev.c +8 -11
@@ -2599,9 +2599,8 @@ static int fuse_device_clone(struct fusestatic long fuse_dev_ioctl_clone (struct file *file,__u32 __user *argp) { -int res;int oldfd; -struct fuse_dev *fud =NULL ; +struct fuse_dev *fud;if (get_user (oldfd, argp))return -EFAULT ;
@@ -2614,17 +2613,15 @@ static long fuse_dev_ioctl_clone(struct* Check against file->f_op because CUSE * uses the same ioctl handler. */ -if (fd_file (f)->f_op == file->f_op) - fud =__fuse_get_dev (fd_file (f)); +if (fd_file (f)->f_op != file->f_op) +return -EINVAL ; - res = -EINVAL ; -if (fud) { -mutex_lock (&fuse_mutex); - res =fuse_device_clone (fud->fc, file); -mutex_unlock (&fuse_mutex); - } + fud =fuse_get_dev (fd_file (f)); +if (IS_ERR (fud)) +return PTR_ERR (fud); -return res; +guard (mutex)(&fuse_mutex); +return fuse_device_clone (fud->fc, file); } static long fuse_dev_ioctl_backing_open(struct file *file,
Greg Kroah-Hartman
maintainerPATCH 20/42 ksmbd: require minimum ACE size in smb_check_perm_dacl()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit d07b26f39246a82399661936dd0c853983cfade7 upstream.
Both ACE-walk loops in smb_check_perm_dacl() only guard against an under-sized remaining buffer, not against an ACE whose declared ace->size is smaller than the struct it claims to describe:
if (offsetof(struct smb_ace, access_req) > aces_size)
break;
ace_size = le16_to_cpu(ace->size);
if (ace_size > aces_size)
break;The first check only requires the 4-byte ACE header to be in bounds; it does not require access_req (4 bytes at offset 4) to be readable. An attacker who has set a crafted DACL on a file they own can declare ace->size == 4 with aces_size == 4, pass both checks, and then
granted |= le32_to_cpu(ace->access_req); /* upper loop */
compare_sids(&sid, &ace->sid); /* lower loop */
reads access_req at offset 4 (OOB by up to 4 bytes) and ace->sid at offset 8 (OOB by up to CIFS_SID_BASE_SIZE + SID_MAX_SUB_AUTHORITIES
* 4 bytes).
Tighten both loops to require
ace_size >= offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE
which is the smallest valid on-wire ACE layout (4-byte header + 4-byte access_req + 8-byte sid base with zero sub-auths). Also reject ACEs whose sid.num_subauth exceeds SID_MAX_SUB_AUTHORITIES before letting compare_sids() dereference sub_auth[] entries.
parse_sec_desc() already enforces an equivalent check (lines 441-448); smb_check_perm_dacl() simply grew weaker validation over time.
Reachability: authenticated SMB client with permission to set an ACL on a file. On a subsequent CREATE against that file, the kernel walks the stored DACL via smb_check_perm_dacl() and triggers the OOB read. Not pre-auth, and the OOB read is not reflected to the attacker, but KASAN reports and kernel state corruption are possible.
--- fs/smb/server/smbacl.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
fs/smb/server/smbacl.c +13 -4
@@ -1342,10 +1342,13 @@ int smb_check_perm_dacl(struct ksmbd_con ace = (struct smb_ace *)((char *)pdacl +sizeof (struct smb_acl )); aces_size = acl_size -sizeof (struct smb_acl );for (i =0 ; i <le16_to_cpu (pdacl->num_aces); i++) { -if (offsetof(struct smb_ace , access_req) > aces_size) +if (offsetof(struct smb_ace , sid) + + aces_size <CIFS_SID_BASE_SIZE )break ; ace_size =le16_to_cpu (ace->size); -if (ace_size > aces_size) +if (ace_size > aces_size || + ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; aces_size -= ace_size; granted |=le32_to_cpu (ace->access_req);
@@ -1360,13 +1363,19 @@ int smb_check_perm_dacl(struct ksmbd_con ace = (struct smb_ace *)((char *)pdacl +sizeof (struct smb_acl )); aces_size = acl_size -sizeof (struct smb_acl );for (i =0 ; i <le16_to_cpu (pdacl->num_aces); i++) { -if (offsetof(struct smb_ace , access_req) > aces_size) +if (offsetof(struct smb_ace , sid) + + aces_size <CIFS_SID_BASE_SIZE )break ; ace_size =le16_to_cpu (ace->size); -if (ace_size > aces_size) +if (ace_size > aces_size || + ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; aces_size -= ace_size; +if (ace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) +break ; +if (!compare_sids (&sid, &ace->sid) || !compare_sids (&sid_unix_NFS_mode, &ace->sid)) { found =1 ;
Greg Kroah-Hartman
maintainerPATCH 21/42 smb: server: fix active_num_conn leak on transport allocation failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 6551300dc452ac16a855a83dbd1e74899542d3b3 upstream.
Commit 77ffbcac4e56 ("smb: server: fix leak of active_num_conn in ksmbd_tcp_new_connection()") addressed the kthread_run() failure path. The earlier alloc_transport() == NULL path in the same function has the same leak, is reachable pre-authentication via any TCP connect to port 445, and was empirically reproduced on UML (ARCH=um, v7.0-rc7): a small number of forced allocation failures were sufficient to put ksmbd into a state where every subsequent connection attempt was rejected for the remainder of the boot.
ksmbd_kthread_fn() increments active_num_conn before calling ksmbd_tcp_new_connection() and discards the return value, so when alloc_transport() returns NULL the socket is released and -ENOMEM returned without decrementing the counter. Each such failure permanently consumes one slot from the max_connections pool; once cumulative failures reach the cap, atomic_inc_return() hits the threshold on every subsequent accept and every new connection is rejected. The counter is only reset by module reload.
An unauthenticated remote attacker can drive the server toward the memory pressure that makes alloc_transport() fail by holding open connections with large RFC1002 lengths up to MAX_STREAM_PROT_LEN (0x00FFFFFF); natural transient allocation failures on a loaded host produce the same drift more slowly.
Mirror the existing rollback pattern in ksmbd_kthread_fn(): on the alloc_transport() failure path, decrement active_num_conn gated on server_conf.max_connections.
Repro details: with the patch reverted, forced alloc_transport() NULL returns leaked counter slots and subsequent connection attempts -- including legitimate connects issued after the forced-fail window had closed -- were all rejected with "Limit the maximum number of connections". With this patch applied, the same connect sequence produces no rejections and the counter cycles cleanly between zero and one on every accept.
--- fs/smb/server/transport_tcp.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/transport_tcp.c +2 -0
@@ -183,6 +183,8 @@ static int ksmbd_tcp_new_connection(stru t =alloc_transport (client_sk);if (!t) {sock_release (client_sk); +if (server_conf.max_connections) +atomic_dec (&active_num_conn);return -ENOMEM ; }
Greg Kroah-Hartman
maintainerPATCH 22/42 smb: client: fix dir separator in SMB1 UNIX mounts
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
commit c4d3fc5844d685441befd0caaab648321013cdfd upstream.
When calling cifs_mount_get_tcon() with SMB1 UNIX mounts, @cifs_sb->mnt_cifs_flags needs to be read or updated only after calling reset_cifs_unix_caps(), otherwise it might end up with missing CIFS_MOUNT_POSIXACL and CIFS_MOUNT_POSIX_PATHS bits.
This fixes the wrong dir separator used in paths caused by the missing CIFS_MOUNT_POSIX_PATHS bit in cifs_sb_info::mnt_cifs_flags.
--- fs/smb/client/connect.c | 10 +++++----- fs/smb/client/smb1ops.c | 19 ++++++++----------- 2 files changed, 13 insertions(+), 16 deletions(-)
fs/smb/client/connect.c +5 -5
@@ -3610,7 +3610,6 @@ int cifs_mount_get_tcon(struct cifs_moun server = mnt_ctx->server; ctx = mnt_ctx->fs_ctx; cifs_sb = mnt_ctx->cifs_sb; - sbflags =cifs_sb_flags (cifs_sb);/* search for existing tcon to this server share */ tcon =cifs_get_tcon (mnt_ctx->ses, ctx);
@@ -3625,9 +3624,10 @@ int cifs_mount_get_tcon(struct cifs_moun* path (i.e., do not remap / and \ and do not map any special characters) */ if (tcon->posix_extensions) { - sbflags |=CIFS_MOUNT_POSIX_PATHS ; - sbflags &= ~(CIFS_MOUNT_MAP_SFM_CHR | -CIFS_MOUNT_MAP_SPECIAL_CHR ); +atomic_or (CIFS_MOUNT_POSIX_PATHS , &cifs_sb->mnt_cifs_flags); +atomic_andnot (CIFS_MOUNT_MAP_SFM_CHR | +CIFS_MOUNT_MAP_SPECIAL_CHR , + &cifs_sb->mnt_cifs_flags); }#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -3651,6 +3651,7 @@ int cifs_mount_get_tcon(struct cifs_moun#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ tcon->unix_ext =0 ;/* server does not support them */ + sbflags =cifs_sb_flags (cifs_sb);/* do not care if a following call succeed - informational */ if (!tcon->pipe && server->ops->qfs_tcon) { server->ops->qfs_tcon (mnt_ctx->xid, tcon, cifs_sb);
@@ -3675,7 +3676,6 @@ int cifs_mount_get_tcon(struct cifs_moun out: mnt_ctx->tcon = tcon; -atomic_set (&cifs_sb->mnt_cifs_flags, sbflags);return rc; }
fs/smb/client/smb1ops.c +8 -11
@@ -49,7 +49,6 @@ void reset_cifs_unix_caps(unsigned int xif (!CIFSSMBQFSUnixInfo (xid, tcon)) {__u64 cap =le64_to_cpu (tcon->fsUnixInfo.Capability); -unsigned int sbflags;cifs_dbg (FYI ,"unix caps which server supports %lld\n" , cap);/*
@@ -76,29 +75,27 @@ void reset_cifs_unix_caps(unsigned int xif (cap &CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP )cifs_dbg (VFS ,"per-share encryption not supported yet\n" ); -if (cifs_sb) - sbflags =cifs_sb_flags (cifs_sb); - cap &=CIFS_UNIX_CAP_MASK ;if (ctx && ctx->no_psx_acl) cap &= ~CIFS_UNIX_POSIX_ACL_CAP ;else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {cifs_dbg (FYI ,"negotiated posix acl support\n" ); -if (cifs_sb) - sbflags |=CIFS_MOUNT_POSIXACL ; +if (cifs_sb) { +atomic_or (CIFS_MOUNT_POSIXACL , + &cifs_sb->mnt_cifs_flags); + } }if (ctx && ctx->posix_paths ==0 ) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP ;else if (cap &CIFS_UNIX_POSIX_PATHNAMES_CAP ) {cifs_dbg (FYI ,"negotiate posix pathnames\n" ); -if (cifs_sb) - sbflags |=CIFS_MOUNT_POSIX_PATHS ; +if (cifs_sb) { +atomic_or (CIFS_MOUNT_POSIX_PATHS , + &cifs_sb->mnt_cifs_flags); + } } -if (cifs_sb) -atomic_set (&cifs_sb->mnt_cifs_flags, sbflags); -cifs_dbg (FYI ,"Negotiate caps 0x%x\n" , (int )cap);#ifdef CONFIG_CIFS_DEBUG2 if (cap &CIFS_UNIX_FCNTL_CAP )
Greg Kroah-Hartman
maintainerPATCH 23/42 smb: server: fix max_connections off-by-one in tcp accept path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
commit ce23158bfe584bd90d1918f279fdf9de57802012 upstream.
The global max_connections check in ksmbd's TCP accept path counts the newly accepted connection with atomic_inc_return(), but then rejects the connection when the result is greater than or equal to server_conf.max_connections.
That makes the effective limit one smaller than configured. For example:
- max_connections=1 rejects the first connection
- max_connections=2 allows only one connection
The per-IP limit in the same function uses <= correctly because it counts only pre-existing connections. The global limit instead checks the post-increment total, so it should reject only when that total exceeds the configured maximum.
Fix this by changing the comparison from >= to >, so exactly max_connections simultaneous connections are allowed and the next one is rejected. This matches the documented meaning of max_connections in fs/smb/server/ksmbd_netlink.h as the "Number of maximum simultaneous connections".
--- fs/smb/server/transport_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/smb/server/transport_tcp.c +1 -1
@@ -281,7 +281,7 @@ static int ksmbd_kthread_fn(void *p) skip_max_ip_conns_limit:if (server_conf.max_connections && -atomic_inc_return (&active_num_conn) >= server_conf.max_connections) { +atomic_inc_return (&active_num_conn) > server_conf.max_connections) {pr_info_ratelimited ("Limit the maximum number of connections(%u)\n" ,atomic_read (&active_num_conn));atomic_dec (&active_num_conn);
Greg Kroah-Hartman
maintainerPATCH 24/42 smb: client: require a full NFS mode SID before reading mode bits
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 2757ad3e4b6f9e0fed4c7739594e702abc5cab21 upstream.
parse_dacl() treats an ACE SID matching sid_unix_NFS_mode as an NFS mode SID and reads sid.sub_auth[2] to recover the mode bits.
That assumes the ACE carries three subauthorities, but compare_sids() only compares min(a, b) subauthorities. A malicious server can return an ACE with num_subauth = 2 and sub_auth[] = {88, 3}, which still matches sid_unix_NFS_mode and then drives the sub_auth[2] read four bytes past the end of the ACE.
Require num_subauth >= 3 before treating the ACE as an NFS mode SID. This keeps the fix local to the special-SID mode path without changing compare_sids() semantics for the rest of cifsacl.
--- fs/smb/client/cifsacl.c | 1 + 1 file changed, 1 insertion(+)
fs/smb/client/cifsacl.c +1 -0
@@ -831,6 +831,7 @@ static void parse_dacl(struct smb_acl *pdump_ace (ppace[i], end_of_acl);#endif if (mode_from_special_sid && + ppace[i]->sid.num_subauth >=3 && (compare_sids (&(ppace[i]->sid), &sid_unix_NFS_mode) ==0 )) {/*
Greg Kroah-Hartman
maintainerPATCH 25/42 smb: client: validate the whole DACL before rewriting it in cifsacl
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 0a8cf165566ba55a39fd0f4de172119dd646d39a upstream.
build_sec_desc() and id_mode_to_cifs_acl() derive a DACL pointer from a server-supplied dacloffset and then use the incoming ACL to rebuild the chmod/chown security descriptor.
The original fix only checked that the struct smb_acl header fits before reading dacl_ptr->size or dacl_ptr->num_aces. That avoids the immediate header-field OOB read, but the rewrite helpers still walk ACEs based on pdacl->num_aces with no structural validation of the incoming DACL body.
A malicious server can return a truncated DACL that still contains a header, claims one or more ACEs, and then drive replace_sids_and_copy_aces() or set_chmod_dacl() past the validated extent while they compare or copy attacker-controlled ACEs.
Factor the DACL structural checks into validate_dacl(), extend them to validate each ACE against the DACL bounds, and use the shared validator before the chmod/chown rebuild paths. parse_dacl() reuses the same validator so the read-side parser and write-side rewrite paths agree on what constitutes a well-formed incoming DACL.
--- fs/smb/client/cifsacl.c | 116 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 31 deletions(-)
fs/smb/client/cifsacl.c +85 -31
@@ -758,6 +758,77 @@ static void dump_ace(struct smb_ace *pac }#endif +static int validate_dacl (struct smb_acl *pdacl,char *end_of_acl) +{ +int i, ace_hdr_size, ace_size, min_ace_size; +u16 dacl_size, num_aces; +char *acl_base, *end_of_dacl; +struct smb_ace *pace; + +if (!pdacl) +return 0 ; + +if (end_of_acl < (char *)pdacl +sizeof (struct smb_acl )) { +cifs_dbg (VFS ,"ACL too small to parse DACL\n" ); +return -EINVAL ; + } + + dacl_size =le16_to_cpu (pdacl->size); +if (dacl_size <sizeof (struct smb_acl ) || + end_of_acl < (char *)pdacl + dacl_size) { +cifs_dbg (VFS ,"ACL too small to parse DACL\n" ); +return -EINVAL ; + } + + num_aces =le16_to_cpu (pdacl->num_aces); +if (!num_aces) +return 0 ; + + ace_hdr_size = offsetof(struct smb_ace , sid) + + offsetof(struct smb_sid , sub_auth); + min_ace_size = ace_hdr_size +sizeof (__le32); +if (num_aces > (dacl_size -sizeof (struct smb_acl )) / min_ace_size) { +cifs_dbg (VFS ,"ACL too small to parse DACL\n" ); +return -EINVAL ; + } + + end_of_dacl = (char *)pdacl + dacl_size; + acl_base = (char *)pdacl; + ace_size =sizeof (struct smb_acl ); + +for (i =0 ; i < num_aces; ++i) { +if (end_of_dacl - acl_base < ace_size) { +cifs_dbg (VFS ,"ACL too small to parse ACE\n" ); +return -EINVAL ; + } + + pace = (struct smb_ace *)(acl_base + ace_size); + acl_base = (char *)pace; + +if (end_of_dacl - acl_base < ace_hdr_size || + pace->sid.num_subauth ==0 || + pace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) { +cifs_dbg (VFS ,"ACL too small to parse ACE\n" ); +return -EINVAL ; + } + + ace_size = ace_hdr_size +sizeof (__le32) * pace->sid.num_subauth; +if (end_of_dacl - acl_base < ace_size || +le16_to_cpu (pace->size) < ace_size) { +cifs_dbg (VFS ,"ACL too small to parse ACE\n" ); +return -EINVAL ; + } + + ace_size =le16_to_cpu (pace->size); +if (end_of_dacl - acl_base < ace_size) { +cifs_dbg (VFS ,"ACL too small to parse ACE\n" ); +return -EINVAL ; + } + } + +return 0 ; +} +static void parse_dacl (struct smb_acl *pdacl,char *end_of_acl,struct smb_sid *pownersid,struct smb_sid *pgrpsid,struct cifs_fattr *fattr,bool mode_from_special_sid)
@@ -765,7 +836,7 @@ static void parse_dacl(struct smb_acl *pint i;u16 num_aces =0 ;int acl_size; -char *acl_base; +char *acl_base, *end_of_dacl;struct smb_ace **ppace;/* BB need to add parm so we can store the SID BB */
@@ -777,12 +848,8 @@ static void parse_dacl(struct smb_acl *preturn ; } -/* validate that we do not go past end of acl */ -if (end_of_acl < (char *)pdacl +sizeof (struct smb_acl ) || - end_of_acl < (char *)pdacl +le16_to_cpu (pdacl->size)) { -cifs_dbg (VFS ,"ACL too small to parse DACL\n" ); +if (validate_dacl (pdacl, end_of_acl))return ; - } cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
@@ -793,6 +860,7 @@ static void parse_dacl(struct smb_acl *puser/group/other have no permissions */ fattr->cf_mode &= ~(0777 ); + end_of_dacl = (char *)pdacl +le16_to_cpu (pdacl->size); acl_base = (char *)pdacl; acl_size =sizeof (struct smb_acl );
@@ -800,35 +868,15 @@ static void parse_dacl(struct smb_acl *pif (num_aces >0 ) {umode_t denied_mode =0 ; -if (num_aces > (le16_to_cpu (pdacl->size) -sizeof (struct smb_acl )) / - (offsetof(struct smb_ace , sid) + - offsetof(struct smb_sid , sub_auth) +sizeof (__le16))) -return ; - ppace = kmalloc_objs(struct smb_ace *, num_aces);if (!ppace)return ;for (i =0 ; i < num_aces; ++i) { -if (end_of_acl - acl_base < acl_size) -break ; - ppace[i] = (struct smb_ace *) (acl_base + acl_size); - acl_base = (char *)ppace[i]; - acl_size = offsetof(struct smb_ace , sid) + - offsetof(struct smb_sid , sub_auth); - -if (end_of_acl - acl_base < acl_size || - ppace[i]->sid.num_subauth ==0 || - ppace[i]->sid.num_subauth >SID_MAX_SUB_AUTHORITIES || - (end_of_acl - acl_base < - acl_size +sizeof (__le32) * ppace[i]->sid.num_subauth) || - (le16_to_cpu (ppace[i]->size) < - acl_size +sizeof (__le32) * ppace[i]->sid.num_subauth)) -break ;#ifdef CONFIG_CIFS_DEBUG2 -dump_ace (ppace[i], end_of_acl); +dump_ace (ppace[i], end_of_dacl);#endif if (mode_from_special_sid && ppace[i]->sid.num_subauth >= 3 &&
@@ -871,6 +919,7 @@ static void parse_dacl(struct smb_acl *p(void *)ppace[i], sizeof(struct smb_ace)); */ + acl_base = (char *)ppace[i]; acl_size =le16_to_cpu (ppace[i]->size); }
@@ -1294,10 +1343,9 @@ static int build_sec_desc(struct smb_nts dacloffset =le32_to_cpu (pntsd->dacloffset);if (dacloffset) { dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); -if (end_of_acl < (char *)dacl_ptr +le16_to_cpu (dacl_ptr->size)) { -cifs_dbg (VFS ,"Server returned illegal ACL size\n" ); -return -EINVAL ; - } + rc =validate_dacl (dacl_ptr, end_of_acl); +if (rc) +return rc; } owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1663,6 +1711,12 @@ id_mode_to_cifs_acl(struct inode *inode, dacloffset =le32_to_cpu (pntsd->dacloffset);if (dacloffset) { dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); + rc =validate_dacl (dacl_ptr, (char *)pntsd + secdesclen); +if (rc) { +kfree (pntsd); +cifs_put_tlink (tlink); +return rc; + }if (mode_from_sid) nsecdesclen +=le16_to_cpu (dacl_ptr->num_aces) *sizeof (struct smb_ace );
Greg Kroah-Hartman
maintainerPATCH 26/42 smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit a58c5af19ff0d6f44f6e9fe31e33a2c92223f77e upstream.
smb2_ioctl_query_info() has two response-copy branches: PASSTHRU_FSCTL and the default QUERY_INFO path. The QUERY_INFO branch clamps qi.input_buffer_length to the server-reported OutputBufferLength and then copies qi.input_buffer_length bytes from qi_rsp->Buffer to userspace, but it never verifies that the flexible-array payload actually fits within rsp_iov[1].iov_len.
A malicious server can return OutputBufferLength larger than the actual QUERY_INFO response, causing copy_to_user() to walk past the response buffer and expose adjacent kernel heap to userspace.
Guard the QUERY_INFO copy with a bounds check on the actual Buffer payload. Use struct_size(qi_rsp, Buffer, qi.input_buffer_length) rather than an open-coded addition so the guard cannot overflow on 32-bit builds.
--- fs/smb/client/smb2ops.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/smb/client/smb2ops.c +6 -0
@@ -1783,6 +1783,12 @@ replay_again: qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1 ].iov_base;if (le32_to_cpu (qi_rsp->OutputBufferLength) < qi.input_buffer_length) qi.input_buffer_length =le32_to_cpu (qi_rsp->OutputBufferLength); +if (qi.input_buffer_length >0 && +struct_size (qi_rsp, Buffer, qi.input_buffer_length) > + rsp_iov[1 ].iov_len) { + rc = -EFAULT ; + goto out; + }if (copy_to_user (&pqi->input_buffer_length, &qi.input_buffer_length,sizeof (qi.input_buffer_length))) {
Greg Kroah-Hartman
maintainerPATCH 27/42 ksmbd: validate response sizes in ipc_validate_msg()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit d6a6aa81eac2c9bff66dc6e191179cb69a14426b upstream.
ipc_validate_msg() computes the expected message size for each response type by adding (or multiplying) attacker-controlled fields from the daemon response to a fixed struct size in unsigned int arithmetic. Three cases can overflow:
KSMBD_EVENT_RPC_REQUEST:
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
KSMBD_EVENT_SHARE_CONFIG_REQUEST:
msg_sz = sizeof(struct ksmbd_share_config_response) +
resp->payload_sz;
KSMBD_EVENT_LOGIN_REQUEST_EXT:
msg_sz = sizeof(struct ksmbd_login_response_ext) +
resp->ngroups * sizeof(gid_t);resp->payload_sz is __u32 and resp->ngroups is __s32. Each addition can wrap in unsigned int; the multiplication by sizeof(gid_t) mixes signed and size_t, so a negative ngroups is converted to SIZE_MAX before the multiply. A wrapped value of msg_sz that happens to equal entry->msg_sz bypasses the size check on the next line, and downstream consumers (smb2pdu.c:6742 memcpy using rpc_resp->payload_sz, kmemdup in ksmbd_alloc_user using resp_ext->ngroups) then trust the unverified length.
Use check_add_overflow() on the RPC_REQUEST and SHARE_CONFIG_REQUEST paths to detect integer overflow without constraining functional payload size; userspace ksmbd-tools grows NDR responses in 4096-byte chunks for calls like NetShareEnumAll, so a hard transport cap is unworkable on the response side. For LOGIN_REQUEST_EXT, reject resp->ngroups outside the signed [0, NGROUPS_MAX] range up front and report the error from ipc_validate_msg() so it fires at the IPC boundary; with that bound the subsequent multiplication and addition stay well below UINT_MAX. The now-redundant ngroups check and pr_err in ksmbd_alloc_user() are removed.
This is the response-side analogue of aab98e2dbd64 ("ksmbd: fix integer overflows on 32 bit systems"), which hardened the request side.
--- fs/smb/server/mgmt/user_config.c | 6 ------ fs/smb/server/transport_ipc.c | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-)
fs/smb/server/mgmt/user_config.c +0 -6
@@ -56,12 +56,6 @@ struct ksmbd_user *ksmbd_alloc_user(stru goto err_free;if (resp_ext) { -if (resp_ext->ngroups >NGROUPS_MAX ) { -pr_err ("ngroups(%u) from login response exceeds max groups(%d)\n" , - resp_ext->ngroups,NGROUPS_MAX ); - goto err_free; - } - user->sgid =kmemdup (resp_ext->____payload, resp_ext->ngroups *sizeof (gid_t),KSMBD_DEFAULT_GFP );
fs/smb/server/transport_ipc.c +13 -3
@@ -13,6 +13,7 @@#include <net/genetlink.h> #include <linux/socket.h> #include <linux/workqueue.h> +#include <linux/overflow.h> #include "vfs_cache.h" #include "transport_ipc.h"
@@ -497,7 +498,9 @@ static int ipc_validate_msg(struct ipc_m {struct ksmbd_rpc_command *resp = entry->response; - msg_sz =sizeof (struct ksmbd_rpc_command ) + resp->payload_sz; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), + resp->payload_sz, &msg_sz)) +return -EINVAL ;break ; }case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST :
@@ -516,8 +519,9 @@ static int ipc_validate_msg(struct ipc_mif (resp->payload_sz < resp->veto_list_sz)return -EINVAL ; - msg_sz =sizeof (struct ksmbd_share_config_response ) + - resp->payload_sz; +if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), + resp->payload_sz, &msg_sz)) +return -EINVAL ; }break ; }
@@ -526,6 +530,12 @@ static int ipc_validate_msg(struct ipc_mstruct ksmbd_login_response_ext *resp = entry->response;if (resp->ngroups) { +if (resp->ngroups <0 || + resp->ngroups >NGROUPS_MAX ) { +pr_err ("ngroups(%d) from login response exceeds max groups(%d)\n" , + resp->ngroups,NGROUPS_MAX ); +return -EINVAL ; + } msg_sz =sizeof (struct ksmbd_login_response_ext ) + resp->ngroups *sizeof (gid_t); }
Greg Kroah-Hartman
maintainerPATCH 28/42 ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 3e4e2ea2a781018ed5d75f969e3e5606beb66e48 upstream.
smb_inherit_dacl() trusts the on-disk num_aces value from the parent directory's DACL xattr and uses it to size a heap allocation:
aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, ...);
num_aces is a u16 read from le16_to_cpu(parent_pdacl->num_aces) without checking that it is consistent with the declared pdacl_size. An authenticated client whose parent directory's security.NTACL is tampered (e.g. via offline xattr corruption or a concurrent path that bypasses parse_dacl()) can present num_aces = 65535 with minimal actual ACE data. This causes a ~8 MB allocation (not kzalloc, so uninitialized) that the subsequent loop only partially populates, and may also overflow the three-way size_t multiply on 32-bit kernels.
Additionally, the ACE walk loop uses the weaker offsetof(struct smb_ace, access_req) minimum size check rather than the minimum valid on-wire ACE size, and does not reject ACEs whose declared size is below the minimum.
Reproduced on UML + KASAN + LOCKDEP against the real ksmbd code path. A legitimate mount.cifs client creates a parent directory over SMB (ksmbd writes a valid security.NTACL xattr), then the NTACL blob on the backing filesystem is rewritten to set num_aces = 0xFFFF while keeping the posix_acl_hash bytes intact so ksmbd_vfs_get_sd_xattr()'s hash check still passes. A subsequent SMB2 CREATE of a child under that parent drives smb2_open() into smb_inherit_dacl() (share has "vfs objects = acl_xattr" set), which fails the page allocator:
WARNING: mm/page_alloc.c:5226 at __alloc_frozen_pages_noprof+0x46c/0x9c0 Workqueue: ksmbd-io handle_ksmbd_work __alloc_frozen_pages_noprof+0x46c/0x9c0 ___kmalloc_large_node+0x68/0x130 __kmalloc_large_node_noprof+0x24/0x70 __kmalloc_noprof+0x4c9/0x690 smb_inherit_dacl+0x394/0x2430 smb2_open+0x595d/0xabe0 handle_ksmbd_work+0x3d3/0x1140
With the patch applied the added guard rejects the tampered value with -EINVAL before any large allocation runs, smb2_open() falls back to smb2_create_sd_buffer(), and the child is created with a default SD. No warning, no splat.
Fix by:
1. Validating num_aces against pdacl_size using the same formula applied in parse_dacl().
2. Replacing the raw kmalloc(sizeof * num_aces * 2) with kmalloc_array(num_aces * 2, sizeof(...)) for overflow-safe allocation.
3. Tightening the per-ACE loop guard to require the minimum valid ACE size (offsetof(smb_ace, sid) + CIFS_SID_BASE_SIZE) and rejecting under-sized ACEs, matching the hardening in smb_check_perm_dacl() and parse_dacl().
v1 -> v2:
- Replace the synthetic test-module splat in the changelog with a real-path UML + KASAN reproduction driven through mount.cifs and SMB2 CREATE; Namjae flagged the kcifs3_test_inherit_dacl_old name in v1 since it does not exist in ksmbd.
- Drop the commit-hash citation from the code comment per Namjae's review; keep the parse_dacl() pointer.
--- fs/smb/server/smbacl.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
fs/smb/server/smbacl.c +23 -5
@@ -1106,8 +1106,24 @@ int smb_inherit_dacl(struct ksmbd_conn * goto free_parent_pntsd; } - aces_base =kmalloc (sizeof (struct smb_ace ) * num_aces *2 , -KSMBD_DEFAULT_GFP ); + aces_size = pdacl_size -sizeof (struct smb_acl ); + +/* +* Validate num_aces against the DACL payload before allocating. +* Each ACE must be at least as large as its fixed-size header +* (up to the SID base), so num_aces cannot exceed the payload +* divided by the minimum ACE size. This mirrors the existing +* check in parse_dacl(). +*/ +if (num_aces > aces_size / (offsetof(struct smb_ace , sid) + + offsetof(struct smb_sid , sub_auth) + +sizeof (__le16))) { + rc = -EINVAL ; + goto free_parent_pntsd; + } + + aces_base =kmalloc_array (num_aces *2 ,sizeof (struct smb_ace ), +KSMBD_DEFAULT_GFP );if (!aces_base) { rc = -ENOMEM ; goto free_parent_pntsd;
@@ -1116,7 +1132,6 @@ int smb_inherit_dacl(struct ksmbd_conn * aces = (struct smb_ace *)aces_base; parent_aces = (struct smb_ace *)((char *)parent_pdacl +sizeof (struct smb_acl )); - aces_size = acl_len -sizeof (struct smb_acl );if (pntsd_type &DACL_AUTO_INHERITED ) inherited_flags =INHERITED_ACE ;
@@ -1124,11 +1139,14 @@ int smb_inherit_dacl(struct ksmbd_conn *for (i =0 ; i < num_aces; i++) {int pace_size; -if (offsetof(struct smb_ace , access_req) > aces_size) +if (aces_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; pace_size =le16_to_cpu (parent_aces->size); -if (pace_size > aces_size) +if (pace_size > aces_size || + pace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; aces_size -= pace_size;
Greg Kroah-Hartman
maintainerPATCH 29/42 ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 30010c952077a1c89ecdd71fc4d574c75a8f5617 upstream.
smb2_get_ea() applies 4-byte alignment padding via memset() after writing each EA entry. The bounds check on buf_free_len is performed before the value memcpy, but the alignment memset fires unconditionally afterward with no check on remaining space.
When the EA value exactly fills the remaining buffer (buf_free_len == 0 after value subtraction), the alignment memset writes 1-3 NUL bytes past the buf_free_len boundary. In compound requests where the response buffer is shared across commands, the first command (e.g., READ) can consume most of the buffer, leaving a tight remainder for the QUERY_INFO EA response. The alignment memset then overwrites past the physical kvmalloc allocation into adjacent kernel heap memory.
Add a bounds check before the alignment memset to ensure buf_free_len can accommodate the padding bytes.
This is the same bug pattern fixed by commit beef2634f81f ("ksmbd: fix potencial OOB in get_file_all_info() for compound requests") and commit fda9522ed6af ("ksmbd: fix OOB write in QUERY_INFO for compound requests"), both of which added bounds checks before unconditional writes in QUERY_INFO response handlers.
--- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/smb2pdu.c +2 -0
@@ -4822,6 +4822,8 @@ static int smb2_get_ea(struct ksmbd_work/* align next xattr entry at 4 byte bundary */ alignment_bytes = ((next_offset +3 ) & ~3 ) - next_offset;if (alignment_bytes) { +if (buf_free_len < alignment_bytes) +break ;memset (ptr,'\0' , alignment_bytes); ptr += alignment_bytes; next_offset += alignment_bytes;
Greg Kroah-Hartman
maintainerPATCH 30/42 ksmbd: use check_add_overflow() to prevent u16 DACL size overflow
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 299f962c0b02d048fb45d248b4da493d03f3175d upstream.
set_posix_acl_entries_dacl() and set_ntacl_dacl() accumulate ACE sizes in u16 variables. When a file has many POSIX ACL entries, the accumulated size can wrap past 65535, causing the pointer arithmetic (char *)pndace + *size to land within already-written ACEs. Subsequent writes then overwrite earlier entries, and pndacl->size gets a truncated value.
Use check_add_overflow() at each accumulation point to detect the wrap before it corrupts the buffer, consistent with existing check_mul_overflow() usage elsewhere in smbacl.c.
--- fs/smb/server/smbacl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/smb/server/smbacl.c +12 -4
@@ -596,6 +596,7 @@ static void set_posix_acl_entries_dacl(sstruct smb_sid *sid;struct smb_ace *ntace;int i, j; +u16 ace_sz;if (!fattr->cf_acls) goto posix_default_acl;
@@ -640,8 +641,10 @@ static void set_posix_acl_entries_dacl(s flags =0x03 ; ntace = (struct smb_ace *)((char *)pndace + *size); - *size +=fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED , flags, + ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED , flags, pace->e_perm,0777 ); +if (check_add_overflow (*size, ace_sz, size)) +break ; (*num_aces)++;if (pace->e_tag ==ACL_USER ) ntace->access_req |=
@@ -650,8 +653,10 @@ static void set_posix_acl_entries_dacl(sif (S_ISDIR (fattr->cf_mode) && (pace->e_tag ==ACL_USER || pace->e_tag ==ACL_GROUP )) { ntace = (struct smb_ace *)((char *)pndace + *size); - *size +=fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED , + ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x03 , pace->e_perm,0777 ); +if (check_add_overflow (*size, ace_sz, size)) +break ; (*num_aces)++;if (pace->e_tag ==ACL_USER ) ntace->access_req |=
@@ -691,8 +696,10 @@ posix_default_acl: } ntace = (struct smb_ace *)((char *)pndace + *size); - *size +=fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x0b , + ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x0b , pace->e_perm,0777 ); +if (check_add_overflow (*size, ace_sz, size)) +break ; (*num_aces)++;if (pace->e_tag ==ACL_USER ) ntace->access_req |=
@@ -728,7 +735,8 @@ static void set_ntacl_dacl(struct mnt_idbreak ;memcpy ((char *)pndace + size, ntace, nt_ace_size); - size += nt_ace_size; +if (check_add_overflow (size, nt_ace_size, &size)) +break ; aces_size -= nt_ace_size; ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); num_aces++;
Greg Kroah-Hartman
maintainerPATCH 31/42 ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
commit def036ef87f8641c1c525d5ae17438d7a1006491 upstream.
rcount is intended to be connection-specific: 2 for curr_conn, 1 for every other connection sharing the same session. However, it is initialised only once before the hash iteration and is never reset. After the loop visits curr_conn, later sibling connections are also checked against rcount == 2, so a sibling with req_running == 1 is incorrectly treated as idle. This makes the outcome depend on the hash iteration order: whether a given sibling is checked against the loose (< 2) or the strict (< 1) threshold is decided by whether it happens to be visited before or after curr_conn.
The function's contract is "wait until every connection sharing this session is idle" so that destroy_previous_session() can safely tear the session down. The latched rcount violates that contract and reopens the teardown race window the wait logic was meant to close:destroy_previous_session() may proceed before sibling channels have actually quiesced, overlapping session teardown with in-flight work on those connections.
Recompute rcount inside the loop so each connection is compared against its own threshold regardless of iteration order.
This is a code-inspection fix for an iteration-order-dependent logic error; a targeted reproducer would require SMB3 multichannel with in-flight work on a sibling channel landing after curr_conn in hash order, which is not something that can be triggered reliably.
--- fs/smb/server/connection.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/smb/server/connection.c +2 -3
@@ -237,7 +237,7 @@ int ksmbd_conn_wait_idle_sess_id(struct {struct ksmbd_conn *conn;int rc, retry_count =0 , max_timeout =120 ; -int rcount =1 , bkt; +int rcount, bkt; retry_idle:if (retry_count >= max_timeout)
@@ -246,8 +246,7 @@ retry_idle:down_read (&conn_list_lock);hash_for_each (conn_list, bkt, conn, hlist) {if (conn->binding ||xa_load (&conn->sessions, sess_id)) { -if (conn == curr_conn) - rcount =2 ; + rcount = (conn == curr_conn) ?2 :1 ;if (atomic_read (&conn->req_running) >= rcount) { rc = wait_event_timeout(conn->req_running_q, atomic_read(&conn->req_running) < rcount,
Greg Kroah-Hartman
maintainerPATCH 32/42 writeback: Fix use after free in inode_switch_wbs_work_fn()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit 6689f01d6740cf358932b3e97ee968c6099800d9 upstream.
inode_switch_wbs_work_fn() has a loop like:
wb_get(new_wb);
while (1) {
list = llist_del_all(&new_wb->switch_wbs_ctxs);
/* Nothing to do? */
if (!list)
break;
... process the items ...
}Now adding of items to the list looks like:
wb_queue_isw()
if (llist_add(&isw->list, &wb->switch_wbs_ctxs))
queue_work(isw_wq, &wb->switch_work);
Because inode_switch_wbs_work_fn() loops when processing isw items, it can happen that wb->switch_work is pending while wb->switch_wbs_ctxs is empty. This is a problem because in that case wb can get freed (no isw items -> no wb reference) while the work is still pending causing use-after-free issues.
We cannot just fix this by cancelling work when freeing wb because that could still trigger problematic 0 -> 1 transitions on wb refcount due to wb_get() in inode_switch_wbs_work_fn(). It could be all handled with more careful code but that seems unnecessarily complex so let's avoid that until it is proven that the looping actually brings practical benefit. Just remove the loop from inode_switch_wbs_work_fn() instead. That way when wb_queue_isw() queues work, we are guaranteed we have added the first item to wb->switch_wbs_ctxs and nobody is going to remove it (and drop the wb reference it holds) until the queued work runs.
--- fs/fs-writeback.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-)
fs/fs-writeback.c +19 -17
@@ -570,28 +570,30 @@ void inode_switch_wbs_work_fn(struct worstruct inode_switch_wbs_context *isw, *next_isw;struct llist_node *list; + list =llist_del_all (&new_wb->switch_wbs_ctxs);/* -* Grab out reference to wb so that it cannot get freed under us +* Nothing to do? That would be a problem as references held by isw +* items protect wb from freeing... +*/ +if (WARN_ON_ONCE (!list)) +return ; + +/* +* Grab our reference to wb so that it cannot get freed under us * after we process all the isw items. */ wb_get (new_wb); -while (1 ) { - list =llist_del_all (&new_wb->switch_wbs_ctxs); -/* Nothing to do? */ -if (!list) -break ; -/* -* In addition to synchronizing among switchers, I_WB_SWITCH -* tells the RCU protected stat update paths to grab the i_page -* lock so that stat transfer can synchronize against them. -* Let's continue after I_WB_SWITCH is guaranteed to be -* visible. -*/ -synchronize_rcu (); +/* +* In addition to synchronizing among switchers, I_WB_SWITCH +* tells the RCU protected stat update paths to grab the i_page +* lock so that stat transfer can synchronize against them. +* Let's continue after I_WB_SWITCH is guaranteed to be +* visible. +*/ +synchronize_rcu (); -llist_for_each_entry_safe (isw, next_isw, list, list) -process_inode_switch_wbs (new_wb, isw); - } +llist_for_each_entry_safe (isw, next_isw, list, list) +process_inode_switch_wbs (new_wb, isw);wb_put (new_wb); }
Greg Kroah-Hartman
maintainerPATCH 33/42 f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Saad <[email protected]>
commit 39d4ee19c1e7d753dd655aebee632271b171f43a upstream.
In f2fs_compress_write_end_io(), dec_page_count(sbi, type) can bring the F2FS_WB_CP_DATA counter to zero, unblocking f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount CPU. The unmount path then proceeds to call f2fs_destroy_page_array_cache(sbi), which destroys sbi->page_array_slab via kmem_cache_destroy(), and eventually kfree(sbi). Meanwhile, the bio completion callback is still executing:
when it reaches page_array_free(sbi, ...), it dereferences sbi->page_array_slab — a destroyed slab cache — to call kmem_cache_free(), causing a use-after-free.
This is the same class of bug as CVE-2026-23234 (which fixed the equivalent race in f2fs_write_end_io() in data.c), but in the compressed writeback completion path that was not covered by that fix.
Fix this by moving dec_page_count() to after page_array_free(), so that all sbi accesses complete before the counter decrement that can unblock unmount. For non-last folios (where atomic_dec_return on cic->pending_pages is nonzero), dec_page_count is called immediately before returning — page_array_free is not reached on this path, so there is no post-decrement sbi access. For the last folio, page_array_free runs while the F2FS_WB_CP_DATA counter is still nonzero (this folio has not yet decremented it), keeping sbi alive, and dec_page_count runs as the final operation.
--- fs/f2fs/compress.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
fs/f2fs/compress.c +11 -3
@@ -1491,10 +1491,10 @@ void f2fs_compress_write_end_io(struct bf2fs_compress_free_page (page); -dec_page_count (sbi, type); - -if (atomic_dec_return (&cic->pending_pages)) +if (atomic_dec_return (&cic->pending_pages)) { +dec_page_count (sbi, type);return ; + }for (i =0 ; i < cic->nr_rpages; i++) {WARN_ON (!cic->rpages[i]);
@@ -1504,6 +1504,14 @@ void f2fs_compress_write_end_io(struct bpage_array_free (sbi, cic->rpages, cic->nr_rpages);kmem_cache_free (cic_entry_slab, cic); + +/* +* Make sure dec_page_count() is the last access to sbi. +* Once it drops the F2FS_WB_CP_DATA counter to zero, the +* unmount thread can proceed to destroy sbi and +* sbi->page_array_slab. +*/ +dec_page_count (sbi, type); } static int f2fs_write_raw_pages(struct compress_ctx *cc,
Greg Kroah-Hartman
maintainerPATCH 34/42 ALSA: usb-audio: apply quirk for MOONDROP JU Jiu
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cryolitia PukNgae <[email protected]>
commit 4513d3e0bbc0585b86ccf2631902593ff97e88f5 upstream.
It(ID 31b2:0111 JU Jiu) reports a MIN value -12800 for volume control, but will mute when setting it less than -10880.
Thanks to my girlfriend Kagura for reporting this issue.
--- sound/usb/mixer.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/usb/mixer.c +7 -0
@@ -1204,6 +1204,13 @@ static void volume_control_quirks(struct cval->min =-11264 ;/* Mute under it */ }break ; +case USB_ID (0x31b2 ,0x0111 ):/* MOONDROP JU Jiu */ +if (!strcmp (kctl->id.name,"PCM Playback Volume" )) { +usb_audio_info (chip, +"set volume quirk for MOONDROP JU Jiu\n" ); + cval->min =-10880 ;/* Mute under it */ + } +break ; } }
Greg Kroah-Hartman
maintainerPATCH 35/42 ALSA: hda/realtek: Add quirk for Legion S7 15IMH
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Naim <[email protected]>
commit 67f4c61a73e9b17dc9593bf27badc6785ecadd78 upstream.
Fix speaker output on the Lenovo Legion S7 15IMH05.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7605,6 +7605,7 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x17aa ,0x3801 ,"Lenovo Yoga9 14IAP7" ,ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN ),HDA_CODEC_QUIRK (0x17aa ,0x3802 ,"DuetITL 2021" ,ALC287_FIXUP_YOGA7_14ITL_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3802 ,"Lenovo Yoga Pro 9 14IRP8" ,ALC287_FIXUP_TAS2781_I2C ), +SND_PCI_QUIRK (0x17aa ,0x3811 ,"Legion S7 15IMH05" ,ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3813 ,"Legion 7i 15IMHG05" ,ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3818 ,"Lenovo C940 / Yoga Duet 7" ,ALC298_FIXUP_LENOVO_C940_DUET7 ), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
Greg Kroah-Hartman
maintainerPATCH 36/42 ALSA: caiaq: take a reference on the USB device in create_card()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Berk Cem Goksel <[email protected]>
commit 80bb50e2d459213cccff3111d5ef98ed4238c0d5 upstream.
The caiaq driver stores a pointer to the parent USB device in cdev->chip.dev but never takes a reference on it. The card's private_free callback, snd_usb_caiaq_card_free(), can run asynchronously via snd_card_free_when_closed() after the USB device has already been disconnected and freed, so any access to cdev->chip.dev in that path dereferences a freed usb_device.
On top of the refcounting issue, the current card_free implementation calls usb_reset_device(cdev->chip.dev). A reset in a free callback is inappropriate: the device is going away, the call takes the device lock in a teardown context, and the reset races with the disconnect path that the callback is already cleaning up after.
Take a reference on the USB device in create_card() with usb_get_dev(), drop it with usb_put_dev() in the free callback, and remove the usb_reset_device() call.
--- sound/usb/caiaq/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/usb/caiaq/device.c +2 -2
@@ -384,7 +384,7 @@ static void card_free(struct snd_card *csnd_usb_caiaq_input_free (cdev);#endif snd_usb_caiaq_audio_free (cdev); -usb_reset_device (cdev->chip.dev); +usb_put_dev (cdev->chip.dev); } static int create_card(struct usb_device *usb_dev,
@@ -410,7 +410,7 @@ static int create_card(struct usb_devicereturn err; cdev =caiaqdev (card); - cdev->chip.dev = usb_dev; + cdev->chip.dev =usb_get_dev (usb_dev); cdev->chip.card = card; cdev->chip.usb_id =USB_ID (le16_to_cpu (usb_dev->descriptor.idVendor),le16_to_cpu (usb_dev->descriptor.idProduct));
Greg Kroah-Hartman
maintainerPATCH 37/42 net/packet: fix TOCTOU race on mmapd vnet_hdr in tpacket_snd()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bingquan Chen <[email protected]>
commit 2c054e17d9d41f1020376806c7f750834ced4dc5 upstream.
In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points directly into the mmap'd TX ring buffer shared with userspace. The kernel validates the header via __packet_snd_vnet_parse() but then re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent userspace thread can modify the vnet_hdr fields between validation and use, bypassing all safety checks.
The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr to a stack-local variable. All other vnet_hdr consumers in the kernel (tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX path is the only caller of virtio_net_hdr_to_skb() that reads directly from user-controlled shared memory.
Fix this by copying vnet_hdr from the mmap'd ring buffer to a stack-local variable before validation and use, consistent with the approach used in packet_snd() and all other callers.
--- net/packet/af_packet.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-)
net/packet/af_packet.c +13 -8
@@ -2717,7 +2717,8 @@ static int tpacket_snd(struct packet_soc {struct sk_buff *skb =NULL ;struct net_device *dev; -struct virtio_net_hdr *vnet_hdr =NULL ; +struct virtio_net_hdr vnet_hdr; +bool has_vnet_hdr = false;struct sockcm_cookie sockc;__be16 proto;int err, reserve =0 ;
@@ -2818,16 +2819,20 @@ static int tpacket_snd(struct packet_soc hlen =LL_RESERVED_SPACE (dev); tlen = dev->needed_tailroom;if (vnet_hdr_sz) { - vnet_hdr = data; data += vnet_hdr_sz; tp_len -= vnet_hdr_sz; -if (tp_len <0 || -__packet_snd_vnet_parse (vnet_hdr, tp_len)) { +if (tp_len <0 ) { + tp_len = -EINVAL ; + goto tpacket_error; + } +memcpy (&vnet_hdr, data - vnet_hdr_sz,sizeof (vnet_hdr)); +if (__packet_snd_vnet_parse (&vnet_hdr, tp_len)) { tp_len = -EINVAL ; goto tpacket_error; } copylen =__virtio16_to_cpu (vio_le (), - vnet_hdr->hdr_len); + vnet_hdr.hdr_len); + has_vnet_hdr = true; } copylen =max_t (int, copylen, dev->hard_header_len); skb = sock_alloc_send_skb(&po->sk,
@@ -2864,12 +2869,12 @@ tpacket_error: } } -if (vnet_hdr_sz) { -if (virtio_net_hdr_to_skb (skb, vnet_hdr,vio_le ())) { +if (has_vnet_hdr) { +if (virtio_net_hdr_to_skb (skb, &vnet_hdr,vio_le ())) { tp_len = -EINVAL ; goto tpacket_error; } -virtio_net_hdr_set_proto (skb, vnet_hdr); +virtio_net_hdr_set_proto (skb, &vnet_hdr); } skb->destructor = tpacket_destruct_skb;
Greg Kroah-Hartman
maintainerPATCH 38/42 crypto: ccp: Dont attempt to copy CSR to userspace if PSP command failed
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit abe4a6d6f606113251868c2c4a06ba904bb41eed upstream.
When retrieving the PEK CSR, don't attempt to copy the blob to userspace if the firmware command failed. If the failure was due to an invalid length, i.e. the userspace buffer+length was too small, copying the number of bytes _firmware_ requires will overflow the kernel-allocated buffer and leak data to userspace.
BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 Read of size 2084 at addr ffff898144612e20 by task syz.9.219/21405 CPU: 14 UID: 0 PID: 21405 Comm: syz.9.219 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.62.0-0 11/19/2025 Call Trace: <TASK> dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 print_address_description ../mm/kasan/report.c:378 [inline] print_report+0xbc/0x260 ../mm/kasan/report.c:482 kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 check_region_inline ../mm/kasan/generic.c:-1 [inline] kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 copy_to_user ../include/linux/uaccess.h:236 [inline] sev_ioctl_do_pek_csr+0x31f/0x590 ../drivers/crypto/ccp/sev-dev.c:1872 sev_ioctl+0x3a4/0x490 ../drivers/crypto/ccp/sev-dev.c:2562 vfs_ioctl ../fs/ioctl.c:51 [inline] __do_sys_ioctl ../fs/ioctl.c:597 [inline] __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
WARN if the driver says the command succeeded, but the firmware error code says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any firwmware error.
--- drivers/crypto/ccp/sev-dev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/crypto/ccp/sev-dev.c +7 -1
@@ -1860,7 +1860,10 @@ cmd: ret =__sev_do_cmd_locked (SEV_CMD_PEK_CSR , &data, &argp->error); -/* If we query the CSR length, FW responded with expected data. */ +/* +* Firmware will returns the length of the CSR blob (either the minimum +* required length or the actual length written), return it to the user. +*/ input.length = data.len;if (copy_to_user ((void __user *)argp->data, &input,sizeof (input))) {
@@ -1868,6 +1871,9 @@ cmd: goto e_free_blob; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free_blob; +if (blob) {if (copy_to_user (input_address, blob, input.length)) ret = -EFAULT ;
Greg Kroah-Hartman
maintainerPATCH 39/42 crypto: ccp: Dont attempt to copy PDH cert to userspace if PSP command failed
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit e76239fed3cffd6d304d8ca3ce23984fd24f57d3 upstream.
When retrieving the PDH cert, don't attempt to copy the blobs to userspace if the firmware command failed. If the failure was due to an invalid length, i.e. the userspace buffer+length was too small, copying the number of bytes _firmware_ requires will overflow the kernel-allocated buffer and leak data to userspace.
BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 Read of size 2084 at addr ffff8885c4ab8aa0 by task syz.0.186/21033 CPU: 51 UID: 0 PID: 21033 Comm: syz.0.186 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.84.12-0 11/17/2025 Call Trace: <TASK> dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 print_address_description ../mm/kasan/report.c:378 [inline] print_report+0xbc/0x260 ../mm/kasan/report.c:482 kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 check_region_inline ../mm/kasan/generic.c:-1 [inline] kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 copy_to_user ../include/linux/uaccess.h:236 [inline] sev_ioctl_do_pdh_export+0x3d3/0x7c0 ../drivers/crypto/ccp/sev-dev.c:2347 sev_ioctl+0x2a2/0x490 ../drivers/crypto/ccp/sev-dev.c:2568 vfs_ioctl ../fs/ioctl.c:51 [inline] __do_sys_ioctl ../fs/ioctl.c:597 [inline] __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
WARN if the driver says the command succeeded, but the firmware error code says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any firwmware error.
--- drivers/crypto/ccp/sev-dev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/crypto/ccp/sev-dev.c +7 -1
@@ -2340,7 +2340,10 @@ cmd: ret =__sev_do_cmd_locked (SEV_CMD_PDH_CERT_EXPORT , &data, &argp->error); -/* If we query the length, FW responded with expected data. */ +/* +* Firmware will return the length of the blobs (either the minimum +* required length or the actual length written), return 'em to the user. +*/ input.cert_chain_len = data.cert_chain_len; input.pdh_cert_len = data.pdh_cert_len;
@@ -2349,6 +2352,9 @@ cmd: goto e_free_cert; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free_cert; +if (pdh_blob) {if (copy_to_user (input_pdh_cert_address, pdh_blob, input.pdh_cert_len)) {
Greg Kroah-Hartman
maintainerPATCH 40/42 crypto: ccp: Dont attempt to copy ID to userspace if PSP command failed
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 4f685dbfa87c546e51d9dc6cab379d20f275e114 upstream.
When retrieving the ID for the CPU, don't attempt to copy the ID blob to userspace if the firmware command failed. If the failure was due to an invalid length, i.e. the userspace buffer+length was too small, copying the number of bytes _firmware_ requires will overflow the kernel-allocated buffer and leak data to userspace.
BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 Read of size 64 at addr ffff8881867f5960 by task syz.0.906/24388 CPU: 130 UID: 0 PID: 24388 Comm: syz.0.906 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.62.0-0 11/19/2025 Call Trace: <TASK> dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 print_address_description ../mm/kasan/report.c:378 [inline] print_report+0xbc/0x260 ../mm/kasan/report.c:482 kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 check_region_inline ../mm/kasan/generic.c:-1 [inline] kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 copy_to_user ../include/linux/uaccess.h:236 [inline] sev_ioctl_do_get_id2+0x361/0x490 ../drivers/crypto/ccp/sev-dev.c:2222 sev_ioctl+0x25f/0x490 ../drivers/crypto/ccp/sev-dev.c:2575 vfs_ioctl ../fs/ioctl.c:51 [inline] __do_sys_ioctl ../fs/ioctl.c:597 [inline] __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
WARN if the driver says the command succeeded, but the firmware error code says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any firwmware error.
--- drivers/crypto/ccp/sev-dev.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/crypto/ccp/sev-dev.c +3 -0
@@ -2224,6 +2224,9 @@ static int sev_ioctl_do_get_id2(struct s goto e_free; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free; +if (id_blob) {if (copy_to_user (input_address, id_blob, data.len)) { ret = -EFAULT ;
Greg Kroah-Hartman
maintainerPATCH 41/42 rxrpc: Fix missing validation of ticket length in non-XDR key preparsing
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anderson Nascimento <[email protected]>
commit ac33733b10b484d666f97688561670afd5861383 upstream.
In rxrpc_preparse(), there are two paths for parsing key payloads: the XDR path (for large payloads) and the non-XDR path (for payloads <= 28 bytes). While the XDR path (rxrpc_preparse_xdr_rxkad()) correctly validates the ticket length against AFSTOKEN_RK_TIX_MAX, the non-XDR path fails to do so.
This allows an unprivileged user to provide a very large ticket length. When this key is later read via rxrpc_read(), the total token size (toksize) calculation results in a value that exceeds AFSTOKEN_LENGTH_MAX, triggering a WARN_ON().
[ 2001.302904] WARNING: CPU: 2 PID: 2108 at net/rxrpc/key.c:778 rxrpc_read+0x109/0x5c0 [rxrpc]
Fix this by adding a check in the non-XDR parsing path of rxrpc_preparse() to ensure the ticket length does not exceed AFSTOKEN_RK_TIX_MAX, bringing it into parity with the XDR parsing logic.
--- net/rxrpc/key.c | 4 ++++ 1 file changed, 4 insertions(+)
net/rxrpc/key.c +4 -0
@@ -502,6 +502,10 @@ static int rxrpc_preparse(struct key_preif (v1->security_index !=RXRPC_SECURITY_RXKAD ) goto error; + ret = -EKEYREJECTED ; +if (v1->ticket_length >AFSTOKEN_RK_TIX_MAX ) + goto error; + plen =sizeof (*token->kad) + v1->ticket_length; prep->quotalen += plen +sizeof (*token);
Greg Kroah-Hartman
maintainerPATCH 42/42 mshv_vtl: Fix vmemmap_shift exceeding MAX_FOLIO_ORDER
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naman Jain <[email protected]>
commit 404cd6bffe17e25e0f94ed2775ffdd6cd10ac3fd upstream.
When registering VTL0 memory via MSHV_ADD_VTL0_MEMORY, the kernel computes pgmap->vmemmap_shift as the number of trailing zeros in the OR of start_pfn and last_pfn, intending to use the largest compound page order both endpoints are aligned to.
However, this value is not clamped to MAX_FOLIO_ORDER, so a sufficiently aligned range (e.g. physical range [0x800000000000, 0x800080000000), corresponding to start_pfn=0x800000000 with 35 trailing zeros) can produce a shift larger than what memremap_pages() accepts, triggering a WARN and returning -EINVAL:
WARNING: ... memremap_pages+0x512/0x650
requested folio size unsupported
The MAX_FOLIO_ORDER check was added by
commit 646b67d57589 ("mm/memremap: reject unreasonable folio/compound page sizes in memremap_pages()").
Fix this by clamping vmemmap_shift to MAX_FOLIO_ORDER so we always request the largest order the kernel supports, in those cases, rather than an out-of-range value.
Also fix the error path to propagate the actual error code from devm_memremap_pages() instead of hard-coding -EFAULT, which was masking the real -EINVAL return.
--- drivers/hv/mshv_vtl_main.c | 12 +++++++++--- include/uapi/linux/mshv.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-)
drivers/hv/mshv_vtl_main.c +9 -3
@@ -386,7 +386,6 @@ static int mshv_vtl_ioctl_add_vtl0_mem(sif (copy_from_user (&vtl0_mem, arg,sizeof (vtl0_mem)))return -EFAULT ; -/* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */ if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) {dev_err (vtl->module_dev,"range start pfn (%llx) > end pfn (%llx)\n" , vtl0_mem.start_pfn, vtl0_mem.last_pfn);
@@ -397,6 +396,10 @@ static int mshv_vtl_ioctl_add_vtl0_mem(sif (!pgmap)return -ENOMEM ; +/* +* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design. +* last_pfn is not reserved or wasted, and reflects 'start_pfn + size' of pagemap range. +*/ pgmap->ranges[0 ].start =PFN_PHYS (vtl0_mem.start_pfn); pgmap->ranges[0 ].end =PFN_PHYS (vtl0_mem.last_pfn) -1 ; pgmap->nr_range =1 ;
@@ -405,8 +408,11 @@ static int mshv_vtl_ioctl_add_vtl0_mem(s/* * Determine the highest page order that can be used for the given memory range. * This works best when the range is aligned; i.e. both the start and the length. +* Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range +* alignment exceeds the maximum supported folio order for this kernel config. */ - pgmap->vmemmap_shift =count_trailing_zeros (vtl0_mem.start_pfn | vtl0_mem.last_pfn); + pgmap->vmemmap_shift =min (count_trailing_zeros (vtl0_mem.start_pfn | vtl0_mem.last_pfn), +MAX_FOLIO_ORDER );dev_dbg (vtl->module_dev,"Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n" , vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift);
@@ -415,7 +421,7 @@ static int mshv_vtl_ioctl_add_vtl0_mem(sif (IS_ERR (addr)) {dev_err (vtl->module_dev,"devm_memremap_pages error: %ld\n" ,PTR_ERR (addr));kfree (pgmap); -return -EFAULT ; +return PTR_ERR (addr); }/* Don't free pgmap, since it has to stick around until the memory
include/uapi/linux/mshv.h +1 -1
@@ -357,7 +357,7 @@ struct mshv_vtl_sint_post_msg {struct mshv_vtl_ram_disposition {__u64 start_pfn; -__u64 last_pfn; +__u64 last_pfn;/* last_pfn is excluded from the range [start_pfn, last_pfn) */ };struct mshv_vtl_set_poll_file {
Hi
no regressions here on x86_64 (Intel 11th Gen. CPU)
Thanks
Hi Greg
Quoted 10 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Linux version 7.0.2-rc1 tested.
Build successfully completed.
Boot successfully completed.
No dmesg regressions.
Video output normal.
Sound output normal.
Lenovo ThinkPad X1 Carbon Gen10(Intel i7-1260P(x86_64) arch linux)
[ 0.000000] Linux version 7.0.2-rc1rv-gce7a64af92ed
(takeshi@ThinkPadX1Gen10J0764) (gcc (GCC) 15.2.1 20260209, GNU ld (GNU Binutils) 2.46) #1 SMP PREEMPT_DYNAMIC Sat Apr 25 00:53:31 JST 2026
Thanks
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Am 24.04.2026 um 15:30 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 7.0.2-rc1-gce7a64af92ed #2 SMP PREEMPT_DYNAMIC Sat Apr 25 07:30:06 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Quoted 8 lines · On Fri, 24 Apr 2026 15:30:25 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64:
Thanks!
Cheers,
Miguel
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
Quoted 15 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.
Quoted 5 lines
thanks,
greg k-h
-------------
I tested kernel version 7.0.2-rc1 by building and booting it in a virtual environment on both x86_64 and arm64 architectures.
Build and boot testing was performed on version 7.0.2-rc1 using the default configuration on both x86_64 and arm64 architectures in a virtual environment. The kernel built and booted successfully, and no dmesg regressions were observed.
kernel version: 7.0.2-rc1
Configurations: x86_64_defconfig, defconfig
Architectures: arm64, x86_64
Kernel Source: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git
Commit: ce7a64af92ed7270208a84dce3ee2e63614212e9
Regards,
Dileep Malepu
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Tested on 3 different amd64 systems. Working well, no regressions observed.
Signature · 1 line
-Barry K. Nathan <[email protected]>
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.2 release. There are 42 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sun, 26 Apr 2026 13:23:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.2-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Tested rc1 against the Fedora build system (aarch64, ppc64le, s390x, x86_64), and boot tested x86_64. No regressions noted.