7.2.11-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainercover 7.2.11-rc1 review
This is the start of the stable review cycle for the 7.2.11 release. There are 281 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 Thu, 15 Oct 2026 11:28:22 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.2.11-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-7.2.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 7.2.11-rc1
Lorenzo Stoakes (ARM) <[email protected]>
mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge
Jens Axboe <[email protected]>
io_uring/kbuf: don't charge provided buffer rings to RLIMIT_MEMLOCK
Hengyu Liang <[email protected]>
io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK
Ali Ahmet Memis <[email protected]>
io_uring/memmap: account the pages a compound region really uses
Adrian Betschart <[email protected]>
drm/amd/display: Don't replace a sink mode that shares the native totals
Kuba Piecuch <[email protected]>
sched_ext: Call ops.dequeue() when a task arrives on a remote local DSQ
Kuba Piecuch <[email protected]>
sched_ext: Generate qseq from a per-task counter
Maíra Canal <[email protected]>
drm/vc4: Fix binner slot allocation failing on an idle GPU
Maíra Canal <[email protected]>
drm/vc4: Disable the V3D interrupt across runtime suspend
Ilia Gavrilov <[email protected]>
vsock: Fix memory leak in vmci_transport_recv_dgram_cb()
Fernando Fernandez Mancera <[email protected]>
net: openvswitch: validate transport header presence in set_ipv6_addr
Vadim Fedorenko <[email protected]>
ptp: ocp: fix PCIe delay estimation calculation
Willem de Bruijn <[email protected]>
net/packet: call packet_parse_headers after virtio_net_hdr_to_skb
Petr Machata <[email protected]>
mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()
Li RongQing <[email protected]>
net/mlx5e: Order ICOSQ cc update after CQ doorbell
Tianyi Gao <[email protected]>
veth: fix peer NETDEV_XDP_ACT_NDO_XMIT after GRO is toggled while down
Gyeyoung Baek <[email protected]>
drm/imagination: Fix reference and vm_bo handling in remap()
Haishuang Yan <[email protected]>
bareudp: set the inner protocol to the protocol of the packet
Eric Dumazet <[email protected]>
flow_dissector: avoid u16 truncation of hlen in bpf_flow_dissect()
Pavan Chebbi <[email protected]>
bnxt_en: Re-write the BARs following any type of PCIe errors
Michael Chan <[email protected]>
bnxt_en: Fix driver init in kdump kernel
Michael Chan <[email protected]>
bnxt_en: Add bnxt_clear_bars() helper
Zongmin Zhou <[email protected]>
riscv: ptrace: Zero-initialize regset buffers before copyin
Leo Yu-Chi Liang <[email protected]>
riscv: fix NR_CPUS range leaking 64-bit default onto 32-bit builds
Richard Fitzgerald <[email protected]>
ASoC: sdw_utils: Switch CS35L56/57/62/63 to use OT25 DAI
Stefan Binding <[email protected]>
ASoC: sdw_utils: Add codec info for CS35L62
Haishuang Yan <[email protected]>
pfcp: make sure the SEID is linear before reading it
Justin Chen <[email protected]>
net: bcmgenet: if UMAC was suspended in SW_RESET, restore it to SW_RESET
Or Har-Toov <[email protected]>
Revert "net/mlx5: E-Switch, preserve max tx speed on vport state modification"
Victor Nogueira <[email protected]>
net/sched: cls_route: reject change with no routing attribute
Haishuang Yan <[email protected]>
devlink: fix devlink_rel reference leak when notify work is pending
Quentin Freimanis <[email protected]>
net: sparx5: start the TOD counters on non-PTP lan969x variants
Eric Dumazet <[email protected]>
net: always dissect GSO packets in __virtio_net_hdr_to_skb()
Eric Dumazet <[email protected]>
flow_dissector: avoid u16 truncation of skb->len when computing thoff
Waiman Long <[email protected]>
cgroup/cpuset: Call is_in_v2_mode() after acquiring cpuset_mutex in cpuset_handle_hotplug()
Han Gao <[email protected]>
spi: sg2044-nor: Honor SPI clock limits
Han Gao <[email protected]>
spi: sg2044-nor: Return transfer errors
Marek Szyprowski <[email protected]>
ASoC: samsung: i2s: enable op_clk in probe to balance runtime PM
Alvin Šipraga <[email protected]>
ASoC: adau1372: fix invalid default state of output ASRC and DAC muxes
Alvin Šipraga <[email protected]>
ASoC: adau1372: allow sleepy powerdown GPIOs
Yingying Tang <[email protected]>
Revert "wifi: ath12k: add panic handler"
Mallesh Koujalagi <[email protected]>
drm/xe/sysctrl: Fix mailbox header handling
Devin Wittmayer <[email protected]>
wifi: mt76: mt792x: pick the SAR table layout from the table itself
Junjie Cao <[email protected]>
wifi: mt76: mt792x: treat 0xff ACPI SAR entries as no limit
Devin Wittmayer <[email protected]>
wifi: mt76: mt7925: don't put the band auto marker in TGID
Nicolas Cavallari <[email protected]>
wifi: mt76: mt7915: disable rx napi when removing device
Tao Gong <[email protected]>
wifi: mt76: mt7996: fix struct mt7996_mcu_wed_rro_ba_delete_event layout
Aaron Ma <[email protected]>
wifi: mt76: mt7925: restore the legacy BSS after MLO teardown
Felix Fietkau <[email protected]>
wifi: mt76: use ALTX queue for packets to disassociated stations
Felix Fietkau <[email protected]>
wifi: mt76: account non-AQL frames per peer rather than per link
Felix Fietkau <[email protected]>
wifi: mt76: add PS buffering support for HW-managed TIM drivers
Felix Fietkau <[email protected]>
wifi: mac80211: add ieee80211_txq_aql_pending()
Felix Fietkau <[email protected]>
wifi: mac80211: add AQL support for multicast packets
Felix Fietkau <[email protected]>
wifi: mt76: mt7996: take over connection monitoring
Pengpeng Hou <[email protected]>
scsi: ufs: mediatek: Handle mPHY power-on failures
Jakub Kicinski <[email protected]>
Revert "net: stmmac: propagate PTP addend and system time programming errors"
Aurelien Jarno <[email protected]>
riscv: vector: Fix output operands in context save
Troy Mitchell <[email protected]>
riscv: vector: Fix data pointer constraints in context save/restore
Leto Liu (刘涛) <[email protected]>
net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
Ovidiu Panait <[email protected]>
net: stmmac: Disable S-Tag processing on dwmac4
Ovidiu Panait <[email protected]>
net: stmmac: Do not advertise S-VLAN stripping when it is disabled
Or Har-Toov <[email protected]>
net/mlx5: Lag, split aggregate speed into oper and max helpers
Jakub Kicinski <[email protected]>
net: make dev_xdp_sb_prog_count() see programs attached through a link
Tvrtko Ursulin <[email protected]>
drm/xe: Do not emit Wa_16010904313 twice
Alan Previn <[email protected]>
drm/xe/mmio: Fix xe_mmio_wait32() to honor delay/sleep maximums
Filipe Manana <[email protected]>
btrfs: fix lost error return value in btrfs_listxattr()
Filipe Manana <[email protected]>
btrfs: fix xattr replace when multiple xattrs are packed in the same item
Yang Xiuwei <[email protected]>
btrfs: don't stash io_uring encoded data across -EAGAIN
Yang Xiuwei <[email protected]>
btrfs: unlock inode and extent in caller when io_uring read extent fails
Yang Xiuwei <[email protected]>
btrfs: free iov when btrfs_uring_read_extent() fails
Yang Xiuwei <[email protected]>
btrfs: always return -EIOCBQUEUED after btrfs_uring_read_extent_endio
Shin'ichiro Kawasaki <[email protected]>
zloop: zero out only the unread tail of short reads
Haibo Chen <[email protected]>
spi: spi-nxp-fspi: exit stop mode before waiting for DLL lock
Fuad Tabba <[email protected]>
arm64/boot: Don't set PMUv3p9 FGT2 bits without PMUv3
Sang-Hoon Choi <[email protected]>
nvmet: use the local P2P device on metadata allocation failure
Guixin Liu <[email protected]>
nvmet: return Invalid Field for invalid NSIDs feature 82h
Bryan Fraschetti <[email protected]>
ice: Restore Ordered MMIO Writes for Tx Doorbells
Jakub Kicinski <[email protected]>
bonding: fix the program leak when XDP is replaced
Mahantesh Salimath <[email protected]>
tee: optee: ffa: support shared memory offsets on large-page kernels
Lorenzo Bianconi <[email protected]>
net: stmmac: propagate PTP addend and system time programming errors
Felix Fietkau <[email protected]>
wifi: mt76: mt7996: program a link again if the driver holds it
Sang-Hoon Choi <[email protected]>
cxgb4/ch_ktls: disable softirqs around tid_list erases
Shashank Mohan Jain <[email protected]>
lib/dim: fix 32-bit overflow in dim_calc_stats() rates
Omar Ramadan <[email protected]>
amt: send the relay's General Query directly from the receive path
Jamal Hadi Salim <[email protected]>
net/sched: em_text: reject unterminated algo before autoload
Maíra Canal <[email protected]>
drm/vc4: Use kvmalloc_objs() for the BO cache size list
Maíra Canal <[email protected]>
drm/vc4: Free the BO cache size list on teardown
Myeonghun Pak <[email protected]>
drm/aspeed: Balance the display clock enable on teardown
Sang-Hoon Choi <[email protected]>
gpio: exar: initialize the ID before registering its cleanup
Oleg Keri <[email protected]>
drm/dp: don't mark the AUX backlight enabled when enabling failed
Waiman Long <[email protected]>
cgroup/cpuset: Don't access cpuset_cgrp_subsys.root in is_in_v2_mode()
Cristian Ciocaltea <[email protected]>
drm/bridge: Fix unlocked list access in drm_bridge_attach()
Cristian Ciocaltea <[email protected]>
drm/bridge: Fix unlocked list_del in drm_bridge_add()
Sai Teja Aluvala <[email protected]>
Bluetooth: btintel_pcie: Add shared HW reset for clean start
Ravindra <[email protected]>
Bluetooth: btintel_pcie: fix TX descriptor bounds check
Naomi Chu <[email protected]>
scsi: ufs: core: Hold a clock reference across the probe
Christian Brauner <[email protected]>
fs: don't let a migrating task hide its reference from do_umount()
Christian Brauner <[email protected]>
mount: refuse MOVE_MOUNT_SET_GROUP on an unbindable mount
Peng Fan <[email protected]>
iommu/dma: skip swiotlb bounce for DMA_ATTR_MMIO in iommu_dma_map_phys
Vincent Jardin <[email protected]>
arm64: dts: lx2160a: fix the iic5 spi3 pinmux offset and value
Vincent Jardin <[email protected]>
arm64: dts: lx2160a: fix IIC1 pinmux submask rejected by pinctrl-single
Vincent Jardin <[email protected]>
arm64: dts: lx2160a: fix incorrect pinmux
Taniya Das <[email protected]>
clk: qcom: gpucc-kaanapali: Mark the GPU CX GDSC as votable
Taniya Das <[email protected]>
clk: qcom: gpucc-glymur: Mark the GPU CX GDSC as votable
Luca Weiss <[email protected]>
clk: qcom: gcc-kaanapali: Fix always-enabling PCIE_RSCC clocks
Luca Weiss <[email protected]>
clk: qcom: gcc-eliza: Fix always-enabling PCIE_RSCC clocks
Darrick J. Wong <[email protected]>
xfs: fix exchange-range-to-eof file size exchange
Norbert Szetei <[email protected]>
xfs: stop exchanging reflink flags when exchanging mappings
Christian Brauner <[email protected]>
namespace: keep the lock on a mount that a propagated copy is moved beneath
Christian Brauner <[email protected]>
namespace: handle mount locking for automounts correctly
Christian Brauner <[email protected]>
namespace: never expire a locked mount
Christian Brauner <[email protected]>
nullfs: don't update the access time
Christian Brauner <[email protected]>
namespace: refuse an automount below a mount that is in no namespace
Christian Brauner <[email protected]>
fcntl: refuse F_SET_RW_HINT on an immutable inode
Christian Brauner <[email protected]>
namei: don't reveal overmounted entries in refwalk
Christian Brauner <[email protected]>
namespace: unhash a dentry before detaching the mounts on it
Christian Brauner <[email protected]>
namespace: don't let a pseudo dentry become the root of a mount
Christian Brauner <[email protected]>
unshare: don't drop active namespace references that were never taken
Christian Brauner <[email protected]>
dcache: don't put a mountpoint on a dentry that's being removed
Christian Brauner <[email protected]>
namespace: check the mounts before reading their parents in pivot_root()
Christian Brauner <[email protected]>
namespace: remove the fsnotify marks of a mount namespace in process context
Christian Brauner <[email protected]>
namespace: don't reconfigure internal superblocks via remount and umount
Christian Brauner <[email protected]>
namespace: look at the topmost mount for a mount namespace file
Christian Brauner <[email protected]>
namespace: keep covered mounts covered in OPEN_TREE_NAMESPACE
Christian Brauner <[email protected]>
namespace: check a recursive bind mount for mount namespace loops
Christian Brauner <[email protected]>
namespace: check a submount for references right before unmounting it
Christian Brauner <[email protected]>
namespace: queue a mount only once for mount notifications
Christian Brauner <[email protected]>
namespace: check the target before walking it in do_mount_setattr()
Christian Brauner <[email protected]>
fs: refuse fspick() on internal superblocks
Christian Brauner <[email protected]>
namespace: don't copy an unmounted mount tree
Christian Brauner <[email protected]>
namespace: don't inherit MNT_UMOUNT in clone_mnt()
Christian Brauner <[email protected]>
statmount: read the parent of an unmounted mount under mount_lock
Christian Brauner <[email protected]>
namespace: reset the old parent's ->overmount in mnt_change_mountpoint()
Christian Brauner <[email protected]>
fs: don't silently unmount busy mounts
Christian Brauner <[email protected]>
mount: keep a copied mount unbindable
Leo Li <[email protected]>
drm/amd/display: disable self-refresh on tearing flips
Leo Li <[email protected]>
drm/amd/display: Fix direct scanout alpha on some DRM_FORMATs
Jesse Zhang <[email protected]>
drm/amdgpu/userq: return the memdup_user() error for the user MQD
Jesse Zhang <[email protected]>
drm/amdgpu/userq: only accept doorbell BOs as queue doorbell
Mikhail Gavrilov <[email protected]>
drm/amdgpu: copy debugfs register data outside the GRBM/SRBM locks
Alex Deucher <[email protected]>
drm/amdgpu: make Mac FB workaround generic
Vitaly Prosyak <[email protected]>
drm/amdgpu: serialize vblank counter reads against GPU reset
Haojie Li <[email protected]>
drm/amdkfd: fix dma_buf reference leak in get_dmabuf_info
Saleel Kudchadker <[email protected]>
drm/amdkfd: align SDMA doorbell base for shader doorbell writes
Felix Gu <[email protected]>
drm/bridge: th1520-dw-hdmi: Fix remove() callback
Felix Gu <[email protected]>
drm/bridge: th1520-dw-hdmi: Fix error check on dw_hdmi_probe() return value
Thomas Hellström <[email protected]>
drm/xe: Fix stale pinned_link entry when fb-pin performs the final unpin
Thomas Hellström <[email protected]>
drm/xe: Fix shrinker accounting double-subtraction on nested external pins
Fan Wu <[email protected]>
drm/xe/i2c: cancel the client work on remove
Zack Rusin <[email protected]>
drm/vmwgfx: validate pitch coming from userspace
Wentao Liang <[email protected]>
drm/vc4: Fix firmware reference leak in vc4_drm_bind()
Fan Wu <[email protected]>
drm/vc4: drain the hangcheck timer and works on V3D unbind
Osama Abdelkader <[email protected]>
drm/panthor: validate userspace queue count against initialized firmware slot count
Gyeyoung Baek <[email protected]>
drm/imagination: Size page table preallocation by device address
Krzysztof Karas <[email protected]>
drm/i915/gt: Unmask interrupts only when ACTIVE is true
Krzysztof Karas <[email protected]>
drm/i915/gem: Prevent overstepping exec array boundary
Sajal Gupta <[email protected]>
drm/gud: don't keep a connector without a CRTC as connector_state
Nguyen Ngoc Thang <[email protected]>
drm/fb-helper: defer setup when fbdev_probe() fails, not just on -EAGAIN
Palla Raghunath <[email protected]>
Bluetooth: RFCOMM: Fix NULL tty_dev dereference in rfcomm_dev_shutdown
Mikhail Gavrilov <[email protected]>
Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
Maxim Skokov <[email protected]>
Bluetooth: RFCOMM: free the skb when the DLC has no owner
Aldo Ariel Panzardo <[email protected]>
Bluetooth: SCO: serialise sco_conn lifetime against sco_recv_scodata()
Iaroslav Voitovych <[email protected]>
Bluetooth: MGMT: Fix status of pending commands flushed on power off
Chengfeng Ye <[email protected]>
Bluetooth: ISO: Serialize concurrent connect calls
Chengfeng Ye <[email protected]>
Bluetooth: ISO: Reject concurrent BIS listener setup
Chengfeng Ye <[email protected]>
Bluetooth: hci_sync: Fix command skb lifetime during scan setup
Chengfeng Ye <[email protected]>
Bluetooth: hci_sock: Serialize dead-device detachment
Runyu Xiao <[email protected]>
Bluetooth: btintel_pcie: use managed IRQ teardown
Chen Pei <[email protected]>
riscv: ptrace: reject CFI regset access when extensions are absent
Wei-Jie Hung <[email protected]>
riscv: patch: fix handling of bpf-jit execmem addresses
Shao Mingyin <[email protected]>
riscv: lib: Fix ZBB strnlen wrap-around regression on huge counts
Zongmin Zhou <[email protected]>
riscv: hwprobe: use _BITULL() rather than BIT() in MIPS vendor uapi header
Ziyi Guo <[email protected]>
riscv: futex: untag the user pointer before the atomic access
Karl Mehltretter <[email protected]>
riscv: fix load_unaligned_zeropad() fixup for RV32
Zongmin Zhou <[email protected]>
riscv: errata: select RISCV_ALTERNATIVE_EARLY for THEAD GHOSTWRITE
Ziyi Guo <[email protected]>
riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp
Stanley Jhu <[email protected]>
scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ
Stanley Jhu <[email protected]>
scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()
Runyu Xiao <[email protected]>
scsi: qedi: Initialize callback state before registration
Ahmed Abdelhaleem Ahmed <[email protected]>
scsi: ch: Do not keep references to data transfer element devices
Shawn Lin <[email protected]>
pmdomain: rockchip: propagate subdomain add errors
Shawn Lin <[email protected]>
pmdomain: rockchip: fix clock leak on domain probe failure
Shawn Lin <[email protected]>
pmdomain: rockchip: don't ignore clock lookup errors on attach
Ming Qian <[email protected]>
pmdomain: imx8m-blk-ctrl: Serialize power on/off across sibling domains
Ridham Khurana <[email protected]>
regulator: tps6594-regulator: Fix n_linear_ranges for TPS65224 BUCK2-4
Alexey Charkov <[email protected]>
regulator: of: fill in supply names in of_regulator_bulk_get_all()
Abhishek Ojha <[email protected]>
regulator: ltc3676: don't read the write-only HRST and CLIRQ registers
Alexey Charkov <[email protected]>
power: sequencing: pcie-m2: Fix leaking array from of_regulator_bulk_get_all()
Shao-Fu Chen <[email protected]>
optee: register TEE devices only once fully initialized
Denis V. Lunev <[email protected]>
openvswitch: fix soft lockup in the netlink flow dump
Karl Bonde Torp <[email protected]>
nvme: fix swapped ZRASF zone state values for full and read only
Weiming Shi <[email protected]>
net: team: free skb when broadcast has no txable port
Weiming Shi <[email protected]>
net: team: stop reusing skb after queue override
Suraj Gupta <[email protected]>
net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
Fredrik Nyberg <[email protected]>
net: usb: ax88179_178a: fix rx frame length for non-last packets
Daniel Machon <[email protected]>
net: sparx5: free the matchall entry on destroy
Josef Bacik <[email protected]>
net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits()
Sebastien Royen <[email protected]>
net: dsa: microchip: fix KSZ8765 fiber detection
Zixuan Chai <[email protected]>
net: bridge: avoid recursive multicast port cleanup
Chengfeng Ye <[email protected]>
net/smc: protect clcsock lifetime in smc_getname
Quchaosheng <[email protected]>
net/packet: guard the ll header push in packet_rcv_spkt()
Guangshuo Li <[email protected]>
mmc: sdhci-sprd: disable runtime PM on remove
Yibo Tan <[email protected]>
mmc: mtk-sd: Cancel request timeout work on remove
Guangshuo Li <[email protected]>
mmc: cavium-thunderx: destroy slot platform devices on remove
Guangshuo Li <[email protected]>
mmc: cavium-octeon: destroy slot platform devices on remove
Mikulas Patocka <[email protected]>
dm: fix reading free memory in do_resume
Ma Xinmeng <[email protected]>
dm-snap: reject the transient exception store for snapshot-merge
Ben Cressey <[email protected]>
dm-integrity: fix buffer overflow in inline mode with large tag size
Ben Cressey <[email protected]>
dm-crypt: reject the lmk IV mode with AEAD ciphers
Mikhail Gavrilov <[email protected]>
mm: don't schedule deferred kernel page table freeing while booting
Lorenzo Stoakes (ARM) <[email protected]>
mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
Nguyen Ngoc Thang <[email protected]>
memstick: rtsx_usb_ms: complete requests after eject instead of dropping them
Raj Ojha <[email protected]>
memstick: core: wait for request completion before freeing card
성병찬 <[email protected]>
KEYS: Fix add_key() race with keyring restriction
Karl Mehltretter <[email protected]>
keys: finalize persistent keyring timeout after link attempt
Daehyeon Ko <[email protected]>
ip6_gre: remove obsolete ERSPAN PMTU update
Natasha Klaus <[email protected]>
io_uring/net: populate CONNECT filter fields for 24-byte sockaddr_in6
Eugene Gvozdetsky <[email protected]>
io_uring/register: don't exempt disabled rings from task restrictions
Tristan Madani <[email protected]>
ice: fix metadata_dst refcount handling on representor teardown
Xuanqiang Luo <[email protected]>
ice: fix use-after-free in dynamic port cleanup
Mingming Cao <[email protected]>
ibmveth: fix TX LTB and filter unwind on open-fail
Mingming Cao <[email protected]>
ibmveth: h_free logical LAN on open-fail after register
Joshua Washington <[email protected]>
gve: fix XSK buffer leak on error descriptor
Joshua Washington <[email protected]>
gve: fix XSK buffer leak when rings are stopped
Joshua Washington <[email protected]>
gve: fix napi_disable deadlock when attempting to disable XSK pools
Jose Ignacio Tornos Martinez <[email protected]>
iavf: send MAC change request synchronously
Ridham Khurana <[email protected]>
gpio: xilinx: fix runtime PM leak on request error path
Fan Wu <[email protected]>
gpio: mpsse: fix race when arming the IRQ poll worker
Eric Biggers <[email protected]>
fsverity: RCU-delay the freeing of struct fsverity_info
Vishal Badole <[email protected]>
EDAC/amd64: Mask UMC chip select to the four implemented selects
Tony Nguyen <[email protected]>
e1000e: add system to disable K1 list
Carlos Llamas <[email protected]>
selftests/mm: cleanup -Wformat issues in hugetlb-mmap
Hui Peng <[email protected]>
sctp: copy zeroed stats to user in sctp_getsockopt_pr_streamstatus() when !streamoute
Stephen Smalley <[email protected]>
selinux: preserve NATIVE_LABELS on already-initialized sb in set_mnt_opts
Christian Göttsche <[email protected]>
selinux: fix data race on AVC latest_notif
Yong-Xuan Wang <[email protected]>
RISC-V: Clear HSTATUS.HU on CPU initialization
Johannes Berg <[email protected]>
Revert "wifi: libertas: reject short monitor TX frames"
Chengfeng Ye <[email protected]>
tipc: hold a reference to nodes found by link name
Yuqi Xu <[email protected]>
tipc: destroy topsrv workqueues before closing connections
Daehyeon Ko <[email protected]>
tcp: reject net_iov in zerocopy receive mapping hints
Marek Szyprowski <[email protected]>
swiotlb: fix default_swiotlb_limit() for non-growable default pool
Sabrina Dubroca <[email protected]>
strparser: make sure __strp_recv isn't running before tearing down the parser
Georgiy Osokin <[email protected]>
tee: shm: reject zero-sized allocations in tee_dyn_shm_alloc_helper()
Josef Bacik <[email protected]>
xen/netfront: don't leak the skb when xennet_fill_frags() fails
Borislav Petkov (AMD) <[email protected]>
x86/CPU/AMD: Fix AMD TLBI Erratum #1718
Pavankumar Kondeti <[email protected]>
workqueue: Fix NULL current_pwq deref in chained work check
Jason A. Donenfeld <[email protected]>
wireguard: noise: reject response consumption after intermediate initiation
Ramses de Norre <[email protected]>
wireguard: queueing: preserve tstamp_type when encapsulating packet
Lu Huang <[email protected]>
wifi: mt76: mt7996: fix uninitialized buf read in mt7996_variant_fem_init()
Cristian Papa <[email protected]>
wifi: mt76: mt7603: initialize global station WCID
Michele Dionisio <[email protected]>
wifi: brcmfmac: fix P2P device removal race in brcmf_detach()
Daehyeon Ko <[email protected]>
vsock/virtio: account only unread bytes in read_skb()
Ji-Ze Hong (Peter Hong) <[email protected]>
usb: f81604: fix struct f81604_int_data size mismatch
Palla Raghunath <[email protected]>
dm ioctl: don't let data_start run past the buffer
Daehyeon Ko <[email protected]>
cipso: adjust cached option offsets when removing CIPSO
Waiman Long <[email protected]>
cgroup/cpuset: Handle cpu hotplug race in guarantee_active_cpus()
Oliver Hartkopp <[email protected]>
can: fix unique skb identifier regression under RPS
zjamg <[email protected]>
can: dev: init_can_skb(): restore skb header initialization
Wentao Liang <[email protected]>
btrfs: scrub: fix local_root reference leak in scrub_print_warning_inode()
Hengyu Liang <[email protected]>
ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands
Michael Garland <[email protected]>
ASoC: amd: yc: Add DMI quirk for Acer Aspire Go 15 (AG15-21P)
Karl Mehltretter <[email protected]>
arm64: irq: exclude the softirq stack switch from KCOV
Mohamed Yassine Jebabli <[email protected]>
ALSA: hda/tas2781: Accept V1 calibration data without CRC
Harin Lee <[email protected]>
ALSA: ctxfi: Fix memory leakage when clearing DAO input mappers
Krzysztof Furman <[email protected]>
Input: xpad - add support for Corsair Novablade Pro
Bihaan Sen <[email protected]>
Input: xpad - add support for 8BitDo Pro 2 Wired Controller for Xbox
Haotian Zhang <[email protected]>
Input: ati_remote2 - fix type confusion in device attribute handlers
Daehyeon Ko <[email protected]>
ipv6: do not warn on route notification size race
Daehyeon Ko <[email protected]>
ipv4: do not warn on route notification size race
Daehyeon Ko <[email protected]>
ipv4: stop route notification sizing when nexthop group shrinks
Daehyeon Ko <[email protected]>
ipv4: stop exception dump when nexthop group shrinks
Daehyeon Ko <[email protected]>
ipv4: stop PMTU walk when nexthop group shrinks
Alice Ryhl <[email protected]>
rust_binder: reschedule node refcount update on thread exit
Michael S. Tsirkin <[email protected]>
ipv4: validate checksum_start before completing checksum
Ido Schimmel <[email protected]>
ipv6: udp: Create exceptions before socket matching
Ido Schimmel <[email protected]>
ipv4: udp: Create exceptions before socket matching
Ido Schimmel <[email protected]>
ipv6: Fix redirect exception creation for UDP/RAW sockets
Jerome Tollet <[email protected]>
net/mlx5e: Prevent stale XSK buffer release on MPWQE refill retry
Jerome Tollet <[email protected]>
net/mlx5e: Prevent stale XSK buffer release on refill retry
Matthew Wilcox (Oracle) <[email protected]>
fs: Free any excess xarray nodes in clear_inode()
Eric Dumazet <[email protected]>
bnxt_en: fix DMA mapping length for padded small packets
-------------
Diffstat:
Documentation/networking/strparser.rst | 2 +- Makefile | 4 +- arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 19 +- arch/arm64/include/asm/el2_setup.h | 5 +- arch/arm64/kernel/Makefile | 3 + arch/riscv/Kconfig | 5 +- arch/riscv/Kconfig.errata | 1 + arch/riscv/include/asm/cpufeature.h | 2 + arch/riscv/include/asm/futex.h | 2 + arch/riscv/include/asm/scs.h | 17 +- arch/riscv/include/asm/vector.h | 8 +- arch/riscv/include/uapi/asm/vendor/mips.h | 4 +- arch/riscv/kernel/cpufeature.c | 12 + arch/riscv/kernel/entry.S | 2 +- arch/riscv/kernel/patch.c | 2 +- arch/riscv/kernel/ptrace.c | 8 + arch/riscv/kernel/setup.c | 2 + arch/riscv/kernel/smpboot.c | 2 + arch/riscv/kernel/suspend.c | 2 + arch/riscv/lib/strnlen.S | 20 +- arch/riscv/mm/extable.c | 4 +- arch/um/drivers/vector_transports.c | 1 + arch/x86/include/asm/cpufeatures.h | 3 + arch/x86/include/asm/tlb.h | 6 + arch/x86/kernel/cpu/amd.c | 4 + drivers/android/binder/node.rs | 20 +- drivers/android/binder/node/wrapper.rs | 34 ++- drivers/ata/libata-scsi.c | 13 +- drivers/block/zloop.c | 31 ++- drivers/bluetooth/btintel_pcie.c | 17 +- drivers/clk/qcom/gcc-eliza.c | 6 +- drivers/clk/qcom/gcc-kaanapali.c | 6 +- drivers/clk/qcom/gpucc-glymur.c | 2 +- drivers/clk/qcom/gpucc-kaanapali.c | 2 +- drivers/edac/amd64_edac.c | 4 +- drivers/gpio/gpio-exar.c | 2 +- drivers/gpio/gpio-mpsse.c | 24 +- drivers/gpio/gpio-xilinx.c | 9 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 77 ++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 17 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 5 + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 13 +- drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 9 +- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 32 ++- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 7 + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 26 ++- .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 20 +- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 5 +- drivers/gpu/drm/bridge/th1520-dw-hdmi.c | 8 +- drivers/gpu/drm/display/drm_dp_helper.c | 4 +- drivers/gpu/drm/drm_bridge.c | 8 +- drivers/gpu/drm/drm_fb_helper.c | 6 +- drivers/gpu/drm/gud/gud_pipe.c | 1 + drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 3 +- drivers/gpu/drm/imagination/pvr_mmu.c | 25 +- drivers/gpu/drm/imagination/pvr_vm.c | 8 +- drivers/gpu/drm/panthor/panthor_sched.c | 3 + drivers/gpu/drm/vc4/vc4_bo.c | 5 +- drivers/gpu/drm/vc4/vc4_drv.c | 5 +- drivers/gpu/drm/vc4/vc4_drv.h | 2 +- drivers/gpu/drm/vc4/vc4_gem.c | 8 +- drivers/gpu/drm/vc4/vc4_irq.c | 24 +- drivers/gpu/drm/vc4/vc4_v3d.c | 65 +++--- drivers/gpu/drm/vc4/vc4_validate.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c | 26 ++- drivers/gpu/drm/xe/display/xe_fb_pin.c | 6 +- drivers/gpu/drm/xe/xe_bo.c | 139 ++++++++--- drivers/gpu/drm/xe/xe_bo.h | 2 + drivers/gpu/drm/xe/xe_i2c.c | 5 +- drivers/gpu/drm/xe/xe_lrc.c | 38 +-- drivers/gpu/drm/xe/xe_mmio.c | 5 +- drivers/gpu/drm/xe/xe_sysctrl_mailbox.c | 16 +- drivers/input/joystick/xpad.c | 4 + drivers/input/misc/ati_remote2.c | 12 +- drivers/iommu/dma-iommu.c | 4 +- drivers/md/dm-crypt.c | 7 +- drivers/md/dm-integrity.c | 4 +- drivers/md/dm-ioctl.c | 14 +- drivers/md/dm-snap.c | 14 ++ drivers/memstick/core/memstick.c | 8 +- drivers/memstick/host/rtsx_usb_ms.c | 31 +-- drivers/mmc/host/cavium-octeon.c | 5 +- drivers/mmc/host/cavium-thunderx.c | 5 +- drivers/mmc/host/mtk-sd.c | 1 + drivers/mmc/host/sdhci-sprd.c | 4 + drivers/net/amt.c | 48 ++-- drivers/net/bareudp.c | 3 +- drivers/net/bonding/bond_main.c | 8 +- drivers/net/can/dev/skb.c | 4 + drivers/net/can/usb/f81604.c | 2 +- drivers/net/can/vxcan.c | 3 + drivers/net/dsa/microchip/ksz_common.h | 2 +- drivers/net/ethernet/airoha/airoha_eth.c | 32 ++- drivers/net/ethernet/airoha/airoha_eth.h | 2 + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 199 ++++++++++------ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 - drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 11 + .../chelsio/inline_crypto/ch_ktls/chcr_ktls.c | 4 +- drivers/net/ethernet/google/gve/gve_main.c | 8 +- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 13 +- drivers/net/ethernet/ibm/ibmveth.c | 22 +- drivers/net/ethernet/intel/e1000e/netdev.c | 7 + drivers/net/ethernet/intel/iavf/iavf.h | 11 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 85 +++++-- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 99 +++++++- drivers/net/ethernet/intel/ice/devlink/port.c | 2 +- drivers/net/ethernet/intel/ice/ice_eswitch.c | 2 +- drivers/net/ethernet/intel/ice/ice_txrx.c | 4 +- .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.c | 2 + drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 13 +- .../ethernet/mellanox/mlx5/core/esw/adj_vport.c | 20 -- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 79 +++++-- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 24 -- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 10 +- .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 9 +- drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c | 28 ++- .../ethernet/microchip/sparx5/sparx5_tc_matchall.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 +- drivers/net/ethernet/xilinx/xilinx_axienet.h | 7 +- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 53 ++++- drivers/net/pfcp.c | 7 + drivers/net/team/team_core.c | 16 +- drivers/net/team/team_mode_broadcast.c | 2 + drivers/net/tun.c | 23 +- drivers/net/usb/ax88179_178a.c | 6 +- drivers/net/veth.c | 1 + drivers/net/virtio_net.c | 2 + drivers/net/wireguard/noise.c | 7 +- drivers/net/wireguard/queueing.h | 2 + drivers/net/wireless/ath/ath12k/core.c | 33 +-- drivers/net/wireless/ath/ath12k/core.h | 3 - drivers/net/wireless/ath/ath12k/hif.h | 9 - drivers/net/wireless/ath/ath12k/pci.c | 8 - .../wireless/broadcom/brcm80211/brcmfmac/core.c | 27 ++- drivers/net/wireless/marvell/libertas/tx.c | 7 - drivers/net/wireless/mediatek/mt76/mt76.h | 10 + drivers/net/wireless/mediatek/mt76/mt7603/init.c | 1 + .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 6 + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 12 + .../net/wireless/mediatek/mt76/mt792x_acpi_sar.c | 134 +++++++---- .../net/wireless/mediatek/mt76/mt792x_acpi_sar.h | 2 + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 10 +- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 3 + drivers/net/wireless/mediatek/mt76/tx.c | 89 +++++++- drivers/net/xen-netfront.c | 4 +- drivers/nvme/target/core.c | 2 +- drivers/nvme/target/pr.c | 4 + drivers/pmdomain/imx/imx8m-blk-ctrl.c | 15 ++ drivers/pmdomain/rockchip/pm-domains.c | 20 +- drivers/power/sequencing/pwrseq-pcie-m2.c | 2 + drivers/ptp/ptp_ocp.c | 2 +- drivers/regulator/ltc3676.c | 15 +- drivers/regulator/of_regulator.c | 24 +- drivers/regulator/tps6594-regulator.c | 6 +- drivers/scsi/ch.c | 29 +-- drivers/scsi/qedi/qedi_main.c | 3 +- drivers/spi/spi-nxp-fspi.c | 22 +- drivers/spi/spi-sg2044-nor.c | 60 ++++- drivers/tee/optee/ffa_abi.c | 38 ++- drivers/tee/optee/optee_msg.h | 4 +- drivers/tee/optee/smc_abi.c | 17 +- drivers/tee/tee_shm.c | 4 + drivers/ufs/core/ufs-mcq.c | 30 +-- drivers/ufs/core/ufshcd.c | 53 +++-- drivers/ufs/host/ufs-mediatek.c | 18 +- fs/btrfs/inode.c | 7 +- fs/btrfs/ioctl.c | 31 +-- fs/btrfs/scrub.c | 4 +- fs/btrfs/xattr.c | 15 +- fs/dcache.c | 4 +- fs/fcntl.c | 3 + fs/fs_context.c | 4 + fs/inode.c | 23 +- fs/mount.h | 6 +- fs/namei.c | 29 +++ fs/namespace.c | 254 ++++++++++++++++----- fs/nullfs.c | 4 +- fs/pnode.c | 108 +++++++-- fs/verity/fsverity_private.h | 15 +- fs/verity/open.c | 13 +- fs/xfs/libxfs/xfs_exchmaps.c | 103 ++------- fs/xfs/libxfs/xfs_log_format.h | 4 +- fs/xfs/xfs_bmap_util.c | 15 +- fs/xfs/xfs_exchrange.c | 51 +++-- include/linux/can/core.h | 3 +- include/linux/can/skb.h | 4 +- include/linux/io_uring_types.h | 2 + include/linux/mount.h | 2 +- include/linux/nsproxy.h | 1 + include/linux/nvme.h | 4 +- include/linux/sched/ext.h | 1 + include/linux/virtio_net.h | 64 +++--- include/net/amt.h | 4 - include/net/bluetooth/rfcomm.h | 1 + include/net/can.h | 2 + include/net/cfg80211.h | 1 + include/net/ip.h | 7 + include/net/mac80211.h | 14 +- include/net/strparser.h | 10 +- io_uring/io_uring.c | 13 +- io_uring/kbuf.c | 6 +- io_uring/memmap.c | 47 +++- io_uring/memmap.h | 2 +- io_uring/net.c | 4 +- io_uring/register.c | 21 +- io_uring/zcrx.c | 2 +- kernel/cgroup/cpuset.c | 40 +++- kernel/dma/swiotlb.c | 6 +- kernel/fork.c | 3 +- kernel/nsproxy.c | 2 +- kernel/sched/ext/ext.c | 25 +- kernel/sched/ext/internal.h | 5 + kernel/sched/sched.h | 1 - kernel/workqueue.c | 2 +- lib/dim/dim.c | 10 +- mm/mremap.c | 70 ++++-- mm/pgtable-generic.c | 20 +- mm/vma.c | 21 +- mm/vma.h | 7 +- net/bluetooth/hci_core.c | 4 + net/bluetooth/hci_sock.c | 2 + net/bluetooth/hci_sync.c | 10 +- net/bluetooth/iso.c | 52 ++++- net/bluetooth/mgmt.c | 2 +- net/bluetooth/rfcomm/core.c | 134 +++++++---- net/bluetooth/rfcomm/sock.c | 5 +- net/bluetooth/rfcomm/tty.c | 2 +- net/bluetooth/sco.c | 87 +++++-- net/bridge/br_multicast.c | 23 +- net/bridge/netfilter/nf_conntrack_bridge.c | 10 +- net/can/af_can.c | 47 +++- net/can/gw.c | 3 + net/can/isotp.c | 16 +- net/can/raw.c | 10 +- net/core/dev.c | 11 +- net/core/flow_dissector.c | 11 +- net/core/skbuff.c | 6 +- net/devlink/core.c | 10 +- net/ipv4/cipso_ipv4.c | 8 + net/ipv4/fib_semantics.c | 3 + net/ipv4/fib_trie.c | 2 - net/ipv4/ip_output.c | 10 +- net/ipv4/route.c | 5 + net/ipv4/tcp.c | 2 + net/ipv4/udp.c | 11 + net/ipv6/ip6_gre.c | 7 - net/ipv6/route.c | 4 +- net/ipv6/udp.c | 13 ++ net/mac80211/debugfs.c | 13 +- net/mac80211/ieee80211_i.h | 2 + net/mac80211/main.c | 1 + net/mac80211/sta_info.c | 17 +- net/mac80211/sta_info.h | 3 +- net/mac80211/status.c | 5 +- net/mac80211/tx.c | 70 ++++-- net/netfilter/nfnetlink_queue.c | 7 + net/netfilter/xt_CHECKSUM.c | 6 +- net/openvswitch/actions.c | 7 +- net/openvswitch/datapath.c | 8 + net/packet/af_packet.c | 28 ++- net/sched/cls_route.c | 6 + net/sched/em_text.c | 3 + net/sctp/socket.c | 6 +- net/smc/af_smc.c | 7 +- net/strparser/strparser.c | 6 +- net/tipc/node.c | 10 +- net/tipc/topsrv.c | 80 +++++-- net/vmw_vsock/af_vsock.c | 2 + net/vmw_vsock/virtio_transport_common.c | 4 +- net/xfrm/xfrm_output.c | 16 +- security/keys/key.c | 6 +- security/keys/persistent.c | 55 +++-- security/selinux/avc.c | 5 +- security/selinux/hooks.c | 9 +- sound/hda/codecs/side-codecs/tas2781_hda.c | 18 +- sound/pci/ctxfi/ctdaio.c | 6 +- sound/soc/amd/yc/acp6x-mach.c | 7 + sound/soc/codecs/adau1372.c | 18 +- sound/soc/samsung/i2s.c | 8 + sound/soc/sdw_utils/soc_sdw_utils.c | 35 ++- tools/testing/selftests/mm/hugetlb-mmap.c | 4 +- tools/testing/vma/tests/vma.c | 4 +- 289 files changed, 3322 insertions(+), 1484 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/281 bnxt_en: fix DMA mapping length for padded small packets
7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a51d233ccd4889aadb71dace863525cc2b00271e ]
Stefan Fleischmann reported Intel IOMMU DMA Read faults on BCM57412 NetXtreme-E NICs when transmitting packets on VLAN/macvlan interfaces:
DMAR: [DMA Read NO_PASID] Request device [18:00.0] fault addr 0xfc499000
[fault reason 0x06] PTE Read access is not set
bnxt_en 0000:18:00.0 eno1np0: Abandoning msg {0xb4 0x41a} len: 0 due to firmware status: 0x2000001
...
NETDEV WATCHDOG: eno1np0 (bnxt_en): transmit queue 0 timed out
The fault address (0xfc499000) is on an exact 4KB page boundary, pointing to a DMA read buffer overrun.
In bnxt_start_xmit(), packets smaller than BNXT_MIN_PKT_SIZE (52 bytes), such as 42-byte untagged ARP frames, are padded:
if (length < BNXT_MIN_PKT_SIZE) {
pad = BNXT_MIN_PKT_SIZE - length;
if (skb_pad(skb, pad))
goto tx_kick_pending;
length = BNXT_MIN_PKT_SIZE;
}
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
...
dma_unmap_len_set(tx_buf, len, len);However, 'len' was initialized earlier to skb_headlen(skb) (e.g. 42 bytes) and is left unadjusted after padding. Consequently, dma_map_single() and dma_unmap_len_set() map and track only 42 bytes.
Later, the hardware TX buffer descriptor is programmed with the padded length:
txbd->tx_bd_len_flags_type =
cpu_to_le32(((len + pad) << TX_BD_LEN_SHIFT) | flags |
TX_BD_FLAGS_PACKET_END);The NIC DMA engine is thus instructed to read 52 bytes from a region where only 42 bytes were DMA-mapped. If skb->data ends near the boundary of a 4KB page (within 'pad' bytes of the next page), the hardware DMA read overruns into the unmapped adjacent page, triggering an IOMMU fault.
This issue was exposed after commit 447cbe95ebb9 ("vlan: fix skb_under_panic and races when toggling HW VLAN offload") because reserving extra VLAN headroom rounded LL_RESERVED_SPACE from 48 up to 64 bytes, shifting skb->data offsets and potentially causing small frames to land right against page boundaries.
Fix this by using skb_put_padto(skb, BNXT_MIN_PKT_SIZE) in bnxt_start_xmit(), before skb_shinfo(skb)->nr_frags is sampled, because padding might linearize the skb.
This ensures skb->len and skb_headlen(skb) reflect the padded size so that dma_map_single() maps the full buffer and the descriptor length is consistent. This also removes the temporary 'pad' variable and masking logic.
The padding is done after the SW USO branch, otherwise bnxt_sw_udp_gso_xmit() would account the padding as UDP payload and send it in extra segments.
Note that SW USO segments are still not padded: with IPv4, a segment carrying less than 10 bytes of UDP payload (small gso_size, or a short last segment) is sent as a frame shorter than BNXT_MIN_PKT_SIZE. This is a separate issue, left for a followup patch.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +12 -13
@@ -486,7 +486,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)struct netdev_queue *txq;int i;dma_addr_t mapping; -unsigned int length, pad =0 ; +unsigned int length;u32 len, free_size, vlan_tag_flags, cfa_action, flags;struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;struct pci_dev *pdev = bp->pdev;
@@ -536,6 +536,16 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)return rc <0 ?NETDEV_TX_BUSY :NETDEV_TX_OK ; } +/* Pad after the SW USO branch: bnxt_sw_udp_gso_xmit() would +* otherwise account the padding as UDP payload. +* Must be done before skb_shinfo(skb)->nr_frags is sampled, +* because skb_put_padto() might linearize the skb. +*/ +if (skb_put_padto (skb,BNXT_MIN_PKT_SIZE )) { +/* SKB already freed. */ + goto tx_kick_pending; + } + free_size =bnxt_tx_avail (bp, txr);if (unlikely (free_size <skb_shinfo (skb)->nr_frags +2 )) {/* We must have raced with NAPI cleanup */
@@ -672,14 +682,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) } normal_tx: -if (length <BNXT_MIN_PKT_SIZE ) { - pad =BNXT_MIN_PKT_SIZE - length; -if (skb_pad (skb, pad)) -/* SKB already freed. */ - goto tx_kick_pending; - length =BNXT_MIN_PKT_SIZE ; - } - mapping =dma_map_single (&pdev->dev, skb->data, len,DMA_TO_DEVICE );if (unlikely (dma_mapping_error (&pdev->dev, mapping)))
@@ -759,10 +761,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_len_flags_type =cpu_to_le32 (flags); } - flags &= ~TX_BD_LEN ; - txbd->tx_bd_len_flags_type = -cpu_to_le32 (((len + pad) <<TX_BD_LEN_SHIFT ) | flags | -TX_BD_FLAGS_PACKET_END ); + txbd->tx_bd_len_flags_type |=cpu_to_le32 (TX_BD_FLAGS_PACKET_END );netdev_tx_sent_queue (txq, skb->len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 2/281 fs: Free any excess xarray nodes in clear_inode()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit ee3f011250104129893d8e9599147e457d4d7280 ]
For many years we've had a hard to hit leak of xarray nodes. Hugh documented it well in commit 786b31121a2c. Recently people and syzbot have found ways to force it to happen with madvise. Rather than fix the leaks where they happen, just call xa_destroy() which has the side-effect of cycling the i_pages lock.
--- fs/inode.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
fs/inode.c +10 -13
@@ -763,21 +763,18 @@ void clear_inode(struct inode *inode)fsverity_cleanup_inode (inode);/* -* We have to cycle the i_pages lock here because reclaim can be in the -* process of removing the last page (in __filemap_remove_folio()) -* and we must not free the mapping under it. +* We have to cycle the i_pages lock here because reclaim +* can be in the process of removing the last page (in +* __filemap_remove_folio()) and we must not free the mapping +* under it. We also remove nodes which are empty; these +* can occur in two different ways. The first is that radix +* tree expansion can fail partway and the second is that THP +* collapse_file() can allocate some temporary nodes and not +* clean them up. */ -xa_lock_irq (&inode->i_data.i_pages); +xa_destroy (&inode->i_data.i_pages); +BUG_ON (inode->i_data.nrpages); -/* -* Almost always, mapping_empty(&inode->i_data) here; but there are -* two known and long-standing ways in which nodes may get left behind -* (when deep radix-tree node allocation failed partway; or when THP -* collapse_file() failed). Until those two known cases are cleaned up, -* or a cleanup function is called here, do not BUG_ON(!mapping_empty), -* nor even WARN_ON(!mapping_empty). -*/ -xa_unlock_irq (&inode->i_data.i_pages);BUG_ON (!(inode_state_read_once (inode) &I_FREEING ));BUG_ON (inode_state_read_once (inode) &I_CLEAR );BUG_ON (!list_empty (&inode->i_wb_list));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 3/281 net/mlx5e: Prevent stale XSK buffer release on refill retry
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jerome Tollet <[email protected]>
[ Upstream commit e01620844c5c88b6fcf819d171df8e3976a0e76f ]
When an XDP redirect to an AF_XDP socket fails because its RX ring is full, the XSK core frees the buffer. During the subsequent batched refill of a legacy cyclic RQ, mlx5e also releases the WQE's XSK buffer before allocating a replacement. If that refill succeeds only partially, a WQE left without a replacement retains its old buffer pointer.
The buffer can meanwhile be allocated to another WQE. A later refill retry can then free the live buffer through the stale pointer and publish the same UMEM frame twice.
Mark the WQE as released immediately after the driver-side free. The flag is already cleared when a replacement buffer is assigned, so refill retries no longer release stale pointers.
The failure is silent and produces no kernel warning or splat. A standalone legacy cyclic-RQ zero-copy libxsk reproducer, using 64-byte UDP traffic offered at 12 Mpps, detected it: stock stopped after 2,854,914 packets in 4.094 seconds, with 4,542 xdp_rx_ring_full events and 64 ownership/double-publication errors. With this change it processed 356,904,225 packets in 30 seconds despite 571,405 xdp_rx_ring_full events, with no ownership or data errors.
--- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +5 -2
@@ -410,8 +410,11 @@ static inline void mlx5e_free_rx_wqe(struct mlx5e_rq *rq,static void mlx5e_xsk_free_rx_wqe (struct mlx5e_wqe_frag_info *wi) { -if (!(wi->flags &BIT (MLX5E_WQE_FRAG_SKIP_RELEASE ))) -xsk_buff_free (*wi->xskp); +if (wi->flags &BIT (MLX5E_WQE_FRAG_SKIP_RELEASE )) +return ; + +xsk_buff_free (*wi->xskp); + wi->flags |=BIT (MLX5E_WQE_FRAG_SKIP_RELEASE ); }static void mlx5e_dealloc_rx_wqe (struct mlx5e_rq *rq,u16 ix)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 4/281 net/mlx5e: Prevent stale XSK buffer release on MPWQE refill retry
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jerome Tollet <[email protected]>
[ Upstream commit 63811edf512584c946e5e96b100e9e280703bbb5 ]
With AF_XDP on a striding RQ, mlx5e defers releasing XSK buffers until an MPWQE is refilled. If XSK allocation then returns -ENOMEM, actual_wq_head is not advanced and a later NAPI poll retries the same WQE.
mlx5e_free_rx_mpwqe() leaves each released slot marked as releasable. On retry it can therefore call xsk_buff_free() again through stale pointers after the frames have returned to the XSK pool and been reallocated.
Set all skip_release_bitmap bits in the common error path of mlx5e_xsk_alloc_rx_mpwqe(). This matches mlx5e_alloc_rx_mpwqe(). A successful allocation already clears the bitmap after replacing every buffer, so retries become idempotent without changing the success path.
Fault injection forced three consecutive failures for one selected MPWQE. Both an early allocation failure and a partial 8-of-16-buffer unwind released the original 16 XSK buffers only once. Each error left a full bitmap, the following NAPI retry skipped the release, and a later successful allocation cleared it. A 20-second AF_XDP zero-copy pressure run exercised 1,575,262 buffer allocation failures without invalid descriptors, WQE errors, or kernel warnings.
--- drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c +2 -0
@@ -3,6 +3,7 @@#include "rx.h" #include "en/xdp.h" +#include <linux/bitmap.h> #include <net/xdp_sock_drv.h> #include <linux/filter.h>
@@ -156,6 +157,7 @@ int mlx5e_xsk_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)xsk_buff_free (xsk_buffs[batch]); err: +bitmap_fill (wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe); rq->stats->buff_alloc_err++;return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 5/281 ipv6: Fix redirect exception creation for UDP/RAW sockets
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit cd51b74bdd0b75aedf255dc67306a16dd057f7ee ]
When an ICMP Redirect Message is matched to a socket, both IPv4 and IPv6 verify that the source IP of the ICMP packet is the current gateway for the quoted packet. Both also pass the socket's bound device as the expected nexthop device.
The difference is that IPv4 treats "oif=0" as "any", whereas IPv6 always requires an exact match (see ip6_redirect_nh_match()), since the gateway address is usually a link-local address.
Therefore, when an IPv6 UDP/RAW socket is not bound to a device, the above verification fails and an exception is not created. This also happens when the socket is bound to a VRF, as l3mdev_update_flow() resets the oif to 0.
Fix this by passing the ifindex of the ingress device as the expected nexthop device. This is consistent with the existing callers of ip6_redirect(). Note that for ICMPv6 Redirect Message packets the VRF driver does not reset skb->dev to the VRF device, so skb->dev is correct, even when it is a VRF port.
--- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/route.c +1 -1
@@ -3261,7 +3261,7 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)void ip6_sk_redirect (struct sk_buff *skb,struct sock *sk) { -ip6_redirect (skb,sock_net (sk), sk->sk_bound_dev_if, +ip6_redirect (skb,sock_net (sk), skb->dev->ifindex,READ_ONCE (sk->sk_mark),sk_uid (sk)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 6/281 ipv4: udp: Create exceptions before socket matching
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 4c3499f79f8c7e8561266bcc220a18538cec0458 ]
Currently, when ICMP Fragmentation Needed and Redirect Message packets are locally delivered and quote a UDP packet, a FIB nexthop exception (FNHE) is only created if the kernel can match the UDP packet to an existing socket.
This behavior allows off-path attackers to conduct a side-channel attack on the FNHE cache in order to discover the ephemeral port used by a connected UDP socket.
Commit 6457378fe796 ("ipv4: use siphash instead of Jenkins in fnhe_hashfun()") and commit 67d6d681e15b ("ipv4: make exception cache less predictible") tried to mitigate such attacks by making it harder for attackers to discover hash collisions in the FNHE cache and by randomizing the number of exceptions a hash bucket can hold, respectively. Unfortunately, both of the mitigations can be bypassed.
Instead, mitigate such attacks by always creating a FNHE, even before trying to find a matching socket. Do that by calling ipv4_update_pmtu() and ipv4_redirect(), the helpers used when the quoted packet did not originate from a socket.
This means that guesses (right or wrong) from an off-path attacker will always result in a FNHE being created or updated in the cache that the attacker can observe.
Pass an oif of 0, in a similar fashion to icmp_err(). This is also the oif used by the socket path for sockets that are not bound to a device.
Note that this does not allow attackers to create FNHEs that they could not create before, as both helpers can already be reached with little to no validation. For example, by sending an ICMP error that quotes an ICMP Echo Reply or one that quotes a UDP source port that matches a wildcard socket.
Also note that in the good case (matched socket) the above scheme comes at the cost of an extra route lookup, as the no socket helpers perform their own lookup before the one performed by ipv4_sk_update_pmtu() / ipv4_sk_redirect(). When the two resolve to different nexthops, it also results in two exceptions being created for the same destination IP. One in the FNHE cache of the nexthop resolved by the no socket helpers and another in the FNHE cache of the nexthop used by the socket.
--- net/ipv4/udp.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/ipv4/udp.c +11 -0
@@ -908,6 +908,15 @@ static struct sock *__udp4_lib_err_encap(struct net *net,return sk; } +static void udp_err_update_exception (struct net *net,struct sk_buff *skb, +int type,int code,u32 info) +{ +if (type ==ICMP_DEST_UNREACH && code ==ICMP_FRAG_NEEDED ) +ipv4_update_pmtu (skb, net, info,0 ,IPPROTO_UDP ); +else if (type ==ICMP_REDIRECT ) +ipv4_redirect (skb, net,0 ,IPPROTO_UDP ); +} +/* * This routine is called by the ICMP module when it gets some * sort of error condition. If err < 0 then the socket should
@@ -931,6 +940,8 @@ int udp_err(struct sk_buff *skb, u32 info)int harderr;int err; +udp_err_update_exception (net, skb, type, code, info); + uh = (struct udphdr *)(skb->data + (iph->ihl <<2 )); sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 7/281 ipv6: udp: Create exceptions before socket matching
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit ac76cab50e899a7346408b8d3c3a4192c2eefb9f ]
Currently, when ICMPv6 Packet Too Big and Redirect Message packets are locally delivered and quote a UDP packet, an exception is only created in the IPv6 exception cache if the kernel can match the UDP packet to an existing socket.
This behavior allows off-path attackers to conduct a side-channel attack on the exception cache in order to discover the ephemeral port used by a connected UDP socket.
Commit 4785305c05b2 ("ipv6: use siphash in rt6_exception_hash()") and commit a00df2caffed ("ipv6: make exception cache less predictible") tried to mitigate such attacks by making it harder for attackers to discover hash collisions in the exception cache and by randomizing the number of exceptions a hash bucket can hold, respectively. Unfortunately, both of the mitigations can be bypassed.
Instead, mitigate such attacks by always creating an exception, even before trying to find a matching socket. Do that by calling ip6_update_pmtu() and ip6_redirect(), the helpers used when the quoted packet did not originate from a socket.
This means that guesses (right or wrong) from an off-path attacker will always result in an exception being created or updated in the cache that the attacker can observe.
Pass the ifindex of the ingress device and the default uid, in a similar fashion to icmpv6_err(). Unlike IPv4, an oif of 0 would not match any nexthop in ip6_redirect_nh_match() and no exception would be created in response to a Redirect Message.
Note that this does not allow attackers to create exceptions that they could not create before, as both helpers can already be reached with little to no validation. For example, by sending an ICMPv6 error that quotes an ICMPv6 Echo Reply or one that quotes a UDP source port that matches a wildcard socket.
Also note that in the good case (matched socket) the above scheme comes at the cost of an extra route lookup, as the no socket helpers perform their own lookup before the one performed by ip6_sk_update_pmtu() / ip6_sk_redirect(). When the two resolve to different nexthops, it also results in two exceptions being created for the same destination IP. One in the exception cache of the nexthop resolved by the no socket helpers and another in the exception cache of the nexthop used by the socket.
--- net/ipv6/udp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
net/ipv6/udp.c +13 -0
@@ -690,6 +690,17 @@ static struct sock *__udp6_lib_err_encap(struct net *net,return sk; } +static void udpv6_err_update_exception (struct net *net,struct sk_buff *skb, +u8 type,__be32 info) +{ +if (type ==ICMPV6_PKT_TOOBIG ) +ip6_update_pmtu (skb, net, info, skb->dev->ifindex,0 , +sock_net_uid (net,NULL )); +else if (type ==NDISC_REDIRECT ) +ip6_redirect (skb, net, skb->dev->ifindex,0 , +sock_net_uid (net,NULL )); +} +static int udpv6_err (struct sk_buff *skb,struct inet6_skb_parm *opt,u8 type,u8 code,int offset,__be32 info) {
@@ -703,6 +714,8 @@ static int udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,int harderr;int err; +udpv6_err_update_exception (net, skb, type, info); + daddr =seg6_get_daddr (skb, opt) ? : &hdr->daddr; saddr = &hdr->saddr; sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 8/281 ipv4: validate checksum_start before completing checksum
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael S. Tsirkin <[email protected]>
commit 6785011f8b16abf40b1e9d8b2e332232b3e68822 upstream.
If a packet with bad checksum metadata gets into the ipv4 stack, skb_checksum_help can corrupt the network header and cause a bunch of mischief.
This was discovered and reported by Paulos, and has been reporoduced by others independently since.
We really shouldn't allow such packets in, but as a defence in depth measure, let's also check before we complete the checksum.
A more complete validation at input is forthcoming, but needs more work.
--- include/net/ip.h | 7 +++++++ net/bridge/netfilter/nf_conntrack_bridge.c | 10 +++++++--- net/ipv4/ip_output.c | 10 +++++++--- net/netfilter/nfnetlink_queue.c | 7 +++++++ net/netfilter/xt_CHECKSUM.c | 6 +++++- net/xfrm/xfrm_output.c | 16 +++++++++++----- 6 files changed, 44 insertions(+), 12 deletions(-)
include/net/ip.h +7 -0
@@ -74,6 +74,13 @@ static inline unsigned int ip_hdrlen(conreturn ip_hdr (skb)->ihl *4 ; } +static inline int ip_check_csum_start (const struct sk_buff *skb) +{ +if (unlikely (skb->csum_start < skb->network_header +ip_hdrlen (skb))) +return -EINVAL ; +return 0 ; +} +struct ipcm_cookie {struct sockcm_cookie sockc;__be32 addr;
net/bridge/netfilter/nf_conntrack_bridge.c +7 -3
@@ -39,9 +39,13 @@ static int nf_br_ip_fragment(struct netint err =0 ;/* for offloaded checksums cleanup checksum before fragmentation */ -if (skb->ip_summed ==CHECKSUM_PARTIAL && - (err =skb_checksum_help (skb))) - goto blackhole; +if (skb->ip_summed ==CHECKSUM_PARTIAL ) { + err =ip_check_csum_start (skb); +if (!err) + err =skb_checksum_help (skb); +if (err) + goto blackhole; + } iph =ip_hdr (skb);
net/ipv4/ip_output.c +7 -3
@@ -771,9 +771,13 @@ int ip_do_fragment(struct net *net, struint err =0 ;/* for offloaded checksums cleanup checksum before fragmentation */ -if (skb->ip_summed ==CHECKSUM_PARTIAL && - (err =skb_checksum_help (skb))) - goto fail; +if (skb->ip_summed ==CHECKSUM_PARTIAL ) { + err =ip_check_csum_start (skb); +if (!err) + err =skb_checksum_help (skb); +if (err) + goto fail; + }/* * Point into the IP datagram header.
net/netfilter/nfnetlink_queue.c +7 -0
@@ -33,6 +33,7 @@#include <linux/rhashtable.h> #include <linux/jhash.h> #include <net/gso.h> +#include <net/ip.h> #include <net/sock.h> #include <net/tcp_states.h> #include <net/netfilter/nf_queue.h>
@@ -667,6 +668,12 @@ nla_put_failure:static int nf_queue_checksum_help (struct sk_buff *entskb) { +if (entskb->protocol ==htons (ETH_P_IP )) { +if (!pskb_network_may_pull (entskb,sizeof (struct iphdr )) || +ip_check_csum_start (entskb)) +return -EINVAL ; + } +if (skb_csum_is_sctp (entskb))return skb_crc32c_csum_help (entskb);
net/netfilter/xt_CHECKSUM.c +5 -1
@@ -15,6 +15,7 @@#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h> +#include <net/ip.h> MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Michael S. Tsirkin <[email protected]>" );
@@ -25,8 +26,11 @@ MODULE_ALIAS("ip6t_CHECKSUM");static unsigned int checksum_tg (struct sk_buff *skb,const struct xt_action_param *par) { -if (skb->ip_summed ==CHECKSUM_PARTIAL && !skb_is_gso (skb)) +if (skb->ip_summed ==CHECKSUM_PARTIAL && !skb_is_gso (skb)) { +if (xt_family (par) ==NFPROTO_IPV4 &&ip_check_csum_start (skb)) +return NF_DROP ;skb_checksum_help (skb); + }return XT_CONTINUE ; }
net/xfrm/xfrm_output.c +11 -5
@@ -823,16 +823,22 @@ int xfrm_output(struct sock *sk, struct }if (skb->ip_summed ==CHECKSUM_PARTIAL ) { - err =skb_checksum_help (skb); -if (err) { -XFRM_INC_STATS (net,LINUX_MIB_XFRMOUTERROR ); -kfree_skb (skb); -return err; +if (skb->protocol ==htons (ETH_P_IP )) { + err =ip_check_csum_start (skb); +if (err) + goto error; } + err =skb_checksum_help (skb); +if (err) + goto error; } out:return xfrm_output2 (net, sk, skb); +error: +XFRM_INC_STATS (net,LINUX_MIB_XFRMOUTERROR ); +kfree_skb (skb); +return err; }EXPORT_SYMBOL_GPL (xfrm_output);
Greg Kroah-Hartman
maintainerPATCH 9/281 rust_binder: reschedule node refcount update on thread exit
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Ryhl <[email protected]>
commit 2a74ccd1bcc170e66525f34e9de8652b57e2cf3d upstream.
When a thread exits via BINDER_THREAD_EXIT, its pending work items are cancelled. If a thread exits while holding a pending node refcount increment (e.g. pushed as deferred work to that thread), the refcount increment was previously dropped because Node::cancel() and NodeWrapper::cancel() were no-ops.
Dropping the refcount update leaves the node's delivery state and count state desynchronized, and userspace will not receive the notification, which can cause the node to never be freed from the process's nodes tree when all external references are dropped.
Fix this by implementing DeliverToRead::cancel() for Node and NodeWrapper to move the pending refcount update to the process's work queue on thread exit so another thread can deliver it to userspace.
[ Dropped first argument in calls to push_work() to adjust to the
existing form without mainline commit dbb17c9ea756 ("rust_binder: move (e)poll wait queue to Process"). - Miguel ]
--- drivers/android/binder/node.rs | 20 ++++++++++++++++--- drivers/android/binder/node/wrapper.rs | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-)
drivers/android/binder/node.rs +17 -3
@@ -49,9 +49,9 @@ pub(crate) struct CouldNotDeliverCritica/// about to drop the weak reference, then the strong increment could be processed after the /// other thread has already exited, which would be too late. /// -/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is +/// Note that trying to create a `ListArc` to the node can succeed even if `has_pushed_node` is /// set. This is because another thread might just have popped the node from a todo list, but not -/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should +/// yet called `do_work`. However, if `has_pushed_node` is false, then creating a `ListArc` should /// always succeed. /// /// Like the other fields in `NodeInner`, the delivery state is protected by the process lock.
@@ -733,7 +733,21 @@ impl DeliverToRead for Node { self.do_work_locked (writer, owner_inner) } -fn cancel (self:DArc <Self >) {} +fn cancel (self:DArc <Self >) { +let _drop_outside_lock; +let mut owner_inner = self.owner.inner.lock (); + +// We only do something on BINDER_THREAD_EXIT, not process exit. +if owner_inner.is_dead { +return ; + } + +// If BINDER_THREAD_EXIT is invoked on a thread with a pending node refcount update, we +// should move ourselves to ensure the refcount update is still delivered. +if let Some (node) =ListArc ::try_from_arc_borrow (self.as_arc_borrow ()) { + _drop_outside_lock = owner_inner.push_work (node); + } + }fn should_sync_wakeup (&self) ->bool {false
drivers/android/binder/node/wrapper.rs +33 -1
@@ -57,7 +57,39 @@ impl DeliverToRead for NodeWrapper { node.do_work_locked (writer, owner_inner) } -fn cancel (self:DArc <Self >) {} +fn cancel (self:DArc <Self >) { +let _drop_outside_lock; +let node = &self.node; +let mut owner_inner = node.owner.inner.lock (); + +// We only do something on BINDER_THREAD_EXIT, not process exit. +if owner_inner.is_dead { +return ; + } + +// We transfer the responsibility of the node refcount update to the scheduled Node because +// NodeWrapper has no way to re-create the ListArc. +let inner = node.inner.access_mut (&mut owner_inner); + +let ds = &mut inner.delivery_state; +assert! (ds.has_pushed_wrapper); +assert! (ds.has_strong_zero2one); + ds.has_pushed_wrapper =false ; + +// We are changing the state to one where the Node is the strong zero2one update instead of +// the wrapper. + ds.has_weak_zero2one =false ; + +if !ds.has_pushed_node { +if let Some (node2) =ListArc ::try_from_arc_borrow (node.as_arc_borrow ()) { + ds.has_pushed_node =true ; + _drop_outside_lock = owner_inner.push_work (node2); + }else { +// This can't actually happen. + ds.has_strong_zero2one =false ; + } + } + }fn should_sync_wakeup (&self) ->bool {false
Greg Kroah-Hartman
maintainerPATCH 10/281 ipv4: stop PMTU walk when nexthop group shrinks
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 6619e01855e65ef35723685a557e3eb106f4ecf5 upstream.
Commit 7d3f3b4367f3 ("net: ipv4: Cache pmtu for all packet paths if multipath enabled") made __ip_rt_update_pmtu() update every path.
For nexthop objects, fib_info_num_path() and fib_info_nhc() independently load nh->nh_grp. RCU protects each group's lifetime but does not make the loads observe the same group. If replacement shrinks the group after the loop accepts an index, fib_info_nhc() returns NULL and update_or_create_fnhe() dereferences it.
A deterministic probe only widened the existing window between the real operations. On v7.2, an RTM_NEWNEXTHOP replacement published a one-member group after the PMTU reader accepted index 1 from a two-member group, producing:
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: update_or_create_fnhe+0x45/0x15b0
Stop when the indexed path is absent. Groups are dense, so no later index exists in that snapshot. The same real-writer window completed 114,423 PMTU iterations without an oops with this check. A reproducer is available on request.
Replacement requires CAP_NET_ADMIN in the network namespace. Where unprivileged user namespaces are permitted, a local user can obtain it in a new user and network namespace.
--- net/ipv4/route.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv4/route.c +2 -0
@@ -1080,6 +1080,8 @@ static void __ip_rt_update_pmtu(struct rfor (nhsel =0 ; nhsel <fib_info_num_path (res.fi); nhsel++) { nhc =fib_info_nhc (res.fi, nhsel); +if (!nhc) +break ;update_or_create_fnhe (nhc, fl4->daddr,0 , mtu, lock, jiffies + net->ipv4.ip_rt_mtu_expires); }
Greg Kroah-Hartman
maintainerPATCH 11/281 ipv4: stop exception dump when nexthop group shrinks
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 4f4afc07dcb2edd4f9afa36595373f8cdb9b58c2 upstream.
Commit 4ce5dc9316de ("inet: switch inet_dump_fib() to RCU protection") allowed IPv4 FIB dumps to run concurrently with nexthop replacement.
fib_dump_info_fnhe() uses fib_info_num_path() as the loop bound, then fib_info_nhc() independently reloads nh->nh_grp. If RTM_NEWNEXTHOP replaces a group with fewer paths between those loads, fib_info_nhc() returns NULL and the dump dereferences it through nhc_flags.
Stop the walk when the indexed path is absent. Nexthop groups are dense, so the current snapshot has no later path.
--- net/ipv4/route.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/route.c +3 -0
@@ -3165,6 +3165,9 @@ int fib_dump_info_fnhe(struct sk_buff *sstruct fnhe_hash_bucket *bucket;int err; +if (!nhc) +break ; +if (nhc->nhc_flags &RTNH_F_DEAD )continue ;
Greg Kroah-Hartman
maintainerPATCH 12/281 ipv4: stop route notification sizing when nexthop group shrinks
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit d3daa33c7af92e38f2274bbd2576f58bfbaf89e6 upstream.
Commit 680aea08e78c ("net: ipv4: Emit notification when fib hardware flags are changed") added an RCU-only fib_nlmsg_size() call for asynchronous hardware flag notifications.
fib_nlmsg_size() checks fib_info_num_path() before each iteration, then fib_info_nhc() independently reloads nh->nh_grp. If RTM_NEWNEXTHOP replaces a group with fewer paths between those loads, fib_info_nhc() returns NULL and fib_nexthop_nlmsg_size() dereferences it.
Stop sizing when the indexed path is absent. Nexthop groups are dense, so the current snapshot has no later path.
--- net/ipv4/fib_semantics.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/fib_semantics.c +3 -0
@@ -542,6 +542,9 @@ size_t fib_nlmsg_size(struct fib_info *fstruct fib_nh_common *nhc =fib_info_nhc (fi, i);size_t nhsize; +if (!nhc) +break ; + nhsize =fib_nexthop_nlmsg_size (nhc, nhs !=1 );if (nhs !=1 )
Greg Kroah-Hartman
maintainerPATCH 13/281 ipv4: do not warn on route notification size race
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit e02a5b6588161673ef75a4bc5cdfb62bd493374d upstream.
Commit 680aea08e78c ("net: ipv4: Emit notification when fib hardware flags are changed") added asynchronous route notifications for hardware flag changes.
fib_alias_hw_flags_set() sizes the skb with fib_nlmsg_size() and later fills it with fib_dump_info() while holding only RCU. With nexthop compatibility mode enabled, a concurrent replacement can grow the group between these independent snapshots. fib_dump_info() can then legitimately return -EMSGSIZE, so the warning does not prove a sizing bug.
Remove the warning. The existing error path still frees the skb and reports the error to listeners.
--- net/ipv4/fib_trie.c | 2 -- 1 file changed, 2 deletions(-)
net/ipv4/fib_trie.c +0 -2
@@ -1079,8 +1079,6 @@ void fib_alias_hw_flags_set(struct net * err =fib_dump_info (skb,0 ,0 ,RTM_NEWROUTE , fri,0 );if (err <0 ) { -/* -EMSGSIZE implies BUG in fib_nlmsg_size() */ -WARN_ON (err == -EMSGSIZE );kfree_skb (skb); goto errout; }
Greg Kroah-Hartman
maintainerPATCH 14/281 ipv6: do not warn on route notification size race
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit c97426ec649d99596d8969e1a052c16b14b7b485 upstream.
fib6_info_hw_flags_set() sizes the skb with rt6_nlmsg_size() and later fills it with rt6_fill_node(). With nexthop compatibility mode enabled, a concurrent replacement can grow the group between these independent snapshots. rt6_fill_node() can then legitimately return -EMSGSIZE, so the warning does not prove a sizing bug.
Remove the warning. The existing error path still frees the skb and reports the error to listeners.
--- net/ipv6/route.c | 2 -- 1 file changed, 2 deletions(-)
net/ipv6/route.c +0 -2
@@ -6474,8 +6474,6 @@ void fib6_info_hw_flags_set(struct net * err =rt6_fill_node (net, skb, f6i,NULL ,NULL ,NULL ,0 ,RTM_NEWROUTE ,0 ,0 ,0 );if (err <0 ) { -/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ -WARN_ON (err == -EMSGSIZE );kfree_skb (skb); goto errout; }
Greg Kroah-Hartman
maintainerPATCH 15/281 Input: ati_remote2 - fix type confusion in device attribute handlers
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haotian Zhang <[email protected]>
commit f321cc430c49b6c1be0d53f2ef19d8342d8029cc upstream.
Previously, the channel_mask and mode_mask attributes were registered on the parent usb_device via sysfs_create_group(). When commit b20d6bf8014b ("Input: ati-remote2 - use driver core to instantiate device attributes") converted the driver to let the driver core manage them via dev_groups in struct usb_driver, the attributes moved to the bound usb_interface devices, but the show and store callbacks were not updated accordingly.
As a result, the callbacks still invoked to_usb_device() on a device pointer belonging to a struct usb_interface, producing an invalid usb_device pointer.
Use to_usb_interface() directly in the attribute handlers to obtain the interface and its driver data.
--- drivers/input/misc/ati_remote2.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/input/misc/ati_remote2.c +4 -8
@@ -672,8 +672,7 @@ static ssize_t ati_remote2_show_channel_struct device_attribute *attr, char *buf) { - struct usb_device *udev = to_usb_device(dev); -struct usb_interface *intf =usb_ifnum_to_if (udev,0 ); + struct usb_interface *intf = to_usb_interface(dev);struct ati_remote2 *ar2 =usb_get_intfdata (intf);return sprintf (buf,"0x%04x\n" , ar2->channel_mask);
@@ -683,8 +682,7 @@ static ssize_t ati_remote2_store_channelstruct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = to_usb_device(dev); -struct usb_interface *intf =usb_ifnum_to_if (udev,0 ); + struct usb_interface *intf = to_usb_interface(dev);struct ati_remote2 *ar2 =usb_get_intfdata (intf);unsigned int mask;int r;
@@ -720,8 +718,7 @@ static ssize_t ati_remote2_show_mode_masstruct device_attribute *attr, char *buf) { - struct usb_device *udev = to_usb_device(dev); -struct usb_interface *intf =usb_ifnum_to_if (udev,0 ); + struct usb_interface *intf = to_usb_interface(dev);struct ati_remote2 *ar2 =usb_get_intfdata (intf);return sprintf (buf,"0x%02x\n" , ar2->mode_mask);
@@ -731,8 +728,7 @@ static ssize_t ati_remote2_store_mode_mastruct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = to_usb_device(dev); -struct usb_interface *intf =usb_ifnum_to_if (udev,0 ); + struct usb_interface *intf = to_usb_interface(dev);struct ati_remote2 *ar2 =usb_get_intfdata (intf);unsigned int mask;int err;
Greg Kroah-Hartman
maintainerPATCH 16/281 Input: xpad - add support for 8BitDo Pro 2 Wired Controller for Xbox
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bihaan Sen <[email protected]>
commit 41363c27b8509bd4efcba244803edac9ba25d1b5 upstream.
The 8BitDo Pro 2 Wired Controller for Xbox is already matched by the vendor-wide XPAD_XBOXONE_VENDOR(0x2dc8) entry, but a later hardware revision reports product ID 0x201e, which has no entry in the xpad_device table. The device therefore binds and functions but is exposed to userspace as "Generic X-Box pad".
Add the VID/PID pair so the controller is named correctly, and set MAP_SHARE_BUTTON to expose the share button as KEY_RECORD.
--- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+)
drivers/input/joystick/xpad.c +1 -0
@@ -379,6 +379,7 @@ static const struct xpad_device { { 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, { 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x2dc8, 0x201e, "8BitDo Pro 2 Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 },
Greg Kroah-Hartman
maintainerPATCH 17/281 Input: xpad - add support for Corsair Novablade Pro
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Furman <[email protected]>
commit f9282b8aa85a8c97c50d656db75feb6d76fc7cbe upstream.
Add device IDs for the Corsair Novablade Pro leverless fight controller in both wired (0x2b1f) and 2.4 GHz receiver (0x2b2b) modes, and add Corsair's vendor ID to the Xbox 360 vendor match list.
Outside of its PS4/PS5 modes the controller uses the Xbox 360 protocol (vendor-specific class, subclass 93, protocol 1) on interface 0, which xpad does not currently bind, so no gamepad device is created. The PS4/PS5 modes present a standard HID gamepad and already work with hid-generic.
Tested on 7.2.5 with the 2.4 GHz receiver and wired.
--- drivers/input/joystick/xpad.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/input/joystick/xpad.c +3 -0
@@ -302,6 +302,8 @@ static const struct xpad_device { { 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 }, { 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 }, { 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 }, + { 0x1b1c, 0x2b1f, "Corsair Novablade Pro (Wired)", 0, XTYPE_XBOX360 }, + { 0x1b1c, 0x2b2b, "Corsair Novablade Pro (2.4 GHz Receiver)", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
@@ -546,6 +548,7 @@ static const struct usb_device_id xpad_tXPAD_XBOX360_VENDOR (0x17ef ),/* Lenovo */ XPAD_XBOX360_VENDOR (0x1949 ),/* Amazon controllers */ XPAD_XBOX360_VENDOR (0x1a86 ),/* Nanjing Qinheng Microelectronics (WCH) */ +XPAD_XBOX360_VENDOR (0x1b1c ),/* Corsair controllers */ XPAD_XBOX360_VENDOR (0x1bad ),/* Harmonix Rock Band guitar and drums */ XPAD_XBOX360_VENDOR (0x1ee9 ),/* ZOTAC Technology Limited */ XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */
Greg Kroah-Hartman
maintainerPATCH 18/281 ALSA: ctxfi: Fix memory leakage when clearing DAO input mappers
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harin Lee <[email protected]>
commit 593d46fc6af9a0178a46e77d6d24b20d2314165f upstream.
Commit e576e7843c0d ("ALSA: ctxfi: Simplify dao_clear_{left,right}_input() functions") centralized the DAO input mapper clearing logic indao_clear_input(), but omitted the kfree() calls.
It removes the mapper entries from the list and sets their pointers to NULL without freeing the allocated array. This leaks memory each time dao_clear_input() is called.
Store the base pointer of the allocation before clearing the mapper entries and free the array after removing entries from the list.
--- sound/pci/ctxfi/ctdaio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
sound/pci/ctxfi/ctdaio.c +5 -1
@@ -221,14 +221,18 @@ static int dao_set_right_input(struct dastatic int dao_clear_input (struct dao *dao,unsigned int start,unsigned int end) { +struct imapper *entry;unsigned int i; -if (!dao->imappers[start]) + entry = dao->imappers[start]; +if (!entry)return 0 ; +for (i = start; i < end; i++) { dao->mgr->imap_delete (dao->mgr, dao->imappers[i]); dao->imappers[i] =NULL ; } +kfree (entry);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 19/281 ALSA: hda/tas2781: Accept V1 calibration data without CRC
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohamed Yassine Jebabli <[email protected]>
commit 408249089c48df1a4d23f60b831be3f3c311e6d1 upstream.
Some Lenovo BIOSes (e.g. Legion Pro 7 16IRX9H, SSID 17aa:38cd) store valid V1 calibration data in the CALI_DATA EFI variable but leave the TimeStamp and CRC fields zeroed. The driver rejects such data, so the amplifiers always run with default parameters on these machines.
The rejection was silent until
commit 4fe238513407 ("ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib") turned it into "V1 CRC error".
The stored values are consistent (R0 = 3.82/3.83 ohm, 1/R0 matching within 1e-4), so accept V1 data when both TimeStamp and CRC are zero and the first device entry is non-zero, and emit a warning.
--- sound/hda/codecs/side-codecs/tas2781_hda.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
sound/hda/codecs/side-codecs/tas2781_hda.c +15 -3
@@ -139,9 +139,21 @@ static void tas2781_apply_calib(struct t*/ crc =crc32 (~0 , data,84 ) ^ ~0 ;if (crc != tmp_val[21 ]) { - cali_data->total_sz =0 ; -dev_err (p->dev,"%s: V1 CRC error\n" , __func__); -return ; +/* +* Some Lenovo BIOSes (e.g. Legion Pro 7 16IRX9H, +* SSID 17aa:38cd) store valid V1 calibration data +* but leave TimeStamp and CRC zeroed. +*/ +if (!tmp_val[20 ] && !tmp_val[21 ] && + tmp_val[0 ] && tmp_val[1 ]) { +dev_warn (p->dev, +"%s: V1 data without CRC, accepting\n" , + __func__); + }else { + cali_data->total_sz =0 ; +dev_err (p->dev,"%s: V1 CRC error\n" , __func__); +return ; + } }for (j = p->ndev -1 ; j >=0 ; j--) {
Greg Kroah-Hartman
maintainerPATCH 20/281 arm64: irq: exclude the softirq stack switch from KCOV
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit a9cd14bfb0c113f1cd77be4349784663bec71bb4 upstream.
On IRQ exit, __irq_exit_rcu() drops HARDIRQ_OFFSET before calling invoke_softirq(). The arm64 do_softirq_own_stack() wrapper and its ____do_softirq() trampoline run before __do_softirq() establishes softirq context, so KCOV records their PCs in the interrupted task's coverage buffer. They also run outside softirq accounting when local_bh_enable() reaches do_softirq().
The IRQ-exit coverage makes the KCOV boot selftest fail even after the scheduler and timer coverage leaks are suppressed. The generic softirq.o is already excluded from KCOV, but that exclusion does not cover the separately compiled arm64 wrappers.
Exclude irq.o from KCOV instrumentation, as is already done for the arm64 entry code. This covers both wrappers even with compilers that lack the no_sanitize_coverage attribute. The softirq action functions remain instrumented for explicit remote coverage.
--- arch/arm64/kernel/Makefile | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kernel/Makefile +3 -0
@@ -25,6 +25,9 @@ KASAN_SANITIZE_stacktrace.o := n KCOV_INSTRUMENT_entry-common.o := n KCOV_INSTRUMENT_idle.o := n +# Softirq stack switching can run outside interrupt context. +KCOV_INSTRUMENT_irq.o := n + # Object file lists. obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ entry-common.o process.o ptrace.o \
Greg Kroah-Hartman
maintainerPATCH 21/281 ASoC: amd: yc: Add DMI quirk for Acer Aspire Go 15 (AG15-21P)
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Garland <[email protected]>
commit d0cb7a7b2a490c381ad97f53155d02a748b60dea upstream.
The Acer Aspire Go 15 (AG15-21P, board MDC Herbag2_MDU) has two PDM DMICs connected to the ACP. The BIOS does not set the AcpDmicConnected _DSD property, so the acp6x machine driver never registers the DMIC card. The existing Herbag_MDU entry does not match this board name, so add a DMI quirk for it.
Tested on BIOS V1.11: the acp6x DMIC capture device is registered and records audio on both channels.
--- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/soc/amd/yc/acp6x-mach.c +7 -0
@@ -762,6 +762,13 @@ static const struct dmi_system_id yc_acp { .driver_data = &acp6x_card, .matches = { +DMI_MATCH (DMI_BOARD_VENDOR ,"MDC" ), + DMI_MATCH(DMI_BOARD_NAME, "Herbag2_MDU"), + } + }, + { + .driver_data = &acp6x_card, + .matches = {DMI_MATCH (DMI_BOARD_VENDOR ,"System76" ), DMI_MATCH(DMI_PRODUCT_VERSION, "pang12"), }
Greg Kroah-Hartman
maintainerPATCH 22/281 ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hengyu Liang <[email protected]>
commit bc8ce2cea5f77c4bd1a5184705e300e83546c0c4 upstream.
Since commit 2e1d2e65e773 ("ata: libata-scsi: terminate deferred commands on time out"), atapi_qc_complete() sets SAM_STAT_CHECK_CONDITION for a failed command only if cmd->result is zero, so that the DID_TIME_OUT or DID_REQUEUE host byte of a terminated command is preserved.
However, cmd->result can also be non-zero for a regular failed ATAPI command completed through libata EH: ata_eh_analyze_tf() calls ata_eh_decide_disposition(), that is, scsi_check_sense(), on the sense data obtained with REQUEST SENSE, and scsi_check_sense() sets the SCSI midlayer internal byte of the result for some sense codes, e.g. SCSIML_STAT_TGT_FAILURE for ILLEGAL REQUEST with ASC 0x20 (INVALID COMMAND OPERATION CODE) or 0x24 (INVALID FIELD IN CDB), or SCSIML_STAT_MED_ERROR for MEDIUM ERROR with ASC 0x11 (UNRECOVERED READ ERROR). For such commands, atapi_qc_complete() keeps the result as is and the command completes with a GOOD status byte, even though it failed and valid sense data is available.
As a result, passthrough users see these failed ATAPI commands as successful. For example, with the emulated IDE CD-ROM drive of QEMU and no medium loaded, a PLAY AUDIO MSF command issued with SG_IO completes with status 0x00 (and no DRIVER_SENSE) instead of 0x02 (CHECK CONDITION) with sense key ILLEGAL REQUEST, ASC/ASCQ 0x20/0x00, and the CDROM ioctls CDROMPLAYTRKIND, CDROMSUBCHNL, CDROMPAUSE, CDROMRESUME, CDROMPLAYMSF and CDROM_GET_MCN return 0 instead of -ENOMEDIUM or -EOPNOTSUPP.
Fix this by setting the status byte to SAM_STAT_CHECK_CONDITION whenever the host byte is not set. Use set_status_byte() rather than overwriting the whole result, so that the SCSI midlayer internal byte set by scsi_check_sense() is preserved, as ata_scsi_qc_complete() already does for ATA commands.
--- drivers/ata/libata-scsi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/ata/libata-scsi.c +9 -4
@@ -3026,10 +3026,15 @@ static void atapi_qc_complete(struct ataif (qc->cdb[0 ] ==ALLOW_MEDIUM_REMOVAL && qc->dev->sdev) qc->dev->sdev->locked =0 ; -if (cmd->result) -ata_scsi_qc_done (qc, false,0 ); -else -ata_scsi_qc_done (qc, true,SAM_STAT_CHECK_CONDITION ); +/* +* Report CHECK CONDITION unless the command was terminated +* with a host byte set. Only set the status byte, so that the +* SCSI midlayer internal byte, which scsi_check_sense() may +* have set from the sense data, is preserved. +*/ +if (get_host_byte (cmd) ==DID_OK ) +set_status_byte (cmd,SAM_STAT_CHECK_CONDITION ); +ata_scsi_qc_done (qc, false,0 ); goto schedule_deferred; }
Greg Kroah-Hartman
maintainerPATCH 23/281 btrfs: scrub: fix local_root reference leak in scrub_print_warning_inode()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 1fd742c7479961da6d0bb794ef8ac6b7b9442847 upstream.
When paths_from_inode() fails, scrub_print_warning_inode() jumps to err without dropping the reference taken by btrfs_get_fs_root(), leaking a reference to the root every time path resolution fails while printing scrub warnings. Every other error and success path of the function drops the reference.
Drop the reference on the paths_from_inode() failure path too.
--- fs/btrfs/scrub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/btrfs/scrub.c +3 -1
@@ -550,8 +550,10 @@ static int scrub_print_warning_inode(u64 } ret =paths_from_inode (inum, ipath); -if (ret <0 ) +if (ret <0 ) { +btrfs_put_root (local_root); goto err; + }/* * we deliberately ignore the bit ipath might have been too small to
Greg Kroah-Hartman
maintainerPATCH 24/281 can: dev: init_can_skb(): restore skb header initialization
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: zjamg <[email protected]>
commit 0a04c0cb8606ff88399489d03ef255afe90d0d5f upstream.
Commit 9f10374bb024 ("can: remove private CAN skb headroom infrastructure") removed the skb_reset_mac_header()/skb_reset_network_header()/ skb_reset_transport_header() calls from init_can_skb(). As a result, RX skbs from alloc_can_skb() and friends again carry mac_header = 0xFFFF. When such an skb reaches packet_rcv_spkt() (SOCK_PACKET), the push length calculation overflows and triggers skb_under_panic -> kernel BUG -> full machine panic.
The same issue was originally reported in 2014 on linux-can and fixed by commit 969439016d2c ("can: add missing initialisations in CAN related skbuffs"). packet_rcv_spkt() itself has never been hardened: only packet_rcv() and tpacket_rcv() gained dev_has_header() checks in commit d549699048b4 ("net/packet: fix packet receive on L3 devices without visible hard header").
--- drivers/net/can/dev/skb.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/can/dev/skb.c +4 -0
@@ -210,6 +210,10 @@ static void init_can_skb(struct sk_buff { skb->pkt_type =PACKET_BROADCAST ; skb->ip_summed =CHECKSUM_UNNECESSARY ; + +skb_reset_mac_header (skb); +skb_reset_network_header (skb); +skb_reset_transport_header (skb); }struct sk_buff *alloc_can_skb (struct net_device *dev,struct can_frame **cf)
Greg Kroah-Hartman
maintainerPATCH 25/281 can: fix unique skb identifier regression under RPS
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Hartkopp <[email protected]>
commit 7093c3b8314a4ef7405c4066a2521398c455efe7 upstream.
Commit d4fb6514ff8e ("can: use skb hash instead of private variable in headroom") moved the per-skb unique identifier used for raw_rcv() duplicate detection into skb->hash.
With RPS enabled, get_rps_cpu() calls skb_get_hash() before the frame reaches the CAN subsystem. Since CAN skbs have no L3/L4 headers, the flow dissector assigns every CAN frame the same non-zero software hash. can_set_skb_uid() only generated a new identifier when skb->hash was 0, so it kept this constant hash. When the SLAB allocator later reused the same skb address, raw_rcv() mistook the next legitimate frame for a duplicate and dropped it.
Fix this by storing the CAN UID in the CAN skb extension (struct can_skb_ext::can_skb_uid) instead of skb->hash, decoupling it from any hash the network stack may compute. can_set_skb_uid() keeps its "assign only if unset" behaviour, which preserves UIDs set before transmission (e.g. by isotp to identify echo frames) across the local loopback path.
Frames whose extension is shared with another clone (e.g. via tc mirred or netem duplicate) are given a private extension copy before the UID is assigned, so that independently received skb clones from real CAN interfaces (can_skb_uid = 0) don't end up with the same UID. The limitation that tc mirred/netem skb duplicates might be dropped in raw_rcv for looped back isotp echo frame skbs is accepted. There is no valid use-case for tc mirred or netem together with isotp which is not capable to operate on different CAN interfaces simultaneously. For routing and modifying CAN frames together with isotp use can-gw.
can-gw and vxcan additionally clear the UID of forwarded/duplicated frames so each newly routed frame gets its own unique identifier.
--- drivers/net/can/vxcan.c | 3 +++ include/linux/can/core.h | 3 ++- include/linux/can/skb.h | 4 +++- include/net/can.h | 2 ++ net/can/af_can.c | 47 ++++++++++++++++++++++++++++++++++++----------- net/can/gw.c | 3 +++ net/can/isotp.c | 16 ++++++++++------ net/can/raw.c | 10 +++++++--- 8 files changed, 66 insertions(+), 22 deletions(-)
drivers/net/can/vxcan.c +3 -0
@@ -78,6 +78,9 @@ static netdev_tx_t vxcan_xmit(struct sk_/* reset CAN GW hop counter */ csx->can_gw_hops =0 ; +/* start with new CAN skb UID in the other namespace */ + csx->can_skb_uid =0 ; + skb->pkt_type =PACKET_BROADCAST ; skb->dev = peer; skb->ip_summed =CHECKSUM_UNNECESSARY ;
include/linux/can/core.h +2 -1
@@ -17,6 +17,7 @@#include <linux/can.h> #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <net/can.h> #define DNAME (dev) ((dev) ? (dev)->name : "any")
@@ -58,7 +59,7 @@ extern void can_rx_unregister(struct net void *data);extern int can_send (struct sk_buff *skb,int loop); -void can_set_skb_uid (struct sk_buff *skb); +void can_set_skb_uid (struct can_skb_ext *csx);void can_sock_destruct (struct sock *sk);#endif /* !_CAN_CORE_H */
include/linux/can/skb.h +3 -1
@@ -43,8 +43,10 @@ static inline struct can_skb_ext *can_skstruct can_skb_ext *csx =skb_ext_add (skb,SKB_EXT_CAN );/* skb_ext_add() returns uninitialized space */ -if (csx) +if (csx) { csx->can_gw_hops =0 ; + csx->can_skb_uid =0 ; + }return csx; }
include/net/can.h +2 -0
@@ -17,12 +17,14 @@* @can_framelen: cached echo CAN frame length for bql * @can_gw_hops: can-gw CAN frame time-to-live counter * @can_ext_flags: CAN skb extensions flags +* @can_skb_uid: CAN skb UID for raw_rcv and isotp echo handling */ struct can_skb_ext {int can_iif;u16 can_framelen;u8 can_gw_hops;u8 can_ext_flags; +u32 can_skb_uid; };#endif /* _NET_CAN_H */
net/can/af_can.c +36 -11
99 lines not on this page · raw message
net/can/gw.c +3 -0
@@ -527,6 +527,9 @@ static void can_can_gw_rcv(struct sk_buf/* put the incremented hop counter in the cloned skb */ ncsx->can_gw_hops = csx->can_gw_hops +1 ; +/* force a new CAN UID generation for the routed frame */ + ncsx->can_skb_uid =0 ; +/* first processing of this CAN frame -> adjust to private hop limit */ if (gwj->limit_hops && ncsx->can_gw_hops ==1 ) ncsx->can_gw_hops = max_hops - gwj->limit_hops +1 ;
net/can/isotp.c +10 -6
@@ -891,7 +891,7 @@ static void isotp_send_cframe(struct iso csx->can_iif = dev->ifindex;/* set uid in tx skb to identify CF echo frames */ -can_set_skb_uid (skb); +can_set_skb_uid (csx); cf = (struct canfd_frame *)skb->data;skb_put_zero (skb, so->ll.mtu);
@@ -917,7 +917,7 @@ static void isotp_send_cframe(struct isopr_notice_once ("can-isotp: cfecho is %08X != 0\n" , old_cfecho);/* set consecutive frame echo tag */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho, csx->can_skb_uid);/* send frame with local echo enabled */ can_send_ret =can_send (skb,1 );
@@ -969,18 +969,22 @@ static void isotp_rcv_echo(struct sk_buf {struct sock *sk = (struct sock *)data;struct isotp_sock *so =isotp_sk (sk); +struct can_skb_ext *csx =can_skb_ext_find (skb);/* only handle my own local echo CF/SF skb's (no FF!) */ if (skb->sk != sk)return ; +if (WARN_ON_ONCE (!csx)) +return ; +/* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock * (no isotp_rcv() caller here), so take it ourselves */ spin_lock (&so->rx_lock);/* so->cfecho may since belong to a new transfer; recheck under lock */ -if (READ_ONCE (so->cfecho) != skb->hash) +if (READ_ONCE (so->cfecho) != csx->can_skb_uid) goto out_unlock;/* cancel local echo timeout */
@@ -1222,7 +1226,7 @@ static int isotp_sendmsg(struct socket * csx->can_iif = dev->ifindex;/* set uid in tx skb to identify CF echo frames */ -can_set_skb_uid (skb); +can_set_skb_uid (csx); so->tx.len = size; so->tx.idx =0 ;
@@ -1261,7 +1265,7 @@ static int isotp_sendmsg(struct socket * cf->data[ae] |= size;/* set CF echo tag for isotp_rcv_echo() (SF-mode) */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho, csx->can_skb_uid); }else {/* send first frame */
@@ -1278,7 +1282,7 @@ static int isotp_sendmsg(struct socket * so->txfc.bs =0 ;/* set CF echo tag for isotp_rcv_echo() (CF-mode) */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho, csx->can_skb_uid); }else {/* standard flow control check */ new_state =ISOTP_WAIT_FIRST_FC ;
net/can/raw.c +7 -3
@@ -77,7 +77,7 @@ MODULE_ALIAS("can-proto-1");struct uniqframe {const struct sk_buff *skb; -u32 hash; +u32 can_skb_uid;unsigned int join_rx_count; };
@@ -133,12 +133,16 @@ static void raw_rcv(struct sk_buff *oskbenum skb_drop_reason reason;struct sockaddr_can *addr;struct sk_buff *skb; +struct can_skb_ext *csx =can_skb_ext_find (oskb);unsigned int *pflags;/* check the received tx sock reference */ if (!ro->recv_own_msgs && oskb->sk == sk)return ; +if (WARN_ON_ONCE (!csx)) +return ; +/* make sure to not pass oversized frames to the socket */ if (!ro->fd_frames &&can_is_canfd_skb (oskb))return ;
@@ -165,7 +169,7 @@ static void raw_rcv(struct sk_buff *oskb/* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr (ro->uniq)->skb == oskb && -this_cpu_ptr (ro->uniq)->hash == oskb->hash) { +this_cpu_ptr (ro->uniq)->can_skb_uid == csx->can_skb_uid) {if (!ro->join_filters)return ;
@@ -175,7 +179,7 @@ static void raw_rcv(struct sk_buff *oskbreturn ; }else {this_cpu_ptr (ro->uniq)->skb = oskb; -this_cpu_ptr (ro->uniq)->hash = oskb->hash; +this_cpu_ptr (ro->uniq)->can_skb_uid = csx->can_skb_uid;this_cpu_ptr (ro->uniq)->join_rx_count =1 ;/* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count >1 )
Greg Kroah-Hartman
maintainerPATCH 26/281 cgroup/cpuset: Handle cpu hotplug race in guarantee_active_cpus()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Waiman Long <[email protected]>
commit 23b1ab15ca91f2cffaf149d9bb0fafeb700c7db2 upstream.
With commit 2125c0034c5d ("cgroup/cpuset: Make cpuset hotplug processing synchronous"), the cpuset hotplug operation becomes synchronous. That commit also removes the code that handles race between cpuset_hotplug_work and cpu hotplug notifier with the assumption that race is now gone. Later commit 7a0aabd9ce69 ("cgroup/cpuset: Always use cpu_active_mask") updates the cpuset code to always use cpu_active_mask instead of cpu_online_mask in some places including guarantee_online_cpus() which is renamed to guarantee_active_cpus() in that commit.
In the case of CPU offline operation, cpu_active_mask is updated first in sched_cpu_deactivate() to remove the offline CPU before cpuset_handle_hotplug() is called to update the effective_cpus of the affected cpusets. The cpu_online_mask is updated after that near the end of the offline operation to remove the offline CPU. As a result, the race comes back and the top cpuset may not have any active CPU leading to NULL pointer dereference during the race window when guarantee_active_cpus() is called after cpu_active_mask is updated to remove the CPU to be torn down but before cpuset_handle_hotplug() is able to properly update the effective_cpus of the top cpuset.
Fix this by adding back the NULL cs check to avoid this problem.
--- kernel/cgroup/cpuset.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
kernel/cgroup/cpuset.c +18 -2
@@ -478,10 +478,26 @@ static void guarantee_active_cpus(structrcu_read_lock (); cs =task_cs (tsk); -while (!cpumask_intersects (cs->effective_cpus, pmask)) +while (!cpumask_intersects (cs->effective_cpus, pmask)) { cs =parent_cs (cs); - +if (unlikely (!cs)) { +/* +* The top cpuset doesn't have any active cpu as a +* consequence of a race between its caller and the cpu +* hotplug operation where cpu_active_mask is updated +* asynchronously before cpuset_handle_hotplug() is +* being called to adjust the effective_cpus of the +* affected cpusets. But we know the top cpuset's +* effective_cpus is on its way to be identical to +* cpu_active_mask minus the exclusive CPUs dedicated +* to other valid cpuset partitions. Just pass back +* the filtered cpu_active_mask in this case. +*/ + goto out_unlock; + } + }cpumask_and (pmask, pmask, cs->effective_cpus); +out_unlock:rcu_read_unlock (); }
Greg Kroah-Hartman
maintainerPATCH 27/281 cipso: adjust cached option offsets when removing CIPSO
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 6d25ffca055a77787c21a36b66c253f76239411b upstream.
cipso_v4_skbuff_delattr() removes the CIPSO bytes but does not adjust cached offsets for options that follow them.
For example, with a valid 10-byte CIPSO option followed by a seven-byte RR option, parsing records rr at offset 30. Removing CIPSO moves RR to offset 20, while the cached offset remains 30. Consumers such as ip_forward_options() and __ip_options_echo() then access the wrong bytes; the latter may interpret packet data as the option length and copy it into fixed-size option storage.
Mirror cipso_v4_delopt() and subtract cipso_len from the srr, rr, ts and router_alert offsets when they follow CIPSO. cipso_len is the distance the first memmove() shifts those options. The later header move and network-header reset relocate the bytes and their offset base together.
--- net/ipv4/cipso_ipv4.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/ipv4/cipso_ipv4.c +8 -0
@@ -2287,6 +2287,14 @@ int cipso_v4_skbuff_delattr(struct sk_bu new_hdr_len - new_hdr_len_actual); opt->optlen -= hdr_len_delta; +if (opt->srr > opt->cipso) + opt->srr -= cipso_len; +if (opt->rr > opt->cipso) + opt->rr -= cipso_len; +if (opt->ts > opt->cipso) + opt->ts -= cipso_len; +if (opt->router_alert > opt->cipso) + opt->router_alert -= cipso_len; opt->cipso =0 ; opt->is_changed =1 ;if (hdr_len_delta !=0 ) {
Greg Kroah-Hartman
maintainerPATCH 28/281 dm ioctl: dont let data_start run past the buffer
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Palla Raghunath <[email protected]>
commit 9b3fcf519d370df94a56f3b272d9eddffffa5be8 upstream.
struct dm_ioctl has seven bytes of trailing padding, so the smallest buffer userspace is allowed to ask for, offsetof(struct dm_ioctl, data), is seven bytes shorter than sizeof(struct dm_ioctl).
get_result_buffer() sets data_start to sizeof(struct dm_ioctl) without looking at how big the buffer actually is. Ask for the minimum and data_start ends up seven bytes past the end. Callers add it to data_size, and ctl_ioctl() copies that much back to userspace:
BUG: KASAN: slab-out-of-bounds in _copy_to_user+0xad/0xd0 Read of size 312 at addr ffff8880169e4c00 by task repro-dm/140 ctl_ioctl+0x5e3/0xcb0 dm_ctl_ioctl+0x25/0x40 allocated 305-byte region [ffff8880169e4c00, ffff8880169e4d31)
A DM_LIST_DEVICES with data_size set to 305 is enough to hit it, and the seven bytes that leak are whatever sat next to the allocation.
Clamp data_start to the buffer size.
Note that this is not a security bug because the out-of-bounds read can only be triggered by root.
--- drivers/md/dm-ioctl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/md/dm-ioctl.c +8 -2
@@ -658,10 +658,16 @@ static void *get_result_buffer(struct dm { param->data_start =align_ptr (param +1 ) - (void *) param; -if (param->data_start < param_size) +if (param->data_start < param_size) { *len = param_size - param->data_start; -else + }else { +/* +* The buffer can be as small as offsetof(*param, data), which +* is less than sizeof(*param), so don't run off the end of it. +*/ *len =0 ; + param->data_start = param_size; + }return ((void *) param) + param->data_start; }
Greg Kroah-Hartman
maintainerPATCH 29/281 usb: f81604: fix struct f81604_int_data size mismatch
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ji-Ze Hong (Peter Hong) <[email protected]>
commit 7f85d1170575645f9f327062d78017a23b2714eb upstream.
The struct f81604_int_data defines 9 bytes of interrupt data:
- Byte 0: Status register (sr)
- Byte 1: Interrupt register (isrc)
- Byte 2: Interrupt enable register (ier)
- Byte 3: Arbitration lost capture (alc)
- Byte 4: Error code capture (ecc)
- Byte 5: Error warning limit register (ewlr)
- Byte 6: RX error counter (rxerr)
- Byte 7: TX error counter (txerr)
- Byte 8: Reserved (val)
The hardware sends exactly 9 bytes for the interrupt endpoint. However, the struct was defined with __aligned(4) attribute which caused the compiler to pad the struct to 12 bytes.
This causes a problem in f81604_read_int_callback() where the short URB check compares urb->actual_length against sizeof(*data). When sizeof(struct f81604_int_data) is 12 but the hardware only sends 9 bytes, the check fails and valid interrupt messages are discarded.
This results in the driver only being able to transmit once because the TX complete interrupt is never processed.
Fix this by removing the __aligned(4) attribute so the struct size matches the actual hardware data size of 9 bytes.
--- drivers/net/can/usb/f81604.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/can/usb/f81604.c +1 -1
@@ -169,7 +169,7 @@ struct f81604_int_data {u8 rxerr;u8 txerr;u8 val; -} __packed__aligned(4) ; +} __packed;struct f81604_sff {__be16 id;
Greg Kroah-Hartman
maintainerPATCH 30/281 vsock/virtio: account only unread bytes in read_skb()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit a463f55c791b96cfd12df8b10ea737d45c80bb18 upstream.
After a partial stream receive, rx_bytes tracks the unread suffix while buf_used and peer credit still cover the whole packet. virtio_transport_read_skb() dequeues that packet but passes pkt_len for both counters, underflowing rx_bytes.
On a connected CID_LOCAL stream with an SK_SKB verdict, a 40-byte read from a 100-byte packet made SIOCINQ report -40, an empty recv return ELOOP, and poll report the empty socket readable. After verdict detach, receiving 40 bytes wrapped the counter to zero and hid those queued bytes until one more byte arrived. The fixed run kept the counter balanced and exposed all queued data immediately.
This was found during an LLM-assisted manual source audit of VSOCK receive accounting while re-evaluating virtio_transport_read_skb() after CVE-2024-50169.
Subtract only skb->len minus the VSOCK offset from rx_bytes. Retain the full packet length for buf_used and peer credit.
--- net/vmw_vsock/virtio_transport_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/vmw_vsock/virtio_transport_common.c +3 -1
@@ -1916,6 +1916,7 @@ int virtio_transport_read_skb(struct vsostruct sock *sk =sk_vsock (vsk);struct virtio_vsock_hdr *hdr;struct sk_buff *skb; +u32 bytes_read;u32 pkt_len;int off =0 ;int err;
@@ -1935,7 +1936,8 @@ int virtio_transport_read_skb(struct vso vvs->msg_count--; pkt_len =le32_to_cpu (hdr->len); -virtio_transport_dec_rx_pkt (vvs, pkt_len, pkt_len); + bytes_read = skb->len -VIRTIO_VSOCK_SKB_CB (skb)->offset; +virtio_transport_dec_rx_pkt (vvs, bytes_read, pkt_len);spin_unlock_bh (&vvs->rx_lock);virtio_transport_send_credit_update (vsk);
Greg Kroah-Hartman
maintainerPATCH 31/281 wifi: brcmfmac: fix P2P device removal race in brcmf_detach()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michele Dionisio <[email protected]>
commit 08a3f02fea636e97a7422d1512f76dacdb5b0887 upstream.
When the driver is removed while the user space process that created the P2P device (e.g. wpa_supplicant) is still exiting, the P2P device interface is removed twice and the kernel crashes.
The two paths are:
- wpa_supplicant, on exit, sends NL80211_CMD_DEL_INTERFACE for the P2P device. nl80211_del_interface() holds RTNL and the wiphy mutex and calls brcmf_p2p_del_vif(), which disables discovery and waits up to 1.5 s for BRCMF_E_IF_DEL. Then it calls brcmf_remove_interface(), which unregisters the wdev and frees the vif and the ifp.
- brcmf_detach() sets the bus down, so BRCMF_E_IF_DEL never arrives, and calls brcmf_remove_interface(ifp, false) for the same ifp. brcmf_p2p_ifp_removed() reads ifp->vif and then blocks on rtnl_lock(). When brcmf_p2p_del_vif() releases RTNL, it calls cfg80211_unregister_wdev() on the wdev that was already unregistered and freed.
The second list_del_rcu() of wdev->list faults on LIST_POISON2:
brcmfmac: brcmf_p2p_del_vif delete P2P vif
brcmfmac: brcmf_p2p_deinit_discovery enter
brcmfmac: brcmf_p2p_del_vif P2P: GO_NEG_PHASE status cleared
brcmfmac: brcmf_detach Enter
brcmfmac: brcmf_bus_change_state 1 -> 0
brcmfmac: brcmf_remove_interface Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_del_if Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_p2p_ifp_removed P2P: device interface removed [1.5 s later, brcmf_p2p_del_vif() timed out]
brcmfmac: brcmf_remove_interface Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_del_if Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_p2p_ifp_removed P2P: device interface removed
Unable to handle kernel paging request at virtual address dead000000000122 Internal error: Oops: 96000044 [#1] PREEMPT_RT SMP pc : _cfg80211_unregister_wdev+0x6c/0x264 [cfg80211] Call trace: _cfg80211_unregister_wdev+0x6c/0x264 [cfg80211] cfg80211_unregister_wdev+0x10/0x1c [cfg80211] brcmf_p2p_ifp_removed+0x84/0xb0 [brcmfmac] brcmf_remove_interface+0x1f4/0x254 [brcmfmac] brcmf_detach+0x88/0x180 [brcmfmac] brcmf_sdio_remove+0x90/0x7b0 [brcmfmac] brcmf_sdiod_remove+0x20/0xa0 [brcmfmac] brcmf_ops_sdio_remove+0xbc/0x12c [brcmfmac] sdio_bus_remove+0x38/0x144 device_release_driver_internal+0x1e8/0x2c0 device_release_driver+0x14/0x20 brcmf_sdio_bus_remove+0x2c/0x40 [brcmfmac] brcmf_fwvid_unregister_vendor+0xd8/0x170 [brcmfmac] __exit_compat+0x18/0x418 [brcmfmac_cyw] __arm64_sys_delete_module+0x1ac/0x244
The log was taken with debug=0x406 on an i.MX 8M Plus board with a CYW55513 (Sona IF513) on SDIO. The driver is the Ezurio backport of brcmfmac from v6.18.22 on a 5.4-rt kernel. The code involved is the same in mainline.
To reproduce:
1. Start wpa_supplicant on wlan0 and let it associate. It creates the P2P device (iw dev shows "type P2P-device").
2. Stop wpa_supplicant and remove the driver without waiting for wpa_supplicant to exit:
kill $(pidof wpa_supplicant)
rmmod brcmfmac_cyw brcmfmac
The crash is reproducible on that board.
For the interface without a netdev (the P2P device), take RTNL and the wiphy mutex in brcmf_detach() before reading iflist, and remove it with locked=true. If brcmf_p2p_del_vif() runs first, brcmf_detach() finds the slot empty. If brcmf_detach() runs first, nl80211 does not find the wdev any more. The interfaces with a netdev are removed as before, because brcmf_del_if() takes RTNL on its own for the primary interface.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 27 ++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +25 -2
@@ -1489,8 +1489,31 @@ void brcmf_detach(struct device *dev)brcmf_bus_change_state (bus_if,BRCMF_BUS_DOWN );/* make sure primary interface removed last */ for (i =BRCMF_MAX_IFS -1 ; i >-1 ; i--) { -if (drvr->iflist[i]) -brcmf_remove_interface (drvr->iflist[i], false); +struct brcmf_if *ifp = drvr->iflist[i]; + +if (!ifp) +continue ; + +if (ifp->ndev) { +brcmf_remove_interface (ifp, false); +continue ; + } + +/* The P2P device interface has no netdev. Its removal can +* race with NL80211_CMD_DEL_INTERFACE issued by a user space +* process that is exiting (e.g. wpa_supplicant), which ends +* in brcmf_p2p_del_vif() under RTNL and the wiphy mutex. If +* both paths remove the interface, the wdev is unregistered +* twice and the vif is used after being freed. Take the same +* locks and re-read iflist, so only one path removes it. +*/ +rtnl_lock (); +wiphy_lock (drvr->wiphy); + ifp = drvr->iflist[i]; +if (ifp) +brcmf_remove_interface (ifp, true); +wiphy_unlock (drvr->wiphy); +rtnl_unlock (); }brcmf_bus_stop (drvr->bus_if);
Greg Kroah-Hartman
maintainerPATCH 32/281 wifi: mt76: mt7603: initialize global station WCID
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Papa <[email protected]>
commit 456de496b53ae73e6e3020fec815dbdc88aa7c07 upstream.
mt7603 uses a driver-private global station WCID for frames that have neither a station nor a vif, including frames injected through a monitor interface. Unlike the core global WCID initialized by mt76_register_device(), this WCID is published without ever being passed to mt76_wcid_init().
Since commit 0335c034e726 ("wifi: mt76: fix race condition related to checking tx queue fill status"), mt76_tx() queues every such frame on the WCID's tx_pending or tx_offchannel queue and links its tx_list. The first injected frame therefore reaches __skb_queue_tail() with an uninitialized sk_buff_head and dereferences a NULL prev pointer.
Initialize the WCID before publishing it.
The fix was tested on an MT7603 PCIe device. Three wildcard probe requests were injected through a monitor interface. The hardware queue head and tail advanced from 0 to 3 and a second radio captured the third request over the air. No oops or reset occurred. After restoring AP mode, a 150 MB transfer also completed without a reset.
--- drivers/net/wireless/mediatek/mt76/mt7603/init.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/mediatek/mt76/mt7603/init.c +1 -0
@@ -230,6 +230,7 @@ mt7603_mac_init(struct mt7603_dev *dev)eth_broadcast_addr (bc_addr);mt7603_wtbl_init (dev,MT7603_WTBL_RESERVED ,-1 , bc_addr); +mt76_wcid_init (&dev->global_sta.wcid,0 ); dev->global_sta.wcid.idx =MT7603_WTBL_RESERVED ;rcu_assign_pointer (dev->mt76.wcid[MT7603_WTBL_RESERVED ], &dev->global_sta.wcid);
Greg Kroah-Hartman
maintainerPATCH 33/281 wifi: mt76: mt7996: fix uninitialized buf read in mt7996_variant_fem_init()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Huang <[email protected]>
commit 52f6a065e0810c739a5dabd33a58047f08100f50 upstream.
When the eFuse block covering MT7976C_EFUSE_OFFSET is invalid, mt7996_mcu_get_eeprom() returns -EINVAL without writing buf, but mt7996_variant_fem_init() tolerates -EINVAL and keeps running, so buf[idx] == 0xc reads uninitialized stack memory. A stale 0x0c byte misclassifies a 0x7976 aDie as 7976C, selects MT7996_FEM_INT and the wrong default EEPROM, overriding valid calibration data. Only consult the eFuse byte when the read succeeded; with an invalid eFuse, fall back to the three explicit aDie version checks.
--- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7996/init.c +1 -1
@@ -1237,7 +1237,7 @@ static int mt7996_variant_fem_init(struc adie_ver =u32_get_bits (regval,MT_ADIE_VERSION_MASK ); idx =MT7976C_EFUSE_OFFSET %MT7996_EEPROM_BLOCK_SIZE ; is_7976c = adie_ver ==0x8a10 || adie_ver ==0x8b00 || - adie_ver ==0x8c10 || buf[idx] ==0xc ; + adie_ver ==0x8c10 || (!ret && buf[idx] ==0xc ); adie_id =u32_get_bits (regval,MT_ADIE_CHIP_ID_MASK ); if (adie_id == 0x7975 || adie_id == 0x7979 ||
Greg Kroah-Hartman
maintainerPATCH 34/281 wireguard: queueing: preserve tstamp_type when encapsulating packet
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ramses de Norre <[email protected]>
commit 65ab9de4bdd4c05d8277cfc20ae0b9f5aff60897 upstream.
Sending traffic through a wireguard tunnel on a host using the fq qdisc fills the log with:
fq: likely mono tstamp with tstamp_type 0
An skb carries a timestamp in skb->tstamp and, separately, a skb->tstamp_type field recording which clock that timestamp came from. The two have to agree.
When wireguard encapsulates a packet it calls wg_reset_packet(), which clears the fields that must not leak from the inner packet into the tunnel packet. It does so in two steps:
skb_scrub_packet(skb, true); memset(&skb->headers, 0, sizeof(skb->headers));
skb_scrub_packet() deliberately keeps skb->tstamp when it holds a monotonic timestamp: that value is the time the packet is scheduled to be sent, and the qdisc still needs it. The memset then zeroes skb->tstamp_type, because that field sits inside the headers group while skb->tstamp does not. The packet therefore leaves wireguard carrying a monotonic timestamp labelled as a realtime one.
Nothing noticed until commit c4f796c4f16b ("net_sched: sch_fq: convert skb->tstamp if not monotonic"): fq used to assume every timestamp was monotonic. It now consults tstamp_type, spots the mismatch, warns, and falls back to treating the value as monotonic. Pacing still ends up correct, so the log spam is the actual problem.
Save tstamp_type before the memset and restore it when encapsulating, next to the hash fields that are already carried over this way. When decapsulating it stays zeroed, which is right: an incoming packet's timestamp is a realtime receive timestamp.
--- drivers/net/wireguard/queueing.h | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireguard/queueing.h +2 -0
@@ -78,12 +78,14 @@ static inline void wg_reset_packet(strucu8 l4_hash = skb->l4_hash;u8 sw_hash = skb->sw_hash;u32 hash = skb->hash; +u8 tstamp_type = skb->tstamp_type;skb_scrub_packet (skb, true);memset (&skb->headers,0 ,sizeof (skb->headers));if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash; skb->hash = hash; + skb->tstamp_type = tstamp_type; } skb->queue_mapping =0 ; skb->nohdr =0 ;
Greg Kroah-Hartman
maintainerPATCH 35/281 wireguard: noise: reject response consumption after intermediate initiation
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason A. Donenfeld <[email protected]>
commit d0305f8d90029556260c6824b61c493c424eba9e upstream.
Two threads begin processing the identical response message, received twice. The first thread, A, runs. While it's running, the second one, B, gets partway through, and during that slow calculation, or even while blocking on down_write(), A completes and then also a handshake initiation that's already been queued up runs in thread C, which itself takes that same down_write(). The handshake initiation creation succeeds, and sets the state back to waiting-for-response, and calls up_write(), at which point thread B resumes, because either its finished its calculations or was finally allowed to acquire down_write(). Thread B then copies the state back to the peer, and begins a new session, using that state, which is the same session as the one made in thread A.
Thread A Thread B Thread C
down_read()
sA = handshake->state
memcpy(cA, handshake->crypto)up_read()
if (sA != 1)
goto failslow_crypto(cA)
down_read() sB = handshake->state memcpy(cB, handshake->crypto) up_read() if (sB != 1) goto fail slow_crypto(cB)
down_write()
if (sA != handshake->state)
goto fail
memcpy(handshake->crypto, cA)
handshake->state = 2up_write()down_write()
if (handshake->state != 2)
goto fail
derive_session(handshake->crypto)up_write()
down_write() slow_crypto(handshake->crypto) handshake->state = 1 up_write() down_write() if (sB != handshake->state) goto fail memcpy(handshake->crypto, cB) handshake->state = 2 up_write() down_write() if (handshake->state != 2) goto fail derive_session(handshake->crypto) up_write()
This seems basically impossible to hit in a meaningful way in practice, but ensure that it absolutely cannot happen by comparing the ephemeral private key that's on the stack with the latest one that the peer's handshake state has.
--- drivers/net/wireguard/noise.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/wireguard/noise.c +4 -3
@@ -784,10 +784,11 @@ wg_noise_handshake_consume_response(stru/* Success! Copy everything to peer */ down_write (&handshake->lock); -/* It's important to check that the state is still the same, while we -* have an exclusive lock. +/* Check that the state is the same and that this is still the +* initiation we started with, while we have an exclusive lock. */ -if (handshake->state != state) { +if (handshake->state != state || +crypto_memneq (handshake->ephemeral_private, ephemeral_private,NOISE_PUBLIC_KEY_LEN )) {up_write (&handshake->lock); goto fail; }
Greg Kroah-Hartman
maintainerPATCH 36/281 workqueue: Fix NULL current_pwq deref in chained work check
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavankumar Kondeti <[email protected]>
commit 980db94e3eeefdd8a1c46f86412c33a7f7806f51 upstream.
current_wq_worker() only tells us that %current is a kworker. It does not guarantee that the worker is currently executing a work item, as worker->current_pwq is populated only while process_one_work() is running the work function.
is_chained_work() can be reached while queueing on a draining or destroying workqueue. If a kworker outside work-item execution reaches that path, current_wq_worker() returns a worker but worker->current_pwq is NULL, and the chained-work test can fault before it emits the intended warning.
Guard the chained-work test with worker->current_pwq. A kworker without current_pwq is not executing work on the target workqueue, so the helper should return false and let the draining/destroying warning fire.
--- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/workqueue.c +1 -1
@@ -2244,7 +2244,7 @@ static bool is_chained_work(struct workq* Return %true iff I'm a worker executing a work item on @wq. If * I'm @worker, it's safe to dereference it without locking. */ -return worker && worker->current_pwq->wq == wq; +return worker && worker->current_pwq && worker->current_pwq->wq == wq; }/*
Greg Kroah-Hartman
maintainerPATCH 37/281 x86/CPU/AMD: Fix AMD TLBI Erratum #1718
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Borislav Petkov (AMD) <[email protected]>
commit 87db7795cbaaf636ae22ae031f4906db7bb77803 upstream.
The processor may fail to invalidate a TLB entry while executing an INVLPGB/TLBSYNC instruction pair.
Detect the erratum and apply a software workaround when a microcode fix is not present.
--- arch/x86/include/asm/cpufeatures.h | 3 +++ arch/x86/include/asm/tlb.h | 6 ++++++ arch/x86/kernel/cpu/amd.c | 4 ++++ 3 files changed, 13 insertions(+)
arch/x86/include/asm/cpufeatures.h +3 -0
@@ -465,6 +465,8 @@#define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0)/* No Nested Data Breakpoints */ #define X86_FEATURE_WRMSR_XX_BASE_NS (20*32+ 1)/* WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */ #define X86_FEATURE_LFENCE_RDTSC (20*32+ 2)/* LFENCE always serializing / synchronizes RDTSC */ + +#define X86_FEATURE_TLBSYNC_SFW_NO (20*32+ 4)/* TLBI Erratum #1718 fixed in microcode */ #define X86_FEATURE_VERW_CLEAR (20*32+ 5)/* The memory form of VERW mitigates TSA */ #define X86_FEATURE_NULL_SEL_CLR_BASE (20*32+ 6)/* Null Selector Clears Base */
@@ -575,4 +577,5 @@#define X86_BUG_TSA X86_BUG( 1*32+ 9)/* "tsa" CPU is affected by Transient Scheduler Attacks */ #define X86_BUG_VMSCAPE X86_BUG( 1*32+10)/* "vmscape" CPU is affected by VMSCAPE attacks from guests */ #define X86_BUG_SEAMRET_INVD_VMCS X86_BUG( 1*32+11)/* "seamret_invd_vmcs" SEAMRET from P-SEAMLDR clears the current VMCS */ +#define X86_BUG_TLBI X86_BUG( 1*32+12)/* "tlbi" AMD TLBI Erratum #1718 */ #endif /* _ASM_X86_CPUFEATURES_H */
arch/x86/include/asm/tlb.h +6 -0
@@ -110,6 +110,12 @@ static inline void __tlbsync(void)/* TLBSYNC: supported in binutils >= 0.36. */ asmvolatile (".byte 0x0f, 0x01, 0xff" :::"memory" ); + +if (!static_cpu_has_bug (X86_BUG_TLBI )) +return ; + +/* TLBSYNC: supported in binutils >= 0.36. */ + asm volatile(".byte 0x0f, 0x01, 0xff" ::: "memory"); }#else /* Some compilers (I'm looking at you clang!) simply can't do DCE */
arch/x86/kernel/cpu/amd.c +4 -0
@@ -1047,6 +1047,10 @@ static void init_amd_zen5(struct cpuinfomsr_clear_bit (MSR_AMD64_CPUID_FN_7 ,18 );pr_emerg_once ("RDSEED32 is broken. Disabling the corresponding CPUID bit.\n" ); } + +if (cpu_has (c,X86_FEATURE_INVLPGB ) && + !cpu_has (c,X86_FEATURE_TLBSYNC_SFW_NO )) +set_cpu_bug (c,X86_BUG_TLBI ); }static void init_amd (struct cpuinfo_x86 *c)
Greg Kroah-Hartman
maintainerPATCH 38/281 xen/netfront: dont leak the skb when xennet_fill_frags() fails
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik <[email protected]>
commit 93ccaf1c26e2133396173b76a071e59024daa622 upstream.
When a response chain has more slots than fit in the skb's frags, xennet_fill_frags() returns an error and xennet_poll() jumps to its error path. That path moves what's left on tmpq to errq to be freed, but the skb being filled was already dequeued from tmpq, so it's never freed. Each chain that overflows leaks the skb and the pages attached to it as frags, and the backend decides how many slots it sends.
Put the skb back on tmpq before taking the error path, like the xennet_set_skb_gso() failure just above it does.
--- drivers/net/xen-netfront.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/xen-netfront.c +3 -1
@@ -1346,8 +1346,10 @@ err: skb->data_len = rx->status; skb->len += rx->status; -if (unlikely (xennet_fill_frags (queue, skb, &tmpq))) +if (unlikely (xennet_fill_frags (queue, skb, &tmpq))) { +__skb_queue_head (&tmpq, skb); goto err; + }if (rx->flags & XEN_NETRXF_csum_blank) skb->ip_summed =CHECKSUM_PARTIAL ;
Greg Kroah-Hartman
maintainerPATCH 39/281 tee: shm: reject zero-sized allocations in tee_dyn_shm_alloc_helper()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Georgiy Osokin <[email protected]>
commit b7f925fd5226deb953c8dcdc9677d3fcc2717c00 upstream.
tee_dyn_shm_alloc_helper() derives nr_pages from a caller-supplied size and passes it to alloc_pages_exact() without checking it. For size == 0 nr_pages is 0, and alloc_pages_exact(0) calls get_order(0), which is documented as undefined and returns BITS_PER_LONG - PAGE_SHIFT. The page allocator then trips its order > MAX_PAGE_ORDER warning and fails the allocation; on a panic_on_warn kernel that ends the boot.
This can be triggered by TEE_IOC_SHM_ALLOC with struct tee_ioctl_shm_alloc_data where size is 0.
Reject a zero page count, as register_shm_helper() already does for the register path.
--- drivers/tee/tee_shm.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/tee/tee_shm.c +4 -0
@@ -343,6 +343,10 @@ int tee_dyn_shm_alloc_helper(struct tee_unsigned int i;int rc =0 ; +/* get_order(0) is undefined and exceeds MAX_PAGE_ORDER. */ +if (!nr_pages) +return -EINVAL ; +/* * Ignore alignment since this is already going to be page aligned * and there's no need for any larger alignment.
Greg Kroah-Hartman
maintainerPATCH 40/281 strparser: make sure __strp_recv isnt running before tearing down the parser
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
commit 0984ebc631792acf8fff105112ee74a6b8f1efcc upstream.
The comment above strp_done() claims that if strp is stopped, strp_recv will no longer be called. That's only true if the caller has a mechanism (eg locking) to guarantee that strp_recv() calls that started before strp_stop() have completed by the time we call strp_done().
This adds a dummy lock_sock/release_sock pair to guarantee that any in-flight strp_recv() (which runs under either bh_lock_sock or lock_sock, depending if it's called from ->sk_data_ready or strp_work) has completed.
Only espintcp can be affected by this race condition, but this patch makes sure no future user of strp can have the bug.
This could crash on strp->sk ("general mode" of strp), but this mode has been here for 9 years and has never been used. It'll be gone soon, no point worrying about it.
Switch the stopped/paused/etc bits to u8's to avoid races between strp_stop() and strp_pause/unpause().
A reproducer has been published and turns the possible UAF into an exploit [1].
--- Documentation/networking/strparser.rst | 2 +- include/net/strparser.h | 10 +++++----- net/strparser/strparser.c | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-)
Documentation/networking/strparser.rst +1 -1
@@ -77,7 +77,7 @@ Functions strp_done is called to release any resources held by the stream parser instance. This must be called after the stream processor - has been stopped. + has been stopped. The socket lock must not be held. ::
include/net/strparser.h +5 -5
@@ -91,11 +91,11 @@ static inline struct strp_msg *strp_msg(struct strparser {struct sock *sk; -u32 stopped :1 ; -u32 paused :1 ; -u32 aborted :1 ; -u32 interrupted :1 ; -u32 unrecov_intr :1 ; +u8 stopped; +u8 paused; +u8 aborted; +u8 interrupted; +u8 unrecov_intr;struct sk_buff **skb_nextp;struct sk_buff *skb_head;
net/strparser/strparser.c +5 -1
@@ -505,12 +505,16 @@ void strp_unpause(struct strparser *strpEXPORT_SYMBOL_GPL (strp_unpause);/* strp must already be stopped so that strp_recv will no longer be called. -* Note that strp_done is not called with the lower socket held. +* Note that strp_done must not be called with the lower socket held. */ void strp_done (struct strparser *strp) {WARN_ON (!strp->stopped); +lock_sock (strp->sk); +/* sync with pending strp_recv */ +release_sock (strp->sk); +cancel_delayed_work_sync (&strp->msg_timer_work);cancel_work_sync (&strp->work);
Greg Kroah-Hartman
maintainerPATCH 41/281 swiotlb: fix default_swiotlb_limit() for non-growable default pool
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Szyprowski <[email protected]>
commit 911655ab1dfb9d526978a75df3b210132620d30a upstream.
Commit ad96ce3252db ("swiotlb: determine potential physical address limit") changed default_swiotlb_limit() to return the maximum physical address that could ever be used by dynamically allocated pools, so that the value stays constant when CONFIG_SWIOTLB_DYNAMIC=y. However, io_tlb_default_mem.phys_limit is returned even when the default pool cannot grow, e.g. when swiotlb_init_remap() is called with a remap callback.
This breaks Xen dom0 on x86: pci_xen_swiotlb_init() passes SWIOTLB_ANY and xen_swiotlb_fixup(), so phys_limit is set to the top of dom0 memory, although xen_swiotlb_fixup() makes the default pool below the 32-bit boundary. xen_swiotlb_dma_supported() then rejects 32-bit DMA masks, even though the bounce buffer is perfectly usable by such devices.
Return phys_limit only if the default pool can actually grow, otherwise report the real end of the default pool, like in the !CONFIG_SWIOTLB_DYNAMIC case.
--- kernel/dma/swiotlb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/dma/swiotlb.c +3 -3
@@ -1680,10 +1680,10 @@ phys_addr_t default_swiotlb_base(void)phys_addr_t default_swiotlb_limit (void ) {#ifdef CONFIG_SWIOTLB_DYNAMIC -return io_tlb_default_mem.phys_limit; -#else -return io_tlb_default_mem.defpool.end -1 ; +if (io_tlb_default_mem.can_grow) +return io_tlb_default_mem.phys_limit;#endif +return io_tlb_default_mem.defpool.end -1 ; }#ifdef CONFIG_DEBUG_FS
Greg Kroah-Hartman
maintainerPATCH 42/281 tcp: reject net_iov in zerocopy receive mapping hints
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 8b1f0af1fd5fd113432233ed8a3862ee7c30a84f upstream.
After copying a readable prefix, receive_fallback_to_copy() asks tcp_zerocopy_set_hint_for_skb() where page mapping can resume. If the next skb is unreadable, find_next_mappable_frag() passes its net_iov fragment to can_map_frag().
skb_frag_page() returns NULL for a net_iov, but can_map_frag() dereferences it in PageCompound(). A v7.2 KASAN run on a connected TCP socket with 64 readable bytes followed by a 4096-byte NET_IOV_DMABUF fragment reported:
BUG: KASAN: null-ptr-deref in can_map_frag tcp_zerocopy_receive -> can_map_frag Kernel panic - not syncing: KASAN: panic_on_warn set
The diagnostic inserted the net_iov directly because the test host has no devmem-capable NIC. Hardware end-to-end reachability remains untested and requires CONFIG_NET_DEVMEM plus a supported DMA-buf-bound RX queue.
Reject all net_iov fragments before skb_frag_page(). This covers both DMABUF and IOURING net_iov types while leaving page-backed checks unchanged. With the guard, the same queue copied the readable prefix, returned a 4096-byte skip hint, and completed without a fault.
--- net/ipv4/tcp.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv4/tcp.c +2 -0
@@ -1908,6 +1908,8 @@ static bool can_map_frag(const skb_frag_if (skb_frag_size (frag) !=PAGE_SIZE ||skb_frag_off (frag))return false; +if (skb_frag_is_net_iov (frag)) +return false; page =skb_frag_page (frag);
Greg Kroah-Hartman
maintainerPATCH 43/281 tipc: destroy topsrv workqueues before closing connections
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 3acdd44385bc7e2e57605e073691ce69cc5a960d upstream.
tipc_topsrv_stop() closed subscriber connections while the topology server's send and receive workqueues were still running. Socket callbacks and subscription events could then queue more work, and in-flight send/recv work could drop the last connection reference during the conn_idr walk.
That race produced several teardown failures: refcount_t addition on 0 from conn_get() on a connection whose release was blocked on idr_lock, a subsequent use-after-free in tipc_conn_close(), queue_work() on an already destroyed workqueue from the listener data-ready callback, and an RCU stall in tipc_topsrv_exit_net() while the walk spun under idr_lock.
Clear srv->listener under idr_lock so it acts as a shutdown flag, skip queue_work() once it is NULL, destroy the workqueues to flush in-flight work, and only then close the remaining connections. Refuse tipc_conn_lookup() after that flag is cleared, and drop idr_lock when the teardown walk finds no connection, so an in-flight subscription event cannot pin idr_in_use while the walk holds the lock.
v3 supersedes the narrower in-thread diff Tung Quang Nguyen posted on 2026-09-23. It keeps his teardown order and adds the lookup refusal and the empty-idr unlock.
--- net/tipc/topsrv.c | 80 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 15 deletions(-)
net/tipc/topsrv.c +65 -15
@@ -55,7 +55,7 @@/** * struct tipc_topsrv - TIPC server structure * @conn_idr: identifier set of connection -* @idr_lock: protect the connection identifier set +* @idr_lock: protect the connection identifier set and listener * @idr_in_use: amount of allocated identifier entry * @net: network namespace instance * @awork: accept work item
@@ -218,6 +218,10 @@ static struct tipc_conn *tipc_conn_lookustruct tipc_conn *con;spin_lock_bh (&s->idr_lock); +if (!s->listener) { +spin_unlock_bh (&s->idr_lock); +return NULL ; + } con =idr_find (&s->conn_idr, conid);if (!connected (con) || !kref_get_unless_zero (&con->kref)) con =NULL ;
@@ -301,10 +305,20 @@ static void tipc_conn_send_to_sock(strucstatic void tipc_conn_send_work (struct work_struct *work) { struct tipc_conn *con = container_of(work, struct tipc_conn, swork); +struct tipc_topsrv *srv; + + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (!srv->listener) { +spin_unlock_bh (&srv->idr_lock); + goto out; + } +spin_unlock_bh (&srv->idr_lock);if (connected (con))tipc_conn_send_to_sock (con); +out:conn_put (con); }
@@ -334,8 +348,14 @@ void tipc_topsrv_queue_evt(struct net *nlist_add_tail (&e->list, &con->outqueue);spin_unlock_bh (&con->outqueue_lock); -if (queue_work (srv->send_wq, &con->swork)) -return ; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +if (queue_work (srv->send_wq, &con->swork)) { +spin_unlock_bh (&srv->idr_lock); +return ; + } + } +spin_unlock_bh (&srv->idr_lock); err:conn_put (con); }
@@ -346,14 +366,20 @@ err:*/ static void tipc_conn_write_space (struct sock *sk) { +struct tipc_topsrv *srv;struct tipc_conn *con;read_lock_bh (&sk->sk_callback_lock); con = sk->sk_user_data;if (connected (con)) { -conn_get (con); -if (!queue_work (con->server->send_wq, &con->swork)) -conn_put (con); + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +conn_get (con); +if (!queue_work (srv->send_wq, &con->swork)) +conn_put (con); + } +spin_unlock_bh (&srv->idr_lock); }read_unlock_bh (&sk->sk_callback_lock); }
@@ -418,8 +444,17 @@ static int tipc_conn_rcv_from_sock(strucstatic void tipc_conn_recv_work (struct work_struct *work) { struct tipc_conn *con = container_of(work, struct tipc_conn, rwork); +struct tipc_topsrv *srv;int count =0 ; + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (!srv->listener) { +spin_unlock_bh (&srv->idr_lock); + goto out; + } +spin_unlock_bh (&srv->idr_lock); +while (connected (con)) {if (tipc_conn_rcv_from_sock (con))break ;
@@ -430,6 +465,7 @@ static void tipc_conn_recv_work(struct w count =0 ; } } +out:conn_put (con); }
@@ -438,6 +474,7 @@ static void tipc_conn_recv_work(struct w*/ static void tipc_conn_data_ready (struct sock *sk) { +struct tipc_topsrv *srv;struct tipc_conn *con;trace_sk_data_ready (sk);
@@ -445,9 +482,14 @@ static void tipc_conn_data_ready(structread_lock_bh (&sk->sk_callback_lock); con = sk->sk_user_data;if (connected (con)) { -conn_get (con); -if (!queue_work (con->server->rcv_wq, &con->rwork)) -conn_put (con); + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +conn_get (con); +if (!queue_work (srv->rcv_wq, &con->rwork)) +conn_put (con); + } +spin_unlock_bh (&srv->idr_lock); }read_unlock_bh (&sk->sk_callback_lock); }
@@ -503,8 +545,12 @@ static void tipc_topsrv_listener_data_reread_lock_bh (&sk->sk_callback_lock); srv = sk->sk_user_data; -if (srv) -queue_work (srv->rcv_wq, &srv->awork); +if (srv) { +spin_lock_bh (&srv->idr_lock); +if (srv->listener) +queue_work (srv->rcv_wq, &srv->awork); +spin_unlock_bh (&srv->idr_lock); + }read_unlock_bh (&sk->sk_callback_lock); }
@@ -701,22 +747,26 @@ static void tipc_topsrv_stop(struct netint id;spin_lock_bh (&srv->idr_lock); + srv->listener =NULL ; +spin_unlock_bh (&srv->idr_lock); +tipc_topsrv_work_stop (srv); + +spin_lock_bh (&srv->idr_lock);for (id =0 ; srv->idr_in_use; id++) { con =idr_find (&srv->conn_idr, id);if (con) { -conn_get (con);spin_unlock_bh (&srv->idr_lock);tipc_conn_close (con); -conn_put (con);spin_lock_bh (&srv->idr_lock); +continue ; } +spin_unlock_bh (&srv->idr_lock); +spin_lock_bh (&srv->idr_lock); }__module_get (lsock->ops->owner);__module_get (lsock->sk->sk_prot_creator->owner); - srv->listener =NULL ;spin_unlock_bh (&srv->idr_lock); -tipc_topsrv_work_stop (srv);sock_release (lsock);idr_destroy (&srv->conn_idr);kfree (srv);
Greg Kroah-Hartman
maintainerPATCH 44/281 tipc: hold a reference to nodes found by link name
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 17e73bae400f6a434dc006e3bee92c94cf781954 upstream.
tipc_node_find_by_name() returns a node after dropping its RCU read lock without taking a reference. The LINK_SET, LINK_GET and LINK_RESET_STATS handlers then lock and access the node, racing with timer-driven cleanup of a down peer. Generic netlink serialization does not exclude the node timer.
The following interleaving can leave a handler using a freed node:
CPU 0: find the node under RCU and release the node read lock CPU 1: tipc_node_timeout() clears the links and unlinks the down node CPU 1: drop the list and timer references, queuing tipc_node_free() CPU 0: leave the RCU read-side critical section
CPU 1: complete the grace period and free the node
CPU 0: acquire the node lock through the stale pointer
LINK_SET also uses the node's media address after releasing the node lock, when passing queued packets to tipc_bearer_xmit().
KASAN on v7.3-rc5 reported:
BUG: KASAN: slab-use-after-free in _raw_read_lock_bh Write of size 4 at addr ffff88807e06f008 by task poc/92 Call Trace: _raw_read_lock_bh kernel/locking/spinlock.c:287 tipc_nl_node_set_link net/tipc/node.c:2475 genl_family_rcv_msg_doit net/netlink/genetlink.c:1114 genl_rcv_msg net/netlink/genetlink.c:1209 netlink_rcv_skb net/netlink/af_netlink.c:2575 Allocated by task 0: tipc_node_create net/tipc/node.c:539 tipc_node_check_dest net/tipc/node.c:1196 tipc_disc_rcv net/tipc/discover.c:252 Freed by task 92: kfree mm/slub.c:6801 rcu_core kernel/rcu/tree.c:2919 Last potentially related work creation: __call_rcu_common.constprop.0 kernel/rcu/tree.c:3181 tipc_node_timeout net/tipc/node.c:814
Acquire a reference to the selected node with kref_get_unless_zero() before leaving RCU, returning NULL if the node has already been released. Release that reference on every caller exit after the last node access, including transmission in LINK_SET. Keep the existing link lookup order and locking so concurrent link removal still takes the existing error paths.
--- net/tipc/node.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
net/tipc/node.c +9 -1
@@ -2419,8 +2419,11 @@ static struct tipc_node *tipc_node_find_ } }tipc_node_read_unlock (n); -if (found_node) +if (found_node) { +if (!kref_get_unless_zero (&found_node->kref)) + found_node =NULL ;break ; + } }rcu_read_unlock ();
@@ -2505,6 +2508,7 @@ out:tipc_node_read_unlock (node);tipc_bearer_xmit (net, bearer_id, &xmitq, &node->links[bearer_id].maddr,NULL ); +tipc_node_put (node);return res; }
@@ -2556,12 +2560,14 @@ int tipc_nl_node_get_link(struct sk_buff link = node->links[bearer_id].link;if (!link) {tipc_node_read_unlock (node); +tipc_node_put (node); err = -EINVAL ; goto err_free; } err =__tipc_nl_add_link (net, &msg, link,0 );tipc_node_read_unlock (node); +tipc_node_put (node);if (err) goto err_free; }
@@ -2632,11 +2638,13 @@ int tipc_nl_node_reset_link_stats(structif (!link) {spin_unlock_bh (&le->lock);tipc_node_read_unlock (node); +tipc_node_put (node);return -EINVAL ; }tipc_link_reset_stats (link);spin_unlock_bh (&le->lock);tipc_node_read_unlock (node); +tipc_node_put (node);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 45/281 Revert "wifi: libertas: reject short monitor TX frames"
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <[email protected]>
commit 9727d1c4e1c971fc42b049b645fdda6852758835 upstream.
This reverts commit 13ff543e0b2c713aedeaadadde686686e949dc78.
The 'goto free' just made things worse, causing a spinlock to be handled incorrectly. Revert this for now.
--- drivers/net/wireless/marvell/libertas/tx.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/net/wireless/marvell/libertas/tx.c +0 -7
@@ -117,13 +117,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sif (priv->wdev->iftype ==NL80211_IFTYPE_MONITOR ) {struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; -if (skb->len <sizeof (*rtap_hdr) +4 +ETH_ALEN ) { -lbs_deb_tx ("tx err: short monitor frame %u\n" , skb->len); - dev->stats.tx_dropped++; - dev->stats.tx_errors++; - goto free; - } -/* set txpd fields from the radiotap header */ txpd->tx_control =cpu_to_le32 (convert_radiotap_rate_to_mv (rtap_hdr->rate));
Greg Kroah-Hartman
maintainerPATCH 46/281 RISC-V: Clear HSTATUS.HU on CPU initialization
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong-Xuan Wang <[email protected]>
commit 6694612317e5225086e39ca1ba97ada2b1942e48 upstream.
The RISC-V privileged specification does not mandate HSTATUS reset values, leaving the HU bit potentially set after hardware reset. When HU=1, hypervisor instructions (HLV/HLVX/HSV) can execute in U-mode to access guest memory, which may cause unintended behavior if not explicitly controlled.
Clear HSTATUS.HU during CPU initialization to ensure hypervisor instructions are only available in HS-mode, preventing unexpected guest memory access from U-mode code.
--- arch/riscv/include/asm/cpufeature.h | 2 ++ arch/riscv/kernel/cpufeature.c | 12 ++++++++++++ arch/riscv/kernel/setup.c | 2 ++ arch/riscv/kernel/smpboot.c | 2 ++ arch/riscv/kernel/suspend.c | 2 ++ 5 files changed, 20 insertions(+)
arch/riscv/include/asm/cpufeature.h +2 -0
@@ -40,6 +40,8 @@ extern u32 thead_vlenb_of;void __init riscv_user_isa_enable (void ); +void riscv_clear_hypervisor_csr (void ); +#define _RISCV_ISA_EXT_DATA (_name, _id, _subset_exts, _subset_exts_size, _validate) { \ .name = #_name, \ .property = #_name, \
arch/riscv/kernel/cpufeature.c +12 -0
@@ -1184,6 +1184,18 @@ void __init riscv_user_isa_enable(void)pr_warn ("Zicbop disabled as it is unavailable on some harts\n" ); } +void riscv_clear_hypervisor_csr (void ) +{ +if (!riscv_has_extension_unlikely (RISCV_ISA_EXT_H )) +return ; + +/* +* Clear HSTATUS.HU to restrict hypervisor instructions to HS-mode. +* This prevents user-mode from executing HLV/HSV instructions. +*/ +csr_clear (CSR_HSTATUS ,HSTATUS_HU ); +} +#ifdef CONFIG_RISCV_ALTERNATIVE /* * Alternative patch sites consider 48 bits when determining when to patch
arch/riscv/kernel/setup.c +2 -0
@@ -364,6 +364,8 @@ void __init setup_arch(char **cmdline_p)if (!IS_ENABLED (CONFIG_RISCV_ISA_ZBB ) || !riscv_isa_extension_available (NULL ,ZBB ))static_branch_disable (&efficient_ffs_key); + +riscv_clear_hypervisor_csr (); }bool arch_cpu_is_hotpluggable (int cpu)
arch/riscv/kernel/smpboot.c +2 -0
@@ -244,6 +244,8 @@ asmlinkage __visible void smp_callin(voinuma_add_cpu (curr_cpuid); +riscv_clear_hypervisor_csr (); +pr_debug ("CPU%u: Booted secondary hartid %lu\n" , curr_cpuid,cpuid_to_hartid_map (curr_cpuid));
arch/riscv/kernel/suspend.c +2 -0
@@ -43,6 +43,8 @@ void suspend_save_csrs(struct suspend_covoid suspend_restore_csrs (struct suspend_context *context) { +riscv_clear_hypervisor_csr (); +csr_write (CSR_SCRATCH ,0 );if (riscv_has_extension_unlikely (RISCV_ISA_EXT_XLINUXENVCFG ))csr_write (CSR_ENVCFG , context->envcfg);
Re: [PATCH 7.2 046/281] RISC-V: Clear HSTATUS.HU on CPU initialization
Quoted 19 lines · On Tue, 13 Oct 2026 13:36:02 +0200 Greg Kroah-Hartman…
7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong-Xuan Wang <[email protected]>
commit
6694612317e5225086e39ca1ba97ada2b1942e48upstream.The RISC-V privileged specification does not mandate HSTATUS reset values, leaving the HU bit potentially set after hardware reset. When HU=1, hypervisor instructions (HLV/HLVX/HSV) can execute in U-mode to access guest memory, which may cause unintended behavior if not explicitly controlled.
Clear HSTATUS.HU during CPU initialization to ensure hypervisor instructions are only available in HS-mode, preventing unexpected guest memory access from U-mode code.
Quoted 7 lines
Signed-off-by Yong-Xuan Wang <[email protected]>Reviewed-by Samuel Holland <[email protected]>[[email protected]: capitalized RISCV_ISA_EXT_h to fix build; added stable cc]Signed-off-by Paul Walmsley <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>
For riscv64, I am seeing:
arch/riscv/kernel/cpufeature.c:1189:36: error: use of undeclared identifier 'RISCV_ISA_EXT_H'
1189 | if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_H))
| ^
It seems it is missing commit
0c5a9ab5192b ("riscv: Standardize extension capitalization")
Either that or manually tweak the identifier to match 7.2.y.
6.18.y also breaks for the same reason.
I hope this helps!
Cheers,
Miguel
Greg Kroah-Hartman
maintainerPATCH 47/281 selinux: fix data race on AVC latest_notif
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Göttsche <[email protected]>
commit 1ca924044bf0de879a1648be93a56939652267d3 upstream.
avc_policy_seqno() reads latest_notif without holding notif_lock, while avc_latest_notif_update() can update it under that lock. KCSAN reports these concurrent accesses during policy boolean updates and permission checks.
Use READ_ONCE() for the lockless read and WRITE_ONCE() for the update. The spinlock continues to serialize the comparison and update against other writers. Reads made while holding notif_lock cannot race with a writer and can remain plain accesses.
This marks both sides of the intentional concurrent access and constrains compiler transformations, without suppressing checking with data_race().
--- security/selinux/avc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
security/selinux/avc.c +3 -2
@@ -579,7 +579,7 @@ static int avc_latest_notif_update(u32 s } }else {if (seqno > selinux_avc.avc_cache.latest_notif) - selinux_avc.avc_cache.latest_notif = seqno; +WRITE_ONCE (selinux_avc.avc_cache.latest_notif, seqno); }spin_unlock_irqrestore (¬if_lock, flag);
@@ -1207,5 +1207,6 @@ int avc_has_perm(u32 ssid, u32 tsid, u16u32 avc_policy_seqno (void ) { -return selinux_avc.avc_cache.latest_notif; +/* Writers hold notif_lock; readers only sample the sequence number. */ +return READ_ONCE (selinux_avc.avc_cache.latest_notif); }
Greg Kroah-Hartman
maintainerPATCH 48/281 selinux: preserve NATIVE_LABELS on already-initialized sb in set_mnt_opts
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <[email protected]>
commit 28b7260548af3d35773477993ad4e4de41578dd7 upstream.
When an NFSv4 filesystem exported with security_label is mounted a second time, sget_fc() returns the existing superblock and nfs_get_root() calls security_sb_set_mnt_opts() again on it. Since the superblock is already SB_INITIALIZED, selinux_set_mnt_opts() takes an early exit without setting SECURITY_LSM_NATIVE_LABELS in *set_kern_flags. nfs_get_root() then sees kflags without SECURITY_LSM_NATIVE_LABELS set and clears NFS_CAP_SECURITY_LABEL on the shared nfs_server, silently disabling per-file labeling for both the new and the original mount.
Commit 3815a245b501 ("security/selinux: fix SECURITY_LSM_NATIVE_LABELS on reused superblock") fixed the same problem in selinux_sb_clone_mnt_opts(). The reused-superblock path for a plain second mount now goes through sb_set_mnt_opts rather than sb_clone_mnt_opts, so it needs the same treatment: on both SE_SBINITIALIZED early exits, set SECURITY_LSM_NATIVE_LABELS in *set_kern_flags when the superblock was already using SECURITY_FS_USE_NATVE.
--- security/selinux/hooks.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
security/selinux/hooks.c +8 -1
@@ -688,8 +688,12 @@ static int selinux_set_mnt_opts(struct s* will be used for both mounts) */ if ((sbsec->flags &SE_SBINITIALIZED ) && (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) - && !opts) + && !opts) { +if ((kern_flags &SECURITY_LSM_NATIVE_LABELS ) && + sbsec->behavior ==SECURITY_FS_USE_NATIVE ) + *set_kern_flags |=SECURITY_LSM_NATIVE_LABELS ; goto out; + } root_isec =backing_inode_security_novalidate (root);
@@ -733,6 +737,9 @@ static int selinux_set_mnt_opts(struct s/* previously mounted with options, but not on this attempt? */ if ((sbsec->flags &SE_MNTMASK ) && !opts) goto out_double_mount; +if ((kern_flags &SECURITY_LSM_NATIVE_LABELS ) && + sbsec->behavior ==SECURITY_FS_USE_NATIVE ) + *set_kern_flags |=SECURITY_LSM_NATIVE_LABELS ; rc =0 ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 49/281 sctp: copy zeroed stats to user in sctp_getsockopt_pr_streamstatus() when !streamoute
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Peng <[email protected]>
commit 538b529509c7ab0d909cb65bb7264edca1788d30 upstream.
When an SCTP stream output extension structure (streamoute) has not yet been allocated, sctp_getsockopt_pr_streamstatus() sets the local stack variables params.sprstat_abandoned_unsent = 0 and params.sprstat_abandoned_sent = 0, but then immediately jumps to 'out:', bypassing copy_to_user(). As a result, when an uninitialized user buffer is passed to getsockopt(SCTP_PR_STREAM_STATUS), the kernel returns success (0) without copying the zeroed stats back to user space, leaving uninitialized data in the user buffer.
Refactor the !streamoute check into an if-else chain so that when streamoute is NULL, params is zeroed and falls through to copy_to_user(), copying the zeroed stats to user space and setting retval = 0 once before returning.
Tested in QEMU against Linux 7.3.0-rc3 using an uninitialized sctp_prstatus user struct passed to getsockopt(SCTP_PR_STREAM_STATUS) on a freshly created stream: on the unfixed kernel the user struct contains uninitialized stack garbage; whereas with this fix applied, getsockopt() copies zeroed stats into user space and returns 0.
--- net/sctp/socket.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
net/sctp/socket.c +1 -5
@@ -7569,11 +7569,7 @@ static int sctp_getsockopt_pr_streamstat/* Not allocated yet, means all stats are 0 */ params.sprstat_abandoned_unsent =0 ; params.sprstat_abandoned_sent =0 ; - retval =0 ; - goto out; - } - -if (policy ==SCTP_PR_SCTP_ALL ) { + }else if (policy ==SCTP_PR_SCTP_ALL ) { params.sprstat_abandoned_unsent =0 ; params.sprstat_abandoned_sent =0 ;for (policy =0 ; policy <=SCTP_PR_INDEX (MAX ); policy++) {
Greg Kroah-Hartman
maintainerPATCH 50/281 selftests/mm: cleanup -Wformat issues in hugetlb-mmap
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Llamas <[email protected]>
commit 28eed9906e01d01cbdfb352e799413b2e8b33b76 upstream.
Commit ae571cd6015c ("selftests/mm: hugetlb-mmap: add setup of HugeTLB pages") and commit 9c5a65f374f8 ("selftests/mm: merge map_hugetlb into hugepage-mmap") added logs of 'hugepage_size' which has a size_t type. However, the incorrect format specifier '%lu' was used which triggers -Wformat warnings when building for 32-bit:
hugetlb-mmap.c:125:55: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat]
125 | ksft_print_msg("Default size hugepages (%lu kB)\n", hugepage_size >> 10);
| ~~~ ^~~~~~~~~~~~~~~~~~~
| %zu hugetlb-mmap.c:134:47: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat]
134 | ksft_exit_skip("Not enough %lu Kb pages\n", hugepage_size >> 10);
| ~~~ ^~~~~~~~~~~~~~~~~~~
| %zuFix this by switching to the expected '%zu' format specifier.
--- tools/testing/selftests/mm/hugetlb-mmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/mm/hugetlb-mmap.c +2 -2
@@ -122,7 +122,7 @@ int main(int argc, char **argv) hugepage_size =default_huge_page_size ();if (!hugepage_size)ksft_exit_skip ("Could not detect default hugetlb page size." ); -ksft_print_msg ("Default size hugepages (%lu kB)\n" , hugepage_size >>10 ); +ksft_print_msg ("Default size hugepages (%zu kB)\n" , hugepage_size >>10 ); }/* munmap will fail if the length is not page aligned */
@@ -131,7 +131,7 @@ int main(int argc, char **argv)hugetlb_set_nr_pages (hugepage_size, nr);if (hugetlb_free_pages (hugepage_size) < nr) -ksft_exit_skip ("Not enough %lu Kb pages\n" , hugepage_size >>10 ); +ksft_exit_skip ("Not enough %zu Kb pages\n" , hugepage_size >>10 );ksft_set_plan (2 );ksft_print_msg ("Mapping %lu Mbytes\n" , (unsigned long )length >>20 );
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerPATCH 51/281 e1000e: add system to disable K1 list
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Nguyen <[email protected]>
commit 1d6500523b8d5112afe0118173ebc8c1ca23784e upstream.
Javier reports seeing packet loss issues related to the re-enablement of K1; disabling it makes the issues go away. Add the reported system to have K1 disabled by default.
Reproduction steps (from the Link):
Plug the cable and ping the default gateway on the LAN. No suspend/resume involved, machine freshly booted and on AC power. Nothing e1000e-related in dmesg apart from the link up/down messages; no "Hardware Unit Hang".
Default (K1 enabled):
$ ping -c 30 192.168.10.1 --- 192.168.10.1 ping statistics --- 30 packets transmitted, 18 received, 40% packet loss, time 29734ms rtt min/avg/max/mdev = 0.211/0.315/0.384/0.046 ms
The lost packets are spread over the run (seq 6, 8, 9, 11, 13, 14, 16, 19, 20, 24, 25, 30), not a single burst. DHCP on this link also takes 1-2 minutes to get a lease, consistent with incoming packets being dropped.
With K1 disabled at runtime:
# ethtool --set-priv-flags enp0s31f6 disable-k1 on $ ethtool --show-priv-flags enp0s31f6 Private flags for enp0s31f6: s0ix-enabled: on disable-k1 : on
$ ping -c 30 192.168.10.1 --- 192.168.10.1 ping statistics --- 30 packets transmitted, 30 received, 0% packet loss, time 29713ms rtt min/avg/max/mdev = 0.169/0.251/0.468/0.054 ms
$ ping -c 30 192.168.10.1 --- 192.168.10.1 ping statistics --- 30 packets transmitted, 30 received, 0% packet loss, time 29677ms rtt min/avg/max/mdev = 0.101/0.222/0.360/0.064 ms
I have only compile tested this, but Javier has tested that disabling K1 on his system (Lenovo ThinkPad P14s Gen 5 (Intel), I219-LM [8086:550a]) resolves his issues.
--- drivers/net/ethernet/intel/e1000e/netdev.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/ethernet/intel/e1000e/netdev.c +7 -0
@@ -67,6 +67,13 @@ static const struct dmi_system_id disable_k1_list[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro 16 Plus PB16250"), }, }, + { + .ident = "Lenovo ThinkPad P14s Gen 5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad P14s Gen 5"), + }, + }, {} };
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerPATCH 52/281 EDAC/amd64: Mask UMC chip select to the four implemented selects
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vishal Badole <[email protected]>
commit 7484bc43ba6b8e189b482db5b75e7842890a82b1 upstream.
For DRAM ECC errors, the chip select value can be found in the MCA_SYND[ErrorInformation] field.
ErrorInformation[2:0] was first documented in Zen1. The 3 bit field implied that up to 8 chip selects may be used.
However, all Zen-based systems have only ever had up to 4 chip selects. So only bits [1:0] would contain a valid chip select value.
Future systems are redefining the field to ErrorInformation[1:0]. This matches the existing 'up to 4 chip selects' implementations. And it frees up the extra bit for other decoding.
Change the current chip select mask from 0x7 to 0x3 to prepare for the decode change.
--- drivers/edac/amd64_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/edac/amd64_edac.c +2 -2
@@ -2796,13 +2796,13 @@ static inline void decode_bus_error(int* the instance_id. For example, instance_id=0xYXXXXX where Y is the channel * number. * -* For DRAM ECC errors, the Chip Select number is given in bits [2:0] of +* For DRAM ECC errors, the Chip Select number is given in bits [1:0] of * the MCA_SYND[ErrorInformation] field. */ static void umc_get_err_info (struct mce *m,struct err_info *err) { err->channel = (m->ipid &GENMASK (31 ,0 )) >>20 ; - err->csrow = m->synd &0x7 ; + err->csrow = m->synd &0x3 ; }static void decode_umc_error (int node_id,struct mce *m)
Greg Kroah-Hartman
maintainerPATCH 53/281 fsverity: RCU-delay the freeing of struct fsverity_info
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit e58c3805ed325fe2d4ae2dd467c0486cc860b733 upstream.
__fsverity_get_info() calls rhashtable_lookup_fast(), which just uses rcu_read_lock() and doesn't directly synchronize with fsverity_remove_info().
For the same inode this isn't a problem: its fsverity_info is removed only at inode eviction time or upon failure to enable verity, when the inode no longer needs its fsverity_info and it will no longer be accessed via that inode.
However, this is broken and can cause a use-after-free for concurrent __fsverity_get_info() for *different* inodes. Those rely on following fsverity_info::rhash_head in the rhashtable under rcu_read_lock() only. They also use fsverity_info::inode to do the key comparison.
Fix this by RCU-delaying the freeing of 'struct fsverity_info' after it's been removed from the rhashtable.
--- fs/verity/fsverity_private.h | 15 ++++++++++++++- fs/verity/open.c | 13 ++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-)
fs/verity/fsverity_private.h +14 -1
@@ -11,6 +11,7 @@#define pr_fmt (fmt) "fs-verity: " fmt#include <linux/fsverity.h> +#include <linux/rcupdate.h> #include <linux/rhashtable.h> /*
@@ -76,7 +77,19 @@ struct merkle_tree_params {struct fsverity_info {struct rhash_head rhash_head;struct merkle_tree_params tree_params; -u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE ]; +union { +u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE ]; + +/* +* Used for final freeing of the struct, in which case root_hash +* is no longer needed. Specifically, the only fields needed +* besides the rcu_head are those needed by fsverity_free_info() +* itself, and those that can be accessed by fsverity_get_info() +* (rhash_head and inode) during the RCU-protected rhashtable +* chain search trying to find another inode's fsverity_info. +*/ +struct rcu_head rcu_head; + };u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE ];struct inode *inode;unsigned long *hash_block_verified;
fs/verity/open.c +12 -1
@@ -399,11 +399,22 @@ void fsverity_free_info(struct fsverity_kmem_cache_free (fsverity_info_cachep, vi); } +static void fsverity_free_info_rcu (struct rcu_head *head) +{ +fsverity_free_info (container_of(head ,struct fsverity_info ,rcu_head )); +} +void fsverity_remove_info (struct fsverity_info *vi) {rhashtable_remove_fast (&fsverity_info_hash, &vi->rhash_head, fsverity_info_hash_params); -fsverity_free_info (vi); +/* +* The freeing must be RCU-delayed because __fsverity_get_info() for a +* *different* inode's fsverity_info in the same rhashtable hash chain +* can still be accessing *this* fsverity_info's rhash_head and inode +* fields as part of the RCU-protected hash chain search. +*/ +call_rcu (&vi->rcu_head, fsverity_free_info_rcu); }void fsverity_cleanup_inode (struct inode *inode)
Greg Kroah-Hartman
maintainerPATCH 54/281 gpio: mpsse: fix race when arming the IRQ poll worker
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 7efa1a1953cd6b20b23a3524d5b4b81789c6ef25 upstream.
gpio_mpsse_irq_enable() arms the poll worker before publishing it:schedule_work() runs before the worker is added to priv->workers. If gpio_mpsse_disconnect() walks the list in that window it misses the worker, and once disconnect returns, the USB core frees mpsse_priv while the orphaned gpio_mpsse_poll() work keeps accessing it, causing a use-after-free.
Fix this by publishing and arming the worker in one irq_spin critical section. Teardown walks the same list under irq_spin, so a worker found on the list is guaranteed to be armed, and cancel_work_sync() handles it whether it is queued or running.
A worker armed after the disconnect walk would still be missed, so also set a new priv->dying flag under irq_spin before the teardown walk, and check it in the same critical section, freeing it via kfree_rcu() instead when the device is going away, since kfree() would be called with the IRQ core's raw spinlock held and may sleep on PREEMPT_RT. schedule_work() is safe to call with irq_spin held, and the next probe gets a fresh mpsse_priv, so the flag never needs to be cleared.
This issue was found by an in-house static analysis tool.
--- drivers/gpio/gpio-mpsse.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
drivers/gpio/gpio-mpsse.c +22 -2
@@ -10,6 +10,7 @@#include <linux/cleanup.h> #include <linux/gpio/driver.h> #include <linux/mutex.h> +#include <linux/rcupdate.h> #include <linux/spinlock.h> #include <linux/usb.h>
@@ -24,6 +25,7 @@ struct mpsse_priv {raw_spinlock_t irq_spin;/* protects worker list */ atomic_t irq_type[16 ];/* pin -> edge detection type */ atomic_t irq_enabled; +atomic_t dying;/* no new workers after disconnect */ int id;u8 gpio_outputs[2 ];/* Output states for GPIOs [L, H] */
@@ -46,6 +48,7 @@ struct mpsse_worker {atomic_t cancelled;struct list_head list;/* linked list */ struct list_head destroy;/* teardown linked list */ +struct rcu_head rcu;/* deferred free for dying path */ };struct bulk_desc {
@@ -525,10 +528,24 @@ static void gpio_mpsse_irq_enable(struct worker->priv = priv;INIT_LIST_HEAD (&worker->list);INIT_WORK (&worker->work, gpio_mpsse_poll); -schedule_work (&worker->work); - scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) { +if (atomic_read (&priv->dying)) { +/* +* Cannot kfree() here: this callback +* runs with the IRQ descriptor's raw +* spinlock held and kfree() may sleep +* on PREEMPT_RT. The worker is not +* yet published, so the deferred free +* is unobservable. +*/ +kfree_rcu (worker, rcu); +return ; + } +list_add (&worker->list, &priv->workers); +schedule_work (&worker->work); + } } }
@@ -704,6 +721,9 @@ static void gpio_mpsse_disconnect(struct {struct mpsse_priv *priv =usb_get_intfdata (intf); + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) +atomic_set (&priv->dying,1 ); +/* * Lock prevents double-free of worker from here and the teardown * step at the beginning of gpio_mpsse_poll
Greg Kroah-Hartman
maintainerPATCH 55/281 gpio: xilinx: fix runtime PM leak on request error path
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ridham Khurana <[email protected]>
commit ff82fc3a4a1d417dee1229681cc5285986edb1fa upstream.
pm_runtime_get_sync() leaves the usage counter incremented even when it fails, and xgpio_request() returns the error without dropping it.
gpiolib does not call ->free() when ->request() fails, so xgpio_free(), which holds the only matching pm_runtime_put(), never runs. The reference is leaked and the controller can no longer runtime-suspend, so its clock stays enabled.
Switch to pm_runtime_resume_and_get(), which only increments the usage counter on success.
--- drivers/gpio/gpio-xilinx.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/gpio/gpio-xilinx.c +1 -8
@@ -271,14 +271,7 @@ static void xgpio_save_regs(struct xgpiostatic int xgpio_request (struct gpio_chip *chip,unsigned int offset) { -int ret; - - ret =pm_runtime_get_sync (chip->parent); -/* -* If the device is already active pm_runtime_get() will return 1 on -* success, but gpio_request still needs to return 0. -*/ -return ret <0 ? ret :0 ; +return pm_runtime_resume_and_get (chip->parent); }static void xgpio_free (struct gpio_chip *chip,unsigned int offset)
Greg Kroah-Hartman
maintainerPATCH 56/281 iavf: send MAC change request synchronously
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Ignacio Tornos Martinez <[email protected]>
commit 436729a56dd4dac611d10b569c5359d2cf705b19 upstream.
After commit ad7c7b2172c3 ("net: hold netdev instance lock during sysfs operations"), iavf_set_mac() is called with the netdev instance lock already held.
The function queues a MAC address change request via iavf_replace_primary_mac() and then waits for completion. However, in the current flow, the actual virtchnl message is sent by the watchdog task, which also needs to acquire the netdev lock to run. Additionally, the adminq_task which processes virtchnl responses also needs the netdev lock.
This creates a deadlock scenario:
1. iavf_set_mac() holds netdev lock and waits for MAC change
2. Watchdog needs netdev lock to send the request -> blocked
3. Even if request is sent, adminq_task needs netdev lock to process PF response -> blocked
4. MAC change times out after 2.5 seconds
5. iavf_set_mac() returns -EAGAIN
This particularly affects VFs during bonding setup when multiple VFs are enslaved in quick succession.
Fix by implementing a synchronous MAC change operation similar to the approach used in commit fdadbf6e84c4 ("iavf: fix incorrect reset handling in callbacks").
The solution:
1. Send the virtchnl ADD_ETH_ADDR message directly (not via watchdog)
2. Poll the admin queue hardware directly for responses
3. Process all received messages (including non-MAC messages)
4. Return when MAC change completes or times out
A new generic function iavf_poll_virtchnl_response() is introduced that can be reused for any future synchronous virtchnl operations. It takes a callback to check completion, allowing flexible condition checking.
This allows the operation to complete synchronously while holding netdev_lock, without relying on watchdog or adminq_task. The function can sleep for up to 2.5 seconds polling hardware, but this is acceptable since netdev_lock is per-device and only serializes operations on the same interface.
To support this, change iavf_add_ether_addrs() to return an error code instead of void, allowing callers to detect failures. Additionally, export iavf_mac_add_reject() to enable proper rollback on local failures (timeouts, send errors) - PF rejections are already handled automatically by iavf_virtchnl_completion().
Remove vc_waitqueue entirely because iavf_set_mac was the only waiter on this waitqueue and after the changes it is not needed.
--- drivers/net/ethernet/intel/iavf/iavf.h | 11 ++ drivers/net/ethernet/intel/iavf/iavf_main.c | 85 ++++++++++++++++---- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 99 +++++++++++++++++++++--- 3 files changed, 165 insertions(+), 30 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +9 -2
@@ -259,7 +259,6 @@ struct iavf_adapter {struct work_struct adminq_task;struct work_struct finish_config;wait_queue_head_t down_waitqueue; -wait_queue_head_t vc_waitqueue;struct iavf_q_vector *q_vectors;struct list_head vlan_filter_list;int num_vlan_filters;
@@ -588,8 +587,9 @@ void iavf_configure_queues(struct iavf_avoid iavf_enable_queues (struct iavf_adapter *adapter);void iavf_disable_queues (struct iavf_adapter *adapter);void iavf_map_queues (struct iavf_adapter *adapter); -void iavf_add_ether_addrs (struct iavf_adapter *adapter); +int iavf_add_ether_addrs (struct iavf_adapter *adapter);void iavf_del_ether_addrs (struct iavf_adapter *adapter); +void iavf_mac_add_reject (struct iavf_adapter *adapter);void iavf_add_vlans (struct iavf_adapter *adapter);void iavf_del_vlans (struct iavf_adapter *adapter);void iavf_set_promiscuous (struct iavf_adapter *adapter);
@@ -606,6 +606,13 @@ void iavf_disable_vlan_stripping(structvoid iavf_virtchnl_completion (struct iavf_adapter *adapter,enum virtchnl_ops v_opcode,enum iavf_status v_retval,u8 *msg,u16 msglen); +int iavf_poll_virtchnl_response (struct iavf_adapter *adapter, +struct iavf_arq_event_info *event, +bool (*condition)(struct iavf_adapter *adapter, +const void *data, +enum virtchnl_ops v_op), +const void *cond_data, +unsigned int timeout_ms);int iavf_config_rss (struct iavf_adapter *adapter);void iavf_cfg_queues_bw (struct iavf_adapter *adapter);void iavf_cfg_queues_quanta_size (struct iavf_adapter *adapter);
drivers/net/ethernet/intel/iavf/iavf_main.c +67 -18
107 lines not on this page · raw message
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +89 -10
163 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 57/281 gve: fix napi_disable deadlock when attempting to disable XSK pools
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Washington <[email protected]>
commit 0cb6939a4dfefa822007b7a71986e06bc4f61f54 upstream.
When disabling XSK pools, GVE calls the unlocked versions of napi_disable and napi_enable. However, the netdev lock has already been acquired before ndo_bpf is called because GVE supports queue management ops. Calling the unlocked versions of napi_disable/enable results in a deadlock when attempting to disable XSK pools, as the thread attempts to re-acquire a lock it already holds.
Update the NAPI calls to use the locked versions.
This issue was found in production.
--- drivers/net/ethernet/google/gve/gve_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/ethernet/google/gve/gve_main.c +4 -4
@@ -1708,17 +1708,17 @@ static int gve_xsk_pool_disable(struct n } napi_rx = &priv->ntfy_blocks[priv->rx[qid].ntfy_id].napi; -napi_disable (napi_rx);/* make sure current rx poll is done */ +napi_disable_locked (napi_rx);/* make sure current rx poll is done */ tx_qid =gve_xdp_tx_queue_id (priv, qid); napi_tx = &priv->ntfy_blocks[priv->tx[tx_qid].ntfy_id].napi; -napi_disable (napi_tx);/* make sure current tx poll is done */ +napi_disable_locked (napi_tx);/* make sure current tx poll is done */ gve_unreg_xsk_pool (priv, qid);smp_mb ();/* Make sure it is visible to the workers on datapath */ -napi_enable (napi_rx); -napi_enable (napi_tx); +napi_enable_locked (napi_rx); +napi_enable_locked (napi_tx);if (gve_is_gqi (priv)) {if (gve_rx_work_pending (&priv->rx[qid]))napi_schedule (napi_rx);
Greg Kroah-Hartman
maintainerPATCH 58/281 gve: fix XSK buffer leak when rings are stopped
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Washington <[email protected]>
commit 73670ddb91a4d22e1deb3efd962242de1ec48e90 upstream.
GVE does not free XSK buffers when resetting ring state as a part of stopping queues. This causes all XSK buffers which are posted to the NIC to be leaked.
Free XSK buffers attached to an allocated buf_state when stopping rings.
This issue was hit in production.
--- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/ethernet/google/gve/gve_rx_dqo.c +6 -0
@@ -113,6 +113,12 @@ static void gve_rx_reset_ring_dqo(structgve_free_to_page_pool (rx, bs, false); elsegve_free_qpl_page_dqo (bs ); + +if (gve_buf_state_is_allocated (rx, bs) && + bs->xsk_buff) { +xsk_buff_free (bs->xsk_buff); + bs->xsk_buff =NULL ; + } } }
Greg Kroah-Hartman
maintainerPATCH 59/281 gve: fix XSK buffer leak on error descriptor
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Washington <[email protected]>
commit 9fed6a8ab8a5bacba2c709cb19d2dd6d2fa9112e upstream.
When the error bit is set in the RX completion descriptor, the buf_state and its attached buffer should be freed. In the case of AF_XDP ZC, the XSK buffer was not freed, leading to a leak.
This issue was caught by LLM.
--- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/google/gve/gve_rx_dqo.c +6 -1
@@ -845,7 +845,12 @@ static int gve_rx_dqo(struct napi_struct }if (unlikely (compl_desc->rx_error)) { -gve_free_buffer (rx, buf_state); +if (buf_state->xsk_buff) { +xsk_buff_free (buf_state->xsk_buff); +gve_free_buf_state (rx, buf_state); + }else { +gve_free_buffer (rx, buf_state); + }return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 60/281 ibmveth: h_free logical LAN on open-fail after register
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingming Cao <[email protected]>
commit af0524bf4ce1a4cbd2946aa81751582951cfcab5 upstream.
ibmveth_open() registers the logical LAN, then allocates the RX buffer pools. A pool failure jumps to out_free_buffer_pools without h_free_logical_lan(), so PHYP still owns the buffer-list page when it is unmapped. request_irq() failure already issued the hypercall before taking the same label.
Move that h_free to the shared post-register unwind so both paths deregister before the buffer list is unmapped.
--- drivers/net/ethernet/ibm/ibmveth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/ethernet/ibm/ibmveth.c +3 -4
@@ -718,10 +718,6 @@ static int ibmveth_open(struct net_devicif (rc !=0 ) {netdev_err (netdev,"unable to request irq 0x%x, rc %d\n" , netdev->irq, rc); -do { - lpar_rc =h_free_logical_lan (adapter->vdev->unit_address); - }while (H_IS_LONG_BUSY (lpar_rc) || (lpar_rc ==H_BUSY )); - goto out_free_buffer_pools; }
@@ -737,6 +733,9 @@ static int ibmveth_open(struct net_devicreturn 0 ; out_free_buffer_pools: +do { + lpar_rc =h_free_logical_lan (adapter->vdev->unit_address); + }while (H_IS_LONG_BUSY (lpar_rc) || (lpar_rc ==H_BUSY ));while (--i >=0 ) {if (adapter->rx_buff_pool[i].active) ibmveth_free_buffer_pool(adapter,
Greg Kroah-Hartman
maintainerPATCH 61/281 ibmveth: fix TX LTB and filter unwind on open-fail
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingming Cao <[email protected]>
commit 84bec0bf035258a1073ffd6f6dc8ea61806aa7d4 upstream.
out_free_buffer_pools reuses open()'s loop index for the TX LTB walk. After the pool unwind i is -1, so the TX buffers allocated earlier are leaked. request_irq() failure has the same leak.
The TX-fail goto on that walk also skips dma_unmap of the filter list (pre-existing since the LTB was added). Rewrite the TX walk to real_num_tx_queues with a pointer check, and unmap the filter list before those frees.
--- drivers/net/ethernet/ibm/ibmveth.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/ibm/ibmveth.c +9 -6
@@ -553,10 +553,15 @@ static int ibmveth_rxq_harvest_buffer(ststatic void ibmveth_free_tx_ltb (struct ibmveth_adapter *adapter,int idx) { +void *ptr = adapter->tx_ltb_ptr[idx]; + +if (!ptr) +return ; + + adapter->tx_ltb_ptr[idx] =NULL ;dma_unmap_single (&adapter->vdev->dev, adapter->tx_ltb_dma[idx], adapter->tx_ltb_size,DMA_TO_DEVICE ); -kfree (adapter->tx_ltb_ptr[idx]); - adapter->tx_ltb_ptr[idx] =NULL ; +kfree (ptr); }static int ibmveth_allocate_tx_ltb (struct ibmveth_adapter *adapter,int idx)
@@ -667,7 +672,7 @@ static int ibmveth_open(struct net_devicfor (i =0 ; i < netdev->real_num_tx_queues; i++) {if (ibmveth_allocate_tx_ltb (adapter, i)) - goto out_free_tx_ltb; + goto out_unmap_filter_list; } adapter->rx_queue.index =0 ;
@@ -745,10 +750,8 @@ out_unmap_filter_list:dma_unmap_single (dev, adapter->filter_list_dma,4096 ,DMA_BIDIRECTIONAL ); -out_free_tx_ltb: -while (--i >=0 ) { +for (i = netdev->real_num_tx_queues -1 ; i >=0 ; i--)ibmveth_free_tx_ltb (adapter, i); - } out_unmap_buffer_list: dma_unmap_single(dev, adapter->buffer_list_dma, 4096,
Greg Kroah-Hartman
maintainerPATCH 62/281 ice: fix use-after-free in dynamic port cleanup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit 1402fc67d2f4e2e1fc7bf8ee0825b8ad994557ff upstream.
ice_dealloc_dynamic_port() uses dyn_port->vsi->idx to erase the dynamic port from pf->dyn_ports. However, it frees the VSI before reading the index for the erase, resulting in a use-after-free.
Follow the reverse of the allocation order in ice_alloc_dynamic_port() by erasing the xarray entry before freeing the VSI.
--- drivers/net/ethernet/intel/ice/devlink/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/devlink/port.c +1 -1
@@ -590,8 +590,8 @@ static void ice_dealloc_dynamic_port(strxa_erase (&pf->sf_nums, devlink_port->attrs.pci_sf.sf);ice_eswitch_detach_sf (pf, dyn_port); -ice_vsi_free (dyn_port->vsi);xa_erase (&pf->dyn_ports, dyn_port->vsi->idx); +ice_vsi_free (dyn_port->vsi);kfree (dyn_port); }
Greg Kroah-Hartman
maintainerPATCH 63/281 ice: fix metadata_dst refcount handling on representor teardown
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 58858b8f14803a7eeac297b3ce20f3b21bf2ff66 upstream.
ice_eswitch_release_repr() uses metadata_dst_free() to release the representor's metadata_dst. metadata_dst_free() directly frees the underlying memory without checking the dst_entry refcount.
When ice_eswitch_port_start_xmit() processes a packet, it takes a reference via dst_hold() and attaches the metadata_dst to the skb. If the representor is torn down while packets are still queued on the lower device (e.g. in a qdisc), the metadata_dst is freed while references are still held.
Use dst_release() instead, which correctly decrements the refcount and only frees the object when all references are dropped. The dst subsystem already handles metadata_dst cleanup in dst_destroy() when DST_METADATA is set.
Other drivers sharing this pattern (nfp, airoha, bnxt) already use dst_release() for their metadata_dst lifecycle.
--- drivers/net/ethernet/intel/ice/ice_eswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_eswitch.c +1 -1
@@ -95,7 +95,7 @@ ice_eswitch_release_repr(struct ice_pf *return ;ice_vsi_update_security (vsi, ice_vsi_ctx_set_antispoof); -metadata_dst_free (repr->dst); +dst_release (&repr->dst->dst); repr->dst =NULL ;ice_fltr_add_mac_and_broadcast (vsi, repr->parent_mac,ICE_FWD_TO_VSI );
Greg Kroah-Hartman
maintainerPATCH 64/281 io_uring/register: dont exempt disabled rings from task restrictions
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugene Gvozdetsky <[email protected]>
commit 6da8f402e362b2f546e2efb7167fc9597aef6faf upstream.
A ring created with IORING_SETUP_R_DISABLED is exempt from its register restrictions until it is enabled. This lets the creator register the restrictions and then enable the ring with IORING_REGISTER_ENABLE_RINGS, whether or not that opcode is in the allowed set.
Since commit ed82f35b926b ("io_uring: allow registration of per-task restrictions"), a ring also inherits restrictions from the task that creates it, and the same exemption applies to those. A task whose register opcodes are restricted can therefore create a disabled ring, issue any register opcode on it, and then enable it.
Mark rings whose restrictions were inherited from the task, and keep checking register opcodes for them while the ring is disabled. Enabling such a ring now requires IORING_REGISTER_ENABLE_RINGS to be in the task's allowed set. Per-ring restrictions registered on a disabled ring work as before.
--- include/linux/io_uring_types.h | 2 ++ io_uring/io_uring.c | 3 ++- io_uring/register.c | 9 ++++++++- 3 files changed, 12 insertions(+), 2 deletions(-)
include/linux/io_uring_types.h +2 -0
@@ -316,6 +316,8 @@ enum {IO_RING_F_DRAIN_DISABLED =BIT (10 ),IO_RING_F_COMPAT =BIT (11 ),IO_RING_F_IOWQ_LIMITS_SET =BIT (12 ), +/* restrictions were inherited from the task that created the ring */ + IO_RING_F_RESTRICT_INHERITED = BIT(13), };struct iou_ctx {};
io_uring/io_uring.c +2 -1
@@ -2967,7 +2967,8 @@ static void io_ctx_restriction_clone(strif (dst->op_registered) ctx->int_flags |=IO_RING_F_OP_RESTRICTED ;if (dst->reg_registered) - ctx->int_flags |=IO_RING_F_REG_RESTRICTED ; + ctx->int_flags |=IO_RING_F_REG_RESTRICTED | +IO_RING_F_RESTRICT_INHERITED ; }static __cold int io_uring_create (struct io_ctx_config *config)
io_uring/register.c +8 -1
@@ -764,7 +764,14 @@ static int __io_uring_register(struct ioif (ctx->submitter_task && ctx->submitter_task != current)return -EEXIST ; -if ((ctx->int_flags &IO_RING_F_REG_RESTRICTED ) && !(ctx->flags &IORING_SETUP_R_DISABLED )) { +/* +* A disabled ring is exempt from its own register restrictions, so +* that the creator can set them up and then enable the ring. That +* does not apply to restrictions inherited from the task. +*/ +if ((ctx->int_flags &IO_RING_F_REG_RESTRICTED ) && + (!(ctx->flags &IORING_SETUP_R_DISABLED ) || + (ctx->int_flags &IO_RING_F_RESTRICT_INHERITED ))) { opcode =array_index_nospec (opcode,IORING_REGISTER_LAST );if (!test_bit (opcode, ctx->restrictions.register_op))return -EACCES ;
Greg Kroah-Hartman
maintainerPATCH 65/281 io_uring/net: populate CONNECT filter fields for 24-byte sockaddr_in6
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Natasha Klaus <[email protected]>
commit aa5d5f8e502318e783545ba5d04bb40130b83e20 upstream.
io_connect_bpf_populate() fills connect.port and connect.v6_addr for AF_INET6 only when addr_len >= sizeof(struct sockaddr_in6), i.e. 28 bytes.
The IPv6 connect paths accept SIN6_LEN_RFC2133 (24 bytes), which already holds sin6_port and sin6_addr. io_connect() passes addr_len to the socket layer unchanged.
At addr_len 24 the filter sees family AF_INET6 with port and address zero, while the kernel connects to the real destination. A filter that denies an IPv6 port or address is bypassed. Denying connect.port == P rejects [::1]:P with -EACCES at addr_len 28 but connects at addr_len 24.
Use SIN6_LEN_RFC2133 as the threshold. sin6_scope_id stays zero when absent.
The threshold mismatch was found by an AI coding assistant (Claude Code) comparing this hook against the net/ipv6 length checks on my instructions; it also drafted the reproducer and this patch. I verified the bypass and the fix in a VM on 7.3-rc6 and that 7.2 has the same code.
--- io_uring/net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
io_uring/net.c +3 -1
@@ -7,6 +7,7 @@#include <linux/un.h> #include <linux/compat.h> #include <net/compat.h> +#include <net/ipv6.h> #include <linux/io_uring.h> #include <uapi/linux/io_uring.h>
@@ -1772,7 +1773,8 @@ void io_connect_bpf_populate(struct io_ucase AF_INET6 : {struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; -if (conn->addr_len < (int )sizeof (*sin6)) +/* The IPv6 stack accepts SIN6_LEN_RFC2133; port and addr are in it. */ +if (conn->addr_len <SIN6_LEN_RFC2133 )break ; bctx->connect.port = sin6->sin6_port; memcpy(bctx->connect.v6_addr, &sin6->sin6_addr,
Greg Kroah-Hartman
maintainerPATCH 66/281 ip6_gre: remove obsolete ERSPAN PMTU update
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 8bc60db48e8cba35488bbd6e1f94aa990afa275a upstream.
A tc tunnel_key action can attach a METADATA_IP_TUNNEL dst to an skb, and mirred can redirect it to a native ip6erspan device. The legacy PMTU update in ip6erspan_tunnel_xmit() treats that metadata dst as a route. Since it has no output device, dst_dev(dst)->mtu dereferences NULL.
On v7.2 with KASAN, an initial UID/GID 65534 process with CapEff 0 used self-created user and network namespaces to trigger:
KASAN: null-ptr-deref RIP: ip6erspan_tunnel_xmit+0x10fc/0x2cc0 Kernel panic - not syncing: Fatal exception in interrupt
The update is obsolete. Commit fe1a4ca0a2b7 ("ip6_gre: process toobig in a better way") changed IPv6 GRE Too Big handling to update the underlay route and removed the equivalent block from __gre6_xmit(). ip6_tnl_xmit() then propagates the underlay PMTU to the overlay route.
Remove the stale ERSPAN copy and its now-unused dst variable. This eliminates the metadata-dst dereference and keeps ERSPAN aligned with IPv6 GRE PMTU handling.
--- net/ipv6/ip6_gre.c | 7 ------- 1 file changed, 7 deletions(-)
net/ipv6/ip6_gre.c +0 -7
@@ -923,7 +923,6 @@ static netdev_tx_t ip6erspan_tunnel_xmit {struct ip_tunnel_info *tun_info =NULL ;struct ip6_tnl *t =netdev_priv (dev); -struct dst_entry *dst =skb_dst (skb);IP_TUNNEL_DECLARE_FLAGS (flags) = { };bool truncate = false;int encap_limit =-1 ;
@@ -1059,12 +1058,6 @@ static netdev_tx_t ip6erspan_tunnel_xmitgre_build_header (skb,8 , flags, proto,0 ,htonl (atomic_fetch_inc (&t->o_seqno))); -/* TooBig packet may have updated dst->dev's mtu */ -if (!t->parms.collect_md && dst) { - mtu =READ_ONCE (dst_dev (dst)->mtu); -if (dst_mtu (dst) > mtu) - dst->ops->update_pmtu (dst,NULL , skb, mtu, false); - } err =ip6_tnl_xmit (skb, dev, dsfield, &fl6, encap_limit, &mtu,NEXTHDR_GRE );if (err !=0 ) {
Greg Kroah-Hartman
maintainerPATCH 67/281 keys: finalize persistent keyring timeout after link attempt
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 25bf14f817168079f731975b8998fc2af380f29e upstream.
When no keyring exists for the requested UID, KEYCTL_GET_PERSISTENT creates and registers one before linking it to the requested destination. The configured timeout is set only after the destination link succeeds.
A destination restricted with KEYCTL_RESTRICT_KEYRING makes that link fail with -EPERM. With persistent_keyring_expiry set to 60 seconds, /proc/keys still reports the registered keyring's expiry as "perm".
The failed call therefore leaves a quota-exempt keyring in the namespace's hidden register, where it may remain until namespace teardown.
Rename the write-locked helper to key_get_or_create_persistent() and return the key reference through a result parameter. Return 0 when it creates a keyring and 1 when the retry finds an existing one. Return a negative error on failure. Another caller may create the keyring between the initial read-locked lookup and the retry under the write lock.
Set the timeout after permission checking and linking. Do this on success, or on failure if the call allocated the keyring. This leaves a new keyring collectible after failure without starting its timeout while linking is still in progress.
--- security/keys/persistent.c | 55 ++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-)
security/keys/persistent.c +32 -23
@@ -33,25 +33,31 @@ static int key_create_persistent_registe }/* -* Create the persistent keyring for the specified user. +* Get or create the persistent keyring for the specified user. * * Called with the namespace's sem locked for writing. +* +* Returns a boolean indicating whether the keyring already existed, +* or a negative error. On success, *persistent_ref holds a reference +* to the keyring. */ -static key_ref_t key_create_persistent (struct user_namespace *ns,kuid_t uid, -struct keyring_index_key *index_key) +static int key_get_or_create_persistent (struct user_namespace *ns,kuid_t uid, +struct keyring_index_key *index_key, +key_ref_t *persistent_ref) {struct key *persistent; -key_ref_t reg_ref, persistent_ref; +key_ref_t reg_ref;if (!ns->persistent_keyring_register) { -long err =key_create_persistent_register (ns); +int err =key_create_persistent_register (ns); +if (err <0 ) -return ERR_PTR (err); +return err; }else { reg_ref =make_key_ref (ns->persistent_keyring_register, true); - persistent_ref =find_key_to_update (reg_ref, index_key); -if (persistent_ref) -return persistent_ref; + *persistent_ref =find_key_to_update (reg_ref, index_key); +if (*persistent_ref) +return 1 ; } persistent = keyring_alloc(index_key->description,
@@ -61,9 +67,10 @@ static key_ref_t key_create_persistent(sKEY_ALLOC_NOT_IN_QUOTA ,NULL , ns->persistent_keyring_register);if (IS_ERR (persistent)) -return ERR_CAST (persistent); +return PTR_ERR (persistent); -return make_key_ref (persistent, true); + *persistent_ref =make_key_ref (persistent, true); +return 0 ; }/*
@@ -78,6 +85,7 @@ static long key_get_persistent(struct uskey_ref_t reg_ref, persistent_ref;char buf[32 ];long ret; +bool created = false;/* Look in the register if it exists */ memset (&index_key,0 ,sizeof (index_key));
@@ -100,23 +108,24 @@ static long key_get_persistent(struct us* also need to create the register. */ down_write (&ns->keyring_sem); - persistent_ref =key_create_persistent (ns, uid, &index_key); + ret =key_get_or_create_persistent (ns, uid, &index_key, + &persistent_ref);up_write (&ns->keyring_sem); -if (!IS_ERR (persistent_ref)) - goto found; - -return PTR_ERR (persistent_ref); +if (ret <0 ) +return ret; + created = ret ==0 ; found: + persistent =key_ref_to_ptr (persistent_ref); ret =key_task_permission (persistent_ref,current_cred (),KEY_NEED_LINK ); -if (ret ==0 ) { - persistent =key_ref_to_ptr (persistent_ref); +if (ret ==0 ) ret =key_link (key_ref_to_ptr (dest_ref), persistent); -if (ret ==0 ) { -key_set_timeout (persistent, persistent_keyring_expiry); - ret = persistent->serial; - } - } + +if (ret ==0 || created) +key_set_timeout (persistent, persistent_keyring_expiry); + +if (ret ==0 ) + ret = persistent->serial;key_ref_put (persistent_ref);return ret;
Greg Kroah-Hartman
maintainerPATCH 68/281 KEYS: Fix add_key() race with keyring restriction
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: 성병찬 <[email protected]>
commit dd3ea3fcba7c75493760cdbccd35f029597e8d5e upstream.
__key_create_or_update() snapshots keyring->restrict_link before taking the destination keyring's semaphore. keyring_restrict() installs a restriction while holding that semaphore.
This allows a writer to observe no restriction, wait for the keyring owner to install a reject-all restriction and return successfully, and then link a key using the stale NULL snapshot. The writer only needs write permission on the destination keyring.
Move the restrict_link read after __key_link_lock() and __key_link_begin(). The read and the subsequent restriction check are then serialized with restriction installation by keyring->sem.
The race was reproduced on v7.2.8 in 19 executions where restriction installation returned before the link completed. All 19 linked the key despite the reject-all restriction. With this change, 312 executions reached the same ordering and every add_key() call failed with -EPERM.
The issue was found by manual concurrency analysis assisted by AI-based analysis and independently verified with a QEMU reproducer and kernel instrumentation.
--- security/keys/key.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
security/keys/key.c +3 -3
@@ -840,9 +840,6 @@ static key_ref_t __key_create_or_update(key_check (keyring); -if (!(flags &KEY_ALLOC_BYPASS_RESTRICTION )) - restrict_link = keyring->restrict_link; - key_ref =ERR_PTR (-ENOTDIR );if (keyring->type != &key_type_keyring) goto error_put_type;
@@ -880,6 +877,9 @@ static key_ref_t __key_create_or_update( goto error_link_end; } +if (!(flags &KEY_ALLOC_BYPASS_RESTRICTION )) + restrict_link = keyring->restrict_link; +if (restrict_link && restrict_link->check) { ret = restrict_link->check (keyring, index_key.type, &prep.payload, restrict_link->key);
Greg Kroah-Hartman
maintainerPATCH 69/281 memstick: core: wait for request completion before freeing card
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raj Ojha <[email protected]>
commit aa0a37b5024d921e96ac4f8f487c8bfbf1f1a582 upstream.
In memstick_alloc_card() and memstick_set_rw_addr(), wait_for_completion_timeout() is used to wait for device identification and address configuration requests to complete.
The memstick subsystem does not provide an abort or cancellation callback in struct memstick_host for in-flight requests. If wait_for_completion_timeout() expires (for instance, when a USB transfer or command retry is delayed), memstick_alloc_card() returns an error and frees the memstick_dev structure via kfree(card).
However, the host controller driver (such as rtsx_usb_ms) is still running the request asynchronously in worker context. When the transfer eventually finishes, the driver writes into host->req->data, which points to memory inside the already freed card structure. This leads to a KASAN slab-use-after-free write:
BUG: KASAN: slab-use-after-free in ms_read_bytes+0x8fe/0x990 Write of size 1 at addr ffff88813c188079 by task kworker/1:5/5239 Workqueue: events rtsx_usb_ms_handle_req Call Trace: ms_read_bytes+0x8fe/0x990 drivers/memstick/host/rtsx_usb_ms.c:450 rtsx_usb_ms_issue_cmd drivers/memstick/host/rtsx_usb_ms.c:477 [inline] rtsx_usb_ms_handle_req+0x557/0x1a00 drivers/memstick/host/rtsx_usb_ms.c:531 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396 worker_thread+0x5ef/0xe50 kernel/workqueue.c:3560 kthread+0x373/0x450 kernel/kthread.c:436 Allocated by task 1662: memstick_alloc_card drivers/memstick/core/memstick.c:383 [inline] memstick_check+0x2c1/0x10d0 drivers/memstick/core/memstick.c:452 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396 Freed by task 1662: kfree+0x20c/0x650 mm/slub.c:6792 memstick_alloc_card drivers/memstick/core/memstick.c:420 [inline] memstick_check+0x72b/0x10d0 drivers/memstick/core/memstick.c:452 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396
Host controller drivers (rtsx_usb_ms, jmb38x_ms, tifm_ms, r592) already implement their own hardware and bus timeouts, and callers in mspro_block and ms_block already rely on wait_for_completion() unconditionally.
Replace wait_for_completion_timeout() with wait_for_completion() in memstick_set_rw_addr() and memstick_alloc_card() so that the card structure is never freed while an asynchronous request is in flight.
--- drivers/memstick/core/memstick.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/memstick/core/memstick.c +2 -6
@@ -370,9 +370,7 @@ int memstick_set_rw_addr(struct memstick { card->next_request = h_memstick_set_rw_addr;memstick_new_req (card->host); -if (!wait_for_completion_timeout (&card->mrq_complete, -msecs_to_jiffies (500 ))) - card->current_mrq.error = -ETIMEDOUT ; +wait_for_completion (&card->mrq_complete);return card->current_mrq.error; }
@@ -405,9 +403,7 @@ static struct memstick_dev *memstick_all card->next_request = h_memstick_read_dev_id;memstick_new_req (host); -if (!wait_for_completion_timeout (&card->mrq_complete, -msecs_to_jiffies (500 ))) - card->current_mrq.error = -ETIMEDOUT ; +wait_for_completion (&card->mrq_complete);if (card->current_mrq.error) goto err_out;
Greg Kroah-Hartman
maintainerPATCH 70/281 memstick: rtsx_usb_ms: complete requests after eject instead of dropping them
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nguyen Ngoc Thang <[email protected]>
commit c96ca94425b076dc398d929366e378d1e22ec794 upstream.
memstick_check() can pass its host->removing check just before rtsx_usb_ms_drv_remove() sets eject/removing. Its next request is then silently dropped: rtsx_usb_ms_request() skips schedule_work() once eject is set, and drv_remove's cancel_work_sync() can also cancel a queued handle_req before it picks the request up. Nobody completes card->mrq_complete.
Once memstick core waits for requests without a timeout ("memstick: core:
wait for request completion before freeing card"), this hangs removal:memstick_check() never returns and memstick_remove_host() blocks in flush_workqueue():
INFO: task kworker/u10:3:65 blocked for more than 20 seconds. Workqueue: kmemstick memstick_check __wait_for_common memstick_check INFO: task kworker/1:1:33 blocked for more than 20 seconds. Workqueue: usb_hub_wq hub_event __flush_workqueue memstick_remove_host rtsx_usb_ms_drv_remove
Never drop a request. rtsx_usb_ms_request() always schedules handle_req, and handle_req fails requests with -ENOMEDIUM once eject is set, without touching the device. drv_remove flushes handle_req instead of cancelling it, and cancels it only after memstick_remove_host(), when no new request can arrive, so it cannot run on a freed host.
The host_mutex drain in drv_remove is removed: handle_req always leaves host->req NULL when it finishes, so the drain never had anything to do, and it would now race with handle_req.
--- drivers/memstick/host/rtsx_usb_ms.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-)
drivers/memstick/host/rtsx_usb_ms.c +11 -20
@@ -27,7 +27,6 @@ struct rtsx_usb_ms {struct memstick_host *msh;struct memstick_request *req; -struct mutex host_mutex;struct work_struct handle_req;struct delayed_work poll_card;
@@ -514,6 +513,13 @@ static void rtsx_usb_ms_handle_req(strucstruct memstick_host *msh = host->msh;int rc; +/* Fail requests after eject so their waiters are released. */ +if (host->eject) { +while (!memstick_next_req (msh, &host->req)) + host->req->error = -ENOMEDIUM ; +return ; + } +if (!host->req) {pm_runtime_get_sync (ms_dev (host)); do {
@@ -547,8 +553,7 @@ static void rtsx_usb_ms_request(struct mdev_dbg (ms_dev (host),"--> %s\n" , __func__); -if (!host->eject) -schedule_work (&host->handle_req); +schedule_work (&host->handle_req); } static int rtsx_usb_ms_set_param(struct memstick_host *msh,
@@ -781,7 +786,6 @@ static int rtsx_usb_ms_drv_probe(struct host->power_mode =MEMSTICK_POWER_OFF ;platform_set_drvdata (pdev, host); -mutex_init (&host->host_mutex);INIT_WORK (&host->handle_req, rtsx_usb_ms_handle_req);INIT_DELAYED_WORK (&host->poll_card, rtsx_usb_ms_poll_card);
@@ -812,27 +816,12 @@ static void rtsx_usb_ms_drv_remove(struc {struct rtsx_usb_ms *host =platform_get_drvdata (pdev);struct memstick_host *msh = host->msh; -int err; host->eject = true; msh->removing = true; -cancel_work_sync (&host->handle_req); +flush_work (&host->handle_req);cancel_delayed_work_sync (&host->poll_card); -mutex_lock (&host->host_mutex); -if (host->req) { -dev_dbg (ms_dev (host), -"%s: Controller removed during transfer\n" , -dev_name (&msh->dev)); - host->req->error = -ENOMEDIUM ; -do { - err =memstick_next_req (msh, &host->req); -if (!err) - host->req->error = -ENOMEDIUM ; - }while (!err); - } -mutex_unlock (&host->host_mutex); -/* Balance possible unbalanced usage count * e.g. unconditional module removal */
@@ -841,6 +830,8 @@ static void rtsx_usb_ms_drv_remove(strucpm_runtime_disable (ms_dev (host));memstick_remove_host (msh); +/* No card, no new requests; wait for the last failed one to finish. */ +cancel_work_sync (&host->handle_req);dev_dbg (ms_dev (host),": Realtek USB Memstick controller has been removed\n" );memstick_free_host (msh);
Greg Kroah-Hartman
maintainerPATCH 71/281 mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
commit 597e4b9ab48a3f841080f627722064853d3f650e upstream.
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap() operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions occur between existing mremap() operations and the original VMA.
Fix another of these - partial copies.
The long-standing mremap() partial VMA logic has the baked-in assumption that the originating VMA is unmapped and thus moved.
However MREMAP_DONTUNMAP defeats this by performing a partial copy instead since it keeps the source VMA around.
An mremap(..., MREMAP_DONTUNMAP) operation disallows resizing of the VMA, but the operation can be performed partially:
|-----------------|
| |
| v
<------> <------>
.new_sz. new_sz
|--.------.--| |------|
| .source. | | dest |
|--.------.--| |------|
<------------>
old_szThe page tables in the specified range are moved, but the original VMA is kept intact.
This interacts poorly with mlock()'d VMAs, as the VMA_LOCKED_BIT flag is cleared for the entire source VMA and set for the entire destination VMA.
This results in an mm->locked_vm leak as the change is therefore not accounted correctly.
The clear solution here is to make the portion of the source VMA which is mremap()'d distinct from the rest of it, a.k.a. split it.
Therefore resolve this issue by splitting it ahead of the rest of the mremap() operation if the VMA is mlock()'d.
This is valid, as the source VMA will lose its VMA_LOCKED_BIT flag, so if a partial remap it will become distinct from the rest of the VMA.
In order to make this change re-expose split_vma() in vma.h for CONFIG_MMU (nommu doesn't compile mremap.c and uses a static helper instead).
Finally, update the sys_map_count check to account for this case.
Note that the early check does not use needs_pre_split() - this is because the VMA has not been looked up by this point, so be conservative and assume that the VMA is mlock()'d in this case for the purposes of the sys_map_count check.
--- mm/mremap.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---------------- mm/vma.c | 4 +-- mm/vma.h | 5 ++++ 3 files changed, 53 insertions(+), 18 deletions(-)
mm/mremap.c +46 -16
@@ -1029,6 +1029,7 @@ static void vrm_stat_account(struct vma_ }static bool __check_map_count_against_split (struct mm_struct *mm, +bool pre_split,bool before_unmaps) {const int sys_map_count =get_sysctl_max_map_count ();
@@ -1080,26 +1081,42 @@ static bool __check_map_count_against_sp* Therefore we must check to ensure we have headroom of 2 additional * VMAs. */ -return map_count +2 <= sys_map_count; + map_count +=2 ; + +/* If pre-split, the -1 observed above doesn't apply. */ +if (pre_split) + map_count++; + +return map_count <= sys_map_count; +} + +static bool needs_pre_split (struct vma_remap_struct *vrm) +{ +/* +* An MREMAP_DONTUNMAP of a mlock()'d VMA needs to unlock the +* source VMA, so split in this case. +*/ +return (vrm->flags &MREMAP_DONTUNMAP ) && +vma_test (vrm->vma,VMA_LOCKED_BIT ); }/* Do we violate the map count limit if we split VMAs when moving the VMA? */ -static bool check_map_count_against_split (void ) +static bool check_map_count_against_split (struct vma_remap_struct *vrm) {return __check_map_count_against_split (current->mm, -/*before_unmaps=*/ false); +needs_pre_split (vrm),/*before_unmaps=*/ false); }/* Do we violate the map count limit if we split VMAs prior to early unmaps? */ -static bool check_map_count_against_split_early (void ) +static bool check_map_count_against_split_early (struct vma_remap_struct *vrm) {return __check_map_count_against_split (current->mm, -/*before_unmaps=*/ true); + vrm->flags &MREMAP_DONTUNMAP ,/*before_unmaps=*/ true); }/* -* Perform checks before attempting to write a VMA prior to it being -* moved. +* Perform checks and preparation before attempting to write a VMA prior to it +* being moved. */ static unsigned long prep_move_vma (struct vma_remap_struct *vrm) {
@@ -1108,19 +1125,17 @@ static unsigned long prep_move_vma(strucunsigned long old_addr = vrm->addr;unsigned long old_len = vrm->old_len;vm_flags_t dummy = vma->vm_flags; +const bool split_before = vma->vm_start != old_addr; +const bool split_after = vma->vm_end != old_addr + old_len; -/* -* We'd prefer to avoid failure later on in do_munmap: we copy a VMA, -* which may not merge, then (if MREMAP_DONTUNMAP is not set) unmap the -* source, which may split, causing a net increase of 2 mappings. -*/ -if (!check_map_count_against_split ()) +/* Avoid failure later on. */ +if (!check_map_count_against_split (vrm))return -ENOMEM ;if (vma->vm_ops && vma->vm_ops->may_split) { -if (vma->vm_start != old_addr) +if (split_before) err = vma->vm_ops->may_split (vma, old_addr); -if (!err && vma->vm_end != old_addr + old_len) +if (!err && split_after) err = vma->vm_ops->may_split (vma, old_addr + old_len);if (err)return err;
@@ -1138,6 +1153,21 @@ static unsigned long prep_move_vma(strucif (err)return err; +/* +* To account mlock()'d pages correctly in the MREMAP_DONTUNMAP +* case perform any split ahead of time for an mlock()'d VMA. +*/ +if (needs_pre_split (vrm)) { +VMA_ITERATOR (vmi, vma->vm_mm, old_addr); + +if (split_before) + err =split_vma (&vmi, vma, old_addr,1 ); +if (!err && split_after) + err =split_vma (&vmi, vma, old_addr + old_len,0 ); + vrm->vmi_needs_invalidate = true; +return err; + } +return 0 ; }
@@ -1992,7 +2022,7 @@ static unsigned long do_mremap(struct vmreturn -EINTR ; vrm->mmap_locked = true; -if (!check_map_count_against_split_early ()) { +if (!check_map_count_against_split_early (vrm)) {mmap_write_unlock (mm);return -ENOMEM ; }
mm/vma.c +2 -2
@@ -590,8 +590,8 @@ out_free_vma:* Split a vma into two pieces at address 'addr', a new vma is allocated * either for the first part or the tail. */ -static int split_vma (struct vma_iterator *vmi,struct vm_area_struct *vma, -unsigned long addr,int new_below) +int split_vma (struct vma_iterator *vmi,struct vm_area_struct *vma, +unsigned long addr,int new_below) {if (vma->vm_mm->map_count >=get_sysctl_max_map_count ())return -ENOMEM ;
mm/vma.h +5 -0
@@ -470,6 +470,11 @@ int do_brk_flags(struct vma_iterator *vmunsigned long unmapped_area (struct vm_unmapped_area_info *info);unsigned long unmapped_area_topdown (struct vm_unmapped_area_info *info); +#ifdef CONFIG_MMU +int split_vma (struct vma_iterator *vmi,struct vm_area_struct *vma, +unsigned long addr,int new_below); +#endif +static inline bool vma_wants_manual_pte_write_upgrade (struct vm_area_struct *vma) {/*
Greg Kroah-Hartman
maintainerPATCH 72/281 mm: dont schedule deferred kernel page table freeing while booting
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit 2fb552b0bee70c24c092720028ab4620f5eb2646 upstream.
Booting with a boot-time function tracer and a filter, for example
ftrace=function ftrace_filter=pud_free_pmd_page
panics on 7.3-rc4 as soon as the tracer starts:
[ 23.531178] Starting tracer 'function' [ 23.675800] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000038: 0000 [#1] SMP KASAN NOPTI [ 23.819917] KASAN: null-ptr-deref in range [0x00000000000001c0-0x00000000000001c7] [ 23.964025] CPU: 0 UID: 0 PID: 0 Comm: swapper Not tainted 7.3.0-rc4-fe2ec83746e5-with-fixes-v2+ #195 PREEMPT(undef) [ 24.252248] RIP: 0010:__queue_work+0xab/0xf00 [ 25.981629] Call Trace: [ 26.125727] <TASK> [ 26.413912] ? pagetable_free_kernel+0x20/0x120 [ 26.990283] queue_work_on+0x97/0xf0 [ 27.134382] __cpa_collapse_large_pages+0x501/0x6f0 [ 27.566662] cpa_flush+0x394/0x620 [ 27.998953] change_page_attr_set_clr+0x321/0x4a0 [ 29.151729] set_memory_rox+0xa2/0xf0 [ 29.584018] create_trampoline+0x431/0x6f0 ... [ 44.343347] Kernel panic - not syncing: Attempted to kill the idle task!
The boot-time tracer is started from early_trace_init(), which runs before workqueue_init_early(). Making its trampoline read-only splits a large page, and CPA collapses it again right away. The split table has been a kernel page table since commit 9e4a3ec3411b ("x86/mm/pat: Allocate split page tables as kernel page tables"), so the collapse frees it through pagetable_free_kernel(), which queues work on system_percpu_wq - still NULL at that point. That commit is correct in itself; it only lets CPA reach pagetable_free_kernel() before the workqueue that function relies on exists.
Keep putting the table on the list, but don't schedule the work while the system is still booting. A core_initcall schedules it once to free whatever was queued by then.
--- mm/pgtable-generic.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
mm/pgtable-generic.c +19 -1
@@ -438,12 +438,30 @@ static void kernel_pgtable_work_func(str __pagetable_free(pt); } +static void schedule_kernel_pgtable_free (void ) +{ +schedule_work (&kernel_pgtable_work.work); +} +void pagetable_free_kernel (struct ptdesc *pt) {spin_lock (&kernel_pgtable_work.lock);list_add (&pt->pt_list, &kernel_pgtable_work.list);spin_unlock (&kernel_pgtable_work.lock); -schedule_work (&kernel_pgtable_work.work); +/* +* The workqueue may not exist yet while the system is booting. +* kernel_pgtable_drain_early() schedules the work once it does. +*/ +if (system_state !=SYSTEM_BOOTING ) +schedule_kernel_pgtable_free (); +} + +static int __init kernel_pgtable_drain_early (void ) +{ +/* Free the kernel page tables queued while booting. */ +schedule_kernel_pgtable_free (); +return 0 ; } +core_initcall (kernel_pgtable_drain_early);#endif
Greg Kroah-Hartman
maintainerPATCH 73/281 dm-crypt: reject the lmk IV mode with AEAD ciphers
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Cressey <[email protected]>
commit 3195e0daf590683992edb4eed32269e569e04924 upstream.
A "capi:" table line that pairs an AEAD cipher with the lmk IV mode, for example "capi:gcm(aes)-lmk" with the integrity:28:aead option, causes an oops when it is loaded. lmk sets tfms_count to 64, but crypt_alloc_tfms_aead only allocates one transform, so crypt_setkey reads past the end of the tfms_aead array and calls crypto_aead_setkey on the values it finds there.
lmk exists for compatibility with Loop-AES, which uses CBC, so refuse it with an AEAD cipher rather than allocate 64 AEAD transforms. The check cannot go in crypt_iv_lmk_ctr with the other lmk checks, because the IV constructor runs after crypt_set_key.
Note that this is not a security bug because the memory corruption can only be triggered by root.
--- drivers/md/dm-crypt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/dm-crypt.c +6 -1
@@ -2895,8 +2895,13 @@ static int crypt_ctr_cipher_new(struct d } } -if (*ivmode && !strcmp (*ivmode,"lmk" )) +if (*ivmode && !strcmp (*ivmode,"lmk" )) { +if (crypt_integrity_aead (cc)) { + ti->error ="AEAD transforms not supported for LMK" ; +return -EINVAL ; + } cc->tfms_count =64 ; + }if (*ivmode && !strcmp (*ivmode,"essiv" )) {if (!*ivopts) {
Greg Kroah-Hartman
maintainerPATCH 74/281 dm-integrity: fix buffer overflow in inline mode with large tag size
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Cressey <[email protected]>
commit 764b683a6180fd72c931c13fea98d383506a3475 upstream.
In inline mode, dm_integrity_check and dm_integrity_inline_recheck compute the checksum of each block into an on-stack buffer of HASH_MAX_DIGESTSIZE bytes. integrity_sector_checksum pads its result with zeroes up to the tag size, so if the tag size is larger than HASH_MAX_DIGESTSIZE, the padding runs past the end of the buffer. With CONFIG_STACKPROTECTOR the kernel panics in dm_integrity_check on the first read.
Enlarge both buffers to hold MAX_TAG_SIZE bytes, as commit b93b6643e9b5 ("dm integrity: fix a crash with unusually large tag size") did for integrity_metadata.
Note that this is not a security bug because the buffer overflow can only be triggered by root.
--- drivers/md/dm-integrity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/md/dm-integrity.c +2 -2
@@ -2721,7 +2721,7 @@ static void dm_integrity_inline_recheck( outgoing_data = dio->integrity_payload +PAGE_SIZE ;while (dio->bio_details.bi_iter.bi_size) { -char digest[HASH_MAX_DIGESTSIZE ]; +char digest[MAX_T (size_t,HASH_MAX_DIGESTSIZE ,MAX_TAG_SIZE )];int r;struct bio_integrity_payload *bip;struct bio_vec bv;
@@ -2788,7 +2788,7 @@ static inline bool dm_integrity_check(stunsigned pos =0 ;while (dio->bio_details.bi_iter.bi_size) { -char digest[HASH_MAX_DIGESTSIZE ]; +char digest[MAX_T (size_t,HASH_MAX_DIGESTSIZE ,MAX_TAG_SIZE )];struct bio_vec bv =bio_iter_iovec (bio, dio->bio_details.bi_iter);char *mem =integrity_kmap (ic, bv.bv_page);integrity_sector_checksum (ic, &dio->ahash_req, dio->bio_details.bi_iter.bi_sector, mem, bv.bv_offset, digest);
Greg Kroah-Hartman
maintainerPATCH 75/281 dm-snap: reject the transient exception store for snapshot-merge
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ma Xinmeng <[email protected]>
commit fcbde6227fcc53c73f08c56b2539e462d545cac6 upstream.
snapshot_merge_next_chunks() calls s->store->type->prepare_merge() without checking it. The transient store ("N") implements neither prepare_merge nor commit_merge, and snapshot_ctr() validates those callbacks only on the handover path (__validate_exception_handover()), so a directly constructed snapshot-merge calls a NULL prepare_merge on resume:
snapshot_merge_resume -> snapshot_merge_next_chunks -> prepare_merge(...)
commit_merge() is NULL for the same reason. Userspace only issues documented device-mapper ioctls (CAP_SYS_ADMIN); this is a misconfiguration the kernel must reject rather than oops on.
Reject the combination in snapshot_ctr() at table-load time (-EINVAL), the same check the handover path already performs; this also covers the commit_merge() call site, which a guard local to the prepare_merge call would miss.
Tested on Linux v6.6.157 KASAN: unpatched, the dmsetup reproducer oopses in snapshot_merge_next_chunks(); with this patch, the table load fails with -EINVAL and no oops. Also present on v6.6.145; still present on the linux-dm tree (555f3d7be91a) and on torvalds/linux master (62f4c998b297) as of 2026-09-22.
Note that this is not a security bug because only root can trigger it.
--- drivers/md/dm-snap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/md/dm-snap.c +14 -0
@@ -1294,6 +1294,20 @@ static int snapshot_ctr(struct dm_target goto bad_store; } +/* +* snapshot-merge requires the optional prepare_merge/commit_merge +* callbacks; the transient exception store does not implement them. +* The handover path checks this in __validate_exception_handover(), +* but a directly constructed snapshot-merge never goes through it. +*/ +if (dm_target_is_snapshot_merge (ti) && + (!s->store->type->prepare_merge || + !s->store->type->commit_merge)) { + ti->error ="Snapshot exception store does not support snapshot-merge." ; + r = -EINVAL ; + goto bad_hash_tables; + } + argv += args_used; argc -= args_used;
Greg Kroah-Hartman
maintainerPATCH 76/281 dm: fix reading free memory in do_resume
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit c9417c1c5269e2bd0570fbe53e4ec03a8d31f008 upstream.
When do_resume calls dm_table_get_mode(new_map), the call is done without holding any locks (it only holds a reference to the md). It may be possible that another concurrent ioctl on the same device will swap table after dm_swap_table and before dm_table_get_mode. In this case, dm_table_get_mode(new_map) reads freed memory.
This race condition was triggered by syzbot.
This commit fixes the race by reading mode of the new table before dm_swap_table. Note that new_map is also passed to dm_ima_need_measure, but this function doesn't attempt to dereference it, so this call should be safe.
Note that this is not a security bug because only root can trigger it and the commonly used tools such as lvm or cryptsetup do not call the ioctls concurrently, so that they can't trigger it acceidentally.
--- drivers/md/dm-ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/md/dm-ioctl.c +3 -1
@@ -1295,6 +1295,7 @@ static int do_resume(struct dm_ioctl *pa/* Do we need to load a new map ? */ if (new_map) {sector_t old_size, new_size; +blk_mode_t new_map_mode;dm_ima_context_table_op (md, ima_context,DM_IMA_TABLE_SAVE );/* Suspend if it isn't already suspended */
@@ -1327,6 +1328,7 @@ static int do_resume(struct dm_ioctl *pa } } + new_map_mode =dm_table_get_mode (new_map); old_size =dm_get_size (md); old_map =dm_swap_table (md, new_map);if (IS_ERR (old_map)) {
@@ -1342,7 +1344,7 @@ static int do_resume(struct dm_ioctl *paif (old_size && new_size && old_size != new_size) need_resize_uevent = true; -if (dm_table_get_mode (new_map) &BLK_OPEN_WRITE ) +if (new_map_mode &BLK_OPEN_WRITE )set_disk_ro (dm_disk (md),0 );else set_disk_ro (dm_disk (md),1 );
Greg Kroah-Hartman
maintainerPATCH 77/281 mmc: cavium-octeon: destroy slot platform devices on remove
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 0f4d4424fc1d651ec3fa63a0a8060ba9087eb0ec upstream.
octeon_mmc_probe() creates host->slot_pdev[i] with of_platform_device_create(), while octeon_mmc_remove() does not destroy the child platform devices.
The probe failure path removes each MMC slot and destroys its associated platform device, but the normal remove path only removes the MMC slot. As a result, the child platform devices remain registered after the Octeon MMC controller is removed.
Destroy each slot platform device during removal after cleaning up the corresponding MMC slot, matching the probe failure cleanup path.
This issue was found by manual code inspection.
--- drivers/mmc/host/cavium-octeon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/cavium-octeon.c +4 -1
@@ -301,9 +301,12 @@ static void octeon_mmc_remove(struct plau64 dma_cfg;int i; -for (i =0 ; i <CAVIUM_MAX_MMC ; i++) +for (i =0 ; i <CAVIUM_MAX_MMC ; i++) {if (host->slot[i])cvm_mmc_of_slot_remove (host->slot[i]); +if (host->slot_pdev[i]) +of_platform_device_destroy (&host->slot_pdev[i]->dev,NULL ); + } dma_cfg =readq (host->dma_base +MIO_EMM_DMA_CFG (host)); dma_cfg &= ~MIO_EMM_DMA_CFG_EN ;
Greg Kroah-Hartman
maintainerPATCH 78/281 mmc: cavium-thunderx: destroy slot platform devices on remove
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 29ee8cf18a21b02cd0b2e35f741b61cd1fe3e14e upstream.
thunder_mmc_probe() creates host->slot_pdev[i] with of_platform_device_create(), while thunder_mmc_remove() does not destroy the child platform devices.
The probe failure path removes each MMC slot and destroys its associated platform device, but the normal remove path only removes the MMC slot. As a result, the child platform devices remain registered after the ThunderX MMC controller is removed.
Destroy each slot platform device during removal after cleaning up the corresponding MMC slot, matching the probe failure cleanup path. Keep an extra device reference around of_platform_device_destroy() as done in the existing error path.
This issue was found by manual code inspection.
--- drivers/mmc/host/cavium-thunderx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/cavium-thunderx.c +4 -1
@@ -173,9 +173,12 @@ static void thunder_mmc_remove(struct pcu64 dma_cfg;int i; -for (i =0 ; i <CAVIUM_MAX_MMC ; i++) +for (i =0 ; i <CAVIUM_MAX_MMC ; i++) {if (host->slot[i])cvm_mmc_of_slot_remove (host->slot[i]); +if (host->slot_pdev[i]) +of_platform_device_destroy (&host->slot_pdev[i]->dev,NULL ); + } dma_cfg =readq (host->dma_base +MIO_EMM_DMA_CFG (host)); dma_cfg &= ~MIO_EMM_DMA_CFG_EN ;
Greg Kroah-Hartman
maintainerPATCH 79/281 mmc: mtk-sd: Cancel request timeout work on remove
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yibo Tan <[email protected]>
commit b38af5386a74416e898955443f2e26547b358cb2 upstream.
The driver queues req_timeout while a request is active. msdc_request_done() uses cancel_delayed_work(), which does not wait for a timeout callback that has already started.
The timeout callback calls mmc_request_done(), which wakes the request waiter, and then continues to use host->dev_comp and check the SDIO IRQ. During unbind, msdc_drv_remove() can return and the managed mmc_host can be freed before the callback finishes.
KASAN reported use-after-free accesses in msdc_request_done() and msdc_recheck_sdio_irq() in each of three unbind tests. The same tests completed without a kernel diagnostic after this change.
Call cancel_delayed_work_sync() after mmc_remove_host() has stopped new requests and before the driver releases the host resources.
--- drivers/mmc/host/mtk-sd.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/mtk-sd.c +1 -0
@@ -3216,6 +3216,7 @@ static void msdc_drv_remove(struct platfplatform_set_drvdata (pdev,NULL );mmc_remove_host (mmc); +cancel_delayed_work_sync (&host->req_timeout);msdc_deinit_hw (host);msdc_gate_clock (host);
Greg Kroah-Hartman
maintainerPATCH 80/281 mmc: sdhci-sprd: disable runtime PM on remove
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit e1c6c10a6a70a69e29b04fcc1ebe4b9bcbc7a49a upstream.
sdhci_sprd_probe() enables runtime PM, while sdhci_sprd_remove() does not perform the corresponding runtime PM cleanup.
The probe failure path disables runtime PM before disabling the clocks, but the normal remove path directly disables clocks that are also managed by the runtime PM callbacks. If the device is runtime suspended, those clocks may already be disabled.
Resume the device before removal, disable runtime PM and drop the temporary runtime PM reference before disabling the clocks.
This issue was found by manual code inspection.
--- drivers/mmc/host/sdhci-sprd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/mmc/host/sdhci-sprd.c +4 -0
@@ -890,6 +890,10 @@ static void sdhci_sprd_remove(struct plastruct sdhci_host *host =platform_get_drvdata (pdev);struct sdhci_sprd_host *sprd_host =TO_SPRD_HOST (host); +pm_runtime_get_sync (&pdev->dev); +pm_runtime_disable (&pdev->dev); +pm_runtime_put_noidle (&pdev->dev); +sdhci_remove_host (host,0 );clk_disable_unprepare (sprd_host->clk_sdio);
Greg Kroah-Hartman
maintainerPATCH 81/281 net/packet: guard the ll header push in packet_rcv_spkt()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Quchaosheng <[email protected]>
commit 28bc1ef699610ee09ce3d46a00552f5a0a0144bd upstream.
packet_rcv_spkt() restores the link layer header with
skb_push(skb, skb->data - skb_mac_header(skb));
That subtraction is only meaningful when the device actually has a link layer header. packet_rcv() and tpacket_rcv() both wrap it in dev_has_header(), which is also the predicate the block comment at the top of the file states the restore in terms of; packet_rcv_spkt() does not. commit d549699048b4 ("net/packet: fix packet receive on L3 devices without visible hard header") introduced the helper and changed the two call sites, and this one stayed behind.
A device without a visible ll header can leave skb->mac_header at the 0xFFFF sentinel that __alloc_skb() initialises it to. A CAN skb does:init_can_skb() sets pkt_type and ip_summed but does not reset the headers, and commit 9f10374bb024 ("can: remove private CAN skb headroom infrastructure") dropped the skb_reset_*_header() calls that used to be there. skb_mac_header() is then 0xFFFF, the length becomes a large negative number and skb_push() reports it through skb_under_panic() -- from softirq context, so it is a full system panic even with panic_on_oops=0:
skbuff: skb_under_panic: text:ffffffff8bd21bc1 len:-65455 put:-65471 head:... data:... tail:0x50 end:0x180 dev:can0 kernel BUG at net/core/skbuff.c:214!
RIP: 0010:skb_panic+0x50/0x60 Call Trace: <IRQ> skb_push+0x38/0x40 packet_rcv_spkt+0xe1/0x170 __netif_receive_skb_core.constprop.0+0x7e8/0xd30 ... Kernel panic - not syncing: Fatal exception in interrupt
The socket type is reachable: packet_create() accepts SOCK_PACKET alongside SOCK_RAW and SOCK_DGRAM behind the same CAP_NET_RAW check, and neither the socket length nor a capability check keeps it away from a CAN interface.
The missing skb_reset_*_header() calls in init_can_skb() are a regression in their own right and are being fixed separately, but a packet socket should not turn a link layer that did not initialise its mac header into a kernel panic. Guard the push the way the other two receive paths do.
Tested on v7.3-rc5 under QEMU with a slcan device on a pty, which is the driver RX path: vcan does not reproduce it, because can_send() resets the headers on the way out. One SOCK_PACKET socket bound to can0 and one frame written into the line discipline panics an unpatched kernel with the trace above; the same image with this patch prints no panic and powers off normally. Both kernels are this tree, defconfig plus CONFIG_CAN_SLCAN=y, differing only in this hunk.
--- net/packet/af_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/packet/af_packet.c +2 -1
@@ -1911,7 +1911,8 @@ static int packet_rcv_spkt(struct sk_buf spkt = &PACKET_SKB_CB (skb)->sa.pkt; -skb_push (skb, skb->data -skb_mac_header (skb)); +if (dev_has_header (dev)) +skb_push (skb, skb->data -skb_mac_header (skb));/* * The SOCK_PACKET socket receives _all_ frames.
Greg Kroah-Hartman
maintainerPATCH 82/281 net/smc: protect clcsock lifetime in smc_getname
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 64a6b36b0e1855288080bc5f89769f27d6dc03c8 upstream.
smc_getname() dereferences smc->clcsock without holding clcsock_release_lock. Link-group termination can release the CLC socket through smc_close_active_abort() while the SMC socket is still open, for example after shutdown(SHUT_WR).
A getsockname() caller can load smc->clcsock, then the termination worker can clear the pointer and call sock_release() before the caller accesses clcsock->ops or invokes getname(). This causes a use-after-free; if the worker clears the pointer before the load, it causes a NULL dereference. The syscall's file reference keeps the SMC socket alive but does not prevent asynchronous release of its CLC socket.
KASAN reported the following with test-only timing instrumentation:
BUG: KASAN: slab-use-after-free in smc_getname+0x19e/0x1b0 Read of size 8 at addr ffff888109abb4e0 by task poc/103 Call Trace: smc_getname+0x19e/0x1b0 do_getsockname+0xe5/0x170 __sys_getsockname+0x8c/0x100 Allocated by task 95: sock_alloc_inode+0x1e/0x280 sock_alloc+0x3d/0x240 __sock_create+0x7e/0x430 smc_create+0x121/0x240 Freed by task 0: kmem_cache_free+0xcc/0x340 rcu_core+0x50a/0x1850 Last potentially related work creation: evict+0x446/0x6c0 smc_clcsock_release+0xa8/0xd0 smc_close_active_abort+0x26a/0x3a0 __smc_lgr_terminate.part.0+0x137/0x2e0
Hold clcsock_release_lock across the pointer check and the getname() callback to serialize with smc_clcsock_release(). Return -EBADF if the CLC socket has already been released, preserving the existing peer state check and the callback's return value otherwise.
--- net/smc/af_smc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
net/smc/af_smc.c +6 -1
@@ -2784,6 +2784,7 @@ int smc_getname(struct socket *sock, str int peer) {struct smc_sock *smc; +int rc = -EBADF ;if (peer && (sock->sk->sk_state !=SMC_ACTIVE ) && (sock->sk->sk_state !=SMC_APPCLOSEWAIT1 ))
@@ -2791,7 +2792,11 @@ int smc_getname(struct socket *sock, str smc =smc_sk (sock->sk); -return smc->clcsock->ops->getname (smc->clcsock, addr, peer); +mutex_lock (&smc->clcsock_release_lock); +if (smc->clcsock) + rc = smc->clcsock->ops->getname (smc->clcsock, addr, peer); +mutex_unlock (&smc->clcsock_release_lock); +return rc; }int smc_sendmsg (struct socket *sock,struct msghdr *msg,size_t len)
Greg Kroah-Hartman
maintainerPATCH 83/281 net: bridge: avoid recursive multicast port cleanup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zixuan Chai <[email protected]>
commit 5158353121bae4f552cb677ce8c5c3ef52f93a0d upstream.
br_multicast_sg_del_exclude_ports() removes automatically added STAR_EXCL port groups by calling br_multicast_del_pg(). For S,G entries, that deletion calls back into br_multicast_sg_del_exclude_ports(), so a large number of STAR_EXCL ports consumes one kernel stack frame per port and can hit the stack guard page.
Keep the complete port-group deletion path for cleanup, but suppress the S,G exclude-port cleanup while that helper is already walking the same entry. Normal deletion callers retain the existing behavior.
--- net/bridge/br_multicast.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
net/bridge/br_multicast.c +18 -5
@@ -81,6 +81,10 @@ __br_multicast_add_group(struct net_brid bool blocked);static void br_multicast_find_del_pg (struct net_bridge *br,struct net_bridge_port_group *pg); +static void __br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp, +bool sg_del_exclude_ports);static void __br_multicast_stop (struct net_bridge_mcast *brmctx); static int br_mc_disabled_update(struct net_device *dev, bool value,
@@ -458,7 +462,7 @@ static void br_multicast_sg_del_exclude_for (pp = &sgmp->ports; (p =mlock_dereference (*pp, sgmp->br)) !=NULL ;) {if (!(p->flags &MDB_PG_FLAGS_PERMANENT )) -br_multicast_del_pg (sgmp, p, pp); +__br_multicast_del_pg (sgmp, p, pp, false);else pp = &p->next; }
@@ -799,9 +803,10 @@ static void br_multicast_destroy_port_grkfree_rcu (pg, rcu); } -void br_multicast_del_pg (struct net_bridge_mdb_entry *mp, -struct net_bridge_port_group *pg, -struct net_bridge_port_group __rcu **pp) +static void __br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp, +bool sg_del_exclude_ports) {struct net_bridge *br = pg->key.port->br;struct net_bridge_group_src *ent;
@@ -816,7 +821,8 @@ void br_multicast_del_pg(struct net_bridif (!br_multicast_is_star_g (&mp->addr)) {rhashtable_remove_fast (&br->sg_port_tbl, &pg->rhnode, br_sg_port_rht_params); -br_multicast_sg_del_exclude_ports (mp); +if (sg_del_exclude_ports) +br_multicast_sg_del_exclude_ports (mp); }else {br_multicast_star_g_handle_mode (pg,MCAST_INCLUDE ); }
@@ -828,6 +834,13 @@ void br_multicast_del_pg(struct net_bridmod_timer (&mp->timer, jiffies); } +void br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp) +{ +__br_multicast_del_pg (mp, pg, pp, true); +} +static void br_multicast_find_del_pg (struct net_bridge *br,struct net_bridge_port_group *pg) {
Greg Kroah-Hartman
maintainerPATCH 84/281 net: dsa: microchip: fix KSZ8765 fiber detection
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastien Royen <[email protected]>
commit fc13ba44da197a186f2f4d77c5b7d73d0f99f053 upstream.
The KSZ8765 is similar to the KSZ8795 but has two fiber ports.
KSZ8_PORT_STATUS_0 is used to detect fiber mode. It is currently defined as 0x08, which is the Global Control 6 MIB Control register and has bit 7 defined as Flush Counter.
Set KSZ8_PORT_STATUS_0 to 0x18, which is the Port 1 Status 0 register where bit 7 is the Fiber Mode bit.
This issue was discovered when upgrading an embedded device from kernel 5.10 to 6.16. The device was using a KSZ8765 device tree configuration and the corresponding hardware, but during boot the kernel incorrectly detected it as a KSZ8795. The relevant boot messages were:
ksz-switch spi0.0: found switch: KSZ8795, rev 0
ksz-switch spi0.0: Device tree specifies chip KSZ8765 but found KSZ8795, please fix it!
--- drivers/net/dsa/microchip/ksz_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/microchip/ksz_common.h +1 -1
@@ -778,7 +778,7 @@ static inline bool ksz_is_sgmii_port(str#define KSZ88_FAMILY_ID 0x88#define KSZ8895_FAMILY_ID 0x95 -#define KSZ8_PORT_STATUS_0 0x08 +#define KSZ8_PORT_STATUS_0 0x18#define KSZ8_PORT_FIBER_MODE BIT(7)#define SW_CHIP_ID_M GENMASK(7, 4)
Greg Kroah-Hartman
maintainerPATCH 85/281 net: skbuff: dont leave stale bytes in skb_copy_and_csum_bits()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik <[email protected]>
commit ab9414ed70bd783e902a85c350620dee269bcb2b upstream.
When skb_copy_and_csum_bits() reaches unreadable frags it returns 0 after copying only the linear part, and the rest of the caller's buffer is left as it was. The callers copy into a buffer that is about to go out on the wire: an ICMP error quoting the offending packet, or a driver's TX bounce buffer in skb_copy_and_csum_dev(). Neither buffer is zeroed beforehand, so whatever was in memory there gets sent.
Zero the part of the buffer we didn't fill. The checksum usually won't match the data any more, so the receiver will usually drop the packet, but either way it no longer carries anything it shouldn't. Only zero for a positive @len, a negative one from a broken caller must not turn into a huge memset().
--- net/core/skbuff.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/core/skbuff.c +5 -1
@@ -3633,8 +3633,12 @@ __wsum skb_copy_and_csum_bits(const stru pos = copy; } -if (!skb_frags_readable (skb)) +if (!skb_frags_readable (skb)) { +/* Don't hand the caller a buffer with stale bytes in it. */ +if (len >0 ) +memset (to,0 , len);return 0 ; + }for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++) {int end;
Greg Kroah-Hartman
maintainerPATCH 86/281 net: sparx5: free the matchall entry on destroy
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Machon <[email protected]>
commit 2b82e16d6084cbc651e3c902198f1945408ee1a5 upstream.
sparx5_tc_matchall_replace() allocates a struct sparx5_mall_entry for every offloaded matchall filter and adds it to sparx5->mall_entries. sparx5_tc_matchall_destroy() removes the entry from the list, but never frees it, so the entry of every deleted mirror and goto matchall filter is leaked.
Free the entry after unlinking it.
The leak was discovered by an AI code review agent, and reproduced with kmemleak on a lan969x EV board (EV23X71A) by repeatedly adding and deleting matchall mirror and goto filters. With the fix, kmemleak no longer reports the leak.
--- drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c +1 -0
@@ -160,6 +160,7 @@ static int sparx5_tc_matchall_destroy(st }list_del (&entry->list); +kfree (entry);return err; }
Greg Kroah-Hartman
maintainerPATCH 87/281 net: usb: ax88179_178a: fix rx frame length for non-last packets
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fredrik Nyberg <[email protected]>
commit 9b6c20f788472d2042717a3c2f1bc60b2b77083e upstream.
Commit 4ce62d5b2f7a ("net: usb: ax88179_178a: stop lying about skb->truesize") replaced skb_clone() with a copy into a new skb for every packet of a bulk-in transfer except the last one. The copy skips the 2-byte IP alignment pseudo header but still copies pkt_len bytes, and pkt_len includes that header. Each of these frames is therefore delivered with two extra trailing bytes: the 0xeeee pseudo header of the next slot when the frame ends on an 8-byte boundary, or slot padding otherwise. The last packet is still trimmed to pkt_len - 2.
IPv4 and IPv6 trim the extra bytes, so most traffic is unaffected. Anything that relies on the frame length is not. MACsec takes the ICV from the last 16 bytes and drops every such frame as InPktsNotValid. In our setup that was 0.2-1.2% of received MACsec frames, depending on how many frames shared a transfer, including service discovery multicast.
Allocate and copy pkt_len - 2 bytes, like the last-packet path.
--- drivers/net/usb/ax88179_178a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/usb/ax88179_178a.c +3 -3
@@ -1457,11 +1457,11 @@ static int ax88179_rx_fixup(struct usbnereturn 1 ; } - ax_skb =netdev_alloc_skb_ip_align (dev->net, pkt_len); + ax_skb =netdev_alloc_skb_ip_align (dev->net, pkt_len -2 );if (!ax_skb)return 0 ; -skb_put (ax_skb, pkt_len); -memcpy (ax_skb->data, skb->data +2 , pkt_len); +skb_put (ax_skb, pkt_len -2 ); +memcpy (ax_skb->data, skb->data +2 , pkt_len -2 );ax88179_rx_checksum (ax_skb, pkt_hdr);usbnet_skb_return (dev, ax_skb);
Greg Kroah-Hartman
maintainerPATCH 88/281 net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suraj Gupta <[email protected]>
commit bcf2573a68a808a5b54cadafa72b6672e662c2bf upstream.
In the dmaengine path the driver pre-submits RX buffers and holds in-flight TX buffers whose SKBs are DMA-mapped by the driver and freed only in the completion callbacks. On ndo_stop() dmaengine_terminate_sync() aborts these descriptors without running their callbacks, and the driver then frees only the ring shells, leaking every SKB still owned by the engine and its DMA mapping on each ifdown. With 128 RX buffers pre-posted per channel, the mapping leak can eventually exhaust a limited IOMMU aperture.
Clear the slot's skb in the TX and RX callbacks so a non-NULL skb marks a slot that still owns a live, DMA-mapped buffer, and on stop unmap and free every such buffer.
axienet_dma_rx_cb() runs from the DMA tasklet and re-arms the RX ring on each completion, so it can race axienet_stop(): a completion may submit a fresh buffer after dmaengine_terminate_sync() has returned, leaving the channel armed with a buffer the teardown then frees while the engine may still write into it (dma_release_channel() does not stop it either). Add a lock that axienet_dma_rx_cb() holds across the @stopping check and the resubmit, and axienet_stop() holds to set @stopping before terminating. Once @stopping is set no callback can arm a new buffer, and any armed just before is aborted by the terminate, so teardown only frees buffers the engine no longer owns.
--- drivers/net/ethernet/xilinx/xilinx_axienet.h | 7 ++- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 51 ++++++++++++++++++---- 2 files changed, 47 insertions(+), 11 deletions(-)
drivers/net/ethernet/xilinx/xilinx_axienet.h +5 -2
@@ -523,8 +523,9 @@ struct skbuf_dma_descriptor {* @stats_work: Work for reading the hardware statistics counters often enough * to catch overflows. * @dma_err_task: Work structure to process Axi DMA errors -* @stopping: Set when @dma_err_task shouldn't do anything because we are -* about to stop the device. +* @stopping: Set when we are about to stop the device: makes @dma_err_task +* a no-op (legacy DMA path) and fences RX descriptor +* resubmission in axienet_dma_rx_cb() (dmaengine path). * @tx_irq: Axidma TX IRQ number * @rx_irq: Axidma RX IRQ number * @eth_irq: Ethernet core IRQ number
@@ -545,6 +546,7 @@ struct skbuf_dma_descriptor {* @tx_ring_tail: TX skb ring buffer tail index. * @rx_ring_head: RX skb ring buffer head index. * @rx_ring_tail: RX skb ring buffer tail index. +* @rx_submit_lock: Protects RX ring resubmission vs teardown in dmaengine path. */ struct axienet_local {struct net_device *ndev;
@@ -626,6 +628,7 @@ struct axienet_local {int tx_ring_tail;int rx_ring_head;int rx_ring_tail; +spinlock_t rx_submit_lock; };/**
drivers/net/ethernet/xilinx/xilinx_axienet_main.c +42 -9
96 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 89/281 net: team: stop reusing skb after queue override
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit b7454f1940c5e6d92e753853c476a769e452f30a upstream.
A nonzero dev_queue_xmit() result does not return ownership of the skb. When an override port's qdisc drops it, the queue override helper used to try another port or the mode transmit op with the freed skb.
Return the handoff decision separately from transmit success. Select only the first override port under RCU and stop after handing it the skb, regardless of the lower transmit result. Keep the existing success and drop accounting.
BUG: KASAN: slab-use-after-free in sk_skb_reason_drop Write of size 4 by task poc/5040 sk_skb_reason_drop (net/core/skbuff.c:1240) dev_kfree_skb_any_reason (net/core/dev.c:3470) ab_transmit (drivers/net/team/team_mode_activebackup.c:49) team_xmit (drivers/net/team/team_core.c:1849) __dev_direct_xmit (net/core/dev.c:4934) Freed by task 5040: __tcf_kfree_skb_list (net/sched/sch_generic.c:43) __dev_queue_xmit (net/core/dev.c:4831) team_xmit (drivers/net/team/team_core.c:1846) Kernel panic - not syncing: KASAN: panic_on_warn set ...
--- drivers/net/team/team_core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/net/team/team_core.c +8 -8
@@ -820,7 +820,8 @@ static struct list_head *__team_get_qom_/* * note: already called with rcu_read_lock */ -static bool team_queue_override_transmit (struct team *team,struct sk_buff *skb) +static bool team_queue_override_transmit (struct team *team,struct sk_buff *skb, +bool *tx_success) {struct list_head *qom_list;struct team_port *port;
@@ -828,11 +829,11 @@ static bool team_queue_override_transmitif (!team->queue_override_enabled || !skb->queue_mapping)return false; qom_list =__team_get_qom_list (team, skb->queue_mapping); -list_for_each_entry_rcu (port, qom_list, qom_list) { -if (!team_dev_queue_xmit (team, port, skb)) -return true; - } -return false; + port = list_first_or_null_rcu(qom_list, struct team_port, qom_list); +if (!port) +return false; + *tx_success = !team_dev_queue_xmit (team, port, skb); +return true; } static void __team_queue_override_port_del(struct team *team,
@@ -1864,8 +1865,7 @@ static netdev_tx_t team_xmit(struct sk_bbool tx_success;unsigned int len = skb->len; - tx_success =team_queue_override_transmit (team, skb); -if (!tx_success) +if (!team_queue_override_transmit (team, skb, &tx_success)) tx_success =READ_ONCE (team->ops.transmit)(team, skb);if (tx_success) {struct team_pcpu_stats *pcpu_stats;
Greg Kroah-Hartman
maintainerPATCH 90/281 net: team: free skb when broadcast has no txable port
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 489114c9ecae44e523361a4b3e610ee5ebd9189c upstream.
bc_transmit() sends the original skb through the last txable port. When no port is txable, it returns false without consuming the skb, but team_xmit() still returns NETDEV_TX_OK. AF_PACKET sends then retain the skb and its socket write-memory charge.
A TX-enabled, link-down port keeps the broadcast transmit op installed. Carrier can stay up through a second link-up, TX-disabled port or be forced on by userspace. Free the original skb on the no-port path while leaving the existing drop accounting intact.
Discovered by Sashiko during review of previous commit.
--- drivers/net/team/team_mode_broadcast.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/team/team_mode_broadcast.c +2 -0
@@ -37,6 +37,8 @@ static bool bc_transmit(struct team *tea ret = !team_dev_queue_xmit (team, last, skb);if (!sum_ret) sum_ret = ret; + }else { +dev_kfree_skb_any (skb); }return sum_ret; }
Greg Kroah-Hartman
maintainerPATCH 91/281 nvme: fix swapped ZRASF zone state values for full and read only
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Bonde Torp <[email protected]>
commit 564e46d9f6e87912effa03f123d37a511d520f09 upstream.
The Zone Management Receive command Zone Receive Action Specific (ZRASF) reporting option values for the Full and Read Only zone states are swapped compared to the NVM Express Zoned Namespace Command Set Specification, Revision 1.5, Figure 35:
- 5h lists the zones in the ZSF:Full state.
- 6h lists the zones in the ZSRO:Read Only state.
The nvmet ZNS backend uses these constants to map the ZRASF value received from the host to a block layer zone condition when filtering zones in Report Zones. Because of the swap, a host asking for full zones was given the read only zones, and a host asking for read only zones was given the full zones.
Swap the values of NVME_ZRASF_ZONE_STATE_FULL and NVME_ZRASF_ZONE_STATE_READONLY to match the specification.
--- include/linux/nvme.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/nvme.h +2 -2
@@ -1266,8 +1266,8 @@ enum {NVME_ZRASF_ZONE_STATE_IMP_OPEN =0x02 ,NVME_ZRASF_ZONE_STATE_EXP_OPEN =0x03 ,NVME_ZRASF_ZONE_STATE_CLOSED =0x04 , -NVME_ZRASF_ZONE_STATE_READONLY =0x05 , -NVME_ZRASF_ZONE_STATE_FULL =0x06 , +NVME_ZRASF_ZONE_STATE_FULL =0x05 , +NVME_ZRASF_ZONE_STATE_READONLY =0x06 ,NVME_ZRASF_ZONE_STATE_OFFLINE =0x07 , NVME_REPORT_ZONE_PARTIAL = 1, };
Greg Kroah-Hartman
maintainerPATCH 92/281 openvswitch: fix soft lockup in the netlink flow dump
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Denis V. Lunev <[email protected]>
commit aaaaf87ea99b8766c9a8aa0e71aa42e6bc8a5320 upstream.
A production compute node carrying a few thousand datapath flows hit a soft lockup inside a single netlink flow dump and panicked.
ovs_flow_cmd_dump() calls ovs_flow_stats_get() for every flow it emits, and that releases stats->lock with spin_unlock_bh() once per CPU that has touched the flow. Every release is a local_bh_enable(), and each one runs the pending softirq backlog in the dumping thread's own context.
The skb bounds the flows one callback emits, but not the softirq work it absorbs. On a CPU that carries the box's packet load the backlog refills as fast as it drains, so the dumping thread becomes that CPU's softirq engine. It never sleeps and it has no reschedule point, so under voluntary preemption nothing can take the CPU away from it:
neither the ksoftirqd the kernel woke to take the work over, nor the stopper thread the softlockup detector dispatches to refresh its timestamp.
Hold BH off across the whole callback instead, the way ctnetlink_dump_table() does, so the nested spin_unlock_bh() stop draining softirqs. The loop already runs under rcu_read_lock() and cannot sleep. What it gives up is preemption under CONFIG_PREEMPT, since a BH-off region is not preemptible outside PREEMPT_RT. The region stays short: the skb caps the flows one callback emits, and empty buckets cost no skb space but are each visited once per dump, as the cursor only moves forward. The table grows on insert and shrinks only on flush, so the walk is bounded by the largest flow count the datapath has held. The softirq backlog the callback used to absorb has no bound at all.
--- net/openvswitch/datapath.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/openvswitch/datapath.c +8 -0
@@ -1529,6 +1529,12 @@ static int ovs_flow_cmd_dump(struct sk_breturn -ENODEV ; } +/* +* Not needed for safety. Stops every spin_unlock_bh() in +* ovs_flow_stats_get() from running the softirq backlog. +*/ +local_bh_disable (); + ti =rcu_dereference (dp->table.ti);for (;;) {struct sw_flow *flow;
@@ -1549,6 +1555,8 @@ static int ovs_flow_cmd_dump(struct sk_b cb->args[0 ] = bucket; cb->args[1 ] = obj; } + +local_bh_enable ();rcu_read_unlock ();return skb->len; }
Greg Kroah-Hartman
maintainerPATCH 93/281 optee: register TEE devices only once fully initialized
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shao-Fu Chen <[email protected]>
commit c108feca0a096f8db25d1b69130035025e9e936d upstream.
optee_probe() called tee_device_register() on both the client and the supplicant device before the rest of struct optee had been initialized.
tee_device_register() calls cdev_device_add(), which does two things at
once: it creates /dev/tee0 and /dev/teepriv0, and it links the device into the tee class so that class_find_device() can find it. From that moment on the device is reachable both from user space via tee_open() and from kernel space via tee_client_open_context(). The only gate in teedev_open() is tee_device_get(), which merely checks that teedev->desc is non-NULL, which was already set by tee_device_alloc(). Therefore, there is effectively no gate at all.
A context opened in that window can run against a struct optee where
- optee->call_queue.mutex is not initialized by optee_cq_init()
- optee->supp mutex and completions is not initialized by optee_supp_init()
- optee->rpmb_dev_mutex is not initialized yet,
- the message argument cache is not initialized by optee_shm_arg_cache_init()
- optee->ctx is still NULL
Any open session or invoke during this window takes uninitialized mutexes and dereferences a NULL pointer.
Fix it by moving both tee_device_register() calls down to the point where all of struct optee is set up.
--- drivers/tee/optee/ffa_abi.c | 16 ++++++++-------- drivers/tee/optee/smc_abi.c | 17 ++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-)
drivers/tee/optee/ffa_abi.c +8 -8
@@ -1123,14 +1123,6 @@ static int optee_ffa_probe(struct ffa_deoptee_set_dev_group (optee); - rc =tee_device_register (optee->teedev); -if (rc) - goto err_unreg_supp_teedev; - - rc =tee_device_register (optee->supp_teedev); -if (rc) - goto err_unreg_supp_teedev; - rc =rhashtable_init (&optee->ffa.global_ids, &shm_rhash_params);if (rc) goto err_unreg_supp_teedev;
@@ -1159,6 +1151,14 @@ static int optee_ffa_probe(struct ffa_deif (optee_ffa_protmem_pool_init (optee, sec_caps))pr_info ("Protected memory service not available\n" ); + rc =tee_device_register (optee->teedev); +if (rc) + goto err_unregister_devices; + + rc =tee_device_register (optee->supp_teedev); +if (rc) + goto err_unregister_devices; + rc =optee_enumerate_devices (PTA_CMD_GET_DEVICES );if (rc) goto err_unregister_devices;
drivers/tee/optee/smc_abi.c +8 -9
@@ -1849,14 +1849,6 @@ static int optee_probe(struct platform_doptee_set_dev_group (optee); - rc =tee_device_register (optee->teedev); -if (rc) - goto err_unreg_supp_teedev; - - rc =tee_device_register (optee->supp_teedev); -if (rc) - goto err_unreg_supp_teedev; -optee_cq_init (&optee->call_queue, thread_count);optee_supp_init (&optee->supp); optee->smc.memremaped_shm = memremaped_shm;
@@ -1916,6 +1908,14 @@ static int optee_probe(struct platform_dif (optee->smc.sec_caps &OPTEE_SMC_SEC_CAP_DYNAMIC_SHM )pr_info ("dynamic shared memory is enabled\n" ); + rc =tee_device_register (optee->teedev); +if (rc) + goto err_disable_shm_cache; + + rc =tee_device_register (optee->supp_teedev); +if (rc) + goto err_disable_shm_cache; + rc =optee_enumerate_devices (PTA_CMD_GET_DEVICES );if (rc) goto err_disable_shm_cache;
@@ -1942,7 +1942,6 @@ err_supp_uninit:optee_shm_arg_cache_uninit (optee);optee_supp_uninit (&optee->supp);mutex_destroy (&optee->call_queue.mutex); -err_unreg_supp_teedev:tee_device_unregister (optee->supp_teedev); err_unreg_teedev:tee_device_unregister (optee->teedev);
Greg Kroah-Hartman
maintainerPATCH 94/281 power: sequencing: pcie-m2: Fix leaking array from of_regulator_bulk_get_all()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Charkov <[email protected]>
commit 0d6c5794fd633427f0d4ad8b51d94061295649da upstream.
of_regulator_bulk_get_all() allocates the consumers array and hands it to the caller, who is expected to free it at an appropriate time. pwrseq-pcie-m2.c never did, leading to a memory leak.
Add an explicit kfree() for the consumers array.
--- drivers/power/sequencing/pwrseq-pcie-m2.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/power/sequencing/pwrseq-pcie-m2.c +2 -0
@@ -562,6 +562,7 @@ err_destroy_mutex:mutex_destroy (&ctx->list_lock); err_free_regulators:regulator_bulk_free (ctx->num_vregs, ctx->regs); +kfree (ctx->regs);return ret; }
@@ -575,6 +576,7 @@ static void pwrseq_pcie_m2_remove(structmutex_destroy (&ctx->list_lock);regulator_bulk_free (ctx->num_vregs, ctx->regs); +kfree (ctx->regs); }static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
Greg Kroah-Hartman
maintainerPATCH 95/281 regulator: ltc3676: dont read the write-only HRST and CLIRQ registers
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abhishek Ojha <[email protected]>
commit 28c2388ee24cdbefbcc458fa41ef7bffaaa1cc83 upstream.
HRST (0x1e) and CLIRQ (0x1f) are write-only command strobes. Writing HRST triggers a hard reset of the chip and writing CLIRQ clears the interrupt; reading them returns nothing useful, and the read itself fires the command.
The result is that a plain register dump resets the board:
cat /sys/kernel/debug/regmap/2-003c/registers
walks every readable register, hits HRST, and the board reboots.
Split the callback back in two so HRST and CLIRQ stay writable but are no longer readable. The readable range is left unchanged (LTC3676_BUCK1 ... LTC3676_IRQSTAT).
--- drivers/regulator/ltc3676.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/regulator/ltc3676.c +12 -3
@@ -232,7 +232,7 @@ static const struct regulator_desc ltc36 LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2), }; -static bool ltc3676_readable_writeable_reg (struct device *dev,unsigned int reg) +static bool ltc3676_writeable_reg (struct device *dev,unsigned int reg) {switch (reg) { case LTC3676_BUCK1 ... LTC3676_IRQSTAT:
@@ -243,6 +243,15 @@ static bool ltc3676_readable_writeable_rreturn false; } +static bool ltc3676_readable_reg (struct device *dev,unsigned int reg) +{ +switch (reg) { + case LTC3676_BUCK1 ... LTC3676_IRQSTAT: +return true; + } +return false; +} +static bool ltc3676_volatile_reg (struct device *dev,unsigned int reg) {switch (reg) {
@@ -255,8 +264,8 @@ static bool ltc3676_volatile_reg(structstatic const struct regmap_config ltc3676_regmap_config = { .reg_bits =8 , .val_bits =8 , - .writeable_reg = ltc3676_readable_writeable_reg, - .readable_reg = ltc3676_readable_writeable_reg, + .writeable_reg = ltc3676_writeable_reg, + .readable_reg = ltc3676_readable_reg, .volatile_reg = ltc3676_volatile_reg, .max_register =LTC3676_CLIRQ , .use_single_read = true,
Greg Kroah-Hartman
maintainerPATCH 96/281 regulator: of: fill in supply names in of_regulator_bulk_get_all()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Charkov <[email protected]>
commit e2151c29cec73f6cc70abf1c7cbc7b9b202489f5 upstream.
of_regulator_bulk_get_all() returns an array it allocated itself, and fills in only the consumer of each entry. Every other way of getting a bulk array has the supply name set, because the caller provides it, and the core expects it to be there: regulator_bulk_enable() prints it when a supply fails to enable, so a caller that hands such an array to it dereferences uninitialised memory on that path.
Copy each name into the array's own allocation, right behind the entries, so that it shares the array's lifetime and callers still have nothing extra to free. That also retires the fixed 64 byte stack buffer the names were assembled in, which is_supply_name() never bounded the copy against.
--- drivers/regulator/of_regulator.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
drivers/regulator/of_regulator.c +17 -7
@@ -935,15 +935,15 @@ static int is_supply_name(const char *naint of_regulator_bulk_get_all (struct device *dev,struct device_node *np,struct regulator_bulk_data **consumers) { -int num_consumers =0 ; +int num_consumers =0 , names_len =0 ;struct regulator *tmp;struct regulator_bulk_data *_consumers =NULL ;struct property *prop; +char *names;int i, n =0 , ret; -char name[64 ];/* -* first pass: get numbers of xxx-supply +* first pass: get numbers of xxx-supply and the room their names take * second pass: fill consumers */ restart:
@@ -953,16 +953,19 @@ restart:continue ;if (!_consumers) { num_consumers++; + names_len += i +1 ;continue ; }else { -memcpy (name, prop->name, i); - name[i] ='\0' ; - tmp =regulator_get (dev, name); +memcpy (names, prop->name, i); + names[i] ='\0' ; + tmp =regulator_get (dev, names);if (IS_ERR (tmp)) { ret =PTR_ERR (tmp); goto error; } + _consumers[n].supply = names; _consumers[n].consumer = tmp; + names += i +1 ; n++;continue ; }
@@ -973,9 +976,16 @@ restart: }if (num_consumers ==0 )return 0 ; - _consumers = kmalloc_objs(struct regulator_bulk_data, num_consumers); +/* +* The supply names are kept in the same allocation as the array, so +* that they share its lifetime and the caller has nothing extra to +* free. +*/ + _consumers =kzalloc (size_add (size_mul (num_consumers,sizeof (*_consumers)), + names_len),GFP_KERNEL );if (!_consumers)return -ENOMEM ; + names = (char *)(_consumers + num_consumers); goto restart; error:
Greg Kroah-Hartman
maintainerPATCH 97/281 regulator: tps6594-regulator: Fix n_linear_ranges for TPS65224 BUCK2-4
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ridham Khurana <[email protected]>
commit 2f15518682c779b1014552cb2ccb4a2052f85f27 upstream.
The TPS65224 BUCK2, BUCK3 and BUCK4 descriptors pass 4 as n_linear_ranges, but tps65224_bucks_2_3_4_ranges[] only has two entries, covering selectors 0x00-0x45.
The linear range helpers loop over n_linear_ranges entries, so any lookup of a selector above 0x45 reads past the end of the array and treats whatever follows it as two more ranges. This happens on the normal registration path when the core checks the voltage constraints against every selector. TPS652G1 uses the same descriptors and is affected too.
Use ARRAY_SIZE() so the count always matches the table.
--- drivers/regulator/tps6594-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/regulator/tps6594-regulator.c +3 -3
@@ -241,21 +241,21 @@ static const struct regulator_desc tps65 TPS65224_MASK_BUCKS_VSET, TPS6594_REG_BUCKX_CTRL(1), TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, - 4, 0, 0, NULL, 0, 0), + ARRAY_SIZE(tps65224_bucks_2_3_4_ranges), 0, 0, NULL, 0, 0),TPS6594_REGULATOR ("BUCK3" ,"buck3" ,TPS6594_BUCK_3 ,REGULATOR_VOLTAGE , tps6594_bucks_ops,TPS65224_MASK_BUCKS_VSET ,TPS6594_REG_BUCKX_VOUT_1 (2 ),TPS65224_MASK_BUCKS_VSET ,TPS6594_REG_BUCKX_CTRL (2 ),TPS6594_BIT_BUCK_EN ,0 ,0 , tps65224_bucks_2_3_4_ranges, -4 ,0 ,0 ,NULL ,0 ,0 ), +ARRAY_SIZE (tps65224_bucks_2_3_4_ranges),0 ,0 ,NULL ,0 ,0 ),TPS6594_REGULATOR ("BUCK4" ,"buck4" ,TPS6594_BUCK_4 ,REGULATOR_VOLTAGE , tps6594_bucks_ops,TPS65224_MASK_BUCKS_VSET ,TPS6594_REG_BUCKX_VOUT_1 (3 ),TPS65224_MASK_BUCKS_VSET ,TPS6594_REG_BUCKX_CTRL (3 ),TPS6594_BIT_BUCK_EN ,0 ,0 , tps65224_bucks_2_3_4_ranges, - 4, 0, 0, NULL, 0, 0), + ARRAY_SIZE(tps65224_bucks_2_3_4_ranges), 0, 0, NULL, 0, 0), }; static const struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
Greg Kroah-Hartman
maintainerPATCH 98/281 pmdomain: imx8m-blk-ctrl: Serialize power on/off across sibling domains
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <[email protected]>
commit 51c2db3ef0cb89a49ab7f47a40efd5d5b074ce8d upstream.
On i.MX8MP the VPU blk-ctrl exposes G1, G2 and VC8000E as three separate genpds, each serialized only by its own genpd lock, so their power_on and power_off callbacks can run concurrently on SMP.
The sequences are not independent: they share the VPUMIX bus domain, the VPU_NOC and the ADB400 handshake. On power up the GPC cannot ack-verify the ADB400 handshake - the ack only completes once blk-ctrl sets the bus clk-en bit - so it just waits a fixed delay instead of polling hskack. A sibling transition landing inside another domain's reset window disturbs that shared clock and handshake timing, the victim's reset does not take effect, and its block registers read back all zeros: the decoder times out or the encoder fails its format check.
Serialize the blk-ctrl reset sequence with a per-blk-ctrl mutex; the driver deliberately avoids a genpd hierarchy, so the genpd core gives no cross-sibling serialization.
--- drivers/pmdomain/imx/imx8m-blk-ctrl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/pmdomain/imx/imx8m-blk-ctrl.c +15 -0
@@ -15,6 +15,7 @@#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/mutex.h> #include <dt-bindings/power/imx8mm-power.h> #include <dt-bindings/power/imx8mn-power.h>
@@ -34,6 +35,12 @@ struct imx8m_blk_ctrl {struct regmap *regmap;struct imx8m_blk_ctrl_domain *domains;struct genpd_onecell_data onecell_data; +/* +* Serializes the blk-ctrl reset/clock sequence across sibling domains; +* their transitions interact through the shared VPUMIX bus domain, +* VPU_NOC and the not-ack-verified ADB400 handshake (ERR050531). +*/ +struct mutex power_lock; };struct imx8m_blk_ctrl_domain_data {
@@ -98,6 +105,8 @@ static int imx8m_blk_ctrl_power_on(strucstruct imx8m_blk_ctrl *bc = domain->bc;int ret; +guard (mutex)(&bc->power_lock); +/* make sure bus domain is awake */ ret =pm_runtime_get_sync (bc->bus_power_dev);if (ret <0 ) {
@@ -164,6 +173,8 @@ static int imx8m_blk_ctrl_power_off(struconst struct imx8m_blk_ctrl_domain_data *data = domain->data;struct imx8m_blk_ctrl *bc = domain->bc; +guard (mutex)(&bc->power_lock); +/* put devices into reset and disable clocks */ if (data->mipi_phy_rst_mask)regmap_clear_bits (bc->regmap,BLK_MIPI_RESET_DIV , data->mipi_phy_rst_mask);
@@ -202,6 +213,10 @@ static int imx8m_blk_ctrl_probe(struct p bc->dev = dev; + ret =devm_mutex_init (dev, &bc->power_lock); +if (ret) +return ret; + bc_data =of_device_get_match_data (dev); base =devm_platform_ioremap_resource (pdev,0 );
Greg Kroah-Hartman
maintainerPATCH 99/281 pmdomain: rockchip: dont ignore clock lookup errors on attach
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shawn Lin <[email protected]>
commit 4c66c423593e26273ea0d644906ed007630c6f6d upstream.
rockchip_pd_attach_dev() treated every of_clk_get() error as the end of the clock list, so a clock that exists but is not available yet (e.g. -EPROBE_DEFER) was silently skipped and the device ended up without pm_clk management. Only -ENOENT means there are no more clocks.
--- drivers/pmdomain/rockchip/pm-domains.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/pmdomain/rockchip/pm-domains.c +13 -1
@@ -745,7 +745,19 @@ static int rockchip_pd_attach_dev(struct } i =0 ; -while ((clk =of_clk_get (dev->of_node, i++)) && !IS_ERR (clk)) { +while (1 ) { + clk =of_clk_get (dev->of_node, i++); +if (IS_ERR (clk)) { + error =PTR_ERR (clk); +if (error == -ENOENT ) +break ; + +dev_err (dev,"failed to get clock %d: %d\n" , i -1 , + error); +pm_clk_destroy (dev); +return error; + } +dev_dbg (dev,"adding clock '%pC' to list of PM clocks\n" , clk); error =pm_clk_add_clk (dev, clk);if (error) {
Greg Kroah-Hartman
maintainerPATCH 100/281 pmdomain: rockchip: fix clock leak on domain probe failure
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shawn Lin <[email protected]>
commit d8b3847770661b7109146e6479eeadcdab9cecf0 upstream.
When of_clk_get() failed in the middle of the loop, the references of the clocks acquired so far were leaked instead of being released by the error path.
--- drivers/pmdomain/rockchip/pm-domains.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pmdomain/rockchip/pm-domains.c +1 -1
@@ -840,7 +840,7 @@ static int rockchip_pm_add_one_domain(stdev_err (pmu->dev,"%pOFn: failed to get clk at index %d: %d\n" , node, i, error); -return error; + goto err_put_clocks; } }
Greg Kroah-Hartman
maintainerPATCH 101/281 pmdomain: rockchip: propagate subdomain add errors
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shawn Lin <[email protected]>
commit 4c0d69d677cf5b0065ebbb3ceb8ba66fddbec630 upstream.
rockchip_pm_add_subdomain() ignored the return value of its recursive call, so a failure deeper in the hierarchy was silently dropped and probe still succeeded with an incomplete domain tree.
--- drivers/pmdomain/rockchip/pm-domains.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/pmdomain/rockchip/pm-domains.c +3 -1
@@ -1016,7 +1016,9 @@ static int rockchip_pm_add_subdomain(str parent_domain->name, child_domain->name); } -rockchip_pm_add_subdomain (pmu, np); + error =rockchip_pm_add_subdomain (pmu, np); +if (error) +return error; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 102/281 scsi: ch: Do not keep references to data transfer element devices
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmed Abdelhaleem Ahmed <[email protected]>
commit 27c0f718d3b3c99e6d315308e95d987d0382a8a8 upstream.
ch_readconfig() looks up the scsi_device of every data transfer element whose SCSI id the changer reports in READ ELEMENT STATUS, and stores it in ch->dt[]. scsi_device_lookup() takes a reference, and nothing ever drops
it: ch_destroy() frees the array with kfree(). ch->dt[] is read nowhere else - it only supplies the vendor, model and revision printed in the same loop.
Once such a drive is removed, its scsi_device can never be released. It stays on the host's device list at its address, so a new device there is refused by anything that walks the list - target_core_pscsi reports "scsi_device_get() failed for H:C:T:L" - and the low-level driver's module can no longer be unloaded. Only a reboot recovers.
It shows with any changer that reports its drives' ids; with the mhvtl virtual library (IBM 3573-TL personality), each create and remove of a library with four drives leaves four references behind, counted by the module's use count in lsmod. With ch not bound the count is unchanged, and with this patch applied it is unchanged too.
Drop the reference as soon as the name has been printed, and remove the now unused dt[] array. That also removes the array leaked when ch_probe() fails after ch_readconfig().
The same leak was reported with an RFC patch in 2022, which was not merged.
--- drivers/scsi/ch.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-)
drivers/scsi/ch.c +9 -20
@@ -112,7 +112,6 @@ typedef struct {int minor;char name[8 ];struct scsi_device *device; -struct scsi_device **dt;/* ptrs to data transfer elements */ u_int firsts[CH_TYPES ];u_int counts[CH_TYPES ];u_int voltags;
@@ -363,15 +362,10 @@ ch_readconfig(scsi_changer *ch) vendor_labels[i]); } -/* look up the devices of the data transfer elements */ - ch->dt =kzalloc_objs (*ch->dt, ch->counts[CHET_DT ]); - -if (!ch->dt) { -kfree (buffer); -return -ENOMEM ; - } - +/* report the devices of the data transfer elements */ for (elem =0 ; elem < ch->counts[CHET_DT ]; elem++) { +struct scsi_device *sdev; + id =-1 ; lun =0 ;if (elem <CH_DT_MAX &&-1 != dt_id[elem]) {
@@ -387,10 +381,8 @@ ch_readconfig(scsi_changer *ch)VPRINTK (KERN_INFO ,"dt 0x%x: " ,elem+ch->firsts[CHET_DT ]);if (data[6 ] &0x80 ) {VPRINTK (KERN_CONT ,"not this SCSI bus\n" ); - ch->dt[elem] =NULL ; }else if (0 == (data[6 ] &0x30 )) {VPRINTK (KERN_CONT ,"ID/LUN unknown\n" ); - ch->dt[elem] =NULL ; }else { id = ch->device->id; lun =0 ;
@@ -400,18 +392,16 @@ ch_readconfig(scsi_changer *ch) }if (-1 != id) {VPRINTK (KERN_CONT ,"ID %i, LUN %i, " ,id,lun); - ch->dt[elem] = -scsi_device_lookup (ch->device->host, - ch->device->channel, - id,lun); -if (!ch->dt[elem]) { + sdev =scsi_device_lookup (ch->device->host, + ch->device->channel, + id, lun); +if (!sdev) {/* should not happen */ VPRINTK (KERN_CONT ,"Huh? device not found!\n" ); }else {VPRINTK (KERN_CONT ,"name: %8.8s %16.16s %4.4s\n" , - ch->dt[elem]->vendor, - ch->dt[elem]->model, - ch->dt[elem]->rev); + sdev->vendor, sdev->model, sdev->rev); +scsi_device_put (sdev); } } }
@@ -575,7 +565,6 @@ static void ch_destroy(struct kref *ref)scsi_changer *ch =container_of (ref, scsi_changer, ref); ch->device =NULL ; -kfree (ch->dt);kfree (ch); }
Greg Kroah-Hartman
maintainerPATCH 103/281 scsi: qedi: Initialize callback state before registration
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 85de8b3a5eaa23d153aff4c7c83dddbc949064c9 upstream.
qedi_get_protocol_tlv_data() can be called asynchronously by QED after qedi_ops->register_ops(). It takes stats_lock and reads ll2_mtu, but __qedi_probe() currently registers the callback before initializing the mutex and assigning the default MTU on the normal probe path.
Initialize the callback-visible state before registering qedi_cb_ops. Keep the recovery path from reinitializing state because it reuses the existing qedi context.
--- drivers/scsi/qedi/qedi_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/scsi/qedi/qedi_main.c +1 -2
@@ -2652,8 +2652,6 @@ retry_probe:snprintf (host_buf,sizeof (host_buf),"host_%d" , qedi->shost->host_no); qedi_ops->common->set_name (qedi->cdev, host_buf); - qedi_ops->register_ops (qedi->cdev, &qedi_cb_ops, qedi); -memset (¶ms,0 ,sizeof (params)); params.mtu =DEF_PATH_MTU +IPV6_HDR_LEN +TCP_HDR_LEN ; qedi->ll2_mtu =DEF_PATH_MTU ;
@@ -2670,6 +2668,7 @@ retry_probe:spin_lock_init (&qedi->task_idx_lock);mutex_init (&qedi->stats_lock); } + qedi_ops->register_ops (qedi->cdev, &qedi_cb_ops, qedi); qedi_ops->ll2->register_cb_ops (qedi->cdev, &qedi_ll2_cb_ops, qedi); qedi_ops->ll2->start (qedi->cdev, ¶ms);
Greg Kroah-Hartman
maintainerPATCH 104/281 scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Jhu <[email protected]>
commit 375f3a5691dd46b5d05b90a8968872ec8b2248c5 upstream.
During MCQ host reset, ufshcd_host_reset_and_restore() stops the host controller via ufshcd_hba_stop() (HCE = 0) before calling ufshcd_complete_requests(hba, true) -> ufshcd_mcq_compl_pending_transfer(hba, true) -> ufshcd_mcq_force_compl_one() -> ufshcd_mcq_compl_all_cqes_lock(). Because ufshcd_mcq_force_compl_one() is its sole caller, ufshcd_mcq_compl_all_cqes_lock() always runs with HCE = 0.
Despite the comment above ufshcd_mcq_compl_all_cqes_lock() stating that reading CQTPy may not be safe with the controller disabled, the function still calls ufshcd_mcq_update_cq_tail_slot() at the end of its sweep:
1. Unsafe CQTPy MMIO read:
Calling ufshcd_mcq_update_cq_tail_slot() at the end of the sweep reads CQTPy over MMIO while HCE = 0, directly contradicting the function's documented contract (commit 1373df88d535 ("scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock()")) that reading CQTPy may not be safe with the controller disabled.
2. Spurious error logs on empty slots:
Sweeping all max_entries slots visits empty entries where command_desc_base_addr is 0, causing ufshcd_mcq_process_cqe() to log unguarded dev_err(hba->dev, "Abnormal CQ entry!\n") messages.
Fix both issues in ufshcd_mcq_compl_all_cqes_lock():
- Remove the ufshcd_mcq_update_cq_tail_slot() call and the redundant hwq->cq_head_slot = hwq->cq_tail_slot assignment without replacement. The two indices are already equal after the sweep: they are equal when the sweep starts, since ufshcd_mcq_poll_cqe_lock() consumes entries until cq_head_slot reaches cq_tail_slot, and the sweep advances cq_head_slot by exactly one full ring. Both indices are also reinitialized before the queue is reused.
- Extract ufshcd_mcq_compl_cqe() and invoke it only on non-empty slots during full-ring sweeps, keeping "Abnormal CQ entry!" logging strictly for unexpected empty entries in ufshcd_mcq_poll_cqe_lock().
--- drivers/ufs/core/ufs-mcq.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-)
drivers/ufs/core/ufs-mcq.c +17 -13
@@ -306,20 +306,24 @@ static int ufshcd_mcq_get_tag(struct ufsreturn div_u64 (addr,ufshcd_get_ucd_size (hba)); } +static void ufshcd_mcq_compl_cqe (struct ufs_hba *hba,struct cq_entry *cqe) +{ +int tag =ufshcd_mcq_get_tag (hba, cqe); + +ufshcd_compl_one_cqe (hba, tag, cqe); +/* After processing the CQE, mark it as an empty (invalid) entry. */ + cqe->command_desc_base_addr =0 ; +} +static void ufshcd_mcq_process_cqe (struct ufs_hba *hba,struct ufs_hw_queue *hwq) {struct cq_entry *cqe =ufshcd_mcq_cur_cqe (hwq); -if (cqe->command_desc_base_addr) { -int tag =ufshcd_mcq_get_tag (hba, cqe); - -ufshcd_compl_one_cqe (hba, tag, cqe); -/* After processed the cqe, mark it empty (invalid) entry */ - cqe->command_desc_base_addr =0 ; - }else { +if (cqe->command_desc_base_addr) +ufshcd_mcq_compl_cqe (hba, cqe); +else dev_err (hba->dev,"Abnormal CQ entry!\n" ); - } }/*
@@ -327,7 +331,7 @@ static void ufshcd_mcq_process_cqe(struc* controller disabled (HCE = 0). Reading host controller registers, e.g. the * CQ tail pointer (CQTPy), may not be safe with the host controller disabled. * Hence, iterate over all completion queue entries. This won't result in -* double completions because ufshcd_mcq_process_cqe() clears a CQE after it +* double completions because ufshcd_mcq_compl_cqe() clears a CQE after it * has been processed. */ void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
@@ -338,13 +342,13 @@ void ufshcd_mcq_compl_all_cqes_lock(struspin_lock_irqsave (&hwq->cq_lock, flags);while (entries >0 ) { -ufshcd_mcq_process_cqe (hba, hwq); +struct cq_entry *cqe =ufshcd_mcq_cur_cqe (hwq); + +if (cqe->command_desc_base_addr) +ufshcd_mcq_compl_cqe (hba, cqe);ufshcd_mcq_inc_cq_head_slot (hwq); entries--; } - -ufshcd_mcq_update_cq_tail_slot (hwq); - hwq->cq_head_slot = hwq->cq_tail_slot;spin_unlock_irqrestore (&hwq->cq_lock, flags); }
Greg Kroah-Hartman
maintainerPATCH 105/281 scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Jhu <[email protected]>
commit 469fa055664bfd8717b087a80d59c03055789c17 upstream.
In MCQ mode, ufshcd_mcq_compl_pending_transfer() uses blk_mq_tagset_busy_iter() to iterate over busy requests during error recovery and host reset. However, both iterator callbacks perform whole-queue operations redundantly for each visited request:
- force_compl == true: ufshcd_mcq_force_compl_one() calls ufshcd_mcq_compl_all_cqes_lock() on every busy request, sweeping the entire completion ring (hwq->max_entries slots) once per active request under spin_lock_irqsave even though the first sweep already cleared all completion entries.
- force_compl == false: ufshcd_mcq_compl_one() acquires cq_lock and polls CQTPy over MMIO via ufshcd_mcq_poll_cqe_lock() for every busy request without doing any per-request work.
Sweep or poll each hardware queue (hba->uhq[i]) once at the start of ufshcd_mcq_compl_pending_transfer(). When force_compl is true, run blk_mq_tagset_busy_iter() afterward to complete residual in-flight requests with DID_REQUEUE, and remove the now-unused ufshcd_mcq_compl_one() callback.
--- drivers/ufs/core/ufshcd.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-)
drivers/ufs/core/ufshcd.c +12 -19
@@ -5975,8 +5975,6 @@ static bool ufshcd_mcq_force_compl_one(sif (blk_mq_is_reserved_rq (rq) || !hwq)return true; -ufshcd_mcq_compl_all_cqes_lock (hba, hwq); -/* * For those cmds of which the cqes are not present in the cq, complete * them explicitly.
@@ -5992,19 +5990,6 @@ static bool ufshcd_mcq_force_compl_one(sreturn true; } -static bool ufshcd_mcq_compl_one (struct request *rq,void *priv) -{ -struct scsi_device *sdev = rq->q->queuedata; -struct Scsi_Host *shost = sdev->host; -struct ufs_hba *hba =shost_priv (shost); -struct ufs_hw_queue *hwq =ufshcd_mcq_req_to_hwq (hba, rq); - -if (!blk_mq_is_reserved_rq (rq) && hwq) -ufshcd_mcq_poll_cqe_lock (hba, hwq); - -return true; -} -/** * ufshcd_mcq_compl_pending_transfer - MCQ mode function. It is * invoked from the error handler context or ufshcd_host_reset_and_restore()
@@ -6019,10 +6004,18 @@ static bool ufshcd_mcq_compl_one(structstatic void ufshcd_mcq_compl_pending_transfer (struct ufs_hba *hba,bool force_compl) { -blk_mq_tagset_busy_iter (&hba->host->tag_set, - force_compl ? ufshcd_mcq_force_compl_one : - ufshcd_mcq_compl_one, -NULL ); +int i; + +for (i =0 ; i < hba->nr_hw_queues; i++) { +if (force_compl) +ufshcd_mcq_compl_all_cqes_lock (hba, &hba->uhq[i]); +else +ufshcd_mcq_poll_cqe_lock (hba, &hba->uhq[i]); + } + +if (force_compl) +blk_mq_tagset_busy_iter (&hba->host->tag_set, + ufshcd_mcq_force_compl_one,NULL ); }/**
Greg Kroah-Hartman
maintainerPATCH 106/281 riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ziyi Guo <[email protected]>
commit 4d0697f192975dab5985e921989be1d85cf580e9 upstream.
Under CONFIG_SHADOW_CALL_STACK, handle_exception() reloads the kernel shadow call stack pointer (gp) only when the trap came from userspace. It made that decision with scs_load_current_if_task_changed, which compares the trap-time tp (read back from sscratch into s5) against the current tp:
beq \prev, tp, _skip_scs
scs_load_current_skip_scs:
tp is a user-writable register. A user task that sets tp to the linear-map address of its own task_struct (¤t) before trapping makes the comparison succeed (can achieve by brute force with KASLR enable under our test), so the kernel skips scs_load_current and keeps running with the gp that userspace left in place. Under CONFIG_SHADOW_CALL_STACK gp is the shadow call stack pointer and load_global_pointer is a no-op, so the compiler-emitted
"sd ra, -8(gp)" / "ld ra, -8(gp)" in every non-leaf function then write to, and return through, an attacker-controlled address -- an unprivileged kernel arbitrary-write and control-flow-hijack primitive. The poisoned gp is saved to task_struct.scs_sp on return, so the reload is skipped on every subsequent entry as well.
Decide "came from userspace" from the hardware sstatus.SPP bit (already in s1 at this point) instead of from tp, mirroring the check that ret_from_exception already uses a few instructions later. SPP is written by hardware on trap entry and cannot be forged from U-mode. Legitimate behaviour is unchanged: user entries (SPP=0) reload the task shadow call stack, nested kernel entries (SPP=1) skip it.
--- arch/riscv/include/asm/scs.h | 17 +++++++++++++---- arch/riscv/kernel/entry.S | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-)
arch/riscv/include/asm/scs.h +13 -4
@@ -4,6 +4,7 @@#ifdef __ASSEMBLER__#include <asm/asm-offsets.h> +#include <asm/csr.h> #ifdef CONFIG_SHADOW_CALL_STACK
@@ -22,9 +23,17 @@ REG_L gp, TASK_TI_SCS_SP(tp) .endm -/* Load task_scs_sp(current) to gp, but only if tp has changed. */ -.macro scs_load_current_if_task_changed prev - beq \prev, tp, _skip_scs +/* + * Load task_scs_sp(current) to gp, but only when the trap came from U-mode. + * The source privilege level is taken from the saved sstatus.SPP bit (written + * by hardware on trap entry), not by comparing tp. tp is a user-writable + * register, so gating the shadow call stack reload on it let a user task that + * set tp == ¤t skip the reload and run the kernel with an attacker + * controlled gp (the shadow call stack pointer). + */ +.macro scs_load_current_if_from_user status, tmp + andi \tmp, \status, SR_SPP + bnez \tmp, _skip_scs scs_load_current _skip_scs: .endm
@@ -42,7 +51,7 @@ _skip_scs: .endm .macro scs_load_current .endm -.macro scs_load_current_if_task_changed prev +.macro scs_load_current_if_from_user status, tmp .endm .macro scs_save_current .endm
arch/riscv/kernel/entry.S +1 -1
@@ -208,7 +208,7 @@ SYM_CODE_START(handle_exception) load_global_pointer /* Load the kernel shadow call stack pointer if coming from userspace */ - scs_load_current_if_task_changed s5 + scs_load_current_if_from_user s1, s5 #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE move a0, sp
Greg Kroah-Hartman
maintainerPATCH 107/281 riscv: errata: select RISCV_ALTERNATIVE_EARLY for THEAD GHOSTWRITE
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zongmin Zhou <[email protected]>
commit 298510bbc7c3017c0faf481c6ea66f1065b657b4 upstream.
errata_probe_ghostwrite() only marks the CPU as vulnerable when it is called at the RISCV_ALTERNATIVES_EARLY_BOOT stage, and the mitigation in ghostwrite_enable_mitigation() only takes effect if the vulnerable state was recorded before the boot alternatives are patched.
The early boot stage is only executed when CONFIG_RISCV_ALTERNATIVE_EARLY is enabled, which currently is only selected by ERRATA_THEAD_MAE. In a kernel built with ERRATA_THEAD_GHOSTWRITE=y but ERRATA_THEAD_MAE=n, the early alternatives never run, so ghostwrite_state is never set to
VULNERABLE: ghostwrite_enable_mitigation() returns false, xtheadvector remains enabled, and sysfs reports "Not affected" on a vulnerable T-Head C9xx CPU.
Select RISCV_ALTERNATIVE_EARLY from ERRATA_THEAD_GHOSTWRITE so that the vulnerability is detected in the early boot stage and the default mitigation is applied.
--- arch/riscv/Kconfig.errata | 1 + 1 file changed, 1 insertion(+)
arch/riscv/Kconfig.errata +1 -0
@@ -146,6 +146,7 @@ config ERRATA_THEAD_PMU config ERRATA_THEAD_GHOSTWRITE bool "Apply T-Head Ghostwrite errata" depends on ERRATA_THEAD && RISCV_ISA_XTHEADVECTOR + select RISCV_ALTERNATIVE_EARLY default y help The T-Head C9xx cores have a vulnerability in the xtheadvector
Greg Kroah-Hartman
maintainerPATCH 108/281 riscv: fix load_unaligned_zeropad() fixup for RV32
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit d4f25b097e46d82718bb737d4540c99b7ab0a408 upstream.
The fixup for load_unaligned_zeropad() runs when REG_L crosses into an unmapped page. REG_L is lw on RV32 and ld on RV64, but the fixup assumes an 8-byte load: it rounds the address down to 8 bytes and derives the shift from three address bits.
On RV32, a load starting in the last three bytes of a mapped page selects the word four bytes earlier and shifts it by 40, 48, or 56 bits, more than the register width. The caller gets earlier bytes instead of the string tail followed by zeroes. This affects RV32 MMU kernels built with RISCV_EFFICIENT_UNALIGNED_ACCESS=y, which selects DCACHE_WORD_ACCESS and lets dcache name hashing and comparison and strscpy() use this path.
Derive the alignment and offset masks from sizeof(data) instead of a fixed
8. This makes RV32 use the correct source word. RV64 code is unchanged: the complete extable.o is byte-for-byte identical before and after.
--- arch/riscv/mm/extable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/mm/extable.c +2 -2
@@ -68,8 +68,8 @@ ex_handler_load_unaligned_zeropad(const addr =regs_get_gpr (regs, reg_addr *sizeof (unsigned long )); - offset = addr &0x7UL ; - addr &= ~0x7UL ; + offset = addr & (sizeof (data) -1 ); + addr &= ~(sizeof (data) -1 ); data = *(unsigned long *)addr >> (offset *8 );
Greg Kroah-Hartman
maintainerPATCH 109/281 riscv: futex: untag the user pointer before the atomic access
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ziyi Guo <[email protected]>
commit 405290be962b32eec842776fbe3bdf81f15b1676 upstream.
access_ok() checks untagged_addr(uaddr), but arch_futex_atomic_op_inuser() and futex_atomic_cmpxchg_inatomic() hand the raw uaddr to the inline asm amoswap/amoadd/.../lr.w+sc.w through the "+m" (*uaddr) operand. When the tagged address ABI is enabled (CONFIG_RISCV_ISA_SUPM, prctl PR_SET_TAGGED_ADDR_CTRL with PMLEN != 0), those two addresses differ: a user pointer whose top PMLEN bits hold a tag passes access_ok() after untagging, but the atomic is then performed on the still-tagged raw address.
Supervisor-mode data accesses are not subject to the U-mode pointer masking (that is governed by menvcfg.PMM, which the kernel does not set), so hardware does not strip the tag for the kernel's own access. With Sv57 and PMLEN=16 the tag bits overlap the canonical-address bits, so a tagged pointer can name a canonical kernel virtual address (e.g. in the linear map) whose untagged form is a valid user address. An unprivileged process can thus make FUTEX_WAKE_OP perform an atomic read-modify-write on an arbitrary kernel address, with the matching FUTEX_OP_CMP_* result serving as a read oracle.
get_user()/put_user()/raw_copy_{to,from}_user() already untag the pointer after the access_ok() check; do the same in the futex helpers so the atomic operates on the address that was actually validated.
--- arch/riscv/include/asm/futex.h | 2 ++ 1 file changed, 2 insertions(+)
arch/riscv/include/asm/futex.h +2 -0
@@ -40,6 +40,7 @@ arch_futex_atomic_op_inuser(int op, intif (!access_ok (uaddr,sizeof (u32)))return -EFAULT ; + uaddr =untagged_addr (uaddr);switch (op) {case FUTEX_OP_SET :
@@ -82,6 +83,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,if (!access_ok (uaddr,sizeof (u32)))return -EFAULT ; + uaddr =untagged_addr (uaddr);__enable_user_access (); __asm__ __volatile__ (
Greg Kroah-Hartman
maintainerPATCH 110/281 riscv: hwprobe: use _BITULL() rather than BIT() in MIPS vendor uapi header
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zongmin Zhou <[email protected]>
commit edba6017c19f97ecc718fad6b50e0908392247ac upstream.
BIT() is a kernel-internal macro that is not available to userspace, but the MIPS vendor extension uapi header uses it without defining or including it. Any userspace program that includes this header and uses RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL fails to build.
Use _BITULL(0) from linux/const.h instead, which keeps the value at 1, so there is no ABI change.
--- arch/riscv/include/uapi/asm/vendor/mips.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/riscv/include/uapi/asm/vendor/mips.h +3 -1
@@ -1,3 +1,5 @@/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#define RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL BIT(0) +#include <linux/const.h> + +#define RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL _BITULL(0)
Greg Kroah-Hartman
maintainerPATCH 111/281 riscv: lib: Fix ZBB strnlen wrap-around regression on huge counts
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shao Mingyin <[email protected]>
commit 282f4a8aa95c5a01b96e55eb5da297560e5f2986 upstream.
The aligned scan boundary is derived from the last valid byte, (s + count - 1). When count is huge (e.g. SIZE_MAX, which FORTIFY strcat/strlcat pass when the destination size is not known at compile time), s + count wraps around and the boundary lands before s, so the ZBB path returns a bogus length. The original implementation (5ba15d419fab) had the same wrap-around in its (s + count) & ~7 boundary computation; after 5d588c684833 the wrapped boundary is caught by the pre-loop guard "bgeu t0, t4, 2f", which then always exits for aligned strings of 8 or more characters and strnlen() returns 8 instead of the real length.
This silently truncates strings built by fortified strcat: the dm sysfs name attribute shows "live-bas" instead of "live-base", the truncated name pollutes the udev database, and blivet/anaconda (as well as LVM/dm-crypt/multipath userspace) break on RISC-V systems.
Detect the wrap-around and saturate the boundary to the top of the address space, making the scan equivalent to strlen(). The saturation clamps the increment to ~s, so it stays branchless and wrap-free:
s + min(count - 1, ~s) == saturating_add(s, count - 1)
Normal counts are unaffected.
--- arch/riscv/lib/strnlen.S | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
arch/riscv/lib/strnlen.S +18 -2
@@ -87,9 +87,25 @@ strnlen_zbb: * Aligned boundary. Use the address of the last valid byte * (s + count - 1) to avoid loading a word past the count * boundary in the loop below. count == 0 is handled above. + * + * Saturate the boundary when s + count would wrap around (very + * large counts, e.g. SIZE_MAX passed by FORTIFY strcat/strlcat + * with a destination whose size is unknown at compile time). + * Without this, the wrapped boundary lands before s and the + * pre-loop guard below always exits, returning a truncated + * length. + * + * Clamping the increment to ~s (== SIZE_MAX - s) keeps the + * computation branchless and wrap-free: + * + * s + min(count - 1, ~s) == saturating_add(s, count - 1) + * + * Saturating makes the scan equivalent to strlen(). */ - add t4, a0, a1 - addi t4, t4, -1 + addi t4, a1, -1 /* count - 1 */ + not t1, a0 /* SIZE_MAX - s */ + minu t4, t4, t1 /* clamp, so s + t4 can never wrap */ + add t4, a0, t4 /* saturated s + count - 1 */ andi t4, t4, -SZREG /* Get the first word. */
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerPATCH 112/281 riscv: patch: fix handling of bpf-jit execmem addresses
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei-Jie Hung <[email protected]>
commit a510e1ae8c9030750c2edf7b0bc9b186cd8c7a06 upstream.
Commit 8718e5a3090b ("riscv: patch: skip fixmap mapping when kernel text is already writable") gated the core_kernel_text() branch of patch_map() on CONFIG_STRICT_KERNEL_RWX, and explicitly left the vmalloc branch unchanged. That branch has a separate problem.
That branch only creates a temporary writable fixmap alias when CONFIG_STRICT_MODULE_RWX is enabled, and otherwise assumes the target is directly writable and returns the address unchanged. That assumption no longer holds: bpf_prog_pack_alloc calls set_memory_rox() on every pack unconditionally in alloc_new_pack(), independently of any CONFIG_STRICT_*_RWX option, so BPF text in the vmalloc area is read-only regardless of what CONFIG_STRICT_MODULE_RWX says.
With CONFIG_STRICT_MODULE_RWX=n, patch_map() returns the read-only address directly, the subsequent copy_to_kernel_nofault() takes a page fault and returns -EFAULT. bpf_arch_text_copy() turns that into -EINVAL, which propagates through bpf_jit_binary_pack_finalize() to the WARN_ON() in bpf_int_jit_compile() and leaves the program un-JITed.
Note that BPF cannot be fixed the way kprobes was in
commit bdc46e507b59 ("riscv: mm: make EXECMEM_KPROBES writable without CONFIG_STRICT_MODULE_RWX"). EXECMEM_BPF is already PAGE_KERNEL, i.e. writable at allocation time; the read-only mapping is established afterwards by generic code in alloc_new_pack(), which arch code cannot influence. The only place this can be handled is patch_map().
This is the same problem that was fixed on arm64 by commit b1480ed230ac ("arm64: patching: fix handling of execmem addresses"), and the fix is the same: CONFIG_EXECMEM is what actually tracks whether the vmalloc area can hold executable memory that needs a temporary alias to be written. CONFIG_BPF_JIT, CONFIG_KPROBES and CONFIG_MODULES all select it.
Note that this is not limited to CONFIG_MODULES=n. Unlike arm64, riscv selects CONFIG_ARCH_OPTIONAL_KERNEL_RWX, so CONFIG_STRICT_MODULE_RWX can be disabled with CONFIG_MODULES=y as well, and the bug is reachable in that configuration too.
The !CONFIG_MMU build is unaffected: it has its own __patch_insn_set() and __patch_insn_write() implementations and never calls patch_map().
--- arch/riscv/kernel/patch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/kernel/patch.c +1 -1
@@ -46,7 +46,7 @@ static __always_inline void *patch_map(vif (core_kernel_text (uintaddr) ||is_kernel_exittext (uintaddr)) { phys =__pa_symbol (addr); - }else if (IS_ENABLED (CONFIG_STRICT_MODULE_RWX )) { + }else if (IS_ENABLED (CONFIG_EXECMEM )) {struct page *page =vmalloc_to_page (addr);BUG_ON (!page);
Greg Kroah-Hartman
maintainerPATCH 113/281 riscv: ptrace: reject CFI regset access when extensions are absent
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Pei <[email protected]>
commit adadf6df0bd55aa40ccbc6519fb443133e103227 upstream.
riscv_cfi_get() and riscv_cfi_set() do not check whether the Zicfilp or Zicfiss extensions are present. On systems without them, PTRACE_GETREGSET on REGSET_CFI still succeeds and returns a zeroed user_cfi_state, misleading debuggers into believing the register set is available, and PTRACE_SETREGSET silently accepts writes that have no effect (e.g. clearing SR_ELP).
Reject the access with -EINVAL when neither branch landing pads nor shadow stack is available to userspace, using the same availability helpers as the prctl path.
--- arch/riscv/kernel/ptrace.c | 6 ++++++ 1 file changed, 6 insertions(+)
arch/riscv/kernel/ptrace.c +6 -0
@@ -299,6 +299,9 @@ static int riscv_cfi_get(struct task_strstruct user_cfi_state user_cfi;struct pt_regs *regs; +if (!is_user_lpad_enabled () && !is_user_shstk_enabled ()) +return -EINVAL ; +memset (&user_cfi,0 ,sizeof (user_cfi)); regs =task_pt_regs (target);
@@ -337,6 +340,9 @@ static int riscv_cfi_set(struct task_strstruct user_cfi_state user_cfi;struct pt_regs *regs; +if (!is_user_lpad_enabled () && !is_user_shstk_enabled ()) +return -EINVAL ; + regs =task_pt_regs (target); ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, &user_cfi,0 ,-1 );
Greg Kroah-Hartman
maintainerPATCH 114/281 Bluetooth: btintel_pcie: use managed IRQ teardown
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 25016fe8c1ed0fccae107bd629089139ffbafe08 upstream.
The PCIe driver registers its MSI-X handlers with devm_request_threaded_irq(), but remove() uses free_irq() directly. The devres actions then retain registrations and attempt to release them again during device cleanup.
Use devm_free_irq() for the remove path and for already registered vectors when a later setup request fails. This removes the managed resource at the same time as the IRQ is released and keeps MSI-X vector teardown ordered after IRQ ownership is gone.
--- drivers/bluetooth/btintel_pcie.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/bluetooth/btintel_pcie.c +6 -2
@@ -1715,7 +1715,7 @@ static irqreturn_t btintel_pcie_irq_msixstatic int btintel_pcie_setup_irq (struct btintel_pcie_data *data) {int err; -int num_irqs, i; +int num_irqs, i, j;for (i =0 ; i <BTINTEL_PCIE_MSIX_VEC_MAX ; i++) data->msix_entries[i].entry = i;
@@ -1744,6 +1744,10 @@ static int btintel_pcie_setup_irq(structKBUILD_MODNAME , msix_entry);if (err) { +for (j =0 ; j < i; j++) +devm_free_irq (&data->pdev->dev, + data->msix_entries[j].vector, + &data->msix_entries[j]);pci_free_irq_vectors (data->pdev); data->alloc_vecs =0 ;return err;
@@ -3003,7 +3007,7 @@ static void btintel_pcie_remove(struct pstruct msix_entry *msix_entry; msix_entry = &data->msix_entries[i]; -free_irq (msix_entry->vector, msix_entry); +devm_free_irq (&pdev->dev, msix_entry->vector, msix_entry); }pci_free_irq_vectors (pdev);
Greg Kroah-Hartman
maintainerPATCH 115/281 Bluetooth: hci_sock: Serialize dead-device detachment
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 381a0925c556a8d91a80a9b9e3e86651d60ffee3 upstream.
Rebinding an HCI socket after its controller is unregistered can race monitor control replay and crash the kernel. hci_sock_bind() clears hci_pi(sk)->hdev and drops the device reference under only the socket lock, whereas send_monitor_control_replay() holds hci_sk_list.lock for reading.
Replay can observe a non-NULL hdev, then bind can clear it and drop the last reference before create_monitor_ctrl_open() reads hdev->id. This can cause a NULL pointer dereference if the pointer is reloaded, or a use-after-free if the old pointer is retained.
The kernel reported:
KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f] RIP: 0010:create_monitor_ctrl_open+0x579/0x800 Call Trace: hci_sock_bind+0xd96/0x1190 __sys_bind+0x166/0x200 __x64_sys_bind+0x6d/0xb0 do_syscall_64+0xdd/0x4a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f
The same missing serialization lets hci_send_to_sock() select a socket for the old device and queue its frame after bind has detached the socket or installed a new binding.
Take hci_sk_list.lock for writing when clearing the device pointer and resetting the socket state. This waits for existing replay and delivery readers to finish before detachment and prevents later readers from using the old binding. Keep hci_dev_put() outside the critical section because the final device release can sleep.
--- net/bluetooth/hci_sock.c | 2 ++ 1 file changed, 2 insertions(+)
net/bluetooth/hci_sock.c +2 -0
@@ -1223,8 +1223,10 @@ static int hci_sock_bind(struct socket **/ hdev =hci_pi (sk)->hdev;if (hdev &&hci_dev_test_flag (hdev,HCI_UNREGISTER )) { +write_lock (&hci_sk_list.lock);hci_pi (sk)->hdev =NULL ; sk->sk_state =BT_OPEN ; +write_unlock (&hci_sk_list.lock);hci_dev_put (hdev); } hdev =NULL ;
Greg Kroah-Hartman
maintainerPATCH 116/281 Bluetooth: hci_sync: Fix command skb lifetime during scan setup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 9af12272061d206af8bc3e40215cb694421ab73a upstream.
During PA sync scan setup, hci_le_set_ext_scan_param_sync() gets the address used for the PA_LINK lookup from hci_sent_cmd_data(). The returned pointer borrows storage from sent_cmd or req_skb, without holding a reference to either skb.
The scan worker runs on req_workqueue while hci_cmd_work() runs on the separate device workqueue. After the scan worker loads sent_cmd, the command worker can free and replace it before hci_sent_cmd_data() dereferences the skb. The command payload can also be freed between returning from the helper and comparing the address. The connection lookup's RCU critical section does not protect the command skb.
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_sent_cmd_data+0x27c/0x2f0 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_sent_cmd_data+0x27c/0x2f0 hci_le_set_scan_param_sync+0x43a/0x850 hci_passive_scan_sync+0xb09/0x1460 hci_update_passive_scan_sync+0x47c/0x6e0 hci_le_pa_create_sync+0x200/0xa70 hci_cmd_sync_work+0x13c/0x290 Allocated by task 95: skb_clone+0x13f/0x340 hci_cmd_work+0x2a9/0x7e0 Freed by task 95: kmem_cache_free+0xba/0x3a0 hci_cmd_work+0x29c/0x7e0
Use hdev->lock to serialize the address snapshot with sent_cmd replacement. Protect req_skb replacement and completion cleanup with the same lock because the helper falls back to that skb. Copy the address before releasing the lock and use the copy for the existing RCU-protected connection lookup. Release the mutex before sending or waiting for commands, preserving the lookup and completion ordering.
--- net/bluetooth/hci_core.c | 4 ++++ net/bluetooth/hci_sync.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-)
net/bluetooth/hci_core.c +4 -0
@@ -4113,9 +4113,11 @@ static int hci_send_cmd_sync(struct hci_bt_dev_dbg (hdev,"skb %p" , skb); +hci_dev_lock (hdev);kfree_skb (hdev->sent_cmd); hdev->sent_cmd =skb_clone (skb,GFP_KERNEL ); +hci_dev_unlock (hdev);if (!hdev->sent_cmd) {skb_queue_head (&hdev->cmd_q, skb);queue_work (hdev->workqueue, &hdev->cmd_work);
@@ -4136,8 +4138,10 @@ static int hci_send_cmd_sync(struct hci_if (READ_ONCE (hdev->req_status) ==HCI_REQ_PEND && !hci_dev_test_and_set_flag (hdev,HCI_CMD_PENDING )) { +hci_dev_lock (hdev);kfree_skb (hdev->req_skb); hdev->req_skb =skb_get (hdev->sent_cmd); +hci_dev_unlock (hdev); }return err;
net/bluetooth/hci_sync.c +9 -1
@@ -32,8 +32,10 @@ static void hci_cmd_sync_complete(structWRITE_ONCE (hdev->req_status,HCI_REQ_DONE );/* Free the request command so it is not used as response */ +hci_dev_lock (hdev);kfree_skb (hdev->req_skb); hdev->req_skb =NULL ; +hci_dev_unlock (hdev);if (skb) {struct sock *sk =hci_skb_sk (skb);
@@ -3060,15 +3062,21 @@ static int hci_le_set_ext_scan_param_syn*/ if (hci_dev_test_flag (hdev,HCI_PA_SYNC )) {struct hci_cp_le_add_to_accept_list *sent; +bdaddr_t bdaddr; +hci_dev_lock (hdev); sent =hci_sent_cmd_data (hdev,HCI_OP_LE_ADD_TO_ACCEPT_LIST ); +if (sent) +bacpy (&bdaddr, &sent->bdaddr); +hci_dev_unlock (hdev); +if (sent) {struct hci_conn *conn;rcu_read_lock (); conn =hci_conn_hash_lookup_ba (hdev,PA_LINK , - &sent->bdaddr); + &bdaddr);if (conn) {struct bt_iso_qos *qos = &conn->iso_qos;
Greg Kroah-Hartman
maintainerPATCH 117/281 Bluetooth: ISO: Reject concurrent BIS listener setup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 555ff78fa719f50ff4cdbdb40aa1acc6e8e327d3 upstream.
iso_sock_listen() drops the socket lock before calling iso_listen_bis() to preserve the hdev->lock ordering. Two concurrent listen() calls on the same broadcast socket can therefore both observe BT_BOUND. Caller A can attach connA and release the locks, then caller B can acquire them and attach connB before A publishes BT_LISTEN.
__iso_chan_add() checks whether connB already has a socket, but not whether the socket already has a connection. The second attachment overwrites iso_pi(sk)->conn, leaking the connA reference and leaving connA->sk intact. Socket teardown follows connB, so later events on connA can cause a stale socket access.
Recheck BT_BOUND and require iso_pi(sk)->conn to be NULL after taking both the HCI device and socket locks in iso_listen_bis(). The connection check also covers the interval between attachment and publication of BT_LISTEN. Reject a competing setup with -EBADFD through the existing unlock path before allocating another connection.
A recorded KASAN report from an instrumented kernel shows:
BUG: KASAN: slab-use-after-free in iso_sock_hold+0x119/0x1f0 Call Trace: iso_sock_hold+0x119/0x1f0 iso_conn_del+0xe4/0x270 hci_disconn_complete_evt+0x351/0x8c0 hci_event_packet+0x71b/0xb20 hci_rx_work+0x293/0x730 Allocated by task 93: sk_prot_alloc+0x113/0x220 sk_alloc+0x2b/0x6d0 bt_sock_alloc+0x29/0x370 iso_sock_alloc.constprop.0+0x19/0x300 iso_sock_create+0x94/0x100 Freed by task 93: kfree+0x121/0x3c0 __sk_destruct+0x42b/0x540 iso_sock_release+0x29d/0x340 __sock_release+0xa1/0x260 sock_close+0x10/0x20
--- net/bluetooth/iso.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/iso.c +5 -0
@@ -1340,6 +1340,11 @@ static int iso_listen_bis(struct sock *shci_dev_lock (hdev);lock_sock (sk); +if (sk->sk_state !=BT_BOUND ||iso_pi (sk)->conn) { + err = -EBADFD ; + goto unlock; + } +/* Fail if user set invalid QoS */ if (iso_pi (sk)->qos_user_set && !check_bcast_qos (&iso_pi (sk)->qos)) {iso_pi (sk)->qos = default_qos;
Greg Kroah-Hartman
maintainerPATCH 118/281 Bluetooth: ISO: Serialize concurrent connect calls
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit e32d80293a0e1a160d5e5101daa8c82148c07510 upstream.
iso_sock_connect() checks the socket state before taking the socket lock and drops the lock again before setting up a connection. Two callers can both pass the admission check while the socket is open or bound.
Caller A can copy its destination for route selection, then caller B can replace the socket destination before A binds or connects the CIS. A then uses B's destination with the route selected for its own request. B can also proceed after A attaches a connection and sets BT_CONNECT. For deferred BIS setup, B can bind a second BIS and overwrite iso_pi(sk)->conn, leaving the first connection's reference and conn->sk back-pointer stranded. Concurrent CIS connects can likewise replace the socket's connection. Later teardown only detaches the current connection, so a callback on the old connection can race with socket release and access a freed socket.
KASAN reported:
BUG: KASAN: slab-use-after-free in iso_sock_hold+0xf7/0x1b0 Call Trace: iso_sock_hold+0xf7/0x1b0 iso_conn_del+0x7b/0x1d0 iso_connect_cfm+0x186/0x16a0 hci_conn_failed+0x154/0x280 hci_abort_conn_sync+0x3dc/0x7d0 hci_cmd_sync_work+0x173/0x300 Allocated by task 121: sk_alloc+0x2b/0x6d0 bt_sock_alloc+0x29/0x370 iso_sock_alloc.constprop.0+0x19/0x300 iso_sock_create+0x94/0x100 Freed by task 121: kfree+0x121/0x3c0 __sk_destruct+0x42b/0x540 iso_sock_release+0x29d/0x340 __sock_release+0xa1/0x260
Check admission under the socket lock and mark the connect operation in progress before publishing its destination. Keep that flag set across route lookup and connection setup, rejecting another connect with -EBADFD before it can change the destination or attach a connection. Clear the flag after either helper returns, including on failure, so a failed setup can be retried.
A separate flag is needed because the socket lock must be released before acquiring the HCI device lock, while BT_CONNECT requires an attached connection. Keep the existing state transitions and the deferred CIS completion through iso_sock_recvmsg().
Reject an existing socket attachment in __iso_chan_add() before taking a new reference or publishing either pointer, so every caller preserves the connection association. Keep the same-socket, same-connection success case for deferred CIS setup. Reject an attached socket before BIS setup so a reusable BIS is not claimed before the attachment is rejected.
In CIS setup, reject a different HCI connection before iso_conn_add() and drop the per-attempt HCI hold directly. An unowned iso_conn may still carry another reference after detachment, so its destruction cannot be relied on to release that hold.
iso_listen_bis() creates a fresh PA HCI/ISO pair under the device lock, so the temporary iso_conn_put() frees the ISO candidate and drops its HCI hold on rejection. iso_conn_ready() uses a freshly allocated, unpublished child with no connection, making the socket-side rejection unreachable.
--- net/bluetooth/iso.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-)
net/bluetooth/iso.c +37 -10
@@ -61,6 +61,7 @@ enum {BT_SK_BIG_SYNC ,BT_SK_PA_SYNC ,BT_SK_KILLED , + BT_SK_CONNECTING, }; struct iso_pinfo {
@@ -350,6 +351,9 @@ static int __iso_chan_add(struct iso_conreturn -EBUSY ; } +if (iso_pi (sk)->conn) +return -EISCONN ; +if (!conn->hcon) {BT_ERR ("conn->hcon missing" );return -EIO ;
@@ -410,6 +414,11 @@ static int iso_connect_bis(struct sock *hci_dev_lock (hdev);lock_sock (sk); +if (iso_pi (sk)->conn) { + err = -EISCONN ; + goto unlock; + } +if (!bis_capable (hdev)) { err = -EOPNOTSUPP ; goto unlock;
@@ -562,6 +571,13 @@ static int iso_connect_cis(struct sock *lockdep_assert_held (&hcon->hdev->lock); +/* The socket lock keeps the current attachment and its hcon stable. */ +if (iso_pi (sk)->conn &&iso_pi (sk)->conn->hcon != hcon) { +hci_conn_drop (hcon); + err = -EISCONN ; + goto unlock; + } + conn =iso_conn_add (hcon);if (!conn) {hci_conn_drop (hcon);
@@ -1269,17 +1285,26 @@ static int iso_sock_connect(struct socke addr->sa_family != AF_BLUETOOTH)return -EINVAL ; -if (sk->sk_state !=BT_OPEN && sk->sk_state !=BT_BOUND ) -return -EBADFD ; +lock_sock (sk); -if (sk->sk_type !=SOCK_SEQPACKET ) -return -EINVAL ; +if ((sk->sk_state !=BT_OPEN && sk->sk_state !=BT_BOUND ) || +test_bit (BT_SK_CONNECTING , &iso_pi (sk)->flags)) { + err = -EBADFD ; + goto done; + } + +if (sk->sk_type !=SOCK_SEQPACKET ) { + err = -EINVAL ; + goto done; + }/* Check if the address type is of LE type */ -if (!bdaddr_type_is_le (sa->iso_bdaddr_type)) -return -EINVAL ; +if (!bdaddr_type_is_le (sa->iso_bdaddr_type)) { + err = -EINVAL ; + goto done; + } -lock_sock (sk); +set_bit (BT_SK_CONNECTING , &iso_pi (sk)->flags);bacpy (&iso_pi (sk)->dst, &sa->iso_bdaddr);iso_pi (sk)->dst_type = sa->iso_bdaddr_type;
@@ -1291,16 +1316,18 @@ static int iso_sock_connect(struct sockeelse err =iso_connect_bis (sk); -if (err) -return err; -lock_sock (sk); +clear_bit (BT_SK_CONNECTING , &iso_pi (sk)->flags); +if (err) + goto done; +if (!test_bit (BT_SK_DEFER_SETUP , &bt_sk (sk)->flags)) { err =bt_sock_wait_state (sk,BT_CONNECTED ,sock_sndtimeo (sk, flags &O_NONBLOCK )); } +done:release_sock (sk);return err; }
Greg Kroah-Hartman
maintainerPATCH 119/281 Bluetooth: MGMT: Fix status of pending commands flushed on power off
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Iaroslav Voitovych <[email protected]>
commit 86ef0f58bdecdedb3a1240971c56d71b7e4ce3fc upstream.
cmd_complete_rsp() receives a struct cmd_lookup and, for a pending command that has no cmd_complete callback, falls through to cmd_status_rsp(cmd, data). cmd_status_rsp() reads data as a u8 *, so the status sent comes from the first byte of match->sk's representation, not from match->mgmt_status.
commit f53e1c9c726d ("Bluetooth: MGMT: Fix possible crash on mgmt_index_removed") changed the callers' data from &status to &match and updated the cmd_complete branch to match->mgmt_status, but left the fall-through passing data unchanged.
In mgmt_index_removed() match->sk is NULL, so every such command is answered with status 0x00 (Success) instead of MGMT_STATUS_INVALID_INDEX. In __mgmt_power_off() it is NULL too, unless a Set Powered command was pending: then settings_rsp() has stored that command's socket in match->sk, and the byte sent comes from the socket pointer. Either way the status the caller set, MGMT_STATUS_NOT_POWERED (or MGMT_STATUS_INVALID_INDEX when the device is being unregistered), is lost.
Pass the status the callers set.
This was seen on a QCA9377 laptop: bluetoothd's Start Discovery, pending when the adapter was powered off, was answered with Command Status 0x00 and no parameters, and bluetoothd 5.72 crashed on the zero-length success. BlueZ master has since added the length check on that path ("adapter: Fix crash on short start discovery reply", BlueZ a734b06059cb), but userspace should still be told Not Powered, not Success.
Tested on Ubuntu 7.0.0-31 with a virtual controller (hci_vhci):
power off is held in HCI Write Scan Enable while a Start Discovery is submitted, and the flush answers it with status 0x00 before this change and 0x0f (Not Powered) after.
--- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/mgmt.c +1 -1
@@ -1489,7 +1489,7 @@ static void cmd_complete_rsp(struct mgmtreturn ; } -cmd_status_rsp (cmd, data); +cmd_status_rsp (cmd, &match->mgmt_status); }static int generic_cmd_complete (struct mgmt_pending_cmd *cmd,u8 status)
Greg Kroah-Hartman
maintainerPATCH 120/281 Bluetooth: SCO: serialise sco_conn lifetime against sco_recv_scodata()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Ariel Panzardo <[email protected]>
commit 816fb1590a4c8cf8d05cd076057616be02e276f0 upstream.
sco_recv_scodata() upgrades the weak hcon->sco_data back-pointer to a strong reference under hdev->lock:
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
...
conn = sco_conn_hold_unless_zero(hcon->sco_data);
hci_dev_unlock(hdev);but the pointer is cleared from the other side without that lock. When the last sco_conn reference is dropped, sco_conn_free() ran
conn->hcon->sco_data = NULL;
with no hdev->lock held, so the RX path could read hcon->sco_data and call kref_get_unless_zero() on an sco_conn that was concurrently freed:
BUG: KASAN: slab-use-after-free in sco_conn_hold_unless_zero+0xbe/0x160
Write of size 4 by task kworker/u17:0
Workqueue: hci0 hci_rx_work
Call Trace:
sco_conn_hold_unless_zero+0xbe/0x160
sco_recv_scodata+0x13f/0x490
hci_rx_work+0x3af/0x730kref_get_unless_zero() only guards against a zero refcount, not against the backing memory already being freed.
Give hcon->sco_data an actual reference on the sco_conn it points to, so the object cannot be freed while the pointer is still installed, and only clear and drop it from sco_conn_del(), which runs under hdev->lock (its callers, sco_connect_cfm() and sco_disconn_cfm(), hold it). The reader in sco_recv_scodata() also takes hdev->lock, so the store and the read are now serialised: the RX path either observes NULL or a reference that is guaranteed to stay valid until it drops its own.
sco_conn_add() no longer hands its kref_init() reference to the caller as the connection's only reference; that initial reference is the one owned by hcon->sco_data, and callers get their own via sco_conn_hold().
Because the sco_conn can now outlive the socket (the association keeps it alive until the link goes down), the hci_conn can no longer be dropped from sco_conn_free() without regressing socket close: closing a connected SCO socket must still tear the link down. Move hci_conn ownership to the socket instead: __sco_chan_add() takes an hci_conn reference and it is released from sco_chan_del() and sco_sock_destruct(), exactly once. The sco_conn no longer owns an hci_conn reference, so sco_conn_add() stops consuming one and sco_connect() drops the hci_connect_sco() reference on every path; sco_connect_cfm() no longer needs its hci_conn_hold() dance.
--- net/bluetooth/sco.c | 87 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 22 deletions(-)
net/bluetooth/sco.c +65 -22
@@ -84,12 +84,14 @@ static void sco_conn_free(struct kref *rif (conn->sk)sco_pi (conn->sk)->conn =NULL ; -if (conn->hcon) { - conn->hcon->sco_data =NULL ; -hci_conn_drop (conn->hcon); - } +/* hcon->sco_data is cleared and the association's reference on the +* sco_conn is dropped in sco_conn_del() under hdev->lock, and the +* hci_conn is now owned by the socket (held in __sco_chan_add() and +* dropped in sco_chan_del()/sco_sock_destruct()), so there is nothing +* left to release towards hcon here. +*/ -/* Ensure no more work items will run since hci_conn has been dropped */ +/* Ensure no more work items will run before the connection is freed */ disable_delayed_work_sync (&conn->timeout_work);kfree (conn);
@@ -188,25 +190,19 @@ static void sco_sock_clear_timer(struct }/* ---- SCO connections ---- */ -/* Consumes a reference on @hcon, which the returned sco_conn owns until it is -* freed. On failure (NULL return) the reference is left for the caller to drop. +/* Returns a new reference the caller must drop with sco_conn_put(). The +* hcon->sco_data association holds its own reference on the sco_conn for the +* connection's lifetime; it is dropped in sco_conn_del() under hdev->lock. +* @hcon is not consumed: the hci_conn reference is taken and owned by the +* socket in __sco_chan_add(). */ static struct sco_conn *sco_conn_add (struct hci_conn *hcon) {struct sco_conn *conn = hcon->sco_data; conn =sco_conn_hold_unless_zero (conn); -if (conn) { -if (!conn->hcon) { -sco_conn_lock (conn); - conn->hcon = hcon; -sco_conn_unlock (conn); - }else { -/* conn already owns a reference on hcon */ -hci_conn_drop (hcon); - } +if (conn)return conn; - } conn = kzalloc_obj(struct sco_conn);if (!conn)
@@ -227,7 +223,10 @@ static struct sco_conn *sco_conn_add(strBT_DBG ("hcon %p conn %p" , hcon, conn); -return conn; +/* kref_init() above set the association reference owned by +* hcon->sco_data; hand the caller its own reference. +*/ +return sco_conn_hold (conn); }/* Delete channel.
@@ -242,6 +241,19 @@ static void sco_chan_del(struct sock *skBT_DBG ("sk %p, conn %p, err %d" , sk, conn, err);if (conn) { +struct hci_conn *hcon; + +sco_conn_lock (conn); + hcon = conn->hcon; +sco_conn_unlock (conn); + +/* Drop the socket's hci_conn reference BEFORE clearing +* conn->sk, so sco_conn_del() on another CPU cannot free +* the hci_conn while we still hold a pointer to it. +*/ +if (hcon) +hci_conn_drop (hcon); +sco_conn_lock (conn); conn->sk =NULL ;sco_conn_unlock (conn);
@@ -266,6 +278,13 @@ static void sco_conn_del(struct hci_connBT_DBG ("hcon %p conn %p, err %d" , hcon, conn, err); +/* Detach from the hci_conn and drop the association's reference. +* The caller holds hdev->lock, which serialises this against the +* read of hcon->sco_data in sco_recv_scodata(). +*/ + hcon->sco_data =NULL ; +sco_conn_put (conn); +sco_conn_lock (conn); sk =sco_sock_hold (conn);sco_conn_unlock (conn);
@@ -290,6 +309,11 @@ static void __sco_chan_add(struct sco_cosco_pi (sk)->conn =sco_conn_hold (conn); conn->sk = sk; +/* The socket owns an hci_conn reference for as long as it stays +* attached; it is dropped in sco_chan_del()/sco_sock_destruct(). +*/ +hci_conn_hold (conn->hcon); +if (parent)bt_accept_enqueue (parent, sk, true); }
@@ -371,6 +395,7 @@ static int sco_connect(struct sock *sk)if (sk->sk_state !=BT_OPEN && sk->sk_state !=BT_BOUND ) {release_sock (sk);sco_conn_put (conn); +hci_conn_drop (hcon); err = -EBADFD ; goto unlock; }
@@ -379,9 +404,13 @@ static int sco_connect(struct sock *sk)sco_conn_put (conn);if (err) {release_sock (sk); +hci_conn_drop (hcon); goto unlock; } +/* __sco_chan_add() took its own hci_conn reference; drop ours. */ +hci_conn_drop (hcon); +/* Update source addr of the socket */ bacpy (&sco_pi (sk)->src, &hcon->src);
@@ -495,9 +524,25 @@ static struct sock *sco_get_sock_listen(static void sco_sock_destruct (struct sock *sk) { +struct sco_conn *conn =sco_pi (sk)->conn; +BT_DBG ("sk %p" , sk); -sco_conn_put (sco_pi (sk)->conn); +/* If the channel was not already torn down via sco_chan_del(), drop +* the socket's own references here. +*/ +if (conn) { +struct hci_conn *hcon; + +sco_conn_lock (conn); + hcon = conn->hcon; +sco_conn_unlock (conn); + +if (hcon) +hci_conn_drop (hcon); +sco_pi (sk)->conn =NULL ; +sco_conn_put (conn); + }skb_queue_purge (&sk->sk_receive_queue);skb_queue_purge (&sk->sk_write_queue);
@@ -1511,12 +1556,10 @@ static void sco_connect_cfm(struct hci_cif (!status) {struct sco_conn *conn; - conn =sco_conn_add (hci_conn_hold (hcon)); + conn =sco_conn_add (hcon);if (conn) {sco_conn_ready (conn);sco_conn_put (conn); - }else { -hci_conn_drop (hcon); } }else sco_conn_del (hcon,bt_to_errno (status));
Greg Kroah-Hartman
maintainerPATCH 121/281 Bluetooth: RFCOMM: free the skb when the DLC has no owner
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxim Skokov <[email protected]>
commit 9d1afbf60ed53c5b051cd124153e0ae3078c8b93 upstream.
rfcomm_recv_data() hands the skb to d->data_ready() and returns 0 without freeing it, so the callback owns the skb from that point on. The tty implementation frees it when the DLC has been detached from its device:
static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc,
struct sk_buff *skb)
{
struct rfcomm_dev *dev = dlc->owner; if (!dev) {
kfree_skb(skb);
return;
}The socket implementation returns without freeing it, and the skb is leaked.
A connected DLC can have no owner: rfcomm_sock_destruct() clears d->owner, while the DLC itself stays on the session until it is closed. Data frames that arrive in that window still find d->state == BT_CONNECTED in rfcomm_recv_data() and are handed to the callback, one leaked skb each.
The leak does not stop on its own either. The remote runs out of credits only once RFCOMM_RX_THROTTLED is set, and for a socket the only place that sets it is rfcomm_sk_data_ready() itself, below the return. rfcomm_process_dlcs() keeps granting credits, so the remote keeps sending and the leak keeps growing.
Free the skb, as the tty side does.
--- net/bluetooth/rfcomm/sock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/bluetooth/rfcomm/sock.c +4 -1
@@ -48,8 +48,11 @@ static void rfcomm_sock_kill(struct sockstatic void rfcomm_sk_data_ready (struct rfcomm_dlc *d,struct sk_buff *skb) {struct sock *sk = d->owner; -if (!sk) + +if (!sk) { +kfree_skb (skb);return ; + }atomic_add (skb->len, &sk->sk_rmem_alloc);skb_queue_tail (&sk->sk_receive_queue, skb);
Greg Kroah-Hartman
maintainerPATCH 122/281 Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit ac022970e9fb0a5f7e7d1f6c8e104c1ed924dd1c upstream.
An RFCOMM connect() issued while a BR/EDR link is being authenticated makes lockdep report a circular dependency, and the reported cycle is a real AB/BA between rfcomm_mutex and hdev->lock.
rfcomm_security_cfm() is called from the HCI event path, which already holds hdev->lock:
hci_rx_work()
hci_event_packet()
hci_cc_read_enc_key_size() [hdev->lock]
hci_encrypt_cfm() [hci_cb_list_lock]
rfcomm_security_cfm() [rfcomm_mutex]while an RFCOMM connect() from userspace takes the same two locks the other way round:
rfcomm_sock_connect()
rfcomm_dlc_open() [rfcomm_mutex]
__rfcomm_dlc_open()
rfcomm_session_create()
kernel_connect()
l2cap_sock_connect()
l2cap_chan_connect() [hdev->lock] WARNING: possible circular locking dependency detected kworker/u131:1/1128 is trying to acquire lock:
rfcomm_mutex, at: rfcomm_security_cfm+0x31/0x3e0 [rfcomm] but task is already holding lock:
hci_cb_list_lock, at: hci_cc_read_enc_key_size+0x1d2/0xcc0
Chain exists of:
rfcomm_mutex --> &hdev->lock --> hci_cb_list_lockhci_auth_complete_evt() and hci_encrypt_change_evt() reach the callback the same way.
Both orders have to be seen in the same boot, which is why a BR/EDR connection alone is not enough to show it: a session set up by the remote side is created by rfcomm_accept_connection() in krfcommd, which calls kernel_accept() and never takes hdev->lock under rfcomm_mutex. Connecting a device that authenticates and encrypts the link and then calling connect() on an RFCOMM socket towards any address - the connect does not have to succeed, the order is recorded before the page timeout
- reports it every time.
Only the session socket has to be connected with the lock held, and it does not: nothing else can see the socket before it is put on the session list. So connect it first and take rfcomm_mutex afterwards, which removes the rfcomm_mutex -> hdev->lock order for good, rather than keeping the HCI event path out of rfcomm_mutex.
rfcomm_session_create() becomes rfcomm_session_connect(), which returns the connected socket without touching the session list, and rfcomm_dlc_open() adds the session once it holds the lock again. If another opener added a session for the same pair while this socket was connecting, that session is used and this socket is dropped. __rfcomm_dlc_open() now takes the session it should use, and its state check runs after the lock is re-acquired, so a DLC that was opened or closed in the meantime is still handled.
Over an existing ACL link the connection can complete before the session reaches the list, and the wakeup from the socket callback is then lost, so krfcommd is woken once the session is visible.
Connecting without the lock opens a window in which the socket can be closed. The DLC is not on a session yet, so rfcomm_dlc_close() finds nothing to do and returns without touching it, and rfcomm_dlc_open() would then attach a DLC whose owner is gone. rfcomm_dlc_close() now marks such a DLC with RFCOMM_CLOSED, and rfcomm_dlc_open() checks the mark once it holds rfcomm_mutex again and drops the socket instead of attaching the DLC. The mark is cleared when an open starts, so a DLC that is reused is not affected. This covers both callers of rfcomm_dlc_open(), the socket and the tty layer.
--- include/net/bluetooth/rfcomm.h | 1 net/bluetooth/rfcomm/core.c | 134 +++++++++++++++++++++++++++++------------ 2 files changed, 96 insertions(+), 39 deletions(-)
include/net/bluetooth/rfcomm.h +1 -0
@@ -207,6 +207,7 @@ struct rfcomm_dlc {#define RFCOMM_AUTH_REJECT 7#define RFCOMM_DEFER_SETUP 8#define RFCOMM_ENC_DROP 9 +#define RFCOMM_CLOSED 10/* Scheduling flags and events */ #define RFCOMM_SCHED_WAKEUP 31
net/bluetooth/rfcomm/core.c +95 -39
191 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 123/281 Bluetooth: RFCOMM: Fix NULL tty_dev dereference in rfcomm_dev_shutdown
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Palla Raghunath <[email protected]>
commit 08e90633377f1b2567ab5ad6810b74c552246a07 upstream.
syzbot hit a NULL pointer dereference in rfcomm_dev_shutdown() when an RFCOMM tty is closed.
rfcomm_dev_add() puts the new device on rfcomm_dev_list first and only then registers the tty device and saves it in dev->tty_dev. If that registration fails, dev->tty_dev is never set at all. The device can be looked up in the meantime, so an open() of /dev/rfcommN gets through rfcomm_tty_install() and attaches to it. When that tty is closed again, rfcomm_dev_shutdown() uses dev->tty_dev without checking it:
Oops: general protection fault, probably for non-canonical address KASAN: null-ptr-deref in range [0x0000000000000040-0x0000000000000047] RIP: 0010:rfcomm_dev_shutdown+0x48/0xb0 net/bluetooth/rfcomm/tty.c:131 Call Trace: tty_port_shutdown+0x1bf/0x220 drivers/tty/tty_port.c:372 tty_port_close+0x4e/0x150 drivers/tty/tty_port.c:705 tty_release+0x359/0x1670 drivers/tty/tty_io.c:1718 __fput+0x418/0xa50 fs/file_table.c:512
rfcomm_dev_destruct() already copes with a NULL dev->tty_dev. Add the same check to rfcomm_dev_shutdown(), so the tty device is only moved when it was actually registered.
--- net/bluetooth/rfcomm/tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/rfcomm/tty.c +1 -1
@@ -128,7 +128,7 @@ static void rfcomm_dev_shutdown(struct t { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); -if (dev->tty_dev->parent) +if (dev->tty_dev && dev->tty_dev->parent)device_move (dev->tty_dev,NULL ,DPM_ORDER_DEV_LAST );/* close the dlc */
Greg Kroah-Hartman
maintainerPATCH 124/281 drm/fb-helper: defer setup when fbdev_probe() fails, not just on -EAGAIN
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nguyen Ngoc Thang <[email protected]>
commit 755c94d178b7e972bb766199d34e4ba4f63a89eb upstream.
__drm_fb_helper_initial_config_and_unlock() calls drm_client_modeset_probe() first, which already fills in each mode_set->mode/num_connectors for every connected output, and only afterwards calls drm_fb_helper_single_fb_probe() to create fb_helper->fb and wire it into those mode_sets via drm_setup_crtcs_fb().
If drm_fb_helper_single_fb_probe() fails with anything other than -EAGAIN (e.g. dev->driver->fbdev_probe() itself fails), the function bails out before drm_setup_crtcs_fb() runs and before setting fb_helper->deferred_setup. The client is left with mode_sets that have a mode and connectors but mode_set->fb == NULL, and nothing marks this fb_helper as needing a retry.
__drm_fb_helper_restore_fbdev_mode_unlocked() only skips committing when fb_helper->deferred_setup is set, so a later .restore() call (drm_lastclose() on process exit, in this report) commits the stale mode_set through drm_client_modeset_commit() -> drm_client_modeset_commit_atomic() -> __drm_atomic_helper_set_config(), which hits WARN_ON(!set->fb).
Mark fb_helper->deferred_setup on any drm_fb_helper_single_fb_probe() failure, not just -EAGAIN, so restore keeps skipping the commit until a later hotplug event successfully re-probes and re-populates mode_set->fb. The real error code is still returned to the caller unchanged.
--- drivers/gpu/drm/drm_fb_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/drm_fb_helper.c +3 -3
@@ -1724,10 +1724,10 @@ __drm_fb_helper_initial_config_and_unloc ret =drm_fb_helper_single_fb_probe (fb_helper);if (ret <0 ) { -if (ret == -EAGAIN ) { - fb_helper->deferred_setup = true; +/* modesets are probed but fb_helper->fb isn't; defer restore too */ + fb_helper->deferred_setup = true; +if (ret == -EAGAIN ) ret =0 ; - }mutex_unlock (&fb_helper->lock); goto err_drm_fb_helper_release_info;
Greg Kroah-Hartman
maintainerPATCH 125/281 drm/gud: dont keep a connector without a CRTC as connector_state
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sajal Gupta <[email protected]>
commit 71ec70ea26e399eb8371fe9d2d5bf5dab09570fb upstream.
If the 'for_each_new_connector_in_state()' loop finishes without hitting the break, connector_state is left pointing at the last connector visited, which has no CRTC, instead of staying NULL.
That skips the "if (!connector_state)" fallback below the loop, which looks up the active connector when the state contains none. The function then carries on with a connector that is not driven.
Fix by resetting connector_state to NULL for each connector visited that has no CRTC, so that it is NULL when none was found and the fallback runs.
--- drivers/gpu/drm/gud/gud_pipe.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/gud/gud_pipe.c +1 -0
@@ -507,6 +507,7 @@ int gud_plane_atomic_check(struct drm_plfor_each_new_connector_in_state (state, connector, connector_state, i) {if (connector_state->crtc)break ; + connector_state =NULL ; }/*
Greg Kroah-Hartman
maintainerPATCH 126/281 drm/i915/gem: Prevent overstepping exec array boundary
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Karas <[email protected]>
commit ebe162db655881a38de43301151ff7ac940602b5 upstream.
It is possible for eb_relocate_parse_slow() to call kvfree() on entries outside the original exec array during following scenario inside eb_relocate_parse_slow():
1) eb_copy_relocations() allocates as many as eb->buffer_count copies for exec entries;
2) eb_parse() appends up to two VMAs, right after incrementing eb->buffer_count;
3) cleanup under "out" label uses this incremented buffer_count to release relocation pointers from exec array via kvfree(), not from VMA array.
To amend this problem, ensure that relocation cleanup uses the original exec object count, excluding the VMAs appended by the command parser.
--- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +1 -1
@@ -1766,6 +1766,7 @@ static int eb_reinit_userptr(struct i915 static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb) { +const unsigned int count = eb->buffer_count;bool have_copy = false;struct eb_vma *ev;int err =0 ;
@@ -1868,7 +1869,6 @@ err: out:if (have_copy) { -const unsigned int count = eb->buffer_count;unsigned int i;for (i =0 ; i < count; i++) {
Greg Kroah-Hartman
maintainerPATCH 127/281 drm/i915/gt: Unmask interrupts only when ACTIVE is true
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Karas <[email protected]>
commit 5346b1cec6afa4f9b4b49a9f84e3cfef95a3f7bb upstream.
There is a small race window between intel_rps_boost() reading a stale ACTIVE state and queuing rps->work, where ACTIVE may be changed via asynchronous calls triggered by wakeref drop. This means that rps_work() could be triggered after the GT has been parked, so unmasking RPS PM interrupts would happen without holding PM wakelock. This sequence of events may be observed during live_rc6_ctx_wa() selftest:
1) live_rc6_ctx_wa()
-> intel_engine_pm_put()
-> wakeref_put()
ASYNC1) wakeref_put() callback
-> __engine_park()
-> intel_gt_pm_put_async()
-> intel_gt_pm_put_async_untracked()
-> intel_wakeref_put_async()ASYNC2) wakeref_put_async() callback
-> __gt_park()
-> intel_rps_park()
-> intel_rps_clear_active() [clear ACTIVE]
WITH INTERRUPTS:
-> rps_disable_interrupts()
-> cancel_work_sync(rps->work)
-> rps_reset_interrupts() [rps->pm_iir = 0]
WITHOUT INTERRUPTS (TIMER mode):
-> rps_stop_timer()
-> cancel_work_sync(rps->work)2) live_rc6_ctx_wa()
-> intel_gt_wait_for_idle()
-> intel_gt_retire_requests_timeout()
-> dma_fence_wait_timeout()
-> ops->wait() [i915_fence_wait()]
-> i915_request_wait_timeout()
-> intel_rps_boost()
-> intel_rps_is_active() [check ACTIVE]
[OPEN RACE WINDOW]
-> queue_work(rps->work)
-> retire_requests()
-> i915_request_retire()
-> intel_rps_dec_waiters() [from 1 to 0]If ASYNC1 and ASYNC2 would execute during [OPEN RACE WINDOW], then:
3) rps_work() executes from the workqueue and may satisfy "(!pm_iir && !client_boost)" test (in TIMER mode rps->pm_iir is zeroed by an earlier rps_work() call or never gets a new value after previous intel_rps_unpark() event), so it jumps to "out" label, bypassing intel_rps_is_active() guard and executes gen6_gt_pm_unmask_irq();
4) GT is parked and runtime PM wakelock is dropped, so only a raw reference in __gt_park() -> intel_display_power_put_async() remains for 100ms, then the MMIO write in gen6_gt_pm_unmask_irq() detects missing wakelock via assert_rpm_wakelock_held() and emits "RPM wakelock ref not held during HW access" tainting kernel.
Commit 3e7abf814193 ("drm/i915: Extract GT render power state management") dropped the "if (rps->interrupts_enabled)" guard that gen6_pm_rps_work() had around this unmask in i915_irq.c. INTEL_RPS_ACTIVE brackets the same window, since it is set in intel_rps_unpark() before rps_enable_interrupts() and rps_start_timer() and cleared in intel_rps_park() before rps_stop_timer() and rps_disable_interrupts().
Skip unmasking when RPS is no longer active (reaching unmask operation is independent of INTERRUPT mode). This does not prevent RPS operation from resuming on the next unpark. In interrupt mode, intel_rps_unpark() calls rps_enable_interrupts(), which enables and unmasks the PM interrupts. In timer mode, it calls rps_start_timer(), restarting periodic engine-busyness evaluation. The timer generates software RPS events and queues rps_work() directly, independently of PM interrupt delivery. Neither mode requires the late worker to unmask interrupts while the GT is parked
--- drivers/gpu/drm/i915/gt/intel_rps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_rps.c +2 -1
@@ -1904,7 +1904,8 @@ static void rps_work(struct work_struct out:spin_lock_irq (gt->irq_lock); -gen6_gt_pm_unmask_irq (gt, rps->pm_events); +if (intel_rps_is_active (rps)) +gen6_gt_pm_unmask_irq (gt, rps->pm_events);spin_unlock_irq (gt->irq_lock); }
Greg Kroah-Hartman
maintainerPATCH 128/281 drm/imagination: Size page table preallocation by device address
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gyeyoung Baek <[email protected]>
commit 789f290b2e81d42820bddcb4010ffbc2ae2ded54 upstream.
Commit 0a8224058a58 ("drm/imagination: Fix page count for page table for map() interface") passed the device address to pvr_mmu_op_context_create(), but the preallocation is still sized from device_addr + sgt_offset with an exclusive end. The offset into the object's pages has no place in a device-virtual range, and the exclusive end allocates one table too many when the range ends on a table boundary.
Count the tables from device_addr and the inclusive end of the range.
The new calculation does not take page table indices into account. This fixes another issue with the previous implementation, where the difference between start and end indices could underflow when a mapping crossed a page table boundary. This would lead to the driver preallocating a huge number of MMU pages, exhausting system memory and triggering an out of memory panic.
--- drivers/gpu/drm/imagination/pvr_mmu.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-)
drivers/gpu/drm/imagination/pvr_mmu.c +12 -13
@@ -2337,7 +2337,7 @@ void pvr_mmu_op_context_destroy(struct p* @ctx: MMU context associated with owning VM context. * @sgt: Scatter gather table containing pages pinned for use by this context. * @device_addr: Virtual device address at the start of the requested mapping. -* @sgt_offset: Start offset of the requested device-virtual memory mapping. +* @sgt_offset: Offset into @sgt of the start of the requested mapping. * @size: Size in bytes of the requested device-virtual memory mapping. For an * unmapping, this should be zero so that no page tables are allocated. *
@@ -2350,7 +2350,6 @@ struct pvr_mmu_op_context * pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt, u64 device_addr, u64 sgt_offset, u64 size) { - u64 start_addr = device_addr + sgt_offset; int err;struct pvr_mmu_op_context *op_ctx =kzalloc_obj (*op_ctx);
@@ -2365,18 +2364,18 @@ pvr_mmu_op_context_create(struct pvr_mmuif (size) {/* -* The number of page table objects we need to prealloc is -* indicated by the mapping size, start address and the sizes -* of the areas mapped per PT or PD. The range calculation is -* identical to that for the index into a table for a device -* address, so we reuse those functions here. +* The page tables needed are set by the device-virtual range +* being mapped: one level 1 table per 1GiB region and one +* level 0 table per 2MiB region the range touches. Tables that +* already exist are not consumed, so this is an upper bound. */ -const u32 l1_start_idx =pvr_page_table_l2_idx (start_addr); -const u32 l1_end_idx =pvr_page_table_l2_idx (start_addr + size); -const u32 l1_count = l1_end_idx - l1_start_idx +1 ; -const u32 l0_start_idx =pvr_page_table_l1_idx (start_addr); -const u32 l0_end_idx =pvr_page_table_l1_idx (start_addr + size); -const u32 l0_count = l0_end_idx - l0_start_idx +1 ; +const u64 last_addr = device_addr + size -1 ; +const u64 l1_count = + (last_addr >>ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT ) - + (device_addr >>ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT ) +1 ; +const u64 l0_count = + (last_addr >>ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT ) - + (device_addr >>ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT ) +1 ;/* * Alloc and push page table entries until we have enough of
Greg Kroah-Hartman
maintainerPATCH 129/281 drm/panthor: validate userspace queue count against initialized firmware slot count
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
commit ec86c43dcfff68eab4db9bdafcd3e2b16e342e18 upstream.
In panthor_drv.c:panthor_ioctl_group_create(),
the queue count is validated against the hardcoded maximum:
if (!args->queues.count || args->queues.count > MAX_CS_PER_CSG) return -EINVAL;
However, if the firmware reports fewer slots than MAX_CS_PER_CSG, panthor_fw_init_ifaces() will only initialize that smaller number of stream interfaces.
If unprivileged userspace requests more queues than the firmware reported (but no more than MAX_CS_PER_CSG), cs_slot_prog_locked() fetches an uninitialized stream interface and may crash when dereferencing cs_iface->input->ringbuf_base.
--- drivers/gpu/drm/panthor/panthor_sched.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/panthor/panthor_sched.c +3 -0
@@ -3675,6 +3675,9 @@ int panthor_group_create(struct panthor_ hweight64(group_args->tiler_core_mask) < group_args->max_tiler_cores)return -EINVAL ; +if (group_args->queues.count > sched->cs_slot_count) +return -EINVAL ; + group =kzalloc_obj (*group);if (!group)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 130/281 drm/vc4: drain the hangcheck timer and works on V3D unbind
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 94cf5971b1d04c6382437387c4dc3836cc7a1437 upstream.
Nothing stops the hangcheck timer that submitted jobs arm, or the job_done_work that the render-done interrupt queues, at teardown:vc4_irq_disable() cancels only overflow_mem_work, and vc4_gem_destroy() runs from the drm-managed release, after vc4_v3d_unbind() has already uninstalled the V3D interrupt and cleared vc4->v3d. A timer still armed by then reads V3D registers through the NULL vc4->v3d pointer, and the late callbacks run on the vc4_dev embedding them after it has been freed.
Drain them in vc4_v3d_unbind(): shut the timer down and cancel reset_work before the interrupt is taken down, because its vc4_irq_reset() re-enables it, then flush job_done_work so that completions queued at teardown still release their jobs.
This issue was found by an in-house static analysis tool.
--- drivers/gpu/drm/vc4/vc4_v3d.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/vc4/vc4_v3d.c +8 -0
@@ -9,6 +9,7 @@#include <linux/component.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/timer.h> #include <drm/drm_print.h>
@@ -497,8 +498,15 @@ static void vc4_v3d_unbind(struct devicestruct drm_device *drm = data;struct vc4_dev *vc4 =to_vc4_dev (drm); +/* A straggler vc4_reset() re-enables the interrupt. */ +timer_shutdown_sync (&vc4->hangcheck.timer); +cancel_work_sync (&vc4->hangcheck.reset_work); +vc4_irq_uninstall (drm); +/* Flush rather than cancel, so queued completions release their jobs. */ +flush_work (&vc4->job_done_work); +/* Disable the binner's overflow memory address, so the next * driver probe (if any) doesn't try to reuse our old * allocation.
Greg Kroah-Hartman
maintainerPATCH 131/281 drm/vc4: Fix firmware reference leak in vc4_drm_bind()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit b816da5d5df1461446a0a5f3fe2b4948a659a790 upstream.
The firmware reference obtained via rpi_firmware_get() is leaked when aperture_remove_all_conflicting_devices() fails, as the error label returns without putting it. This happens before the firmware is consumed and put further down in the function.
Put the firmware reference before jumping to err.
--- drivers/gpu/drm/vc4/vc4_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_drv.c +4 -1
@@ -360,8 +360,11 @@ static int vc4_drm_bind(struct device *d } ret =aperture_remove_all_conflicting_devices (driver->name); -if (ret) +if (ret) { +if (firmware) +rpi_firmware_put (firmware); goto err; + }if (firmware) { ret = rpi_firmware_property(firmware,
Greg Kroah-Hartman
maintainerPATCH 132/281 drm/vmwgfx: validate pitch coming from userspace
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
commit 21bc51cb89ced74d6645a138cc2f21184bc75094 upstream.
Validate the pitch, alongside the box dimensions before trying to copy data from the underlying surface. Fixes possible out of bounds reads with cursor snooping.
--- drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c +21 -5
@@ -324,6 +324,7 @@ void vmw_kms_cursor_snoop(struct vmw_surunsigned long kmap_num;SVGA3dCopyBox *box;u32 box_count; +u64 src_extent;void *virtual;bool is_iomem;struct vmw_dma_cmd {
@@ -335,6 +336,8 @@ void vmw_kms_cursor_snoop(struct vmw_survmw_surface_get_desc (VMW_CURSOR_SNOOP_FORMAT );const u32 image_pitch =VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; +BUILD_BUG_ON (sizeof (*srf->snooper.image) != desc->pitchBytesPerBlock); + cmd = container_of(header, struct vmw_dma_cmd, header);/* No snooper installed, nothing to copy */
@@ -372,8 +375,19 @@ void vmw_kms_cursor_snoop(struct vmw_surreturn ; } +if (box->w ==0 || box->h ==0 ) +return ; + + src_extent = (u64)(box->h -1 ) * cmd->dma.guest.pitch + + (u64 )box->w * desc->pitchBytesPerBlock; +if (src_extent > bo->base.size) { +DRM_ERROR ("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n" , + src_extent, bo->base.size); +return ; + } + kmap_offset = cmd->dma.guest.ptr.offset >>PAGE_SHIFT ; - kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >>PAGE_SHIFT ; + kmap_num =PFN_UP (src_extent); ret =ttm_bo_reserve (bo, true, false,NULL );if (unlikely (ret !=0 )) {
@@ -387,14 +401,16 @@ void vmw_kms_cursor_snoop(struct vmw_sur virtual =ttm_kmap_obj_virtual (&map, &is_iomem); -if (box->w ==VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) { +if (box->w ==VMW_CURSOR_SNOOP_WIDTH && + box->h ==VMW_CURSOR_SNOOP_HEIGHT && + cmd->dma.guest.pitch == image_pitch) {memcpy (srf->snooper.image, virtual,VMW_CURSOR_SNOOP_HEIGHT * image_pitch); }else { -/* Image is unsigned pointer. */ +/* The destination stride is in pixels. */ for (i =0 ; i < box->h; i++) -memcpy (srf->snooper.image + i * image_pitch, - virtual + i * cmd->dma.guest.pitch, +memcpy (srf->snooper.image + i *VMW_CURSOR_SNOOP_WIDTH , + virtual + (size_t )i * cmd->dma.guest.pitch, box->w * desc->pitchBytesPerBlock); } srf->snooper.id++;
Greg Kroah-Hartman
maintainerPATCH 133/281 drm/xe/i2c: cancel the client work on remove
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 611857adc9e7b0ee1239a0baf38498922ca5a12e upstream.
xe_i2c_notifier() stores the DesignWare adapter in i2c->adapter and schedules i2c->work when the adapter is registered under the xe I2C platform device, and xe_i2c_client_work() then instantiates the AMC client device on that adapter.
xe_i2c_remove() tears down the AMC, unregisters the client devices, the bus notifier and the adapter platform device, but it never drains i2c->work. A work item that is still queued or running when the adapter is unregistered dereferences i2c->adapter in i2c_new_client_device() after platform_device_unregister() has released the adapter. The work item is also embedded in the devm-allocated struct xe_i2c, so a work item still queued after the drm device devm unwind frees that allocation runs its callback on freed memory.
The bus notifier is the only thing that schedules this work, and it is unregistered after the client devices. An instance that is still queued when the teardown runs can therefore write i2c->client[XE_I2C_CLIENT_AMC] while the loop is unregistering and clearing the same array, and an AMC client it instantiates late is only cleaned up by the adapter's own child sweep in i2c_del_adapter().
Move bus_unregister_notifier() in front of the client teardown loop and cancel the work right after it, so no new instance can be scheduled and a queued instance is drained before the client array is touched. A running instance still finds a live adapter, since the adapter is unregistered later.
--- drivers/gpu/drm/xe/xe_i2c.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_i2c.c +4 -1
@@ -330,12 +330,15 @@ static void xe_i2c_remove(void *data)xe_i2c_irq_reset (xe);xe_amc_exit (i2c); +/* Stop the notifier from arming the client work before teardown. */ +bus_unregister_notifier (&i2c_bus_type, &i2c->bus_notifier); +cancel_work_sync (&i2c->work); +for (i =0 ; i <XE_I2C_MAX_CLIENTS ; i++) {i2c_unregister_device (i2c->client[i]); i2c->client[i] =NULL ; } -bus_unregister_notifier (&i2c_bus_type, &i2c->bus_notifier);xe_i2c_unregister_adapter (i2c); xe->i2c =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 134/281 drm/xe: Fix shrinker accounting double-subtraction on nested external pins
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit 83d5acca1f4f6132038ea88c72c5844f62e42d44 upstream.
xe_bo_pin_external() and xe_bo_unpin_external() support nested pins, since the underlying ttm_bo_pin()/ttm_bo_unpin() maintain a pin_count refcount rather than a boolean. However, the shrinker accounting calls xe_ttm_tt_account_subtract() and xe_ttm_tt_account_add() are invoked unconditionally on every pin_external()/unpin_external() call, instead of only on the transition into and out of the pinned state.
An external BO (dma-buf) can be pinned more than once while already pinned, for example when it has multiple attachments/importers, each independently calling xe_bo_pin_external(). Each such nested pin subtracts the BO's pages from the shrinker's accounting again, even though the BO's pages were already removed from consideration by the first pin. Symmetrically, each nested unpin adds them back again before the BO is actually unpinned. This desynchronizes the shrinker's page and object counts from reality, and since they are declared as signed long but interpreted as unsigned long in xe_shrinker_count(), the underflow can turn into an enormous shrinkable/purgeable page count, causing the shrinker to be invoked excessively under memory pressure.
Guard the accounting calls with the same pin-count transition checks already used to guard the pinned_link list maintenance, so accounting is only updated on the outermost pin and the final unpin.
While centralizing this logic into xe_bo_account_pin()/ xe_bo_account_unpin(), also close a second, related accounting gap affecting imported dma-bufs. For an imported bo's ttm_tt, xe's ttm_tt_populate hook (xe_ttm_tt_populate()) early-returns without calling xe_ttm_tt_account_add(), since TTM_TT_FLAG_EXTERNAL is set without TTM_TT_FLAG_EXTERNAL_MAPPABLE. However, TTM core's ttm_tt_populate() wrapper unconditionally marks the tt as populated on driver-hook success, so ttm_tt_is_populated() still reports true for it. xe_bo_account_pin()/xe_bo_account_unpin() trusted ttm_tt_is_populated() as a proxy for "these pages are accounted for by the shrinker", and would subtract/add pages for such a tt that were never added in the first place, again underflowing the shrinker's counts. This is reachable today via xe_bo_pin_external(), and would have become newly reachable via the fb-pin path once this patch routes __xe_pin_fb_vma() through xe_bo_pin_account() below, so fix it here rather than in a later patch, to avoid a commit in this series that introduces the regression before fixing it. Skip the accounting for imported bos, using the same EXTERNAL && !EXTERNAL_MAPPABLE test xe_ttm_tt_populate()/xe_ttm_tt_unpopulate() use to decide whether to act, via a new xe_ttm_bo_is_imported() helper (hoisted up from its only prior use site).
v2:
- Fix the critical issue caught by Sashiko AI review: the pin-count transition check introduced here was still bypassed by the fb-pin path (__xe_pin_fb_vma()/__xe_unpin_fb_vma()), which could leave a stale pinned_link entry and a permanent shrinker accounting leak when the fb-unpin performed the true last unpin. Addressed in a separate follow-up patch in this series rather than folded in here, since it is a distinct bug with its own Fixes: tag.
- Drop the unneeded local "last_unpin" variable in xe_bo_unpin_external(), restoring the original inline bo->ttm.pin_count == 1 check; it was a no-op rename not used by any of the new accounting helpers, and was going to be deleted again by the follow-up patch anyway.
v3:
- Exclude imported dma-bufs from the pin/unpin shrinker accounting, fixing another underflow caught by Sashiko AI review.
- Add a short comment on the backup-object pin site noting it's already populated/accounted at pin time, addressing (as a false-positive clarification, no code fix needed) a separate Medium-severity accounting-leak concern also caught by Sashiko AI review.
--- drivers/gpu/drm/xe/display/xe_fb_pin.c | 6 - drivers/gpu/drm/xe/xe_bo.c | 116 +++++++++++++++++++++++++-------- drivers/gpu/drm/xe/xe_bo.h | 2 3 files changed, 95 insertions(+), 29 deletions(-)
drivers/gpu/drm/xe/display/xe_fb_pin.c +3 -3
@@ -356,7 +356,7 @@ static struct i915_vma *__xe_pin_fb_vma(drm_exec_retry_on_contention (&exec);xe_validation_retry_on_oom (&ctx, &ret);if (!ret) -ttm_bo_pin (&bo->ttm); +xe_bo_pin_account (bo); }if (ret) goto err;
@@ -373,7 +373,7 @@ static struct i915_vma *__xe_pin_fb_vma( err_unpin:ttm_bo_reserve (&bo->ttm, false, false,NULL ); -ttm_bo_unpin (&bo->ttm); +xe_bo_unpin_account (bo);ttm_bo_unreserve (&bo->ttm); err:kfree (vma);
@@ -393,7 +393,7 @@ static void __xe_unpin_fb_vma(struct i91xe_ggtt_node_remove (vma->node, false);ttm_bo_reserve (&vma->bo->ttm, false, false,NULL ); -ttm_bo_unpin (&vma->bo->ttm); +xe_bo_unpin_account (vma->bo);ttm_bo_unreserve (&vma->bo->ttm);kfree (vma); }
drivers/gpu/drm/xe/xe_bo.c +90 -26
185 lines not on this page · raw message
drivers/gpu/drm/xe/xe_bo.h +2 -0
@@ -228,6 +228,8 @@ int xe_bo_pin_external(struct xe_bo *bo,int xe_bo_pin (struct xe_bo *bo,struct drm_exec *exec);void xe_bo_unpin_external (struct xe_bo *bo);void xe_bo_unpin (struct xe_bo *bo); +void xe_bo_pin_account (struct xe_bo *bo); +void xe_bo_unpin_account (struct xe_bo *bo);int xe_bo_validate (struct xe_bo *bo,struct xe_vm *vm,bool allow_res_evict,struct drm_exec *exec);
Greg Kroah-Hartman
maintainerPATCH 135/281 drm/xe: Fix stale pinned_link entry when fb-pin performs the final unpin
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit cf238c067eaae1cbfb00738e29219b9568d2313e upstream.
xe_bo_pin_external() and xe_bo_unpin_external() maintain the bo's pinned_link list membership in xe->pinned.late.external, based on whether the current call is the outermost pin or the final unpin. However, the same external bo's pin_count can also be raised and lowered directly by __xe_pin_fb_vma()/__xe_unpin_fb_vma(), which pin the bo as a display scanout buffer without going through xe_bo_pin_external()/xe_bo_unpin_external() at all, and have no notion of, or ownership over, pinned_link.
If a bo is pinned both externally (e.g. dma-buf export) and as an fb, and the external unpin happens first, xe_bo_unpin_external() correctly observes pin_count > 1 and leaves the bo on pinned_link. When the fb unpin later performs the true last unpin (pin_count 1 -> 0), it never touches pinned_link, leaving the bo linked on xe->pinned.late.external indefinitely. Once the bo is subsequently freed, this stale list entry points into freed memory, corrupting the list and risking a use-after-free the next time the list is walked or spliced.
The backup object pin/unpin sites in xe_bo_notifier_prepare_pinned()/ xe_bo_notifier_unprepare_pinned() have the same bypass characteristic, though they never add their bo to a pinned list, so are not affected by this particular list-corruption issue.
Move the pinned_link removal into xe_bo_account_unpin(), which already runs on every unpin path (kernel, external, framebuffer, backup object) right before the true 1 -> 0 pin_count transition. Since list_del_init() only operates on the node itself, this removal is list-agnostic and safe to perform regardless of which list (external or kernel_bo_present) the bo happens to be linked on, or which code path is performing the final unpin. Drop the now-redundant explicit list_del_init() calls in xe_bo_unpin_external() and xe_bo_unpin().
v2:
- New patch
v3:
- Rebased on changes to previous patch.
--- drivers/gpu/drm/xe/xe_bo.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +16 -9
@@ -483,12 +483,27 @@ static void xe_bo_account_pin(struct xe_* ttm_bo_unpin(), so that the check against the true 1->0 transition sees * the pin count that is about to be released. See xe_bo_account_pin() for * why imported bos are excluded. +* +* On the true last unpin, also removes @bo from whichever pinned-bo list +* (external or kernel_bo_present) it may currently be linked on, since a +* bo's final unpin can happen through a pin path (e.g. framebuffer, +* backup object) that has no notion of, or ownership over, that list. +* This is safe and list-agnostic: list_del_init() only needs the node +* itself, not knowledge of which list it is threaded through, and is a +* no-op if @bo is not linked. */ static void xe_bo_account_unpin (struct xe_bo *bo) {struct xe_device *xe =xe_bo_device (bo); +bool last_unpin = bo->ttm.pin_count ==1 ; + +if (last_unpin && !list_empty (&bo->pinned_link)) { +spin_lock (&xe->pinned.lock); +list_del_init (&bo->pinned_link); +spin_unlock (&xe->pinned.lock); + } -if (bo->ttm.pin_count ==1 && bo->ttm.ttm &&ttm_tt_is_populated (bo->ttm.ttm) && +if (last_unpin && bo->ttm.ttm &&ttm_tt_is_populated (bo->ttm.ttm) && !xe_ttm_bo_is_imported (&bo->ttm))xe_ttm_tt_account_add (xe, bo->ttm.ttm); }
@@ -3149,11 +3164,6 @@ void xe_bo_unpin_external(struct xe_bo *xe_assert (xe,xe_bo_is_pinned (bo));xe_assert (xe,xe_bo_is_user (bo)); -spin_lock (&xe->pinned.lock); -if (bo->ttm.pin_count ==1 && !list_empty (&bo->pinned_link)) -list_del_init (&bo->pinned_link); -spin_unlock (&xe->pinned.lock); -xe_bo_unpin_account (bo);/*
@@ -3172,10 +3182,7 @@ void xe_bo_unpin(struct xe_bo *bo)xe_assert (xe,xe_bo_is_pinned (bo));if (mem_type_is_vram (place->mem_type) || bo->flags &XE_BO_FLAG_GGTT ) { -spin_lock (&xe->pinned.lock);xe_assert (xe, !list_empty (&bo->pinned_link)); -list_del_init (&bo->pinned_link); -spin_unlock (&xe->pinned.lock);if (bo->backup_obj) {if (xe_bo_is_pinned (bo->backup_obj))
Greg Kroah-Hartman
maintainerPATCH 136/281 drm/bridge: th1520-dw-hdmi: Fix error check on dw_hdmi_probe() return value
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit add916cfcec5b71cb242db85b91b2437be7390cf upstream.
The error check after calling dw_hdmi_probe() was incorrectly checking the struct pointer hdmi instead of the probe result hdmi->dw_hdmi.
Fix this by checking the correct variable.
--- drivers/gpu/drm/bridge/th1520-dw-hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/bridge/th1520-dw-hdmi.c +2 -2
@@ -135,8 +135,8 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev) plat_data->priv_data = hdmi; hdmi->dw_hdmi =dw_hdmi_probe (pdev, plat_data); -if (IS_ERR (hdmi)) -return PTR_ERR (hdmi); +if (IS_ERR (hdmi->dw_hdmi)) +return PTR_ERR (hdmi->dw_hdmi);platform_set_drvdata (pdev, hdmi);
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerPATCH 137/281 drm/bridge: th1520-dw-hdmi: Fix remove() callback
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit 01c83795d50ccdb441f60e89ff50767cb2f6045a upstream.
This driver stores struct th1520_hdmi * in platform drvdata, but th1520_dw_hdmi_remove() was reading it back as struct dw_hdmi * and passing it to dw_hdmi_remove(), so teardown runs on the wrong pointer.
Retrieve struct th1520_hdmi * from platform drvdata and pass hdmi->dw_hdmi to dw_hdmi_remove().
--- drivers/gpu/drm/bridge/th1520-dw-hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/bridge/th1520-dw-hdmi.c +2 -2
@@ -145,9 +145,9 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)static void th1520_dw_hdmi_remove (struct platform_device *pdev) { -struct dw_hdmi *hdmi =platform_get_drvdata (pdev); +struct th1520_hdmi *hdmi =platform_get_drvdata (pdev); -dw_hdmi_remove (hdmi); +dw_hdmi_remove (hdmi->dw_hdmi); }static const struct of_device_id th1520_dw_hdmi_of_table[] = {
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerPATCH 138/281 drm/amdkfd: align SDMA doorbell base for shader doorbell writes
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Saleel Kudchadker <[email protected]>
commit f145d5b3f740de05d85257acdc82f6877180f5c6 upstream.
On GC 9.4.3, 9.4.4 and 9.5.0, doorbell writes issued from shaders are routed to an SDMA engine at 32-byte (4 doorbell index) granularity. SDMA engine doorbell ranges are 10 indices apart, so the range of every odd engine starts 2 indices into a 4-index block that begins in the previous engine's range. A shader ringing the doorbell of a queue on an odd engine therefore rings the previous engine instead. The intended queue never sees the doorbell, so its work stalls and the application hangs.
Align the per-engine doorbell base up to a 4-index boundary on these ASICs. Each engine only uses 4 of its 10 indices, so the aligned base plus the queue offset stays within the engine's range. Even engines are already aligned, so only the doorbell IDs of odd-engine queues change.
Only doorbells rung by the device itself are routed this way. Doorbell writes from the host, including the kernel's own SDMA rings, are not affected.
The doorbell ID of an SDMA queue is saved in CRIU checkpoints and checked again on restore. A checkpoint taken before this change that contains an SDMA queue on an odd engine will fail to restore with -EINVAL. This is intentional: the restored process still holds the old doorbell address, so accepting the stale ID would bring back the same stall.
Tested on MI300X with a shader-rung SDMA doorbell test: queues on odd engines hung before this change and complete with it.
v2: use u32 instead of uint32_t for the new locals (checkpatch)
v3: name the routing granularity, use dev->node_id, document the
layout invariants, describe impact
v4: express the granularity in doorbell indices, drop unrelated
cleanups, explain the CRIU restore behavior, add test note
--- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 32 ++++++++++++++---- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 7 +++ 2 files changed, 33 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +26 -6
@@ -599,12 +599,32 @@ static int allocate_doorbell(struct qcm_* we need the physical sdma engine id in order to get the * correct doorbell offset. */ -uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id * -get_num_all_sdma_engines (qpd->dqm) + - q->properties.sdma_engine_id] - + (q->properties.sdma_queue_id &1 ) - *KFD_QUEUE_DOORBELL_MIRROR_OFFSET - + (q->properties.sdma_queue_id >>1 ); +u32 engine_base = idx_offset[dev->node_id * +get_num_all_sdma_engines (qpd->dqm) + + q->properties.sdma_engine_id]; +u32 valid_id; + +/* +* With the aqua_vanjaram doorbell layout, a shader doorbell +* write whose 32-byte block starts in the previous engine's +* range rings that engine instead. Engine ranges are 10 +* indices apart (sdma_doorbell_range = 20 dwords, halved for +* 8-byte doorbells, in aqua_vanjaram_doorbell_index_init()), +* which puts odd engines 2 indices into a shared block. +* Aligning costs at most 2 indices, and 8 queues per engine use +* only 4 of the 10, so the aligned base stays in range. The +* 512-index mirror offset keeps the alignment. +*/ +if (KFD_GC_VERSION (dev) ==IP_VERSION (9 ,4 ,3 ) || +KFD_GC_VERSION (dev) ==IP_VERSION (9 ,4 ,4 ) || +KFD_GC_VERSION (dev) ==IP_VERSION (9 ,5 ,0 )) + engine_base =ALIGN (engine_base, +KFD_SDMA_SHADER_DOORBELL_GRANULARITY ); + + valid_id = engine_base + + (q->properties.sdma_queue_id &1 ) * +KFD_QUEUE_DOORBELL_MIRROR_OFFSET + + (q->properties.sdma_queue_id >>1 );if (restore_id && *restore_id != valid_id)return -EINVAL ;
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +7 -0
@@ -132,6 +132,13 @@*/ #define KFD_QUEUE_DOORBELL_MIRROR_OFFSET 512 +/* +* On GC 9.4.3, 9.4.4 and 9.5.0, doorbell writes issued from shaders are +* routed to an SDMA engine at 32-byte granularity, i.e. 4 indices with the +* 8-byte SDMA doorbells used on SOC15. +*/ +#define KFD_SDMA_SHADER_DOORBELL_GRANULARITY 4 +/** * enum kfd_ioctl_flags - KFD ioctl flags * Various flags that can be set in &amdkfd_ioctl_desc.flags to control how
Greg Kroah-Hartman
maintainerPATCH 139/281 drm/amdkfd: fix dma_buf reference leak in get_dmabuf_info
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haojie Li <[email protected]>
commit e6895021a328594368a2a19406a53ffca1ce51c7 upstream.
When kzalloc fails for metadata_buffer in amdgpu_amdkfd_get_dmabuf_info(), the function returns -ENOMEM directly without calling dma_buf_put(), leaking the dma_buf reference obtained earlier via dma_buf_get().
Fix both issues by:
- Adding an error check after the first amdgpu_bo_get_metadata() call
- Replacing the direct return with r = -ENOMEM and goto out_put to ensure dma_buf_put() is called on all error paths
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +6 -2
@@ -597,14 +597,18 @@ int amdgpu_amdkfd_get_dmabuf_info(struct/* first get metadata_size by buffer = NULL */ r =amdgpu_bo_get_metadata (bo,NULL ,0 , metadata_size,NULL ); +if (r) + goto out_put;/* user buf_size is bigger than bo metadata_size * allocate a buf at kernel space and copy */ if (*metadata_size <= buffer_size) { *metadata_buffer =kzalloc (*metadata_size,GFP_KERNEL ); -if (!*metadata_buffer) -return -ENOMEM ; +if (!*metadata_buffer) { + r = -ENOMEM ; + goto out_put; + } r =amdgpu_bo_get_metadata (bo, *metadata_buffer, *metadata_size,NULL , &metadata_flags);