6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 953/1887 spi: spi-dw-dma: fix print error log when wait finish transaction
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Yakovlev <[email protected]>
[ Upstream commit 3b46d61890632c8f8b117147b6923bff4b42ccb7 ]
If an error occurs, the device may not have a current message. In this case, the system will crash.
In this case, it's better to use dev from the struct ctlr (struct spi_controller*).
--- drivers/spi/spi-dw-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-dw-dma.c +1 -1
@@ -231,7 +231,7 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed) msecs_to_jiffies(ms));if (ms ==0 ) { -dev_err (&dws->master->cur_msg->spi->dev, +dev_err (&dws->master->dev,"DMA transaction timed out\n" );return -ETIMEDOUT ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 954/1887 s390/mm: Add missing secure storage access fixups for donated memory
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Janosch Frank <[email protected]>
[ Upstream commit b00be77302d7ec4ad0367bb236494fce7172b730 ]
There are special cases where secure storage access exceptions happen in a kernel context for pages that don't have the PG_arch_1 bit set. That bit is set for non-exported guest secure storage (memory) but is absent on storage donated to the Ultravisor since the kernel isn't allowed to export donated pages.
Prior to this patch we would try to export the page by calling arch_make_folio_accessible() which would instantly return since the arch bit is absent signifying that the page was already exported and no further action is necessary. This leads to secure storage access exception loops which can never be resolved.
With this patch we unconditionally try to export and if that fails we fixup.
--- arch/s390/mm/fault.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/s390/mm/fault.c +9 -2
@@ -855,10 +855,17 @@ void do_secure_storage_access(struct pt_regs *regs) page =phys_to_page (addr);if (unlikely (!try_get_page (page)))break ; - rc =arch_make_page_accessible (page); + rc =uv_convert_from_secure (page_to_phys (page)); +if (!rc) +clear_bit (PG_arch_1, &page->flags);put_page (page); +/* +* There are some valid fixup types for kernel +* accesses to donated secure memory. zeropad is one +* of them. +*/ if (rc) -BUG (); +return do_no_context (regs,0 );break ;default :do_fault_error (regs,VM_FAULT_BADMAP );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 955/1887 KVM: SEV: Use long-term pin when registering encrypted memory regions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ge Yang <[email protected]>
[ Upstream commit 7e066cb9b71a22c3e5ef233de63ff14525baf6f0 ]
When registering an encrypted memory region for SEV-MEM/SEV-ES guests, pin the pages with FOLL_TERM so that the pages are migrated out of MIGRATE_CMA/ZONE_MOVABLE. Failure to do so violates the CMA/MOVABLE mechanisms and can result in fragmentation due to unmovable pages, e.g. can make CMA allocations fail.
Stable-dep-of: b6408b6cec5d ("KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock")
--- arch/x86/kvm/svm/sev.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
arch/x86/kvm/svm/sev.c +8 -7
@@ -393,7 +393,7 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)static struct page **sev_pin_memory (struct kvm *kvm,unsigned long uaddr,unsigned long ulen,unsigned long *n, -int write) +unsigned int flags) {struct kvm_sev_info *sev = &to_kvm_svm (kvm)->sev_info;unsigned long npages, size;
@@ -437,7 +437,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,return ERR_PTR (-ENOMEM );/* Pin the user virtual address. */ - npinned =pin_user_pages_fast (uaddr, npages, write ?FOLL_WRITE :0 , pages); + npinned =pin_user_pages_fast (uaddr, npages, flags, pages);if (npinned != npages) {pr_err ("SEV: Failure locking %lu pages.\n" , npages); ret = -ENOMEM ;
@@ -525,7 +525,7 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp) vaddr_end = vaddr + size;/* Lock the user memory. */ - inpages =sev_pin_memory (kvm, vaddr, size, &npages,1 ); + inpages =sev_pin_memory (kvm, vaddr, size, &npages,FOLL_WRITE );if (IS_ERR (inpages))return PTR_ERR (inpages);
@@ -958,7 +958,7 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)if (IS_ERR (src_p))return PTR_ERR (src_p); - dst_p =sev_pin_memory (kvm, dst_vaddr &PAGE_MASK ,PAGE_SIZE , &n,1 ); + dst_p =sev_pin_memory (kvm, dst_vaddr &PAGE_MASK ,PAGE_SIZE , &n,FOLL_WRITE );if (IS_ERR (dst_p)) {sev_unpin_memory (kvm, src_p, n);return PTR_ERR (dst_p);
@@ -1025,7 +1025,7 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)if (copy_from_user (¶ms, (void __user *)(uintptr_t )argp->data,sizeof (params)))return -EFAULT ; - pages =sev_pin_memory (kvm, params.guest_uaddr, params.guest_len, &n,1 ); + pages =sev_pin_memory (kvm, params.guest_uaddr, params.guest_len, &n,FOLL_WRITE );if (IS_ERR (pages))return PTR_ERR (pages);
@@ -1507,7 +1507,7 @@ static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)/* Pin guest memory */ guest_page =sev_pin_memory (kvm, params.guest_uaddr &PAGE_MASK , -PAGE_SIZE , &n,1 ); +PAGE_SIZE , &n,FOLL_WRITE );if (IS_ERR (guest_page)) { ret =PTR_ERR (guest_page); goto e_free_trans;
@@ -1971,7 +1971,8 @@ int sev_mem_enc_register_region(struct kvm *kvm,return -ENOMEM ;mutex_lock (&kvm->lock); - region->pages =sev_pin_memory (kvm, range->addr, range->size, ®ion->npages,1 ); + region->pages =sev_pin_memory (kvm, range->addr, range->size, ®ion->npages, +FOLL_WRITE |FOLL_LONGTERM );if (IS_ERR (region->pages)) { ret =PTR_ERR (region->pages);mutex_unlock (&kvm->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 956/1887 KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock
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 b6408b6cec5df76a165575777800ef2aba12b109 ]
Take and hold kvm->lock for before checking sev_guest() in sev_mem_enc_register_region(), as sev_guest() isn't stable unless kvm->lock is held (or KVM can guarantee KVM_SEV_INIT{2} has completed and can't rollack state). If KVM_SEV_INIT{2} fails, KVM can end up trying to add to a not-yet-initialized sev->regions_list, e.g. triggering a #GP
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] CPU: 110 UID: 0 PID: 72717 Comm: syz.15.11462 Tainted: G U W O 6.16.0-smp-DEV #1 NONE Tainted: [U]=USER, [W]=WARN, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.52.0-0 10/28/2024 RIP: 0010:sev_mem_enc_register_region+0x3f0/0x4f0 ../include/linux/list.h:83 Code: <41> 80 3c 04 00 74 08 4c 89 ff e8 f1 c7 a2 00 49 39 ed 0f 84 c6 00 RSP: 0018:ffff88838647fbb8 EFLAGS: 00010256 RAX: dffffc0000000000 RBX: 1ffff92015cf1e0b RCX: dffffc0000000000 RDX: 0000000000000000 RSI: 0000000000001000 RDI: ffff888367870000 RBP: ffffc900ae78f050 R08: ffffea000d9e0007 R09: 1ffffd4001b3c000 R10: dffffc0000000000 R11: fffff94001b3c001 R12: 0000000000000000 R13: ffff8982ab0bde00 R14: ffffc900ae78f058 R15: 0000000000000000 FS: 00007f34e9dc66c0(0000) GS:ffff89ee64d33000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fe180adef98 CR3: 000000047210e000 CR4: 0000000000350ef0 Call Trace: <TASK> kvm_arch_vm_ioctl+0xa72/0x1240 ../arch/x86/kvm/x86.c:7371 kvm_vm_ioctl+0x649/0x990 ../virt/kvm/kvm_main.c:5363 __se_sys_ioctl+0x101/0x170 ../fs/ioctl.c:51 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x6f/0x1f0 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f34e9f7e9a9 Code: <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f34e9dc6038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f34ea1a6080 RCX: 00007f34e9f7e9a9 RDX: 0000200000000280 RSI: 000000008010aebb RDI: 0000000000000007 RBP: 00007f34ea000d69 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 00007f34ea1a6080 R15: 00007ffce77197a8 </TASK>
with a syzlang reproducer that looks like:
syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000040)={0x0, &(0x7f0000000180)=ANY=[], 0x70}) (async) syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000080)={0x0, &(0x7f0000000180)=ANY=[@ANYBLOB="..."], 0x4f}) (async)
r0 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000200), 0x0, 0x0)
r1 = ioctl$KVM_CREATE_VM(r0, 0xae01, 0x0)
r2 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000240), 0x0, 0x0)
r3 = ioctl$KVM_CREATE_VM(r2, 0xae01, 0x0)
ioctl$KVM_SET_CLOCK(r3, 0xc008aeba, &(0x7f0000000040)={0x1, 0x8, 0x0, 0x5625e9b0}) (async) ioctl$KVM_SET_PIT2(r3, 0x8010aebb, &(0x7f0000000280)={[...], 0x5}) (async)
ioctl$KVM_SET_PIT2(r1, 0x4070aea0, 0x0) (async)
r4 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0)
openat$kvm(0xffffffffffffff9c, 0x0, 0x0, 0x0) (async)
ioctl$KVM_SET_USER_MEMORY_REGION(r4, 0x4020ae46, &(0x7f0000000400)={0x0, 0x0, 0x0, 0x2000, &(0x7f0000001000/0x2000)=nil}) (async) r5 = ioctl$KVM_CREATE_VCPU(r4, 0xae41, 0x2)
close(r0) (async)
openat$kvm(0xffffffffffffff9c, &(0x7f0000000000), 0x8000, 0x0) (async)
ioctl$KVM_SET_GUEST_DEBUG(r5, 0x4048ae9b, &(0x7f0000000300)={0x4376ea830d46549b, 0x0, [0x46, 0x0, 0x0, 0x0, 0x0, 0x1000]}) (async) ioctl$KVM_RUN(r5, 0xae80, 0x0)
Opportunistically use guard() to avoid having to define a new error label and goto usage.
--- arch/x86/kvm/svm/sev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/sev.c +2 -4
@@ -1956,6 +1956,8 @@ int sev_mem_enc_register_region(struct kvm *kvm,struct enc_region *region;int ret =0 ; +guard (mutex)(&kvm->lock); +if (!sev_guest (kvm))return -ENOTTY ;
@@ -1970,12 +1972,10 @@ int sev_mem_enc_register_region(struct kvm *kvm,if (!region)return -ENOMEM ; -mutex_lock (&kvm->lock); region->pages =sev_pin_memory (kvm, range->addr, range->size, ®ion->npages,FOLL_WRITE |FOLL_LONGTERM );if (IS_ERR (region->pages)) { ret =PTR_ERR (region->pages); -mutex_unlock (&kvm->lock); goto e_free; }
@@ -1993,8 +1993,6 @@ int sev_mem_enc_register_region(struct kvm *kvm, region->size = range->size;list_add_tail (®ion->list, &sev->regions_list); -mutex_unlock (&kvm->lock); -return ret; e_free:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 957/1887 usb: gadget: f_hid: dont call cdev_init while cdev in use
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Zimmermann <[email protected]>
[ Upstream commit 81ebd43cc0d6d106ce7b6ccbf7b5e40ca7f5503d ]
When calling unbind, then bind again, cdev_init reinitialized the cdev, even though there may still be references to it. That's the case when the /dev/hidg* device is still opened. This obviously unsafe behavior like oopes.
This fixes this by using cdev_alloc to put the cdev on the heap. That way, we can simply allocate a new one in hidg_bind.
--- drivers/usb/gadget/function/f_hid.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/usb/gadget/function/f_hid.c +12 -5
@@ -72,7 +72,7 @@ struct f_hidg {struct usb_request *req;struct device dev; -struct cdev cdev; +struct cdev *cdev;struct usb_function func;struct usb_ep *in_ep;
@@ -554,8 +554,9 @@ static int f_hidg_release(struct inode *inode, struct file *fd)static int f_hidg_open (struct inode *inode,struct file *fd) { +struct kobject *parent = inode->i_cdev->kobj.parent;struct f_hidg *hidg = - container_of(inode->i_cdev, struct f_hidg, cdev); + container_of(parent, struct f_hidg, dev.kobj); fd->private_data = hidg;
@@ -1000,8 +1001,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg->req =NULL ;/* create char device */ -cdev_init (&hidg->cdev, &f_hidg_fops); - status =cdev_device_add (&hidg->cdev, &hidg->dev); + hidg->cdev =cdev_alloc (); +if (!hidg->cdev) { + status = -ENOMEM ; + goto fail_free_descs; + } + hidg->cdev->ops = &f_hidg_fops; + + status =cdev_device_add (hidg->cdev, &hidg->dev);if (status) goto fail_free_descs;
@@ -1246,7 +1253,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) {struct f_hidg *hidg =func_to_hidg (f); -cdev_device_del (&hidg->cdev, &hidg->dev); +cdev_device_del (hidg->cdev, &hidg->dev);usb_free_all_descriptors (f); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 958/1887 pmdomain: imx8mp-blk-ctrl: Keep the NOC_HDCP clock enabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacky Bai <[email protected]>
[ Upstream commit e91d5f94acf68618ea3ad9c92ac28614e791ae7d ]
Keep the NOC_HDCP clock always enabled to fix the potential hang caused by the NoC ADB400 port power down handshake.
--- drivers/soc/imx/imx8mp-blk-ctrl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/soc/imx/imx8mp-blk-ctrl.c +1 -7
@@ -250,9 +250,6 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,regmap_set_bits (bc->regmap,HDMI_RTX_RESET_CTL0 ,BIT (12 ));regmap_clear_bits (bc->regmap,HDMI_TX_CONTROL0 ,BIT (3 ));break ; -case IMX8MP_HDMIBLK_PD_HDCP : -regmap_set_bits (bc->regmap,HDMI_RTX_CLK_CTL0 ,BIT (11 )); -break ;case IMX8MP_HDMIBLK_PD_HRV :regmap_set_bits (bc->regmap,HDMI_RTX_CLK_CTL1 ,BIT (3 ) |BIT (4 ) |BIT (5 ));regmap_set_bits (bc->regmap,HDMI_RTX_RESET_CTL0 ,BIT (15 ));
@@ -306,9 +303,6 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,regmap_clear_bits (bc->regmap,HDMI_RTX_CLK_CTL0 ,BIT (7 ));regmap_clear_bits (bc->regmap,HDMI_RTX_CLK_CTL1 ,BIT (22 ) |BIT (24 ));break ; -case IMX8MP_HDMIBLK_PD_HDCP : -regmap_clear_bits (bc->regmap,HDMI_RTX_CLK_CTL0 ,BIT (11 )); -break ;case IMX8MP_HDMIBLK_PD_HRV :regmap_clear_bits (bc->regmap,HDMI_RTX_RESET_CTL0 ,BIT (15 ));regmap_clear_bits (bc->regmap,HDMI_RTX_CLK_CTL1 ,BIT (3 ) |BIT (4 ) |BIT (5 ));
@@ -337,7 +331,7 @@ static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,regmap_write (bc->regmap,HDMI_RTX_CLK_CTL0 ,0x0 );regmap_write (bc->regmap,HDMI_RTX_CLK_CTL1 ,0x0 );regmap_set_bits (bc->regmap,HDMI_RTX_CLK_CTL0 , -BIT (0 ) |BIT (1 ) |BIT (10 )); +BIT (0 ) |BIT (1 ) |BIT (10 ) |BIT (11 ));regmap_set_bits (bc->regmap,HDMI_RTX_RESET_CTL0 ,BIT (0 ));/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 959/1887 xfrm: hold dev ref until after transport_finish NF_HOOK
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qi Tang <[email protected]>
[ Upstream commit 1c428b03840094410c5fb6a5db30640486bbbfcb ]
After async crypto completes, xfrm_input_resume() calls dev_put() immediately on re-entry before the skb reaches transport_finish. The skb->dev pointer is then used inside NF_HOOK and its okfn, which can race with device teardown.
Remove the dev_put from the async resumption entry and instead drop the reference after the NF_HOOK call in transport_finish, using a saved device pointer since NF_HOOK may consume the skb. This covers NF_DROP, NF_QUEUE and NF_STOLEN paths that skip the okfn.
For non-transport exits (decaps, gro, drop) and secondary async return points, release the reference inline when async is set.
--- net/ipv4/xfrm4_input.c | 5 ++++- net/ipv6/xfrm6_input.c | 5 ++++- net/xfrm/xfrm_input.c | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-)
net/ipv4/xfrm4_input.c +4 -1
@@ -48,6 +48,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) {struct xfrm_offload *xo =xfrm_offload (skb);struct iphdr *iph =ip_hdr (skb); +struct net_device *dev = skb->dev; iph->protocol =XFRM_MODE_SKB_CB (skb)->protocol;
@@ -71,8 +72,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) }NF_HOOK (NFPROTO_IPV4 ,NF_INET_PRE_ROUTING , -dev_net (skb->dev),NULL , skb, skb->dev,NULL , +dev_net (dev),NULL , skb, dev,NULL , xfrm4_rcv_encap_finish); +if (async) +dev_put (dev);return 0 ; }
net/ipv6/xfrm6_input.c +4 -1
@@ -41,6 +41,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,int xfrm6_transport_finish (struct sk_buff *skb,int async) {struct xfrm_offload *xo =xfrm_offload (skb); +struct net_device *dev = skb->dev;int nhlen = skb->data -skb_network_header (skb); skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -66,8 +67,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) }NF_HOOK (NFPROTO_IPV6 ,NF_INET_PRE_ROUTING , -dev_net (skb->dev),NULL , skb, skb->dev,NULL , +dev_net (dev),NULL , skb, dev,NULL , xfrm6_transport_finish2); +if (async) +dev_put (dev);return 0 ; }
net/xfrm/xfrm_input.c +12 -3
@@ -634,11 +634,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)else nexthdr = x->type->input (x, skb); -if (nexthdr == -EINPROGRESS ) +if (nexthdr == -EINPROGRESS ) { +if (async) +dev_put (skb->dev);return 0 ; -resume: -dev_put (skb->dev); + } +dev_put (skb->dev); +resume:spin_lock (&x->lock);if (nexthdr <0 ) {if (nexthdr == -EBADMSG ) {
@@ -704,6 +707,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp->olen =0 ;if (skb_valid_dst (skb))skb_dst_drop (skb); +if (async) +dev_put (skb->dev);gro_cells_receive (&gro_cells, skb);return 0 ; }else {
@@ -723,6 +728,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp->olen =0 ;if (skb_valid_dst (skb))skb_dst_drop (skb); +if (async) +dev_put (skb->dev);gro_cells_receive (&gro_cells, skb);return err; }
@@ -733,6 +740,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) drop_unlock:spin_unlock (&x->lock); drop: +if (async) +dev_put (skb->dev);xfrm_rcv_cb (skb, family, x && x->type ? x->type->proto : nexthdr,-1 );kfree_skb (skb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 960/1887 net/sched: sch_netem: fix out-of-bounds access in packet corruption
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yucheng Lu <[email protected]>
[ Upstream commit d64cb81dcbd54927515a7f65e5e24affdc73c14b ]
In netem_enqueue(), the packet corruption logic uses get_random_u32_below(skb_headlen(skb)) to select an index for modifying skb->data. When an AF_PACKET TX_RING sends fully non-linear packets over an IPIP tunnel, skb_headlen(skb) evaluates to 0.
Passing 0 to get_random_u32_below() takes the variable-ceil slow path which returns an unconstrained 32-bit random integer. Using this unconstrained value as an offset into skb->data results in an out-of-bounds memory access.
Fix this by verifying skb_headlen(skb) is non-zero before attempting to corrupt the linear data area. Fully non-linear packets will silently bypass the corruption logic.
--- net/sched/sch_netem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/sched/sch_netem.c +3 -2
@@ -508,8 +508,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, goto finish_segs; } - skb->data[prandom_u32_max (skb_headlen (skb))] ^= -1 <<prandom_u32_max (8 ); +if (skb_headlen (skb)) + skb->data[prandom_u32_max (skb_headlen (skb))] ^= +1 <<prandom_u32_max (8 ); }if (unlikely (sch->q.qlen >= sch->limit)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 961/1887 crypto: af_alg - limit RX SG extraction by receive buffer budget
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douya Le <[email protected]>
[ Upstream commit 8eceab19eba9dcbfd2a0daec72e1bf48aa100170 ]
Make af_alg_get_rsgl() limit each RX scatterlist extraction to the remaining receive buffer budget.
af_alg_get_rsgl() currently uses af_alg_readable() only as a gate before extracting data into the RX scatterlist. Limit each extraction to the remaining af_alg_rcvbuf(sk) budget so that receive-side accounting matches the amount of data attached to the request.
If skcipher cannot obtain enough RX space for at least one chunk while more data remains to be processed, reject the recvmsg call instead of rounding the request length down to zero.
--- crypto/af_alg.c | 2 ++ crypto/algif_skcipher.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-)
crypto/af_alg.c +2 -0
@@ -1126,6 +1126,8 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, seglen =min_t (size_t, (maxsize - len),msg_data_left (msg)); +/* Never pin more pages than the remaining RX accounting budget. */ + seglen =min_t (size_t, seglen,af_alg_rcvbuf (sk));if (list_empty (&areq->rsgl_list)) { rsgl = &areq->first_rsgl;
crypto/algif_skcipher.c +7 -1
@@ -82,8 +82,14 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,* If more buffers are to be expected to be processed, process only * full block size buffers. */ -if (ctx->more || len < ctx->used) +if (ctx->more || len < ctx->used) { +if (len < bs) { + err = -EINVAL ; + goto free; + } + len -= len % bs; + }/* * Create a per request TX SGL for this request which tracks the
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 962/1887 ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 3e4e2ea2a781018ed5d75f969e3e5606beb66e48 ]
smb_inherit_dacl() trusts the on-disk num_aces value from the parent directory's DACL xattr and uses it to size a heap allocation:
aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, ...);
num_aces is a u16 read from le16_to_cpu(parent_pdacl->num_aces) without checking that it is consistent with the declared pdacl_size. An authenticated client whose parent directory's security.NTACL is tampered (e.g. via offline xattr corruption or a concurrent path that bypasses parse_dacl()) can present num_aces = 65535 with minimal actual ACE data. This causes a ~8 MB allocation (not kzalloc, so uninitialized) that the subsequent loop only partially populates, and may also overflow the three-way size_t multiply on 32-bit kernels.
Additionally, the ACE walk loop uses the weaker offsetof(struct smb_ace, access_req) minimum size check rather than the minimum valid on-wire ACE size, and does not reject ACEs whose declared size is below the minimum.
Reproduced on UML + KASAN + LOCKDEP against the real ksmbd code path. A legitimate mount.cifs client creates a parent directory over SMB (ksmbd writes a valid security.NTACL xattr), then the NTACL blob on the backing filesystem is rewritten to set num_aces = 0xFFFF while keeping the posix_acl_hash bytes intact so ksmbd_vfs_get_sd_xattr()'s hash check still passes. A subsequent SMB2 CREATE of a child under that parent drives smb2_open() into smb_inherit_dacl() (share has "vfs objects = acl_xattr" set), which fails the page allocator:
WARNING: mm/page_alloc.c:5226 at __alloc_frozen_pages_noprof+0x46c/0x9c0 Workqueue: ksmbd-io handle_ksmbd_work __alloc_frozen_pages_noprof+0x46c/0x9c0 ___kmalloc_large_node+0x68/0x130 __kmalloc_large_node_noprof+0x24/0x70 __kmalloc_noprof+0x4c9/0x690 smb_inherit_dacl+0x394/0x2430 smb2_open+0x595d/0xabe0 handle_ksmbd_work+0x3d3/0x1140
With the patch applied the added guard rejects the tampered value with -EINVAL before any large allocation runs, smb2_open() falls back to smb2_create_sd_buffer(), and the child is created with a default SD. No warning, no splat.
Fix by:
1. Validating num_aces against pdacl_size using the same formula applied in parse_dacl().
2. Replacing the raw kmalloc(sizeof * num_aces * 2) with kmalloc_array(num_aces * 2, sizeof(...)) for overflow-safe allocation.
3. Tightening the per-ACE loop guard to require the minimum valid ACE size (offsetof(smb_ace, sid) + CIFS_SID_BASE_SIZE) and rejecting under-sized ACEs, matching the hardening in smb_check_perm_dacl() and parse_dacl().
v1 -> v2:
- Replace the synthetic test-module splat in the changelog with a real-path UML + KASAN reproduction driven through mount.cifs and SMB2 CREATE; Namjae flagged the kcifs3_test_inherit_dacl_old name in v1 since it does not exist in ksmbd.
- Drop the commit-hash citation from the code comment per Namjae's review; keep the parse_dacl() pointer.
--- fs/smb/server/smbacl.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
fs/smb/server/smbacl.c +23 -4
@@ -1150,7 +1150,24 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, goto free_parent_pntsd; } - aces_base =kmalloc (sizeof (struct smb_ace ) * num_aces *2 ,GFP_KERNEL ); + aces_size = pdacl_size -sizeof (struct smb_acl ); + +/* +* Validate num_aces against the DACL payload before allocating. +* Each ACE must be at least as large as its fixed-size header +* (up to the SID base), so num_aces cannot exceed the payload +* divided by the minimum ACE size. This mirrors the existing +* check in parse_dacl(). +*/ +if (num_aces > aces_size / (offsetof(struct smb_ace , sid) + + offsetof(struct smb_sid , sub_auth) + +sizeof (__le16))) { + rc = -EINVAL ; + goto free_parent_pntsd; + } + + aces_base =kmalloc_array (num_aces *2 ,sizeof (struct smb_ace ), +GFP_KERNEL );if (!aces_base) { rc = -ENOMEM ; goto free_parent_pntsd;
@@ -1159,7 +1176,6 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, aces = (struct smb_ace *)aces_base; parent_aces = (struct smb_ace *)((char *)parent_pdacl +sizeof (struct smb_acl )); - aces_size = acl_len -sizeof (struct smb_acl );if (pntsd_type &DACL_AUTO_INHERITED ) inherited_flags =INHERITED_ACE ;
@@ -1167,11 +1183,14 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,for (i =0 ; i < num_aces; i++) {int pace_size; -if (offsetof(struct smb_ace , access_req) > aces_size) +if (aces_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; pace_size =le16_to_cpu (parent_aces->size); -if (pace_size > aces_size) +if (pace_size > aces_size || + pace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; aces_size -= pace_size;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 963/1887 ksmbd: validate response sizes in ipc_validate_msg()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit d6a6aa81eac2c9bff66dc6e191179cb69a14426b ]
ipc_validate_msg() computes the expected message size for each response type by adding (or multiplying) attacker-controlled fields from the daemon response to a fixed struct size in unsigned int arithmetic. Three cases can overflow:
KSMBD_EVENT_RPC_REQUEST:
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
KSMBD_EVENT_SHARE_CONFIG_REQUEST:
msg_sz = sizeof(struct ksmbd_share_config_response) +
resp->payload_sz;
KSMBD_EVENT_LOGIN_REQUEST_EXT:
msg_sz = sizeof(struct ksmbd_login_response_ext) +
resp->ngroups * sizeof(gid_t);resp->payload_sz is __u32 and resp->ngroups is __s32. Each addition can wrap in unsigned int; the multiplication by sizeof(gid_t) mixes signed and size_t, so a negative ngroups is converted to SIZE_MAX before the multiply. A wrapped value of msg_sz that happens to equal entry->msg_sz bypasses the size check on the next line, and downstream consumers (smb2pdu.c:6742 memcpy using rpc_resp->payload_sz, kmemdup in ksmbd_alloc_user using resp_ext->ngroups) then trust the unverified length.
Use check_add_overflow() on the RPC_REQUEST and SHARE_CONFIG_REQUEST paths to detect integer overflow without constraining functional payload size; userspace ksmbd-tools grows NDR responses in 4096-byte chunks for calls like NetShareEnumAll, so a hard transport cap is unworkable on the response side. For LOGIN_REQUEST_EXT, reject resp->ngroups outside the signed [0, NGROUPS_MAX] range up front and report the error from ipc_validate_msg() so it fires at the IPC boundary; with that bound the subsequent multiplication and addition stay well below UINT_MAX. The now-redundant ngroups check and pr_err in ksmbd_alloc_user() are removed.
This is the response-side analogue of aab98e2dbd64 ("ksmbd: fix integer overflows on 32 bit systems"), which hardened the request side.
--- fs/smb/server/transport_ipc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/smb/server/transport_ipc.c +4 -1
@@ -13,6 +13,7 @@#include <net/genetlink.h> #include <linux/socket.h> #include <linux/workqueue.h> +#include <linux/overflow.h> #include "vfs_cache.h" #include "transport_ipc.h"
@@ -478,7 +479,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)if (entry->type ==KSMBD_EVENT_RPC_REQUEST ) {struct ksmbd_rpc_command *resp = entry->response; - msg_sz =sizeof (struct ksmbd_rpc_command ) + resp->payload_sz; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), + resp->payload_sz, &msg_sz)) +return -EINVAL ; }else if (entry->type ==KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST ) {struct ksmbd_spnego_authen_response *resp = entry->response;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 964/1887 usb: gadget: f_rndis: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit e367599529dc42578545a7f85fde517b35b3cda7 ]
The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks:
console:/ # ls -l /sys/class/net/usb0
lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0
ls: .../gadget.0/net/usb0: No such file or directory
Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering.
To maintain compatibility with legacy composite drivers (e.g., multi.c), the borrowed_net flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase.
--- drivers/usb/gadget/function/f_rndis.c | 42 ++++++++++++++++----------- drivers/usb/gadget/function/u_rndis.h | 31 +++++++++++++++----- 2 files changed, 48 insertions(+), 25 deletions(-)
drivers/usb/gadget/function/f_rndis.c +25 -17
@@ -679,6 +679,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)struct f_rndis_opts *rndis_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_rndis (c))
@@ -696,21 +697,18 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_iad_descriptor.bFunctionClass = rndis_opts->class; rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; - } -/* -* in drivers/usb/gadget/configfs.c:configfs_composite_bind() -* configurations are bound in sequence with list_for_each_entry, -* in each configuration its functions are bound in sequence -* with list_for_each_entry, so we assume no race condition -* with regard to rndis_opts->bound access -*/ -if (!rndis_opts->bound) { -gether_set_gadget (rndis_opts->net, cdev->gadget); - status =gether_register_netdev (rndis_opts->net); -if (status) -return status; - rndis_opts->bound = true; +if (rndis_opts->bind_count ==0 && !rndis_opts->borrowed_net) { +if (!device_is_registered (&rndis_opts->net->dev)) { +gether_set_gadget (rndis_opts->net, cdev->gadget); + status =gether_register_netdev (rndis_opts->net); + }else + status =gether_attach_gadget (rndis_opts->net, cdev->gadget); + +if (status) +return status; + net = rndis_opts->net; + } } us = usb_gstrings_attach(cdev, rndis_strings,
@@ -809,6 +807,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) } rndis->notify_req =no_free_ptr (request); + rndis_opts->bind_count++; +no_free_ptr (net); +/* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt().
@@ -827,11 +828,11 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)struct f_rndis_opts *opts; opts = container_of(f, struct f_rndis_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net); - opts->borrowed_net = opts->bound = true; + opts->borrowed_net = true; opts->net = net; }EXPORT_SYMBOL_GPL (rndis_borrow_net);
@@ -889,7 +890,7 @@ static void rndis_free_inst(struct usb_function_instance *f) opts = container_of(f, struct f_rndis_opts, func_inst);if (!opts->borrowed_net) { -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -958,6 +959,9 @@ static void rndis_free(struct usb_function *f)static void rndis_unbind (struct usb_configuration *c,struct usb_function *f) {struct f_rndis *rndis =func_to_rndis (f); +struct f_rndis_opts *rndis_opts; + + rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);kfree (f->os_desc_table); f->os_desc_n =0 ;
@@ -965,6 +969,10 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)kfree (rndis->notify_req->buf);usb_ep_free_request (rndis->notify, rndis->notify_req); + + rndis_opts->bind_count--; +if (rndis_opts->bind_count ==0 && !rndis_opts->borrowed_net) +gether_detach_gadget (rndis_opts->net); }static struct usb_function *rndis_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_rndis.h +23 -8
@@ -15,12 +15,34 @@#include <linux/usb/composite.h> +/** +* struct f_rndis_opts - RNDIS function options +* @func_inst: USB function instance. +* @vendor_id: Vendor ID. +* @manufacturer: Manufacturer string. +* @net: The net_device associated with the RNDIS function. +* @bind_count: Tracks the number of configurations the RNDIS function is +* bound to, preventing double-registration of the @net device. +* @borrowed_net: True if the net_device is shared and pre-registered during +* the legacy composite driver's bind phase (e.g., multi.c). +* If false, the RNDIS function will register the net_device +* during its own bind phase. +* @rndis_interf_group: ConfigFS group for RNDIS interface. +* @rndis_os_desc: USB OS descriptor for RNDIS. +* @rndis_ext_compat_id: Extended compatibility ID. +* @class: USB class. +* @subclass: USB subclass. +* @protocol: USB protocol. +* @lock: Protects the data from concurrent access by configfs read/write +* and create symlink/remove symlink operations. +* @refcnt: Reference counter for the function instance. +*/ struct f_rndis_opts {struct usb_function_instance func_inst;u32 vendor_id;const char *manufacturer;struct net_device *net; -bool bound; +int bind_count;bool borrowed_net;struct config_group *rndis_interf_group;
@@ -30,13 +52,6 @@ struct f_rndis_opts {u8 class;u8 subclass;u8 protocol; - -/* -* Read/write access to configfs attributes is handled by configfs. -* -* This is to protect the data from concurrent access by read/write -* and create symlink/remove symlink. -*/ struct mutex lock;int refcnt; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 965/1887 usb: gadget: f_subset: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit 06524cd1c9011bee141a87e43ab878641ed3652b ]
The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks:
console:/ # ls -l /sys/class/net/usb0
lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0
ls: .../gadget.0/net/usb0: No such file or directory
Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering.
To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase.
--- drivers/usb/gadget/function/f_subset.c | 57 +++++++++++++------------- drivers/usb/gadget/function/u_gether.h | 22 ++++++---- 2 files changed, 44 insertions(+), 35 deletions(-)
drivers/usb/gadget/function/f_subset.c +29 -28
@@ -299,25 +299,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)struct usb_ep *ep;struct f_gether_opts *gether_opts; + struct net_device *net __free(detach_gadget) = NULL; gether_opts = container_of(f->fi, struct f_gether_opts, func_inst); -/* -* in drivers/usb/gadget/configfs.c:configfs_composite_bind() -* configurations are bound in sequence with list_for_each_entry, -* in each configuration its functions are bound in sequence -* with list_for_each_entry, so we assume no race condition -* with regard to gether_opts->bound access -*/ -if (!gether_opts->bound) { -mutex_lock (&gether_opts->lock); -gether_set_gadget (gether_opts->net, cdev->gadget); - status =gether_register_netdev (gether_opts->net); -mutex_unlock (&gether_opts->lock); -if (status) -return status; - gether_opts->bound = true; - } + scoped_guard(mutex, &gether_opts->lock) +if (gether_opts->bind_count ==0 && !gether_opts->bound) { +if (!device_is_registered (&gether_opts->net->dev)) { +gether_set_gadget (gether_opts->net, cdev->gadget); + status =gether_register_netdev (gether_opts->net); + }else + status =gether_attach_gadget (gether_opts->net, cdev->gadget); + +if (status) +return status; + net = gether_opts->net; + } us =usb_gstrings_attach (cdev, geth_strings,ARRAY_SIZE (geth_string_defs));
@@ -330,20 +327,18 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; subset_data_intf.bInterfaceNumber = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &fs_subset_in_desc);if (!ep) - goto fail; +return -ENODEV ; geth->port.in_ep = ep; ep =usb_ep_autoconfig (cdev->gadget, &fs_subset_out_desc);if (!ep) - goto fail; +return -ENODEV ; geth->port.out_ep = ep;/* support all relevant hardware speeds... we expect that when
@@ -361,23 +356,21 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, fs_eth_function, hs_eth_function, ss_eth_function, ss_eth_function);if (status) - goto fail; +return status;/* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). */ + gether_opts->bind_count++; +no_free_ptr (net); +DBG (cdev,"CDC Subset: %s speed IN/%s OUT/%s\n" ,gadget_is_superspeed (c->cdev->gadget) ?"super" :gadget_is_dualspeed (c->cdev->gadget) ?"dual" :"full" , geth->port.in_ep->name, geth->port.out_ep->name);return 0 ; - -fail: -ERROR (cdev,"%s: can't bind, err %d\n" , f->name, status); - -return status; }static inline struct f_gether_opts *to_f_gether_opts (struct config_item *item)
@@ -420,7 +413,7 @@ static void geth_free_inst(struct usb_function_instance *f)struct f_gether_opts *opts; opts = container_of(f, struct f_gether_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -464,8 +457,16 @@ static void geth_free(struct usb_function *f)static void geth_unbind (struct usb_configuration *c,struct usb_function *f) { +struct f_gether_opts *opts; + + opts = container_of(f->fi, struct f_gether_opts, func_inst); + geth_string_defs[0 ].id =0 ;usb_free_all_descriptors (f); + + opts->bind_count--; +if (opts->bind_count ==0 && !opts->bound) +gether_detach_gadget (opts->net); }static struct usb_function *geth_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_gether.h +15 -7
@@ -15,17 +15,25 @@#include <linux/usb/composite.h> +/** +* struct f_gether_opts - subset function options +* @func_inst: USB function instance. +* @net: The net_device associated with the subset function. +* @bound: True if the net_device is shared and pre-registered during the +* legacy composite driver's bind phase (e.g., multi.c). If false, +* the subset function will register the net_device during its own +* bind phase. +* @bind_count: Tracks the number of configurations the subset function is +* bound to, preventing double-registration of the @net device. +* @lock: Protects the data from concurrent access by configfs read/write +* and create symlink/remove symlink operations. +* @refcnt: Reference counter for the function instance. +*/ struct f_gether_opts {struct usb_function_instance func_inst;struct net_device *net;bool bound; - -/* -* Read/write access to configfs attributes is handled by configfs. -* -* This is to protect the data from concurrent access by read/write -* and create symlink/remove symlink. -*/ +int bind_count;struct mutex lock;int refcnt; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 966/1887 usb: gadget: f_eem: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit d9270c9a8118c1535409db926ac1e2545dc97b81 ]
The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks:
console:/ # ls -l /sys/class/net/usb0
lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0
ls: .../gadget.0/net/usb0: No such file or directory
Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering.
To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase.
--- drivers/usb/gadget/function/f_eem.c | 59 +++++++++++++++-------------- drivers/usb/gadget/function/u_eem.h | 21 +++++++--- 2 files changed, 46 insertions(+), 34 deletions(-)
drivers/usb/gadget/function/f_eem.c +31 -28
@@ -7,6 +7,7 @@* Copyright (C) 2009 EF Johnson Technologies */ +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h>
@@ -251,24 +252,22 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)struct usb_ep *ep;struct f_eem_opts *eem_opts; + struct net_device *net __free(detach_gadget) = NULL; eem_opts = container_of(f->fi, struct f_eem_opts, func_inst); -/* -* in drivers/usb/gadget/configfs.c:configfs_composite_bind() -* configurations are bound in sequence with list_for_each_entry, -* in each configuration its functions are bound in sequence -* with list_for_each_entry, so we assume no race condition -* with regard to eem_opts->bound access -*/ -if (!eem_opts->bound) { -mutex_lock (&eem_opts->lock); -gether_set_gadget (eem_opts->net, cdev->gadget); - status =gether_register_netdev (eem_opts->net); -mutex_unlock (&eem_opts->lock); -if (status) -return status; - eem_opts->bound = true; - } + + scoped_guard(mutex, &eem_opts->lock) +if (eem_opts->bind_count ==0 && !eem_opts->bound) { +if (!device_is_registered (&eem_opts->net->dev)) { +gether_set_gadget (eem_opts->net, cdev->gadget); + status =gether_register_netdev (eem_opts->net); + }else + status =gether_attach_gadget (eem_opts->net, cdev->gadget); + +if (status) +return status; + net = eem_opts->net; + } us =usb_gstrings_attach (cdev, eem_strings,ARRAY_SIZE (eem_string_defs));
@@ -279,21 +278,19 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; eem->ctrl_id = status; eem_intf.bInterfaceNumber = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &eem_fs_in_desc);if (!ep) - goto fail; +return -ENODEV ; eem->port.in_ep = ep; ep =usb_ep_autoconfig (cdev->gadget, &eem_fs_out_desc);if (!ep) - goto fail; +return -ENODEV ; eem->port.out_ep = ep;/* support all relevant hardware speeds... we expect that when
@@ -309,18 +306,16 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, eem_fs_function, eem_hs_function, eem_ss_function, eem_ss_function);if (status) - goto fail; +return status; + + eem_opts->bind_count++; +no_free_ptr (net);DBG (cdev,"CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n" ,gadget_is_superspeed (c->cdev->gadget) ?"super" :gadget_is_dualspeed (c->cdev->gadget) ?"dual" :"full" , eem->port.in_ep->name, eem->port.out_ep->name);return 0 ; - -fail: -ERROR (cdev,"%s: can't bind, err %d\n" , f->name, status); - -return status; }static void eem_cmd_complete (struct usb_ep *ep,struct usb_request *req)
@@ -599,7 +594,7 @@ static void eem_free_inst(struct usb_function_instance *f)struct f_eem_opts *opts; opts = container_of(f, struct f_eem_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -642,9 +637,17 @@ static void eem_free(struct usb_function *f)static void eem_unbind (struct usb_configuration *c,struct usb_function *f) { +struct f_eem_opts *opts; +DBG (c->cdev,"eem unbind\n" ); + opts = container_of(f->fi, struct f_eem_opts, func_inst); +usb_free_all_descriptors (f); + + opts->bind_count--; +if (opts->bind_count ==0 && !opts->bound) +gether_detach_gadget (opts->net); }static struct usb_function *eem_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_eem.h +15 -6
@@ -15,17 +15,26 @@#include <linux/usb/composite.h> +/** +* struct f_eem_opts - EEM function options +* @func_inst: USB function instance. +* @net: The net_device associated with the EEM function. +* @bound: True if the net_device is shared and pre-registered during the +* legacy composite driver's bind phase (e.g., multi.c). If false, +* the EEM function will register the net_device during its own +* bind phase. +* @bind_count: Tracks the number of configurations the EEM function is +* bound to, preventing double-registration of the @net device. +* @lock: Protects the data from concurrent access by configfs read/write +* and create symlink/remove symlink operations. +* @refcnt: Reference counter for the function instance. +*/ struct f_eem_opts {struct usb_function_instance func_inst;struct net_device *net;bool bound; +int bind_count; -/* -* Read/write access to configfs attributes is handled by configfs. -* -* This is to protect the data from concurrent access by read/write -* and create symlink/remove symlink. -*/ struct mutex lock;int refcnt; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 967/1887 usb: gadget: f_ecm: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit b2cc4fae67a51f60d81d6af2678696accb07c656 ]
The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks:
console:/ # ls -l /sys/class/net/usb0
lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0
ls: .../gadget.0/net/usb0: No such file or directory
Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering.
To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase.
--- drivers/usb/gadget/function/f_ecm.c | 41 +++++++++++++++++------------ drivers/usb/gadget/function/u_ecm.h | 21 ++++++++++----- 2 files changed, 39 insertions(+), 23 deletions(-)
drivers/usb/gadget/function/f_ecm.c +24 -17
@@ -692,6 +692,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)struct usb_ep *ep;struct f_ecm_opts *ecm_opts; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_ecm (cdev->gadget))
@@ -699,22 +700,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); -/* -* in drivers/usb/gadget/configfs.c:configfs_composite_bind() -* configurations are bound in sequence with list_for_each_entry, -* in each configuration its functions are bound in sequence -* with list_for_each_entry, so we assume no race condition -* with regard to ecm_opts->bound access -*/ -if (!ecm_opts->bound) { -mutex_lock (&ecm_opts->lock); -gether_set_gadget (ecm_opts->net, cdev->gadget); - status =gether_register_netdev (ecm_opts->net); -mutex_unlock (&ecm_opts->lock); -if (status) -return status; - ecm_opts->bound = true; - } + scoped_guard(mutex, &ecm_opts->lock) +if (ecm_opts->bind_count ==0 && !ecm_opts->bound) { +if (!device_is_registered (&ecm_opts->net->dev)) { +gether_set_gadget (ecm_opts->net, cdev->gadget); + status =gether_register_netdev (ecm_opts->net); + }else + status =gether_attach_gadget (ecm_opts->net, cdev->gadget); + +if (status) +return status; + net = ecm_opts->net; + } ecm_string_defs[1 ].s = ecm->ethaddr;
@@ -805,6 +802,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->notify_req =no_free_ptr (request); + ecm_opts->bind_count++; +no_free_ptr (net); + DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -853,7 +853,7 @@ static void ecm_free_inst(struct usb_function_instance *f)struct f_ecm_opts *opts; opts = container_of(f, struct f_ecm_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -897,9 +897,12 @@ static void ecm_free(struct usb_function *f)static void ecm_unbind (struct usb_configuration *c,struct usb_function *f) {struct f_ecm *ecm =func_to_ecm (f); +struct f_ecm_opts *ecm_opts;DBG (c->cdev,"ecm unbind\n" ); + ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); +usb_free_all_descriptors (f);if (atomic_read (&ecm->notify_count)) {
@@ -909,6 +912,10 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)kfree (ecm->notify_req->buf);usb_ep_free_request (ecm->notify, ecm->notify_req); + + ecm_opts->bind_count--; +if (ecm_opts->bind_count ==0 && !ecm_opts->bound) +gether_detach_gadget (ecm_opts->net); }static struct usb_function *ecm_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_ecm.h +15 -6
@@ -15,17 +15,26 @@#include <linux/usb/composite.h> +/** +* struct f_ecm_opts - ECM function options +* @func_inst: USB function instance. +* @net: The net_device associated with the ECM function. +* @bound: True if the net_device is shared and pre-registered during the +* legacy composite driver's bind phase (e.g., multi.c). If false, +* the ECM function will register the net_device during its own +* bind phase. +* @bind_count: Tracks the number of configurations the ECM function is +* bound to, preventing double-registration of the @net device. +* @lock: Protects the data from concurrent access by configfs read/write +* and create symlink/remove symlink operations. +* @refcnt: Reference counter for the function instance. +*/ struct f_ecm_opts {struct usb_function_instance func_inst;struct net_device *net;bool bound; +int bind_count; -/* -* Read/write access to configfs attributes is handled by configfs. -* -* This is to protect the data from concurrent access by read/write -* and create symlink/remove symlink. -*/ struct mutex lock;int refcnt; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 968/1887 drm/i915/dsi: Dont do DSC horizontal timing adjustments in command mode
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <[email protected]>
[ Upstream commit 4dfce79e098915d8e5fc2b9e1d980bc3251dd32c ]
Stop adjusting the horizontal timing values based on the compression ratio in command mode. Bspec seems to be telling us to do this only in video mode, and this is also how the Windows driver does things.
This should also fix a div-by-zero on some machines because the adjusted htotal ends up being so small that we end up with line_time_us==0 when trying to determine the vtotal value in command mode.
Note that this doesn't actually make the display on the Huawei Matebook E work, but at least the kernel no longer explodes when the driver loads.
--- drivers/gpu/drm/i915/display/icl_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/display/icl_dsi.c +2 -2
@@ -913,7 +913,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,* non-compressed link speeds, and simplifies down to the ratio between * compressed and non-compressed bpp. */ -if (crtc_state->dsc.compression_enable) { +if (is_vid_mode (intel_dsi) && crtc_state->dsc.compression_enable) { mul = crtc_state->dsc.compressed_bpp; div =mipi_dsi_pixel_format_to_bpp (intel_dsi->pixel_format); }
@@ -1518,7 +1518,7 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder,struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; -if (pipe_config->dsc.compressed_bpp) { +if (is_vid_mode (intel_dsi) && pipe_config->dsc.compressed_bpp) {int div = pipe_config->dsc.compressed_bpp;int mul =mipi_dsi_pixel_format_to_bpp (intel_dsi->pixel_format);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 969/1887 Bluetooth: hci_event: move wake reason storage into validated event handlers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleh Konko <[email protected]>
[ Upstream commit 2b2bf47cd75518c36fa2d41380e4a40641cc89cd ]
hci_store_wake_reason() is called from hci_event_packet() immediately after stripping the HCI event header but before hci_event_func() enforces the per-event minimum payload length from hci_ev_table. This means a short HCI event frame can reach bacpy() before any bounds check runs.
Rather than duplicating skb parsing and per-event length checks inside hci_store_wake_reason(), move wake-address storage into the individual event handlers after their existing event-length validation has succeeded. Convert hci_store_wake_reason() into a small helper that only stores an already-validated bdaddr while the caller holds hci_dev_lock(). Use the same helper after hci_event_func() with a NULL address to preserve the existing unexpected-wake fallback semantics when no validated event handler records a wake address.
Annotate the helper with __must_hold(&hdev->lock) and add lockdep_assert_held(&hdev->lock) so future call paths keep the lock contract explicit.
Call the helper from hci_conn_request_evt(), hci_conn_complete_evt(), hci_sync_conn_complete_evt(), le_conn_complete_evt(), hci_le_adv_report_evt(), hci_le_ext_adv_report_evt(), hci_le_direct_adv_report_evt(), hci_le_pa_sync_established_evt(), and hci_le_past_received_evt().
--- net/bluetooth/hci_event.c | 93 ++++++++++++++------------------------- 1 file changed, 34 insertions(+), 59 deletions(-)
net/bluetooth/hci_event.c +34 -59
@@ -80,6 +80,10 @@ static void *hci_le_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,return data; } +static void hci_store_wake_reason(struct hci_dev *hdev, + const bdaddr_t *bdaddr, u8 addr_type) + __must_hold(&hdev->lock); +static u8 hci_cc_inquiry_cancel (struct hci_dev *hdev,void *data,struct sk_buff *skb) {
@@ -3078,6 +3082,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,bt_dev_dbg (hdev,"status 0x%2.2x" , status);hci_dev_lock (hdev); +hci_store_wake_reason (hdev, &ev->bdaddr,BDADDR_BREDR );/* Check for existing connection: *
@@ -3262,6 +3267,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,bt_dev_dbg (hdev,"bdaddr %pMR type 0x%x" , &ev->bdaddr, ev->link_type); +hci_dev_lock (hdev); +hci_store_wake_reason (hdev, &ev->bdaddr,BDADDR_BREDR ); +hci_dev_unlock (hdev); +/* Reject incoming connection from device with same BD ADDR against * CVE-2020-26555 */
@@ -4915,6 +4924,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,bt_dev_dbg (hdev,"status 0x%2.2x" , status);hci_dev_lock (hdev); +hci_store_wake_reason (hdev, &ev->bdaddr,BDADDR_BREDR ); conn =hci_conn_hash_lookup_ba (hdev, ev->link_type, &ev->bdaddr);if (!conn) {
@@ -5623,6 +5633,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,u8 addr_type;hci_dev_lock (hdev); +hci_store_wake_reason (hdev, bdaddr, bdaddr_type);/* Advertising stops when a connection is created. On a failed * connection it keeps running, so leave the state bit alone.
@@ -6251,6 +6262,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data, info->length + 1))break ; +hci_store_wake_reason (hdev, &info->bdaddr, info->bdaddr_type); +if (info->length <=max_adv_len (hdev)) { rssi = info->data[info->length]; process_adv_report(hdev, info->type, &info->bdaddr,
@@ -6334,6 +6347,8 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data, info->length))break ; +hci_store_wake_reason (hdev, &info->bdaddr, info->bdaddr_type); + evt_type =__le16_to_cpu (info->type); legacy_evt_type =ext_evt_type_to_legacy (hdev, evt_type);if (legacy_evt_type !=LE_ADV_INVALID ) {
@@ -6371,6 +6386,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,return ;hci_dev_lock (hdev); +hci_store_wake_reason (hdev, &ev->bdaddr, ev->bdaddr_type);hci_dev_clear_flag (hdev,HCI_PA_SYNC );
@@ -6608,6 +6624,8 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,for (i =0 ; i < ev->num; i++) {struct hci_ev_le_direct_adv_info *info = &ev->info[i]; +hci_store_wake_reason (hdev, &info->bdaddr, info->bdaddr_type); + process_adv_report(hdev, info->type, &info->bdaddr, info->bdaddr_type, &info->direct_addr, info->direct_addr_type, info->rssi, NULL, 0,
@@ -7063,73 +7081,29 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,return true; } -static void hci_store_wake_reason (struct hci_dev *hdev,u8 event, -struct sk_buff *skb) +static void hci_store_wake_reason (struct hci_dev *hdev, +const bdaddr_t *bdaddr,u8 addr_type) + __must_hold(&hdev->lock) { -struct hci_ev_le_advertising_info *adv; -struct hci_ev_le_direct_adv_info *direct_adv; -struct hci_ev_le_ext_adv_info *ext_adv; -const struct hci_ev_conn_complete *conn_complete = (void *)skb->data; -const struct hci_ev_conn_request *conn_request = (void *)skb->data; - -hci_dev_lock (hdev); +lockdep_assert_held (&hdev->lock);/* If we are currently suspended and this is the first BT event seen, * save the wake reason associated with the event. */ if (!hdev->suspended || hdev->wake_reason) - goto unlock; +return ; + +if (!bdaddr) { + hdev->wake_reason =MGMT_WAKE_REASON_UNEXPECTED ; +return ; + }/* Default to remote wake. Values for wake_reason are documented in the * Bluez mgmt api docs. */ hdev->wake_reason =MGMT_WAKE_REASON_REMOTE_WAKE ; - -/* Once configured for remote wakeup, we should only wake up for -* reconnections. It's useful to see which device is waking us up so -* keep track of the bdaddr of the connection event that woke us up. -*/ -if (event ==HCI_EV_CONN_REQUEST ) { -bacpy (&hdev->wake_addr, &conn_request->bdaddr); - hdev->wake_addr_type =BDADDR_BREDR ; - }else if (event ==HCI_EV_CONN_COMPLETE ) { -bacpy (&hdev->wake_addr, &conn_complete->bdaddr); - hdev->wake_addr_type =BDADDR_BREDR ; - }else if (event ==HCI_EV_LE_META ) { -struct hci_ev_le_meta *le_ev = (void *)skb->data; -u8 subevent = le_ev->subevent; -u8 *ptr = &skb->data[sizeof (*le_ev)]; -u8 num_reports = *ptr; - -if ((subevent ==HCI_EV_LE_ADVERTISING_REPORT || - subevent ==HCI_EV_LE_DIRECT_ADV_REPORT || - subevent ==HCI_EV_LE_EXT_ADV_REPORT ) && - num_reports) { - adv = (void *)(ptr +1 ); - direct_adv = (void *)(ptr +1 ); - ext_adv = (void *)(ptr +1 ); - -switch (subevent) { -case HCI_EV_LE_ADVERTISING_REPORT : -bacpy (&hdev->wake_addr, &adv->bdaddr); - hdev->wake_addr_type = adv->bdaddr_type; -break ; -case HCI_EV_LE_DIRECT_ADV_REPORT : -bacpy (&hdev->wake_addr, &direct_adv->bdaddr); - hdev->wake_addr_type = direct_adv->bdaddr_type; -break ; -case HCI_EV_LE_EXT_ADV_REPORT : -bacpy (&hdev->wake_addr, &ext_adv->bdaddr); - hdev->wake_addr_type = ext_adv->bdaddr_type; -break ; - } - } - }else { - hdev->wake_reason =MGMT_WAKE_REASON_UNEXPECTED ; - } - -unlock: -hci_dev_unlock (hdev); +bacpy (&hdev->wake_addr, bdaddr); + hdev->wake_addr_type = addr_type; }#define HCI_EV_VL (_op, _func, _min_len, _max_len) \
@@ -7374,14 +7348,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)skb_pull (skb,HCI_EVENT_HDR_SIZE ); -/* Store wake reason if we're suspended */ -hci_store_wake_reason (hdev, event, skb); -bt_dev_dbg (hdev,"event 0x%2.2x" , event);hci_event_func (hdev, event, skb, &opcode, &status, &req_complete, &req_complete_skb); +hci_dev_lock (hdev); +hci_store_wake_reason (hdev,NULL ,0 ); +hci_dev_unlock (hdev); +if (req_complete) {req_complete (hdev, status, opcode); }else if (req_complete_skb) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 970/1887 bpf: Fix incorrect pruning due to atomic fetch precision tracking
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <[email protected]>
[ Upstream commit 179ee84a89114b854ac2dd1d293633a7f6c8dac1 ]
When backtrack_insn encounters a BPF_STX instruction with BPF_ATOMIC and BPF_FETCH, the src register (or r0 for BPF_CMPXCHG) also acts as a destination, thus receiving the old value from the memory location.
The current backtracking logic does not account for this. It treats atomic fetch operations the same as regular stores where the src register is only an input. This leads the backtrack_insn to fail to propagate precision to the stack location, which is then not marked as precise!
Later, the verifier's path pruning can incorrectly consider two states equivalent when they differ in terms of stack state. Meaning, two branches can be treated as equivalent and thus get pruned when they should not be seen as such.
Fix it as follows: Extend the BPF_LDX handling in backtrack_insn to also cover atomic fetch operations via is_atomic_fetch_insn() helper. When the fetch dst register is being tracked for precision, clear it, and propagate precision over to the stack slot. For non-stack memory, the precision walk stops at the atomic instruction, same as regular BPF_LDX. This covers all fetch variants.
Before:
0: (b7) r1 = 8 ; R1=8 1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8 2: (b7) r2 = 0 ; R2=0
3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
4: (bf) r3 = r10 ; R3=fp0 R10=fp0
5: (0f) r3 += r2
mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
mark_precise: frame0: regs=r2 stack= before 2: (b7) r2 = 0
6: R2=8 R3=fp8
6: (b7) r0 = 0 ; R0=0
7: (95) exit
After:
0: (b7) r1 = 8 ; R1=8 1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8 2: (b7) r2 = 0 ; R2=0
3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
4: (bf) r3 = r10 ; R3=fp0 R10=fp0
5: (0f) r3 += r2
mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
mark_precise: frame0: regs= stack=-8 before 2: (b7) r2 = 0
mark_precise: frame0: regs= stack=-8 before 1: (7b) *(u64 *)(r10 -8) = r1
mark_precise: frame0: regs=r1 stack= before 0: (b7) r1 = 8
6: R2=8 R3=fp8
6: (b7) r0 = 0 ; R0=0
7: (95) exit
--- kernel/bpf/verifier.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
kernel/bpf/verifier.c +26 -4
@@ -473,6 +473,13 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn) insn->imm ==BPF_CMPXCHG ; } +static bool is_atomic_fetch_insn (const struct bpf_insn *insn) +{ +return BPF_CLASS (insn->code) ==BPF_STX && +BPF_MODE (insn->code) ==BPF_ATOMIC && + (insn->imm &BPF_FETCH ); +} +/* string representation of 'enum bpf_reg_type' * * Note that reg_type_str() can not appear more than once in a single verbose()
@@ -2608,10 +2615,25 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,* dreg still needs precision before this insn */ } - }else if (class ==BPF_LDX ) { -if (!(*reg_mask & dreg)) + }else if (class ==BPF_LDX ||is_atomic_fetch_insn (insn)) { +u32 load_reg = dreg; +u8 base_reg = insn->src_reg; + +/* +* Atomic fetch operation writes the old value into +* a register (sreg or r0) and if it was tracked for +* precision, propagate to the stack slot like we do +* in regular ldx. +*/ +if (is_atomic_fetch_insn (insn)) { + load_reg = insn->imm ==BPF_CMPXCHG ? +1u <<BPF_REG_0 : sreg; + base_reg = insn->dst_reg; + } + +if (!(*reg_mask & load_reg))return 0 ; - *reg_mask &= ~dreg; + *reg_mask &= ~load_reg;/* scalars can only be spilled into stack w/o losing precision. * Load from any other memory can be zero extended.
@@ -2619,7 +2641,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,* by 'precise' mark in corresponding register of this state. * No further tracking necessary. */ -if (insn->src_reg !=BPF_REG_FP ) +if (base_reg !=BPF_REG_FP )return 0 ;/* dreg = *(u64 *)[fp - off] was a fill from the stack.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 971/1887 bpf: Reject sleepable kprobe_multi programs at attach time
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Varun R Mallya <[email protected]>
[ Upstream commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 ]
kprobe.multi programs run in atomic/RCU context and cannot sleep. However, bpf_kprobe_multi_link_attach() did not validate whether the program being attached had the sleepable flag set, allowing sleepable helpers such as bpf_copy_from_user() to be invoked from a non-sleepable context.
This causes a "sleeping function called from invalid context" splat:
BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo preempt_count: 1, expected: 0 RCU nest depth: 2, expected: 0
Fix this by rejecting sleepable programs early in bpf_kprobe_multi_link_attach(), before any further processing.
--- kernel/trace/bpf_trace.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/trace/bpf_trace.c +4 -0
@@ -2730,6 +2730,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prif (prog->expected_attach_type !=BPF_TRACE_KPROBE_MULTI )return -EINVAL ; +/* kprobe_multi is not allowed to be sleepable. */ +if (prog->aux->sleepable) +return -EINVAL ; + flags = attr->link_create.kprobe_multi.flags;if (flags & ~BPF_F_KPROBE_MULTI_RETURN )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 972/1887 bpf: sockmap: Fix use-after-free of sk->sk_socket in sk_psock_verdict_data_ready().
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit ad8391d37f334ee73ba91926f8b4e4cf6d31ea04 ]
syzbot reported use-after-free of AF_UNIX socket's sk->sk_socket in sk_psock_verdict_data_ready(). [0]
In unix_stream_sendmsg(), the peer socket's ->sk_data_ready() is called after dropping its unix_state_lock().
Although the sender socket holds the peer's refcount, it does not prevent the peer's sock_orphan(), and the peer's sk_socket might be freed after one RCU grace period.
Let's fetch the peer's sk->sk_socket and sk->sk_socket->ops under RCU in sk_psock_verdict_data_ready().
[0]:
BUG: KASAN: slab-use-after-free in sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278 Read of size 8 at addr ffff8880594da860 by task syz.4.1842/11013 CPU: 1 UID: 0 PID: 11013 Comm: syz.4.1842 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026 Call Trace: <TASK> dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xba/0x230 mm/kasan/report.c:482 kasan_report+0x117/0x150 mm/kasan/report.c:595 sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278 unix_stream_sendmsg+0x8a3/0xe80 net/unix/af_unix.c:2482 sock_sendmsg_nosec net/socket.c:721 [inline] __sock_sendmsg net/socket.c:736 [inline] ____sys_sendmsg+0x972/0x9f0 net/socket.c:2585 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2639 __sys_sendmsg net/socket.c:2671 [inline] __do_sys_sendmsg net/socket.c:2676 [inline] __se_sys_sendmsg net/socket.c:2674 [inline] __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2674 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:0x7facf899c819 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007facf9827028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007facf8c15fa0 RCX: 00007facf899c819 RDX: 0000000000000000 RSI: 0000200000000500 RDI: 0000000000000004 RBP: 00007facf8a32c91 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007facf8c16038 R14: 00007facf8c15fa0 R15: 00007ffd41b01c78 </TASK> Allocated by task 11013: kasan_save_stack mm/kasan/common.c:57 [inline] kasan_save_track+0x3e/0x80 mm/kasan/common.c:78 unpoison_slab_object mm/kasan/common.c:340 [inline] __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366 kasan_slab_alloc include/linux/kasan.h:253 [inline] slab_post_alloc_hook mm/slub.c:4538 [inline] slab_alloc_node mm/slub.c:4866 [inline] kmem_cache_alloc_lru_noprof+0x2b8/0x640 mm/slub.c:4885 sock_alloc_inode+0x28/0xc0 net/socket.c:316 alloc_inode+0x6a/0x1b0 fs/inode.c:347 new_inode_pseudo include/linux/fs.h:3003 [inline] sock_alloc net/socket.c:631 [inline] __sock_create+0x12d/0x9d0 net/socket.c:1562 sock_create net/socket.c:1656 [inline] __sys_socketpair+0x1c4/0x560 net/socket.c:1803 __do_sys_socketpair net/socket.c:1856 [inline] __se_sys_socketpair net/socket.c:1853 [inline] __x64_sys_socketpair+0x9b/0xb0 net/socket.c:1853 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 Freed by task 15: kasan_save_stack mm/kasan/common.c:57 [inline] kasan_save_track+0x3e/0x80 mm/kasan/common.c:78 kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:253 [inline] __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285 kasan_slab_free include/linux/kasan.h:235 [inline] slab_free_hook mm/slub.c:2685 [inline] slab_free mm/slub.c:6165 [inline] kmem_cache_free+0x187/0x630 mm/slub.c:6295 rcu_do_batch kernel/rcu/tree.c:2617 [inline] rcu_core+0x7cd/0x1070 kernel/rcu/tree.c:2869 handle_softirqs+0x22a/0x870 kernel/softirq.c:622 run_ksoftirqd+0x36/0x60 kernel/softirq.c:1063 smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160 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
--- net/core/skmsg.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/core/skmsg.c +10 -3
@@ -1266,12 +1266,19 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)static void sk_psock_verdict_data_ready (struct sock *sk) { -struct socket *sock = sk->sk_socket; +const struct proto_ops *ops =NULL ; +struct socket *sock;int copied; -if (unlikely (!sock || !sock->ops || !sock->ops->read_skb)) +rcu_read_lock (); + sock =READ_ONCE (sk->sk_socket); +if (likely (sock)) + ops =READ_ONCE (sock->ops); +rcu_read_unlock (); +if (!ops || !ops->read_skb)return ; - copied = sock->ops->read_skb (sk, sk_psock_verdict_recv); + + copied = ops->read_skb (sk, sk_psock_verdict_recv);if (copied >=0 ) {struct sk_psock *psock;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 973/1887 Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 2969554bcfccb5c609f6b6cd4a014933f3a66dd0 ]
hci_cmd_sync_queue_once() needs to indicate whether a queue item was added, so caller can know if callbacks are called, so it can avoid leaking resources.
Change the function to return -EEXIST if queue item already exists.
Modify all callsites to handle that.
--- net/bluetooth/hci_sync.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +6 -3
@@ -811,7 +811,7 @@ int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy) { if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) - return 0; + return -EEXIST;return hci_cmd_sync_queue (hdev, func, data, destroy); }
@@ -3326,6 +3326,8 @@ static int update_passive_scan_sync(struct hci_dev *hdev, void *data)int hci_update_passive_scan (struct hci_dev *hdev) { +int err; +/* Only queue if it would have any effect */ if (!test_bit(HCI_UP, &hdev->flags) || test_bit(HCI_INIT, &hdev->flags) ||
@@ -3335,8 +3337,9 @@ int hci_update_passive_scan(struct hci_dev *hdev) hci_dev_test_flag(hdev, HCI_UNREGISTER))return 0 ; -return hci_cmd_sync_queue_once (hdev, update_passive_scan_sync,NULL , -NULL ); + err =hci_cmd_sync_queue_once (hdev, update_passive_scan_sync,NULL , +NULL ); +return (err == -EEXIST ) ?0 : err; }int hci_write_sc_support_sync (struct hci_dev *hdev,u8 val)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 974/1887 net: use skb_header_pointer() for TCPv4 GSO frag_off check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoyu Su <[email protected]>
[ Upstream commit ddc748a391dd8642ba6b2e4fe22e7f2ddf84b7f0 ]
Syzbot reported a KMSAN uninit-value warning in gso_features_check() called from netif_skb_features() [1].
gso_features_check() reads iph->frag_off to decide whether to clear mangleid_features. Accessing the IPv4 header via ip_hdr()/inner_ip_hdr() can rely on skb header offsets that are not always safe for direct dereference on packets injected from PF_PACKET paths.
Use skb_header_pointer() for the TCPv4 frag_off check so the header read is robust whether data is already linear or needs copying.
[1] https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
--- net/core/dev.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
net/core/dev.c +8 -3
@@ -3633,10 +3633,15 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,* IPv4 header has the potential to be fragmented. */ if (skb_shinfo (skb)->gso_type &SKB_GSO_TCPV4 ) { -struct iphdr *iph = skb->encapsulation ? -inner_ip_hdr (skb) :ip_hdr (skb); +const struct iphdr *iph; +struct iphdr _iph; +int nhoff = skb->encapsulation ? +skb_inner_network_offset (skb) : +skb_network_offset (skb); -if (!(iph->frag_off &htons (IP_DF ))) + iph =skb_header_pointer (skb, nhoff,sizeof (_iph), &_iph); + +if (!iph || !(iph->frag_off &htons (IP_DF ))) features &= ~NETIF_F_TSO_MANGLEID ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 975/1887 mpls: add seqcount to protect the platform_label{,s} pair
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
[ Upstream commit 629ec78ef8608d955ce217880cdc3e1873af3a15 ]
The RCU-protected codepaths (mpls_forward, mpls_dump_routes) can have an inconsistent view of platform_labels vs platform_label in case of a concurrent resize (resize_platform_label_table, under platform_mutex). This can lead to OOB accesses.
This patch adds a seqcount, so that we get a consistent snapshot.
Note that mpls_label_ok is also susceptible to this, so the check against RTA_DST in rtm_to_route_config, done outside platform_mutex, is not sufficient. This value gets passed to mpls_label_ok once more in both mpls_route_add and mpls_route_del, so there is no issue, but that additional check must not be removed.
--- include/net/netns/mpls.h | 1 + net/mpls/af_mpls.c | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-)
include/net/netns/mpls.h +1 -0
@@ -16,6 +16,7 @@ struct netns_mpls {int default_ttl;size_t platform_labels;struct mpls_route __rcu *__rcu *platform_label; +seqcount_t platform_label_seq;struct ctl_table_header *ctl; };
net/mpls/af_mpls.c +30 -10
@@ -74,16 +74,31 @@ static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt, struct nlmsghdr *nlh, struct net *net, u32 portid, unsigned int nlm_flags); -static struct mpls_route *mpls_route_input_rcu (struct net *net,unsigned index) +static struct mpls_route __rcu **mpls_platform_label_rcu (struct net *net,size_t *platform_labels) { -struct mpls_route *rt =NULL ; +struct mpls_route __rcu **platform_label; +unsigned int sequence; -if (index < net->mpls.platform_labels) { -struct mpls_route __rcu **platform_label = -rcu_dereference_rtnl (net->mpls.platform_label); - rt =rcu_dereference_rtnl (platform_label[index]); - } -return rt; +do { + sequence =read_seqcount_begin (&net->mpls.platform_label_seq); + platform_label =rcu_dereference_rtnl (net->mpls.platform_label); + *platform_labels = net->mpls.platform_labels; + }while (read_seqcount_retry (&net->mpls.platform_label_seq, sequence)); + +return platform_label; +} + +static struct mpls_route *mpls_route_input_rcu (struct net *net,unsigned int index) +{ +struct mpls_route __rcu **platform_label; +size_t platform_labels; + + platform_label =mpls_platform_label_rcu (net, &platform_labels); + +if (index >= platform_labels) +return NULL ; + +return rcu_dereference_rtnl (platform_label[index]); }bool mpls_output_possible (const struct net_device *dev)
@@ -2209,8 +2224,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)if (index <MPLS_LABEL_FIRST_UNRESERVED ) index =MPLS_LABEL_FIRST_UNRESERVED ; - platform_label =rtnl_dereference (net->mpls.platform_label); - platform_labels = net->mpls.platform_labels; + platform_label =mpls_platform_label_rcu (net, &platform_labels);if (filter.filter_set) flags |=NLM_F_DUMP_FILTERED ;
@@ -2597,8 +2611,12 @@ static int resize_platform_label_table(struct net *net, size_t limit) }/* Update the global pointers */ +local_bh_disable (); +write_seqcount_begin (&net->mpls.platform_label_seq); net->mpls.platform_labels = limit;rcu_assign_pointer (net->mpls.platform_label, labels); +write_seqcount_end (&net->mpls.platform_label_seq); +local_bh_enable ();rtnl_unlock ();
@@ -2679,6 +2697,8 @@ static int mpls_net_init(struct net *net)struct ctl_table *table;int i; +seqcount_init (&net->mpls.platform_label_seq); + net->mpls.platform_labels =0 ; net->mpls.platform_label =NULL ; net->mpls.ip_ttl_propagate =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 976/1887 HID: core: Add reserved item tag for main items
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatsuya S <[email protected]>
[ Upstream commit c600a55922640b1c4dcfdc5a694cadd2dd9d1599 ]
For main items, separate warning of reserved item tag from warning of unknown item tag.
This comes from 6.2.2.4 Main Items of Device Class Definition for HID 1.11 specification.
Stable-dep-of: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
--- drivers/hid/hid-core.c | 6 +++++- include/linux/hid.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-)
drivers/hid/hid-core.c +5 -1
@@ -640,7 +640,11 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) ret =hid_add_field (parser,HID_FEATURE_REPORT , data);break ;default : -hid_warn (parser->device,"unknown main item tag 0x%x\n" , item->tag); +if (item->tag >=HID_MAIN_ITEM_TAG_RESERVED_MIN && + item->tag <=HID_MAIN_ITEM_TAG_RESERVED_MAX ) +hid_warn (parser->device,"reserved main item tag 0x%x\n" , item->tag); +else +hid_warn (parser->device,"unknown main item tag 0x%x\n" , item->tag); ret =0 ; }
include/linux/hid.h +2 -0
@@ -80,6 +80,8 @@ struct hid_item {#define HID_MAIN_ITEM_TAG_FEATURE 11#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 +#define HID_MAIN_ITEM_TAG_RESERVED_MIN 13 +#define HID_MAIN_ITEM_TAG_RESERVED_MAX 15/* * HID report descriptor main item contents
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 977/1887 HID: rate-limit hid_warn to prevent log flooding
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Chen <[email protected]>
[ Upstream commit 4051ead99888f101be92c7ce90d2de09aac6fd1c ]
Syzkaller can create many uhid devices that trigger repeated warnings like:
"hid-generic xxxx: unknown main item tag 0x0"
These messages can flood the system log, especially if a crash occurs (e.g., with a slow UART console, leading to soft lockups). To mitigate this, convert hid_warn() to use dev_warn_ratelimited().
This helps reduce log noise and improves system stability under fuzzing or faulty device scenarios.
Stable-dep-of: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
--- drivers/hid/hid-core.c | 4 ++-- include/linux/hid.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/hid/hid-core.c +2 -2
@@ -642,9 +642,9 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)default :if (item->tag >=HID_MAIN_ITEM_TAG_RESERVED_MIN && item->tag <=HID_MAIN_ITEM_TAG_RESERVED_MAX ) -hid_warn (parser->device,"reserved main item tag 0x%x\n" , item->tag); +hid_warn_ratelimited (parser->device,"reserved main item tag 0x%x\n" , item->tag);else -hid_warn (parser->device,"unknown main item tag 0x%x\n" , item->tag); +hid_warn_ratelimited (parser->device,"unknown main item tag 0x%x\n" , item->tag); ret =0 ; }
include/linux/hid.h +2 -0
@@ -1248,6 +1248,8 @@ do { \ dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)#define hid_warn (hid, fmt, ...) \ dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__) +#define hid_warn_ratelimited (hid, fmt, ...) \ + dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__)#define hid_info (hid, fmt, ...) \ dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)#define hid_dbg (hid, fmt, ...) \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 978/1887 HID: core: Mitigate potential OOB by removing bogus memset()
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 0a3fe972a7cb1404f693d6f1711f32bc1d244b1c ]
The memset() in hid_report_raw_event() has the good intention of clearing out bogus data by zeroing the area from the end of the incoming data string to the assumed end of the buffer. However, as we have previously seen, doing so can easily result in OOB reads and writes in the subsequent thread of execution.
The current suggestion from one of the HID maintainers is to remove the memset() and simply return if the incoming event buffer size is not large enough to fill the associated report.
Suggested-by Benjamin Tissoires <[email protected]>
--- drivers/hid/hid-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/hid/hid-core.c +3 -3
@@ -2052,9 +2052,9 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 * }if (csize < rsize) { -dbg_hid ("report %d is too short, (%d < %d)\n" , report->id, - csize, rsize); -memset (cdata + csize,0 , rsize - csize); +hid_warn_ratelimited (hid,"Event data for report %d was too short (%d vs %d)\n" , + report->id, rsize, csize); +return -EINVAL ; }if ((hid->claimed &HID_CLAIMED_HIDDEV ) && hid->hiddev_report_event)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 979/1887 HID: logitech-hidpp: Prevent use-after-free on force feedback initialisation failure
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 f7a4c78bfeb320299c1b641500fe7761eadbd101 ]
Presently, if the force feedback initialisation fails when probing the Logitech G920 Driving Force Racing Wheel for Xbox One, an error number will be returned and propagated before the userspace infrastructure (sysfs and /dev/input) has been torn down. If userspace ignores the errors and continues to use its references to these dangling entities, a UAF will promptly follow.
We have 2 options; continue to return the error, but ensure that all of the infrastructure is torn down accordingly or continue to treat this condition as a warning by emitting the message but returning success. It is thought that the original author's intention was to emit the warning but keep the device functional, less the force feedback feature, so let's go with that.
--- drivers/hid/hid-logitech-hidpp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hid/hid-logitech-hidpp.c +3 -1
@@ -4278,10 +4278,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)if (hidpp->quirks &HIDPP_QUIRK_CLASS_G920 ) { ret =hidpp_ff_init (hidpp, &data); -if (ret) +if (ret) {hid_warn (hidpp->hid_dev,"Unable to initialize force feedback support, errno %d\n" , ret); + ret =0 ; + } }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 980/1887 net: ioam6: fix OOB and missing lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Iurman <[email protected]>
[ Upstream commit b30b1675aa2bcf0491fd3830b051df4e08a7c8ca ]
When trace->type.bit6 is set:
if (trace->type.bit6) {
...
queue = skb_get_tx_queue(dev, skb);
qdisc = rcu_dereference(queue->qdisc);This code can lead to an out-of-bounds access of the dev->_tx[] array when is_input is true. In such a case, the packet is on the RX path and skb->queue_mapping contains the RX queue index of the ingress device. If the ingress device has more RX queues than the egress device (dev) has TX queues, skb_get_queue_mapping(skb) will exceed dev->num_tx_queues. Add a check to avoid this situation since skb_get_tx_queue() does not clamp the index. This issue has also revealed that per queue visibility cannot be accurate and will be replaced later as a new feature.
While at it, add missing lock around qdisc_qstats_qlen_backlog(). The function __ioam6_fill_trace_data() is called from both softirq and process contexts, hence the use of spin_lock_bh() here.
--- net/ipv6/ioam6.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/ipv6/ioam6.c +5 -1
@@ -737,12 +737,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,struct Qdisc *qdisc;__u32 qlen, backlog; -if (skb_dst (skb)->dev->flags &IFF_LOOPBACK ) { +if (skb_dst (skb)->dev->flags &IFF_LOOPBACK || +skb_get_queue_mapping (skb) >=skb_dst (skb)->dev->num_tx_queues) { *(__be32 *)data =cpu_to_be32 (IOAM6_U32_UNAVAILABLE ); }else { queue =skb_get_tx_queue (skb_dst (skb)->dev, skb); qdisc =rcu_dereference (queue->qdisc); + +spin_lock_bh (qdisc_lock (qdisc));qdisc_qstats_qlen_backlog (qdisc, &qlen, &backlog); +spin_unlock_bh (qdisc_lock (qdisc)); *(__be32 *)data =cpu_to_be32 (backlog); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 981/1887 xfrm: Wait for RCU readers during policy netns exit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Klassert <[email protected]>
[ Upstream commit 069daad4f2ae9c5c108131995529d5f02392c446 ]
xfrm_policy_fini() frees the policy_bydst hash tables after flushing the policy work items and deleting all policies, but it does not wait for concurrent RCU readers to leave their read-side critical sections first.
The policy_bydst tables are published via rcu_assign_pointer() and are looked up through rcu_dereference_check(), so netns teardown must also wait for an RCU grace period before freeing the table memory.
Fix this by adding synchronize_rcu() before freeing the policy hash tables.
--- net/xfrm/xfrm_policy.c | 2 ++ 1 file changed, 2 insertions(+)
net/xfrm/xfrm_policy.c +2 -0
@@ -4142,6 +4142,8 @@ static void xfrm_policy_fini(struct net *net)#endif xfrm_policy_flush (net,XFRM_POLICY_TYPE_MAIN , false); +synchronize_rcu (); +WARN_ON (!list_empty (&net->xfrm.policy_all));for (dir =0 ; dir <XFRM_POLICY_MAX ; dir++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 982/1887 ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 4e65a8b8daa18d63255ec58964dd192c7fdd9f8b ]
We need to check __in6_dev_get() for possible NULL value, as suggested by Yiming Qian.
Also add skb_dst_dev_rcu() instead of skb_dst_dev(), and two missing READ_ONCE().
Note that @dev can't be NULL.
--- net/ipv6/ioam6.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
net/ipv6/ioam6.c +16 -10
@@ -650,6 +650,9 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, struct ioam6_schema *sc, unsigned int sclen, bool is_input) { +/* Note: skb_dst_dev_rcu() can't be NULL at this point. */ +struct net_device *dev =skb_dst_dev_rcu (skb); +struct inet6_dev *i_skb_dev, *idev;struct timespec64 ts;ktime_t tstamp;u64 raw64;
@@ -660,13 +663,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, data = trace->data + trace->remlen *4 - trace->nodelen *4 - sclen *4 ; + i_skb_dev = skb->dev ?__in6_dev_get (skb->dev) :NULL ; + idev =__in6_dev_get (dev); +/* hop_lim and node_id */ if (trace->type.bit0) { byte =ipv6_hdr (skb)->hop_limit;if (is_input) byte--; - raw32 =dev_net (skb_dst (skb)->dev)->ipv6.sysctl.ioam6_id; + raw32 =READ_ONCE (dev_net (dev)->ipv6.sysctl.ioam6_id); *(__be32 *)data =cpu_to_be32 ((byte <<24 ) | raw32); data +=sizeof (__be32);
@@ -674,18 +680,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,/* ingress_if_id and egress_if_id */ if (trace->type.bit1) { -if (!skb->dev) +if (!i_skb_dev) raw16 =IOAM6_U16_UNAVAILABLE ;else - raw16 = (__force u16 )__in6_dev_get (skb->dev)->cnf.ioam6_id; + raw16 = (__force u16 )READ_ONCE (i_skb_dev->cnf.ioam6_id); *(__be16 *)data =cpu_to_be16 (raw16); data +=sizeof (__be16); -if (skb_dst (skb)->dev->flags &IFF_LOOPBACK ) +if ((dev->flags &IFF_LOOPBACK ) || !idev) raw16 =IOAM6_U16_UNAVAILABLE ;else - raw16 = (__force u16 )__in6_dev_get (skb_dst (skb)->dev)->cnf.ioam6_id; + raw16 = (__force u16 )READ_ONCE (idev->cnf.ioam6_id); *(__be16 *)data =cpu_to_be16 (raw16); data +=sizeof (__be16);
@@ -765,7 +771,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,if (is_input) byte--; - raw64 =dev_net (skb_dst (skb)->dev)->ipv6.sysctl.ioam6_id_wide; + raw64 =READ_ONCE (dev_net (dev)->ipv6.sysctl.ioam6_id_wide); *(__be64 *)data =cpu_to_be64 (((u64 )byte <<56 ) | raw64); data +=sizeof (__be64);
@@ -773,18 +779,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,/* ingress_if_id and egress_if_id (wide) */ if (trace->type.bit9) { -if (!skb->dev) +if (!i_skb_dev) raw32 =IOAM6_U32_UNAVAILABLE ;else - raw32 =__in6_dev_get (skb->dev)->cnf.ioam6_id_wide; + raw32 =READ_ONCE (i_skb_dev->cnf.ioam6_id_wide); *(__be32 *)data =cpu_to_be32 (raw32); data +=sizeof (__be32); -if (skb_dst (skb)->dev->flags &IFF_LOOPBACK ) +if ((dev->flags &IFF_LOOPBACK ) || !idev) raw32 =IOAM6_U32_UNAVAILABLE ;else - raw32 =__in6_dev_get (skb_dst (skb)->dev)->cnf.ioam6_id_wide; + raw32 =READ_ONCE (idev->cnf.ioam6_id_wide); *(__be32 *)data =cpu_to_be32 (raw32); data +=sizeof (__be32);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 983/1887 xfrm: account XFRMA_IF_ID in aevent size calculation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keenan Dong <[email protected]>
[ Upstream commit 7081d46d32312f1a31f0e0e99c6835a394037599 ]
xfrm_get_ae() allocates the reply skb with xfrm_aevent_msgsize(), then build_aevent() appends attributes including XFRMA_IF_ID when x->if_id is set.
xfrm_aevent_msgsize() does not include space for XFRMA_IF_ID. For states with if_id, build_aevent() can fail with -EMSGSIZE and hit BUG_ON(err < 0) in xfrm_get_ae(), turning a malformed netlink interaction into a kernel panic.
Account XFRMA_IF_ID in the size calculation unconditionally and replace the BUG_ON with normal error unwinding.
--- net/xfrm/xfrm_user.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/xfrm/xfrm_user.c +8 -2
@@ -2366,7 +2366,8 @@ static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x) +nla_total_size_64bit (sizeof (struct xfrm_lifetime_cur )) +nla_total_size (sizeof (struct xfrm_mark )) +nla_total_size (4 )/* XFRM_AE_RTHR */ - +nla_total_size (4 );/* XFRM_AE_ETHR */ + +nla_total_size (4 )/* XFRM_AE_ETHR */ + +nla_total_size (sizeof (x->if_id));/* XFRMA_IF_ID */ }static int build_aevent (struct sk_buff *skb,struct xfrm_state *x,const struct km_event *c)
@@ -2467,7 +2468,12 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, c.portid = nlh->nlmsg_pid; err =build_aevent (r_skb, x, &c); -BUG_ON (err <0 ); +if (err <0 ) { +spin_unlock_bh (&x->lock); +xfrm_state_put (x); +kfree_skb (r_skb); +return err; + } err =nlmsg_unicast (xfrm_net_nlsk (net, skb), r_skb,NETLINK_CB (skb).portid);spin_unlock_bh (&x->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 984/1887 btrfs: fix zero size inode with non-zero size after log replay
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 5254d4181add9dfaa5e3519edd71cc8f752b2f85 ]
When logging that an inode exists, as part of logging a new name or logging new dir entries for a directory, we always set the generation of the logged inode item to 0. This is to signal during log replay (in overwrite_item()), that we should not set the i_size since we only logged that an inode exists, so the i_size of the inode in the subvolume tree must be preserved (as when we log new names or that an inode exists, we don't log extents).
This works fine except when we have already logged an inode in full mode or it's the first time we are logging an inode created in a past transaction, that inode has a new i_size of 0 and then we log a new name for the inode (due to a new hardlink or a rename), in which case we log an i_size of 0 for the inode and a generation of 0, which causes the log replay code to not update the inode's i_size to 0 (in overwrite_item()).
An example scenario:
mkdir /mnt/dir
xfs_io -f -c "pwrite 0 64K" /mnt/dir/foo
sync
xfs_io -c "truncate 0" -c "fsync" /mnt/dir/foo
ln /mnt/dir/foo /mnt/dir/bar
xfs_io -c "fsync" /mnt/dir
<power fail>
After log replay the file remains with a size of 64K. This is because when we first log the inode, when we fsync file foo, we log its current i_size of 0, and then when we create a hard link we log again the inode in exists mode (LOG_INODE_EXISTS) but we set a generation of 0 for the inode item we add to the log tree, so during log replay overwrite_item() sees that the generation is 0 and i_size is 0 so we skip updating the inode's i_size from 64K to 0.
Fix this by making sure at fill_inode_item() we always log the real generation of the inode if it was logged in the current transaction with the i_size we logged before. Also if an inode created in a previous transaction is logged in exists mode only, make sure we log the i_size stored in the inode item located from the commit root, so that if we log multiple times that the inode exists we get the correct i_size.
A test case for fstests will follow soon.
--- fs/btrfs/tree-log.c | 99 +++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 34 deletions(-)
fs/btrfs/tree-log.c +65 -34
@@ -4200,24 +4200,34 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, u64 logged_isize) {struct btrfs_map_token token; +u64 gen =BTRFS_I (inode)->generation;u64 flags;btrfs_init_map_token (&token, leaf);if (log_inode_only) { -/* set the generation to zero so the recover code -* can tell the difference between an logging -* just to say 'this inode exists' and a logging -* to say 'update this inode with these values' +/* +* Set the generation to zero so the recover code can tell the +* difference between a logging just to say 'this inode exists' +* and a logging to say 'update this inode with these values'. +* But only if the inode was not already logged before. +* We access ->logged_trans directly since it was already set +* up in the call chain by btrfs_log_inode(), and data_race() +* to avoid false alerts from KCSAN and since it was set already +* and one can set it to 0 since that only happens on eviction +* and we are holding a ref on the inode. */ -btrfs_set_token_inode_generation (&token, item,0 ); +ASSERT (data_race (BTRFS_I (inode)->logged_trans) >0 ); +if (data_race (BTRFS_I (inode)->logged_trans) < trans->transid) + gen =0 ; +btrfs_set_token_inode_size (&token, item, logged_isize); }else { -btrfs_set_token_inode_generation (&token, item, -BTRFS_I (inode)->generation);btrfs_set_token_inode_size (&token, item, inode->i_size); } +btrfs_set_token_inode_generation (&token, item, gen); +btrfs_set_token_inode_uid (&token, item,i_uid_read (inode));btrfs_set_token_inode_gid (&token, item,i_gid_read (inode));btrfs_set_token_inode_mode (&token, item, inode->i_mode);
@@ -5033,42 +5043,63 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,return 0 ; } -static int logged_inode_size (struct btrfs_root *log,struct btrfs_inode *inode, -struct btrfs_path *path,u64 *size_ret) +static int get_inode_size_to_log (struct btrfs_trans_handle *trans, +struct btrfs_inode *inode, +struct btrfs_path *path,u64 *size_ret) {struct btrfs_key key; +struct btrfs_inode_item *item;int ret; key.objectid =btrfs_ino (inode); key.type =BTRFS_INODE_ITEM_KEY ; key.offset =0 ; - ret =btrfs_search_slot (NULL , log, &key, path,0 ,0 ); -if (ret <0 ) { -return ret; - }else if (ret >0 ) { - *size_ret =0 ; - }else { -struct btrfs_inode_item *item; +/* +* Our caller called inode_logged(), so logged_trans is up to date. +* Use data_race() to silence any warning from KCSAN. Once logged_trans +* is set, it can only be reset to 0 after inode eviction. +*/ +if (data_race (inode->logged_trans) == trans->transid) { + ret =btrfs_search_slot (NULL , inode->root->log_root, &key, path,0 ,0 ); + }else if (inode->generation < trans->transid) { + path->search_commit_root = true; + path->skip_locking = true; + ret =btrfs_search_slot (NULL , inode->root, &key, path,0 ,0 ); + path->search_commit_root = false; + path->skip_locking = false; - item =btrfs_item_ptr (path->nodes[0 ], path->slots[0 ], - struct btrfs_inode_item); - *size_ret =btrfs_inode_size (path->nodes[0 ], item); -/* -* If the in-memory inode's i_size is smaller then the inode -* size stored in the btree, return the inode's i_size, so -* that we get a correct inode size after replaying the log -* when before a power failure we had a shrinking truncate -* followed by addition of a new name (rename / new hard link). -* Otherwise return the inode size from the btree, to avoid -* data loss when replaying a log due to previously doing a -* write that expands the inode's size and logging a new name -* immediately after. -*/ -if (*size_ret > inode->vfs_inode.i_size) - *size_ret = inode->vfs_inode.i_size; + }else { + *size_ret =0 ; +return 0 ; } +/* +* If the inode was logged before or is from a past transaction, then +* its inode item must exist in the log root or in the commit root. +*/ +ASSERT (ret <=0 ); +if (WARN_ON_ONCE (ret >0 )) + ret = -ENOENT ; + +if (ret <0 ) +return ret; + + item =btrfs_item_ptr (path->nodes[0 ], path->slots[0 ], + struct btrfs_inode_item); + *size_ret =btrfs_inode_size (path->nodes[0 ], item); +/* +* If the in-memory inode's i_size is smaller then the inode size stored +* in the btree, return the inode's i_size, so that we get a correct +* inode size after replaying the log when before a power failure we had +* a shrinking truncate followed by addition of a new name (rename / new +* hard link). Otherwise return the inode size from the btree, to avoid +* data loss when replaying a log due to previously doing a write that +* expands the inode's size and logging a new name immediately after. +*/ +if (*size_ret > inode->vfs_inode.i_size) + *size_ret = inode->vfs_inode.i_size; +btrfs_release_path (path);return 0 ; }
@@ -6573,7 +6604,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ret =drop_inode_items (trans, log, path, inode,BTRFS_XATTR_ITEM_KEY ); }else { -if (inode_only ==LOG_INODE_EXISTS && ctx->logged_before) { +if (inode_only ==LOG_INODE_EXISTS ) {/* * Make sure the new inode item we write to the log has * the same isize as the current one (if it exists).
@@ -6587,7 +6618,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,* (zeroes), as if an expanding truncate happened, * instead of getting a file of 4Kb only. */ - ret =logged_inode_size (log, inode, path, &logged_isize); + ret =get_inode_size_to_log (trans, inode, path, &logged_isize);if (ret) goto out_unlock; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 985/1887 Bluetooth: hci_sync: annotate data-races around hdev->req_status
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit b6807cfc195ef99e1ac37b2e1e60df40295daa8c ]
__hci_cmd_sync_sk() sets hdev->req_status under hdev->req_lock:
hdev->req_status = HCI_REQ_PEND;
However, several other functions read or write hdev->req_status without holding any lock:
- hci_send_cmd_sync() reads req_status in hci_cmd_work (workqueue)
- hci_cmd_sync_complete() reads/writes from HCI event completion
- hci_cmd_sync_cancel() / hci_cmd_sync_cancel_sync() read/write
- hci_abort_conn() reads in connection abort path
Since __hci_cmd_sync_sk() runs on hdev->req_workqueue while hci_send_cmd_sync() runs on hdev->workqueue, these are different workqueues that can execute concurrently on different CPUs. The plain C accesses constitute a data race.
Add READ_ONCE()/WRITE_ONCE() annotations on all concurrent accesses to hdev->req_status to prevent potential compiler optimizations that could affect correctness (e.g., load fusing in the wait_event condition or store reordering).
--- net/bluetooth/hci_request.c | 2 +- net/bluetooth/hci_sync.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-)
net/bluetooth/hci_request.c +1 -1
@@ -46,7 +46,7 @@ void hci_req_purge(struct hci_request *req)bool hci_req_status_pend (struct hci_dev *hdev) { -return hdev->req_status ==HCI_REQ_PEND ; +return READ_ONCE (hdev->req_status) ==HCI_REQ_PEND ; } static int req_run(struct hci_request *req, hci_req_complete_t complete,
net/bluetooth/hci_sync.c +10 -10
@@ -24,11 +24,11 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, {bt_dev_dbg (hdev,"result 0x%2.2x" , result); -if (hdev->req_status !=HCI_REQ_PEND ) +if (READ_ONCE (hdev->req_status) !=HCI_REQ_PEND )return ; hdev->req_result = result; - hdev->req_status =HCI_REQ_DONE ; +WRITE_ONCE (hdev->req_status,HCI_REQ_DONE );if (skb) {struct sock *sk =hci_skb_sk (skb);
@@ -163,20 +163,20 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,hci_cmd_sync_add (&req, opcode, plen, param, event, sk); - hdev->req_status =HCI_REQ_PEND ; +WRITE_ONCE (hdev->req_status,HCI_REQ_PEND ); err =hci_req_sync_run (&req);if (err <0 )return ERR_PTR (err); err =wait_event_interruptible_timeout (hdev->req_wait_q, - hdev->req_status !=HCI_REQ_PEND , +READ_ONCE (hdev->req_status) !=HCI_REQ_PEND , timeout);if (err == -ERESTARTSYS )return ERR_PTR (-EINTR ); -switch (hdev->req_status) { +switch (READ_ONCE (hdev->req_status)) {case HCI_REQ_DONE : err = -bt_to_errno (hdev->req_result);break ;
@@ -190,7 +190,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,break ; } - hdev->req_status =0 ; +WRITE_ONCE (hdev->req_status,0 ); hdev->req_result =0 ; skb = hdev->req_skb; hdev->req_skb =NULL ;
@@ -696,9 +696,9 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err) {bt_dev_dbg (hdev,"err 0x%2.2x" , err); -if (hdev->req_status ==HCI_REQ_PEND ) { +if (READ_ONCE (hdev->req_status) ==HCI_REQ_PEND ) { hdev->req_result = err; - hdev->req_status =HCI_REQ_CANCELED ; +WRITE_ONCE (hdev->req_status,HCI_REQ_CANCELED );queue_work (hdev->workqueue, &hdev->cmd_sync_cancel_work); }
@@ -714,12 +714,12 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err) {bt_dev_dbg (hdev,"err 0x%2.2x" , err); -if (hdev->req_status ==HCI_REQ_PEND ) { +if (READ_ONCE (hdev->req_status) ==HCI_REQ_PEND ) {/* req_result is __u32 so error must be positive to be properly * propagated. */ hdev->req_result = err <0 ? -err : err; - hdev->req_status =HCI_REQ_CANCELED ; +WRITE_ONCE (hdev->req_status,HCI_REQ_CANCELED );wake_up_interruptible (&hdev->req_wait_q); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 986/1887 ALSA: mixer: oss: Add card disconnect checkpoints
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit 084d5d44418148662365eced3e126ad1a81ee3e2 ]
ALSA OSS mixer layer calls the kcontrol ops rather individually, and pending calls might be not always caught at disconnecting the device.
For avoiding the potential UAF scenarios, add sanity checks of the card disconnection at each entry point of OSS mixer accesses. The rwsem is taken just before that check, hence the rest context should be covered by that properly.
--- sound/core/oss/mixer_oss.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
sound/core/oss/mixer_oss.c +32 -0
@@ -540,6 +540,10 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,if (numid ==ID_UNKNOWN )return ;down_read (&card->controls_rwsem); +if (card->shutdown) { +up_read (&card->controls_rwsem); +return ; + } kctl =snd_ctl_find_numid_locked (card, numid);if (!kctl) {up_read (&card->controls_rwsem);
@@ -579,6 +583,10 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,if (numid ==ID_UNKNOWN )return ;down_read (&card->controls_rwsem); +if (card->shutdown) { +up_read (&card->controls_rwsem); +return ; + } kctl =snd_ctl_find_numid_locked (card, numid);if (!kctl) {up_read (&card->controls_rwsem);
@@ -645,6 +653,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,if (numid ==ID_UNKNOWN )return ;down_read (&card->controls_rwsem); +if (card->shutdown) { +up_read (&card->controls_rwsem); +return ; + } kctl =snd_ctl_find_numid_locked (card, numid);if (!kctl) {up_read (&card->controls_rwsem);
@@ -688,6 +700,10 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,if (numid ==ID_UNKNOWN )return ;down_read (&card->controls_rwsem); +if (card->shutdown) { +up_read (&card->controls_rwsem); +return ; + } kctl =snd_ctl_find_numid_locked (card, numid);if (!kctl) {up_read (&card->controls_rwsem);
@@ -833,6 +849,10 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned goto __free_only; }down_read (&card->controls_rwsem); +if (card->shutdown) { + err = -ENODEV ; + goto __unlock; + } kctl =snd_mixer_oss_test_id (mixer,"Capture Source" ,0 );if (! kctl) { err = -ENOENT ;
@@ -886,6 +906,10 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned goto __free_only; }down_read (&card->controls_rwsem); +if (card->shutdown) { + err = -ENODEV ; + goto __unlock; + } kctl =snd_mixer_oss_test_id (mixer,"Capture Source" ,0 );if (! kctl) { err = -ENOENT ;
@@ -937,6 +961,10 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slint err;down_read (&card->controls_rwsem); +if (card->shutdown) { +up_read (&card->controls_rwsem); +return -ENODEV ; + } kcontrol =snd_mixer_oss_test_id (mixer, name, index);if (kcontrol ==NULL ) {up_read (&card->controls_rwsem);
@@ -1069,6 +1097,10 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,if (snd_mixer_oss_build_test_all (mixer, ptr, &slot))return 0 ;down_read (&mixer->card->controls_rwsem); +if (mixer->card->shutdown) { +up_read (&mixer->card->controls_rwsem); +return -ENODEV ; + } kctl =NULL ;if (!ptr->index) kctl =snd_mixer_oss_test_id (mixer,"Capture Source" ,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 987/1887 ima: verify the previous kernels IMA buffer lies in addressable RAM
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harshit Mogalapalli <[email protected]>
[ Upstream commit 10d1c75ed4382a8e79874379caa2ead8952734f9 ]
Patch series "Address page fault in ima_restore_measurement_list()", v3.
When the second-stage kernel is booted via kexec with a limiting command line such as "mem=<size>" we observe a pafe fault that happens.
BUG: unable to handle page fault for address: ffff97793ff47000
RIP: ima_restore_measurement_list+0xdc/0x45a
#PF: error_code(0x0000) not-present pageThis happens on x86_64 only, as this is already fixed in aarch64 in
commit: cbf9c4b9617b ("of: check previous kernel's ima-kexec-buffer against memory bounds")
This patch (of 3):
When the second-stage kernel is booted with a limiting command line (e.g. "mem=<size>"), the IMA measurement buffer handed over from the previous kernel may fall outside the addressable RAM of the new kernel. Accessing such a buffer can fault during early restore.
Introduce a small generic helper, ima_validate_range(), which verifies that a physical [start, end] range for the previous-kernel IMA buffer lies within addressable memory:
- On x86, use pfn_range_is_mapped().
- On OF based architectures, use page_is_ram().
--- include/linux/ima.h | 1 + security/integrity/ima/ima_kexec.c | 35 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
include/linux/ima.h +1 -0
@@ -145,6 +145,7 @@ static inline int ima_measure_critical_data(const char *event_label,#ifdef CONFIG_HAVE_IMA_KEXEC int __init ima_free_kexec_buffer (void );int __init ima_get_kexec_buffer (void **addr,size_t *size); +int ima_validate_range (phys_addr_t phys,size_t size);#endif #ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
security/integrity/ima/ima_kexec.c +35 -0
@@ -12,6 +12,8 @@#include <linux/kexec.h> #include <linux/of.h> #include <linux/ima.h> +#include <linux/mm.h> +#include <linux/overflow.h> #include "ima.h" #ifdef CONFIG_IMA_KEXEC
@@ -164,3 +166,36 @@ void __init ima_load_kexec_buffer(void)pr_debug ("Error restoring the measurement list: %d\n" , rc); } } + +/* +* ima_validate_range - verify a physical buffer lies in addressable RAM +* @phys: physical start address of the buffer from previous kernel +* @size: size of the buffer +* +* On success return 0. On failure returns -EINVAL so callers can skip +* restoring. +*/ +int ima_validate_range (phys_addr_t phys,size_t size) +{ +unsigned long start_pfn, end_pfn; +phys_addr_t end_phys; + +if (check_add_overflow (phys, (phys_addr_t )size -1 , &end_phys)) +return -EINVAL ; + + start_pfn =PHYS_PFN (phys); + end_pfn =PHYS_PFN (end_phys); + +#ifdef CONFIG_X86 +if (!pfn_range_is_mapped (start_pfn, end_pfn)) +#else + if (!page_is_ram(start_pfn) || !page_is_ram(end_pfn)) +#endif + { +pr_warn ("IMA: previous kernel measurement buffer %pa (size 0x%zx) lies outside available memory\n" , + &phys, size); +return -EINVAL ; + } + +return 0 ; +}
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 988/1887 xfs: remove xfs_attr_leaf_hasname
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
[ Upstream commit 3a65ea768b8094e4699e72f9ab420eb9e0f3f568 ]
The calling convention of xfs_attr_leaf_hasname() is problematic, because it returns a NULL buffer when xfs_attr3_leaf_read fails, a valid buffer when xfs_attr3_leaf_lookup_int returns -ENOATTR or -EEXIST, and a non-NULL buffer pointer for an already released buffer when xfs_attr3_leaf_lookup_int fails with other error values.
Fix this by simply open coding xfs_attr_leaf_hasname in the callers, so that the buffer release code is done by each caller of xfs_attr3_leaf_read.
--- fs/xfs/libxfs/xfs_attr.c | 74 +++++++++++++--------------------------- 1 file changed, 23 insertions(+), 51 deletions(-)
fs/xfs/libxfs/xfs_attr.c +23 -51
@@ -49,7 +49,6 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);*/ STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); -STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp); STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args);/*
@@ -866,11 +865,11 @@ xfs_attr_lookup(return xfs_attr_sf_findname (args,NULL ,NULL );if (xfs_attr_is_leaf (dp)) { - error =xfs_attr_leaf_hasname (args, &bp); - -if (bp) -xfs_trans_brelse (args->trans, bp); - + error =xfs_attr3_leaf_read (args->trans, args->dp,0 , &bp); +if (error) +return error; + error =xfs_attr3_leaf_lookup_int (bp, args); +xfs_trans_brelse (args->trans, bp);return error; }
@@ -1246,27 +1245,6 @@ xfs_attr_leaf_try_add(return error; } -/* -* Return EEXIST if attr is found, or ENOATTR if not -*/ -STATIC int -xfs_attr_leaf_hasname ( -struct xfs_da_args *args, -struct xfs_buf **bp) -{ -int error =0 ; - - error =xfs_attr3_leaf_read (args->trans, args->dp,0 , bp); -if (error) -return error; - - error =xfs_attr3_leaf_lookup_int (*bp, args); -if (error != -ENOATTR && error != -EEXIST ) -xfs_trans_brelse (args->trans, *bp); - -return error; -} -/* * Remove a name from the leaf attribute list structure *
@@ -1277,25 +1255,22 @@ STATIC intxfs_attr_leaf_removename ( struct xfs_da_args *args) { -struct xfs_inode *dp; -struct xfs_buf *bp; +struct xfs_inode *dp = args->dp;int error, forkoff; +struct xfs_buf *bp;trace_xfs_attr_leaf_removename (args); -/* -* Remove the attribute. -*/ - dp = args->dp; - - error =xfs_attr_leaf_hasname (args, &bp); -if (error == -ENOATTR ) { + error =xfs_attr3_leaf_read (args->trans, args->dp,0 , &bp); +if (error) +return error; + error =xfs_attr3_leaf_lookup_int (bp, args); +if (error != -EEXIST ) {xfs_trans_brelse (args->trans, bp); -if (args->op_flags &XFS_DA_OP_RECOVERY ) +if (error == -ENOATTR && (args->op_flags &XFS_DA_OP_RECOVERY ))return 0 ;return error; - }else if (error != -EEXIST ) -return error; + }xfs_attr3_leaf_remove (bp, args);
@@ -1319,23 +1294,20 @@ xfs_attr_leaf_removename(* Returns 0 on successful retrieval, otherwise an error. */ STATIC int -xfs_attr_leaf_get (xfs_da_args_t *args) +xfs_attr_leaf_get ( +struct xfs_da_args *args) { -struct xfs_buf *bp; -int error; +struct xfs_buf *bp; +int error;trace_xfs_attr_leaf_get (args); - error =xfs_attr_leaf_hasname (args, &bp); - -if (error == -ENOATTR ) { -xfs_trans_brelse (args->trans, bp); -return error; - }else if (error != -EEXIST ) + error =xfs_attr3_leaf_read (args->trans, args->dp,0 , &bp); +if (error)return error; - - - error =xfs_attr3_leaf_getvalue (bp, args); + error =xfs_attr3_leaf_lookup_int (bp, args); +if (error == -EEXIST ) + error =xfs_attr3_leaf_getvalue (bp, args);xfs_trans_brelse (args->trans, bp);return error; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 989/1887 xfrm: always flush state and policy upon NETDEV_UNREGISTER event
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
[ Upstream commit 4efa91a28576054aae0e6dad9cba8fed8293aef8 ]
syzbot is reporting that "struct xfrm_state" refcount is leaking.
unregister_netdevice: waiting for netdevsim0 to become free. Usage count = 2
ref_tracker: netdev@ffff888052f24618 has 1/1 users at
__netdev_tracker_alloc include/linux/netdevice.h:4400 [inline]
netdev_tracker_alloc include/linux/netdevice.h:4412 [inline]
xfrm_dev_state_add+0x3a5/0x1080 net/xfrm/xfrm_device.c:316
xfrm_state_construct net/xfrm/xfrm_user.c:986 [inline]
xfrm_add_sa+0x34ff/0x5fa0 net/xfrm/xfrm_user.c:1022
xfrm_user_rcv_msg+0x58e/0xc00 net/xfrm/xfrm_user.c:3507
netlink_rcv_skb+0x158/0x420 net/netlink/af_netlink.c:2550
xfrm_netlink_rcv+0x71/0x90 net/xfrm/xfrm_user.c:3529
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x5aa/0x870 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x8c8/0xdd0 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:727 [inline]
__sock_sendmsg net/socket.c:742 [inline]
____sys_sendmsg+0xa5d/0xc30 net/socket.c:2592
___sys_sendmsg+0x134/0x1d0 net/socket.c:2646
__sys_sendmsg+0x16d/0x220 net/socket.c:2678
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7fThis is because commit d77e38e612a0 ("xfrm: Add an IPsec hardware offloading API") implemented xfrm_dev_unregister() as no-op despite xfrm_dev_state_add() from xfrm_state_construct() acquires a reference to "struct net_device".
I guess that that commit expected that NETDEV_DOWN event is fired before NETDEV_UNREGISTER event fires, and also assumed that xfrm_dev_state_add() is called only if (dev->features & NETIF_F_HW_ESP) != 0.
Sabrina Dubroca identified steps to reproduce the same symptoms as below.
echo 0 > /sys/bus/netdevsim/new_device
dev=$(ls -1 /sys/bus/netdevsim/devices/netdevsim0/net/)
ip xfrm state add src 192.168.13.1 dst 192.168.13.2 proto esp \
spi 0x1000 mode tunnel aead 'rfc4106(gcm(aes))' $key 128 \
offload crypto dev $dev dir out
ethtool -K $dev esp-hw-offload off
echo 0 > /sys/bus/netdevsim/del_deviceLike these steps indicate, the NETIF_F_HW_ESP bit can be cleared after xfrm_dev_state_add() acquired a reference to "struct net_device". Also, xfrm_dev_state_add() does not check for the NETIF_F_HW_ESP bit when acquiring a reference to "struct net_device".
Commit 03891f820c21 ("xfrm: handle NETDEV_UNREGISTER for xfrm device") re-introduced the NETDEV_UNREGISTER event to xfrm_dev_event(), but that commit for unknown reason chose to share xfrm_dev_down() between the NETDEV_DOWN event and the NETDEV_UNREGISTER event.
I guess that that commit missed the behavior in the previous paragraph.
Therefore, we need to re-introduce xfrm_dev_unregister() in order to release the reference to "struct net_device" by unconditionally flushing state and policy.
--- net/xfrm/xfrm_device.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
net/xfrm/xfrm_device.c +10 -1
@@ -424,6 +424,13 @@ static int xfrm_dev_down(struct net_device *dev)return NOTIFY_DONE ; } +static int xfrm_dev_unregister (struct net_device *dev) +{ +xfrm_dev_state_flush (dev_net (dev), dev, true); + +return NOTIFY_DONE ; +} +static int xfrm_dev_event (struct notifier_block *this,unsigned long event,void *ptr) {struct net_device *dev =netdev_notifier_info_to_dev (ptr);
@@ -436,8 +443,10 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, voidreturn xfrm_api_check (dev);case NETDEV_DOWN : -case NETDEV_UNREGISTER :return xfrm_dev_down (dev); + +case NETDEV_UNREGISTER : +return xfrm_dev_unregister (dev); }return NOTIFY_DONE ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 990/1887 usb: dwc3: gadget: Move vbus draw to workqueue context
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prashanth K <[email protected]>
[ Upstream commit 54aaa3b387c2f580a99dc86a9cc2eb6dfaf599a7 ]
Currently dwc3_gadget_vbus_draw() can be called from atomic context, which in turn invokes power-supply-core APIs. And some these PMIC APIs have operations that may sleep, leading to kernel panic.
Fix this by moving the vbus_draw into a workqueue context.
--- drivers/usb/dwc3/core.c | 19 ++++++++++++++++++- drivers/usb/dwc3/core.h | 4 ++++ drivers/usb/dwc3/gadget.c | 8 +++----- 3 files changed, 25 insertions(+), 6 deletions(-)
drivers/usb/dwc3/core.c +18 -1
@@ -1855,6 +1855,20 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)return edev; } +static void dwc3_vbus_draw_work (struct work_struct *work) +{ + struct dwc3 *dwc = container_of(work, struct dwc3, vbus_draw_work); +union power_supply_propval val = {0 }; +int ret; + + val.intval =1000 * (dwc->current_limit); + ret =power_supply_set_property (dwc->usb_psy,POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT , &val); + +if (ret <0 ) +dev_dbg (dwc->dev,"Error (%d) setting vbus draw (%d mA)\n" , + ret, dwc->current_limit); +} +static struct power_supply *dwc3_get_usb_power_supply (struct dwc3 *dwc) {struct power_supply *usb_psy;
@@ -1869,6 +1883,7 @@ static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)if (!usb_psy)return ERR_PTR (-EPROBE_DEFER ); +INIT_WORK (&dwc->vbus_draw_work, dwc3_vbus_draw_work);return usb_psy; }
@@ -2120,8 +2135,10 @@ static int dwc3_remove(struct platform_device *pdev)dwc3_free_event_buffers (dwc);dwc3_free_scratch_buffers (dwc); -if (dwc->usb_psy) +if (dwc->usb_psy) { +cancel_work_sync (&dwc->vbus_draw_work);power_supply_put (dwc->usb_psy); + }return 0 ; }
drivers/usb/dwc3/core.h +4 -0
@@ -1035,6 +1035,8 @@ struct dwc3_scratchpad_array {* @role_switch_default_mode: default operation mode of controller while * usb role is USB_ROLE_NONE. * @usb_psy: pointer to power supply interface. +* @vbus_draw_work: Work to set the vbus drawing limit +* @current_limit: How much current to draw from vbus, in milliAmperes. * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY
@@ -1207,6 +1209,8 @@ struct dwc3 {enum usb_dr_mode role_switch_default_mode;struct power_supply *usb_psy; +struct work_struct vbus_draw_work; +unsigned int current_limit;u32 fladj;u32 ref_clk_per;
drivers/usb/dwc3/gadget.c +3 -5
@@ -3019,8 +3019,6 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,static int dwc3_gadget_vbus_draw (struct usb_gadget *g,unsigned int mA) {struct dwc3 *dwc =gadget_to_dwc (g); -union power_supply_propval val = {0 }; -int ret;if (dwc->usb2_phy)return usb_phy_set_power (dwc->usb2_phy, mA);
@@ -3028,10 +3026,10 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)if (!dwc->usb_psy)return -EOPNOTSUPP ; - val.intval =1000 * mA; - ret =power_supply_set_property (dwc->usb_psy,POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT , &val); + dwc->current_limit = mA; +schedule_work (&dwc->vbus_draw_work); -return ret; +return 0 ; }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 991/1887 ksmbd: fix signededness bug in smb_direct_prepare_negotiation()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Carlini <[email protected]>
[ Upstream commit 6b4f875aac344cdd52a1f34cc70ed2f874a65757 ]
smb_direct_prepare_negotiation() casts an unsigned __u32 value from sp->max_recv_size and req->preferred_send_size to a signed int before computing min_t(int, ...). A maliciously provided preferred_send_size of 0x80000000 will return as smaller than max_recv_size, and then be used to set the maximum allowed alowed receive size for the next message.
By sending a second message with a large value (>1420 bytes) the attacker can then achieve a heap buffer overflow.
This fix replaces min_t(int, ...) with min_t(u32)
--- fs/smb/server/transport_rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/transport_rdma.c +2 -2
@@ -1967,9 +1967,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t) goto out; req = (struct smb_direct_negotiate_req *)recvmsg->packet; - st->max_recv_size =min_t (int, st->max_recv_size, + st->max_recv_size =min_t (u32, st->max_recv_size,le32_to_cpu (req->preferred_send_size)); - st->max_send_size =min_t (int, st->max_send_size, + st->max_send_size =min_t (u32, st->max_send_size,le32_to_cpu (req->max_receive_size)); st->max_fragmented_send_size =le32_to_cpu (req->max_fragmented_size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 992/1887 ASoC: qcom: q6asm: handle the responses after closing
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
[ Upstream commit a354f030dbce17ab3cf299660a38b162d97f7151 ]
For record path, multiple read requests are queued to dsp in advance. However when data stream is closed, the pending read requests are rejected by the dsp and a response is sent to the driver, this case is not handled in the driver resulting in errors like below
q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp
This is same for both write and eos.
Fix this by allowing ASM_DATA_CMD_READ_V2, ASM_DATA_CMD_EOS and ASM_DATA_CMD_WRITE_V2 as expected response.
Stable-dep-of: 8a066a81ee0c ("ASoC: qcom: q6asm: drop DSP responses for closed data streams")
--- sound/soc/qcom/qdsp6/q6asm.c | 5 +++++ 1 file changed, 5 insertions(+)
sound/soc/qcom/qdsp6/q6asm.c +5 -0
@@ -637,6 +637,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, client_event =ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE ;break ;case ASM_STREAM_CMD_OPEN_WRITE_V3 : +case ASM_DATA_CMD_WRITE_V2 :case ASM_STREAM_CMD_OPEN_READ_V3 :case ASM_STREAM_CMD_OPEN_READWRITE_V2 :case ASM_STREAM_CMD_SET_ENCDEC_PARAM :
@@ -653,6 +654,10 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, goto done; }break ; +case ASM_DATA_CMD_EOS : +case ASM_DATA_CMD_READ_V2 : +/* response as result of close stream */ +break ;default :dev_err (ac->dev,"command[0x%x] not expecting rsp\n" , result->opcode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 993/1887 ASoC: qcom: q6asm: drop DSP responses for closed data streams
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cédric Bellegarde <[email protected]>
[ Upstream commit 8a066a81ee0c1b6cdbd81393536c3b2d19ccef25 ]
'Commit a354f030dbce ("ASoC: qcom: q6asm: handle the responses after closing")' attempted to ignore DSP responses arriving after a stream had been closed.
However, those responses were still handled, causing lockups.
Fix this by unconditionally dropping all DSP responses associated with closed data streams.
--- sound/soc/qcom/qdsp6/q6asm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/qcom/qdsp6/q6asm.c +2 -2
@@ -637,7 +637,6 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, client_event =ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE ;break ;case ASM_STREAM_CMD_OPEN_WRITE_V3 : -case ASM_DATA_CMD_WRITE_V2 :case ASM_STREAM_CMD_OPEN_READ_V3 :case ASM_STREAM_CMD_OPEN_READWRITE_V2 :case ASM_STREAM_CMD_SET_ENCDEC_PARAM :
@@ -656,8 +655,9 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,break ;case ASM_DATA_CMD_EOS :case ASM_DATA_CMD_READ_V2 : +case ASM_DATA_CMD_WRITE_V2 :/* response as result of close stream */ -break ; + goto done;default :dev_err (ac->dev,"command[0x%x] not expecting rsp\n" , result->opcode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 994/1887 wifi: rtw89: pci: validate sequence number of TX release report
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <[email protected]>
[ Upstream commit 957eda596c7665f2966970fd1dcc35fe299b38e8 ]
Hardware rarely reports abnormal sequence number in TX release report, which will access out-of-bounds of wd_ring->pages array, causing NULL pointer dereference.
BUG: kernel NULL pointer dereference, address: 0000000000000000
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 1 PID: 1085 Comm: irq/129-rtw89_p Tainted: G S U
6.1.145-17510-g2f3369c91536 #1 (HASH:69e8 1)
Call Trace:
<IRQ>
rtw89_pci_release_tx+0x18f/0x300 [rtw89_pci (HASH:4c83 2)]
rtw89_pci_napi_poll+0xc2/0x190 [rtw89_pci (HASH:4c83 2)]
net_rx_action+0xfc/0x460 net/core/dev.c:6578 net/core/dev.c:6645 net/core/dev.c:6759
handle_softirqs+0xbe/0x290 kernel/softirq.c:601
? rtw89_pci_interrupt_threadfn+0xc5/0x350 [rtw89_pci (HASH:4c83 2)]
__local_bh_enable_ip+0xeb/0x120 kernel/softirq.c:499 kernel/softirq.c:423
</IRQ>
<TASK>
rtw89_pci_interrupt_threadfn+0xf8/0x350 [rtw89_pci (HASH:4c83 2)]
? irq_thread+0xa7/0x340 kernel/irq/manage.c:0
irq_thread+0x177/0x340 kernel/irq/manage.c:1205 kernel/irq/manage.c:1314
? thaw_kernel_threads+0xb0/0xb0 kernel/irq/manage.c:1202
? irq_forced_thread_fn+0x80/0x80 kernel/irq/manage.c:1220
kthread+0xea/0x110 kernel/kthread.c:376
? synchronize_irq+0x1a0/0x1a0 kernel/irq/manage.c:1287
? kthread_associate_blkcg+0x80/0x80 kernel/kthread.c:331
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
</TASK>To prevent crash, validate rpp_info.seq before using.
--- drivers/net/wireless/realtek/rtw89/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw89/pci.c +6 -1
@@ -472,11 +472,16 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, tx_status =le32_get_bits (rpp->dword,RTW89_PCI_RPP_TX_STATUS ); txch =rtw89_core_get_ch_dma (rtwdev, qsel); -if (txch ==RTW89_TXCH_CH12 ) { +if (unlikely (txch ==RTW89_TXCH_CH12 )) {rtw89_warn (rtwdev,"should no fwcmd release report\n" );return ; } +if (unlikely (seq >=RTW89_PCI_TXWD_NUM_MAX )) { +rtw89_warn (rtwdev,"invalid seq %d\n" , seq); +return ; + } + tx_ring = &rtwpci->tx_rings[txch]; wd_ring = &tx_ring->wd_ring; txwd = &wd_ring->pages[seq];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 995/1887 cifs: Fix locking usage for tcon fields
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shyam Prasad N <[email protected]>
[ Upstream commit 96c4af418586ee9a6aab61738644366426e05316 ]
We used to use the cifs_tcp_ses_lock to protect a lot of objects that are not just the server, ses or tcon lists. We later introduced srv_lock, ses_lock and tc_lock to protect fields within the corresponding structs. This was done to provide a more granular protection and avoid unnecessary serialization.
There were still a couple of uses of cifs_tcp_ses_lock to provide tcon fields. In this patch, I've replaced them with tc_lock.
--- fs/smb/client/smb2misc.c | 6 +++--- fs/smb/client/smb2ops.c | 10 +++------- fs/smb/client/smb2pdu.c | 2 ++ 3 files changed, 8 insertions(+), 10 deletions(-)
fs/smb/client/smb2misc.c +3 -3
@@ -847,14 +847,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,int rc;cifs_dbg (FYI ,"%s: tc_count=%d\n" , __func__, tcon->tc_count); -spin_lock (&cifs_tcp_ses_lock); +spin_lock (&tcon->tc_lock);if (tcon->tc_count <=0 ) {struct TCP_Server_Info *server =NULL ;trace_smb3_tcon_ref (tcon->debug_id, tcon->tc_count, netfs_trace_tcon_ref_see_cancelled_close);WARN_ONCE (tcon->tc_count <0 ,"tcon refcount is negative" ); -spin_unlock (&cifs_tcp_ses_lock); +spin_unlock (&tcon->tc_lock);if (tcon->ses) { server = tcon->ses->server;
@@ -868,7 +868,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, tcon->tc_count++;trace_smb3_tcon_ref (tcon->debug_id, tcon->tc_count, netfs_trace_tcon_ref_get_cancelled_close); -spin_unlock (&cifs_tcp_ses_lock); +spin_unlock (&tcon->tc_lock); rc =__smb2_handle_cancelled_cmd (tcon,SMB2_CLOSE_HE ,0 , persistent_fid, volatile_fid, false);
fs/smb/client/smb2ops.c +3 -7
@@ -2863,7 +2863,9 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, struct cifs_tcon, tcon_list);if (tcon) { +spin_lock (&tcon->tc_lock); tcon->tc_count++; +spin_unlock (&tcon->tc_lock);trace_smb3_tcon_ref (tcon->debug_id, tcon->tc_count, netfs_trace_tcon_ref_get_dfs_refer); }
@@ -2928,13 +2930,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, out:if (tcon && !tcon->ipc) {/* ipc tcons are not refcounted */ -spin_lock (&cifs_tcp_ses_lock); - tcon->tc_count--; -trace_smb3_tcon_ref (tcon->debug_id, tcon->tc_count, - netfs_trace_tcon_ref_dec_dfs_refer); -/* tc_count can never go negative */ -WARN_ON (tcon->tc_count <0 ); -spin_unlock (&cifs_tcp_ses_lock); +cifs_put_tcon (tcon, netfs_trace_tcon_ref_put_dfs_refer); }kfree (utf16_path);kfree (dfs_req);
fs/smb/client/smb2pdu.c +2 -0
@@ -4025,7 +4025,9 @@ void smb2_reconnect_server(struct work_struct *work)list_for_each_entry (tcon, &ses->tcon_list, tcon_list) {if (tcon->need_reconnect || tcon->need_reopen_files) { +spin_lock (&tcon->tc_lock); tcon->tc_count++; +spin_unlock (&tcon->tc_lock);trace_smb3_tcon_ref (tcon->debug_id, tcon->tc_count, netfs_trace_tcon_ref_get_reconnect_server);list_add_tail (&tcon->rlist, &tmp_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 996/1887 team: avoid NETDEV_CHANGEMTU event when unregistering slave
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
[ Upstream commit bb4c698633c0e19717586a6524a33196cff01a32 ]
syzbot is reporting
unregister_netdevice: waiting for netdevsim0 to become free. Usage count = 3
ref_tracker: netdev@ffff88807dcf8618 has 1/2 users at
__netdev_tracker_alloc include/linux/netdevice.h:4400 [inline]
netdev_hold include/linux/netdevice.h:4429 [inline]
inetdev_init+0x201/0x4e0 net/ipv4/devinet.c:286
inetdev_event+0x251/0x1610 net/ipv4/devinet.c:1600
notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85
call_netdevice_notifiers_mtu net/core/dev.c:2318 [inline]
netif_set_mtu_ext+0x5aa/0x800 net/core/dev.c:9886
netif_set_mtu+0xd7/0x1b0 net/core/dev.c:9907
dev_set_mtu+0x126/0x260 net/core/dev_api.c:248
team_port_del+0xb07/0xcb0 drivers/net/team/team_core.c:1333
team_del_slave drivers/net/team/team_core.c:1936 [inline]
team_device_event+0x207/0x5b0 drivers/net/team/team_core.c:2929
notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85
call_netdevice_notifiers_extack net/core/dev.c:2281 [inline]
call_netdevice_notifiers net/core/dev.c:2295 [inline]
__dev_change_net_namespace+0xcb7/0x2050 net/core/dev.c:12592
do_setlink+0x2ce/0x4590 net/core/rtnetlink.c:3060
rtnl_changelink net/core/rtnetlink.c:3776 [inline]
__rtnl_newlink net/core/rtnetlink.c:3935 [inline]
rtnl_newlink+0x15a9/0x1be0 net/core/rtnetlink.c:4072
rtnetlink_rcv_msg+0x7d5/0xbe0 net/core/rtnetlink.c:6958
netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894problem. Ido Schimmel found steps to reproduce
ip link add name team1 type team
ip link add name dummy1 mtu 1499 master team1 type dummy ip netns add ns1
ip link set dev dummy1 netns ns1
ip -n ns1 link del dev dummy1
and also found that the same issue was fixed in the bond driver in commit f51048c3e07b ("bonding: avoid NETDEV_CHANGEMTU event when unregistering slave").
Let's do similar thing for the team driver, with commit ad7c7b2172c3 ("net:
hold netdev instance lock during sysfs operations") and commit 303a8487a657 ("net: s/__dev_set_mtu/__netif_set_mtu/") also applied.
--- drivers/net/team/team.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/net/team/team.c +15 -6
@@ -1361,7 +1361,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev,static void __team_port_change_port_removed (struct team_port *port); -static int team_port_del (struct team *team,struct net_device *port_dev) +static int team_port_del (struct team *team,struct net_device *port_dev,bool unregister) {struct net_device *dev = team->dev;struct team_port *port;
@@ -1399,7 +1399,10 @@ static int team_port_del(struct team *team, struct net_device *port_dev)__team_port_change_port_removed (port);team_port_set_orig_dev_addr (port); -dev_set_mtu (port_dev, port->orig.mtu); +if (unregister) +__dev_set_mtu (port_dev, port->orig.mtu); +else +dev_set_mtu (port_dev, port->orig.mtu);kfree_rcu (port, rcu);netdev_info (dev,"Port device %s removed\n" , portname);__team_compute_features (team);
@@ -1714,7 +1717,7 @@ static void team_uninit(struct net_device *dev)mutex_lock (&team->lock);list_for_each_entry_safe (port, tmp, &team->port_list, list) -team_port_del (team, port->dev); +team_port_del (team, port->dev, false);__team_change_mode (team,NULL );/* cleanup */ __team_options_unregister (team, team_options,ARRAY_SIZE (team_options));
@@ -2025,13 +2028,14 @@ static int team_add_slave(struct net_device *dev, struct net_device *port_dev,return err; } -static int team_del_slave (struct net_device *dev,struct net_device *port_dev) +static int __team_del_slave (struct net_device *dev,struct net_device *port_dev, +bool unregister) {struct team *team =netdev_priv (dev);int err;mutex_lock (&team->lock); - err =team_port_del (team, port_dev); + err =team_port_del (team, port_dev, unregister);mutex_unlock (&team->lock);if (err)
@@ -2047,6 +2051,11 @@ static int team_del_slave(struct net_device *dev, struct net_device *port_dev)return err; } +static int team_del_slave (struct net_device *dev,struct net_device *port_dev) +{ +return __team_del_slave (dev, port_dev, false); +} +static netdev_features_t team_fix_features (struct net_device *dev,netdev_features_t features) {
@@ -3146,7 +3155,7 @@ static int team_device_event(struct notifier_block *unused, !!netif_oper_up(port->dev));break ;case NETDEV_UNREGISTER : -team_del_slave (port->team->dev, dev); +__team_del_slave (port->team->dev, dev, true);break ;case NETDEV_FEAT_CHANGE :if (!port->team->notifier_ctx) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 997/1887 smb: client: prevent races in ->query_interfaces()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrique Carvalho <[email protected]>
[ Upstream commit c3c06e42e1527716c54f3ad2ced6a034b5f3a489 ]
It was possible for two query interface works to be concurrently trying to update the interfaces.
Prevent this by checking and updating iface_last_update under iface_lock.
--- fs/smb/client/smb2ops.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
fs/smb/client/smb2ops.c +8 -9
@@ -590,13 +590,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, p = buf;spin_lock (&ses->iface_lock); -/* do not query too frequently, this time with lock held */ -if (ses->iface_last_update && -time_before (jiffies, ses->iface_last_update + - (SMB_INTERFACE_POLL_INTERVAL *HZ ))) { -spin_unlock (&ses->iface_lock); -return 0 ; - }/* * Go through iface_list and mark them as inactive
@@ -727,7 +720,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ses->iface_count++;spin_unlock (&ses->iface_lock); - ses->iface_last_update = jiffies; next_iface: nb_iface++; next =le32_to_cpu (p->Next);
@@ -792,10 +784,17 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_struct TCP_Server_Info *pserver;/* do not query too frequently */ +spin_lock (&ses->iface_lock);if (ses->iface_last_update &&time_before (jiffies, ses->iface_last_update + - (SMB_INTERFACE_POLL_INTERVAL *HZ ))) + (SMB_INTERFACE_POLL_INTERVAL *HZ ))) { +spin_unlock (&ses->iface_lock);return 0 ; + } + + ses->iface_last_update = jiffies; + +spin_unlock (&ses->iface_lock); rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_QUERY_NETWORK_INTERFACE_INFO,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 998/1887 kcm: fix zero-frag skb in frag_list on partial sendmsg error
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 ca220141fa8ebae09765a242076b2b77338106b0 ]
Syzkaller reported a warning in kcm_write_msgs() when processing a message with a zero-fragment skb in the frag_list.
When kcm_sendmsg() fills MAX_SKB_FRAGS fragments in the current skb, it allocates a new skb (tskb) and links it into the frag_list before copying data. If the copy subsequently fails (e.g. -EFAULT from user memory), tskb remains in the frag_list with zero fragments:
head skb (msg being assembled, NOT yet in sk_write_queue)
+-----------+
| frags[17] | (MAX_SKB_FRAGS, all filled with data)
| frag_list-+--> tskb
+-----------+ +----------+
| frags[0] | (empty! copy failed before filling)
+----------+For SOCK_SEQPACKET with partial data already copied, the error path saves this message via partial_message for later completion. For SOCK_SEQPACKET, sock_write_iter() automatically sets MSG_EOR, so a subsequent zero-length write(fd, NULL, 0) completes the message and queues it to sk_write_queue. kcm_write_msgs() then walks the frag_list and hits:
WARN_ON(!skb_shinfo(skb)->nr_frags)
TCP has a similar pattern where skbs are enqueued before data copy and cleaned up on failure via tcp_remove_empty_skb(). KCM was missing the equivalent cleanup.
Fix this by tracking the predecessor skb (frag_prev) when allocating a new frag_list entry. On error, if the tail skb has zero frags, use frag_prev to unlink and free it in O(1) without walking the singly-linked frag_list. frag_prev is safe to dereference because the entire message chain is only held locally (or in kcm->seq_skb) and is not added to sk_write_queue until MSG_EOR, so the send path cannot free it underneath us.
Also change the WARN_ON to WARN_ON_ONCE to avoid flooding the log if the condition is somehow hit repeatedly.
There are currently no KCM selftests in the kernel tree; a simple reproducer is available at [1].
[1] https://gist.github.com/mrpre/a94d431c757e8d6f168f4dd1a3749daa
--- net/kcm/kcmsock.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
net/kcm/kcmsock.c +19 -2
@@ -634,7 +634,7 @@ static int kcm_write_msgs(struct kcm_sock *kcm) sent =0 ; do_frag_list: -if (WARN_ON (!skb_shinfo (skb)->nr_frags)) { +if (WARN_ON_ONCE (!skb_shinfo (skb)->nr_frags)) { ret = -EINVAL ; goto out; }
@@ -908,7 +908,7 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) {struct sock *sk = sock->sk;struct kcm_sock *kcm =kcm_sk (sk); -struct sk_buff *skb =NULL , *head =NULL ; +struct sk_buff *skb =NULL , *head =NULL , *frag_prev =NULL ;size_t copy, copied =0 ;long timeo =sock_sndtimeo (sk, msg->msg_flags &MSG_DONTWAIT ); int eor = (sock->type == SOCK_DGRAM) ?
@@ -983,6 +983,7 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)else skb->next = tskb; + frag_prev = skb; skb = tskb; skb->ip_summed =CHECKSUM_UNNECESSARY ;continue ;
@@ -1070,6 +1071,22 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) out_error:kcm_push (kcm); +/* When MAX_SKB_FRAGS was reached, a new skb was allocated and +* linked into the frag_list before data copy. If the copy +* subsequently failed, this skb has zero frags. Remove it from +* the frag_list to prevent kcm_write_msgs from later hitting +* WARN_ON(!skb_shinfo(skb)->nr_frags). +*/ +if (frag_prev && !skb_shinfo (skb)->nr_frags) { +if (head == frag_prev) +skb_shinfo (head)->frag_list =NULL ; +else + frag_prev->next =NULL ; +kfree_skb (skb); +/* Update skb as it may be saved in partial_message via goto */ + skb = frag_prev; + } +if (sock->type ==SOCK_SEQPACKET ) {/* Wrote some bytes before encountering an * error, return partial success.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 999/1887 vhost: move vdpa group bound check to vhost_vdpa
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugenio Pérez <[email protected]>
[ Upstream commit cd025c1e876b4e262e71398236a1550486a73ede ]
Remove duplication by consolidating these here. This reduces the posibility of a parent driver missing them.
While we're at it, fix a bug in vdpa_sim where a valid ASID can be assigned to a group equal to ngroups, causing an out of bound write.
Message-Id: <[email protected]>
--- drivers/vdpa/mlx5/net/mlx5_vnet.c | 3 --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 6 ------ drivers/vhost/vdpa.c | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-)
drivers/vdpa/mlx5/net/mlx5_vnet.c +0 -3
@@ -2845,9 +2845,6 @@ static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, {struct mlx5_vdpa_dev *mvdev =to_mvdev (vdev); -if (group >=MLX5_VDPA_NUMVQ_GROUPS ) -return -EINVAL ; - mvdev->group2asid[group] = asid;return 0 ; }
drivers/vdpa/vdpa_sim/vdpa_sim.c +0 -6
@@ -599,12 +599,6 @@ static int vdpasim_set_group_asid(struct vdpa_device *vdpa, unsigned int group,struct vhost_iotlb *iommu;int i; -if (group > vdpasim->dev_attr.ngroups) -return -EINVAL ; - -if (asid >= vdpasim->dev_attr.nas) -return -EINVAL ; - iommu = &vdpasim->iommu[asid];spin_lock (&vdpasim->lock);
drivers/vhost/vdpa.c +1 -1
@@ -546,7 +546,7 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,case VHOST_VDPA_SET_GROUP_ASID :if (copy_from_user (&s, argp,sizeof (s)))return -EFAULT ; -if (s.num >= vdpa->nas) +if (idx >= vdpa->ngroups || s.num >= vdpa->nas)return -EINVAL ;if (!ops->set_group_asid)return -EOPNOTSUPP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1000/1887 9p/xen: protect xen_9pfs_front_free against concurrent calls
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Stabellini <[email protected]>
[ Upstream commit ce8ded2e61f47747e31eeefb44dc24a2160a7e32 ]
The xenwatch thread can race with other back-end change notifications and call xen_9pfs_front_free() twice, hitting the observed general protection fault due to a double-free. Guard the teardown path so only one caller can release the front-end state at a time, preventing the crash.
This is a fix for the following double-free:
[ 27.052347] Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] SMP DEBUG_PAGEALLOC NOPTI [ 27.052357] CPU: 0 UID: 0 PID: 32 Comm: xenwatch Not tainted 6.18.0-02087-g51ab33fc0a8b-dirty #60 PREEMPT(none) [ 27.052363] RIP: e030:xen_9pfs_front_free+0x1d/0x150 [ 27.052368] Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 41 55 41 54 55 48 89 fd 48 c7 c7 48 d0 92 85 53 e8 cb cb 05 00 48 8b 45 08 48 8b 55 00 <48> 3b 28 0f 85 f9 28 35 fe 48 3b 6a 08 0f 85 ef 28 35 fe 48 89 42 [ 27.052377] RSP: e02b:ffffc9004016fdd0 EFLAGS: 00010246 [ 27.052381] RAX: 6b6b6b6b6b6b6b6b RBX: ffff88800d66e400 RCX: 0000000000000000 [ 27.052385] RDX: 6b6b6b6b6b6b6b6b RSI: 0000000000000000 RDI: 0000000000000000 [ 27.052389] RBP: ffff88800a887040 R08: 0000000000000000 R09: 0000000000000000 [ 27.052393] R10: 0000000000000000 R11: 0000000000000000 R12: ffff888009e46b68 [ 27.052397] R13: 0000000000000200 R14: 0000000000000000 R15: ffff88800a887040 [ 27.052404] FS: 0000000000000000(0000) GS:ffff88808ca57000(0000) knlGS:0000000000000000 [ 27.052408] CS: e030 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 27.052412] CR2: 00007f9714004360 CR3: 0000000004834000 CR4: 0000000000050660 [ 27.052418] Call Trace: [ 27.052420] <TASK> [ 27.052422] xen_9pfs_front_changed+0x5d5/0x720 [ 27.052426] ? xenbus_otherend_changed+0x72/0x140 [ 27.052430] ? __pfx_xenwatch_thread+0x10/0x10 [ 27.052434] xenwatch_thread+0x94/0x1c0 [ 27.052438] ? __pfx_autoremove_wake_function+0x10/0x10 [ 27.052442] kthread+0xf8/0x240 [ 27.052445] ? __pfx_kthread+0x10/0x10 [ 27.052449] ? __pfx_kthread+0x10/0x10 [ 27.052452] ret_from_fork+0x16b/0x1a0 [ 27.052456] ? __pfx_kthread+0x10/0x10 [ 27.052459] ret_from_fork_asm+0x1a/0x30 [ 27.052463] </TASK> [ 27.052465] Modules linked in: [ 27.052471] ---[ end trace 0000000000000000 ]---
Message-ID: <[email protected]>
--- net/9p/trans_xen.c | 85 ++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 41 deletions(-)
net/9p/trans_xen.c +44 -41
@@ -273,45 +273,52 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv) {int i, j; -write_lock (&xen_9pfs_lock); -list_del (&priv->list); -write_unlock (&xen_9pfs_lock); - -for (i =0 ; i < priv->num_rings; i++) { -struct xen_9pfs_dataring *ring = &priv->rings[i]; - -cancel_work_sync (&ring->work); - -if (!priv->rings[i].intf) -break ; -if (priv->rings[i].irq >0 ) -unbind_from_irqhandler (priv->rings[i].irq, ring); -if (priv->rings[i].data.in) { -for (j =0 ; - j < (1 << priv->rings[i].intf->ring_order); - j++) { -grant_ref_t ref; - - ref = priv->rings[i].intf->ref[j]; -gnttab_end_foreign_access (ref,NULL ); - } -free_pages_exact (priv->rings[i].data.in, +if (priv->rings) { +for (i =0 ; i < priv->num_rings; i++) { +struct xen_9pfs_dataring *ring = &priv->rings[i]; + +cancel_work_sync (&ring->work); + +if (!priv->rings[i].intf) +break ; +if (priv->rings[i].irq >0 ) +unbind_from_irqhandler (priv->rings[i].irq, ring); +if (priv->rings[i].data.in) { +for (j =0 ; + j < (1 << priv->rings[i].intf->ring_order); + j++) { +grant_ref_t ref; + + ref = priv->rings[i].intf->ref[j]; +gnttab_end_foreign_access (ref,NULL ); + } +free_pages_exact (priv->rings[i].data.in,1UL << (priv->rings[i].intf->ring_order +XEN_PAGE_SHIFT )); + } +gnttab_end_foreign_access (priv->rings[i].ref,NULL ); +free_page ((unsigned long )priv->rings[i].intf); } -gnttab_end_foreign_access (priv->rings[i].ref,NULL ); -free_page ((unsigned long )priv->rings[i].intf); +kfree (priv->rings); } -kfree (priv->rings);kfree (priv->tag);kfree (priv); }static void xen_9pfs_front_remove (struct xenbus_device *dev) { -struct xen_9pfs_front_priv *priv =dev_get_drvdata (&dev->dev); +struct xen_9pfs_front_priv *priv; +write_lock (&xen_9pfs_lock); + priv =dev_get_drvdata (&dev->dev); +if (priv ==NULL ) { +write_unlock (&xen_9pfs_lock); +return ; + }dev_set_drvdata (&dev->dev,NULL ); +list_del (&priv->list); +write_unlock (&xen_9pfs_lock); +xen_9pfs_front_free (priv); }
@@ -378,7 +385,7 @@ static int xen_9pfs_front_init(struct xenbus_device *dev) {int ret, i;struct xenbus_transaction xbt; -struct xen_9pfs_front_priv *priv =dev_get_drvdata (&dev->dev); +struct xen_9pfs_front_priv *priv;char *versions, *v;unsigned int max_rings, max_ring_order, len =0 ;
@@ -406,6 +413,10 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)if (p9_xen_trans.maxsize >XEN_FLEX_RING_SIZE (max_ring_order)) p9_xen_trans.maxsize =XEN_FLEX_RING_SIZE (max_ring_order) /2 ; + priv =kzalloc (sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + priv->dev = dev; priv->num_rings =XEN_9PFS_NUM_RINGS ; priv->rings =kcalloc (priv->num_rings,sizeof (*priv->rings),GFP_KERNEL );
@@ -464,6 +475,11 @@ static int xen_9pfs_front_init(struct xenbus_device *dev) goto error; } +write_lock (&xen_9pfs_lock); +dev_set_drvdata (&dev->dev, priv); +list_add_tail (&priv->list, &xen_9pfs_devs); +write_unlock (&xen_9pfs_lock); +xenbus_switch_state (dev, XenbusStateInitialised);return 0 ;
@@ -478,19 +494,6 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)static int xen_9pfs_front_probe (struct xenbus_device *dev,const struct xenbus_device_id *id) { -struct xen_9pfs_front_priv *priv =NULL ; - - priv =kzalloc (sizeof (*priv),GFP_KERNEL ); -if (!priv) -return -ENOMEM ; - - priv->dev = dev; -dev_set_drvdata (&dev->dev, priv); - -write_lock (&xen_9pfs_lock); -list_add_tail (&priv->list, &xen_9pfs_devs); -write_unlock (&xen_9pfs_lock); -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1001/1887 usb: chipidea: udc: fix DMA and SG cleanup in _ep_nuke()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Peter <[email protected]>
[ Upstream commit cea2a1257a3b5ea3e769a445b34af13e6aa5a123 ]
The ChipIdea UDC driver can encounter "not page aligned sg buffer" errors when a USB device is reconnected after being disconnected during an active transfer. This occurs because _ep_nuke() returns requests to the gadget layer without properly unmapping DMA buffers or cleaning up scatter-gather bounce buffers.
Root cause:
When a disconnect happens during a multi-segment DMA transfer, the request's num_mapped_sgs field and sgt.sgl pointer remain set with stale values. The request is returned to the gadget driver with status -ESHUTDOWN but still has active DMA state. If the gadget driver reuses this request on reconnect without reinitializing it, the stale DMA state causes _hardware_enqueue() to skip DMA mapping (seeing non-zero num_mapped_sgs) and attempt to use freed/invalid DMA addresses, leading to alignment errors and potential memory corruption.
The normal completion path via _hardware_dequeue() properly calls usb_gadget_unmap_request_by_dev() and sglist_do_debounce() before returning the request. The _ep_nuke() path must do the same cleanup to ensure requests are returned in a clean, reusable state.
Fix:
Add DMA unmapping and bounce buffer cleanup to _ep_nuke() to mirror the cleanup sequence in _hardware_dequeue():
- Call usb_gadget_unmap_request_by_dev() if num_mapped_sgs is set
- Call sglist_do_debounce() with copy=false if bounce buffer exists
This ensures that when requests are returned due to endpoint shutdown, they don't retain stale DMA mappings. The 'false' parameter to sglist_do_debounce() prevents copying data back (appropriate for shutdown path where transfer was aborted).
--- drivers/usb/chipidea/udc.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/chipidea/udc.c +4 -0
@@ -773,6 +773,10 @@ __acquires(hwep->lock)list_del_init (&hwreq->queue); hwreq->req.status = -ESHUTDOWN ; +/* Unmap DMA before giving back */ +usb_gadget_unmap_request_by_dev (hwep->ci->dev->parent, + &hwreq->req, hwep->dir); +if (hwreq->req.complete !=NULL ) {spin_unlock (hwep->lock);usb_gadget_giveback_request (&hwep->ep, &hwreq->req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1002/1887 iommu/amd: move wait_on_sem() out of spinlock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Soni <[email protected]>
[ Upstream commit d2a0cac10597068567d336e85fa3cbdbe8ca62bf ]
With iommu.strict=1, the existing completion wait path can cause soft lockups under stressed environment, as wait_on_sem() busy-waits under the spinlock with interrupts disabled.
Move the completion wait in iommu_completion_wait() out of the spinlock. wait_on_sem() only polls the hardware-updated cmd_sem and does not require iommu->lock, so holding the lock during the busy wait unnecessarily increases contention and extends the time with interrupts disabled.
--- drivers/iommu/amd/iommu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/iommu/amd/iommu.c +9 -5
@@ -918,7 +918,12 @@ static int wait_on_sem(struct amd_iommu *iommu, u64 data) {int i =0 ; -while (*iommu->cmd_sem != data && i <LOOP_TIMEOUT ) { +/* +* cmd_sem holds a monotonically non-decreasing completion sequence +* number. +*/ +while ((__s64)(READ_ONCE (*iommu->cmd_sem) - data) <0 && + i <LOOP_TIMEOUT ) {udelay (1 ); i +=1 ; }
@@ -1187,14 +1192,13 @@ static int iommu_completion_wait(struct amd_iommu *iommu)build_completion_wait (&cmd, iommu, data); ret =__iommu_queue_command_sync (iommu, &cmd, false); +raw_spin_unlock_irqrestore (&iommu->lock, flags); +if (ret) - goto out_unlock; +return ret; ret =wait_on_sem (iommu, data); -out_unlock: -raw_spin_unlock_irqrestore (&iommu->lock, flags); -return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1003/1887 arch: turn off -Werror for architectures with known warnings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnd Bergmann <[email protected]>
[ Upstream commit 0f0d2871e78db648a2578abbeb9103f484f9b754 ]
A couple of architectures enable -Werror for their own files regardless of CONFIG_WERROR but also have known warnings that fail the build with -Wmissing-prototypes enabled by default:
arch/alpha/lib/memcpy.c:153:8: error: no previous prototype for 'memcpy' [-Werror=missing-prototypes] arch/alpha/kernel/irq.c:96:1: error: no previous prototype for 'handle_irq' [-Werror=missing-prototypes] arch/mips/kernel/signal.c:673:17: error: no previous prototype for ‘sys_rt_sigreturn’ [-Werror=missing-prototypes] arch/mips/kernel/signal.c:636:17: error: no previous prototype for ‘sys_sigreturn’ [-Werror=missing-prototypes] arch/mips/kernel/syscall.c:51:16: error: no previous prototype for ‘sysm_pipe’ [-Werror=missing-prototypes] arch/mips/mm/fault.c:323:17: error: no previous prototype for ‘do_page_fault’ [-Werror=missing-prototypes] arch/sparc/vdso/vma.c:246:12: warning: no previous prototype for ‘init_vdso_image’ [-Wmissing-prototypes]v arch/sparc/vdso/vdso32/../vclock_gettime.c:343:1: warning: no previous prototype for ‘__vdso_gettimeofday_stick’ [-Wmissing-prototypes] arch/sparc/vdso/vclock_gettime.c:343:1: warning: no previous prototype for ‘__vdso_gettimeofday_stick’ [-Wmissing-prototypes] arch/sparc/prom/p1275.c:52:6: warning: no previous prototype for ‘prom_cif_init’ [-Wmissing-prototypes] arch/sparc/prom/misc_64.c:165:5: warning: no previous prototype for ‘prom_get_mmu_ihandle’ [-Wmissing-prototypes]
This appears to be an artifact from the times when this architecture code was better maintained that most device drivers and before CONFIG_WERROR was added. Now it just gets in the way, so remove all of these.
Powerpc and x86 both still have their own Kconfig options to enable -Werror for some of their files. These architectures are better maintained than most and the options are easy to disable, so leave those untouched.
Stable-dep-of: dd5712f3379c ("alpha: fix user-space corruption during memory compaction")
--- arch/alpha/lib/Makefile | 1 - arch/alpha/mm/Makefile | 2 -- arch/mips/Kbuild | 6 ------ arch/sparc/kernel/Makefile | 1 - arch/sparc/lib/Makefile | 1 - arch/sparc/mm/Makefile | 1 - arch/sparc/prom/Makefile | 1 - 7 files changed, 13 deletions(-)
arch/alpha/lib/Makefile +0 -1
@@ -4,7 +4,6 @@ # asflags-y := $(KBUILD_CFLAGS) -ccflags-y := -Werror # Many of these routines have implementations tuned for ev6. # Choose them iff we're targeting ev6 specifically.
arch/alpha/mm/Makefile +0 -2
@@ -3,6 +3,4 @@ # Makefile for the linux alpha-specific parts of the memory manager. # -ccflags-y := -Werror - obj-y := init.o fault.o
arch/mips/Kbuild +0 -6
@@ -1,10 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# Fail on warnings - also for files referenced in subdirs -# -Werror can be disabled for specific files using: -# CFLAGS_<file.o> := -Wno-error -ifeq ($(W),) -subdir-ccflags-y := -Werror -endif # platform specific definitions include arch/mips/Kbuild.platforms
arch/sparc/kernel/Makefile +0 -1
@@ -5,7 +5,6 @@ # asflags-y := -ansi -ccflags-y := -Werror # Undefine sparc when processing vmlinux.lds - it is used # And teach CPP we are doing $(BITS) builds (for this case)
arch/sparc/lib/Makefile +0 -1
@@ -3,7 +3,6 @@ # asflags-y := -ansi -DST_DIV0=0x02 -ccflags-y := -Werror lib-$(CONFIG_SPARC32) += ashrdi3.o lib-$(CONFIG_SPARC32) += memcpy.o memset.o
arch/sparc/mm/Makefile +0 -1
@@ -3,7 +3,6 @@ # asflags-y := -ansi -ccflags-y := -Werror obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o obj-y += fault_$(BITS).o
arch/sparc/prom/Makefile +0 -1
@@ -3,7 +3,6 @@ # Linux. # asflags := -ansi -ccflags := -Werror lib-y := bootstr_$(BITS).o lib-y += init_$(BITS).o
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1004/1887 alpha: fix user-space corruption during memory compaction
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Magnus Lindholm <[email protected]>
[ Upstream commit dd5712f3379cfe760267cdd28ff957d9ab4e51c7 ]
Alpha systems can suffer sporadic user-space crashes and heap corruption when memory compaction is enabled.
Symptoms include SIGSEGV, glibc allocator failures (e.g. "unaligned tcache chunk"), and compiler internal errors. The failures disappear when compaction is disabled or when using global TLB invalidation.
The root cause is insufficient TLB shootdown during page migration. Alpha relies on ASN-based MM context rollover for instruction cache coherency, but this alone is not sufficient to prevent stale data or instruction translations from surviving migration.
Fix this by introducing a migration-specific helper that combines:
- MM context invalidation (ASN rollover),
- immediate per-CPU TLB invalidation (TBI),
- synchronous cross-CPU shootdown when required.
The helper is used only by migration/compaction paths to avoid changing global TLB semantics.
Additionally, update flush_tlb_other(), pte_clear(), to use READ_ONCE()/WRITE_ONCE() for correct SMP memory ordering.
This fixes observed crashes on both UP and SMP Alpha systems.
--- arch/alpha/include/asm/pgtable.h | 33 ++++++++- arch/alpha/include/asm/tlbflush.h | 4 +- arch/alpha/mm/Makefile | 2 +- arch/alpha/mm/tlbflush.c | 112 ++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 arch/alpha/mm/tlbflush.c
arch/alpha/include/asm/pgtable.h +32 -1
@@ -17,6 +17,7 @@#include <asm/processor.h> /* For TASK_SIZE */ #include <asm/machvec.h> #include <asm/setup.h> +#include <linux/page_table_check.h> struct mm_struct ;struct vm_area_struct ;
@@ -210,6 +211,9 @@ extern inline void pud_set(pud_t * pudp, pmd_t * pmdp) {pud_val (*pudp) = _PAGE_TABLE | ((((unsigned long ) pmdp) -PAGE_OFFSET ) << (32 -PAGE_SHIFT )); } +extern void migrate_flush_tlb_page (struct vm_area_struct *vma, +unsigned long addr); +extern inline unsigned long pmd_page_vaddr (pmd_t pmd) {
@@ -229,7 +233,7 @@ extern inline int pte_none(pte_t pte) { return !pte_val(pte); }extern inline int pte_present (pte_t pte) {return pte_val (pte) & _PAGE_VALID; }extern inline void pte_clear (struct mm_struct *mm,unsigned long addr,pte_t *ptep) { -pte_val (*ptep) =0 ; +WRITE_ONCE (pte_val (*ptep),0 ); }extern inline int pmd_none (pmd_t pmd) {return !pmd_val (pmd); }
@@ -291,6 +295,33 @@ extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)extern pgd_t swapper_pg_dir[1024 ]; +#ifdef CONFIG_COMPACTION +#define __HAVE_ARCH_PTEP_GET_AND_CLEAR + +static inline pte_t ptep_get_and_clear (struct mm_struct *mm, +unsigned long address, +pte_t *ptep) +{ +pte_t pte =READ_ONCE (*ptep); + +pte_clear (mm, address, ptep); +return pte; +} + +#define __HAVE_ARCH_PTEP_CLEAR_FLUSH + +static inline pte_t ptep_clear_flush (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep) +{ +struct mm_struct *mm = vma->vm_mm; +pte_t pte =ptep_get_and_clear (mm, addr, ptep); + +page_table_check_pte_clear (mm, pte); +migrate_flush_tlb_page (vma, addr); +return pte; +} + +#endif /* * The Alpha doesn't have any external MMU info: the kernel page * tables contain all the necessary information.
arch/alpha/include/asm/tlbflush.h +3 -1
@@ -91,7 +91,9 @@ flush_tlb_other(struct mm_struct *mm)unsigned long *mmc = &mm->context[smp_processor_id ()];/* Check it's not zero first to avoid cacheline ping pong when possible. */ -if (*mmc) *mmc =0 ; + +if (READ_ONCE (*mmc)) +WRITE_ONCE (*mmc,0 ); }#ifndef CONFIG_SMP
arch/alpha/mm/Makefile +1 -1
@@ -3,4 +3,4 @@ # Makefile for the linux alpha-specific parts of the memory manager. # -obj-y := init.o fault.o +obj-y := init.o fault.o tlbflush.o
arch/alpha/mm/tlbflush.c new file +112 -0
112 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1005/1887 md-cluster: fix NULL pointer dereference in process_metadata_update
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiasheng Jiang <[email protected]>
[ Upstream commit f150e753cb8dd756085f46e86f2c35ce472e0a3c ]
The function process_metadata_update() blindly dereferences the 'thread' pointer (acquired via rcu_dereference_protected) within the wait_event() macro.
While the code comment states "daemon thread must exist", there is a valid race condition window during the MD array startup sequence (md_run):
1. bitmap_load() is called, which invokes md_cluster_ops->join().
2. join() starts the "cluster_recv" thread (recv_daemon).
3. At this point, recv_daemon is active and processing messages.
4. However, mddev->thread (the main MD thread) is not initialized until later in md_run().
If a METADATA_UPDATED message is received from a remote node during this specific window, process_metadata_update() will be called while mddev->thread is still NULL, leading to a kernel panic.
To fix this, we must validate the 'thread' pointer. If it is NULL, we release the held lock (no_new_dev_lockres) and return early, safely ignoring the update request as the array is not yet fully ready to process it.
--- drivers/md/md-cluster.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/md/md-cluster.c +10 -1
@@ -526,11 +526,20 @@ static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg)static void process_metadata_update (struct mddev *mddev,struct cluster_msg *msg) {int got_lock =0 ; +struct md_thread *thread;struct md_cluster_info *cinfo = mddev->cluster_info; mddev->good_device_nr =le32_to_cpu (msg->raid_slot);dlm_lock_sync (cinfo->no_new_dev_lockres,DLM_LOCK_CR ); -wait_event (mddev->thread->wqueue, + + thread = mddev->thread; +if (!thread) { +pr_warn ("md-cluster: Received metadata update but MD thread is not ready\n" ); +dlm_unlock_sync (cinfo->no_new_dev_lockres); +return ; + } + +wait_event (thread->wqueue, (got_lock =mddev_trylock (mddev)) ||test_bit (MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD , &cinfo->state));md_reload_sb (mddev, mddev->good_device_nr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1006/1887 btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure()
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 8ceaad6cd6e7fa5f73b0b2796a2e85d75d37e9f3 ]
[BUG]
There is a bug report that when btrfs hits ENOSPC error in a critical path, btrfs flips RO (this part is expected, although the ENOSPC bug still needs to be addressed).
The problem is after the RO flip, if there is a read repair pending, we can hit the ASSERT() inside btrfs_repair_io_failure() like the following:
BTRFS info (device vdc): relocating block group 30408704 flags metadata|raid1
------------[ cut here ]------------ BTRFS: Transaction aborted (error -28) WARNING: fs/btrfs/extent-tree.c:3235 at __btrfs_free_extent.isra.0+0x453/0xfd0, CPU#1: btrfs/383844 Modules linked in: kvm_intel kvm irqbypass [...] ---[ end trace 0000000000000000 ]--- BTRFS info (device vdc state EA): 2 enospc errors during balance BTRFS info (device vdc state EA): balance: ended with status: -30 BTRFS error (device vdc state EA): parent transid verify failed on logical 30556160 mirror 2 wanted 8 found 6 BTRFS error (device vdc state EA): bdev /dev/nvme0n1 errs: wr 0, rd 0, flush 0, corrupt 10, gen 0 [...] assertion failed: !(fs_info->sb->s_flags & SB_RDONLY) :: 0, in fs/btrfs/bio.c:938 ------------[ cut here ]------------ assertion failed: !(fs_info->sb->s_flags & SB_RDONLY) :: 0, in fs/btrfs/bio.c:938 kernel BUG at fs/btrfs/bio.c:938! Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 0 UID: 0 PID: 868 Comm: kworker/u8:13 Tainted: G W N 6.19.0-rc6+ #4788 PREEMPT(full) Tainted: [W]=WARN, [N]=TEST Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 Workqueue: btrfs-endio simple_end_io_work RIP: 0010:btrfs_repair_io_failure.cold+0xb2/0x120 RSP: 0000:ffffc90001d2bcf0 EFLAGS: 00010246 RAX: 0000000000000051 RBX: 0000000000001000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff8305cf42 RDI: 00000000ffffffff RBP: 0000000000000002 R08: 00000000fffeffff R09: ffffffff837fa988 R10: ffffffff8327a9e0 R11: 6f69747265737361 R12: ffff88813018d310 R13: ffff888168b8a000 R14: ffffc90001d2bd90 R15: ffff88810a169000 FS: 0000000000000000(0000) GS:ffff8885e752c000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 ------------[ cut here ]------------
[CAUSE]
The cause of -ENOSPC error during the test case btrfs/124 is still unknown, although it's known that we still have cases where metadata can be over-committed but can not be fulfilled correctly, thus if we hit such ENOSPC error inside a critical path, we have no choice but abort the current transaction.
This will mark the fs read-only.
The problem is inside the btrfs_repair_io_failure() path that we require the fs not to be mount read-only. This is normally fine, but if we are doing a read-repair meanwhile the fs flips RO due to a critical error, we can enter btrfs_repair_io_failure() with super block set to read-only, thus triggering the above crash.
[FIX]
Just replace the ASSERT() with a proper return if the fs is already read-only.
--- fs/btrfs/extent_io.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/btrfs/extent_io.c +7 -1
@@ -557,9 +557,15 @@ static int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,struct btrfs_io_context *bioc =NULL ;int ret =0 ; -ASSERT (!(fs_info->sb->s_flags &SB_RDONLY ));BUG_ON (!mirror_num); +/* +* The fs either mounted RO or hit critical errors, no need +* to continue repairing. +*/ +if (unlikely (sb_rdonly (fs_info->sb))) +return 0 ; +if (btrfs_repair_one_zone (fs_info, logical))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1007/1887 btrfs: dont BUG() on unexpected delayed ref type in run_one_delayed_ref()
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 c7d1d4ff56744074e005771aff193b927392d51f ]
There is no need to BUG(), we can just return an error and log an error message.
--- fs/btrfs/extent-tree.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/btrfs/extent-tree.c +10 -6
@@ -1707,6 +1707,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, struct btrfs_delayed_extent_op *extent_op, int insert_reserved) { +struct btrfs_fs_info *fs_info = trans->fs_info;int ret =0 ;if (TRANS_ABORTED (trans)) {
@@ -1716,19 +1717,22 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, }if (node->type ==BTRFS_TREE_BLOCK_REF_KEY || - node->type ==BTRFS_SHARED_BLOCK_REF_KEY ) + node->type ==BTRFS_SHARED_BLOCK_REF_KEY ) { ret =run_delayed_tree_ref (trans, node, extent_op, insert_reserved); -else if (node->type ==BTRFS_EXTENT_DATA_REF_KEY || - node->type ==BTRFS_SHARED_DATA_REF_KEY ) + }else if (node->type ==BTRFS_EXTENT_DATA_REF_KEY || + node->type ==BTRFS_SHARED_DATA_REF_KEY ) { ret =run_delayed_data_ref (trans, node, extent_op, insert_reserved); -else -BUG (); + }else { + ret = -EUCLEAN ; +btrfs_err (fs_info,"unexpected delayed ref node type: %u" , node->type); + } +if (ret && insert_reserved)btrfs_pin_extent (trans, node->bytenr, node->num_bytes,1 );if (ret <0 ) -btrfs_err (trans->fs_info, +btrfs_err (fs_info,"failed to run delayed ref for logical %llu num_bytes %llu type %u action %u ref_mod %d: %d" , node->bytenr, node->num_bytes, node->type, node->action, node->ref_mod, ret);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1008/1887 media: hantro: Disable multicore support
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Reichel <[email protected]>
[ Upstream commit ccdeb8d57f7fb3e5c05d72cb7dfb9bc78f09f542 ]
Avoid exposing equal Hantro video codecs to userspace. Equal video codecs allow scheduling work between the cores. For that kernel support is required, which does not yet exist. Until that is implemented avoid exposing each core separately to userspace so that multicore can be added in the future without breaking userspace ABI.
This was written with Rockchip RK3588 in mind (which has 4 Hantro H1 cores), but applies to all SoCs.
Stable-dep-of: e0203ddf9af7 ("media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC")
--- .../media/platform/verisilicon/hantro_drv.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+)
drivers/media/platform/verisilicon/hantro_drv.c +47 -0
@@ -896,6 +896,49 @@ static const struct media_device_ops hantro_m2m_media_ops = { .req_queue = v4l2_m2m_request_queue, }; +/* +* Some SoCs, like RK3588 have multiple identical Hantro cores, but the +* kernel is currently missing support for multi-core handling. Exposing +* separate devices for each core to userspace is bad, since that does +* not allow scheduling tasks properly (and creates ABI). With this workaround +* the driver will only probe for the first core and early exit for the other +* cores. Once the driver gains multi-core support, the same technique +* for detecting the main core can be used to cluster all cores together. +*/ +static int hantro_disable_multicore (struct hantro_dev *vpu) +{ +struct device_node *node =NULL ; +const char *compatible; +bool is_main_core; +int ret; + +/* Intentionally ignores the fallback strings */ + ret =of_property_read_string (vpu->dev->of_node,"compatible" , &compatible); +if (ret) +return ret; + +/* The first compatible and available node found is considered the main core */ +do { + node =of_find_compatible_node (node,NULL , compatible); +if (of_device_is_available (node)) +break ; + }while (node); + +if (!node) +return -EINVAL ; + + is_main_core = (vpu->dev->of_node == node); + +of_node_put (node); + +if (!is_main_core) { +dev_info (vpu->dev,"missing multi-core support, ignoring this instance\n" ); +return -ENODEV ; + } + +return 0 ; +} +static int hantro_probe (struct platform_device *pdev) {const struct of_device_id *match;
@@ -916,6 +959,10 @@ static int hantro_probe(struct platform_device *pdev) match =of_match_node (of_hantro_match, pdev->dev.of_node); vpu->variant = match->data; + ret =hantro_disable_multicore (vpu); +if (ret) +return ret; +/* * Support for nxp,imx8mq-vpu is kept for backwards compatibility * but it's deprecated. Please update your DTS file to use
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1009/1887 media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Dufresne <[email protected]>
[ Upstream commit db6b97a4f8041e479be9ef4b8b07022636c96f50 ]
Adding a reference count to the v4l2_m2m_dev structure allow safely sharing it across multiple hardware nodes. This can be used to prevent running jobs concurrently on m2m cores that have some internal resource sharing.
Stable-dep-of: e0203ddf9af7 ("media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC")
--- drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++ include/media/v4l2-mem2mem.h | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+)
drivers/media/v4l2-core/v4l2-mem2mem.c +23 -0
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {* @job_work: worker to run queued jobs. * @job_queue_flags: flags of the queue status, %QUEUE_PAUSED. * @m2m_ops: driver callbacks +* @kref: device reference count */ struct v4l2_m2m_dev {struct v4l2_m2m_ctx *curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {unsigned long job_queue_flags;const struct v4l2_m2m_ops *m2m_ops; + +struct kref kref; }; static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1207,6 +1210,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)INIT_LIST_HEAD (&m2m_dev->job_queue);spin_lock_init (&m2m_dev->job_spinlock);INIT_WORK (&m2m_dev->job_work, v4l2_m2m_device_run_work); +kref_init (&m2m_dev->kref);return m2m_dev; }
@@ -1218,6 +1222,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev) }EXPORT_SYMBOL_GPL (v4l2_m2m_release); +void v4l2_m2m_get (struct v4l2_m2m_dev *m2m_dev) +{ +kref_get (&m2m_dev->kref); +} +EXPORT_SYMBOL_GPL (v4l2_m2m_get); + +static void v4l2_m2m_release_from_kref (struct kref *kref) +{ + struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref); + +v4l2_m2m_release (m2m_dev); +} + +void v4l2_m2m_put (struct v4l2_m2m_dev *m2m_dev) +{ +kref_put (&m2m_dev->kref, v4l2_m2m_release_from_kref); +} +EXPORT_SYMBOL_GPL (v4l2_m2m_put); +struct v4l2_m2m_ctx *v4l2_m2m_ctx_init (struct v4l2_m2m_dev *m2m_dev,void *drv_priv,int (*queue_init)(void *priv,struct vb2_queue *src_vq,struct vb2_queue *dst_vq))
include/media/v4l2-mem2mem.h +21 -0
@@ -537,6 +537,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,*/ void v4l2_m2m_release (struct v4l2_m2m_dev *m2m_dev); +/** +* v4l2_m2m_get() - take a reference to the m2m_dev structure +* +* @m2m_dev: opaque pointer to the internal data to handle M2M context +* +* This is used to share the M2M device across multiple devices. This +* can be used to avoid scheduling two hardware nodes concurrently. +*/ +void v4l2_m2m_get (struct v4l2_m2m_dev *m2m_dev); + +/** +* v4l2_m2m_put() - remove a reference to the m2m_dev structure +* +* @m2m_dev: opaque pointer to the internal data to handle M2M context +* +* Once the M2M device has no more references, v4l2_m2m_release() will be +* called automatically. Users of this method should never call +* v4l2_m2m_release() directly. See v4l2_m2m_get() for more details. +*/ +void v4l2_m2m_put (struct v4l2_m2m_dev *m2m_dev); +/** * v4l2_m2m_ctx_init() - allocate and initialize a m2m context *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1010/1887 media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <[email protected]>
[ Upstream commit e0203ddf9af7c8e170e1e99ce83b4dc07f0cd765 ]
For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and g2 VPU cannot decode simultaneously; otherwise, it will cause below bus error and produce corrupted pictures, even potentially lead to system hang.
[ 110.527986] hantro-vpu 38310000.video-codec: frame decode timed out. [ 110.583517] hantro-vpu 38310000.video-codec: bus error detected.
Therefore, it is necessary to ensure that g1 and g2 operate alternately. This allows for successful multi-instance decoding of H.264 and HEVC.
To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the v4l2_m2m_dev can handle the scheduling.
--- drivers/media/platform/verisilicon/hantro.h | 2 + .../media/platform/verisilicon/hantro_drv.c | 42 +++++++++++++++++-- .../media/platform/verisilicon/imx8m_vpu_hw.c | 8 ++++ 3 files changed, 49 insertions(+), 3 deletions(-)
drivers/media/platform/verisilicon/hantro.h +2 -0
@@ -76,6 +76,7 @@ struct hantro_irq {* @double_buffer: core needs double buffering * @legacy_regs: core uses legacy register set * @late_postproc: postproc must be set up at the end of the job +* @shared_devices: an array of device ids that cannot run concurrently */ struct hantro_variant {unsigned int enc_offset;
@@ -100,6 +101,7 @@ struct hantro_variant { unsigned int double_buffer : 1; unsigned int legacy_regs : 1; unsigned int late_postproc : 1; +const struct of_device_id *shared_devices; };/**
drivers/media/platform/verisilicon/hantro_drv.c +39 -3
72 lines not on this page · raw message
drivers/media/platform/verisilicon/imx8m_vpu_hw.c +8 -0
@@ -359,6 +359,12 @@ const struct hantro_variant imx8mq_vpu_variant = { .num_regs = ARRAY_SIZE(imx8mq_reg_names) }; +static const struct of_device_id imx8mq_vpu_shared_resources[]__initconst = { + { .compatible ="nxp,imx8mq-vpu-g1" , }, + { .compatible ="nxp,imx8mq-vpu-g2" , }, + {/* sentinel */ } +}; +const struct hantro_variant imx8mq_vpu_g1_variant = { .dec_fmts = imx8m_vpu_dec_fmts, .num_dec_fmts =ARRAY_SIZE (imx8m_vpu_dec_fmts),
@@ -372,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = { .num_irqs = ARRAY_SIZE(imx8mq_irqs), .clk_names = imx8mq_g1_clk_names, .num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names), + .shared_devices = imx8mq_vpu_shared_resources, };const struct hantro_variant imx8mq_vpu_g2_variant = {
@@ -387,6 +394,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = { .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs), .clk_names = imx8mq_g2_clk_names, .num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names), + .shared_devices = imx8mq_vpu_shared_resources, };const struct hantro_variant imx8mm_vpu_g1_variant = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1011/1887 btrfs: reserve enough transaction items for qgroup ioctls
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 f9a4e3015db1aeafbef407650eb8555445ca943e ]
Currently our qgroup ioctls don't reserve any space, they just do a transaction join, which does not reserve any space, neither for the quota tree updates nor for the delayed refs generated when updating the quota tree. The quota root uses the global block reserve, which is fine most of the time since we don't expect a lot of updates to the quota root, or to be too close to -ENOSPC such that other critical metadata updates need to resort to the global reserve.
However this is not optimal, as not reserving proper space may result in a transaction abort due to not reserving space for delayed refs and then abusing the use of the global block reserve.
For example, the following reproducer (which is unlikely to model any real world use case, but just to illustrate the problem), triggers such a transaction abort due to -ENOSPC when running delayed refs:
$ cat test.sh #!/bin/bash
DEV=/dev/nullb0
MNT=/mnt/nullb0
umount $DEV &> /dev/null
# Limit device to 1G so that it's much faster to reproduce the issue. mkfs.btrfs -f -b 1G $DEV
mount -o commit=600 $DEV $MNT
fallocate -l 800M $MNT/filler
btrfs quota enable $MNT
for ((i = 1; i <= 400000; i++)); do
btrfs qgroup create 1/$i $MNT
done
umount $MNT
When running this, we can see in dmesg/syslog that a transaction abort happened:
[436.490] BTRFS error (device nullb0): failed to run delayed ref for logical 30408704 num_bytes 16384 type 176 action 1 ref_mod 1: -28 [436.493] ------------[ cut here ]------------ [436.494] BTRFS: Transaction aborted (error -28) [436.495] WARNING: fs/btrfs/extent-tree.c:2247 at btrfs_run_delayed_refs+0xd9/0x110 [btrfs], CPU#4: umount/2495372 [436.497] Modules linked in: btrfs loop (...) [436.508] CPU: 4 UID: 0 PID: 2495372 Comm: umount Tainted: G W 6.19.0-rc8-btrfs-next-225+ #1 PREEMPT(full) [436.510] Tainted: [W]=WARN [436.511] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 [436.513] RIP: 0010:btrfs_run_delayed_refs+0xdf/0x110 [btrfs] [436.514] Code: 0f 82 ea (...) [436.518] RSP: 0018:ffffd511850b7d78 EFLAGS: 00010292 [436.519] RAX: 00000000ffffffe4 RBX: ffff8f120dad37e0 RCX: 0000000002040001 [436.520] RDX: 0000000000000002 RSI: 00000000ffffffe4 RDI: ffffffffc090fd80 [436.522] RBP: 0000000000000000 R08: 0000000000000001 R09: ffffffffc04d1867 [436.523] R10: ffff8f18dc1fffa8 R11: 0000000000000003 R12: ffff8f173aa89400 [436.524] R13: 0000000000000000 R14: ffff8f173aa89400 R15: 0000000000000000 [436.526] FS: 00007fe59045d840(0000) GS:ffff8f192e22e000(0000) knlGS:0000000000000000 [436.527] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [436.528] CR2: 00007fe5905ff2b0 CR3: 000000060710a002 CR4: 0000000000370ef0 [436.530] Call Trace: [436.530] <TASK> [436.530] btrfs_commit_transaction+0x73/0xc00 [btrfs] [436.531] ? btrfs_attach_transaction_barrier+0x1e/0x70 [btrfs] [436.532] sync_filesystem+0x7a/0x90 [436.533] generic_shutdown_super+0x28/0x180 [436.533] kill_anon_super+0x12/0x40 [436.534] btrfs_kill_super+0x12/0x20 [btrfs] [436.534] deactivate_locked_super+0x2f/0xb0 [436.534] cleanup_mnt+0xea/0x180 [436.535] task_work_run+0x58/0xa0 [436.535] exit_to_user_mode_loop+0xed/0x480 [436.536] ? __x64_sys_umount+0x68/0x80 [436.536] do_syscall_64+0x2a5/0xf20 [436.537] entry_SYSCALL_64_after_hwframe+0x76/0x7e [436.537] RIP: 0033:0x7fe5906b6217 [436.538] Code: 0d 00 f7 (...) [436.540] RSP: 002b:00007ffcd87a61f8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 [436.541] RAX: 0000000000000000 RBX: 00005618b9ecadc8 RCX: 00007fe5906b6217 [436.541] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00005618b9ecb100 [436.542] RBP: 0000000000000000 R08: 00007ffcd87a4fe0 R09: 00000000ffffffff [436.544] R10: 0000000000000103 R11: 0000000000000246 R12: 00007fe59081626c [436.544] R13: 00005618b9ecb100 R14: 0000000000000000 R15: 00005618b9ecacc0 [436.545] </TASK> [436.545] ---[ end trace 0000000000000000 ]---
Fix this by changing the qgroup ioctls to use start transaction instead of joining so that proper space is reserved for the delayed refs generated for the updates to the quota root. This way we don't get any transaction abort.
--- fs/btrfs/ioctl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
fs/btrfs/ioctl.c +9 -3
@@ -4667,7 +4667,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) goto drop_write; } - trans =btrfs_join_transaction (root); +/* 2 BTRFS_QGROUP_RELATION_KEY items. */ + trans =btrfs_start_transaction (root,2 );if (IS_ERR (trans)) { ret =PTR_ERR (trans); goto out;
@@ -4729,7 +4730,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) goto out; } - trans =btrfs_join_transaction (root); +/* +* 1 BTRFS_QGROUP_INFO_KEY item. +* 1 BTRFS_QGROUP_LIMIT_KEY item. +*/ + trans =btrfs_start_transaction (root,2 );if (IS_ERR (trans)) { ret =PTR_ERR (trans); goto out;
@@ -4775,7 +4780,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) goto drop_write; } - trans =btrfs_join_transaction (root); +/* 1 BTRFS_QGROUP_LIMIT_KEY item. */ + trans =btrfs_start_transaction (root,1 );if (IS_ERR (trans)) { ret =PTR_ERR (trans); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1012/1887 perf/x86/intel/uncore: Fix die ID init and look up bugs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zide Chen <[email protected]>
[ Upstream commit a16d1ec4dd0cdcf689f324adde6067083bce9099 ]
In snbep_pci2phy_map_init(), in the nr_node_ids > 8 path, uncore_device_to_die() may return -1 when all CPUs associated with the UBOX device are offline.
Remove the WARN_ON_ONCE(die_id == -1) check for two reasons:
- The current code breaks out of the loop. This is incorrect because pci_get_device() does not guarantee iteration in domain or bus order, so additional UBOX devices may be skipped during the scan.
- Returning -EINVAL is incorrect, since marking offline buses with die_id == -1 is expected and should not be treated as an error.
Separately, when NUMA is disabled on a NUMA-capable platform, pcibus_to_node() returns NUMA_NO_NODE, causing uncore_device_to_die() to return -1 for all PCI devices. As a result, spr_update_device_location(), used on Intel SPR and EMR, ignores the corresponding PMON units and does not add them to the RB tree.
Fix this by using uncore_pcibus_to_dieid(), which retrieves topology from the UBOX GIDNIDMAP register and works regardless of whether NUMA is enabled in Linux. This requires snbep_pci2phy_map_init() to be added in spr_uncore_pci_init().
Keep uncore_device_to_die() only for the nr_node_ids > 8 case, where NUMA is expected to be enabled.
--- arch/x86/events/intel/uncore_snbep.c | 5 ----- 1 file changed, 5 deletions(-)
arch/x86/events/intel/uncore_snbep.c +0 -5
@@ -1458,11 +1458,6 @@ static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool } }raw_spin_unlock (&pci2phy_map_lock); - -if (WARN_ON_ONCE (die_id ==-1 )) { - err = -EINVAL ; -break ; - } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1013/1887 i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ]
The logic used to abort the DMA ring contains several flaws:
1. The driver unconditionally issues a ring abort even when the ring has already stopped.
2. The completion used to wait for abort completion is never re-initialized, resulting in incorrect wait behavior.
3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which resets hardware ring pointers and disrupts the controller state.
4. If the ring is already stopped, the abort operation should be considered successful without attempting further action.
Fix the abort handling by checking whether the ring is running before issuing an abort, re-initializing the completion when needed, ensuring that RING_CTRL_ENABLE remains asserted during abort, and treating an already stopped ring as a successful condition.
--- drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
drivers/i3c/master/mipi-i3c-hci/dma.c +17 -10
@@ -448,16 +448,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,struct hci_rh_data *rh = &rings->headers[xfer_list[0 ].ring_number];unsigned int i;bool did_unqueue = false; - -/* stop the ring */ -rh_reg_write (RING_CONTROL ,RING_CTRL_ABORT ); -if (wait_for_completion_timeout (&rh->op_done,HZ ) ==0 ) { -/* -* We're deep in it if ever this condition is ever met. -* Hardware might still be writing to memory, etc. -*/ -dev_crit (&hci->master.dev,"unable to abort the ring\n" ); -WARN_ON (1 ); +u32 ring_status; + + ring_status =rh_reg_read (RING_STATUS ); +if (ring_status &RING_STATUS_RUNNING ) { +/* stop the ring */ +reinit_completion (&rh->op_done); +rh_reg_write (RING_CONTROL ,RING_CTRL_ENABLE |RING_CTRL_ABORT ); +wait_for_completion_timeout (&rh->op_done,HZ ); + ring_status =rh_reg_read (RING_STATUS ); +if (ring_status &RING_STATUS_RUNNING ) { +/* +* We're deep in it if ever this condition is ever met. +* Hardware might still be writing to memory, etc. +*/ +dev_crit (&hci->master.dev,"unable to abort the ring\n" ); +WARN_ON (1 ); + } }for (i =0 ; i < n; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1014/1887 i3c: mipi-i3c-hci: Fix race in DMA ring dequeue
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 1dca8aee80eea76d2aae21265de5dd64f6ba0f09 ]
The HCI DMA dequeue path (hci_dma_dequeue_xfer()) may be invoked for multiple transfers that timeout around the same time. However, the function is not serialized and can race with itself.
When a timeout occurs, hci_dma_dequeue_xfer() stops the ring, processes incomplete transfers, and then restarts the ring. If another timeout triggers a parallel call into the same function, the two instances may interfere with each other - stopping or restarting the ring at unexpected times.
Add a mutex so that hci_dma_dequeue_xfer() is serialized with respect to itself.
--- drivers/i3c/master/mipi-i3c-hci/core.c | 2 ++ drivers/i3c/master/mipi-i3c-hci/dma.c | 2 ++ drivers/i3c/master/mipi-i3c-hci/hci.h | 1 + 3 files changed, 5 insertions(+)
drivers/i3c/master/mipi-i3c-hci/core.c +2 -0
@@ -751,6 +751,8 @@ static int i3c_hci_probe(struct platform_device *pdev)if (IS_ERR (hci->base_regs))return PTR_ERR (hci->base_regs); +mutex_init (&hci->control_mutex); +platform_set_drvdata (pdev, hci);/* temporary for dev_printk's, to be replaced in i3c_master_register */ hci->master.dev.init_name =dev_name (&pdev->dev);
drivers/i3c/master/mipi-i3c-hci/dma.c +2 -0
@@ -450,6 +450,8 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,bool did_unqueue = false;u32 ring_status; +guard (mutex)(&hci->control_mutex); + ring_status =rh_reg_read (RING_STATUS );if (ring_status &RING_STATUS_RUNNING ) {/* stop the ring */
drivers/i3c/master/mipi-i3c-hci/hci.h +1 -0
@@ -43,6 +43,7 @@ struct i3c_hci {const struct hci_io_ops *io;void *io_data;const struct hci_cmd_ops *cmd; +struct mutex control_mutex;atomic_t next_cmd_tid;u32 caps;unsigned int quirks;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1015/1887 scsi: qla2xxx: Completely fix fcport double free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Riabchun <[email protected]>
[ Upstream commit c0b7da13a04bd70ef6070bfb9ea85f582294560a ]
In qla24xx_els_dcmd_iocb() sp->free is set to qla2x00_els_dcmd_sp_free(). When an error happens, this function is called by qla2x00_sp_release(), when kref_put() releases the first and the last reference.
qla2x00_els_dcmd_sp_free() frees fcport by calling qla2x00_free_fcport(). Doing it one more time after kref_put() is a bad idea.
--- drivers/scsi/qla2xxx/qla_iocb.c | 2 -- 1 file changed, 2 deletions(-)
drivers/scsi/qla2xxx/qla_iocb.c +0 -2
@@ -2754,7 +2754,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,if (!elsio->u.els_logo.els_logo_pyld) {/* ref: INIT */ kref_put (&sp->cmd_kref, qla2x00_sp_release); -qla2x00_free_fcport (fcport);return QLA_FUNCTION_FAILED ; }
@@ -2779,7 +2778,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,if (rval !=QLA_SUCCESS ) {/* ref: INIT */ kref_put (&sp->cmd_kref, qla2x00_sp_release); -qla2x00_free_fcport (fcport);return QLA_FUNCTION_FAILED ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1016/1887 ceph: fix memory leaks in ceph_mdsc_build_path()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
[ Upstream commit 040d159a45ded7f33201421a81df0aa2a86e5a0b ]
Add __putname() calls to error code paths that did not free the "path" pointer obtained by __getname(). If ownership of this pointer is not passed to the caller via path_info.path, the function must free it before returning.
--- fs/ceph/mds_client.c | 1 + 1 file changed, 1 insertion(+)
fs/ceph/mds_client.c +1 -0
@@ -2453,6 +2453,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,* cannot ever succeed. Creating paths that long is * possible with Ceph, but Linux cannot use them. */ +__putname (path);return ERR_PTR (-ENAMETOOLONG ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1017/1887 ASoC: amd: acp: Add setbias level for rt5682s codec in machine driver
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Venkata Prasad Potturu <[email protected]>
[ Upstream commit 9e693e81745f03845788ef409f03a39e92f8dd48 ]
Add set_bais_level function for rt5682s codec to enable bclk and lrclk before codec widgets power on and disable bclk and lrclk after widgets power down, to avoid pop noise
Stable-dep-of: 30c64fb98399 ("ASoC: amd: acp-mach-common: Add missing error check for clock acquisition")
--- sound/soc/amd/acp/acp-mach-common.c | 62 ++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-)
sound/soc/amd/acp/acp-mach-common.c +56 -6
@@ -167,11 +167,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) &constraints_channels);snd_pcm_hw_constraint_list (runtime,0 ,SNDRV_PCM_HW_PARAM_RATE , &constraints_rates); -if (!drvdata->soc_mclk) { - ret =acp_clk_enable (drvdata); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to enable HS clk: %d\n" , ret); -return ret; + +if (strcmp (codec_dai->name,"rt5682s-aif1" ) &&strcmp (codec_dai->name,"rt5682s-aif2" )) { +if (!drvdata->soc_mclk) { + ret =acp_clk_enable (drvdata); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to enable HS clk: %d\n" , ret); +return ret; + } } }
@@ -280,7 +283,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)static const struct snd_soc_ops acp_card_rt5682s_ops = { .startup = acp_card_hs_startup, - .shutdown = acp_card_shutdown, };static const unsigned int dmic_channels[] = {
@@ -570,6 +572,52 @@ SND_SOC_DAILINK_DEF(sof_dmic,SND_SOC_DAILINK_DEF (pdm_dmic,DAILINK_COMP_ARRAY (COMP_CPU ("acp-pdm-dmic" ))); +static int acp_rtk_set_bias_level (struct snd_soc_card *card, +struct snd_soc_dapm_context *dapm, +enum snd_soc_bias_level level) +{ +struct snd_soc_component *component = dapm->component; +struct acp_card_drvdata *drvdata = card->drvdata; +int ret =0 ; + +if (!component) +return 0 ; + +if (strncmp (component->name,"i2c-RTL5682" ,11 ) && +strncmp (component->name,"i2c-10EC1019" ,12 )) +return 0 ; + +/* +* For Realtek's codec and amplifier components, +* the lrck and bclk must be enabled brfore their all dapms be powered on, +* and must be disabled after their all dapms be powered down +* to avoid any pop. +*/ +switch (level) { +case SND_SOC_BIAS_STANDBY : +if (snd_soc_dapm_get_bias_level (dapm) ==SND_SOC_BIAS_OFF ) { +clk_set_rate (drvdata->wclk,48000 ); +clk_set_rate (drvdata->bclk,48000 *64 ); + +/* Increase bclk's enable_count */ + ret =clk_prepare_enable (drvdata->bclk); +if (ret <0 ) +dev_err (component->dev,"Failed to enable bclk %d\n" , ret); + }else { +/* +* Decrease bclk's enable_count. +* While the enable_count is 0, the bclk would be closed. +*/ +clk_disable_unprepare (drvdata->bclk); + } +break ; +default : +break ; + } + +return ret; +} +int acp_sofdsp_dai_links_create (struct snd_soc_card *card) {struct snd_soc_dai_link *links;
@@ -730,6 +778,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) card->dai_link = links; card->num_links = num_links; + card->set_bias_level = acp_rtk_set_bias_level;return 0 ; }
@@ -907,6 +956,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) card->dai_link = links; card->num_links = num_links; + card->set_bias_level = acp_rtk_set_bias_level;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1018/1887 ASoC: amd: acp: Refactor dai format implementation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Venkata Prasad Potturu <[email protected]>
[ Upstream commit af830fc44a2d273b163e76b17f51b128ce694481 ]
Refactor dai format implementation in dai_link specific snd_soc_ops.
Stable-dep-of: 30c64fb98399 ("ASoC: amd: acp-mach-common: Add missing error check for clock acquisition")
--- sound/soc/amd/acp/acp-mach-common.c | 152 ++++++++++++++++++++++------ 1 file changed, 122 insertions(+), 30 deletions(-)
sound/soc/amd/acp/acp-mach-common.c +122 -30
@@ -86,13 +86,6 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=RT5682 )return -EINVAL ; - ret =snd_soc_dai_set_fmt (codec_dai,SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF - |SND_SOC_DAIFMT_CBP_CFP ); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); -return ret; - } - ret =snd_soc_dai_set_pll (codec_dai,RT5682_PLL2 ,RT5682_PLL2_S_MCLK ,PCO_PLAT_CLK ,RT5682_PLL_FREQ );if (ret <0 ) {
@@ -191,9 +184,41 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)clk_disable_unprepare (drvdata->wclk); } +static int acp_card_rt5682_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params) +{ +struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct snd_soc_card *card = rtd->card; +struct acp_card_drvdata *drvdata = card->drvdata; +struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 ); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 ); +int ret; +unsigned int fmt; + +if (drvdata->soc_mclk) + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; +else + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; + + ret =snd_soc_dai_set_fmt (cpu_dai, fmt); +if (ret && ret != -ENOTSUPP ) { +dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } + + ret =snd_soc_dai_set_fmt (codec_dai, fmt); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } + +return 0 ; +} +static const struct snd_soc_ops acp_card_rt5682_ops = { .startup = acp_card_hs_startup, .shutdown = acp_card_shutdown, + .hw_params = acp_card_rt5682_hw_params, };/* Define RT5682S CODEC component*/
@@ -212,7 +237,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 );struct snd_soc_component *component = codec_dai->component; -unsigned int fmt;int ret;dev_info (rtd->dev,"codec dai name = %s\n" , codec_dai->name);
@@ -220,17 +244,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=RT5682S )return -EINVAL ; -if (drvdata->soc_mclk) - fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; -else - fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; - - ret =snd_soc_dai_set_fmt (codec_dai, fmt); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); -return ret; - } - ret =snd_soc_dai_set_pll (codec_dai,RT5682S_PLL2 ,RT5682S_PLL_S_MCLK ,PCO_PLAT_CLK ,RT5682_PLL_FREQ );if (ret <0 ) {
@@ -281,8 +294,40 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)return snd_soc_dapm_add_routes (&rtd->card->dapm, rt5682s_map,ARRAY_SIZE (rt5682s_map)); } +static int acp_card_rt5682s_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params) +{ +struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct snd_soc_card *card = rtd->card; +struct acp_card_drvdata *drvdata = card->drvdata; +struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 ); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 ); +int ret; +unsigned int fmt; + +if (drvdata->soc_mclk) + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; +else + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; + + ret =snd_soc_dai_set_fmt (cpu_dai, fmt); +if (ret && ret != -ENOTSUPP ) { +dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } + + ret =snd_soc_dai_set_fmt (codec_dai, fmt); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } + +return 0 ; +} +static const struct snd_soc_ops acp_card_rt5682s_ops = { .startup = acp_card_hs_startup, + .hw_params = acp_card_rt5682s_hw_params, };static const unsigned int dmic_channels[] = {
@@ -351,13 +396,26 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,struct snd_soc_card *card = rtd->card;struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *codec_dai; +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 );int srate, i, ret =0 ; +unsigned int fmt; srate =params_rate (params);if (drvdata->amp_codec_id !=RT1019 )return -EINVAL ; +if (drvdata->soc_mclk) + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; +else + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; + + ret =snd_soc_dai_set_fmt (cpu_dai, fmt); +if (ret && ret != -ENOTSUPP ) { +dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } +for_each_rtd_codec_dais (rtd, i, codec_dai) {if (strcmp (codec_dai->name,"rt1019-aif" ))continue ;
@@ -426,9 +484,33 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd) ARRAY_SIZE(max98360a_map)); } +static int acp_card_maxim_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params) +{ +struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct snd_soc_card *card = rtd->card; +struct acp_card_drvdata *drvdata = card->drvdata; +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 ); +unsigned int fmt; +int ret; + +if (drvdata->soc_mclk) + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; +else + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; + + ret =snd_soc_dai_set_fmt (cpu_dai, fmt); +if (ret && ret != -ENOTSUPP ) { +dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } +return 0 ; +} +static const struct snd_soc_ops acp_card_maxim_ops = { .startup = acp_card_amp_startup, .shutdown = acp_card_shutdown, + .hw_params = acp_card_maxim_hw_params, };/* Declare nau8825 codec components */
@@ -446,7 +528,6 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 );struct snd_soc_component *component = codec_dai->component; -unsigned int fmt;int ret;dev_info (rtd->dev,"codec dai name = %s\n" , codec_dai->name);
@@ -454,16 +535,6 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=NAU8825 )return -EINVAL ; -if (drvdata->soc_mclk) - fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; -else - fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; - - ret =snd_soc_dai_set_fmt (codec_dai, fmt); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); -return ret; - } ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -492,8 +563,12 @@ static int acp_nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) {struct snd_soc_pcm_runtime *rtd =asoc_substream_to_rtd (substream); +struct snd_soc_card *card = rtd->card; +struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 ); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 );int ret; +unsigned int fmt; ret =snd_soc_dai_set_sysclk (codec_dai,NAU8825_CLK_FLL_FS , (48000 *256 ),SND_SOC_CLOCK_IN );
@@ -507,6 +582,23 @@ static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,return ret; } +if (drvdata->soc_mclk) + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ; +else + fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBP_CFP ; + + ret =snd_soc_dai_set_fmt (cpu_dai, fmt); +if (ret && ret != -ENOTSUPP ) { +dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } + + ret =snd_soc_dai_set_fmt (codec_dai, fmt); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to set dai fmt: %d\n" , ret); +return ret; + } +return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1019/1887 ASoC: amd: acp: Refactor i2s clocks programming sequence
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Venkata Prasad Potturu <[email protected]>
[ Upstream commit ca9d237994db63dca68f2b04e257a4738847deee ]
Refactor i2s clock values based on hw_params and use srate and bclk_ratio variables in clock enable API instead hard-code values.
Stable-dep-of: 30c64fb98399 ("ASoC: amd: acp-mach-common: Add missing error check for clock acquisition")
--- sound/soc/amd/acp/acp-mach-common.c | 169 ++++++++++++++++------------ 1 file changed, 94 insertions(+), 75 deletions(-)
sound/soc/amd/acp/acp-mach-common.c +94 -75
@@ -54,10 +54,11 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; -static int acp_clk_enable (struct acp_card_drvdata *drvdata) +static int acp_clk_enable (struct acp_card_drvdata *drvdata, +unsigned int srate,unsigned int bclk_ratio) { -clk_set_rate (drvdata->wclk,48000 ); -clk_set_rate (drvdata->bclk,48000 *64 ); +clk_set_rate (drvdata->wclk, srate); +clk_set_rate (drvdata->bclk, srate * bclk_ratio);return clk_prepare_enable (drvdata->wclk); }
@@ -86,27 +87,6 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=RT5682 )return -EINVAL ; - ret =snd_soc_dai_set_pll (codec_dai,RT5682_PLL2 ,RT5682_PLL2_S_MCLK , -PCO_PLAT_CLK ,RT5682_PLL_FREQ ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set codec PLL: %d\n" , ret); -return ret; - } - - ret =snd_soc_dai_set_sysclk (codec_dai,RT5682_SCLK_S_PLL2 , -RT5682_PLL_FREQ ,SND_SOC_CLOCK_IN ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set codec SYSCLK: %d\n" , ret); -return ret; - } - -/* Set tdm/i2s1 master bclk ratio */ - ret =snd_soc_dai_set_bclk_ratio (codec_dai,64 ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set rt5682 tdm bclk ratio: %d\n" , ret); -return ret; - } - drvdata->wclk =clk_get (component->dev,"rt5682-dai-wclk" ); drvdata->bclk =clk_get (component->dev,"rt5682-dai-bclk" );
@@ -161,16 +141,6 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)snd_pcm_hw_constraint_list (runtime,0 ,SNDRV_PCM_HW_PARAM_RATE , &constraints_rates); -if (strcmp (codec_dai->name,"rt5682s-aif1" ) &&strcmp (codec_dai->name,"rt5682s-aif2" )) { -if (!drvdata->soc_mclk) { - ret =acp_clk_enable (drvdata); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to enable HS clk: %d\n" , ret); -return ret; - } - } - } -return ret; }
@@ -193,7 +163,11 @@ static int acp_card_rt5682_hw_params(struct snd_pcm_substream *substream,struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 );struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 );int ret; -unsigned int fmt; +unsigned int fmt, srate, ch, format; + + srate =params_rate (params); + ch =params_channels (params); + format =8 *params_format (params);if (drvdata->soc_mclk) fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ;
@@ -212,6 +186,35 @@ static int acp_card_rt5682_hw_params(struct snd_pcm_substream *substream,return ret; } + ret =snd_soc_dai_set_pll (codec_dai,RT5682_PLL2 ,RT5682_PLL2_S_MCLK , +PCO_PLAT_CLK ,RT5682_PLL_FREQ ); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set codec PLL: %d\n" , ret); +return ret; + } + + ret =snd_soc_dai_set_sysclk (codec_dai,RT5682_SCLK_S_PLL2 , +RT5682_PLL_FREQ ,SND_SOC_CLOCK_IN ); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set codec SYSCLK: %d\n" , ret); +return ret; + } + +/* Set tdm/i2s1 master bclk ratio */ + ret =snd_soc_dai_set_bclk_ratio (codec_dai, ch * format); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set rt5682 tdm bclk ratio: %d\n" , ret); +return ret; + } + +if (!drvdata->soc_mclk) { + ret =acp_clk_enable (drvdata, srate, ch * format); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to enable HS clk: %d\n" , ret); +return ret; + } + } +return 0 ; }
@@ -244,27 +247,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=RT5682S )return -EINVAL ; - ret =snd_soc_dai_set_pll (codec_dai,RT5682S_PLL2 ,RT5682S_PLL_S_MCLK , -PCO_PLAT_CLK ,RT5682_PLL_FREQ ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set codec PLL: %d\n" , ret); -return ret; - } - - ret =snd_soc_dai_set_sysclk (codec_dai,RT5682S_SCLK_S_PLL2 , -RT5682_PLL_FREQ ,SND_SOC_CLOCK_IN ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set codec SYSCLK: %d\n" , ret); -return ret; - } - -/* Set tdm/i2s1 master bclk ratio */ - ret =snd_soc_dai_set_bclk_ratio (codec_dai,64 ); -if (ret <0 ) { -dev_err (rtd->dev,"Failed to set rt5682 tdm bclk ratio: %d\n" , ret); -return ret; - } -if (!drvdata->soc_mclk) { drvdata->wclk =clk_get (component->dev,"rt5682-dai-wclk" ); drvdata->bclk =clk_get (component->dev,"rt5682-dai-bclk" );
@@ -303,7 +285,11 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_dai *codec_dai =asoc_rtd_to_codec (rtd,0 );struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 );int ret; -unsigned int fmt; +unsigned int fmt, srate, ch, format; + + srate =params_rate (params); + ch =params_channels (params); + format =8 *params_format (params);if (drvdata->soc_mclk) fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ;
@@ -322,6 +308,30 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,return ret; } + ret =snd_soc_dai_set_pll (codec_dai,RT5682S_PLL2 ,RT5682S_PLL_S_MCLK , +PCO_PLAT_CLK ,RT5682_PLL_FREQ ); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set codec PLL: %d\n" , ret); +return ret; + } + + ret =snd_soc_dai_set_sysclk (codec_dai,RT5682S_SCLK_S_PLL2 , +RT5682_PLL_FREQ ,SND_SOC_CLOCK_IN ); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set codec SYSCLK: %d\n" , ret); +return ret; + } + +/* Set tdm/i2s1 master bclk ratio */ + ret =snd_soc_dai_set_bclk_ratio (codec_dai, ch * format); +if (ret <0 ) { +dev_err (rtd->dev,"Failed to set rt5682 tdm bclk ratio: %d\n" , ret); +return ret; + } + +clk_set_rate (drvdata->wclk, srate); +clk_set_rate (drvdata->bclk, srate * ch * format); +return 0 ; }
@@ -397,10 +407,12 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *codec_dai;struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 ); -int srate, i, ret =0 ; -unsigned int fmt; +int i, ret =0 ; +unsigned int fmt, srate, ch, format; srate =params_rate (params); + ch =params_channels (params); + format =8 *params_format (params);if (drvdata->amp_codec_id !=RT1019 )return -EINVAL ;
@@ -421,7 +433,7 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,continue ; ret =snd_soc_dai_set_pll (codec_dai,0 ,RT1019_PLL_S_BCLK , -64 * srate,256 * srate); + ch * format * srate,256 * srate);if (ret <0 )return ret;
@@ -431,16 +443,20 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,return ret; } +if (!drvdata->soc_mclk) { + ret =acp_clk_enable (drvdata, srate, ch * format); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to enable AMP clk: %d\n" , ret); +return ret; + } + } +return 0 ; }static int acp_card_amp_startup (struct snd_pcm_substream *substream) {struct snd_pcm_runtime *runtime = substream->runtime; -struct snd_soc_pcm_runtime *rtd =asoc_substream_to_rtd (substream); -struct snd_soc_card *card = rtd->card; -struct acp_card_drvdata *drvdata = card->drvdata; -int ret =0 ; runtime->hw.channels_max =DUAL_CHANNEL ; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -448,14 +464,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)snd_pcm_hw_constraint_list (runtime,0 ,SNDRV_PCM_HW_PARAM_RATE , &constraints_rates); -if (!drvdata->soc_mclk) { - ret =acp_clk_enable (drvdata); -if (ret <0 ) { -dev_err (rtd->card->dev,"Failed to enable AMP clk: %d\n" , ret); -return ret; - } - } -return ret; +return 0 ; }static const struct snd_soc_ops acp_card_rt1019_ops = {
@@ -491,9 +500,13 @@ static int acp_card_maxim_hw_params(struct snd_pcm_substream *substream,struct snd_soc_card *card = rtd->card;struct acp_card_drvdata *drvdata = card->drvdata;struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (rtd,0 ); -unsigned int fmt; +unsigned int fmt, srate, ch, format;int ret; + srate =params_rate (params); + ch =params_channels (params); + format =8 *params_format (params); +if (drvdata->soc_mclk) fmt =SND_SOC_DAIFMT_I2S |SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBC_CFC ;else
@@ -504,6 +517,14 @@ static int acp_card_maxim_hw_params(struct snd_pcm_substream *substream,dev_err (rtd->dev,"Failed to set dai fmt: %d\n" , ret);return ret; } + +if (!drvdata->soc_mclk) { + ret =acp_clk_enable (drvdata, srate, ch * format); +if (ret <0 ) { +dev_err (rtd->card->dev,"Failed to enable AMP clk: %d\n" , ret); +return ret; + } + }return 0 ; }
@@ -688,8 +709,6 @@ static int acp_rtk_set_bias_level(struct snd_soc_card *card,switch (level) {case SND_SOC_BIAS_STANDBY :if (snd_soc_dapm_get_bias_level (dapm) ==SND_SOC_BIAS_OFF ) { -clk_set_rate (drvdata->wclk,48000 ); -clk_set_rate (drvdata->bclk,48000 *64 );/* Increase bclk's enable_count */ ret =clk_prepare_enable (drvdata->bclk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1020/1887 ASoC: amd: acp-mach-common: Add missing error check for clock acquisition
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ni <[email protected]>
[ Upstream commit 30c64fb9839949f085c8eb55b979cbd8a4c51f00 ]
The acp_card_rt5682_init() and acp_card_rt5682s_init() functions did not check the return values of clk_get(). This could lead to a kernel crash when the invalid pointers are later dereferenced by clock core functions.
Fix this by:
1. Changing clk_get() to the device-managed devm_clk_get().
2. Adding IS_ERR() checks immediately after each clock acquisition.
--- sound/soc/amd/acp/acp-mach-common.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
sound/soc/amd/acp/acp-mach-common.c +14 -4
@@ -87,8 +87,13 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)if (drvdata->hs_codec_id !=RT5682 )return -EINVAL ; - drvdata->wclk =clk_get (component->dev,"rt5682-dai-wclk" ); - drvdata->bclk =clk_get (component->dev,"rt5682-dai-bclk" ); + drvdata->wclk =devm_clk_get (component->dev,"rt5682-dai-wclk" ); +if (IS_ERR (drvdata->wclk)) +return PTR_ERR (drvdata->wclk); + + drvdata->bclk =devm_clk_get (component->dev,"rt5682-dai-bclk" ); +if (IS_ERR (drvdata->bclk)) +return PTR_ERR (drvdata->bclk); ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT |
@@ -248,8 +253,13 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)return -EINVAL ;if (!drvdata->soc_mclk) { - drvdata->wclk =clk_get (component->dev,"rt5682-dai-wclk" ); - drvdata->bclk =clk_get (component->dev,"rt5682-dai-bclk" ); + drvdata->wclk =devm_clk_get (component->dev,"rt5682-dai-wclk" ); +if (IS_ERR (drvdata->wclk)) +return PTR_ERR (drvdata->wclk); + + drvdata->bclk =devm_clk_get (component->dev,"rt5682-dai-bclk" ); +if (IS_ERR (drvdata->bclk)) +return PTR_ERR (drvdata->bclk); } ret = snd_soc_card_jack_new(card, "Headset Jack",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1021/1887 bonding: fix type confusion in bond_setup_by_slave()
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 950803f7254721c1c15858fbbfae3deaaeeecb11 ]
kernel BUG at net/core/skbuff.c:2306!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI RIP: 0010:pskb_expand_head+0xa08/0xfe0 net/core/skbuff.c:2306 RSP: 0018:ffffc90004aff760 EFLAGS: 00010293 RAX: 0000000000000000 RBX: ffff88807e3c8780 RCX: ffffffff89593e0e RDX: ffff88807b7c4900 RSI: ffffffff89594747 RDI: ffff88807b7c4900 RBP: 0000000000000820 R08: 0000000000000005 R09: 0000000000000000 R10: 00000000961a63e0 R11: 0000000000000000 R12: ffff88807e3c8780 R13: 00000000961a6560 R14: dffffc0000000000 R15: 00000000961a63e0 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fe1a0ed8df0 CR3: 000000002d816000 CR4: 00000000003526f0 Call Trace: <TASK> ipgre_header+0xdd/0x540 net/ipv4/ip_gre.c:900 dev_hard_header include/linux/netdevice.h:3439 [inline] packet_snd net/packet/af_packet.c:3028 [inline] packet_sendmsg+0x3ae5/0x53c0 net/packet/af_packet.c:3108 sock_sendmsg_nosec net/socket.c:727 [inline] __sock_sendmsg net/socket.c:742 [inline] ____sys_sendmsg+0xa54/0xc30 net/socket.c:2592 ___sys_sendmsg+0x190/0x1e0 net/socket.c:2646 __sys_sendmsg+0x170/0x220 net/socket.c:2678 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x106/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fe1a0e6c1a9
When a non-Ethernet device (e.g. GRE tunnel) is enslaved to a bond, bond_setup_by_slave() directly copies the slave's header_ops to the bond device:
bond_dev->header_ops = slave_dev->header_ops;
This causes a type confusion when dev_hard_header() is later called on the bond device. Functions like ipgre_header(), ip6gre_header(),all use netdev_priv(dev) to access their device-specific private data. When called with the bond device, netdev_priv() returns the bond's private data (struct bonding) instead of the expected type (e.g. struct ip_tunnel), leading to garbage values being read and kernel crashes.
Fix this by introducing bond_header_ops with wrapper functions that delegate to the active slave's header_ops using the slave's own device. This ensures netdev_priv() in the slave's header functions always receives the correct device.
The fix is placed in the bonding driver rather than individual device drivers, as the root cause is bond blindly inheriting header_ops from the slave without considering that these callbacks expect a specific netdev_priv() layout.
The type confusion can be observed by adding a printk in ipgre_header() and running the following commands:
ip link add dummy0 type dummy
ip addr add 10.0.0.1/24 dev dummy0
ip link set dummy0 up
ip link add gre1 type gre local 10.0.0.1 ip link add bond1 type bond mode active-backup ip link set gre1 master bond1
ip link set gre1 up
ip link set bond1 up
ip addr add fe80::1/64 dev bond1
--- drivers/net/bonding/bond_main.c | 47 ++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)
drivers/net/bonding/bond_main.c +46 -1
@@ -1543,6 +1543,50 @@ static void bond_compute_features(struct bonding *bond)netdev_change_features (bond_dev); } +static int bond_header_create (struct sk_buff *skb,struct net_device *bond_dev, +unsigned short type,const void *daddr, +const void *saddr,unsigned int len) +{ +struct bonding *bond =netdev_priv (bond_dev); +const struct header_ops *slave_ops; +struct slave *slave; +int ret =0 ; + +rcu_read_lock (); + slave =rcu_dereference (bond->curr_active_slave); +if (slave) { + slave_ops =READ_ONCE (slave->dev->header_ops); +if (slave_ops && slave_ops->create) + ret = slave_ops->create (skb, slave->dev, + type, daddr, saddr, len); + } +rcu_read_unlock (); +return ret; +} + +static int bond_header_parse (const struct sk_buff *skb,unsigned char *haddr) +{ +struct bonding *bond =netdev_priv (skb->dev); +const struct header_ops *slave_ops; +struct slave *slave; +int ret =0 ; + +rcu_read_lock (); + slave =rcu_dereference (bond->curr_active_slave); +if (slave) { + slave_ops =READ_ONCE (slave->dev->header_ops); +if (slave_ops && slave_ops->parse) + ret = slave_ops->parse (skb, haddr); + } +rcu_read_unlock (); +return ret; +} + +static const struct header_ops bond_header_ops = { + .create = bond_header_create, + .parse = bond_header_parse, +}; +static void bond_setup_by_slave (struct net_device *bond_dev,struct net_device *slave_dev) {
@@ -1550,7 +1594,8 @@ static void bond_setup_by_slave(struct net_device *bond_dev,dev_close (bond_dev); - bond_dev->header_ops = slave_dev->header_ops; + bond_dev->header_ops = slave_dev->header_ops ? + &bond_header_ops :NULL ; bond_dev->type = slave_dev->type; bond_dev->hard_header_len = slave_dev->hard_header_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1022/1887 ksmbd: validate inherited ACE SID length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shota Zaizen <[email protected]>
[ Upstream commit 996454bc0da84d5a1dedb1a7861823087e01a7ae ]
smb_inherit_dacl() walks the parent directory DACL loaded from the security descriptor xattr. It verifies that each ACE contains the fixed SID header before using it, but does not verify that the variable-length SID described by sid.num_subauth is fully contained in the ACE.
A malformed inheritable ACE can advertise more subauthorities than are present in the ACE. compare_sids() may then read past the ACE. smb_set_ace() also clamps the copied destination SID, but used the unchecked source SID count to compute the inherited ACE size. That could advance the temporary inherited ACE buffer pointer and nt_size accounting past the allocated buffer.
Fix this by validating the parent ACE SID count and SID length before using the SID during inheritance. Compute the inherited ACE size from the copied SID so the size matches the bounded destination SID. Reject the inherited DACL if size accumulation would overflow smb_acl.size or the security descriptor allocation size.
--- fs/smb/server/smbacl.c | 66 +++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 14 deletions(-)
fs/smb/server/smbacl.c +52 -14
@@ -1105,7 +1105,26 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, ace->flags = flags; ace->access_req = access_req;smb_copy_sid (&ace->sid, sid); - ace->size =cpu_to_le16 (1 +1 +2 +4 +1 +1 +6 + (sid->num_subauth *4 )); + ace->size =cpu_to_le16 (1 +1 +2 +4 +1 +1 +6 + + (ace->sid.num_subauth *4 )); +} + +static int smb_append_inherited_ace (struct smb_ace **ace,int *nt_size, +int *ace_cnt,const struct smb_sid *sid, +u8 type,u8 flags,__le32 access_req) +{ +int ace_size; + +smb_set_ace (*ace, sid, type, flags, access_req); + ace_size =le16_to_cpu ((*ace)->size); +/* pdacl->size is __le16 and includes struct smb_acl. */ +if (check_add_overflow (*nt_size, ace_size, nt_size) || + *nt_size >U16_MAX - (int )sizeof (struct smb_acl )) +return -EINVAL ; + + (*ace_cnt)++; + *ace = (struct smb_ace *)((char *)*ace + ace_size); +return 0 ; } int smb_inherit_dacl(struct ksmbd_conn *conn,
@@ -1193,6 +1212,12 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, CIFS_SID_BASE_SIZE)break ; +if (parent_aces->sid.num_subauth >SID_MAX_SUB_AUTHORITIES || + pace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE + +sizeof (__le32) * parent_aces->sid.num_subauth) +break ; + aces_size -= pace_size; flags = parent_aces->flags;
@@ -1222,22 +1247,24 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, }if (is_dir && creator && flags &CONTAINER_INHERIT_ACE ) { -smb_set_ace (aces, psid, parent_aces->type, inherited_flags, - parent_aces->access_req); - nt_size +=le16_to_cpu (aces->size); - ace_cnt++; - aces = (struct smb_ace *)((char *)aces +le16_to_cpu (aces->size)); + rc =smb_append_inherited_ace (&aces, &nt_size, &ace_cnt, + psid, parent_aces->type, + inherited_flags, + parent_aces->access_req); +if (rc) + goto free_aces_base; flags |=INHERIT_ONLY_ACE ; psid = creator; }else if (is_dir && !(parent_aces->flags &NO_PROPAGATE_INHERIT_ACE )) { psid = &parent_aces->sid; } -smb_set_ace (aces, psid, parent_aces->type, flags | inherited_flags, - parent_aces->access_req); - nt_size +=le16_to_cpu (aces->size); - aces = (struct smb_ace *)((char *)aces +le16_to_cpu (aces->size)); - ace_cnt++; + rc =smb_append_inherited_ace (&aces, &nt_size, &ace_cnt, psid, + parent_aces->type, + flags | inherited_flags, + parent_aces->access_req); +if (rc) + goto free_aces_base; pass: parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); }
@@ -1247,7 +1274,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,struct smb_acl *pdacl;struct smb_sid *powner_sid =NULL , *pgroup_sid =NULL ;int powner_sid_size =0 , pgroup_sid_size =0 , pntsd_size; -int pntsd_alloc_size; +size_t pntsd_alloc_size;if (parent_pntsd->osidoffset) { powner_sid = (struct smb_sid *)((char *)parent_pntsd +
@@ -1260,8 +1287,19 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, pgroup_sid_size =1 +1 +6 + (pgroup_sid->num_subauth *4 ); } - pntsd_alloc_size =sizeof (struct smb_ntsd ) + powner_sid_size + - pgroup_sid_size +sizeof (struct smb_acl ) + nt_size; +if (check_add_overflow (sizeof (struct smb_ntsd ), + (size_t )powner_sid_size, + &pntsd_alloc_size) || +check_add_overflow (pntsd_alloc_size, + (size_t )pgroup_sid_size, + &pntsd_alloc_size) || +check_add_overflow (pntsd_alloc_size,sizeof (struct smb_acl ), + &pntsd_alloc_size) || +check_add_overflow (pntsd_alloc_size, (size_t )nt_size, + &pntsd_alloc_size)) { + rc = -EINVAL ; + goto free_aces_base; + } pntsd =kzalloc (pntsd_alloc_size,GFP_KERNEL );if (!pntsd) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1023/1887 ata: libata-scsi: avoid Non-NCQ command starvation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Le Moal <[email protected]>
[ Upstream commit 0ea84089dbf62a92dc7889c79e6b18fc89260808 ]
When a non-NCQ command is issued while NCQ commands are being executed, ata_scsi_qc_issue() indicates to the SCSI layer that the command issuing should be deferred by returning SCSI_MLQUEUE_XXX_BUSY. This command deferring is correct and as mandated by the ACS specifications since NCQ and non-NCQ commands cannot be mixed.
However, in the case of a host adapter using multiple submission queues, when the target device is under a constant load of NCQ commands, there are no guarantees that requeueing the non-NCQ command will be executed later and it may be deferred again repeatedly as other submission queues can constantly issue NCQ commands from different CPUs ahead of the non-NCQ command. This can lead to very long delays for the execution of non-NCQ commands, and even complete starvation for these commands in the worst case scenario.
Since the block layer and the SCSI layer do not distinguish between queueable (NCQ) and non queueable (non-NCQ) commands, libata-scsi SAT implementation must ensure forward progress for non-NCQ commands in the presence of NCQ command traffic. This is similar to what SAS HBAs with a hardware/firmware based SAT implementation do.
Implement such forward progress guarantee by limiting requeueing of non-NCQ commands from ata_scsi_qc_issue(): when a non-NCQ command is received and NCQ commands are in-flight, do not force a requeue of the non-NCQ command by returning SCSI_MLQUEUE_XXX_BUSY and instead return 0 to indicate that the command was accepted but hold on to the qc using the new deferred_qc field of struct ata_port.
This deferred qc will be issued using the work item deferred_qc_work running the function ata_scsi_deferred_qc_work() once all in-flight commands complete, which is checked with the port qc_defer() callback return value indicating that no further delay is necessary. This check is done using the helper function ata_scsi_schedule_deferred_qc() which is called from ata_scsi_qc_complete(). This thus excludes this mechanism from all internal non-NCQ commands issued by ATA EH.
When a port deferred_qc is non NULL, that is, the port has a command waiting for the device queue to drain, the issuing of all incoming commands (both NCQ and non-NCQ) is deferred using the regular busy mechanism. This simplifies the code and also avoids potential denial of service problems if a user issues too many non-NCQ commands.
Finally, whenever ata EH is scheduled, regardless of the reason, a deferred qc is always requeued so that it can be retried once EH completes. This is done by calling the function ata_scsi_requeue_deferred_qc() from ata_eh_set_pending(). This avoids the need for any special processing for the deferred qc in case of NCQ error, link or device reset, or device timeout.
--- drivers/ata/libata-core.c | 5 +++ drivers/ata/libata-eh.c | 6 +++ drivers/ata/libata-scsi.c | 93 +++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 2 + include/linux/libata.h | 3 ++ 5 files changed, 109 insertions(+)
drivers/ata/libata-core.c +5 -0
@@ -5499,6 +5499,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)mutex_init (&ap->scsi_scan_mutex);INIT_DELAYED_WORK (&ap->hotplug_task, ata_scsi_hotplug);INIT_DELAYED_WORK (&ap->scsi_rescan_task, ata_scsi_dev_rescan); +INIT_WORK (&ap->deferred_qc_work, ata_scsi_deferred_qc_work);INIT_LIST_HEAD (&ap->eh_done_q);init_waitqueue_head (&ap->eh_wait_q);init_completion (&ap->park_req_pending);
@@ -6114,6 +6115,10 @@ static void ata_port_detach(struct ata_port *ap) } } +/* Make sure the deferred qc work finished. */ +cancel_work_sync (&ap->deferred_qc_work); +WARN_ON (ap->deferred_qc); +/* Tell EH to disable all devices */ ap->pflags |=ATA_PFLAG_UNLOADING ;ata_port_schedule_eh (ap);
drivers/ata/libata-eh.c +6 -0
@@ -910,6 +910,12 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) ap->pflags |=ATA_PFLAG_EH_PENDING ; +/* +* If we have a deferred qc, requeue it so that it is retried once EH +* completes. +*/ +ata_scsi_requeue_deferred_qc (ap); +if (!fastdrain)return ;
drivers/ata/libata-scsi.c +93 -0
117 lines not on this page · raw message
drivers/ata/libata.h +2 -0
@@ -142,6 +142,8 @@ extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,void ata_scsi_sdev_config (struct scsi_device *sdev);int ata_scsi_dev_config (struct scsi_device *sdev,struct ata_device *dev);int __ata_scsi_queuecmd (struct scsi_cmnd *scmd,struct ata_device *dev); +void ata_scsi_deferred_qc_work (struct work_struct *work); +void ata_scsi_requeue_deferred_qc (struct ata_port *ap);/* libata-eh.c */ extern unsigned int ata_internal_cmd_timeout (struct ata_device *dev,u8 cmd);
include/linux/libata.h +3 -0
@@ -830,6 +830,9 @@ struct ata_port {u64 qc_active;int nr_active_links;/* #links with active qcs */ +struct work_struct deferred_qc_work; +struct ata_queued_cmd *deferred_qc; +struct ata_link link;/* host default link */ struct ata_link *slave_link;/* see ata_slave_link_init() */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1024/1887 HID: Intel-ish-hid: Ishtp: Fix sensor reads after ACPI S3 suspend
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Even Xu <[email protected]>
[ Upstream commit bdab6c94bb24758081625e619330b04cfd56570a ]
After legacy suspend/resume via ACPI S3, sensor read operation fails with timeout. Also, it will cause delay in resume operation as there will be retries on failure.
This is caused by commit f645a90e8ff7 ("HID: intel-ish-hid:
ishtp-hid-client: use helper functions for connection"), which used helper functions to simplify connect, reset and disconnect process. Also avoid freeing and allocating client buffers again during reconnect process.
But there is a case, when ISH firmware resets after ACPI S3 suspend, ishtp bus driver frees client buffers. Since there is no realloc again during reconnect, there are no client buffers available to send connection requests to the firmware. Without successful connection to the firmware, subsequent sensor reads will timeout.
To address this issue, ishtp bus driver does not free client buffers on warm reset after S3 resume. Simply add the buffers from the read list to free list of buffers.
Stable-dep-of: 56f7db581ee7 ("HID: intel-ish-hid: fix NULL-ptr-deref in ishtp_bus_remove_all_clients")
--- drivers/hid/intel-ish-hid/ishtp/bus.c | 2 ++ drivers/hid/intel-ish-hid/ishtp/client.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-)
drivers/hid/intel-ish-hid/ishtp/bus.c +2 -0
@@ -730,6 +730,8 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,spin_lock_irqsave (&ishtp_dev->cl_list_lock, flags);list_for_each_entry (cl, &ishtp_dev->cl_list, link) { cl->state =ISHTP_CL_DISCONNECTED ; +if (warm_reset && cl->device->reference_count) +continue ;/* * Wake any pending process. The waiter would check dev->state
drivers/hid/intel-ish-hid/ishtp/client.c +3 -1
@@ -49,7 +49,9 @@ static void ishtp_read_list_flush(struct ishtp_cl *cl)list_for_each_entry_safe (rb, next, &cl->dev->read_list.list, list)if (rb->cl &&ishtp_cl_cmp_id (cl, rb->cl)) {list_del (&rb->list); -ishtp_io_rb_free (rb); +spin_lock (&cl->free_list_spinlock); +list_add_tail (&rb->list, &cl->free_rb_list.list); +spin_unlock (&cl->free_list_spinlock); }spin_unlock_irqrestore (&cl->dev->read_list_spinlock, flags); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1025/1887 HID: intel-ish-hid: fix NULL-ptr-deref in ishtp_bus_remove_all_clients
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Lin <[email protected]>
[ Upstream commit 56f7db581ee73af53cd512e00a6261a025bf1d58 ]
During a warm reset flow, the cl->device pointer may be NULL if the reset occurs while clients are still being enumerated. Accessing cl->device->reference_count without a NULL check leads to a kernel panic.
This issue was identified during multi-unit warm reboot stress clycles. Add a defensive NULL check for cl->device to ensure stability under such intensive testing conditions.
KASAN: null-ptr-deref in range [0000000000000000-0000000000000007] Workqueue: ish_fw_update_wq fw_reset_work_fn Call Trace: ishtp_bus_remove_all_clients+0xbe/0x130 [intel_ishtp] ishtp_reset_handler+0x85/0x1a0 [intel_ishtp] fw_reset_work_fn+0x8a/0xc0 [intel_ish_ipc]
--- drivers/hid/intel-ish-hid/ishtp/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/intel-ish-hid/ishtp/bus.c +1 -1
@@ -730,7 +730,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,spin_lock_irqsave (&ishtp_dev->cl_list_lock, flags);list_for_each_entry (cl, &ishtp_dev->cl_list, link) { cl->state =ISHTP_CL_DISCONNECTED ; -if (warm_reset && cl->device->reference_count) +if (warm_reset && cl->device && cl->device->reference_count)continue ;/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1026/1887 apparmor: Fix & Optimize table creation from possibly unaligned memory
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
[ Upstream commit 6fc367bfd4c8886e6b1742aabbd1c0bdc310db3a ]
Source blob may come from userspace and might be unaligned. Try to optize the copying process by avoiding unaligned memory accesses.
- Added Fixes tag
- Added "Fix &" to description as this doesn't just optimize but fixes a potential unaligned memory access
--- security/apparmor/include/match.h | 12 +++++++----- security/apparmor/match.c | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-)
security/apparmor/include/match.h +7 -5
@@ -105,16 +105,18 @@ struct aa_dfa {extern struct aa_dfa *nulldfa;extern struct aa_dfa *stacksplitdfa; -#define byte_to_byte (X ) (X) -#define UNPACK_ARRAY (TABLE ,BLOB ,LEN ,TTYPE ,BTYPE ,NTOHX ) \ do { \ typeof(LEN) __i; \ TTYPE *__t = (TTYPE *) TABLE; \ BTYPE *__b = (BTYPE *) BLOB; \ - for (__i = 0; __i < LEN; __i++) { \ - __t[__i] = NTOHX(__b[__i]); \ - } \ + BUILD_BUG_ON(sizeof(TTYPE) != sizeof(BTYPE)); \ + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) \ + memcpy(__t, __b, (LEN) * sizeof(BTYPE)); \ + else/* copy & convert from big-endian */ \ +for (__i =0 ; __i <LEN ; __i++) { \ + __t[__i] =NTOHX (&__b[__i]); \ + } \ }while (0 ) static inline size_t table_size(size_t len, size_t el_size)
security/apparmor/match.c +4 -4
@@ -8,6 +8,7 @@* Copyright 2009-2012 Canonical Ltd. */ +#include <asm/unaligned.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/mm.h>
@@ -110,14 +111,13 @@ static struct table_header *unpack_table(char *blob, size_t bsize) table->td_flags = th.td_flags; table->td_lolen = th.td_lolen;if (th.td_flags ==YYTD_DATA8 ) -UNPACK_ARRAY (table->td_data, blob, th.td_lolen, - u8, u8, byte_to_byte); +memcpy (table->td_data, blob, th.td_lolen);else if (th.td_flags ==YYTD_DATA16 )UNPACK_ARRAY (table->td_data, blob, th.td_lolen, - u16, __be16, be16_to_cpu); + u16, __be16, get_unaligned_be16);else if (th.td_flags ==YYTD_DATA32 )UNPACK_ARRAY (table->td_data, blob, th.td_lolen, - u32, __be32, be32_to_cpu); + u32, __be32, get_unaligned_be32);else goto fail;/* if table was vmalloced make sure the page tables are synced
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1027/1887 iommu/vt-d: Clear Present bit before tearing down PASID entry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
[ Upstream commit 75ed00055c059dedc47b5daaaa2f8a7a019138ff ]
The Intel VT-d Scalable Mode PASID table entry consists of 512 bits (64 bytes). When tearing down an entry, the current implementation zeros the entire 64-byte structure immediately using multiple 64-bit writes.
Since the IOMMU hardware may fetch these 64 bytes using multiple internal transactions (e.g., four 128-bit bursts), updating or zeroing the entire entry while it is active (P=1) risks a "torn" read. If a hardware fetch occurs simultaneously with the CPU zeroing the entry, the hardware could observe an inconsistent state, leading to unpredictable behavior or spurious faults.
Follow the "Guidance to Software for Invalidations" in the VT-d spec (Section 6.5.3.3) by implementing the recommended ownership handshake:
1. Clear only the 'Present' (P) bit of the PASID entry.
2. Use a dma_wmb() to ensure the cleared bit is visible to hardware before proceeding.
3. Execute the required invalidation sequence (PASID cache, IOTLB, and Device-TLB flush) to ensure the hardware has released all cached references.
4. Only after the flushes are complete, zero out the remaining fields of the PASID entry.
Also, add a dma_wmb() in pasid_set_present() to ensure that all other fields of the PASID entry are visible to the hardware before the Present bit is set.
--- drivers/iommu/intel/pasid.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
drivers/iommu/intel/pasid.c +20 -2
@@ -262,7 +262,7 @@ intel_pasid_clear_entry(struct device *dev, u32 pasid, bool fault_ignore)if (WARN_ON (!pe))return ; -if (fault_ignore &&pasid_pte_is_present (pe)) +if (fault_ignore)pasid_clear_entry_with_fpd (pe);else pasid_clear_entry (pe);
@@ -358,9 +358,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)*/ static inline void pasid_set_present (struct pasid_entry *pe) { +dma_wmb ();pasid_set_bits (&pe->val[0 ],1 <<0 ,1 ); } +/* +* Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry. +* This initiates the transition of the entry's ownership from hardware +* to software. The caller is responsible for fulfilling the invalidation +* handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to +* Software for Invalidations). +*/ +static inline void pasid_clear_present (struct pasid_entry *pe) +{ +pasid_set_bits (&pe->val[0 ],1 <<0 ,0 ); +dma_wmb (); +} +/* * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID * entry.
@@ -470,7 +484,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, did =pasid_get_domain_id (pte); pgtt =pasid_pte_get_pgtt (pte); -intel_pasid_clear_entry (dev, pasid, fault_ignore); +pasid_clear_present (pte);spin_unlock (&iommu->lock);if (!ecap_coherent (iommu->ecap))
@@ -486,6 +500,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,/* Device IOTLB doesn't need to be flushed in caching mode. */ if (!cap_caching_mode (iommu->cap))devtlb_invalidation_with_pasid (iommu, dev, pasid); + +intel_pasid_clear_entry (dev, pasid, fault_ignore); +if (!ecap_coherent (iommu->ecap)) +clflush_cache_range (pte,sizeof (*pte)); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1028/1887 ext4: drop extent cache when splitting extent fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
[ Upstream commit 79b592e8f1b435796cbc2722190368e3e8ffd7a1 ]
When the split extent fails, we might leave some extents still being processed and return an error directly, which will result in stale extent entries remaining in the extent status tree. So drop all of the remaining potentially stale extents if the splitting fails.
Message-ID: <[email protected]>
--- fs/ext4/extents.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ext4/extents.c +6 -2
@@ -3268,7 +3268,8 @@ static int ext4_split_extent_at(handle_t *handle,if (IS_ERR (path)) {EXT4_ERROR_INODE (inode,"Failed split extent on %u, err %ld" , split,PTR_ERR (path)); -return PTR_ERR (path); + err =PTR_ERR (path); + goto out_err; } depth =ext_depth (inode); ex = path[depth].p_ext;
@@ -3323,9 +3324,12 @@ static int ext4_split_extent_at(handle_t *handle,* and err is a non-zero error code. */ ext4_ext_dirty (handle, inode, path + path->p_depth); -return err; out:ext4_ext_show_leaf (inode, *ppath); +out_err: +if (err) +/* Remove all remaining potentially stale extents. */ +ext4_es_remove_extent (inode, ee_block, ee_len);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1029/1887 ipvs: do not keep dest_dst if dev is going down
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit 8fde939b0206afc1d5846217a01a16b9bc8c7896 ]
There is race between the netdev notifier ip_vs_dst_event() and the code that caches dst with dev that is going down. As the FIB can be notified for the closed device after our handler finishes, it is possible valid route to be returned and cached resuling in a leaked dev reference until the dest is not removed.
To prevent new dest_dst to be attached to dest just after the handler dropped the old one, add a netif_running() check to make sure the notifier handler is not currently running for device that is closing.
--- net/netfilter/ipvs/ip_vs_xmit.c | 46 ++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +36 -10
@@ -306,6 +306,12 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,return true; } +/* rt has device that is down */ +static bool rt_dev_is_down (const struct net_device *dev) +{ +return dev && !netif_running (dev); +} +/* Get route to destination or remote server */ static int __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
@@ -321,9 +327,11 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,if (dest) { dest_dst =__ip_vs_dst_check (dest); -if (likely (dest_dst)) +if (likely (dest_dst)) { rt = (struct rtable *) dest_dst->dst_cache; -else { +if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.ip; + }else { dest_dst =ip_vs_dest_dst_alloc ();spin_lock_bh (&dest->dst_lock);if (!dest_dst) {
@@ -339,14 +347,22 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,ip_vs_dest_dst_free (dest_dst); goto err_unreach; } -__ip_vs_dst_set (dest, dest_dst, &rt->dst,0 ); +/* It is forbidden to attach dest->dest_dst if +* device is going down. +*/ +if (!rt_dev_is_down (dst_dev_rcu (&rt->dst))) +__ip_vs_dst_set (dest, dest_dst, &rt->dst,0 ); +else + noref =0 ;spin_unlock_bh (&dest->dst_lock);IP_VS_DBG (10 ,"new dst %pI4, src %pI4, refcnt=%d\n" , &dest->addr.ip, &dest_dst->dst_saddr.ip,atomic_read (&rt->dst.__refcnt)); +if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.ip; +if (!noref) +ip_vs_dest_dst_free (dest_dst); } -if (ret_saddr) - *ret_saddr = dest_dst->dst_saddr.ip; }else { noref =0 ;
@@ -483,9 +499,11 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,if (dest) { dest_dst =__ip_vs_dst_check (dest); -if (likely (dest_dst)) +if (likely (dest_dst)) { rt =dst_rt6_info (dest_dst->dst_cache); -else { +if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.in6; + }else {u32 cookie; dest_dst =ip_vs_dest_dst_alloc ();
@@ -506,14 +524,22 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, } rt =dst_rt6_info (dst); cookie =rt6_get_cookie (rt); -__ip_vs_dst_set (dest, dest_dst, &rt->dst, cookie); +/* It is forbidden to attach dest->dest_dst if +* device is going down. +*/ +if (!rt_dev_is_down (dst_dev_rcu (&rt->dst))) +__ip_vs_dst_set (dest, dest_dst, &rt->dst, cookie); +else + noref =0 ;spin_unlock_bh (&dest->dst_lock);IP_VS_DBG (10 ,"new dst %pI6, src %pI6, refcnt=%d\n" , &dest->addr.in6, &dest_dst->dst_saddr.in6,atomic_read (&rt->dst.__refcnt)); +if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.in6; +if (!noref) +ip_vs_dest_dst_free (dest_dst); } -if (ret_saddr) - *ret_saddr = dest_dst->dst_saddr.in6; }else { noref =0 ; dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1030/1887 btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boris Burkov <[email protected]>
[ Upstream commit b14c5e04bd0f722ed631845599d52d03fcae1bc1 ]
I have been observing a number of systems aborting at insert_dev_extents() in btrfs_create_pending_block_groups(). The following is a sample stack trace of such an abort coming from forced chunk allocation (typically behind CONFIG_BTRFS_EXPERIMENTAL) but this can theoretically happen to any DUP chunk allocation.
[81.801] ------------[ cut here ]------------ [81.801] BTRFS: Transaction aborted (error -17) [81.801] WARNING: fs/btrfs/block-group.c:2876 at btrfs_create_pending_block_groups+0x721/0x770 [btrfs], CPU#1: bash/319 [81.802] Modules linked in: virtio_net btrfs xor zstd_compress raid6_pq null_blk [81.803] CPU: 1 UID: 0 PID: 319 Comm: bash Kdump: loaded Not tainted 6.19.0-rc6+ #319 NONE [81.803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 [81.804] RIP: 0010:btrfs_create_pending_block_groups+0x723/0x770 [btrfs] [81.806] RSP: 0018:ffffa36241a6bce8 EFLAGS: 00010282 [81.806] RAX: 000000000000000d RBX: ffff8e699921e400 RCX: 0000000000000000 [81.807] RDX: 0000000002040001 RSI: 00000000ffffffef RDI: ffffffffc0608bf0 [81.807] RBP: 00000000ffffffef R08: ffff8e69830f6000 R09: 0000000000000007 [81.808] R10: ffff8e699921e5e8 R11: 0000000000000000 R12: ffff8e6999228000 [81.808] R13: ffff8e6984d82000 R14: ffff8e69966a69c0 R15: ffff8e69aa47b000 [81.809] FS: 00007fec6bdd9740(0000) GS:ffff8e6b1b379000(0000) knlGS:0000000000000000 [81.809] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [81.810] CR2: 00005604833670f0 CR3: 0000000116679000 CR4: 00000000000006f0 [81.810] Call Trace: [81.810] <TASK> [81.810] __btrfs_end_transaction+0x3e/0x2b0 [btrfs] [81.811] btrfs_force_chunk_alloc_store+0xcd/0x140 [btrfs] [81.811] kernfs_fop_write_iter+0x15f/0x240 [81.812] vfs_write+0x264/0x500 [81.812] ksys_write+0x6c/0xe0 [81.812] do_syscall_64+0x66/0x770 [81.812] entry_SYSCALL_64_after_hwframe+0x76/0x7e [81.813] RIP: 0033:0x7fec6be66197 [81.814] RSP: 002b:00007fffb159dd30 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 [81.815] RAX: ffffffffffffffda RBX: 00007fec6bdd9740 RCX: 00007fec6be66197 [81.815] RDX: 0000000000000002 RSI: 0000560483374f80 RDI: 0000000000000001 [81.816] RBP: 0000560483374f80 R08: 0000000000000000 R09: 0000000000000000 [81.816] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000002 [81.817] R13: 00007fec6bfb85c0 R14: 00007fec6bfb5ee0 R15: 00005604833729c0 [81.817] </TASK> [81.817] irq event stamp: 20039 [81.818] hardirqs last enabled at (20047): [<ffffffff99a68302>] __up_console_sem+0x52/0x60 [81.818] hardirqs last disabled at (20056): [<ffffffff99a682e7>] __up_console_sem+0x37/0x60 [81.819] softirqs last enabled at (19470): [<ffffffff999d2b46>] __irq_exit_rcu+0x96/0xc0 [81.819] softirqs last disabled at (19463): [<ffffffff999d2b46>] __irq_exit_rcu+0x96/0xc0 [81.820] ---[ end trace 0000000000000000 ]--- [81.820] BTRFS: error (device dm-7 state A) in btrfs_create_pending_block_groups:2876: errno=-17 Object already exists
Inspecting these aborts with drgn, I observed a pattern of overlapping chunk_maps. Note how stripe 1 of the first chunk overlaps in physical address with stripe 0 of the second chunk.
Physical Start Physical End Length Logical Type Stripe
----------------------------------------------------------------------------------------------------
0x0000000102500000 0x0000000142500000 1.0G 0x0000000641d00000 META|DUP 0/2 0x0000000142500000 0x0000000182500000 1.0G 0x0000000641d00000 META|DUP 1/2 0x0000000142500000 0x0000000182500000 1.0G 0x0000000601d00000 META|DUP 0/2 0x0000000182500000 0x00000001c2500000 1.0G 0x0000000601d00000 META|DUP 1/2
Now how could this possibly happen? All chunk allocation is protected by the chunk_mutex so racing allocations should see a consistent view of the CHUNK_ALLOCATED bit in the chunk allocation extent-io-tree (device->alloc_state as set by chunk_map_device_set_bits()) The tree itself is protected by a spin lock, and clearing/setting the bits is always protected by fs_info->mapping_tree_lock, so no race is apparent.
It turns out that there is a subtle bug in the logic regarding chunk allocations that have happened in the current transaction, known as "pending extents". The chunk allocation as defined in find_free_dev_extent() is a loop which searches the commit root of the dev_root and looks for gaps between DEV_EXTENT items. For those gaps, it then checks alloc_state bitmap for any pending extents and adjusts the hole that it finds accordingly. However, the logic in that adjustment assumes that the first pending extent is the only one in that range.
e.g., given a layout with two non-consecutive pending extents in a hole passed to dev_extent_hole_check() via *hole_start and *hole_size:
|----pending A----| real hole |----pending B----|
| candidate hole |
*hole_start *hole_start + *hole_sizethe code incorrectly returns a "hole" from the end of pending extent A until the passed in hole end, failing to account for pending B.
However, it is not entirely obvious that it is actually possible to produce such a layout. I was able to reproduce it, but with some
contortions: I continued to use the force chunk allocation sysfs file and I introduced a long delay (10 seconds) into the start of the cleaner thread. I also prevented the unused bgs cleaning logic from ever deleting metadata bgs. These help make it easier to deterministically produce the condition but shouldn't really matter if you imagine the conditions happening by race/luck. Allocations/frees can happen concurrently with the cleaner thread preparing to process an unused extent and both create some used chunks with an unused chunk interleaved, all during one transaction. Then btrfs_delete_unused_bgs() sees the unused one and clears it, leaving a range with several pending chunk allocations and a gap in the middle.
The basic idea is that the unused_bgs cleanup work happens on a worker so if we allocate 3 block groups in one transaction, then the cleaner work kicked off by the previous transaction comes through and deletes the middle one of the 3, then the commit root shows no dev extents and we have the bad pattern in the extent-io-tree. One final consideration is that the code happens to loop to the next hole if there are no more extents at all, so we need one more dev extent way past the area we are working in. Something like the following demonstrates the technique:
# push the BG frontier out to 20G fallocate -l 20G $mnt/foo # allocate one more that will prevent the "no more dev extents" luck fallocate -l 1G $mnt/sticky # sync sync # clear out the allocation area rm $mnt/foo sync _cleaner # let everything quiesce sleep 20 sync
# dev tree should have one bg 20G out and the rest at the beginning.. # sort of like an empty FS but with a random sticky chunk.
# kick off the cleaner in the background, remember it will sleep 10s # before doing interesting work _cleaner &
sleep 3
# create 3 trivial block groups, all empty, all immediately marked as unused. echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" echo 1 > "$(_btrfs_sysfs_space_info $dev data)/force_chunk_alloc" echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc"
# let the cleaner thread definitely finish, it will remove the data bg sleep 10
# this allocation sees the non-consecutive pending metadata chunks with # data chunk gap of 1G and allocates a 2G extent in that hole. ENOSPC! echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc"
As for the fix, it is not that obvious. I could not see a trivial way to do it even by adding backup loops into find_free_dev_extent(), so I opted to change the semantics of dev_extent_hole_check() to not stop looping until it finds a sufficiently big hole. For clarity, this also required changing the helper function contains_pending_extent() into two new helpers which find the first pending extent and the first suitable hole in a range.
I attempted to clean up the documentation and range calculations to be as consistent and clear as possible for the future.
I also looked at the zoned case and concluded that the loop there is different and not to be unified with this one. As far as I can tell, the zoned check will only further constrain the hole so looping back to find more holes is acceptable. Though given that zoned really only appends, I find it highly unlikely that it is susceptible to this bug.
--- fs/btrfs/volumes.c | 243 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 183 insertions(+), 60 deletions(-)
fs/btrfs/volumes.c +183 -60
@@ -1471,30 +1471,158 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags, }/* -* Try to find a chunk that intersects [start, start + len] range and when one -* such is found, record the end of it in *start +* Find the first pending extent intersecting a range. +* +* @device: the device to search +* @start: start of the range to check +* @len: length of the range to check +* @pending_start: output pointer for the start of the found pending extent +* @pending_end: output pointer for the end of the found pending extent (inclusive) +* +* Search for a pending chunk allocation that intersects the half-open range +* [start, start + len). +* +* Return: true if a pending extent was found, false otherwise. +* If the return value is true, store the first pending extent in +* [*pending_start, *pending_end]. Otherwise, the two output variables +* may still be modified, to something outside the range and should not +* be used. */ -static bool contains_pending_extent (struct btrfs_device *device,u64 *start, -u64 len) +static bool first_pending_extent (struct btrfs_device *device,u64 start,u64 len, +u64 *pending_start,u64 *pending_end) { -u64 physical_start, physical_end; -lockdep_assert_held (&device->fs_info->chunk_mutex); -if (!find_first_extent_bit (&device->alloc_state, *start, - &physical_start, &physical_end, +if (!find_first_extent_bit (&device->alloc_state, start, + pending_start, pending_end,CHUNK_ALLOCATED ,NULL )) { -if (in_range (physical_start, *start, len) || -in_range (*start, physical_start, - physical_end +1 - physical_start)) { - *start = physical_end +1 ; +if (in_range (*pending_start, start, len) || +in_range (start, *pending_start, *pending_end +1 - *pending_start)) {return true; } }return false; } +/* +* Find the first real hole accounting for pending extents. +* +* @device: the device containing the candidate hole +* @start: input/output pointer for the hole start position +* @len: input/output pointer for the hole length +* @min_hole_size: the size of hole we are looking for +* +* Given a potential hole specified by [*start, *start + *len), check for pending +* chunk allocations within that range. If pending extents are found, the hole is +* adjusted to represent the first true free space that is large enough when +* accounting for pending chunks. +* +* Note that this function must handle various cases involving non consecutive +* pending extents. +* +* Returns: true if a suitable hole was found and false otherwise. +* If the return value is true, then *start and *len are set to represent the hole. +* If the return value is false, then *start is set to the largest hole we +* found and *len is set to its length. +* If there are no holes at all, then *start is set to the end of the range and +* *len is set to 0. +*/ +static bool find_hole_in_pending_extents (struct btrfs_device *device,u64 *start, +u64 *len,u64 min_hole_size) +{ +u64 pending_start, pending_end; +u64 end; +u64 max_hole_start =0 ; +u64 max_hole_len =0 ; + +lockdep_assert_held (&device->fs_info->chunk_mutex); + +if (*len ==0 ) +return false; + + end = *start + *len -1 ; + +/* +* Loop until we either see a large enough hole or check every pending +* extent overlapping the candidate hole. +* At every hole that we observe, record it if it is the new max. +* At the end of the iteration, set the output variables to the max hole. +*/ +while (true) { +if (first_pending_extent (device, *start, *len, &pending_start, &pending_end)) { +/* +* Case 1: the pending extent overlaps the start of +* candidate hole. That means the true hole is after the +* pending extent, but we need to find the next pending +* extent to properly size the hole. In the next loop, +* we will reduce to case 2 or 3. +* e.g., +* +* |----pending A----| real hole |----pending B----| +* | candidate hole | +* *start end +*/ +if (pending_start <= *start) { + *start = pending_end +1 ; + goto next; + } +/* +* Case 2: The pending extent starts after *start (and overlaps +* [*start, end), so the first hole just goes up to the start +* of the pending extent. +* e.g., +* +* | real hole |----pending A----| +* | candidate hole | +* *start end +*/ + *len = pending_start - *start; +if (*len > max_hole_len) { + max_hole_start = *start; + max_hole_len = *len; + } +if (*len >= min_hole_size) +break ; +/* +* If the hole wasn't big enough, then we advance past +* the pending extent and keep looking. +*/ + *start = pending_end +1 ; + goto next; + }else { +/* +* Case 3: There is no pending extent overlapping the +* range [*start, *start + *len - 1], so the only remaining +* hole is the remaining range. +* e.g., +* +* | candidate hole | +* | real hole | +* *start end +*/ + +if (*len > max_hole_len) { + max_hole_start = *start; + max_hole_len = *len; + } +break ; + } +next: +if (*start > end) +break ; + *len = end - *start +1 ; + } +if (max_hole_len) { + *start = max_hole_start; + *len = max_hole_len; + }else { + *start = end +1 ; + *len =0 ; + } +return max_hole_len >= min_hole_size; +} +static u64 dev_extent_search_start (struct btrfs_device *device,u64 start) {switch (device->fs_devices->chunk_alloc_policy) {
@@ -1556,58 +1684,57 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device,return changed; } -/** -* dev_extent_hole_check - check if specified hole is suitable for allocation -* @device: the device which we have the hole -* @hole_start: starting position of the hole -* @hole_size: the size of the hole -* @num_bytes: the size of the free space that we need +/* +* Validate and adjust a hole for chunk allocation +* +* @device: the device containing the candidate hole +* @hole_start: input/output pointer for the hole start position +* @hole_size: input/output pointer for the hole size +* @num_bytes: minimum allocation size required * -* This function may modify @hole_start and @hole_size to reflect the suitable -* position for allocation. Returns 1 if hole position is updated, 0 otherwise. +* Check if the specified hole is suitable for allocation and adjust it if +* necessary. The hole may be modified to skip over pending chunk allocations +* and to satisfy stricter zoned requirements on zoned filesystems. +* +* For regular (non-zoned) allocation, if the hole after adjustment is smaller +* than @num_bytes, the search continues past additional pending extents until +* either a sufficiently large hole is found or no more pending extents exist. +* +* Return: true if a suitable hole was found and false otherwise. +* If the return value is true, then *hole_start and *hole_size are set to +* represent the hole we found. +* If the return value is false, then *hole_start is set to the largest +* hole we found and *hole_size is set to its length. +* If there are no holes at all, then *hole_start is set to the end of the range +* and *hole_size is set to 0. */ static bool dev_extent_hole_check (struct btrfs_device *device,u64 *hole_start,u64 *hole_size,u64 num_bytes) { -bool changed = false; -u64 hole_end = *hole_start + *hole_size; +bool found = false; +const u64 hole_end = *hole_start + *hole_size -1 ; -for (;;) { -/* -* Check before we set max_hole_start, otherwise we could end up -* sending back this offset anyway. -*/ -if (contains_pending_extent (device, hole_start, *hole_size)) { -if (hole_end >= *hole_start) - *hole_size = hole_end - *hole_start; -else - *hole_size =0 ; - changed = true; - } +ASSERT (*hole_size >0 ); -switch (device->fs_devices->chunk_alloc_policy) { -case BTRFS_CHUNK_ALLOC_REGULAR : -/* No extra check */ -break ; -case BTRFS_CHUNK_ALLOC_ZONED : -if (dev_extent_hole_check_zoned (device, hole_start, - hole_size, num_bytes)) { - changed = true; -/* -* The changed hole can contain pending extent. -* Loop again to check that. -*/ -continue ; - } -break ; -default : -BUG (); - } +again: + *hole_size = hole_end - *hole_start +1 ; + found =find_hole_in_pending_extents (device, hole_start, hole_size, num_bytes); +if (!found) +return found; +ASSERT (*hole_size >= num_bytes); +switch (device->fs_devices->chunk_alloc_policy) { +case BTRFS_CHUNK_ALLOC_REGULAR : +return found; +case BTRFS_CHUNK_ALLOC_ZONED : +if (dev_extent_hole_check_zoned (device, hole_start, hole_size, num_bytes)) + goto again;break ; +default : +BUG (); } -return changed; +return found; }/*
@@ -1667,7 +1794,6 @@ static int find_free_dev_extent_start(struct btrfs_device *device, max_hole_start = search_start; max_hole_size =0 ; -again:if (search_start >= search_end ||test_bit (BTRFS_DEV_STATE_REPLACE_TGT , &device->dev_state)) { ret = -ENOSPC ;
@@ -1754,11 +1880,7 @@ static int find_free_dev_extent_start(struct btrfs_device *device,*/ if (search_end > search_start) { hole_size = search_end - search_start; -if (dev_extent_hole_check (device, &search_start, &hole_size, - num_bytes)) { -btrfs_release_path (path); - goto again; - } +dev_extent_hole_check (device, &search_start, &hole_size, num_bytes);if (hole_size > max_hole_size) { max_hole_start = search_start;
@@ -4939,6 +5061,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)u64 old_size =btrfs_device_get_total_bytes (device);u64 diff;u64 start; +u64 pending_start, pending_end; new_size =round_down (new_size, fs_info->sectorsize); start = new_size;
@@ -4972,7 +5095,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)* in-memory chunks are synced to disk so that the loop below sees them * and relocates them accordingly. */ -if (contains_pending_extent (device, &start, diff)) { +if (first_pending_extent (device, start, diff, &pending_start, &pending_end)) {mutex_unlock (&fs_info->chunk_mutex); ret =btrfs_commit_transaction (trans);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1031/1887 net: stmmac: fix oops when split header is enabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jie Zhang <[email protected]>
[ Upstream commit babab1b42ed68877ef669a08384becf281ad2582 ]
For GMAC4, when split header is enabled, in some rare cases, the hardware does not fill buf2 of the first descriptor with payload. Thus we cannot assume buf2 is always fully filled if it is not the last descriptor. Otherwise, the length of buf2 of the second descriptor will be calculated wrong and cause an oops:
Unable to handle kernel paging request at virtual address ffff00019246bfc0 ... x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000 Call trace: dcache_inval_poc+0x28/0x58 (P) dma_direct_sync_single_for_cpu+0x38/0x6c __dma_sync_single_for_cpu+0x34/0x6c stmmac_napi_poll_rx+0x8f0/0xb60 __napi_poll.constprop.0+0x30/0x144 net_rx_action+0x160/0x274 handle_softirqs+0x1b8/0x1fc
...
To fix this, the PL bit-field in RDES3 register is used for all descriptors, whether it is the last descriptor or not.
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +17 -3
@@ -4744,13 +4744,27 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,if (!priv->sph)return 0 ; -/* Not last descriptor */ -if (status & rx_not_ls) +/* For GMAC4, when split header is enabled, in some rare cases, the +* hardware does not fill buf2 of the first descriptor with payload. +* Thus we cannot assume buf2 is always fully filled if it is not +* the last descriptor. Otherwise, the length of buf2 of the second +* descriptor will be calculated wrong and cause an oops. +* +* If this is the last descriptor, 'plen' is the length of the +* received packet that was transferred to system memory. +* Otherwise, it is the accumulated number of bytes that have been +* transferred for the current packet. +* +* Thus 'plen - len' always gives the correct length of buf2. +*/ + +/* Not GMAC4 and not last descriptor */ +if (!priv->plat->has_gmac4 && (status & rx_not_ls))return priv->dma_conf.dma_buf_sz; +/* GMAC4 or last descriptor */ plen =stmmac_get_rx_frame_len (priv, p, coe); -/* Last descriptor */ return plen - len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1032/1887 ext4: remove unnecessary e4b->bd_buddy_page check in ext4_mb_load_buddy_gfp
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kemeng Shi <[email protected]>
[ Upstream commit 285164b80175157c18a06425cf25591c9f942b1a ]
e4b->bd_buddy_page is only set if we initialize ext4_buddy successfully. So e4b->bd_buddy_page is always NULL in error handle branch. Just remove the dead check.
Stable-dep-of: bdc56a9c46b2 ("ext4: fix e4b bitmap inconsistency reports")
--- fs/ext4/mballoc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
fs/ext4/mballoc.c +1 -2
@@ -1614,8 +1614,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,put_page (page);if (e4b->bd_bitmap_page)put_page (e4b->bd_bitmap_page); -if (e4b->bd_buddy_page) -put_page (e4b->bd_buddy_page); + e4b->bd_buddy =NULL ; e4b->bd_bitmap =NULL ;return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1033/1887 ext4: convert some BUG_ONs in mballoc to use WARN_RATELIMITED instead
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
[ Upstream commit 19b8b035a776939ceb3de0f45aded4751d7849ef ]
In cases where we have an obvious way of continuing, let's use WARN_RATELIMITED() instead of BUG_ON().
Stable-dep-of: bdc56a9c46b2 ("ext4: fix e4b bitmap inconsistency reports")
--- fs/ext4/mballoc.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
fs/ext4/mballoc.c +19 -6
@@ -1546,7 +1546,13 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,put_page (page); page =find_or_create_page (inode->i_mapping, pnum, gfp);if (page) { -BUG_ON (page->mapping != inode->i_mapping); +if (WARN_RATELIMIT (page->mapping != inode->i_mapping, +"ext4: bitmap's paging->mapping != inode->i_mapping\n" )) { +/* should never happen */ +unlock_page (page); + ret = -EINVAL ; + goto err; + }if (!PageUptodate (page)) { ret =ext4_mb_init_cache (page,NULL , gfp);if (ret) {
@@ -1582,7 +1588,13 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,put_page (page); page =find_or_create_page (inode->i_mapping, pnum, gfp);if (page) { -BUG_ON (page->mapping != inode->i_mapping); +if (WARN_RATELIMIT (page->mapping != inode->i_mapping, +"ext4: buddy bitmap's page->mapping != inode->i_mapping\n" )) { +/* should never happen */ +unlock_page (page); + ret = -EINVAL ; + goto err; + }if (!PageUptodate (page)) { ret =ext4_mb_init_cache (page, e4b->bd_bitmap, gfp);
@@ -2305,7 +2317,9 @@ void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,continue ; buddy =mb_find_buddy (e4b, i, &max); -BUG_ON (buddy ==NULL ); +if (WARN_RATELIMIT (buddy ==NULL , +"ext4: mb_simple_scan_group: mb_find_buddy failed, (%d)\n" , i)) +continue ; k =mb_find_next_zero_bit (buddy, max,0 );if (k >= max) {
@@ -4316,15 +4330,14 @@ static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac)if (ac->ac_f_ex.fe_len ==0 )return ; err =ext4_mb_load_buddy (ac->ac_sb, ac->ac_f_ex.fe_group, &e4b); -if (err) { +if (WARN_RATELIMIT (err, +"ext4: mb_load_buddy failed (%d)" , err))/* * This should never happen since we pin the * pages in the ext4_allocation_context so * ext4_mb_load_buddy() should never fail. */ -WARN (1 ,"mb_load_buddy failed (%d)" , err);return ; - }ext4_lock_group (ac->ac_sb, ac->ac_f_ex.fe_group);mb_free_blocks (ac->ac_inode, &e4b, ac->ac_f_ex.fe_start, ac->ac_f_ex.fe_len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1034/1887 ext4: delete redundant calculations in ext4_mb_get_buddy_page_lock()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <[email protected]>
[ Upstream commit f2fec3e99a32d7c14dbf63c824f8286ebc94b18d ]
'blocks_per_page' is always 1 after 'if (blocks_per_page >= 2)', 'pnum' and 'block' are equal in this case.
Stable-dep-of: bdc56a9c46b2 ("ext4: fix e4b bitmap inconsistency reports")
--- fs/ext4/mballoc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/ext4/mballoc.c +2 -3
@@ -1385,9 +1385,8 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,return 0 ; } - block++; - pnum = block / blocks_per_page; - page =find_or_create_page (inode->i_mapping, pnum, gfp); +/* blocks_per_page == 1, hence we need another page for the buddy */ + page =find_or_create_page (inode->i_mapping, block +1 , gfp);if (!page)return -ENOMEM ;BUG_ON (page->mapping != inode->i_mapping);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1035/1887 ext4: convert bd_bitmap_page to bd_bitmap_folio
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit 99b150d84e4939735cfce245e32e3d29312c68ec ]
There is no need to make this a multi-page folio, so leave all the infrastructure around it in pages. But since we're locking it, playing with its refcount and checking whether it's uptodate, it needs to move to the folio API.
Stable-dep-of: bdc56a9c46b2 ("ext4: fix e4b bitmap inconsistency reports")
--- fs/ext4/mballoc.c | 98 ++++++++++++++++++++++++----------------------- fs/ext4/mballoc.h | 2 +- 2 files changed, 52 insertions(+), 48 deletions(-)
fs/ext4/mballoc.c +51 -47
@@ -1360,9 +1360,10 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,int block, pnum, poff;int blocks_per_page;struct page *page; +struct folio *folio; e4b->bd_buddy_page =NULL ; - e4b->bd_bitmap_page =NULL ; + e4b->bd_bitmap_folio =NULL ; blocks_per_page =PAGE_SIZE / sb->s_blocksize;/*
@@ -1373,12 +1374,13 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, block = group *2 ; pnum = block / blocks_per_page; poff = block % blocks_per_page; - page =find_or_create_page (inode->i_mapping, pnum, gfp); -if (!page) -return -ENOMEM ; -BUG_ON (page->mapping != inode->i_mapping); - e4b->bd_bitmap_page = page; - e4b->bd_bitmap =page_address (page) + (poff * sb->s_blocksize); + folio =__filemap_get_folio (inode->i_mapping, pnum, +FGP_LOCK |FGP_ACCESSED |FGP_CREAT , gfp); +if (IS_ERR (folio)) +return PTR_ERR (folio); +BUG_ON (folio->mapping != inode->i_mapping); + e4b->bd_bitmap_folio = folio; + e4b->bd_bitmap =folio_address (folio) + (poff * sb->s_blocksize);if (blocks_per_page >=2 ) {/* buddy and bitmap are on the same page */
@@ -1396,9 +1398,9 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,static void ext4_mb_put_buddy_page_lock (struct ext4_buddy *e4b) { -if (e4b->bd_bitmap_page) { -unlock_page (e4b->bd_bitmap_page); -put_page (e4b->bd_bitmap_page); +if (e4b->bd_bitmap_folio) { +folio_unlock (e4b->bd_bitmap_folio); +folio_put (e4b->bd_bitmap_folio); }if (e4b->bd_buddy_page) {unlock_page (e4b->bd_buddy_page);
@@ -1418,6 +1420,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)struct ext4_group_info *this_grp;struct ext4_buddy e4b;struct page *page; +struct folio *folio;int ret =0 ;might_sleep ();
@@ -1444,11 +1447,11 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) goto err; } - page = e4b.bd_bitmap_page; - ret =ext4_mb_init_cache (page,NULL , gfp); + folio = e4b.bd_bitmap_folio; + ret =ext4_mb_init_cache (&folio->page,NULL , gfp);if (ret) goto err; -if (!PageUptodate (page)) { +if (!folio_test_uptodate (folio)) { ret = -EIO ; goto err; }
@@ -1490,6 +1493,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,int pnum;int poff;struct page *page; +struct folio *folio;int ret;struct ext4_group_info *grp;struct ext4_sb_info *sbi =EXT4_SB (sb);
@@ -1508,7 +1512,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, e4b->bd_sb = sb; e4b->bd_group = group; e4b->bd_buddy_page =NULL ; - e4b->bd_bitmap_page =NULL ; + e4b->bd_bitmap_folio =NULL ;if (unlikely (EXT4_MB_GRP_NEED_INIT (grp))) {/*
@@ -1529,53 +1533,53 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, pnum = block / blocks_per_page; poff = block % blocks_per_page; -/* we could use find_or_create_page(), but it locks page -* what we'd like to avoid in fast path ... */ - page =find_get_page_flags (inode->i_mapping, pnum,FGP_ACCESSED ); -if (page ==NULL || !PageUptodate (page)) { -if (page) +/* Avoid locking the folio in the fast path ... */ + folio =__filemap_get_folio (inode->i_mapping, pnum,FGP_ACCESSED ,0 ); +if (IS_ERR (folio) || !folio_test_uptodate (folio)) { +if (!IS_ERR (folio))/* -* drop the page reference and try -* to get the page with lock. If we +* drop the folio reference and try +* to get the folio with lock. If we * are not uptodate that implies -* somebody just created the page but -* is yet to initialize the same. So +* somebody just created the folio but +* is yet to initialize it. So * wait for it to initialize. */ -put_page (page); - page =find_or_create_page (inode->i_mapping, pnum, gfp); -if (page) { -if (WARN_RATELIMIT (page->mapping != inode->i_mapping, -"ext4: bitmap's paging->mapping != inode->i_mapping\n" )) { +folio_put (folio); + folio =__filemap_get_folio (inode->i_mapping, pnum, +FGP_LOCK |FGP_ACCESSED |FGP_CREAT , gfp); +if (!IS_ERR (folio)) { +if (WARN_RATELIMIT (folio->mapping != inode->i_mapping, +"ext4: bitmap's mapping != inode->i_mapping\n" )) {/* should never happen */ -unlock_page (page); +folio_unlock (folio); ret = -EINVAL ; goto err; } -if (!PageUptodate (page)) { - ret =ext4_mb_init_cache (page,NULL , gfp); +if (!folio_test_uptodate (folio)) { + ret =ext4_mb_init_cache (&folio->page,NULL , gfp);if (ret) { -unlock_page (page); +folio_unlock (folio); goto err; } -mb_cmp_bitmaps (e4b,page_address (page) + +mb_cmp_bitmaps (e4b,folio_address (folio) + (poff * sb->s_blocksize)); } -unlock_page (page); +folio_unlock (folio); } } -if (page ==NULL ) { - ret = -ENOMEM ; +if (IS_ERR (folio)) { + ret =PTR_ERR (folio); goto err; } -if (!PageUptodate (page)) { +if (!folio_test_uptodate (folio)) { ret = -EIO ; goto err; }/* Pages marked accessed already */ - e4b->bd_bitmap_page = page; - e4b->bd_bitmap =page_address (page) + (poff * sb->s_blocksize); + e4b->bd_bitmap_folio = folio; + e4b->bd_bitmap =folio_address (folio) + (poff * sb->s_blocksize); block++; pnum = block / blocks_per_page;
@@ -1623,8 +1627,8 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, err:if (page)put_page (page); -if (e4b->bd_bitmap_page) -put_page (e4b->bd_bitmap_page); +if (e4b->bd_bitmap_folio) +folio_put (e4b->bd_bitmap_folio); e4b->bd_buddy =NULL ; e4b->bd_bitmap =NULL ;
@@ -1639,8 +1643,8 @@ static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,static void ext4_mb_unload_buddy (struct ext4_buddy *e4b) { -if (e4b->bd_bitmap_page) -put_page (e4b->bd_bitmap_page); +if (e4b->bd_bitmap_folio) +folio_put (e4b->bd_bitmap_folio);if (e4b->bd_buddy_page)put_page (e4b->bd_buddy_page); }
@@ -2065,7 +2069,7 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,* double allocate blocks. The reference is dropped * in ext4_mb_release_context */ - ac->ac_bitmap_page = e4b->bd_bitmap_page; + ac->ac_bitmap_page = &e4b->bd_bitmap_folio->page;get_page (ac->ac_bitmap_page); ac->ac_buddy_page = e4b->bd_buddy_page;get_page (ac->ac_buddy_page);
@@ -3727,7 +3731,7 @@ static void ext4_free_data_in_buddy(struct super_block *sb,* balance refcounts from ext4_mb_free_metadata() */ put_page (e4b.bd_buddy_page); -put_page (e4b.bd_bitmap_page); +folio_put (e4b.bd_bitmap_folio); }ext4_unlock_group (sb, entry->efd_group);ext4_mb_unload_buddy (&e4b);
@@ -5889,7 +5893,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,struct rb_node *parent =NULL , *new_node;BUG_ON (!ext4_handle_valid (handle)); -BUG_ON (e4b->bd_bitmap_page ==NULL ); +BUG_ON (e4b->bd_bitmap_folio ==NULL );BUG_ON (e4b->bd_buddy_page ==NULL ); new_node = &new_entry->efd_node;
@@ -5902,7 +5906,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,* on-disk bitmap and lose not-yet-available * blocks */ get_page (e4b->bd_buddy_page); -get_page (e4b->bd_bitmap_page); +folio_get (e4b->bd_bitmap_folio); }while (*n) { parent = *n;
fs/ext4/mballoc.h +1 -1
@@ -203,7 +203,7 @@ struct ext4_allocation_context {struct ext4_buddy {struct page *bd_buddy_page;void *bd_buddy; -struct page *bd_bitmap_page; +struct folio *bd_bitmap_folio;void *bd_bitmap;struct ext4_group_info *bd_info;struct super_block *bd_sb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1036/1887 ext4: convert bd_buddy_page to bd_buddy_folio
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit 5eea586b47f05b5f5518cf8f9dd9283a01a8066d ]
There is no need to make this a multi-page folio, so leave all the infrastructure around it in pages. But since we're locking it, playing with its refcount and checking whether it's uptodate, it needs to move to the folio API.
Stable-dep-of: bdc56a9c46b2 ("ext4: fix e4b bitmap inconsistency reports")
--- fs/ext4/mballoc.c | 91 +++++++++++++++++++++++------------------------ fs/ext4/mballoc.h | 2 +- 2 files changed, 46 insertions(+), 47 deletions(-)
fs/ext4/mballoc.c +45 -46
@@ -1351,7 +1351,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)* Lock the buddy and bitmap pages. This make sure other parallel init_group * on the same buddy page doesn't happen whild holding the buddy page lock. * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap -* are on the same page e4b->bd_buddy_page is NULL and return value is 0. +* are on the same page e4b->bd_buddy_folio is NULL and return value is 0. */ static int ext4_mb_get_buddy_page_lock (struct super_block *sb,ext4_group_t group,struct ext4_buddy *e4b,gfp_t gfp)
@@ -1359,10 +1359,9 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,struct inode *inode =EXT4_SB (sb)->s_buddy_cache;int block, pnum, poff;int blocks_per_page; -struct page *page;struct folio *folio; - e4b->bd_buddy_page =NULL ; + e4b->bd_buddy_folio =NULL ; e4b->bd_bitmap_folio =NULL ; blocks_per_page =PAGE_SIZE / sb->s_blocksize;
@@ -1388,11 +1387,12 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, }/* blocks_per_page == 1, hence we need another page for the buddy */ - page =find_or_create_page (inode->i_mapping, block +1 , gfp); -if (!page) -return -ENOMEM ; -BUG_ON (page->mapping != inode->i_mapping); - e4b->bd_buddy_page = page; + folio =__filemap_get_folio (inode->i_mapping, block +1 , +FGP_LOCK |FGP_ACCESSED |FGP_CREAT , gfp); +if (IS_ERR (folio)) +return PTR_ERR (folio); +BUG_ON (folio->mapping != inode->i_mapping); + e4b->bd_buddy_folio = folio;return 0 ; }
@@ -1402,9 +1402,9 @@ static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b)folio_unlock (e4b->bd_bitmap_folio);folio_put (e4b->bd_bitmap_folio); } -if (e4b->bd_buddy_page) { -unlock_page (e4b->bd_buddy_page); -put_page (e4b->bd_buddy_page); +if (e4b->bd_buddy_folio) { +folio_unlock (e4b->bd_buddy_folio); +folio_put (e4b->bd_buddy_folio); } }
@@ -1419,7 +1419,6 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)struct ext4_group_info *this_grp;struct ext4_buddy e4b; -struct page *page;struct folio *folio;int ret =0 ;
@@ -1456,7 +1455,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) goto err; } -if (e4b.bd_buddy_page ==NULL ) { +if (e4b.bd_buddy_folio ==NULL ) {/* * If both the bitmap and buddy are in * the same page we don't need to force
@@ -1466,11 +1465,11 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) goto err; }/* init buddy cache */ - page = e4b.bd_buddy_page; - ret =ext4_mb_init_cache (page, e4b.bd_bitmap, gfp); + folio = e4b.bd_buddy_folio; + ret =ext4_mb_init_cache (&folio->page, e4b.bd_bitmap, gfp);if (ret) goto err; -if (!PageUptodate (page)) { +if (!folio_test_uptodate (folio)) { ret = -EIO ; goto err; }
@@ -1492,7 +1491,6 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,int block;int pnum;int poff; -struct page *page;struct folio *folio;int ret;struct ext4_group_info *grp;
@@ -1511,7 +1509,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, e4b->bd_info = grp; e4b->bd_sb = sb; e4b->bd_group = group; - e4b->bd_buddy_page =NULL ; + e4b->bd_buddy_folio =NULL ; e4b->bd_bitmap_folio =NULL ;if (unlikely (EXT4_MB_GRP_NEED_INIT (grp))) {
@@ -1577,7 +1575,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, goto err; } -/* Pages marked accessed already */ +/* Folios marked accessed already */ e4b->bd_bitmap_folio = folio; e4b->bd_bitmap =folio_address (folio) + (poff * sb->s_blocksize);
@@ -1585,48 +1583,49 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, pnum = block / blocks_per_page; poff = block % blocks_per_page; - page =find_get_page_flags (inode->i_mapping, pnum,FGP_ACCESSED ); -if (page ==NULL || !PageUptodate (page)) { -if (page) -put_page (page); - page =find_or_create_page (inode->i_mapping, pnum, gfp); -if (page) { -if (WARN_RATELIMIT (page->mapping != inode->i_mapping, -"ext4: buddy bitmap's page->mapping != inode->i_mapping\n" )) { + folio =__filemap_get_folio (inode->i_mapping, pnum,FGP_ACCESSED ,0 ); +if (IS_ERR (folio) || !folio_test_uptodate (folio)) { +if (!IS_ERR (folio)) +folio_put (folio); + folio =__filemap_get_folio (inode->i_mapping, pnum, +FGP_LOCK |FGP_ACCESSED |FGP_CREAT , gfp); +if (!IS_ERR (folio)) { +if (WARN_RATELIMIT (folio->mapping != inode->i_mapping, +"ext4: buddy bitmap's mapping != inode->i_mapping\n" )) {/* should never happen */ -unlock_page (page); +folio_unlock (folio); ret = -EINVAL ; goto err; } -if (!PageUptodate (page)) { - ret =ext4_mb_init_cache (page, e4b->bd_bitmap, +if (!folio_test_uptodate (folio)) { + ret =ext4_mb_init_cache (&folio->page, e4b->bd_bitmap, gfp);if (ret) { -unlock_page (page); +folio_unlock (folio); goto err; } } -unlock_page (page); +folio_unlock (folio); } } -if (page ==NULL ) { - ret = -ENOMEM ; +if (IS_ERR (folio)) { + ret =PTR_ERR (folio); goto err; } -if (!PageUptodate (page)) { +if (!folio_test_uptodate (folio)) { ret = -EIO ; goto err; } -/* Pages marked accessed already */ - e4b->bd_buddy_page = page; - e4b->bd_buddy =page_address (page) + (poff * sb->s_blocksize); +/* Folios marked accessed already */ + e4b->bd_buddy_folio = folio; + e4b->bd_buddy =folio_address (folio) + (poff * sb->s_blocksize);return 0 ; err: -if (page) -put_page (page); +if (folio) +folio_put (folio);if (e4b->bd_bitmap_folio)folio_put (e4b->bd_bitmap_folio);
@@ -1645,8 +1644,8 @@ static void ext4_mb_unload_buddy(struct ext4_buddy *e4b) {if (e4b->bd_bitmap_folio)folio_put (e4b->bd_bitmap_folio); -if (e4b->bd_buddy_page) -put_page (e4b->bd_buddy_page); +if (e4b->bd_buddy_folio) +folio_put (e4b->bd_buddy_folio); }
@@ -2071,7 +2070,7 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,*/ ac->ac_bitmap_page = &e4b->bd_bitmap_folio->page;get_page (ac->ac_bitmap_page); - ac->ac_buddy_page = e4b->bd_buddy_page; + ac->ac_buddy_page = &e4b->bd_buddy_folio->page;get_page (ac->ac_buddy_page);/* store last allocated for subsequent stream allocation */ if (ac->ac_flags &EXT4_MB_STREAM_ALLOC ) {
@@ -3730,7 +3729,7 @@ static void ext4_free_data_in_buddy(struct super_block *sb,/* No more items in the per group rb tree * balance refcounts from ext4_mb_free_metadata() */ -put_page (e4b.bd_buddy_page); +folio_put (e4b.bd_buddy_folio);folio_put (e4b.bd_bitmap_folio); }ext4_unlock_group (sb, entry->efd_group);
@@ -5894,7 +5893,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,BUG_ON (!ext4_handle_valid (handle));BUG_ON (e4b->bd_bitmap_folio ==NULL ); -BUG_ON (e4b->bd_buddy_page ==NULL ); +BUG_ON (e4b->bd_buddy_folio ==NULL ); new_node = &new_entry->efd_node; cluster = new_entry->efd_start_cluster;
@@ -5905,7 +5904,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,* otherwise we'll refresh it from * on-disk bitmap and lose not-yet-available * blocks */ -get_page (e4b->bd_buddy_page); +folio_get (e4b->bd_buddy_folio);folio_get (e4b->bd_bitmap_folio); }while (*n) {
fs/ext4/mballoc.h +1 -1
@@ -201,7 +201,7 @@ struct ext4_allocation_context {#define AC_STATUS_BREAK 3struct ext4_buddy { -struct page *bd_buddy_page; +struct folio *bd_buddy_folio;void *bd_buddy;struct folio *bd_bitmap_folio;void *bd_bitmap;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1037/1887 ext4: fix e4b bitmap inconsistency reports
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongjian Sun <[email protected]>
[ Upstream commit bdc56a9c46b2a99c12313122b9352b619a2e719e ]
A bitmap inconsistency issue was observed during stress tests under mixed huge-page workloads. Ext4 reported multiple e4b bitmap check failures like:
ext4_mb_complex_scan_group:2508: group 350, 8179 free clusters as per group info. But got 8192 blocks
Analysis and experimentation confirmed that the issue is caused by a race condition between page migration and bitmap modification. Although this timing window is extremely narrow, it is still hit in practice:
folio_lock ext4_mb_load_buddy__migrate_folio
check ref count
folio_mc_copy __filemap_get_folio
folio_try_get(folio)
......
mb_mark_used
ext4_mb_unload_buddy __folio_migrate_mapping
folio_ref_freezefolio_unlock
The root cause of this issue is that the fast path of load_buddy only increments the folio's reference count, which is insufficient to prevent concurrent folio migration. We observed that the folio migration process acquires the folio lock. Therefore, we can determine whether to take the fast path in load_buddy by checking the lock status. If the folio is locked, we opt for the slow path (which acquires the lock) to close this concurrency window.
Additionally, this change addresses the following issues:
When the DOUBLE_CHECK macro is enabled to inspect bitmap-related issues, the following error may be triggered:
corruption in group 324 at byte 784(6272): f in copy != ff on disk/prealloc
Analysis reveals that this is a false positive. There is a specific race window where the bitmap and the group descriptor become momentarily inconsistent, leading to this error report:
ext4_mb_load_buddy ext4_mb_load_buddy
__filemap_get_folio(create|lock)
folio_lock
ext4_mb_init_cache
folio_mark_uptodate
__filemap_get_folio(no lock)
......
mb_mark_used
mb_mark_used_double
mb_cmp_bitmaps
mb_set_bits(e4b->bd_bitmap) folio_unlock
The original logic assumed that since mb_cmp_bitmaps is called when the bitmap is newly loaded from disk, the folio lock would be sufficient to prevent concurrent access. However, this overlooks a specific race
condition: if another process attempts to load buddy and finds the folio is already in an uptodate state, it will immediately begin using it without holding folio lock.
--- fs/ext4/mballoc.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
fs/ext4/mballoc.c +11 -10
@@ -1533,16 +1533,17 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,/* Avoid locking the folio in the fast path ... */ folio =__filemap_get_folio (inode->i_mapping, pnum,FGP_ACCESSED ,0 ); -if (IS_ERR (folio) || !folio_test_uptodate (folio)) { +if (IS_ERR (folio) || !folio_test_uptodate (folio) ||folio_test_locked (folio)) { +/* +* folio_test_locked is employed to detect ongoing folio +* migrations, since concurrent migrations can lead to +* bitmap inconsistency. And if we are not uptodate that +* implies somebody just created the folio but is yet to +* initialize it. We can drop the folio reference and +* try to get the folio with lock in both cases to avoid +* concurrency. +*/ if (!IS_ERR (folio)) -/* -* drop the folio reference and try -* to get the folio with lock. If we -* are not uptodate that implies -* somebody just created the folio but -* is yet to initialize it. So -* wait for it to initialize. -*/ folio_put (folio); folio =__filemap_get_folio (inode->i_mapping, pnum,FGP_LOCK |FGP_ACCESSED |FGP_CREAT , gfp);
@@ -1584,7 +1585,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, poff = block % blocks_per_page; folio =__filemap_get_folio (inode->i_mapping, pnum,FGP_ACCESSED ,0 ); -if (IS_ERR (folio) || !folio_test_uptodate (folio)) { +if (IS_ERR (folio) || !folio_test_uptodate (folio) ||folio_test_locked (folio)) {if (!IS_ERR (folio))folio_put (folio); folio = __filemap_get_folio(inode->i_mapping, pnum,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1038/1887 iommu/vt-d: Clear Present bit before tearing down context entry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
[ Upstream commit c1e4f1dccbe9d7656d1c6872ebeadb5992d0aaa2 ]
When tearing down a context entry, the current implementation zeros the entire 128-bit entry using multiple 64-bit writes. This creates a window where the hardware can fetch a "torn" entry — where some fields are already zeroed while the 'Present' bit is still set — leading to unpredictable behavior or spurious faults.
While x86 provides strong write ordering, the compiler may reorder writes to the two 64-bit halves of the context entry. Even without compiler reordering, the hardware fetch is not guaranteed to be atomic with respect to multiple CPU writes.
Align with the "Guidance to Software for Invalidations" in the VT-d spec (Section 6.5.3.3) by implementing the recommended ownership handshake:
1. Clear only the 'Present' (P) bit of the context entry first to signal the transition of ownership from hardware to software.
2. Use dma_wmb() to ensure the cleared bit is visible to the IOMMU.
3. Perform the required cache and context-cache invalidation to ensure hardware no longer has cached references to the entry.
4. Fully zero out the entry only after the invalidation is complete.
Also, add a dma_wmb() to context_set_present() to ensure the entry is fully initialized before the 'Present' bit becomes visible.
--- drivers/iommu/intel/iommu.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
drivers/iommu/intel/iommu.c +24 -2
@@ -169,7 +169,26 @@ static phys_addr_t root_entry_uctp(struct root_entry *re)static inline void context_set_present (struct context_entry *context) { - context->lo |=1 ; +u64 val; + +dma_wmb (); + val =READ_ONCE (context->lo) |1 ; +WRITE_ONCE (context->lo, val); +} + +/* +* Clear the Present (P) bit (bit 0) of a context table entry. This initiates +* the transition of the entry's ownership from hardware to software. The +* caller is responsible for fulfilling the invalidation handshake recommended +* by the VT-d spec, Section 6.5.3.3 (Guidance to Software for Invalidations). +*/ +static inline void context_clear_present (struct context_entry *context) +{ +u64 val; + + val =READ_ONCE (context->lo) &GENMASK_ULL (63 ,1 ); +WRITE_ONCE (context->lo, val); +dma_wmb (); }static inline void context_set_fault_enable (struct context_entry *context)
@@ -2355,7 +2374,7 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 did_old =context_domain_id (context); } -context_clear_entry (context); +context_clear_present (context);__iommu_flush_cache (iommu, context,sizeof (*context));spin_unlock (&iommu->lock); iommu->flush.flush_context(iommu,
@@ -2374,6 +2393,9 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 DMA_TLB_DSI_FLUSH);__iommu_flush_dev_iotlb (info,0 ,MAX_AGAW_PFN_WIDTH ); + +context_clear_entry (context); +__iommu_flush_cache (iommu, context,sizeof (*context)); } static int domain_setup_first_level(struct intel_iommu *iommu,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1039/1887 hwrng: core - use RCU and work_struct to fix race condition
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lianjie Wang <[email protected]>
[ Upstream commit cc2f39d6ac48e6e3cb2d6240bc0d6df839dd0828 ]
Currently, hwrng_fill is not cleared until the hwrng_fillfn() thread exits. Since hwrng_unregister() reads hwrng_fill outside the rng_mutex lock, a concurrent hwrng_unregister() may call kthread_stop() again on the same task.
Additionally, if hwrng_unregister() is called immediately after hwrng_register(), the stopped thread may have never been executed. Thus, hwrng_fill remains dirty even after hwrng_unregister() returns. In this case, subsequent calls to hwrng_register() will fail to start new threads, and hwrng_unregister() will call kthread_stop() on the same freed task. In both cases, a use-after-free occurs:
refcount_t: addition on 0; use-after-free.
WARNING: ... at lib/refcount.c:25 refcount_warn_saturate+0xec/0x1c0
Call Trace: kthread_stop+0x181/0x360 hwrng_unregister+0x288/0x380 virtrng_remove+0xe3/0x200
This patch fixes the race by protecting the global hwrng_fill pointer inside the rng_mutex lock, so that hwrng_fillfn() thread is stopped only once, and calls to kthread_run() and kthread_stop() are serialized with the lock held.
To avoid deadlock in hwrng_fillfn() while being stopped with the lock held, we convert current_rng to RCU, so that get_current_rng() can read current_rng without holding the lock. To remove the lock from put_rng(), we also delay the actual cleanup into a work_struct.
Since get_current_rng() no longer returns ERR_PTR values, the IS_ERR() checks are removed from its callers.
With hwrng_fill protected by the rng_mutex lock, hwrng_fillfn() can no longer clear hwrng_fill itself. Therefore, if hwrng_fillfn() returns directly after current_rng is dropped, kthread_stop() would be called on a freed task_struct later. To fix this, hwrng_fillfn() calls schedule() now to keep the task alive until being stopped. The kthread_stop() call is also moved from hwrng_unregister() to drop_current_rng(), ensuring kthread_stop() is called on all possible paths where current_rng becomes NULL, so that the thread would not wait forever.
--- drivers/char/hw_random/core.c | 149 ++++++++++++++++++++++------------ include/linux/hw_random.h | 2 + 2 files changed, 100 insertions(+), 51 deletions(-)
drivers/char/hw_random/core.c +98 -51
@@ -22,22 +22,24 @@#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/random.h> +#include <linux/rcupdate.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/uaccess.h> +#include <linux/workqueue.h> #define RNG_MODULE_NAME "hw_random"#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) -static struct hwrng *current_rng; +static struct hwrng __rcu *current_rng;/* the current rng has been explicitly chosen by user via sysfs */ static int cur_rng_set_by_user;static struct task_struct *hwrng_fill;/* list of registered rngs */ static LIST_HEAD (rng_list); -/* Protects rng_list and current_rng */ +/* Protects rng_list, hwrng_fill and updating on current_rng */ static DEFINE_MUTEX (rng_mutex);/* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ static DEFINE_MUTEX (reading_mutex);
@@ -76,18 +78,39 @@ static void add_early_randomness(struct hwrng *rng)add_device_randomness (rng_fillbuf, bytes_read); } -static inline void cleanup_rng (struct kref *kref) +static void cleanup_rng_work (struct work_struct *work) { - struct hwrng *rng = container_of(kref, struct hwrng, ref); + struct hwrng *rng = container_of(work, struct hwrng, cleanup_work); + +/* +* Hold rng_mutex here so we serialize in case they set_current_rng +* on rng again immediately. +*/ +mutex_lock (&rng_mutex); + +/* Skip if rng has been reinitialized. */ +if (kref_read (&rng->ref)) { +mutex_unlock (&rng_mutex); +return ; + }if (rng->cleanup) rng->cleanup (rng);complete (&rng->cleanup_done); +mutex_unlock (&rng_mutex); +} + +static inline void cleanup_rng (struct kref *kref) +{ + struct hwrng *rng = container_of(kref, struct hwrng, ref); + +schedule_work (&rng->cleanup_work); }static int set_current_rng (struct hwrng *rng) { +struct hwrng *old_rng;int err;BUG_ON (!mutex_is_locked (&rng_mutex));
@@ -96,8 +119,14 @@ static int set_current_rng(struct hwrng *rng)if (err)return err; -drop_current_rng (); - current_rng = rng; + old_rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); +rcu_assign_pointer (current_rng, rng); + +if (old_rng) { +synchronize_rcu (); +kref_put (&old_rng->ref, cleanup_rng); + }/* if necessary, start hwrng thread */ if (!hwrng_fill) {
@@ -113,47 +142,56 @@ static int set_current_rng(struct hwrng *rng)static void drop_current_rng (void ) { -BUG_ON (!mutex_is_locked (&rng_mutex)); -if (!current_rng) +struct hwrng *rng; + + rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); +if (!rng)return ; +RCU_INIT_POINTER (current_rng,NULL ); +synchronize_rcu (); + +if (hwrng_fill) { +kthread_stop (hwrng_fill); + hwrng_fill =NULL ; + } +/* decrease last reference for triggering the cleanup */ -kref_put (¤t_rng->ref, cleanup_rng); - current_rng =NULL ; +kref_put (&rng->ref, cleanup_rng); } -/* Returns ERR_PTR(), NULL or refcounted hwrng */ +/* Returns NULL or refcounted hwrng */ static struct hwrng *get_current_rng_nolock (void ) { -if (current_rng) -kref_get (¤t_rng->ref); +struct hwrng *rng; + + rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); +if (rng) +kref_get (&rng->ref); -return current_rng; +return rng; }static struct hwrng *get_current_rng (void ) {struct hwrng *rng; -if (mutex_lock_interruptible (&rng_mutex)) -return ERR_PTR (-ERESTARTSYS ); +rcu_read_lock (); + rng =rcu_dereference (current_rng); +if (rng) +kref_get (&rng->ref); - rng =get_current_rng_nolock (); +rcu_read_unlock (); -mutex_unlock (&rng_mutex);return rng; }static void put_rng (struct hwrng *rng) { -/* -* Hold rng_mutex here so we serialize in case they set_current_rng -* on rng again immediately. -*/ -mutex_lock (&rng_mutex);if (rng)kref_put (&rng->ref, cleanup_rng); -mutex_unlock (&rng_mutex); }static int hwrng_init (struct hwrng *rng)
@@ -222,10 +260,6 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,while (size) { rng =get_current_rng (); -if (IS_ERR (rng)) { - err =PTR_ERR (rng); - goto out; - }if (!rng) { err = -ENODEV ; goto out;
@@ -312,7 +346,7 @@ static struct miscdevice rng_miscdev = {static int enable_best_rng (void ) { -struct hwrng *rng, *new_rng =NULL ; +struct hwrng *rng, *cur_rng, *new_rng =NULL ;int ret = -ENODEV ;BUG_ON (!mutex_is_locked (&rng_mutex));
@@ -330,7 +364,9 @@ static int enable_best_rng(void) new_rng = rng; } - ret = ((new_rng == current_rng) ?0 :set_current_rng (new_rng)); + cur_rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); + ret = ((new_rng == cur_rng) ?0 :set_current_rng (new_rng));if (!ret) cur_rng_set_by_user =0 ;
@@ -381,8 +417,6 @@ static ssize_t rng_current_show(struct device *dev,struct hwrng *rng; rng =get_current_rng (); -if (IS_ERR (rng)) -return PTR_ERR (rng); ret =snprintf (buf,PAGE_SIZE ,"%s\n" , rng ? rng->name :"none" );put_rng (rng);
@@ -426,8 +460,6 @@ static ssize_t rng_quality_show(struct device *dev,struct hwrng *rng; rng =get_current_rng (); -if (IS_ERR (rng)) -return PTR_ERR (rng);if (!rng)/* no need to put_rng */ return -ENODEV ;
@@ -442,6 +474,7 @@ static ssize_t rng_quality_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t len) { + struct hwrng *rng;u16 quality;int ret = -EINVAL ;
@@ -458,12 +491,13 @@ static ssize_t rng_quality_store(struct device *dev, goto out; } -if (!current_rng) { + rng =rcu_dereference_protected (current_rng,lockdep_is_held (&rng_mutex)); +if (!rng) { ret = -ENODEV ; goto out; } - current_rng->quality = quality; + rng->quality = quality; current_quality = quality;/* obsolete */ /* the best available RNG may have changed */
@@ -509,8 +543,20 @@ static int hwrng_fillfn(void *unused)struct hwrng *rng; rng =get_current_rng (); -if (IS_ERR (rng) || !rng) +if (!rng) { +/* +* Keep the task_struct alive until kthread_stop() +* is called to avoid UAF in drop_current_rng(). +*/ +while (!kthread_should_stop ()) { +set_current_state (TASK_INTERRUPTIBLE ); +if (!kthread_should_stop ()) +schedule (); + } +set_current_state (TASK_RUNNING );break ; + } +mutex_lock (&reading_mutex); rc =rng_get_data (rng, rng_fillbuf,rng_buffer_size (),1 );
@@ -538,14 +584,13 @@ static int hwrng_fillfn(void *unused)add_hwgenerator_randomness ((void *)rng_fillbuf, rc, entropy >>10 ); } - hwrng_fill =NULL ;return 0 ; }int hwrng_register (struct hwrng *rng) {int err = -EINVAL ; -struct hwrng *tmp; +struct hwrng *cur_rng, *tmp;bool is_new_current = false;if (!rng->name || (!rng->data_read && !rng->read))
@@ -561,12 +606,15 @@ int hwrng_register(struct hwrng *rng) }list_add_tail (&rng->list, &rng_list); +INIT_WORK (&rng->cleanup_work, cleanup_rng_work);init_completion (&rng->cleanup_done);complete (&rng->cleanup_done);init_completion (&rng->dying); -if (!current_rng || - (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { + cur_rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); +if (!cur_rng || + (!cur_rng_set_by_user && rng->quality > cur_rng->quality)) {/* * Set new rng as current as the new rng source * provides better entropy quality and was not
@@ -604,15 +652,19 @@ EXPORT_SYMBOL_GPL(hwrng_register);void hwrng_unregister (struct hwrng *rng) { -struct hwrng *old_rng, *new_rng; +struct hwrng *cur_rng, *old_rng, *new_rng;int err;mutex_lock (&rng_mutex); - old_rng = current_rng; + old_rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex));list_del (&rng->list);complete_all (&rng->dying); -if (current_rng == rng) { + + cur_rng =rcu_dereference_protected (current_rng, +lockdep_is_held (&rng_mutex)); +if (cur_rng == rng) { err =enable_best_rng ();if (err) {drop_current_rng ();
@@ -621,12 +673,7 @@ void hwrng_unregister(struct hwrng *rng) } new_rng =get_current_rng_nolock (); -if (list_empty (&rng_list)) { -mutex_unlock (&rng_mutex); -if (hwrng_fill) -kthread_stop (hwrng_fill); - }else -mutex_unlock (&rng_mutex); +mutex_unlock (&rng_mutex);if (new_rng) {if (old_rng != new_rng)
@@ -721,7 +768,7 @@ static int __init hwrng_modinit(void) static void __exit hwrng_modexit(void) {mutex_lock (&rng_mutex); -BUG_ON (current_rng); +WARN_ON (rcu_access_pointer (current_rng));kfree (rng_buffer);kfree (rng_fillbuf);mutex_unlock (&rng_mutex);
include/linux/hw_random.h +2 -0
@@ -16,6 +16,7 @@#include <linux/types.h> #include <linux/list.h> #include <linux/kref.h> +#include <linux/workqueue.h> /** * struct hwrng - Hardware Random Number Generator driver
@@ -49,6 +50,7 @@ struct hwrng {/* internal. */ struct list_head list;struct kref ref; +struct work_struct cleanup_work;struct completion cleanup_done;struct completion dying; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1040/1887 rcu: Fix rcu_read_unlock() deadloop due to softirq
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yao Kai <[email protected]>
[ Upstream commit d41e37f26b3157b3f1d10223863519a943aa239b ]
Commit 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") removes the recursion-protection code from __rcu_read_unlock(). Therefore, we could invoke the deadloop in raise_softirq_irqoff() with ftrace enabled as follows:
WARNING: CPU: 0 PID: 0 at kernel/trace/trace.c:3021 __ftrace_trace_stack.constprop.0+0x172/0x180 Modules linked in: my_irq_work(O) CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G O 6.18.0-rc7-dirty #23 PREEMPT(full) Tainted: [O]=OOT_MODULE Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:__ftrace_trace_stack.constprop.0+0x172/0x180 RSP: 0018:ffffc900000034a8 EFLAGS: 00010002 RAX: 0000000000000000 RBX: 0000000000000004 RCX: 0000000000000000 RDX: 0000000000000003 RSI: ffffffff826d7b87 RDI: ffffffff826e9329 RBP: 0000000000090009 R08: 0000000000000005 R09: ffffffff82afbc4c R10: 0000000000000008 R11: 0000000000011d7a R12: 0000000000000000 R13: ffff888003874100 R14: 0000000000000003 R15: ffff8880038c1054 FS: 0000000000000000(0000) GS:ffff8880fa8ea000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055b31fa7f540 CR3: 00000000078f4005 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: <IRQ> trace_buffer_unlock_commit_regs+0x6d/0x220 trace_event_buffer_commit+0x5c/0x260 trace_event_raw_event_softirq+0x47/0x80 raise_softirq_irqoff+0x6e/0xa0 rcu_read_unlock_special+0xb1/0x160 unwind_next_frame+0x203/0x9b0 __unwind_start+0x15d/0x1c0 arch_stack_walk+0x62/0xf0 stack_trace_save+0x48/0x70 __ftrace_trace_stack.constprop.0+0x144/0x180 trace_buffer_unlock_commit_regs+0x6d/0x220 trace_event_buffer_commit+0x5c/0x260 trace_event_raw_event_softirq+0x47/0x80 raise_softirq_irqoff+0x6e/0xa0 rcu_read_unlock_special+0xb1/0x160 unwind_next_frame+0x203/0x9b0 __unwind_start+0x15d/0x1c0 arch_stack_walk+0x62/0xf0 stack_trace_save+0x48/0x70 __ftrace_trace_stack.constprop.0+0x144/0x180 trace_buffer_unlock_commit_regs+0x6d/0x220 trace_event_buffer_commit+0x5c/0x260 trace_event_raw_event_softirq+0x47/0x80 raise_softirq_irqoff+0x6e/0xa0 rcu_read_unlock_special+0xb1/0x160 unwind_next_frame+0x203/0x9b0 __unwind_start+0x15d/0x1c0 arch_stack_walk+0x62/0xf0 stack_trace_save+0x48/0x70 __ftrace_trace_stack.constprop.0+0x144/0x180 trace_buffer_unlock_commit_regs+0x6d/0x220 trace_event_buffer_commit+0x5c/0x260 trace_event_raw_event_softirq+0x47/0x80 raise_softirq_irqoff+0x6e/0xa0 rcu_read_unlock_special+0xb1/0x160 __is_insn_slot_addr+0x54/0x70 kernel_text_address+0x48/0xc0 __kernel_text_address+0xd/0x40 unwind_get_return_address+0x1e/0x40 arch_stack_walk+0x9c/0xf0 stack_trace_save+0x48/0x70 __ftrace_trace_stack.constprop.0+0x144/0x180 trace_buffer_unlock_commit_regs+0x6d/0x220 trace_event_buffer_commit+0x5c/0x260 trace_event_raw_event_softirq+0x47/0x80 __raise_softirq_irqoff+0x61/0x80 __flush_smp_call_function_queue+0x115/0x420 __sysvec_call_function_single+0x17/0xb0 sysvec_call_function_single+0x8c/0xc0 </IRQ>
Commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work") fixed the infinite loop in rcu_read_unlock_special() for IRQ work by setting a flag before calling irq_work_queue_on(). We fix this issue by setting the same flag before calling raise_softirq_irqoff() and rename the flag to defer_qs_pending for more common.
--- kernel/rcu/tree.h | 2 +- kernel/rcu/tree_plugin.h | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-)
kernel/rcu/tree.h +1 -1
@@ -186,7 +186,7 @@ struct rcu_data {/* during and after the last grace */ /* period it is aware of. */ struct irq_work defer_qs_iw;/* Obtain later scheduler attention. */ -int defer_qs_iw_pending;/* Scheduler attention pending? */ +int defer_qs_pending;/* irqwork or softirq pending? */ struct work_struct strict_work;/* Schedule readers for strict GPs. */ /* 2) batch handling */
kernel/rcu/tree_plugin.h +9 -6
@@ -475,8 +475,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)union rcu_special special; rdp =this_cpu_ptr (&rcu_data); -if (rdp->defer_qs_iw_pending ==DEFER_QS_PENDING ) - rdp->defer_qs_iw_pending =DEFER_QS_IDLE ; +if (rdp->defer_qs_pending ==DEFER_QS_PENDING ) + rdp->defer_qs_pending =DEFER_QS_IDLE ;/* * If RCU core is waiting for this CPU to exit its critical section,
@@ -635,7 +635,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)* 5. Deferred QS reporting does not happen. */ if (rcu_preempt_depth () >0 ) -WRITE_ONCE (rdp->defer_qs_iw_pending,DEFER_QS_IDLE ); +WRITE_ONCE (rdp->defer_qs_pending,DEFER_QS_IDLE );local_irq_restore (flags); }
@@ -674,7 +674,10 @@ static void rcu_read_unlock_special(struct task_struct *t)// Using softirq, safe to awaken, and either the // wakeup is free or there is either an expedited // GP in flight or a potential need to deboost. -raise_softirq_irqoff (RCU_SOFTIRQ ); +if (rdp->defer_qs_pending !=DEFER_QS_PENDING ) { + rdp->defer_qs_pending =DEFER_QS_PENDING ; +raise_softirq_irqoff (RCU_SOFTIRQ ); + } }else {// Enabling BH or preempt does reschedule, so... // Also if no expediting and no possible deboosting,
@@ -683,13 +686,13 @@ static void rcu_read_unlock_special(struct task_struct *t)set_tsk_need_resched (current);set_preempt_need_resched ();if (IS_ENABLED (CONFIG_IRQ_WORK ) && irqs_were_disabled && - expboost && rdp->defer_qs_iw_pending !=DEFER_QS_PENDING && + expboost && rdp->defer_qs_pending !=DEFER_QS_PENDING &&cpu_online (rdp->cpu)) {// Get scheduler to re-evaluate and call hooks. // If !IRQ_WORK, FQS scan will eventually IPI. rdp->defer_qs_iw =IRQ_WORK_INIT_HARD (rcu_preempt_deferred_qs_handler); - rdp->defer_qs_iw_pending =DEFER_QS_PENDING ; + rdp->defer_qs_pending =DEFER_QS_PENDING ;irq_work_queue_on (&rdp->defer_qs_iw, rdp->cpu); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1041/1887 gfs2: fix memory leaks in gfs2_fill_super error path
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 da6f5bbc2e7902f578b503f2a4c3d8d09ca4b102 ]
Fix two memory leaks in the gfs2_fill_super() error handling path when transitioning a filesystem to read-write mode fails.
First leak: kthread objects (thread_struct, task_struct, etc.) When gfs2_freeze_lock_shared() fails after init_threads() succeeds, the created kernel threads (logd and quotad) are never destroyed. This occurs because the fail_per_node label doesn't call gfs2_destroy_threads().
Second leak: quota bitmap buffer (8192 bytes)
When gfs2_make_fs_rw() fails after gfs2_quota_init() succeeds but before other operations complete, the allocated quota bitmap is never freed.
The fix moves thread cleanup to the fail_per_node label to handle all error paths uniformly. gfs2_destroy_threads() is safe to call unconditionally as it checks for NULL pointers. Quota cleanup is added in gfs2_make_fs_rw() to properly handle the withdrawal case where quota initialization succeeds but the filesystem is then withdrawn.
Thread leak backtrace (gfs2_freeze_lock_shared failure):
unreferenced object 0xffff88801d7bca80 (size 4480):
copy_process+0x3a1/0x4670 kernel/fork.c:2422
kernel_clone+0xf3/0x6e0 kernel/fork.c:2779
kthread_create_on_node+0x100/0x150 kernel/kthread.c:478
init_threads+0xab/0x350 fs/gfs2/ops_fstype.c:611
gfs2_fill_super+0xe5c/0x1240 fs/gfs2/ops_fstype.c:1265Quota leak backtrace (gfs2_make_fs_rw failure):
unreferenced object 0xffff88812de7c000 (size 8192):
gfs2_quota_init+0xe5/0x820 fs/gfs2/quota.c:1409
gfs2_make_fs_rw+0x7a/0xe0 fs/gfs2/super.c:149
gfs2_fill_super+0xfbb/0x1240 fs/gfs2/ops_fstype.c:1275--- fs/gfs2/ops_fstype.c | 12 ++++++------ fs/gfs2/super.c | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-)
fs/gfs2/ops_fstype.c +6 -6
@@ -1273,12 +1273,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)if (error) {gfs2_freeze_unlock (&sdp->sd_freeze_gh); -if (sdp->sd_quotad_process) -kthread_stop (sdp->sd_quotad_process); - sdp->sd_quotad_process =NULL ; -if (sdp->sd_logd_process) -kthread_stop (sdp->sd_logd_process); - sdp->sd_logd_process =NULL ;fs_err (sdp,"can't make FS RW: %d\n" , error); goto fail_per_node; }
@@ -1288,6 +1282,12 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) fail_per_node:init_per_node (sdp,UNDO ); +if (sdp->sd_quotad_process) +kthread_stop (sdp->sd_quotad_process); + sdp->sd_quotad_process =NULL ; +if (sdp->sd_logd_process) +kthread_stop (sdp->sd_logd_process); + sdp->sd_logd_process =NULL ; fail_inodes:init_inodes (sdp,UNDO ); fail_sb:
fs/gfs2/super.c +3 -1
@@ -157,8 +157,10 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)gfs2_log_pointers_init (sdp, head.lh_blkno); error =gfs2_quota_init (sdp); -if (!error &&gfs2_withdrawn (sdp)) +if (!error &&gfs2_withdrawn (sdp)) { +gfs2_quota_cleanup (sdp); error = -EIO ; + }if (!error)set_bit (SDF_JOURNAL_LIVE , &sdp->sd_flags);return error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1042/1887 ext4: dont set EXT4_GET_BLOCKS_CONVERT when splitting before submitting I/O
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
[ Upstream commit feaf2a80e78f89ee8a3464126077ba8683b62791 ]
When allocating blocks during within-EOF DIO and writeback with dioread_nolock enabled, EXT4_GET_BLOCKS_PRE_IO was set to split an existing large unwritten extent. However, EXT4_GET_BLOCKS_CONVERT was set when calling ext4_split_convert_extents(), which may potentially result in stale data issues.
Assume we have an unwritten extent, and then DIO writes the second half.
[UUUUUUUUUUUUUUUU] on-disk extent U: unwritten extent
[UUUUUUUUUUUUUUUU] extent status tree
|<- ->| ----> dio write this range
First, ext4_iomap_alloc() call ext4_map_blocks() with EXT4_GET_BLOCKS_PRE_IO, EXT4_GET_BLOCKS_UNWRIT_EXT and EXT4_GET_BLOCKS_CREATE flags set. ext4_map_blocks() find this extent and call ext4_split_convert_extents() with EXT4_GET_BLOCKS_CONVERT and the above flags set.
Then, ext4_split_convert_extents() calls ext4_split_extent() with EXT4_EXT_MAY_ZEROOUT, EXT4_EXT_MARK_UNWRIT2 and EXT4_EXT_DATA_VALID2 flags set, and it calls ext4_split_extent_at() to split the second half with EXT4_EXT_DATA_VALID2, EXT4_EXT_MARK_UNWRIT1, EXT4_EXT_MAY_ZEROOUT and EXT4_EXT_MARK_UNWRIT2 flags set. However, ext4_split_extent_at() failed to insert extent since a temporary lack -ENOSPC. It zeroes out the first half but convert the entire on-disk extent to written since the EXT4_EXT_DATA_VALID2 flag set, but left the second half as unwritten in the extent status tree.
[0000000000SSSSSS] data S: stale data, 0: zeroed [WWWWWWWWWWWWWWWW] on-disk extent W: written extent [WWWWWWWWWWUUUUUU] extent status tree
Finally, if the DIO failed to write data to the disk, the stale data in the second half will be exposed once the cached extent entry is gone.
Fix this issue by not passing EXT4_GET_BLOCKS_CONVERT when splitting an unwritten extent before submitting I/O, and make ext4_split_convert_extents() to zero out the entire extent range to zero for this case, and also mark the extent in the extent status tree for consistency.
Message-ID: <[email protected]>
--- fs/ext4/extents.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
fs/ext4/extents.c +8 -4
@@ -3730,11 +3730,15 @@ static int ext4_split_convert_extents(handle_t *handle,/* Convert to unwritten */ if (flags &EXT4_GET_BLOCKS_CONVERT_UNWRITTEN ) { split_flag |=EXT4_EXT_DATA_VALID1 ; -/* Convert to initialized */ - }else if (flags &EXT4_GET_BLOCKS_CONVERT ) { +/* Split the existing unwritten extent */ + }else if (flags & (EXT4_GET_BLOCKS_UNWRIT_EXT | +EXT4_GET_BLOCKS_CONVERT )) { split_flag |= ee_block + ee_len <= eof_block ?EXT4_EXT_MAY_ZEROOUT :0 ; - split_flag |= (EXT4_EXT_MARK_UNWRIT2 |EXT4_EXT_DATA_VALID2 ); + split_flag |=EXT4_EXT_MARK_UNWRIT2 ; +/* Convert to initialized */ +if (flags &EXT4_GET_BLOCKS_CONVERT ) + split_flag |=EXT4_EXT_DATA_VALID2 ; } flags |=EXT4_GET_BLOCKS_PRE_IO ;return ext4_split_extent (handle, inode, ppath, map, split_flag, flags);
@@ -3899,7 +3903,7 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,/* get_block() before submitting IO, split the extent */ if (flags &EXT4_GET_BLOCKS_PRE_IO ) { ret =ext4_split_convert_extents (handle, inode, map, ppath, - flags |EXT4_GET_BLOCKS_CONVERT ); + flags);if (ret <0 ) { err = ret; goto out2;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1043/1887 rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 24481a7f573305706054c59e275371f8d0fe919f ]
The security operations that verify the RESPONSE packets decrypt bits of it in place - however, the sk_buff may be shared with a packet sniffer, which would lead to the sniffer seeing an apparently corrupt packet (actually decrypted).
Fix this by handing a copy of the packet off to the specific security handler if the packet was cloned.
--- net/rxrpc/conn_event.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-)
net/rxrpc/conn_event.c +29 -1
@@ -285,6 +285,34 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call) } } +static int rxrpc_verify_response (struct rxrpc_connection *conn, +struct sk_buff *skb, +u32 *_abort_code) +{ +int ret; + +if (skb_cloned (skb)) { +/* Copy the packet if shared so that we can do in-place +* decryption. +*/ +struct sk_buff *nskb =skb_copy (skb,GFP_NOFS ); + +if (nskb) { +rxrpc_new_skb (nskb, rxrpc_skb_unshared); + ret = conn->security->verify_response (conn, nskb, _abort_code); +rxrpc_free_skb (nskb, rxrpc_skb_freed); + }else { +/* OOM - Drop the packet. */ +rxrpc_see_skb (skb, rxrpc_skb_unshared_nomem); + ret = -ENOMEM ; + } + }else { + ret = conn->security->verify_response (conn, skb, _abort_code); + } + +return ret; +} +/* * connection-level Rx packet processor */
@@ -345,7 +373,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, }spin_unlock_bh (&conn->state_lock); - ret = conn->security->verify_response (conn, skb, _abort_code); + ret =rxrpc_verify_response (conn, skb, _abort_code);if (ret <0 )return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1044/1887 rxrpc: Fix memory leaks in rxkad_verify_response()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 34f61a07e0cdefaecd3ec03bb5fb22215643678f ]
Fix rxkad_verify_response() to free the ticket and the server key under all circumstances by initialising the ticket pointer to NULL and then making all paths through the function after the first allocation has been done go through a single common epilogue that just releases everything - where all the releases skip on a NULL pointer.
--- net/rxrpc/rxkad.c | 1 + 1 file changed, 1 insertion(+)
net/rxrpc/rxkad.c +1 -0
@@ -1311,6 +1311,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,kfree (ticket);kfree (response); +key_put (server_key);_leave (" = 0" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1045/1887 KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
[ Upstream commit 5d291ef0585ed880ed4dd71ea1a5965e0a65fb53 ]
If loading L1's CR3 fails on a nested #VMEXIT, nested_svm_vmexit() returns an error code that is ignored by most callers, and continues to run L1 with corrupted state. A sane recovery is not possible in this case, and HW behavior is to cause a shutdown. Inject a triple fault instead, and do not return early from nested_svm_vmexit(). Continue cleaning up the vCPU state (e.g. clear pending exceptions), to handle the failure as gracefully as possible.
Quoted 1 line
From the APM:
Upon #VMEXIT, the processor performs the following actions in order to return to the host execution context:
...
if (illegal host state loaded, or exception while loading host state)
shutdown
else
execute first host instruction following the VMRUN
Remove the return value of nested_svm_vmexit(), which is mostly unchecked anyway.
--- arch/x86/kvm/svm/nested.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/nested.c +2 -3
@@ -1057,9 +1057,8 @@ int nested_svm_vmexit(struct vcpu_svm *svm)nested_svm_uninit_mmu_context (vcpu); - rc =nested_svm_load_cr3 (vcpu, vmcb01->save.cr3, false, true); -if (rc) -return 1 ; +if (nested_svm_load_cr3 (vcpu, vmcb01->save.cr3, false, true)) +kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu);/* * Drop what we picked up for L2 via svm_complete_interrupts() so it
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1046/1887 KVM: nSVM: Always use NextRIP as vmcb02s NextRIP after first L2 VMRUN
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
[ Upstream commit 8d397582f6b5e9fbcf09781c7c934b4910e94a50 ]
For guests with NRIPS disabled, L1 does not provide NextRIP when running an L2 with an injected soft interrupt, instead it advances the current RIP before running it. KVM uses the current RIP as the NextRIP in vmcb02 to emulate a CPU without NRIPS.
However, after L2 runs the first time, NextRIP will be updated by the CPU and/or KVM, and the current RIP is no longer the correct value to use in vmcb02. Hence, after save/restore, use the current RIP if and only if a nested run is pending, otherwise use NextRIP. Give soft_int_next_rip the same treatment, as it's the same logic, just for a narrower use case.
--- arch/x86/kvm/svm/nested.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
arch/x86/kvm/svm/nested.c +16 -10
@@ -684,24 +684,30 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, vmcb02->control.event_inj_err = svm->nested.ctl.event_inj_err;/* -* next_rip is consumed on VMRUN as the return address pushed on the +* NextRIP is consumed on VMRUN as the return address pushed on the * stack for injected soft exceptions/interrupts. If nrips is exposed -* to L1, take it verbatim from vmcb12. If nrips is supported in -* hardware but not exposed to L1, stuff the actual L2 RIP to emulate -* what a nrips=0 CPU would do (L1 is responsible for advancing RIP -* prior to injecting the event). +* to L1, take it verbatim from vmcb12. +* +* If nrips is supported in hardware but not exposed to L1, stuff the +* actual L2 RIP to emulate what a nrips=0 CPU would do (L1 is +* responsible for advancing RIP prior to injecting the event). This is +* only the case for the first L2 run after VMRUN. After that (e.g. +* during save/restore), NextRIP is updated by the CPU and/or KVM, and +* the value of the L2 RIP from vmcb12 should not be used. */ -if (svm->nrips_enabled) - vmcb02->control.next_rip = svm->nested.ctl.next_rip; -else if (boot_cpu_has (X86_FEATURE_NRIPS )) - vmcb02->control.next_rip = vmcb12_rip; +if (boot_cpu_has (X86_FEATURE_NRIPS )) { +if (svm->nrips_enabled || !svm->nested.nested_run_pending) + vmcb02->control.next_rip = svm->nested.ctl.next_rip; +else + vmcb02->control.next_rip = vmcb12_rip; + } svm->nmi_l1_to_l2 =is_evtinj_nmi (vmcb02->control.event_inj);if (is_evtinj_soft (vmcb02->control.event_inj)) { svm->soft_int_injected = true; svm->soft_int_csbase = vmcb12_csbase; svm->soft_int_old_rip = vmcb12_rip; -if (svm->nrips_enabled) +if (svm->nrips_enabled || !svm->nested.nested_run_pending) svm->soft_int_next_rip = svm->nested.ctl.next_rip;else svm->soft_int_next_rip = vmcb12_rip;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1047/1887 KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
[ Upstream commit b53ab5167a81537777ac780bbd93d32613aa3bda ]
svm_copy_lbrs() always marks VMCB_LBR dirty in the destination VMCB. However, nested_svm_vmexit() uses it to copy LBRs to vmcb12, and clearing clean bits in vmcb12 is not architecturally defined.
Move vmcb_mark_dirty() to callers and drop it for vmcb12.
This also facilitates incoming refactoring that does not pass the entire VMCB to svm_copy_lbrs().
--- arch/x86/kvm/svm/nested.c | 3 +++ arch/x86/kvm/svm/svm.c | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/nested.c +3 -0
@@ -589,10 +589,12 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12*/ svm_copy_lbrs (vmcb02, vmcb12); vmcb02->save.dbgctl &= ~DEBUGCTL_RESERVED_BITS ; +vmcb_mark_dirty (vmcb02,VMCB_LBR );svm_update_lbrv (&svm->vcpu); }else if (unlikely (vmcb01->control.virt_ext &LBR_CTL_ENABLE_MASK )) {svm_copy_lbrs (vmcb02, vmcb01); +vmcb_mark_dirty (vmcb02,VMCB_LBR ); } }
@@ -1012,6 +1014,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)svm_update_lbrv (vcpu); }else if (unlikely (vmcb01->control.virt_ext &LBR_CTL_ENABLE_MASK )) {svm_copy_lbrs (vmcb01, vmcb02); +vmcb_mark_dirty (vmcb01,VMCB_LBR );svm_update_lbrv (vcpu); }
arch/x86/kvm/svm/svm.c +6 -4
@@ -910,8 +910,6 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb) to_vmcb->save.br_to = from_vmcb->save.br_to; to_vmcb->save.last_excp_from = from_vmcb->save.last_excp_from; to_vmcb->save.last_excp_to = from_vmcb->save.last_excp_to; - -vmcb_mark_dirty (to_vmcb,VMCB_LBR ); }static void svm_enable_lbrv (struct kvm_vcpu *vcpu)
@@ -925,8 +923,10 @@ static void svm_enable_lbrv(struct kvm_vcpu *vcpu)set_msr_interception (vcpu, svm->msrpm,MSR_IA32_LASTINTTOIP ,1 ,1 );/* Move the LBR msrs to the vmcb02 so that the guest can see them. */ -if (is_guest_mode (vcpu)) +if (is_guest_mode (vcpu)) {svm_copy_lbrs (svm->vmcb, svm->vmcb01.ptr); +vmcb_mark_dirty (svm->vmcb,VMCB_LBR ); + } }static void svm_disable_lbrv (struct kvm_vcpu *vcpu)
@@ -943,8 +943,10 @@ static void svm_disable_lbrv(struct kvm_vcpu *vcpu)* Move the LBR msrs back to the vmcb01 to avoid copying them * on nested guest entries. */ -if (is_guest_mode (vcpu)) +if (is_guest_mode (vcpu)) {svm_copy_lbrs (svm->vmcb01.ptr, svm->vmcb); +vmcb_mark_dirty (svm->vmcb01.ptr,VMCB_LBR ); + } }static int svm_get_lbr_msr (struct vcpu_svm *svm,u32 index)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1048/1887 spi: microchip-core-qspi: control built-in cs manually
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Conor Dooley <[email protected]>
[ Upstream commit 7672749e1496215e8683ce57cf323119033954cf ]
The coreQSPI IP supports only a single chip select, which is automagically operated by the hardware - set low when the transmit buffer first gets written to and set high when the number of bytes written to the TOTALBYTES field of the FRAMES register have been sent on the bus. Additional devices must use GPIOs for their chip selects. It was reported to me that if there are two devices attached to this QSPI controller that the in-built chip select is set low while linux tries to access the device attached to the GPIO.
This went undetected as the boards that connected multiple devices to the SPI controller all exclusively used GPIOs for chip selects, not relying on the built-in chip select at all. It turns out that this was because the built-in chip select, when controlled automagically, is set low when active and high when inactive, thereby ruling out its use for active-high devices or devices that need to transmit with the chip select disabled.
Modify the driver so that it controls chip select directly, retaining the behaviour for mem_ops of setting the chip select active for the entire duration of the transfer in the exec_op callback. For regular transfers, implement the set_cs callback for the core to use.
As part of this, the existing setup callback, mchp_coreqspi_setup_op(), is removed. Modifying the CLKIDLE field is not safe to do during operation when there are multiple devices, so this code is removed entirely. Setting the MASTER and ENABLE fields is something that can be done once at probe, it doesn't need to be re-run for each device. Instead the new setup callback sets the built-in chip select to its inactive state for active-low devices, as the reset value of the chip select in software controlled mode is low.
--- drivers/spi/spi-microchip-core-qspi.c | 79 ++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 14 deletions(-)
drivers/spi/spi-microchip-core-qspi.c +65 -14
@@ -74,6 +74,13 @@#define STATUS_FLAGSX4 BIT(8)#define STATUS_MASK GENMASK(8, 0) +/* +* QSPI Direct Access register defines +*/ +#define DIRECT_ACCESS_EN_SSEL BIT(0) +#define DIRECT_ACCESS_OP_SSEL BIT(1) +#define DIRECT_ACCESS_OP_SSEL_SHIFT 1 +#define BYTESUPPER_MASK GENMASK(31, 16)#define BYTESLOWER_MASK GENMASK(15, 0)
@@ -158,6 +165,38 @@ static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_mreturn 0 ; } +static void mchp_coreqspi_set_cs (struct spi_device *spi,bool enable) +{ +struct mchp_coreqspi *qspi =spi_controller_get_devdata (spi->controller); +u32 val; + + val =readl (qspi->regs +REG_DIRECT_ACCESS ); + + val &= ~DIRECT_ACCESS_OP_SSEL ; + val |= !enable <<DIRECT_ACCESS_OP_SSEL_SHIFT ; + +writel (val, qspi->regs +REG_DIRECT_ACCESS ); +} + +static int mchp_coreqspi_setup (struct spi_device *spi) +{ +struct mchp_coreqspi *qspi =spi_controller_get_devdata (spi->controller); +u32 val; + +/* +* Active low devices need to be specifically set to their inactive +* states during probe. +*/ +if (spi->mode &SPI_CS_HIGH ) +return 0 ; + + val =readl (qspi->regs +REG_DIRECT_ACCESS ); + val |=DIRECT_ACCESS_OP_SSEL ; +writel (val, qspi->regs +REG_DIRECT_ACCESS ); + +return 0 ; +} +static inline void mchp_coreqspi_read_op (struct mchp_coreqspi *qspi) {u32 control, data;
@@ -298,19 +337,6 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devireturn 0 ; } -static int mchp_coreqspi_setup_op (struct spi_device *spi_dev) -{ -struct spi_controller *ctlr = spi_dev->master; -struct mchp_coreqspi *qspi =spi_controller_get_devdata (ctlr); -u32 control =readl_relaxed (qspi->regs +REG_CONTROL ); - - control |= (CONTROL_MASTER |CONTROL_ENABLE ); - control &= ~CONTROL_CLKIDLE ; -writel_relaxed (control, qspi->regs +REG_CONTROL ); - -return 0 ; -} -static inline void mchp_coreqspi_config_op (struct mchp_coreqspi *qspi,const struct spi_mem_op *op) {u32 idle_cycles =0 ;
@@ -409,6 +435,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *oreinit_completion (&qspi->data_completion);mchp_coreqspi_config_op (qspi, op); +mchp_coreqspi_set_cs (mem->spi, true);if (op->cmd.opcode) { qspi->txbuf = &opcode; qspi->rxbuf =NULL ;
@@ -449,6 +476,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o err = -ETIMEDOUT ; error: +mchp_coreqspi_set_cs (mem->spi, false);mutex_unlock (&qspi->op_lock);mchp_coreqspi_disable_ints (qspi);
@@ -505,6 +533,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)struct device *dev = &pdev->dev;struct device_node *np = dev->of_node;int ret; +u32 num_cs, val; ctlr =devm_spi_alloc_master (&pdev->dev,sizeof (*qspi));if (!ctlr)
@@ -538,12 +567,34 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)return ret; } +/* +* The IP core only has a single CS, any more have to be provided via +* gpios +*/ +if (of_property_read_u32 (pdev->dev.of_node,"num-cs" , &num_cs)) + num_cs =1 ; + + ctlr->num_chipselect = num_cs; + ctlr->bits_per_word_mask =SPI_BPW_MASK (8 ); ctlr->mem_ops = &mchp_coreqspi_mem_ops; - ctlr->setup = mchp_coreqspi_setup_op; ctlr->mode_bits =SPI_CPOL |SPI_CPHA |SPI_RX_DUAL |SPI_RX_QUAD |SPI_TX_DUAL |SPI_TX_QUAD ; ctlr->dev.of_node = np; + ctlr->setup = mchp_coreqspi_setup; + ctlr->set_cs = mchp_coreqspi_set_cs; + ctlr->use_gpio_descriptors = true; + + val =readl_relaxed (qspi->regs +REG_CONTROL ); + val |= (CONTROL_MASTER |CONTROL_ENABLE ); +writel_relaxed (val, qspi->regs +REG_CONTROL ); + +/* +* Put cs into software controlled mode +*/ + val =readl_relaxed (qspi->regs +REG_DIRECT_ACCESS ); + val |=DIRECT_ACCESS_EN_SSEL ; +writel (val, qspi->regs +REG_DIRECT_ACCESS ); ret =spi_register_controller (ctlr);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1049/1887 ALSA: pcm: oss: Fix data race at accessing runtime.oss.trigger
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit 901ac0ff15edf9503162e2cf6579bd11a30f1ed4 ]
Currently the runtime.oss.trigger field may be accessed concurrently without protection, which may lead to the data race. And, in this case, it may lead to more severe problem because it's a bit field; as writing the data, it may overwrite other bit fields as well, which confuses the operation completely, as spotted by fuzzing.
Fix it by covering runtime.oss.trigger bit fled also with the existing params_lock mutex in both snd_pcm_oss_get_trigger() and snd_pcm_oss_poll().
--- sound/core/oss/pcm_oss.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
sound/core/oss/pcm_oss.c +23 -6
@@ -2161,10 +2161,16 @@ static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file) psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK ]; csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE ]; -if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger) - result |=PCM_ENABLE_OUTPUT ; -if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger) - result |=PCM_ENABLE_INPUT ; +if (psubstream && psubstream->runtime) { +guard (mutex)(&psubstream->runtime->oss.params_lock); +if (psubstream->runtime->oss.trigger) + result |=PCM_ENABLE_OUTPUT ; + } +if (csubstream && csubstream->runtime) { +guard (mutex)(&csubstream->runtime->oss.params_lock); +if (csubstream->runtime->oss.trigger) + result |=PCM_ENABLE_INPUT ; + }return result; }
@@ -2839,6 +2845,17 @@ static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) runtime->oss.period_frames; } +static bool need_input_retrigger (struct snd_pcm_runtime *runtime) +{ +bool ret; + +guard (mutex)(&runtime->oss.params_lock); + ret = runtime->oss.trigger; +if (ret) + runtime->oss.trigger =0 ; +return ret; +} +static __poll_t snd_pcm_oss_poll (struct file *file,poll_table * wait) {struct snd_pcm_oss_file *pcm_oss_file;
@@ -2871,11 +2888,11 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) snd_pcm_oss_capture_ready(csubstream)) mask |=EPOLLIN |EPOLLRDNORM ;snd_pcm_stream_unlock_irq (csubstream); -if (ostate !=SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { +if (ostate !=SNDRV_PCM_STATE_RUNNING && +need_input_retrigger (runtime)) {struct snd_pcm_oss_file ofile;memset (&ofile,0 ,sizeof (ofile)); ofile.streams[SNDRV_PCM_STREAM_CAPTURE ] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE ]; - runtime->oss.trigger =0 ;snd_pcm_oss_set_trigger (&ofile,PCM_ENABLE_INPUT ); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1050/1887 RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Gunthorpe <[email protected]>
[ Upstream commit c9341307ea16b9395c2e4c9c94d8499d91fe31d0 ]
Sashiko points out the radix_tree itself is RCU safe, but nothing ever frees the mlx4_srq struct with RCU, and it isn't even accessed within the RCU critical section. It also will crash if an event is delivered before the srq object is finished initializing.
Use the spinlock since it isn't easy to make RCU work, use refcount_inc_not_zero() to protect against partially initialized objects, and order the refcount_set() to be after the srq is fully initialized.
--- drivers/net/ethernet/mellanox/mlx4/srq.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/net/ethernet/mellanox/mlx4/srq.c +8 -6
@@ -44,13 +44,14 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) {struct mlx4_srq_table *srq_table = &mlx4_priv (dev)->srq_table;struct mlx4_srq *srq; +unsigned long flags; -rcu_read_lock (); +spin_lock_irqsave (&srq_table->lock, flags); srq =radix_tree_lookup (&srq_table->tree, srqn & (dev->caps.num_srqs -1 )); -rcu_read_unlock (); -if (srq) -refcount_inc (&srq->refcount); -else { +if (!srq || !refcount_inc_not_zero (&srq->refcount)) + srq =NULL ; +spin_unlock_irqrestore (&srq_table->lock, flags); +if (!srq) {mlx4_warn (dev,"Async event for bogus SRQ %08x\n" , srqn);return ; }
@@ -203,8 +204,9 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,if (err) goto err_radix; -refcount_set (&srq->refcount,1 );init_completion (&srq->free); +smp_wmb (); +refcount_set (&srq->refcount,1 );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1051/1887 spi: mpc52xx: Convert to platform remove callback returning void
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 3fa689a85df4664a62ea931be31e5276cde1e8fe ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 0f997fdae819 ("spi: mpc52xx: fix controller deregistration")
--- drivers/spi/spi-mpc52xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/spi/spi-mpc52xx.c +2 -4
@@ -513,7 +513,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)return rc; } -static int mpc52xx_spi_remove (struct platform_device *op) +static void mpc52xx_spi_remove (struct platform_device *op) {struct spi_master *master =spi_master_get (platform_get_drvdata (op));struct mpc52xx_spi *ms =spi_master_get_devdata (master);
@@ -531,8 +531,6 @@ static int mpc52xx_spi_remove(struct platform_device *op)spi_unregister_master (master);iounmap (ms->regs);spi_master_put (master); - -return 0 ; }static const struct of_device_id mpc52xx_spi_match[] = {
@@ -547,6 +545,6 @@ static struct platform_driver mpc52xx_spi_of_driver = { .of_match_table = mpc52xx_spi_match, }, .probe = mpc52xx_spi_probe, - .remove = mpc52xx_spi_remove, + .remove_new = mpc52xx_spi_remove, };module_platform_driver (mpc52xx_spi_of_driver);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1052/1887 spi: mpc52xx: switch to use modern name
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Yingliang <[email protected]>
[ Upstream commit d6503d1192491bb9d38916b70f87e77ce93c3bb6 ]
Change legacy name master to modern name host or controller.
No functional changed.
Stable-dep-of: 0f997fdae819 ("spi: mpc52xx: fix controller deregistration")
--- drivers/spi/spi-mpc52xx.c | 56 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-)
drivers/spi/spi-mpc52xx.c +28 -28
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");/* Driver internal data */ struct mpc52xx_spi { -struct spi_master *master; +struct spi_controller *host;void __iomem *regs;int irq0;/* MODF irq */ int irq1;/* SPIF irq */
@@ -152,7 +152,7 @@ mpc52xx_spi_fsmstate_idle(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)u8 ctrl1;if (status && irq) -dev_err (&ms->master->dev,"spurious irq, status=0x%.2x\n" , +dev_err (&ms->host->dev,"spurious irq, status=0x%.2x\n" , status);/* Check if there is another transfer waiting. */
@@ -235,7 +235,7 @@ static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,return FSM_CONTINUE ; }else if (status &SPI_STATUS_MODF ) { ms->modf_count++; -dev_err (&ms->master->dev,"mode fault\n" ); +dev_err (&ms->host->dev,"mode fault\n" );mpc52xx_spi_chipsel (ms,0 ); ms->message->status = -EIO ;if (ms->message->complete)
@@ -280,7 +280,7 @@ static int mpc52xx_spi_fsmstate_wait(int irq, struct mpc52xx_spi *ms, u8 status, u8 data) { if (status && irq) - dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n", + dev_err(&ms->host->dev, "spurious irq, status=0x%.2x\n", status);if (((int )mftb ()) - ms->timestamp <0 )
@@ -361,12 +361,12 @@ static void mpc52xx_spi_wq(struct work_struct *work) }/* -* spi_master ops +* spi_controller ops */ static int mpc52xx_spi_transfer (struct spi_device *spi,struct spi_message *m) { -struct mpc52xx_spi *ms =spi_master_get_devdata (spi->master); +struct mpc52xx_spi *ms =spi_controller_get_devdata (spi->controller);unsigned long flags; m->actual_length =0 ;
@@ -385,7 +385,7 @@ static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)*/ static int mpc52xx_spi_probe (struct platform_device *op) { -struct spi_master *master; +struct spi_controller *host;struct mpc52xx_spi *ms;struct gpio_desc *gpio_cs;void __iomem *regs;
@@ -406,7 +406,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)out_8 (regs +SPI_PORTDATA ,0x8 );/* Deassert /SS signal */ /* Clear the status register and re-read it to check for a MODF -* failure. This driver cannot currently handle multiple masters +* failure. This driver cannot currently handle multiple hosts * on the SPI bus. This fault will also occur if the SPI signals * are not connected to any pins (port_config setting) */ in_8 (regs +SPI_STATUS );
@@ -419,22 +419,22 @@ static int mpc52xx_spi_probe(struct platform_device *op) goto err_init; } -dev_dbg (&op->dev,"allocating spi_master struct\n" ); - master =spi_alloc_master (&op->dev,sizeof (*ms)); -if (!master) { +dev_dbg (&op->dev,"allocating spi_controller struct\n" ); + host =spi_alloc_host (&op->dev,sizeof (*ms)); +if (!host) { rc = -ENOMEM ; goto err_alloc; } - master->transfer = mpc52xx_spi_transfer; - master->mode_bits =SPI_CPOL |SPI_CPHA |SPI_LSB_FIRST ; - master->bits_per_word_mask =SPI_BPW_MASK (8 ); - master->dev.of_node = op->dev.of_node; + host->transfer = mpc52xx_spi_transfer; + host->mode_bits =SPI_CPOL |SPI_CPHA |SPI_LSB_FIRST ; + host->bits_per_word_mask =SPI_BPW_MASK (8 ); + host->dev.of_node = op->dev.of_node; -platform_set_drvdata (op, master); +platform_set_drvdata (op, host); - ms =spi_master_get_devdata (master); - ms->master = master; + ms =spi_controller_get_devdata (host); + ms->host = host; ms->regs = regs; ms->irq0 =irq_of_parse_and_map (op->dev.of_node,0 ); ms->irq1 =irq_of_parse_and_map (op->dev.of_node,1 );
@@ -442,7 +442,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) ms->ipb_freq =mpc5xxx_get_bus_frequency (&op->dev); ms->gpio_cs_count =gpiod_count (&op->dev,NULL );if (ms->gpio_cs_count >0 ) { - master->num_chipselect = ms->gpio_cs_count; + host->num_chipselect = ms->gpio_cs_count; ms->gpio_cs =kmalloc_array (ms->gpio_cs_count,sizeof (*ms->gpio_cs),GFP_KERNEL );
@@ -489,24 +489,24 @@ static int mpc52xx_spi_probe(struct platform_device *op)if (!ms->irq0)dev_info (&op->dev,"using polled mode\n" ); -dev_dbg (&op->dev,"registering spi_master struct\n" ); - rc =spi_register_master (master); +dev_dbg (&op->dev,"registering spi_controller struct\n" ); + rc =spi_register_controller (host);if (rc) goto err_register; -dev_info (&ms->master->dev,"registered MPC5200 SPI bus\n" ); +dev_info (&ms->host->dev,"registered MPC5200 SPI bus\n" );return rc; err_register: -dev_err (&ms->master->dev,"initialization failed\n" ); +dev_err (&ms->host->dev,"initialization failed\n" ); err_gpio:while (i-- >0 )gpiod_put (ms->gpio_cs[i]);kfree (ms->gpio_cs); err_alloc_gpio: -spi_master_put (master); +spi_controller_put (host); err_alloc: err_init:iounmap (regs);
@@ -515,8 +515,8 @@ static int mpc52xx_spi_probe(struct platform_device *op)static void mpc52xx_spi_remove (struct platform_device *op) { -struct spi_master *master =spi_master_get (platform_get_drvdata (op)); -struct mpc52xx_spi *ms =spi_master_get_devdata (master); +struct spi_controller *host =spi_controller_get (platform_get_drvdata (op)); +struct mpc52xx_spi *ms =spi_controller_get_devdata (host);int i;free_irq (ms->irq0, ms);
@@ -528,9 +528,9 @@ static void mpc52xx_spi_remove(struct platform_device *op)gpiod_put (ms->gpio_cs[i]);kfree (ms->gpio_cs); -spi_unregister_master (master); +spi_unregister_controller (host);iounmap (ms->regs); -spi_master_put (master); +spi_controller_put (host); }static const struct of_device_id mpc52xx_spi_match[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1053/1887 spi: mpc52xx: fix controller deregistration
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 0f997fdae819a8c2cc83bd4ff7d935ad76c727c9 ]
Make sure to deregister the controller before disabling and releasing underlying resources like interrupts and gpios during driver unbind.
--- drivers/spi/spi-mpc52xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-mpc52xx.c +2 -1
@@ -519,6 +519,8 @@ static void mpc52xx_spi_remove(struct platform_device *op)struct mpc52xx_spi *ms =spi_controller_get_devdata (host);int i; +spi_unregister_controller (host); +free_irq (ms->irq0, ms);free_irq (ms->irq1, ms);
@@ -528,7 +530,6 @@ static void mpc52xx_spi_remove(struct platform_device *op)gpiod_put (ms->gpio_cs[i]);kfree (ms->gpio_cs); -spi_unregister_controller (host);iounmap (ms->regs);spi_controller_put (host); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1054/1887 drm/amdgpu: limit AV1 to the first instance on VCN4 encode
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David (Ming Qiang) Wu <[email protected]>
[ Upstream commit f823323b4abdc171b510190280a01565e21bd392 ]
AV1 is only supported on the first instance.
Added vcn_v4_0_enc_find_ib_param() to help search for an IB param.
Stable-dep-of: 2444eb0ec828 ("drm/amdgpu/vcn4: Prevent OOB reads when parsing IB")
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 62 ++++++++++++++++++++------- 1 file changed, 46 insertions(+), 16 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +46 -16
@@ -1696,7 +1696,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, create = ptr + addr + offset - start; -/* H246, HEVC and VP9 can run on any instance */ +/* H264, HEVC and VP9 can run on any instance */ if (create[0 ] ==0x7 || create[0 ] ==0x10 || create[0 ] ==0x11 )continue ;
@@ -1710,7 +1710,29 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,return r; } -#define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003) +#define RADEON_VCN_ENGINE_TYPE_ENCODE (0x00000002) +#define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003) + +#define RADEON_VCN_ENGINE_INFO (0x30000001) +#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET 16 + +#define RENCODE_ENCODE_STANDARD_AV1 2 +#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 +#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET 64 + +/* return the offset in ib if id is found, -1 otherwise +* to speed up the searching we only search upto max_offset +*/ +static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int max_offset) +{ +int i; + +for (i =0 ; i < ib->length_dw && i < max_offset && ib->ptr[i] >=8 ; i += ib->ptr[i]/4 ) { +if (ib->ptr[i +1 ] == id) +return i; + } +return -1 ; +} static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
@@ -1720,27 +1742,35 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,struct amdgpu_vcn_decode_buffer *decode_buffer;uint64_t addr;uint32_t val; +int idx;/* The first instance can decode anything */ if (!ring->me)return 0 ; -/* unified queue ib header has 8 double words. */ -if (ib->length_dw <8 ) -return 0 ; - - val =amdgpu_ib_get_value (ib,6 );//RADEON_VCN_ENGINE_TYPE -if (val !=RADEON_VCN_ENGINE_TYPE_DECODE ) -return 0 ; - - decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10 ]; - -if (!(decode_buffer->valid_buf_flag &0x1 )) +/* RADEON_VCN_ENGINE_INFO is at the top of ib block */ + idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , +RADEON_VCN_ENGINE_INFO_MAX_OFFSET ); +if (idx <0 )/* engine info is missing */ return 0 ; - addr = ((u64 )decode_buffer->msg_buffer_address_hi) <<32 | - decode_buffer->msg_buffer_address_lo; -return vcn_v4_0_dec_msg (p, job, addr); + val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ +if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) { + decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx +6 ]; + +if (!(decode_buffer->valid_buf_flag &0x1 )) +return 0 ; + + addr = ((u64 )decode_buffer->msg_buffer_address_hi) <<32 | + decode_buffer->msg_buffer_address_lo; +return vcn_v4_0_dec_msg (p, job, addr); + }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { + idx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , +RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET ); +if (idx >=0 && ib->ptr[idx +2 ] ==RENCODE_ENCODE_STANDARD_AV1 ) +return vcn_v4_0_limit_sched (p, job); + } +return 0 ; }static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1055/1887 drm/amdgpu/vcn4: Fix IB parsing with multiple engine info packages
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
[ Upstream commit 2b10cb58d7a3fd621ec9b2ba765a092e562ef998 ]
There can be multiple engine info packages in one IB and the first one may be common engine, not decode/encode.
We need to parse the entire IB instead of stopping after finding first engine info.
Stable-dep-of: 2444eb0ec828 ("drm/amdgpu/vcn4: Prevent OOB reads when parsing IB")
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 52 +++++++++++---------------- 1 file changed, 21 insertions(+), 31 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +21 -31
@@ -1712,22 +1712,16 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,#define RADEON_VCN_ENGINE_TYPE_ENCODE (0x00000002)#define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003) -#define RADEON_VCN_ENGINE_INFO (0x30000001) -#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET 16 -#define RENCODE_ENCODE_STANDARD_AV1 2#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 -#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET 64 -/* return the offset in ib if id is found, -1 otherwise -* to speed up the searching we only search upto max_offset -*/ -static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int max_offset) +/* return the offset in ib if id is found, -1 otherwise */ +static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start) {int i; -for (i =0 ; i < ib->length_dw && i < max_offset && ib->ptr[i] >=8 ; i += ib->ptr[i]/4 ) { +for (i = start; i < ib->length_dw && ib->ptr[i] >=8 ; i += ib->ptr[i] /4 ) {if (ib->ptr[i +1 ] == id)return i; }
@@ -1742,33 +1736,29 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,struct amdgpu_vcn_decode_buffer *decode_buffer;uint64_t addr;uint32_t val; -int idx; +int idx =0 , sidx;/* The first instance can decode anything */ if (!ring->me)return 0 ; -/* RADEON_VCN_ENGINE_INFO is at the top of ib block */ - idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , -RADEON_VCN_ENGINE_INFO_MAX_OFFSET ); -if (idx <0 )/* engine info is missing */ -return 0 ; - - val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ -if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) { - decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx +6 ]; - -if (!(decode_buffer->valid_buf_flag &0x1 )) -return 0 ; - - addr = ((u64 )decode_buffer->msg_buffer_address_hi) <<32 | - decode_buffer->msg_buffer_address_lo; -return vcn_v4_0_dec_msg (p, job, addr); - }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { - idx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , -RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET ); -if (idx >=0 && ib->ptr[idx +2 ] ==RENCODE_ENCODE_STANDARD_AV1 ) -return vcn_v4_0_limit_sched (p, job); +while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx)) >=0 ) { + val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ +if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) { + decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx +6 ]; + +if (!(decode_buffer->valid_buf_flag &0x1 )) +return 0 ; + + addr = ((u64 )decode_buffer->msg_buffer_address_hi) <<32 | + decode_buffer->msg_buffer_address_lo; +return vcn_v4_0_dec_msg (p, job, addr); + }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { + sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx); +if (sidx >=0 && ib->ptr[sidx +2 ] ==RENCODE_ENCODE_STANDARD_AV1 ) +return vcn_v4_0_limit_sched (p, job); + } + idx += ib->ptr[idx] /4 ; }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1056/1887 drm/amdgpu/vcn4: Prevent OOB reads when parsing IB
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Cheng <[email protected]>
[ Upstream commit 2444eb0ec8283f4a3845eb7febad378476e1ba3c ]
Rewrite the IB parsing to use amdgpu_ib_get_value() which handles the bounds checks.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +12 -11
@@ -1720,9 +1720,10 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start) {int i; +uint32_t len; -for (i = start; i < ib->length_dw && ib->ptr[i] >=8 ; i += ib->ptr[i] /4 ) { -if (ib->ptr[i +1 ] == id) +for (i = start; (len =amdgpu_ib_get_value (ib, i)) >=8 ; i += len /4 ) { +if (amdgpu_ib_get_value (ib, i +1 ) == id)return i; }return -1 ;
@@ -1733,8 +1734,6 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib) {struct amdgpu_ring *ring =amdgpu_job_ring (job); -struct amdgpu_vcn_decode_buffer *decode_buffer; -uint64_t addr;uint32_t val;int idx =0 , sidx;
@@ -1745,20 +1744,22 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx)) >=0 ) { val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) { - decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx +6 ]; +uint32_t valid_buf_flag =amdgpu_ib_get_value (ib, idx +6 ); +uint64_t msg_buffer_addr; -if (!(decode_buffer->valid_buf_flag &0x1 )) +if (!(valid_buf_flag &0x1 ))return 0 ; - addr = ((u64 )decode_buffer->msg_buffer_address_hi) <<32 | - decode_buffer->msg_buffer_address_lo; -return vcn_v4_0_dec_msg (p, job, addr); + msg_buffer_addr = ((u64 )amdgpu_ib_get_value (ib, idx +7 )) <<32 | +amdgpu_ib_get_value (ib, idx +8 ); +return vcn_v4_0_dec_msg (p, job, msg_buffer_addr); }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx); -if (sidx >=0 && ib->ptr[sidx +2 ] ==RENCODE_ENCODE_STANDARD_AV1 ) +if (sidx >=0 && +amdgpu_ib_get_value (ib, sidx +2 ) ==RENCODE_ENCODE_STANDARD_AV1 )return vcn_v4_0_limit_sched (p, job); } - idx += ib->ptr[idx] /4 ; + idx +=amdgpu_ib_get_value (ib, idx) /4 ; }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1057/1887 spi: rspi: Convert to platform remove callback returning void
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 72ec0e8f89a1536e4594606d60a946636ee7d94b ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 9944fa6726af ("spi: rspi: fix controller deregistration")
--- drivers/spi/spi-rspi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/spi/spi-rspi.c +2 -4
@@ -1172,14 +1172,12 @@ static void rspi_release_dma(struct spi_controller *ctlr)dma_release_channel (ctlr->dma_rx); } -static int rspi_remove (struct platform_device *pdev) +static void rspi_remove (struct platform_device *pdev) {struct rspi_data *rspi =platform_get_drvdata (pdev);rspi_release_dma (rspi->ctlr);pm_runtime_disable (&pdev->dev); - -return 0 ; }static const struct spi_ops rspi_ops = {
@@ -1440,7 +1438,7 @@ static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);static struct platform_driver rspi_driver = { .probe = rspi_probe, - .remove = rspi_remove, + .remove_new = rspi_remove, .id_table = spi_driver_ids, .driver = { .name ="renesas_spi" ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1058/1887 spi: rspi: fix controller deregistration
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 9944fa6726afb1e6eb7e2212764e7da0c97f2dcc ]
Make sure to deregister the controller before releasing underlying resources like DMA during driver unbind.
--- drivers/spi/spi-rspi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/spi/spi-rspi.c +8 -2
@@ -1176,8 +1176,14 @@ static void rspi_remove(struct platform_device *pdev) {struct rspi_data *rspi =platform_get_drvdata (pdev); +spi_controller_get (rspi->ctlr); + +spi_unregister_controller (rspi->ctlr); +rspi_release_dma (rspi->ctlr);pm_runtime_disable (&pdev->dev); + +spi_controller_put (rspi->ctlr); }static const struct spi_ops rspi_ops = {
@@ -1388,9 +1394,9 @@ static int rspi_probe(struct platform_device *pdev)if (ret <0 )dev_warn (&pdev->dev,"DMA not available, using PIO\n" ); - ret =devm_spi_register_controller (&pdev->dev, ctlr); + ret =spi_register_controller (ctlr);if (ret <0 ) { -dev_err (&pdev->dev,"devm_spi_register_controller error.\n" ); +dev_err (&pdev->dev,"failed to register controller\n" ); goto error3; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1059/1887 spi: fsl-spi: Convert to platform remove callback returning void
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 fc4935a0f7ab1521a5f0500a9894d97558067985 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 9b7abfed4c37 ("spi: fsl: fix controller deregistration")
--- drivers/spi/spi-fsl-spi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/spi/spi-fsl-spi.c +4 -7
@@ -717,13 +717,12 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)return ret; } -static int of_fsl_spi_remove (struct platform_device *ofdev) +static void of_fsl_spi_remove (struct platform_device *ofdev) {struct spi_master *master =platform_get_drvdata (ofdev);struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (master);fsl_spi_cpm_free (mpc8xxx_spi); -return 0 ; }static struct platform_driver of_fsl_spi_driver = {
@@ -732,7 +731,7 @@ static struct platform_driver of_fsl_spi_driver = { .of_match_table = of_fsl_spi_match, }, .probe = of_fsl_spi_probe, - .remove = of_fsl_spi_remove, + .remove_new = of_fsl_spi_remove, };#ifdef CONFIG_MPC832x_RDB
@@ -764,20 +763,18 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)return PTR_ERR_OR_ZERO (master); } -static int plat_mpc8xxx_spi_remove (struct platform_device *pdev) +static void plat_mpc8xxx_spi_remove (struct platform_device *pdev) {struct spi_master *master =platform_get_drvdata (pdev);struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (master);fsl_spi_cpm_free (mpc8xxx_spi); - -return 0 ; }MODULE_ALIAS ("platform:mpc8xxx_spi" );static struct platform_driver mpc8xxx_spi_driver = { .probe = plat_mpc8xxx_spi_probe, - .remove = plat_mpc8xxx_spi_remove, + .remove_new = plat_mpc8xxx_spi_remove, .driver = { .name ="mpc8xxx_spi" , },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1060/1887 spi: fsl-spi: switch to use modern name
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Yingliang <[email protected]>
[ Upstream commit d32382ca5614614df0cbb91a1b7fab9c47bfef9b ]
Change legacy name master to modern name host or controller.
No functional changed.
Stable-dep-of: 9b7abfed4c37 ("spi: fsl: fix controller deregistration")
--- drivers/spi/spi-fsl-spi.c | 76 +++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-)
drivers/spi/spi-fsl-spi.c +38 -38
@@ -88,7 +88,7 @@ static int fsl_spi_get_type(struct device *dev)static void fsl_spi_change_mode (struct spi_device *spi) { -struct mpc8xxx_spi *mspi =spi_master_get_devdata (spi->master); +struct mpc8xxx_spi *mspi =spi_controller_get_devdata (spi->controller);struct spi_mpc8xxx_cs *cs = spi->controller_state;struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;__be32 __iomem *mode = ®_base->mode;
@@ -186,7 +186,7 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,u32 hz =0 ;struct spi_mpc8xxx_cs *cs = spi->controller_state; - mpc8xxx_spi =spi_master_get_devdata (spi->master); + mpc8xxx_spi =spi_controller_get_devdata (spi->controller);if (t) { bits_per_word = t->bits_per_word;
@@ -260,7 +260,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,static int fsl_spi_bufs (struct spi_device *spi,struct spi_transfer *t,bool is_dma_mapped) { -struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (spi->master); +struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (spi->controller);struct fsl_spi_reg __iomem *reg_base;unsigned int len = t->len;u8 bits_per_word;
@@ -401,7 +401,7 @@ static int fsl_spi_setup(struct spi_device *spi)spi_set_ctldata (spi, cs); initial_setup = true; } - mpc8xxx_spi =spi_master_get_devdata (spi->master); + mpc8xxx_spi =spi_controller_get_devdata (spi->controller); reg_base = mpc8xxx_spi->reg_base;
@@ -495,7 +495,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)static void fsl_spi_grlib_cs_control (struct spi_device *spi,bool on) { -struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (spi->master); +struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (spi->controller);struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;u32 slvsel;u16 cs = spi->chip_select;
@@ -509,8 +509,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)static void fsl_spi_grlib_probe (struct device *dev) { -struct spi_master *master =dev_get_drvdata (dev); -struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (master); +struct spi_controller *host =dev_get_drvdata (dev); +struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (host);struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;int mbits;u32 capabilities;
@@ -527,8 +527,8 @@ static void fsl_spi_grlib_probe(struct device *dev) mpc8xxx_spi->native_chipselects =SPCAP_SSSZ (capabilities);mpc8xxx_spi_write_reg (®_base->slvsel,0xffffffff ); } - master->num_chipselect = mpc8xxx_spi->native_chipselects; - master->set_cs = fsl_spi_grlib_cs_control; + host->num_chipselect = mpc8xxx_spi->native_chipselects; + host->set_cs = fsl_spi_grlib_cs_control; }static void fsl_spi_cs_control (struct spi_device *spi,bool on)
@@ -542,35 +542,35 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on)iowrite32be (on ?0 :SPI_BOOT_SEL_BIT , pinfo->immr_spi_cs); } -static struct spi_master *fsl_spi_probe (struct device *dev, +static struct spi_controller *fsl_spi_probe (struct device *dev,struct resource *mem,unsigned int irq) {struct fsl_spi_platform_data *pdata =dev_get_platdata (dev); -struct spi_master *master; +struct spi_controller *host;struct mpc8xxx_spi *mpc8xxx_spi;struct fsl_spi_reg __iomem *reg_base;u32 regval;int ret =0 ; - master =spi_alloc_master (dev,sizeof (struct mpc8xxx_spi )); -if (master ==NULL ) { + host =spi_alloc_host (dev,sizeof (struct mpc8xxx_spi )); +if (host ==NULL ) { ret = -ENOMEM ; goto err; } -dev_set_drvdata (dev, master); +dev_set_drvdata (dev, host);mpc8xxx_spi_probe (dev, mem, irq); - master->setup = fsl_spi_setup; - master->cleanup = fsl_spi_cleanup; - master->prepare_message = fsl_spi_prepare_message; - master->transfer_one = fsl_spi_transfer_one; - master->unprepare_message = fsl_spi_unprepare_message; - master->use_gpio_descriptors = true; - master->set_cs = fsl_spi_cs_control; + host->setup = fsl_spi_setup; + host->cleanup = fsl_spi_cleanup; + host->prepare_message = fsl_spi_prepare_message; + host->transfer_one = fsl_spi_transfer_one; + host->unprepare_message = fsl_spi_unprepare_message; + host->use_gpio_descriptors = true; + host->set_cs = fsl_spi_cs_control; - mpc8xxx_spi =spi_master_get_devdata (master); + mpc8xxx_spi =spi_controller_get_devdata (host); mpc8xxx_spi->max_bits_per_word =32 ; mpc8xxx_spi->type =fsl_spi_get_type (dev);
@@ -588,13 +588,13 @@ static struct spi_master *fsl_spi_probe(struct device *dev,fsl_spi_grlib_probe (dev);if (mpc8xxx_spi->flags &SPI_CPM_MODE ) - master->bits_per_word_mask = + host->bits_per_word_mask = (SPI_BPW_RANGE_MASK (4 ,8 ) |SPI_BPW_MASK (16 ) |SPI_BPW_MASK (32 ));else - master->bits_per_word_mask = + host->bits_per_word_mask = (SPI_BPW_RANGE_MASK (4 ,16 ) |SPI_BPW_MASK (32 )); - master->bits_per_word_mask &= + host->bits_per_word_mask &=SPI_BPW_RANGE_MASK (1 , mpc8xxx_spi->max_bits_per_word);if (mpc8xxx_spi->flags &SPI_QE_CPU_MODE )
@@ -631,19 +631,19 @@ static struct spi_master *fsl_spi_probe(struct device *dev,mpc8xxx_spi_write_reg (®_base->mode, regval); - ret =devm_spi_register_master (dev, master); + ret =devm_spi_register_controller (dev, host);if (ret <0 ) goto err_probe;dev_info (dev,"at 0x%p (irq = %d), %s mode\n" , reg_base, mpc8xxx_spi->irq,mpc8xxx_spi_strmode (mpc8xxx_spi->flags)); -return master; +return host; err_probe:fsl_spi_cpm_free (mpc8xxx_spi); err_cpm_init: -spi_master_put (master); +spi_controller_put (host); err:return ERR_PTR (ret); }
@@ -652,7 +652,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) {struct device *dev = &ofdev->dev;struct device_node *np = ofdev->dev.of_node; -struct spi_master *master; +struct spi_controller *host;struct resource mem;int irq, type;int ret;
@@ -705,9 +705,9 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) goto unmap_out; } - master =fsl_spi_probe (dev, &mem, irq); + host =fsl_spi_probe (dev, &mem, irq); -return PTR_ERR_OR_ZERO (master); +return PTR_ERR_OR_ZERO (host); unmap_out: #if IS_ENABLED(CONFIG_FSL_SOC)
@@ -719,8 +719,8 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)static void of_fsl_spi_remove (struct platform_device *ofdev) { -struct spi_master *master =platform_get_drvdata (ofdev); -struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (master); +struct spi_controller *host =platform_get_drvdata (ofdev); +struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (host);fsl_spi_cpm_free (mpc8xxx_spi); }
@@ -746,7 +746,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) {struct resource *mem;int irq; -struct spi_master *master; +struct spi_controller *host;if (!dev_get_platdata (&pdev->dev))return -EINVAL ;
@@ -759,14 +759,14 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)if (irq <=0 )return -EINVAL ; - master =fsl_spi_probe (&pdev->dev, mem, irq); -return PTR_ERR_OR_ZERO (master); + host =fsl_spi_probe (&pdev->dev, mem, irq); +return PTR_ERR_OR_ZERO (host); }static void plat_mpc8xxx_spi_remove (struct platform_device *pdev) { -struct spi_master *master =platform_get_drvdata (pdev); -struct mpc8xxx_spi *mpc8xxx_spi =spi_master_get_devdata (master); +struct spi_controller *host =platform_get_drvdata (pdev); +struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (host);fsl_spi_cpm_free (mpc8xxx_spi); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1061/1887 spi: fsl: fix controller deregistration
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 9b7abfed4c3754062d1f3ffd452e65a38667f586 ]
Make sure to deregister the controller before releasing underlying resources like DMA during driver unbind.
--- drivers/spi/spi-fsl-spi.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/spi/spi-fsl-spi.c +13 -1
@@ -631,7 +631,7 @@ static struct spi_controller *fsl_spi_probe(struct device *dev,mpc8xxx_spi_write_reg (®_base->mode, regval); - ret =devm_spi_register_controller (dev, host); + ret =spi_register_controller (host);if (ret <0 ) goto err_probe;
@@ -722,7 +722,13 @@ static void of_fsl_spi_remove(struct platform_device *ofdev)struct spi_controller *host =platform_get_drvdata (ofdev);struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (host); +spi_controller_get (host); + +spi_unregister_controller (host); +fsl_spi_cpm_free (mpc8xxx_spi); + +spi_controller_put (host); }static struct platform_driver of_fsl_spi_driver = {
@@ -768,7 +774,13 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)struct spi_controller *host =platform_get_drvdata (pdev);struct mpc8xxx_spi *mpc8xxx_spi =spi_controller_get_devdata (host); +spi_controller_get (host); + +spi_unregister_controller (host); +fsl_spi_cpm_free (mpc8xxx_spi); + +spi_controller_put (host); }MODULE_ALIAS ("platform:mpc8xxx_spi" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1062/1887 drm/amdkfd: Clear VRAM on allocation to prevent stale data exposure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Shetaia <[email protected]>
[ Upstream commit ad52d61d82181dbdb7f05826de38352d5e550cc2 ]
KFD VRAM allocations set AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE but not AMDGPU_GEM_CREATE_VRAM_CLEARED, leaving freshly allocated VRAM with stale data from prior use observable by compute kernels.
The GEM ioctl path already sets VRAM_CLEARED for all userspace allocations via amdgpu_gem_create_ioctl() and amdgpu_mode_dumb_create(). The KFD path was missing this flag, allowing stale page table remnants to leak into user buffers.
This causes crashes in RCCL P2P transport where non-zero data in ptrExchange/head/tail fields corrupts the protocol handshake.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +2 -1
@@ -1665,7 +1665,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(*/ if (flags &KFD_IOC_ALLOC_MEM_FLAGS_VRAM ) { domain = alloc_domain =AMDGPU_GEM_DOMAIN_VRAM ; - alloc_flags =AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE ; + alloc_flags =AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE | +AMDGPU_GEM_CREATE_VRAM_CLEARED ; alloc_flags |= (flags &KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC ) ?AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED :0 ; }else if (flags &KFD_IOC_ALLOC_MEM_FLAGS_GTT ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1063/1887 spi: mpc52xx: fix use-after-free on registration failure
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 f62c060272b9d7423b1650b844e8e4e7b8f9f925 ]
Make sure to disable and free the interrupts in case controller registration fails to avoid a potential use-after-free and resource leak.
This issue was flagged by Sashiko when reviewing a controller deregistration fix.
--- drivers/spi/spi-mpc52xx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/spi/spi-mpc52xx.c +3 -0
@@ -500,6 +500,9 @@ static int mpc52xx_spi_probe(struct platform_device *op) err_register:dev_err (&ms->host->dev,"initialization failed\n" ); +free_irq (ms->irq0, ms); +free_irq (ms->irq1, ms); +cancel_work_sync (&ms->work); err_gpio:while (i-- >0 )gpiod_put (ms->gpio_cs[i]);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1064/1887 AppArmor: Allow apparmor to handle unaligned dfa tables
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
[ Upstream commit 64802f731214a51dfe3c6c27636b3ddafd003eb0 ]
The dfa tables can originate from kernel or userspace and 8-byte alignment isn't always guaranteed and as such may trigger unaligned memory accesses on various architectures. Resulting in the following
[ 73.901376] WARNING: CPU: 0 PID: 341 at security/apparmor/match.c:316 aa_dfa_unpack+0x6cc/0x720
[ 74.015867] Modules linked in: binfmt_misc evdev flash sg drm drm_panel_orientation_quirks backlight i2c_core configfs nfnetlink autofs4 ext4 crc16 mbcache jbd2 hid_generic usbhid sr_mod hid cdrom sd_mod ata_generic ohci_pci ehci_pci ehci_hcd ohci_hcd pata_ali libata sym53c8xx scsi_transport_spi tg3 scsi_mod usbcore libphy scsi_common mdio_bus usb_common
[ 74.428977] CPU: 0 UID: 0 PID: 341 Comm: apparmor_parser Not tainted 6.18.0-rc6+ #9 NONE
[ 74.536543] Call Trace:
[ 74.568561] [<0000000000434c24>] dump_stack+0x8/0x18
[ 74.633757] [<0000000000476438>] __warn+0xd8/0x100
[ 74.696664] [<00000000004296d4>] warn_slowpath_fmt+0x34/0x74
[ 74.771006] [<00000000008db28c>] aa_dfa_unpack+0x6cc/0x720
[ 74.843062] [<00000000008e643c>] unpack_pdb+0xbc/0x7e0
[ 74.910545] [<00000000008e7740>] unpack_profile+0xbe0/0x1300
[ 74.984888] [<00000000008e82e0>] aa_unpack+0xe0/0x6a0
[ 75.051226] [<00000000008e3ec4>] aa_replace_profiles+0x64/0x1160
[ 75.130144] [<00000000008d4d90>] policy_update+0xf0/0x280
[ 75.201057] [<00000000008d4fc8>] profile_replace+0xa8/0x100
[ 75.274258] [<0000000000766bd0>] vfs_write+0x90/0x420
[ 75.340594] [<00000000007670cc>] ksys_write+0x4c/0xe0
[ 75.406932] [<0000000000767174>] sys_write+0x14/0x40
[ 75.472126] [<0000000000406174>] linux_sparc_syscall+0x34/0x44
[ 75.548802] ---[ end trace 0000000000000000 ]---
[ 75.609503] dfa blob stream 0xfff0000008926b96 not aligned.
[ 75.682695] Kernel unaligned access at TPC[8db2a8] aa_dfa_unpack+0x6e8/0x720
Work around it by using the get_unaligned_xx() helpers.
--- security/apparmor/match.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
security/apparmor/match.c +7 -7
@@ -87,11 +87,11 @@ static struct table_header *unpack_table(char *blob, size_t bsize)/* loaded td_id's start at 1, subtract 1 now to avoid doing * it every time we use td_id as an index */ - th.td_id =be16_to_cpu (*(__be16 *) (blob)) -1 ; + th.td_id =get_unaligned_be16 (blob) -1 ;if (th.td_id >YYTD_ID_MAX ) goto out; - th.td_flags =be16_to_cpu (*(__be16 *) (blob +2 )); - th.td_lolen =be32_to_cpu (*(__be32 *) (blob +8 )); + th.td_flags =get_unaligned_be16 (blob +2 ); + th.td_lolen =get_unaligned_be32 (blob +8 ); blob +=sizeof (struct table_header ); if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
@@ -337,14 +337,14 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)if (size <sizeof (struct table_set_header )) goto fail; -if (ntohl (*(__be32 *) data) !=YYTH_MAGIC ) +if (get_unaligned_be32 (data) !=YYTH_MAGIC ) goto fail; - hsize =ntohl (*(__be32 *) (data +4 )); + hsize =get_unaligned_be32 (data +4 );if (size < hsize) goto fail; - dfa->flags =ntohs (*(__be16 *) (data +12 )); + dfa->flags =get_unaligned_be16 (data +12 );if (dfa->flags & ~(YYTH_FLAGS )) goto fail;
@@ -353,7 +353,7 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)* if (dfa->flags & YYTH_FLAGS_OOB_TRANS) { * if (hsize < 16 + 4) * goto fail; -* dfa->max_oob = ntol(*(__be32 *) (data + 16)); +* dfa->max_oob = get_unaligned_be32(data + 16); * if (dfa->max <= MAX_OOB_SUPPORTED) { * pr_err("AppArmor DFA OOB greater than supported\n"); * goto fail;
Signature · 1 line
2.53.0