6.18.49-rc1 review
Greg Kroah-Hartman
maintainercover 6.18.49-rc1 review
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.49-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.18.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 6.18.49-rc1
Miguel Peñaranda <[email protected]>
usb: usbfs: fix use-after-free of usb_device in usbdev_release()
Devin Wittmayer <[email protected]>
wifi: mt76: mt7925: ensure tx headroom in usb_sdio_tx_prepare_skb
Shuangpeng Bai <[email protected]>
USB: c67x00: fix use-after-free in c67x00_add_iso_urb()
Johan Hovold <[email protected]>
USB: serial: spcp8x5: drop broken carrier detect support
Jiale Yao <[email protected]>
USB: serial: option: fix slab OOB read in interrupt URB callback
Will Porter <[email protected]>
ALSA: usb-audio: Complete cleanup after system-resume errors
Marouane El Moufid <[email protected]>
ALSA: usb-audio: fix OOB write in snd_usbmidi_novation_output()
Griffin Kroah-Hartman <[email protected]>
usb: core: Strengthen error handling in hub_hub_status()
Griffin Kroah-Hartman <[email protected]>
usb: core: Add lock to usb_wakeup_notification()
Christian Borntraeger <[email protected]>
KVM: s390: vsie: zero stale crypto bits
Bartosz Golaszewski <[email protected]>
crypto: qce - Remove unsafe/deprecated algorithms
Thorsten Blum <[email protected]>
crypto: mxs-dcp - fix source scatterlist length access
Md Sadre Alam <[email protected]>
crypto: qce - fix CCM AAD buffer underallocation
Jan Sebastian Götte <[email protected]>
crypto: krb5 - use kfree_sensitive() for derived key buffers
Thorsten Blum <[email protected]>
crypto: atmel-tdes - use scatterlist length before DMA mapping
Eric Biggers <[email protected]>
crypto: qcom-rng - Allow zero as a random number
Eric Biggers <[email protected]>
crypto: qcom-rng - Remove crypto_rng interface
Eric Biggers <[email protected]>
crypto: qcom-rng - Enable clock in hwrng case
Bryam Vargas <[email protected]>
crypto: virtio - bound the akcipher result length
Eric Biggers <[email protected]>
kunit: irq: Continue increasing hrtimer interval for longer
Eric Biggers <[email protected]>
mm/swap: reject swapon() on filesystem-level encrypted files
Fourie Zhang <[email protected]>
netfilter: nf_tables: don't queue packet path object notifications
Eric Biggers <[email protected]>
netfilter: nft_set_pipapo_avx2: add missing vzeroupper
Kyle Zeng <[email protected]>
vxlan: keep the last remote linked during FDB flush
Kyle Zeng <[email protected]>
batman-adv: reject unrepresentable multicast TVLV offsets
Kyle Zeng <[email protected]>
ipv6: seg6: clear IPv4 control block on IPIP decapsulation
Norbert Szetei <[email protected]>
net: bridge: mcast: fix use-after-free of a master VLAN's multicast context
Zihan Xi <[email protected]>
xfrm: bound nat keepalive state collection
Zihan Xi <[email protected]>
xfrm: fix xfrm_state_construct() auth-trunc leak
Asim Viladi Oglu Manizada <[email protected]>
xfrm: ah6: validate routing header segments_left
Zihan Xi <[email protected]>
xfrm: avoid lock inversion in nat keepalive work
Zhiling Zou <[email protected]>
xfrm: drop ESP-in-TCP packets with no ingress device
Sabrina Dubroca <[email protected]>
xfrm: espintcp: fix UAF during close
Hyunwoo Kim <[email protected]>
net/tcp-ao: fix use-after-free of current_key on reconnect to another peer
Qing Ming <[email protected]>
tcp: fix AO info use-after-free in tcp_ao_connect_init()
Rastislav Szabo <[email protected]>
net/tcp: fix TCP-AO key deletion in VRFs
Pratik Vishwakarma <[email protected]>
x86/CPU/AMD: Carve out a Zen5 models range
Qing Ming <[email protected]>
gtp: serialize PDP context updates
Jiayuan Chen <[email protected]>
tls: device: fix out-of-bounds write in tls_append_frag()
Sean Christopherson <[email protected]>
KVM: SEV: Wire up kvm_x86_ops.gmem_xxx() if and only if CONFIG_KVM_AMD_SEV=y
Sean Christopherson <[email protected]>
KVM: SEV: Mark vCPU RUNNABLE after AP_CREATE, even if VMSA is unusable
Sean Christopherson <[email protected]>
KVM: SEV: Extract loading of guest-provided VMSA to a separate helper
Sean Christopherson <[email protected]>
KVM: SEV: Track the GPA of the guest-controlled VMSA used for SNP guests
Pankaj Gupta <[email protected]>
KVM: SEV: Drop FOLL_WRITE for encrypted region registration
Shuangpeng Bai <[email protected]>
usb: gadget: f_tcm: keep port count until LUN teardown completes
Aleksandr Nogikh <[email protected]>
usb: usbtest: disable dynamic ID support
Baokun Li <[email protected]>
fuse: fix invalidate lock leak on open O_TRUNC DAX failure
Baokun Li <[email protected]>
fuse: fix invalidate lock leak on setattr writeback failure
Lucas De Marchi <[email protected]>
xhci: dbgtty: Fix unregister on tty_alloc_driver() failure
Lucas De Marchi <[email protected]>
xhci: dbgtty: Fix unregister on tty_register_driver() failure
Semih Baskan <[email protected]>
usb: xhci: Handle USB3 port events when there is one roothub
Michal Pecio <[email protected]>
usb: xhci: Handle bogus TRB pointers in Missed Service Error events
Haoxiang Li <[email protected]>
accessibility: speakup: unregister tty ldisc on later init failures
Griffin Kroah-Hartman <[email protected]>
fpga: dfl: fme: add error handling
DaeMyung Kang <[email protected]>
ksmbd: harden file lifetime during session teardown
Raman Varabets <[email protected]>
HID: ft260: fix stack-use-after-return write in I2C read race
Michael Zaidman <[email protected]>
HID: ft260: validate i2c input report length
Jann Horn <[email protected]>
HID: asus: fix missing hid_is_usb() check
Antheas Kapenekakis <[email protected]>
HID: asus: simplify RGB init sequence
Jose Villaseñor Montfort <[email protected]>
HID: magicmouse: prevent unbounded recursion in magicmouse_raw_event()
Jens Axboe <[email protected]>
io_uring: defer eventfd signaling when queued from a wakeup handler
Pavel Begunkov <[email protected]>
io_uring/rsrc: improve regbuf iov validation
Caleb Sander Mateos <[email protected]>
io_uring: simplify IORING_SETUP_DEFER_TASKRUN && !SQPOLL check
Jens Axboe <[email protected]>
io_uring/futex: only mark private futex waits as inflight
Aboorva Devarajan <[email protected]>
powerpc/hv-gpci: fix preempt count leak in sysfs show paths
Jesper Dangaard Brouer <[email protected]>
veth: fix OOB txq access in veth_poll() with asymmetric queue counts
Stephen Smalley <[email protected]>
selinux: switch two allocations to use kzalloc_objs()
Cristian Ciocaltea <[email protected]>
ASoC: nau8821: Cancel pending work before suspend
Michael Neuling <[email protected]>
riscv: Fix register corruption from uninitialized cregs on error
Jiayuan Chen <[email protected]>
bpf: Fix use-after-free in offloaded map/prog info fill
Cristian Ciocaltea <[email protected]>
ASoC: nau8821: Cancel delayed work on component remove
Bryam Vargas <[email protected]>
selinux: require a class's permission values to cover its permission count
Bryam Vargas <[email protected]>
selinux: reject a permission value exceeding the class permission count
Christian Göttsche <[email protected]>
selinux: more strict policy parsing
Christian Göttsche <[email protected]>
selinux: use u16 for security classes
Wentao Guan <[email protected]>
Revert "selinux: reject a permission value exceeding the class permission count"
Dmitry Bogdanov <[email protected]>
nvme-tcp: fix usage of page_frag_cache
Jinu Kim <[email protected]>
KVM: x86/mmu: Check write tracking in all address spaces
Jia Yao <[email protected]>
drm/xe/guc_ads: use uncached mapping for UM queue BO
Jia Yao <[email protected]>
drm/xe/guc_ads: allocate UM queues in VRAM on dGFX
Jia Yao <[email protected]>
drm/xe/guc_ads: allocate UM queues in a separate BO
Peiyang He <[email protected]>
RDMA/rxe: Fix OOB in free_rd_atomic_resources()
Ibrahim Hashimov <[email protected]>
RDMA/rxe: Fix responder UAF on IB_QP_MAX_DEST_RD_ATOMIC modify_qp
-------------
Diffstat:
Documentation/filesystems/fscrypt.rst | 4 + Makefile | 4 +- arch/powerpc/perf/hv-gpci.c | 24 +- arch/riscv/kernel/compat_signal.c | 2 + arch/riscv/kernel/ptrace.c | 4 +- arch/s390/kvm/vsie.c | 1 + arch/x86/kernel/cpu/amd.c | 1 + arch/x86/kvm/mmu/page_track.c | 32 ++- arch/x86/kvm/svm/sev.c | 76 +++--- arch/x86/kvm/svm/svm.c | 8 +- arch/x86/kvm/svm/svm.h | 13 +- crypto/krb5/krb5_api.c | 8 +- drivers/accessibility/speakup/main.c | 1 + drivers/crypto/Kconfig | 1 - drivers/crypto/atmel-tdes.c | 5 +- drivers/crypto/mxs-dcp.c | 2 +- drivers/crypto/qce/aead.c | 58 +---- drivers/crypto/qce/common.c | 55 +---- drivers/crypto/qce/common.h | 16 +- drivers/crypto/qce/regs-v5.h | 4 - drivers/crypto/qce/sha.c | 30 +-- drivers/crypto/qce/sha.h | 1 - drivers/crypto/qce/skcipher.c | 97 +------- drivers/crypto/qcom-rng.c | 156 ++----------- .../crypto/virtio/virtio_crypto_akcipher_algs.c | 3 +- drivers/fpga/dfl-fme-perf.c | 2 + drivers/gpu/drm/xe/xe_bo.h | 14 ++ drivers/gpu/drm/xe/xe_guc_ads.c | 92 +++++--- drivers/gpu/drm/xe/xe_guc_ads_types.h | 5 + drivers/hid/hid-asus.c | 52 ++--- drivers/hid/hid-ft260.c | 41 +++- drivers/hid/hid-magicmouse.c | 25 +- drivers/infiniband/sw/rxe/rxe_qp.c | 18 +- drivers/net/gtp.c | 21 +- drivers/net/veth.c | 3 +- drivers/net/vxlan/vxlan_core.c | 11 +- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 4 + drivers/nvme/host/tcp.c | 8 + drivers/target/target_core_fabric_configfs.c | 8 + drivers/usb/c67x00/c67x00-sched.c | 4 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/hub.c | 7 +- drivers/usb/gadget/function/f_tcm.c | 2 +- drivers/usb/host/xhci-dbgtty.c | 15 +- drivers/usb/host/xhci-ring.c | 20 +- drivers/usb/misc/usbtest.c | 1 + drivers/usb/serial/option.c | 20 +- drivers/usb/serial/spcp8x5.c | 13 -- fs/fuse/dir.c | 9 +- fs/fuse/file.c | 4 +- fs/smb/server/smb2pdu.c | 6 +- fs/smb/server/vfs_cache.c | 179 +++++++++++++-- fs/smb/server/vfs_cache.h | 4 +- include/kunit/run-in-irq-context.h | 10 +- include/linux/io_uring_types.h | 8 + include/linux/skbuff.h | 24 ++ include/target/target_core_fabric.h | 2 + io_uring/eventfd.c | 8 +- io_uring/eventfd.h | 2 +- io_uring/futex.c | 21 +- io_uring/io_uring.c | 7 +- io_uring/poll.c | 23 +- io_uring/rsrc.c | 31 +-- io_uring/waitid.c | 2 +- kernel/bpf/offload.c | 10 +- mm/swapfile.c | 7 + net/batman-adv/tvlv.c | 5 +- net/bridge/br_multicast.c | 4 +- net/ipv4/tcp_ao.c | 19 +- net/ipv6/ah6.c | 29 ++- net/ipv6/seg6_local.c | 7 + net/netfilter/nf_tables_api.c | 36 +-- net/netfilter/nft_set_pipapo_avx2.c | 17 +- net/tls/tls_device.c | 3 +- net/xfrm/espintcp.c | 9 +- net/xfrm/xfrm_nat_keepalive.c | 53 ++++- net/xfrm/xfrm_user.c | 2 +- security/selinux/include/security.h | 1 + security/selinux/ss/avtab.c | 35 ++- security/selinux/ss/avtab.h | 13 ++ security/selinux/ss/conditional.c | 25 +- security/selinux/ss/constraint.h | 1 + security/selinux/ss/policydb.c | 254 +++++++++++++++++---- security/selinux/ss/policydb.h | 31 ++- security/selinux/ss/services.c | 8 +- sound/soc/codecs/nau8821.c | 13 ++ sound/usb/card.c | 14 +- sound/usb/midi.c | 2 + 88 files changed, 1156 insertions(+), 776 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/83 RDMA/rxe: Fix responder UAF on IB_QP_MAX_DEST_RD_ATOMIC modify_qp
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
[ Upstream commit 6f7014237405e7f032b5c53a82d9eccf6161c291 ]
rxe_qp_from_attr() handles IB_QP_MAX_DEST_RD_ATOMIC outside the IB_QP_STATE path, so it holds no state_lock and runs while the responder task rxe_receiver() (recv_task on rxe_wq) is live. A modify_qp() setting only that attribute calls free_rd_atomic_resources() then alloc_rd_atomic_resources(), swapping qp->resp.resources[] while rxe_prepare_res()/find_resource() walk it; free_rd_atomic_resources() also leaves the cached pointer qp->resp.res dangling. A local unprivileged user can race the free/realloc into a use-after-free in rxe_receiver() (local DoS).
Drain recv_task around the swap with rxe_disable_task()/rxe_enable_task(), as rxe_qp_reset() already does when tearing this array down, re-enabling only after alloc_rd_atomic_resources() succeeds so the responder never resumes against a NULL qp->resp.resources on the ENOMEM path. Also clear qp->resp.res in free_rd_atomic_resources(), like the rxe_resp.c completion paths.
Reproduced under KASAN; the slab-use-after-free in rxe_receiver() is gone.
--- drivers/infiniband/sw/rxe/rxe_qp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/infiniband/sw/rxe/rxe_qp.c +14 -1
@@ -124,6 +124,7 @@ static void free_rd_atomic_resources(struct rxe_qp *qp) }kfree (qp->resp.resources); qp->resp.resources =NULL ; + qp->resp.res =NULL ; } }
@@ -660,11 +661,23 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask, qp->attr.max_dest_rd_atomic = max_dest_rd_atomic; +/* +* Not gated by IB_QP_STATE, so the responder task is live. +* Quiesce recv_task like rxe_qp_reset() before swapping the +* rd_atomic array, so rxe_receiver() cannot race the free/ +* realloc. +*/ +rxe_disable_task (&qp->recv_task);free_rd_atomic_resources (qp); - err =alloc_rd_atomic_resources (qp, max_dest_rd_atomic); +/* +* On ENOMEM leave recv_task quiesced: qp->resp.resources is +* NULL and rxe_prepare_res()/find_resource() would deref it. +* Re-enable only after a fresh array is installed. +*/ if (err)return err; +rxe_enable_task (&qp->recv_task); }if (mask &IB_QP_EN_SQD_ASYNC_NOTIFY )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 2/83 RDMA/rxe: Fix OOB in free_rd_atomic_resources()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
[ Upstream commit de329533792a373186d79dca1ca120f8fa0afd05 ]
free_rd_atomic_resources() iterates using qp->attr.max_dest_rd_atomic. Updating max_dest_rd_atomic before freeing the old array can make the free path walk past the old allocation and trigger a slab out-of-bounds write catched by KASAN:
==================================================================
BUG: KASAN: slab-out-of-bounds in free_rd_atomic_resource drivers/infiniband/sw/rxe/rxe_qp.c:180 [inline] BUG: KASAN: slab-out-of-bounds in free_rd_atomic_resources drivers/infiniband/sw/rxe/rxe_qp.c:171 [inline] BUG: KASAN: slab-out-of-bounds in free_rd_atomic_resources drivers/infiniband/sw/rxe/rxe_qp.c:163 [inline] BUG: KASAN: slab-out-of-bounds in rxe_qp_from_attr+0x1e88/0x2150 drivers/infiniband/sw/rxe/rxe_qp.c:712 Write of size 4 at addr ffff88802b8dddb8 by task syz.3.451/11063 CPU: 0 UID: 0 PID: 11063 Comm: syz.3.451 Not tainted 7.1.0 #2 PREEMPT(full) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x10e/0x1f0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xf7/0x600 mm/kasan/report.c:482 kasan_report+0xe4/0x120 mm/kasan/report.c:595 free_rd_atomic_resource drivers/infiniband/sw/rxe/rxe_qp.c:180 [inline] free_rd_atomic_resources drivers/infiniband/sw/rxe/rxe_qp.c:171 [inline] free_rd_atomic_resources drivers/infiniband/sw/rxe/rxe_qp.c:163 [inline] rxe_qp_from_attr+0x1e88/0x2150 drivers/infiniband/sw/rxe/rxe_qp.c:712 rxe_modify_qp+0x1e2/0x530 drivers/infiniband/sw/rxe/rxe_verbs.c:623 ib_security_modify_qp+0x223/0xfa0 drivers/infiniband/core/security.c:625 _ib_modify_qp+0x333/0xec0 drivers/infiniband/core/verbs.c:1915 modify_qp+0x13ca/0x1940 drivers/infiniband/core/uverbs_cmd.c:1932 ib_uverbs_modify_qp+0xcb/0x120 drivers/infiniband/core/uverbs_cmd.c:1958 ib_uverbs_write+0xb86/0x1030 drivers/infiniband/core/uverbs_main.c:680 vfs_write+0x2aa/0x1070 fs/read_write.c:686 ksys_write+0x1f8/0x250 fs/read_write.c:740 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x116/0x800 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fefc75a70cd Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 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 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007fefc8495018 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007fefc7835fa0 RCX: 00007fefc75a70cd RDX: 0000000000000078 RSI: 0000200000000240 RDI: 0000000000000007 RBP: 00007fefc764f10f R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fefc7836038 R14: 00007fefc7835fa0 R15: 00007ffcf0586aa0 </TASK> Allocated by task 11063: kasan_save_stack+0x33/0x60 mm/kasan/common.c:57 kasan_save_track+0x14/0x30 mm/kasan/common.c:78 poison_kmalloc_redzone mm/kasan/common.c:398 [inline] __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:415 kasan_kmalloc include/linux/kasan.h:263 [inline] __do_kmalloc_node mm/slub.c:5296 [inline] __kmalloc_noprof+0x32a/0x850 mm/slub.c:5308 kmalloc_noprof include/linux/slab.h:954 [inline] kzalloc_noprof include/linux/slab.h:1188 [inline] alloc_rd_atomic_resources drivers/infiniband/sw/rxe/rxe_qp.c:155 [inline] rxe_qp_from_attr+0x3f8/0x2150 drivers/infiniband/sw/rxe/rxe_qp.c:714 rxe_modify_qp+0x1e2/0x530 drivers/infiniband/sw/rxe/rxe_verbs.c:623 ib_security_modify_qp+0x223/0xfa0 drivers/infiniband/core/security.c:625 _ib_modify_qp+0x333/0xec0 drivers/infiniband/core/verbs.c:1915 modify_qp+0x13ca/0x1940 drivers/infiniband/core/uverbs_cmd.c:1932 ib_uverbs_modify_qp+0xcb/0x120 drivers/infiniband/core/uverbs_cmd.c:1958 ib_uverbs_write+0xb86/0x1030 drivers/infiniband/core/uverbs_main.c:680 vfs_write+0x2aa/0x1070 fs/read_write.c:686 ksys_write+0x1f8/0x250 fs/read_write.c:740 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x116/0x800 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The buggy address belongs to the object at ffff88802b8ddd80 which belongs to the cache kmalloc-64 of size 64
The buggy address is located 0 bytes to the right of
allocated 56-byte region [ffff88802b8ddd80, ffff88802b8dddb8)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2b8dd
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff888015c418c0 dead000000000100 dead000000000122
raw: 0000000000000000 0000000800200020 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2c40(GFP_NOFS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 4651, tgid 4651 ((udev-worker)), ts 123427165316, free_ts 123425874255
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0xfc/0x120 mm/page_alloc.c:1853
prep_new_page mm/page_alloc.c:1861 [inline]
get_page_from_freelist+0x75b/0x3220 mm/page_alloc.c:3941
__alloc_frozen_pages_noprof+0x27e/0x2b00 mm/page_alloc.c:5221
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab mm/slub.c:3467 [inline]
new_slab+0xa6/0x670 mm/slub.c:3525
refill_objects+0x278/0x420 mm/slub.c:7272
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x2ed/0x640 mm/slub.c:4652
alloc_from_pcs mm/slub.c:4750 [inline]
slab_alloc_node mm/slub.c:4884 [inline]
__do_kmalloc_node mm/slub.c:5295 [inline]
__kmalloc_noprof+0x68d/0x850 mm/slub.c:5308
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
tomoyo_encode2+0x100/0x3e0 security/tomoyo/realpath.c:45
tomoyo_encode+0x29/0x50 security/tomoyo/realpath.c:80
tomoyo_realpath_from_path+0x18c/0x690 security/tomoyo/realpath.c:283
tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
tomoyo_check_open_permission+0x2ab/0x3c0 security/tomoyo/file.c:776
tomoyo_file_open+0x6b/0x90 security/tomoyo/tomoyo.c:334
security_file_open+0x7a/0x1b0 security/security.c:2739
do_dentry_open+0x57e/0x1690 fs/open.c:924
vfs_open+0x82/0x3f0 fs/open.c:1079
do_open fs/namei.c:4699 [inline]
path_openat+0x218a/0x3190 fs/namei.c:4858
page last free pid 1 tgid 1 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1397 [inline]
__free_frozen_pages+0x763/0xfc0 mm/page_alloc.c:2938
selinux_genfs_get_sid security/selinux/hooks.c:1364 [inline]
inode_doinit_with_dentry+0x903/0x1320 security/selinux/hooks.c:1563
selinux_d_instantiate+0x26/0x30 security/selinux/hooks.c:6658
security_d_instantiate+0x123/0x190 security/security.c:3704
d_splice_alias_ops+0x92/0x850 fs/dcache.c:3141
kernfs_iop_lookup+0x23f/0x2d0 fs/kernfs/dir.c:1289
lookup_open.isra.0+0x659/0x1080 fs/namei.c:4484
open_last_lookups fs/namei.c:4611 [inline]
path_openat+0x17dd/0x3190 fs/namei.c:4855
do_file_open+0x20c/0x430 fs/namei.c:4887
do_sys_openat2+0x101/0x1d0 fs/open.c:1364
do_sys_open fs/open.c:1370 [inline]
__do_sys_openat fs/open.c:1386 [inline]
__se_sys_openat fs/open.c:1381 [inline]
__x64_sys_openat+0x141/0x200 fs/open.c:1381
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x116/0x800 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88802b8ddc80: 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc
ffff88802b8ddd00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>ffff88802b8ddd80: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
^
ffff88802b8dde00: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc
ffff88802b8dde80: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fcFix the OOB by moving the assignment after free_rd_atomic_resources() so the old array is freed using the old bound. This matches the original ordering in commit 8700e3e7c485 ("Soft RoCE driver").
--- drivers/infiniband/sw/rxe/rxe_qp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/infiniband/sw/rxe/rxe_qp.c +1 -2
@@ -659,8 +659,6 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,int max_dest_rd_atomic = attr->max_dest_rd_atomic ?roundup_pow_of_two (attr->max_dest_rd_atomic) :0 ; - qp->attr.max_dest_rd_atomic = max_dest_rd_atomic; -/* * Not gated by IB_QP_STATE, so the responder task is live. * Quiesce recv_task like rxe_qp_reset() before swapping the
@@ -669,6 +667,7 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,*/ rxe_disable_task (&qp->recv_task);free_rd_atomic_resources (qp); + qp->attr.max_dest_rd_atomic = max_dest_rd_atomic; err =alloc_rd_atomic_resources (qp, max_dest_rd_atomic);/* * On ENOMEM leave recv_task quiesced: qp->resp.resources is
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 3/83 drm/xe/guc_ads: allocate UM queues in a separate BO
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Yao <[email protected]>
commit 99b01815957bd7d848420cb697f79ed11f7f215c upstream.
Move the UM queues into a dedicated BO (ads->um_queue_bo) and avoid CPU memset operations on it, which eliminates the CPU as a potential cacheline-polluting agent and helps maintain consistency between GAM writes and GuC reads.
We also need to ensure the base_dpa for the queue is contiguous on hw where this is used instead of a GGTT address. Another good reason to split this out to a separate BO.
--- drivers/gpu/drm/xe/xe_bo.h | 14 +++++ drivers/gpu/drm/xe/xe_guc.c | 6 ++ drivers/gpu/drm/xe/xe_guc_ads.c | 89 +++++++++++++++++---------- drivers/gpu/drm/xe/xe_guc_ads_types.h | 5 ++ 4 files changed, 82 insertions(+), 32 deletions(-)
drivers/gpu/drm/xe/xe_bo.h +14 -0
@@ -6,6 +6,7 @@#ifndef _XE_BO_H_#define _XE_BO_H_ +#include <drm/drm_prime.h> #include <drm/ttm/ttm_tt.h> #include "xe_bo_types.h"
@@ -455,6 +456,19 @@ void xe_bo_dev_fini(struct xe_bo_dev *bo_device);struct sg_table *xe_bo_sg (struct xe_bo *bo); +/** +* xe_bo_sg_is_contiguous() - Check if a BO's DMA address space is contiguous. +* @bo: the BO to check (must have a valid sg table, i.e. !xe_bo_is_vram()) +* @len: required contiguous length in bytes +* +* Returns true if the first @len bytes of the BO are mapped to a contiguous +* DMA address range. +*/ +static inline bool xe_bo_sg_is_contiguous (struct xe_bo *bo,size_t len) +{ +return drm_prime_get_contiguous_size (xe_bo_sg (bo)) >= len; +} +/* * xe_sg_segment_size() - Provides upper limit for sg segment size. * @dev: device pointer
drivers/gpu/drm/xe/xe_guc.c +6 -0
@@ -700,6 +700,12 @@ static int xe_guc_realloc_post_hwconfig(struct xe_guc *guc)if (ret)return ret; +if (guc->ads.um_queue_bo) { + ret =xe_managed_bo_reinit_in_vram (xe, tile, &guc->ads.um_queue_bo); +if (ret) +return ret; + } +return 0 ; }
drivers/gpu/drm/xe/xe_guc_ads.c +57 -32
134 lines not on this page · raw message
drivers/gpu/drm/xe/xe_guc_ads_types.h +5 -0
@@ -16,6 +16,11 @@ struct xe_bo;struct xe_guc_ads {/** @bo: XE BO for GuC ads blob */ struct xe_bo *bo; +/** +* @um_queue_bo: Dedicated BO for the HW fault ring (UM queues). +* NULL if the platform does not support USM. +*/ +struct xe_bo *um_queue_bo;/** @golden_lrc_size: golden LRC size */ size_t golden_lrc_size;/** @regset_size: size of register set passed to GuC for save/restore */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 4/83 drm/xe/guc_ads: allocate UM queues in VRAM on dGFX
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Yao <[email protected]>
commit f342810a141f8a7e8b3786a6e4b6c0695a078a74 upstream.
On iGPU, the UM queue BO is allocated in system memory. On dGFX, the BO was previously created in system memory and later reallocated in xe_guc_realloc_post_hwconfig(). Allocate the UM queue BO directly in VRAM on dGFX, where it is ultimately required.
--- drivers/gpu/drm/xe/xe_guc.c | 6 ------ drivers/gpu/drm/xe/xe_guc_ads.c | 8 +++++--- 2 files changed, 5 insertions(+), 9 deletions(-)
drivers/gpu/drm/xe/xe_guc.c +0 -6
@@ -700,12 +700,6 @@ static int xe_guc_realloc_post_hwconfig(struct xe_guc *guc)if (ret)return ret; -if (guc->ads.um_queue_bo) { - ret =xe_managed_bo_reinit_in_vram (xe, tile, &guc->ads.um_queue_bo); -if (ret) -return ret; - } -return 0 ; }
drivers/gpu/drm/xe/xe_guc_ads.c +5 -3
@@ -392,15 +392,17 @@ int xe_guc_ads_init(struct xe_guc_ads *ads)/* * Allocate a separate BO for the HW fault ring (UM queues). * -* Round the size up to the next power of two so that +* Round the size up to the next power of two so that on iGPU * (system memory, no IOMMU) the TTM pool issues a single * alloc_pages(order=N) call, maximising the chance of getting * a physically contiguous block. GuC requires contiguous DPA. */ -size_t um_size =roundup_pow_of_two (GUC_UM_QUEUE_SIZE * +size_t um_size =IS_DGFX (xe) ? +GUC_UM_QUEUE_SIZE *GUC_UM_HW_QUEUE_MAX : +roundup_pow_of_two (GUC_UM_QUEUE_SIZE *GUC_UM_HW_QUEUE_MAX ); -u32 um_flags =XE_BO_FLAG_SYSTEM | +u32 um_flags =XE_BO_FLAG_VRAM_IF_DGFX (tile) |XE_BO_FLAG_GGTT |XE_BO_FLAG_GGTT_INVALIDATE |XE_BO_FLAG_PINNED_NORESTORE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 5/83 drm/xe/guc_ads: use uncached mapping for UM queue BO
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Yao <[email protected]>
commit 8d5134ae4177fa4f5a9bc8e71e6656cfc2852882 upstream.
On Pre-Xe3p platform, the GAM write the UM queue through DPA using UC. if GuC reads the queue via GGTT (WB), stale data may be observed when the cacheline has been polluted by another agent.
To match the GAM's UC writes, configure the GuC mapping as UC as well.
Reviewed by: Matthew Auld <[email protected]>
--- drivers/gpu/drm/xe/xe_guc_ads.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_guc_ads.c +2 -1
@@ -405,7 +405,8 @@ int xe_guc_ads_init(struct xe_guc_ads *ads)u32 um_flags =XE_BO_FLAG_VRAM_IF_DGFX (tile) |XE_BO_FLAG_GGTT |XE_BO_FLAG_GGTT_INVALIDATE | -XE_BO_FLAG_PINNED_NORESTORE ; +XE_BO_FLAG_PINNED_NORESTORE | +XE_BO_FLAG_NEEDS_UC ; bo =xe_managed_bo_create_pin_map (xe, tile, um_size, um_flags);if (IS_ERR (bo))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 6/83 KVM: x86/mmu: Check write tracking in all address spaces
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinu Kim <[email protected]>
[ Upstream commit 0f38453cdb2e17566ccb7c0f3dabd5bd21caca26 ]
kvm_gfn_is_write_tracked() checks only the supplied memslot, but page tracking is per-address-space and shadow pages are shared across all address spaces. With SMM, a GFN can therefore be write-tracked in one address space and appear untracked through the other.
Check the supplied slot first, then the slot for the other address space. This ensures all callers honor write tracking regardless of the active address space. In particular, it prevents mmu_try_to_unsync_pages() from marking an upper-level shadow page unsync and eventually triggering the BUG in pte_list_remove().
Message-ID: <[email protected]>
--- arch/x86/kvm/mmu/page_track.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)
arch/x86/kvm/mmu/page_track.c +26 -6
@@ -130,13 +130,23 @@ void __kvm_write_track_remove_gfn(struct kvm *kvm,kvm_mmu_gfn_allow_lpage (slot, gfn); } -/* -* check if the corresponding access on the specified guest page is tracked. -*/ +static bool __kvm_gfn_is_write_tracked (const struct kvm_memory_slot *slot, +gfn_t gfn) +{ +int index; + +if (!slot) +return false; + + index =gfn_to_index (gfn, slot->base_gfn,PG_LEVEL_4K ); +return !!READ_ONCE (slot->arch.gfn_write_track[index]); +} + +/* check if write access is tracked on the specified guest page. */ bool kvm_gfn_is_write_tracked (struct kvm *kvm,const struct kvm_memory_slot *slot,gfn_t gfn) { -int index; +const struct kvm_memory_slot *other_slot;if (!slot)return false;
@@ -144,8 +154,18 @@ bool kvm_gfn_is_write_tracked(struct kvm *kvm,if (!kvm_page_track_write_tracking_enabled (kvm))return false; - index =gfn_to_index (gfn, slot->base_gfn,PG_LEVEL_4K ); -return !!READ_ONCE (slot->arch.gfn_write_track[index]); +BUILD_BUG_ON (KVM_MAX_NR_ADDRESS_SPACES >2 ); + +if (__kvm_gfn_is_write_tracked (slot, gfn)) +return true; + +if (kvm_arch_nr_memslot_as_ids (kvm) >1 ) { + other_slot =__gfn_to_memslot (__kvm_memslots (kvm, slot->as_id ^1 ), gfn); +if (__kvm_gfn_is_write_tracked (other_slot, gfn)) +return true; + } + +return false; }#ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 7/83 nvme-tcp: fix usage of page_frag_cache
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Bogdanov <[email protected]>
commit 36ac05f7cfd59d90c597071304b14e98090d5dd1 upstream.
nvme uses page_frag_cache to preallocate PDU for each preallocated request of block device. Block devices are created in parallel threads, consequently page_frag_cache is used in not thread-safe manner. That leads to incorrect refcounting of backstore pages and premature free.
That can be catched by !sendpage_ok inside network stack:
WARNING: CPU: 7 PID: 467 at ../net/core/skbuff.c:6931 skb_splice_from_iter+0xfa/0x310. tcp_sendmsg_locked+0x782/0xce0 tcp_sendmsg+0x27/0x40 sock_sendmsg+0x8b/0xa0 nvme_tcp_try_send_cmd_pdu+0x149/0x2a0
Then random panic may occur.
Fix that by serializing the usage of page_frag_cache.
[carlos.bilbao: adjust context in nvme_tcp_free_queue; branch predates 19bdb70c77d3 ("nvme-tcp: lockdep: use dynamic lockdep keys per socket instance")]
--- drivers/nvme/host/tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/nvme/host/tcp.c +8 -0
@@ -145,6 +145,7 @@ struct nvme_tcp_queue {struct mutex queue_lock;struct mutex send_mutex; +struct mutex pf_cache_lock;struct llist_head req_list;struct list_head send_list;
@@ -556,9 +557,11 @@ static int nvme_tcp_init_request(struct blk_mq_tag_set *set,struct nvme_tcp_queue *queue = &ctrl->queues[queue_idx];u8 hdgst =nvme_tcp_hdgst_len (queue); +mutex_lock (&queue->pf_cache_lock); req->pdu =page_frag_alloc (&queue->pf_cache,sizeof (struct nvme_tcp_cmd_pdu ) + hdgst,GFP_KERNEL | __GFP_ZERO); +mutex_unlock (&queue->pf_cache_lock);if (!req->pdu)return -ENOMEM ;
@@ -1423,9 +1426,11 @@ static int nvme_tcp_alloc_async_req(struct nvme_tcp_ctrl *ctrl)struct nvme_tcp_request *async = &ctrl->async_req;u8 hdgst =nvme_tcp_hdgst_len (queue); +mutex_lock (&queue->pf_cache_lock); async->pdu =page_frag_alloc (&queue->pf_cache,sizeof (struct nvme_tcp_cmd_pdu ) + hdgst,GFP_KERNEL | __GFP_ZERO); +mutex_unlock (&queue->pf_cache_lock);if (!async->pdu)return -ENOMEM ;
@@ -1453,6 +1458,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)kfree (queue->pdu);mutex_destroy (&queue->send_mutex);mutex_destroy (&queue->queue_lock); +mutex_destroy (&queue->pf_cache_lock); }static int nvme_tcp_init_connection (struct nvme_tcp_queue *queue)
@@ -1775,6 +1781,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,INIT_LIST_HEAD (&queue->send_list);mutex_init (&queue->send_mutex);INIT_WORK (&queue->io_work, nvme_tcp_io_work); +mutex_init (&queue->pf_cache_lock);if (qid >0 ) queue->cmnd_capsule_len = nctrl->ioccsz *16 ;
@@ -1906,6 +1913,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, err_destroy_mutex:mutex_destroy (&queue->send_mutex);mutex_destroy (&queue->queue_lock); +mutex_destroy (&queue->pf_cache_lock);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 8/83 Revert "selinux: reject a permission value exceeding the class permission count"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
This reverts commit 9b46fba7528f58ca09eac67ec7d474ff1e9af066.
The stable pick applied the nprim bound after symtab_insert() because the upstream context (the SEL_VEC_MAX check from commit 18fa21f10d00 "selinux: more strict policy parsing") does not exist in this tree. On that error path perm_destroy() frees a key/datum pair that is already linked into the symtab, leading to a double free when the failed policydb is torn down.
Drop it here; it is re-applied later in this series in its upstream form, after its strict-parsing prerequisite.
--- security/selinux/ss/policydb.c | 3 --- 1 file changed, 3 deletions(-)
security/selinux/ss/policydb.c +0 -3
@@ -1168,9 +1168,6 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f rc =symtab_insert (s, key, perdatum);if (rc) goto bad; -/* indexes an nprim-sized array in security_get_permissions() */ -if (perdatum->value > s->nprim) - goto bad;return 0 ; bad:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 9/83 selinux: use u16 for security classes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Göttsche <[email protected]>
[ Upstream commit fa79a596848fe38c55ccab8832ac35dac07fb00c ]
Security class identifiers are limited to 2^16, thus use the appropriate type u16 consistently.
--- security/selinux/ss/policydb.c | 5 +++-- security/selinux/ss/policydb.h | 10 +++++----- security/selinux/ss/services.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-)
security/selinux/ss/policydb.c +3 -2
@@ -951,7 +951,7 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)return 0 ; } -int policydb_class_isvalid (struct policydb *p,unsigned int class) +int policydb_class_isvalid (struct policydb *p,u16 class) {if (!class || class > p->p_classes.nprim)return 0 ;
@@ -2039,7 +2039,8 @@ static int filename_trans_read_helper(struct policydb *p, struct policy_file *fpstruct filename_trans_key *ft =NULL ;struct filename_trans_datum **dst, *datum, *first =NULL ;char *name =NULL ; -u32 len, ttype, tclass, ndatum, i; +u32 len, ttype, ndatum, i; +u16 tclass;__le32 buf[3 ];int rc;
security/selinux/ss/policydb.h +5 -5
@@ -48,7 +48,7 @@ struct common_datum {/* Class attributes */ struct class_datum { -u32 value;/* class value */ +u16 value;/* class value */ char *comkey;/* common name */ struct common_datum *comdatum;/* common datum */ struct symtab permissions;/* class-specific permission symbol table */
@@ -82,7 +82,7 @@ struct role_datum {struct role_trans_key {u32 role;/* current role */ u32 type;/* program executable type, or new object type */ -u32 tclass;/* process class, or new object class */ +u16 tclass;/* process class, or new object class */ };struct role_trans_datum {
@@ -139,7 +139,7 @@ struct cat_datum {struct range_trans {u32 source_type;u32 target_type; -u32 target_class; +u16 target_class; };/* Boolean data type */
@@ -195,7 +195,7 @@ struct ocontext { } ibendport; } u;union { -u32 sclass;/* security class for genfs */ +u16 sclass;/* security class for genfs */ u32 behavior;/* labeling behavior for fs_use */ } v;struct context context[2 ];/* security context(s) */
@@ -322,7 +322,7 @@ struct policy_file {extern void policydb_destroy (struct policydb *p);extern int policydb_load_isids (struct policydb *p,struct sidtab *s);extern int policydb_context_isvalid (struct policydb *p,struct context *c); -extern int policydb_class_isvalid (struct policydb *p,unsigned int class); +extern int policydb_class_isvalid (struct policydb *p,u16 class);extern int policydb_type_isvalid (struct policydb *p,unsigned int type);extern int policydb_role_isvalid (struct policydb *p,unsigned int role);extern int policydb_read (struct policydb *p,struct policy_file *fp);
security/selinux/ss/services.c +1 -1
@@ -3290,7 +3290,7 @@ static int get_classes_callback(void *k, void *d, void *args) {struct class_datum *datum = d;char *name = k, **classes = args; -u32 value = datum->value -1 ; +u16 value = datum->value -1 ; classes[value] =kstrdup (name,GFP_ATOMIC );if (!classes[value])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 10/83 selinux: more strict policy parsing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Göttsche <[email protected]>
[ Upstream commit 18fa21f10d008a0fc22565109c7d38f304295912 ]
Be more strict during parsing of policies and reject invalid values.
Add some error messages in the case of policy parse failures, to enhance debugging, either on a malformed policy or a too strict check.
--- security/selinux/include/security.h | 1 + security/selinux/ss/avtab.c | 35 ++++- security/selinux/ss/avtab.h | 13 ++ security/selinux/ss/conditional.c | 18 +-- security/selinux/ss/constraint.h | 1 + security/selinux/ss/policydb.c | 196 +++++++++++++++++++++++----- security/selinux/ss/policydb.h | 23 +++- security/selinux/ss/services.c | 6 +- 8 files changed, 233 insertions(+), 60 deletions(-)
security/selinux/include/security.h +1 -0
@@ -225,6 +225,7 @@ int security_read_policy(void **data, size_t *len);int security_read_state_kernel (void **data,size_t *len);int security_policycap_supported (unsigned int req_cap); +/* Maximum supported number of permissions per class */ #define SEL_VEC_MAX 32struct av_decision {u32 allowed;
security/selinux/ss/avtab.c +29 -6
@@ -349,7 +349,7 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *postruct avtab_extended_perms xperms;__le32 buf32[ARRAY_SIZE (xperms.perms.p)];int rc; -unsigned int set, vers = pol->policyvers; +unsigned int vers = pol->policyvers;memset (&key,0 ,sizeof (struct avtab_key ));memset (&datum,0 ,sizeof (struct avtab_datum ));
@@ -360,9 +360,12 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *popr_err ("SELinux: avtab: truncated entry\n" );return rc; } +/* Read five or more items: source type, target type, +* target class, AV type, and at least one datum. +*/ items2 =le32_to_cpu (buf32[0 ]); -if (items2 >ARRAY_SIZE (buf32)) { -pr_err ("SELinux: avtab: entry overflow\n" ); +if (items2 <5 || items2 >ARRAY_SIZE (buf32)) { +pr_err ("SELinux: avtab: invalid item count\n" );return -EINVAL ; } rc =next_entry (buf32, fp,sizeof (u32) * items2);
@@ -391,6 +394,13 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *poreturn -EINVAL ; } +if (!policydb_type_isvalid (pol, key.source_type) || + !policydb_type_isvalid (pol, key.target_type) || + !policydb_class_isvalid (pol, key.target_class)) { +pr_err ("SELinux: avtab: invalid type or class\n" ); +return -EINVAL ; + } + val =le32_to_cpu (buf32[items++]); enabled = (val &AVTAB_ENABLED_OLD ) ?AVTAB_ENABLED :0 ;
@@ -409,6 +419,11 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pofor (i =0 ; i <ARRAY_SIZE (spec_order); i++) {if (val & spec_order[i]) { +if (items >= items2) { +pr_err ("SELinux: avtab: entry has too many items (%d/%d)\n" , + items +1 , items2); +return -EINVAL ; + } key.specified = spec_order[i] | enabled; datum.u.data =le32_to_cpu (buf32[items++]); rc =insertf (a, &key, &datum, p);
@@ -444,9 +459,13 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *poreturn -EINVAL ; } - set =hweight16 (key.specified & (AVTAB_XPERMS |AVTAB_TYPE |AVTAB_AV )); -if (!set || set >1 ) { -pr_err ("SELinux: avtab: more than one specifier\n" ); +if (hweight16 (key.specified & ~AVTAB_ENABLED ) !=1 ) { +pr_err ("SELinux: avtab: not exactly one specifier\n" ); +return -EINVAL ; + } + +if (key.specified & ~AVTAB_SPECIFIER_MASK ) { +pr_err ("SELinux: avtab: invalid specifier\n" );return -EINVAL ; }
@@ -471,6 +490,10 @@ int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *popr_err ("SELinux: avtab: truncated entry\n" );return rc; } +if (!avtab_is_valid_xperm_specified (xperms.specified)) +pr_warn_once_policyload (pol, +"SELinux: avtab: unsupported xperm specifier %#x\n" , + xperms.specified); rc =next_entry (&xperms.driver, fp,sizeof (u8));if (rc) {pr_err ("SELinux: avtab: truncated entry\n" );
security/selinux/ss/avtab.h +13 -0
@@ -44,6 +44,7 @@ struct avtab_key { AVTAB_XPERMS_DONTAUDIT)#define AVTAB_ENABLED_OLD 0x80000000/* reserved for used in cond_avtab */ #define AVTAB_ENABLED 0x8000/* reserved for used in cond_avtab */ +#define AVTAB_SPECIFIER_MASK (AVTAB_AV | AVTAB_TYPE | AVTAB_XPERMS | AVTAB_ENABLED)u16 specified;/* what field is specified */ };
@@ -68,6 +69,18 @@ struct avtab_extended_perms {struct extended_perms_data perms; }; +static inline bool avtab_is_valid_xperm_specified (u8 specified) +{ +switch (specified) { +case AVTAB_XPERMS_IOCTLFUNCTION : +case AVTAB_XPERMS_IOCTLDRIVER : +case AVTAB_XPERMS_NLMSG : +return true; +default : +return false; + } +} +struct avtab_datum {union {u32 data;/* access vector or type value */
security/selinux/ss/conditional.c +7 -11
@@ -199,19 +199,12 @@ int cond_index_bool(void *key, void *datum, void *datap)return 0 ; } -static int bool_isvalid (struct cond_bool_datum *b) -{ -if (!(b->state ==0 || b->state ==1 )) -return 0 ; -return 1 ; -} -int cond_read_bool (struct policydb *p,struct symtab *s,struct policy_file *fp) {char *key =NULL ;struct cond_bool_datum *booldatum;__le32 buf[3 ]; -u32 len; +u32 len, val;int rc; booldatum =kzalloc (sizeof (*booldatum),GFP_KERNEL );
@@ -223,11 +216,12 @@ int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp) goto err; booldatum->value =le32_to_cpu (buf[0 ]); - booldatum->state =le32_to_cpu (buf[1 ]); + val =le32_to_cpu (buf[1 ]); rc = -EINVAL ; -if (!bool_isvalid (booldatum)) +if (!val_is_boolean (val)) goto err; + booldatum->state = (int )val; len =le32_to_cpu (buf[2 ]);
@@ -241,6 +235,7 @@ int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp)return 0 ; err: +pr_err ("SELinux: conditional: failed to read boolean\n" );cond_destroy_bool (key, booldatum,NULL );return rc; }
@@ -362,7 +357,8 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)return 0 ; } -if (expr->boolean > p->p_bools.nprim) { +if (expr->expr_type ==COND_BOOL && + (expr->boolean ==0 || expr->boolean > p->p_bools.nprim)) {pr_err ("SELinux: conditional expressions uses unknown bool.\n" );return 0 ; }
security/selinux/ss/constraint.h +1 -0
@@ -50,6 +50,7 @@ struct constraint_expr {u32 op;/* operator */ struct ebitmap names;/* names */ +/* internally unused, only forwarded via policydb_write() */ struct type_set *type_names;struct constraint_expr *next;/* next expression */
security/selinux/ss/policydb.c +161 -35
402 lines not on this page · raw message
security/selinux/ss/policydb.h +19 -4
@@ -74,7 +74,7 @@ struct class_datum {/* Role attributes */ struct role_datum {u32 value;/* internal role value */ -u32 bounds;/* boundary of role */ +u32 bounds;/* boundary of role, 0 for none */ struct ebitmap dominates;/* set of roles dominated by this role */ struct ebitmap types;/* set of authorized types for role */ };
@@ -110,7 +110,8 @@ struct role_allow {/* Type attributes */ struct type_datum {u32 value;/* internal type value */ -u32 bounds;/* boundary of type */ +u32 bounds;/* boundary of type, 0 for none */ +/* internally unused, only forwarded via policydb_write() */ unsigned char primary;/* primary name? */ unsigned char attribute;/* attribute ?*/ };
@@ -118,7 +119,7 @@ struct type_datum {/* User attributes */ struct user_datum {u32 value;/* internal user value */ -u32 bounds;/* bounds of user */ +u32 bounds;/* bounds of user, 0 for none */ struct ebitmap roles;/* set of authorized roles for user */ struct mls_range range;/* MLS range (min - max) for user */ struct mls_level dfltlevel;/* default login MLS level for user */
@@ -195,7 +196,7 @@ struct ocontext { } ibendport; } u;union { -u16 sclass;/* security class for genfs */ +u16 sclass;/* security class for genfs (can be 0 for wildcard) */ u32 behavior;/* labeling behavior for fs_use */ } v;struct context context[2 ];/* security context(s) */
@@ -388,9 +389,23 @@ static inline char *sym_name(struct policydb *p, unsigned int sym_num, return p->sym_val_to_name[sym_num][element_nr]; } +static inline bool val_is_boolean (u32 value) +{ +return value ==0 || value ==1 ; +} +extern int str_read (char **strp,gfp_t flags,struct policy_file *fp,u32 len);extern u16 string_to_security_class (struct policydb *p,const char *name);extern u32 string_to_av_perm (struct policydb *p,u16 tclass,const char *name); +#define pr_warn_once_policyload (policy, fmt, ...) \ + do { \ + static const void *prev_policy__; \ + if (prev_policy__ != policy) { \ + pr_warn(fmt, ##__VA_ARGS__); \ + prev_policy__ = policy; \ + } \ + } while (0) +#endif /* _SS_POLICYDB_H_ */
security/selinux/ss/services.c +2 -4
@@ -446,8 +446,6 @@ static int dump_masked_av_helper(void *k, void *d, void *args)struct perm_datum *pdatum = d;char **permission_names = args; -BUG_ON (pdatum->value <1 || pdatum->value >32 ); - permission_names[pdatum->value -1 ] = (char *)k;return 0 ;
@@ -466,7 +464,7 @@ static void security_dump_masked_av(struct policydb *policydb,char *tclass_name;char *scontext_name =NULL ;char *tcontext_name =NULL ; -char *permission_names[32 ]; +char *permission_names[SEL_VEC_MAX ];int index;u32 length;bool need_comma = false;
@@ -507,7 +505,7 @@ static void security_dump_masked_av(struct policydb *policydb,"scontext=%s tcontext=%s tclass=%s perms=" , reason, scontext_name, tcontext_name, tclass_name); -for (index =0 ; index <32 ; index++) { +for (index =0 ; index <SEL_VEC_MAX ; index++) {u32 mask = (1 << index);if ((mask & permissions) ==0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 11/83 selinux: reject a permission value exceeding the class permission count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit d14b5d0e97fccd27974fedc03b903408872907fd ]
perm_read() bounds a permission value by SEL_VEC_MAX but never by the nprim of the owning class or common, which is taken verbatim from the policy image. security_get_permissions() then writes perms[value - 1] into an nprim-sized kcalloc() array, so a class declaring fewer permissions than its largest permission value drives an out-of-bounds heap write. The top-level symbol tables are validated this way; the nested per-class permission table is not.
Reject a permission whose value exceeds nprim, which is already set when perm_read() runs. Well-formed policies are unaffected.
--- security/selinux/ss/policydb.c | 3 +++ 1 file changed, 3 insertions(+)
security/selinux/ss/policydb.c +3 -0
@@ -1160,6 +1160,9 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f rc = -EINVAL ;if (perdatum->value <1 || perdatum->value >SEL_VEC_MAX ) goto bad; +/* indexes an nprim-sized array in security_get_permissions() */ +if (perdatum->value > s->nprim) + goto bad; rc =str_read (&key,GFP_KERNEL , fp, len);if (rc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 12/83 selinux: require a classs permission values to cover its permission count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit b98a8ac50775540f3804397ed08f61ef9910bcab ]
security_get_permissions() sizes an array by the class's permissions.nprim and fills it at value - 1, from the inherited common's permission table and then the class's own. A value no permission defines leaves a NULL that sel_make_perm_files() passes to d_alloc_name(), an oops inside sel_write_load() that strands selinux_state.policy_mutex and leaves every later load in uninterruptible sleep; two permissions sharing a value overwrite the first kstrdup(). Bounding each value by nprim catches neither, and neither would a count: the symbol table is keyed on the permission name, so duplicates pass.
Track the values each permission table claims and require them to cover exactly what its count declares, rejecting a count no value can reach. Conforming policies are unaffected.
--- security/selinux/ss/policydb.c | 51 ++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-)
security/selinux/ss/policydb.c +46 -5
@@ -1139,7 +1139,18 @@ int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len)return 0 ; } -static int perm_read (struct policydb *p,struct symtab *s,struct policy_file *fp) +/* +* Bitmap of the permission values a symtab has claimed. Values are 1-based +* and bounded by SEL_VEC_MAX, the width of an access vector, so the whole set +* fits in a u32 and the callers reject an nprim past that width. +*/ +static u32 perm_claimed_mask (u32 nprim) +{ +return nprim ?U32_MAX >> (SEL_VEC_MAX - nprim) :0 ; +} + +static int perm_read (struct policydb *p,struct symtab *s, +struct policy_file *fp,u32 *claimed) {char *key =NULL ;struct perm_datum *perdatum;
@@ -1163,6 +1174,10 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f/* indexes an nprim-sized array in security_get_permissions() */ if (perdatum->value > s->nprim) goto bad; +/* two permissions cannot share one slot of that array */ +if (*claimed & (1U << (perdatum->value -1 ))) + goto bad; + *claimed |=1U << (perdatum->value -1 ); rc =str_read (&key,GFP_KERNEL , fp, len);if (rc)
@@ -1183,7 +1198,7 @@ static int common_read(struct policydb *p, struct symtab *s, struct policy_filechar *key =NULL ;struct common_datum *comdatum;__le32 buf[4 ]; -u32 i, len, nel; +u32 i, len, nel, claimed =0 ;int rc; comdatum =kzalloc (sizeof (*comdatum),GFP_KERNEL );
@@ -1205,17 +1220,28 @@ static int common_read(struct policydb *p, struct symtab *s, struct policy_fileif (rc) goto bad; comdatum->permissions.nprim =le32_to_cpu (buf[2 ]); +/* no permission value can reach a slot past SEL_VEC_MAX */ + rc = -EINVAL ; +if (comdatum->permissions.nprim >SEL_VEC_MAX ) + goto bad; rc =str_read (&key,GFP_KERNEL , fp, len);if (rc) goto bad;for (i =0 ; i < nel; i++) { - rc =perm_read (p, &comdatum->permissions, fp); + rc =perm_read (p, &comdatum->permissions, fp, &claimed);if (rc) goto bad; } + rc = -EINVAL ; +if (claimed !=perm_claimed_mask (comdatum->permissions.nprim)) { +pr_err ("SELinux: common %s does not define every permission it declares\n" , + key); + goto bad; + } +hash_eval (&comdatum->permissions.table,"common_permissions" , key); rc =symtab_insert (s, key, comdatum);
@@ -1351,7 +1377,7 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *char *key =NULL ;struct class_datum *cladatum;__le32 buf[6 ]; -u32 i, len, len2, ncons, nel, val; +u32 i, len, len2, ncons, nel, val, claimed =0 , inherited =0 ;int rc; cladatum =kzalloc (sizeof (*cladatum),GFP_KERNEL );
@@ -1379,6 +1405,10 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *if (rc) goto bad; cladatum->permissions.nprim =le32_to_cpu (buf[3 ]); +/* no permission value can reach a slot past SEL_VEC_MAX */ + rc = -EINVAL ; +if (cladatum->permissions.nprim >SEL_VEC_MAX ) + goto bad; ncons =le32_to_cpu (buf[5 ]);
@@ -1413,11 +1443,22 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file * } }for (i =0 ; i < nel; i++) { - rc =perm_read (p, &cladatum->permissions, fp); + rc =perm_read (p, &cladatum->permissions, fp, &claimed);if (rc) goto bad; } +/* the class's own permissions must claim the slots the common leaves */ +if (cladatum->comdatum) + inherited = cladatum->comdatum->permissions.nprim; + rc = -EINVAL ; +if (claimed != (perm_claimed_mask (cladatum->permissions.nprim) & + ~perm_claimed_mask (inherited))) { +pr_err ("SELinux: class %s does not define every permission it declares\n" , + key); + goto bad; + } +hash_eval (&cladatum->permissions.table,"class_permissions" , key); rc =read_cons_helper (p, &cladatum->constraints, ncons,0 , fp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 13/83 ASoC: nau8821: Cancel delayed work on component remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Ciocaltea <[email protected]>
[ Upstream commit dbd3fd05cddfdeec1e49b0a66269881c09eebd17 ]
Attempting to unload the driver while a jack detection work is pending would likely crash the kernel when it is eventually scheduled for execution:
[ 1984.896308] BUG: unable to handle page fault for address: ffffffffc10c2a20 [...] [ 1984.896388] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 [ 1984.896396] Workqueue: events nau8821_jdet_work [snd_soc_nau8821] [ 1984.896414] RIP: 0010:__mutex_lock+0x9f/0x11d0 [...] [ 1984.896504] Call Trace: [ 1984.896511] <TASK> [ 1984.896524] ? snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] [ 1984.896572] ? snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] [ 1984.896596] snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] [ 1984.896622] nau8821_jdet_work+0xeb/0x1e0 [snd_soc_nau8821] [ 1984.896636] process_one_work+0x211/0x590 [ 1984.896649] ? srso_return_thunk+0x5/0x5f [ 1984.896670] worker_thread+0x1cd/0x3a0
Cancel unscheduled jdet_work or wait for its execution to finish before the component driver gets removed.
--- sound/soc/codecs/nau8821.c | 9 +++++++++ 1 file changed, 9 insertions(+)
sound/soc/codecs/nau8821.c +9 -0
@@ -1269,6 +1269,14 @@ static int nau8821_component_probe(struct snd_soc_component *component)return 0 ; } +static void nau8821_component_remove (struct snd_soc_component *component) +{ +struct nau8821 *nau8821 =snd_soc_component_get_drvdata (component); + +if (nau8821->jdet_active) +cancel_delayed_work_sync (&nau8821->jdet_work); +}; +/** * nau8821_calc_fll_param - Calculate FLL parameters. * @fll_in: external clock provided to codec.
@@ -1627,6 +1635,7 @@ static int __maybe_unused nau8821_resume(struct snd_soc_component *component)static const struct snd_soc_component_driver nau8821_component_driver = { .probe = nau8821_component_probe, + .remove = nau8821_component_remove, .set_sysclk = nau8821_set_sysclk, .set_pll = nau8821_set_fll, .set_bias_level = nau8821_set_bias_level,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 14/83 bpf: Fix use-after-free in offloaded map/prog info fill
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit a0c584fc18056709c8e047a82a6045d6c209f4ce ]
When querying info for an offloaded BPF map or program, bpf_map_offload_info_fill_ns() and bpf_prog_offload_info_fill_ns() obtain the network namespace with get_net(dev_net(offmap->netdev)). However, the associated netdev's netns may be racing with teardown during netns destruction. If the netns refcount has already reached 0, get_net() performs a refcount_t increment on 0, triggering:
refcount_t: addition on 0; use-after-free.
Although rtnl_lock and bpf_devs_lock ensure the netdev pointer remains valid, they cannot prevent the netns refcount from reaching zero.
Fix this by using maybe_get_net() instead of get_net(). maybe_get_net() uses refcount_inc_not_zero() and returns NULL if the refcount is already zero, which causes ns_get_path_cb() to fail and the caller to return -ENOENT -- the correct behavior when the netns is being destroyed.
--- kernel/bpf/offload.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
kernel/bpf/offload.c +4 -6
@@ -445,9 +445,8 @@ static struct ns_common *bpf_prog_offload_info_fill_ns(void *private_data)if (aux->offload) { args->info->ifindex = aux->offload->netdev->ifindex; - net =dev_net (aux->offload->netdev); -get_net (net); - ns = &net->ns; + net =maybe_get_net (dev_net (aux->offload->netdev)); + ns = net ? &net->ns :NULL ; }else { args->info->ifindex =0 ; ns =NULL ;
@@ -657,9 +656,8 @@ static struct ns_common *bpf_map_offload_info_fill_ns(void *private_data)if (args->offmap->netdev) { args->info->ifindex = args->offmap->netdev->ifindex; - net =dev_net (args->offmap->netdev); -get_net (net); - ns = &net->ns; + net =maybe_get_net (dev_net (args->offmap->netdev)); + ns = net ? &net->ns :NULL ; }else { args->info->ifindex =0 ; ns =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 15/83 riscv: Fix register corruption from uninitialized cregs on error
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Neuling <[email protected]>
[ Upstream commit 6ebcbb53fc9bc30843054ed99fd60b8e542628f4 ]
compat_riscv_gpr_set() calls cregs_to_regs() unconditionally, even when user_regset_copyin() fails. Since cregs is an uninitialized stack variable, a copyin failure causes uninitialized stack data to be written into the target task's pt_regs, corrupting its register state and potentially leaking kernel stack contents.
compat_restore_sigcontext() has the same issue: it calls cregs_to_regs() even when __copy_from_user() fails, leading to the same corruption of the signal-returning task's register state on error.
Only call cregs_to_regs() when the user copy succeeds.
--- arch/riscv/kernel/compat_signal.c | 2 ++ arch/riscv/kernel/ptrace.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
arch/riscv/kernel/compat_signal.c +2 -0
@@ -107,6 +107,8 @@ static long compat_restore_sigcontext(struct pt_regs *regs,/* sc_regs is structured the same as the start of pt_regs */ err =__copy_from_user (&cregs, &sc->sc_regs,sizeof (sc->sc_regs)); +if (unlikely (err)) +return err;cregs_to_regs (&cregs, regs);
arch/riscv/kernel/ptrace.c +2 -2
@@ -372,8 +372,8 @@ static int compat_riscv_gpr_set(struct task_struct *target,struct compat_user_regs_struct cregs; ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, &cregs,0 ,-1 ); - -cregs_to_regs (&cregs,task_pt_regs (target)); +if (!ret) +cregs_to_regs (&cregs,task_pt_regs (target));return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 16/83 ASoC: nau8821: Cancel pending work before suspend
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Ciocaltea <[email protected]>
[ Upstream commit 7786b10688ac0ebeaff655923cbb2c7d34a98995 ]
A jack detection work that is unscheduled or in progress while executing the suspend handler could trigger a race condition.
Ensure state consistency by cancelling any pending work or wait for its execution to complete before processing the suspend. Since driver (re)enables both insert and eject interrupts on resume, there is no risk to miss the related jack events. Therefore, flush_delayed_work() is not required here.
--- sound/soc/codecs/nau8821.c | 4 ++++ 1 file changed, 4 insertions(+)
sound/soc/codecs/nau8821.c +4 -0
@@ -1611,6 +1611,10 @@ static int __maybe_unused nau8821_suspend(struct snd_soc_component *component)if (nau8821->irq)disable_irq (nau8821->irq); + +if (nau8821->jdet_active) +cancel_delayed_work_sync (&nau8821->jdet_work); +snd_soc_component_force_bias_level (component,SND_SOC_BIAS_OFF );/* Power down codec power; don't support button wakeup */ snd_soc_component_disable_pin (component,"MICBIAS" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 17/83 selinux: switch two allocations to use kzalloc_objs()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <[email protected]>
[ Upstream commit cf6a513f1937581eb012a217b29817e025a1a0ef ]
These were the only two allocations in the policy loading logic that were not already using kzalloc_objs() for the policy data structures. Fix these to be consistent with the rest and to protect against ill-formed policy.
--- security/selinux/ss/conditional.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
security/selinux/ss/conditional.c +3 -4
@@ -165,7 +165,7 @@ void cond_policydb_destroy(struct policydb *p)int cond_init_bool_indexes (struct policydb *p) {kfree (p->bool_val_to_struct); - p->bool_val_to_struct =kmalloc_array ( + p->bool_val_to_struct =kcalloc ( p->p_bools.nprim,sizeof (*p->bool_val_to_struct),GFP_KERNEL );if (!p->bool_val_to_struct)return -ENOMEM ;
@@ -706,9 +706,8 @@ static int duplicate_policydb_bools(struct policydb *newdb,struct cond_bool_datum **cond_bool_array;int rc; - cond_bool_array =kmalloc_array (orig->p_bools.nprim, -sizeof (*orig->bool_val_to_struct), -GFP_KERNEL ); + cond_bool_array =kcalloc (orig->p_bools.nprim, +sizeof (*orig->bool_val_to_struct),GFP_KERNEL );if (!cond_bool_array)return -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 18/83 veth: fix OOB txq access in veth_poll() with asymmetric queue counts
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesper Dangaard Brouer <[email protected]>
[ Upstream commit 08f566e8f83bb70f04ad5aba5be352c490a01c8a ]
XDP redirect into a veth device (via bpf_redirect()) calls veth_xdp_xmit(), which enqueues frames into the peer's ptr_ring using
smp_processor_id() % peer->real_num_rx_queues
as the ring index. With an asymmetric veth pair where the peer has fewer TX queues than RX queues, that index can exceed peer->real_num_tx_queues.
veth_poll() then resolves peer_txq for the ring via:
peer_txq = peer_dev ? netdev_get_tx_queue(peer_dev, queue_idx) : NULL;
where queue_idx = rq->xdp_rxq.queue_index. When queue_idx exceeds peer_dev->real_num_tx_queues this is an out-of-bounds (OOB) access into the peer's netdev_queue array, triggering DEBUG_NET_WARN_ON_ONCE in netdev_get_tx_queue().
The normal ndo_start_xmit path is not affected: the stack clamps skb->queue_mapping via netdev_cap_txqueue() before invoking ndo_start_xmit, so rxq in veth_xmit() never exceeds real_num_tx_queues.
Fix veth_poll() by clamping: only dereference peer_txq when queue_idx is within bounds, otherwise set it to NULL. The out-of-range rings are fed exclusively via XDP redirect (veth_xdp_xmit), never via ndo_start_xmit (veth_xmit), so the peer txq was never stopped and there is nothing to wake; NULL is the correct fallback.
--- drivers/net/veth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/veth.c +2 -1
@@ -978,7 +978,8 @@ static int veth_poll(struct napi_struct *napi, int budget)/* NAPI functions as RCU section */ peer_dev =rcu_dereference_check (priv->peer,rcu_read_lock_bh_held ()); - peer_txq = peer_dev ?netdev_get_tx_queue (peer_dev, queue_idx) :NULL ; + peer_txq = (peer_dev && queue_idx < peer_dev->real_num_tx_queues) ? +netdev_get_tx_queue (peer_dev, queue_idx) :NULL ;xdp_set_return_frame_no_direct (); done =veth_xdp_rcv (rq, budget, &bq, &stats);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 19/83 powerpc/hv-gpci: fix preempt count leak in sysfs show paths
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit dbc30a57bd8e026995e9fa8e8c31cffd18542c01 ]
Four sysfs show() callbacks in hv-gpci take get_cpu_var(hv_gpci_reqb) (which calls preempt_disable()) but only call the matching put_cpu_var() on the error path under the 'out:' label. Every successful read leaks one preempt_disable():
processor_bus_topology_show()
processor_config_show()
affinity_domain_via_virtual_processor_show()
affinity_domain_via_domain_show()
(affinity_domain_via_partition_show() was already correct.)
On a CONFIG_PREEMPT=y kernel, repeated reads raise preempt_count and eventually return to userspace with preemption still disabled. The next user-mode page fault then hits faulthandler_disabled() == 1, gets forced to SIGSEGV, and the resulting coredump trips 'BUG: scheduling while atomic' in call_usermodehelper_exec -> wait_for_completion_state -> schedule:
BUG: scheduling while atomic: <task>/<pid>/0x00000004 ... __schedule_bug+0x6c/0x90 __schedule+0x58c/0x13a0 schedule+0x48/0x1a0 schedule_timeout+0x104/0x170 wait_for_completion_state+0x16c/0x330 call_usermodehelper_exec+0x254/0x2d0 vfs_coredump+0x1050/0x2590 get_signal+0xb9c/0xc80 do_notify_resume+0xf8/0x470
Add an out_success label that calls put_cpu_var() before returning the byte count, mirroring affinity_domain_via_partition_show().
--- arch/powerpc/perf/hv-gpci.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
arch/powerpc/perf/hv-gpci.c +16 -8
@@ -210,7 +210,7 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att 0, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out;
@@ -244,12 +244,14 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att starting_index, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out; } +out_success: +put_cpu_var (hv_gpci_reqb);return n; out:
@@ -278,7 +280,7 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute 0, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out;
@@ -312,12 +314,14 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute starting_index, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out; } +out_success: +put_cpu_var (hv_gpci_reqb);return n; out:
@@ -346,7 +350,7 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, 0, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out;
@@ -382,12 +386,14 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, starting_index, secondary_index, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out; } +out_success: +put_cpu_var (hv_gpci_reqb);return n; out:
@@ -416,7 +422,7 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device 0, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out;
@@ -448,12 +454,14 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device starting_index, 0, buf, &n, arg);if (!ret) -return n; + goto out_success;if (ret !=H_PARAMETER ) goto out; } +out_success: +put_cpu_var (hv_gpci_reqb);return n; out:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 20/83 io_uring/futex: only mark private futex waits as inflight
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
commit 4d327bbd1cd2485783553b6b2b401aa475f90dd0 upstream.
Inflight tracking of futex wait requests exists to ensure that do_exit() -> io_uring_files_cancel() cancels them before the mm goes away, as a private futex wait depends on the mm private futex hash staying alive for the duration of the request.
Shared futexes have no such dependency. A FLAGS_SHARED request always resolves to either an inode based key or an mm-shared key, both of which fail futex_key_is_private() and hence always hash into the global futex hash, whose lifetime isn't tied to the mm.
Only mark vectored futex waits as inflight if the futex is private.
--- io_uring/futex.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
io_uring/futex.c +13 -4
@@ -149,14 +149,16 @@ int io_futex_prep(struct io_kiocb *req,int io_futex_wait_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe) { + struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);int ret; ret =io_futex_prep (req, sqe);if (unlikely (ret))return ret; -/* Mark as inflight, so file exit cancelation will find it */ -io_req_track_inflight (req); +/* inflight tracking only needed for mm private hash */ +if (!(iof->futex_flags &FLAGS_SHARED )) +io_req_track_inflight (req);return 0 ; }
@@ -179,6 +181,7 @@ int io_futexv_prep(struct io_kiocb *req, { struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);struct futex_vector *futexv; +unsigned int i;int ret;/* No flags or mask supported for waitv */
@@ -202,8 +205,14 @@ int io_futexv_prep(struct io_kiocb *req,return ret; } -/* Mark as inflight, so file exit cancelation will find it */ -io_req_track_inflight (req); +/* inflight tracking only needed for mm private hash */ +for (i =0 ; i < iof->futex_nr; i++) { +if (!(futexv[i].w.flags &FLAGS_SHARED )) { +io_req_track_inflight (req); +break ; + } + } + iof->futexv_owned =0 ; iof->futexv_unqueued =0 ; req->flags |=REQ_F_ASYNC_DATA ;
Greg Kroah-Hartman
maintainerPATCH 21/83 io_uring: simplify IORING_SETUP_DEFER_TASKRUN && !SQPOLL check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Caleb Sander Mateos <[email protected]>
[ Upstream commit 7cb3a68376da0bc0afab8157223cb479c97de9ff ]
io_uring_sanitise_params() already rejects flags that include both IORING_SETUP_SQPOLL and IORING_SETUP_DEFER_TASKRUN. So it's unnecessary to check IORING_SETUP_SQPOLL in io_uring_create() when IORING_SETUP_DEFER_TASKRUN has already been checked. Drop the !(ctx->flags & IORING_SETUP_SQPOLL) check for the task_complete case.
Stable-dep-of: cd305ee3633a ("io_uring: defer eventfd signaling when queued from a wakeup handler")
--- io_uring/io_uring.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
io_uring/io_uring.c +1 -2
@@ -3867,8 +3867,7 @@ static __cold int io_uring_create(unsignstatic_branch_deferred_inc (&io_key_has_sqarray);if ((ctx->flags &IORING_SETUP_DEFER_TASKRUN ) && - !(ctx->flags &IORING_SETUP_IOPOLL ) && - !(ctx->flags &IORING_SETUP_SQPOLL )) + !(ctx->flags &IORING_SETUP_IOPOLL )) ctx->task_complete = true;if (ctx->task_complete || (ctx->flags &IORING_SETUP_IOPOLL ))
Greg Kroah-Hartman
maintainerPATCH 22/83 io_uring/rsrc: improve regbuf iov validation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov <[email protected]>
[ Upstream commit 2e02f9efdbc6c73544e315b7eb85e55a59776b6f ]
Deduplicate io_buffer_validate() calls by moving the checks into io_sqe_buffer_register(). Now we also don't need special handling in io_buffer_validate() passing through buffer removal requests. I also was using it as a cleanup before some other changes.
Stable-dep-of: cd305ee3633a ("io_uring: defer eventfd signaling when queued from a wakeup handler")
--- io_uring/rsrc.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-)
io_uring/rsrc.c +10 -21
@@ -94,20 +94,6 @@ int io_validate_user_buf_range(u64 uaddrreturn 0 ; } -static int io_buffer_validate (struct iovec *iov) -{ -/* -* Don't impose further limits on the size and buffer -* constraints here, we'll -EINVAL later when IO is -* submitted if they are wrong. -*/ -if (!iov->iov_base) -return iov->iov_len ? -EFAULT :0 ; - -return io_validate_user_buf_range ((unsigned long )iov->iov_base, - iov->iov_len); -} -static void io_release_ubuf (void *priv) {struct io_mapped_ubuf *imu = priv;
@@ -317,9 +303,6 @@ static int __io_sqe_buffers_update(struc err = -EFAULT ;break ; } - err =io_buffer_validate (iov); -if (err) -break ; node =io_sqe_buffer_register (ctx, iov, &last_hpage);if (IS_ERR (node)) { err =PTR_ERR (node);
@@ -788,8 +771,17 @@ static struct io_rsrc_node *io_sqe_buffestruct io_imu_folio_data data;bool coalesced = false; -if (!iov->iov_base) +if (!iov->iov_base) { +if (iov->iov_len) +return ERR_PTR (-EFAULT ); +/* remove the buffer without installing a new one */ return NULL ; + } + + ret =io_validate_user_buf_range ((unsigned long )iov->iov_base, + iov->iov_len); +if (ret) +return ERR_PTR (ret); node =io_rsrc_node_alloc (ctx,IORING_RSRC_BUFFER );if (!node)
@@ -895,9 +887,6 @@ int io_sqe_buffers_register(struct io_ri ret =PTR_ERR (iov);break ; } - ret =io_buffer_validate (iov); -if (ret) -break ;if (ctx->compat) arg +=sizeof (struct compat_iovec );else
Greg Kroah-Hartman
maintainerPATCH 23/83 io_uring: defer eventfd signaling when queued from a wakeup handler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
[ Upstream commit cd305ee3633a45fcf5f3a5d83f99f3cb77d87b6e ]
io_req_local_work_add() signals the CQ ring eventfd inline when it is the one to push the first entry onto ->work_list. For DEFER_TASKRUN rings that add is frequently done from a waitqueue wakeup handler, where an arbitrary waitqueue lock is held.
eventfd_signal_mask() only refuses to recurse when current->in_eventfd is set, but that bit is set by eventfd_signal_mask() itself. If the wake chain starts somewhere else, signal goes out inline and can feed back into epoll.
Add IOU_F_TWQ_IN_WAKE, set it on the task_work add done from the three waitqueue callbacks, and use it to force io_eventfd_signal() down the existing call_rcu_hurry() deferral instead of signaling inline.
--- include/linux/io_uring_types.h | 8 ++++++++ io_uring/eventfd.c | 8 ++++---- io_uring/eventfd.h | 2 +- io_uring/futex.c | 4 ++-- io_uring/io_uring.c | 4 ++-- io_uring/poll.c | 23 ++++++++++++----------- io_uring/waitid.c | 2 +- 7 files changed, 30 insertions(+), 21 deletions(-)
include/linux/io_uring_types.h +8 -0
@@ -17,6 +17,14 @@ enum {* It's also ignored unless IORING_SETUP_DEFER_TASKRUN is set. */ IOU_F_TWQ_LAZY_WAKE =1 , + +/* +* Set when task_work is queued from a waitqueue wakeup handler, where +* an arbitrary provider waitqueue lock is held. Signaling the CQ ring +* eventfd inline from there can recurse back into that lock through +* epoll, so the eventfd signal must be deferred. +*/ + IOU_F_TWQ_IN_WAKE = 2, }; enum io_uring_cmd_flags {
io_uring/eventfd.c +4 -4
@@ -50,9 +50,9 @@ static void io_eventfd_do_signal(struct/* * Returns true if the caller should put the ev_fd reference, false if not. */ -static bool __io_eventfd_signal (struct io_ev_fd *ev_fd) +static bool __io_eventfd_signal (struct io_ev_fd *ev_fd,bool defer) { -if (eventfd_signal_allowed ()) { +if (!defer &&eventfd_signal_allowed ()) {eventfd_signal_mask (ev_fd->cq_ev_fd,EPOLL_URING_WAKE );return true; }
@@ -72,7 +72,7 @@ static bool io_eventfd_trigger(struct ioreturn !ev_fd->eventfd_async ||io_wq_current_is_worker (); } -void io_eventfd_signal (struct io_ring_ctx *ctx,bool cqe_event) +void io_eventfd_signal (struct io_ring_ctx *ctx,bool cqe_event,bool defer) {bool skip = false;struct io_ev_fd *ev_fd;
@@ -112,7 +112,7 @@ void io_eventfd_signal(struct io_ring_ctspin_unlock (&ctx->completion_lock); } -if (skip ||__io_eventfd_signal (ev_fd)) +if (skip ||__io_eventfd_signal (ev_fd, defer))io_eventfd_put (ev_fd); }
io_uring/eventfd.h +1 -1
@@ -4,4 +4,4 @@ int io_eventfd_register(struct io_ring_c unsigned int eventfd_async);int io_eventfd_unregister (struct io_ring_ctx *ctx); -void io_eventfd_signal (struct io_ring_ctx *ctx,bool cqe_event); +void io_eventfd_signal (struct io_ring_ctx *ctx,bool cqe_event,bool defer);
io_uring/futex.c +2 -2
@@ -174,7 +174,7 @@ static void io_futex_wakev_fn(struct wakio_req_set_res (req,0 ,0 ); req->io_task_work.func = io_futexv_complete; -io_req_task_work_add (req); +__io_req_task_work_add (req,IOU_F_TWQ_IN_WAKE ); }int io_futexv_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe)
@@ -230,7 +230,7 @@ static void io_futex_wake_fn(struct wakeio_req_set_res (req,0 ,0 ); req->io_task_work.func = io_futex_complete; -io_req_task_work_add (req); +__io_req_task_work_add (req,IOU_F_TWQ_IN_WAKE ); }int io_futexv_wait (struct io_kiocb *req,unsigned int issue_flags)
io_uring/io_uring.c +2 -2
@@ -578,7 +578,7 @@ void __io_commit_cqring_flush(struct io_if (ctx->off_timeout_used)io_flush_timeouts (ctx);if (ctx->has_evfd) -io_eventfd_signal (ctx, true); +io_eventfd_signal (ctx, true, false); }static inline void __io_cq_lock (struct io_ring_ctx *ctx)
@@ -1312,7 +1312,7 @@ static void io_req_local_work_add(structif (!head) {io_ctx_mark_taskrun (ctx);if (ctx->has_evfd) -io_eventfd_signal (ctx, false); +io_eventfd_signal (ctx, false, flags &IOU_F_TWQ_IN_WAKE ); } nr_wait =atomic_read (&ctx->cq_wait_nr);
io_uring/poll.c +12 -11
@@ -190,9 +190,9 @@ enum { IOU_POLL_REQUEUE = 4, }; -static void __io_poll_execute (struct io_kiocb *req,int mask) +static void __io_poll_execute (struct io_kiocb *req,int mask,unsigned tw_flags) { -unsigned flags =0 ; +unsigned flags = tw_flags;io_req_set_res (req, mask,0 ); req->io_task_work.func = io_poll_task_func;
@@ -200,14 +200,15 @@ static void __io_poll_execute(struct io_trace_io_uring_task_add (req, mask);if (!(req->flags &REQ_F_POLL_NO_LAZY )) - flags =IOU_F_TWQ_LAZY_WAKE ; + flags |=IOU_F_TWQ_LAZY_WAKE ;__io_req_task_work_add (req, flags); } -static inline void io_poll_execute (struct io_kiocb *req,int res) +static inline void io_poll_execute (struct io_kiocb *req,int res, +unsigned tw_flags) {if (io_poll_get_ownership (req)) -__io_poll_execute (req, res); +__io_poll_execute (req, res, tw_flags); }/*
@@ -323,7 +324,7 @@ void io_poll_task_func(struct io_kiocb *if (ret ==IOU_POLL_NO_ACTION ) {return ; }else if (ret ==IOU_POLL_REQUEUE ) { -__io_poll_execute (req,0 ); +__io_poll_execute (req,0 ,0 );return ; }io_poll_remove_entries (req);
@@ -362,7 +363,7 @@ static void io_poll_cancel_req(struct io {io_poll_mark_cancelled (req);/* kick tw, which should complete the request */ -io_poll_execute (req,0 ); +io_poll_execute (req,0 ,0 ); }#define IO_ASYNC_POLL_COMMON (EPOLLONESHOT | EPOLLPRI)
@@ -371,7 +372,7 @@ static __cold int io_pollfree_wake(struc {io_poll_mark_cancelled (req);/* we have to kick tw in case it's not already */ -io_poll_execute (req,0 ); +io_poll_execute (req,0 ,IOU_F_TWQ_IN_WAKE );/* * If the waitqueue is being freed early but someone is already
@@ -426,7 +427,7 @@ static int io_poll_wake(struct wait_queuelse req->flags &= ~REQ_F_SINGLE_POLL ; } -__io_poll_execute (req, mask); +__io_poll_execute (req, mask,IOU_F_TWQ_IN_WAKE ); }return 1 ; }
@@ -614,7 +615,7 @@ static int __io_arm_poll_handler(structif (mask && (poll->events &EPOLLET ) &&io_poll_can_finish_inline (req, ipt)) { -__io_poll_execute (req, mask); +__io_poll_execute (req, mask,0 );return 0 ; }io_napi_add (req);
@@ -625,7 +626,7 @@ static int __io_arm_poll_handler(struct* poll was waken up, queue up a tw, it'll deal with it. */ if (atomic_cmpxchg (&req->poll_refs,1 ,0 ) !=1 ) -__io_poll_execute (req,0 ); +__io_poll_execute (req,0 ,0 ); }return 0 ; }
io_uring/waitid.c +1 -1
@@ -237,7 +237,7 @@ static int io_waitid_wait(struct wait_qureturn 1 ; req->io_task_work.func = io_waitid_cb; -io_req_task_work_add (req); +__io_req_task_work_add (req,IOU_F_TWQ_IN_WAKE );return 1 ; }
Greg Kroah-Hartman
maintainerPATCH 24/83 HID: magicmouse: prevent unbounded recursion in magicmouse_raw_event()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Villaseñor Montfort <[email protected]>
[ Upstream commit db8d634128d2ba88d79c0b601e983ebe14bb0519 ]
magicmouse_raw_event() handles DOUBLE_REPORT_ID (0xf7) packets, which pack two touch reports into one, by splitting the packet and calling itself on each half. The only guard against runaway recursion is a "size < 1" check, which stops zero-sized calls but does not bound the recursion depth.
A malicious HID device that matches this driver can send a report starting with DOUBLE_REPORT_ID and filled with the sequence [0xf7, 0x00]. Each level consumes two bytes and recurses on the remainder, so an incoming report of up to HID_MAX_BUFFER_SIZE (16 KiB) drives roughly 8000 nested calls. That easily exhausts the 16 KiB kernel stack, leading to a stack overflow: a panic with CONFIG_VMAP_STACK, or memory corruption without it.
A double report only ever wraps two normal reports; it is never legitimately nested. Refuse to re-enter the DOUBLE_REPORT_ID case from a recursive call so the recursion depth is bounded to two, while all valid packets keep being parsed exactly as before.
--- drivers/hid/hid-magicmouse.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
drivers/hid/hid-magicmouse.c +20 -5
@@ -383,8 +383,8 @@ static void magicmouse_emit_touch(struct } } -static int magicmouse_raw_event (struct hid_device *hdev, -struct hid_report *report,u8 *data,int size) +static int __magicmouse_raw_event (struct hid_device *hdev, +struct hid_report *report,u8 *data,int size,bool nested) {struct magicmouse_sc *msc =hid_get_drvdata (hdev);struct input_dev *input = msc->input;
@@ -495,6 +495,15 @@ static int magicmouse_raw_event(struct h* packet. */ +/* +* A double report only ever wraps two normal reports, so it is +* never nested. Refuse to recurse a second time; otherwise a +* malicious device could chain DOUBLE_REPORT_ID packets to drive +* unbounded recursion and overflow the kernel stack. +*/ +if (nested) +return 0 ; +/* Ensure that we have at least 2 elements (report type and size) */ if (size <2 )return 0 ;
@@ -506,9 +515,9 @@ static int magicmouse_raw_event(struct hreturn 0 ; } -magicmouse_raw_event (hdev, report, data +2 , data[1 ]); -magicmouse_raw_event (hdev, report, data +2 + data[1 ], - size -2 - data[1 ]); +__magicmouse_raw_event (hdev, report, data +2 , data[1 ], true); +__magicmouse_raw_event (hdev, report, data +2 + data[1 ], + size -2 - data[1 ], true);return 0 ;default :return 0 ;
@@ -534,6 +543,12 @@ static int magicmouse_raw_event(struct hreturn 1 ; } +static int magicmouse_raw_event (struct hid_device *hdev, +struct hid_report *report,u8 *data,int size) +{ +return __magicmouse_raw_event (hdev, report, data, size, false); +} +static int magicmouse_event (struct hid_device *hdev,struct hid_field *field,struct hid_usage *usage,__s32 value) {
Greg Kroah-Hartman
maintainerPATCH 25/83 HID: asus: simplify RGB init sequence
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Antheas Kapenekakis <[email protected]>
[ Upstream commit 56d1b33e644cca1bedffbc73d28778ed4ae30f64 ]
Currently, RGB initialization forks depending on whether a device is NKEY. However, in reality both initialization forks are the same, other than the NKEY initialization initializing the LED_REPORT_ID1, LED_REPORT_ID2 endpoints, and the non-NKEY initialization having a functionality check which is skipped for the NKEY path.
Therefore, merge the if blocks, gate the ID1/ID2 initializations behind the NKEY quirk instead, and introduce the functionality check for NKEY devices (it is supported by them).
There should be no functional change with this patch.
Stable-dep-of: 02bf61dfb44f ("HID: asus: fix missing hid_is_usb() check")
--- drivers/hid/hid-asus.c | 52 ++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 30 deletions(-)
drivers/hid/hid-asus.c +22 -30
@@ -638,13 +638,20 @@ static int asus_kbd_register_leds(structunsigned char kbd_func;int ret; -if (drvdata->quirks &QUIRK_ROG_NKEY_KEYBOARD ) { -/* Initialize keyboard */ - ret =asus_kbd_init (hdev,FEATURE_KBD_REPORT_ID ); -if (ret <0 ) -return ret; + ret =asus_kbd_init (hdev,FEATURE_KBD_REPORT_ID ); +if (ret <0 ) +return ret; + +/* Get keyboard functions */ + ret =asus_kbd_get_functions (hdev, &kbd_func,FEATURE_KBD_REPORT_ID ); +if (ret <0 ) +return ret; + +/* Check for backlight support */ +if (!(kbd_func &SUPPORT_KBD_BACKLIGHT )) +return -ENODEV ; -/* The LED endpoint is initialised in two HID */ +if (drvdata->quirks &QUIRK_ROG_NKEY_KEYBOARD ) { ret =asus_kbd_init (hdev,FEATURE_KBD_LED_REPORT_ID1 );if (ret <0 )return ret;
@@ -652,34 +659,19 @@ static int asus_kbd_register_leds(struct ret =asus_kbd_init (hdev,FEATURE_KBD_LED_REPORT_ID2 );if (ret <0 )return ret; + } -if (dmi_match (DMI_PRODUCT_FAMILY ,"ProArt P16" )) { - ret =asus_kbd_disable_oobe (hdev); -if (ret <0 ) -return ret; - } - -if (drvdata->quirks &QUIRK_ROG_ALLY_XPAD ) { - intf =to_usb_interface (hdev->dev.parent); - udev =interface_to_usbdev (intf); -validate_mcu_fw_version (hdev, -le16_to_cpu (udev->descriptor.idProduct)); - } - - }else { -/* Initialize keyboard */ - ret =asus_kbd_init (hdev,FEATURE_KBD_REPORT_ID ); -if (ret <0 ) -return ret; - -/* Get keyboard functions */ - ret =asus_kbd_get_functions (hdev, &kbd_func,FEATURE_KBD_REPORT_ID ); +if (dmi_match (DMI_PRODUCT_FAMILY ,"ProArt P16" )) { + ret =asus_kbd_disable_oobe (hdev);if (ret <0 )return ret; + } -/* Check for backlight support */ -if (!(kbd_func &SUPPORT_KBD_BACKLIGHT )) -return -ENODEV ; +if (drvdata->quirks &QUIRK_ROG_ALLY_XPAD ) { + intf =to_usb_interface (hdev->dev.parent); + udev =interface_to_usbdev (intf); +validate_mcu_fw_version (hdev, +le16_to_cpu (udev->descriptor.idProduct)); } drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
Greg Kroah-Hartman
maintainerPATCH 26/83 HID: asus: fix missing hid_is_usb() check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit 02bf61dfb44f17ec187d1da1a82495951bbd12df ]
to_usb_interface() can only be used on a hid_device whose parent is really USB; uhid can create devices that identify as being on BUS_USB, but don't actually have a USB parent.
Fix the use of to_usb_interface() without a hid_is_usb() check.
I have verified that it is currently possible to trigger a kernel splat due to this bug in an ASAN build, and that this commit fixes the issue.
--- drivers/hid/hid-asus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/hid-asus.c +1 -1
@@ -667,7 +667,7 @@ static int asus_kbd_register_leds(structreturn ret; } -if (drvdata->quirks &QUIRK_ROG_ALLY_XPAD ) { +if ((drvdata->quirks &QUIRK_ROG_ALLY_XPAD ) &&hid_is_usb (hdev)) { intf =to_usb_interface (hdev->dev.parent); udev =interface_to_usbdev (intf); validate_mcu_fw_version(hdev,
Greg Kroah-Hartman
maintainerPATCH 27/83 HID: ft260: validate i2c input report length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Zaidman <[email protected]>
[ Upstream commit 80c4bbb2b38513e9c3d84805fa61a0ee16d79c45 ]
Add two checks to ft260_raw_event() to prevent out-of-bounds reads from malicious or malfunctioning devices:
First, reject reports shorter than the 2-byte header (report ID + length fields). Without this, even accessing xfer->length on a 1-byte report is an OOB read.
Second, validate xfer->length against the actual data capacity of the received HID report. Each I2C data report ID (0xD0 through 0xDE) defines a different report size in the HID descriptor, so the available payload varies per report. A corrupted length field could cause memcpy to read beyond the report buffer.
Stable-dep-of: bf3e39df3a39 ("HID: ft260: fix stack-use-after-return write in I2C read race")
--- drivers/hid/hid-ft260.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
drivers/hid/hid-ft260.c +14 -2
@@ -1068,10 +1068,22 @@ static int ft260_raw_event(struct hid_destruct ft260_device *dev =hid_get_drvdata (hdev);struct ft260_i2c_input_report *xfer = (void *)data; +if (size < offsetof(struct ft260_i2c_input_report , data)) { +hid_err (hdev,"short report %d\n" , size); +return -1 ; + } +if (xfer->report >=FT260_I2C_REPORT_MIN && xfer->report <=FT260_I2C_REPORT_MAX ) { -ft260_dbg ("i2c resp: rep %#02x len %d\n" , xfer->report, - xfer->length); +ft260_dbg ("i2c resp: rep %#02x len %d size %d\n" , + xfer->report, xfer->length, size); + +if (xfer->length > size - + offsetof(struct ft260_i2c_input_report , data)) { +hid_err (hdev,"report %#02x: length %d exceeds HID report size\n" , + xfer->report, xfer->length); +return -1 ; + }if ((dev->read_buf ==NULL ) || (xfer->length > dev->read_len - dev->read_idx)) {
Greg Kroah-Hartman
maintainerPATCH 28/83 HID: ft260: fix stack-use-after-return write in I2C read race
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raman Varabets <[email protected]>
[ Upstream commit bf3e39df3a397fd82967a31d17c4e02c7feab221 ]
ft260_i2c_read() points dev->read_buf at a caller-supplied buffer (often an on-stack variable), arms a completion and waits up to five seconds for the device to return the data. The HID input callback ft260_raw_event() runs in the input/IRQ path, independent of the dev->lock mutex held by the read path, and copies the device-supplied payload into dev->read_buf after a plain NULL check.
These two paths share read_buf, read_idx and read_len with no serialization. If the device delays its response until the read times out, ft260_i2c_read() resets the controller, clears read_buf and returns, unwinding the stack frame the buffer lived in. A response that arrives at that moment lets ft260_raw_event() pass the NULL check and then memcpy() the device-controlled payload into the now-freed stack location, a bounded but attacker-influenced stack-use-after-return write triggerable by malicious or malfunctioning hardware.
Add a dedicated spinlock that serializes every access to read_buf, read_idx and read_len. ft260_raw_event() now holds it across the NULL check, the memcpy and the index update, while the read path takes it when arming and when clearing the buffer, so the teardown can no longer slip between the check and the copy.
--- drivers/hid/hid-ft260.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
drivers/hid/hid-ft260.c +24 -1
@@ -240,6 +240,8 @@ struct ft260_device {struct mutex lock;u8 write_buf[FT260_REPORT_MAX_LENGTH ];unsigned long need_wakeup_at; +/* Protects read_buf, read_idx and read_len against ft260_raw_event() */ +spinlock_t read_lock;u8 *read_buf;u16 read_idx;u16 read_len;
@@ -501,6 +503,7 @@ static int ft260_i2c_read(struct ft260_dint timeout, ret =0 ;struct ft260_i2c_read_request_report rep;struct hid_device *hdev = dev->hdev; +unsigned long irqflags;u8 bus_busy =0 ;if ((flag &FT260_FLAG_START_REPEATED ) ==FT260_FLAG_START_REPEATED )
@@ -526,9 +529,11 @@ static int ft260_i2c_read(struct ft260_dreinit_completion (&dev->wait); +spin_lock_irqsave (&dev->read_lock, irqflags); dev->read_idx =0 ; dev->read_buf = data; dev->read_len = rd_len; +spin_unlock_irqrestore (&dev->read_lock, irqflags); ret =ft260_hid_output_report (hdev, (u8 *)&rep,sizeof (rep));if (ret <0 ) {
@@ -543,7 +548,9 @@ static int ft260_i2c_read(struct ft260_d goto ft260_i2c_read_exit; } +spin_lock_irqsave (&dev->read_lock, irqflags); dev->read_buf =NULL ; +spin_unlock_irqrestore (&dev->read_lock, irqflags);if (flag &FT260_FLAG_STOP ) bus_busy =FT260_I2C_STATUS_BUS_BUSY ;
@@ -562,7 +569,9 @@ static int ft260_i2c_read(struct ft260_d }while (len >0 ); ft260_i2c_read_exit: +spin_lock_irqsave (&dev->read_lock, irqflags); dev->read_buf =NULL ; +spin_unlock_irqrestore (&dev->read_lock, irqflags);return ret; }
@@ -1018,6 +1027,7 @@ static int ft260_probe(struct hid_device "FT260 usb-i2c bridge");mutex_init (&dev->lock); +spin_lock_init (&dev->read_lock);init_completion (&dev->wait); ret =ft260_xfer_status (dev,FT260_I2C_STATUS_BUS_BUSY );
@@ -1067,6 +1077,7 @@ static int ft260_raw_event(struct hid_de {struct ft260_device *dev =hid_get_drvdata (hdev);struct ft260_i2c_input_report *xfer = (void *)data; +unsigned long irqflags;if (size < offsetof(struct ft260_i2c_input_report , data)) {hid_err (hdev,"short report %d\n" , size);
@@ -1075,6 +1086,8 @@ static int ft260_raw_event(struct hid_deif (xfer->report >=FT260_I2C_REPORT_MIN && xfer->report <=FT260_I2C_REPORT_MAX ) { +bool complete_read; +ft260_dbg ("i2c resp: rep %#02x len %d size %d\n" , xfer->report, xfer->length, size);
@@ -1085,8 +1098,15 @@ static int ft260_raw_event(struct hid_dereturn -1 ; } +/* +* Hold read_lock so a timed-out ft260_i2c_read() cannot +* clear read_buf between the NULL check and the memcpy. +*/ +spin_lock_irqsave (&dev->read_lock, irqflags); +if ((dev->read_buf ==NULL ) || (xfer->length > dev->read_len - dev->read_idx)) { +spin_unlock_irqrestore (&dev->read_lock, irqflags);hid_err (hdev,"unexpected report %#02x, length %d\n" , xfer->report, xfer->length);return -1 ;
@@ -1095,8 +1115,11 @@ static int ft260_raw_event(struct hid_dememcpy (&dev->read_buf[dev->read_idx], &xfer->data, xfer->length); dev->read_idx += xfer->length; + complete_read = dev->read_idx == dev->read_len; + +spin_unlock_irqrestore (&dev->read_lock, irqflags); -if (dev->read_idx == dev->read_len) +if (complete_read)complete (&dev->wait); }else {
Greg Kroah-Hartman
maintainerPATCH 29/83 ksmbd: harden file lifetime during session teardown
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
commit a42896bebfcc287ed1e61d820a888e33b1eb80ce upstream.
__close_file_table_ids() is the per-session teardown that closes every fp belonging to a session (or to one tree connect on that session) by walking the session's volatile-id idr. The current loop has three related problems on busy or racing workloads:
* Sleeping under ft->lock. The session-teardown skip callback, session_fd_check(), already sleeps in ksmbd_vfs_copy_durable_owner() -> kstrdup(GFP_KERNEL) and down_write(&fp->f_ci->m_lock) (a rw_semaphore). Running the callback inside write_lock(&ft->lock) trips CONFIG_DEBUG_ATOMIC_SLEEP / CONFIG_PROVE_LOCKING on a durable-fd workload.
* Refcount accounting blind to f_state. The unconditional atomic_dec_and_test(&fp->refcount) does not distinguish FP_INITED (idr-owned reference still intact) from FP_CLOSED (an earlier ksmbd_close_fd() already consumed the idr-owned reference while leaving fp in the idr because a holder kept refcount non-zero). When the latter races with teardown the same path over-decrements into a holder reference and ksmbd_fd_put() later UAFs that holder.
* FP_NEW window. Between __open_id() publishing fp into the session idr and ksmbd_update_fstate(..., FP_INITED) committing the transition at the end of smb2_open(), an fp is in FP_NEW and an intervening teardown that takes a transient reference and unpublishes the volatile id leaves the original idr-owned reference orphaned -- the opener is unaware that fp has been unpublished, returns success to the client, and the fp leaks at refcount = 1.
Refactor __close_file_table_ids() to take a transient reference on fp and unpublish fp from the session idr *under ft->lock* before calling skip() outside the lock. A transient ref protects lifetime but not concurrent field mutation, so the idr_remove() is what keeps __ksmbd_lookup_fd() through this session's idr from granting a new ksmbd_fp_get() reference to an fp whose fp->conn / fp->tcon / fp->volatile_id / op->conn / lock_list links are about to be rewritten by session_fd_check(). Durable reconnect is unaffected because it reaches fp through the global durable table (ksmbd_lookup_durable_fd -> global_ft).
Decide n_to_drop together with any FP_INITED -> FP_CLOSED transition under ft->lock so teardown and ksmbd_close_fd() never both consume the idr-owned reference. See ksmbd_mark_fp_closed() for the per-state accounting. For the FP_NEW path to be safe, the opener has to learn that fp was unpublished: ksmbd_update_fstate() now returns -ENOENT when an FP_NEW -> FP_INITED transition finds f_state already advanced or the volatile id cleared (both committed by teardown under ft->lock); smb2_open() propagates that as STATUS_OBJECT_NAME_INVALID and drops the original reference via ksmbd_fd_put().
The list removal cannot be left for a deferred final putter because fp->volatile_id has already been cleared and __ksmbd_remove_fd() will intentionally skip both idr_remove() and list_del_init(). Move the m_fp_list unlink in __ksmbd_remove_fd() above the volatile-id check so that an FP_NEW fp that happened to be added to m_fp_list (smb2_open() adds fp->node before ksmbd_update_fstate() runs) is still cleaned up on the deferred putter path; list_del_init() on an empty node is a no-op and remains safe for fps that were never added.
Add a defensive guard in session_fd_check() that refuses non-FP_INITED fps so that even if a teardown reaches an FP_NEW fp it falls into the close branch (where the n_to_drop = 1 accounting keeps the opener's reference alive) instead of the durable-preserve branch (which mutates fp->conn / fp->tcon).
Validation on a debug kernel additionally built with CONFIG_DEBUG_LIST and CONFIG_DEBUG_OBJECTS_WORK used a same-session two-tcon workload (open/write storm on one tcon, 50 tree disconnects on the other) and reported no list-corruption, work_struct ODEBUG, sleep-in-atomic, lockdep or kmemleak reports. Reverting only the __close_file_table_ids() hunk while keeping a forced-is_reconnectable() harness produced the expected sleep-in-atomic at vfs_cache.c:1095, confirming the ft->lock-out-of-sleepable-skip discipline.
KASAN-enabled direct SMB2 coverage with durable handles enabled exercised ksmbd_close_tree_conn_fds(), ksmbd_close_session_fds(), the FP_NEW failure path, tree_conn_fd_check(), and a non-zero session_fd_check() durable-preserve return. This produced no KASAN, DEBUG_LIST, ODEBUG, or WARNING reports.
--- fs/smb/server/smb2pdu.c | 6 + fs/smb/server/vfs_cache.c | 179 ++++++++++++++++++++++++++++++++++++++++------ fs/smb/server/vfs_cache.h | 4 - 3 files changed, 164 insertions(+), 25 deletions(-)
fs/smb/server/smb2pdu.c +4 -2
@@ -3765,8 +3765,10 @@ err_out1: err_out2:if (!rc) { -ksmbd_update_fstate (&work->sess->file_table, fp,FP_INITED ); - rc =ksmbd_iov_pin_rsp (work, (void *)rsp, iov_len); + rc =ksmbd_update_fstate (&work->sess->file_table, fp, +FP_INITED ); +if (!rc) + rc =ksmbd_iov_pin_rsp (work, (void *)rsp, iov_len); }if (rc) {if (rc == -EINVAL )
fs/smb/server/vfs_cache.c +158 -21
252 lines not on this page · raw message
fs/smb/server/vfs_cache.h +2 -2
@@ -175,8 +175,8 @@ int ksmbd_close_inode_fds(struct ksmbd_wint ksmbd_init_global_file_table (void );void ksmbd_free_global_file_table (void );void ksmbd_set_fd_limit (unsigned long limit); -void ksmbd_update_fstate (struct ksmbd_file_table *ft,struct ksmbd_file *fp, -unsigned int state); +int ksmbd_update_fstate (struct ksmbd_file_table *ft,struct ksmbd_file *fp, +unsigned int state);bool ksmbd_vfs_compare_durable_owner (struct ksmbd_file *fp,struct ksmbd_user *user);
Greg Kroah-Hartman
maintainerPATCH 30/83 fpga: dfl: fme: add error handling
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit b5ba63e247075087ab8a6a087622c762dc4172e9 upstream.
Add error handling to devm_kasprint in fme_perf_pmu_register().
--- drivers/fpga/dfl-fme-perf.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/fpga/dfl-fme-perf.c +2 -0
@@ -925,6 +925,8 @@ static int fme_perf_pmu_register(structPERF_PMU_CAP_NO_EXCLUDE ; name =devm_kasprintf (priv->dev,GFP_KERNEL ,"dfl_fme%d" , pdev->id); +if (!name) +return -ENOMEM ; ret =perf_pmu_register (pmu, name,-1 );if (ret)
Greg Kroah-Hartman
maintainerPATCH 31/83 accessibility: speakup: unregister tty ldisc on later init failures
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit a76acbaec9b8fd74413646984d2e3626d0543e39 upstream.
The ldisc registration is intentionally non-fatal, since some synth drivers do not use tty/ldisc. However, once speakup_init() continues past the registration point and later fails, the init unwind path should mirror speakup_exit() and call spk_ttyio_unregister_ldisc().
Add the missing unregister call to the error path after synth_release(), matching the normal module exit cleanup order.
--- drivers/accessibility/speakup/main.c | 1 + 1 file changed, 1 insertion(+)
drivers/accessibility/speakup/main.c +1 -0
@@ -2444,6 +2444,7 @@ error_kbdnotifier:mutex_lock (&spk_mutex);synth_release ();mutex_unlock (&spk_mutex); +spk_ttyio_unregister_ldisc ();speakup_kobj_exit (); error_kobjects:
Greg Kroah-Hartman
maintainerPATCH 32/83 usb: xhci: Handle bogus TRB pointers in Missed Service Error events
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Pecio <[email protected]>
commit 3d9eeb336131bc5a174367c384fa00c15c8744fd upstream.
xHCI 1.0 allowed these pointers to be zero. Some Intel chipsets from the era usually set it to zero, but sometimes (apparently) to the next TRB after the one referenced by the previous transfer event on the endpoint.
Usually that's indeed the missed TD, but it may also be the last TRB of a two-TRB TD already completed with Short Packet on its first TRB. Then the driver skips all pending TDs, failing to find a match.
When handling Missed Service Error, scan TD list twice and only really skip TDs in the second pass if the first pass found a match. This won't catch bogus pointers to wrong TDs, but such a bug would be practically impossible to detect automatically and isn't known to exist.
--- drivers/usb/host/xhci-ring.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/usb/host/xhci-ring.c +16 -2
@@ -2653,6 +2653,17 @@ static bool xhci_spurious_success_tx_eve } } +static struct xhci_td *find_td_by_dma (struct xhci_ring *ep_ring,dma_addr_t dma) +{ +struct xhci_td *td; + +if (dma) +list_for_each_entry (td, &ep_ring->td_list, td_list) +if (trb_in_td (td, dma)) +return td; +return NULL ; +} +/* * If this function returns an error condition, it means it got a Transfer * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -2845,8 +2856,11 @@ static int handle_tx_event(struct xhci_hxhci_dequeue_td (xhci, td, ep_ring, td->status); } -/* If the TRB pointer is NULL, missed TDs will be skipped on the next event */ -if (trb_comp_code ==COMP_MISSED_SERVICE_ERROR && !ep_trb_dma) +/* +* We don't know how many TDs were missed when ep_trb_dma is zero (as permitted by +* xHCI 1.0) or bogus. Bail out leaving ep->skip set, next event will sort it out. +*/ +if (trb_comp_code ==COMP_MISSED_SERVICE_ERROR && !find_td_by_dma (ep_ring, ep_trb_dma))return 0 ;if (list_empty (&ep_ring->td_list)) {
Greg Kroah-Hartman
maintainerPATCH 33/83 usb: xhci: Handle USB3 port events when there is one roothub
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Semih Baskan <[email protected]>
commit 3e91ec3e7d80a327fb558207613c80415d3bf756 upstream.
handle_port_status() drops every USB3 port event when xhci->shared_hcd is NULL. The check dates from a time when xhci-plat always created a shared hcd, so a NULL one could only mean the hcd had been removed.
Since commit 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") that is no longer true. A controller whose USB2 root hub has no ports gets a single roothub, the USB3 rhub is served by the main hcd, and shared_hcd stays NULL for the lifetime of the device. Every SuperSpeed port event is then thrown away as bogus behind a debug message, so devices never enumerate even though the port sees the device and its change bits stay set:
0x006a1203 Powered Connected Enabled Link:U0 PortSpeed:4
Change: CSC WRC PRC PLC
Broadcom Northstar is such a controller. USB3 works there up to 5.15 and stops working from 5.19 onwards.
Ask xhci_get_usb3_hcd() instead. It returns the shared hcd when there is one, the main hcd when the USB2 root hub has no ports, and NULL once the shared hcd is gone, which keeps the original meaning of the check.
Tested on an Asus RT-N18U (BCM47081), which has a single roothub. Before the change nothing enumerates on the USB3 port; after it SuperSpeed devices enumerate normally over repeated connect and disconnect cycles, the change bits shown above clear, and USB2 is unaffected on both ports.
--- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/host/xhci-ring.c +1 -1
@@ -2026,7 +2026,7 @@ static void handle_port_status(struct xh vdev = xhci->devs[port->slot_id];/* We might get interrupts after shared_hcd is removed */ -if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd ==NULL ) { +if (port->rhub == &xhci->usb3_rhub &&xhci_get_usb3_hcd (xhci) ==NULL ) {xhci_dbg (xhci,"ignore port event for removed USB3 hcd\n" ); bogus_port_status = true; goto cleanup;
Greg Kroah-Hartman
maintainerPATCH 34/83 xhci: dbgtty: Fix unregister on tty_register_driver() failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lucas De Marchi <[email protected]>
commit a916fa66a43e10f63198b6ce978badffc678821a upstream.
If tty_register_driver() fails, it drops the reference, but fails to set the global dbc_tty_driver to NULL, causing the unregister to be called again when module exits.
On module unload dbc_tty_exit() only gates its cleanup on the driver pointer being non-NULL, so it operates on the already-freed driver:
module_init(xhci_hcd_init)
xhci_hcd_init()
xhci_dbc_init() [return value ignored]
dbc_tty_init()
tty_register_driver() fails
tty_driver_kref_put() -> driver freed
(dbc_tty_driver left dangling)
...
module_exit(xhci_hcd_fini)
xhci_hcd_fini()
xhci_dbc_exit()
dbc_tty_exit()
if (dbc_tty_driver) -> true (dangling)
tty_unregister_driver() -> use-after-free--- drivers/usb/host/xhci-dbgtty.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/xhci-dbgtty.c +1 -0
@@ -651,6 +651,7 @@ int dbc_tty_init(void)pr_err ("Can't register dbc tty driver\n" );tty_driver_kref_put (dbc_tty_driver);idr_destroy (&dbc_tty_minors); + dbc_tty_driver =NULL ; }return ret;
Greg Kroah-Hartman
maintainerPATCH 35/83 xhci: dbgtty: Fix unregister on tty_alloc_driver() failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lucas De Marchi <[email protected]>
commit 25b8dfc13495a6c1cf4abacc8ef20196c7f20e5c upstream.
Make sure to set dbc_tty_driver to NULL to match the check in dbc_tty_exit(). For that, make detached error handling path common to the other branch in the same function.
--- drivers/usb/host/xhci-dbgtty.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/usb/host/xhci-dbgtty.c +11 -5
@@ -628,8 +628,8 @@ int dbc_tty_init(void) dbc_tty_driver =tty_alloc_driver (64 ,TTY_DRIVER_REAL_RAW |TTY_DRIVER_DYNAMIC_DEV );if (IS_ERR (dbc_tty_driver)) { -idr_destroy (&dbc_tty_minors); -return PTR_ERR (dbc_tty_driver); + ret =PTR_ERR (dbc_tty_driver); + goto fail; } dbc_tty_driver->driver_name ="dbc_serial" ;
@@ -649,12 +649,18 @@ int dbc_tty_init(void) ret =tty_register_driver (dbc_tty_driver);if (ret) {pr_err ("Can't register dbc tty driver\n" ); -tty_driver_kref_put (dbc_tty_driver); -idr_destroy (&dbc_tty_minors); - dbc_tty_driver =NULL ; + goto fail_put; }return ret; + +fail_put: +tty_driver_kref_put (dbc_tty_driver); +fail: +idr_destroy (&dbc_tty_minors); + dbc_tty_driver =NULL ; + +return ret; }void dbc_tty_exit (void )
Greg Kroah-Hartman
maintainerPATCH 36/83 fuse: fix invalidate lock leak on setattr writeback failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
commit 9afeca0d569c9fc89d758fe7a9339d1e8afb1546 upstream.
fuse_do_setattr() takes filemap_invalidate_lock() for a DAX truncate (fault_blocked = true) and releases it at the out:/error: labels. But when a writeback flush is also needed, a write_inode_now() failure returns directly and leaks the lock, so any later fault or truncate on the file stalls on the stale rwsem.
For example, truncate(2) on a setuid file reaches fuse_do_setattr() with both ATTR_SIZE and ATTR_MODE set:
truncate(2)
└─ do_truncate()
├─ dentry_needs_remove_privs() # S_ISUID
└─ notify_change() # KILL_SUID -> ATTR_MODE
└─ fuse_setattr() # no killpriv:
│ # ia_valid |= ATTR_MODE
└─ fuse_do_setattr()
├─ filemap_invalidate_lock() # IS_DAX && is_truncate
└─ write_inode_now() # is_wb && ATTR_MODE
└─ if (err) # e.g. daemon -> -EIO
return err # <- lock leakedFix this by adding an unlock label that releases the lock before returning the error, and use it for the fuse_dax_break_layouts() failure path as well.
--- fs/fuse/dir.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
fs/fuse/dir.c +4 -5
@@ -1976,10 +1976,8 @@ int fuse_do_setattr(struct mnt_idmap *idfilemap_invalidate_lock (mapping); fault_blocked = true; err =fuse_dax_break_layouts (inode,0 ,-1 ); -if (err) { -filemap_invalidate_unlock (mapping); -return err; - } +if (err) + goto unlock; }if (attr->ia_valid &ATTR_OPEN ) {
@@ -2006,7 +2004,7 @@ int fuse_do_setattr(struct mnt_idmap *id ATTR_TIMES_SET)) { err =write_inode_now (inode, true);if (err) -return err; + goto unlock;fuse_set_nowrite (inode);fuse_release_nowrite (inode);
@@ -2114,6 +2112,7 @@ error:clear_bit (FUSE_I_SIZE_UNSTABLE , &fi->state); +unlock:if (fault_blocked)filemap_invalidate_unlock (mapping);return err;
Greg Kroah-Hartman
maintainerPATCH 37/83 fuse: fix invalidate lock leak on open O_TRUNC DAX failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
commit a927f1867e61b78f39f9da0bbba3c98c2ca151fe upstream.
fuse_open() takes filemap_invalidate_lock() for a DAX truncate (dax_truncate = true) and releases it before the out_inode_unlock label. But when fuse_dax_break_layouts() fails, the goto out_inode_unlock skips the unlock and leaks the rwsem, so any later fault or truncate on the file stalls on the stale lock.
fuse_dax_break_layouts() can fail with -ERESTARTSYS when a signal interrupts the wait for busy DAX pages to drain:
open("file", O_RDWR | O_TRUNC)
└─ fuse_open()
├─ filemap_invalidate_lock() # dax_truncate
└─ fuse_dax_break_layouts()
└─ dax_break_layout()
└─ wait_page_idle() # TASK_INTERRUPTIBLE
└─ fuse_wait_dax_page() # unlock, schedule, re-lock
└─ signal → -ERESTARTSYS
goto out_inode_unlock # <- lock leakedFix this by moving filemap_invalidate_unlock() below the label so that all error paths release the lock, and rename the label to out_unlock as it now covers more than just the inode lock.
--- fs/fuse/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/fuse/file.c +2 -2
@@ -268,7 +268,7 @@ static int fuse_open(struct inode *inodefilemap_invalidate_lock (inode->i_mapping); err =fuse_dax_break_layouts (inode,0 ,-1 );if (err) - goto out_inode_unlock; + goto out_unlock; }if (is_wb_truncate || dax_truncate)
@@ -292,9 +292,9 @@ static int fuse_open(struct inode *inodeelse if (!(ff->open_flags &FOPEN_KEEP_CACHE ))invalidate_inode_pages2 (inode->i_mapping); } +out_unlock:if (dax_truncate)filemap_invalidate_unlock (inode->i_mapping); -out_inode_unlock:if (is_wb_truncate || dax_truncate)inode_unlock (inode);
Greg Kroah-Hartman
maintainerPATCH 38/83 usb: usbtest: disable dynamic ID support
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
commit 00e2071f6d5621a5ddea311a5e6b143ae6e474af upstream.
The usbtest driver relies on the driver_info field of struct usb_device_id to point to a valid struct usbtest_info descriptor. This structure contains essential test configurations, such as endpoint addresses and test modes, which are required during probe.
When a user dynamically adds a new device ID via the sysfs new_id interface without specifying a reference device, the USB core initializes driver_info to 0 (NULL). When a matching device is subsequently probed, usbtest_probe() unconditionally casts driver_info to a struct usbtest_info pointer and dereferences it, leading to a NULL pointer dereference crash:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:usbtest_probe+0x3b9/0x1280 drivers/usb/misc/usbtest.c:2822
Because usbtest strictly requires pre-defined usbtest_info descriptors to function, dynamic ID binding via sysfs is fundamentally unsupported for this driver.
Fix this by setting .no_dynamic_id = 1 on usbtest_driver. This instructs the USB core to skip creating the new_id and remove_id sysfs interfaces for usbtest, preventing invalid dynamic ID entries from being created.
--- drivers/usb/misc/usbtest.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/misc/usbtest.c +1 -0
@@ -3054,6 +3054,7 @@ static struct usb_driver usbtest_driver .disconnect = usbtest_disconnect, .suspend = usbtest_suspend, .resume = usbtest_resume, + .no_dynamic_id = 1, };/*-------------------------------------------------------------------------*/
Greg Kroah-Hartman
maintainerPATCH 39/83 usb: gadget: f_tcm: keep port count until LUN teardown completes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit c39d0916da47d94909391876c9e5bd429ea7b1b9 upstream.
tcm_usbg_drop_nexus() permits session removal once tpg_port_count reaches zero. However, usbg_port_unlink() currently decrements that count from the fabric_pre_unlink() callback, before core_dev_del_lun() waits for active se_lun references to drain.
If removal of the last LUN races a nexus removal, the latter can observe a zero port count and call target_remove_session(). This frees sess_cmd_map while an in-flight struct usbg_cmd, including its work item, can still be accessed.
Overlapping the last-LUN unlink with nexus removal reproduces this lifetime violation as a DEBUG_OBJECTS "free active" warning for usbg_cmd_work, followed by a target-core BUG/Oops.
The generic target-core unlink path has no callback after core_dev_del_lun() completes. Add an optional fabric_post_unlink() callback and use it for the f_tcm port count. The count now remains nonzero until core_dev_del_lun() has finished draining active LUN references, preventing nexus removal from freeing the session during command completion.
--- drivers/target/target_core_fabric_configfs.c | 8 ++++++++ drivers/usb/gadget/function/f_tcm.c | 2 +- include/target/target_core_fabric.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-)
drivers/target/target_core_fabric_configfs.c +8 -0
@@ -690,6 +690,14 @@ static void target_fabric_port_unlink( }core_dev_del_lun (se_tpg, lun); + +if (tf->tf_ops->fabric_post_unlink) { +/* +* Allow fabrics to release state that must remain valid until +* core_dev_del_lun() has drained all active LUN references. +*/ + tf->tf_ops->fabric_post_unlink (se_tpg, lun); + } }static void target_fabric_port_release (struct config_item *item)
drivers/usb/gadget/function/f_tcm.c +1 -1
@@ -2023,7 +2023,7 @@ static const struct target_core_fabric_o .fabric_enable_tpg = usbg_enable_tpg, .fabric_drop_tpg = usbg_drop_tpg, .fabric_post_link = usbg_port_link, - .fabric_pre_unlink = usbg_port_unlink, + .fabric_post_unlink = usbg_port_unlink, .fabric_init_nodeacl = usbg_init_nodeacl, .tfc_wwn_attrs = usbg_wwn_attrs,
include/target/target_core_fabric.h +2 -0
@@ -95,6 +95,8 @@ struct target_core_fabric_ops { struct se_lun *);void (*fabric_pre_unlink)(struct se_portal_group *,struct se_lun *); +void (*fabric_post_unlink)(struct se_portal_group *se_tpg, +struct se_lun *lun);struct se_tpg_np *(*fabric_make_np)(struct se_portal_group *,struct config_group *,const char *);void (*fabric_drop_np)(struct se_tpg_np *);
Greg Kroah-Hartman
maintainerPATCH 40/83 KVM: SEV: Drop FOLL_WRITE for encrypted region registration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pankaj Gupta <[email protected]>
commit ee1a586dd1fa2f245b3b753a3e44d9263a49240b upstream.
When pinning SEV guest memory, drop FOLL_WRITE and rely on FOLL_LONGTERM to break CoW, as *KVM* doesn't actually to the memory using the GUP'd pages. Omitting FOLL_WRITE fixes a regression when using file-backed guest memory that was introduced when KVM (correctly) added FOLL_LONG (e.g. to ensure anonymous memory is migrated out of MIGRATE_CMA/ZONE_MOVABLE before a long term pin).
Unfortunately, as of commits:
8ac268436e6d ("mm/gup: disallow FOLL_LONGTERM GUP-nonfast writing to file-backed mappings") a6e79df92e4a ("mm/gup: disallow FOLL_LONGTERM GUP-fast writing to file-backed mappings")
GUP uses FOLL_LONGTERM as a canary of sorts to detect pins that are likely to be problematic, and disallows WRITE+LONGTERM pins for file-backed memory. As a result, backing SEV+ guests with file-backed memory, e.g. virtio-pmem, fails due to the disallowed FOLL_LONGTERM+FOLL_WRITE combination.
Note, in the past, FOLL_WRITE was required to trigger CoW unsharing, to prevent replacing the page in the (primary MMU's) page tables during a later write fault after already having pinned a (shared) page in MAP_PRIVATE mappings. FOLL_LONGTERM does that nowadays, even without FOLL_WRITE (see gup_must_unshare()).
--- arch/x86/kvm/svm/sev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/x86/kvm/svm/sev.c +5 -1
@@ -2727,8 +2727,12 @@ int sev_mem_enc_register_region(struct kif (!region)return -ENOMEM ; +/* +* Do NOT specify FOLL_WRITE, as KVM isn't using the pinned pages to +* write memory, and FOLL_LONGTERM itself triggers CoW unshare. +*/ region->pages =sev_pin_memory (kvm, range->addr, range->size, ®ion->npages, -FOLL_WRITE |FOLL_LONGTERM ); +FOLL_LONGTERM );if (IS_ERR (region->pages)) { ret =PTR_ERR (region->pages); goto e_free;
Greg Kroah-Hartman
maintainerPATCH 41/83 KVM: SEV: Track the GPA of the guest-controlled VMSA used for SNP guests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 42a39ad5d592aec87a70527a4e694f6210694482 upstream.
Track the GPA of the guest-provided VMSA used after AP_CREATION events when running SNP guests, instead of simply tracking whether or not the vCPU is using a guest-provided VMSA. KVM needs to know the GPA of the VMSA that's actively being used so that it can react to MMU invalidation events, i.e. so that KVM can drop the VMSA if its backing guest_memfd page is punched out of existence.
Opportunistically rename snp_vmsa_gpa to clarify that it tracks the pending VMSA GPA, whereas snp_guest_vmsa_gpa now tracks the in-use VMSA GPA.
Note! Take care to track the GPA, not the GFN, as VALID_PAGE() won't behave correctly if an invalid GFN is converted to a GPA for checking.
Note #2! Keep snp_has_guest_vmsa so that switching to a guest-provided VMSA is sticky, even if the guest-provided VMSA becomes invalid.
No functional change intended.
--- arch/x86/kvm/svm/sev.c | 14 +++++++++----- arch/x86/kvm/svm/svm.h | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-)
arch/x86/kvm/svm/sev.c +9 -5
@@ -4037,6 +4037,7 @@ static void sev_snp_init_protected_guest/* Clear use of the VMSA */ svm->vmcb->control.vmsa_pa =INVALID_PAGE ; + svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ;/* * When replacing the VMSA during SEV-SNP AP creation,
@@ -4044,11 +4045,11 @@ static void sev_snp_init_protected_guest*/ vmcb_mark_all_dirty (svm->vmcb); -if (!VALID_PAGE (svm->sev_es.snp_vmsa_gpa)) +if (!VALID_PAGE (svm->sev_es.snp_pending_vmsa_gpa))return ; - gfn =gpa_to_gfn (svm->sev_es.snp_vmsa_gpa); - svm->sev_es.snp_vmsa_gpa =INVALID_PAGE ; + gfn =gpa_to_gfn (svm->sev_es.snp_pending_vmsa_gpa); + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; slot =gfn_to_memslot (vcpu->kvm, gfn);if (!slot)
@@ -4073,6 +4074,7 @@ static void sev_snp_init_protected_guest svm->sev_es.snp_has_guest_vmsa = true;/* Use the new VMSA */ + svm->sev_es.snp_guest_vmsa_gpa =gfn_to_gpa (gfn); svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn);/* Mark the vCPU as runnable */
@@ -4139,10 +4141,10 @@ static int sev_snp_ap_creation(struct vcreturn -EINVAL ; } - target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2; + target_svm->sev_es.snp_pending_vmsa_gpa = svm->vmcb->control.exit_info_2;break ;case SVM_VMGEXIT_AP_DESTROY : - target_svm->sev_es.snp_vmsa_gpa =INVALID_PAGE ; + target_svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ;break ;default : vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n",
@@ -4731,6 +4733,8 @@ int sev_vcpu_create(struct kvm_vcpu *vcpreturn -ENOMEM ; svm->sev_es.vmsa =page_address (vmsa_page); + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; + svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ; vcpu->arch.guest_tsc_protected =snp_is_secure_tsc_enabled (vcpu->kvm);
arch/x86/kvm/svm/svm.h +2 -1
@@ -248,7 +248,8 @@ struct vcpu_sev_es_state {u64 ghcb_registered_gpa;struct mutex snp_vmsa_mutex;/* Used to handle concurrent updates of VMSA. */ -gpa_t snp_vmsa_gpa; +gpa_t snp_pending_vmsa_gpa; +gpa_t snp_guest_vmsa_gpa;bool snp_ap_waiting_for_reset;bool snp_has_guest_vmsa; };
Greg Kroah-Hartman
maintainerPATCH 42/83 KVM: SEV: Extract loading of guest-provided VMSA to a separate helper
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 0060569e4f18a7dee2dd8728595e909f19a23c24 upstream.
Extract the loading/retrieval of a guest-provided VMSA to a separate helper so that KVM can reuse the core logic when refreshing the VMSA after an MMU invalidation from guest_memfd.
No functional change intended.
--- arch/x86/kvm/svm/sev.c | 52 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 21 deletions(-)
arch/x86/kvm/svm/sev.c +31 -21
@@ -4013,29 +4013,17 @@ next_range:BUG (); } -/* -* Invoked as part of svm_vcpu_reset() processing of an init event. -*/ -static void sev_snp_init_protected_guest_state (struct kvm_vcpu *vcpu) +static void sev_snp_reload_vmsa (struct kvm_vcpu *vcpu,gpa_t gpa) {struct vcpu_svm *svm =to_svm (vcpu);struct kvm_memory_slot *slot; +gfn_t gfn =gpa_to_gfn (gpa);struct page *page;kvm_pfn_t pfn; -gfn_t gfn; - -guard (mutex)(&svm->sev_es.snp_vmsa_mutex); -if (!svm->sev_es.snp_ap_waiting_for_reset) -return ; - - svm->sev_es.snp_ap_waiting_for_reset = false; +lockdep_assert_held (&svm->sev_es.snp_vmsa_mutex); -/* Mark the vCPU as offline and not runnable */ - vcpu->arch.pv.pv_unhalted = false; -kvm_set_mp_state (vcpu,KVM_MP_STATE_HALTED ); - -/* Clear use of the VMSA */ +/* Clear use of the VMSA. */ svm->vmcb->control.vmsa_pa =INVALID_PAGE ; svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ;
@@ -4045,12 +4033,9 @@ static void sev_snp_init_protected_guest*/ vmcb_mark_all_dirty (svm->vmcb); -if (!VALID_PAGE (svm->sev_es.snp_pending_vmsa_gpa)) +if (!VALID_PAGE (gpa))return ; - gfn =gpa_to_gfn (svm->sev_es.snp_pending_vmsa_gpa); - svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; - slot =gfn_to_memslot (vcpu->kvm, gfn);if (!slot)return ;
@@ -4074,7 +4059,7 @@ static void sev_snp_init_protected_guest svm->sev_es.snp_has_guest_vmsa = true;/* Use the new VMSA */ - svm->sev_es.snp_guest_vmsa_gpa =gfn_to_gpa (gfn); + svm->sev_es.snp_guest_vmsa_gpa = gpa; svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn);/* Mark the vCPU as runnable */
@@ -4088,6 +4073,31 @@ static void sev_snp_init_protected_guestkvm_release_page_clean (page); } +/* +* Invoked as part of svm_vcpu_reset() processing of an init event. +*/ +static void sev_snp_init_protected_guest_state (struct kvm_vcpu *vcpu) +{ +struct vcpu_svm *svm =to_svm (vcpu); +gpa_t gpa; + +guard (mutex)(&svm->sev_es.snp_vmsa_mutex); + +if (!svm->sev_es.snp_ap_waiting_for_reset) +return ; + + svm->sev_es.snp_ap_waiting_for_reset = false; + +/* Mark the vCPU as offline and not runnable */ + vcpu->arch.pv.pv_unhalted = false; +kvm_set_mp_state (vcpu,KVM_MP_STATE_HALTED ); + + gpa = svm->sev_es.snp_pending_vmsa_gpa; + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; + +sev_snp_reload_vmsa (vcpu, gpa); +} +static int sev_snp_ap_creation (struct vcpu_svm *svm) {struct kvm_sev_info *sev =to_kvm_sev_info (svm->vcpu.kvm);
Greg Kroah-Hartman
maintainerPATCH 43/83 KVM: SEV: Mark vCPU RUNNABLE after AP_CREATE, even if VMSA is unusable
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 98ade8c48c28c227fe2e80e545ff0c57cd4712a3 upstream.
Always mark the vCPU as RUNNABLE after responding to AP_CREATE, even if the guest-specified VMSA is unusable, e.g. isn't backed by a memslot or doesn't have a backing guest_memfd page. If the VMSA is unusable, leaving the vCPU in a non-running state will effectively hang the vCPU instead of reporting an error to userspace. This will also allow retrying the VMSA load in the future, to fix a bug where KVM doesn't honor guest_memfd invalidation events, e.g. if AP_CREATION races with PUNCH_HOLE.
--- arch/x86/kvm/svm/sev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/sev.c +9 -3
@@ -4062,9 +4062,6 @@ static void sev_snp_reload_vmsa(struct k svm->sev_es.snp_guest_vmsa_gpa = gpa; svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn); -/* Mark the vCPU as runnable */ -kvm_set_mp_state (vcpu,KVM_MP_STATE_RUNNABLE ); -/* * gmem pages aren't currently migratable, but if this ever changes * then care should be taken to ensure svm->sev_es.vmsa is pinned
@@ -4096,6 +4093,15 @@ static void sev_snp_init_protected_guest svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ;sev_snp_reload_vmsa (vcpu, gpa); + +/* +* Mark the vCPU as runnable for CREATE requests, indicated by a valid +* VMSA GPA, even if installing the VMSA failed, so that KVM_RUN will +* fail instead of blocking indefinitely and hanging the vCPU, e.g. if +* the backing guest_memfd page is unavailable. +*/ +if (VALID_PAGE (gpa)) +kvm_set_mp_state (vcpu,KVM_MP_STATE_RUNNABLE ); }static int sev_snp_ap_creation (struct vcpu_svm *svm)
Greg Kroah-Hartman
maintainerPATCH 44/83 KVM: SEV: Wire up kvm_x86_ops.gmem_xxx() if and only if CONFIG_KVM_AMD_SEV=y
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 01a96ff30dde5127c37497f1e098e639e7ae152f upstream.
Wire up the SEV-SNP guest_memfd kvm_x86_ops hooks if and only if SEV is actually enabled, and drop the now-unnecessary stubs. Leaving the hooks NULL allows the static call infrastructure to elide the CALL+RET, and more importantly, referencing the hooks if and only if SEV support is enabled will allow conditionally definining the hooks using their corresponding HAVE_KVM_ARCH_GMEM_XXX Kconfig.
No functional change intended.
--- arch/x86/kvm/svm/svm.c | 8 ++++---- arch/x86/kvm/svm/svm.h | 10 ---------- 2 files changed, 4 insertions(+), 14 deletions(-)
arch/x86/kvm/svm/svm.c +4 -4
@@ -5262,6 +5262,10 @@ struct kvm_x86_ops svm_x86_ops __initdat .vm_copy_enc_context_from = sev_vm_copy_enc_context_from, .vm_move_enc_context_from = sev_vm_move_enc_context_from, + + .gmem_prepare = sev_gmem_prepare, + .gmem_invalidate = sev_gmem_invalidate, + .gmem_max_mapping_level = sev_gmem_max_mapping_level, #endif .check_emulate_instruction = svm_check_emulate_instruction,
@@ -5273,10 +5277,6 @@ struct kvm_x86_ops svm_x86_ops __initdat .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector, .vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons, .alloc_apic_backing_page = svm_alloc_apic_backing_page, - - .gmem_prepare = sev_gmem_prepare, - .gmem_invalidate = sev_gmem_invalidate, - .gmem_max_mapping_level = sev_gmem_max_mapping_level, };/*
arch/x86/kvm/svm/svm.h +0 -10
@@ -906,16 +906,6 @@ static inline int sev_cpu_init(struct svstatic inline int sev_dev_get_attr (u32 group,u64 attr,u64 *val) {return -ENXIO ; }#define max_sev_asid 0static inline void sev_handle_rmp_fault (struct kvm_vcpu *vcpu,gpa_t gpa,u64 error_code) {} -static inline int sev_gmem_prepare (struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order) -{ -return 0 ; -} -static inline void sev_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end) {} -static inline int sev_gmem_max_mapping_level (struct kvm *kvm,kvm_pfn_t pfn,bool is_private) -{ -return 0 ; -} -static inline struct vmcb_save_area *sev_decrypt_vmsa (struct kvm_vcpu *vcpu) {return NULL ;
Greg Kroah-Hartman
maintainerPATCH 45/83 tls: device: fix out-of-bounds write in tls_append_frag()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
commit b17cf742eaad70ae29ac558cefb3aa9bbeea03d4 upstream.
Found with syzkaller and a local syzbot instance running on top of a netdevsim TLS offload emulation; tls_device.c is otherwise only reachable on a machine with a NIC that implements the offload.
tls_push_data() only checks whether the open record still has room for another frag at the bottom of its loop, and the MSG_MORE early break skips that check. The record survives to the next syscall with the frag count it already had, and tls_append_frag() does not check either, so with TLS_TX_ZEROCOPY_RO every splice(SPLICE_F_MORE) of a byte or two adds a non-coalescing pipe page and num_frags walks off the end of tls_record_info.frags[MAX_SKB_FRAGS]. Once the record is pushed, tls_push_record() runs the same index over sg_tx_data[MAX_SKB_FRAGS] and the sg_set_page() writes land on the destruct_work that follows it, which the workqueue then calls.
The byte limit is fine because copy drops to 0 and the loop falls through to the same check; the frag count has no such feedback.
Push the record rather than keep a full one open, which is what a plain TCP socket does - tcp_sendmsg_locked() uses tcp_mark_push() and new_segment in both the copy and the MSG_SPLICE_PAGES paths, and tls_sw already sets full_record when the sk_msg ring fills up, MSG_MORE or not.
BUG: KASAN: slab-out-of-bounds in tls_append_frag ( net/tls/tls_device.c:269) Write of size 8 at addr ffff8881104d1530 by task tls_oob/450 CPU: 2 UID: 0 PID: 450 Comm: tls_oob Not tainted 7.2.0-rc7+ #329 PREEMPT Call Trace: <TASK> dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) print_report (mm/kasan/report.c:378 mm/kasan/report.c:482) kasan_report (mm/kasan/report.c:595) tls_append_frag (net/tls/tls_device.c:269) tls_push_data (net/tls/tls_device.c:518) tls_device_sendmsg (net/tls/tls_device.c:583) inet_sendmsg (net/ipv4/af_inet.c:865) sock_sendmsg (net/socket.c:775 net/socket.c:790 net/socket.c:813) splice_to_socket (fs/splice.c:884) do_splice (fs/splice.c:936 fs/splice.c:1349) __do_splice (fs/splice.c:1431) __x64_sys_splice (fs/splice.c:1634 fs/splice.c:1616) do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) </TASK>
and, once the record is pushed:
UBSAN: array-index-out-of-bounds in net/tls/tls_device.c:300:24 index 18 is out of range for type 'skb_frag_t [17]' UBSAN: array-index-out-of-bounds in net/tls/tls_device.c:301:41 index 18 is out of range for type 'scatterlist [17]' UBSAN: array-index-out-of-bounds in net/tls/tls_device.c:302:39 index 18 is out of range for type 'scatterlist [17]' UBSAN: array-index-out-of-bounds in net/tls/tls_device.c:307:38 index 26 is out of range for type 'scatterlist [17]'
kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
BUG: unable to handle page fault for address: ffffea000411a680 #PF: supervisor instruction fetch in kernel mode #PF: error_code(0x0011) - permissions violation Oops: Oops: 0011 [#1] SMP KASAN PTI Workqueue: ktls_device_destruct 0xffffea000411a680 RIP: 0010:0xffffea000411a680 Call Trace: <TASK> worker_thread (kernel/workqueue.c:3405 kernel/workqueue.c:3486) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:158) ret_from_fork_asm (arch/x86/entry/entry_64.S:245) </TASK>
--- net/tls/tls_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/tls/tls_device.c +2 -1
@@ -530,7 +530,8 @@ handle_error:if (!size) { last_record: tls_push_record_flags = flags; -if (flags &MSG_MORE ) { +if ((flags &MSG_MORE ) && + record->num_frags <MAX_SKB_FRAGS -1 ) { more = true;break ; }
Greg Kroah-Hartman
maintainerPATCH 46/83 gtp: serialize PDP context updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <[email protected]>
commit 498386b6d402737db1e2eeed4c385acbf0ef9e34 upstream.
PDP contexts can be deleted through GTP_CMD_DELPDP or while the GTP network device is being unregistered. The latter is serialized by RTNL, but the generic-netlink delete path only holds RCU.
Running both paths concurrently can therefore make both paths delete the same PDP context. The issue was found through static analysis and reproduced on a KASAN-enabled kernel by a simple two-thread program racing GTP_CMD_DELPDP against RTM_DELLINK:
Oops: general protection fault, probably for non-canonical address
KASAN: maybe wild-memory-access in range
[0xdead000000000120-0xdead000000000127]
RIP: gtp_genl_del_pdp+0x1c1/0x420 [gtp]
RBP: dead000000000122The second deletion dereferenced the poisoned hlist pprev pointer.
Serialize gtp_pdp_add(), gtp_genl_del_pdp(), and gtp_dellink() with a shared mutex. Keep the mutex held until the final use of a PDP context in the NEWPDP path, and keep the RCU read-side section around the complete PDP context use in the DELPDP path.
--- drivers/net/gtp.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/net/gtp.c +17 -4
@@ -12,6 +12,7 @@#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt#include <linux/module.h> +#include <linux/mutex.h> #include <linux/skbuff.h> #include <linux/udp.h> #include <linux/rculist.h>
@@ -108,6 +109,7 @@ struct gtp_net { };static u32 gtp_h_initval; +static DEFINE_MUTEX (gtp_pdp_lock);static struct genl_family gtp_genl_family;
@@ -151,7 +153,8 @@ static struct pdp_ctx *gtp0_pdp_find(str head = >p->tid_hash[gtp0_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af == family && pdp->gtp_version ==GTP_V0 && pdp->u.v0.tid == tid)
@@ -168,7 +171,8 @@ static struct pdp_ctx *gtp1_pdp_find(str head = >p->tid_hash[gtp1u_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af == family && pdp->gtp_version ==GTP_V1 && pdp->u.v1.i_tei == tid)
@@ -185,7 +189,8 @@ static struct pdp_ctx *ipv4_pdp_find(str head = >p->addr_hash[ipv4_hashfn (ms_addr) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_addr) { +hlist_for_each_entry_rcu (pdp, head, hlist_addr, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af ==AF_INET && pdp->ms.addr.s_addr == ms_addr)return pdp;
@@ -220,7 +225,8 @@ static struct pdp_ctx *ipv6_pdp_find(str head = >p->addr_hash[ipv6_hashfn (ms_addr) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_addr) { +hlist_for_each_entry_rcu (pdp, head, hlist_addr, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af ==AF_INET6 &&ipv6_pdp_addr_equal (&pdp->ms.addr6, ms_addr))return pdp;
@@ -1555,9 +1561,11 @@ static void gtp_dellink(struct net_devicstruct pdp_ctx *pctx;int i; +mutex_lock (>p_pdp_lock);for (i =0 ; i < gtp->hash_size; i++)hlist_for_each_entry_safe (pctx, next, >p->tid_hash[i], hlist_tid)pdp_context_delete (pctx); +mutex_unlock (>p_pdp_lock);list_del (>p->list);unregister_netdevice_queue (dev, head);
@@ -2053,6 +2061,7 @@ static int gtp_genl_new_pdp(struct sk_bu goto out_unlock; } +mutex_lock (>p_pdp_lock); pctx =gtp_pdp_add (gtp, sk, info);if (IS_ERR (pctx)) { err =PTR_ERR (pctx);
@@ -2060,6 +2069,7 @@ static int gtp_genl_new_pdp(struct sk_bugtp_tunnel_notify (pctx,GTP_CMD_NEWPDP ,GFP_KERNEL ); err =0 ; } +mutex_unlock (>p_pdp_lock); out_unlock:rtnl_unlock ();
@@ -2134,6 +2144,8 @@ static int gtp_genl_del_pdp(struct sk_buif (!info->attrs[GTPA_VERSION ])return -EINVAL ; +mutex_lock (>p_pdp_lock); +rcu_read_lock (); pctx =gtp_find_pdp (sock_net (skb->sk), info->attrs);
@@ -2154,6 +2166,7 @@ static int gtp_genl_del_pdp(struct sk_bu out_unlock:rcu_read_unlock (); +mutex_unlock (>p_pdp_lock);return err; }
Greg Kroah-Hartman
maintainerPATCH 47/83 x86/CPU/AMD: Carve out a Zen5 models range
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratik Vishwakarma <[email protected]>
commit 52075128273ace53e6254e37899a47d40d4baf45 upstream.
Family 0x1a, model 0xd0..0xd7 belongs to the Zen5 generation. Carve it out from the larger, Zen6 range where former doesn't belong.
[ bp: Rewrite commit message, add tags. ]
--- arch/x86/kernel/cpu/amd.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/kernel/cpu/amd.c +1 -0
@@ -513,6 +513,7 @@ static void bsp_init_amd(struct cpuinfo_ case 0x00 ... 0x2f: case 0x40 ... 0x4f: case 0x60 ... 0x7f: + case 0xd0 ... 0xd7:setup_force_cpu_cap (X86_FEATURE_ZEN5 );break ; case 0x50 ... 0x5f:
Greg Kroah-Hartman
maintainerPATCH 48/83 net/tcp: fix TCP-AO key deletion in VRFs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rastislav Szabo <[email protected]>
commit 94ad9e114a1c7b16ea418c1456ac3835e038ab3f upstream.
TCP-AO keys with TCP_AO_KEYF_IFINDEX store the VRF L3 interface index in l3index. tcp_ao_del_cmd() validates the supplied ifindex, but does not assign it to its local l3index before matching keys.
As a result, deleting a key scoped to a non-default VRF always fails with ENOENT because it is matched against l3index 0.
--- net/ipv4/tcp_ao.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/tcp_ao.c +3 -0
@@ -1854,6 +1854,9 @@ static int tcp_ao_del_cmd(struct sock *sif (cmd.ifindex && !(cmd.keyflags &TCP_AO_KEYF_IFINDEX ))return -EINVAL ; +if (cmd.keyflags &TCP_AO_KEYF_IFINDEX ) + l3index = cmd.ifindex; + ao_info =setsockopt_ao_info (sk);if (IS_ERR (ao_info))return PTR_ERR (ao_info);
Greg Kroah-Hartman
maintainerPATCH 49/83 tcp: fix AO info use-after-free in tcp_ao_connect_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <[email protected]>
commit ea30dc5267e367b8a5e1e06cc074f813bcbf18b2 upstream.
tcp_v4_connect() adds a SYN-SENT socket to the ehash before calling tcp_connect(). If TCP-AO is configured, tcp_connect() first verifies that a key matches the peer and the bound device's current L3 master. tcp_ao_connect_init() later resolves the L3 master again and removes keys which do not match it.
The socket lock does not stabilize the bound device's VRF membership. Detaching the device from its VRF between the initial validation and the L3-master calculation in tcp_ao_connect_init() can therefore make the validation succeed while initialization observes the default L3 domain and removes the only key. The subsequent AO lookup then fails, so the no-key path clears tp->ao_info and frees it directly.
The receive path can find the socket in the ehash and load tp->ao_info under RCU before acquiring the socket lock. A reader which loaded the old pointer can thus continue into tcp_inbound_ao_hash() after the direct free.
The issue was found during a static audit of TCP-AO object lifetime. An unprivileged reproducer in self-created user and network namespaces raced connect() with detaching a veth from its VRF while sending TCP-AO segments. It triggered the same KASAN report on two fresh boots:
BUG: KASAN: slab-use-after-free in tcp_inbound_ao_hash+0x585/0x19f0 Write of size 8 at addr ffff88800bf88128 by task tcp_ao_vrf_race/232 Call Trace: tcp_inbound_ao_hash+0x585/0x19f0 tcp_inbound_hash+0x677/0xa80 tcp_v4_rcv+0x1c3e/0x3ab0 Allocated by task 235: tcp_ao_alloc_info+0x43/0xf0 tcp_ao_add_cmd+0xdf7/0x13b0 do_tcp_setsockopt+0x168c/0x2640 Freed by task 235: kfree+0x1b8/0x550 tcp_connect+0x252/0x4f00 tcp_v4_connect+0x1114/0x1720
The bad address is 40 bytes inside the freed 128-byte object, matching the tcp_ao_info counters.key_not_found field. The two runs used 1000 attempts each, reached the no-key path 366 and 411 times, and produced one and two KASAN reports respectively. With this change, the same reproducer reached the no-key path 366 times in 1000 attempts without a KASAN report or oops.
Use tcp_ao_destroy_sock() for the no-key path. It unpublishes the AO info, updates the socket memory and static-key accounting, and defers the free until after an RCU grace period.
Also drop the WARN_ON_ONCE() and its stale comment. The VRF detach race makes the no-key state reachable during normal operation, so it is a handled condition rather than an impossible assertion. On panic_on_warn kernels the WARN would turn this handled race into a kernel panic.
--- net/ipv4/tcp_ao.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
net/ipv4/tcp_ao.c +1 -6
@@ -1147,12 +1147,7 @@ void tcp_ao_connect_init(struct sock *sk ao_info->lisn =htonl (tp->write_seq); ao_info->snd_sne =0 ; }else { -/* Can't happen: tcp_connect() verifies that there's -* at least one tcp-ao key that matches the remote peer. -*/ -WARN_ON_ONCE (1 ); -rcu_assign_pointer (tp->ao_info,NULL ); -kfree (ao_info); +tcp_ao_destroy_sock (sk, false); } }
Greg Kroah-Hartman
maintainerPATCH 50/83 net/tcp-ao: fix use-after-free of current_key on reconnect to another peer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit da4471557f279d0f56605158a625bb6e49ef7d41 upstream.
tcp_inbound_ao_hash() is called before bh_lock_sock_nested() is taken, with only rcu_read_lock() held. On the fast path for established sockets, if the rnext_keyid sent by the peer differs from current_key->sndid, the key the peer asked for is looked up and stored in current_key. The lookup is inside the RCU read side, but current_key outlives it.
When the socket is disconnected and connect() is called again for another peer, tcp_ao_connect_init() unlinks every key that does not match the new peer and frees it with call_rcu(). If current_key points at such a key, it is cleared to NULL.
The fast path reads sk_state only once on entry, so a softirq that got into it while the socket was still established can update current_key after that loop has already run. The update is inside the RCU read side, so it comes before the call_rcu() callback, and once the callback frees the key, current_key is left pointing at freed memory.
The next transmission picks that pointer up in tcp_get_current_key(). tcp_ao_transmit_skb() then reads the traffic key from the freed object, which is the use-after-free.
Wait for one grace period before unlinking, and only if a key is going to be removed. By the time tcp_connect() runs the socket is already in TCP_SYN_SENT, and TCP_AO_ESTABLISHED does not contain TCPF_SYN_SENT, so a softirq entering after the wait cannot reach the fast path, and the ones already in it have finished. The existing NULL handling in the loop is then enough.
--- net/ipv4/tcp_ao.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/ipv4/tcp_ao.c +9 -0
@@ -1120,6 +1120,15 @@ void tcp_ao_connect_init(struct sock *sk l3index =l3mdev_master_ifindex_by_index (sock_net (sk), sk->sk_bound_dev_if); +hlist_for_each_entry (key, &ao_info->head, node) { +if (tcp_ao_key_cmp (key, l3index, addr, key->prefixlen, + family,-1 ,-1 )) { +/* pairs with tcp_inbound_ao_hash() */ +synchronize_rcu (); +break ; + } + } +hlist_for_each_entry_safe (key, next, &ao_info->head, node) {if (!tcp_ao_key_cmp (key, l3index, addr, key->prefixlen, family,-1 ,-1 ))continue ;
Greg Kroah-Hartman
maintainerPATCH 51/83 xfrm: espintcp: fix UAF during close
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
commit deb232e884877bf10b4ce2580909eedec986c284 upstream.
ZDI reported and analyzed a race condition during close for espintcp sockets:
espintcp_close() frees emsg->skb via kfree_skb() without holding
any socket lock. Concurrently, the xfrm_trans_reinject work queue
invokes esp_output_tcp_finish() -> espintcp_push_skb() ->
espintcp_push_msgs() -> skb_send_sock_locked(), which reads the
same skb as a data source.Fix this by adding a synchronize_rcu() call after resetting sk_prot, since esp_output_tcp_finish() runs under RCU and won't use a socket with sk_prot == &tcp_prot. Simply taking the socket lock in espintcp_close() could lead to leaks, if esp_output_tcp_finish() re-adds an skb in the slot we just freed. After this, the existing barrier() is no longer needed.
--- net/xfrm/espintcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/xfrm/espintcp.c +2 -1
@@ -518,7 +518,8 @@ static void espintcp_close(struct sock *strp_stop (&ctx->strp); sk->sk_prot = &tcp_prot; -barrier (); + +synchronize_rcu ();disable_work_sync (&ctx->work);strp_done (&ctx->strp);
Greg Kroah-Hartman
maintainerPATCH 52/83 xfrm: drop ESP-in-TCP packets with no ingress device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit e1d7c5ac1c246ce5775f604515de0a59fbf2116e upstream.
ESP-in-TCP receives records through the TCP strparser. handle_esp() restores skb->dev from the saved skb_iif before passing the packet into the XFRM input path.
Queued TCP data can be processed after the original ingress device has been removed, for example during veth or net namespace teardown. In that case dev_get_by_index_rcu() returns NULL. The XFRM IPv4 and IPv6 input paths both expect skb->dev to be valid while building the route lookup, so queued ESP-in-TCP data can dereference a NULL device.
Drop the packet if the saved ingress device can no longer be resolved. Such a packet can no longer be routed through the normal XFRM receive path, and this preserves the existing behaviour for packets whose ingress device still exists.
--- net/xfrm/espintcp.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/xfrm/espintcp.c +6 -0
@@ -40,6 +40,11 @@ static void handle_esp(struct sk_buff *srcu_read_lock (); skb->dev =dev_get_by_index_rcu (sock_net (sk), skb->skb_iif); +if (!skb->dev) { +XFRM_INC_STATS (sock_net (sk),LINUX_MIB_XFRMINERROR ); +kfree_skb (skb); + goto out; + }local_bh_disable ();#if IS_ENABLED (CONFIG_IPV6 )if (sk->sk_family ==AF_INET6 )
@@ -48,6 +53,7 @@ static void handle_esp(struct sk_buff *s#endif xfrm4_rcv_encap (skb,IPPROTO_ESP ,0 ,TCP_ENCAP_ESPINTCP );local_bh_enable (); +out:rcu_read_unlock (); }
Greg Kroah-Hartman
maintainerPATCH 53/83 xfrm: avoid lock inversion in nat keepalive work
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 763fe700b7c58ad64fe5202c5638848244dd4127 upstream.
nat_keepalive_work() walks the state table while xfrm_state_walk() holds net->xfrm.xfrm_state_lock. Its callback then acquires x->lock, which conflicts with the delete path taking the same locks in reverse order via xfrm_state_delete() and __xfrm_state_delete(). This creates an AB-BA deadlock that is reported by lockdep when a NAT keepalive worker races with SA deletion.
Fix this by splitting the keepalive walk into two phases. First, collect the candidate states while the walk holds xfrm_state_lock and take a reference on each state. Then, after the walk completes, process each collected state and acquire x->lock without nesting it under xfrm_state_lock.
--- net/xfrm/xfrm_nat_keepalive.c | 57 +++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-)
net/xfrm/xfrm_nat_keepalive.c +48 -9
@@ -156,24 +156,51 @@ static void nat_keepalive_send(struct na }struct nat_keepalive_work_ctx { +struct list_head states;time64_t next_run;time64_t now; }; -static int nat_keepalive_work_single (struct xfrm_state *x,int count,void *ptr) +struct nat_keepalive_state { +struct list_head list; +struct xfrm_state *x; +}; + +static int nat_keepalive_work_collect (struct xfrm_state *x,int count,void *ptr) {struct nat_keepalive_work_ctx *ctx = ptr; +struct nat_keepalive_state *state; + +if (!READ_ONCE (x->nat_keepalive_interval)) +return 0 ; + + state =kmalloc_obj (*state,GFP_ATOMIC ); +if (!state) +return -ENOMEM ; + +xfrm_state_hold (x); + state->x = x; +list_add_tail (&state->list, &ctx->states); +return 0 ; +} + +static void nat_keepalive_work_single (struct xfrm_state *x, +struct nat_keepalive_work_ctx *ctx) +{bool send_keepalive = false;struct nat_keepalive ka; -time64_t next_run; +time64_t next_run =0 ;u32 interval;int delta; +spin_lock_bh (&x->lock); + +if (x->km.state ==XFRM_STATE_DEAD ) + goto out; + interval = x->nat_keepalive_interval;if (!interval) -return 0 ; - -spin_lock (&x->lock); + goto out; delta = (int )(ctx->now - x->lastused);if (delta < interval) {
@@ -187,29 +214,41 @@ static int nat_keepalive_work_single(str send_keepalive = true; } -spin_unlock (&x->lock); +out: +spin_unlock_bh (&x->lock);if (send_keepalive)nat_keepalive_send (&ka); -if (!ctx->next_run || next_run < ctx->next_run) +if (next_run && (!ctx->next_run || next_run < ctx->next_run)) ctx->next_run = next_run; -return 0 ; }static void nat_keepalive_work (struct work_struct *work) { +struct nat_keepalive_state *state, *tmp;struct nat_keepalive_work_ctx ctx;struct xfrm_state_walk walk;struct net *net; +int err; +INIT_LIST_HEAD (&ctx.states); ctx.next_run =0 ; ctx.now =ktime_get_real_seconds (); net = container_of(work, struct net, xfrm.nat_keepalive_work.work);xfrm_state_walk_init (&walk,IPPROTO_ESP ,NULL ); -xfrm_state_walk (net, &walk, nat_keepalive_work_single, &ctx); + err =xfrm_state_walk (net, &walk, nat_keepalive_work_collect, &ctx);xfrm_state_walk_done (&walk, net); +list_for_each_entry_safe (state, tmp, &ctx.states, list) { +nat_keepalive_work_single (state->x, &ctx); +xfrm_state_put (state->x); +kfree (state); + } +if (err == -ENOMEM ) { +schedule_delayed_work (&net->xfrm.nat_keepalive_work,0 ); +return ; + }if (ctx.next_run)schedule_delayed_work (&net->xfrm.nat_keepalive_work, (ctx.next_run - ctx.now) *HZ );
Greg Kroah-Hartman
maintainerPATCH 54/83 xfrm: ah6: validate routing header segments_left
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit 7bad4bda74dc4713f398d3b7624ff05478e3a568 upstream.
AH6 rearranges routing-header addresses before computing or verifying the ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than the number of addresses described by the routing header's hdrlen field.
That assumption does not hold for raw IPv6 HDRINCL packets. A packet with hdrlen equal to 2 describes one address, but can carry an arbitrary segments_left value. With segments_left equal to 255, the function moves its address pointer 4,064 bytes backwards and passes a 4,064-byte length to memmove(), resulting in an out-of-bounds access.
Validate the invariant locally before modifying the routing header or performing any address-pointer arithmetic, and propagate malformed-header errors to the existing AH6 input and output error paths.
--- net/ipv6/ah6.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-)
net/ipv6/ah6.c +18 -11
@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struc* Rearrange the destination address in @iph and the addresses in @rthdr * so that they appear in the order they will at the final destination. * See Appendix A2 of RFC 2402 for details. +* +* Return: 0 on success, -EINVAL if segments_left exceeds the number of +* addresses described by hdrlen. */ -static void ipv6_rearrange_rthdr (struct ipv6hdr *iph,struct ipv6_rt_hdr *rthdr) +static int ipv6_rearrange_rthdr (struct ipv6hdr *iph,struct ipv6_rt_hdr *rthdr) { -int segments, segments_left; +unsigned int segments, segments_left;struct in6_addr *addrs;struct in6_addr final_addr; segments_left = rthdr->segments_left;if (segments_left ==0 ) -return ; - rthdr->segments_left =0 ; +return 0 ; -/* The value of rthdr->hdrlen has been verified either by the system -* call if it is locally generated, or by ipv6_rthdr_rcv() for incoming -* packets. So we can assume that it is even and that segments is -* greater than or equal to segments_left. -* -* For the same reason we can assume that this option is of type 0. +/* Raw locally generated packets can reach AH6 without the invariant +* required by the rt0-style address rearrangement below. */ segments = rthdr->hdrlen >>1 ; +if (segments_left > segments) +return -EINVAL ; + + rthdr->segments_left =0 ; addrs = ((struct rt0_hdr *)rthdr)->addr; final_addr = addrs[segments -1 ];
@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct addrs[0 ] = iph->daddr; iph->daddr = final_addr; + +return 0 ; }static int ipv6_clear_mutable_options (struct ipv6hdr *iph,int len,int dir)
@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(st } exthdr = { .iph = iph };char *end = exthdr.raw + len;int nexthdr = iph->nexthdr; +int err; exthdr.iph++;
@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(stbreak ;case NEXTHDR_ROUTING : -ipv6_rearrange_rthdr (iph, exthdr.rth); + err =ipv6_rearrange_rthdr (iph, exthdr.rth); +if (err) +return err;break ;default :
Greg Kroah-Hartman
maintainerPATCH 55/83 xfrm: fix xfrm_state_construct() auth-trunc leak
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit c12cbf56320fb633484ee0ca1fb7d68d6b64b213 upstream.
attach_auth_trunc() can allocate x->aalg while leaving x->props.aalgo at zero when the selected auth algorithm has no sadb_alg_id. One real case is cmac(aes).
xfrm_state_construct() then treats !x->props.aalgo as "no auth algorithm attached yet" and calls attach_auth(). That overwrites x->aalg and loses the first allocation. Any later failure or teardown only frees the replacement pointer.
Check whether x->aalg is already attached instead of inferring that state from x->props.aalgo.
--- net/xfrm/xfrm_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/xfrm/xfrm_user.c +1 -1
@@ -916,7 +916,7 @@ static struct xfrm_state *xfrm_state_conif ((err =attach_auth_trunc (&x->aalg, &x->props.aalgo, attrs[XFRMA_ALG_AUTH_TRUNC ], extack))) goto error; -if (!x->props.aalgo) { +if (!x->aalg) {if ((err =attach_auth (&x->aalg, &x->props.aalgo, attrs[XFRMA_ALG_AUTH ], extack))) goto error;
Greg Kroah-Hartman
maintainerPATCH 56/83 xfrm: bound nat keepalive state collection
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 4e9442ce551ebd84b52ad649df721e2dc28af95a upstream.
The v1 nat keepalive fix allocates a GFP_ATOMIC object for every state while collecting references for phase two. This makes the worker's temporary memory use depend on the number of states and lets -ENOMEM abort the scan.
Replace the allocated list with a fixed-size batch. When the batch is full, return a private walk status so xfrm_state_walk() leaves a cursor; drain the references after the walk releases xfrm_state_lock and resume from the cursor. This bounds temporary memory use and avoids the allocation failure path.
The v1 fix also moved nat_keepalive_send() out of the walk callback. Keep the phase-two drain BH-disabled, as required by local_lock_nested_bh() used by the keepalive sockets.
--- net/xfrm/xfrm_nat_keepalive.c | 46 +++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 25 deletions(-)
net/xfrm/xfrm_nat_keepalive.c +21 -25
@@ -155,32 +155,30 @@ static void nat_keepalive_send(struct na } } +enum { +NAT_KEEPALIVE_BATCH_SIZE =16 , +NAT_KEEPALIVE_BATCH_FULL =1 , +}; +struct nat_keepalive_work_ctx { -struct list_head states; +struct xfrm_state *batch[NAT_KEEPALIVE_BATCH_SIZE ]; +unsigned int nr;time64_t next_run;time64_t now; }; -struct nat_keepalive_state { -struct list_head list; -struct xfrm_state *x; -}; -static int nat_keepalive_work_collect (struct xfrm_state *x,int count,void *ptr) {struct nat_keepalive_work_ctx *ctx = ptr; -struct nat_keepalive_state *state;if (!READ_ONCE (x->nat_keepalive_interval))return 0 ; - state =kmalloc_obj (*state,GFP_ATOMIC ); -if (!state) -return -ENOMEM ; +if (ctx->nr ==ARRAY_SIZE (ctx->batch)) +return NAT_KEEPALIVE_BATCH_FULL ;xfrm_state_hold (x); - state->x = x; -list_add_tail (&state->list, &ctx->states); + ctx->batch[ctx->nr++] = x;return 0 ; }
@@ -226,29 +224,27 @@ out:static void nat_keepalive_work (struct work_struct *work) { -struct nat_keepalive_state *state, *tmp;struct nat_keepalive_work_ctx ctx;struct xfrm_state_walk walk;struct net *net; -int err; +int err, i; -INIT_LIST_HEAD (&ctx.states); ctx.next_run =0 ; ctx.now =ktime_get_real_seconds (); net = container_of(work, struct net, xfrm.nat_keepalive_work.work);xfrm_state_walk_init (&walk,IPPROTO_ESP ,NULL ); - err =xfrm_state_walk (net, &walk, nat_keepalive_work_collect, &ctx); +do { + ctx.nr =0 ; + err =xfrm_state_walk (net, &walk, nat_keepalive_work_collect, &ctx); +local_bh_disable (); +for (i =0 ; i < ctx.nr; i++) { +nat_keepalive_work_single (ctx.batch[i], &ctx); +xfrm_state_put (ctx.batch[i]); + } +local_bh_enable (); + }while (err ==NAT_KEEPALIVE_BATCH_FULL );xfrm_state_walk_done (&walk, net); -list_for_each_entry_safe (state, tmp, &ctx.states, list) { -nat_keepalive_work_single (state->x, &ctx); -xfrm_state_put (state->x); -kfree (state); - } -if (err == -ENOMEM ) { -schedule_delayed_work (&net->xfrm.nat_keepalive_work,0 ); -return ; - }if (ctx.next_run)schedule_delayed_work (&net->xfrm.nat_keepalive_work, (ctx.next_run - ctx.now) *HZ );
Greg Kroah-Hartman
maintainerPATCH 57/83 net: bridge: mcast: fix use-after-free of a master VLANs multicast context
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 50e5c6605cc9c2dd57bd2d1b3459674d19738983 upstream.
br_multicast_toggle_one_vlan() clears BR_VLFLAG_MCAST_ENABLED under br->multicast_lock before stopping a VLAN's multicast context. That is the teardown handshake: lockless readers gate on the flag through br_multicast_ctx_should_use() -> br_multicast_ctx_vlan_disabled(), so once it is cleared under the lock no reader can arm the context again.
For a master VLAN the handshake never runs. __vlan_del() clears BRIDGE_VLAN_INFO_BRENTRY before calling br_vlan_put_master(), so br_multicast_toggle_one_vlan(masterv, false) returns early on !br_vlan_is_brentry(vlan): the flag stays set and br->multicast_lock is never taken. br_vlan_put_master() then drains the context in br_multicast_ctx_deinit() and frees the VLAN through call_rcu(), while a reader still inside rcu_read_lock() sees the context as enabled and re-arms it. The port and port-VLAN branch of the function has no br_vlan_is_brentry() test and flips the flag under br->multicast_lock, so it is not affected.
The reader is the bridge transmit path. For a master VLAN br_multicast_rcv() selects brmctx = &vlan->br_mcast_ctx with pmctx = NULL, so IGMP sent to the bridge device re-arms the context's timers after br_multicast_ctx_deinit() has already stopped them.
BUG: KASAN: slab-use-after-free in detach_if_pending+0x412/0x4a0 Write of size 8 at addr ffff88810ac39918 by task brmc/601 __mod_timer+0x51a/0xc50 br_multicast_host_join+0x25b/0x390 __br_multicast_add_group+0x468/0x530 br_ip4_multicast_add_group+0x1a0/0x260 br_multicast_rcv+0x2cda/0x61e0 br_dev_xmit+0x6c4/0x1540 Allocated by task 610: br_vlan_add+0x111/0xb40 br_vlan_info+0x370/0x3e0 Freed by task 0: kfree+0x1a7/0x4f0 rcu_core+0x7dc/0x10a0
Only test br_vlan_is_brentry() when enabling, like the br_multicast_ctx_vlan_global_disabled() test next to it. Disabling then always clears BR_VLFLAG_MCAST_ENABLED under br->multicast_lock before br_multicast_ctx_deinit() drains the context.
--- net/bridge/br_multicast.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/bridge/br_multicast.c +2 -2
@@ -4311,8 +4311,8 @@ void br_multicast_toggle_one_vlan(structif (br_vlan_is_master (vlan)) { br = vlan->br; -if (!br_vlan_is_brentry (vlan) || - (on && +if (on && + (!br_vlan_is_brentry (vlan) ||br_multicast_ctx_vlan_global_disabled (&vlan->br_mcast_ctx)))return ;
Greg Kroah-Hartman
maintainerPATCH 58/83 ipv6: seg6: clear IPv4 control block on IPIP decapsulation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 44930446dde45a7a90fe1446fa38eb0e2c561646 upstream.
End.DX4 and End.DT4 decapsulate an IPv4 packet through decap_and_validate() and send it directly to IPv4 routing. The inner packet therefore bypasses ip_rcv_core(), which normally clears IPCB before IPv4 interprets skb->cb.
The skb instead retains IP6CB data from the outer packet. IP6CB and IPCB use the same skb->cb storage, so IP6CB(skb)->lastopt overlaps IPCB(skb)->opt.optlen and srr, while IP6CB(skb)->nhoff overlaps rr and ts.
The sender can make the stale optlen byte nonzero with a valid outer extension-header chain. The reproducers put an eight-byte Destination Options header immediately after the 40-byte IPv6 header and before the Segment Routing Header. ipv6_destopt_rcv() records the sender-controlled Destination Options offset in both lastopt and nhoff, setting them to
40. On the reproduced little-endian x86-64 kernel, IPv4 therefore sees optlen = 40 and rr = 40.
Both tcp_v4_save_options() and __ip_options_echo() skip option copying when optlen is zero. Here optlen is 40, so the TCP SYN path allocates room for 40 bytes of option data and calls __ip_options_echo(). The stale rr value makes that function read inner packet byte 41 as the Record Route option length. The reproducers set that sender-controlled byte to 255, so __ip_options_echo() copies 255 bytes into the 40-byte option-data area.
Separate End.DX4 and End.DT4 reproducers on the unpatched v7.2-rc5 kernel both produced:
BUG: KASAN: slab-out-of-bounds in __ip_options_echo() Write of size 255
The relevant End.DX4 call path is:
__ip_options_echo
tcp_v4_route_req
tcp_conn_request
tcp_v4_conn_request
tcp_rcv_state_process
tcp_v4_do_rcv
tcp_v4_rcv
ip_protocol_deliver_rcu
ip_local_deliver_finish
ip_local_deliver
input_action_end_dx4_finish
input_action_end_dx4
The relevant End.DT4 call path is:
__ip_options_echo
tcp_v4_route_req
tcp_conn_request
tcp_v4_conn_request
tcp_rcv_state_process
tcp_v4_do_rcv
tcp_v4_rcv
ip_protocol_deliver_rcu
ip_local_deliver_finish
ip_local_deliver
input_action_end_dt4
tcp_v4_save_options() is inlined into the tcp_v4_route_req() path, so it does not appear as a separate frame.
When decap_and_validate() handles IPPROTO_IPIP, save the ingress interface from IP6CB, clear IPCB, and restore the saved value. Doing this in the common decapsulation path covers End.DX4, End.DT4, and End.DT46's IPv4 arm.
Use IP6CB(skb)->iif rather than skb->skb_iif. These actions run after l3mdev processing, which can replace skb_iif with the L3 master; IP6CB iif still records the receiving interface set at IPv6 ingress.
--- net/ipv6/seg6_local.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/ipv6/seg6_local.c +7 -0
@@ -256,6 +256,13 @@ static bool decap_and_validate(struct skif (iptunnel_pull_offloads (skb))return false; +if (proto ==IPPROTO_IPIP ) { +int iif =IP6CB (skb)->iif; + +memset (IPCB (skb),0 ,sizeof (*IPCB (skb))); +IPCB (skb)->iif = iif; + } +return true; }
Greg Kroah-Hartman
maintainerPATCH 59/83 batman-adv: reject unrepresentable multicast TVLV offsets
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit f12c2de4f542e3220e17e0606f492110064f04cb upstream.
The network and transport header fields in struct sk_buff are 16-bit offsets from skb->head, and U16_MAX is reserved as the unset transport header value. batadv_tvlv_call_handler() sets both fields from a received multicast TVLV without checking whether the TVLV end is representable.
If the end offset exceeds the field's range, skb_set_transport_header() truncates it so that the transport header precedes the network header. The negative difference is then returned by skb_network_header_len() as a large u32. batadv_mcast_forw_packet() consequently accepts an oversized multicast tracker and accesses memory beyond the skb data.
Add skb_set_transport_header_careful(), an offset-aware counterpart to skb_reset_transport_header_careful(), which validates the final head-relative offset before assigning it. Use the new helper in batadv_tvlv_call_handler() and reject unrepresentable TVLVs before setting the network header.
--- include/linux/skbuff.h | 24 ++++++++++++++++++++++++ net/batman-adv/tvlv.c | 5 ++++- 2 files changed, 28 insertions(+), 1 deletion(-)
include/linux/skbuff.h +24 -0
@@ -3110,6 +3110,30 @@ static inline void skb_set_transport_hea skb->transport_header += offset; } +/** +* skb_set_transport_header_careful - conditionally set transport header +* @skb: buffer to alter +* @offset: offset to add to skb->data +* +* Hardened version of skb_set_transport_header(). +* +* Returns: true if the operation was a success. +*/ +static inline bool __must_check +skb_set_transport_header_careful (struct sk_buff *skb,const int offset) +{ +long thoff = skb->data - skb->head + offset; + + if (unlikely(thoff != (typeof(skb->transport_header))thoff)) +return false; + + if (unlikely(thoff == (typeof(skb->transport_header))~0U)) +return false; + + skb->transport_header = thoff; +return true; +} +static inline unsigned char *skb_network_header (const struct sk_buff *skb) {return skb->head + skb->network_header;
net/batman-adv/tvlv.c +4 -1
@@ -420,8 +420,11 @@ static int batadv_tvlv_call_handler(strureturn NET_RX_SUCCESS ; tvlv_offset = (unsigned char *)tvlv_value - skb->data; +if (!skb_set_transport_header_careful (skb, + tvlv_offset + tvlv_value_len)) +return -EINVAL ; +skb_set_network_header (skb, tvlv_offset); -skb_set_transport_header (skb, tvlv_offset + tvlv_value_len);return tvlv_handler->mcast_handler (bat_priv, skb); }
Greg Kroah-Hartman
maintainerPATCH 60/83 vxlan: keep the last remote linked during FDB flush
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit d5d4a7b538b52db63927773a8905fcd9f78a42e2 upstream.
A non-nexthop FDB entry is expected to have at least one remote while it remains reachable through the FDB hash table. A filtered bulk flush violates this invariant when every remote matches: It unlinks the last remote in vxlan_fdb_dst_destroy() and only afterwards tells vxlan_flush() to destroy the parent FDB entry.
An RCU reader can find the parent during this interval. first_remote_rcu() then applies list_entry_rcu() to the empty list head, producing an invalid remote pointer that the receive learning path can read from and write to.
When a matching remote is the sole remaining remote, leave it linked and ask the caller to destroy the entire FDB entry. vxlan_fdb_destroy() keeps the remote attached while sending the deletion notification and removing the parent from the lookup structures.
--- drivers/net/vxlan/vxlan_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/net/vxlan/vxlan_core.c +5 -4
@@ -3060,18 +3060,19 @@ vxlan_fdb_flush_match_remotes(struct vxlconst struct vxlan_fdb_flush_desc *desc, bool *p_destroy_fdb) { - bool remotes_flushed = false; struct vxlan_rdst *rd, *tmp;list_for_each_entry_safe (rd, tmp, &f->remotes, list) {if (!vxlan_fdb_flush_remote_matches (desc, rd))continue ; +if (list_is_singular (&f->remotes)) { + *p_destroy_fdb = true; +return ; + } +vxlan_fdb_dst_destroy (vxlan, f, rd, true); - remotes_flushed = true; } - - *p_destroy_fdb = remotes_flushed &&list_empty (&f->remotes); }/* Purge the forwarding table */
Greg Kroah-Hartman
maintainerPATCH 61/83 netfilter: nft_set_pipapo_avx2: add missing vzeroupper
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 55dd20f0f4b1be5c9c8a0275d8d763c86563eac2 upstream.
Since pipapo_get_avx2() uses YMM registers, execute vzeroupper before returning from it. This is needed to avoid degrading the performance of any later SSE code that may happen to be executed.
--- net/netfilter/nft_set_pipapo_avx2.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
net/netfilter/nft_set_pipapo_avx2.c +8 -9
@@ -1156,6 +1156,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(struct nft_pipapo_scratch *scratch;const struct nft_pipapo_field *f;unsigned long *res, *fill, *map; +struct nft_pipapo_elem *e;bool map_index;int i;
@@ -1228,14 +1229,11 @@ struct nft_pipapo_elem *pipapo_get_avx2( next_match:if (ret <0 ) { scratch->map_index = map_index; -kernel_fpu_end (); -__local_unlock_nested_bh (&scratch->bh_lock); -return NULL ; + e =NULL ; + goto out; }if (last) { -struct nft_pipapo_elem *e; - e = f->mt[ret].e;if (unlikely (__nft_set_elem_expired (&e->ext, tstamp) || !nft_set_elem_active (&e->ext, genmask))) {
@@ -1245,9 +1243,7 @@ next_match: } scratch->map_index = map_index; -kernel_fpu_end (); -__local_unlock_nested_bh (&scratch->bh_lock); -return e; + goto out; } map_index = !map_index;
@@ -1255,9 +1251,12 @@ next_match: data +=NFT_PIPAPO_GROUPS_PADDED_SIZE (f); } + e =NULL ; +out: + asmvolatile ("vzeroupper" );kernel_fpu_end ();__local_unlock_nested_bh (&scratch->bh_lock); -return NULL ; +return e; }/**
Greg Kroah-Hartman
maintainerPATCH 62/83 netfilter: nf_tables: dont queue packet path object notifications
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fourie Zhang <[email protected]>
commit 7904b94768e983bcb2be34a8d6d1f3450f5b838b upstream.
All file:line references below are against v7.2-rc4 (ac5b0e5651b1). The trace was captured on 7.2.0-rc6-kasan72rc6 (075b74841bd0), where the same lines apply.
nft_obj_notify() is exported and reached from the packet path. Its only in-tree caller is nft_quota_obj_eval() (net/netfilter/nft_quota.c:68), which notifies with GFP_ATOMIC while evaluating a rule for a transiting packet, holding no mutex.
Since commit 67cc570edaa0 ("netfilter: nf_tables: coalesce multiple notifications into one skbuff") that notification is no longer sent immediately. __nft_obj_notify() queues it onto nft_net->notify_list via nft_notify_enqueue() (net/netfilter/nf_tables_api.c:1211), which is a bare list_add_tail(). notify_list has no lock of its own (include/net/netfilter/nf_tables.h:1951), it is serialised by commit_mutex:
the six other enqueue sites all run inside a netlink transaction, and the drain in nft_commit_notify() (net/netfilter/nf_tables_api.c:10746) does list_del() + kfree_skb() from nf_tables_commit() with commit_mutex held.
Sending packets through a chain that references a depleted quota object therefore races an unlocked list_add_tail() against list_del() + kfree_skb() on another CPU. The WRITE_ONCE(prev->next, new) in __list_add() then stores through an sk_buff that has already been freed:
BUG: KASAN: slab-use-after-free in __nft_obj_notify+0x2c5/0x2d0
Write of size 8 at addr ff110001047183c0 by task poc/76
CPU: 0 UID: 1000 PID: 76 Comm: poc Tainted: G W 7.2.0-rc6-kasan72rc6 #4
Call Trace:
<IRQ>
__nft_obj_notify (include/linux/list.h:164 include/linux/list.h:191
net/netfilter/nf_tables_api.c:1211
net/netfilter/nf_tables_api.c:8743)
nft_quota_obj_eval (net/netfilter/nft_quota.c:68)
nft_do_chain_inet
nf_hook_slow
__ip_local_out
ip_push_pending_frames
udp_send_skb
udp_sendmsg
__x64_sys_sendto
Allocated by task 77:
__alloc_skb (net/core/skbuff.c:704)
__nft_obj_notify (include/net/netlink.h:1055
net/netfilter/nf_tables_api.c:8731)
nft_quota_obj_eval (net/netfilter/nft_quota.c:68)
nft_do_chain
Freed by task 79:
nf_tables_commit (include/linux/skbuff.h:1332
net/netfilter/nf_tables_api.c:10759
net/netfilter/nf_tables_api.c:11185)
nfnetlink_rcv_batch (net/netfilter/nfnetlink.c:574)
netlink_unicast
netlink_sendmsg
The buggy address belongs to the cache skbuff_head_cache of size 232Queueing from the packet path is wrong even leaving the race aside:notify_list is only drained by nft_commit_notify() from nf_tables_commit() (:11185), so a notification enqueued outside a transaction is not sent until some later netlink batch commits, if one ever does.
The gfp argument that nft_obj_notify() still takes is a leftover of the pre-67cc570edaa0 behaviour, where this path called nfnetlink_send() directly. Restore that: split the message construction out into nft_obj_notify_alloc() and let each caller decide what to do with the skb. nft_obj_notify(), the exported one reached from the packet path, sends it straight away; nf_tables_obj_notify(), which runs under commit_mutex, keeps queueing it, so transaction notifications are still coalesced.
--- net/netfilter/nf_tables_api.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-)
net/netfilter/nf_tables_api.c +23 -13
@@ -8585,18 +8585,17 @@ static int nf_tables_delobj(struct sk_bureturn nft_delobj (&ctx, obj); } -static void -__nft_obj_notify (struct net *net,const struct nft_table *table, -struct nft_object *obj,u32 portid,u32 seq,int event, -u16 flags,int family,int report,gfp_t gfp) +static struct sk_buff * +nft_obj_notify_alloc (struct net *net,const struct nft_table *table, +struct nft_object *obj,u32 portid,u32 seq,int event, +u16 flags,int family,int report,gfp_t gfp) { -struct nftables_pernet *nft_net =nft_pernet (net);struct sk_buff *skb;int err;if (!report && !nfnetlink_has_listeners (net,NFNLGRP_NFTABLES )) -return ; +return NULL ; skb =nlmsg_new (NLMSG_GOODSIZE , gfp);if (skb ==NULL )
@@ -8610,10 +8609,10 @@ __nft_obj_notify(struct net *net, const goto err; } -nft_notify_enqueue (skb, report, &nft_net->notify_list); -return ; +return skb; err:nfnetlink_set_err (net, portid,NFNLGRP_NFTABLES , -ENOBUFS ); +return NULL ; } void nft_obj_notify(struct net *net, const struct nft_table *table,
@@ -8622,6 +8621,7 @@ void nft_obj_notify(struct net *net, con {char *buf =kasprintf (gfp,"%s:%u" , table->name,nft_base_seq (net)); +struct sk_buff *skb; audit_log_nfcfg(buf, family,
@@ -8632,17 +8632,27 @@ void nft_obj_notify(struct net *net, con gfp);kfree (buf); -__nft_obj_notify (net, table, obj, portid, seq, event, - flags, family, report, gfp); +/* Called from the packet path, holding no mutex: notify_list is +* serialised by commit_mutex, so send this notification directly. +*/ + skb =nft_obj_notify_alloc (net, table, obj, portid, seq, event, + flags, family, report, gfp); +if (skb) +nfnetlink_send (skb, net, portid,NFNLGRP_NFTABLES , report, gfp); }EXPORT_SYMBOL_GPL (nft_obj_notify);static void nf_tables_obj_notify (const struct nft_ctx *ctx,struct nft_object *obj,int event) { -__nft_obj_notify (ctx->net, ctx->table, obj, ctx->portid, - ctx->seq, event, ctx->flags, ctx->family, - ctx->report,GFP_KERNEL ); +struct nftables_pernet *nft_net =nft_pernet (ctx->net); +struct sk_buff *skb; + + skb =nft_obj_notify_alloc (ctx->net, ctx->table, obj, ctx->portid, + ctx->seq, event, ctx->flags, ctx->family, + ctx->report,GFP_KERNEL ); +if (skb) +nft_notify_enqueue (skb, ctx->report, &nft_net->notify_list); }/*
Greg Kroah-Hartman
maintainerPATCH 63/83 mm/swap: reject swapon() on filesystem-level encrypted files
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit c310a8932a3107c9bc8f01d473e9d085f8aa9c98 upstream.
ext4 and f2fs don't prevent filesystem-level encrypted files from being set up directly as swap files. In this case, encryption is bypassed.
No one should be doing this, vs. the methods of encrypted swap that actually do work (such as swapping to a dm-crypt device, or swapping to a loopback device on top of a filesystem-level encrypted file).
Nevertheless, to prevent user error, make swapon() explicitly reject this case. Document this behavior in fscrypt.rst as well.
--- Documentation/filesystems/fscrypt.rst | 4 ++++ mm/swapfile.c | 7 +++++++ 2 files changed, 11 insertions(+)
Documentation/filesystems/fscrypt.rst +4 -0
@@ -1245,6 +1245,10 @@ astute users may notice some differences - DAX (Direct Access) is not supported on encrypted files. +- Encrypted files cannot be used directly as swap files. To swap to + an encrypted file, set up a loopback device on top of it. + Alternatively, encrypted swap can use a dm-crypt device. + - The maximum length of an encrypted symlink is 2 bytes shorter than the maximum length of an unencrypted symlink. For example, on an EXT4 filesystem with a 4K block size, unencrypted symlinks can be up
mm/swapfile.c +7 -0
@@ -3519,6 +3519,13 @@ SYSCALL_DEFINE2(swapon, const char __use error = -EBUSY ; goto bad_swap_unlock_inode; } +if (IS_ENCRYPTED (inode)) { +pr_warn_once ( +"Filesystem-level encrypted swapfile '%s' is unsupported. Create a loop device over it, or use dm-crypt\n" , + name->name); + error = -EINVAL ; + goto bad_swap_unlock_inode; + }/* * The swap subsystem needs a major overhaul to support this.
Greg Kroah-Hartman
maintainerPATCH 64/83 kunit: irq: Continue increasing hrtimer interval for longer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit faa6c4c4e4ac69926564688a926105621295d613 upstream.
Currently, kunit_irq_test_timer_func() stops increasing the hrtimer interval as soon as some forward progress is made in each of softirq and task context. Update it to use a more aggressive strategy: increase the interval as long as the hrtimer is running significantly faster than either context.
This resolves an occasional hang in the CRC and crypto library tests under qemu-system-s390x. It was exposed by the change in the default preemption model on s390 from NONE to LAZY. That seems to have exposed the issue by allowing some forward progress to be made while the actual system timer tick is still starved, preventing jiffies from increasing or the task context from making much progress towards max_iterations.
--- include/kunit/run-in-irq-context.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
include/kunit/run-in-irq-context.h +6 -4
@@ -38,11 +38,13 @@ static enum hrtimer_restart kunit_irq_te softirq_calls =atomic_read (&state->softirq_func_calls);/* -* If the timer is firing too often for the softirq or task to ever have -* a chance to run, increase the timer interval. This is needed on very -* slow systems. +* If the hrtimer is running much faster than the bh_work or the task, +* then it is firing too fast and might be starving those contexts as +* well as the actual system timer tick. Increase the interval. */ -if (hardirq_calls >=20 && (softirq_calls ==0 || task_calls ==0 )) +if (hardirq_calls >=20 && + (hardirq_calls /2 > softirq_calls || + hardirq_calls /2 > task_calls)) state->interval =ktime_add_ns (state->interval,250 );if (!state->func (state->test_specific_state))
Greg Kroah-Hartman
maintainerPATCH 65/83 crypto: virtio - bound the akcipher result length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit f77a956f6a19f9463ef1527c9d0cda50dded6b92 upstream.
virtio_crypto_dataq_akcipher_callback() sets the result length from the device-reported response length without bounding it to the destination buffer, which was allocated for the original request length. sg_copy_from_buffer() then reads that many bytes from the destination buffer; a backend reporting a larger length over-reads adjacent kernel heap into the caller's scatterlist (an out-of-bounds read).
Clamp the reported length to the originally requested destination length. A conforming device reports no more than that, so valid results are unaffected.
Message-ID: <[email protected]>
--- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +2 -1
@@ -88,7 +88,8 @@ static void virtio_crypto_dataq_akcipher }/* actual length may be less than dst buffer */ - akcipher_req->dst_len = len -sizeof (vc_req->status); + akcipher_req->dst_len = min_t(unsigned int, len - sizeof(vc_req->status), + akcipher_req->dst_len);sg_copy_from_buffer (akcipher_req->dst,sg_nents (akcipher_req->dst), vc_akcipher_req->dst_buf, akcipher_req->dst_len);virtio_crypto_akcipher_finalize_req (vc_akcipher_req, akcipher_req, error);
Greg Kroah-Hartman
maintainerPATCH 66/83 crypto: qcom-rng - Enable clock in hwrng case
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 0fd97bbda2842d7dcccee599ac2c0e9554bdddbc upstream.
Fix qcom-rng.c to enable the clock before accessing the hardware.
--- drivers/crypto/qcom-rng.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/crypto/qcom-rng.c +16 -0
@@ -113,6 +113,13 @@ static int qcom_rng_seed(struct crypto_rreturn 0 ; } +static int qcom_hwrng_init (struct hwrng *hwrng) +{ + struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng); + +return clk_prepare_enable (qrng->clk); +} +static int qcom_hwrng_read (struct hwrng *hwrng,void *data,size_t max,bool wait) { struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
@@ -120,6 +127,13 @@ static int qcom_hwrng_read(struct hwrngreturn qcom_rng_read (qrng, data, max); } +static void qcom_hwrng_cleanup (struct hwrng *hwrng) +{ + struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng); + +clk_disable_unprepare (qrng->clk); +} +static int qcom_rng_enable (struct qcom_rng *rng) {u32 val;
@@ -208,7 +222,9 @@ static int qcom_rng_probe(struct platforif (rng->match_data->hwrng_support) { rng->hwrng.name ="qcom_hwrng" ; + rng->hwrng.init = qcom_hwrng_init; rng->hwrng.read = qcom_hwrng_read; + rng->hwrng.cleanup = qcom_hwrng_cleanup; rng->hwrng.quality =QCOM_TRNG_QUALITY ; ret =devm_hwrng_register (&pdev->dev, &rng->hwrng);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 67/83 crypto: qcom-rng - Remove crypto_rng interface
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 2ecdf5c9910e20f73639bc322f0518a3439d17c0 upstream.
qcom-rng.c exposes the same hardware through two completely separate interfaces, crypto_rng and hwrng. However, the implementation of this is buggy because it permits generation operations from these interfaces to run concurrently with each other, accessing the same registers. That is, qcom_rng_generate() synchronizes with itself but not with qcom_hwrng_read(). This results in potential repetition of output from the RNG, output of non-random values, etc.
Fortunately, there's actually no point in hardware RNG drivers implementing the crypto_rng interface. It's not actually used by anything besides the "rng" algorithm type of AF_ALG, which in turn is not actually used in practice. Other crypto_rng hardware drivers are likewise being phased out, leaving just the hwrng support.
Thus, remove it to simplify the code and avoid conflict (and confusion) with the hwrng interface which is the one that actually matters.
--- drivers/crypto/Kconfig | 1 drivers/crypto/qcom-rng.c | 158 +++++----------------------------------------- 2 files changed, 19 insertions(+), 140 deletions(-)
drivers/crypto/Kconfig +0 -1
@@ -659,7 +659,6 @@ config CRYPTO_DEV_QCOM_RNG tristate "Qualcomm Random Number Generator Driver" depends on ARCH_QCOM || COMPILE_TEST depends on HW_RANDOM - select CRYPTO_RNG help This driver provides support for the Random Number Generator hardware found on Qualcomm SoCs.
drivers/crypto/qcom-rng.c +19 -139
226 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 68/83 crypto: qcom-rng - Allow zero as a random number
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 4ef04bdc0c9f98836d1638be516f6bf1bad55f69 upstream.
Zero is a valid random number and needs to be allowed. Otherwise the output is distinguishable from random.
--- drivers/crypto/qcom-rng.c | 2 -- 1 file changed, 2 deletions(-)
drivers/crypto/qcom-rng.c +0 -2
@@ -54,8 +54,6 @@ static int qcom_rng_read(struct qcom_rngreturn ret; val =readl_relaxed (rng->base +PRNG_DATA_OUT ); -if (!val) -return -EINVAL ;if ((max - currsize) >=WORD_SZ ) {memcpy (data, &val,WORD_SZ );
Greg Kroah-Hartman
maintainerPATCH 69/83 crypto: atmel-tdes - use scatterlist length before DMA mapping
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit ba199bdaa80b09a7dd92f28751de7f3dbb06c510 upstream.
Using sg_dma_len() is only valid after mapping the scatterlist with dma_map_sg(). However, atmel_tdes_crypt_start() uses it before mapping to compare input/output lengths and to compute the transfer count.
Use the original scatterlist lengths before DMA mapping to avoid reading stale or uninitialized DMA lengths when CONFIG_NEED_SG_DMA_LENGTH=y.
Drop the output scatterlist length in the fast path since it is equal to ->in_sg->length and does not change the transfer count.
--- drivers/crypto/atmel-tdes.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/crypto/atmel-tdes.c +2 -3
@@ -463,14 +463,13 @@ static int atmel_tdes_crypt_start(structIS_ALIGNED (dd->out_sg->length, dd->ctx->block_size); fast = in && out; -if (sg_dma_len (dd->in_sg) !=sg_dma_len (dd->out_sg)) +if (dd->in_sg->length != dd->out_sg->length) fast =0 ; }if (fast) { - count =min_t (size_t, dd->total,sg_dma_len (dd->in_sg)); - count =min_t (size_t, count,sg_dma_len (dd->out_sg)); + count =min_t (size_t, dd->total, dd->in_sg->length); err =dma_map_sg (dd->dev, dd->in_sg,1 ,DMA_TO_DEVICE );if (!err) {
Greg Kroah-Hartman
maintainerPATCH 70/83 crypto: krb5 - use kfree_sensitive() for derived key buffers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Sebastian Götte <[email protected]>
commit f7d53dd3f267e46a784f219a75072f2f400d42b9 upstream.
crypto_krb5_prepare_encryption() and crypto_krb5_prepare_checksum() free the buffer holding the freshly derived keys with plain kfree(), leaving the key material behind in the freed slab object.
--- crypto/krb5/krb5_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
crypto/krb5/krb5_api.c +4 -4
@@ -263,10 +263,10 @@ struct crypto_aead *crypto_krb5_prepare_ goto err; } -kfree (keys.data); +kfree_sensitive (keys.data);return ci; err: -kfree (keys.data); +kfree_sensitive (keys.data);return ERR_PTR (ret); }EXPORT_SYMBOL (crypto_krb5_prepare_encryption);
@@ -333,10 +333,10 @@ struct crypto_shash *crypto_krb5_prepare goto err; } -kfree (keys.data); +kfree_sensitive (keys.data);return ci; err: -kfree (keys.data); +kfree_sensitive (keys.data);return ERR_PTR (ret); }EXPORT_SYMBOL (crypto_krb5_prepare_checksum);
Greg Kroah-Hartman
maintainerPATCH 71/83 crypto: qce - fix CCM AAD buffer underallocation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Md Sadre Alam <[email protected]>
commit 7f2345f47dd189625f657cd72437179ab4170ee1 upstream.
The AAD buffer allocated in qce_aead_ccm_prepare_buf_assoclen() can be smaller than the length later programmed into the DMA scatterlist.
The allocation size is currently calculated as:
ALIGN(assoclen, 16) + MAX_CCM_ADATA_HEADER_LEN
while the DMA length is set to:
ALIGN(assoclen + adata_header_len, 16)
Since ALIGN() does not distribute over addition, the allocation can be smaller than the DMA length. For example, when assoclen = 32 and adata_header_len = 2:
allocation = ALIGN(32, 16) + 6 = 38
DMA length = ALIGN(32 + 2, 16) = 48
As a result, the QCE hardware can read beyond the allocated buffer while computing the CBC-MAC over the associated data. The extra bytes are folded into the authentication tag, resulting in an incorrect tag and causing CCM self-test failures such as:
alg: aead: ccm-aes-qce encryption test failed (wrong result) on test vector 8
Fix the allocation by adding the maximum possible AAD header length before alignment:
ALIGN(assoclen + MAX_CCM_ADATA_HEADER_LEN, 16)
This guarantees that the allocated buffer is large enough for the fully padded AAD data for all supported header sizes.
--- drivers/crypto/qce/aead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/qce/aead.c +1 -1
@@ -203,7 +203,7 @@ qce_aead_ccm_prepare_buf_assoclen(struct/* Get the msg */ msg_sg =scatterwalk_ffwd (__sg, req->src, req->assoclen); - rctx->adata =kzalloc ((ALIGN (assoclen,16 ) +MAX_CCM_ADATA_HEADER_LEN ) * + rctx->adata =kzalloc (ALIGN (assoclen +MAX_CCM_ADATA_HEADER_LEN ,16 ) *sizeof (unsigned char ),GFP_ATOMIC );if (!rctx->adata)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 72/83 crypto: mxs-dcp - fix source scatterlist length access
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit c5bcb084a9871e5b62afb5f48b60adfa13b5d9f8 upstream.
mxs_dcp_aes_block_crypt() uses sg_dma_len() without mapping the source scatterlist with dma_map_sg() first. Therefore, sg_dma_len() is invalid and could return zero or a stale DMA length, causing encryption and decryption to process the wrong number of bytes when CONFIG_NEED_SG_DMA_LENGTH=y.
Use the original scatterlist length instead.
--- drivers/crypto/mxs-dcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/mxs-dcp.c +1 -1
@@ -353,7 +353,7 @@ static int mxs_dcp_aes_block_crypt(strucfor_each_sg (req->src, src,sg_nents (req->src), i) { src_buf =sg_virt (src); - len =sg_dma_len (src); + len = src->length; tlen += len; limit_hit = tlen > req->cryptlen;
Greg Kroah-Hartman
maintainerPATCH 73/83 crypto: qce - Remove unsafe/deprecated algorithms
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit 7e28b0a5c4b7d075b98ce6d8f5290a9d3deb5b92 upstream.
Remove algorithms that are either unsafe or deprecated and have no in-kernel users that cannot be served by the ARM CE implementations.
AES-ECB reveals plaintext patterns (identical plaintext blocks produce identical ciphertext blocks) and should not be exposed as a hardware- accelerated primitive. DES, Triple DES and HMAC-SHA1 have been deprecated for years.
Remove sha1, ecb(aes), ecb(des), cbc(des), ecb(des3_ede), cbc(des3_ede), hmac(sha1) and all AEAD variants built on these primitives as well as authenc(hmac(sha256),cbc(des)). Also clean up the - now dead - code, flags and constants.
--- drivers/crypto/qce/aead.c | 56 ------------------------ drivers/crypto/qce/common.c | 55 +++++------------------ drivers/crypto/qce/common.h | 16 +----- drivers/crypto/qce/regs-v5.h | 4 - drivers/crypto/qce/sha.c | 30 ------------ drivers/crypto/qce/sha.h | 1 drivers/crypto/qce/skcipher.c | 97 ------------------------------------------ 7 files changed, 20 insertions(+), 239 deletions(-)
drivers/crypto/qce/aead.c +1 -55
@@ -8,8 +8,6 @@#include <crypto/gcm.h> #include <crypto/authenc.h> #include <crypto/internal/aead.h> -#include <crypto/internal/des.h> -#include <crypto/sha1.h> #include <crypto/sha2.h> #include <crypto/scatterwalk.h> #include "aead.h"
@@ -597,7 +595,6 @@ static int qce_aead_setkey(struct cryptostruct qce_aead_ctx *ctx =crypto_aead_ctx (tfm);struct crypto_authenc_keys authenc_keys;unsigned long flags =to_aead_tmpl (tfm)->alg_flags; -u32 _key[6 ];int err; err =crypto_authenc_extractkeys (&authenc_keys, key, keylen);
@@ -608,26 +605,7 @@ static int qce_aead_setkey(struct crypto authenc_keys.authkeylen > QCE_MAX_KEY_SIZE)return -EINVAL ; -if (IS_DES (flags)) { - err =verify_aead_des_key (tfm, authenc_keys.enckey, authenc_keys.enckeylen); -if (err) -return err; - }else if (IS_3DES (flags)) { - err =verify_aead_des3_key (tfm, authenc_keys.enckey, authenc_keys.enckeylen); -if (err) -return err; -/* -* The crypto engine does not support any two keys -* being the same for triple des algorithms. The -* verify_skcipher_des3_key does not check for all the -* below conditions. Schedule fallback in this case. -*/ -memcpy (_key, authenc_keys.enckey,DES3_EDE_KEY_SIZE ); -if (!((_key[0 ] ^ _key[2 ]) | (_key[1 ] ^ _key[3 ])) || - !((_key[2 ] ^ _key[4 ]) | (_key[3 ] ^ _key[5 ])) || - !((_key[0 ] ^ _key[4 ]) | (_key[1 ] ^ _key[5 ]))) - ctx->need_fallback = true; - }else if (IS_AES (flags)) { +if (IS_AES (flags)) {/* No random key sizes */ if (authenc_keys.enckeylen != AES_KEYSIZE_128 && authenc_keys.enckeylen != AES_KEYSIZE_192 &&
@@ -699,38 +677,6 @@ struct qce_aead_def {static const struct qce_aead_def aead_def[] = { { - .flags =QCE_ALG_DES |QCE_MODE_CBC |QCE_HASH_SHA1_HMAC , - .name ="authenc(hmac(sha1),cbc(des))" , - .drv_name ="authenc-hmac-sha1-cbc-des-qce" , - .blocksize =DES_BLOCK_SIZE , - .ivsize =DES_BLOCK_SIZE , - .maxauthsize =SHA1_DIGEST_SIZE , - }, - { - .flags =QCE_ALG_3DES |QCE_MODE_CBC |QCE_HASH_SHA1_HMAC , - .name ="authenc(hmac(sha1),cbc(des3_ede))" , - .drv_name ="authenc-hmac-sha1-cbc-3des-qce" , - .blocksize =DES3_EDE_BLOCK_SIZE , - .ivsize =DES3_EDE_BLOCK_SIZE , - .maxauthsize =SHA1_DIGEST_SIZE , - }, - { - .flags =QCE_ALG_DES |QCE_MODE_CBC |QCE_HASH_SHA256_HMAC , - .name ="authenc(hmac(sha256),cbc(des))" , - .drv_name ="authenc-hmac-sha256-cbc-des-qce" , - .blocksize =DES_BLOCK_SIZE , - .ivsize =DES_BLOCK_SIZE , - .maxauthsize =SHA256_DIGEST_SIZE , - }, - { - .flags =QCE_ALG_3DES |QCE_MODE_CBC |QCE_HASH_SHA256_HMAC , - .name ="authenc(hmac(sha256),cbc(des3_ede))" , - .drv_name ="authenc-hmac-sha256-cbc-3des-qce" , - .blocksize =DES3_EDE_BLOCK_SIZE , - .ivsize =DES3_EDE_BLOCK_SIZE , - .maxauthsize =SHA256_DIGEST_SIZE , - }, - { .flags =QCE_ALG_AES |QCE_MODE_CBC |QCE_HASH_SHA256_HMAC , .name ="authenc(hmac(sha256),cbc(aes))" , .drv_name ="authenc-hmac-sha256-cbc-aes-qce" ,
drivers/crypto/qce/common.c +12 -43
113 lines not on this page · raw message
drivers/crypto/qce/common.h +3 -13
@@ -22,7 +22,7 @@/* IV length in bytes */ #define QCE_AES_IV_LENGTH AES_BLOCK_SIZE -/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ +/* max of AES_BLOCK_SIZE */ #define QCE_MAX_IV_SIZE AES_BLOCK_SIZE/* maximum nonce bytes */
@@ -33,14 +33,10 @@#define QCE_MAX_ALIGN_SIZE 64/* cipher algorithms */ -#define QCE_ALG_DES BIT(0) -#define QCE_ALG_3DES BIT(1)#define QCE_ALG_AES BIT(2)/* hash and hmac algorithms */ -#define QCE_HASH_SHA1 BIT(3)#define QCE_HASH_SHA256 BIT(4) -#define QCE_HASH_SHA1_HMAC BIT(5)#define QCE_HASH_SHA256_HMAC BIT(6)#define QCE_HASH_AES_CMAC BIT(7)
@@ -58,21 +54,15 @@#define QCE_ENCRYPT BIT(30)#define QCE_DECRYPT BIT(31) -#define IS_DES (flags) (flags & QCE_ALG_DES) -#define IS_3DES (flags) (flags & QCE_ALG_3DES)#define IS_AES (flags) (flags & QCE_ALG_AES) -#define IS_SHA1 (flags) (flags & QCE_HASH_SHA1)#define IS_SHA256 (flags) (flags & QCE_HASH_SHA256) -#define IS_SHA1_HMAC (flags) (flags & QCE_HASH_SHA1_HMAC)#define IS_SHA256_HMAC (flags) (flags & QCE_HASH_SHA256_HMAC)#define IS_CMAC (flags) (flags & QCE_HASH_AES_CMAC) -#define IS_SHA (flags) (IS_SHA1(flags) || IS_SHA256(flags)) -#define IS_SHA_HMAC (flags) \ - (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags)) +#define IS_SHA (flags) IS_SHA256(flags) +#define IS_SHA_HMAC (flags) IS_SHA256_HMAC(flags)#define IS_CBC (mode) (mode & QCE_MODE_CBC) -#define IS_ECB (mode) (mode & QCE_MODE_ECB)#define IS_CTR (mode) (mode & QCE_MODE_CTR)#define IS_XTS (mode) (mode & QCE_MODE_XTS)#define IS_CCM (mode) (mode & QCE_MODE_CCM)
drivers/crypto/qce/regs-v5.h +0 -4
@@ -203,7 +203,6 @@#define AUTH_SIZE_SHIFT 9#define AUTH_SIZE_MASK GENMASK(13, 9) -#define AUTH_SIZE_SHA1 0#define AUTH_SIZE_SHA256 1#define AUTH_SIZE_ENUM_1_BYTES 0#define AUTH_SIZE_ENUM_2_BYTES 1
@@ -284,15 +283,12 @@#define ENCR_KEY_SZ_SHIFT 3#define ENCR_KEY_SZ_MASK GENMASK(5, 3) -#define ENCR_KEY_SZ_DES 0 -#define ENCR_KEY_SZ_3DES 1#define ENCR_KEY_SZ_AES128 0#define ENCR_KEY_SZ_AES256 2#define ENCR_ALG_SHIFT 0#define ENCR_ALG_MASK GENMASK(2, 0)#define ENCR_ALG_NONE 0 -#define ENCR_ALG_DES 1#define ENCR_ALG_AES 2#define ENCR_ALG_KASUMI 4#define ENCR_ALG_SNOW_3G 5
drivers/crypto/qce/sha.c +2 -28
@@ -24,10 +24,6 @@ struct qce_sha_saved_state {static LIST_HEAD (ahash_algs); -static const u32 std_iv_sha1[SHA256_DIGEST_SIZE /sizeof (u32)] = { -SHA1_H0 ,SHA1_H1 ,SHA1_H2 ,SHA1_H3 ,SHA1_H4 ,0 ,0 ,0 -}; -static const u32 std_iv_sha256[SHA256_DIGEST_SIZE /sizeof (u32)] = {SHA256_H0 ,SHA256_H1 ,SHA256_H2 ,SHA256_H3 ,SHA256_H4 ,SHA256_H5 ,SHA256_H6 ,SHA256_H7
@@ -348,9 +344,7 @@ static int qce_ahash_hmac_setkey(structreturn 0 ; } -if (digestsize ==SHA1_DIGEST_SIZE ) - alg_name ="sha1-qce" ; -else if (digestsize ==SHA256_DIGEST_SIZE ) +if (digestsize ==SHA256_DIGEST_SIZE ) alg_name ="sha256-qce" ;else return -EINVAL ;
@@ -412,15 +406,6 @@ struct qce_ahash_def {static const struct qce_ahash_def ahash_def[] = { { - .flags =QCE_HASH_SHA1 , - .name ="sha1" , - .drv_name ="sha1-qce" , - .digestsize =SHA1_DIGEST_SIZE , - .blocksize =SHA1_BLOCK_SIZE , - .statesize =sizeof (struct qce_sha_saved_state ), - .std_iv = std_iv_sha1, - }, - { .flags =QCE_HASH_SHA256 , .name ="sha256" , .drv_name ="sha256-qce" ,
@@ -430,15 +415,6 @@ static const struct qce_ahash_def ahash_ .std_iv = std_iv_sha256, }, { - .flags = QCE_HASH_SHA1_HMAC, - .name = "hmac(sha1)", - .drv_name = "hmac-sha1-qce", - .digestsize = SHA1_DIGEST_SIZE, - .blocksize = SHA1_BLOCK_SIZE, - .statesize = sizeof(struct qce_sha_saved_state), - .std_iv = std_iv_sha1, - }, - { .flags = QCE_HASH_SHA256_HMAC, .name = "hmac(sha256)", .drv_name = "hmac-sha256-qce",
@@ -475,9 +451,7 @@ static int qce_ahash_register_one(const alg->halg.digestsize = def->digestsize; alg->halg.statesize = def->statesize; -if (IS_SHA1 (def->flags)) - tmpl->hash_zero = sha1_zero_message_hash; -else if (IS_SHA256 (def->flags)) +if (IS_SHA256 (def->flags)) tmpl->hash_zero = sha256_zero_message_hash; base = &alg->halg.base;
drivers/crypto/qce/sha.h +0 -1
@@ -7,7 +7,6 @@#define _SHA_H_#include <crypto/scatterwalk.h> -#include <crypto/sha1.h> #include <crypto/sha2.h> #include "common.h"
drivers/crypto/qce/skcipher.c +2 -95
133 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 74/83 KVM: s390: vsie: zero stale crypto bits
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit 34d5b5b646c91cfb9338d7a12c955a70ffb8c66b upstream.
When shadowing crypto access bits from a format0 apcb (crycb 0 or 1), the bits 64..255 are unchanged from whatever is in the vsie page in the crycb and thus in the apcb. This gives a nested guest potential access to a device no longer available. Zero out the remaining bits.
Message-ID: <[email protected]>
--- arch/s390/kvm/vsie.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/kvm/vsie.c +1 -0
@@ -184,6 +184,7 @@ static int setup_apcb10(struct kvm_vcpu sizeof(struct kvm_s390_apcb0)))return -EFAULT ; +memset (apcb_s,0 ,sizeof (*apcb_s)); apcb_s->apm[0 ] = apcb_h->apm[0 ] & tmp.apm[0 ]; apcb_s->aqm[0 ] = apcb_h->aqm[0 ] & tmp.aqm[0 ] &0xffff000000000000UL ; apcb_s->adm[0 ] = apcb_h->adm[0 ] & tmp.adm[0 ] &0xffff000000000000UL ;
Greg Kroah-Hartman
maintainerPATCH 75/83 usb: core: Add lock to usb_wakeup_notification()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit e263e18a9e7b1ff3e7301f0801c6ff87c31adfb6 upstream.
Add a spin lock to usb_wakeup notification to prevent a race condition with dereferencing freed memory. This could be hit by the xHCI driver as it calls this function from an IRQ and could race with the hub_disconnect() function, which properly grabs this lock to protect the state of the device.
--- drivers/usb/core/hub.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/core/hub.c +3 -0
@@ -757,10 +757,12 @@ void usb_wakeup_notification(struct usb_ {struct usb_hub *hub;struct usb_port *port_dev; +unsigned long flags;if (!hdev)return ; +spin_lock_irqsave (&device_state_lock, flags); hub =usb_hub_to_struct_hub (hdev);if (hub) { port_dev = hub->ports[portnum -1 ];
@@ -770,6 +772,7 @@ void usb_wakeup_notification(struct usb_set_bit (portnum, hub->wakeup_bits);kick_hub_wq (hub); } +spin_unlock_irqrestore (&device_state_lock, flags); }EXPORT_SYMBOL_GPL (usb_wakeup_notification);
Greg Kroah-Hartman
maintainerPATCH 76/83 usb: core: Strengthen error handling in hub_hub_status()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit a29496745aa335d97f617385809583241e118610 upstream.
Add additional error handling after the call to get_hub_status() in hub_hub_status().
get_hub_status() uses usb_control_msg() which does not verify that the message is the correct length, substituting it for usb_control_msg_recv() would also solve this issue but increase memory allocations.
Instead, error handling is copied from the method used in hub_ext_port_status(), which shares the same flow of logic as hub_hub_status().
--- drivers/usb/core/hub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/core/hub.c +3 -1
@@ -998,10 +998,12 @@ static int hub_hub_status(struct usb_hubmutex_lock (&hub->status_mutex); ret =get_hub_status (hub->hdev, &hub->status->hub); -if (ret <0 ) { +if (ret < (int )sizeof (hub->status->hub)) {if (ret != -ENODEV )dev_err (hub->intfdev,"%s failed (err = %d)\n" , __func__, ret); +if (ret >=0 ) + ret = -EIO ; }else { *status =le16_to_cpu (hub->status->hub.wHubStatus); *change =le16_to_cpu (hub->status->hub.wHubChange);
Greg Kroah-Hartman
maintainerPATCH 77/83 ALSA: usb-audio: fix OOB write in snd_usbmidi_novation_output()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marouane El Moufid <[email protected]>
commit 1035a8f63bae28e498b0e7b5ac91d749844a7158 upstream.
snd_usbmidi_novation_output() lays out a two-byte header at transfer_buffer[0..1] and passes &transfer_buffer[2] together with a length of ep->max_transfer - 2 to snd_rawmidi_transmit():
count = snd_rawmidi_transmit(ep->ports[0].substream, &transfer_buffer[2], ep->max_transfer - 2);
ep->max_transfer comes from the output endpoint's wMaxPacketSize via usb_maxpacket(). A malformed or malicious device can advertise a bulk OUT endpoint with a wMaxPacketSize of 1 - the USB core only clamps this value downwards - so ep->max_transfer becomes 1 and the count argument becomes -1.
snd_rawmidi_transmit() passes the negative count on to __snd_rawmidi_transmit_peek(), where "if (count1 > count) count1 = count" leaves count1 negative; get_aligned_size() keeps it negative for a byte-stream substream, so the following memcpy(buffer, ..., count1) runs with a (size_t)-1 length and writes far past the transfer buffer, which was allocated with usb_alloc_coherent(ep->max_transfer).
This is the same class of bug that was fixed for snd_usbmidi_akai_output() in commit 0970274613fb ("ALSA: usb-audio: fix OOB write in snd_usbmidi_akai_output()"); the novation output routine was left unguarded. Bail out when the endpoint cannot hold the two-byte header plus at least one payload byte.
--- sound/usb/midi.c | 2 ++ 1 file changed, 2 insertions(+)
sound/usb/midi.c +2 -0
@@ -871,6 +871,8 @@ static void snd_usbmidi_novation_output(if (!ep->ports[0 ].active)return ; +if (ep->max_transfer <3 ) +return ; transfer_buffer = urb->transfer_buffer; count = snd_rawmidi_transmit(ep->ports[0].substream, &transfer_buffer[2],
Greg Kroah-Hartman
maintainerPATCH 78/83 ALSA: usb-audio: Complete cleanup after system-resume errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Will Porter <[email protected]>
commit 1739a976312e110c93a8dee66a1cdf893a1b187e upstream.
A failed system resume can leave the card unusable until reboot. usb_audio_resume() jumps to err_out when snd_usb_pcm_resume() or snd_usb_mixer_resume() fails. The error path skips the out: block, which restores D0 and decrements chip->num_suspended_intf.
The card stays in SNDRV_CTL_POWER_D3hot, so later control access blocks in snd_power_ref_and_wait(). USB core logs an interface resume callback error. It does not retry that callback, so a later callback cannot complete the skipped cleanup.
usb_audio_suspend() increments num_suspended_intf before returning success. A system-resume callback must consume the system-suspend count even if a component resume fails. Otherwise, the stranded count skews later suspend and resume cycles.
Do not apply this cleanup to runtime-resume errors. Runtime PM can retry -EAGAIN or -EBUSY without another suspend callback. The count must continue to describe that suspended interface. Other runtime-resume errors latch runtime_error in the PM core and do not cause an immediate callback retry.
Both parts of the system-resume error path are longstanding. Commit 88a8516a2128a ("ALSA: usbaudio: implement USB autosuspend") introduced err_out past the D0 restore. Commit 862b2509d157c ("ALSA: usb-audio: Fix inconsistent card PM state after resume") later moved num_suspended_intf-- into the out: block. The error path now skips both operations.
No third-party code is needed to reach the error path. snd_usb_mixer_resume() ends in snd_usb_mixer_activate(), which returns the result of usb_submit_urb() for devices that have a mixer status URB. Its mixer->private_resume hook can also fail through scarlett2_init_notify(). snd_usb_pcm_resume() issues a SET_CUR request to a UAC3 power domain. It can return -EPIPE or -EIO when the device stalls the request.
Route a component error through out: only when system_suspend is nonzero. Continue to return runtime-resume errors through err_out. Later component resume stages remain skipped. The original error still reaches USB core. A later transfer can fail if the device did not recover.
I reproduced the system-resume failure on an Audient iD14 MkI with an out-of-tree diagnostic mixer resume hook. An injected -EIO on the unpatched core left control readers in uninterruptible sleep in snd_power_ref_and_wait() until a reboot. With this patch, the same failure restored control access. A second system suspend and resume also succeeded after I disabled fault injection.
--- sound/usb/card.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
sound/usb/card.c +10 -4
@@ -1278,8 +1278,11 @@ static int usb_audio_resume(struct usb_ilist_for_each_entry (as, &chip->pcm_list, list) { err =snd_usb_pcm_resume (as); -if (err <0 ) - goto err_out; +if (err <0 ) { +if (!chip->system_suspend) + goto err_out; + goto out; + } }/*
@@ -1288,8 +1291,11 @@ static int usb_audio_resume(struct usb_i*/ list_for_each_entry (mixer, &chip->mixer_list, list) { err =snd_usb_mixer_resume (mixer); -if (err <0 ) - goto err_out; +if (err <0 ) { +if (!chip->system_suspend) + goto err_out; + goto out; + } }list_for_each (p, &chip->midi_list) {
Greg Kroah-Hartman
maintainerPATCH 79/83 USB: serial: option: fix slab OOB read in interrupt URB callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiale Yao <[email protected]>
commit 885d802f544ca7bfa8f3984d94233cce715bb6b3 upstream.
The interrupt URB buffer is allocated in setup_port_interrupt_in() based on the endpoint's wMaxPacketSize:
buffer_size = usb_endpoint_maxp(epd);
port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);When a USB device declares wMaxPacketSize = 8 on its interrupt IN endpoint, the buffer is allocated from kmalloc-8 cache (exactly 8 bytes).
If the device sends a short packet (actual_length < wMaxPacketSize), the URB completes with status == 0 and the callback proceeds to read:
data[sizeof(struct usb_ctrlrequest)]
which evaluates to data[8], accessing 1 byte beyond the allocated 8-byte buffer. This results in a slab out-of-bounds read.
Fix this by adding the missing bounds check: first verify that the actual length is large enough to contain the struct usb_ctrlrequest header before accessing req_pkt->bRequestType and req_pkt->bRequest, and then verify that there is an additional byte for the modem signal state before reading data[sizeof(struct usb_ctrlrequest)] inside the conditional. Use sizeof(*req_pkt) instead of sizeof(struct usb_ctrlrequest) for consistency.
--- drivers/usb/serial/option.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/usb/serial/option.c +17 -3
@@ -2690,12 +2690,26 @@ static void option_instat_callback(strucdev_dbg (dev,"%s: NULL req_pkt\n" , __func__);return ; } + +if (urb->actual_length <sizeof (*req_pkt)) { +dev_err (dev,"%s: short packet: %u bytes\n" , __func__, + urb->actual_length); +return ; + } +if ((req_pkt->bRequestType ==0xA1 ) && (req_pkt->bRequest ==0x20 )) { +unsigned char signals;int old_dcd_state; -unsigned char signals = *((unsigned char *) - urb->transfer_buffer + -sizeof (struct usb_ctrlrequest )); + +if (urb->actual_length <sizeof (*req_pkt) +1 ) { +dev_err (dev,"%s: short interrupt transfer: %u bytes\n" , + __func__, urb->actual_length); +return ; + } + + signals = *((unsigned char *)urb->transfer_buffer + +sizeof (*req_pkt));dev_dbg (dev,"%s: signal x%x\n" , __func__, signals);
Greg Kroah-Hartman
maintainerPATCH 80/83 USB: serial: spcp8x5: drop broken carrier detect support
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit d37186bd95a07e334447f47274a38a311dad2172 upstream.
The driver does not support modem status notifications and instead used to fetch the modem status once at open() and subsequently operate on and report stale state.
As part of fixing this, a call to fetch the status was added to carrier_raised(), which does not work as that callback must not sleep (e.g. unlike tiocmget()).
Drop the broken carrier detect support.
--- drivers/usb/serial/spcp8x5.c | 13 ------------- 1 file changed, 13 deletions(-)
drivers/usb/serial/spcp8x5.c +0 -13
@@ -237,18 +237,6 @@ static void spcp8x5_set_work_mode(structdev_err (&port->dev,"failed to set work mode: %d\n" , ret); } -static int spcp8x5_carrier_raised (struct usb_serial_port *port) -{ -u8 msr; -int ret; - - ret =spcp8x5_get_msr (port, &msr); -if (ret || msr &MSR_STATUS_LINE_DCD ) -return 1 ; - -return 0 ; -} -static void spcp8x5_dtr_rts (struct usb_serial_port *port,int on) {struct spcp8x5_private *priv =usb_get_serial_port_data (port);
@@ -460,7 +448,6 @@ static struct usb_serial_driver spcp8x5_ .num_bulk_out = 1, .open = spcp8x5_open, .dtr_rts = spcp8x5_dtr_rts, - .carrier_raised = spcp8x5_carrier_raised, .set_termios = spcp8x5_set_termios, .init_termios = spcp8x5_init_termios, .tiocmget = spcp8x5_tiocmget,
Greg Kroah-Hartman
maintainerPATCH 81/83 USB: c67x00: fix use-after-free in c67x00_add_iso_urb()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit b1e24de475bf2d66fffc9103f3444b783527d55a upstream.
When TD creation fails for the last packet of an isochronous URB, c67x00_add_iso_urb() gives the URB back before updating the endpoint scheduling state.
c67x00_giveback_urb() frees the URB private data, and the completion callback may release the final URB reference. The following accesses to urbp->ep_data, urb->interval, and urbp->cnt can therefore use freed memory.
Update next_frame and cnt before giving back the failed final packet, making the giveback the last operation that uses the URB and its private data.
--- drivers/usb/c67x00/c67x00-sched.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/c67x00/c67x00-sched.c +2 -2
@@ -761,13 +761,13 @@ static int c67x00_add_iso_urb(struct c67 ret); urb->iso_frame_desc[urbp->cnt].actual_length =0 ; urb->iso_frame_desc[urbp->cnt].status = ret; -if (urbp->cnt +1 == urb->number_of_packets) -c67x00_giveback_urb (c67x00, urb,0 ); } urbp->ep_data->next_frame =frame_add (urbp->ep_data->next_frame, urb->interval); urbp->cnt++; +if (ret && urbp->cnt == urb->number_of_packets) +c67x00_giveback_urb (c67x00, urb,0 ); }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 82/83 wifi: mt76: mt7925: ensure tx headroom in usb_sdio_tx_prepare_skb
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
commit ef3e34874d2332d0f63e72c2c35ce5c93568c125 upstream.
mt7925_usb_sdio_tx_prepare_skb() pushes a TX descriptor and a USB header onto every skb and assumes the headroom for them is already there. That holds for locally generated traffic, where mac80211 reserves hw->extra_tx_headroom, but forwarded frames are sent through ieee80211_8023_xmit(), which does not reserve it. Bridge a wired interface to an mt7925u AP and the first forwarded frame that arrives short panics the kernel:
skbuff: skb_under_panic: len:415 put:4 tail:0x19b end:0x640 dev:wlan1 kernel BUG at net/core/skbuff.c:212!
Call trace: skb_panic+0x58/0x60 (P) skb_push+0x58/0x60 mt7925_usb_sdio_tx_prepare_skb+0xf8/0x1b8 [mt7925_common] mt76u_tx_queue_skb+0xa0/0x1f8 [mt76_usb] __mt76_tx_queue_skb+0x54/0xe8 [mt76] mt76_txq_schedule.part.0+0x204/0x478 [mt76] mt76_txq_schedule_all+0x50/0x80 [mt76] mt792x_tx_worker+0x68/0x100 [mt792x_lib] __mt76_worker_fn+0x84/0x150 [mt76]
Whether a given setup hits it depends on how much headroom the ingress netdev leaves in its rx skbs. Reproduced on a Raspberry Pi 5 bridging onboard ethernet to a Netgear A9000; originally reported on an MT7986 router running OpenWrt. Nick Morrow's testing on a Pi 4 (bcmgenet), which leaves more headroom, helped narrow the trigger to the ingress path.
The same bug was fixed on mt7921 by commit 98c4d0abf5c4 ("mt76:
mt7921: don't assume adequate headroom for SDIO headers"), but mt7925 was copied from mt7921 without the fix. Add the same guard here.
--- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7925/mac.c +4 -0
@@ -1425,6 +1425,10 @@ int mt7925_usb_sdio_tx_prepare_skb(strucif (!wcid) wcid = &dev->mt76.global_wcid; + err =skb_cow_head (skb,MT_SDIO_TXD_SIZE +MT_SDIO_HDR_SIZE ); +if (err) +return err; +if (sta) {struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
Greg Kroah-Hartman
maintainerPATCH 83/83 usb: usbfs: fix use-after-free of usb_device in usbdev_release()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Peñaranda <[email protected]>
commit 0dd68b5d01d022fc9c5e71c82a82b0a94d3d0671 upstream.
usbdev_release() drops its reference to the struct usb_device before draining the list of completed async URBs, but that drain path reads back through the same object: free_async() calls dec_usb_memory_use_count() for any URB whose buffer came from the usbfs mmap() region, and its first statement is bus_to_hcd(ps->dev->bus).
After a disconnect the usbfs reference can be the last one, in which case usb_put_dev() frees the device and the subsequent loop reads offset 80 of freed memory and uses the result as a struct usb_hcd *, which hcd_buffer_free_pages() then dereferences.
This is reachable by an unprivileged process that has read/write access to a /dev/bus/usb node: mmap() the fd, submit one URB with a buffer inside the mapping, wait for the device to be unplugged, then munmap() and close(). It reproduces on every attempt rather than being a race, because a live MAP_SHARED vma holds a reference on the struct file, so usbdev_release() cannot run until the last vma is gone and the freeing branch of dec_usb_memory_use_count() is always taken.
BUG: KASAN: slab-use-after-free in dec_usb_memory_use_count+0x3ae/0x410 Read of size 8 at addr ffff8880122ee050 by task poc/769 CPU: 1 UID: 1000 PID: 769 Comm: poc Tainted: G B 6.12.94 #3 Call Trace: dec_usb_memory_use_count+0x3ae/0x410 free_async+0x2aa/0x4f0 usbdev_release+0x375/0x460 __fput+0x3ea/0xb50 __x64_sys_close+0x86/0x100 Allocated by task 11: usb_alloc_dev+0x55/0xd90 hub_event+0x2524/0x43d0 Freed by task 769: kfree+0x121/0x360 device_release+0xd2/0x280 usb_put_dev+0x23/0x30 usbdev_release+0x2d8/0x460
Release the device reference after the drain loop instead. Nothing between the two points requires it to have been dropped.
--- drivers/usb/core/devio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/core/devio.c +1 -1
@@ -1113,7 +1113,6 @@ static int usbdev_release(struct inode *if (!ps->suspend_allowed)usb_autosuspend_device (dev);usb_unlock_device (dev); -usb_put_dev (dev);put_pid (ps->disc_pid);put_cred (ps->cred);
@@ -1122,6 +1121,7 @@ static int usbdev_release(struct inode *free_async (as); as =async_getcompleted (ps); } +usb_put_dev (dev);kfree (ps);return 0 ;
Hi,
Build tested in our x86,arm64,loongarch,riscv config successfully without error.
Best Regards
Wentao Guan
Log:
Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #2 SMP PREEMPT_DYNAMIC Tue Sep 1 00:20:48 CST 2026 Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #3 SMP PREEMPT_DYNAMIC Tue Sep 1 00:37:39 CST 2026 Linux version 6.18.49-rc1+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT
Linux version 6.18.49-rc1+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #4 SMP PREEMPT Tue Sep 1 00:54:32 CST 2026 Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin18) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC
Linux version 6.18.49-rc1-g52d189f2c6b3 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin18) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #1 SMP PREEMPT_DYNAMIC Mon Aug 31 23:58:15 CST 2026
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.18.49-rc1-g52d189f2c6b3 #1 SMP PREEMPT_DYNAMIC Mon Aug 31 18:39:24 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Am 31.08.2026 um 15:33 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.49-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Hi!
Quoted 4 lines
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.18.y
Best regards,
Pavel
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.49-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Quoted 8 lines · On Mon, 31 Aug 2026 15:33:36 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64 and arm32:
Thanks!
Cheers,
Miguel
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.49-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.49 release. There are 83 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 02 Sep 2026 13:32:19 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.49-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
Tested on an amd64 laptop (Lenovo ThinkPad T14 Gen 1). Working well, no regressions observed.
Signature · 1 line
-Barry K. Nathan <[email protected]>