6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 1065/1887 selinux: allow multiple opens of /sys/fs/selinux/policy
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <[email protected]>
[ Upstream commit a02cd6805562305f936e807da83e253b719dd965 ]
Currently there can only be a single open of /sys/fs/selinux/policy at any time. This allows any process to block any other process from reading the kernel policy. The original motivation seems to have been a mix of preventing an inconsistent view of the policy size and preventing userspace from allocating kernel memory without bound, but this is arguably equally bad. Eliminate the policy_opened flag and shrink the critical section that the policy mutex is held. While we are making changes here, drop a couple of extraneous BUG_ONs.
--- security/selinux/selinuxfs.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-)
security/selinux/selinuxfs.c +4 -22
@@ -74,7 +74,6 @@ struct selinux_fs_info {int *bool_pending_values;struct dentry *class_dir;unsigned long last_class_ino; -bool policy_opened;struct dentry *policycap_dir;unsigned long last_ino;struct selinux_state *state;
@@ -401,41 +400,29 @@ static int sel_open_policy(struct inode *inode, struct file *filp)struct policy_load_memory *plm =NULL ;int rc; -BUG_ON (filp->private_data); - -mutex_lock (&fsi->state->policy_mutex); - rc =avc_has_perm (&selinux_state,current_sid (),SECINITSID_SECURITY ,SECCLASS_SECURITY ,SECURITY__READ_POLICY ,NULL );if (rc) - goto err; - - rc = -EBUSY ; -if (fsi->policy_opened) - goto err; +return rc; - rc = -ENOMEM ; plm =kzalloc (sizeof (*plm),GFP_KERNEL );if (!plm) - goto err; +return -ENOMEM ; +mutex_lock (&fsi->state->policy_mutex); rc =security_read_policy (state, &plm->data, &plm->len);if (rc) goto err; -if ((size_t )i_size_read (inode) != plm->len) {inode_lock (inode);i_size_write (inode, plm->len);inode_unlock (inode); } - - fsi->policy_opened =1 ; +mutex_unlock (&fsi->state->policy_mutex); filp->private_data = plm; -mutex_unlock (&fsi->state->policy_mutex); -return 0 ; err:mutex_unlock (&fsi->state->policy_mutex);
@@ -448,13 +435,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp)static int sel_release_policy (struct inode *inode,struct file *filp) { -struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;struct policy_load_memory *plm = filp->private_data; -BUG_ON (!plm); - - fsi->policy_opened =0 ; -vfree (plm->data);kfree (plm);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1066/1887 media: videobuf2: Set vma_flags in vb2_dma_sg_mmap
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Janne Grunau <[email protected]>
[ Upstream commit 7254b31a13aaa0c2c0f9ffbc335b718656117ff4 ]
vb2_dma_contig sets VMA flags VM_DONTEXPAND and VM_DONTDUMP and I do not see a reason why vb2_dma_sg should behave differently. This avoids hitting WARN_ON(!(vma->vm_flags & VM_DONTEXPAND)); in drm_gem_mmap_obj() during mmap() of an imported dma-buf from the out of tree Apple ISP camera capture driver which uses vb2_dma_sg_memops.
gst-launch-1.0 v4l2src ! gtk4paintablesink
[ 38.201528] ------------[ cut here ]------------ [ 38.202135] WARNING: CPU: 7 PID: 2362 at drivers/gpu/drm/drm_gem.c:1144 drm_gem_mmap_obj+0x1f8/0x210 [ 38.203278] Modules linked in: rfcomm snd_seq_dummy snd_hrtimer
snd_seq snd_seq_device uinput nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables qrtr bnep nls_ascii i2c_dev loop fuse dm_multipath nfnetlink brcmfmac_wcc hid_magicmouse hci_bcm4377 brcmfmac brcmutil bluetooth ecdh_generic cfg80211 ecc btrfs xor xor_neon rfkill hid_apple raid6_pq joydev aop_als apple_nvmem_spmi industrialio snd_soc_aop apple_z2 snd_soc_cs42l84 tps6598x snd_soc_tas2764 macsmc_reboot spi_nor macsmc_hwmon rtc_macsmc gpio_macsmc macsmc_power regmap_spmi macsmc_input dockchannel_hid panel_summit appledrm nvme_apple dwc3 snd_soc_macaudio drm_client_lib nvme_core phy_apple_atc hwmon apple_sart apple_dockchannel macsmc apple_rtkit_helper spmi_apple_controller aop apple_wdt mfd_core nvmem_apple_efuses pinctrl_apple_gpio apple_isp apple_dcp videobuf2_dma_sg mux_core spi_apple
[ 38.203300] videobuf2_memops i2c_pasemi_platform snd_soc_apple_mca videobuf2_v4l2 videodev clk_apple_nco videobuf2_common snd_pcm_dmaengine adpdrm asahi apple_admac adpdrm_mipi drm_dma_helper pwm_apple i2c_pasemi_core drm_display_helper mc cec apple_dart ofpart apple_soc_cpufreq leds_pwm phram [ 38.217677] CPU: 7 UID: 1000 PID: 2362 Comm: gst-launch-1.0 Tainted: G W 6.17.6+ #asahi-dev PREEMPT(full) [ 38.219040] Tainted: [W]=WARN [ 38.219398] Hardware name: Apple MacBook Pro (13-inch, M2, 2022) (DT) [ 38.220213] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [ 38.221088] pc : drm_gem_mmap_obj+0x1f8/0x210 [ 38.221643] lr : drm_gem_mmap_obj+0x78/0x210 [ 38.222178] sp : ffffc0008dc678e0 [ 38.222579] x29: ffffc0008dc678e0 x28: 0000000000042a97 x27: ffff8000b701b480 [ 38.223465] x26: 00000000000000fb x25: ffffc0008dc67d20 x24: ffffc0008dc67968 [ 38.224402] x23: ffff8000e3ca5600 x22: ffff8000265b7800 x21: ffff80003000c0c0 [ 38.225279] x20: 0000000000000000 x19: ffff8000b68c5200 x18: ffffc0008dc67968 [ 38.226151] x17: 0000000000000000 x16: 0000000000000000 x15: ffffc000810a30a8 [ 38.227042] x14: 00007fff637effff x13: 00005555de91ffff x12: 00007fff63293fff [ 38.227942] x11: 0000000000000000 x10: ffff8000184ecf08 x9 : ffffc0007a1900c8 [ 38.228824] x8 : ffffc0008dc67968 x7 : 0000000000000012 x6 : ffffc0015cf1c000 [ 38.229703] x5 : ffffc0008dc676a0 x4 : ffffc00081a27dc0 x3 : 0000000000000038 [ 38.230607] x2 : 0000000000000003 x1 : 0000000000000003 x0 : 00000000100000fb [ 38.231488] Call trace: [ 38.231806] drm_gem_mmap_obj+0x1f8/0x210 (P) [ 38.232342] drm_gem_mmap+0x140/0x260 [ 38.232813] __mmap_region+0x488/0x9a0 [ 38.233277] mmap_region+0xd0/0x148 [ 38.233703] do_mmap+0x350/0x5c0 [ 38.234148] vm_mmap_pgoff+0x14c/0x200 [ 38.234612] ksys_mmap_pgoff+0x150/0x208 [ 38.235107] __arm64_sys_mmap+0x34/0x50 [ 38.235611] invoke_syscall+0x50/0x120 [ 38.236075] el0_svc_common.constprop.0+0x48/0xf0 [ 38.236680] do_el0_svc+0x24/0x38 [ 38.237113] el0_svc+0x38/0x168 [ 38.237507] el0t_64_sync_handler+0xa0/0xe8 [ 38.238034] el0t_64_sync+0x198/0x1a0 [ 38.238491] ---[ end trace 0000000000000000 ]---
There were discussions in [1] at the end of 2023 that mmap() on imported dma-bufs should not be supported but as of v6.17 drm_gem_shmem_mmap() in drm_gem_shmem_helper.c still supports it.
This might affect all gpu or accel drivers using drm_gem_shmem_mmap() or the wrapper drm_gem_shmem_object_mmap().
[1] https://lore.kernel.org/dri-devel/[email protected]/
--- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/common/videobuf2/videobuf2-dma-sg.c +1 -0
@@ -343,6 +343,7 @@ static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)return err; } + vma->vm_flags |=VM_DONTEXPAND |VM_DONTDUMP ;/* * Use common vm_area operations to track buffer refcount. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1067/1887 netfilter: nf_tables: use list_del_rcu for netlink hooks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ]
nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need to use list_del_rcu(), this list can be walked by concurrent dumpers.
Add a new helper and use it consistently.
--- net/netfilter/nf_tables_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/nf_tables_api.c +2 -2
@@ -308,7 +308,7 @@ static void nft_netdev_unregister_hooks(struct net *net,list_for_each_entry_safe (hook, next, hook_list, list) {nf_unregister_net_hook (net, &hook->ops);if (release_netdev) { -list_del (&hook->list); +list_del_rcu (&hook->list);kfree_rcu (hook, rcu); } }
@@ -8101,7 +8101,7 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, flowtable->data.type->setup (&flowtable->data, hook->ops.dev,FLOW_BLOCK_UNBIND );if (release_netdev) { -list_del (&hook->list); +list_del_rcu (&hook->list);kfree_rcu (hook, rcu); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1068/1887 Revert "net/smc: Introduce TCP ULP support"
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: D. Wythe <[email protected]>
[ Upstream commit df31a6b0a3057e66994ad6ccf5d95b9b9514f033 ]
This reverts commit d7cd421da9da2cc7b4d25b8537f66db5c8331c40.
As reported by Al Viro, the TCP ULP support for SMC is fundamentally broken. The implementation attempts to convert an active TCP socket into an SMC socket by modifying the underlying struct file, dentry, and inode in-place, which violates core VFS invariants that assume these structures are immutable for an open file, creating a risk of use after free errors and general system instability.
Given the severity of this design flaw and the fact that cleaner alternatives (e.g., LD_PRELOAD, BPF) exist for legacy application transparency, the correct course of action is to remove this feature entirely.
--- net/smc/af_smc.c | 113 +++++++---------------------------------------- 1 file changed, 17 insertions(+), 96 deletions(-)
net/smc/af_smc.c +17 -96
@@ -3275,8 +3275,8 @@ static const struct proto_ops smc_sock_ops = { .splice_read = smc_splice_read, }; -static int __smc_create (struct net *net,struct socket *sock,int protocol, -int kern,struct socket *clcsock) +static int smc_create (struct net *net,struct socket *sock,int protocol, +int kern) {int family = (protocol ==SMCPROTO_SMC6 ) ?PF_INET6 :PF_INET ;struct smc_sock *smc;
@@ -3306,102 +3306,33 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,/* default behavior from limit_smc_hs in every net namespace */ smc->limit_smc_hs = net->smc.limit_smc_hs; - rc =0 ; -if (!clcsock) { - rc =sock_create_kern (net, family,SOCK_STREAM ,IPPROTO_TCP , - &smc->clcsock); -if (rc) { -sk_common_release (sk); - goto out; - } - -/* smc_clcsock_release() does not wait smc->clcsock->sk's -* destruction; its sk_state might not be TCP_CLOSE after -* smc->sk is close()d, and TCP timers can be fired later, -* which need net ref. -*/ - sk = smc->clcsock->sk; - sk->sk_net_refcnt =1 ; -get_net_track (net, &sk->ns_tracker,GFP_KERNEL ); -sock_inuse_add (net,1 ); - }else { - smc->clcsock = clcsock; + rc =sock_create_kern (net, family,SOCK_STREAM ,IPPROTO_TCP , + &smc->clcsock); +if (rc) { +sk_common_release (sk); + goto out; } +/* smc_clcsock_release() does not wait smc->clcsock->sk's +* destruction; its sk_state might not be TCP_CLOSE after +* smc->sk is close()d, and TCP timers can be fired later, +* which need net ref. +*/ + sk = smc->clcsock->sk; + sk->sk_net_refcnt =1 ; +get_net_track (net, &sk->ns_tracker,GFP_KERNEL ); +sock_inuse_add (net,1 ); + out:return rc; } -static int smc_create (struct net *net,struct socket *sock,int protocol, -int kern) -{ -return __smc_create (net, sock, protocol, kern,NULL ); -} -static const struct net_proto_family smc_sock_family_ops = { .family =PF_SMC , .owner =THIS_MODULE , .create = smc_create, }; -static int smc_ulp_init (struct sock *sk) -{ -struct socket *tcp = sk->sk_socket; -struct net *net =sock_net (sk); -struct socket *smcsock; -int protocol, ret; - -/* only TCP can be replaced */ -if (tcp->type !=SOCK_STREAM || sk->sk_protocol !=IPPROTO_TCP || - (sk->sk_family !=AF_INET && sk->sk_family !=AF_INET6 )) -return -ESOCKTNOSUPPORT ; -/* don't handle wq now */ -if (tcp->state !=SS_UNCONNECTED || !tcp->file || tcp->wq.fasync_list) -return -ENOTCONN ; - -if (sk->sk_family ==AF_INET ) - protocol =SMCPROTO_SMC ; -else - protocol =SMCPROTO_SMC6 ; - - smcsock =sock_alloc (); -if (!smcsock) -return -ENFILE ; - - smcsock->type =SOCK_STREAM ; -__module_get (THIS_MODULE );/* tried in __tcp_ulp_find_autoload */ - ret =__smc_create (net, smcsock, protocol,1 , tcp); -if (ret) { -sock_release (smcsock);/* module_put() which ops won't be NULL */ -return ret; - } - -/* replace tcp socket to smc */ - smcsock->file = tcp->file; - smcsock->file->private_data = smcsock; - smcsock->file->f_inode =SOCK_INODE (smcsock);/* replace inode when sock_close */ - smcsock->file->f_path.dentry->d_inode =SOCK_INODE (smcsock);/* dput() in __fput */ - tcp->file =NULL ; - -return ret; -} - -static void smc_ulp_clone (const struct request_sock *req,struct sock *newsk, -const gfp_t priority) -{ -struct inet_connection_sock *icsk =inet_csk (newsk); - -/* don't inherit ulp ops to child when listen */ - icsk->icsk_ulp_ops =NULL ; -} - -static struct tcp_ulp_ops smc_ulp_ops__read_mostly = { - .name ="smc" , - .owner =THIS_MODULE , - .init = smc_ulp_init, - .clone = smc_ulp_clone, -}; -unsigned int smc_net_id;static __net_init int smc_net_init (struct net *net)
@@ -3521,17 +3452,9 @@ static int __init smc_init(void) goto out_sock; } - rc =tcp_register_ulp (&smc_ulp_ops); -if (rc) { -pr_err ("%s: tcp_ulp_register fails with %d\n" , __func__, rc); - goto out_ib; - } -static_branch_enable (&tcp_have_smc);return 0 ; -out_ib: -smc_ib_unregister_client (); out_sock:sock_unregister (PF_SMC ); out_proto6:
@@ -3561,7 +3484,6 @@ static int __init smc_init(void) static void __exit smc_exit(void) {static_branch_disable (&tcp_have_smc); -tcp_unregister_ulp (&smc_ulp_ops);sock_unregister (PF_SMC );smc_core_exit ();smc_ib_unregister_client ();
@@ -3585,5 +3507,4 @@ MODULE_AUTHOR("Ursula Braun <[email protected]>");MODULE_DESCRIPTION ("smc socket address family" );MODULE_LICENSE ("GPL" );MODULE_ALIAS_NETPROTO (PF_SMC ); -MODULE_ALIAS_TCP_ULP ("smc" );MODULE_ALIAS_GENL_FAMILY (SMC_GENL_FAMILY_NAME );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1069/1887 crypto: jitter - replace LFSR with SHA3-256
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Müller <[email protected]>
[ Upstream commit bb897c55042e9330bcf88b4b13cbdd6f9fabdd5e ]
Using the kernel crypto API, the SHA3-256 algorithm is used as conditioning element to replace the LFSR in the Jitter RNG. All other parts of the Jitter RNG are unchanged.
The application and use of the SHA-3 conditioning operation is identical to the user space Jitter RNG 3.4.0 by applying the following concept:
- the Jitter RNG initializes a SHA-3 state which acts as the "entropy pool" when the Jitter RNG is allocated.
- When a new time delta is obtained, it is inserted into the "entropy pool" with a SHA-3 update operation. Note, this operation in most of the cases is a simple memcpy() onto the SHA-3 stack.
- To cause a true SHA-3 operation for each time delta operation, a second SHA-3 operation is performed hashing Jitter RNG status information. The final message digest is also inserted into the "entropy pool" with a SHA-3 update operation. Yet, this data is not considered to provide any entropy, but it shall stir the entropy pool.
- To generate a random number, a SHA-3 final operation is performed to calculate a message digest followed by an immediate SHA-3 init to re-initialize the "entropy pool". The obtained message digest is one block of the Jitter RNG that is returned to the caller.
Mathematically speaking, the random number generated by the Jitter RNG is:
aux_t = SHA-3(Jitter RNG state data)
Jitter RNG block = SHA-3(time_i || aux_i || time_(i-1) || aux_(i-1) ||
... || time_(i-255) || aux_(i-255))
when assuming that the OSR = 1, i.e. the default value.
This operation implies that the Jitter RNG has an output-blocksize of 256 bits instead of the 64 bits of the LFSR-based Jitter RNG that is replaced with this patch.
The patch also replaces the varying number of invocations of the conditioning function with one fixed number of invocations. The use of the conditioning function consistent with the userspace Jitter RNG library version 3.4.0.
The code is tested with a system that exhibited the least amount of entropy generated by the Jitter RNG: the SiFive Unmatched RISC-V system. The measured entropy rate is well above the heuristically implied entropy value of 1 bit of entropy per time delta. On all other tested systems, the measured entropy rate is even higher by orders of magnitude. The measurement was performed using updated tooling provided with the user space Jitter RNG library test framework.
The performance of the Jitter RNG with this patch is about en par with the performance of the Jitter RNG without the patch.
Stable-dep-of: 01d798e9feb3 ("crypto: jitterentropy - replace long-held spinlock with mutex")
--- crypto/Kconfig | 1 + crypto/jitterentropy-kcapi.c | 183 +++++++++++++++++++++++++++++++---- crypto/jitterentropy.c | 145 +++++++++------------------ crypto/jitterentropy.h | 10 +- 4 files changed, 219 insertions(+), 120 deletions(-)
crypto/Kconfig +1 -0
@@ -1279,6 +1279,7 @@ endif # if CRYPTO_DRBG_MENU config CRYPTO_JITTERENTROPY tristate "CPU Jitter Non-Deterministic RNG (Random Number Generator)" select CRYPTO_RNG + select CRYPTO_SHA3 help CPU Jitter RNG (Random Number Generator) from the Jitterentropy library
crypto/jitterentropy-kcapi.c +163 -20
246 lines not on this page · raw message
crypto/jitterentropy.c +48 -97
266 lines not on this page · raw message
crypto/jitterentropy.h +7 -3
@@ -2,14 +2,18 @@extern void *jent_zalloc (unsigned int len);extern void jent_zfree (void *ptr); -extern void jent_memcpy (void *dest,const void *src,unsigned int n);extern void jent_get_nstime (__u64 *out); +extern int jent_hash_time (void *hash_state,__u64 time,u8 *addtl, +unsigned int addtl_len,__u64 hash_loop_cnt, +unsigned int stuck); +int jent_read_random_block (void *hash_state,char *dst,unsigned int dst_len);struct rand_data ; -extern int jent_entropy_init (void ); +extern int jent_entropy_init (void *hash_state);extern int jent_read_entropy (struct rand_data *ec,unsigned char *data,unsigned int len);extern struct rand_data *jent_entropy_collector_alloc (unsigned int osr, -unsigned int flags); +unsigned int flags, +void *hash_state);extern void jent_entropy_collector_free (struct rand_data *entropy_collector);
Signature · 1 line
2.53.0
Re: [PATCH 6.1 1069/1887] crypto: jitter - replace LFSR with SHA3-256
[+Cc [email protected]]
Quoted 11 lines · Greg Kroah-Hartman
6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Müller <[email protected]>
[ Upstream commit
bb897c55042e9330bcf88b4b13cbdd6f9fabdd5e]Using the kernel crypto API, the SHA3-256 algorithm is used as conditioning element to replace the LFSR in the Jitter RNG. All other parts of the Jitter RNG are unchanged.
For some reason this is going by on stable@ without linux-crypto@ being Cc'ed, which is itself grounds for a nack.
But also this commit had known bugs that were fixed in follow-up commits such as 735b72568c73, 908dffaf88a2, 9aa7e045f4af7, maybe others.
Now, these changes were all to the known-problematic and little-used "FIPS RNG" instead of the regular one. So, ideally, it shouldn't matter much. The thing is, before v7.1, certain things actually *did* pull from the "FIPS RNG" even when the kernel wasn't booted with fips=1.
So pulling in known-broken commits to it is a little concerning.
- Eric
Sasha Levin
maintainerRe: [PATCH 6.1 1069/1887] crypto: jitter - replace LFSR with SHA3-256
Quoted 2 lines
But also this commit had known bugs that were fixed in follow-up commits such as
735b72568c73,908dffaf88a2,9aa7e045f4af7, maybe others.
Queued the first one for 6.1. 908dffaf88a2 ("crypto: jitter - add oversampling of noise source") is already in 6.1. 9aa7e045f4af ("crypto: jitter - Mark intermediary memory as clean") only adds a KMSAN annotation and is not in 6.12 or 6.6 either, so I left it out.
Signature · 2 lines
Thanks, Sasha
Re: [PATCH 6.1 1069/1887] crypto: jitter - replace LFSR with SHA3-256
Quoted 7 lines · Sasha Levin
Quoted 2 lines
But also this commit had known bugs that were fixed in follow-up commits such as
735b72568c73,908dffaf88a2,9aa7e045f4af7, maybe others.Queued the first one for 6.1.
908dffaf88a2("crypto: jitter - add oversampling of noise source") is already in 6.1.9aa7e045f4af("crypto: jitter - Mark intermediary memory as clean") only adds a KMSAN annotation and is not in 6.12 or 6.6 either, so I left it out.
Okay, there are more too and this should just be reverted, but whatever. It's clear stable is just doing its own thing here for some reason.
- Eric
Greg Kroah-Hartman
maintainerPATCH 1070/1887 crypto: jitterentropy - replace long-held spinlock with mutex
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haixin Xu <[email protected]>
[ Upstream commit 01d798e9feb30212952d4e992801ba6bd6a82351 ]
jent_kcapi_random() serializes the shared jitterentropy state, but it currently holds a spinlock across the jent_read_entropy() call. That path performs expensive jitter collection and SHA3 conditioning, so parallel readers can trigger stalls as contending waiters spin for the same lock.
To prevent non-preemptible lock hold, replace rng->jent_lock with a mutex so contended readers sleep instead of spinning on a shared lock held across expensive entropy generation.
--- crypto/jitterentropy-kcapi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
crypto/jitterentropy-kcapi.c +7 -7
@@ -42,6 +42,7 @@#include <linux/fips.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <linux/time.h> #include <crypto/internal/rng.h>
@@ -180,7 +181,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len)***************************************************************************/ struct jitterentropy { -spinlock_t jent_lock; +struct mutex jent_lock;struct rand_data *entropy_collector;struct crypto_shash *tfm;struct shash_desc *sdesc;
@@ -190,7 +191,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) {struct jitterentropy *rng =crypto_tfm_ctx (tfm); -spin_lock (&rng->jent_lock); +mutex_lock (&rng->jent_lock);if (rng->sdesc) {shash_desc_zero (rng->sdesc);
@@ -205,7 +206,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm)if (rng->entropy_collector)jent_entropy_collector_free (rng->entropy_collector); rng->entropy_collector =NULL ; -spin_unlock (&rng->jent_lock); +mutex_unlock (&rng->jent_lock); }static int jent_kcapi_init (struct crypto_tfm *tfm)
@@ -215,7 +216,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm)struct shash_desc *sdesc;int size, ret =0 ; -spin_lock_init (&rng->jent_lock); +mutex_init (&rng->jent_lock);/* * Use SHA3-256 as conditioner. We allocate only the generic
@@ -250,7 +251,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) goto err; } -spin_lock_init (&rng->jent_lock);return 0 ; err:
@@ -265,7 +265,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm,struct jitterentropy *rng =crypto_rng_ctx (tfm);int ret =0 ; -spin_lock (&rng->jent_lock); +mutex_lock (&rng->jent_lock); ret =jent_read_entropy (rng->entropy_collector, rdata, dlen);
@@ -291,7 +291,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, ret = -EINVAL ; } -spin_unlock (&rng->jent_lock); +mutex_unlock (&rng->jent_lock);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1071/1887 tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit bddc09212c24934643bd44fc794748d2bbb3b6cd ]
In the SIOCGIFHWADDR path, tap_ioctl() copies 16 bytes of an uninitialised on-stack struct sockaddr_storage to userspace via ifr_hwaddr, but netif_get_mac_address() only writes sa_family and dev->addr_len (6 for Ethernet) bytes, leaving sa_data[6..13] uninitialised.
Those 8 trailing bytes leak kernel stack contents; SIOCGIFHWADDR on a macvtap chardev returns kernel .text and direct-map pointers, defeating KASLR.
Initialise ss at declaration.
--- drivers/net/tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/tap.c +1 -1
@@ -995,7 +995,7 @@ static long tap_ioctl(struct file *file, unsigned int cmd,unsigned int __user *up = argp;unsigned short u;int __user *sp = argp; -struct sockaddr sa; +struct sockaddr sa = {};int s;int ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1072/1887 libceph: Fix potential out-of-bounds access in __ceph_x_decrypt()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
[ Upstream commit 821365487aa58d06bda65c676ba215d506ba9768 ]
In __ceph_x_decrypt(), a part of the buffer p is interpreted as a ceph_x_encrypt_header, and the magic field of this struct is accessed. This happens without any guarantee that the buffer is large enough to hold this struct. The function parameter ciphertext_len represents the length of the ciphertext to decrypt and is guaranteed to be at most the remaining size of the allocated buffer p. However, this value is not necessarily greater than sizeof(ceph_x_encrypt_header). E.g., a message frame of type FRAME_TAG_AUTH_REPLY_MORE, that is just as long to hold the ciphertext at its end with a ciphertext_len of 8 or less, can trigger an out-of-bounds memory access when accessing hdr->magic.
This patch fixes the issue by adding a check to ensure that the decrypted plaintext in the buffer is large enough to represent at least the ceph_x_encrypt_header.
--- net/ceph/auth_x.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ceph/auth_x.c +5 -0
@@ -86,6 +86,11 @@ static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,if (ret)return ret; +if (plaintext_len <sizeof (*hdr)) { +pr_err ("%s plaintext too small %d\n" , __func__, plaintext_len); +return -EINVAL ; + } +if (le64_to_cpu (hdr->magic) !=CEPHX_ENC_MAGIC ) {pr_err ("%s bad magic\n" , __func__);return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1073/1887 ceph: fix BUG_ON in __ceph_build_xattrs_blob() due to stale blob size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <[email protected]>
[ Upstream commit 0c22d9511cbde746622f8e4c11aaa63fe76d45f9 ]
The generic/642 test-case can reproduce the kernel crash:
[40243.605254] ------------[ cut here ]------------ [40243.605956] kernel BUG at fs/ceph/xattr.c:918! [40243.607142] Oops: invalid opcode: 0000 [#1] SMP PTI [40243.608067] CPU: 7 UID: 0 PID: 498762 Comm: kworker/7:1 Not tainted 7.0.0-rc7+ #3 PREEMPT(full) [40243.609700] Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [40243.611820] Workqueue: ceph-msgr ceph_con_workfn [40243.612715] RIP: 0010:__ceph_build_xattrs_blob+0x1b8/0x1e0 [40243.613731] Code: 0f 84 82 fe ff ff e9 cf 8e 56 ff 48 8d 65 e8 31 c0 5b 41 5c 41 5d 5d 31 d2 31 c9 31 f6 31 ff 45 31 c0 45 31 c9 c3 cc cc cc cc <0f> 0b 4c 8b 62 08 41 8b 85 24 07 00 00 49 83 c4 04 41 89 44 24 fc [40243.616888] RSP: 0018:ffffcc80c4d4b688 EFLAGS: 00010287 [40243.617773] RAX: 0000000000010026 RBX: 0000000000000001 RCX: 0000000000000000 [40243.618928] RDX: ffff8a773798dee0 RSI: 0000000000000000 RDI: 0000000000000000 [40243.620158] RBP: ffffcc80c4d4b6a0 R08: 0000000000000000 R09: 0000000000000000 [40243.621573] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a75f3b58000 [40243.622907] R13: ffff8a75f3b58000 R14: 0000000000000080 R15: 000000000000bffd [40243.624054] FS: 0000000000000000(0000) GS:ffff8a787d1b4000(0000) knlGS:0000000000000000 [40243.625331] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [40243.626269] CR2: 000072f390b623c0 CR3: 000000011c02a003 CR4: 0000000000372ef0 [40243.627408] Call Trace: [40243.627839] <TASK> [40243.628188] __prep_cap+0x3fd/0x4a0 [40243.628789] ? do_raw_spin_unlock+0x4e/0xe0 [40243.629474] ceph_check_caps+0x46a/0xc80 [40243.630094] ? __lock_acquire+0x4a2/0x2650 [40243.630773] ? find_held_lock+0x31/0x90 [40243.631347] ? handle_cap_grant+0x79f/0x1060 [40243.632068] ? lock_release+0xd9/0x300 [40243.632696] ? __mutex_unlock_slowpath+0x3e/0x340 [40243.633429] ? lock_release+0xd9/0x300 [40243.634052] handle_cap_grant+0xcf6/0x1060 [40243.634745] ceph_handle_caps+0x122b/0x2110 [40243.635415] mds_dispatch+0x5bd/0x2160 [40243.636034] ? ceph_con_process_message+0x65/0x190 [40243.636828] ? lock_release+0xd9/0x300 [40243.637431] ceph_con_process_message+0x7a/0x190 [40243.638184] ? kfree+0x311/0x4f0 [40243.638749] ? kfree+0x311/0x4f0 [40243.639268] process_message+0x16/0x1a0 [40243.639915] ? sg_free_table+0x39/0x90 [40243.640572] ceph_con_v2_try_read+0xf58/0x2120 [40243.641255] ? lock_acquire+0xc8/0x300 [40243.641863] ceph_con_workfn+0x151/0x820 [40243.642493] process_one_work+0x22f/0x630 [40243.643093] ? process_one_work+0x254/0x630 [40243.643770] worker_thread+0x1e2/0x400 [40243.644332] ? __pfx_worker_thread+0x10/0x10 [40243.645020] kthread+0x109/0x140 [40243.645560] ? __pfx_kthread+0x10/0x10 [40243.646125] ret_from_fork+0x3f8/0x480 [40243.646752] ? __pfx_kthread+0x10/0x10 [40243.647316] ? __pfx_kthread+0x10/0x10 [40243.647919] ret_from_fork_asm+0x1a/0x30 [40243.648556] </TASK> [40243.648902] Modules linked in: overlay hctr2 libpolyval chacha libchacha adiantum libnh libpoly1305 essiv intel_rapl_msr intel_rapl_common intel_uncore_frequency_common skx_edac_common nfit kvm_intel kvm irqbypass joydev ghash_clmulni_intel aesni_intel rapl input_leds mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 pata_acpi bochs qemu_fw_cfg i2c_smbus sch_fq_codel rbd dm_crypt msr parport_pc ppdev lp parport efi_pstore [40243.654766] ---[ end trace 0000000000000000 ]---
Commit d93231a6bc8a ("ceph: prevent a client from exceeding the MDS maximum xattr size") moved the required_blob_size computation to before the __build_xattrs() call, introducing a race.
__build_xattrs() releases and reacquires i_ceph_lock during execution. In that window, handle_cap_grant() may update i_xattrs.blob with a newer MDS-provided blob and bump i_xattrs.version. When __build_xattrs() detects that index_version < version, it destroys and rebuilds the entire xattr rb-tree from the new blob, potentially increasing count, names_size, and vals_size.
The prealloc_blob size check that follows still uses the stale required_blob_size computed before the rebuild, so it passes even when prealloc_blob is too small for the now-larger tree. After __set_xattr() adds one more xattr on top, __ceph_build_xattrs_blob() is called from the cap flush path and hits:
BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
Fix this by recomputing required_blob_size after __build_xattrs() returns, using the current tree state. Also re-validate against m_max_xattr_size to fall back to the sync path if the rebuilt tree now exceeds the MDS limit.
--- fs/ceph/xattr.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/ceph/xattr.c +16 -0
@@ -1208,6 +1208,22 @@ int __ceph_setxattr(struct inode *inode, const char *name, ceph_cap_string(issued));__build_xattrs (inode); +/* +* __build_xattrs() may have released and reacquired i_ceph_lock, +* during which handle_cap_grant() could have replaced i_xattrs.blob +* with a newer MDS-provided blob and bumped i_xattrs.version. If that +* caused __build_xattrs() to rebuild the rb-tree from the new blob, +* count/names_size/vals_size may now be larger than when +* required_blob_size was computed above. Recompute it here so the +* prealloc_blob size check below reflects the current tree state. +*/ + required_blob_size =__get_required_blob_size (ci, name_len, val_len); +if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) { +dout ("sync (size too large): %d > %llu\n" , + required_blob_size, mdsc->mdsmap->m_max_xattr_size); + goto do_sync; + } +if (!ci->i_xattrs.prealloc_blob || required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {struct ceph_buffer *blob;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1074/1887 fsnotify: fix inode reference leak in fsnotify_recalc_mask()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ]
fsnotify_recalc_mask() fails to handle the return value of __fsnotify_recalc_mask(), which may return an inode pointer that needs to be released via fsnotify_drop_object() when the connector's HAS_IREF flag transitions from set to cleared.
This manifests as a hung task with the following call trace:
INFO: task umount:1234 blocked for more than 120 seconds. Call Trace: __schedule schedule fsnotify_sb_delete generic_shutdown_super kill_anon_super cleanup_mnt task_work_run do_exit do_group_exit
The race window that triggers the iref leak:
Thread A (adding mark) Thread B (removing mark)
────────────────────── ────────────────────────
fsnotify_add_mark_locked():
fsnotify_add_mark_list():
spin_lock(conn->lock)
add mark_B(evictable) to list
spin_unlock(conn->lock)
return
/* ---- gap: no lock held ---- */
fsnotify_detach_mark(mark_A):
spin_lock(mark_A->lock)
clear ATTACHED flag on mark_A
spin_unlock(mark_A->lock)
fsnotify_put_mark(mark_A)
fsnotify_recalc_mask():
spin_lock(conn->lock)
__fsnotify_recalc_mask():
/* mark_A skipped: ATTACHED cleared */
/* only mark_B(evictable) remains */
want_iref = false
has_iref = true /* not yet cleared */
-> HAS_IREF transitions true -> false
-> returns inode pointer
spin_unlock(conn->lock)
/* BUG: return value discarded!
* iput() and fsnotify_put_sb_watched_objects()
* are never called */Fix this by deferring the transition true -> false of HAS_IREF flag from fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B).
--- fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
fs/notify/mark.c +36 -3
@@ -153,7 +153,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,return inode; } -static void *__fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) +/* +* Calculate mask of events for a list of marks. +* +* Return true if any of the attached marks want to hold an inode reference. +*/ +static bool __fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) {u32 new_mask =0 ;bool want_iref = false;
@@ -173,6 +178,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) } *fsnotify_conn_mask_p (conn) = new_mask; +return want_iref; +} + +/* +* Calculate mask of events for a list of marks after attach/modify mark +* and get an inode reference for the connector if needed. +* +* A concurrent add of evictable mark and detach of non-evictable mark can +* lead to __fsnotify_recalc_mask() returning false want_iref, but in this +* case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called +* from fsnotify_put_mark(). +*/ +static void fsnotify_recalc_mask_set_iref (struct fsnotify_mark_connector *conn) +{ +bool has_iref = conn->flags &FSNOTIFY_CONN_FLAG_HAS_IREF ; +bool want_iref =__fsnotify_recalc_mask (conn) || has_iref; + + (void )fsnotify_update_iref (conn, want_iref); +} + +/* +* Calculate mask of events for a list of marks after detach mark +* and return the inode object if its reference is no longer needed. +*/ +static void *fsnotify_recalc_mask_clear_iref (struct fsnotify_mark_connector *conn) +{ +bool want_iref =__fsnotify_recalc_mask (conn); +return fsnotify_update_iref (conn, want_iref); }
@@ -209,7 +242,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)spin_lock (&conn->lock); update_children = !fsnotify_conn_watches_children (conn); -__fsnotify_recalc_mask (conn); +fsnotify_recalc_mask_set_iref (conn); update_children &=fsnotify_conn_watches_children (conn);spin_unlock (&conn->lock);/*
@@ -342,7 +375,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) objp =fsnotify_detach_connector_from_object (conn, &type); free_conn = true; }else { - objp =__fsnotify_recalc_mask (conn); + objp =fsnotify_recalc_mask_clear_iref (conn); type = conn->type; }WRITE_ONCE (mark->connector,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1075/1887 sched/psi: fix race between file release and pressure write
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ]
A potential race condition exists between pressure write and cgroup file release regarding the priv member of struct kernfs_open_file, which triggers the uaf reported in [1].
Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1
==== ====
vfs_rmdir() kernfs_iop_rmdir() cgroup_rmdir() cgroup_kn_lock_live() cgroup_destroy_locked() cgroup_addrm_files() cgroup_rm_file() kernfs_remove_by_name() kernfs_remove_by_name_ns() vfs_write() __kernfs_remove() new_sync_write() kernfs_drain() kernfs_fop_write_iter() kernfs_drain_open_files() cgroup_file_write() kernfs_release_file() pressure_write() cgroup_file_release() ctx = of->priv; kfree(ctx);
of->priv = NULL; cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv
The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards the memory deallocation of of->priv performed within cgroup_file_release(). However, the operations involving of->priv executed within pressure_write() are not entirely covered by the protection of cgroup_mutex. Consequently, if the code in pressure_write(), specifically the section handling the ctx variable executes after cgroup_file_release() has completed, a uaf vulnerability involving of->priv is triggered.
Therefore, the issue can be resolved by extending the scope of the cgroup_mutex lock within pressure_write() to encompass all code paths involving of->priv, thereby properly synchronizing the race condition occurring between cgroup_file_release() and pressure_write().
And, if an live kn lock can be successfully acquired while executing the pressure write operation, it indicates that the cgroup deletion process has not yet reached its final stage; consequently, the priv pointer within open_file cannot be NULL. Therefore, the operation to retrieve the ctx value must be moved to a point *after* the live kn lock has been successfully acquired.
In another situation, specifically after entering cgroup_kn_lock_live() but before acquiring cgroup_mutex, there exists a different class of race condition:
CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()
cgroup_kn_lock_live(memory.pressure)
cgroup_tryget(cgrp)
kernfs_break_active_protection(kn)
... blocks on cgroup_mutex
cgroup_pressure_write() cgroup_kn_lock_live(cgroup.pressure) cgroup_file_show(memory.pressure, false)
kernfs_show(false)
kernfs_drain_open_files()
cgroup_file_release(of)
kfree(ctx)
of->priv = NULL
cgroup_kn_unlock()
... acquires cgroup_mutex
ctx = of->priv; // may now be NULL
if (ctx->psi.trigger) // NULL dereference
Consequently, there is a possibility that of->priv is NULL, the pressure write needs to check for this.
Now that the scope of the cgroup_mutex has been expanded, the original explicit cgroup_get/put operations are no longer necessary, this is because acquiring/releasing the live kn lock inherently executes a cgroup get/put operation.
[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 Call Trace: pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 Allocated by task 9352: cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 do_dentry_open+0x83d/0x13e0 fs/open.c:949 Freed by task 9353: cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 kernfs_release_file fs/kernfs/file.c:764 [inline] kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525
--- kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
kernel/cgroup/cgroup.c +16 -8
@@ -3786,33 +3786,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)static ssize_t pressure_write (struct kernfs_open_file *of,char *buf,size_t nbytes,enum psi_res res) { -struct cgroup_file_ctx *ctx = of->priv; +struct cgroup_file_ctx *ctx;struct psi_trigger *new;struct cgroup *cgrp;struct psi_group *psi; +ssize_t ret =0 ; cgrp =cgroup_kn_lock_live (of->kn, false);if (!cgrp)return -ENODEV ; -cgroup_get (cgrp); -cgroup_kn_unlock (of->kn); + ctx = of->priv; +if (!ctx) { + ret = -ENODEV ; + goto out_unlock; + }/* Allow only one trigger per file descriptor */ if (ctx->psi.trigger) { -cgroup_put (cgrp); -return -EBUSY ; + ret = -EBUSY ; + goto out_unlock; } psi =cgroup_psi (cgrp); new =psi_trigger_create (psi, buf, res, of->file, of);if (IS_ERR (new)) { -cgroup_put (cgrp); -return PTR_ERR (new); + ret =PTR_ERR (new); + goto out_unlock; }smp_store_release (&ctx->psi.trigger, new); -cgroup_put (cgrp); + +out_unlock: +cgroup_kn_unlock (of->kn); +if (ret) +return ret;return nbytes; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1076/1887 netfilter: nat: use kfree_rcu to release ops
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 6eda0d771f94267f73f57c94630aa47e90957915 ]
Florian Westphal says:
"Historically this is not an issue, even for normal base hooks: the data path doesn't use the original nf_hook_ops that are used to register the callbacks.
However, in v5.14 I added the ability to dump the active netfilter hooks from userspace.
This code will peek back into the nf_hook_ops that are available at the tail of the pointer-array blob used by the datapath.
The nat hooks are special, because they are called indirectly from the central nat dispatcher hook. They are currently invisible to the nfnl hook dump subsystem though.
But once that changes the nat ops structures have to be deferred too."
Update nf_nat_register_fn() to deal with partial exposition of the hooks from error path which can be also an issue for nfnetlink_hook.
--- include/linux/netfilter.h | 2 ++ net/ipv4/netfilter/iptable_nat.c | 4 ++-- net/ipv6/netfilter/ip6table_nat.c | 4 ++-- net/netfilter/nf_nat_core.c | 10 ++++++---- 4 files changed, 12 insertions(+), 8 deletions(-)
include/linux/netfilter.h +2 -0
@@ -83,6 +83,8 @@ enum nf_hook_ops_type { };struct nf_hook_ops { +struct rcu_head rcu; +/* User fills in from here down. */ nf_hookfn *hook;struct net_device *dev;
net/ipv4/netfilter/iptable_nat.c +2 -2
@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)while (i)nf_nat_ipv4_unregister_fn (net, &ops[--i]); -kfree (ops); +kfree_rcu (ops, rcu);return ret; } }
@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)for (i =0 ; i <ARRAY_SIZE (nf_nat_ipv4_ops); i++)nf_nat_ipv4_unregister_fn (net, &ops[i]); -kfree (ops); +kfree_rcu (ops, rcu); }static int iptable_nat_table_init (struct net *net)
net/ipv6/netfilter/ip6table_nat.c +2 -2
@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net)while (i)nf_nat_ipv6_unregister_fn (net, &ops[--i]); -kfree (ops); +kfree_rcu (ops, rcu);return ret; } }
@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)for (i =0 ; i <ARRAY_SIZE (nf_nat_ipv6_ops); i++)nf_nat_ipv6_unregister_fn (net, &ops[i]); -kfree (ops); +kfree_rcu (ops, rcu); }static int ip6table_nat_table_init (struct net *net)
net/netfilter/nf_nat_core.c +6 -4
@@ -1050,9 +1050,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, ret =nf_register_net_hooks (net, nat_ops, ops_count);if (ret <0 ) {mutex_unlock (&nf_nat_proto_mutex); -for (i =0 ; i < ops_count; i++) -kfree (nat_ops[i].priv); -kfree (nat_ops); +for (i =0 ; i < ops_count; i++) { + priv = nat_ops[i].priv; +kfree_rcu (priv, rcu_head); + } +kfree_rcu (nat_ops, rcu);return ret; }
@@ -1116,7 +1118,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, } nat_proto_net->nat_hook_ops =NULL ; -kfree (nat_ops); +kfree_rcu (nat_ops, rcu); } unlock:mutex_unlock (&nf_nat_proto_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1077/1887 ice: fix double-free of tx_buf skb
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Schmidt <[email protected]>
[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ]
If ice_tso() or ice_tx_csum() fail, the error path in ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points to it and is marked as valid (ICE_TX_BUF_SKB).
'next_to_use' remains unchanged, so the potential problem will likely fix itself when the next packet is transmitted and the tx_buf gets overwritten. But if there is no next packet and the interface is brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() will find the tx_buf and free the skb for the second time.
The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error path, so that ice_unmap_and_free_tx_buf().
Move the initialization of 'first' up, to ensure it's already valid in case we hit the linearization error path.
The bug was spotted by AI while I had it looking for something else. It also proposed an initial version of the patch.
I reproduced the bug and tested the fix by adding code to inject failures, on a build with KASAN.
I looked for similar bugs in related Intel drivers and did not find any.
--- drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/ice_txrx.c +4 -2
@@ -2277,6 +2277,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)ice_trace (xmit_frame_ring, tx_ring, skb); +/* record the location of the first descriptor for this packet */ + first = &tx_ring->tx_buf[tx_ring->next_to_use]; + count =ice_xmit_desc_count (skb);if (ice_chk_linearize (skb, count)) {if (__skb_linearize (skb))
@@ -2302,8 +2305,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) offload.tx_ring = tx_ring; -/* record the location of the first descriptor for this packet */ - first = &tx_ring->tx_buf[tx_ring->next_to_use]; first->skb = skb; first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); first->gso_segs =1 ;
@@ -2365,6 +2366,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) out_drop:ice_trace (xmit_frame_ring_drop, tx_ring, skb);dev_kfree_skb_any (skb); + first->skb =NULL ;return NETDEV_TX_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1078/1887 erofs: unify lcn as u64 for 32-bit platforms
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit 2d8c7edcb661812249469f4a5b62e9339118846f ]
As sashiko reported [1], lcn was typed as unsigned long (or unsigned int sometimes), which is only 32 bits wide on 32-bit platforms, which causes (lcn << lclusterbits) to be truncated at 4 GiB.
In order to consolidate the logic, just use u64 consistently around the codebase.
[1] https://sashiko.dev/r/20260420034612.1899973-1-hsiangkao%40linux.alibaba.com
--- fs/erofs/zmap.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
fs/erofs/zmap.c +9 -9
@@ -30,7 +30,7 @@ struct z_erofs_maprecorder {struct erofs_map_blocks *map;void *kaddr; -unsigned long lcn; +u64 lcn;/* compression extent information gathered */ u8 type, headtype;u16 clusterofs;
@@ -41,7 +41,7 @@ struct z_erofs_maprecorder { };static int legacy_load_cluster_from_disk (struct z_erofs_maprecorder *m, -unsigned long lcn) +u64 lcn) {struct inode *const inode = m->inode;struct erofs_inode *const vi =EROFS_I (inode);
@@ -245,7 +245,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, }static int compacted_load_cluster_from_disk (struct z_erofs_maprecorder *m, -unsigned long lcn,bool lookahead) +u64 lcn,bool lookahead) {struct inode *const inode = m->inode;struct erofs_inode *const vi =EROFS_I (inode);
@@ -296,7 +296,7 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, }static int z_erofs_load_cluster_from_disk (struct z_erofs_maprecorder *m, -unsigned int lcn,bool lookahead) +u64 lcn,bool lookahead) {const unsigned int datamode =EROFS_I (m->inode)->datalayout;
@@ -316,7 +316,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,const unsigned int lclusterbits = vi->z_logical_clusterbits;while (m->lcn >= lookback_distance) { -unsigned long lcn = m->lcn - lookback_distance; +u64 lcn = m->lcn - lookback_distance;int err;/* load extent head logical cluster if needed */
@@ -343,7 +343,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,return 0 ;default :erofs_err (m->inode->i_sb, -"unknown type %u @ lcn %lu of nid %llu" , +"unknown type %u @ lcn %llu of nid %llu" , m->type, lcn, vi->nid);DBG_BUGON (1 );return -EOPNOTSUPP ;
@@ -363,7 +363,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,struct erofs_inode *const vi =EROFS_I (m->inode);struct erofs_map_blocks *const map = m->map;const unsigned int lclusterbits = vi->z_logical_clusterbits; -unsigned long lcn; +u64 lcn;int err; DBG_BUGON(m->type != Z_EROFS_LCLUSTER_TYPE_PLAIN &&
@@ -416,7 +416,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, fallthrough;default :erofs_err (m->inode->i_sb, -"cannot found CBLKCNT @ lcn %lu of nid %llu" , +"cannot found CBLKCNT @ lcn %llu of nid %llu" , lcn, vi->nid);DBG_BUGON (1 );return -EFSCORRUPTED ;
@@ -426,7 +426,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,return 0 ; err_bonus_cblkcnt:erofs_err (m->inode->i_sb, -"bogus CBLKCNT @ lcn %lu of nid %llu" , +"bogus CBLKCNT @ lcn %llu of nid %llu" , lcn, vi->nid);DBG_BUGON (1 );return -EFSCORRUPTED ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1079/1887 f2fs: fix data loss caused by incorrect use of nat_entry flag
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <[email protected]>
[ Upstream commit 238e14eb7226f883b72caccd2d37bf5707df066b ]
Data loss can occur when fsync is performed on a newly created file (before any checkpoint has been written) concurrently with a checkpoint operation. The scenario is as follows:
create & write & fsync 'file A' write checkpoint
- f2fs_do_sync_file // inline inode
- f2fs_write_inode // inode folio is dirty
- f2fs_write_checkpoint
- f2fs_flush_merged_writes
- f2fs_sync_node_pages
- f2fs_flush_nat_entries
- f2fs_fsync_node_pages // no dirty node
- f2fs_need_inode_block_update // return false
SPO and lost 'file A'
f2fs_flush_nat_entries() sets the IS_CHECKPOINTED and HAS_LAST_FSYNC flags for the nat_entry, but this does not mean that the checkpoint has actually completed successfully. However, f2fs_need_inode_block_update() checks these flags and incorrectly assumes that the checkpoint has finished.
The root cause is that the semantics of IS_CHECKPOINTED and HAS_LAST_FSYNC are only guaranteed after the checkpoint write fully completes.
This patch modifies f2fs_need_inode_block_update() to acquire the sbi->node_write lock before reading the nat_entry flags, ensuring that once IS_CHECKPOINTED and HAS_LAST_FSYNC are observed to be set, the checkpoint operation has already completed.
--- fs/f2fs/node.c | 2 ++ 1 file changed, 2 insertions(+)
fs/f2fs/node.c +2 -0
@@ -417,6 +417,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)struct nat_entry *e;bool need_update = true; +f2fs_down_read (&sbi->node_write);f2fs_down_read (&nm_i->nat_tree_lock); e =__lookup_nat_cache (nm_i, ino); if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
@@ -424,6 +425,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino) get_nat_flag(e, HAS_FSYNCED_INODE))) need_update = false;f2fs_up_read (&nm_i->nat_tree_lock); +f2fs_up_read (&sbi->node_write);return need_update; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1080/1887 f2fs: avoid reading already updated pages during GC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianan Huang <[email protected]>
[ Upstream commit 570e2ccc7cb35fe720106964e65060602d3d2ac4 ]
We found the following issue during fuzz testing:
page: refcount:3 mapcount:0 mapping:00000000b6e89c65 index:0x18b2dc pfn:0x161ba9 memcg:f8ffff800e269c00 aops:f2fs_meta_aops ino:2 flags: 0x52880000000080a9(locked|waiters|uptodate|lru|private|zone=1|kasantag=0x4a) raw: 52880000000080a9 fffffffec6e17588 fffffffec0ccc088 a7ffff8067063618 raw: 000000000018b2dc 0000000000000009 00000003ffffffff f8ffff800e269c00 page dumped because: VM_BUG_ON_FOLIO(folio_test_uptodate(folio)) page_owner tracks the page as allocated post_alloc_hook+0x58c/0x5ec prep_new_page+0x34/0x284 get_page_from_freelist+0x2dcc/0x2e8c __alloc_pages_noprof+0x280/0x76c __folio_alloc_noprof+0x18/0xac __filemap_get_folio+0x6bc/0xdc4 pagecache_get_page+0x3c/0x104 do_garbage_collect+0x5c78/0x77a4 f2fs_gc+0xd74/0x25f0 gc_thread_func+0xb28/0x2930 kthread+0x464/0x5d8 ret_from_fork+0x10/0x20 ------------[ cut here ]------------ kernel BUG at mm/filemap.c:1563! folio_end_read+0x140/0x168 f2fs_finish_read_bio+0x5c4/0xb80 f2fs_read_end_io+0x64c/0x708 bio_endio+0x85c/0x8c0 blk_update_request+0x690/0x127c scsi_end_request+0x9c/0xb8c scsi_io_completion+0xf0/0x250 scsi_finish_command+0x430/0x45c scsi_complete+0x178/0x6d4 blk_mq_complete_request+0xcc/0x104 scsi_done_internal+0x214/0x454 scsi_done+0x24/0x34
which is similar to the problem reported by syzbot:
https://syzkaller.appspot.com/bug?extid=3686758660f980b402dc
This case is consistent with the description in commit 9bf1a3f ("f2fs: avoid GC causing encrypted file corrupted"):
Page 1 is moved from blkaddr A to blkaddr B by move_data_block, and after being written it is marked as uptodate. Then, Page 1 is moved from blkaddr B to blkaddr C, VM_BUG_ON_FOLIO was triggered in the endio initiated by ra_data_block.
There is no need to read Page 1 again from blkaddr B, since it has already been updated. Therefore, avoid initiating I/O in this case.
--- fs/f2fs/gc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/f2fs/gc.c +4 -1
@@ -1183,7 +1183,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index) .in_list = 0, .retry = 0, }; -int err; +int err =0 ; page =f2fs_grab_cache_page (mapping, index, true);if (!page)
@@ -1237,6 +1237,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index) goto put_page; } +if (PageUptodate (fio.encrypted_page)) + goto put_encrypted_page; + err =f2fs_submit_page_bio (&fio);if (err) goto put_encrypted_page;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1081/1887 greybus: raw: fix use-after-free on cdev close
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Riégel <[email protected]>
[ Upstream commit 983cc2c7efbce04ecbf6328448d895044dd6ab31 ]
This addresses a use-after-free bug when a raw bundle is disconnected but its chardev is still opened by an application. When the application releases the cdev, it causes the following panic when init on free is enabled (CONFIG_INIT_ON_FREE_DEFAULT_ON=y):
refcount_t: underflow; use-after-free.
WARNING: CPU: 0 PID: 139 at lib/refcount.c:28 refcount_warn_saturate+0xd0/0x130
...
Call Trace:
<TASK>
cdev_put+0x18/0x30
__fput+0x255/0x2a0
__x64_sys_close+0x3d/0x80
do_syscall_64+0xa4/0x290
entry_SYSCALL_64_after_hwframe+0x77/0x7fThe cdev is contained in the "gb_raw" structure, which is freed in the disconnect operation. When the cdev is released at a later time, cdev_put gets an address that points to freed memory.
To fix this use-after-free, convert the struct device from a pointer to being embedded, that makes the lifetime of the cdev and of this device the same. Then, use cdev_device_add, which guarantees that the device won't be released until all references to the cdev have been released. Finally, delegate the freeing of the structure to the device release function, instead of freeing immediately in the disconnect callback.
--- drivers/staging/greybus/raw.c | 67 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 34 deletions(-)
drivers/staging/greybus/raw.c +33 -34
@@ -21,9 +21,8 @@ struct gb_raw {struct list_head list;int list_data;struct mutex list_lock; -dev_t dev;struct cdev cdev; -struct device *device; +struct device dev; };struct raw_data {
@@ -145,6 +144,15 @@ static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)return retval; } +static void raw_dev_release (struct device *dev) +{ + struct gb_raw *raw = container_of(dev, struct gb_raw, dev); + +ida_free (&minors,MINOR (raw->dev.devt)); + +kfree (raw); +} +static int gb_raw_probe (struct gb_bundle *bundle,const struct greybus_bundle_id *id) {
@@ -161,15 +169,30 @@ static int gb_raw_probe(struct gb_bundle *bundle,if (cport_desc->protocol_id !=GREYBUS_PROTOCOL_RAW )return -ENODEV ; + minor =ida_alloc (&minors,GFP_KERNEL ); +if (minor <0 ) +return minor; + raw =kzalloc (sizeof (*raw),GFP_KERNEL ); -if (!raw) +if (!raw) { +ida_free (&minors, minor);return -ENOMEM ; + } + +device_initialize (&raw->dev); + raw->dev.devt =MKDEV (raw_major, minor); + raw->dev.class = raw_class; + raw->dev.parent = &bundle->dev; + raw->dev.release = raw_dev_release; + retval =dev_set_name (&raw->dev,"gb!raw%d" , minor); +if (retval) + goto error_put_device; connection =gb_connection_create (bundle,le16_to_cpu (cport_desc->id), gb_raw_request_handler);if (IS_ERR (connection)) { retval =PTR_ERR (connection); - goto error_free; + goto error_put_device; }INIT_LIST_HEAD (&raw->list);
@@ -178,46 +201,26 @@ static int gb_raw_probe(struct gb_bundle *bundle, raw->connection = connection;greybus_set_drvdata (bundle, raw); - minor =ida_simple_get (&minors,0 ,0 ,GFP_KERNEL ); -if (minor <0 ) { - retval = minor; - goto error_connection_destroy; - } - - raw->dev =MKDEV (raw_major, minor);cdev_init (&raw->cdev, &raw_fops); retval =gb_connection_enable (connection);if (retval) - goto error_remove_ida; + goto error_connection_destroy; - retval =cdev_add (&raw->cdev, raw->dev,1 ); + retval =cdev_device_add (&raw->cdev, &raw->dev);if (retval) goto error_connection_disable; - raw->device =device_create (raw_class, &connection->bundle->dev, - raw->dev, raw,"gb!raw%d" , minor); -if (IS_ERR (raw->device)) { - retval =PTR_ERR (raw->device); - goto error_del_cdev; - } -return 0 ; -error_del_cdev: -cdev_del (&raw->cdev); - error_connection_disable:gb_connection_disable (connection); -error_remove_ida: -ida_simple_remove (&minors, minor); - error_connection_destroy:gb_connection_destroy (connection); -error_free: -kfree (raw); +error_put_device: +put_device (&raw->dev);return retval; }
@@ -228,11 +231,8 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)struct raw_data *raw_data;struct raw_data *temp; -// FIXME - handle removing a connection when the char device node is open. -device_destroy (raw_class, raw->dev); -cdev_del (&raw->cdev); +cdev_device_del (&raw->cdev, &raw->dev);gb_connection_disable (connection); -ida_simple_remove (&minors,MINOR (raw->dev));gb_connection_destroy (connection);mutex_lock (&raw->list_lock);
@@ -241,8 +241,7 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)kfree (raw_data); }mutex_unlock (&raw->list_lock); - -kfree (raw); +put_device (&raw->dev); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1082/1887 fs/ntfs3: fix missing run load for vcn0 in attr_data_get_block_locked()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
[ Upstream commit d7ea8495fd307b58f8867acd81a1b40075b1d3ba ]
When a compressed or sparse attribute has its clusters frame-aligned, vcn is rounded down to the frame start using cmask, which can result in vcn != vcn0. In this case, vcn and vcn0 may reside in different attribute segments.
The code already handles the case where vcn is in a different segment by loading its runs before allocation. However, it fails to load runs for vcn0 when vcn0 resides in a different segment than vcn. This causes run_lookup_entry() to return SPARSE_LCN for vcn0 since its segment was never loaded into the in-memory run list, triggering the WARN_ON(1).
Fix this by adding a missing check for vcn0 after the existing vcn segment check. If vcn0 falls outside the current segment range [svcn, evcn1), find and load the attribute segment containing vcn0 before performing the run lookup.
The following scenario triggers the bug:
attr_data_get_block_locked()
vcn = vcn0 & cmask <- vcn != vcn0 after frame alignment
load runs for vcn segment <- vcn0 segment not loaded! attr_allocate_clusters() <- allocation succeeds
run_lookup_entry(vcn0) <- vcn0 not in run -> SPARSE_LCN
WARN_ON(1) <- bug fires here!
--- fs/ntfs3/attrib.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/ntfs3/attrib.c +16 -0
@@ -1048,6 +1048,22 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,if (err) goto out; } + +if (vcn0 < svcn || evcn1 <= vcn0) { +struct ATTRIB *attr2; +struct ATTR_LIST_ENTRY *le2 = le_b; +struct mft_inode *mi2; + + attr2 =ni_find_attr (ni, attr_b, &le2,ATTR_DATA ,NULL , +0 , &vcn0, &mi2); +if (!attr2) { + err = -EINVAL ; + goto out; + } + err =attr_load_runs (attr2, ni, run,NULL ); +if (err) + goto out; + } }if (vcn + to_alloc > asize)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1083/1887 iommu/amd: Fix clone_alias() to use the original devices devid
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasant Hegde <[email protected]>
[ Upstream commit faad224fe0f0857a04ff2eb3c90f0de57f47d0f3 ]
Currently clone_alias() assumes first argument (pdev) is always the original device pointer. This function is called by pci_for_each_dma_alias() which based on topology decides to send original or alias device details in first argument.
This meant that the source devid used to look up and copy the DTE may be incorrect, leading to wrong or stale DTE entries being propagated to alias device.
Fix this by passing the original pdev as the opaque data argument to both the direct clone_alias() call and pci_for_each_dma_alias(). Inside clone_alias(), retrieve the original device from data and compute devid from it.
--- drivers/iommu/amd/iommu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/iommu/amd/iommu.c +4 -3
@@ -217,10 +217,11 @@ static struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devidreturn NULL ; } -static int clone_alias (struct pci_dev *pdev,u16 alias,void *data) +static int clone_alias (struct pci_dev *pdev_origin,u16 alias,void *data) {struct amd_iommu *iommu;struct dev_table_entry *dev_table; +struct pci_dev *pdev = data;u16 devid =pci_dev_id (pdev);if (devid == alias)
@@ -252,9 +253,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev)* part of the PCI DMA aliases if it's bus differs * from the original device. */ -clone_alias (pdev, iommu->pci_seg->alias_table[pci_dev_id (pdev)],NULL ); +clone_alias (pdev, iommu->pci_seg->alias_table[pci_dev_id (pdev)], pdev); -pci_for_each_dma_alias (pdev, clone_alias,NULL ); +pci_for_each_dma_alias (pdev, clone_alias, pdev); }static void setup_aliases (struct amd_iommu *iommu,struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1084/1887 sctp: disable BH before calling udp_tunnel_xmit_skb()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 2cd7e6971fc2787408ceef17906ea152791448cf ]
udp_tunnel_xmit_skb() / udp_tunnel6_xmit_skb() are expected to run with BH disabled. After commit 6f1a9140ecda ("add xmit recursion limit to tunnel xmit functions"), on the path:
udp(6)_tunnel_xmit_skb() -> ip(6)tunnel_xmit()
dev_xmit_recursion_inc()/dec() must stay balanced on the same CPU.
Without local_bh_disable(), the context may move between CPUs, which can break the inc/dec pairing. This may lead to incorrect recursion level detection and cause packets to be dropped in ip(6)_tunnel_xmit() or __dev_queue_xmit().
Fix it by disabling BH around both IPv4 and IPv6 SCTP UDP xmit paths.
In my testing, after enabling the SCTP over UDP:
# ip net exec ha sysctl -w net.sctp.udp_port=9899 # ip net exec ha sysctl -w net.sctp.encap_port=9899 # ip net exec hb sysctl -w net.sctp.udp_port=9899 # ip net exec hb sysctl -w net.sctp.encap_port=9899
# ip net exec ha iperf3 -s
- without this patch:
# ip net exec hb iperf3 -c 192.168.0.1 --sctp [ 5] 0.00-10.00 sec 37.2 MBytes 31.2 Mbits/sec sender [ 5] 0.00-10.00 sec 37.1 MBytes 31.1 Mbits/sec receiver
- with this patch:
# ip net exec hb iperf3 -c 192.168.0.1 --sctp [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec sender [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec receiver
--- net/sctp/ipv6.c | 10 +++++++--- net/sctp/protocol.c | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-)
net/sctp/ipv6.c +7 -3
@@ -227,6 +227,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)struct ipv6_pinfo *np =inet6_sk (sk);__u8 tclass = np->tclass;__be32 label; +int err;pr_debug ("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n" , __func__, skb, skb->len, &fl6->saddr, &fl6->daddr);
@@ -263,9 +264,12 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)skb_set_inner_ipproto (skb,IPPROTO_SCTP ); label =ip6_make_flowlabel (sock_net (sk), skb, fl6->flowlabel, true, fl6); -return udp_tunnel6_xmit_skb (dst, sk, skb,NULL , &fl6->saddr, - &fl6->daddr, tclass,ip6_dst_hoplimit (dst), - label,sctp_sk (sk)->udp_port, t->encap_port, false); +local_bh_disable (); + err =udp_tunnel6_xmit_skb (dst, sk, skb,NULL , &fl6->saddr, + &fl6->daddr, tclass,ip6_dst_hoplimit (dst), + label,sctp_sk (sk)->udp_port, t->encap_port, false); +local_bh_enable (); +return err; }/* Returns the dst cache entry for the given source and destination ip
net/sctp/protocol.c +2 -0
@@ -1078,9 +1078,11 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)skb_reset_inner_mac_header (skb);skb_reset_inner_transport_header (skb);skb_set_inner_ipproto (skb,IPPROTO_SCTP ); +local_bh_disable ();udp_tunnel_xmit_skb ((struct rtable *)dst, sk, skb, fl4->saddr, fl4->daddr, dscp,ip4_dst_hoplimit (dst), df,sctp_sk (sk)->udp_port, t->encap_port, false, false); +local_bh_enable ();return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1085/1887 bpf: Fix OOB in pcpu_init_value
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lang Xu <[email protected]>
[ Upstream commit 576afddfee8d1108ee299bf10f581593540d1a36 ]
An out-of-bounds read occurs when copying element from a BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the same value_size that is not rounded up to 8 bytes.
The issue happens when:
1. A CGROUP_STORAGE map is created with value_size not aligned to 8 bytes (e.g., 4 bytes)
2. A pcpu map is created with the same value_size (e.g., 4 bytes)
3. Update element in 2 with data in 1
pcpu_init_value assumes that all sources are rounded up to 8 bytes, and invokes copy_map_value_long to make a data copy, However, the assumption doesn't stand since there are some cases where the source may not be rounded up to 8 bytes, e.g., CGROUP_STORAGE, skb->data. the verifier verifies exactly the size that the source claims, not the size rounded up to 8 bytes by kernel, an OOB happens when the source has only 4 bytes while the copy size(4) is rounded up to 8.
--- kernel/bpf/hashtab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/bpf/hashtab.c +2 -2
@@ -963,8 +963,8 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,for_each_possible_cpu (cpu) {if (cpu == current_cpu) -bpf_long_memcpy (per_cpu_ptr (pptr, cpu), value, - size); +memcpy (per_cpu_ptr (pptr, cpu), value, + htab->map.value_size);else memset (per_cpu_ptr (pptr, cpu),0 , size); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1086/1887 bpf: Fix RCU stall in bpf_fd_array_map_clear()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit 4406942e65ca128c56c67443832988873c21d2e9 ]
Add a missing cond_resched() in bpf_fd_array_map_clear() loop.
For PROG_ARRAY maps with many entries this loop calls prog_array_map_poke_run() per entry which can be expensive, and without yielding this can cause RCU stalls under load:
rcu: Stack dump where RCU GP kthread last ran:
CPU: 0 UID: 0 PID: 30932 Comm: kworker/0:2 Not tainted 6.14.0-13195-g967e8def1100 #2 PREEMPT(undef) Workqueue: events prog_array_map_clear_deferred RIP: 0010:write_comp_data+0x38/0x90 kernel/kcov.c:246 Call Trace: <TASK> prog_array_map_poke_run+0x77/0x380 kernel/bpf/arraymap.c:1096 __fd_array_map_delete_elem+0x197/0x310 kernel/bpf/arraymap.c:925 bpf_fd_array_map_clear kernel/bpf/arraymap.c:1000 [inline] prog_array_map_clear_deferred+0x119/0x1b0 kernel/bpf/arraymap.c:1141 process_one_work+0x898/0x19d0 kernel/workqueue.c:3238 process_scheduled_works kernel/workqueue.c:3319 [inline] worker_thread+0x770/0x10b0 kernel/workqueue.c:3400 kthread+0x465/0x880 kernel/kthread.c:464 ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:153 ret_from_fork_asm+0x19/0x30 arch/x86/entry/entry_64.S:245 </TASK>
--- kernel/bpf/arraymap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/bpf/arraymap.c +3 -1
@@ -940,8 +940,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map) struct bpf_array *array = container_of(map, struct bpf_array, map);int i; -for (i =0 ; i < array->map.max_entries; i++) +for (i =0 ; i < array->map.max_entries; i++) {fd_array_map_delete_elem (map, &i); +cond_resched (); + } } static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1087/1887 wifi: mt76: Fix memory leak after mt76_connac_mcu_alloc_sta_req()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
[ Upstream commit c41075ce8cf05ed8c0e7b7efef000dce548ffc42 ]
mt76_connac_mcu_alloc_sta_req() allocates an skb which is expected to be freed eventually by mt76_mcu_skb_send_msg(). However, currently if an intermediate function fails before sending, the allocated skb is leaked.
Specifically, mt76_connac_mcu_sta_wed_update() and mt76_connac_mcu_sta_key_tlv() may fail, leading to an immediate memory leak in the error path.
Fix this by explicitly freeing the skb in these error paths. Commit 7c0f63fe37a5 ("wifi: mt76: mt7996: fix memory leak on mt7996_mcu_sta_key_tlv error") made a similar change.
Compile tested only. Issue found using a prototype static analysis tool and code review.
--- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +3 -1
@@ -2652,8 +2652,10 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,return PTR_ERR (skb); ret =mt76_connac_mcu_sta_key_tlv (sta_key_conf, skb, key, cmd); -if (ret) +if (ret) { +dev_kfree_skb (skb);return ret; + }return mt76_mcu_skb_send_msg (dev, skb, mcu_cmd, true); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1088/1887 powerpc/64s: Fix unmap race with PMD migration entries
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ritesh Harjani (IBM) <[email protected]>
[ Upstream commit bbcbf045d6c778e82b47a35fc8728387708e9a3d ]
The following race is possible with migration swap entries or device-private THP entries. e.g. when move_pages is called on a PMD THP page, then there maybe an intermediate state, where PMD entry acts as a migration swap entry (pmd_present() is true). Then if an munmap happens at the same time, then this VM_BUG_ON() can happen in pmdp_huge_get_and_clear_full().
This patch fixes that.
Thread A: move_pages() syscall
add_folio_for_migration()
mmap_read_lock(mm)
folio_isolate_lru(folio)
mmap_read_unlock(mm)
do_move_pages_to_node()
migrate_pages()
try_to_migrate_one()
spin_lock(ptl)
set_pmd_migration_entry()
pmdp_invalidate() # PMD: _PAGE_INVALID | _PAGE_PTE | pfn
set_pmd_at() # PMD: migration swap entry (pmd_present=0)
spin_unlock(ptl)
[page copy phase] # <--- RACE WINDOW -->
Thread B: munmap()
mmap_write_downgrade(mm)
unmap_vmas() -> zap_pmd_range()
zap_huge_pmd()
__pmd_trans_huge_lock()
pmd_is_huge(): # !pmd_present && !pmd_none -> TRUE (swap entry)
pmd_lock() -> # spin_lock(ptl), waits for Thread A to release ptl
pmdp_huge_get_and_clear_full()
VM_BUG_ON(!pmd_present(*pmdp)) # HITS![ 287.738700][ T1867] ------------[ cut here ]------------
[ 287.743843][ T1867] kernel BUG at arch/powerpc/mm/book3s64/pgtable.c:187!
cpu 0x0: Vector: 700 (Program Check) at [c00000044037f4f0]
pc: c000000000094ca4: pmdp_huge_get_and_clear_full+0x6c/0x23c
lr: c000000000645dec: zap_huge_pmd+0xb0/0x868
sp: c00000044037f790
msr: 800000000282b033
current = 0xc0000004032c1a00
paca = 0xc000000004fe0000 irqmask: 0x03 irq_happened: 0x09
pid = 1867, comm = a.outkernel BUG at :187!
Linux version 6.19.0-12136-g14360d4f917c-dirty (powerpc64le-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #27 SMP PREEMPT Sun Feb 22 10:38:56 IST 2026 enter ? for help
[link register ] c000000000645dec zap_huge_pmd+0xb0/0x868
[c00000044037f790] c00000044037f7d0 (unreliable)
[c00000044037f7d0] c000000000645dcc zap_huge_pmd+0x90/0x868
[c00000044037f840] c0000000005724cc unmap_page_range+0x176c/0x1f40
[c00000044037fa00] c000000000572ea0 unmap_vmas+0xb0/0x1d8
[c00000044037fa90] c0000000005af254 unmap_region+0xb4/0x128
[c00000044037fb50] c0000000005af400 vms_complete_munmap_vmas+0x138/0x310
[c00000044037fbe0] c0000000005b0f1c do_vmi_align_munmap+0x1ec/0x238
[c00000044037fd30] c0000000005b3688 __vm_munmap+0x170/0x1f8
[c00000044037fdf0] c000000000587f74 sys_munmap+0x2c/0x40
[c00000044037fe10] c000000000032668 system_call_exception+0x128/0x350
[c00000044037fe50] c00000000000d05c system_call_vectored_common+0x15c/0x2ec
---- Exception: 3000 (System Call Vectored) at 0000000010064a2c
SP (7fff9b1ee9c0) is in userspace
0:mon> zh
commit a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages"), enabled migration for device-private PMD entries. Hence this is one
other path where this warning could get trigger from.
------------[ cut here ]------------ WARNING: arch/powerpc/mm/book3s64/hash_pgtable.c:199 at hash__pmd_hugepage_update+0x48/0x284, CPU#3: hmm-tests/1905 Modules linked in: test_hmm CPU: 3 UID: 0 PID: 1905 Comm: hmm-tests Tainted: G B W L N 7.0.0-rc1-01438-g7e2f0ee7581c #21 PREEMPT Tainted: [B]=BAD_PAGE, [W]=WARN, [L]=SOFTLOCKUP, [N]=TEST Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries NIP [c000000000096b70] hash__pmd_hugepage_update+0x48/0x284 LR [c000000000096e7c] hash__pmdp_huge_get_and_clear+0xd0/0xd4 Call Trace: [c000000604707670] [c000000004e102b8] 0xc000000004e102b8 (unreliable) [c000000604707700] [c00000000064ec3c] set_pmd_migration_entry+0x414/0x498 [c000000604707760] [c00000000063e5a4] migrate_vma_collect_pmd+0x12e8/0x16c4 [c000000604707890] [c00000000059282c] walk_pgd_range+0x7fc/0xd2c [c000000604707990] [c000000000592e40] __walk_page_range+0xe4/0x2ac [c000000604707a10] [c000000000593534] walk_page_range_mm_unsafe+0x204/0x2a4 [c000000604707ab0] [c00000000063af10] migrate_vma_setup+0x1dc/0x2e8 [c000000604707b10] [c008000006a21838] dmirror_migrate_to_system.constprop.0+0x210/0x4b0 [test_hmm] [c000000604707c30] [c008000006a245b0] dmirror_fops_unlocked_ioctl+0x454/0xa5c [test_hmm] [c000000604707d20] [c0000000006aab84] sys_ioctl+0x4ec/0x1178 [c000000604707e10] [c0000000000326a8] system_call_exception+0x128/0x350 [c000000604707e50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec ---- interrupt: 3000 at 0x7fffbe44f50c
--- arch/powerpc/include/asm/book3s/64/pgtable.h | 16 ++++++++++++++++ arch/powerpc/mm/book3s64/pgtable.c | 13 +++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +16 -0
@@ -1285,6 +1285,22 @@ extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,static inline pmd_t pmdp_huge_get_and_clear (struct mm_struct *mm,unsigned long addr,pmd_t *pmdp) { +pmd_t old_pmd; + +/* +* Non-present PMDs can be migration entries or device-private THP +* entries. This can happen at 2 places: +* - When the address space is being unmapped zap_huge_pmd(), and we +* encounter non-present pmds. +* - migrate_vma_collect_huge_pmd() could calls this during migration +* of device-private pmd entries. +*/ +if (!pmd_present (*pmdp)) { + old_pmd =READ_ONCE (*pmdp); +pmd_clear (pmdp); +return old_pmd; + } +if (radix_enabled ())return radix__pmdp_huge_get_and_clear (mm, addr, pmdp);return hash__pmdp_huge_get_and_clear (mm, addr, pmdp);
arch/powerpc/mm/book3s64/pgtable.c +9 -4
@@ -134,16 +134,21 @@ pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp, int full) { pmd_t pmd; +bool was_present =pmd_present (*pmdp); +VM_BUG_ON (addr & ~HPAGE_PMD_MASK ); -VM_BUG_ON ((pmd_present (*pmdp) && !pmd_trans_huge (*pmdp) && - !pmd_devmap (*pmdp)) || !pmd_present (*pmdp)); +VM_BUG_ON (was_present && !pmd_trans_huge (*pmdp) && !pmd_devmap (*pmdp)); +/* +* Check pmdp_huge_get_and_clear() for non-present pmd case. +*/ pmd =pmdp_huge_get_and_clear (vma->vm_mm, addr, pmdp);/* * if it not a fullmm flush, then we can possibly end up converting * this PMD pte entry to a regular level 0 PTE by a parallel page fault. -* Make sure we flush the tlb in this case. +* Make sure we flush the tlb in this case. TLB flush not needed for +* non-present case. */ -if (!full) +if (was_present && !full)flush_pmd_tlb_range (vma, addr, addr +HPAGE_PMD_SIZE );return pmd; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1089/1887 btrfs: fix deadlock between reflink and transaction commit when using flushoncommit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <[email protected]>
[ Upstream commit b48c980b6a7e409050bb3067165db31cc6205e3e ]
When using the flushoncommit mount option, we can have a deadlock between a transaction commit and a reflink operation that copied an inline extent to an offset beyond the current i_size of the destination node.
The deadlock happens like this:
1) Task A clones an inline extent from inode X to an offset of inode Y that is beyond Y's current i_size. This means we copied the inline extent's data to a folio of inode Y that is beyond its EOF, using a call to copy_inline_to_page();
2) Task B starts a transaction commit and calls btrfs_start_delalloc_flush() to flush delalloc;
3) The delalloc flushing sees the new dirty folio of inode Y and when it attempts to flush it, it ends up at extent_writepage() and sees that the offset of the folio is beyond the i_size of inode Y, so it attempts to invalidate the folio by calling folio_invalidate(), which ends up at btrfs' folio invalidate callback - btrfs_invalidate_folio(). There it tries to lock the folio's range in inode Y's extent io tree, but it blocks since it's currently locked by task A - during a reflink we lock the inodes and the source and destination ranges after flushing all delalloc and waiting for ordered extent completion - after that we don't expect to have dirty folios in the ranges, the exception is if we have to copy an inline extent's data (because the destination offset is not zero);
4) Task A then attempts to start a transaction to update the inode item, and then it's blocked since the current transaction is in the TRANS_STATE_COMMIT_START state. Therefore task A has to wait for the current transaction to become unblocked (its state >= TRANS_STATE_UNBLOCKED).
So task A is waiting for the transaction commit done by task B, and the later waiting on the extent lock of inode Y that is currently held by task A.
Syzbot recently reported this with the following stack traces:
INFO: task kworker/u8:7:1053 blocked for more than 143 seconds.
Not tainted syzkaller #0
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/u8:7 state:D stack:23520 pid:1053 tgid:1053 ppid:2 task_flags:0x4208060 flags:0x00080000
Workqueue: writeback wb_workfn (flush-btrfs-46)
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5298 [inline]
__schedule+0x1553/0x5240 kernel/sched/core.c:6911
__schedule_loop kernel/sched/core.c:6993 [inline]
schedule+0x164/0x360 kernel/sched/core.c:7008
wait_extent_bit fs/btrfs/extent-io-tree.c:811 [inline]
btrfs_lock_extent_bits+0x59c/0x700 fs/btrfs/extent-io-tree.c:1914
btrfs_lock_extent fs/btrfs/extent-io-tree.h:152 [inline]
btrfs_invalidate_folio+0x43d/0xc40 fs/btrfs/inode.c:7704
extent_writepage fs/btrfs/extent_io.c:1852 [inline]
extent_write_cache_pages fs/btrfs/extent_io.c:2580 [inline]
btrfs_writepages+0x12ff/0x2440 fs/btrfs/extent_io.c:2713
do_writepages+0x32e/0x550 mm/page-writeback.c:2554
__writeback_single_inode+0x133/0x11a0 fs/fs-writeback.c:1750
writeback_sb_inodes+0x995/0x19d0 fs/fs-writeback.c:2042
wb_writeback+0x456/0xb70 fs/fs-writeback.c:2227
wb_do_writeback fs/fs-writeback.c:2374 [inline]
wb_workfn+0x41a/0xf60 fs/fs-writeback.c:2414
process_one_work kernel/workqueue.c:3276 [inline]
process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359
worker_thread+0xa53/0xfc0 kernel/workqueue.c:3440
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
INFO: task syz.4.64:6910 blocked for more than 143 seconds.
Not tainted syzkaller #0
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:syz.4.64 state:D stack:22752 pid:6910 tgid:6905 ppid:5944 task_flags:0x400140 flags:0x00080002
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5298 [inline]
__schedule+0x1553/0x5240 kernel/sched/core.c:6911
__schedule_loop kernel/sched/core.c:6993 [inline]
schedule+0x164/0x360 kernel/sched/core.c:7008
wait_current_trans+0x39f/0x590 fs/btrfs/transaction.c:535
start_transaction+0x6a7/0x1650 fs/btrfs/transaction.c:705
clone_copy_inline_extent fs/btrfs/reflink.c:299 [inline]
btrfs_clone+0x128a/0x24d0 fs/btrfs/reflink.c:529
btrfs_clone_files+0x271/0x3f0 fs/btrfs/reflink.c:750
btrfs_remap_file_range+0x76b/0x1320 fs/btrfs/reflink.c:903
vfs_copy_file_range+0xda7/0x1390 fs/read_write.c:1600
__do_sys_copy_file_range fs/read_write.c:1683 [inline]
__se_sys_copy_file_range+0x2fb/0x480 fs/read_write.c:1650
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:0x7f5f73afc799
RSP: 002b:00007f5f7315e028 EFLAGS: 00000246 ORIG_RAX: 0000000000000146
RAX: ffffffffffffffda RBX: 00007f5f73d75fa0 RCX: 00007f5f73afc799
RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000005
RBP: 00007f5f73b92c99 R08: 0000000000000863 R09: 0000000000000000
R10: 00002000000000c0 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f5f73d76038 R14: 00007f5f73d75fa0 R15: 00007fff138a5068
</TASK>
INFO: task syz.4.64:6975 blocked for more than 143 seconds.
Not tainted syzkaller #0
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:syz.4.64 state:D stack:24736 pid:6975 tgid:6905 ppid:5944 task_flags:0x400040 flags:0x00080002
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5298 [inline]
__schedule+0x1553/0x5240 kernel/sched/core.c:6911
__schedule_loop kernel/sched/core.c:6993 [inline]
schedule+0x164/0x360 kernel/sched/core.c:7008
wb_wait_for_completion+0x3e8/0x790 fs/fs-writeback.c:227
__writeback_inodes_sb_nr+0x24c/0x2d0 fs/fs-writeback.c:2838
try_to_writeback_inodes_sb+0x9a/0xc0 fs/fs-writeback.c:2886
btrfs_start_delalloc_flush fs/btrfs/transaction.c:2175 [inline]
btrfs_commit_transaction+0x82e/0x31a0 fs/btrfs/transaction.c:2364
btrfs_ioctl+0xca7/0xd00 fs/btrfs/ioctl.c:5206
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
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:0x7f5f73afc799
RSP: 002b:00007f5f7313d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f5f73d76090 RCX: 00007f5f73afc799
RDX: 0000000000000000 RSI: 0000000000009408 RDI: 0000000000000004
RBP: 00007f5f73b92c99 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f5f73d76128 R14: 00007f5f73d76090 R15: 00007fff138a5068
</TASK>Fix this by updating the i_size of the destination inode of a reflink operation after we copy an inline extent's data to an offset beyond the i_size and before attempting to start a transaction to update the inode's item.
--- fs/btrfs/reflink.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
fs/btrfs/reflink.c +53 -0
@@ -179,6 +179,14 @@ static int clone_copy_inline_extent(struct inode *dst,if (new_key->offset >0 ) { ret =copy_inline_to_page (BTRFS_I (dst), new_key->offset, inline_data, size, datal, comp_type); + +/* +* Increase the i_size before starting a transaction, see the +* comment at the copy_to_page label below. +*/ +if (ret ==0 && new_key->offset + datal >i_size_read (dst)) +i_size_write (dst, new_key->offset + datal); + goto out; }
@@ -312,6 +320,51 @@ static int clone_copy_inline_extent(struct inode *dst, ret =copy_inline_to_page (BTRFS_I (dst), new_key->offset, inline_data, size, datal, comp_type); + +/* +* If we copied the inline extent data to a page/folio beyond the i_size +* of the destination inode, then we need to increase the i_size before +* we start a transaction to update the inode item. This is to prevent a +* deadlock when the flushoncommit mount option is used, which happens +* like this: +* +* 1) Task A clones an inline extent from inode X to an offset of inode +* Y that is beyond Y's current i_size. This means we copied the +* inline extent's data to a folio of inode Y that is beyond its EOF, +* using the call above to copy_inline_to_page(); +* +* 2) Task B starts a transaction commit and calls +* btrfs_start_delalloc_flush() to flush delalloc; +* +* 3) The delalloc flushing sees the new dirty folio of inode Y and when +* it attempts to flush it, it ends up at extent_writepage() and sees +* that the offset of the folio is beyond the i_size of inode Y, so +* it attempts to invalidate the folio by calling folio_invalidate(), +* which ends up at btrfs' folio invalidate callback - +* btrfs_invalidate_folio(). There it tries to lock the folio's range +* in inode Y's extent io tree, but it blocks since it's currently +* locked by task A - during reflink we lock the inodes and the +* source and destination ranges after flushing all delalloc and +* waiting for ordered extent completion - after that we don't expect +* to have dirty folios in the ranges, the exception is if we have to +* copy an inline extent's data (because the destination offset is +* not zero); +* +* 4) Task A then does the 'goto out' below and attempts to start a +* transaction to update the inode item, and then it's blocked since +* the current transaction is in the TRANS_STATE_COMMIT_START state. +* Therefore task A has to wait for the current transaction to become +* unblocked (its state >= TRANS_STATE_UNBLOCKED). +* +* This leads to a deadlock - the task committing the transaction +* waiting for the delalloc flushing which is blocked during folio +* invalidation on the inode's extent lock and the reflink task waiting +* for the current transaction to be unblocked so that it can start a +* a new one to update the inode item (while holding the extent lock). +*/ +if (ret ==0 && new_key->offset + datal >i_size_read (dst)) +i_size_write (dst, new_key->offset + datal); + goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1090/1887 fs/mbcache: cancel shrink work before destroying the cache
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyungJung Joo <[email protected]>
[ Upstream commit d227786ab1119669df4dc333a61510c52047cce4 ]
mb_cache_destroy() calls shrinker_free() and then frees all cache entries and the cache itself, but it does not cancel the pending c_shrink_work work item first.
If mb_cache_entry_create() schedules c_shrink_work via schedule_work() and the work item is still pending or running when mb_cache_destroy() runs, mb_cache_shrink_worker() will access the cache after its memory has been freed, causing a use-after-free.
This is only reachable by a privileged user (root or CAP_SYS_ADMIN) who can trigger the last put of a mounted ext2/ext4/ocfs2 filesystem.
Cancel the work item with cancel_work_sync() before calling shrinker_free(), ensuring the worker has finished and will not be rescheduled before the cache is torn down.
--- fs/mbcache.c | 1 + 1 file changed, 1 insertion(+)
fs/mbcache.c +1 -0
@@ -406,6 +406,7 @@ void mb_cache_destroy(struct mb_cache *cache) {struct mb_cache_entry *entry, *next; +cancel_work_sync (&cache->c_shrink_work);unregister_shrinker (&cache->c_shrink);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1091/1887 sctp: validate embedded INIT chunk and address list lengths in cookie
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 6f4c80a2a7e6d06753b89a578b710a2499a5e62b ]
sctp_unpack_cookie() only checked that the embedded INIT chunk length did not exceed the remaining cookie payload, but did not ensure that the INIT chunk is large enough to contain a complete INIT header.
A malformed COOKIE_ECHO can therefore carry a truncated INIT chunk whose length field is smaller than sizeof(struct sctp_init_chunk). Later, sctp_process_init() accesses INIT parameters unconditionally, which may lead to out-of-bounds reads.
In addition, raw_addr_list_len is not fully validated against the remaining cookie payload. When cookie authentication is disabled, an attacker can supply an oversized raw_addr_list_len and cause sctp_raw_to_bind_addrs() to read beyond the end of the cookie. The address parser also lacks sufficient bounds checks for parameter headers and lengths, allowing malformed address parameters to trigger out-of-bounds reads.
Fix this by:
- requiring the embedded INIT chunk length to be at least sizeof(struct sctp_init_chunk);
- validating that the INIT chunk and raw address list together fit within the cookie payload;
- verifying sufficient data exists for each address parameter header and payload before parsing it.
Note that sctp_verify_init() must be called after sctp_unpack_cookie() and before sctp_process_init() when cookie authentication is disabled. This will be addressed in a separate patch.
--- net/sctp/bind_addr.c | 11 ++++++++++- net/sctp/sm_make_chunk.c | 12 +++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-)
net/sctp/bind_addr.c +10 -1
@@ -275,6 +275,16 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, param = (struct sctp_paramhdr *)raw_addr_list; rawaddr = (union sctp_addr_param *)raw_addr_list; +if (addrs_len <sizeof (*param)) { + retval = -EINVAL ; + goto out_err; + } + len =ntohs (param->length); +if (addrs_len < len) { + retval = -EINVAL ; + goto out_err; + } + af =sctp_get_af_specific (param_type2af (param->type));if (unlikely (!af) || !af->from_addr_param (&addr, rawaddr,htons (port),0 )) {
@@ -291,7 +301,6 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, goto out_err; next: - len =ntohs (param->length); addrs_len -= len; raw_addr_list += len; }
net/sctp/sm_make_chunk.c +11 -1
@@ -1750,8 +1750,9 @@ struct sctp_association *sctp_unpack_cookie(struct sk_buff *skb = chunk->skb;struct sctp_cookie *bear_cookie;__u8 *digest = ep->digest; +struct sctp_chunkhdr *ch; +unsigned int len, chlen;enum sctp_scope scope; -unsigned int len;ktime_t kt;/* Header size is static data prior to the actual cookie, including
@@ -1779,6 +1780,15 @@ struct sctp_association *sctp_unpack_cookie( cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; + ch = (struct sctp_chunkhdr *)(bear_cookie +1 ); + chlen =ntohs (ch->length); +if (chlen <sizeof (struct sctp_init_chunk )) + goto malformed; +if (chlen > len - fixed_size) + goto malformed; +if (bear_cookie->raw_addr_list_len > len - fixed_size - chlen) + goto malformed; +if (!sctp_sk (ep->base.sk)->hmac) goto no_hmac;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1092/1887 net/mlx5e: xsk: Fix DMA and xdp_frame leak on XDP_TX xmit failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <[email protected]>
[ Upstream commit b69004f5a6ad32da84d8aa5b23b9c0caafe6252e ]
In the XSK branch of mlx5e_xmit_xdp_buff(), when sq->xmit_xdp_frame() returns false (e.g. XDPSQ is full), the function returns without unmapping the DMA address or freeing the xdp_frame allocated by xdp_convert_zc_to_xdp_frame(). The xdpi_fifo push only happens on success, so the completion path cannot recover these entries.
With CONFIG_DMA_API_DEBUG=y, the leak surfaces on driver unbind:
DMA-API: pci 0000:08:00.0: device driver has pending DMA allocations while released from device [count=1116]
One of leaked entries details: [device address=0x000000010ffd7028] [size=1534 bytes] [mapped with DMA_TO_DEVICE] [mapped as phy]
WARNING: kernel/dma/debug.c:881 at dma_debug_device_change+0x127/0x180 ... DMA-API: Mapped at: debug_dma_map_phys+0x4b/0xd0 dma_map_phys+0xfd/0x2d0 mlx5e_xdp_handle+0x5ae/0xac0 [mlx5_core] mlx5e_xsk_skb_from_cqe_mpwrq_linear+0xc4/0x170 [mlx5_core] mlx5e_handle_rx_cqe_mpwrq+0xc1/0x290 [mlx5_core]
Add the missing unmap + xdp_return_frame, matching the cleanup already done in mlx5e_xdp_xmit(). has_frags is rejected earlier in this branch, so no per-frag unmap is needed.
--- drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +5 -1
@@ -100,8 +100,12 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, xdpi.frame.dma_addr = dma_addr;if (unlikely (!INDIRECT_CALL_2 (sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, - mlx5e_xmit_xdp_frame, sq, &xdptxd,NULL ,0 ))) + mlx5e_xmit_xdp_frame, sq, &xdptxd,NULL ,0 ))) { +dma_unmap_single (sq->pdev, dma_addr, xdptxd.len, +DMA_TO_DEVICE ); +xdp_return_frame (xdpf);return false; + }mlx5e_xdpi_fifo_push (&sq->db.xdpi_fifo, &xdpi);return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1093/1887 net/mlx5: Add generic getters for other functions caps
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shay Drory <[email protected]>
[ Upstream commit 47d0c500d76c7b1d220c47cd875763fef04eba2e ]
Downstream patch requires to get other function GENERAL2 caps while mlx5_vport_get_other_func_cap() gets only one type of caps (general). Rename it to represent this and introduce a generic implementation of mlx5_vport_get_other_func_cap().
Stable-dep-of: 894e036a24a2 ("net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list")
--- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 6 ++++-- include/linux/mlx5/vport.h | 2 ++ 5 files changed, 11 insertions(+), 5 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +1 -1
@@ -3905,7 +3905,7 @@ static int mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch *esw, u16 vport_num,if (!query_ctx)return -ENOMEM ; - err =mlx5_vport_get_other_func_cap (esw->dev, vport_num, query_ctx); + err =mlx5_vport_get_other_func_general_cap (esw->dev, vport_num, query_ctx);if (err) goto out_free;
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +2 -1
@@ -315,7 +315,8 @@ void mlx5_unload_one_devl_locked(struct mlx5_core_dev *dev, bool suspend);int mlx5_load_one (struct mlx5_core_dev *dev,bool recovery);int mlx5_load_one_devl_locked (struct mlx5_core_dev *dev,bool recovery); -int mlx5_vport_get_other_func_cap (struct mlx5_core_dev *dev,u16 function_id,void *out); +#define mlx5_vport_get_other_func_general_cap (dev, fid, out) \ + mlx5_vport_get_other_func_cap(dev, fid, out, MLX5_CAP_GENERAL)void mlx5_events_work_enqueue (struct mlx5_core_dev *dev,struct work_struct *work);static inline u32 mlx5_sriov_get_vf_total_msix (struct pci_dev *pdev)
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c +2 -1
@@ -4,6 +4,7 @@#include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/mlx5/driver.h> +#include <linux/mlx5/vport.h> #include "mlx5_core.h" #include "mlx5_irq.h" #include "pci_irq.h"
@@ -101,7 +102,7 @@ int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int function_id, goto out; } - ret =mlx5_vport_get_other_func_cap (dev, function_id, query_cap); + ret =mlx5_vport_get_other_func_general_cap (dev, function_id, query_cap);if (ret) goto out;
drivers/net/ethernet/mellanox/mlx5/core/vport.c +4 -2
@@ -1166,14 +1166,16 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev) }EXPORT_SYMBOL_GPL (mlx5_query_nic_system_image_guid); -int mlx5_vport_get_other_func_cap (struct mlx5_core_dev *dev,u16 function_id,void *out) +int mlx5_vport_get_other_func_cap (struct mlx5_core_dev *dev,u16 function_id,void *out, +u16 opmod) { -u16 opmod = (MLX5_CAP_GENERAL <<1 ) | (HCA_CAP_OPMOD_GET_MAX &0x01 );u8 in[MLX5_ST_SZ_BYTES (query_hca_cap_in)] = {}; + opmod = (opmod <<1 ) | (HCA_CAP_OPMOD_GET_MAX &0x01 );MLX5_SET (query_hca_cap_in, in, opcode,MLX5_CMD_OP_QUERY_HCA_CAP );MLX5_SET (query_hca_cap_in, in, op_mod, opmod);MLX5_SET (query_hca_cap_in, in, function_id, function_id);MLX5_SET (query_hca_cap_in, in, other_function, true);return mlx5_cmd_exec_inout (dev, query_hca_cap, in, out); } +EXPORT_SYMBOL_GPL (mlx5_vport_get_other_func_cap);
include/linux/mlx5/vport.h +2 -0
@@ -132,4 +132,6 @@ int mlx5_nic_vport_affiliate_multiport(struct mlx5_core_dev *master_mdev,int mlx5_nic_vport_unaffiliate_multiport (struct mlx5_core_dev *port_mdev);u64 mlx5_query_nic_system_image_guid (struct mlx5_core_dev *mdev); +int mlx5_vport_get_other_func_cap (struct mlx5_core_dev *dev,u16 function_id,void *out, +u16 opmod);#endif /* __MLX5_VPORT_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1094/1887 net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <[email protected]>
[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ]
mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using the PF's log_max_current_uc/mc_list capabilities. When querying a VF vport with a larger configured max (via devlink), the firmware response can overflow this buffer:
BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] Call Trace: <TASK> dump_stack_lvl+0x69/0xa0 print_report+0x176/0x4e4 kasan_report+0xc8/0x100 mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] esw_vport_change_handler+0x6a/0x90 [mlx5_core] process_one_work+0x87f/0x15e0 worker_thread+0x62b/0x1020 kthread+0x375/0x490 ret_from_fork+0x4dc/0x810 ret_from_fork_asm+0x11/0x20 </TASK>
Fix by querying the vport's own HCA caps to size the buffer correctly. Refactor the function to allocate and return the MAC list internally, removing the caller's dependency on knowing the correct max.
--- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- include/linux/mlx5/vport.h | 4 +- 3 files changed, 59 insertions(+), 30 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +3 -10
@@ -516,23 +516,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, struct mlx5_vport *vport, int list_type) { bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; -u8 (*mac_list)[ETH_ALEN ]; +u8 (*mac_list)[ETH_ALEN ] =NULL ;struct l2addr_node *node;struct vport_addr *addr;struct hlist_head *hash;struct hlist_node *tmp; -int size; +int size =0 ;int err;int hi;int i; - size = is_uc ?MLX5_MAX_UC_PER_VPORT (esw->dev) : -MLX5_MAX_MC_PER_VPORT (esw->dev); - - mac_list =kcalloc (size,ETH_ALEN ,GFP_KERNEL ); -if (!mac_list) -return ; - hash = is_uc ? vport->uc_list : vport->mc_list;for_each_l2hash_node (node, tmp, hash, hi) {
@@ -544,7 +537,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, goto out; err =mlx5_query_nic_vport_mac_list (esw->dev, vport->vport, list_type, - mac_list, &size); + &mac_list, &size);if (err) goto out; esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
drivers/net/ethernet/mellanox/mlx5/core/vport.c +54 -18
105 lines not on this page · raw message
include/linux/mlx5/vport.h +2 -2
@@ -94,8 +94,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev,int mlx5_query_nic_vport_mac_list (struct mlx5_core_dev *dev,u16 vport,enum mlx5_list_type list_type, -u8 addr_list[][ETH_ALEN ], -int *list_size); +u8 (**mac_list)[ETH_ALEN ], +int *mac_list_size); int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, enum mlx5_list_type list_type, u8 addr_list[][ETH_ALEN],
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1095/1887 net: phy: clean the sfp upstream if phy probing fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Chevallier <[email protected]>
[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ]
Sashiko reported that we don't call sfp_bus_del_upstream() in the probe failure path, so let's add it, otherwise the sfp-bus is left with a dangling 'upstream' field, that may be used later on during SFP events.
This issue existed before the generic phylib sfp support, back when drivers were calling phy_sfp_probe themselves.
--- drivers/net/phy/phy_device.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/phy/phy_device.c +6 -0
@@ -1399,6 +1399,9 @@ int phy_sfp_probe(struct phy_device *phydev, ret =sfp_bus_add_upstream (bus, phydev, ops);sfp_bus_put (bus); + +if (ret) + phydev->sfp_bus =NULL ; }return ret; }
@@ -3143,6 +3146,9 @@ static int phy_probe(struct device *dev)return 0 ; out: +sfp_bus_del_upstream (phydev->sfp_bus); + phydev->sfp_bus =NULL ; +/* Re-assert the reset signal on error */ phy_device_reset (phydev,1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1096/1887 gpio: mvebu: Use IS_REACHABLE instead of IS_ENABLED for CONFIG_PWM
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 3101b1e4ba3874a7dbcc4da6d788e1408a69a5d7 ]
To check if a certain function (here e.g. pwmchip_add()) can be called IS_REACHABLE is the better check. The relevant difference to IS_ENABLED is that IS_REACHABLE evaluates to 0 if the current code is builtin but the checked symbol is =m and so must not be used.
Today there is no practical impact as CONFIG_PWM is a bool.
Stable-dep-of: b9ad50d7505e ("gpio: mvebu: fix NULL pointer dereference in suspend/resume")
--- drivers/gpio/gpio-mvebu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpio-mvebu.c +3 -3
@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)BUG (); } -if (IS_ENABLED (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ))mvebu_pwm_suspend (mvchip);return 0 ;
@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)BUG (); } -if (IS_ENABLED (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ))mvebu_pwm_resume (mvchip);return 0 ;
@@ -1238,7 +1238,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) "failed to register gpiochip\n");/* Some MVEBU SoCs have simple PWM support for GPIO lines */ -if (IS_ENABLED (CONFIG_PWM )) { +if (IS_REACHABLE (CONFIG_PWM )) { err =mvebu_pwm_probe (pdev, mvchip, id);if (err)return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1097/1887 gpio: mvebu: fix NULL pointer dereference in suspend/resume
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ]
mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO banks during suspend/resume, but not all banks have PWM functionality. GPIO banks without PWM have mvchip->mvpwm set to NULL.
Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer dereference when it tries to access mvpwm->blink_select.
Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write [00000020] *pgd=00000000 Internal error: Oops: 815 [#1] PREEMPT ARM Modules linked in: CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 Hardware name: Marvell Armada 370/XP (Device Tree) PC is at regmap_mmio_read+0x38/0x54 LR is at regmap_mmio_read+0x38/0x54 pc : [<c05fd2ac>] lr : [<c05fd2ac>] psr: 200f0013 sp : f0c11d10 ip : 00000000 fp : c100d2f0 r10: c14fb854 r9 : 00000000 r8 : 00000000 r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 135ec059 DAC: 00000051 Call trace: regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac _regmap_bus_reg_read from _regmap_read+0x60/0x154 _regmap_read from regmap_read+0x3c/0x60 regmap_read from mvebu_gpio_suspend+0xa4/0x14c mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 dpm_run_callback from device_suspend+0x124/0x630 device_suspend from dpm_suspend+0x124/0x270 dpm_suspend from dpm_suspend_start+0x64/0x6c dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 suspend_devices_and_enter from pm_suspend+0x2fc/0x308 pm_suspend from state_store+0x6c/0xc8 state_store from kernfs_fop_write_iter+0x10c/0x1f8 kernfs_fop_write_iter from vfs_write+0x270/0x468 vfs_write from ksys_write+0x70/0xf0 ksys_write from ret_fast_syscall+0x0/0x54
Add a NULL check for mvchip->mvpwm before calling the PWM suspend/resume functions.
--- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpio/gpio-mvebu.c +2 -2
@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)BUG (); } -if (IS_REACHABLE (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ) && mvchip->mvpwm)mvebu_pwm_suspend (mvchip);return 0 ;
@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)BUG (); } -if (IS_REACHABLE (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ) && mvchip->mvpwm)mvebu_pwm_resume (mvchip);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1098/1887 wifi: fix leak if split 6 GHz scanning fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fedor Pchelkin <[email protected]>
[ Upstream commit e8694f7cc29287e843648d1075177b9a2000d957 ]
rdev->int_scan_req is leaked if cfg80211_scan() fails. Note that it's supposed to be released at ___cfg80211_scan_done() but this doesn't happen as rdev->scan_req is NULL at that point, too, leading to the early return from the freeing function.
unreferenced object 0xffff8881161d0800 (size 512):
comm "wpa_supplicant", pid 379, jiffies 4294749765 hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 f0 81 13 16 81 88 ff ff ................
backtrace (crc c867fdb6):
kmemleak_alloc+0x89/0x90
__kmalloc_noprof+0x2fd/0x410
cfg80211_scan+0x133/0x730
nl80211_trigger_scan+0xc69/0x1cc0
genl_family_rcv_msg_doit+0x204/0x2f0
genl_rcv_msg+0x431/0x6b0
netlink_rcv_skb+0x143/0x3f0
genl_rcv+0x27/0x40
netlink_unicast+0x4f6/0x820
netlink_sendmsg+0x797/0xce0
__sock_sendmsg+0xc4/0x160
____sys_sendmsg+0x5e4/0x890
___sys_sendmsg+0xf8/0x180
__sys_sendmsg+0x136/0x1e0
__x64_sys_sendmsg+0x76/0xc0
x64_sys_call+0x13f0/0x17d0Found by Linux Verification Center (linuxtesting.org).
--- net/wireless/scan.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/wireless/scan.c +8 -1
@@ -995,6 +995,7 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev)struct cfg80211_scan_request *request;struct cfg80211_scan_request *rdev_req = rdev->scan_req;u32 n_channels =0 , idx, i; +int err;if (!(rdev->wiphy.flags &WIPHY_FLAG_SPLIT_SCAN_6GHZ ))return rdev_scan (rdev, rdev_req);
@@ -1021,8 +1022,14 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) } rdev_req->scan_6ghz = false; + err =rdev_scan (rdev, request); +if (err) { +kfree (request); +return err; + } + rdev->int_scan_req = request; -return rdev_scan (rdev, request); +return 0 ; } void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1099/1887 l2tp: pppol2tp: hold reference to session in pppol2tp_ioctl()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit a213a8950414c684999dcf03edeea6c46ede172e ]
pppol2tp_ioctl() read sock->sk->sk_user_data directly without any locks or reference counting. If a controllable sleep was induced during copy_from_user() (e.g. via a userfaultfd page fault sleep), a concurrent socket close could trigger pppol2tp_session_close() asynchronously. This frees the l2tp_session structure via the l2tp_session_del_work workqueue. Upon resuming, the ioctl thread dereferences the stale session pointer, resulting in a Use-After-Free (UAF).
Fix this by securely fetching the session reference using the RCU-safe, refcounted helper pppol2tp_sock_to_session(sk) on entry. This locks the session's refcount across the sleep. We structured the function to exit via standard err breaks, guaranteeing that l2tp_session_put() is cleanly called on all return paths to drop the reference.
To preserve existing behavior we validate the session and its magic signature only for the specific L2TP commands that require it. This ensures that generic/unknown ioctls called on an unconnected socket still return -ENOIOCTLCMD and correctly fall back to generic handlers (e.g. in sock_do_ioctl()).
--- net/l2tp/l2tp_ppp.c | 82 +++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 32 deletions(-)
net/l2tp/l2tp_ppp.c +50 -32
@@ -1056,64 +1056,76 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, {struct pppol2tp_ioc_stats stats;struct l2tp_session *session; +int err =0 ; + + session =pppol2tp_sock_to_session (sock->sk); +/* Validate session presence and magic integrity ONLY for commands +* that belong to L2TP and require a valid session. +*/ switch (cmd) {case PPPIOCGMRU :case PPPIOCGFLAGS : - session = sock->sk->sk_user_data; +case PPPIOCSMRU : +case PPPIOCSFLAGS : +case PPPIOCGL2TPSTATS :if (!session)return -ENOTCONN ; -if (WARN_ON (session->magic !=L2TP_SESSION_MAGIC )) +if (session->magic !=L2TP_SESSION_MAGIC ) { +sock_put (sock->sk);return -EBADF ; + } +break ; +default : +break ; + } +switch (cmd) { +case PPPIOCGMRU : +case PPPIOCGFLAGS :/* Not defined for tunnels */ -if (!session->session_id && !session->peer_session_id) -return -ENOSYS ; +if (!session->session_id && !session->peer_session_id) { + err = -ENOSYS ; +break ; + } -if (put_user (0 , (int __user *)arg)) -return -EFAULT ; +if (put_user (0 , (int __user *)arg)) { + err = -EFAULT ; +break ; + }break ;case PPPIOCSMRU :case PPPIOCSFLAGS : - session = sock->sk->sk_user_data; -if (!session) -return -ENOTCONN ; - -if (WARN_ON (session->magic !=L2TP_SESSION_MAGIC )) -return -EBADF ; -/* Not defined for tunnels */ -if (!session->session_id && !session->peer_session_id) -return -ENOSYS ; +if (!session->session_id && !session->peer_session_id) { + err = -ENOSYS ; +break ; + } -if (!access_ok ((int __user *)arg,sizeof (int ))) -return -EFAULT ; +if (!access_ok ((int __user *)arg,sizeof (int ))) { + err = -EFAULT ; +break ; + }break ;case PPPIOCGL2TPSTATS : - session = sock->sk->sk_user_data; -if (!session) -return -ENOTCONN ; - -if (WARN_ON (session->magic !=L2TP_SESSION_MAGIC )) -return -EBADF ; -/* Session 0 represents the parent tunnel */ if (!session->session_id && !session->peer_session_id) {u32 session_id; -int err;if (copy_from_user (&stats, (void __user *)arg, -sizeof (stats))) -return -EFAULT ; +sizeof (stats))) { + err = -EFAULT ; +break ; + } session_id = stats.session_id; err =pppol2tp_tunnel_copy_stats (&stats, session->tunnel);if (err <0 ) -return err; +break ; stats.session_id = session_id; }else {
@@ -1123,15 +1135,21 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, stats.tunnel_id = session->tunnel->tunnel_id; stats.using_ipsec =l2tp_tunnel_uses_xfrm (session->tunnel); -if (copy_to_user ((void __user *)arg, &stats,sizeof (stats))) -return -EFAULT ; +if (copy_to_user ((void __user *)arg, &stats,sizeof (stats))) { + err = -EFAULT ; +break ; + }break ;default : -return -ENOIOCTLCMD ; + err = -ENOIOCTLCMD ; +break ; } -return 0 ; +if (session) +sock_put (sock->sk); + +return err; }/*****************************************************************************
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1100/1887 netfilter: nft_ct: bail out on template ct in get eval
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 3027ecbdb5fdf9200251c21d4818e4c447ef78e1 ]
I noticed this issue while looking at a historic syzbot report [1].
A rule like the one below is enough to trigger the bug:
table ip t {
chain pre {
type filter hook prerouting priority raw;
ct zone set 1
ct original saddr 1.2.3.4 accept
}
}The first expression attaches a per-cpu template ct via nft_ct_set_zone_eval() (nf_ct_tmpl_alloc -> kzalloc, tuple is all zero, nf_ct_l3num(ct) == 0). The next expression then calls nft_ct_get_eval() on the same skb, treats the template as a real ct and hits the 16-byte memcpy path. With dreg at NFT_REG32_15 this overflows past struct nft_regs on the kernel stack; with smaller dreg values it silently clobbers adjacent registers.
Reject template ct at the eval entry and in nft_ct_get_fast_eval(), mirroring the check nft_ct_set_eval() already has. Additionally, bound the address copy in NFT_CT_SRC / NFT_CT_DST by priv->len instead of by nf_ct_l3num(ct): nf_ct_get_tuple() zeroes the tuple before pkt_to_tuple() fills in only the protocol-relevant leading bytes, so the trailing bytes of tuple->{src,dst}.u3.all are well-defined zero. priv->len is validated at rule load, so the copy size is now bounded by the destination register rather than by an untrusted field on the conntrack.
[1]: https://syzkaller.appspot.com/bug?id=389cf09cb72926114fce90dc85a2c3231dcb647c
--- net/netfilter/nft_ct.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
net/netfilter/nft_ct.c +3 -5
@@ -88,7 +88,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,break ; } -if (ct ==NULL ) +if (!ct ||nf_ct_is_template (ct)) goto err;switch (priv->key) {
@@ -190,12 +190,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, tuple = &ct->tuplehash[priv->dir].tuple;switch (priv->key) {case NFT_CT_SRC : -memcpy (dest, tuple->src.u3.all, -nf_ct_l3num (ct) ==NFPROTO_IPV4 ?4 :16 ); +memcpy (dest, tuple->src.u3.all, priv->len);return ;case NFT_CT_DST : -memcpy (dest, tuple->dst.u3.all, -nf_ct_l3num (ct) ==NFPROTO_IPV4 ?4 :16 ); +memcpy (dest, tuple->dst.u3.all, priv->len);return ;case NFT_CT_PROTO_SRC :nft_reg_store16 (dest, (__force u16 )tuple->src.u.all);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1101/1887 erofs: fix use-after-free on sbi->sync_decompress
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit 1aee05e814d292064bf5fa15733741040cdc48ba ]
z_erofs_decompress_kickoff() can race with filesystem unmount, causing a use-after-free on sbi->sync_decompress.
When I/O completes, z_erofs_endio() calls z_erofs_decompress_kickoff() to queue z_erofs_decompressqueue_work() asynchronously. Then, after all folios are unlocked, unmount workflow can proceed and sbi will be freed before accessing to sbi->sync_decompress.
Thread (unmount) I/O completion kworker
queue_work
z_erofs_decompressqueue_work
(all folios are unlocked)cleanup_mnt
..
erofs_kill_sb
erofs_sb_free
kfree(sbi)
access sbi->sync_decompress // UAF!!
--- fs/erofs/zdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/erofs/zdata.c +1 -1
@@ -1281,10 +1281,10 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,if (atomic_add_return (bios, &io->pending_bios))return ;if (z_erofs_in_atomic ()) { -queue_work (z_erofs_workqueue, &io->u.work);/* enable sync decompression for readahead */ if (sbi->opt.sync_decompress ==EROFS_SYNC_DECOMPRESS_AUTO ) sbi->opt.sync_decompress =EROFS_SYNC_DECOMPRESS_FORCE_ON ; +queue_work (z_erofs_workqueue, &io->u.work);return ; } gfp_flag =memalloc_noio_save ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1102/1887 btrfs: only release the dirty pages io tree after successful writes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
[ Upstream commit 4066c55e109475a06d18a1f127c939d551211956 ]
[WARNING]
With extra warning on dirty extent buffers at umount (aka, the next patch in the series), test case generic/388 can trigger the following warning about dirty extent buffers at unmount time:
BTRFS critical (device dm-2 state E): emergency shutdown
BTRFS error (device dm-2 state E): error while writing out transaction: -30
BTRFS warning (device dm-2 state E): Skipping commit of aborted transaction.
BTRFS error (device dm-2 state EA): Transaction 9 aborted (error -30)
BTRFS: error (device dm-2 state EA) in cleanup_transaction:2068: errno=-30 Readonly filesystem BTRFS info (device dm-2 state EA): forced readonly
BTRFS info (device dm-2 state EA): last unmount of filesystem 4fbf2e15-f941-49a0-bc7c-716315d2777c
------------[ cut here ]------------ WARNING: disk-io.c:3311 at invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs], CPU#8: umount/914368 CPU: 8 UID: 0 PID: 914368 Comm: umount Tainted: G OE 7.1.0-rc1-custom+ #372 PREEMPT(full) 2de38db8d1deae71fde295430a0ff3ab98ccf596 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022 RIP: 0010:invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs] Call Trace: <TASK> close_ctree+0x52e/0x574 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] generic_shutdown_super+0x89/0x1a0 kill_anon_super+0x16/0x40 btrfs_kill_super+0x16/0x20 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] deactivate_locked_super+0x2d/0xb0 cleanup_mnt+0xdc/0x140 task_work_run+0x5a/0xa0 exit_to_user_mode_loop+0x123/0x4b0 do_syscall_64+0x243/0x7c0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS warning (device dm-2 state EA): unable to release extent buffer 30539776 owner 9 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30621696 owner 257 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30638080 owner 258 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30654464 owner 7 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30703616 owner 2 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30720000 owner 10 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30736384 owner 4 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30752768 owner 11 gen 9 refs 2 flags 0x7
I'm using a stripped down version, which seems to trigger the warning more reliably:
_fsstress_pid=""
workload()
{
dmesg -C
mkfs.btrfs -f -K $dev > /dev/null
echo 1 > /sys/kernel/debug/clear_warn_once
mount $dev $mnt
$fsstress -w -n 1024 -p 4 -d $mnt &
_fsstress_pid=$!
sleep 0
$godown $mnt
pkill --echo -PIPE fsstress > /dev/null
wait $_fsstress_pid
unset _fsstress_pid
umount $mnt if dmesg | grep -q "WARNING"; then
fail
fi
}
for (( i = 0; i < $runtime; i++ )); do
echo "=== $i/$runtime ==="
workload
done
[CAUSE]
Inside btrfs_write_and_wait_transaction(), we first try to write all dirty ebs, then wait for them to finish.
After that we call btrfs_extent_io_tree_release() to free all extent states from dirty_pages io tree.
However if we hit an error from btrfs_write_marked_extent(), then we still call btrfs_extent_io_tree_release() to clear that dirty_pages io tree, which may contain dirty records that we haven't yet submitted.
Furthermore, the later transaction cleanup path will utilize that dirty_pages io tree to properly cleanup those dirty ebs, but since it's already empty, no dirty ebs are properly cleaned up, thus will later trigger the warnings inside invalidate_btree_folios().
[FIX]
Normally such dirty ebs won't cause problems, as when the iput() is called on the btree inode, the dirty ebs will be forcibly written back, and since the fs is already in an error status, such writeback will not reach disk and finish immediately.
But it's still better to get rid of such dirty ebs, if we ended up with dirty ebs but the fs is not in an error status, then such writeback at iput() time will be too late, as all workers are already stopped but writeback will utilize workers, which will lead to NULL pointer dereferences.
Instead of unconditionally calling btrfs_extent_io_tree_release(), only call it if btrfs_write_and_wait_transaction() finished successfully, so that @dirty_pages extent io tree is kept untouched for transaction cleanup.
--- fs/btrfs/disk-io.c | 1 + fs/btrfs/transaction.c | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-)
fs/btrfs/disk-io.c +1 -0
@@ -5134,6 +5134,7 @@ static int btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,free_extent_buffer_stale (eb); } } +extent_io_tree_release (dirty_pages);return ret; }
fs/btrfs/transaction.c +4 -5
@@ -1231,14 +1231,13 @@ static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)blk_finish_plug (&plug); ret2 =btrfs_wait_extents (fs_info, dirty_pages); -extent_io_tree_release (&trans->transaction->dirty_pages); -if (ret)return ret; -else if (ret2) +if (ret2)return ret2; -else -return 0 ; + +extent_io_tree_release (&trans->transaction->dirty_pages); +return 0 ; }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1103/1887 net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <[email protected]>
[ Upstream commit 5b0c911bcdbd982f7748d11c0b39ec5808eae2de ]
syzbot reported a kernel BUG triggered from pn_socket_sendmsg() via pn_socket_autobind():
kernel BUG at net/phonet/socket.c:213!
RIP: 0010:pn_socket_autobind net/phonet/socket.c:213 [inline] RIP: 0010:pn_socket_sendmsg+0x240/0x250 net/phonet/socket.c:421 Call Trace: sock_sendmsg_nosec+0x112/0x150 net/socket.c:797 __sock_sendmsg net/socket.c:812 [inline] __sys_sendto+0x402/0x590 net/socket.c:2280 ...
pn_socket_autobind() calls pn_socket_bind() with port 0 and, on -EINVAL, assumes the socket was already bound and asserts that the port is non-zero:
err = pn_socket_bind(sock, ..., sizeof(struct sockaddr_pn));
if (err != -EINVAL)
return err;
BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
return 0; /* socket was already bound */However pn_socket_bind() also returns -EINVAL when sk->sk_state is not TCP_CLOSE, even when the socket has never been bound and pn_port() is still 0. In that case the BUG_ON() fires and panics the kernel from a user-triggerable path.
Treat the "bind returned -EINVAL but pn_port() is still 0" case as a regular error and propagate -EINVAL to the caller instead of crashing. Existing callers already translate a non-zero return from pn_socket_autobind() into -ENOBUFS/-EAGAIN, so returning -EINVAL here only changes behaviour from panic to a normal errno.
--- net/phonet/socket.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/phonet/socket.c +8 -2
@@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock) sa.spn_family =AF_PHONET ; err =pn_socket_bind (sock, (struct sockaddr *)&sa,sizeof (struct sockaddr_pn )); -if (err != -EINVAL ) +/* +* pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE +* without a prior bind, so -EINVAL alone is not sufficient to infer +* that the socket was already bound. Only treat it as "already +* bound" when the port is non-zero; otherwise propagate the error +* instead of crashing the kernel. +*/ +if (err != -EINVAL ||unlikely (!pn_port (pn_sk (sock->sk)->sobject)))return err; -BUG_ON (!pn_port (pn_sk (sock->sk)->sobject));return 0 ;/* socket was already bound */ }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1104/1887 net: mana: Guard mana_remove against double invocation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit 50271d7ec95144d26808025b508f463780517d3c ]
If PM resume fails (e.g., mana_attach() returns an error), mana_probe() calls mana_remove(), which tears down the device and sets gd->gdma_context = NULL and gd->driver_data = NULL.
However, a failed resume callback does not automatically unbind the driver. When the device is eventually unbound, mana_remove() is invoked a second time. Without a NULL check, it dereferences gc->dev with gc == NULL, causing a kernel panic.
Add an early return if gdma_context or driver_data is NULL so the second invocation is harmless. Move the dev = gc->dev assignment after the guard so it cannot dereference NULL.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +6 -1
@@ -2276,11 +2276,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending) {struct gdma_context *gc = gd->gdma_context;struct mana_context *ac = gd->driver_data; -struct device *dev = gc->dev; +struct device *dev;struct net_device *ndev;int err;int i; +if (!gc || !ac) +return ; + + dev = gc->dev; +for (i =0 ; i < ac->num_ports; i++) { ndev = ac->ports[i];if (!ndev) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1105/1887 drm/amd/display: Add interface to enable DPIA trace
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stylon Wang <[email protected]>
[ Upstream commit 71ba6b577a353fa880b2e5c85cdd780765c51fed ]
[Why]
DPIA traces from DMUB is not enabled by default, which is less convenient to debug DPIA related issues because we have to resort to other debug tools to enable DPIA trace.
[How]
Exposes interfaces to update trace mask from the DMUB GPINT commands. Also provides DC implementations to enable DPIA trace.
Stable-dep-of: 4ae3e16f4b3b ("drm/amd/display: Avoid NULL dereference in dc_dmub_srv error paths")
--- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 29 +++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 3 ++ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 18 ++++++++++++ 3 files changed, 50 insertions(+)
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +29 -0
@@ -1034,3 +1034,32 @@ bool dc_dmub_check_min_version(struct dmub_srv *srv)return true;return srv->hw_funcs.is_psrsu_supported (srv); } + +void dc_dmub_srv_enable_dpia_trace (const struct dc *dc) +{ +struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; +struct dmub_srv *dmub; +enum dmub_status status; +static const uint32_t timeout_us =30 ; + +if (!dc_dmub_srv || !dc_dmub_srv->dmub) { +DC_LOG_ERROR ("%s: invalid parameters." , __func__); +return ; + } + + dmub = dc_dmub_srv->dmub; + + status =dmub_srv_send_gpint_command (dmub,DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1 ,0x0010 , timeout_us); +if (status !=DMUB_STATUS_OK ) { +DC_LOG_ERROR ("timeout updating trace buffer mask word\n" ); +return ; + } + + status =dmub_srv_send_gpint_command (dmub,DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK ,0x0000 , timeout_us); +if (status !=DMUB_STATUS_OK ) { +DC_LOG_ERROR ("timeout updating trace buffer mask word\n" ); +return ; + } + +DC_LOG_DEBUG ("Enabled DPIA trace\n" ); +}
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +3 -0
@@ -90,4 +90,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv);void dc_send_update_cursor_info_to_dmu (struct pipe_ctx *pCtx,uint8_t pipe_idx);bool dc_dmub_check_min_version (struct dmub_srv *srv); + +void dc_dmub_srv_enable_dpia_trace (const struct dc *dc); +#endif /* _DMUB_DC_SRV_H_ */
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +18 -0
@@ -540,6 +540,24 @@ enum dmub_gpint_command {* DESC: Notifies DMCUB detection is done so detection required can be cleared. */ DMUB_GPINT__NOTIFY_DETECTION_DONE =12 , +/** +* DESC: Updates the trace buffer lower 32-bit mask. +* ARGS: The new mask +* RETURN: Lower 32-bit mask. +*/ +DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK =101 , +/** +* DESC: Updates the trace buffer lower 32-bit mask. +* ARGS: The new mask +* RETURN: Lower 32-bit mask. +*/ +DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0 =102 , +/** +* DESC: Updates the trace buffer mask bi0~bit15. +* ARGS: The new mask +* RETURN: Lower 32-bit mask. +*/ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1 = 103, };/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1106/1887 drm/amd/display: Avoid NULL dereference in dc_dmub_srv error paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit 4ae3e16f4b3bf64140f773629b765d605ee079a9 ]
In dc_dmub_srv_log_diagnostic_data() anddc_dmub_srv_enable_dpia_trace().
Both functions check:
if (!dc_dmub_srv || !dc_dmub_srv->dmub)
and then call DC_LOG_ERROR() inside that block.
DC_LOG_ERROR() uses dc_dmub_srv->ctx internally. So if dc_dmub_srv is NULL, the logging itself can dereference a NULL pointer and cause a crash.
Fix this by splitting the checks.
First check if dc_dmub_srv is NULL and return immediately. Then check dc_dmub_srv->dmub and log the error only when dc_dmub_srv is valid.
Fixes the below:../display/dc/dc_dmub_srv.c:962 dc_dmub_srv_log_diagnostic_data() error: we previously assumed 'dc_dmub_srv' could be null (see line 961) ../display/dc/dc_dmub_srv.c:1167 dc_dmub_srv_enable_dpia_trace() error: we previously assumed 'dc_dmub_srv' could be null (see line 1166)
--- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +8 -2
@@ -804,7 +804,10 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) {struct dmub_diagnostic_data diag_data = {0 }; -if (!dc_dmub_srv || !dc_dmub_srv->dmub) { +if (!dc_dmub_srv) +return ; + +if (!dc_dmub_srv->dmub) {DC_LOG_ERROR ("%s: invalid parameters." , __func__);return ; }
@@ -1042,7 +1045,10 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)enum dmub_status status;static const uint32_t timeout_us =30 ; -if (!dc_dmub_srv || !dc_dmub_srv->dmub) { +if (!dc_dmub_srv) +return ; + +if (!dc_dmub_srv->dmub) {DC_LOG_ERROR ("%s: invalid parameters." , __func__);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1107/1887 wifi: mt76: mt7921: Place upper limit on station AID
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rory Little <[email protected]>
[ Upstream commit 4d0bf21e3e20619d51d06c0c36207aabab8b712c ]
Any station configured with an AID over 20 causes a firmware crash. This situation occurred in our testing using an AP interface on 7922 hardware, with a modified hostapd, sourced from Mediatek's OpenWRT feeds.
In stock hostapd, station AIDs begin counting at 1, and this configuration is prevented with an upper limit on associated stations. However, the modified hostapd began allocation at 65, which caused the firmware to crash. This fix does not allow these AIDs to work, but will prevent the firmware crash.
This crash was only seen on IFTYPE_AP interfaces, and the fix does not appear to have an effect on IFTYPE_STATION behavior.
--- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ 2 files changed, 8 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +6 -0
@@ -716,6 +716,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;int ret, idx; +if (sta->aid >MT7921_MAX_AID ) +return -ENOENT ; + idx =mt76_wcid_alloc (dev->mt76.wcid_mask,MT7921_WTBL_STA -1 );if (idx <0 )return -ENOSPC ;
@@ -756,6 +759,9 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +if (sta->aid >MT7921_MAX_AID ) +return ; +mt7921_mutex_acquire (dev);if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls)
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +2 -0
@@ -21,6 +21,8 @@#define MT7921_WATCHDOG_TIME (HZ / 4)#define MT7921_RESET_TIMEOUT (30 * HZ) +#define MT7921_MAX_AID 20 +#define MT7921_TX_RING_SIZE 2048#define MT7921_TX_MCU_RING_SIZE 256#define MT7921_TX_FWDL_RING_SIZE 128
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1108/1887 drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
[ Upstream commit e8b4d37eba05141ee01794fc6b7f2da808cee83b ]
[Why & How]
The aux_rd_interval array in struct dc_lttpr_caps is declared with MAX_REPEATER_CNT - 1 (7) elements, indexed 0..6. However, the offset parameter passed to dp_get_eq_aux_rd_interval() can be as large as MAX_REPEATER_CNT (8) when a sink reports 8 LTTPR repeaters via DPCD. This leads to an out-of-bounds read of aux_rd_interval[7] when offset is 8.
Fix this by growing aux_rd_interval to MAX_REPEATER_CNT elements to accommodate the full range of valid repeater counts defined by the DP spec.
--- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dc_types.h +1 -1
@@ -403,7 +403,7 @@ struct dc_lttpr_caps {uint8_t max_ext_timeout;union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates; -uint8_t aux_rd_interval[MAX_REPEATER_CNT -1 ]; +uint8_t aux_rd_interval[MAX_REPEATER_CNT ]; };struct dc_dongle_dfp_cap_ext {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1109/1887 KVM: Dont WARN if memory is dirtied without a vCPU when the VM is dying
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit 8618004d3e897c0f1b71d9a9ab860461289bb89a ]
When marking a page dirty, complain about not having a running/loaded vCPU if and only if the VM is still alive, i.e. its refcount is non-zero. This will allow fixing a memory leak for x86 SEV-ES guests without hitting what is effectively a false positive on the WARN.
For some SEV-ES VM-Exits, KVM keeps a writable mapping of a guest page across an exit to userspace, and typically unmaps the page on the next KVM_RUN. But if userspace never calls KVM_RUN after such an exit, then KVM needs to unmap the page when the vCPU is destroyed, which in turn triggers the WARN about not having a running vCPU.
Alternatively, SEV-ES could temporarily load the vCPU to suppress the WARN, as is done in nested_vmx_free_vcpu() (but for completely unrelated reasons; suppressing WARN from nested_put_vmcs12_pages() is pure happenstance). But loading a vCPU during destruction is gross (ideally nVMX code would be cleaned up), risks complicating the SEV-ES code (KVM would need to ensure the temporarily load()+put() only runs when the vCPU isn't already loaded), and is ultimately pointless.
The motivation for the WARN is to guard against KVM dirtying guest memory without pushing the corresponding GFN to the active vCPU's dirty ring, e.g. to ensure userspace doesn't miss a dirty page. But for the VM's refcount to reach zero, there can't be _any_ userspace mappings to the dirty ring, as mapping the dirty ring requires doing mmap() on the vCPU FD. I.e. if userspace had a valid mapping for the dirty ring, then the vCPU file and thus the owning VM would still be alive. And so since userspace can't possibly reach the dirty ring, whether or not KVM technically "misses" a push to the dirty ring is irrelevant.
Message-ID: <[email protected]>
Message-ID: <[email protected]>
--- virt/kvm/kvm_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/kvm_main.c +2 -1
@@ -3321,7 +3321,8 @@ void mark_page_dirty_in_slot(struct kvm *kvm,struct kvm_vcpu *vcpu =kvm_get_running_vcpu ();#ifdef CONFIG_HAVE_KVM_DIRTY_RING -if (WARN_ON_ONCE (!vcpu) ||WARN_ON_ONCE (vcpu->kvm != kvm)) +if (WARN_ON_ONCE (!vcpu &&refcount_read (&kvm->users_count)) || !vcpu || +WARN_ON_ONCE (vcpu->kvm != kvm))return ;#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1110/1887 f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <[email protected]>
[ Upstream commit 019f9dda7f66e55eb94cd32e1d3fff5835f73fbc ]
f2fs_need_dentry_mark() reads nat_entry flags without mutual exclusion with the checkpoint path, which can result in an incorrect inode block marking state. The scenario is as follows:
create & write & fsync 'file A' write checkpoint
- f2fs_do_sync_file // inline inode
- f2fs_write_inode // inode folio is dirty
- f2fs_write_checkpoint
- f2fs_flush_merged_writes
- f2fs_sync_node_pages
- f2fs_fsync_node_pages // no dirty node
- f2fs_need_inode_block_update // return true
- f2fs_fsync_node_pages // inode dirtied
- f2fs_need_dentry_mark //return true
- f2fs_flush_nat_entries
- f2fs_write_checkpoint end
- __write_node_folio // inode with DENT_BIT_SHIFT set
SPO, "fsck --dry-run" find inode has already checkpointed but still with DENT_BIT_SHIFT set
The state observed by f2fs_need_dentry_mark() can differ from the state observed in __write_node_folio() after acquiring sbi->node_write. The root cause is that the semantics of IS_CHECKPOINTED and HAS_FSYNCED_INODE are only guaranteed after the checkpoint write has fully completed.
This patch moves set_dentry_mark() into __write_node_folio() and protects it with the sbi->node_write lock.
--- fs/f2fs/node.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-)
fs/f2fs/node.c +5 -9
@@ -1692,13 +1692,12 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, goto redirty_out; } -if (atomic) { -if (!test_opt (sbi,NOBARRIER ) && !f2fs_sb_has_blkzoned (sbi)) - fio.op_flags |=REQ_PREFLUSH |REQ_FUA ; -if (IS_INODE (page)) -set_dentry_mark (page, +if (atomic && !test_opt (sbi,NOBARRIER ) && !f2fs_sb_has_blkzoned (sbi)) + fio.op_flags |=REQ_PREFLUSH |REQ_FUA ; + +if (IS_INODE (page) && (atomic ||is_fsync_dnode (page))) +set_dentry_mark (page,f2fs_need_dentry_mark (sbi,ino_of_node (page))); - }/* should add to global list before clearing PAGECACHE status */ if (f2fs_in_warm_node_list (sbi, page)) {
@@ -1853,9 +1852,6 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,if (is_inode_flag_set (inode,FI_DIRTY_INODE ))f2fs_update_inode (inode, page); -if (!atomic) -set_dentry_mark (page, -f2fs_need_dentry_mark (sbi, ino)); }/* may be written by other thread */ if (!PageDirty (page))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1111/1887 drm/amdkfd: Add upper bound check for num_of_nodes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alysa Liu <[email protected]>
[ Upstream commit 74b73fa56a395d46745e4f245225963e9f8be7f1 ]
drm/amdkfd: Add upper bound check for num_of_nodes in kfd_ioctl_get_process_apertures_new.
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 3 +++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 + drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 11 +++++++++++ 3 files changed, 15 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +3 -0
@@ -772,6 +772,9 @@ static int kfd_ioctl_get_process_apertures_new(struct file *filp, goto out_unlock; } +if (args->num_of_nodes >kfd_topology_get_num_devices ()) +return -EINVAL ; +/* Fill in process-aperture information for all available * nodes, but not more than args->num_of_nodes as that is * the amount of memory allocated by user
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +1 -0
@@ -1048,6 +1048,7 @@ struct kfd_dev *kfd_device_by_id(uint32_t gpu_id);struct kfd_dev *kfd_device_by_pci_dev (const struct pci_dev *pdev);struct kfd_dev *kfd_device_by_adev (const struct amdgpu_device *adev);int kfd_topology_enum_kfd_devices (uint8_t idx,struct kfd_dev **kdev); +uint32_t kfd_topology_get_num_devices (void );int kfd_numa_node_to_apic_id (int numa_node_id);void kfd_double_confirm_iommu_support (struct kfd_dev *gpu);
drivers/gpu/drm/amd/amdkfd/kfd_topology.c +11 -0
@@ -2109,6 +2109,17 @@ int kfd_topology_remove_device(struct kfd_dev *gpu)return res; } +uint32_t kfd_topology_get_num_devices (void ) +{ +uint32_t num_devices; + +down_read (&topology_lock); + num_devices = sys_props.num_devices; +up_read (&topology_lock); + +return num_devices; +} +/* kfd_topology_enum_kfd_devices - Enumerate through all devices in KFD * topology. If GPU device is found @idx, then valid kfd_dev pointer is * returned through @kdev
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1112/1887 drm/msm: always recover the gpu
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anna Maniscalco <[email protected]>
[ Upstream commit 01a0d6cd7032e9993feea19fadb03ef9d5b488f2 ]
Previously, in case there was no more work to do, recover worker wouldn't trigger recovery and would instead rely on the gpu going to sleep and then resuming when more work is submitted.
Recover_worker will first increment the fence of the hung ring so, if there's only one job submitted to a ring and that causes an hang, it will early out.
There's no guarantee that the gpu will suspend and resume before more work is submitted and if the gpu is in a hung state it will stay in that state and probably trigger a timeout again.
Just stop checking and always recover the gpu.
Patchwork: https://patchwork.freedesktop.org/patch/704066/
Message-ID: <[email protected]>
--- drivers/gpu/drm/msm/msm_gpu.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
drivers/gpu/drm/msm/msm_gpu.c +14 -16
@@ -421,25 +421,23 @@ static void recover_worker(struct kthread_work *work)msm_update_fence (ring->fctx, fence); } -if (msm_gpu_active (gpu)) { - gpu->funcs->recover (gpu); + gpu->funcs->recover (gpu); -/* retire completed submits, plus the one that hung: */ -retire_submits (gpu); +/* retire completed submits, plus the one that hung: */ +retire_submits (gpu); -/* -* Replay all remaining submits starting with highest priority -* ring -*/ -for (i =0 ; i < gpu->nr_rings; i++) { -struct msm_ringbuffer *ring = gpu->rb[i]; -unsigned long flags; +/* +* Replay all remaining submits starting with highest priority +* ring +*/ +for (i =0 ; i < gpu->nr_rings; i++) { +struct msm_ringbuffer *ring = gpu->rb[i]; +unsigned long flags; -spin_lock_irqsave (&ring->submit_lock, flags); -list_for_each_entry (submit, &ring->submits, node) - gpu->funcs->submit (gpu, submit); -spin_unlock_irqrestore (&ring->submit_lock, flags); - } +spin_lock_irqsave (&ring->submit_lock, flags); +list_for_each_entry (submit, &ring->submits, node) + gpu->funcs->submit (gpu, submit); +spin_unlock_irqrestore (&ring->submit_lock, flags); }pm_runtime_put (&gpu->pdev->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1113/1887 fbdev: omap2: fix inconsistent lock returns in omapfb_mmap
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <[email protected]>
[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ]
Fix the warning about inconsistent returns for '&rg->lock' in omapfb_mmap() function. The warning arises because the error path uses 'ofbi->region' while the normal path uses 'rg'.
smatch warnings:drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap()
warn: inconsistent returns '&rg->lock'.
Stable-dep-of: 7958e67375aa ("fbdev: omap2: fix use-after-free in omapfb_mmap")
--- drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/video/fbdev/omap2/omapfb/omapfb-main.c +1 -1
@@ -1119,7 +1119,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)return 0 ; error: -omapfb_put_mem_region (ofbi->region); +omapfb_put_mem_region (rg);return r; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1114/1887 fbdev: omap2: fix use-after-free in omapfb_mmap
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <[email protected]>
[ Upstream commit 7958e67375aa111522086286bba13cfc0816ce8d ]
omapfb_mmap() has a race condition with OMAPFB_SETUP_PLANE ioctl that can lead to use-after-free:
The fb_mmap() entry point holds mm_lock but not lock (fb_info->lock), while ioctl handlers like OMAPFB_SETUP_PLANE hold lock but not mm_lock. This allows concurrent execution.
In omapfb_mmap():
1. rg = omapfb_get_mem_region(ofbi->region); // Get old region ref
2. start = omapfb_get_region_paddr(ofbi); // Read from NEW region
3. len = fix->smem_len; // Read from NEW region
4. vm_iomap_memory(vma, start, len); // Map NEW region memory
5. atomic_inc(&rg->map_count); // Increment OLD region!
Concurrently, OMAPFB_SETUP_PLANE can:
- Reassign ofbi->region = new_rg
- Update fix->smem_len
- OMAPFB_SETUP_MEM then checks NEW region's map_count (0!) and frees it
This leaves userspace with a mapping to freed physical memory.
The fix is to read all required values (start, len) from the same region reference (rg) that will have its map_count incremented, preventing the region from being freed while still mapped.
--- drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/video/fbdev/omap2/omapfb/omapfb-main.c +8 -1
@@ -1097,7 +1097,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) rg =omapfb_get_mem_region (ofbi->region); - start =omapfb_get_region_paddr (ofbi); +if (ofbi->rotation_type ==OMAP_DSS_ROT_VRFB ) + start = rg->vrfb.paddr[0 ]; +else + start = rg->paddr; + len = fix->smem_len; DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
@@ -1107,6 +1111,8 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) vma->vm_ops = &mmap_user_ops; vma->vm_private_data = rg; +atomic_inc (&rg->map_count); + r =vm_iomap_memory (vma, start, len);if (r) goto error;
@@ -1119,6 +1125,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)return 0 ; error: +atomic_dec (&rg->map_count);omapfb_put_mem_region (rg);return r;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1115/1887 gcov: use atomic counter updates to fix concurrent access crashes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Khorenko <[email protected]>
[ Upstream commit 56cb9b7d96b28a1173a510ab25354b6599ad3a33 ]
GCC's GCOV instrumentation can merge global branch counters with loop induction variables as an optimization. In inflate_fast(), the inner copy loops get transformed so that the GCOV counter value is loaded multiple times to compute the loop base address, start index, and end bound. Since GCOV counters are global (not per-CPU), concurrent execution on different CPUs causes the counter to change between loads, producing inconsistent values and out-of-bounds memory writes.
The crash manifests during IPComp (IP Payload Compression) processing when inflate_fast() runs concurrently on multiple CPUs:
BUG: unable to handle page fault for address: ffffd0a3c0902ffa RIP: inflate_fast+1431 Call Trace: zlib_inflate __deflate_decompress crypto_comp_decompress ipcomp_decompress [xfrm_ipcomp] ipcomp_input [xfrm_ipcomp] xfrm_input
At the crash point, the compiler generated three loads from the same global GCOV counter (__gcov0.inflate_fast+216) to compute base, start, and end for an indexed loop. Another CPU modified the counter between loads, making the values inconsistent - the write went 3.4 MB past a 65 KB buffer.
Add -fprofile-update=prefer-atomic to CFLAGS_GCOV at the global level in the top-level Makefile, guarded by a try-run compile test. The test compiles a minimal program with and without -fprofile-update=prefer-atomic using the full KBUILD_CFLAGS, then compares undefined symbols in the resulting object files. If prefer-atomic introduces new undefined references (such as __atomic_fetch_add_8 on i386 or __aarch64_ldadd8_relax on arm64 with outline-atomics), the flag is not added -- the kernel does not link against libatomic.
On architectures where GCC inlines 64-bit atomic counter updates (x86_64, s390, ...) the test passes and the flag is enabled, preventing the compiler from merging counters with loop induction variables and fixing the observed concurrent-access crash.
On architectures where the flag would introduce libatomic dependencies, it is silently omitted and behaviour is no worse than before this patch.
Move the CFLAGS_GCOV block from its original position (before the arch Makefile include) to after the core KBUILD_CFLAGS assignments but before the scripts/Makefile.gcc-plugins include. This placement ensures the try-run test sees arch-specific flags (-m32, -march=, -mno-outline-atomics) while avoiding GCC plugin flags (-fplugin=) that would break the test on clean builds when plugin shared objects do not yet exist.
--- Makefile | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-)
Makefile +21 -6
@@ -760,12 +760,6 @@ endif # KBUILD_EXTMOD # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux -CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -ifdef CONFIG_CC_IS_GCC -CFLAGS_GCOV += -fno-tree-loop-im -endif -export CFLAGS_GCOV - # The arch Makefiles can override CC_FLAGS_FTRACE. We may also append it later. ifdef CONFIG_FUNCTION_TRACER CC_FLAGS_FTRACE := -pg
@@ -1090,6 +1084,27 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) # Ensure compilers do not transform certain loops into calls to wcslen() KBUILD_CFLAGS += -fno-builtin-wcslen +CFLAGS_GCOV := -fprofile-arcs -ftest-coverage +ifdef CONFIG_CC_IS_GCC +CFLAGS_GCOV += -fno-tree-loop-im +# Use atomic counter updates to avoid concurrent-access crashes in GCOV. +# Only enable if -fprofile-update=prefer-atomic does not introduce new +# undefined symbols (e.g. libatomic calls that the kernel cannot link). +CFLAGS_GCOV += $(call try-run,\ + echo 'long long x; void f(void){x++;}' | \ + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \ + -ftest-coverage -x c - -c -o "$$TMP.base" && \ + echo 'long long x; void f(void){x++;}' | \ + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \ + -ftest-coverage -fprofile-update=prefer-atomic \ + -x c - -c -o "$$TMP" && \ + $(NM) "$$TMP.base" | grep ' U ' > "$$TMP.ubase" || true ; \ + $(NM) "$$TMP" | grep ' U ' > "$$TMP.utest" || true ; \ + cmp -s "$$TMP.ubase" "$$TMP.utest",\ + -fprofile-update=prefer-atomic) +endif +export CFLAGS_GCOV + # change __FILE__ to the relative path from the srctree KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1116/1887 fbdev: fix use-after-free in store_modes()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Bridges <[email protected]>
[ Upstream commit 2c1c805c65fb7dc7524e20376d6987721e73a0b1 ]
store_modes() replaces a framebuffer's modelist with modes from userspace. On success it frees the old modelist with fb_destroy_modelist(). Two fields still point into that freed list.
One pointer is fb_display[i].mode, the mode a console is using. fbcon_new_modelist() moves these pointers to the new list. It only does so for consoles still mapped to the framebuffer. An unmapped console is skipped and keeps its stale pointer. Unbinding fbcon, for example, sets con2fb_map[i] to -1 but leaves fb_display[i].mode set. An FBIOPUT_VSCREENINFO ioctl with FB_ACTIVATE_INV_MODE later reaches fbcon_mode_deleted(). That function reads the stale fb_display[i].mode through fb_mode_is_equal(). The read is a use-after-free.
The other pointer is fb_info->mode, the current mode. It is set through the mode sysfs attribute. store_modes() does not update fb_info->mode, so it is left pointing into the freed list. show_mode(), the attribute's read handler, dereferences the stale fb_info->mode through mode_string(). The read is a use-after-free.
Clear both pointers before freeing the list. Commit a1f305893074 ("fbcon:
Set fb_display[i]->mode to NULL when the mode is released") added the helper fbcon_delete_modelist(). It clears every fb_display[i].mode that points into a given list. So far it is called only from the unregister path. Call it from store_modes() too, and set fb_info->mode to NULL.
--- drivers/video/fbdev/core/fbsysfs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/video/fbdev/core/fbsysfs.c +8 -1
@@ -194,8 +194,15 @@ static ssize_t store_modes(struct device *device,if (fb_new_modelist (fb_info)) {fb_destroy_modelist (&fb_info->modelist);list_splice (&old_list, &fb_info->modelist); - }else + }else { +/* +* fb_display[i].mode and fb_info->mode both point into the old +* list. Clear them before it is freed. +*/ +fbcon_delete_modelist (&old_list); + fb_info->mode =NULL ;fb_destroy_modelist (&old_list); + }unlock_fb_info (fb_info);console_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1117/1887 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +1 -0
@@ -557,6 +557,7 @@ static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, .vmhub = AMDGPU_MMHUB_0, + .no_user_fence = true, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1118/1887 drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +1 -0
@@ -561,6 +561,7 @@ static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, .vmhub = AMDGPU_MMHUB_0, + .no_user_fence = true, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1119/1887 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +2 -0
@@ -641,6 +641,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .vmhub =AMDGPU_MMHUB_1 , .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr,
@@ -671,6 +672,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .vmhub =AMDGPU_MMHUB_0 , .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1120/1887 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +1 -0
@@ -762,6 +762,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .vmhub =AMDGPU_MMHUB_0 , .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1121/1887 drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +1 -0
@@ -1769,6 +1769,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, .vmhub = AMDGPU_MMHUB_0, + .no_user_fence = true, .get_rptr = vcn_v4_0_unified_ring_get_rptr, .get_wptr = vcn_v4_0_unified_ring_get_wptr, .set_wptr = vcn_v4_0_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1122/1887 drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +3 -0
@@ -1736,6 +1736,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, + .no_user_fence = true, .secure_submission_supported = true, .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v3_0_dec_ring_get_rptr,
@@ -1914,6 +1915,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .vmhub =AMDGPU_MMHUB_0 , .get_rptr = vcn_v3_0_dec_ring_get_rptr,
@@ -2016,6 +2018,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1123/1887 drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +4 -0
@@ -1527,6 +1527,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .vmhub =AMDGPU_MMHUB_1 , .get_rptr = vcn_v2_5_dec_ring_get_rptr,
@@ -1558,6 +1559,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = {static const struct amdgpu_ring_funcs vcn_v2_6_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .vmhub =AMDGPU_MMHUB_0 , .get_rptr = vcn_v2_5_dec_ring_get_rptr,
@@ -1659,6 +1661,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .vmhub = AMDGPU_MMHUB_1, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr,
@@ -1689,6 +1692,7 @@ static const struct amdgpu_ring_funcs vcn_v2_6_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1124/1887 drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +2 -0
@@ -2013,6 +2013,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .vmhub =AMDGPU_MMHUB_0 , .get_rptr = vcn_v2_0_dec_ring_get_rptr,
@@ -2045,6 +2046,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1125/1887 Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeungJu Cheon <[email protected]>
[ Upstream commit 9ca7053d6215d89c33f28893bfd1625a32919d3f ]
iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and iso_conn_big_sync() call hci_get_route() using iso_pi(sk)->dst, iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock().
These fields may be modified concurrently by connect() or setsockopt() on the same socket, resulting in data-races reported by KCSAN.
Fix this by snapshotting the required fields under lock_sock() before calling hci_get_route().
BUG: KCSAN: data-race in memcmp+0x45/0xb0
race at unknown origin, with read to 0xffff8880122135cf of 1 bytes by task 333 on cpu 1:
memcmp+0x45/0xb0 hci_get_route+0x27e/0x490 iso_connect_cis+0x4c/0xa10 iso_sock_connect+0x60e/0xb30 __sys_connect_file+0xbd/0xe0 __sys_connect+0xe0/0x110 __x64_sys_connect+0x40/0x50 x64_sys_call+0xcad/0x1c60 do_syscall_64+0x133/0x590 entry_SYSCALL_64_after_hwframe+0x77/0x7f
--- net/bluetooth/iso.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
net/bluetooth/iso.c +20 -6
@@ -267,12 +267,19 @@ static int iso_connect_bis(struct sock *sk)struct iso_conn *conn;struct hci_conn *hcon;struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type;int err; -BT_DBG ("%pMR" , &iso_pi (sk)->src); +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; +release_sock (sk); - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); +BT_DBG ("%pMR" , &src); + + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return -EHOSTUNREACH ;
@@ -337,12 +344,19 @@ static int iso_connect_cis(struct sock *sk)struct iso_conn *conn;struct hci_conn *hcon;struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type;int err; -BT_DBG ("%pMR -> %pMR" , &iso_pi (sk)->src, &iso_pi (sk)->dst); +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; +release_sock (sk); - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); +BT_DBG ("%pMR -> %pMR" , &src, &dst); + + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return -EHOSTUNREACH ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1126/1887 KVM: SEV: Ignore Port I/O requests of length 0
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit 3988bd2723de407ae90fa7a6f6029b4e60238c58 ]
Explicitly ignore Port I/O requests of length '0' (or count '0'), so that setting up the software scratch area (and other code) doesn't have to worry about underflowing the length, and to allow for WARNing on trying to configure the scratch area with len==0.
Message-ID: <[email protected]>
--- arch/x86/kvm/svm/sev.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/kvm/svm/sev.c +8 -0
@@ -2952,6 +2952,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) control->exit_info_1, control->exit_info_2); ret = -EINVAL ;break ; +case SVM_EXIT_IOIO : +if (!((control->exit_info_1 &SVM_IOIO_SIZE_MASK ) >>SVM_IOIO_SIZE_SHIFT )) +return 1 ; + + fallthrough;default : ret =svm_invoke_exit_handler (vcpu, exit_code); }
@@ -2972,6 +2977,9 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)if (unlikely (check_mul_overflow (count, size, &bytes)))return -EINVAL ; +if (!bytes) +return 1 ; + r =setup_vmgexit_scratch (svm, in, bytes);if (r)return r;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1127/1887 usb: typec: tcpm/tcpci_maxim: validate header NDO against RX_BYTE_CNT
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
[ Upstream commit aa2f716327be1818e1cb156da8a2844804aaec2f ]
A broken/malicious port can transmit a CRC-valid frame whose header advertises up to seven data objects but whose body carries fewer than that. Check for this, and rightfully reject the message, instead of reading from uninitialized stack memory.
--- drivers/usb/typec/tcpm/tcpci_maxim.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/usb/typec/tcpm/tcpci_maxim.c +9 -0
@@ -191,6 +191,15 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status) rx_buf_ptr = rx_buf +TCPC_RECEIVE_BUFFER_RX_BYTE_BUF_OFFSET ; msg.header =cpu_to_le16 (*(u16 *)rx_buf_ptr); rx_buf_ptr = rx_buf_ptr +sizeof (msg.header); + +if (count <TCPC_RECEIVE_BUFFER_RX_BYTE_BUF_OFFSET +sizeof (msg.header) + +pd_header_cnt_le (msg.header) *sizeof (msg.payload[0 ])) { +max_tcpci_write16 (chip,TCPC_ALERT ,TCPC_ALERT_RX_STATUS ); +dev_err (chip->dev,"Invalid TCPC_RX_BYTE_CNT %d for header cnt %d\n" , + count,pd_header_cnt_le (msg.header)); +return ; + } +for (payload_index =0 ; payload_index <pd_header_cnt_le (msg.header); payload_index++, rx_buf_ptr +=sizeof (msg.payload[0 ])) msg.payload[payload_index] =cpu_to_le32 (*(u32 *)rx_buf_ptr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1128/1887 usb: typec: tcpm: bound altmode_desc[] per iteration in svdm_consume_modes()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
[ Upstream commit 3389c149c68c3fea61910ad5d34f7bf3bff44e32 ]
svdm_consume_modes() checks pmdata->altmodes against the array size once before the loop over the count, but forgot to check the bound at every point in the loop.
In the well-behaved SVDM discovery flow this is harmless because each of at most SVID_DISCOVERY_MAX SVIDs contributes at most MODE_DISCOVERY_MAX modes, exactly filling altmode_desc[ALTMODE_DISCOVERY_MAX]. But the CMDT_RSP_ACK handler in tcpm_pd_svdm() does not correlate an incoming ACK with any request the port actually sent. Once port->partner is set, an unsolicited Discover Modes ACK is consumed unconditionally. A broken or malicious port partner can therefore drive altmodes to ALTMODE_DISCOVERY_MAX - 1 via the normal flow, and then send one extra Discover Modes ACK with seven VDOs. Because the pre-loop check passes, the loop could then writes up to five entries past altmode_desc[]. For mode_data_prime the next field in struct tcpm_port is the partner_altmode[] pointer array, which then receives partner-chosen SVID/VDO bytes.
Move the bound check inside the loop so the array can never be indexed past ALTMODE_DISCOVERY_MAX regardless of how many VDOs the partner supplies or how the function was reached.
--- drivers/usb/typec/tcpm/tcpm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/usb/typec/tcpm/tcpm.c +4 -5
@@ -1544,17 +1544,16 @@ static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt)struct typec_altmode_desc *paltmode;int i; -if (pmdata->altmodes >=ARRAY_SIZE (port->partner_altmode)) { -/* Already logged in svdm_consume_svids() */ -return ; - } -if (pmdata->svid_index <0 || pmdata->svid_index >= pmdata->nsvids) {tcpm_log (port,"Invalid SVID index %d" , pmdata->svid_index);return ; }for (i =1 ; i < cnt; i++) { +if (pmdata->altmodes >=ALTMODE_DISCOVERY_MAX ) { +/* Already logged in svdm_consume_svids() */ +return ; + } paltmode = &pmdata->altmode_desc[pmdata->altmodes];memset (paltmode,0 ,sizeof (*paltmode));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1129/1887 usb: typec: tcpm: validate VDO count in Discover Identity ACK handlers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
[ Upstream commit 8fbc349e8383125dd2d8de1c1e926279d398ab17 ]
Properly validate the count passed from a device when calling svdm_consume_identity() or svdm_consume_identity_sop_prime() as the device-controlled value could index off of the static arrays, which could leak data.
--- drivers/usb/typec/tcpm/tcpm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/typec/tcpm/tcpm.c +3 -0
@@ -1476,6 +1476,9 @@ static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt)u32 vdo = p[VDO_INDEX_IDH ];u32 product = p[VDO_INDEX_PRODUCT ]; +if (cnt <=VDO_INDEX_PRODUCT ) +return ; +memset (&port->mode_data,0 ,sizeof (port->mode_data)); port->partner_ident.id_header = vdo;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1130/1887 Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heitor Alves de Siqueira <[email protected]>
[ Upstream commit 525daaea459fc215f432de1b8debbd9144bf97b0 ]
Since hci_dev_close_sync() can now be called during the reset path, we should also set HCI_CMD_DRAIN_WORKQUEUE. This avoids queuing timeouts while the hdev workqueue is being drained.
--- net/bluetooth/hci_sync.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/bluetooth/hci_sync.c +8 -0
@@ -5256,6 +5256,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)bt_dev_dbg (hdev,"" ); +/* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during +* reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer(). +*/ +hci_dev_set_flag (hdev,HCI_CMD_DRAIN_WORKQUEUE ); +synchronize_rcu (); +cancel_delayed_work (&hdev->power_off);cancel_delayed_work (&hdev->ncmd_timer);cancel_delayed_work (&hdev->le_scan_disable);
@@ -5274,6 +5280,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)if (!test_and_clear_bit (HCI_UP , &hdev->flags)) {cancel_delayed_work_sync (&hdev->cmd_timer); +hci_dev_clear_flag (hdev,HCI_CMD_DRAIN_WORKQUEUE );return err; }
@@ -5367,6 +5374,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)/* Clear flags */ hdev->flags &=BIT (HCI_RAW );hci_dev_clear_volatile_flags (hdev); +hci_dev_clear_flag (hdev,HCI_CMD_DRAIN_WORKQUEUE );memset (hdev->eir,0 ,sizeof (hdev->eir));memset (hdev->dev_class,0 ,sizeof (hdev->dev_class));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1131/1887 netfilter: nf_tables: Extend nft_expr_ops::dump callback parameters
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Phil Sutter <[email protected]>
[ Upstream commit 7d34aa3e03b6a56306296bd98b26c6a1710cd57b ]
Add a 'reset' flag just like with nft_object_ops::dump. This will be useful to reset "anonymous stateful objects", e.g. simple rule counters.
No functional change intended.
Stable-dep-of: 18014147d3ee ("netfilter: nf_tables: fix dst corruption in same register operation")
--- include/net/netfilter/nf_tables.h | 3 ++- include/net/netfilter/nft_fib.h | 2 +- include/net/netfilter/nft_meta.h | 4 ++-- include/net/netfilter/nft_reject.h | 3 ++- net/ipv4/netfilter/nft_dup_ipv4.c | 3 ++- net/ipv6/netfilter/nft_dup_ipv6.c | 3 ++- net/netfilter/nf_tables_api.c | 2 +- net/netfilter/nft_bitwise.c | 6 ++++-- net/netfilter/nft_byteorder.c | 3 ++- net/netfilter/nft_cmp.c | 9 ++++++--- net/netfilter/nft_compat.c | 9 ++++++--- net/netfilter/nft_connlimit.c | 3 ++- net/netfilter/nft_counter.c | 3 ++- net/netfilter/nft_ct.c | 6 ++++-- net/netfilter/nft_dup_netdev.c | 3 ++- net/netfilter/nft_dynset.c | 3 ++- net/netfilter/nft_exthdr.c | 9 ++++++--- net/netfilter/nft_fib.c | 2 +- net/netfilter/nft_flow_offload.c | 3 ++- net/netfilter/nft_fwd_netdev.c | 6 ++++-- net/netfilter/nft_hash.c | 4 ++-- net/netfilter/nft_immediate.c | 3 ++- net/netfilter/nft_last.c | 3 ++- net/netfilter/nft_limit.c | 5 +++-- net/netfilter/nft_log.c | 3 ++- net/netfilter/nft_lookup.c | 3 ++- net/netfilter/nft_masq.c | 3 ++- net/netfilter/nft_meta.c | 5 +++-- net/netfilter/nft_nat.c | 3 ++- net/netfilter/nft_numgen.c | 6 ++++-- net/netfilter/nft_objref.c | 6 ++++-- net/netfilter/nft_osf.c | 3 ++- net/netfilter/nft_payload.c | 6 ++++-- net/netfilter/nft_queue.c | 6 ++++-- net/netfilter/nft_quota.c | 3 ++- net/netfilter/nft_range.c | 3 ++- net/netfilter/nft_redir.c | 3 ++- net/netfilter/nft_reject.c | 3 ++- net/netfilter/nft_rt.c | 2 +- net/netfilter/nft_socket.c | 2 +- net/netfilter/nft_synproxy.c | 3 ++- net/netfilter/nft_tproxy.c | 2 +- net/netfilter/nft_tunnel.c | 2 +- net/netfilter/nft_xfrm.c | 2 +- 44 files changed, 108 insertions(+), 61 deletions(-)
include/net/netfilter/nf_tables.h +2 -1
@@ -930,7 +930,8 @@ struct nft_expr_ops {void (*destroy_clone)(const struct nft_ctx *ctx,const struct nft_expr *expr);int (*dump)(struct sk_buff *skb, -const struct nft_expr *expr); +const struct nft_expr *expr, +bool reset);int (*validate)(const struct nft_ctx *ctx,const struct nft_expr *expr); bool (*reduce)(struct nft_regs_track *track,
include/net/netfilter/nft_fib.h +1 -1
@@ -18,7 +18,7 @@ nft_fib_is_loopback(const struct sk_buff *skb, const struct net_device *in)return skb->pkt_type ==PACKET_LOOPBACK || in->flags &IFF_LOOPBACK ; } -int nft_fib_dump (struct sk_buff *skb,const struct nft_expr *expr); +int nft_fib_dump (struct sk_buff *skb,const struct nft_expr *expr,bool reset);int nft_fib_init (const struct nft_ctx *ctx,const struct nft_expr *expr,const struct nlattr *const tb[]);int nft_fib_validate (const struct nft_ctx *ctx,const struct nft_expr *expr);
include/net/netfilter/nft_meta.h +2 -2
@@ -24,10 +24,10 @@ int nft_meta_set_init(const struct nft_ctx *ctx, const struct nlattr * const tb[]);int nft_meta_get_dump (struct sk_buff *skb, -const struct nft_expr *expr); +const struct nft_expr *expr,bool reset);int nft_meta_set_dump (struct sk_buff *skb, -const struct nft_expr *expr); +const struct nft_expr *expr,bool reset); void nft_meta_get_eval(const struct nft_expr *expr, struct nft_regs *regs,
include/net/netfilter/nft_reject.h +2 -1
@@ -21,7 +21,8 @@ int nft_reject_init(const struct nft_ctx *ctx,const struct nft_expr *expr, const struct nlattr * const tb[]); -int nft_reject_dump (struct sk_buff *skb,const struct nft_expr *expr); +int nft_reject_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset);int nft_reject_icmp_code (u8 code);int nft_reject_icmpv6_code (u8 code);
net/ipv4/netfilter/nft_dup_ipv4.c +2 -1
@@ -52,7 +52,8 @@ static int nft_dup_ipv4_init(const struct nft_ctx *ctx,return err; } -static int nft_dup_ipv4_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_dup_ipv4_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_dup_ipv4 *priv =nft_expr_priv (expr);
net/ipv6/netfilter/nft_dup_ipv6.c +2 -1
@@ -50,7 +50,8 @@ static int nft_dup_ipv6_init(const struct nft_ctx *ctx,return err; } -static int nft_dup_ipv6_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_dup_ipv6_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_dup_ipv6 *priv =nft_expr_priv (expr);
net/netfilter/nf_tables_api.c +1 -1
@@ -2976,7 +2976,7 @@ static int nf_tables_fill_expr_info(struct sk_buff *skb, NFTA_EXPR_DATA);if (data ==NULL ) goto nla_put_failure; -if (expr->ops->dump (skb, expr) <0 ) +if (expr->ops->dump (skb, expr, false) <0 ) goto nla_put_failure;nla_nest_end (skb, data); }
net/netfilter/nft_bitwise.c +4 -2
@@ -233,7 +233,8 @@ static int nft_bitwise_dump_shift(struct sk_buff *skb,return 0 ; } -static int nft_bitwise_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_bitwise_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_bitwise *priv =nft_expr_priv (expr);int err =0 ;
@@ -394,7 +395,8 @@ static int nft_bitwise_fast_init(const struct nft_ctx *ctx, }static int -nft_bitwise_fast_dump (struct sk_buff *skb,const struct nft_expr *expr) +nft_bitwise_fast_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_bitwise_fast_expr *priv =nft_expr_priv (expr);struct nft_data data;
net/netfilter/nft_byteorder.c +2 -1
@@ -149,7 +149,8 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, priv->len); } -static int nft_byteorder_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_byteorder_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_byteorder *priv =nft_expr_priv (expr);
net/netfilter/nft_cmp.c +6 -3
@@ -92,7 +92,8 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,return 0 ; } -static int nft_cmp_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_cmp_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_cmp_expr *priv =nft_expr_priv (expr);
@@ -253,7 +254,8 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,return __nft_cmp_offload (ctx, flow, &cmp); } -static int nft_cmp_fast_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_cmp_fast_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_cmp_fast_expr *priv =nft_expr_priv (expr);enum nft_cmp_ops op = priv->inv ?NFT_CMP_NEQ :NFT_CMP_EQ ;
@@ -347,7 +349,8 @@ static int nft_cmp16_fast_offload(struct nft_offload_ctx *ctx,return __nft_cmp_offload (ctx, flow, &cmp); } -static int nft_cmp16_fast_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_cmp16_fast_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_cmp16_fast_expr *priv =nft_expr_priv (expr);enum nft_cmp_ops op = priv->inv ?NFT_CMP_NEQ :NFT_CMP_EQ ;
net/netfilter/nft_compat.c +6 -3
@@ -332,7 +332,8 @@ static int nft_extension_dump_info(struct sk_buff *skb, int attr,return 0 ; } -static int nft_target_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_target_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct xt_target *target = expr->ops->data;void *info =nft_expr_priv (expr);
@@ -596,12 +597,14 @@ static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr,return -1 ; } -static int nft_match_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_match_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {return __nft_match_dump (skb, expr,nft_expr_priv (expr)); } -static int nft_match_large_dump (struct sk_buff *skb,const struct nft_expr *e) +static int nft_match_large_dump (struct sk_buff *skb, +const struct nft_expr *e,bool reset) {struct nft_xt_match_priv *priv =nft_expr_priv (e);
net/netfilter/nft_connlimit.c +2 -1
@@ -179,7 +179,8 @@ static void nft_connlimit_eval(const struct nft_expr *expr,nft_connlimit_do_eval (priv, regs, pkt,NULL ); } -static int nft_connlimit_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_connlimit_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_connlimit *priv =nft_expr_priv (expr);
net/netfilter/nft_counter.c +2 -1
@@ -222,7 +222,8 @@ void nft_counter_eval(const struct nft_expr *expr, struct nft_regs *regs,nft_counter_do_eval (priv, regs, pkt); } -static int nft_counter_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_counter_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_counter_percpu_priv *priv =nft_expr_priv (expr);
net/netfilter/nft_ct.c +4 -2
@@ -649,7 +649,8 @@ static void nft_ct_set_destroy(const struct nft_ctx *ctx,nf_ct_netns_put (ctx->net, ctx->family); } -static int nft_ct_get_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_ct_get_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_ct *priv =nft_expr_priv (expr);
@@ -711,7 +712,8 @@ static bool nft_ct_get_reduce(struct nft_regs_track *track,return nft_expr_reduce_bitwise (track, expr); } -static int nft_ct_set_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_ct_set_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_ct *priv =nft_expr_priv (expr);
net/netfilter/nft_dup_netdev.c +2 -1
@@ -44,7 +44,8 @@ static int nft_dup_netdev_init(const struct nft_ctx *ctx, sizeof(int)); } -static int nft_dup_netdev_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_dup_netdev_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_dup_netdev *priv =nft_expr_priv (expr);
net/netfilter/nft_dynset.c +2 -1
@@ -373,7 +373,8 @@ static void nft_dynset_destroy(const struct nft_ctx *ctx,nf_tables_destroy_set (ctx, priv->set); } -static int nft_dynset_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_dynset_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_dynset *priv =nft_expr_priv (expr);u32 flags = priv->invert ?NFT_DYNSET_F_INV :0 ;
net/netfilter/nft_exthdr.c +6 -3
@@ -672,7 +672,8 @@ static int nft_exthdr_dump_common(struct sk_buff *skb, const struct nft_exthdr *return -1 ; } -static int nft_exthdr_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_exthdr_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_exthdr *priv =nft_expr_priv (expr);
@@ -682,7 +683,8 @@ static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)return nft_exthdr_dump_common (skb, priv); } -static int nft_exthdr_dump_set (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_exthdr_dump_set (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_exthdr *priv =nft_expr_priv (expr);
@@ -692,7 +694,8 @@ static int nft_exthdr_dump_set(struct sk_buff *skb, const struct nft_expr *expr)return nft_exthdr_dump_common (skb, priv); } -static int nft_exthdr_dump_strip (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_exthdr_dump_strip (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_exthdr *priv =nft_expr_priv (expr);
net/netfilter/nft_fib.c +1 -1
@@ -121,7 +121,7 @@ int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr, }EXPORT_SYMBOL_GPL (nft_fib_init); -int nft_fib_dump (struct sk_buff *skb,const struct nft_expr *expr) +int nft_fib_dump (struct sk_buff *skb,const struct nft_expr *expr,bool reset) {const struct nft_fib *priv =nft_expr_priv (expr);
net/netfilter/nft_flow_offload.c +2 -1
@@ -462,7 +462,8 @@ static void nft_flow_offload_destroy(const struct nft_ctx *ctx,nf_ct_netns_put (ctx->net, ctx->family); } -static int nft_flow_offload_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_flow_offload_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_flow_offload *priv =nft_expr_priv (expr);
net/netfilter/nft_fwd_netdev.c +4 -2
@@ -56,7 +56,8 @@ static int nft_fwd_netdev_init(const struct nft_ctx *ctx, sizeof(int)); } -static int nft_fwd_netdev_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_fwd_netdev_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_fwd_netdev *priv =nft_expr_priv (expr);
@@ -196,7 +197,8 @@ static int nft_fwd_neigh_init(const struct nft_ctx *ctx, addr_len); } -static int nft_fwd_neigh_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_fwd_neigh_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_fwd_neigh *priv =nft_expr_priv (expr);
net/netfilter/nft_hash.c +2 -2
@@ -139,7 +139,7 @@ static int nft_symhash_init(const struct nft_ctx *ctx, }static int nft_jhash_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_jhash *priv =nft_expr_priv (expr);
@@ -176,7 +176,7 @@ static bool nft_jhash_reduce(struct nft_regs_track *track, }static int nft_symhash_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_symhash *priv =nft_expr_priv (expr);
net/netfilter/nft_immediate.c +2 -1
@@ -228,7 +228,8 @@ static void nft_immediate_destroy(const struct nft_ctx *ctx, } } -static int nft_immediate_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_immediate_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_immediate_expr *priv =nft_expr_priv (expr);
net/netfilter/nft_last.c +2 -1
@@ -65,7 +65,8 @@ static void nft_last_eval(const struct nft_expr *expr,WRITE_ONCE (last->set,1 ); } -static int nft_last_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_last_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_last_priv *priv =nft_expr_priv (expr);struct nft_last *last = priv->last;
net/netfilter/nft_limit.c +3 -2
@@ -207,7 +207,8 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx,return 0 ; } -static int nft_limit_pkts_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_limit_pkts_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_limit_priv_pkts *priv =nft_expr_priv (expr);
@@ -266,7 +267,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx, }static int nft_limit_bytes_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_limit_priv *priv =nft_expr_priv (expr);
net/netfilter/nft_log.c +2 -1
@@ -185,7 +185,8 @@ static void nft_log_destroy(const struct nft_ctx *ctx,nf_logger_put (ctx->family, li->type); } -static int nft_log_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_log_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_log *priv =nft_expr_priv (expr);const struct nf_loginfo *li = &priv->loginfo;
net/netfilter/nft_lookup.c +2 -1
@@ -179,7 +179,8 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx,nf_tables_destroy_set (ctx, priv->set); } -static int nft_lookup_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_lookup_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_lookup *priv =nft_expr_priv (expr);u32 flags = priv->invert ?NFT_LOOKUP_F_INV :0 ;
net/netfilter/nft_masq.c +2 -1
@@ -72,7 +72,8 @@ static int nft_masq_init(const struct nft_ctx *ctx,return nf_ct_netns_get (ctx->net, ctx->family); } -static int nft_masq_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_masq_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_masq *priv =nft_expr_priv (expr);
net/netfilter/nft_meta.c +3 -2
@@ -667,7 +667,7 @@ int nft_meta_set_init(const struct nft_ctx *ctx,EXPORT_SYMBOL_GPL (nft_meta_set_init);int nft_meta_get_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_meta *priv =nft_expr_priv (expr);
@@ -682,7 +682,8 @@ int nft_meta_get_dump(struct sk_buff *skb, }EXPORT_SYMBOL_GPL (nft_meta_get_dump); -int nft_meta_set_dump (struct sk_buff *skb,const struct nft_expr *expr) +int nft_meta_set_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_meta *priv =nft_expr_priv (expr);
net/netfilter/nft_nat.c +2 -1
@@ -259,7 +259,8 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,return nf_ct_netns_get (ctx->net, family); } -static int nft_nat_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_nat_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_nat *priv =nft_expr_priv (expr);
net/netfilter/nft_numgen.c +4 -2
@@ -112,7 +112,8 @@ static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg,return -1 ; } -static int nft_ng_inc_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_ng_inc_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_ng_inc *priv =nft_expr_priv (expr);
@@ -168,7 +169,8 @@ static int nft_ng_random_init(const struct nft_ctx *ctx, NULL, NFT_DATA_VALUE, sizeof(u32)); } -static int nft_ng_random_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_ng_random_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_ng_random *priv =nft_expr_priv (expr);
net/netfilter/nft_objref.c +4 -2
@@ -78,7 +78,8 @@ static int nft_objref_init(const struct nft_ctx *ctx,return 0 ; } -static int nft_objref_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_objref_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_object *obj =nft_objref_priv (expr);
@@ -188,7 +189,8 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,return 0 ; } -static int nft_objref_map_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_objref_map_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_objref_map *priv =nft_expr_priv (expr);
net/netfilter/nft_osf.c +2 -1
@@ -97,7 +97,8 @@ static int nft_osf_init(const struct nft_ctx *ctx,return 0 ; } -static int nft_osf_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_osf_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_osf *priv =nft_expr_priv (expr);
net/netfilter/nft_payload.c +4 -2
@@ -198,7 +198,8 @@ static int nft_payload_init(const struct nft_ctx *ctx, priv->len); } -static int nft_payload_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_payload_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_payload *priv =nft_expr_priv (expr);
@@ -851,7 +852,8 @@ static int nft_payload_set_init(const struct nft_ctx *ctx, priv->len); } -static int nft_payload_set_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_payload_set_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_payload_set *priv =nft_expr_priv (expr);
net/netfilter/nft_queue.c +4 -2
@@ -151,7 +151,8 @@ static int nft_queue_sreg_init(const struct nft_ctx *ctx,return 0 ; } -static int nft_queue_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_queue_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_queue *priv =nft_expr_priv (expr);
@@ -167,7 +168,8 @@ static int nft_queue_dump(struct sk_buff *skb, const struct nft_expr *expr) }static int -nft_queue_sreg_dump (struct sk_buff *skb,const struct nft_expr *expr) +nft_queue_sreg_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_queue *priv =nft_expr_priv (expr);
net/netfilter/nft_quota.c +2 -1
@@ -223,7 +223,8 @@ static int nft_quota_init(const struct nft_ctx *ctx,return nft_quota_do_init (tb, priv); } -static int nft_quota_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_quota_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_quota *priv =nft_expr_priv (expr);
net/netfilter/nft_range.c +2 -1
@@ -111,7 +111,8 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *exprreturn err; } -static int nft_range_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_range_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_range_expr *priv =nft_expr_priv (expr);
net/netfilter/nft_redir.c +2 -1
@@ -76,7 +76,8 @@ static int nft_redir_init(const struct nft_ctx *ctx,return nf_ct_netns_get (ctx->net, ctx->family); } -static int nft_redir_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_redir_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_redir *priv =nft_expr_priv (expr);
net/netfilter/nft_reject.c +2 -1
@@ -68,7 +68,8 @@ int nft_reject_init(const struct nft_ctx *ctx, }EXPORT_SYMBOL_GPL (nft_reject_init); -int nft_reject_dump (struct sk_buff *skb,const struct nft_expr *expr) +int nft_reject_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {const struct nft_reject *priv =nft_expr_priv (expr);
net/netfilter/nft_rt.c +1 -1
@@ -146,7 +146,7 @@ static int nft_rt_get_init(const struct nft_ctx *ctx, }static int nft_rt_get_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_rt *priv =nft_expr_priv (expr);
net/netfilter/nft_socket.c +1 -1
@@ -235,7 +235,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, }static int nft_socket_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_socket *priv =nft_expr_priv (expr);
net/netfilter/nft_synproxy.c +2 -1
@@ -274,7 +274,8 @@ static void nft_synproxy_destroy(const struct nft_ctx *ctx,nft_synproxy_do_destroy (ctx); } -static int nft_synproxy_dump (struct sk_buff *skb,const struct nft_expr *expr) +static int nft_synproxy_dump (struct sk_buff *skb, +const struct nft_expr *expr,bool reset) {struct nft_synproxy *priv =nft_expr_priv (expr);
net/netfilter/nft_tproxy.c +1 -1
@@ -294,7 +294,7 @@ static void nft_tproxy_destroy(const struct nft_ctx *ctx, }static int nft_tproxy_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_tproxy *priv =nft_expr_priv (expr);
net/netfilter/nft_tunnel.c +1 -1
@@ -108,7 +108,7 @@ static int nft_tunnel_get_init(const struct nft_ctx *ctx, }static int nft_tunnel_get_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_tunnel *priv =nft_expr_priv (expr);
net/netfilter/nft_xfrm.c +1 -1
@@ -212,7 +212,7 @@ static void nft_xfrm_get_eval(const struct nft_expr *expr, }static int nft_xfrm_get_dump (struct sk_buff *skb, -const struct nft_expr *expr) +const struct nft_expr *expr,bool reset) {const struct nft_xfrm *priv =nft_expr_priv (expr);
Signature · 1 line
2.53.0
Re: [PATCH 6.1 1131/1887] netfilter: nf_tables: Extend nft_expr_ops::dump callback parameters
Hi,
Quoted 1 line · Greg Kroah-Hartman
6.1-stable review patch. If anyone has any objections, please let me know.
Not quite an objection (the "no functional change" still holds IMO), but I don't get why it is being backported.
Quoted 6 lines
------------------
From: Phil Sutter <[email protected]>
[ Upstream commit
7d34aa3e03b6a56306296bd98b26c6a1710cd57b]
Quoted 8 lines
Add a 'reset' flag just like with
nft_object_ops::dump. This will be useful to reset "anonymous stateful objects", e.g. simple rule counters.No functional change intended.
Signed-off-by Phil Sutter <[email protected]>Signed-off-by Pablo Neira Ayuso <[email protected]>Stable-dep-of:
18014147d3ee("netfilter:nf_tables: fix dst corruption in same register operation")
I don't see how this commit could require the extra callback parameter. Is it really just to avoid a context change in nft_byteorder.c?
Cheers, Phil
Sasha Levin
maintainerRe: [PATCH 6.1 1131/1887] netfilter: nf_tables: Extend nft_expr_ops::dump callback parameters
Quoted 2 lines
Not quite an objection (the "no functional change" still holds IMO), but I don't get why it is being backported.
Yes, it is only there to avoid a context change in nft_byteorder.c. The upstream fix 18014147d3ee ("netfilter: nf_tables: fix dst corruption in same register operation") has a hunk there that carries the two-line nft_byteorder_dump() prototype from 7d34aa3e03b6 ("netfilter: nf_tables: Extend nft_expr_ops::dump callback parameters") as context.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 1132/1887 netfilter: nf_tables: fix dst corruption in same register operation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 18014147d3ee7831dce53fe65d7fc8d428b02552 ]
For lshift and rshift, the shift operations are performed in a loop over 32-bit words. The loop calculates the shifted value and write it to dst, and then immediately reads from src to calculate the carry for the next iteration. Because src and dst could point to the same memory location, the carry is incorrectly calculated using the newly modified dst value instead of the original src value.
Adding a temporary local variable to cache the original value before writing to dst and using it for the carry calculation solves the problem. In addition, partial overlap is rejected from control plane for all kind of operations including byteorder. This was tested with the following bytecode:
table test_table ip flags 0 use 1 handle 1
ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1 ip test_table test_chain 2
[ immediate reg 1 0x44332211 0x88776655 ]
[ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
[ cmp eq reg 1 0x66443322 0x00887766 ]
[ counter pkts 0 bytes 0 ]
ip test_table test_chain 4 3
[ immediate reg 1 0x44332211 0x88776655 ]
[ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
[ cmp eq reg 1 0x55443322 0x00887766 ]
[ counter pkts 21794 bytes 1917798 ]
--- include/net/netfilter/nf_tables.h | 7 +++++++ net/netfilter/nft_bitwise.c | 15 +++++++++++---- net/netfilter/nft_byteorder.c | 13 ++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-)
include/net/netfilter/nf_tables.h +7 -0
@@ -187,6 +187,13 @@ static inline u64 nft_reg_load64(const u32 *sreg)return get_unaligned ((u64 *)sreg); } +static inline bool nft_reg_overlap (u8 src,u8 dst,u32 len) +{ +unsigned int n =DIV_ROUND_UP (len,sizeof (u32)); + +return src != dst && src < dst + n && dst < src + n; +} +static inline void nft_data_copy (u32 *dst,const struct nft_data *src,unsigned int len) {
net/netfilter/nft_bitwise.c +11 -4
@@ -42,8 +42,10 @@ static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src,u32 carry =0 ;for (i =DIV_ROUND_UP (priv->len,sizeof (u32)); i >0 ; i--) { - dst[i -1 ] = (src[i -1 ] << shift) | carry; - carry = src[i -1 ] >> (BITS_PER_TYPE (u32) - shift); +u32 tmp_src = src[i -1 ]; + + dst[i -1 ] = (tmp_src << shift) | carry; + carry = tmp_src >> (BITS_PER_TYPE (u32) - shift); } }
@@ -55,8 +57,10 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src,u32 carry =0 ;for (i =0 ; i <DIV_ROUND_UP (priv->len,sizeof (u32)); i++) { - dst[i] = carry | (src[i] >> shift); - carry = src[i] << (BITS_PER_TYPE (u32) - shift); +u32 tmp_src = src[i]; + + dst[i] = carry | (tmp_src >> shift); + carry = tmp_src << (BITS_PER_TYPE (u32) - shift); } }
@@ -183,6 +187,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,if (err <0 )return err; +if (nft_reg_overlap (priv->sreg, priv->dreg, priv->len)) +return -EINVAL ; +if (tb[NFTA_BITWISE_OP ]) { priv->op =ntohl (nla_get_be32 (tb[NFTA_BITWISE_OP ]));switch (priv->op) {
net/netfilter/nft_byteorder.c +10 -3
@@ -144,9 +144,16 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,if (err <0 )return err; -return nft_parse_register_store (ctx, tb[NFTA_BYTEORDER_DREG ], - &priv->dreg,NULL ,NFT_DATA_VALUE , - priv->len); + err =nft_parse_register_store (ctx, tb[NFTA_BYTEORDER_DREG ], + &priv->dreg,NULL ,NFT_DATA_VALUE , + priv->len); +if (err <0 ) +return err; + +if (nft_reg_overlap (priv->sreg, priv->dreg, priv->len)) +return -EINVAL ; + +return 0 ; } static int nft_byteorder_dump(struct sk_buff *skb,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1133/1887 blk-mq: pop cached request if it is usable
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit dc278e9bf2b9513a763353e6b9cc21e0f532954e ]
When submitting a bio to blk-mq, if the task should sleep after peeking a cached request, but before it pops it, the plug flushes and calls blk_mq_free_plug_rqs, freeing the cached_rqs. This creates a use-after-free bug. Fix this by popping the cached request before any possible blocking calls if it is suitable for use.
Popping this request first holds a queue reference, so avoid any serialization races with queue freezes and can safely proceed with dispatching that request to the driver. This potentially increases a timing window from when a driver wants to freeze its queue to when requests stop being dispatched. That scenario is off the fast path though, and drivers need to appropriately handle requests during a freeze request anyway.
The downside is the popped element needs to be individually freed when we performed a bio plug merge. The cached request would have had to be freed later anyway, but this patch does it inline with building the plug list instead of after flushing it.
--- block/blk-mq.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-)
block/blk-mq.c +13 -15
@@ -2953,16 +2953,7 @@ static bool blk_mq_can_use_cached_rq(struct request *rq, struct blk_plug *plug,if (op_is_flush (rq->cmd_flags) !=op_is_flush (bio->bi_opf))return false; -/* -* If any qos ->throttle() end up blocking, we will have flushed the -* plug and hence killed the cached_rq list as well. Pop this entry -* before we throttle. -*/ plug->cached_rq =rq_list_next (rq); -rq_qos_throttle (rq->q, bio); - - rq->cmd_flags = bio->bi_opf; -INIT_LIST_HEAD (&rq->queuelist);return true; }
@@ -2994,20 +2985,23 @@ void blk_mq_submit_bio(struct bio *bio) rq =rq_list_peek (&plug->cached_rq);if (rq && rq->q != q) rq =NULL ; +if (rq && !blk_mq_can_use_cached_rq (rq, plug, bio)) + rq =NULL ; }if (rq) {if (unlikely (bio_may_exceed_limits (bio, &q->limits))) { bio =__bio_split_to_limits (bio, &q->limits, &nr_segs);if (!bio) -return ; + goto free_rq; }if (!bio_integrity_prep (bio)) -return ; + goto free_rq;if (blk_mq_attempt_bio_merge (q, bio, nr_segs)) -return ; -if (blk_mq_can_use_cached_rq (rq, plug, bio)) - goto done; -percpu_ref_get (&q->q_usage_counter); + goto free_rq; +rq_qos_throttle (q, bio); + rq->cmd_flags = bio->bi_opf; +INIT_LIST_HEAD (&rq->queuelist); + goto done; }else {if (unlikely (bio_queue_enter (bio)))return ;
@@ -3056,6 +3050,10 @@ void blk_mq_submit_bio(struct bio *bio)else blk_mq_run_dispatch_ops (rq->q,blk_mq_try_issue_directly (rq->mq_hctx, rq)); +return ; + +free_rq: +blk_mq_free_request (rq); }#ifdef CONFIG_BLK_MQ_STACKING
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1134/1887 bpf, skmsg: fix verdict sk_data_ready racing with ktls rx
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xingwang Xiang <[email protected]>
[ Upstream commit ddf8029623a1af20e984c040e89ff918158397ab ]
sk_psock_strp_data_ready() already checks tls_sw_has_ctx_rx() and defers to psock->saved_data_ready when a TLS RX context is present, avoiding a conflict with the TLS strparser's ownership of the receive queue (commit e91de6afa81c, "bpf: Fix running sk_skb program types with ktls").
sk_psock_verdict_data_ready() has no equivalent guard. When a socket is inserted into a sockmap (BPF_SK_SKB_VERDICT) before TLS RX is configured, tls_sw_strparser_arm() saves sk_psock_verdict_data_ready as rx_ctx->saved_data_ready. On data arrival:
tls_data_ready -> tls_strp_data_ready -> tls_rx_msg_ready
-> saved_data_ready() = sk_psock_verdict_data_ready()
-> tcp_read_skb() drains sk_receive_queue via __skb_unlink()
without calling tcp_eat_skb(), so copied_seq is not advanced.tls_strp_msg_load() then finds tcp_inq() >= full_len (stale), calls tcp_recv_skb() on the now-empty queue, hits WARN_ON_ONCE(!first), and returns with rx_ctx->strp.anchor.frag_list pointing at a psock-owned (potentially freed) skb. tls_decrypt_sg() subsequently walks thatfrag_list: use-after-free.
Apply the same fix as sk_psock_strp_data_ready(): if a TLS RX context is present, call psock->saved_data_ready (sock_def_readable) to wake recv() waiters and return immediately, leaving the receive queue untouched. TLS retains sole ownership of the queue and decrypts the record normally through tls_sw_recvmsg().
--- net/core/skmsg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
net/core/skmsg.c +7 -2
@@ -1267,10 +1267,17 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)static void sk_psock_verdict_data_ready (struct sock *sk) {const struct proto_ops *ops =NULL ; +struct sk_psock *psock;struct socket *sock;int copied;rcu_read_lock (); + psock =sk_psock (sk); +if (psock &&tls_sw_has_ctx_rx (sk)) { + psock->saved_data_ready (sk); +rcu_read_unlock (); +return ; + } sock =READ_ONCE (sk->sk_socket);if (likely (sock)) ops =READ_ONCE (sock->ops);
@@ -1280,8 +1287,6 @@ static void sk_psock_verdict_data_ready(struct sock *sk) copied = ops->read_skb (sk, sk_psock_verdict_recv);if (copied >=0 ) { -struct sk_psock *psock; -rcu_read_lock (); psock =sk_psock (sk);if (psock)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1135/1887 hwmon: (lm90) Stop work before releasing hwmon device
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit b09a45601094c7f4ec4db8090b825fa61e169d93 ]
Sashiko reports:
In lm90_probe(), the devm action to cancel the alert_work and report_work (lm90_restore_conf) is registered in lm90_init_client() before devm_hwmon_device_register_with_info() is called.
Because devm executes cleanup actions in reverse order during module unbind or probe failure, the hwmon device is unregistered and freed first.
If lm90_alert_work() or lm90_report_alarms() runs in the window between the hwmon device being freed and the delayed works being cancelled, lm90_update_alarms() will dereference the freed data->hwmon_dev here.
Fix the problem by canceling the workers separately after registering the hwmon device and before registering the interrupt handler. This ensures that the workers are canceled after interrupts are disabled and before the hwmon device is released. Add "shutdown" flag to indicate that device shutdown is in progress to prevent workers from being re-armed.
--- drivers/hwmon/lm90.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
drivers/hwmon/lm90.c +20 -4
@@ -694,6 +694,7 @@ struct lm90_data {struct mutex update_lock;struct delayed_work alert_work;struct work_struct report_work; +bool shutdown;/* true if shutting down */ bool valid;/* true if register values are valid */ bool alarms_valid;/* true if status register values are valid */ unsigned long last_updated;/* in jiffies */
@@ -1112,6 +1113,9 @@ static void lm90_report_alarms(struct work_struct *work)static int lm90_update_alarms_locked (struct lm90_data *data,bool force) { +if (data->shutdown) +return 0 ; +if (force || !data->alarms_valid ||time_after (jiffies, data->alarms_updated +msecs_to_jiffies (data->update_interval))) {struct i2c_client *client = data->client;
@@ -2557,15 +2561,23 @@ static void lm90_restore_conf(void *_data)struct lm90_data *data = _data;struct i2c_client *client = data->client; -cancel_delayed_work_sync (&data->alert_work); -cancel_work_sync (&data->report_work); -/* Restore initial configuration */ if (data->flags &LM90_HAVE_CONVRATE )lm90_write_convrate (data, data->convrate_orig);lm90_write_reg (client,LM90_REG_CONFIG1 , data->config_orig); } +static void lm90_stop_work (void *_data) +{ +struct lm90_data *data = _data; + +mutex_lock (&data->update_lock); + data->shutdown = true; +mutex_unlock (&data->update_lock); +cancel_delayed_work_sync (&data->alert_work); +cancel_work_sync (&data->report_work); +} +static int lm90_init_client (struct i2c_client *client,struct lm90_data *data) {struct device_node *np = client->dev.of_node;
@@ -2914,6 +2926,10 @@ static int lm90_probe(struct i2c_client *client) data->hwmon_dev = hwmon_dev; + err =devm_add_action_or_reset (&client->dev, lm90_stop_work, data); +if (err) +return err; +if (client->irq) {dev_dbg (dev,"IRQ: %d\n" , client->irq); err = devm_request_threaded_irq(dev, client->irq,
@@ -2942,7 +2958,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,*/ struct lm90_data *data =i2c_get_clientdata (client); -if ((data->flags &LM90_HAVE_BROKEN_ALERT ) && +if (!data->shutdown && (data->flags &LM90_HAVE_BROKEN_ALERT ) && (data->current_alarms & data->alert_alarms)) {if (!(data->config &0x80 )) {dev_dbg (&client->dev,"Disabling ALERT#\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1136/1887 netfilter: bridge: eb_tables: close module init race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ]
sashiko reports for unrelated patch:
Does the core ebtables initialization in ebtables.c suffer from a similar race? Once nf_register_sockopt() completes, the sockopts are exposed globally.
sockopt has to be registered last, just like in ip/ip6/arptables.
--- net/bridge/netfilter/ebtables.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
net/bridge/netfilter/ebtables.c +6 -5
@@ -2607,19 +2607,20 @@ static int __init ebtables_init(void) {int ret; - ret =xt_register_target (&ebt_standard_target); + ret =register_pernet_subsys (&ebt_net_ops);if (ret <0 )return ret; - ret =nf_register_sockopt (&ebt_sockopts); + + ret =xt_register_target (&ebt_standard_target);if (ret <0 ) { -xt_unregister_target (&ebt_standard_target); +unregister_pernet_subsys (&ebt_net_ops);return ret; } - ret =register_pernet_subsys (&ebt_net_ops); + ret =nf_register_sockopt (&ebt_sockopts);if (ret <0 ) { -nf_unregister_sockopt (&ebt_sockopts);xt_unregister_target (&ebt_standard_target); +unregister_pernet_subsys (&ebt_net_ops);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1137/1887 netfilter: ebtables: move to two-stage removal scheme
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ]
Like previous patches for x_tables, follow same pattern in ebtables. We can't reuse xt helpers: ebt_table struct layout is incompatible.
table->ops assignment is now done while still holding the ebt mutex to make sure we never expose partially-filled table struct.
--- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- 4 files changed, 40 insertions(+), 26 deletions(-)
net/bridge/netfilter/ebtable_broute.c +1 -1
@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) static void __exit ebtable_broute_fini(void) { -unregister_pernet_subsys (&broute_net_ops);ebt_unregister_template (&broute_table); +unregister_pernet_subsys (&broute_net_ops); }module_init (ebtable_broute_init);
net/bridge/netfilter/ebtable_filter.c +1 -1
@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) static void __exit ebtable_filter_fini(void) { -unregister_pernet_subsys (&frame_filter_net_ops);ebt_unregister_template (&frame_filter); +unregister_pernet_subsys (&frame_filter_net_ops); }module_init (ebtable_filter_init);
net/bridge/netfilter/ebtable_nat.c +1 -1
@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) static void __exit ebtable_nat_fini(void) { -unregister_pernet_subsys (&frame_nat_net_ops);ebt_unregister_template (&frame_nat); +unregister_pernet_subsys (&frame_nat_net_ops); }module_init (ebtable_nat_init);
net/bridge/netfilter/ebtables.c +37 -23
115 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1138/1887 ksmbd: validate SID in parent security descriptor during ACL inheritance
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junyi Liu <[email protected]>
[ Upstream commit 69f030cf95488ae1186c72ac8c66fd279664ea7f ]
Introduce smb_validate_ntsd_sid() helper to safely validate Owner SID and Group SID inside the NT Security Descriptor (smb_ntsd) retrieved from the parent directory.
--- fs/smb/server/smbacl.c | 66 ++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-)
fs/smb/server/smbacl.c +50 -16
@@ -1127,6 +1127,40 @@ static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size,return 0 ; } +static int smb_validate_ntsd_sid (struct smb_ntsd *pntsd,size_t pntsd_size, +unsigned int sid_offset,struct smb_sid **sid, +size_t *sid_size) +{ +size_t sid_end; + + *sid =NULL ; + *sid_size =0 ; + +if (!sid_offset) +return 0 ; + +if (sid_offset <sizeof (struct smb_ntsd ) || +check_add_overflow (sid_offset, (size_t )CIFS_SID_BASE_SIZE , + &sid_end) || + sid_end > pntsd_size) +return -EINVAL ; + + *sid = (struct smb_sid *)((char *)pntsd + sid_offset); +if ((*sid)->num_subauth >SID_MAX_SUB_AUTHORITIES ) +return -EINVAL ; + +if (check_add_overflow ((size_t )CIFS_SID_BASE_SIZE , +sizeof (__le32) * (size_t )(*sid)->num_subauth, + &sid_end)) +return -EINVAL ; + +if (sid_offset > pntsd_size || sid_end > pntsd_size - sid_offset) +return -EINVAL ; + + *sid_size = sid_end; +return 0 ; +} +int smb_inherit_dacl (struct ksmbd_conn *conn,const struct path *path,unsigned int uid,unsigned int gid)
@@ -1139,27 +1173,27 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,struct dentry *parent = path->dentry->d_parent;struct user_namespace *user_ns =mnt_user_ns (path->mnt);int inherited_flags =0 , flags =0 , i, ace_cnt =0 , nt_size =0 , pdacl_size; -int rc =0 , num_aces, pntsd_type, pntsd_size, acl_len, aces_size; +int rc =0 , num_aces, pntsd_type, ppntsd_size, acl_len, aces_size;unsigned int dacloffset;size_t dacl_struct_end;char *aces_base;bool is_dir =S_ISDIR (d_inode (path->dentry)->i_mode); - pntsd_size =ksmbd_vfs_get_sd_xattr (conn, user_ns, + ppntsd_size =ksmbd_vfs_get_sd_xattr (conn, user_ns, parent, &parent_pntsd); -if (pntsd_size <=0 ) +if (ppntsd_size <=0 )return -ENOENT ; dacloffset =le32_to_cpu (parent_pntsd->dacloffset);if (!dacloffset ||check_add_overflow (dacloffset,sizeof (struct smb_acl ), &dacl_struct_end) || - dacl_struct_end > (size_t )pntsd_size) { + dacl_struct_end > (size_t )ppntsd_size) { rc = -EINVAL ; goto free_parent_pntsd; } parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); - acl_len = pntsd_size - dacloffset; + acl_len = ppntsd_size - dacloffset; num_aces =le32_to_cpu (parent_pdacl->num_aces); pntsd_type =le16_to_cpu (parent_pntsd->type); pdacl_size =le16_to_cpu (parent_pdacl->size);
@@ -1273,19 +1307,19 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,struct smb_ntsd *pntsd;struct smb_acl *pdacl;struct smb_sid *powner_sid =NULL , *pgroup_sid =NULL ; -int powner_sid_size =0 , pgroup_sid_size =0 , pntsd_size; +size_t powner_sid_size =0 , pgroup_sid_size =0 , pntsd_size;size_t pntsd_alloc_size; -if (parent_pntsd->osidoffset) { - powner_sid = (struct smb_sid *)((char *)parent_pntsd + -le32_to_cpu (parent_pntsd->osidoffset)); - powner_sid_size =1 +1 +6 + (powner_sid->num_subauth *4 ); - } -if (parent_pntsd->gsidoffset) { - pgroup_sid = (struct smb_sid *)((char *)parent_pntsd + -le32_to_cpu (parent_pntsd->gsidoffset)); - pgroup_sid_size =1 +1 +6 + (pgroup_sid->num_subauth *4 ); - } + rc =smb_validate_ntsd_sid (parent_pntsd, ppntsd_size, +le32_to_cpu (parent_pntsd->osidoffset), + &powner_sid, &powner_sid_size); +if (rc) + goto free_aces_base; + rc =smb_validate_ntsd_sid (parent_pntsd, ppntsd_size, +le32_to_cpu (parent_pntsd->gsidoffset), + &pgroup_sid, &pgroup_sid_size); +if (rc) + goto free_aces_base; if (check_add_overflow(sizeof(struct smb_ntsd), (size_t)powner_sid_size,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1139/1887 Bluetooth: btmtk: fix urb->setup_packet leak in error paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit dd1dda6b8d6e1f4376a5b3055a04f0ecbdb4d6bd ]
The setup_packet of control urb is not freed if usb_submit_urb fails or the submitted urb is killed. Add free in these two paths.
--- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/bluetooth/btusb.c +2 -0
@@ -2562,6 +2562,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)return ; }else if (urb->status == -ENOENT ) {/* Avoid suspend failed when usb_kill_urb */ +kfree (urb->setup_packet);return ; }
@@ -2635,6 +2636,7 @@ static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev)if (err != -EPERM && err != -ENODEV )bt_dev_err (hdev,"urb %p submission failed (%d)" , urb, -err); +kfree (dr);usb_unanchor_urb (urb); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1140/1887 erofs: fix metabuf leak in inode xattr initialization
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Zhu <[email protected]>
[ Upstream commit 79b09c54c6563df9846ca3094bcfd72082c3e1d7 ]
commit bb88e8da0025 ("erofs: use meta buffers for xattr operations") converted xattr operations to use on-stack erofs_buf instances. erofs_init_inode_xattrs() uses such a metabuf while reading the inline xattr header and shared xattr id array.
Some error paths after erofs_read_metabuf() leave through out_unlock without dropping the metabuf, so the folio reference can leak.
Consolidate the cleanup at out_unlock. erofs_put_metabuf() is a no-op if no folio has been acquired, and this keeps all paths after taking EROFS_I_BL_XATTR_BIT covered by a single cleanup site.
--- fs/erofs/xattr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/erofs/xattr.c +2 -3
@@ -35,6 +35,7 @@ static int init_inode_xattrs(struct inode *inode)return 0 ; } + it.buf = __EROFS_BUF_INITIALIZER;if (wait_on_bit_lock (&vi->flags,EROFS_I_BL_XATTR_BIT ,TASK_KILLABLE ))return -ERESTARTSYS ;
@@ -67,7 +68,6 @@ static int init_inode_xattrs(struct inode *inode) goto out_unlock; } - it.buf = __EROFS_BUF_INITIALIZER; it.blkaddr =erofs_blknr (sb,erofs_iloc (inode) + vi->inode_isize); it.ofs =erofs_blkoff (sb,erofs_iloc (inode) + vi->inode_isize);
@@ -83,7 +83,6 @@ static int init_inode_xattrs(struct inode *inode) vi->xattr_shared_xattrs =kmalloc_array (vi->xattr_shared_count,sizeof (uint),GFP_KERNEL );if (!vi->xattr_shared_xattrs) { -erofs_put_metabuf (&it.buf); ret = -ENOMEM ; goto out_unlock; }
@@ -110,13 +109,13 @@ static int init_inode_xattrs(struct inode *inode)le32_to_cpu (*(__le32 *)(it.kaddr + it.ofs)); it.ofs +=sizeof (__le32); } -erofs_put_metabuf (&it.buf);/* paired with smp_mb() at the beginning of the function. */ smp_mb ();set_bit (EROFS_I_EA_INITED_BIT , &vi->flags); out_unlock: +erofs_put_metabuf (&it.buf);clear_and_wake_up_bit (EROFS_I_BL_XATTR_BIT , &vi->flags);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1141/1887 test_kprobes: clear kprobes between test runs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
[ Upstream commit ef5581bb30efb939cc2bf093475c6cc85258e5cd ]
Running the kprobes sanity tests twice makes all tests fail and eventually crashes the kernel.
[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run
...
# Totals: pass:5 fail:0 skip:0 total:5
ok 1 kprobes_test
[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run
...
# test_kprobe: EXPECTATION FAILED at lib/tests/test_kprobes.c:64 Expected 0 == register_kprobe(&kp), but
register_kprobe(&kp) == -22 (0xffffffffffffffea) ... Unable to handle kernel paging request ...
The testsuite defines several kprobes and kretprobes as static variables that are preserved across test runs.
After register_kprobe and unregister_kprobe, a kprobe contains some leftover data that must be cleared before the kprobe can be registered again. The tests are setting symbol_name to define the probe location. Address and flags must be cleared.
The existing code clears some of the probes between subsequent tests, but not between two test runs. The leftover data from a previous test run makes the registrations fail in the next run.
Move the cleanups for all kprobes into kprobes_test_init, this function is called before each single test (including the first test of a test run).
--- lib/test_kprobes.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
lib/test_kprobes.c +17 -11
@@ -12,6 +12,12 @@#define div_factor 3 +#define KP_CLEAR (_kp) \ +do { \ + (_kp).addr = NULL; \ + (_kp).flags = 0; \ +} while (0) +static u32 rand1, preh_val, posth_val;static u32 (*target)(u32 value);static u32 (*target2)(u32 value);
@@ -115,10 +121,6 @@ static void test_kprobes(struct kunit *test) current_test = test; -/* addr and flags should be cleard for reusing kprobe. */ - kp.addr =NULL ; - kp.flags =0 ; -KUNIT_EXPECT_EQ (test,0 ,register_kprobes (kps,2 )); preh_val =0 ; posth_val =0 ;
@@ -193,9 +195,6 @@ static void test_kretprobes(struct kunit *test)struct kretprobe *rps[2 ] = {&rp, &rp2}; current_test = test; -/* addr and flags should be cleard for reusing kprobe. */ - rp.kp.addr =NULL ; - rp.kp.flags =0 ;KUNIT_EXPECT_EQ (test,0 ,register_kretprobes (rps,2 )); krph_val =0 ;
@@ -257,8 +256,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test)unsigned long myretaddr = (unsigned long )__builtin_return_address (0 ); current_test = test; - rp3.kp.addr =NULL ; - rp3.kp.flags =0 ;/* * Run the stacktrace_driver() to record correct return address in
@@ -319,8 +316,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)struct kretprobe *rps[2 ] = {&rp3, &rp4}; current_test = test; - rp3.kp.addr =NULL ; - rp3.kp.flags =0 ;//KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver());
@@ -334,6 +329,17 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)static int kprobes_test_init (struct kunit *test) { +KP_CLEAR (kp); +KP_CLEAR (kp2); +#ifdef CONFIG_KRETPROBES +KP_CLEAR (rp.kp); +KP_CLEAR (rp2.kp); +#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE +KP_CLEAR (rp3.kp); +KP_CLEAR (rp4.kp); +#endif +#endif + target = kprobe_target; target2 = kprobe_target2; stacktrace_target = kprobe_stacktrace_target;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1142/1887 hwmon: (lm90) Add lock protection to lm90_alert
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 873e919e3101063a7a75989510ccfc125a4391cf ]
Sashiko reports:
lm90_alert() executes in the smbus alert context and calls lm90_update_confreg() to disable the hardware alert line, without acquiring hwmon_lock.
Concurrently, sysfs write operations (such as lm90_write_convrate) hold the hwmon_lock, temporarily modify data->config, and then restore it.
If an alert interrupt occurs concurrently with a sysfs write, the sysfs path will overwrite the alert handler's modifications to data->config and the hardware register.
This unintentionally re-enables the hardware alert line while the alarm is still active, causing an interrupt storm.
Add the missing lock to lm90_alert() to solve the problem.
--- drivers/hwmon/lm90.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/hwmon/lm90.c +2 -0
@@ -2958,6 +2958,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,*/ struct lm90_data *data =i2c_get_clientdata (client); +mutex_lock (&data->update_lock);if (!data->shutdown && (data->flags &LM90_HAVE_BROKEN_ALERT ) && (data->current_alarms & data->alert_alarms)) {if (!(data->config &0x80 )) {
@@ -2967,6 +2968,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,schedule_delayed_work (&data->alert_work,max_t (int,HZ ,msecs_to_jiffies (data->update_interval))); } +mutex_unlock (&data->update_lock); }else {dev_dbg (&client->dev,"Everything OK\n" ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1143/1887 crypto: qat - protect service table iterations with service_lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
[ Upstream commit 5c6f845e77ec35f9b7b047cc8f9789bf397cdd3e ]
The service_table list is protected by service_lock when entries are added or removed (in adf_service_add() and adf_service_remove()), but several functions iterate over the list without holding this lock.
A concurrent adf_service_register() or adf_service_unregister() call could modify the list during traversal, leading to list corruption or a use-after-free.
Fix this by holding service_lock across all list_for_each_entry() iterations of service_table in adf_dev_init(), adf_dev_start(), adf_dev_stop(), adf_dev_shutdown(), adf_dev_restarting_notify(), adf_dev_restarted_notify(), and adf_error_notifier().
The lock ordering is safe: callers of the static helpers (adf_dev_up() and adf_dev_down()) acquire state_lock before service_lock, and no event_hld callback or service_lock holder ever acquires state_lock in the reverse order.
--- drivers/crypto/qat/qat_common/adf_init.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/crypto/qat/qat_common/adf_init.c +14 -0
@@ -136,16 +136,19 @@ int adf_dev_init(struct adf_accel_dev *accel_dev)* This is to facilitate any ordering dependencies between services * prior to starting any of the accelerators. */ +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (service->event_hld (accel_dev,ADF_EVENT_INIT )) {dev_err (&GET_DEV (accel_dev),"Failed to initialise service %s\n" , service->name); +mutex_unlock (&service_lock);return -EFAULT ; }set_bit (accel_dev->accel_id, service->init_status); } +mutex_unlock (&service_lock);return 0 ; }
@@ -190,16 +193,19 @@ int adf_dev_start(struct adf_accel_dev *accel_dev)return -EFAULT ; } +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (service->event_hld (accel_dev,ADF_EVENT_START )) {dev_err (&GET_DEV (accel_dev),"Failed to start service %s\n" , service->name); +mutex_unlock (&service_lock);return -EFAULT ; }set_bit (accel_dev->accel_id, service->start_status); } +mutex_unlock (&service_lock);clear_bit (ADF_STATUS_STARTING , &accel_dev->status);set_bit (ADF_STATUS_STARTED , &accel_dev->status);
@@ -249,6 +255,7 @@ void adf_dev_stop(struct adf_accel_dev *accel_dev) }clear_bit (ADF_STATUS_CRYPTO_ALGS_REGISTERED , &accel_dev->status); +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (!test_bit (accel_dev->accel_id, service->start_status))
@@ -261,6 +268,7 @@ void adf_dev_stop(struct adf_accel_dev *accel_dev)clear_bit (accel_dev->accel_id, service->start_status); } } +mutex_unlock (&service_lock);if (wait)msleep (100 );
@@ -307,6 +315,7 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev) &accel_dev->status); } +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (!test_bit (accel_dev->accel_id, service->init_status))
@@ -318,6 +327,7 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev)else clear_bit (accel_dev->accel_id, service->init_status); } +mutex_unlock (&service_lock); hw_data->disable_iov (accel_dev);
@@ -347,6 +357,7 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)struct service_hndl *service;struct list_head *list_itr; +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (service->event_hld (accel_dev,ADF_EVENT_RESTARTING ))
@@ -354,6 +365,7 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)"Failed to restart service %s.\n" , service->name); } +mutex_unlock (&service_lock);return 0 ; }
@@ -362,6 +374,7 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)struct service_hndl *service;struct list_head *list_itr; +mutex_lock (&service_lock);list_for_each (list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list);if (service->event_hld (accel_dev,ADF_EVENT_RESTARTED ))
@@ -369,6 +382,7 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)"Failed to restart service %s.\n" , service->name); } +mutex_unlock (&service_lock);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1144/1887 nvmet: return DHCHAP status codes from nvmet_setup_auth()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hannes Reinecke <[email protected]>
[ Upstream commit 44e3c25efae8575e06f1c5d1dc40058a991e3cb2 ]
A failure in nvmet_setup_auth() does not mean that the NVMe authentication command failed, so we should rather return a protocol error with a 'failure1' response than an NVMe status.
Also update the type used for dhchap_step and dhchap_status to u8 to avoid confusions with nvme status. Furthermore, split dhchap_status and nvme status so we don't accidentally mix these return values.
[dwagner: - use u8 as type for dhchap_{step|status}
- separate nvme status from dhcap_status]
Stable-dep-of: 3a413ece2504 ("nvmet-auth: validate reply message payload bounds against transfer length")
--- drivers/nvme/target/auth.c | 20 +++++------ drivers/nvme/target/fabrics-cmd-auth.c | 49 +++++++++++++------------- drivers/nvme/target/fabrics-cmd.c | 11 +++--- drivers/nvme/target/nvmet.h | 8 ++--- 4 files changed, 43 insertions(+), 45 deletions(-)
drivers/nvme/target/auth.c +8 -12
@@ -125,12 +125,11 @@ int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id)return ret; } -int nvmet_setup_auth (struct nvmet_ctrl *ctrl) +u8 nvmet_setup_auth (struct nvmet_ctrl *ctrl) {int ret =0 ;struct nvmet_host_link *p;struct nvmet_host *host =NULL ; -const char *hash_name;down_read (&nvmet_config_sem);if (nvmet_is_disc_subsys (ctrl->subsys))
@@ -148,13 +147,16 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) }if (!host) {pr_debug ("host %s not found\n" , ctrl->hostnqn); - ret = -EPERM ; + ret =NVME_AUTH_DHCHAP_FAILURE_FAILED ; goto out_unlock; } ret =nvmet_setup_dhgroup (ctrl, host->dhchap_dhgroup_id); -if (ret <0 ) +if (ret <0 ) {pr_warn ("Failed to setup DH group" ); + ret =NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE ; + goto out_unlock; + }if (!host->dhchap_secret) {pr_debug ("No authentication provided\n" );
@@ -165,12 +167,6 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl)pr_debug ("Re-use existing hash ID %d\n" , ctrl->shash_id); }else { - hash_name =nvme_auth_hmac_name (host->dhchap_hash_id); -if (!hash_name) { -pr_warn ("Hash ID %d invalid\n" , host->dhchap_hash_id); - ret = -EINVAL ; - goto out_unlock; - } ctrl->shash_id = host->dhchap_hash_id; }
@@ -179,7 +175,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) ctrl->host_key =nvme_auth_extract_key (host->dhchap_secret +10 , host->dhchap_key_hash);if (IS_ERR (ctrl->host_key)) { - ret =PTR_ERR (ctrl->host_key); + ret =NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE ; ctrl->host_key =NULL ; goto out_free_hash; }
@@ -197,7 +193,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) ctrl->ctrl_key =nvme_auth_extract_key (host->dhchap_ctrl_secret +10 , host->dhchap_ctrl_key_hash);if (IS_ERR (ctrl->ctrl_key)) { - ret =PTR_ERR (ctrl->ctrl_key); + ret =NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE ; ctrl->ctrl_key =NULL ; goto out_free_hash; }
drivers/nvme/target/fabrics-cmd-auth.c +25 -24
110 lines not on this page · raw message
drivers/nvme/target/fabrics-cmd.c +6 -5
@@ -210,7 +210,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)struct nvmf_connect_data *d;struct nvmet_ctrl *ctrl =NULL ;u16 status; -int ret; +u8 dhchap_status;if (!nvmet_check_transfer_len (req,sizeof (struct nvmf_connect_data )))return ;
@@ -252,11 +252,12 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)uuid_copy (&ctrl->hostid, &d->hostid); - ret =nvmet_setup_auth (ctrl); -if (ret <0 ) { -pr_err ("Failed to setup authentication, error %d\n" , ret); + dhchap_status =nvmet_setup_auth (ctrl); +if (dhchap_status) { +pr_err ("Failed to setup authentication, dhchap status %u\n" , + dhchap_status);nvmet_ctrl_put (ctrl); -if (ret == -EPERM ) +if (dhchap_status ==NVME_AUTH_DHCHAP_FAILURE_FAILED ) status = (NVME_SC_CONNECT_INVALID_HOST |NVME_STATUS_DNR );else status =NVME_SC_INTERNAL ;
drivers/nvme/target/nvmet.h +4 -4
@@ -111,8 +111,8 @@ struct nvmet_sq {struct delayed_work auth_expired_work;bool authenticated;u16 dhchap_tid; -u16 dhchap_status; -int dhchap_step; +u8 dhchap_status; +u8 dhchap_step;u8 *dhchap_c1;u8 *dhchap_c2;u32 dhchap_s1;
@@ -706,7 +706,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req);int nvmet_auth_set_key (struct nvmet_host *host,const char *secret,bool set_ctrl);int nvmet_auth_set_host_hash (struct nvmet_host *host,const char *hash); -int nvmet_setup_auth (struct nvmet_ctrl *ctrl); +u8 nvmet_setup_auth (struct nvmet_ctrl *ctrl);void nvmet_auth_sq_init (struct nvmet_sq *sq);void nvmet_destroy_auth (struct nvmet_ctrl *ctrl);void nvmet_auth_sq_free (struct nvmet_sq *sq);
@@ -726,7 +726,7 @@ int nvmet_auth_ctrl_exponential(struct nvmet_req *req,int nvmet_auth_ctrl_sesskey (struct nvmet_req *req,u8 *buf,int buf_size);#else -static inline int nvmet_setup_auth (struct nvmet_ctrl *ctrl) +static inline u8 nvmet_setup_auth (struct nvmet_ctrl *ctrl) {return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1145/1887 nvmet-auth: validate reply message payload bounds against transfer length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tianchu Chen <[email protected]>
[ Upstream commit 3a413ece2504c70aa34a20be4dafec04e8c741f9 ]
nvmet_auth_reply() accesses the variable-length rval[] array using attacker-controlled hl (hash length) and dhvlen (DH value length) fields without verifying they fit within the allocated buffer of tl bytes.
A malicious NVMe-oF initiator can craft a DHCHAP_REPLY message with a small transfer length but large hl/dhvlen values, causing out-of-bounds heap reads when the target processes the DH public key (rval + 2*hl) or performs the host response memcmp.
With DH authentication configured, the OOB pointer is passed directly to sg_init_one() and read by crypto_kpp_compute_shared_secret(), reaching up to 526 bytes past the buffer. This is exploitable pre-authentication.
Add bounds validation ensuring sizeof(*data) + 2*hl + dhvlen <= tl before any access to the variable-length fields.
Discovered by Atuin - Automated Vulnerability Discovery Engine.
--- drivers/nvme/target/fabrics-cmd-auth.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/nvme/target/fabrics-cmd-auth.c +12 -3
@@ -109,13 +109,22 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)return 0 ; } -static u8 nvmet_auth_reply (struct nvmet_req *req,void *d) +static u8 nvmet_auth_reply (struct nvmet_req *req,void *d,u32 tl) {struct nvmet_ctrl *ctrl = req->sq->ctrl;struct nvmf_auth_dhchap_reply_data *data = d; -u16 dhvlen =le16_to_cpu (data->dhvlen); +u16 dhvlen;u8 *response; +if (tl <sizeof (*data)) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; + + dhvlen =le16_to_cpu (data->dhvlen); + +/* Validate that hl and dhvlen fit within the transfer length */ +if (sizeof (*data) +2 * (size_t )data->hl + dhvlen > tl) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; +pr_debug ("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n" , __func__, ctrl->cntlid, req->sq->qid, data->hl, data->cvalid, dhvlen);
@@ -287,7 +296,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)switch (data->auth_id) {case NVME_AUTH_DHCHAP_MESSAGE_REPLY : - dhchap_status =nvmet_auth_reply (req, d); + dhchap_status =nvmet_auth_reply (req, d, tl);if (dhchap_status ==0 ) req->sq->dhchap_step =NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1146/1887 nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit 53cd102a7a56079b11b897835bd9b94c14e6322c ]
nvmet_execute_disc_get_log_page() validates only the dword alignment of the host-supplied Log Page Offset (lpo). The 64-bit offset is then added to a small kzalloc'd buffer that holds the discovery log page and the result is passed straight to nvmet_copy_to_sgl(), which memcpy()s data_len bytes out to the host with no source-side bound check:
u64 offset = nvmet_get_log_page_offset(req->cmd); /* 64-bit host */
size_t data_len = nvmet_get_log_page_len(req->cmd); /* 32-bit host */
...
if (offset & 0x3) { ... } /* only check */
...
alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req);
buffer = kzalloc(alloc_len, GFP_KERNEL);
...
status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);The Discovery controller is unauthenticated -- nvmet_host_allowed() returns true unconditionally for the discovery subsystem -- so the call is reachable pre-authentication by any TCP/RDMA/FC peer that can reach the nvmet target. With a discovery log page of ~1 KiB, an attacker requesting up to 4 KiB starting at offset == alloc_len reads the next slab page out and gets its content returned over the fabric (an empirical run on a default nvmet-tcp loopback target leaked 81 canonical kernel pointers in one Get Log Page response). Pointing the offset at unmapped kernel memory faults the in-kernel memcpy and crashes (or panics, on panic_on_oops=1) the target host instead.
The attacker-controlled source-side offset pattern "nvmet_copy_to_sgl(req, 0, buffer + ATTACKER_OFFSET, ...)" is unique to nvmet_execute_disc_get_log_page in the entire nvmet codebase: every other Get Log Page handler in admin-cmd.c either ignores lpo (and silently starts every response at offset 0) or tracks a local destination offset with a fixed source pointer.
Validate the host-supplied offset against the log page size, cap the copy length to what is actually available, and zero-fill any remainder of the host transfer buffer. The zero-fill matches the existing short-response pattern in nvmet_execute_get_log_changed_ns() (admin-cmd.c) and prevents leaking transport SGL contents when the host asks for more bytes than the log page contains.
--- drivers/nvme/target/discovery.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/nvme/target/discovery.c +22 -1
@@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)u64 offset =nvmet_get_log_page_offset (req->cmd);size_t data_len =nvmet_get_log_page_len (req->cmd);size_t alloc_len; +size_t copy_len;struct nvmet_subsys_link *p;struct nvmet_port *r;u32 numrec =0 ;
@@ -239,7 +240,27 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)up_read (&nvmet_config_sem); - status =nvmet_copy_to_sgl (req,0 , buffer + offset, data_len); +/* +* Validate the host-supplied log page offset before copying out. +* Without this check, the host controls a 64-bit byte offset into +* a small kzalloc'd buffer: a value past the log page lets the +* subsequent memcpy read adjacent kernel heap, and a value aimed +* at unmapped kernel memory faults the in-kernel copy and crashes +* the target host. The Discovery controller is unauthenticated, +* so the bug is reachable from any reachable fabric peer. +*/ +if (offset > alloc_len) { + req->error_loc = + offsetof(struct nvme_get_log_page_command , lpo); + status =NVME_SC_INVALID_FIELD |NVME_STATUS_DNR ; + goto out_free_buffer; + } + + copy_len =min_t (size_t, data_len, alloc_len - offset); + status =nvmet_copy_to_sgl (req,0 , buffer + offset, copy_len); +if (!status && copy_len < data_len) + status =nvmet_zero_sgl (req, copy_len, data_len - copy_len); +out_free_buffer:kfree (buffer); out:nvmet_req_complete (req, status);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1147/1887 USB: iowarrior: fix use-after-free on disconnect race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit c602254ba4c10f60a73cd99d147874f86a3f485c ]
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/iowarrior.c | 57 +++++++++++++++--------------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/usb/misc/iowarrior.c +24 -33
@@ -71,6 +71,7 @@ static struct usb_driver iowarrior_driver;/* Structure to hold all of our device specific stuff */ struct iowarrior { +struct kref kref;struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */
@@ -243,8 +244,10 @@ static void iowarrior_write_callback(struct urb *urb)/* * iowarrior_delete */ -static inline void iowarrior_delete (struct iowarrior *dev) +static inline void iowarrior_delete (struct kref *kref) { + struct iowarrior *dev = container_of(kref, struct iowarrior, kref); +kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -641,6 +644,9 @@ static int iowarrior_open(struct inode *inode, struct file *file) }/* increment our usage count for the driver */ ++dev->opened; + +kref_get (&dev->kref); +/* save our object in the file's private structure */ file->private_data = dev; retval =0 ;
@@ -656,7 +662,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)static int iowarrior_release (struct inode *inode,struct file *file) {struct iowarrior *dev; -int retval =0 ; dev = file->private_data;if (!dev)
@@ -664,29 +669,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)/* lock our device */ mutex_lock (&dev->mutex); + dev->opened =0 ;/* we're closing now */ -if (dev->opened <=0 ) { - retval = -ENODEV ;/* close called more than once */ -mutex_unlock (&dev->mutex); - }else { - dev->opened =0 ;/* we're closing now */ - retval =0 ; -if (dev->present) { -/* -The device is still connected so we only shutdown -pending read-/write-ops. -*/ -usb_kill_urb (dev->int_in_urb); -wake_up_interruptible (&dev->read_wait); -wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* The device was unplugged, cleanup resources */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); - } +if (dev->present) { +usb_kill_urb (dev->int_in_urb); +wake_up_interruptible (&dev->read_wait); +wake_up_interruptible (&dev->write_wait); } -return retval; +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); + +return 0 ; }static __poll_t iowarrior_poll (struct file *file,poll_table * wait)
@@ -771,6 +765,7 @@ static int iowarrior_probe(struct usb_interface *interface,if (!dev)return retval; +kref_init (&dev->kref);mutex_init (&dev->mutex);atomic_set (&dev->intr_idx,0 );
@@ -889,7 +884,8 @@ static int iowarrior_probe(struct usb_interface *interface,return retval; error: -iowarrior_delete (dev); +kref_put (&dev->kref, iowarrior_delete); +return retval; }
@@ -913,19 +909,14 @@ static void iowarrior_disconnect(struct usb_interface *interface)usb_kill_anchored_urbs (&dev->submitted);if (dev->opened) { -/* There is a process that holds a filedescriptor to the device , -so we only shutdown read-/write-ops going on. -Deleting the device is postponed until close() was called. -*/ usb_kill_urb (dev->int_in_urb);wake_up_interruptible (&dev->read_wait);wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* no process is using the device, cleanup now */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); } + +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); }/* usb specific object needed to register this driver with the usb subsystem */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1148/1887 usb: gadget: function: Simplify diagnostic messaging in printer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrzej Pietrasiewicz <[email protected]>
[ Upstream commit 57b7b733b1a7aeab25bc2670afff608214284863 ]
Don't issue messages which can be easily achieved with ftrace. In case of printer_open() the return code is propagated to other layers so the user will know about -EBUSY anyway.
Stable-dep-of: 30adce93d5c4 ("usb: gadget: f_printer: take kref only for successful open")
--- drivers/usb/gadget/function/f_printer.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/usb/gadget/function/f_printer.c +1 -8
@@ -365,7 +365,7 @@ printer_open(struct inode *inode, struct file *fd)spin_unlock_irqrestore (&dev->lock, flags);kref_get (&dev->kref); -DBG (dev,"printer_open returned %x\n" , ret); +return ret; }
@@ -383,7 +383,6 @@ printer_close(struct inode *inode, struct file *fd)spin_unlock_irqrestore (&dev->lock, flags);kref_put (&dev->kref, printer_dev_free); -DBG (dev,"printer_close\n" );return 0 ; }
@@ -881,8 +880,6 @@ static void printer_reset_interface(struct printer_dev *dev)if (dev->interface <0 )return ; -DBG (dev,"%s\n" , __func__); -if (dev->in_ep->desc)usb_ep_disable (dev->in_ep);
@@ -920,8 +917,6 @@ static void printer_soft_reset(struct printer_dev *dev) {struct usb_request *req; -INFO (dev,"Received Printer Reset Request\n" ); -if (usb_ep_disable (dev->in_ep))DBG (dev,"Failed to disable USB in_ep\n" );if (usb_ep_disable (dev->out_ep))
@@ -1218,8 +1213,6 @@ static void printer_func_disable(struct usb_function *f) {struct printer_dev *dev =func_to_printer (f); -DBG (dev,"%s\n" , __func__); -printer_reset_interface (dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1149/1887 usb: gadget: f_printer: take kref only for successful open
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
[ Upstream commit 30adce93d5c4a5a1ec29d9249e3fdfcc391d406b ]
printer_open() returns -EBUSY when the character device is already open, but it increments dev->kref regardless of the return value. VFS does not call ->release() for a failed open, so every rejected second open permanently leaks one reference.
Move kref_get() into the successful-open branch.
--- drivers/usb/gadget/function/f_printer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/gadget/function/f_printer.c +1 -2
@@ -360,12 +360,11 @@ printer_open(struct inode *inode, struct file *fd) ret =0 ;/* Change the printer status to show that it's on-line. */ dev->printer_status |=PRINTER_SELECTED ; +kref_get (&dev->kref); }spin_unlock_irqrestore (&dev->lock, flags); -kref_get (&dev->kref); -return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1150/1887 usb: free iso schedules on failed submit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit b9399d25fbb34a05bbe76eeedd730f62ff2670e9 ]
EHCI and FOTG210 isochronous submits build an ehci_iso_sched before linking the URB to the endpoint queue, and keep the staged schedule in urb->hcpriv until iso_stream_schedule() and the link helpers consume it. If the controller is no longer accessible, or usb_hcd_link_urb_to_ep() fails, submit jumps to done_not_linked before that handoff happens and leaks the staged schedule still attached to urb->hcpriv.
Free the staged schedule from done_not_linked when submit fails before the URB is linked and clear urb->hcpriv after the free.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an EHCI host controller with a USB isochronous device to test with, no runtime testing was able to be performed.
--- drivers/usb/host/ehci-sched.c | 11 +++++++++-- drivers/usb/host/fotg210-hcd.c | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-)
drivers/usb/host/ehci-sched.c +9 -2
@@ -1623,6 +1623,7 @@ iso_stream_schedule( status =1 ;/* and give it back immediately */ iso_sched_free (stream, sched); sched =NULL ; + urb->hcpriv =NULL ; } } urb->error_count = skip / period;
@@ -1653,8 +1654,6 @@ iso_stream_schedule(return status; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -1966,6 +1965,10 @@ static int itd_submit(struct ehci_hcd *ehci, struct urb *urb,usb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
@@ -2343,6 +2346,10 @@ static int sitd_submit(struct ehci_hcd *ehci, struct urb *urb,usb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
drivers/usb/host/fotg210-hcd.c +4 -2
@@ -4272,8 +4272,6 @@ static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,return 0 ; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -4567,6 +4565,10 @@ static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,else usb_hcd_unlink_urb_from_ep (fotg210_to_hcd (fotg210), urb); done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&fotg210->lock, flags); done:return status;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1151/1887 smb/client: fix chown/chgrp with SMB3 POSIX Extensions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ralph Boehme <[email protected]>
[ Upstream commit 760ef2c579c2609cf17fb1cd5392f64d42d43d33 ]
Ownership (chown) and group (chgrp) modifications were being ignored when mounting with SMB3 POSIX Extensions unless CIFS_MOUNT_CIFS_ACL or CIFS_MOUNT_MODE_FROM_SID were also explicitly set.
Fix this by checking for posix_extensions in cifs_setattr_nounix() when updating UID and GID, ensuring that id_mode_to_cifs_acl() is called to map and set the ownership/group information on the server.
--- fs/smb/client/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/smb/client/inode.c +2 -1
@@ -3004,7 +3004,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) gid = attrs->ia_gid;if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID )) { + (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) || +cifs_sb_master_tcon (cifs_sb)->posix_extensions) {if (uid_valid (uid) ||gid_valid (gid)) { mode =NO_CHANGE_64 ; rc = id_mode_to_cifs_acl(inode, full_path, &mode,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1152/1887 ksmbd: validate NTLMv2 response before updating session key
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haofeng Li <[email protected]>
[ Upstream commit 954d196bebb2b50151cb96454c72dc113b2af1ac ]
ksmbd_auth_ntlmv2() derives the NTLMv2 session key into sess->sess_key before it verifies the NTLMv2 response. ksmbd_decode_ntlmssp_auth_blob() then continues into KEY_XCH even when ksmbd_auth_ntlmv2() failed.
With SMB3 multichannel binding, the failed authentication operates on an existing session and the session setup error path does not expire binding sessions. A client can send a binding session setup with a bad NT proof and KEY_XCH and still modify sess->sess_key before STATUS_LOGON_FAILURE is returned.
Relevant path:
smb2_sess_setup()
-> conn->binding = true
-> ntlm_authenticate()
-> session_user()
-> ksmbd_decode_ntlmssp_auth_blob()
-> ksmbd_auth_ntlmv2()
-> calc_ntlmv2_hash()
-> hmac_md5_usingrawkey(..., sess->sess_key)
-> crypto_memneq() returns mismatch
-> KEY_XCH arc4_crypt(..., sess->sess_key, ...)
-> out_err without expiring the binding sessionDerive the base session key into a local buffer and copy it to sess->sess_key only after the proof matches. Return immediately on authentication failure so KEY_XCH is only processed after successful authentication.
--- fs/smb/server/auth.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
fs/smb/server/auth.c +16 -6
@@ -72,13 +72,12 @@ void ksmbd_copy_gss_neg_header(void *buf)/** * ksmbd_gen_sess_key() - function to generate session key -* @sess: session of connection +* @sess_key: output buffer for the session key * @hash: source hash value to be used for find session key * @hmac: source hmac value to be used for finding session key * */ -static int ksmbd_gen_sess_key (struct ksmbd_session *sess,char *hash, -char *hmac) +static int ksmbd_gen_sess_key (char *sess_key,char *hash,char *hmac) {struct ksmbd_crypto_ctx *ctx;int rc;
@@ -111,7 +110,7 @@ static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, goto out; } - rc =crypto_shash_final (CRYPTO_HMACMD5 (ctx), sess->sess_key); + rc =crypto_shash_final (CRYPTO_HMACMD5 (ctx), sess_key);if (rc) {ksmbd_debug (AUTH ,"Could not generate hmacmd5 hash error %d\n" , rc); goto out;
@@ -222,6 +221,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, {char ntlmv2_hash[CIFS_ENCPWD_SIZE ];char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE ]; +char sess_key[SMB2_NTLMV2_SESSKEY_SIZE ];struct ksmbd_crypto_ctx *ctx =NULL ;char *construct =NULL ;int rc, len;
@@ -276,19 +276,27 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,ksmbd_release_crypto_ctx (ctx); ctx =NULL ; - rc =ksmbd_gen_sess_key (sess, ntlmv2_hash, ntlmv2_rsp); + rc =ksmbd_gen_sess_key (sess_key, ntlmv2_hash, ntlmv2_rsp);if (rc) {ksmbd_debug (AUTH ,"Could not generate sess key\n" ); goto out; }if (crypto_memneq (ntlmv2->ntlmv2_hash, ntlmv2_rsp, -CIFS_HMAC_MD5_HASH_SIZE )) +CIFS_HMAC_MD5_HASH_SIZE )) { rc = -EINVAL ; + goto out; + } + +memcpy (sess->sess_key, sess_key,sizeof (sess_key)); + rc =0 ; out:if (ctx)ksmbd_release_crypto_ctx (ctx);kfree (construct); +memzero_explicit (ntlmv2_hash,sizeof (ntlmv2_hash)); +memzero_explicit (ntlmv2_rsp,sizeof (ntlmv2_rsp)); +memzero_explicit (sess_key,sizeof (sess_key));return rc; }
@@ -345,6 +353,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, nt_len -CIFS_ENCPWD_SIZE , domain_name, conn->ntlmssp.cryptkey);kfree (domain_name); +if (ret) +return ret;/* The recovered secondary session key */ if (conn->ntlmssp.client_flags &NTLMSSP_NEGOTIATE_KEY_XCH ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1153/1887 ksmbd: use opener credentials for ADS I/O
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit baa5e094886fffa7e6272edcb5e08be5ce28262c ]
Alternate data streams are stored as xattrs. Unlike regular file I/O, their read and write paths therefore call VFS xattr helpers which recheck inode permissions and LSM policy using the current task credentials.
Run ADS I/O with the credentials captured when the SMB handle was opened.
--- fs/smb/server/vfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
fs/smb/server/vfs.c +9 -2
@@ -285,17 +285,20 @@ static ssize_t ksmbd_vfs_getcasexattr(struct user_namespace *user_ns,static int ksmbd_vfs_stream_read (struct ksmbd_file *fp,char *buf,loff_t *pos,size_t count) { +const struct cred *saved_cred;ssize_t v_len;char *stream_buf =NULL ;ksmbd_debug (VFS ,"read stream data pos : %llu, count : %zd\n" , *pos, count); + saved_cred =override_creds (fp->filp->f_cred); v_len =ksmbd_vfs_getcasexattr (file_mnt_user_ns (fp->filp), fp->filp->f_path.dentry, fp->stream.name, fp->stream.size, &stream_buf); +revert_creds (saved_cred);if ((int )v_len <=0 )return (int )v_len;
@@ -414,6 +417,7 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,static int ksmbd_vfs_stream_write (struct ksmbd_file *fp,char *buf,loff_t *pos,size_t count) { +const struct cred *saved_cred;char *stream_buf =NULL , *wbuf;struct user_namespace *user_ns =file_mnt_user_ns (fp->filp);size_t size;
@@ -434,6 +438,7 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, count =XATTR_SIZE_MAX - *pos; } + saved_cred =override_creds (fp->filp->f_cred); v_len = ksmbd_vfs_getcasexattr(user_ns, fp->filp->f_path.dentry, fp->stream.name,
@@ -442,14 +447,14 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,if (v_len <0 ) {pr_err ("not found stream in xattr : %zd\n" , v_len); err = v_len; - goto out; + goto out_revert; }if (v_len < size) { wbuf =kvzalloc (size,GFP_KERNEL );if (!wbuf) { err = -ENOMEM ; - goto out; + goto out_revert; }if (v_len >0 )
@@ -467,6 +472,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, size,0 , true); +out_revert: +revert_creds (saved_cred);if (err <0 ) goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1154/1887 ksmbd: use opener credentials for delete-on-close
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 52e2f21911158ec961cd5aae19c56460db382af0 ]
Delete-on-close can be completed by deferred or durable handle teardown, where no request work is available. Both the base-file unlink and the ADS xattr removal consequently run with the ksmbd worker credentials and can bypass filesystem permission checks.
Run both operations with the credentials captured in struct file when the handle was opened. This preserves the authenticated user's fsuid, fsgid, supplementary groups and capability restrictions at final close.
--- fs/smb/server/vfs.c | 7 +++++-- fs/smb/server/vfs_cache.c | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-)
fs/smb/server/vfs.c +5 -2
@@ -1086,13 +1086,15 @@ int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns,int ksmbd_vfs_unlink (struct file *filp) { +const struct cred *saved_cred;int err =0 ;struct dentry *dir, *dentry = filp->f_path.dentry;struct user_namespace *user_ns =file_mnt_user_ns (filp); + saved_cred =override_creds (filp->f_cred); err =mnt_want_write (filp->f_path.mnt);if (err) -return err; + goto out_revert; dir =dget_parent (dentry); err =ksmbd_vfs_lock_parent (dir, dentry);
@@ -1112,7 +1114,8 @@ int ksmbd_vfs_unlink(struct file *filp) out:dput (dir);mnt_drop_write (filp->f_path.mnt); - +out_revert: +revert_creds (saved_cred);return err; }
fs/smb/server/vfs_cache.c +4 -0
@@ -283,9 +283,13 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)write_unlock (&ci->m_lock);if (remove_stream_xattr) { +const struct cred *saved_cred; + + saved_cred =override_creds (filp->f_cred); err =ksmbd_vfs_remove_xattr (file_mnt_user_ns (filp), &filp->f_path, fp->stream.name); +revert_creds (saved_cred);if (err)pr_err ("remove xattr failed : %s\n" , fp->stream.name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1155/1887 ksmbd: prevent path traversal bypass by restricting caseless retry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 54bab9ba5a9f156ffa9324fcbe5a356fd0242f95 ]
ksmbd_vfs_path_lookup() enforces LOOKUP_BENEATH to restrict path resolution within the share root. When a crafted path attempts to escape the share boundary using parent-directory components ('..'), vfs_path_parent_lookup() detects this and immediately fails, returning -EXDEV.
However, a bug exists in __ksmbd_vfs_kern_path() under caseless mode. The function fails to intercept the -EXDEV error and erroneously falls through to the caseless retry logic, which is intended only for genuinely missing files. During this retry process, the path is reconstructed, leading to an unintended LOOKUP_BENEATH bypass that allows write-capable users to create zero-length files or directories outside the exported share.
Fix this by ensuring that the execution only proceeds to the caseless lookup retry when the error is specifically -ENOENT. Any other errors, such as -EXDEV from a path traversal attempt, must be returned immediately.
--- fs/smb/server/vfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/vfs.c +2 -2
@@ -1239,7 +1239,7 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,if (!err)return 0 ; -if (caseless) { +if (caseless && err == -ENOENT ) {char *filepath;size_t path_len, remain_len;
@@ -1270,7 +1270,7 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, err =vfs_path_lookup (share_conf->vfs_path.dentry, share_conf->vfs_path.mnt, filepath, - flags, + flags |LOOKUP_BENEATH , path);if (!is_last) next[0 ] ='/' ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1156/1887 netpoll: fix a use-after-free on shutdown path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 45f1458a85017a023f138b22ac5c76abd477db42 ]
There is a use-after-free error on netpoll, which is clearly detected by KASAN.
BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x3b/0x80
Read of size 1 at addr ... by task kworker/9:1
Workqueue: events queue_process
Call Trace:
skb_dequeue+0x1e/0xb0
queue_process+0x2c/0x600
process_scheduled_works+0x4b6/0x850
worker_thread+0x414/0x5a0
Allocated by task 242:
__netpoll_setup+0x201/0x4a0
netpoll_setup+0x249/0x550
enabled_store+0x32f/0x380
Freed by task 0:
kfree+0x1b7/0x540
rcu_core+0x3f8/0x7a0The problem happens when there is a pending TX worker running in parallel with the cleanup path.
This is what happens on netpoll shutdown path:
1) __netpoll_cleanup() is called
2) set dev->npinfo to NULL
3) call_rcu() with rcu_cleanup_netpoll_info()
3.1) rcu_cleanup_netpoll_info() tries to cancel all workers with
cancel_delayed_work(), but doesn't wait for the worker to finish
4) and kfree(npinfo);
Because 3.1) doesn't really cancel the work, as the comment says "we can't call cancel_delayed_work_sync here, as we are in softirq", the TX worker can run after 4).
Tl;DR: queue_process() is not an RCU reader, it reaches npinfo through the work item via container_of().
Use disable_delayed_work_sync() to ensure the worker is completely stopped and prevent any future re-arming attempts. Once npinfo is set to NULL, senders will bail out and not queue new work. The disable flag ensures any in-flight re-arming attempts also fail silently.
In the future, we can do the cleanup inline here without needing the npinfo->rcu rcu_head, but that is net-next material.
--- net/core/netpoll.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
net/core/netpoll.c +2 -8
@@ -830,14 +830,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) container_of(rcu_head, struct netpoll_info, rcu);skb_queue_purge (&npinfo->txq); - -/* we can't call cancel_delayed_work_sync here, as we are in softirq */ -cancel_delayed_work (&npinfo->tx_work); - -/* clean after last, unfinished work */ -__skb_queue_purge (&npinfo->txq); -/* now cancel it again */ -cancel_delayed_work (&npinfo->tx_work);kfree (npinfo); }
@@ -863,6 +855,8 @@ void __netpoll_cleanup(struct netpoll *np) ops->ndo_netpoll_cleanup (np->dev);RCU_INIT_POINTER (np->dev->npinfo,NULL ); +synchronize_rcu (); +cancel_delayed_work_sync (&npinfo->tx_work);call_rcu (&npinfo->rcu, rcu_cleanup_netpoll_info); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1157/1887 usb: typec: tcpci_rt1711h: unregister TCPCI port with devres
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e8da46d99d3710106e7c44db14566bf9b57386b5 ]
rt1711h_probe() registers the TCPCI port before requesting the interrupt and enabling alert interrupts. If either of those later steps fails, the probe function returns without unregistering the TCPCI port. The explicit unregister currently only happens from the remove callback.
Register a devres action immediately after tcpci_register_port() succeeds, so tcpci_unregister_port() runs on later probe failures and on driver detach. Drop the remove callback to avoid unregistering the same port twice.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/usb/typec/tcpm/tcpci_rt1711h.c +8 -5
@@ -327,6 +327,8 @@ static int rt1711h_check_revision(struct i2c_client *i2c, struct rt1711h_chip *creturn ret; } +static void rt1711h_unregister_tcpci_port (void *tcpci); +static int rt1711h_probe (struct i2c_client *client,const struct i2c_device_id *i2c_id) {
@@ -379,6 +381,10 @@ static int rt1711h_probe(struct i2c_client *client,if (IS_ERR_OR_NULL (chip->tcpci))return PTR_ERR (chip->tcpci); + ret =devm_add_action_or_reset (chip->dev, rt1711h_unregister_tcpci_port, chip->tcpci); +if (ret) +return ret; + ret = devm_request_threaded_irq(chip->dev, client->irq, NULL, rt1711h_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
@@ -396,11 +402,9 @@ static int rt1711h_probe(struct i2c_client *client,return 0 ; } -static void rt1711h_remove (struct i2c_client *client) +static void rt1711h_unregister_tcpci_port (void *tcpci) { -struct rt1711h_chip *chip =i2c_get_clientdata (client); - -tcpci_unregister_port (chip->tcpci); +tcpci_unregister_port (tcpci); }static const struct i2c_device_id rt1711h_id[] = {
@@ -425,7 +429,6 @@ static struct i2c_driver rt1711h_i2c_driver = { .of_match_table = of_match_ptr(rt1711h_of_match), }, .probe = rt1711h_probe, - .remove = rt1711h_remove, .id_table = rt1711h_id, };module_i2c_driver (rt1711h_i2c_driver);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1158/1887 ALSA: hda/cs35l41: Fix firmware load work teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
[ Upstream commit b65020d5398f499c09498c9786dba6d67ae57664 ]
cs35l41_hda creates ALSA controls whose private data points at the cs35l41_hda object. The firmware load control can also queue fw_load_work.
Those controls are not removed on component unbind, and device remove only cancels fw_load_work through cs35l41_remove_dsp(). That helper is skipped when halo_initialized is false. With firmware_autostart disabled, a firmware load can be requested before the DSP has been initialized. If the component or device is removed before the queued work runs, the worker can run after teardown and dereference driver state that is no longer valid.
Track the created controls and remove them on unbind so no new control callback can reach the driver data or queue more work. Then cancel fw_load_work to drain any request that was already queued. Also cancel the work unconditionally during device remove before runtime PM teardown.
--- sound/pci/hda/cs35l41_hda.c | 74 ++++++++++++++++++++++++++++--------- sound/pci/hda/cs35l41_hda.h | 4 ++ 2 files changed, 61 insertions(+), 17 deletions(-)
sound/pci/hda/cs35l41_hda.c +57 -17
@@ -894,6 +894,44 @@ static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctreturn snd_ctl_enum_info (uinfo,1 ,ARRAY_SIZE (hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids); } +static void cs35l41_remove_controls (struct cs35l41_hda *cs35l41) +{ +if (!cs35l41->codec) +return ; + +if (cs35l41->fw_load_ctl) { +snd_ctl_remove (cs35l41->codec->card, cs35l41->fw_load_ctl); + cs35l41->fw_load_ctl =NULL ; + } + +if (cs35l41->fw_type_ctl) { +snd_ctl_remove (cs35l41->codec->card, cs35l41->fw_type_ctl); + cs35l41->fw_type_ctl =NULL ; + } +} + +static int cs35l41_add_control (struct cs35l41_hda *cs35l41, +struct snd_kcontrol_new *ctl, +struct snd_kcontrol **kctl) +{ +int ret; + + *kctl =snd_ctl_new1 (ctl, cs35l41); +if (!*kctl) +return -ENOMEM ; + + ret =snd_ctl_add (cs35l41->codec->card, *kctl); +if (ret) { +dev_err (cs35l41->dev,"Failed to add KControl %s = %d\n" , ctl->name, ret); + *kctl =NULL ; +return ret; + } + +dev_dbg (cs35l41->dev,"Added Control %s\n" , ctl->name); + +return 0 ; +} +static int cs35l41_create_controls (struct cs35l41_hda *cs35l41) {char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN ];
@@ -919,23 +957,19 @@ static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)scnprintf (fw_load_ctl_name,SNDRV_CTL_ELEM_ID_NAME_MAXLEN ,"%s DSP1 Firmware Load" , cs35l41->amp_name); - ret =snd_ctl_add (cs35l41->codec->card,snd_ctl_new1 (&fw_type_ctl, cs35l41)); -if (ret) { -dev_err (cs35l41->dev,"Failed to add KControl %s = %d\n" , fw_type_ctl.name, ret); -return ret; - } - -dev_dbg (cs35l41->dev,"Added Control %s\n" , fw_type_ctl.name); - - ret =snd_ctl_add (cs35l41->codec->card,snd_ctl_new1 (&fw_load_ctl, cs35l41)); -if (ret) { -dev_err (cs35l41->dev,"Failed to add KControl %s = %d\n" , fw_load_ctl.name, ret); -return ret; - } + ret =cs35l41_add_control (cs35l41, &fw_type_ctl, &cs35l41->fw_type_ctl); +if (ret) + goto err; -dev_dbg (cs35l41->dev,"Added Control %s\n" , fw_load_ctl.name); + ret =cs35l41_add_control (cs35l41, &fw_load_ctl, &cs35l41->fw_load_ctl); +if (ret) + goto err;return 0 ; + +err: +cs35l41_remove_controls (cs35l41); +return ret; }static int cs35l41_hda_bind (struct device *dev,struct device *master,void *master_data)
@@ -990,8 +1024,13 @@ static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *struct cs35l41_hda *cs35l41 =dev_get_drvdata (dev);struct hda_component *comps = master_data; -if (comps[cs35l41->index].dev == dev) +if (comps[cs35l41->index].dev == dev) {memset (&comps[cs35l41->index],0 ,sizeof (*comps)); + +cs35l41_remove_controls (cs35l41); +cancel_work_sync (&cs35l41->fw_load_work); + cs35l41->codec =NULL ; + } }static const struct component_ops cs35l41_hda_comp_ops = {
@@ -1529,6 +1568,9 @@ void cs35l41_hda_remove(struct device *dev) {struct cs35l41_hda *cs35l41 =dev_get_drvdata (dev); +component_del (cs35l41->dev, &cs35l41_hda_comp_ops); +cancel_work_sync (&cs35l41->fw_load_work); +pm_runtime_get_sync (cs35l41->dev);pm_runtime_dont_use_autosuspend (cs35l41->dev);pm_runtime_disable (cs35l41->dev);
@@ -1536,8 +1578,6 @@ void cs35l41_hda_remove(struct device *dev)if (cs35l41->halo_initialized)cs35l41_remove_dsp (cs35l41); -component_del (cs35l41->dev, &cs35l41_hda_comp_ops); -pm_runtime_put_noidle (cs35l41->dev);if (cs35l41_safe_reset (cs35l41->regmap, cs35l41->hw_cfg.bst_type))
sound/pci/hda/cs35l41_hda.h +4 -0
@@ -45,6 +45,8 @@ enum cs35l41_hda_gpio_function { CS35l41_SYNC, }; +struct snd_kcontrol ; +struct cs35l41_hda {struct device *dev;struct regmap *regmap;
@@ -62,6 +64,8 @@ struct cs35l41_hda {int speaker_id;struct mutex fw_mutex;struct work_struct fw_load_work; +struct snd_kcontrol *fw_type_ctl; +struct snd_kcontrol *fw_load_ctl;struct regmap_irq_chip_data *irq_data;bool firmware_running;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1159/1887 perf/core: Detach event groups during remove_on_exec
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taeyang Lee <[email protected]>
[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
perf_event_remove_on_exec() removes events by calling perf_event_exit_event(). For top-level events, this removes the event from the context with DETACH_EXIT only.
This can leave inconsistent group state when a removed event is a group leader and the group contains siblings without remove_on_exec. If the group was active, the surviving siblings can remain active and attached to the removed leader's sibling list, but are no longer represented by a valid group leader on the PMU context active lists.
A later close of the removed leader uses DETACH_GROUP and can promote the still-active siblings from this stale group state. The next schedule-in can then add an already-linked active_list entry again, corrupting the PMU context active list.
With DEBUG_LIST enabled, this is caught as a list_add double-add in merge_sched_in().
Fix this by detaching group relationships when remove_on_exec removes an event. This preserves the existing task-exit and revoke behavior, while ensuring surviving siblings are ungrouped before the removed event leaves the context.
--- kernel/events/core.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
kernel/events/core.c +7 -6
@@ -4345,7 +4345,8 @@ static void perf_event_enable_on_exec(int ctxn)static void perf_remove_from_owner (struct perf_event *event);static void perf_event_exit_event (struct perf_event *event, -struct perf_event_context *ctx); +struct perf_event_context *ctx, +unsigned long detach_flags);/* * Removes all events from the current task that have been marked
@@ -4376,7 +4377,7 @@ static void perf_event_remove_on_exec(int ctxn) modified = true; -perf_event_exit_event (event, ctx); +perf_event_exit_event (event, ctx,DETACH_GROUP ); }raw_spin_lock_irqsave (&ctx->lock, flags);
@@ -13044,10 +13045,10 @@ static void sync_child_event(struct perf_event *child_event) }static void -perf_event_exit_event (struct perf_event *event,struct perf_event_context *ctx) +perf_event_exit_event (struct perf_event *event,struct perf_event_context *ctx, +unsigned long detach_flags) {struct perf_event *parent_event = event->parent; -unsigned long detach_flags =0 ;if (parent_event) {/*
@@ -13062,7 +13063,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)* Do destroy all inherited groups, we don't care about those * and being thorough is better. */ - detach_flags =DETACH_GROUP |DETACH_CHILD ; + detach_flags |=DETACH_GROUP |DETACH_CHILD ;mutex_lock (&parent_event->child_mutex); }
@@ -13141,7 +13142,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)perf_event_task (child, child_ctx,0 );list_for_each_entry_safe (child_event, next, &child_ctx->event_list, event_entry) -perf_event_exit_event (child_event, child_ctx); +perf_event_exit_event (child_event, child_ctx,0 );mutex_unlock (&child_ctx->mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1160/1887 KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit 2f2312c422fd2695da772cecb30c69994b795964 ]
Put all vmcs12 pages if KVM synthesizes a nested VM-Exit due to invalid guest while emulating VMLAUNCH or VMRESUME. The invalid guest state path doesn't use nested_vmx_vmexit() as that API is intended to be used if and only if L2 is active, and the open coded equivalent neglects to put the vmcs12 pages. Failure to put the vmcs12 pages leaks any pinned pages (and/or mappings) if L1 retries VMLAUNCH/VMRESUME.
Note, the !from_vmenter scenario doesn't suffer the same problem, as vmx_get_nested_state_pages() only gets/pins/maps the vmcs12 pages if L2 is active, i.e. if a "full" VM-Exit is guaranteed before KVM will retry getting vmcs12 pages.
--- arch/x86/kvm/vmx/nested.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kvm/vmx/nested.c +5 -0
@@ -3543,6 +3543,11 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,if (!from_vmentry)return NVMX_VMENTRY_VMEXIT ; +kvm_vcpu_unmap (vcpu, &vmx->nested.apic_access_page_map, false); +kvm_vcpu_unmap (vcpu, &vmx->nested.virtual_apic_map, true); +kvm_vcpu_unmap (vcpu, &vmx->nested.pi_desc_map, true); + vmx->nested.pi_desc =NULL ; +load_vmcs12_host_state (vcpu, vmcs12); vmcs12->vm_exit_reason = exit_reason.full;if (enable_shadow_vmcs ||evmptr_is_valid (vmx->nested.hv_evmcs_vmptr))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1161/1887 ksmbd: fix path resolution in ksmbd_vfs_kern_path_create
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davide Ornaghi <[email protected]>
[ Upstream commit 1c8951963d8ed357f70f59e0ad4ddce2199d2016 ]
The SMB2 open lookup is rooted at the share with LOOKUP_BENEATH, but the create/mkdir/hardlink sink is not: ksmbd_vfs_kern_path_create() builds an absolute path with convert_to_unix_name() and resolves it from AT_FDCWD via start_creating_path(), so a ".." component is walked from the real filesystem root and escapes the export.
An authenticated client races a missing path component so the rooted open lookup returns -ENOENT (taking the create branch) while the same component is present (a directory) when the create walk runs; the create then resolves ".." out of the share.
Root the create walk at the share like the lookup and rename paths already
are: resolve the parent with vfs_path_parent_lookup(..., LOOKUP_BENEATH, &share_conf->vfs_path) and create the final component with start_creating_noperm(). convert_to_unix_name() then has no callers and is removed.
--- fs/smb/server/misc.c | 33 ------------------------------- fs/smb/server/misc.h | 1 - fs/smb/server/vfs.c | 47 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 40 deletions(-)
fs/smb/server/misc.c +0 -33
@@ -284,39 +284,6 @@ char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename)return ksmbd_casefold_sharename (um, name); } -/** -* convert_to_unix_name() - convert windows name to unix format -* @share: ksmbd_share_config pointer -* @name: file name that is relative to share -* -* Return: converted name on success, otherwise NULL -*/ -char *convert_to_unix_name (struct ksmbd_share_config *share,const char *name) -{ -int no_slash =0 , name_len, path_len; -char *new_name; - -if (name[0 ] =='/' ) - name++; - - path_len = share->path_sz; - name_len =strlen (name); - new_name =kmalloc (path_len + name_len +2 ,GFP_KERNEL ); -if (!new_name) -return new_name; - -memcpy (new_name, share->path, path_len); -if (new_name[path_len -1 ] !='/' ) { - new_name[path_len] ='/' ; - no_slash =1 ; - } - -memcpy (new_name + path_len + no_slash, name, name_len); - path_len += name_len + no_slash; - new_name[path_len] =0x00 ; -return new_name; -} -char *ksmbd_convert_dir_info_name (struct ksmbd_dir_info *d_info,const struct nls_table *local_nls,int *conv_len)
fs/smb/server/misc.h +0 -1
@@ -22,7 +22,6 @@ void ksmbd_strip_last_slash(char *path);void ksmbd_conv_path_to_windows (char *path);char *ksmbd_casefold_sharename (struct unicode_map *um,const char *name);char *ksmbd_extract_sharename (struct unicode_map *um,const char *treename); -char *convert_to_unix_name (struct ksmbd_share_config *share,const char *name);#define KSMBD_DIR_INFO_ALIGNMENT 8struct ksmbd_dir_info ;
fs/smb/server/vfs.c +41 -6
56 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1162/1887 ksmbd: bound DACL dedup walk to copied ACEs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 58d97fcd0bf1aee694e244cc28635b9df95b543b ]
set_ntacl_dacl() can stop copying ACEs before consuming the full input DACL when size accounting overflows.
When that happens, num_aces reflects only the ACEs that were actually copied into the output DACL, but set_posix_acl_entries_dacl() still receives nt_num_aces and uses it to walk the existing ACE array during dedup.
That makes the dedup walk scan past the copied ACE array and inspect buffer tail that does not contain valid ACEs.
Split the two meanings currently carried by the NT ACE count. Pass the number of copied NT ACEs to bound the dedup walk, and preserve the original "input DACL had NT ACEs" state separately for the Everyone/default ACL fallback.
This keeps the dedup walk aligned with the ACEs that are actually present in the rebuilt DACL.
--- fs/smb/server/smbacl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/smb/server/smbacl.c +10 -6
@@ -603,7 +603,8 @@ static void parse_dacl(struct user_namespace *user_ns,static void set_posix_acl_entries_dacl (struct user_namespace *user_ns,struct smb_ace *pndace,struct smb_fattr *fattr,u32 *num_aces, -u16 *size,u32 nt_aces_num) +u16 *size,u32 existing_nt_aces, +bool had_nt_aces) {struct posix_acl_entry *pace;struct smb_sid *sid;
@@ -635,14 +636,14 @@ static void set_posix_acl_entries_dacl(struct user_namespace *user_ns, gid =posix_acl_gid_translate (user_ns, pace);id_to_sid (gid,SIDUNIX_GROUP , sid); - }else if (pace->e_tag ==ACL_OTHER && !nt_aces_num) { + }else if (pace->e_tag ==ACL_OTHER && !had_nt_aces) {smb_copy_sid (sid, &sid_everyone); }else {kfree (sid);continue ; } ntace = pndace; -for (j =0 ; j < nt_aces_num; j++) { +for (j =0 ; j < existing_nt_aces; j++) {if (ntace->sid.sub_auth[ntace->sid.num_subauth -1 ] == sid->sub_auth[sid->num_subauth -1 ]) goto pass_same_sid;
@@ -686,7 +687,7 @@ static void set_posix_acl_entries_dacl(struct user_namespace *user_ns,kfree (sid); } -if (nt_aces_num) +if (had_nt_aces)return ; posix_default_acl:
@@ -740,6 +741,7 @@ static void set_ntacl_dacl(struct user_namespace *user_ns, {struct smb_ace *ntace, *pndace;int nt_num_aces =le32_to_cpu (nt_dacl->num_aces), num_aces =0 ; +u32 copied_nt_aces;unsigned short size =0 ;int i;
@@ -780,8 +782,10 @@ static void set_ntacl_dacl(struct user_namespace *user_ns, } } + copied_nt_aces = num_aces;set_posix_acl_entries_dacl (user_ns, pndace, fattr, - &num_aces, &size, nt_num_aces); + &num_aces, &size, copied_nt_aces, + nt_num_aces !=0 ); pndacl->num_aces =cpu_to_le32 (num_aces); pndacl->size =cpu_to_le16 (le16_to_cpu (pndacl->size) + size); }
@@ -799,7 +803,7 @@ static void set_mode_dacl(struct user_namespace *user_ns,if (fattr->cf_acls) {set_posix_acl_entries_dacl (user_ns, pndace, fattr, - &num_aces, &size, num_aces); + &num_aces, &size, num_aces, false); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1163/1887 drm/amdgpu: fix aperture mapping leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit ea772a440d56b285f4d491affac50ecd41f6b402 ]
amdgpu_pci_remove() calls drm_dev_unplug() before invoking the driver fini routines. This causes drm_dev_enter() in amdgpu_ttm_fini() to always return false, so iounmap(aper_base_kaddr) never runs on normal driver unload, leaving an orphaned entry in the x86 PAT interval tree.
On connected_to_cpu hardware, the aperture is mapped write-back (WB) via ioremap_cache(). On reload, IP discovery calls memremap(..., MEMREMAP_WC) over the same range. The WC vs WB conflict causes:
ioremap error for 0x..., requested 0x1, got 0x0
amdgpu: discovery failed: -2
Fix by switching to devres-managed mappings so cleanup is guaranteed regardless of drm_dev_enter() state:
- connected_to_cpu path: devm_memremap(MEMREMAP_WB). For IORESOURCE_SYSTEM_RAM ranges this takes the try_ram_remap() shortcut, returning __va(offset) from the existing kernel direct map. No new ioremap VA or PAT entry is created, so there is nothing to orphan.
- dGPU path: devm_ioremap_wc() registers iounmap() as a devres action, guaranteeing cleanup at device_del() time.
Also remove iounmap(aper_base_kaddr) from amdgpu_device_unmap_mmio() since the mapping is now devres-owned.
v2: Remove redundant x86_64 guard (Lijo)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 33 ++++++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +0 -2
@@ -4102,8 +4102,6 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)iounmap (adev->rmmio); adev->rmmio =NULL ; -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr =NULL ;/* Memory manager related */
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +15 -18
@@ -1777,15 +1777,20 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)/* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_buffer_funcs_status (adev, false);#ifdef CONFIG_64BIT -#ifdef CONFIG_X86 -if (adev->gmc.xgmi.connected_to_cpu) - adev->mman.aper_base_kaddr =ioremap_cache (adev->gmc.aper_base, - adev->gmc.visible_vram_size); - - else -#endif - adev->mman.aper_base_kaddr =ioremap_wc (adev->gmc.aper_base, - adev->gmc.visible_vram_size); +if (adev->gmc.xgmi.connected_to_cpu) { +void *kaddr =devm_memremap (adev->dev, adev->gmc.aper_base, + adev->gmc.visible_vram_size, +MEMREMAP_WB ); +if (IS_ERR (kaddr)) +return PTR_ERR (kaddr); + adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr; + }else { + adev->mman.aper_base_kaddr =devm_ioremap_wc (adev->dev, + adev->gmc.aper_base, + adev->gmc.visible_vram_size); +if (!adev->mman.aper_base_kaddr) +return -ENOMEM ; + }#endif /*
@@ -1923,7 +1928,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)*/ void amdgpu_ttm_fini (struct amdgpu_device *adev) { -int idx;if (!adev->mman.initialized)return ;
@@ -1942,14 +1946,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)amdgpu_ttm_fw_reserve_vram_fini (adev);amdgpu_ttm_drv_reserve_vram_fini (adev); -if (drm_dev_enter (adev_to_drm (adev), &idx)) { - -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); - adev->mman.aper_base_kaddr =NULL ; - -drm_dev_exit (idx); - } + adev->mman.aper_base_kaddr =NULL ;amdgpu_vram_mgr_fini (adev);amdgpu_gtt_mgr_fini (adev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1164/1887 tcp: challenge ACK for non-exact RST in SYN-RECEIVED
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
[ Upstream commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 ]
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response.
--- include/net/tcp.h | 2 ++ net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++---------- net/ipv4/tcp_minisocks.c | 12 ++++++++- 3 files changed, 56 insertions(+), 14 deletions(-)
include/net/tcp.h +2 -0
@@ -1641,6 +1641,8 @@ static inline bool tcp_paws_reject(const struct tcp_options_received *rx_opt,bool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack (struct sock *sk,struct sk_buff *skb, +struct request_sock *req);static inline void tcp_mib_init (struct net *net) {
net/ipv4/tcp_input.c +43 -13
79 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +11 -1
@@ -709,7 +709,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,* elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ -if ((flg &TCP_FLAG_ACK ) && !fastopen && +if ((flg &TCP_FLAG_ACK ) && !(flg &TCP_FLAG_RST ) && !fastopen && (TCP_SKB_CB (skb)->ack_seq !=tcp_rsk (req)->snt_isn +1 ))return sk;
@@ -742,6 +742,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, flg &= ~TCP_FLAG_SYN ; } +/* RFC 5961 section 3.2, as clarified by RFC 9293 section +* 3.10.7.4, requires a challenge ACK for a non-exact +* in-window RST in SYN-RECEIVED. +*/ +if ((flg &TCP_FLAG_RST ) && +TCP_SKB_CB (skb)->seq !=tcp_rsk (req)->rcv_nxt) { +tcp_reqsk_send_challenge_ack (sk, skb, req); +return NULL ; + } +/* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1165/1887 media: vivid: fix cleanup bugs in vivid_init()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit a07c179a92e949172ca52f6d4a13202ea88cd4b7 ]
When platform_device_register() fails in vivid_init(), the embedded struct device in vivid_pdev has already been initialized by device_initialize(), but the failure path jumps to free_output_strings without dropping the device reference for the current platform device:
vivid_init()
-> platform_device_register(&vivid_pdev)
-> device_initialize(&vivid_pdev.dev)
-> setup_pdev_dma_masks(&vivid_pdev)
-> platform_device_add(&vivid_pdev)This leads to a reference leak when platform_device_register() fails. Fix this by calling platform_device_put() before jumping to the common cleanup path.
Also, the unreg_driver label incorrectly calls platform_driver_register() instead of platform_driver_unregister(), which breaks cleanup when workqueue creation fails after successful driver registration. Fix that as well.
The reference leak was identified by a static analysis tool I developed and confirmed by manual review. The incorrect cleanup call was found during code inspection.
--- drivers/media/test-drivers/vivid/vivid-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/media/test-drivers/vivid/vivid-core.c +3 -1
@@ -2163,8 +2163,10 @@ static int __init vivid_init(void)int ret; ret =platform_device_register (&vivid_pdev); -if (ret) +if (ret) { +platform_device_put (&vivid_pdev);return ret; + } ret =platform_driver_register (&vivid_pdrv);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1166/1887 drm/vc4: Shut down BO cache timer before teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 6273dd3ffb54ec581855b82ae77331b66028249c ]
The BO cache timer callback schedules time_work, and time_work can rearm the timer through vc4_bo_cache_free_old().
vc4_bo_cache_destroy() deletes the timer and then cancels the work, which does not break that cycle: the work being cancelled can rearm the timer, and the timer then queues work again after teardown.
Use timer_shutdown_sync() instead, so the timer cannot be rearmed and the cycle ends with cancel_work_sync().
--- drivers/gpu/drm/vc4/vc4_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_bo.c +1 -1
@@ -1050,7 +1050,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)struct vc4_dev *vc4 =to_vc4_dev (dev);int i; -del_timer (&vc4->bo_cache.time_timer); +timer_shutdown_sync (&vc4->bo_cache.time_timer);cancel_work_sync (&vc4->bo_cache.time_work);vc4_bo_cache_purge (dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1167/1887 drm/amd/amdgpu: Fix errors & warnings in amdgpu _bios, _cs, _dma_buf, _fence.c
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit 9e690184586bfb88efa176cdf912414f6c53519c ]
The following checkpatch errors & warning is removed.
ERROR: else should follow close brace '}'
ERROR: trailing statements should be on next line
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
WARNING: Possible repeated word: 'Fences'
WARNING: Missing a blank line after declarations
WARNING: braces {} are not necessary for single statement blocks
WARNING: Comparisons should place the constant on the right side of the test
WARNING: printk() should include KERN_<LEVEL> facility level
Stable-dep-of: 65bff2661760 ("drm/amdgpu: Release VFCT ACPI table reference")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 16 +++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 16 ++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 14 ++++++++------ 4 files changed, 24 insertions(+), 24 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +7 -9
@@ -105,9 +105,8 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev) adev->bios =NULL ; vram_base =pci_resource_start (adev->pdev,0 ); bios =ioremap_wc (vram_base, size); -if (!bios) { +if (!bios)return false; - } adev->bios =kmalloc (size,GFP_KERNEL );if (!adev->bios) {
@@ -134,9 +133,8 @@ bool amdgpu_read_bios(struct amdgpu_device *adev) adev->bios =NULL ;/* XXX: some cards may return 0 for rom size? ddx has a workaround */ bios =pci_map_rom (adev->pdev, &size); -if (!bios) { +if (!bios)return false; - } adev->bios =kzalloc (size,GFP_KERNEL );if (adev->bios ==NULL ) {
@@ -169,9 +167,9 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev) header[AMD_VBIOS_SIGNATURE_END ] =0 ;if ((!AMD_IS_VALID_VBIOS (header)) || -0 !=memcmp ((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET ], -AMD_VBIOS_SIGNATURE , -strlen (AMD_VBIOS_SIGNATURE ))) +memcmp ((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET ], +AMD_VBIOS_SIGNATURE , +strlen (AMD_VBIOS_SIGNATURE )) !=0 )return false;/* valid vbios, go on */
@@ -265,7 +263,7 @@ static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios, status =acpi_evaluate_object (atrm_handle,NULL , &atrm_arg, &buffer);if (ACPI_FAILURE (status)) { -printk ("failed to evaluate ATRM got %s\n" ,acpi_format_exception (status)); +DRM_ERROR ("failed to evaluate ATRM got %s\n" ,acpi_format_exception (status));return -ENODEV ; }
@@ -407,7 +405,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)struct acpi_table_header *hdr;acpi_size tbl_size;UEFI_ACPI_VFCT *vfct; -unsigned offset; +unsigned int offset;if (!ACPI_SUCCESS (acpi_get_table ("VFCT" ,1 , &hdr)))return false;
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +8 -8
@@ -384,7 +384,7 @@ static int amdgpu_cs_p2_dependencies(struct amdgpu_cs_parser *p, {struct drm_amdgpu_cs_chunk_dep *deps = chunk->kdata;struct amdgpu_fpriv *fpriv = p->filp->driver_priv; -unsigned num_deps; +unsigned int num_deps;int i, r; num_deps = chunk->length_dw * 4 /
@@ -456,7 +456,7 @@ static int amdgpu_cs_p2_syncobj_in(struct amdgpu_cs_parser *p, struct amdgpu_cs_chunk *chunk) {struct drm_amdgpu_cs_chunk_sem *deps = chunk->kdata; -unsigned num_deps; +unsigned int num_deps;int i, r; num_deps = chunk->length_dw * 4 /
@@ -474,7 +474,7 @@ static int amdgpu_cs_p2_syncobj_timeline_wait(struct amdgpu_cs_parser *p, struct amdgpu_cs_chunk *chunk) {struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps = chunk->kdata; -unsigned num_deps; +unsigned int num_deps;int i, r; num_deps = chunk->length_dw * 4 /
@@ -494,7 +494,7 @@ static int amdgpu_cs_p2_syncobj_out(struct amdgpu_cs_parser *p, struct amdgpu_cs_chunk *chunk) {struct drm_amdgpu_cs_chunk_sem *deps = chunk->kdata; -unsigned num_deps; +unsigned int num_deps;int i; num_deps = chunk->length_dw * 4 /
@@ -528,7 +528,7 @@ static int amdgpu_cs_p2_syncobj_timeline_signal(struct amdgpu_cs_parser *p, struct amdgpu_cs_chunk *chunk) {struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps = chunk->kdata; -unsigned num_deps; +unsigned int num_deps;int i; num_deps = chunk->length_dw * 4 /
@@ -721,6 +721,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,if (used_vis_vram < total_vis_vram) {u64 free_vis_vram = total_vis_vram - used_vis_vram; + adev->mm_stats.accum_us_vis =min (adev->mm_stats.accum_us_vis + increment_us, us_upper_bound);
@@ -1043,9 +1044,8 @@ static int amdgpu_cs_patch_ibs(struct amdgpu_cs_parser *p,/* the IB should be reserved at this point */ r =amdgpu_bo_kmap (aobj, (void **)&kptr); -if (r) { +if (r)return r; - } kptr += va_start - (m->start *AMDGPU_GPU_PAGE_SIZE );
@@ -1318,7 +1318,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser) {struct amdgpu_device *adev = parser->adev;struct amdgpu_bo_list_entry *e; -unsigned i; +unsigned int i;for (i =0 ; i < parser->num_post_deps; i++) {drm_syncobj_put (parser->post_deps[i].syncobj);
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +1 -1
@@ -173,7 +173,7 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,if (!bo->tbo.pin_count) {/* move buffer into GTT or VRAM */ struct ttm_operation_ctx ctx = { false, false }; -unsigned domains =AMDGPU_GEM_DOMAIN_GTT ; +unsigned int domains =AMDGPU_GEM_DOMAIN_GTT ;if (bo->preferred_domains &AMDGPU_GEM_DOMAIN_VRAM && attach->peer2peer) {
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +8 -6
@@ -42,7 +42,6 @@#include "amdgpu_reset.h" /* -* Fences * Fences mark an event in the GPUs pipeline and are used * for GPU/CPU synchronization. When the fence is written, * it is expected that all buffers associated with that fence
@@ -139,7 +138,7 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring)* Returns 0 on success, -ENOMEM on failure. */ int amdgpu_fence_emit (struct amdgpu_ring *ring,struct dma_fence **f,struct amdgpu_job *job, -unsigned flags) +unsigned int flags) {struct amdgpu_device *adev = ring->adev;struct dma_fence *fence;
@@ -173,11 +172,11 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd adev->fence_context + ring->idx, seq);/* Against remove in amdgpu_job_{free, free_cb} */ dma_fence_get (fence); - } -else + }else {dma_fence_init (fence, &amdgpu_fence_ops, &ring->fence_drv.lock, adev->fence_context + ring->idx, seq); + } } amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
@@ -393,7 +392,7 @@ signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,* Returns the number of emitted fences on the ring. Used by the * dynpm code to ring track activity. */ -unsigned amdgpu_fence_count_emitted (struct amdgpu_ring *ring) +unsigned int amdgpu_fence_count_emitted (struct amdgpu_ring *ring) {uint64_t emitted;
@@ -421,7 +420,7 @@ unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring)*/ int amdgpu_fence_driver_start_ring (struct amdgpu_ring *ring,struct amdgpu_irq_src *irq_src, -unsigned irq_type) +unsigned int irq_type) {struct amdgpu_device *adev = ring->adev;uint64_t index;
@@ -636,6 +635,7 @@ void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)for (i =0 ; i <AMDGPU_MAX_RINGS ; i++) {struct amdgpu_ring *ring = adev->rings[i]; +if (!ring || !ring->fence_drv.initialized)continue ;
@@ -824,6 +824,7 @@ static int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused)for (i =0 ; i <AMDGPU_MAX_RINGS ; ++i) {struct amdgpu_ring *ring = adev->rings[i]; +if (!ring || !ring->fence_drv.initialized)continue ;
@@ -897,6 +898,7 @@ static void amdgpu_debugfs_reset_work(struct work_struct *work) reset_work);struct amdgpu_reset_context reset_context; +memset (&reset_context,0 ,sizeof (reset_context)); reset_context.method =AMD_RESET_METHOD_NONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1168/1887 drm/amdgpu: Use dbg level for VBIOS check messages
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <[email protected]>
[ Upstream commit 635c659fceed82f934623188471ff604e098aab7 ]
Driver has different ways to fetch VBIOS. If one of the methods doesn't find an authentic one, it will show misleading info messages eventhough a subsequent method finds a valid VBIOS. Keep the message level at debug and add device context.
Stable-dep-of: 65bff2661760 ("drm/amdgpu: Release VFCT ACPI table reference")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +14 -12
@@ -47,35 +47,37 @@/* Check if current bios is an ATOM BIOS. * Return true if it is ATOM BIOS. Otherwise, return false. */ -static bool check_atom_bios (uint8_t *bios,size_t size) +static bool check_atom_bios (struct amdgpu_device *adev,size_t size) {uint16_t tmp, bios_header_start; +uint8_t *bios = adev->bios;if (!bios || size <0x49 ) { -DRM_INFO ("vbios mem is null or mem size is wrong\n" ); +dev_dbg (adev->dev,"VBIOS mem is null or mem size is wrong\n" );return false; }if (!AMD_IS_VALID_VBIOS (bios)) { -DRM_INFO ("BIOS signature incorrect %x %x\n" , bios[0 ], bios[1 ]); +dev_dbg (adev->dev,"VBIOS signature incorrect %x %x\n" , bios[0 ], + bios[1 ]);return false; } bios_header_start = bios[0x48 ] | (bios[0x49 ] <<8 );if (!bios_header_start) { -DRM_INFO ("Can't locate bios header\n" ); +dev_dbg (adev->dev,"Can't locate VBIOS header\n" );return false; } tmp = bios_header_start +4 ;if (size < tmp) { -DRM_INFO ("BIOS header is broken\n" ); +dev_dbg (adev->dev,"VBIOS header is broken\n" );return false; }if (!memcmp (bios + tmp,"ATOM" ,4 ) || !memcmp (bios + tmp,"MOTA" ,4 )) { -DRM_DEBUG ("ATOMBIOS detected\n" ); +dev_dbg (adev->dev,"ATOMBIOS detected\n" );return true; }
@@ -117,7 +119,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)memcpy_fromio (adev->bios, bios, size);iounmap (bios); -if (!check_atom_bios (adev->bios, size)) { +if (!check_atom_bios (adev, size)) {kfree (adev->bios);return false; }
@@ -145,7 +147,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)memcpy_fromio (adev->bios, bios, size);pci_unmap_rom (adev->pdev, bios); -if (!check_atom_bios (adev->bios, size)) { +if (!check_atom_bios (adev, size)) {kfree (adev->bios);return false; }
@@ -185,7 +187,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)/* read complete BIOS */ amdgpu_asic_read_bios_from_rom (adev, adev->bios, len); -if (!check_atom_bios (adev->bios, len)) { +if (!check_atom_bios (adev, len)) {kfree (adev->bios);return false; }
@@ -215,7 +217,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)memcpy_fromio (adev->bios, bios, romlen);iounmap (bios); -if (!check_atom_bios (adev->bios, romlen)) +if (!check_atom_bios (adev, romlen)) goto free_bios; adev->bios_size = romlen;
@@ -337,7 +339,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)break ; } -if (!check_atom_bios (adev->bios, size)) { +if (!check_atom_bios (adev, size)) {kfree (adev->bios);return false; }
@@ -440,7 +442,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) vhdr->ImageLength, GFP_KERNEL); -if (!check_atom_bios (adev->bios, vhdr->ImageLength)) { +if (!check_atom_bios (adev, vhdr->ImageLength)) {kfree (adev->bios);return false; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1169/1887 drm/amdgpu: Add wrapper for freeing vbios memory
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <[email protected]>
[ Upstream commit e986e89659e18ba986db044df58f165042817dc3 ]
Use bios_release wrapper to release memory allocated for vbios image and reset the variables.
v2:
Use the same wrapper for clean up in sw_fini (Alex Deucher)
Stable-dep-of: 65bff2661760 ("drm/amdgpu: Release VFCT ACPI table reference")
--- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 20 ++++++++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +-- 3 files changed, 16 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu.h +1 -0
@@ -384,6 +384,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev);bool amdgpu_read_bios (struct amdgpu_device *adev);bool amdgpu_soc15_read_bios_from_rom (struct amdgpu_device *adev,u8 *bios,u32 length_bytes); +void amdgpu_bios_release (struct amdgpu_device *adev);/* * Clocks */
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +14 -6
@@ -84,6 +84,13 @@ static bool check_atom_bios(struct amdgpu_device *adev, size_t size)return false; } +void amdgpu_bios_release (struct amdgpu_device *adev) +{ +kfree (adev->bios); + adev->bios =NULL ; + adev->bios_size =0 ; +} +/* If you boot an IGP board with a discrete card as the primary, * the IGP rom is not accessible via the rom bar as the IGP rom is * part of the system bios. On boot, the system bios puts a
@@ -120,7 +127,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)iounmap (bios);if (!check_atom_bios (adev, size)) { -kfree (adev->bios); +amdgpu_bios_release (adev);return false; }
@@ -148,7 +155,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)pci_unmap_rom (adev->pdev, bios);if (!check_atom_bios (adev, size)) { -kfree (adev->bios); +amdgpu_bios_release (adev);return false; }
@@ -188,7 +195,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)amdgpu_asic_read_bios_from_rom (adev, adev->bios, len);if (!check_atom_bios (adev, len)) { -kfree (adev->bios); +amdgpu_bios_release (adev);return false; }
@@ -224,7 +231,8 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)return true; free_bios: -kfree (adev->bios); +amdgpu_bios_release (adev); +return false; }
@@ -340,7 +348,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) }if (!check_atom_bios (adev, size)) { -kfree (adev->bios); +amdgpu_bios_release (adev);return false; } adev->bios_size = size;
@@ -443,7 +451,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) GFP_KERNEL);if (!check_atom_bios (adev, vhdr->ImageLength)) { -kfree (adev->bios); +amdgpu_bios_release (adev);return false; } adev->bios_size = vhdr->ImageLength;
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +1 -2
@@ -4196,8 +4196,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)if (amdgpu_emu_mode !=1 )amdgpu_atombios_fini (adev); -kfree (adev->bios); - adev->bios =NULL ; +amdgpu_bios_release (adev); px =amdgpu_device_supports_px (adev_to_drm (adev));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1170/1887 drm/amdgpu: Release VFCT ACPI table reference
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
[ Upstream commit 65bff26617607c1331283232016c0e89088c5b78 ]
amdgpu_acpi_vfct_bios() fetches the VFCT table with acpi_get_table() but never releases it. acpi_get_table() takes a reference on the table (incrementing its validation_count and mapping it on the 0->1 transition); without a paired acpi_put_table() the mapping is leaked on every call, whether or not a matching VBIOS image is found.
Route all exit paths after the table is acquired through a common acpi_put_table(). The VBIOS image is copied out with kmemdup() before the table is released, so it remains valid for the caller.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +11 -6
@@ -416,13 +416,14 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)acpi_size tbl_size;UEFI_ACPI_VFCT *vfct;unsigned int offset; +bool r = false;if (!ACPI_SUCCESS (acpi_get_table ("VFCT" ,1 , &hdr)))return false; tbl_size = hdr->length;if (tbl_size <sizeof (UEFI_ACPI_VFCT )) {dev_info (adev->dev,"ACPI VFCT table present but broken (too short #1),skipping\n" ); -return false; + goto out; } vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -435,13 +436,13 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) offset +=sizeof (VFCT_IMAGE_HEADER );if (offset > tbl_size) {dev_info (adev->dev,"ACPI VFCT image header truncated,skipping\n" ); -return false; + goto out; } offset += vhdr->ImageLength;if (offset > tbl_size) {dev_info (adev->dev,"ACPI VFCT image truncated,skipping\n" ); -return false; + goto out; } if (vhdr->ImageLength &&
@@ -452,15 +453,19 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)if (!check_atom_bios (adev, vhdr->ImageLength)) {amdgpu_bios_release (adev); -return false; + goto out; } adev->bios_size = vhdr->ImageLength; - return true; + r = true; + goto out; } }dev_info (adev->dev,"ACPI VFCT table present but broken (too short #2),skipping\n" ); -return false; + +out: +acpi_put_table (hdr); +return r; }#else static inline bool amdgpu_acpi_vfct_bios (struct amdgpu_device *adev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1171/1887 drm/i915/mst: limit DP MST ESI service loop
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
[ Upstream commit 005771c18c5b2c98cb4e7517661aea460990fd3f ]
The loop in intel_dp_check_mst_status() keeps servicing interrupts originating from the sink without bound. Add an upper bound to the new interrupts occurring during interrupt processing to not get stuck on potentially stuck sink devices. Use arbitrary 32 tries to clear incoming interrupts in one go.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
Note: The condition likely pre-dates the commit in the Fixes: tag, but this is about as far back as a backport has any chance of succeeding. Before that, the retry had a goto.
--- drivers/gpu/drm/i915/display/intel_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp.c +7 -1
@@ -3864,10 +3864,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) {struct drm_i915_private *i915 =dp_to_i915 (intel_dp);bool link_ok = true; +int tries =33 ;drm_WARN_ON_ONCE (&i915->drm, intel_dp->active_mst_links <0 ); -for (;;) { +while (--tries) {u8 esi[4 ] = {};u8 ack[4 ] = {};
@@ -3900,6 +3901,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)drm_dp_mst_hpd_irq_send_new_request (&intel_dp->mst_mgr); } +if (!tries) { +drm_dbg_kms (&i915->drm,"DPRX ESI not clearing, device may be stuck\n" ); + link_ok = false; + } +return link_ok; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1172/1887 drm/i915/gt: Fix NULL deref on sched_engine alloc failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
[ Upstream commit 82ec992c404c3dc774c5e9f3d4aa858e97187675 ]
Avoid using intel_context_put() before intel_context_init() in execlists_create_virtual() as the kref_put() inside would lead to NULL deref on the IOCTL path when sched_engine allocation fails.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- .../drm/i915/gt/intel_execlists_submission.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
drivers/gpu/drm/i915/gt/intel_execlists_submission.c +10 -9
@@ -3932,11 +3932,11 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count, {struct virtual_engine *ve;unsigned int n; -int err; +int err = -ENOMEM ; ve =kzalloc (struct_size (ve, siblings, count),GFP_KERNEL );if (!ve) -return ERR_PTR (-ENOMEM ); + goto err; ve->base.i915 = siblings[0 ]->i915; ve->base.gt = siblings[0 ]->gt;
@@ -3968,10 +3968,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,intel_engine_init_execlists (&ve->base); ve->base.sched_engine =i915_sched_engine_create (ENGINE_VIRTUAL ); -if (!ve->base.sched_engine) { - err = -ENOMEM ; - goto err_put; - } +if (!ve->base.sched_engine) + goto err_noput; ve->base.sched_engine->private_data = &ve->base; ve->base.cops = &virtual_context_ops;
@@ -3987,10 +3985,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,intel_context_init (&ve->context, &ve->base); ve->base.breadcrumbs =intel_breadcrumbs_create (NULL ); -if (!ve->base.breadcrumbs) { - err = -ENOMEM ; +if (!ve->base.breadcrumbs) goto err_put; - }for (n =0 ; n < count; n++) {struct intel_engine_cs *sibling = siblings[n];
@@ -4063,8 +4059,13 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,virtual_engine_initial_hint (ve);return &ve->context; +err_noput: +kfree (ve); + goto err; + err_put:intel_context_put (&ve->context); +err:return ERR_PTR (err); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1173/1887 drm/i915/bios: range check LFP Data Block panel_type2
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
[ Upstream commit 2084503f2d087bf956198e7f6eb25b03a7049cb2 ]
While the panel_type from LFP Data Block is range checked, panel_type2 is not. Add a few helpers for range checking, and use them to not only check panel_type2, but also improve clarity and correctness in the panel type selection.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
v2:
- Fix commit message typo (Michał)
- Add is_panel_type_pnp() (Ville)
--- drivers/gpu/drm/i915/display/intel_bios.c | 36 ++++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-)
drivers/gpu/drm/i915/display/intel_bios.c +28 -8
@@ -618,6 +618,21 @@ static void dump_pnp_id(struct drm_i915_private *i915, pnp_id->mfg_week, pnp_id->mfg_year + 1990); } +static bool is_panel_type_valid (int panel_type) +{ +return panel_type >=0 && panel_type <16 ; +} + +static bool is_panel_type_pnp (int panel_type) +{ +return panel_type ==0xff ; +} + +static bool is_panel_type_valid_or_pnp (int panel_type) +{ +return is_panel_type_valid (panel_type) ||is_panel_type_pnp (panel_type); +} +static int opregion_get_panel_type (struct drm_i915_private *i915,const struct intel_bios_encoder_data *devdata,const struct edid *edid,bool use_fallback)
@@ -635,15 +650,21 @@ static int vbt_get_panel_type(struct drm_i915_private *i915,if (!lvds_options)return -1 ; -if (lvds_options->panel_type >0xf && - lvds_options->panel_type !=0xff ) { +if (!is_panel_type_valid_or_pnp (lvds_options->panel_type)) {drm_dbg_kms (&i915->drm,"Invalid VBT panel type 0x%x\n" , lvds_options->panel_type);return -1 ; } -if (devdata && devdata->child.handle ==DEVICE_HANDLE_LFP2 ) +if (devdata && devdata->child.handle ==DEVICE_HANDLE_LFP2 ) { +if (!is_panel_type_valid_or_pnp (lvds_options->panel_type2)) { +drm_dbg_kms (&i915->drm,"Invalid VBT panel type 2 0x%x\n" , + lvds_options->panel_type2); +return -1 ; + } +return lvds_options->panel_type2; + }drm_WARN_ON (&i915->drm, devdata && devdata->child.handle !=DEVICE_HANDLE_LFP1 );
@@ -755,13 +776,12 @@ static int get_panel_type(struct drm_i915_private *i915, panel_types[i].name, panel_types[i].panel_type); } -if (panel_types[PANEL_TYPE_OPREGION ].panel_type >=0 ) +if (is_panel_type_valid (panel_types[PANEL_TYPE_OPREGION ].panel_type)) i =PANEL_TYPE_OPREGION ; -else if (panel_types[PANEL_TYPE_VBT ].panel_type ==0xff && - panel_types[PANEL_TYPE_PNPID ].panel_type >=0 ) +else if (is_panel_type_pnp (panel_types[PANEL_TYPE_VBT ].panel_type) && +is_panel_type_valid (panel_types[PANEL_TYPE_PNPID ].panel_type)) i =PANEL_TYPE_PNPID ; -else if (panel_types[PANEL_TYPE_VBT ].panel_type !=0xff && - panel_types[PANEL_TYPE_VBT ].panel_type >=0 ) +else if (is_panel_type_valid (panel_types[PANEL_TYPE_VBT ].panel_type)) i =PANEL_TYPE_VBT ;else i =PANEL_TYPE_FALLBACK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1174/1887 drm/amdkfd: Check bounds on CRIU restore queue type and mqd size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <[email protected]>
[ Upstream commit 47ea05f246bebc81c7796f56265cffd812cf0601 ]
We weren't checking whether the values provided in the private data in kfd CRIU restore were within bounds.
For queue type, add a KFD_QUEUE_TYPE_MAX and ensure the provided type is less than it.
For mqd_size, add new function mqd_size_from_queue_type and confirm that the provided mqd_size matches expectations.
--- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 5 ++++ .../drm/amd/amdkfd/kfd_device_queue_manager.h | 2 ++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 ++- .../amd/amdkfd/kfd_process_queue_manager.c | 24 +++++++++++++------ 4 files changed, 26 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +5 -0
@@ -2437,6 +2437,11 @@ static void kfd_process_hw_exception(struct work_struct *work)amdgpu_amdkfd_gpu_reset (dqm->dev->adev); } +size_t mqd_size_from_queue_type (struct device_queue_manager *dqm,enum kfd_queue_type type) +{ +return dqm->mqd_mgrs[get_mqd_type_from_queue_type (type)]->mqd_size; +} +#if defined(CONFIG_DEBUG_FS ) static void seq_reg_dump(struct seq_file *m,
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +2 -0
@@ -279,6 +279,8 @@ unsigned int get_queues_per_pipe(struct device_queue_manager *dqm);unsigned int get_pipes_per_mec (struct device_queue_manager *dqm);unsigned int get_num_sdma_queues (struct device_queue_manager *dqm);unsigned int get_num_xgmi_sdma_queues (struct device_queue_manager *dqm); +size_t mqd_size_from_queue_type (struct device_queue_manager *dqm, +enum kfd_queue_type type);static inline unsigned int get_sh_mem_bases_32 (struct kfd_process_device *pdd) {
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +2 -1
@@ -404,7 +404,8 @@ enum kfd_queue_type {KFD_QUEUE_TYPE_SDMA ,KFD_QUEUE_TYPE_HIQ ,KFD_QUEUE_TYPE_DIQ , -KFD_QUEUE_TYPE_SDMA_XGMI +KFD_QUEUE_TYPE_SDMA_XGMI , + KFD_QUEUE_TYPE_MAX, }; enum kfd_queue_format {
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +17 -7
@@ -829,6 +829,23 @@ int kfd_criu_restore_queue(struct kfd_process *p, goto exit; } + pdd =kfd_process_device_data_by_id (p, q_data->gpu_id); +if (!pdd) { +pr_err ("Failed to get pdd\n" ); + ret = -EINVAL ; + goto exit; + } + +if (q_data->type >=KFD_QUEUE_TYPE_MAX ) { + ret = -EINVAL ; + goto exit; + } + +if (q_data->mqd_size !=mqd_size_from_queue_type (pdd->dev->dqm, q_data->type)) { + ret = -EINVAL ; + goto exit; + } + *priv_data_offset +=sizeof (*q_data); q_extra_data_size = (uint64_t )q_data->ctl_stack_size + q_data->mqd_size;
@@ -851,13 +868,6 @@ int kfd_criu_restore_queue(struct kfd_process *p, *priv_data_offset += q_extra_data_size; - pdd =kfd_process_device_data_by_id (p, q_data->gpu_id); -if (!pdd) { -pr_err ("Failed to get pdd\n" ); - ret = -EINVAL ; - goto exit; - } -if (!pdd->doorbell_index &&kfd_alloc_process_doorbells (pdd->dev, &pdd->doorbell_index) <0 ) { ret = -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1175/1887 drm/amdgpu: keep amdgpu_ctx_mgr in ctx structure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Zhu <[email protected]>
[ Upstream commit c30e326e488ec43f6b0931f16ddba16a3370ed4a ]
Keep amdgpu_ctx_mgr in ctx structure to track fpriv.
v2: add missing fpriv declaration lost in rebase
Stable-dep-of: c1dc4ccb82c9 ("drm/amdgpu: Fix context pstate override handling")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h | 1 + 2 files changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +2 -0
@@ -304,6 +304,7 @@ static int amdgpu_ctx_get_stable_pstate(struct amdgpu_ctx *ctx,static int amdgpu_ctx_init (struct amdgpu_ctx_mgr *mgr,int32_t priority,struct drm_file *filp,struct amdgpu_ctx *ctx) { +struct amdgpu_fpriv *fpriv = filp->driver_priv;u32 current_stable_pstate;int r;
@@ -332,6 +333,7 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority,else ctx->stable_pstate = current_stable_pstate; + ctx->ctx_mgr = &(fpriv->ctx_mgr);return 0 ; }
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +1 -0
@@ -57,6 +57,7 @@ struct amdgpu_ctx {unsigned long ras_counter_ce;unsigned long ras_counter_ue;uint32_t stable_pstate; +struct amdgpu_ctx_mgr *ctx_mgr; };struct amdgpu_ctx_mgr {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1176/1887 drm/amdgpu: Fix context pstate override handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
[ Upstream commit c1dc4ccb82c9e56325d8e7514ca4c90bd1efb351 ]
There are several problems in the context pstate handling code.
The most serious ones are potential use-after-free and NULL pointer dereferences at context initialization time. Both are due amdgpu_ctx_init() not holding the adev->pm.stable_pstate_ctx_lock, which is otherwise used from both sysfs and the context code itself for modifying and clearing the stored context pointer.
Second issue is that context fini can trample over the pstate configuration set via sysfs. This is due the restore state (ctx->stable_pstate) being saved at context init time, and not if, or when the context actually changes the pstate. As the context exits it will therefore incorrectly restore to what was set before the sysfs override was requested.
The simplest fix is to drastically simplify how the state is tracked, by clearly defining the points at which pstate ownership is taken and released, and to handle all transitions under the correct lock.
Instead of at context init time, the previous state is saved only at the point the context overrides the current state, and is restored on context exit only if the context is still the owner of the current override state.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 71 +++++++++++++++---------- 1 file changed, 42 insertions(+), 29 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +42 -29
@@ -305,7 +305,6 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority, struct drm_file *filp, struct amdgpu_ctx *ctx) { struct amdgpu_fpriv *fpriv = filp->driver_priv; -u32 current_stable_pstate;int r; r =amdgpu_ctx_priority_permit (filp, priority);
@@ -323,37 +322,22 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority, ctx->vram_lost_counter =atomic_read (&mgr->adev->vram_lost_counter); ctx->init_priority = priority; ctx->override_priority =AMDGPU_CTX_PRIORITY_UNSET ; - - r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); -if (r) -return r; - -if (mgr->adev->pm.stable_pstate_ctx) - ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate; -else - ctx->stable_pstate = current_stable_pstate; + ctx->stable_pstate =AMDGPU_CTX_STABLE_PSTATE_NONE ; ctx->ctx_mgr = &(fpriv->ctx_mgr);return 0 ; } -static int amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, -u32 stable_pstate) +static int __amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, +u32 stable_pstate) {struct amdgpu_device *adev = ctx->mgr->adev;enum amd_dpm_forced_level level; +struct amdgpu_ctx *current_ctx;u32 current_stable_pstate; -int r; +int r =0 ; -mutex_lock (&adev->pm.stable_pstate_ctx_lock); -if (adev->pm.stable_pstate_ctx && adev->pm.stable_pstate_ctx != ctx) { - r = -EBUSY ; - goto done; - } - - r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); -if (r || (stable_pstate == current_stable_pstate)) - goto done; +lockdep_assert_held (&adev->pm.stable_pstate_ctx_lock);switch (stable_pstate) {case AMDGPU_CTX_STABLE_PSTATE_NONE :
@@ -372,17 +356,41 @@ static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx, level =AMD_DPM_FORCED_LEVEL_PROFILE_PEAK ;break ;default : - r = -EINVAL ; - goto done; +return -EINVAL ; } + current_ctx = adev->pm.stable_pstate_ctx; +if (current_ctx && current_ctx != ctx) +return -EBUSY ; + + r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); +if (r || current_stable_pstate == stable_pstate) +return r; + r =amdgpu_dpm_force_performance_level (adev, level); +if (r) +return r; -if (level ==AMD_DPM_FORCED_LEVEL_AUTO ) - adev->pm.stable_pstate_ctx =NULL ; -else +if (!current_ctx) { adev->pm.stable_pstate_ctx = ctx; -done: +/* +* Serialized by context taking ownership for the first time +* while holding adev->pm.stable_pstate_ctx_lock). +*/ +WRITE_ONCE (ctx->stable_pstate, current_stable_pstate); + } + +return 0 ; +} + +static int amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, +u32 stable_pstate) +{ +struct amdgpu_device *adev = ctx->mgr->adev; +int r; + +mutex_lock (&adev->pm.stable_pstate_ctx_lock); + r =__amdgpu_ctx_set_stable_pstate (ctx, stable_pstate);mutex_unlock (&adev->pm.stable_pstate_ctx_lock);return r;
@@ -408,7 +416,12 @@ static void amdgpu_ctx_fini(struct kref *ref) }if (drm_dev_enter (adev_to_drm (adev), &idx)) { -amdgpu_ctx_set_stable_pstate (ctx, ctx->stable_pstate); +mutex_lock (&adev->pm.stable_pstate_ctx_lock); +if (adev->pm.stable_pstate_ctx == ctx) { +__amdgpu_ctx_set_stable_pstate (ctx, ctx->stable_pstate); + adev->pm.stable_pstate_ctx =NULL ; + } +mutex_unlock (&adev->pm.stable_pstate_ctx_lock);drm_dev_exit (idx); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1177/1887 net/mlx5: Fix MCIA register buffer overflow on 32 dword reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gal Pressman <[email protected]>
[ Upstream commit 11c057d23465c7a5817a7284c896d19d54c0b616 ]
The MCIA register can return up to 32 dwords (128 bytes) when the device advertises the mcia_32dwords capability, but struct mlx5_ifc_mcia_reg_bits only defines dword_0..11, leaving room for just 12 dwords (48 bytes) of data.
mlx5_query_mcia() clamps the read size to mlx5_mcia_max_bytes() and then memcpy()s that many bytes out of the register, potentially reading past the end of the 'out' buffer. On kernels built with FORTIFY_SOURCE this is caught as a buffer overflow while reading the module EEPROM via ethtool:
detected buffer overflow in memcpy
kernel BUG at lib/string_helpers.c:1048!
RIP: 0010:fortify_panic+0x13/0x20 Call Trace: mlx5_query_mcia.isra.0+0x200/0x210 [mlx5_core] mlx5_query_module_eeprom_by_page+0x4a/0xa0 [mlx5_core] mlx5e_get_module_eeprom_by_page+0xbb/0x120 [mlx5_core] eeprom_prepare_data+0xf3/0x170 ethnl_default_doit+0xf1/0x3b0
Extend the mcia_reg layout to 32 dwords.
--- drivers/net/ethernet/mellanox/mlx5/core/port.c | 4 ++-- include/linux/mlx5/mlx5_ifc.h | 13 +------------ 2 files changed, 3 insertions(+), 14 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/port.c +2 -2
@@ -316,7 +316,7 @@ static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num, status);return -EIO ; } - ptr =MLX5_ADDR_OF (mcia_reg, out, dword_0); + ptr =MLX5_ADDR_OF (mcia_reg, out, dwords); *module_id = ptr[0 ];
@@ -401,7 +401,7 @@ static int mlx5_query_mcia(struct mlx5_core_dev *dev,return -EIO ; } - ptr =MLX5_ADDR_OF (mcia_reg, out, dword_0); + ptr =MLX5_ADDR_OF (mcia_reg, out, dwords);memcpy (data, ptr, size);return size;
include/linux/mlx5/mlx5_ifc.h +1 -12
@@ -11017,18 +11017,7 @@ struct mlx5_ifc_mcia_reg_bits {u8 reserved_at_60[0x20 ]; -u8 dword_0[0x20 ]; -u8 dword_1[0x20 ]; -u8 dword_2[0x20 ]; -u8 dword_3[0x20 ]; -u8 dword_4[0x20 ]; -u8 dword_5[0x20 ]; -u8 dword_6[0x20 ]; -u8 dword_7[0x20 ]; -u8 dword_8[0x20 ]; -u8 dword_9[0x20 ]; -u8 dword_10[0x20 ]; -u8 dword_11[0x20 ]; +u8 dwords[0x400 ]; };struct mlx5_ifc_dcbx_param_bits {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1178/1887 drm/vc4: hvs/v3d: Fix null dereference in unbind
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregor Herburger <[email protected]>
[ Upstream commit 7dc3680b7ffe01add3e9299fde8471d2dd53a8ae ]
The hvs and v3d drivers use dev_get_drvdata(master) in their unbind functions. Since the vc4-drm gets removed before its dependent drivers (vc4_hvs/vc4_v3d) the vc4_hvs_unbind/vc4_v3d_unbind functions try to get drvdata of its master and fails with a null dereference error.
Use the data pointer passed to the unbind functions directly instead of dev_get_drvdata(master). This avoids using potentially freed memory.
--- drivers/gpu/drm/vc4/vc4_hvs.c | 2 +- drivers/gpu/drm/vc4/vc4_v3d.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/vc4/vc4_hvs.c +1 -1
@@ -945,7 +945,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)static void vc4_hvs_unbind (struct device *dev,struct device *master,void *data) { -struct drm_device *drm =dev_get_drvdata (master); +struct drm_device *drm = data;struct vc4_dev *vc4 =to_vc4_dev (drm);struct vc4_hvs *hvs = vc4->hvs;struct drm_mm_node *node, *next;
drivers/gpu/drm/vc4/vc4_v3d.c +1 -1
@@ -511,7 +511,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)static void vc4_v3d_unbind (struct device *dev,struct device *master,void *data) { -struct drm_device *drm =dev_get_drvdata (master); +struct drm_device *drm = data;struct vc4_dev *vc4 =to_vc4_dev (drm);/* A straggler vc4_reset() re-enables the interrupt. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1179/1887 cifs: prevent readdir from changing file size due to stale directory metadata
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <[email protected]>
[ Upstream commit e8a8d54c2d508891c142a928fc7d298c4c8bd0dd ]
Windows Server's directory enumeration metadata lags behind the actual file size after a write+close or rename. A concurrent readdir() in the window between close() returning to userspace and stat() being called overwrites the correct cached i_size with the stale server value, causing stat() to return the wrong size.
Once _cifsFileInfo_put() removes the last writable handle from openFileList, is_size_safe_to_change() permits readdir to overwrite i_size. smb2_close_getattr() then stamps cifs_i->time = jiffies, making the corrupt cached value appear fresh to the next stat().
The existing check (see Fixes:) only blocked stale size updates while an active RW lease was held, not after the last writable handle closes.
Add cifsInodeInfo->time_last_write, written via smp_store_release() at writable close and on setattr/truncate. is_size_safe_to_change() checks is_inode_writable() first (acquiring open_file_lock), then rejects a readdir size update if time_last_write falls within acregmax jiffies. The spinlock release in _cifsFileInfo_put() forms a store-release barrier that pairs with the spin_lock() (load-acquire) in is_inode_writable(), ensuring the subsequent smp_load_acquire() on time_last_write observes any update from a concurrent close(). When a size update is rejected and the server value differs from the cached one, cifs_i->time is cleared to force a fresh QUERY_INFO on the next stat().
readdir is also blocked from changing i_size while writable handles are open or an RW lease is held, even on direct-IO mounts.
For deferred close (closetimeo > 0), time_last_write is refreshed at the actual server close in smb2_deferred_work_close() and in the cifs_close_deferred_file*() drain paths invoked by lease/oplock breaks and tcon teardown, anchoring the protection window to the real close time rather than the earlier userspace close.
time_last_write == 0 skips the time_before() check to avoid false positives near boot on 32-bit systems where jiffies starts close to INITIAL_JIFFIES.
Does not reproduce against Samba or with actimeo=0.
[ Adapted for this tree: only the time_last_write field, its initialisation and the
stores at writable close, deferred close, truncate and the deferred-close drain paths are kept; the readdir size-check hunks do not apply here. ]
Stable-dep-of: c2f2e83e3bbc ("cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths")
--- fs/smb/client/cifsfs.c | 1 + fs/smb/client/cifsglob.h | 1 + fs/smb/client/file.c | 18 ++++++++++++++++-- fs/smb/client/inode.c | 4 ++++ fs/smb/client/misc.c | 27 ++++++++++++++++++++++++--- 5 files changed, 46 insertions(+), 5 deletions(-)
fs/smb/client/cifsfs.c +1 -0
@@ -399,6 +399,7 @@ cifs_alloc_inode(struct super_block *sb)return NULL ; cifs_inode->cifsAttrs =0x20 ;/* default */ cifs_inode->time =0 ; + cifs_inode->time_last_write =0 ;/* * Until the file is open and we have gotten oplock info back from the * server, can not assume caching of file data or metadata.
fs/smb/client/cifsglob.h +1 -0
@@ -1505,6 +1505,7 @@ struct cifsInodeInfo {spinlock_t writers_lock;unsigned int writers;/* Number of writers on this inode */ unsigned long time;/* jiffies of last update of inode */ +unsigned long time_last_write;/* jiffies of last writable close or truncate */ u64 server_eof;/* current file size on server -- protected by i_lock */ u64 uniqueid;/* server inode number */ u64 createtime;/* creation time on server */
fs/smb/client/file.c +16 -2
@@ -1001,11 +1001,21 @@ void smb2_deferred_work_close(struct work_struct *work) {struct cifsFileInfo *cfile =container_of (work, struct cifsFileInfo, deferred.work); +struct cifsInodeInfo *cinode =CIFS_I (d_inode (cfile->dentry)); -spin_lock (&CIFS_I (d_inode (cfile->dentry))->deferred_lock); +spin_lock (&cinode->deferred_lock);cifs_del_deferred_close (cfile); cfile->deferred_close_scheduled = false; -spin_unlock (&CIFS_I (d_inode (cfile->dentry))->deferred_lock); +spin_unlock (&cinode->deferred_lock); +/* +* Refresh time_last_write immediately before the actual server close +* so the protection window is anchored to the real close time, not +* the earlier userspace close time stored by cifs_close(). +*/ +if (OPEN_FMODE (cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&cinode->time_last_write, jiffies); + }_cifsFileInfo_put (cfile, true, false); }
@@ -1021,6 +1031,10 @@ int cifs_close(struct inode *inode, struct file *file)if (file->private_data !=NULL ) { cfile = file->private_data; file->private_data =NULL ; +if (file->f_mode &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&cinode->time_last_write, jiffies); + } dclose =kmalloc (sizeof (struct cifs_deferred_close ),GFP_KERNEL ); if ((cifs_sb->ctx->closetimeo && cinode->oplock == CIFS_CACHE_RHW_FLG) && cinode->lease_granted &&
fs/smb/client/inode.c +4 -0
@@ -2898,6 +2898,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)if ((attrs->ia_valid &ATTR_SIZE ) && attrs->ia_size !=i_size_read (inode)) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&cifsInode->time_last_write, jiffies);truncate_setsize (inode, attrs->ia_size);fscache_resize_cookie (cifs_inode_cookie (inode), attrs->ia_size); }
@@ -3112,6 +3114,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if ((attrs->ia_valid &ATTR_SIZE ) && attrs->ia_size !=i_size_read (inode)) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&cifsInode->time_last_write, jiffies);truncate_setsize (inode, attrs->ia_size);fscache_resize_cookie (cifs_inode_cookie (inode), attrs->ia_size); }
fs/smb/client/misc.c +24 -3
@@ -784,7 +784,14 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)spin_unlock (&cifs_inode->open_file_lock);list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) { -_cifsFileInfo_put (tmp_list->cfile, false, false); +struct cifsFileInfo *cfile = tmp_list->cfile; + +if (OPEN_FMODE (cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (cfile, false, false);list_del (&tmp_list->list);kfree (tmp_list); }
@@ -817,7 +824,14 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)spin_unlock (&tcon->open_file_lock);list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) { -_cifsFileInfo_put (tmp_list->cfile, true, false); +struct cifsFileInfo *cfile = tmp_list->cfile; + +if (OPEN_FMODE (cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (cfile, true, false);list_del (&tmp_list->list);kfree (tmp_list); }
@@ -891,7 +905,14 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)spin_unlock (&tcon->open_file_lock);list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) { -_cifsFileInfo_put (tmp_list->cfile, true, false); +struct cifsFileInfo *cfile = tmp_list->cfile; + +if (OPEN_FMODE (cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (cfile, true, false);list_del (&tmp_list->list);kfree (tmp_list); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1180/1887 cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <[email protected]>
[ Upstream commit c2f2e83e3bbc5483730fd4ee903182761f1ae50f ]
In cifs_close_deferred_file(), cifs_close_all_deferred_files(), and cifs_close_deferred_file_under_dentry(), when a pending deferred close is cancelled via cancel_delayed_work(), the subsequent kmalloc_obj() to add the file to the local processing list may fail under memory pressure. The loop breaks immediately, but the cancelled work is no longer pending (it would have called _cifsFileInfo_put()), and the cfile is never added to file_head for processing. The cifsFileInfo reference and the open server handle both leak.
Fix by saving the cfile that failed allocation in a local variable, breaking as before, and calling _cifsFileInfo_put() on it after releasing the lock. Any files later in the iteration are unaffected since their deferred work is still pending and will fire normally.
--- fs/smb/client/misc.c | 45 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-)
fs/smb/client/misc.c +39 -6
@@ -757,7 +757,7 @@ cifs_del_deferred_close(struct cifsFileInfo *cfile)void cifs_close_deferred_file (struct cifsInodeInfo *cifs_inode) { -struct cifsFileInfo *cfile =NULL ; +struct cifsFileInfo *cfile =NULL , *failed_cfile =NULL ;struct file_list *tmp_list, *tmp_next_list;struct list_head file_head;
@@ -774,8 +774,10 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)spin_unlock (&cifs_inode->deferred_lock); tmp_list =kmalloc (sizeof (struct file_list ),GFP_ATOMIC ); -if (tmp_list ==NULL ) +if (tmp_list ==NULL ) { + failed_cfile = cfile;break ; + } tmp_list->cfile = cfile;list_add_tail (&tmp_list->list, &file_head); }
@@ -783,6 +785,15 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode) }spin_unlock (&cifs_inode->open_file_lock); +if (failed_cfile) { +if (OPEN_FMODE (failed_cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (failed_cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (failed_cfile, false, false); + } +list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) {struct cifsFileInfo *cfile = tmp_list->cfile;
@@ -800,7 +811,7 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)void cifs_close_all_deferred_files (struct cifs_tcon *tcon) { -struct cifsFileInfo *cfile; +struct cifsFileInfo *cfile, *failed_cfile =NULL ;struct file_list *tmp_list, *tmp_next_list;struct list_head file_head;
@@ -814,8 +825,10 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)spin_unlock (&CIFS_I (d_inode (cfile->dentry))->deferred_lock); tmp_list =kmalloc (sizeof (struct file_list ),GFP_ATOMIC ); -if (tmp_list ==NULL ) +if (tmp_list ==NULL ) { + failed_cfile = cfile;break ; + } tmp_list->cfile = cfile;list_add_tail (&tmp_list->list, &file_head); }
@@ -823,6 +836,15 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon) }spin_unlock (&tcon->open_file_lock); +if (failed_cfile) { +if (OPEN_FMODE (failed_cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (failed_cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (failed_cfile, true, false); + } +list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) {struct cifsFileInfo *cfile = tmp_list->cfile;
@@ -875,7 +897,7 @@ void cifs_close_all_deferred_files_sb(struct cifs_sb_info *cifs_sb)void cifs_close_deferred_file_under_dentry (struct cifs_tcon *tcon,const char *path) { -struct cifsFileInfo *cfile; +struct cifsFileInfo *cfile, *failed_cfile =NULL ;struct file_list *tmp_list, *tmp_next_list;struct list_head file_head;void *page;
@@ -894,8 +916,10 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)spin_unlock (&CIFS_I (d_inode (cfile->dentry))->deferred_lock); tmp_list =kmalloc (sizeof (struct file_list ),GFP_ATOMIC ); -if (tmp_list ==NULL ) +if (tmp_list ==NULL ) { + failed_cfile = cfile;break ; + } tmp_list->cfile = cfile;list_add_tail (&tmp_list->list, &file_head); }
@@ -904,6 +928,15 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path) }spin_unlock (&tcon->open_file_lock); +if (failed_cfile) { +if (OPEN_FMODE (failed_cfile->f_flags) &FMODE_WRITE ) { +/* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +smp_store_release (&CIFS_I (d_inode (failed_cfile->dentry))->time_last_write, + jiffies); + } +_cifsFileInfo_put (failed_cfile, true, false); + } +list_for_each_entry_safe (tmp_list, tmp_next_list, &file_head, list) {struct cifsFileInfo *cfile = tmp_list->cfile;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1181/1887 tipc: serialize udp bearer replicast list updates
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 350e592ff4e30e48ffb55e142d11a73e63f4869c ]
tipc_udp_rcast_add() and cleanup_bearer() both update ub->rcast.list with list_add_rcu() / list_del_rcu(), but nothing serializes them. The add runs from the encap receive softirq (via tipc_udp_rcast_disc()) without rtnl_lock(), so it can race the cleanup delete and corrupt the list:
list_del corruption. prev->next should be ffff8880298d7ab8,
but was ffff88802449ad38. (prev=ffff888027e3ec98) kernel BUG at lib/list_debug.c:62! RIP: __list_del_entry_valid_or_report+0x17a/0x200 Workqueue: events cleanup_bearer Call Trace: cleanup_bearer (net/tipc/udp_media.c:811) process_one_work (kernel/workqueue.c:3302) worker_thread (kernel/workqueue.c:3466)
The bearer can be enabled from an unprivileged user namespace, as the TIPCv2 generic-netlink ops carry no GENL_ADMIN_PERM.
Add a spinlock to struct udp_bearer and take it around the list_add_rcu() in tipc_udp_rcast_add() and the list_del_rcu() loop in cleanup_bearer() so the two writers can no longer corrupt the list.
Reject a duplicate peer under the same lock before allocating, and remove tipc_udp_is_known_peer(). The old lockless pre-check in tipc_udp_rcast_disc() was racy: two softirqs discovering the same peer could both find it absent and add it twice.
cleanup_bearer() runs from a workqueue after tipc_udp_disable() clears the bearer's up bit, so an encap softirq can still reach tipc_udp_rcast_add() and add a peer after cleanup_bearer() has already emptied the list, leaking that entry when the bearer is freed. Mark the bearer disabled under rcast_lock once the list is emptied and refuse further additions.
--- net/tipc/udp_media.c | 56 +++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
net/tipc/udp_media.c +27 -29
@@ -94,6 +94,8 @@ struct udp_replicast {* @ifindex: local address scope * @work: used to schedule deferred work on a bearer * @rcast: associated udp_replicast container +* @rcast_lock: serialize updates to @rcast.list against concurrent updaters +* @disabled: bearer is being torn down; reject further @rcast.list additions */ struct udp_bearer {struct tipc_bearer __rcu *bearer;
@@ -101,6 +103,8 @@ struct udp_bearer {u32 ifindex;struct work_struct work;struct udp_replicast rcast; +spinlock_t rcast_lock; +bool disabled; };static int tipc_udp_is_mcast_addr (struct udp_media_addr *addr)
@@ -279,26 +283,6 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,return err; } -static bool tipc_udp_is_known_peer (struct tipc_bearer *b, -struct udp_media_addr *addr) -{ -struct udp_replicast *rcast, *tmp; -struct udp_bearer *ub; - - ub =rcu_dereference_rtnl (b->media_ptr); -if (!ub) { -pr_err_ratelimited ("UDP bearer instance not found\n" ); -return false; - } - -list_for_each_entry_safe (rcast, tmp, &ub->rcast.list, list) { -if (!memcmp (&rcast->addr, addr,sizeof (struct udp_media_addr ))) -return true; - } - -return false; -} -static int tipc_udp_rcast_add (struct tipc_bearer *b,struct udp_media_addr *addr) {
@@ -309,16 +293,34 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b,if (!ub)return -ENODEV ; +spin_lock_bh (&ub->rcast_lock); +if (ub->disabled) { +spin_unlock_bh (&ub->rcast_lock); +return 0 ; + } +list_for_each_entry (rcast, &ub->rcast.list, list) { +if (!memcmp (&rcast->addr, addr,sizeof (*addr))) { +spin_unlock_bh (&ub->rcast_lock); +return 0 ; + } + } + rcast =kmalloc (sizeof (*rcast),GFP_ATOMIC ); -if (!rcast) +if (!rcast) { +spin_unlock_bh (&ub->rcast_lock);return -ENOMEM ; + }if (dst_cache_init (&rcast->dst_cache,GFP_ATOMIC )) { +spin_unlock_bh (&ub->rcast_lock);kfree (rcast);return -ENOMEM ; }memcpy (&rcast->addr, addr,sizeof (struct udp_media_addr )); +list_add_rcu (&rcast->list, &ub->rcast.list); + b->bcast_addr.broadcast =TIPC_REPLICAST_SUPPORT ; +spin_unlock_bh (&ub->rcast_lock);if (ntohs (addr->proto) ==ETH_P_IP )pr_info ("New replicast peer: %pI4\n" , &rcast->addr.ipv4);
@@ -326,8 +328,6 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b, else if (ntohs(addr->proto) == ETH_P_IPV6) pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);#endif - b->bcast_addr.broadcast =TIPC_REPLICAST_SUPPORT ; -list_add_rcu (&rcast->list, &ub->rcast.list);return 0 ; }
@@ -362,9 +362,6 @@ static int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb)return 0 ; } -if (likely (tipc_udp_is_known_peer (b, &src))) -return 0 ; -return tipc_udp_rcast_add (b, &src); }
@@ -646,9 +643,6 @@ int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)return -EINVAL ; } -if (tipc_udp_is_known_peer (b, &addr)) -return 0 ; -return tipc_udp_rcast_add (b, &addr); }
@@ -680,6 +674,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,return -ENOMEM ;INIT_LIST_HEAD (&ub->rcast.list); +spin_lock_init (&ub->rcast_lock);if (!attrs[TIPC_NLA_BEARER_UDP_OPTS ]) goto err;
@@ -813,11 +808,14 @@ static void cleanup_bearer(struct work_struct *work)struct udp_replicast *rcast, *tmp;struct tipc_net *tn; +spin_lock_bh (&ub->rcast_lock);list_for_each_entry_safe (rcast, tmp, &ub->rcast.list, list) {dst_cache_destroy (&rcast->dst_cache);list_del_rcu (&rcast->list);kfree_rcu (rcast, rcu); } + ub->disabled = true; +spin_unlock_bh (&ub->rcast_lock); tn =tipc_net (sock_net (ub->ubsock->sk));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1182/1887 iommu/amd: Wait for completion instead of returning early in iommu_completion_wait()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Feng <[email protected]>
[ Upstream commit 1e75a8255f11c81fb07e81e5029cfd75804350a0 ]
need_sync is a per-IOMMU flag shared by all domains and devices behind that IOMMU. It is set whenever a command is queued with sync == true and cleared when a completion-wait (CWAIT) command is queued. However, a cleared need_sync only means that a covering CWAIT has been queued, not that all previously queued commands have actually completed in hardware.
iommu_completion_wait() read need_sync locklessly and returned early when it was false. This breaks the "block until all previously queued commands have completed" contract in a multi-CPU scenario:
CPU2: queue inv-B => need_sync = true
CPU1: queue CWAIT(N); need_sync = false; then wait_on_sem(N)
CPU2: read need_sync == false => return 0 (no wait!)
CPU2 returns without waiting for any sequence number even though its inv-B may not have completed yet (CWAIT(N), queued after inv-B, has not been signaled). CPU2 then proceeds to, for example, free page-table pages while the IOMMU can still walk stale translations, opening a use-after-free window. This is a logical race in the meaning of the flag, not a memory-visibility issue, so barriers alone do not help.
Fix it without losing the optimization of avoiding redundant CWAIT
commands: take iommu->lock before testing need_sync, and when it is false do not return early but wait for the last allocated sequence number (cmd_sem_val). Since need_sync == false implies no sync command was queued after the last CWAIT, that CWAIT is FIFO-ordered after every not-yet-completed command, so waiting for its sequence number guarantees all prior commands (possibly queued by another CPU) have completed. The common path with pending work is unchanged and no extra hardware command is issued.
--- drivers/iommu/amd/iommu.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/iommu/amd/iommu.c +16 -6
@@ -1184,11 +1184,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu)int ret;u64 data; -if (!iommu->need_sync) -return 0 ; -raw_spin_lock_irqsave (&iommu->lock, flags); +if (!iommu->need_sync) { +/* +* No command has been queued since the last completion-wait. +* A concurrent CPU may have already queued that CWAIT and +* cleared need_sync; need_sync == false only means a covering +* CWAIT is queued, not that all prior commands have completed. +* Wait for the last allocated sequence number so that any +* command queued before this call (possibly on another CPU) +* is guaranteed to have completed before returning. +*/ + data = iommu->cmd_sem_val; +raw_spin_unlock_irqrestore (&iommu->lock, flags); +return wait_on_sem (iommu, data); + } + data = ++iommu->cmd_sem_val;build_completion_wait (&cmd, iommu, data);
@@ -1198,9 +1210,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)if (ret)return ret; - ret =wait_on_sem (iommu, data); - -return ret; +return wait_on_sem (iommu, data); }static int iommu_flush_dte (struct amd_iommu *iommu,u16 devid)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1183/1887 scsi: core: wake eh reliably when using scsi_schedule_eh
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Jeffery <[email protected]>
[ Upstream commit dccf3b1798b70f94e958b3d00b83010399e6fb05 ]
Drivers which use the scsi_schedule_eh function to run the error handler currently risk the error handler thread never waking once all commands are timed out or inactive. There is no enforced memory order between setting the host into error recovery state and counting busy commands. This can result in a race with scsi_dec_host_busy where neither CPU sees both conditions of all commands inactive and the host error state to request waking the error handler.
To fix this, run the scsi_schedule_eh's scsi_eh_wakeup from a new work item which will use rcu to ensure scsi_schedule_eh's call to scsi_host_busy will occur after the error state is globally visible and will be seen by any current scsi_dec_host_busy callers.
--- drivers/scsi/hosts.c | 2 ++ drivers/scsi/scsi_error.c | 22 +++++++++++++++++++++- drivers/scsi/scsi_priv.h | 1 + include/scsi/scsi_host.h | 3 +++ 4 files changed, 27 insertions(+), 1 deletion(-)
drivers/scsi/hosts.c +2 -0
@@ -344,6 +344,7 @@ static void scsi_host_dev_release(struct device *dev)/* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */ rcu_barrier (); +cancel_work_sync (&shost->eh_work);if (shost->tmf_work_q)destroy_workqueue (shost->tmf_work_q);if (shost->ehandler)
@@ -409,6 +410,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)INIT_LIST_HEAD (&shost->starved_list);init_waitqueue_head (&shost->host_wait);mutex_init (&shost->scan_mutex); +INIT_WORK (&shost->eh_work, scsi_rcu_eh_wakeup); index =ida_alloc (&host_index_ida,GFP_KERNEL );if (index <0 ) {
drivers/scsi/scsi_error.c +21 -1
@@ -73,6 +73,26 @@ void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy) } } +void scsi_rcu_eh_wakeup (struct work_struct *work) +{ + struct Scsi_Host *shost = container_of(work, struct Scsi_Host, eh_work); +unsigned long flags; +unsigned int busy; + +/* +* Ensure any running scsi_dec_host_busy has completed its rcu section +* so changes to host state and host_eh_scheduled are visible to all +* future calls of scsi_dec_host_busy +*/ +synchronize_rcu (); + + busy =scsi_host_busy (shost); + +spin_lock_irqsave (shost->host_lock, flags); +scsi_eh_wakeup (shost, busy); +spin_unlock_irqrestore (shost->host_lock, flags); +} +/** * scsi_schedule_eh - schedule EH for SCSI host * @shost: SCSI host to invoke error handling on.
@@ -88,7 +108,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost)if (scsi_host_set_state (shost,SHOST_RECOVERY ) ==0 ||scsi_host_set_state (shost,SHOST_CANCEL_RECOVERY ) ==0 ) { shost->host_eh_scheduled++; -scsi_eh_wakeup (shost,scsi_host_busy (shost)); +queue_work (shost->tmf_work_q, &shost->eh_work); }spin_unlock_irqrestore (shost->host_lock, flags);
drivers/scsi/scsi_priv.h +1 -0
@@ -87,6 +87,7 @@ extern enum blk_eh_timer_return scsi_timeout(struct request *req);extern int scsi_error_handler (void *host);extern enum scsi_disposition scsi_decide_disposition (struct scsi_cmnd *cmd);extern void scsi_eh_wakeup (struct Scsi_Host *shost,unsigned int busy); +extern void scsi_rcu_eh_wakeup (struct work_struct *work);extern void scsi_eh_scmd_add (struct scsi_cmnd *); void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q,
include/scsi/scsi_host.h +3 -0
@@ -704,6 +704,9 @@ struct Scsi_Host {*/ struct device *dma_dev; +/* Used for an rcu-synchronizing eh wakeup */ +struct work_struct eh_work; +/* * We should ensure that this is aligned, both for better performance * and also because some compilers (m68k) don't automatically force
Signature · 1 line
2.53.0