Skip to contentSkip to conversation

6.18.55-rc1 review

PATCH In review Greg Kroah-Hartman 9 participants 404 messages Sep 30 – Oct 2 Page 1 of 3

Subsystems (2)
lore
Share & tools
lore

Greg Kroah-Hartman

author maintainer
#0 lore raw

cover 6.18.55-rc1 review

This is the start of the stable review cycle for the 6.18.55 release. There are 395 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 Fri, 02 Oct 2026 15:23:04 +0000. Anything received after that time might be too late.

The whole patch series can be found in one patch at:

	https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.55-rc1.gz

or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.18.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <[email protected]>

    Linux 6.18.55-rc1

Jiayuan Chen <[email protected]>
bpf: Reject key-less BTF for hash maps

Bernard Pidoux <[email protected]>
rose: don't warn on stray CALL_ACCEPTED/CLEAR_CONFIRMATION in state 3

Bernard Pidoux <[email protected]>
rose: use timer_shutdown_sync() for t0timer teardown

Bernard Pidoux <[email protected]>
rose: guard rose_transmit_link() against a NULL neighbour

Bernard Pidoux <[email protected]>
rose: keep the route needed for routing loop detection

Tejun Heo <[email protected]>
sched_ext: Derive SCX_RQ_IN_WAKEUP from the core enqueue flags

Shardul Bankar <[email protected]>
hfsplus: avoid double unload_nls() on mount failure

Liew Rui Yan <[email protected]>
mm/damon/core: fix unconditionally skip last region

Chunfeng Song <[email protected]>
rust: net: phy: fix off-by-one bit positions in device status accessors

Greg Kroah-Hartman <[email protected]>
Revert "rust: net: phy: fix off-by-one bit positions in device status accessors"

Xie Bo <[email protected]>
RISC-V: KVM: Serialize IMSIC attributes with vCPU migration

Jiakai Xu <[email protected]>
RISC-V: KVM: Fix null pointer dereference in kvm_riscv_aia_imsic_rw_attr()

Ilya Maximets <[email protected]>
net/sched: act_ct: avoid modifying shared unconfirmed ct entry

Ilya Maximets <[email protected]>
net/sched: act_ct: fix helper UAF due to extensions realloc

Melody Wang <[email protected]>
x86/sev: Make vTPM SVSM calls preemption-safe

Nikunj A Dadhania <[email protected]>
x86/sev: Remove redundant ghcbs_initialized checks around __sev_{get,put}_ghcb()

Borislav Petkov (AMD) <[email protected]>
x86/sev: Carve out the SVSM code into a separate compilation unit

Borislav Petkov (AMD) <[email protected]>
x86/sev: Add internal header guards

Borislav Petkov (AMD) <[email protected]>
x86/sev: Move the internal header

Dapeng Mi <[email protected]>
perf/x86/intel: Remove incorrect LionCove PEBS data-source constraints

Dapeng Mi <[email protected]>
perf/x86/intel: Update event constraints and cache_extra_regsfor LNL

Dapeng Mi <[email protected]>
perf/x86/intel: Fix GRT PEBS load/store direction for latency events, to fix sample classification

Dapeng Mi <[email protected]>
perf/x86/intel: Update event constraints and cache_extra_regsfor ADL

Yuqi Xu <[email protected]>
net: ipconfig: bound DHCP option construction

Thorsten Blum <[email protected]>
net: ipconfig: Remove outdated comment and indent code block

Théo Lebrun <[email protected]>
net: macb: fix dma_alloc_coherent() leak on macb_alloc() error paths

Chen Changcheng <[email protected]>
HID: alps: unregister DualPoint Stick input device on remove

Bastien Nocera <[email protected]>
HID: hid-alps: Use pm_ptr instead of #ifdef CONFIG_PM

Liz Fong-Jones <[email protected]>
PCI: Fix BAR resize for devices on a root bus

Christian Brauner <[email protected]>
super: make iterate_supers_type() deletion-safe

Longlong Xia <[email protected]>
mm/hugetlb: do not dissolve gigantic pages without runtime support

Usama Arif <[email protected]>
mm/hugetlb: create hstate_is_gigantic_no_runtime helper

Jinjiang Tu <[email protected]>

    mm/rmap: fix missing barrier between anon_vma init and vma->anon_vma publish

Lorenzo Stoakes <[email protected]>
mm/rmap: allocate anon_vma_chain objects unlocked when possible

shechenglong <[email protected]>
drm/client: fix restore of partially initialized client

Thomas Zimmermann <[email protected]>
drm/client: Pass force parameter to client restore

Thomas Zimmermann <[email protected]>
drm/client: Remove holds_console_lock parameter from suspend/resume

Wentao Liang <[email protected]>
drm/amdgpu: Fix acpi device leak in amdgpu_acpi_enumerate_xcc()

Ankit Nautiyal <[email protected]>
drm/i915/quirks: Limit eDP rate to HBR2 on HP Pavilion Plus 14-ew1

Jouni Högander <[email protected]>
drm/i915/psr: Disable PSR2 on Xiaomi Book Pro 14 2026 as a quirk

Jouni Högander <[email protected]>
drm/i915/psr: Fixes for Dell XPS DA14260 quirk

Jouni Högander <[email protected]>
drm/i915/psr: Disable Panel Replay on Dell XPS 14 DA14260 as a quirk

Viken Dadhaniya <[email protected]>
i2c: qcom-geni: Fix hardcoded clock index in SE_GENI_CLK_SEL

Xiang Mei <[email protected]>
vlan: require the MAC header to be present in __vlan_insert_inner_tag()

Hui Peng <[email protected]>
cgroup/cpuset: Return PERR_NOCPUS in remote_partition_enable() on subpartitions_cpus conflict

Waiman Long <[email protected]>
cgroup/cpuset: Ensure domain isolated CPUs stay in root or isolated partition

Waiman Long <[email protected]>
cgroup/cpuset: Move up prstate_housekeeping_conflict() helper

Jakub Kicinski <[email protected]>
net: tls: fix silent data drop under pipe back-pressure

Darrick J. Wong <[email protected]>
xfs: fix cursor and pointer handling when recovering iunlink buckets

Darrick J. Wong <[email protected]>
xfs: fix blockgc group quota scanning when usrquota isn't enforced

Darrick J. Wong <[email protected]>
xfs: drop dquot flush lock when we can't find a buffer to flush

Darrick J. Wong <[email protected]>
xfs: don't let hidden_space go negative in xfs_metafile_resv_init

Darrick J. Wong <[email protected]>
xfs: call xfs_dquot_set_prealloc_limits if we installed default rtb limits

Darrick J. Wong <[email protected]>
xfs: fix wild memcpy access when formatting ondisk rtrefcount btree roots

Darrick J. Wong <[email protected]>
xfs: fix rtgroup repair estimations

Darrick J. Wong <[email protected]>
xfs: check di_forkoff correctly in scrub

Darrick J. Wong <[email protected]>
xfs: use the correct reservations for rtrmap/refcount recovery

Darrick J. Wong <[email protected]>
xfs: don't call xfs_exchange_range_finish for a dry run

Darrick J. Wong <[email protected]>
xfs: check padding field in xfs_ioc_commit_range

Darrick J. Wong <[email protected]>
xfs: use correct jiffies comparison function in xchk_maybe_relax

Darrick J. Wong <[email protected]>
xfs: release orphanage dir inode if chown fails

Darrick J. Wong <[email protected]>
xfs: fix attr fork block count checks in xrep_inode_blockcounts

Darrick J. Wong <[email protected]>
xfs: don't assert when XFS_SCRUB_TYPE_HEALTHY scans return corruption

Zihan Xi <[email protected]>
smb: client: validate POSIX create context length

Zihan Xi <[email protected]>
smb: client: preserve create-context parsing errors

Zihan Xi <[email protected]>
smb: client: clean up failed cached directory opens

Zihan Xi <[email protected]>
smb: client: fix create context out-of-bounds reads

Hui Peng <[email protected]>

    Bluetooth: RFCOMM: fix NULL dereference of dlc->session in RFCOMM_CONNINFO

Aldo Ariel Panzardo <[email protected]>
Bluetooth: mgmt: fix race in read_unconf_index_list()

Aldo Ariel Panzardo <[email protected]>
Bluetooth: L2CAP: validate frame length before control and FCS access

Aldo Ariel Panzardo <[email protected]>
Bluetooth: ISO: release unused CIS holds after channel attach

Aldo Ariel Panzardo <[email protected]>
Bluetooth: ISO: balance the parent hold in hci_bind_bis()

Aldo Ariel Panzardo <[email protected]>
Bluetooth: hci_sock: reject out-of-range OCF values

Aldo Ariel Panzardo <[email protected]>
Bluetooth: hci_sock: validate event length before filtering

Aldo Ariel Panzardo <[email protected]>
Bluetooth: hci_conn: fix CIS hold ownership on reuse

Tan Chi <[email protected]>
RISC-V: KVM: Fix HSM hart status error propagation

Xie Bo <[email protected]>
RISC-V: KVM: Propagate interrupted G-stage faults

Myeonghun Pak <[email protected]>
RISC-V: KVM: Synchronize hrtimer callback during teardown

Fuad Tabba <[email protected]>
KVM: arm64: Transfer the hyp stack pages out of the host stage-2

Lorenzo Stoakes (ARM) <[email protected]>
KVM: arm64: nv: Fix null ptr deref on nested wp/unmap, teardown race

Lorenzo Stoakes (ARM) <[email protected]>
KVM: arm64: Fix spurious warning for benign stage 2 teardown race

Karl Mehltretter <[email protected]>
KVM: arm64: Fix AArch32 DBGBXVR<n> handling

Sean Christopherson <[email protected]>
KVM: SEV: Do cache maintenance on the source VM during intra-host migration

Sean Christopherson <[email protected]>
KVM: SEV: Free have_run_cpus during VM destruction even if VM is no longer SEV

Zeng Chi <[email protected]>
KVM: Don't treat reserved xarray entries as having memory attributes

David Ballesteros <[email protected]>
KVM: Ensure memory attributes xarray nodes are accounted to the caller's memcg

Anthony Krowiak <[email protected]>
s390/vfio-ap: fix KVM GISC and page leak when queue removed from host config

Niklas Schnelle <[email protected]>
s390/pci: Don't report recovery success on skipped recovery

Niklas Schnelle <[email protected]>
s390/pci: Report SCLP status on error events when no pdev is associated

Niklas Schnelle <[email protected]>
s390/pci: Fix missing device lock in zpci_report_status()

Niklas Schnelle <[email protected]>
s390/pci: Fix leak of struct pci_dev reference in zpci_report_status()

Peter Oberparleiter <[email protected]>
s390/cmf: Fix virtual vs physical address confusion

Vineeth Vijayan <[email protected]>
s390/cio: Fix NULL pointer dereference in ccw_device_get_util_str()

Ilya Titov <[email protected]>
pinctrl: sunxi: keep a shadow copy of the data register output latches

Myeonghun Pak <[email protected]>
pinctrl: single: free the IRQ on domain creation failure

Puranjay Mohan <[email protected]>
perf/core: Run sched_task() for PMUs with only CPU-wide events

Puranjay Mohan <[email protected]>

    perf/core: Fix NULL pmu_ctx passed to pmu->sched_task()

Helge Deller <[email protected]>
parisc: Increase kernel stack size to 32kb

Yehyeong Lee <[email protected]>
scsi: libiscsi_tcp: Check the data direction of a Data-In PDU

Myeonghun Pak <[email protected]>
nfc: trf7970a: power down on startup RX gain failure

Doruk Tan Ozturk <[email protected]>
nfc: port100: reject frames whose declared length exceeds the received data

Aamir Ahmed <[email protected]>
nfc: llcp: drop truncated I/RR/RNR PDUs in nfc_llcp_recv_hdlc()

Luxiao Xu <[email protected]>
nfc: fix use-after-free in nfc_get_local_general_bytes

Aohan Mei <[email protected]>
netfilter: nf_tables: skip expired catchall elements on insert and delete

Luxiao Xu <[email protected]>
netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read

Weiming Shi <[email protected]>
netfilter: ip6t_rpfilter: reject routes without inet6_dev

Wentao Liang <[email protected]>
net: usb: lan78xx: Fix URB reference leak in lan78xx_submit_deferred_urbs()

Ming Wang <[email protected]>
net: usb: cdc_mbim: add MeiG Smart SRM821 to ZLP whitelist

Zhang Yunfei <[email protected]>
net: txgbe: fix FDIR filter restore for VF rules

Abhishek Ojha <[email protected]>
net: phy: micrel: Advance register data pointer in write loop

Guangshuo Li <[email protected]>
net: ena: fix MMIO read buffer leak on probe failure

Guangshuo Li <[email protected]>
net: ena: fix PHC cleanup on probe failure

Fourie Zhang <[email protected]>
net: bridge: mdb: restart port group walk after deletion

Gajdos Tamás <[email protected]>
net: atl1e: fix soft lockup on out-of-range hw_next_to_clean read

Gajdos Tamás <[email protected]>
net: atl1c: fix soft lockup on out-of-range tpd_cons read

Ilya Maximets <[email protected]>
net: openvswitch: conntrack: fix helper UAF due to extensions realloc

Ilya Maximets <[email protected]>
net: openvswitch: conntrack: remove 'add_helper' dead code

Ilya Maximets <[email protected]>
net: openvswitch: conntrack: avoid modifying shared unconfirmed ct entry

Wentao Liang <[email protected]>
net: hisilicon: hns_dsaf_mac: fix mdio device leak in hns_mac_register_phy()

Gajdos Tamás <[email protected]>
net: atl1: fix soft lockup on out-of-range cmb_tpd_next_to_clean read

Zijie Huang <[email protected]>
net: arp: terminate device name before lookup

Myeonghun Pak <[email protected]>
net: airoha: npu: cancel wdt_work after releasing the WDT IRQ

Weiming Shi <[email protected]>
net/sched: reject IDR error pointers when deleting actions

Andrea Parri <[email protected]>
net/mlx5e: fix swapped IPv6 IPsec policy masks

Ralf Lici <[email protected]>
net/mlx5e: advertise MACsec offload only when supported

Wentao Liang <[email protected]>
net/mlx5: Fix rev_entry reference leak in mlx5_tc_ct_shared_counter_get()

Wei Jie LAW <[email protected]>
HID: wacom: fix OOB read in wacom_wac_pen_serial_enforce()

Junjie Cao <[email protected]>
HID: quirks: add ALWAYS_POLL quirk for SDINNOVATION gaming keyboard

Chen Changcheng <[email protected]>
HID: alps: fix use-after-free on input2 registration failure

Willem de Bruijn <[email protected]>
packet: use ubuf_info completion for TX_RING packets

Angel J <[email protected]>
PCI: of_property: Omit bus properties without a subordinate bus

SJ Park <[email protected]>
mm/damon/vaddr: avoid hw-driven pte updates during damon_hugetlb_mkold()

Jaewook You <[email protected]>
mm/hugetlb: preserve mremap address delta when skipping page tables

Karl Mehltretter <[email protected]>
gpio: tps65219: Fix TPS65214 GPIO direction programming

Karl Mehltretter <[email protected]>
gpio: tps65219: Use the variant-specific direction callback

Karl Mehltretter <[email protected]>
gpio: tps65219: Fix GPIO input value reads

Peiyang He <[email protected]>
drm/virtio: fix NULL pointer dereference on fence allocation failure

Peiyang He <[email protected]>
drm/virtio: fix memory leak of fence event on execbuffer failure

Matthew Brost <[email protected]>
drm/xe: Keep walking on SVM eviction failure

Szymon Acedański <[email protected]>
drm/xe: Limit sg segment size to PAGE_SIZE on Xen PV

Tangudu Tilak Tirumalesh <[email protected]>
drm/xe: harden adjust_idledly() against divide-by-zero and overflow

Matthew Auld <[email protected]>
drm/xe/vm: nuke PTs only after unlinking contested VMAs

Peiyang He <[email protected]>
drm/nouveau: don't bump pin count on failed re-pin in nouveau_bo_pin_locked()

Jonghyuk Kim(MalHyuk) <[email protected]>
drm/nouveau: RCU-free the scheduler-containing nouveau_sched

Wentao Liang <[email protected]>
drm/nouveau: Fix runtime PM leak in nouveau_connector_detect()

Wentao Liang <[email protected]>
drm/nouveau: Fix gem reference leak in validate_init()

Peiyang He <[email protected]>
drm/nouveau: fix double-free in nvif_vmm_dtor

Wentao Liang <[email protected]>
drm/nouveau: Fix bridge reference leak in nv1a_ram_new()

Guangshuo Li <[email protected]>
drm/nouveau: fix autosuspend cleanup during teardown

Peiyang He <[email protected]>
drm/nouveau/uvmm: fix UAF in nouveau_uvmm_sm when BO is in TTM_PL_SYSTEM

Wentao Liang <[email protected]>
drm/amdgpu: Fix vmid_wait fence leak in amdgpu_ring_init()

Wentao Liang <[email protected]>
drm/amdgpu: Fix runtime PM leak in amdgpu_debugfs_test_ib_show()

Wentao Liang <[email protected]>
drm/amdgpu: Fix last_update fence leak in amdgpu_vm_init()

Ivan Lipski <[email protected]>
drm/amd/display: Bump frame warning limit for clang builds of dml

Wentao Liang <[email protected]>
drm/amd/display: Fix dc stream excess put in dm_update_crtc_state()

Imre Deak <[email protected]>
drm/i915/dp_mst: Fix configuring TUs for a disconnected stream

Imre Deak <[email protected]>
drm/i915/dp_mst: Fix configuring FEC for a disconnected stream

Christian König <[email protected]>
drm/i915: fix incorrect RCU teardown order

Brajesh Gupta <[email protected]>
drm/imagination: Fix page count for page table for map() interface

Brajesh Gupta <[email protected]>
drm/imagination: Propagate map failures correctly from pvr_mmu_map_sgl()

Dongliang Qin <[email protected]>
rds: ib: Clear the sg list when mapping an MR fails

Hui Peng <[email protected]>
mctp: route: iterate socket tag list in mctp_lookup_prealloc_tag()

Zixuan Chai <[email protected]>
llc: reserve device headroom for allocated frames

Ridham Khurana <[email protected]>
gpio: zynq: fix runtime PM leak on request error path

Bartosz Golaszewski <[email protected]>
gpio: cdev: fix kernel stack leak to user-space in error path

Wentao Liang <[email protected]>
gpio: arizona: Fix runtime PM leak in arizona_gpio_direction_out()

Hui Peng <[email protected]>
ipv6: sr: enforce exact attribute length for SEG6_ATTR_DST

Norbert Szetei <[email protected]>
ipv6: do not let ipv6_find_hdr() return an offset past the packet end

Fan Wu <[email protected]>
ipe: protect the dm-verity root hash with RCU

Fan Wu <[email protected]>
ipe: fix use-after-free when auditing a newly loaded policy

Wentao Liang <[email protected]>
fsl/fman: Fix clk reference leak in read_dts_node()

Josef Bacik <[email protected]>
writeback: report a Tasks-RCU quiescent state per cgwb drain pass

Pavankumar Kondeti <[email protected]>
workqueue: Fix NULL current_pwq deref in flush dependency check

Patrick Lu (Anthropic) <[email protected]>
writeback: bound cleanup_offline_cgwb() rescans by rotating scanned inodes

Christian Brauner <[email protected]>
fs/ntfs3: use d_instantiate_new() in ntfs_create_inode() and murder syzbot's "WARNING in do_new_mount" saga

Hui Peng <[email protected]>
fou: reject omitted FOU_ATTR_IPPROTO on FOU_ENCAP_DIRECT

Guopeng Zhang <[email protected]>
cgroup/pids: Restore pids.events notifications in local mode

Holger Dengler <[email protected]>
crypto: s390/hmac - Generate intermediate CV for API partial block handling

Andrea Parri <[email protected]>
bpf: fs/xattr: don't assume the inode is locked in path_unlink/path_rmdir

Myeonghun Pak <[email protected]>
bna: prevent IOC timer rearm during teardown

Matthias Goergens <[email protected]>
ata: libata-scsi: bound the ATA passthru sense descriptor writes

David Carlier <[email protected]>
arm64: errata: match the target implementation CPU's own MIDR

Fuad Tabba <[email protected]>
arm64/boot: Disable trapping of PMZR_EL0 writes to EL2

Dairui Zhang <[email protected]>
af_packet: fix integer overflow in prb_calc_retire_blk_tmo()

Aohan Mei <[email protected]>
sctp: discard the rest of the packet on a stale-cookie error

Willem de Bruijn <[email protected]>
tcp: prevent collapsing skbs across boundary in rtx queue

Eric Dumazet <[email protected]>
tipc: reject invalid and unexpected GRP_ACK_MSG to prevent bc_ackers underflow

Willem de Bruijn <[email protected]>
virtio_net: copy zerocopy frags in start_xmit without NAPI

Mario Limonciello <[email protected]>
x86/PCI: Disable enhanced atomics on AMD NBIO 7.7 and 7.11

Masami Hiramatsu (Google) <[email protected]>
x86/mce: Fix hardware debug register corruption on task migration

Pablo Neira Ayuso <[email protected]>
netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase

Pablo Neira Ayuso <[email protected]>
rculist: add list_splice_rcu() for private lists

Mark Amirkan <[email protected]>
mptcp: return sk_wait_data() errors from recvmsg()

Zhan Xusheng <[email protected]>
sched/core: Account PSI IRQ time to the execution context, not the scheduling context

Namhyung Kim <[email protected]>
perf/core: Fix a refcount leak in attach_perf_ctx_data()

Sean Christopherson <[email protected]>
perf/x86/intel: Make @data a mandatory param for intel_guest_get_msrs()

Sean Christopherson <[email protected]>
perf/x86/intel: Don't pointlessly context switch DS_AREA (and PEBS config) if PEBS is unused

Sean Christopherson <[email protected]>
perf/x86/intel: Don't write PEBS_ENABLED on host<=>guest xfers if CPU has PEBS isolation, to fix stuck PEBS_ENABLED

Sean Christopherson <[email protected]>
perf/x86/intel: Ensure KVM guest PEBS path doesn't set unwanted PERF_GLOBAL_CTRL bits

Hui Peng <[email protected]>

    autofs: fix sbi->pipe file reference leak in autofs_kill_sb()

Eric Dumazet <[email protected]>
vlan: ensure sufficient headroom in vlan_dev_hard_header()

Eric Dumazet <[email protected]>
net/sched: sch_teql: fix shadowed err in __teql_resolve()

Eric Dumazet <[email protected]>
bridge: check llc_mac_hdr_init() return value in br_send_bpdu()

Eric Dumazet <[email protected]>
llc: fix skb UAF and leaks on llc_mac_hdr_init() failure

Eric Dumazet <[email protected]>
gve: DQO: reject TSO packets with an out of range MSS

Eddie Phillips <[email protected]>
gve: fix TX drop when GSO MSS is too small for hw

Eric Dumazet <[email protected]>
gve: DQO: fix header length used by gve_can_send_tso() for UDP GSO

Ankit Garg <[email protected]>
gve: add support for UDP GSO for DQO format

Ankit Garg <[email protected]>
gve: Enable hw-gro by default if device supported

Ankit Garg <[email protected]>
gve: Advertise NETIF_F_GRO_HW instead of NETIF_F_LRO

Ankit Garg <[email protected]>
gve: Allow ethtool to configure rx_buf_len

Ankit Garg <[email protected]>
gve: Use extack to log xdp config verification errors

Ankit Garg <[email protected]>
gve: Consolidate and persist ethtool ring changes

Coia Prant <[email protected]>
net: ethernet: stmmac: dwmac-rk: fix bulk clock leak when the PHY clock fails

Ginger Li <[email protected]>

    tipc: Fix a data race on mon->peer_cnt in mon_timeout()

Sidraya Jayagond <[email protected]>
net/smc: fix UAF on lgr list traversal in smcr_port_err()

Sang-Hoon Choi <[email protected]>
nfp: hold IPsec RX state under the XArray lock

Aleksei Sviridkin <[email protected]>
net: phylink: record the PHY only once bringup cannot fail

Yilin Zhang <[email protected]>
tcp: fix use-after-free of retransmit_skb_hint in tcp_send_synack()

Aleksei Sviridkin <[email protected]>
net: dsa: mt7530: leave the MDIO IRQ mappings to regmap-irq

Aleksei Sviridkin <[email protected]>
net: dsa: mt7530: fix NULL dereference on unbind of MT7531 and MT7621

Haseeb Malik <[email protected]>
macsec: initialize SecY before registering the netdevice

David Dai <[email protected]>
bonding: crypto offload enabled, non-offload slave failover, rekey failed

Pengpeng Hou <[email protected]>
drm/imagination: clamp freelist reconstruction requests

Norbert Szetei <[email protected]>
net: xps: reject an out of range traffic class

Sanghyun Park <[email protected]>
vxlan: use one headroom snapshot for neighbour replies

Xuanqiang Luo <[email protected]>
ip_gre: Reject enabling collect metadata through changelink

Florian Fainelli <[email protected]>
net: bcmgenet: mask DMA_TIMEOUT_MASK when reading DMA_RING0_TIMEOUT

Florian Fainelli <[email protected]>
net: bcmgenet: validate Ethernet address in bcmgenet_set_mac_addr

Florian Fainelli <[email protected]>
net: bcmgenet: do not skip WoL power up on GENET V1

Florian Fainelli <[email protected]>
net: bcmgenet: initialize u64 stats seq counter for all queues

Florian Fainelli <[email protected]>
net: bcmgenet: fix 64-bit RTNL stats reading in ethtool on 32-bit systems

Lorenzo Bianconi <[email protected]>

    net: stmmac: clear stale buf->page after recycling on skb build failure

Ivan Delalande <[email protected]>
tg3: use random MAC address when tg3_get_device_address fails

Johan Almbladh <[email protected]>
bpf: Fix BSWAP 32 and 16 on MIPS64

Johan Almbladh <[email protected]>
bpf: Fix immediate JMP JEQ/JNE on MIPS32

Ido Schimmel <[email protected]>

    vrf: Stop corrupting skb->csum when capturing CHECKSUM_COMPLETE packets

Shihuang Liu <[email protected]>
net: skbuff: fix pull-bound underflow in skb_checksum_setup_ipv6()

Jakub Kicinski <[email protected]>
veth: manage XDP program pointers during channel resize

Nicolai Buchwitz <[email protected]>
net: bcmgenet: stop Tx NAPI before disabling the queues

Victor Nogueira <[email protected]>
net/sched: act_gate: budget the per-entry list in get_fill_size

Deepanshu Kartikey <[email protected]>

    nfc: pn533: fix OOB read in pn533_acr122_is_rx_frame_valid()

Ömer Mete Kaya <[email protected]>
nfc: llcp: fix slab-out-of-bounds reads when logging service names

Ömer Mete Kaya <[email protected]>
nfc: llcp: fix WKS SAP hijacking via prefix match in nfc_llcp_wks_sap()

Ömer Mete Kaya <[email protected]>
nfc: llcp: fix -ENOMEM on connect with zero-length service name

Pengpeng Hou <[email protected]>
nfc: st21nfca: validate ISO15693 inventory length

Cong Nguyen <[email protected]>
nfc: llcp: fix sdreq TLV list leak on parse/alloc/send failure

Chris Gellermann <[email protected]>
nfc: virtual_ncidev: Add missing ioctl compat handler

Chris Gellermann <[email protected]>
selftests/nci: Fix out-of-bounds store on thread join

Chaithanya Lagisetty <[email protected]>
selftests: nci: Fix uninitialized family ID on missing attribute

Lee Jones <[email protected]>
nfc: llcp: Fix race condition in accept_queue lifecycle

Lei Zhu <[email protected]>
selftests: nci: Correct pthread_create return value check

Aldo Ariel Panzardo <[email protected]>
nfc: llcp: Fix list corruption / refcount desync in nfc_llcp_recv_dm()

Pengpeng Hou <[email protected]>
nfc: st21nfca: validate received frame size

Pengpeng Hou <[email protected]>
nfc: nfcmrvl: validate helper command length before pull

Weiming Shi <[email protected]>
bpf: Reject dev-bound-only programs on other devices

Bernard Ladenthin <[email protected]>
net/sched: fix potential stack infoleak in em_text_dump()

Björn Töpel <[email protected]>
eth: fbnic: Avoid rounding zero ring sizes

Maxime Chevallier <[email protected]>
net: stmmac: selftests: Account for alignment shift on dwmac1000 for Jumbo test

Maxime Chevallier <[email protected]>
net: stmmac: dwmac4: Use the correct bufzise when the len is exactly 8K

Maxime Chevallier <[email protected]>
net: stmmac: selftests: Capture all packets for vlan checks

Maxime Chevallier <[email protected]>

    net: stmmac: selftests: Check the dev->features for S-TAG offload testing

Maxime Chevallier <[email protected]>
net: stmmac: selftests: Support running selftests on DSA conduits

Xin Long <[email protected]>
sctp: hold asoc or transport before mod_timer() in timer handlers

Bernardo Soares <[email protected]>
net/mlx5: Bridge, don't fail unlink of untracked/unsupported peer ports

Bernardo Soares <[email protected]>
net/mlx5: Bridge, don't fail switchdev events of sibling eswitch ports

Zhao Gongyi <[email protected]>
bpf, sockmap: Reject max_entries > INT_MAX in sock_map_alloc

Emil Tsalapatis <[email protected]>
bpf: Fix bpf_sock context code generation

Emil Tsalapatis <[email protected]>
bpf: Fix bounds check for skb-backed dynptrs

Manaf Meethalavalappu Pallikunhi <[email protected]>
thermal: gov_step_wise: Fix stale mitigation vote with non-zero lower bounds

Coia Prant <[email protected]>
net: pcs: xpcs: fix clock reference leak on xpcs_init_clks failure

Jakub Kicinski <[email protected]>
genetlink: report the real command id for dump-only ops in policy dumps

bui duc phuc <[email protected]>
net: ethernet: ti: netcp: fix pm_runtime usage counter leak on error

Muhammad Bilal <[email protected]>
net: spacemit: clear TX descriptor on fragment mapping failure

Mikhail Zaslonko <[email protected]>
s390/debug: Fix NULL pointer dereference in debug_info_copy()

Mikhail Zaslonko <[email protected]>
s390/debug: Do not register views for failed static debug areas

Nemesa Garg <[email protected]>
drm/i915/psr: Clear stale sel fetch enable bits on sel fetch disable

Myeonghun Pak <[email protected]>
tg3: clean up PHYLIB resources on probe failure

Shardul Bankar <[email protected]>
udp: remove a disconnected socket from the 4-tuple hash table

Shardul Bankar <[email protected]>
udp: relocate a connected socket in the 4-tuple hash table on re-connect

Kuniyuki Iwashima <[email protected]>
ipv6: Fix dst leak for uncached routes.

Pengpeng Hou <[email protected]>
net: usb: sr9700: include receive overhead in the length check

Ivan Vecera <[email protected]>
dpll: use exact lookup for reference sync pin id

Kuniyuki Iwashima <[email protected]>
ipv6: Prevent rt6_insert_exception() for dying fib6_info.

Ratheesh Kannoth <[email protected]>
octeontx2-af: Fix memory scaling limitation in SR-IOV mode

Hui Peng <[email protected]>
Bluetooth: RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame()

Ravindra <[email protected]>
Bluetooth: btintel_pcie: validate device-supplied DMA indices

Hui Peng <[email protected]>
Bluetooth: bnep: fix out-of-bounds reads on short RX/TX frames and control fallthrough

Ralf Lici <[email protected]>
ovpn: reject invalid peer VPN addresses

Ralf Lici <[email protected]>
ovpn: reject multipeer peers without VPN addresses

Ralf Lici <[email protected]>
ovpn: reject duplicate peer VPN addresses

Ralf Lici <[email protected]>
ovpn: always unhash old VPN addresses before rehashing

Ralf Lici <[email protected]>
ovpn: replace bind when clearing stale local source

Ralf Lici <[email protected]>
ovpn: replace bind when learning local endpoint

Ralf Lici <[email protected]>
ovpn: validate peer state before caching UDP dst

Ralf Lici <[email protected]>
ovpn: track UDP socket route key for peer dst cache

Ralf Lici <[email protected]>
ovpn: skip UDP source validation for unspecified addresses

Ralf Lici <[email protected]>
ovpn: preserve IPv6 scope id for netlink peer endpoints

Li Youhong <[email protected]>
drm/bridge: samsung-dsim: fix TE GPIO lifetime for host attach

Benjamin Leggett <[email protected]>
drm/virtio: sync shmem backing on guest-bound transfers

Dmitry Osipenko <[email protected]>
Revert "drm/virtio: Allow importing prime buffers when 3D is enabled"

Junrui Luo <[email protected]>
drm/virtio: release the GEM object on virtio_gpu_vram_create() errors

Junrui Luo <[email protected]>
drm/virtio: fix object leaks in virtio_gpu_resource_create_blob_ioctl()

Junrui Luo <[email protected]>
drm/virtio: fix object leak in virtio_gpu_resource_create_ioctl()

Junrui Luo <[email protected]>
drm/virtio: fix object leak when drm_gem_handle_create() fails

Jamal Hadi Salim <[email protected]>
net/sched: sch_hfsc: bound the classify inner-filter walk with a drift budget

Yuqi Xu <[email protected]>
bpf: Check params size before reading reserved fields

Aamir Ahmed <[email protected]>
net: usb: catc: bound the RX packet length in catc_rx_done()

Kumar Kartikeya Dwivedi <[email protected]>
bpf: Bound ownership depth through local kptrs and graph roots

Yiqi Sun <[email protected]>
sctp: avoid livelock while updating retransmit path

Alexander Duyck <[email protected]>
eth: fbnic: Handle FW mailbox completions flagged with an error

Mike Marciniszyn (Meta) <[email protected]>
eth fbnic: Add debugfs hooks for firmware mailbox

Mohsin Bashir <[email protected]>
eth: fbnic: Reuse RX mailbox pages

Alexander Duyck <[email protected]>
eth: fbnic: Set AW_FLUSH_MODE alongside AW_FLUSH when flushing the mailbox

Alexander Duyck <[email protected]>
eth: fbnic: reset num_napi when the napi vectors are freed

Björn Töpel <[email protected]>
eth: fbnic: Handle maximum standalone channels

Kuniyuki Iwashima <[email protected]>
ip6_gre: Call ip6erspan_tunnel_unlink_md() in ip6erspan_changelink().

Lorenzo Bianconi <[email protected]>
net: ethernet: mtk_eth_soc: unregister net_devices in case of probe failure

Jérémy Jean <[email protected]>
net: gue: reject invalid REMCSUM offsets

Nguyen Ngoc Thang <[email protected]>
net/sched: act_ct: don't WARN on benign flow_offload_alloc() failure

Giuseppe Ranieri <[email protected]>
drm/nouveau/disp: don't reject HDMI config on cards without SCDC

Francesco Magazzu <[email protected]>
drm/nouveau/clk: don't clobber reclock status when restoring volt/fan

Dan Carpenter <[email protected]>
drm/nouveau/clk: fix list cursor use after loop in nvkm_clk_ustate_update

Joseph Qi <[email protected]>
ocfs2: make ocfs2_calc_xattr_init() return void

Zeng Heng <[email protected]>
arm64: io: Reject non-user protection in ioremap_prot()

Naman Gulati <[email protected]>
netfilter: ctnetlink: fix suspicious RCU usage in expect_iter_name

Julian Anastasov <[email protected]>
ipvs: revalidate ihl before icmp_send

Karl Mehltretter <[email protected]>
netfilter: nft_synproxy: use the family-aware checksum helper

Florian Westphal <[email protected]>
netfilter: nfnetlink_queue: hold nfnl mutex in event notifier

Jérémy Jean <[email protected]>
netfilter: flowtable: publish HW_DEAD after worker is done

Linkui Xiao <[email protected]>

    ipv4: fib: fix data-race and stale genid check around nh->nh_saddr

Kumar Kartikeya Dwivedi <[email protected]>
libbpf: Reject truncated ldimm64 CO-RE relocations

Kumar Kartikeya Dwivedi <[email protected]>
bpf: Restrict CO-RE poisoning to relocatable instructions

Shay Drory <[email protected]>
net/mlx5: devcom, Base component size on linked devices

Heyang Tan <[email protected]>
octeontx2-af: use seq_file for rsrc_alloc debugfs

Kyle Hendry <[email protected]>
net: pcs: rzn1-miic: Fix config array initialization

Jamal Hadi Salim <[email protected]>
net/sched: cls_u32: fix manual hash table handle IDR aliasing

Björn Töpel <[email protected]>
eth: fbnic: Fix payload page pool error cleanup

Weiming Shi <[email protected]>
bpf: Skip unsettled links in link iterator

Zhiling Zou <[email protected]>
xsk: Use a 32-bit compare in xsk_map_gen_lookup

Julian Sun <[email protected]>
fs: avoid repeated scans in evict_inodes()

Vineeth Vijayan <[email protected]>
s390/cio: Guard PMCW field accesses with dnv check

Vineeth Vijayan <[email protected]>
s390/cio: Check pmcw.dnv before pmcw.ena in I/O entry points

Vineeth Vijayan <[email protected]>
s390/cio: Fix cio_update_schib() to not cache invalid schib

Karl Mehltretter <[email protected]>
s390/pci/docs: Fix sriov_numvfs attribute name

Niklas Schnelle <[email protected]>
docs: s390/pci: Improve and update PCI documentation

Bart Van Assche <[email protected]>
scsi: megaraid_sas: Protect megasas_get_ctrl_info() in megasas_resume()

Eva Kurchatova <[email protected]>
selftests: cgroup: give the O_TMPFILE open in get_temp_fd() a mode

Lee Jones <[email protected]>
Bluetooth: mgmt: Dequeue pending mesh_send_sync entries on cancel

Zijun Hu <[email protected]>
Bluetooth: btnxpuart: Fix skb leak in nxp_process_fw_dump()

Christiano Amora <[email protected]>
Bluetooth: SMP: reject Security Request over BR/EDR

Andre Przywara <[email protected]>
pinctrl: sunxi: A523: fix voltage withstand encoding

ZHOU Jiaxiang <[email protected]>
scsi: sd_zbc: Reject disks with too many zones

Ran Hongyun <[email protected]>
squashfs: Add dictionary size range check to prevent shift-out-of-bounds

Mark Brown <[email protected]>
KVM: arm64: Fix FGT mapping for HFGITR_EL2.nGCSEPP

Karl Mehltretter <[email protected]>
KVM: arm64: Return -EINVAL for an empty SMCCC filter range at base 0

Fuad Tabba <[email protected]>
KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2

Fuad Tabba <[email protected]>
KVM: arm64: Include VM type when checking VM capabilities in pKVM

Fuad Tabba <[email protected]>
KVM: arm64: Fix MTE flag initialization for protected VMs

Marc Zyngier <[email protected]>
KVM: arm64: vgic-v3: Fix GICv3 trapping in protected mode

Fuad Tabba <[email protected]>
KVM: arm64: Do not clear VM-wide SVE feature on vCPU init failure

Fuad Tabba <[email protected]>
KVM: arm64: Validate the SVE vector length in pkvm_vcpu_init_sve()

Fuad Tabba <[email protected]>
KVM: arm64: vgic-its: Skip unreachable devices instead of failing the save

Fuad Tabba <[email protected]>
KVM: arm64: vgic-its: Free the caches when GITS_BASER changes

SeungJu Cheon <[email protected]>
RISC-V: KVM: Fix perf-backed counter accounting across stop and read

SeungJu Cheon <[email protected]>
RISC-V: KVM: Report snapshot write failure to the guest

SeungJu Cheon <[email protected]>
RISC-V: KVM: Preserve firmware counter value across stop/start

Zongmin Zhou <[email protected]>
KVM: riscv: Fix NACL hfence entry update order

Benjamin Tissoires <[email protected]>
HID: bpf: fix __hid_bpf_hw_check_params report length

Slawomir Stepien <[email protected]>
HID: amd_sfh: Validate PCI BAR size before mapping

Sean Anderson <[email protected]>
pinctrl: meson: Fix typo in s4 group name

Donggeun Yoo <[email protected]>
bpf, arm64: set up the frame pointer for the exception callback

Geliang Tang <[email protected]>
bpf, sockmap: Fix self-redirect copied_seq double-counting

Pu Lehui <[email protected]>
bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk

Kumar Kartikeya Dwivedi <[email protected]>
bpf: Register dtor for freeing special fields

Jiayuan Chen <[email protected]>
bpf: Fix out-of-bounds read of rtt_min in sock_ops

Jose Fernandez (Anthropic) <[email protected]>
bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()

Jim Mattson <[email protected]>
KVM: x86/pmu: Move Intel PMU global MSRs to intel_is_valid_msr()

Oscar Priego Verdugo <[email protected]>
HID: elecom: fix bus type for M-XGL20DLBK

Lovekesh Solanki <[email protected]>
HID: multitouch: Add report ID mismatch quirk for ASUS ROG Z13 Folio

Jiayuan Chen <[email protected]>
tcp: Skip cond_resched() in inet_csk_listen_stop() under BPF context

Jiayuan Chen <[email protected]>
bpf: Fix out-of-bounds read of sk_protocol in bpf_sock_destroy()

Jiayuan Chen <[email protected]>
bpf: Fix divide-by-zero in btf_struct_walk()

Sven Schnelle <[email protected]>
selftests/ftrace: Fix unique symbol check in kprobe_non_uniq_symbol.tc

Weiming Shi <[email protected]>
bpf: Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL

Daniel Borkmann <[email protected]>
bpf: Fix bpf_skb_change_tail wrt csum partial skbs

Steffen Eiden <[email protected]>
s390/uv: Prevent potential out-of-bounds read

Steffen Eiden <[email protected]>
s390/uv: Fix loop condition in uv_find_secrets

Claudio Imbrenda <[email protected]>
KVM: s390: Fix IRQ injection with SIGP Stop and Store Status

Mostafa Saleh <[email protected]>
remoteproc: qcom_q6v5_adsp: Fix iommu_unmap() usage

Sean Rhodes <[email protected]>
ALSA: hda/realtek: Add StarFighter HDA SSID

Sean Rhodes <[email protected]>
ALSA: hda/realtek: Limit Star Labs internal mic boost

Leo Li <[email protected]>
drm/amd/display: Atomize IRQ register read/modify/write ops

Wenwu Hou <[email protected]>
erofs: fix large folio race in erofs_fscache_req_complete

Darrick J. Wong <[email protected]>
xfs: don't stash removename operations with unknown ftype

-------------

Diffstat:

 Documentation/arch/arm64/booting.rst               |   1 +
 Documentation/arch/s390/pci.rst                    | 144 +++++---
 Makefile                                           |   4 +-
 arch/arm64/include/asm/el2_setup.h                 |   9 +-
 arch/arm64/include/asm/io.h                        |   3 +-
 arch/arm64/include/asm/kvm_pkvm.h                  |  10 +-
 arch/arm64/kernel/cpu_errata.c                     |  15 +-
 arch/arm64/kvm/arm.c                               |   4 +-
 arch/arm64/kvm/emulate-nested.c                    |   2 +-
 arch/arm64/kvm/hyp/nvhe/pkvm.c                     |  38 +-
 arch/arm64/kvm/hyp/nvhe/setup.c                    |  10 +
 arch/arm64/kvm/hyp/nvhe/sys_regs.c                 |   5 +
 arch/arm64/kvm/hypercalls.c                        |   3 +-
 arch/arm64/kvm/mmu.c                               |  15 +-
 arch/arm64/kvm/nested.c                            |  15 +-
 arch/arm64/kvm/sys_regs.c                          |   1 +
 arch/arm64/kvm/vgic/vgic-its.c                     |  43 ++-
 arch/arm64/net/bpf_jit_comp.c                      |   2 +
 arch/mips/net/bpf_jit_comp32.c                     |   2 +-
 arch/mips/net/bpf_jit_comp64.c                     |   3 +-
 arch/parisc/include/asm/thread_info.h              |   2 +-
 arch/riscv/kvm/aia_imsic.c                         |  11 +-
 arch/riscv/kvm/mmu.c                               |   2 +
 arch/riscv/kvm/nacl.c                              |  20 +-
 arch/riscv/kvm/vcpu_exit.c                         |   2 +-
 arch/riscv/kvm/vcpu_pmu.c                          |  33 +-
 arch/riscv/kvm/vcpu_sbi_hsm.c                      |   4 +-
 arch/riscv/kvm/vcpu_timer.c                        |   5 +-
 arch/s390/crypto/hmac_s390.c                       |   5 +-
 arch/s390/include/asm/debug.h                      |   8 +-
 arch/s390/kernel/debug.c                           |  15 +-
 arch/s390/kernel/uv.c                              |   8 +-
 arch/s390/kvm/interrupt.c                          |  72 ++--
 arch/s390/pci/pci_event.c                          |   7 +-
 arch/s390/pci/pci_report.c                         |  32 +-
 arch/s390/pci/pci_report.h                         |   4 +-
 arch/x86/boot/startup/sev-startup.c                |   3 +-
 arch/x86/coco/sev/Makefile                         |   2 +-
 arch/x86/coco/sev/core.c                           | 388 +--------------------
 .../asm/sev-internal.h => coco/sev/internal.h}     |  32 ++
 arch/x86/coco/sev/noinstr.c                        |   7 +-
 arch/x86/coco/sev/svsm.c                           | 362 +++++++++++++++++++
 arch/x86/coco/sev/vc-handle.c                      |   3 +-
 arch/x86/events/intel/core.c                       |  79 +++--
 arch/x86/events/intel/ds.c                         |  36 +-
 arch/x86/kernel/cpu/mce/core.c                     |  27 +-
 arch/x86/kvm/pmu.c                                 |   8 -
 arch/x86/kvm/svm/sev.c                             |  18 +-
 arch/x86/kvm/vmx/pmu_intel.c                       |   3 +
 arch/x86/pci/fixup.c                               |  99 ++++++
 drivers/ata/libata-scsi.c                          |  10 +-
 drivers/bluetooth/btintel_pcie.c                   |  16 +
 drivers/bluetooth/btnxpuart.c                      |   8 +-
 drivers/dpll/dpll_netlink.c                        |   3 +-
 drivers/gpio/gpio-arizona.c                        |   8 +-
 drivers/gpio/gpio-tps65219.c                       |  12 +-
 drivers/gpio/gpio-zynq.c                           |  10 +-
 drivers/gpio/gpiolib-cdev.c                        |  32 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c        |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   8 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c           |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c             |   1 +
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |   8 +-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h  |  12 +
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c |   3 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |   3 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c  |  62 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h  |  28 ++
 drivers/gpu/drm/amd/display/dc/dml/Makefile        |   6 +-
 drivers/gpu/drm/bridge/samsung-dsim.c              |   2 +-
 drivers/gpu/drm/clients/drm_fbdev_client.c         |  28 +-
 drivers/gpu/drm/clients/drm_log.c                  |   4 +-
 drivers/gpu/drm/drm_client_event.c                 |  20 +-
 drivers/gpu/drm/drm_fb_helper.c                    |  24 +-
 drivers/gpu/drm/drm_file.c                         |   2 +-
 drivers/gpu/drm/drm_modeset_helper.c               |   6 +-
 drivers/gpu/drm/i915/display/intel_cursor.c        |   7 +-
 drivers/gpu/drm/i915/display/intel_display_types.h |   2 +
 drivers/gpu/drm/i915/display/intel_dp_mst.c        |  24 +-
 drivers/gpu/drm/i915/display/intel_dp_mst.h        |   2 +
 drivers/gpu/drm/i915/display/intel_link_bw.c       |   3 +-
 drivers/gpu/drm/i915/display/intel_psr.c           |  26 ++
 drivers/gpu/drm/i915/display/intel_quirks.c        |  37 +-
 drivers/gpu/drm/i915/display/intel_quirks.h        |   2 +
 drivers/gpu/drm/i915/display/skl_universal_plane.c |   9 +-
 drivers/gpu/drm/i915/gem/i915_gem_object.c         |   2 +-
 drivers/gpu/drm/i915/i915_driver.c                 |   6 +-
 drivers/gpu/drm/imagination/pvr_free_list.c        |  15 +-
 drivers/gpu/drm/imagination/pvr_mmu.c              |  19 +-
 drivers/gpu/drm/imagination/pvr_mmu.h              |   2 +-
 drivers/gpu/drm/imagination/pvr_vm.c               |   4 +-
 drivers/gpu/drm/nouveau/nouveau_bo.c               |   3 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c        |   5 +-
 drivers/gpu/drm/nouveau/nouveau_display.c          |   4 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c              |   5 +-
 drivers/gpu/drm/nouveau/nouveau_gem.c              |   2 +
 drivers/gpu/drm/nouveau/nouveau_sched.c            |   2 +-
 drivers/gpu/drm/nouveau/nouveau_sched.h            |   1 +
 drivers/gpu/drm/nouveau/nouveau_uvmm.c             |  13 +-
 drivers/gpu/drm/nouveau/nvif/vmm.c                 |   1 +
 drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c   |   3 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c     |  23 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c   |   2 +
 drivers/gpu/drm/radeon/radeon_device.c             |   4 +-
 drivers/gpu/drm/virtio/virtgpu_drv.h               |   5 +
 drivers/gpu/drm/virtio/virtgpu_gem.c               |   2 +-
 drivers/gpu/drm/virtio/virtgpu_ioctl.c             |  49 ++-
 drivers/gpu/drm/virtio/virtgpu_prime.c             |   2 +-
 drivers/gpu/drm/virtio/virtgpu_submit.c            |  11 +-
 drivers/gpu/drm/virtio/virtgpu_vq.c                |  46 +++
 drivers/gpu/drm/virtio/virtgpu_vram.c              |  17 +-
 drivers/gpu/drm/xe/display/xe_display.c            |   6 +-
 drivers/gpu/drm/xe/xe_bo.c                         |   7 +
 drivers/gpu/drm/xe/xe_bo.h                         |  19 +
 drivers/gpu/drm/xe/xe_hw_engine.c                  |  27 +-
 drivers/gpu/drm/xe/xe_vm.c                         |  21 +-
 drivers/hid/amd-sfh-hid/amd_sfh_common.h           |   4 +
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c             |  10 +
 drivers/hid/bpf/hid_bpf_dispatch.c                 |  12 +-
 drivers/hid/hid-alps.c                             |  31 +-
 drivers/hid/hid-ids.h                              |   3 +
 drivers/hid/hid-multitouch.c                       |  29 +-
 drivers/hid/hid-quirks.c                           |   3 +-
 drivers/hid/wacom_sys.c                            |   5 +-
 drivers/i2c/busses/i2c-qcom-geni.c                 |  38 +-
 drivers/net/bonding/bond_main.c                    |   2 +-
 drivers/net/dsa/mt7530-mdio.c                      |  18 +-
 drivers/net/dsa/mt7530.c                           |   3 -
 drivers/net/ethernet/airoha/airoha_npu.c           |  18 +-
 drivers/net/ethernet/amazon/ena/ena_netdev.c       |   2 +
 drivers/net/ethernet/atheros/atl1c/atl1c_main.c    |   3 +
 drivers/net/ethernet/atheros/atl1e/atl1e_main.c    |   3 +
 drivers/net/ethernet/atheros/atlx/atl1.c           |   3 +
 drivers/net/ethernet/broadcom/genet/bcmgenet.c     |  34 +-
 drivers/net/ethernet/broadcom/tg3.c                |  15 +-
 drivers/net/ethernet/brocade/bna/bnad.c            |  24 +-
 drivers/net/ethernet/cadence/macb_main.c           |  14 +-
 drivers/net/ethernet/freescale/fman/fman.c         |   1 +
 drivers/net/ethernet/google/gve/gve.h              |  12 +-
 drivers/net/ethernet/google/gve/gve_adminq.c       |  12 +-
 drivers/net/ethernet/google/gve/gve_desc_dqo.h     |   5 +
 drivers/net/ethernet/google/gve/gve_ethtool.c      | 105 +++---
 drivers/net/ethernet/google/gve/gve_main.c         |  93 +++--
 drivers/net/ethernet/google/gve/gve_tx_dqo.c       |  71 +++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c  |   3 +
 drivers/net/ethernet/marvell/octeontx2/af/common.h |  45 ++-
 .../ethernet/marvell/octeontx2/af/rvu_debugfs.c    | 104 ++----
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |   6 +-
 .../ethernet/mellanox/mlx5/core/en/rep/bridge.c    |  45 ++-
 drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c |   3 +
 .../mellanox/mlx5/core/en_accel/ipsec_fs.c         |   4 +-
 .../ethernet/mellanox/mlx5/core/en_accel/macsec.c  |   2 +
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |   1 -
 .../net/ethernet/mellanox/mlx5/core/esw/bridge.c   |  15 +-
 .../net/ethernet/mellanox/mlx5/core/esw/bridge.h   |   2 +
 .../net/ethernet/mellanox/mlx5/core/lib/devcom.c   |   5 +-
 drivers/net/ethernet/meta/fbnic/fbnic_csr.h        |   5 +
 drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c    |  48 +++
 drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c    |  13 +-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c         |  74 +++-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.h         |   2 +
 drivers/net/ethernet/meta/fbnic/fbnic_pci.c        |  18 +-
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c       |   4 +-
 drivers/net/ethernet/netronome/nfp/crypto/ipsec.c  |   3 +-
 drivers/net/ethernet/spacemit/k1_emac.c            |   3 +
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c     |   5 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c |   4 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h         |   2 +-
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c    |   4 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   1 +
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c | 109 ++++--
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/wangxun/txgbe/txgbe_fdir.c    |  13 +-
 drivers/net/macsec.c                               |  84 ++---
 drivers/net/ovpn/netlink.c                         | 108 +++++-
 drivers/net/ovpn/peer.c                            | 121 +++++--
 drivers/net/ovpn/peer.h                            |  25 +-
 drivers/net/ovpn/udp.c                             | 193 ++++++++--
 drivers/net/pcs/pcs-rzn1-miic.c                    |   3 +-
 drivers/net/pcs/pcs-xpcs.c                         |   4 +-
 drivers/net/phy/micrel.c                           |   1 +
 drivers/net/phy/phylink.c                          |  20 +-
 drivers/net/usb/catc.c                             |  15 +-
 drivers/net/usb/cdc_mbim.c                         |   5 +
 drivers/net/usb/lan78xx.c                          |   2 +
 drivers/net/usb/sr9700.c                           |   3 +-
 drivers/net/veth.c                                 |   2 +
 drivers/net/virtio_net.c                           |   9 +
 drivers/net/vrf.c                                  |   2 -
 drivers/net/vxlan/vxlan_core.c                     |   6 +-
 drivers/nfc/microread/microread.c                  |   6 +-
 drivers/nfc/nfcmrvl/fw_dnld.c                      |  11 +-
 drivers/nfc/pn533/pn533.c                          |  14 +-
 drivers/nfc/pn533/pn533.h                          |   4 +-
 drivers/nfc/pn533/usb.c                            |   4 +-
 drivers/nfc/pn544/pn544.c                          |   7 +-
 drivers/nfc/port100.c                              |   7 +
 drivers/nfc/st21nfca/core.c                        |  12 +-
 drivers/nfc/st21nfca/i2c.c                         |  29 +-
 drivers/nfc/trf7970a.c                             |   4 +-
 drivers/nfc/virtual_ncidev.c                       |   3 +-
 drivers/pci/of_property.c                          |  11 +-
 drivers/pci/setup-bus.c                            |  23 +-
 drivers/pinctrl/meson/pinctrl-meson-s4.c           |   2 +-
 drivers/pinctrl/pinctrl-single.c                   |   3 +-
 drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c      |   2 +-
 drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c        |   2 +-
 drivers/pinctrl/sunxi/pinctrl-sunxi.c              |  82 ++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.h              |   9 +
 drivers/remoteproc/qcom_q6v5_adsp.c                |   8 +-
 drivers/s390/cio/chp.c                             |   3 +
 drivers/s390/cio/cio.c                             |  11 +-
 drivers/s390/cio/cio.h                             |   5 +-
 drivers/s390/cio/cmf.c                             |   2 +-
 drivers/s390/cio/device.c                          |   9 +-
 drivers/s390/cio/device_fsm.c                      |   3 +
 drivers/s390/cio/device_ops.c                      |  23 ++
 drivers/s390/cio/vfio_ccw_fsm.c                    |   2 +-
 drivers/s390/crypto/vfio_ap_ops.c                  |  18 +-
 drivers/scsi/libiscsi_tcp.c                        |   3 +
 drivers/scsi/megaraid/megaraid_sas_base.c          |   4 +-
 drivers/scsi/sd_zbc.c                              |   8 +-
 drivers/thermal/gov_step_wise.c                    |  10 +-
 fs/autofs/inode.c                                  |   4 +
 fs/bpf_fs_kfuncs.c                                 |   4 -
 fs/erofs/fscache.c                                 |   2 +
 fs/fs-writeback.c                                  |  25 +-
 fs/hfsplus/super.c                                 |   1 -
 fs/inode.c                                         |  11 +-
 fs/kernfs/mount.c                                  |   4 +-
 fs/ntfs3/inode.c                                   |   7 +-
 fs/ocfs2/namei.c                                   |   9 +-
 fs/ocfs2/xattr.c                                   |  13 +-
 fs/ocfs2/xattr.h                                   |   8 +-
 fs/smb/client/cached_dir.c                         |  32 +-
 fs/smb/client/smb2inode.c                          |   4 +-
 fs/smb/client/smb2ops.c                            |  28 +-
 fs/smb/client/smb2pdu.c                            |  51 ++-
 fs/squashfs/xz_wrapper.c                           |   6 +-
 fs/super.c                                         |  43 +--
 fs/xfs/libxfs/xfs_metafile.c                       |   8 +-
 fs/xfs/libxfs/xfs_rtrefcount_btree.c               |   4 +-
 fs/xfs/scrub/dir_repair.c                          |  19 +-
 fs/xfs/scrub/health.c                              |   6 +-
 fs/xfs/scrub/inode.c                               |   2 +-
 fs/xfs/scrub/inode_repair.c                        |   2 +-
 fs/xfs/scrub/orphanage.c                           |   6 +-
 fs/xfs/scrub/repair.c                              |  21 +-
 fs/xfs/scrub/scrub.h                               |   2 +-
 fs/xfs/scrub/trace.h                               |  12 +-
 fs/xfs/xfs_dquot.c                                 |   8 +-
 fs/xfs/xfs_exchrange.c                             |  13 +-
 fs/xfs/xfs_icache.c                                |   2 +-
 fs/xfs/xfs_log_recover.c                           |  13 +-
 fs/xfs/xfs_qm.c                                    |  10 +-
 fs/xfs/xfs_refcount_item.c                         |   8 +-
 fs/xfs/xfs_rmap_item.c                             |   8 +-
 include/drm/drm_client.h                           |  22 +-
 include/drm/drm_client_event.h                     |  12 +-
 include/drm/drm_fb_helper.h                        |   8 +-
 include/linux/bpf_mem_alloc.h                      |   6 +
 include/linux/if_vlan.h                            |   3 +
 include/linux/rculist.h                            |  29 ++
 include/linux/skbuff.h                             |  24 +-
 include/net/gue.h                                  |  19 +-
 include/net/ip6_route.h                            |   4 +-
 include/net/netfilter/nf_conntrack.h               |   5 +
 include/net/nfc/hci.h                              |   2 +-
 include/net/nfc/nfc.h                              |   3 +-
 include/net/rose.h                                 |  28 +-
 include/net/tcp.h                                  |   4 +-
 kernel/bpf/btf.c                                   | 140 +++++---
 kernel/bpf/crypto.c                                |   5 +-
 kernel/bpf/hashtab.c                               | 114 +++++-
 kernel/bpf/memalloc.c                              | 106 ++++--
 kernel/bpf/offload.c                               |   2 +
 kernel/bpf/syscall.c                               |   5 +-
 kernel/cgroup/cpuset.c                             |  53 +--
 kernel/cgroup/pids.c                               |   5 +
 kernel/events/core.c                               |  17 +-
 kernel/sched/core.c                                |   2 +-
 kernel/sched/ext.c                                 |   7 +-
 kernel/workqueue.c                                 |   2 +-
 mm/backing-dev.c                                   |   5 +-
 mm/damon/core.c                                    |  24 +-
 mm/damon/vaddr.c                                   |  21 +-
 mm/hugetlb.c                                       |  41 ++-
 mm/rmap.c                                          |  23 +-
 mm/vma.c                                           |   8 +
 net/8021q/vlan_dev.c                               |   5 +
 net/bluetooth/bnep/core.c                          |  17 +-
 net/bluetooth/bnep/netdev.c                        |   8 +-
 net/bluetooth/hci_conn.c                           |  14 +-
 net/bluetooth/hci_sock.c                           |  20 +-
 net/bluetooth/iso.c                                |   7 +
 net/bluetooth/l2cap_core.c                         |  10 +-
 net/bluetooth/mgmt.c                               |  27 +-
 net/bluetooth/rfcomm/core.c                        |   3 +-
 net/bluetooth/rfcomm/sock.c                        |   6 +-
 net/bluetooth/smp.c                                |  17 +
 net/bridge/br_mdb.c                                |   2 +
 net/bridge/br_stp_bpdu.c                           |   5 +-
 net/core/dev.c                                     |   2 +-
 net/core/filter.c                                  |  46 ++-
 net/core/skbuff.c                                  |   9 +-
 net/core/skmsg.c                                   |   4 +
 net/core/sock_map.c                                |   1 +
 net/ipv4/arp.c                                     |   1 +
 net/ipv4/fib_semantics.c                           |  13 +-
 net/ipv4/fou_core.c                                |   4 +
 net/ipv4/inet_connection_sock.c                    |   3 +-
 net/ipv4/ip_gre.c                                  |  12 +
 net/ipv4/ipconfig.c                                |  90 ++---
 net/ipv4/tcp_output.c                              |   3 +
 net/ipv4/udp.c                                     |  44 ++-
 net/ipv6/exthdrs_core.c                            |   3 +
 net/ipv6/ip6_fib.c                                 |   2 +-
 net/ipv6/ip6_gre.c                                 |   2 +-
 net/ipv6/netfilter/ip6t_rpfilter.c                 |   2 +-
 net/ipv6/netfilter/ip6t_rt.c                       |  11 +-
 net/ipv6/route.c                                   |  12 +-
 net/ipv6/seg6.c                                    |   4 +-
 net/llc/llc_c_ac.c                                 |   2 +-
 net/llc/llc_s_ac.c                                 |   4 +
 net/llc/llc_sap.c                                  |   8 +-
 net/mctp/route.c                                   |   2 +-
 net/mptcp/protocol.c                               |   2 +-
 net/netfilter/ipvs/ip_vs_core.c                    |   6 +
 net/netfilter/nf_conntrack_netlink.c               |   3 +-
 net/netfilter/nf_flow_table_offload.c              |   7 +-
 net/netfilter/nf_tables_api.c                      |  18 +-
 net/netfilter/nfnetlink_queue.c                    |   8 +-
 net/netfilter/nft_synproxy.c                       |   3 +-
 net/netlink/genetlink.c                            |   8 +-
 net/nfc/core.c                                     |  15 +-
 net/nfc/digital_dep.c                              |   8 +-
 net/nfc/llcp.h                                     |   1 +
 net/nfc/llcp_commands.c                            |   2 +-
 net/nfc/llcp_core.c                                | 173 ++++++---
 net/nfc/llcp_sock.c                                |  67 +++-
 net/nfc/nci/core.c                                 |  10 +-
 net/nfc/netlink.c                                  |   7 +-
 net/nfc/nfc.h                                      |   3 +-
 net/openvswitch/conntrack.c                        |  37 +-
 net/packet/af_packet.c                             | 104 +++---
 net/rds/ib_frmr.c                                  |  11 +-
 net/rose/rose_in.c                                 |  13 +-
 net/rose/rose_link.c                               |   5 +
 net/rose/rose_route.c                              |  81 ++++-
 net/sched/act_api.c                                |   2 +-
 net/sched/act_ct.c                                 |  41 ++-
 net/sched/act_gate.c                               |  30 +-
 net/sched/cls_u32.c                                |  12 +-
 net/sched/em_text.c                                |   2 +-
 net/sched/sch_hfsc.c                               |  22 ++
 net/sched/sch_teql.c                               |   7 +-
 net/sctp/associola.c                               |  15 +-
 net/sctp/input.c                                   |   7 +-
 net/sctp/sm_sideeffect.c                           |  37 +-
 net/sctp/sm_statefuns.c                            |   2 +
 net/smc/smc_core.c                                 |   2 +
 net/smc/smc_ib.c                                   |  10 +-
 net/tipc/group.c                                   |   4 +-
 net/tipc/monitor.c                                 |   3 +-
 net/tls/tls_sw.c                                   |   6 +-
 net/xdp/xskmap.c                                   |   2 +-
 rust/kernel/net/phy.rs                             |  38 +-
 security/ipe/eval.c                                |  12 +-
 security/ipe/eval.h                                |   2 +-
 security/ipe/fs.c                                  |   8 +-
 security/ipe/hooks.c                               |  22 +-
 security/ipe/policy_fs.c                           |   3 +
 sound/hda/codecs/realtek/alc269.c                  |   9 +
 tools/lib/bpf/libbpf.c                             |   7 +
 tools/lib/bpf/relo_core.c                          |  58 +--
 .../testing/selftests/bpf/prog_tests/linked_list.c |   4 +-
 tools/testing/selftests/cgroup/test_cpuset_prs.sh  |   2 +
 tools/testing/selftests/cgroup/test_memcontrol.c   |   2 +-
 .../ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc |   2 +-
 tools/testing/selftests/nci/nci_dev.c              |  45 ++-
 virt/kvm/kvm_main.c                                |  30 +-
 382 files changed, 4875 insertions(+), 2189 deletions(-)
author maintainer
#1 lore raw

PATCH 1/395 xfs: dont stash removename operations with unknown ftype

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Darrick J. Wong <[email protected]>

[ Upstream commit 865b751e75039fc07838b3200f9740256653da9a ]

LOLLM notices that the behavior of xrep_dir_replay_update changes based on the ftype recorded in the stashed removename information. It also notices that the unlink iops sometimes set that ftype to FT_UNKNOWN because the regular directory tree update code paths don't need to know the ftype of the child.

Unfortunately, this results in incorrect link counts, which eventually trips link count errors in later phases of xfs_scrub, or in xfs_repair. Fix this by creating a second xfs_name with the type set correctly.

Fixes 8559b21a64d983 ("xfs: implement live updates for directory repairs")
Assisted-by LOLLM # finding obvious bugs
---
 fs/xfs/scrub/dir_repair.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
fs/xfs/scrub/dir_repair.c +17 -2
index 36432705c44a7..ad3d414d9705d 100644
@@ -1381,9 +1381,24 @@ xrep_dir_live_update(
 		if (p->delta > 0)
 			error = xrep_dir_stash_createname(rd, p->name,
 					p->ip->i_ino);
-		else
-			error = xrep_dir_stash_removename(rd, p->name,
+		else {
+			/*
+			 * xfs_dentry_to_name in unlink or rename-exchange can
+			 * pass us names with ftype FT_UNKNOWN, but we really
+			 * must know the ftype of the child that is being
+			 * removed so that we can do nlink updates correctly
+			 * without holding inode references.
+			 */
+			struct xfs_name	name = {
+				.name	= p->name->name,
+				.len	= p->name->len,
+				.type	= xfs_mode_to_ftype(
+						VFS_IC(p->ip)->i_mode),
+			};
+
+			error = xrep_dir_stash_removename(rd, &name,
 					p->ip->i_ino);
+		}
 		mutex_unlock(&rd->pscan.lock);
 		if (error)
 			goto out_abort;
Signature · 1 line
2.53.0
author maintainer
#2 lore raw

PATCH 2/395 erofs: fix large folio race in erofs_fscache_req_complete

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Wenwu Hou <[email protected]>

This patch is for stable only. Commit c37460cd9b2fc ("erofs: remove fscache backend entirely") upstream removed this code.

xas_for_each() iteration can race with reclamation of an unlocked large folio and splitting of its replacement shadow entry. Fix this by advancing past the entire folio before unlocking it.

For example:
CPU A: EROFS completion Other CPUs
---------------------------------- -----------------------------------
Find F at index 0.
Mark F uptodate.
Unlock F.

Reclaim F.
Replace indices 0–3 with a multi-index workingset shadow.

Another reader inserts a smaller folio, e.g. order-0 at index 0. Split the large shadow entry:
index 0: new folio index 1: shadow index 2: shadow index 3: shadow
Find a shadow at index 1.
folio_mark_uptodate(folio).

This can cause a kernel panic such as:

[1030374.432778] [     C31] BUG: unable to handle page fault for address: 00001846af017b01
[1030374.432971] [     C31] #PF: supervisor write access in kernel mode
[1030374.432973] [     C31] #PF: error_code(0x0002) - not-present page
[1030374.433543] [     C31] PGD 5a44f75067 P4D 5a44f75067 PUD 0
[1030374.433546] [     C31] Oops: 0002 [#1] PREEMPT SMP NOPTI
[1030374.433549] [     C31] CPU: 31 PID: 2425624 Comm: node Kdump: loaded Tainted: G           OE K    6.6.88-****
[1030374.434154] [     C31] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS ?-20260421_110423-CN.l65g09119.cloud.sqa.na131 04/01/2014
[1030374.434156] [     C31] RIP: 0010:erofs_fscache_req_complete+0xc1/0x1a0 [erofs]
[1030374.434764] [     C31] Code: 17 c5 c3 48 89 c7 48 85 c0 0f 84 af 00 00 00 48 81 ff 06 04 00 00 74 1b 48 81 ff 02 04 00 00 0f 84 b9 00 00 00 66 85 ed 75 04 <f0> 80 0f 08 e8 96 04 24 c3 48 8b 54 24 18 f6 c2 03 0f 95 c0 48 85
[1030374.435044] [     C31] RSP: 0000:ffffb8f2fc973cc0 EFLAGS: 00010046
[1030374.435641] [     C31]
[1030374.435642] [     C31] RAX: 00001846af017b01 RBX: 000000000000000f RCX: 0000000000000001
[1030374.436885] [     C31] RDX: 000000000000000c RSI: ffffa02ab337d468 RDI: 00001846af017b01
[1030374.437127] [     C31] RBP: 0000000000000000 R08: ffffffffffffffc0 R09: 0000000000000002
[1030374.437672] [     C31] R10: 0000000000000005 R11: 0000000000000191 R12: ffffa0060ec72300
[1030374.437673] [     C31] R13: 0000000008000000 R14: ffffffffc11b1990 R15: 0000000000007000
[1030374.437677] [     C31] FS:  00007f4928cdec80(0000) GS:ffffa07dc5f80000(0000) knlGS:0000000000000000
[1030374.437678] [     C31] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[1030374.437680] [     C31] CR2: 00001846af017b01 CR3: 00000063d5356006 CR4: 0000000000770ee0
[1030374.437681] [     C31] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[1030374.437682] [     C31] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
[1030374.437684] [     C31] PKRU: 55555558
[1030374.437684] [     C31] Call Trace:
[1030374.437687] [     C31]  <TASK>
[1030374.437692] [     C31]  erofs_fscache_req_put+0x27/0x40 [erofs]
[1030374.438900] [     C31]  cachefiles_read_complete+0x48/0x110 [cachefiles]
[1030374.440448] [     C31]  iomap_dio_bio_end_io+0x128/0x160
[1030374.440456] [     C31]  ? __pfx_stripe_end_io+0x10/0x10 [dm_mod]
[1030374.440950] [     C31]  clone_endio+0x123/0x1f0 [dm_mod]
[1030374.441550] [     C31]  blk_mq_end_request_batch+0xf4/0x440
[1030374.441556] [     C31]  ? nohz_balancer_kick+0x31/0x270
[1030374.441561] [     C31]  ? dma_direct_unmap_sg+0x48/0x1d0
[1030374.441565] [     C31]  ? dma_pool_free+0x22/0x60
[1030374.441569] [     C31]  ? nvme_pci_complete_batch+0xaf/0xc0 [nvme]
[1030374.442070] [     C31]  nvme_irq+0x6e/0x80 [nvme]
[1030374.442422] [     C31]  ? __pfx_nvme_pci_complete_batch+0x10/0x10 [nvme]
[1030374.442428] [     C31]  __handle_irq_event_percpu+0x46/0x1a0
[1030374.442431] [     C31]  handle_irq_event+0x37/0x80
[1030374.442433] [     C31]  handle_edge_irq+0x93/0x240
[1030374.442436] [     C31]  __common_interrupt+0x3b/0xa0
[1030374.442441] [     C31]  common_interrupt+0x3f/0xa0
[1030374.442446] [     C31]  asm_common_interrupt+0x22/0x40
Fixes d435d53228dd ("erofs: change to use asynchronous io for fscache readpage/readahead")
---
 fs/erofs/fscache.c | 2 ++
 1 file changed, 2 insertions(+)
fs/erofs/fscache.c +2 -0
index 7a346e20f7b7a..754f7d04488da 100644
@@ -67,6 +67,8 @@ static void erofs_fscache_req_complete(struct erofs_fscache_rq *req)
 			continue;
 		if (!failed)
 			folio_mark_uptodate(folio);
+		/* Skip the entire folio before unlocking allows it to be split. */
+		xas_advance(&xas, folio_next_index(folio) - 1);
 		folio_unlock(folio);
 	}
 	rcu_read_unlock();
Signature · 1 line
2.53.0
author maintainer
#3 lore raw

PATCH 3/395 drm/amd/display: Atomize IRQ register read/modify/write ops

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Leo Li <[email protected]>

[ Upstream commit 63e19ef3ddab806c472748c825f4dc88dcd994e8 ]

[Why]

The OTG_GLOBAL_SYNC_STATUS register controls various HW IRQ sources for the output timing generator (OTG). VUPDATE_NO_LOCK is one of them.

To enable the IRQ, driver sets the VUPDATE_NO_LOCK_EN bit in the GLOBAL_SYNC_STATUS register.

To ack the IRQ after it fires, the driver sets the VUPDATE_NO_LOCK_CLEAR bit in the same GLOBAL_SYNC_STATUS register.

The bit sets are done through read/modify/write operations, which are not atomic. Thus, the following race is possible:

Thread A: IRQ handler:
*HW IRQ fires*
# IRQ disable
val = read(GLOBAL_SYNC_STATUS)
unset(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# ACK reads VUPDATE_NO_LOCK_EN unset val1 = read(GLOBAL_SYNC_STATUS) set(val1, VUPDATE_NO_LOCK_CLEAR)
# IRQ enable
val = read(GLOBAL_SYNC_STATUS)
set(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# BAD! clears VUPDATE_NO_LOCK_EN write(val1, GLOBAL_SYNC_STATUS)

Regarding the tagged Fixes: change, it appears the change made this race more likely to occur. Since VUPDATE_NO_LOCK is now the sole IRQ source for vblank handling, a single race on high refresh panels can lead to a time out.

[How]

The GLOBAL_SYNC_STATUS register is only one example, other IRQ control registers also share the same scheme. On top of GLOBAL_SYNC_STATUS, let's clean up those as well.

To keep things simple, Let's atomize the IRQ rmw ops via a single driver-wide spinlock. Due to the small scope of this lock, it is unlikely to cause noticeable overhead on top of all the existing locking within the IRQ set/handle paths.

Since DM is responsible for locking, wrap dc_interrupt_set/ack with the spinlock in the new amdgpu_dm_irq_set/ack functions. Migrate/drop all references in DM to dc_interrupt_set/ack to use amdgpu_dm_irq_set/ack instead.

Fixes c87e6635d2db ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
(cherry picked from commit 70de0a0216583a53c946155f8c8adedfdca6b4e7)
(cherry picked from commit 63e19ef3ddab806c472748c825f4dc88dcd994e8)

Modified for unit tests not present in 7.2.y

---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  4 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 ++++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  3 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  3 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 62 +++++++++++--------
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 28 +++++++++
 6 files changed, 82 insertions(+), 30 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -2
index 89686abcaf92d..a9b9d7d911f25 100644
@@ -3100,7 +3100,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
 		if (acrtc && state->stream_status[i].plane_count != 0 &&
 		    amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
 			irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
-			rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+			rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
 			if (rc)
 				drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n",
 					 enable ? "enable" : "disable");
@@ -3124,7 +3124,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
 			/* During gpu-reset we disable and then enable vblank irq, so
 			 * don't use amdgpu_irq_get/put() to avoid refcount change.
 			 */
-			if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
+			if (!amdgpu_dm_irq_set(adev, irq_source, enable))
 				drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
 
 		} else if (acrtc && state->stream_status[i].plane_count != 0) {
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +12 -0
index caf6f7387a20a..a83fdd7b644ab 100644
@@ -527,6 +527,18 @@ struct amdgpu_display_manager {
 	struct common_irq_params
 	vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
 
+	/**
+	 * @irq_reg_lock:
+	 *
+	 * Serializes the read-modify-writes of the HW interrupt control
+	 * registers. Several interrupt sources share one register - e.g. the
+	 * enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK
+	 * live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must
+	 * not race with acking another. Held only across amdgpu_dm_irq_set()
+	 * and amdgpu_dm_irq_ack().
+	 */
+	spinlock_t irq_reg_lock;
+
 	/**
 	 * @dmub_trace_params:
 	 *
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +2 -1
index 7880683031524..9082b862e7aa9 100644
@@ -31,6 +31,7 @@
 #include "amdgpu_dm_psr.h"
 #include "amdgpu_dm_replay.h"
 #include "amdgpu_dm_crtc.h"
+#include "amdgpu_dm_irq.h"
 #include "amdgpu_dm_plane.h"
 #include "amdgpu_dm_trace.h"
 #include "amdgpu_dm_debugfs.h"
@@ -86,7 +87,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
 
 	irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
 
-	rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+	rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
 
 	DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
 		      acrtc->crtc_id, enable ? "en" : "dis", rc);
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +2 -1
index ddda474d58788..7633af2429198 100644
@@ -1189,12 +1189,13 @@ void dm_helpers_free_gpu_mem(
 
 bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
 {
+	struct amdgpu_device *adev = ctx->driver_context;
 	enum dc_irq_source irq_source;
 	bool ret;
 
 	irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
 
-	ret = dc_interrupt_set(ctx->dc, irq_source, enable);
+	ret = amdgpu_dm_irq_set(adev, irq_source, enable);
 
 	DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
 			 enable ? "en" : "dis", ret);
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +36 -26

166 lines not on this page · raw message

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +28 -0
index 4f6b58f4f90d7..f0a4577848f35 100644
@@ -81,6 +81,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
 					enum dc_irq_source irq_source,
 					void *ih_index);
 
+/**
+ * amdgpu_dm_irq_set - enable or disable a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to toggle
+ * @enable: true to enable the source, false to disable it
+ *
+ * DM-wide replacement for dc_interrupt_set(). As locking is DM's
+ * responsibility, this is a thin wrapper serializes the underlying
+ * read-modify-write against the other interrupt sources sharing HW control
+ * registers with @src, so DM must never call dc_interrupt_set() directly.
+ *
+ * Returns: true if the source was toggled.
+ */
+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
+		       bool enable);
+
+/**
+ * amdgpu_dm_irq_ack - acknowledge a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to acknowledge
+ *
+ * DM-wide replacement for dc_interrupt_ack(), serialized the same way as
+ * amdgpu_dm_irq_set().
+ */
+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src);
+
 void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);
 
 void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
Signature · 1 line
2.53.0
author maintainer
#4 lore raw

PATCH 4/395 ALSA: hda/realtek: Limit Star Labs internal mic boost

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Rhodes <[email protected]>

[ Upstream commit 186d4adbb40138e7cb7cffc87a81e95630ced123 ]

The 30 dB internal mic boost is too high for laptops, especially with fans. Limit Star Labs internal mic boost to 10 dB.

---
 sound/hda/codecs/realtek/alc269.c | 6 ++++++
 1 file changed, 6 insertions(+)
sound/hda/codecs/realtek/alc269.c +6 -0
index aab2456bacaf6..5cc6c2d64e1af 100644
@@ -3986,6 +3986,7 @@ enum {
 	ALC245_FIXUP_CLEVO_NOISY_MIC,
 	ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
 	ALC233_FIXUP_MEDION_MTL_SPK,
+	ALC269_FIXUP_STARLABS_LIMIT_INT_MIC_BOOST,
 	ALC233_FIXUP_STARLABS_STARFIGHTER,
 	ALC294_FIXUP_BASS_SPEAKER_15,
 	ALC283_FIXUP_DELL_HP_RESUME,
@@ -6467,6 +6468,10 @@ static const struct hda_fixup alc269_fixups[] = {
 			{ }
 		},
 	},
+	[ALC269_FIXUP_STARLABS_LIMIT_INT_MIC_BOOST] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc269_fixup_limit_int_mic_boost,
+	},
 	[ALC233_FIXUP_STARLABS_STARFIGHTER] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc233_fixup_starlabs_starfighter,
@@ -7699,6 +7704,7 @@ static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
 	SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
 	SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
+	SND_PCI_QUIRK_VENDOR(0x2145, "Star Labs", ALC269_FIXUP_STARLABS_LIMIT_INT_MIC_BOOST),
 	{}
 };
 
Signature · 1 line
2.53.0
author maintainer
#5 lore raw

PATCH 5/395 ALSA: hda/realtek: Add StarFighter HDA SSID

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Rhodes <[email protected]>

[ Upstream commit cd401c70df472d3eddd0b6b055726a03c212181a ]

Support the new StarFighter HDA SSID while keeping the existing SSID chained to the same quirk until the new match reaches backports.

---
 sound/hda/codecs/realtek/alc269.c | 3 +++
 1 file changed, 3 insertions(+)
sound/hda/codecs/realtek/alc269.c +3 -0
index 5cc6c2d64e1af..681cdb00a11d3 100644
@@ -6475,6 +6475,8 @@ static const struct hda_fixup alc269_fixups[] = {
 	[ALC233_FIXUP_STARLABS_STARFIGHTER] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc233_fixup_starlabs_starfighter,
+		.chained = true,
+		.chain_id = ALC269_FIXUP_STARLABS_LIMIT_INT_MIC_BOOST,
 	},
 	[ALC294_FIXUP_BASS_SPEAKER_15] = {
 		.type = HDA_FIXUP_FUNC,
@@ -7624,6 +7626,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
 	SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK),
+	SND_PCI_QUIRK(0x2145, 0x0001, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER),
 	SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
 	SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
Signature · 1 line
2.53.0
author maintainer
#6 lore raw

PATCH 6/395 remoteproc: qcom_q6v5_adsp: Fix iommu_unmap() usage

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mostafa Saleh <[email protected]>

[ Upstream commit 0d8e2195bce6f08c1c53c5ef4d7347fe46418101 ]

During adsp_map_carveout, the IOVA is computed by combining the physical address and the SID:

    iova = adsp->mem_phys | (sid << 32);

However, adsp_unmap_carveout() uses the physical address and not the IOVA in iommu_unmap(), causing the unmap to fail or leak mappings because the address doesn't match the original IOVA.

Cache the constructed IOVA within the qcom_adsp device struct during mapping and use it during unmapping.

Fixes f22eedff28af ("remoteproc: qcom: Add support for memory sandbox")
---
 drivers/remoteproc/qcom_q6v5_adsp.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/remoteproc/qcom_q6v5_adsp.c +4 -4
index b7d472afd5a9b..004dab45cf3c7 100644
@@ -104,6 +104,7 @@ struct qcom_adsp {
 	struct completion stop_done;
 
 	phys_addr_t mem_phys;
+	unsigned long iova;
 	phys_addr_t mem_reloc;
 	void *mem_region;
 	size_t mem_size;
@@ -333,7 +334,7 @@ static void adsp_unmap_carveout(struct rproc *rproc)
 	struct qcom_adsp *adsp = rproc->priv;
 
 	if (adsp->has_iommu)
-		iommu_unmap(rproc->domain, adsp->mem_phys, adsp->mem_size);
+		iommu_unmap(rproc->domain, adsp->iova, adsp->mem_size);
 }
 
 static int adsp_map_carveout(struct rproc *rproc)
@@ -341,7 +342,6 @@ static int adsp_map_carveout(struct rproc *rproc)
 	struct qcom_adsp *adsp = rproc->priv;
 	struct of_phandle_args args;
 	long long sid;
-	unsigned long iova;
 	int ret;
 
 	if (!adsp->has_iommu)
@@ -358,9 +358,9 @@ static int adsp_map_carveout(struct rproc *rproc)
 	of_node_put(args.np);
 
 	/* Add SID configuration for ADSP Firmware to SMMU */
-	iova =  adsp->mem_phys | (sid << 32);
+	adsp->iova = adsp->mem_phys | (sid << 32);
 
-	ret = iommu_map(rproc->domain, iova, adsp->mem_phys,
+	ret = iommu_map(rproc->domain, adsp->iova, adsp->mem_phys,
 			adsp->mem_size,	IOMMU_READ | IOMMU_WRITE,
 			GFP_KERNEL);
 	if (ret) {
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 7/395 KVM: s390: Fix IRQ injection with SIGP Stop and Store Status

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Claudio Imbrenda <[email protected]>

[ Upstream commit d343407b728a80b74be3c24b59f15e60289ea527 ]

When __inject_sigp_stop() is called for a Stop and Store Status operation, if the vCPU is running, the interrupt is marked as pending and the status is stored by the thread performing the KVM_RUN IOCTL.

If the vCPU is already stopped, the status is stored immediately.

Storing the status means writing into userspace, which might fault, and __inject_sigp_stop() is called from do_inject_vcpu() which in turn is always called holding a spinlock, which is obviously an issue.

Fix this by returning -EWOULDBLOCK from __inject_sigp_stop(), and adding a bool flag to indicate whether a store status is needed. The callers of do_inject_vcpu() are modified to pass the pointer to the bool flag; whenever a Store Status operation is needed, the callers can now perform it outside the spinlock.

Opportunistically refactor kvm_s390_set_irq_state() to use scoped_guard() and __free().

Fixes 6cddd432e3da ("KVM: s390: handle stop irqs without action_bits")
[ Added Fixes tag while picking -- Claudio ]

Message-ID: <[email protected]>

---
 arch/s390/kvm/interrupt.c | 70 +++++++++++++++++++++------------------
 1 file changed, 38 insertions(+), 32 deletions(-)
arch/s390/kvm/interrupt.c +38 -32
index 1c83962baf5f6..d39884e63fa13 100644
@@ -1579,23 +1579,21 @@ static int __inject_set_prefix(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 }
 
 #define KVM_S390_STOP_SUPP_FLAGS (KVM_S390_STOP_FLAG_STORE_STATUS)
-static int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
+static int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq, bool *storestatus)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
 	struct kvm_s390_stop_info *stop = &li->irq.stop;
-	int rc = 0;
 
 	vcpu->stat.inject_stop_signal++;
 	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_SIGP_STOP, 0, 0);
 
 	if (irq->u.stop.flags & ~KVM_S390_STOP_SUPP_FLAGS)
 		return -EINVAL;
-
 	if (is_vcpu_stopped(vcpu)) {
-		if (irq->u.stop.flags & KVM_S390_STOP_FLAG_STORE_STATUS)
-			rc = kvm_s390_store_status_unloaded(vcpu,
-						KVM_S390_STORE_STATUS_NOADDR);
-		return rc;
+		if (!(irq->u.stop.flags & KVM_S390_STOP_FLAG_STORE_STATUS))
+			return 0;
+		*storestatus = true;
+		return -EWOULDBLOCK;
 	}
 
 	if (test_and_set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs))
@@ -2132,7 +2130,7 @@ void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu)
 	spin_unlock(&li->lock);
 }
 
-static int do_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
+static int do_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq, bool *storestatus)
 {
 	int rc;
 
@@ -2144,7 +2142,7 @@ static int do_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 		rc = __inject_set_prefix(vcpu, irq);
 		break;
 	case KVM_S390_SIGP_STOP:
-		rc = __inject_sigp_stop(vcpu, irq);
+		rc = __inject_sigp_stop(vcpu, irq, storestatus);
 		break;
 	case KVM_S390_RESTART:
 		rc = __inject_sigp_restart(vcpu);
@@ -2180,11 +2178,16 @@ static int do_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+	bool storestatus = false;
 	int rc;
 
 	spin_lock(&li->lock);
-	rc = do_inject_vcpu(vcpu, irq);
+	rc = do_inject_vcpu(vcpu, irq, &storestatus);
 	spin_unlock(&li->lock);
+
+	if (rc == -EWOULDBLOCK && storestatus)
+		rc = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
+
 	if (!rc)
 		kvm_s390_vcpu_wakeup(vcpu);
 	return rc;
@@ -2928,7 +2931,8 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
 int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-	struct kvm_s390_irq *buf;
+	struct kvm_s390_irq *buf __free(kvfree) = NULL;
+	bool tmp, storestatus = false;
 	int r = 0;
 	int n;
 
@@ -2936,31 +2940,33 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len
 	if (!buf)
 		return -ENOMEM;
 
-	if (copy_from_user((void *) buf, irqstate, len)) {
-		r = -EFAULT;
-		goto out_free;
-	}
+	if (copy_from_user((void *)buf, irqstate, len))
+		return -EFAULT;
 
-	/*
-	 * Don't allow setting the interrupt state
-	 * when there are already interrupts pending
-	 */
-	spin_lock(&li->lock);
-	if (li->pending_irqs) {
-		r = -EBUSY;
-		goto out_unlock;
-	}
+	scoped_guard(spinlock, &li->lock) {
+		/*
+		 * Don't allow setting the interrupt state
+		 * when there are already interrupts pending
+		 */
+		if (li->pending_irqs)
+			return -EBUSY;
 
-	for (n = 0; n < len / sizeof(*buf); n++) {
-		r = do_inject_vcpu(vcpu, &buf[n]);
-		if (r)
-			break;
+		for (n = 0; n < len / sizeof(*buf); n++) {
+			tmp = false;
+			r = do_inject_vcpu(vcpu, &buf[n], &tmp);
+			if (r == -EWOULDBLOCK && tmp) {
+				storestatus = true;
+				r = 0;
+			}
+			if (r)
+				break;
+		}
 	}
 
-out_unlock:
-	spin_unlock(&li->lock);
-out_free:
-	vfree(buf);
+	if (storestatus) {
+		n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
+		return r ? r : n;
+	}
 
 	return r;
 }
Signature · 1 line
2.53.0
author maintainer
#8 lore raw

PATCH 8/395 s390/uv: Fix loop condition in uv_find_secrets

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Steffen Eiden <[email protected]>

[ Upstream commit d12ce6bce5ec5175c3581e01c71e7a5abb286d9b ]

Systems with more than 85 UV secrets got -ENOENT for any secret past the first page.

Fix this by setting the start index at the beginning of the loop in uv_find_secret() and not at the end. First test if there are more secrets left by comparing start_idx with list->next_secret_idx, and then set the start index to the next secret index.

Fixes 7c9137af2042 ("s390/uv: Retrieve UV secrets support")

Message-ID: <[email protected]>

---
 arch/s390/kernel/uv.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kernel/uv.c +4 -2
index 5d17609bcfe1d..92abeb54f9c1b 100644
@@ -878,11 +878,14 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
 		   struct uv_secret_list *list,
 		   struct uv_secret_list_item_hdr *secret)
 {
-	u16 start_idx = 0;
+	u16 start_idx;
 	u16 list_rc;
 	int ret;
 
+	list->next_secret_idx = 0;
+
 	do {
+		start_idx = list->next_secret_idx;
 		uv_list_secrets(list, start_idx, &list_rc, NULL);
 		if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) {
 			if (list_rc == UVC_RC_INV_CMD)
@@ -893,7 +896,6 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
 		ret = find_secret_in_page(secret_id, list, secret);
 		if (ret == 0)
 			return ret;
-		start_idx = list->next_secret_idx;
 	} while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx);
 
 	return -ENOENT;
Signature · 1 line
2.53.0
author maintainer
#9 lore raw

PATCH 9/395 s390/uv: Prevent potential out-of-bounds read

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Steffen Eiden <[email protected]>

[ Upstream commit f47190b08b71e8482072978373ee88cb2dfbdaf4 ]

When the system has more than 85 secrets, the uv_secret_list struct array only holds up to 85 items per page, resulting in an out of bounds read in find_secret_in_page if the targeted secret is in the next page or not stored at all.

Fix this by looping over the number of stored secrets which is the per sub-list count of stored secrets and not the overall count.

Fixes 7c9137af2042 ("s390/uv: Retrieve UV secrets support")

Message-ID: <[email protected]>

---
 arch/s390/kernel/uv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/uv.c +1 -1
index 92abeb54f9c1b..d49206bf74155 100644
@@ -857,7 +857,7 @@ static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN],
 {
 	u16 i;
 
-	for (i = 0; i < list->total_num_secrets; i++) {
+	for (i = 0; i < list->num_secr_stored; i++) {
 		if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) {
 			*secret = list->secrets[i].hdr;
 			return 0;
Signature · 1 line
2.53.0
author maintainer
#10 lore raw

PATCH 10/395 bpf: Fix bpf_skb_change_tail wrt csum partial skbs

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Daniel Borkmann <[email protected]>

[ Upstream commit 3b55f350c68a0aceff108f47f9d31f47ebffaf7b ]

Cilium generates ICMP "frag needed" replies from BPF when a LB DSR packet exceeds the egress MTU. The reply is built by first trimming the packet down to target size via bpf_skb_change_tail(), and then pushing the ICMP error headers in front of it.

The trim is rejected for skbs which carry a checksum offload, e.g. TCP packets aggregated by GRO on ingress where tcp_gro_complete() leaves the skb as CHECKSUM_PARTIAL. __bpf_skb_min_len() raises the minimum length to the end of the L4 checksum field, so a trim to 42 bytes bails out with -EINVAL given a min_len of 52 in this case, and due to that the ICMP generator fails. This is not the case if GRO is turned off.

Fix this bpf_skb_change_tail() restriction and drop the checksum offload when the new length no longer covers the checksum field. The BPF program rewrites the skb into an ICMP error and computes the checksum itself anyway.

---
 net/core/filter.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
net/core/filter.c +5 -6
index 35427793ddb7e..42f5688dc1fab 100644
@@ -3825,12 +3825,6 @@ static u32 __bpf_skb_min_len(const struct sk_buff *skb)
 		if (offset > 0)
 			min_len = offset;
 	}
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		offset = skb_checksum_start_offset(skb) +
-			 skb->csum_offset + sizeof(__sum16);
-		if (offset > 0)
-			min_len = offset;
-	}
 	return min_len;
 }
 
@@ -3847,6 +3841,11 @@ static int bpf_skb_grow_rcsum(struct sk_buff *skb, unsigned int new_len)
 
 static int bpf_skb_trim_rcsum(struct sk_buff *skb, unsigned int new_len)
 {
+	if (skb->ip_summed == CHECKSUM_PARTIAL &&
+	    new_len < skb_checksum_start_offset(skb) + skb->csum_offset +
+		      sizeof(__sum16))
+		skb->ip_summed = CHECKSUM_NONE;
+
 	return __skb_trim_rcsum(skb, new_len);
 }
 
Signature · 1 line
2.53.0
author maintainer
#11 lore raw

PATCH 11/395 bpf: Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Weiming Shi <[email protected]>

[ Upstream commit e4a62833adff6ef0fe7c0b90393204fe3c26b5c5 ]

An LWT_SEG6LOCAL program can invalidate its cached SRH with bpf_lwt_seg6_adjust_srh() and then call bpf_skb_pull_data(). The latter may reallocate skb->head, leaving the per-CPU SRH pointer dangling. Post-program SRH validation then writes through that pointer.

Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL programs so the verifier rejects this unsafe helper combination. Other LWT program types continue to expose the helper through lwt_out_func_proto().

---
 net/core/filter.c | 2 ++
 1 file changed, 2 insertions(+)
net/core/filter.c +2 -0
index 42f5688dc1fab..0b849567afe9f 100644
@@ -8725,6 +8725,8 @@ static const struct bpf_func_proto *
 lwt_seg6local_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 {
 	switch (func_id) {
+	case BPF_FUNC_skb_pull_data:
+		return NULL;
 #if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
 	case BPF_FUNC_lwt_seg6_store_bytes:
 		return &bpf_lwt_seg6_store_bytes_proto;
Signature · 1 line
2.53.0
author maintainer
#12 lore raw

PATCH 12/395 selftests/ftrace: Fix unique symbol check in kprobe_non_uniq_symbol.tc

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Schnelle <[email protected]>

[ Upstream commit d22c3e0088e85be8131f7a9283f759cdbb20726d ]

The current regex also matches symbols in modules, which makes the test fail on s390 where name_show is present only once in the kernel, but also multiple times in modules:

000001b1401cdc20 t name_show
000001b0c05e6c40 t name_show [mdev]
000001b0c0495f30 t name_show [i2c_core]

Fix this by changing the regular expression to only match the function name.

Fixes 03b80ff8023a ("selftests/ftrace: Add new test case which checks non unique symbol")
---
 .../selftests/ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc +1 -1
index bc9514428dbaf..07b1177c16344 100644
@@ -6,7 +6,7 @@
 SYMBOL='name_show'
 
 # We skip this test on kernel where SYMBOL is unique or does not exist.
-if [ "$(grep -c -E "[[:alnum:]]+ t ${SYMBOL}" /proc/kallsyms)" -le '1' ]; then
+if [ "$(grep -c -E "[[:alnum:]]+ t ${SYMBOL}$" /proc/kallsyms)" -le '1' ]; then
 	exit_unsupported
 fi
 
Signature · 1 line
2.53.0
author maintainer
#13 lore raw

PATCH 13/395 bpf: Fix divide-by-zero in btf_struct_walk()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiayuan Chen <[email protected]>

[ Upstream commit b0b3dc66529676228cb938cbcad66920f735c223 ]

When an access goes past the struct and the last member is a flexible array, btf_struct_walk() folds the offset back into a single element with (off - moff) % t->size, but never checks that the element type has a size.

BTF takes an empty struct, so this in program BTF

	/* event could be empty */
	struct event {
 #ifdef HAVE_TIMESTAMP
		__u64 ts;
 #endif
	};

	struct batch {
		int nr;
		struct event events[];
	};

divides by zero at prog load time. Getting there needs a PTR_TO_BTF_ID that is not MEM_ALLOC, e.g. a plain read of a local kptr stashed in a map from a sleepable program.

Oops: divide error: 0000 [#1] SMP KASAN PTI
RIP: 0010:btf_struct_walk+0x53f/0x1570
Call Trace:
 <TASK>
 btf_struct_access+0x42a/0xcd0
 check_ptr_to_btf_access+0x4dc/0x1160
 check_mem_access+0x3a45/0x8740
 check_load_mem+0x36a/0xd10
 do_check_common+0x3ef0/0xb210
 bpf_check+0x6d3b/0x8580
 bpf_prog_load+0xf7c/0x2720
 __sys_bpf+0xa83/0x3690
 __x64_sys_bpf+0xc7/0x150
 x64_sys_call+0x1f3f/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
 </TASK>

Reject a zero-sized element type. The fixed array path in the same function already bails out on the same thing:

	btf_struct_walk()
	...
		/* skip empty array */
		if (moff == mtrue_end)
			continue;

		msize /= total_nelems;
Fixes 9c5f8a1008a1 ("bpf: Support variable length array in tracing programs")
---
 kernel/bpf/btf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/btf.c +1 -1
index f92e1c16c3569..86a4f76e79403 100644
@@ -7004,7 +7004,7 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
 		if (btf_type_is_int(t))
 			return WALK_SCALAR;
 
-		if (!btf_type_is_struct(t))
+		if (!btf_type_is_struct(t) || !t->size)
 			goto error;
 
 		off = (off - moff) % t->size;
Signature · 1 line
2.53.0
author maintainer
#14 lore raw

PATCH 14/395 bpf: Fix out-of-bounds read of sk_protocol in bpf_sock_destroy()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiayuan Chen <[email protected]>

[ Upstream commit 01b245ba016d44861690594e10f67e026ce8552f ]

sk_protocol lives in struct sock, not in struct sock_common. A timewait or request sock handed to bpf_sock_destroy() by the tcp iterator is neither, so reading sk->sk_protocol runs past the object:

==================================================================

BUG: KASAN: slab-out-of-bounds in bpf_sock_destroy+0xc7/0xe0
Read of size 2 at addr ffff8881047d11b4 by task test_progs/428

Tainted: [W]=WARN
Call Trace:
 <TASK>
 dump_stack_lvl+0x91/0xf0
 print_report+0xd1/0x630
 kasan_report+0xf3/0x130
 __asan_report_load2_noabort+0x14/0x30
 bpf_sock_destroy+0xc7/0xe0
 bpf_prog_c3dd61f9d9cd9f37_iter_tcp6_timewait+0x9f/0xb7
 bpf_iter_run_prog+0x538/0xde0
 bpf_iter_tcp_seq_show+0x26b/0x4b0
 bpf_seq_read+0x424/0x1210
 vfs_read+0x197/0xe40
 ksys_read+0x119/0x240
 __x64_sys_read+0x72/0xc0
 x64_sys_call+0x647/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e

Only check sk_protocol on full socks. tcp_abort() already knows how to deal with TIME_WAIT and NEW_SYN_RECV socks. Also fix the comment, it never matched the code.

---
 net/core/filter.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
net/core/filter.c +9 -4
index 0b849567afe9f..4f0a052d9aed1 100644
@@ -12497,8 +12497,9 @@ __bpf_kfunc_start_defs();
  * @sock: Pointer to socket to be destroyed
  *
  * Return:
- * On error, may return EPROTONOSUPPORT, EINVAL.
- * EPROTONOSUPPORT if protocol specific destroy handler is not supported.
+ * On error, may return EOPNOTSUPP, or whatever the protocol specific
+ * destroy handler returns.
+ * EOPNOTSUPP if protocol specific destroy handler is not supported.
  * 0 otherwise
  */
 __bpf_kfunc int bpf_sock_destroy(struct sock_common *sock)
@@ -12510,8 +12511,12 @@ __bpf_kfunc int bpf_sock_destroy(struct sock_common *sock)
 	 * Supporting protocols will need to acquire sock lock in the BPF context
 	 * prior to invoking this kfunc.
 	 */
-	if (!sk->sk_prot->diag_destroy || (sk->sk_protocol != IPPROTO_TCP &&
-					   sk->sk_protocol != IPPROTO_UDP))
+	if (!sk->sk_prot->diag_destroy)
+		return -EOPNOTSUPP;
+
+	if (sk_fullsock(sk) &&
+	    sk->sk_protocol != IPPROTO_TCP &&
+	    sk->sk_protocol != IPPROTO_UDP)
 		return -EOPNOTSUPP;
 
 	return sk->sk_prot->diag_destroy(sk, ECONNABORTED);
Signature · 1 line
2.53.0
author maintainer
#15 lore raw

PATCH 15/395 tcp: Skip cond_resched() in inet_csk_listen_stop() under BPF context

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiayuan Chen <[email protected]>

[ Upstream commit eaab8cab451b9502ce224cd202550375b894a467 ]

bpf_sock_destroy() runs from the tcp iterator, under rcu_read_lock(). If the sock is a listener that still has children in its accept queue, tcp_abort() ends up in inet_csk_listen_stop() and the cond_resched() there trips the debug check:

BUG: sleeping function called from invalid context at net/ipv4/inet_connection_sock.c:1523

in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 628, name: test_progs
preempt_count: 0, expected: 0
RCU nest depth: 1, expected: 0
locks held by test_progs/628: 3, last CPU#3:
#0: ffff8881158cee18 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x56/0x1210 #1: ffff8881106bb858 (sk_lock-AF_INET6){+.+.}-{0:0}, at: bpf_iter_tcp_seq_show+0x32b/0x4b0 #2: ffffffffb435af20 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x46b/0xde0

CPU: 3 UID: 0 PID: 628 Comm: test_progs Tainted: G        W           7.2.0+ #65 PREEMPT
Tainted: [W]=WARN
Call Trace:
 <TASK>
 dump_stack_lvl+0xc1/0xf0
 dump_stack+0x10/0x20
 __might_resched+0x3d2/0x610
 inet_csk_listen_stop+0x7b/0xbf0
 tcp_abort+0x23b/0x3b0
 bpf_sock_destroy+0xfc/0x140
 bpf_prog_448133d24601754f_iter_tcp6_server+0x81/0x8a
 bpf_iter_run_prog+0x538/0xde0
 bpf_iter_tcp_seq_show+0x26b/0x4b0
 bpf_seq_read+0x424/0x1210
 vfs_read+0x197/0xe40
 ksys_read+0x119/0x240
 __x64_sys_read+0x72/0xc0
 x64_sys_call+0x647/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7fad39b28aca
RSP: 002b:00007ffc381c61c0 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 00007ffc381c6a88 RCX: 00007fad39b28aca
RDX: 0000000000000032 RSI: 00007ffc381c6250 RDI: 0000000000000014
RBP: 00007ffc381c61e0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003
R13: 0000000000000000 R14: 000055f077c1bbb0 R15: 00007fad3a0f3000
 </TASK>

The commit that added the kfunc already guards lock_sock() in tcp_abort() and udp_abort() with has_current_bpf_ctx(), but missed the listener path. Do the same for the cond_resched(). The loop runs inside the iterator's rcu_read_lock(), it must not reschedule or report a quiescent state there.

---
 net/ipv4/inet_connection_sock.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/ipv4/inet_connection_sock.c +2 -1
index 6193db63b2973..a44c8096725fe 100644
@@ -1533,7 +1533,8 @@ void inet_csk_listen_stop(struct sock *sk)
 		local_bh_enable();
 		sock_put(child);
 
-		cond_resched();
+		if (!has_current_bpf_ctx())
+			cond_resched();
 	}
 	if (queue->fastopenq.rskq_rst_head) {
 		/* Free all the reqs queued in rskq_rst_head. */
Signature · 1 line
2.53.0
author maintainer
#16 lore raw

PATCH 16/395 HID: multitouch: Add report ID mismatch quirk for ASUS ROG Z13 Folio

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lovekesh Solanki <[email protected]>

[ Upstream commit aaaea79efba5a27cb9e0a5a628046d829d3f2cbb ]

Commit e716edafedad ("HID: multitouch: Check to ensure report responses match the request") introduced validating GET_FEATURE responses return the requested report ID.

ASUS ROG Z13 Flow (2025) GZ302EA touchpad (USB 0b05:1a30) returns a different report ID for Win8 feature request. Before this check, the response was still processed and allowed device to switch into its full Touchpad Precision mode.

After the validation, the response is discarded before hid_report_raw_event() processes it and device remains in fallback mode and no longer exposes ABS_MT_SLOT, ABS_MT_TOOL_TYPE or the multi-finger BTN_TOOL_* capabilities for palm rejection.

Add a device quirk to allow the known firmware behavior for this device while preserving report ID validation for all other devices.

The device previously matched the generic MT_CLS_WIN_8 entry, so base the new class on MT_CLS_WIN_8 to keep it on the same quirk set as before the regression. MT_QUIRK_CONFIDENCE must be set
explicitly: it is normally enabled by the class name check in mt_touch_input_mapping(), which only matches the MT_CLS_WIN_8* names, and it is what makes ABS_MT_TOOL_TYPE available for touchpads.

Fixes e716edafedad ("HID: multitouch: Check to ensure report responses match the request")
---
 drivers/hid/hid-multitouch.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)
drivers/hid/hid-multitouch.c +27 -2
index 35f9f4f76a550..4b736cd012db9 100644
@@ -79,6 +79,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_APPLE_TOUCHBAR		BIT(23)
 #define MT_QUIRK_YOGABOOK9I		BIT(24)
 #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE	BIT(25)
+#define MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH	BIT(26)
 
 #define MT_INPUTMODE_TOUCHSCREEN	0x02
 #define MT_INPUTMODE_TOUCHPAD		0x03
@@ -233,6 +234,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 #define MT_CLS_APPLE_TOUCHBAR			0x0114
 #define MT_CLS_YOGABOOK9I			0x0115
 #define MT_CLS_EGALAX_P80H84			0x0116
+#define MT_CLS_ASUS_ROG_Z13_FOLIO		0x0117
 #define MT_CLS_SIS				0x0457
 
 #define MT_DEFAULT_MAXCONTACT	10
@@ -403,6 +405,16 @@ static const struct mt_class mt_classes[] = {
 		.quirks = MT_QUIRK_ALWAYS_VALID |
 			MT_QUIRK_CONTACT_CNT_ACCURATE |
 			MT_QUIRK_ASUS_CUSTOM_UP },
+	{ .name = MT_CLS_ASUS_ROG_Z13_FOLIO,
+		.quirks = MT_QUIRK_ALWAYS_VALID |
+			MT_QUIRK_IGNORE_DUPLICATES |
+			MT_QUIRK_HOVERING |
+			MT_QUIRK_CONTACT_CNT_ACCURATE |
+			MT_QUIRK_STICKY_FINGERS |
+			MT_QUIRK_WIN8_PTP_BUTTONS |
+			MT_QUIRK_CONFIDENCE |
+			MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH,
+		.export_all_inputs = true },
 	{ .name = MT_CLS_VTL,
 		.quirks = MT_QUIRK_ALWAYS_VALID |
 			MT_QUIRK_CONTACT_CNT_ACCURATE |
@@ -505,6 +517,7 @@ static const struct attribute_group mt_attribute_group = {
 
 static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
 {
+	struct mt_device *td = hid_get_drvdata(hdev);
 	int ret;
 	u32 size = hid_report_len(report);
 	u8 *buf;
@@ -526,8 +539,14 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
 		dev_warn(&hdev->dev, "failed to fetch feature %d\n",
 			 report->id);
 	} else {
-		/* The report ID in the request and the response should match */
-		if (report->id != buf[0]) {
+		/*
+		 * The report ID in the request and the response should match.
+		 * Some firmware (e.g. the ASUS ROG Z13 Folio
+		 * touchpad) returns a mismatched ID on this specific fetch;
+		 * tolerate it only for devices explicitly flagged as such.
+		 */
+		if (report->id != buf[0] &&
+		    !(td->mtclass.quirks & MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH)) {
 			hid_err(hdev, "Returned feature report did not match the request\n");
 			goto free;
 		}
@@ -2716,6 +2735,12 @@ static const struct hid_device_id mt_devices[] = {
 		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
 			   I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288) },
 
+	/* Asus ROG Flow Z13 (2025) GZ302EA keyboard-cover touchpad */
+	{ .driver_data = MT_CLS_ASUS_ROG_Z13_FOLIO,
+		HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ASUSTEK,
+			USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO) },
+
 	/* Generic MT device */
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
 
Signature · 1 line
2.53.0
author maintainer
#17 lore raw

PATCH 17/395 HID: elecom: fix bus type for M-XGL20DLBK

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Oscar Priego Verdugo <[email protected]>

[ Upstream commit 8e2a4b458ad25e13422bb059758c30a6562aa9cf ]

The M-XGL20DLBK is matched as a USB device by hid-elecom, but its entry in hid_have_special_driver[] uses HID_BLUETOOTH_DEVICE.

This prevents the special-driver quirk entry from matching the USB device handled by hid-elecom. Use HID_USB_DEVICE there as well.

Fixes 55633e681afb ("HID: elecom: add support for EX-G M-XGL20DLBK wireless mouse")
---
 drivers/hid/hid-quirks.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/hid-quirks.c +1 -1
index ebf865c2dbb38..92aea01e1d644 100644
@@ -421,7 +421,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_ELECOM)
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) },
Signature · 1 line
2.53.0
author maintainer
#18 lore raw

PATCH 18/395 KVM: x86/pmu: Move Intel PMU global MSRs to intel_is_valid_msr()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jim Mattson <[email protected]>

[ Upstream commit 79a71cc2568f4b5d42284da2aa26f3b4f47ce01b ]

Commit c85cdc1cc1ea ("KVM: x86/pmu: Move handling PERF_GLOBAL_CTRL and friends to common x86") moved the existence check for the following Intel PMU MSRs to kvm_pmu_is_valid_msr():
- MSR_CORE_PERF_GLOBAL_STATUS
- MSR_CORE_PERF_GLOBAL_CTRL
- MSR_CORE_PERF_GLOBAL_OVF_CTRL

That commit deemed these MSRs valid whenever pmu->version > 1. It intended to share the check with AMD PerfMonV2 because both vendor implementations require version 2 or greater for global PMU controls. However, as noted in the commit message, AMD uses different MSR indices for its global PMU registers.

Commit 4a2771895ca6 ("KVM: x86/svm/pmu: Add AMD PerfMonV2 support") subsequently added AMD PerfMonV2 support and set pmu->version = 2. Because kvm_pmu_is_valid_msr() validated the Intel MSRs whenever pmu->version > 1, KVM incorrectly permitted AMD guests with PerfMonV2 to access these Intel MSRs without a #GP.

Move the validation of these Intel MSRs to intel_is_valid_msr() and remove the common switch statement from kvm_pmu_is_valid_msr(). AMD already validates its own global PMU MSRs in amd_is_valid_msr().

---
 arch/x86/kvm/pmu.c           | 8 --------
 arch/x86/kvm/vmx/pmu_intel.c | 3 +++
 2 files changed, 3 insertions(+), 8 deletions(-)
arch/x86/kvm/pmu.c +0 -8
index 487ad19a236e3..31b2b75156dbf 100644
@@ -710,14 +710,6 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
 
 bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
 {
-	switch (msr) {
-	case MSR_CORE_PERF_GLOBAL_STATUS:
-	case MSR_CORE_PERF_GLOBAL_CTRL:
-	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
-		return kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
-	default:
-		break;
-	}
 	return kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr) ||
 	       kvm_pmu_call(is_valid_msr)(vcpu, msr);
 }
arch/x86/kvm/vmx/pmu_intel.c +3 -0
index 333d7c573d40a..a9d21a97c9621 100644
@@ -190,6 +190,9 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
 	int ret;
 
 	switch (msr) {
+	case MSR_CORE_PERF_GLOBAL_STATUS:
+	case MSR_CORE_PERF_GLOBAL_CTRL:
+	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
 	case MSR_CORE_PERF_FIXED_CTR_CTRL:
 		return kvm_pmu_has_perf_global_ctrl(pmu);
 	case MSR_IA32_PEBS_ENABLE:
Signature · 1 line
2.53.0
author maintainer
#19 lore raw

PATCH 19/395 bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jose Fernandez (Anthropic) <[email protected]>

[ Upstream commit 85136bf22404474a815fc0ed26ec0d1cbc1bc3f9 ]

__htab_map_lookup_and_delete_batch() has no rescheduling point. The batch count bounds how many entries are copied out, not how many buckets are visited, so one BPF_MAP_LOOKUP_BATCH call can walk the map end to end. The empty-bucket fast path is worse: it stays inside a single rcu_read_lock() / bpf_disable_instrumentation() section for any run of consecutive empty buckets.

That holds up on small maps, but it falls apart at scale. On a 144-CPU arm64 host running a CONFIG_PREEMPT_NONE kernel, periodic BPF_MAP_LOOKUP_BATCH calls against an LRU hash map with 16,777,216 buckets held a CPU inside the batch op for 77+ seconds and triggered the soft lockup watchdog.

Commit 75134f16e7dd ("bpf: Add schedule points in batch ops") fixed this same problem in the generic batch ops, but not in this htab-native path, which every htab-based hash map variant uses for its lookup[_and_delete] batch ops.

Complete that fix here. Leave the critical section after 64 consecutive empty buckets, call cond_resched_tasks_rcu_qs(), and resume at the saved bucket cursor. No locks are held at that point, and resuming from the cursor is already the function's behavior for non-empty buckets. Add the same call to the per-bucket loop after copy_to_user(), where every lock has been dropped. cond_resched_rcu() is not enough here: sleeping with bpf_prog_active elevated makes tracing programs on that CPU silently skip their invocations.

Plain cond_resched() is not enough either. It is a no-op under PREEMPT and PREEMPT_LAZY, the only models arm64 and x86 have offered since commit 7dadeaa6e851 ("sched: Further restrict the preemption modes"). It is also never a Tasks RCU quiescent state, in any model: the reschedule counts as a preemption. The walking task stays a holdout and stalls every synchronize_rcu_tasks() caller, ftrace and BPF trampoline teardown included, until the syscall returns [1]. cond_resched_tasks_rcu_qs() is the usual tool for that [2]. It reports the quiescent state at each yield and still reschedules as cond_resched() does on PREEMPT_NONE and PREEMPT_VOLUNTARY kernels.

---
 kernel/bpf/hashtab.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)
kernel/bpf/hashtab.c +21 -3
index 7f8e029a6af8d..070ac56d47e99 100644
@@ -1675,6 +1675,12 @@ static int htab_lru_percpu_map_lookup_and_delete_elem(struct bpf_map *map,
 						 flags);
 }
 
+/*
+ * Max consecutive empty buckets to walk in one RCU +
+ * instrumentation-disabled section before rescheduling.
+ */
+#define HTAB_BATCH_EMPTY_RESCHED 64
+
 static int
 __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 				   const union bpf_attr *attr,
@@ -1696,6 +1702,7 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 	unsigned long flags = 0;
 	bool locked = false;
 	struct htab_elem *l;
+	u32 empty_cnt = 0;
 	struct bucket *b;
 	int ret = 0;
 
@@ -1864,12 +1871,21 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 	}
 
 next_batch:
-	/* If we are not copying data, we can go to next bucket and avoid
-	 * unlocking the rcu.
+	/*
+	 * If we are not copying data, we can go to next bucket and avoid
+	 * unlocking the rcu. Bound the walk though: after
+	 * HTAB_BATCH_EMPTY_RESCHED consecutive empty buckets, fully exit
+	 * the critical section (no locks are held here) and reschedule.
 	 */
 	if (!bucket_cnt && (batch + 1 < htab->n_buckets)) {
 		batch++;
-		goto again_nocopy;
+		if (++empty_cnt < HTAB_BATCH_EMPTY_RESCHED)
+			goto again_nocopy;
+		empty_cnt = 0;
+		rcu_read_unlock();
+		bpf_enable_instrumentation();
+		cond_resched_tasks_rcu_qs();
+		goto again;
 	}
 
 	rcu_read_unlock();
@@ -1883,11 +1899,13 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 	}
 
 	total += bucket_cnt;
+	empty_cnt = 0;
 	batch++;
 	if (batch >= htab->n_buckets) {
 		ret = -ENOENT;
 		goto after_loop;
 	}
+	cond_resched_tasks_rcu_qs();
 	goto again;
 
 after_loop:
Signature · 1 line
2.53.0
author maintainer
#20 lore raw

PATCH 20/395 bpf: Fix out-of-bounds read of rtt_min in sock_ops

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiayuan Chen <[email protected]>

[ Upstream commit 75f8cf22463d82bb1fb0239a3d485fc8f4c8ef03 ]

A sockops prog reading skops->rtt_min never checks the sk type: on the tcp_conn_request() path sock_ops->sk is a request_sock (non-full), and the ctx rewrite casts it to a tcp_sock (full) and reads rtt_min past the end of the request_sock, returning dirty adjacent memory.

	SEC("sockops")
	int prog(struct bpf_sock_ops *skops)
	{
		switch (skops->op) {
		case BPF_SOCK_OPS_RWND_INIT:
			leak = skops->rtt_min;   /* reads the request_sock OOB */
		...
		}
	}

For instance one such read returned rtt_min=0xffff8881, the high half of a leaked kernel pointer.

Guarding that cast is exactly what SOCK_OPS_GET_FIELD() does -- it checks is_locked_tcp_sock and returns 0 when sock_ops->sk is not a locked full socket. Every other tcp_sock field in sock_ops goes through it; rtt_min is the only one open-coded, so it skips the check.

Read rtt_min through SOCK_OPS_GET_FIELD() too. rtt_min is a bit special:
it is a struct minmax and we only want the current min, so pass rtt_min.s[0].v. That is equivalent to the old hand-computed offset

offsetof(struct tcp_sock, rtt_min) + sizeof_field(struct minmax_sample, t)

(s[0] sits at rtt_min + 0 and .v at + sizeof(.t), i.e. what minmax_get() returns), so the loaded field is unchanged and only the full-sock guard is added. The two BUILD_BUG_ON()s that protected the hand-computed offset are no longer needed.

Before patch:

	0: r1 = *(u64 *)(r1 +0)      ; r1 = skops->sk
	1: r1 = *(u32 *)(r1 +2324)   ; ((tcp_sock *)sk)->rtt_min.s[0].v

After patch:

	0: *(u64 *)(r1 +56) = r9
	1: r9 = *(u8 *)(r1 +50)      ; is_locked_tcp_sock
	2: if r9 == 0 goto pc+4      ; not a locked full sock -> 0
	3: r9 = *(u64 *)(r1 +56)
	4: r1 = *(u64 *)(r1 +0)      ; r1 = skops->sk
	5: r1 = *(u32 *)(r1 +2324)   ; rtt_min.s[0].v
	6: goto pc+2
	7: r9 = *(u64 *)(r1 +56)
	8: r1 = 0
---
 net/core/filter.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
net/core/filter.c +1 -12
index 4f0a052d9aed1..dea8dd48d4aa6 100644
@@ -10787,18 +10787,7 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
 		break;
 
 	case offsetof(struct bpf_sock_ops, rtt_min):
-		BUILD_BUG_ON(sizeof_field(struct tcp_sock, rtt_min) !=
-			     sizeof(struct minmax));
-		BUILD_BUG_ON(sizeof(struct minmax) <
-			     sizeof(struct minmax_sample));
-
-		*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
-						struct bpf_sock_ops_kern, sk),
-				      si->dst_reg, si->src_reg,
-				      offsetof(struct bpf_sock_ops_kern, sk));
-		*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
-				      offsetof(struct tcp_sock, rtt_min) +
-				      sizeof_field(struct minmax_sample, t));
+		SOCK_OPS_GET_FIELD(rtt_min, rtt_min.s[0].v, struct tcp_sock);
 		break;
 
 	case offsetof(struct bpf_sock_ops, bpf_sock_ops_cb_flags):
Signature · 1 line
2.53.0
author maintainer
#21 lore raw

PATCH 21/395 bpf: Register dtor for freeing special fields

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit 1df97a7453eec80c1912c2d0360290a3970a7671 ]

There is a race window where BPF hash map elements can leak special fields if the program with access to the map value recreates these special fields between the check_and_free_fields done on the map value and its eventual return to the memory allocator.

Several ways were explored prior to this patch, most notably [0] tried to use a poison value to reject attempts to recreate special fields for map values that have been logically deleted but still accessible to BPF programs (either while sitting in the free list or when reused). While this approach works well for task work, timers, wq, etc., it is harder to apply the idea to kptrs, which have a similar race and failure mode.

Instead, we change bpf_mem_alloc to allow registering destructor for allocated elements, such that when they are returned to the allocator, any special fields created while they were accessible to programs in the mean time will be freed. If these values get reused, we do not free the fields again before handing the element back. The special fields thus may remain initialized while the map value sits in a free list.

When bpf_mem_alloc is retired in the future, a similar concept can be introduced to kmalloc_nolock-backed kmem_cache, paired with the existing idea of a constructor.

Note that the destructor registration happens in map_check_btf, after the BTF record is populated and (at that point) avaiable for inspection and duplication. Duplication is necessary since the freeing of embedded bpf_mem_alloc can be decoupled from actual map lifetime due to logic introduced to reduce the cost of rcu_barrier()s in mem alloc free path in 9f2c6e96c65e ("bpf: Optimize rcu_barrier usage between hash map and bpf_mem_alloc.").

As such, once all callbacks are done, we must also free the duplicated record. To remove dependency on the bpf_map itself, also stash the key size of the map to obtain value from htab_elem long after the map is gone.

[0]: https://lore.kernel.org/bpf/[email protected]

Fixes 14a324f6a67e ("bpf: Wire up freeing of referenced kptr")
Fixes 1bfbc267ec91 ("bpf: Enable bpf_timer and bpf_wq in any context")

Stable-dep-of: 1c21452d02ee ("bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk")

---
 include/linux/bpf_mem_alloc.h |  6 +++
 kernel/bpf/hashtab.c          | 87 +++++++++++++++++++++++++++++++++++
 kernel/bpf/memalloc.c         | 58 ++++++++++++++++++-----
 3 files changed, 140 insertions(+), 11 deletions(-)
include/linux/bpf_mem_alloc.h +6 -0
index e45162ef59bb1..4ce0d27f8ea26 100644
@@ -14,6 +14,8 @@ struct bpf_mem_alloc {
 	struct obj_cgroup *objcg;
 	bool percpu;
 	struct work_struct work;
+	void (*dtor_ctx_free)(void *ctx);
+	void *dtor_ctx;
 };
 
 /* 'size != 0' is for bpf_mem_alloc which manages fixed-size objects.
@@ -32,6 +34,10 @@ int bpf_mem_alloc_percpu_init(struct bpf_mem_alloc *ma, struct obj_cgroup *objcg
 /* The percpu allocation with a specific unit size. */
 int bpf_mem_alloc_percpu_unit_init(struct bpf_mem_alloc *ma, int size);
 void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma);
+void bpf_mem_alloc_set_dtor(struct bpf_mem_alloc *ma,
+			    void (*dtor)(void *obj, void *ctx),
+			    void (*dtor_ctx_free)(void *ctx),
+			    void *ctx);
 
 /* Check the allocation size for kmalloc equivalent allocator */
 int bpf_mem_alloc_check_size(bool percpu, size_t size);
kernel/bpf/hashtab.c +87 -0

123 lines not on this page · raw message

kernel/bpf/memalloc.c +47 -11

108 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#22 lore raw

PATCH 22/395 bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pu Lehui <[email protected]>

[ Upstream commit 1c21452d02eec2f008e2c5535820f85adbd7587a ]

Syzkaller repeatedly triggered UAF splats related to nodes in waiting_for_gp_ttrace within the bpf memalloc:

BUG: KASAN: slab-use-after-free in llist_del_first+0x85/0x110 lib/llist.c:61
Read of size 8 at addr ffff8881572cd080 by task syz.4.470/5112
 ...
 llist_del_first+0x85/0x110 lib/llist.c:61
 alloc_bulk+0x193/0x460 kernel/bpf/memalloc.c:229
 bpf_mem_refill+0x386/0x560 kernel/bpf/memalloc.c:436

Freed by task 14:
 ...
 __free_rcu kernel/bpf/memalloc.c:281 [inline]
 __free_rcu_tasks_trace+0x48/0xd0 kernel/bpf/memalloc.c:291
 rcu_tasks_invoke_cbs+0x1ec/0x3e0 kernel/rcu/tasks.h:571
 rcu_tasks_one_gp+0x13d/0x220 kernel/rcu/tasks.h:621
 rcu_tasks_kthread+0xf3/0x120 kernel/rcu/tasks.h:651

The reason is that the UAF occurs after the RCU Tasks Trace GP expires:
when the __free_rcu() callback runs, there is no synchronization protecting llist_del_all() against concurrent alloc_bulk() operating on waiting_for_gp_ttrace, leading to the race condition below:

CPU0 CPU1
__free_rcu (RCU Tasks Trace callback)
alloc_bulk
llist_del_first(&c->waiting_for_gp_ttrace)

    entry = smp_load_acquire(&head->first);
    do {
      if (entry == NULL)
        return NULL;
                                               free_all(llist_del_all(&c->waiting_for_gp_ttrace))
                                                 llist_for_each_safe(pos, t, llnode)
                                                   free_one(pos);
      next = READ_ONCE(entry->next); <-- trigger UAF
    } while (!try_cmpxchg(&head->first, &entry, next));

In addition, there is also a theoretical race condition on the free_by_rcu_ttrace list. This race requires two preconditions: an in-flight Tasks Trace GP keeping c->call_rcu_ttrace_in_progress == 1, and concurrent cross-CPU frees repopulating c->free_by_rcu_ttrace with new nodes. Under these conditions, the following scenario triggers UAF:

// CPU0
// irq work is still busy (on PREEMPT_RT)
alloc_bulk()
llist_del_first(&c->free_by_rcu_ttrace)

    entry = smp_load_acquire(&head->first);
    do {
      if (entry == NULL)
        return NULL;

        // CPU1
        bpf_mem_alloc_destroy()
          WRITE_ONCE(c->draining, true)
          // wait for CPU0
          irq_work_sync()

                // CPU2
                do_call_rcu_ttrace(tgt(CPU0))
                  if (c->draining) {
                    llist_del_all(&c->free_by_rcu_ttrace)
                    free_all()
                  }

// CPU0 continue

      next = READ_ONCE(entry->next); <-- trigger UAF
    while (!try_cmpxchg(&head->first, &entry, next));

Fix this by introducing a raw spinlock to synchronize the concurrent consumption on waiting_for_gp_ttrace and free_by_rcu_ttrace.

---
 kernel/bpf/memalloc.c | 50 ++++++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 22 deletions(-)
kernel/bpf/memalloc.c +28 -22
index 682a9f34214bd..ed69c895cf865 100644
@@ -119,6 +119,7 @@ struct bpf_mem_cache {
 	struct llist_head waiting_for_gp_ttrace;
 	struct rcu_head rcu_ttrace;
 	atomic_t call_rcu_ttrace_in_progress;
+	raw_spinlock_t lock;
 };
 
 struct bpf_mem_caches {
@@ -214,25 +215,24 @@ static void alloc_bulk(struct bpf_mem_cache *c, int cnt, int node, bool atomic)
 	gfp = __GFP_NOWARN | __GFP_ACCOUNT;
 	gfp |= atomic ? GFP_NOWAIT : GFP_KERNEL;
 
-	for (i = 0; i < cnt; i++) {
-		/*
-		 * For every 'c' llist_del_first(&c->free_by_rcu_ttrace); is
-		 * done only by one CPU == current CPU. Other CPUs might
-		 * llist_add() and llist_del_all() in parallel.
-		 */
-		obj = llist_del_first(&c->free_by_rcu_ttrace);
-		if (!obj)
-			break;
-		add_obj_to_free_list(c, obj);
-	}
-	if (i >= cnt)
-		return;
+	/*
+	 * c->lock serializes concurrent llist_del_first() against
+	 * llist_del_all() in __free_rcu() and do_call_rcu_ttrace().
+	 */
+	scoped_guard(raw_spinlock_irqsave, &c->lock) {
+		for (i = 0; i < cnt; i++) {
+			obj = llist_del_first(&c->free_by_rcu_ttrace);
+			if (!obj)
+				break;
+			add_obj_to_free_list(c, obj);
+		}
 
-	for (; i < cnt; i++) {
-		obj = llist_del_first(&c->waiting_for_gp_ttrace);
-		if (!obj)
-			break;
-		add_obj_to_free_list(c, obj);
+		for (; i < cnt; i++) {
+			obj = llist_del_first(&c->waiting_for_gp_ttrace);
+			if (!obj)
+				break;
+			add_obj_to_free_list(c, obj);
+		}
 	}
 	if (i >= cnt)
 		return;
@@ -279,8 +279,12 @@ static int free_all(struct bpf_mem_cache *c, struct llist_node *llnode, bool per
 static void __free_rcu(struct rcu_head *head)
 {
 	struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu_ttrace);
+	struct llist_node *llnode;
+
+	scoped_guard(raw_spinlock_irqsave, &c->lock)
+		llnode = llist_del_all(&c->waiting_for_gp_ttrace);
 
-	free_all(c, llist_del_all(&c->waiting_for_gp_ttrace), !!c->percpu_size);
+	free_all(c, llnode, !!c->percpu_size);
 	atomic_set(&c->call_rcu_ttrace_in_progress, 0);
 }
 
@@ -311,7 +315,8 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 
 	if (atomic_xchg(&c->call_rcu_ttrace_in_progress, 1)) {
 		if (unlikely(READ_ONCE(c->draining))) {
-			llnode = llist_del_all(&c->free_by_rcu_ttrace);
+			scoped_guard(raw_spinlock_irqsave, &c->lock)
+				llnode = llist_del_all(&c->free_by_rcu_ttrace);
 			free_all(c, llnode, !!c->percpu_size);
 		}
 		return;
@@ -546,6 +551,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
 			c->objcg = objcg;
 			c->percpu_size = percpu_size;
 			c->tgt = c;
+			raw_spin_lock_init(&c->lock);
 			init_refill_work(c);
 			prefill_mem_cache(c, cpu);
 		}
@@ -568,7 +574,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
 			c->objcg = objcg;
 			c->percpu_size = percpu_size;
 			c->tgt = c;
-
+			raw_spin_lock_init(&c->lock);
 			init_refill_work(c);
 			prefill_mem_cache(c, cpu);
 		}
@@ -620,7 +626,7 @@ int bpf_mem_alloc_percpu_unit_init(struct bpf_mem_alloc *ma, int size)
 		c->objcg = objcg;
 		c->percpu_size = percpu_size;
 		c->tgt = c;
-
+		raw_spin_lock_init(&c->lock);
 		init_refill_work(c);
 		prefill_mem_cache(c, cpu);
 	}
Signature · 1 line
2.53.0
author maintainer
#23 lore raw

PATCH 23/395 bpf, sockmap: Fix self-redirect copied_seq double-counting

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Geliang Tang <[email protected]>

[ Upstream commit 490a83d6386eec1d29f470c8d7331677fb46c3b7 ]

When a BPF stream_verdict program redirects an skb back to the same socket (self-redirect with BPF_F_INGRESS), sk_psock_verdict_apply() calls tcp_eat_skb() which advances tcp_sk->copied_seq. However, the skb is then delivered to the socket's psock ingress queue and later read by tcp_bpf_recvmsg_parser(), which also advances copied_seq via the copied_from_self accounting path. This double-counting causes copied_seq to advance by 2x the actual data length, triggering:

  TCP recvmsg seq # bug 2: copied BF2E806, seq BF2E7FD, \
			   rcvnxt BF2E806, fl 0
  WARNING: net/ipv4/tcp.c:2745 at tcp_recvmsg_locked+0x72b/0x2640
  Call Trace:
   tcp_recvmsg+0x10a/0x500
   sock_recvmsg+0x168/0x1d0
   __sys_recvfrom+0x19a/0x2a0
   __x64_sys_recvfrom+0xe4/0x1f0
   do_syscall_64+0xf7/0x530
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

cleanup rbuf bug: copied BF2E806 seq BF2E806 rcvnxt BF2E806

  WARNING: net/ipv4/tcp.c:1609 at tcp_cleanup_rbuf+0xf2/0x1c0
  Call Trace:
   tcp_recvmsg_locked+0x8d1/0x2640
   tcp_recvmsg+0x10a/0x500
   sock_recvmsg+0x168/0x1d0
   __sys_recvfrom+0x19a/0x2a0
   __x64_sys_recvfrom+0xe4/0x1f0
   do_syscall_64+0xf7/0x530
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

Fix this by converting self-redirect verdict to __SK_PASS at the beginning of sk_psock_verdict_apply(). This bypasses the __SK_REDIRECT case entirely (which calls sk_psock_eat_skb), letting the __SK_PASS path queue the skb to the psock ingress queue. The data is then read via tcp_bpf_recvmsg_parser(), which advances copied_seq exactly once through copied_from_self. Cross-socket redirects continue through __SK_REDIRECT with sk_psock_eat_skb() unchanged.

---
 net/core/skmsg.c | 4 ++++
 1 file changed, 4 insertions(+)
net/core/skmsg.c +4 -0
index c1c315ae2b22b..f5c12ef68675c 100644
@@ -1036,6 +1036,10 @@ static int sk_psock_verdict_apply(struct sk_psock *psock, struct sk_buff *skb,
 	int err = 0;
 	u32 len, off;
 
+	if (verdict == __SK_REDIRECT && skb_bpf_ingress(skb) &&
+	    skb_bpf_redirect_fetch(skb) == psock->sk)
+		verdict = __SK_PASS;
+
 	switch (verdict) {
 	case __SK_PASS:
 		err = -EIO;
Signature · 1 line
2.53.0
author maintainer
#24 lore raw

PATCH 24/395 bpf, arm64: set up the frame pointer for the exception callback

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Donggeun Yoo <[email protected]>

[ Upstream commit ef1fb82f12186dd26153b14d9fbcf4ec98db81b3 ]

A program acting as exception boundary saves all callee-saved registers, so build_prologue() takes the exception_cb path and never calls push_callee_regs(). That is the only place find_used_callee_regs() runs, and with it the only place ctx->fp_used is set, so the callback prologue does not emit the

mov x25, sp

that points BPF_REG_FP at the frame the callback runs on. x25 keeps whatever it held when bpf_throw() was called. If the throw came from a subprogram that uses its own BPF stack, that is the subprogram's frame pointer, and since the subprogram never returns it never restores x25 either.

Stack accesses through BPF_REG_FP are rewritten to be stack pointer relative, so those still land in the callback's own frame. Materializing the register does not: a callback that passes the address of a local variable to a helper hands over an address in the dead subprogram's frame. That address is below the callback's stack pointer by then, and the helper's own call chain covers it, so the helper can write over its own return address. 0x1234 below is the value the helper was asked to store:

  pc : 0x1234
  lr : 0x1234
  Call trace:
   0x1234 (P)
   bpf_test_run+0x188/0x3e0
   bpf_prog_test_run_skb+0x47c/0x998
   __sys_bpf+0xbdc/0xdd8
  Kernel panic - not syncing: Oops: Fatal exception in interrupt

Set ctx->fp_used on the exception callback path so that the existing code further down sets x25 from the stack pointer. The epilogue restores it from the main program's save area along with the other callee-saved registers, as it already does. x86 sets the frame pointer for the callback from the argument it is passed, and powerpc computes it from the stack pointer.

Fixes 5d4fa9ec5643 ("bpf, arm64: Avoid blindly saving/restoring all callee-saved registers")
---
 arch/arm64/net/bpf_jit_comp.c | 2 ++
 1 file changed, 2 insertions(+)
arch/arm64/net/bpf_jit_comp.c +2 -0
index 7be20cb32a271..10b9079c1212f 100644
@@ -592,6 +592,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
 		 * 12 registers are on the stack
 		 */
 		emit(A64_SUB_I(1, A64_SP, A64_FP, 96), ctx);
+		/* The callback may use its own BPF stack, set up fp for it. */
+		ctx->fp_used = true;
 	}
 
 	/* Stack must be multiples of 16B */
Signature · 1 line
2.53.0
author maintainer
#25 lore raw

PATCH 25/395 pinctrl: meson: Fix typo in s4 group name

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Anderson <[email protected]>

[ Upstream commit 692f32609a30f75ca3401e25b504bfd06bd5662a ]

One of the i2c pin groups has some junk at the end. The name should be i2c2_scl_h1, and indeed that's the name used by i2c2_pins3 in meson-s4.dtsi.

Fixes 775214d389c25 ("pinctrl: meson: add pinctrl driver support for Meson-S4 Soc")
---
 drivers/pinctrl/meson/pinctrl-meson-s4.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pinctrl/meson/pinctrl-meson-s4.c +1 -1
index 872948699e9fe..365dafe457a9f 100644
@@ -854,7 +854,7 @@ static const char * const i2c1_groups[] = {
 static const char * const i2c2_groups[] = {
 	"i2c2_sda_d", "i2c2_scl_d",
 	"i2c2_sda_h8", "i2c2_scl_h9",
-	"i2c2_sda_h0", "i2c2_scl_h1l,"
+	"i2c2_sda_h0", "i2c2_scl_h1",
 };
 
 static const char * const i2c3_groups[] = {
Signature · 1 line
2.53.0
author maintainer
#26 lore raw

PATCH 26/395 HID: amd_sfh: Validate PCI BAR size before mapping

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Slawomir Stepien <[email protected]>

[ Upstream commit 65bcc5f89704efe5b9d69d4ea2c1002d90c31382 ]

The amd_sfh driver maps PCI BAR 2 using pcim_iomap_regions() and subsequently accesses MMIO registers at offsets up to 0x10958 (e.g., AMD_P2C_MSG3 at 0x1068C). However, the driver never validates that the BAR size is large enough to cover these accesses. If the driver is bound to a device with a smaller BAR 2, this leads to an out-of-bounds memory access and a page fault during the probe function.

For example, a page fault can occur when reading from privdata->mmio + AMD_P2C_MSG3 in mp2_select_ops():

  BUG: unable to handle page fault for address: ffffc9000390368c
  PGD 100000067 P4D 100000067 PUD 1012c1067 PMD 105b64067 PTE 0
  Oops: Oops: 0000 [#1] SMP KASAN NOPTI
  RIP: 0010:readl arch/x86/include/asm/io.h:59 [inline]
  RIP: 0010:mp2_select_ops drivers/hid/amd-sfh-hid/amd_sfh_pcie.c:282
  [inline]
  RIP: 0010:amd_mp2_pci_probe+0x337/0x5f0
  drivers/hid/amd-sfh-hid/amd_sfh_pcie.c:487
  Call Trace:
   <TASK>
   local_pci_probe drivers/pci/pci-driver.c:332 [inline]
   pci_call_probe drivers/pci/pci-driver.c:394 [inline]
   __pci_device_probe drivers/pci/pci-driver.c:455 [inline]
   pci_device_probe+0x431/0xc90 drivers/pci/pci-driver.c:489

Fix this by verifying that the length of BAR 2 is at least 128KB before attempting to map it. Since the maximum accessed offset is 0x10958, and PCI BAR sizes are powers of 2, any legitimate hardware will have a BAR size of at least 128KB.

---
 drivers/hid/amd-sfh-hid/amd_sfh_common.h |  4 ++++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c   | 10 ++++++++++
 2 files changed, 14 insertions(+)
drivers/hid/amd-sfh-hid/amd_sfh_common.h +4 -0
index 78f830c133e5c..bd8dc16feb614 100644
@@ -12,11 +12,15 @@
 
 #include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/sizes.h>
 #include "amd_sfh_hid.h"
 
 #define PCI_DEVICE_ID_AMD_MP2		0x15E4
 #define PCI_DEVICE_ID_AMD_MP2_1_1	0x164A
 
+/* The BAR 2 size must cover the highest register offset (0x10958) */
+#define AMD_SFH_MIN_BAR_SIZE		SZ_128K
+
 #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
 #define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4))
 
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +10 -0
index 4b81cebdc3359..039b6ac327d3d 100644
@@ -451,6 +451,16 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 	if (rc)
 		return rc;
 
+	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, "BAR 2 is not IORESOURCE_MEM\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_len(pdev, 2) < AMD_SFH_MIN_BAR_SIZE) {
+		dev_err(&pdev->dev, "BAR 2 is too small\n");
+		return -EINVAL;
+	}
+
 	rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
 	if (rc)
 		return rc;
Signature · 1 line
2.53.0
author maintainer
#27 lore raw

PATCH 27/395 HID: bpf: fix __hid_bpf_hw_check_params report length

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Benjamin Tissoires <[email protected]>

[ Upstream commit c4afa4862b878d56e0cc1021298794ac1b45bc49 ]

Turns out that USB, I2C and other transport drivers (except uhid which just passes the data) still need to have the report ID in the first byte.

Because they expect the first byte to be the report ID or 0, when the report ID is 0, they strip that first byte before forwarding to the device. This means that the transport layer forwards a buffer of size N-1 to the device, which gets rejected.

Fixes 5599f8019661 ("HID: bpf: export hid_hw_output_report as a BPF kfunc")
---
 drivers/hid/bpf/hid_bpf_dispatch.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/hid/bpf/hid_bpf_dispatch.c +8 -4
index e6cf551b41e8e..9fbbf59cefa16 100644
@@ -362,7 +362,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
 
 static int
 __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
-			  enum hid_report_type rtype)
+			  enum hid_report_type rtype, bool hw_request)
 {
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
@@ -391,6 +391,10 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
 
 	report_len = hid_report_len(report);
 
+	/* unnumbered reports need to have a report ID reserved in the first byte */
+	if (hw_request && report_enum->numbered == 0)
+		report_len += 1;
+
 	if (*buf__sz > report_len)
 		*buf__sz = report_len;
 
@@ -423,7 +427,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
 		return -EDEADLOCK;
 
 	/* check arguments */
-	ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
+	ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true);
 	if (ret)
 		return ret;
 
@@ -483,7 +487,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
 		return -EDEADLOCK;
 
 	/* check arguments */
-	ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT);
+	ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, true);
 	if (ret)
 		return ret;
 
@@ -509,7 +513,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *b
 		return -EDEADLOCK;
 
 	/* check arguments */
-	ret = __hid_bpf_hw_check_params(ctx, buf, &size, type);
+	ret = __hid_bpf_hw_check_params(ctx, buf, &size, type, false);
 	if (ret)
 		return ret;
 
Signature · 1 line
2.53.0
author maintainer
#28 lore raw

PATCH 28/395 KVM: riscv: Fix NACL hfence entry update order

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zongmin Zhou <[email protected]>

[ Upstream commit b3d346838ec65fac7fd83f5dbcedd13cadfffddb ]

The SBI v3.0 specification (section 15.1.2) requires a nested HFENCE entry to be populated as follows:
1) find an unused entry with Config.Pending == 0
2) update the Page_Number and Page_Count words
3) update the Config word with Config.Pending set

__kvm_riscv_nacl_hfence() writes the Config word first, so the SBI implementation (or NACL hardware) can observe a pending entry with pnum/pcount values left over from the previous use of that entry, resulting in incorrect TLB flush ranges.

Write pnum and pcount first and the Config word last. Since the consumer is an external agent on coherent shared memory, use WRITE_ONCE() to stop the compiler from reordering the stores and smp_wmb() to make the parameter words globally visible before the Pending bit is set.

Fixes d466c19cead5 ("RISC-V: KVM: Add common nested acceleration support")
---
 arch/riscv/kvm/nacl.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
arch/riscv/kvm/nacl.c +16 -4
index 08a95ad9ada2c..f922e9f62fee3 100644
@@ -42,12 +42,24 @@ void __kvm_riscv_nacl_hfence(void *shmem,
 		}
 	}
 
-	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
-	*entp = cpu_to_lelong(control);
+	/*
+	 * Per SBI v3.0 section 15.1.2, the Page_Number and Page_Count
+	 * words must be updated before the Config word with its Pending
+	 * bit set. WRITE_ONCE() stops the compiler from reordering the
+	 * stores and smp_wmb() makes the parameter words globally
+	 * visible to the SBI implementation (or NACL hardware) before
+	 * the Pending bit is set.
+	 */
 	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
-	*entp = cpu_to_lelong(page_num);
+	WRITE_ONCE(*entp, cpu_to_lelong(page_num));
 	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
-	*entp = cpu_to_lelong(page_count);
+	WRITE_ONCE(*entp, cpu_to_lelong(page_count));
+
+	/* Ensure the parameter words are visible before the Pending bit */
+	smp_wmb();
+
+	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
+	WRITE_ONCE(*entp, cpu_to_lelong(control));
 }
 
 int kvm_riscv_nacl_enable(void)
Signature · 1 line
2.53.0
author maintainer
#29 lore raw

PATCH 29/395 RISC-V: KVM: Preserve firmware counter value across stop/start

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: SeungJu Cheon <[email protected]>

[ Upstream commit 8b3fd1a8b305321171602bfa7c41212441cf69e4 ]

Firmware events accumulate in kvpmu->fw_event[].value while running, but counter stop only clears fw_event[].started without saving the value back to pmc->counter_val. A subsequent counter start without SBI_PMU_START_FLAG_SET_INIT_VALUE reloads the stale counter_val into fw_event[].value, losing all events counted so far.

Save fw_event[].value into counter_val when actually stopping a running counter, and remove the now redundant synchronization from the snapshot path.

---
 arch/riscv/kvm/vcpu_pmu.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
arch/riscv/kvm/vcpu_pmu.c +6 -6
index ef55089c0c1a6..f3a8fd52d13a5 100644
@@ -648,10 +648,12 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 				goto out;
 			}
 
-			if (!kvpmu->fw_event[fevent_code].started)
+			if (!kvpmu->fw_event[fevent_code].started) {
 				sbiret = SBI_ERR_ALREADY_STOPPED;
-
-			kvpmu->fw_event[fevent_code].started = false;
+			} else {
+				kvpmu->fw_event[fevent_code].started = false;
+				pmc->counter_val = kvpmu->fw_event[fevent_code].value;
+			}
 		} else if (pmc->perf_event) {
 			if (pmc->started) {
 				/* Stop counting the counter */
@@ -669,9 +671,7 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 		}
 
 		if (snap_flag_set && !sbiret) {
-			if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW)
-				pmc->counter_val = kvpmu->fw_event[fevent_code].value;
-			else if (pmc->perf_event)
+			if (pmc->perf_event)
 				pmc->counter_val += perf_event_read_value(pmc->perf_event,
 									  &enabled, &running);
 			/*
Signature · 1 line
2.53.0
author maintainer
#30 lore raw

PATCH 30/395 RISC-V: KVM: Report snapshot write failure to the guest

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: SeungJu Cheon <[email protected]>

[ Upstream commit 057dd2639ceae79adced5d8fe52c32d562edcb3a ]

If kvm_vcpu_write_guest() fails while updating the PMU snapshot area on counter stop, the guest may receive SBI_SUCCESS without the snapshot being updated, leaving stale data in shared memory.

Return SBI_ERR_FAILURE when the snapshot write fails.

Fixes c2f41ddbcdd7 ("RISC-V: KVM: Implement SBI PMU Snapshot feature")
---
 arch/riscv/kvm/vcpu_pmu.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
arch/riscv/kvm/vcpu_pmu.c +4 -3
index f3a8fd52d13a5..a32a12df726da 100644
@@ -700,9 +700,10 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 		}
 	}
 
-	if (shmem_needs_update)
-		kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
-					     sizeof(struct riscv_pmu_snapshot_data));
+	if (shmem_needs_update &&
+	    kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
+				 sizeof(struct riscv_pmu_snapshot_data)))
+		sbiret = SBI_ERR_FAILURE;
 
 out:
 	retdata->err_val = sbiret;
Signature · 1 line
2.53.0
author maintainer
#31 lore raw

PATCH 31/395 RISC-V: KVM: Fix perf-backed counter accounting across stop and read

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: SeungJu Cheon <[email protected]>

[ Upstream commit c7e2cc38c56142cdab25e6f73602a8222bf9479b ]

pmu_ctr_read() adds the event count returned by perf_event_read_value() to counter_val, which can accumulate the same count repeatedly across reads. kvm_riscv_vcpu_pmu_ctr_stop() also leaves counter_val stale by not folding the current event count into it.

Make reads of perf-backed counters side-effect free, and use perf_event_pause() when stopping a counter to fold the current event count into counter_val while resetting it. This preserves the counter value across stop/start and lets the snapshot path use counter_val directly.

Fixes 0cb74b65d2e5 ("RISC-V: KVM: Implement perf support without sampling")
---
 arch/riscv/kvm/vcpu_pmu.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
arch/riscv/kvm/vcpu_pmu.c +8 -8
index a32a12df726da..b374d92c9aa63 100644
@@ -249,12 +249,13 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
 	if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW) {
 		fevent_code = get_event_code(pmc->event_idx);
 		pmc->counter_val = kvpmu->fw_event[fevent_code].value;
+		*out_val = pmc->counter_val;
 	} else if (pmc->perf_event) {
-		pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running);
+		*out_val = pmc->counter_val +
+			   perf_event_read_value(pmc->perf_event, &enabled, &running);
 	} else {
 		return -EINVAL;
 	}
-	*out_val = pmc->counter_val;
 
 	return 0;
 }
@@ -619,7 +620,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 {
 	struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
 	int i, pmc_index, sbiret = 0;
-	u64 enabled, running;
 	struct kvm_pmc *pmc;
 	int fevent_code;
 	bool snap_flag_set = flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
@@ -656,8 +656,11 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 			}
 		} else if (pmc->perf_event) {
 			if (pmc->started) {
-				/* Stop counting the counter */
-				perf_event_disable(pmc->perf_event);
+				/*
+				 * Stop the counter and fold the live count into counter_val.
+				 * Reset the event value to avoid redundant accumulation.
+				 */
+				pmc->counter_val += perf_event_pause(pmc->perf_event, true);
 				pmc->started = false;
 			} else {
 				sbiret = SBI_ERR_ALREADY_STOPPED;
@@ -671,9 +674,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
 		}
 
 		if (snap_flag_set && !sbiret) {
-			if (pmc->perf_event)
-				pmc->counter_val += perf_event_read_value(pmc->perf_event,
-									  &enabled, &running);
 			/*
 			 * The counter and overflow indicies in the snapshot region are w.r.to
 			 * cbase. Modify the set bit in the counter mask instead of the pmc_index
Signature · 1 line
2.53.0
author maintainer
#32 lore raw

PATCH 32/395 KVM: arm64: vgic-its: Free the caches when GITS_BASER changes

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit 8cd92f77ae4f5371a7d581f8324c24919670b304 ]

A guest that disables the ITS and re-points or shrinks GITS_BASER<n> with VALID still set keeps the devices and collections it mapped against the old table, as KVM frees them only when VALID is cleared. The contents of the table are IMPLEMENTATION DEFINED, so a write that gives GITS_BASER<n> a different address or size may lose whatever the old value described. Free the list whenever the stored value changes, and drop the translation cache with it.

The cache is not empty just because the ITS is disabled: its->enabled is written under the cmd_lock, while vgic_its_resolve_lpi() tests it under the its_lock, so an injection can still cache an entry after the ITS was disabled. Hence the invalidation inside the its_lock section.

Test for a change rather than a write: its_restore_enable() rewrites GITS_BASER<n> from its probe-time cache on resume, and KVM reports GITS_TYPER.HCC as 0, so nothing re-maps the boot CPU's collection afterwards.

---
 arch/arm64/kvm/vgic/vgic-its.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
arch/arm64/kvm/vgic/vgic-its.c +8 -3
index cdaf2af5e765d..9b5f8d308fac0 100644
@@ -1648,7 +1648,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 				      unsigned long val)
 {
 	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
-	u64 entry_size, table_type;
+	u64 old, entry_size, table_type;
 	u64 reg, *regptr, clearbits = 0;
 
 	/* When GITS_CTLR.Enable is 1, we ignore write accesses. */
@@ -1671,7 +1671,9 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 		return;
 	}
 
-	reg = update_64bit_reg(*regptr, addr & 7, len, val);
+	old = *regptr;
+
+	reg = update_64bit_reg(old, addr & 7, len, val);
 	reg &= ~GITS_BASER_RO_MASK;
 	reg &= ~clearbits;
 
@@ -1681,7 +1683,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 
 	*regptr = reg;
 
-	if (!(reg & GITS_BASER_VALID)) {
+	/* The ITS driver rewrites an unchanged GITS_BASER<n> on resume. */
+	if (reg != old) {
 		/* Take the its_lock to prevent a race with a save/restore */
 		mutex_lock(&its->its_lock);
 		switch (table_type) {
@@ -1692,6 +1695,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 			vgic_its_free_collection_list(kvm, its);
 			break;
 		}
+		/* A concurrent injection may have cached a translation. */
+		vgic_its_invalidate_cache(its);
 		mutex_unlock(&its->its_lock);
 	}
 }
Signature · 1 line
2.53.0
author maintainer
#33 lore raw

PATCH 33/395 KVM: arm64: vgic-its: Skip unreachable devices instead of failing the save

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit cc5d96036e01ac330d24b2f0c336d60f82ab4930 ]

vgic_its_save_device_tables() aborts with -EINVAL when a device's entry falls outside the device table, which a guest can arrange on its own: an indirect table lets it clear an L1 entry's valid bit without touching GITS_BASER. That fails a save userspace should be able to issue reliably.

Skip the device instead, and point the saved DTE chain past it, as commit ad1e686e2378d ("KVM: arm64: vgic-its: Point saved ITEs at the next valid entry") does for ITEs. compute_next_devid_offset() takes the next device off the list whether or not it was saved, so the predecessor would otherwise point at an entry the save never wrote. Restore follows that offset while it stays inside the table being scanned: within an L2 block, or anywhere in a flat table. Both need userspace to remove a memslot under the table, since dropping an L1 entry takes the whole block with it and scan_its_table() stops at the block boundary.

---
 arch/arm64/kvm/vgic/vgic-its.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)
arch/arm64/kvm/vgic/vgic-its.c +19 -13
index 9b5f8d308fac0..763fa5dff1672 100644
@@ -2017,18 +2017,22 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
-static u32 compute_next_devid_offset(struct list_head *h,
+static u32 compute_next_devid_offset(struct vgic_its *its, u64 baser,
 				     struct its_device *dev)
 {
-	struct its_device *next;
-	u32 next_offset;
+	struct its_device *next = dev;
 
-	if (list_is_last(&dev->dev_list, h))
-		return 0;
-	next = list_next_entry(dev, dev_list);
-	next_offset = next->device_id - dev->device_id;
+	/*
+	 * Point at the next device vgic_its_save_device_tables() saves. It
+	 * sorts device_list first, so the subtraction cannot underflow.
+	 */
+	list_for_each_entry_continue(next, &its->device_list, dev_list) {
+		if (vgic_its_check_id(its, baser, next->device_id, NULL))
+			return min_t(u32, next->device_id - dev->device_id,
+				     VITS_DTE_MAX_DEVID_OFFSET);
+	}
 
-	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
+	return 0;
 }
 
 static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
@@ -2268,17 +2272,18 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
  * vgic_its_save_dte - Save a device table entry at a given GPA
  *
  * @its: ITS handle
+ * @baser: GITS_BASER<dev> the caller is saving against
  * @dev: ITS device
  * @ptr: GPA
  */
-static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
-			     gpa_t ptr)
+static int vgic_its_save_dte(struct vgic_its *its, u64 baser,
+			     struct its_device *dev, gpa_t ptr)
 {
 	u64 val, itt_addr_field;
 	u32 next_offset;
 
 	itt_addr_field = dev->itt_addr >> 8;
-	next_offset = compute_next_devid_offset(&its->device_list, dev);
+	next_offset = compute_next_devid_offset(its, baser, dev);
 	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
 	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
 	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
@@ -2377,15 +2382,16 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
 		int ret;
 		gpa_t eaddr;
 
+		/* Don't fail a save that userspace must be able to issue. */
 		if (!vgic_its_check_id(its, baser,
 				       dev->device_id, &eaddr))
-			return -EINVAL;
+			continue;
 
 		ret = vgic_its_save_itt(its, dev);
 		if (ret)
 			return ret;
 
-		ret = vgic_its_save_dte(its, dev, eaddr);
+		ret = vgic_its_save_dte(its, baser, dev, eaddr);
 		if (ret)
 			return ret;
 	}
Signature · 1 line
2.53.0
author maintainer
#34 lore raw

PATCH 34/395 KVM: arm64: Validate the SVE vector length in pkvm_vcpu_init_sve()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit 2a2eb10795a1e495aebc7f829ccecb72c05b4fd9 ]

pkvm_vcpu_init_sve() clamps only the upper bound of the host-provided sve_max_vl, so an invalid vector length reaches sve_state_size_from_vl() and the WARN_ON() there, which is fatal at EL2. The existing !sve_state_size test rejects such a length, but only after the macro has run.

Check sve_vl_valid() before deriving the state size. A valid length cannot yield a zero size, so the !sve_state_size test goes with it.

Fixes 5db1bef93342 ("KVM: arm64: Track SVE state in the hypervisor vcpu structure")
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +3 -2
index cafd09565f83b..c33bd7d376c66 100644
@@ -450,14 +450,15 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 
 	/* Limit guest vector length to the maximum supported by the host. */
 	sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
-	sve_state_size = sve_state_size_from_vl(sve_max_vl);
 	sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
 
-	if (!sve_state || !sve_state_size) {
+	if (!sve_vl_valid(sve_max_vl) || !sve_state) {
 		ret = -EINVAL;
 		goto err;
 	}
 
+	sve_state_size = sve_state_size_from_vl(sve_max_vl);
+
 	ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
 	if (ret)
 		goto err;
Signature · 1 line
2.53.0
author maintainer
#35 lore raw

PATCH 35/395 KVM: arm64: Do not clear VM-wide SVE feature on vCPU init failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit a1b3c788ad31837e348075e93dbba3f447492776 ]

pkvm_vcpu_init_sve() clears KVM_ARM_VCPU_SVE in kvm->arch.vcpu_features when it fails, but vcpu_has_sve() tests KVM_ARCH_FLAG_GUEST_HAS_SVE, which is left set. Later vCPUs on that VM then skip the SVE setup and register with a NULL sve_state, which the guest's first FP access hands to sve_load_state().

Return the error without touching vcpu_features.

Fixes 5db1bef93342 ("KVM: arm64: Track SVE state in the hypervisor vcpu structure")
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +4 -9
index c33bd7d376c66..b3ea49f121870 100644
@@ -441,7 +441,7 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	unsigned int sve_max_vl;
 	size_t sve_state_size;
 	void *sve_state;
-	int ret = 0;
+	int ret;
 
 	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
 		vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
@@ -452,24 +452,19 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
 	sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
 
-	if (!sve_vl_valid(sve_max_vl) || !sve_state) {
-		ret = -EINVAL;
-		goto err;
-	}
+	if (!sve_vl_valid(sve_max_vl) || !sve_state)
+		return -EINVAL;
 
 	sve_state_size = sve_state_size_from_vl(sve_max_vl);
 
 	ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
 	if (ret)
-		goto err;
+		return ret;
 
 	vcpu->arch.sve_state = sve_state;
 	vcpu->arch.sve_max_vl = sve_max_vl;
 
 	return 0;
-err:
-	clear_bit(KVM_ARM_VCPU_SVE, vcpu->kvm->arch.vcpu_features);
-	return ret;
 }
 
 static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
Signature · 1 line
2.53.0
author maintainer
#36 lore raw

PATCH 36/395 KVM: arm64: vgic-v3: Fix GICv3 trapping in protected mode

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

[ Upstream commit 567ebfedb5bd204a8ce6a11695f02730f1bf57f4 ]

As we are about to start trapping a bunch of extra things, augment the pKVM trap description with all the registers trapped by ICH_HCR_EL2.TC, making them legal instead of resulting in a UNDEF injection in the guest.

While we're at it, ensure that pKVM captures the vgic model so that it can be checked by the emulation code.

Stable-dep-of: 4f16c5fc8dc4 ("KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2")

---
 arch/arm64/kvm/hyp/nvhe/pkvm.c     | 3 +++
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 5 +++++
 2 files changed, 8 insertions(+)
arch/arm64/kvm/hyp/nvhe/pkvm.c +3 -0
index b3ea49f121870..26a19185e2ada 100644
@@ -338,6 +338,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	/* CTR_EL0 is always under host control, even for protected VMs. */
 	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
 
+	/* Preserve the vgic model so that GICv3 emulation works */
+	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
+
 	if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
 		set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
 
arch/arm64/kvm/hyp/nvhe/sys_regs.c +5 -0
index 82da9b03692d4..3108b5185c204 100644
@@ -444,6 +444,8 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
 
 	/* Scalable Vector Registers are restricted. */
 
+	HOST_HANDLED(SYS_ICC_PMR_EL1),
+
 	RAZ_WI(SYS_ERRIDR_EL1),
 	RAZ_WI(SYS_ERRSELR_EL1),
 	RAZ_WI(SYS_ERXFR_EL1),
@@ -457,9 +459,12 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
 
 	/* Limited Ordering Regions Registers are restricted. */
 
+	HOST_HANDLED(SYS_ICC_DIR_EL1),
+	HOST_HANDLED(SYS_ICC_RPR_EL1),
 	HOST_HANDLED(SYS_ICC_SGI1R_EL1),
 	HOST_HANDLED(SYS_ICC_ASGI1R_EL1),
 	HOST_HANDLED(SYS_ICC_SGI0R_EL1),
+	HOST_HANDLED(SYS_ICC_CTLR_EL1),
 	{ SYS_DESC(SYS_ICC_SRE_EL1), .access = pvm_gic_read_sre, },
 
 	HOST_HANDLED(SYS_CCSIDR_EL1),
Signature · 1 line
2.53.0
author maintainer
#37 lore raw

PATCH 37/395 KVM: arm64: Fix MTE flag initialization for protected VMs

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit ebbcaece84738f71b35f32339bdeb8776004e641 ]

The function pkvm_init_features_from_host() initializes guest features, propagating them from the host. The logic to propagate KVM_ARCH_FLAG_MTE_ENABLED (Memory Tagging Extension) has a couple of issues.

First, the check was in the common path, before the divergence for protected and non-protected VMs. For non-protected VMs, this was unnecessary, as 'kvm->arch.flags' is completely overwritten by host_arch_flags immediately after, which already contains the MTE flag. For protected VMs, this was setting the flag even if the feature is not allowed.

Second, the check was reading 'host_kvm->arch.flags' instead of using the local 'host_arch_flags', which is read once from the host flags.

Fix these by moving the MTE flag check inside the protected-VM-only path, checking if the feature is allowed, and changing it to use the correct host_arch_flags local variable. This ensures non-protected VMs get the flag via the bulk copy, and protected VMs get it via an explicit check.

Fixes b7f345fbc32a ("KVM: arm64: Fix FEAT_MTE in pKVM")

Stable-dep-of: 4f16c5fc8dc4 ("KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2")

---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +3 -3
index 26a19185e2ada..1b73a2411a998 100644
@@ -341,9 +341,6 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	/* Preserve the vgic model so that GICv3 emulation works */
 	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
 
-	if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
-		set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
-
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
 		hyp_vm->kvm.arch.flags = host_arch_flags;
@@ -359,6 +356,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		return;
 	}
 
+	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_MTE))
+		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_MTE_ENABLED);
+
 	bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
Signature · 1 line
2.53.0
author maintainer
#38 lore raw

PATCH 38/395 KVM: arm64: Include VM type when checking VM capabilities in pKVM

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit 43a21a0f0c4ab7de755f2cee2ff4700f26fe0bba ]

Certain features and capabilities are restricted in protected mode. Most of these features are restricted only for protected VMs, but some are restricted for ALL VMs in protected mode.

Extend the pKVM capability check to pass the VM (kvm), and use that when determining supported features.

Stable-dep-of: 4f16c5fc8dc4 ("KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2")

---
 arch/arm64/include/asm/kvm_pkvm.h | 10 ++++++----
 arch/arm64/kvm/arm.c              |  4 ++--
 arch/arm64/kvm/hyp/nvhe/pkvm.c    | 10 +++++-----
 3 files changed, 13 insertions(+), 11 deletions(-)
arch/arm64/include/asm/kvm_pkvm.h +6 -4
index 08be89c95466e..7195be508d994 100644
@@ -23,10 +23,12 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm);
 int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu);
 
 /*
- * This functions as an allow-list of protected VM capabilities.
- * Features not explicitly allowed by this function are denied.
+ * Check whether the specific capability is allowed in pKVM.
+ *
+ * Certain features are allowed only for non-protected VMs in pKVM, which is why
+ * this takes the VM (kvm) as a parameter.
  */
-static inline bool kvm_pvm_ext_allowed(long ext)
+static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
 {
 	switch (ext) {
 	case KVM_CAP_IRQCHIP:
@@ -43,7 +45,7 @@ static inline bool kvm_pvm_ext_allowed(long ext)
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		return true;
 	default:
-		return false;
+		return !kvm || !kvm_vm_is_protected(kvm);
 	}
 }
 
arch/arm64/kvm/arm.c +2 -2
index 5d2435dd76f35..52549bebb7829 100644
@@ -87,7 +87,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 	if (cap->flags)
 		return -EINVAL;
 
-	if (kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(cap->cap))
+	if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, cap->cap))
 		return -EINVAL;
 
 	switch (cap->cap) {
@@ -312,7 +312,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
 	int r;
 
-	if (kvm && kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(ext))
+	if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, ext))
 		return 0;
 
 	switch (ext) {
arch/arm64/kvm/hyp/nvhe/pkvm.c +5 -5
index 1b73a2411a998..43195083fe7d0 100644
@@ -356,23 +356,23 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		return;
 	}
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_MTE))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
 		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_MTE_ENABLED);
 
 	bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PMU_V3))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PMU_V3))
 		set_bit(KVM_ARM_VCPU_PMU_V3, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_ADDRESS))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_ADDRESS))
 		set_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_GENERIC))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
 		set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_SVE)) {
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) {
 		set_bit(KVM_ARM_VCPU_SVE, allowed_features);
 		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
 	}
Signature · 1 line
2.53.0
author maintainer
#39 lore raw

PATCH 39/395 KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

[ Upstream commit 4f16c5fc8dc4c5596e3777ab9f449a54e3f85fd5 ]

pkvm_init_features_from_host() takes KVM_ARCH_FLAG_GUEST_HAS_SVE and KVM_ARM_VCPU_SVE from the host separately, but pkvm_vcpu_init_sve() tests the bit while vcpu_has_sve() reads the flag. A host that sets the flag without the bit gets a vCPU with a NULL sve_state that the world switch loads the guest's SVE state from.

Derive the flag from the bit, and drop the protected path's copy of the host's flag, which is dead code since protected VMs are not allowed SVE.

Fixes 41d6028e28bd ("KVM: arm64: Convert the SVE guest vcpu flag to a vm flag")
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +5 -4
index 43195083fe7d0..6eade6babbbd4 100644
@@ -353,7 +353,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
 			hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
 
-		return;
+		goto out;
 	}
 
 	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
@@ -372,13 +372,14 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
 		set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
 
-	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) {
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE))
 		set_bit(KVM_ARM_VCPU_SVE, allowed_features);
-		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
-	}
 
 	bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
 		   allowed_features, KVM_VCPU_MAX_FEATURES);
+out:
+	__assign_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &kvm->arch.flags,
+		     kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SVE));
 }
 
 static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu)
Signature · 1 line
2.53.0
author maintainer
#40 lore raw

PATCH 40/395 KVM: arm64: Return -EINVAL for an empty SMCCC filter range at base 0

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Karl Mehltretter <[email protected]>

[ Upstream commit 64dc6f1db7e620f2e9337bb181f305fb0561da79 ]

kvm_smccc_set_filter() only rejects a range if its inclusive end, base + nr_functions - 1, is below base. That catches an empty range (nr_functions == 0) at every nonzero base, but at base 0 the end wraps to U32_MAX and KVM tries to insert [0, U32_MAX], which overlaps the reserved Arm Architecture Calls ranges. KVM_ARM_VM_SMCCC_FILTER then returns -EEXIST instead of the -EINVAL that the smccc_filter selftest expects for an empty range.

Reject a zero function count explicitly.

Tested with a userspace reproducer on an arm64 VHE host under QEMU TCG:
EEXIST before, EINVAL after.

Fixes 821d935c87bc ("KVM: arm64: Introduce support for userspace SMCCC filtering")
Assisted-by LLM
---
 arch/arm64/kvm/hypercalls.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/kvm/hypercalls.c +2 -1
index 58c5fe7d75727..ccbfe847f78b9 100644
@@ -185,7 +185,8 @@ static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user
 	start = filter.base;
 	end = start + filter.nr_functions - 1;
 
-	if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS)
+	if (!filter.nr_functions || end < start ||
+	    filter.action >= NR_SMCCC_FILTER_ACTIONS)
 		return -EINVAL;
 
 	mutex_lock(&kvm->arch.config_lock);
Signature · 1 line
2.53.0
author maintainer
#41 lore raw

PATCH 41/395 KVM: arm64: Fix FGT mapping for HFGITR_EL2.nGCSEPP

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mark Brown <[email protected]>

[ Upstream commit 089e4f3c4862ba3f29dff2361caa8084879194fd ]

The encoding to trap mapping currently maps a FGT on OP_GCSPOPX to HFGITR_EL2.nGCSEPP but as per DDI0601 2026-06 this FGT controls trapping of GCSPUSHX and GCSPOPCX, and not the separate GCSPOPX instruction. Update the mapping to reflect the architecture.

Fixes 863ac38984a82 ("KVM: arm64: Add missing HFGITR_EL2 FGT entries to nested virt")
---
 arch/arm64/kvm/emulate-nested.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kvm/emulate-nested.c +1 -1
index 8778188407047..fbb37edfbabae 100644
@@ -1423,7 +1423,7 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
 	SR_FGT(OP_AT_S1E1A, 		HFGITR, ATS1E1A, 1),
 	SR_FGT(OP_COSP_RCTX, 		HFGITR, COSPRCTX, 1),
 	SR_FGT(OP_GCSPUSHX, 		HFGITR, nGCSEPP, 0),
-	SR_FGT(OP_GCSPOPX, 		HFGITR, nGCSEPP, 0),
+	SR_FGT(OP_GCSPOPCX, 		HFGITR, nGCSEPP, 0),
 	SR_FGT(OP_GCSPUSHM, 		HFGITR, nGCSPUSHM_EL1, 0),
 	SR_FGT(OP_BRB_IALL, 		HFGITR, nBRBIALL, 0),
 	SR_FGT(OP_BRB_INJ, 		HFGITR, nBRBINJ, 0),
Signature · 1 line
2.53.0
author maintainer
#42 lore raw

PATCH 42/395 squashfs: Add dictionary size range check to prevent shift-out-of-bounds

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ran Hongyun <[email protected]>

[ Upstream commit 1f7745fb3580152ca902ef181b605f33cabfb1d0 ]

When an abnormal SquashFS image (COMP_OPTS flag is 1 but dictionary size is 0) is mounted, and performs shift operations using dictionarysize, the shift exponent is -1, causing a shift-out-of-bounds.

Detail as below:
squashfs_comp_opts(msblk, buffer, length)
squashfs_xz_comp_opts()

    if (comp_opts)
      n = ffs(opts->dict_size) - 1;<----opts->dict_size=0, n=-1
      if (opts->dict_size != (1 << n) && opts->dict_size !=
	  	(1 << n) + (1 << (n + 1))) <----shift-out-of-bounds

Fix it by adding a dictionary size range check before the shift operation.

---
 fs/squashfs/xz_wrapper.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
fs/squashfs/xz_wrapper.c +3 -3
index 6c49481a2f8c4..7d54cd524d6d9 100644
@@ -57,10 +57,10 @@ static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk,
 
 		opts->dict_size = le32_to_cpu(comp_opts->dictionary_size);
 
-		/* the dictionary size should be 2^n or 2^n+2^(n+1) */
+		/* the dictionary size should be positive and 2^n or 2^n+2^(n+1) */
 		n = ffs(opts->dict_size) - 1;
-		if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) +
-						(1 << (n + 1))) {
+		if (opts->dict_size <= 0 || (opts->dict_size != (1 << n) &&
+			opts->dict_size != (1 << n) + (1 << (n + 1)))) {
 			err = -EIO;
 			goto out;
 		}
Signature · 1 line
2.53.0
author maintainer
#43 lore raw

PATCH 43/395 scsi: sd_zbc: Reject disks with too many zones

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: ZHOU Jiaxiang <[email protected]>

[ Upstream commit b6ec0f79745967c751c85df373062c8d15e45fc4 ]

sd_zbc_read_zones() computes the number of zones with 64-bit arithmetic and stores the result in the unsigned int nr_zones field of struct zoned_disk_info, silently truncating counts that exceed 32 bits. The truncated count is later used to size per-zone resources, while the device may still report more zones than fit.

Moreover, sd_zbc_report_zones() counts the reported zones with a signed int zone_idx, which overflows past INT_MAX. Reject devices reporting more than INT_MAX zones at scan time; such a device is not realistic for any medium that exists today, and accepting it produces inconsistent zone bookkeeping.

---
 drivers/scsi/sd_zbc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/scsi/sd_zbc.c +7 -1
index a8db66428f80d..6f566d4f7706b 100644
@@ -595,7 +595,7 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
 int sd_zbc_read_zones(struct scsi_disk *sdkp, struct queue_limits *lim,
 		u8 buf[SD_BUF_SIZE])
 {
-	unsigned int nr_zones;
+	u64 nr_zones;
 	u32 zone_blocks = 0;
 	int ret;
 
@@ -627,6 +627,12 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, struct queue_limits *lim,
 		goto err;
 
 	nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
+	if (nr_zones > INT_MAX) {
+		sd_printk(KERN_ERR, sdkp, "Too many zones (%llu)\n",
+			  nr_zones);
+		ret = -EINVAL;
+		goto err;
+	}
 	sdkp->early_zone_info.nr_zones = nr_zones;
 	sdkp->early_zone_info.zone_blocks = zone_blocks;
 
Signature · 1 line
2.53.0
author maintainer
#44 lore raw

PATCH 44/395 pinctrl: sunxi: A523: fix voltage withstand encoding

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Andre Przywara <[email protected]>

[ Upstream commit ef56085dfd1df3a53ecce8a4ff440cf6d67f430d ]

The Allwinner A523 uses the same GPIO voltage "withstand" programming (setting the input level voltage thresholds) as the previous SoCs, but for some odd reason inverts the encoding of 1.8V vs. 3.3V.

Add a new bias voltage type to note this difference, and select it for the A523. At the same time also use the newer "CTL" version, which in addition allows to turn off the withstand programming for I/O voltages other than exact 1.8V or 3.3V (for instance for 2.5V sometimes used for Ethernet PHYs). The A523 has that enable register, but didn't use it so far.

This fixes eMMC and reportedly Ethernet operation on some A523 boards.

---
 drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c | 2 +-
 drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c   | 2 +-
 drivers/pinctrl/sunxi/pinctrl-sunxi.c         | 6 ++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.h         | 2 ++
 4 files changed, 10 insertions(+), 2 deletions(-)
drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c +1 -1
index 462aa1c4a5fa6..e27e4945def26 100644
@@ -26,7 +26,7 @@ static const u8 a523_r_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
 static struct sunxi_pinctrl_desc a523_r_pinctrl_data = {
 	.irq_banks = ARRAY_SIZE(a523_r_irq_bank_map),
 	.irq_bank_map = a523_r_irq_bank_map,
-	.io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+	.io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL_INV,
 	.pin_base = PL_BASE,
 };
 
drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c +1 -1
index b6f78f1f30ac4..88d8acd5bc245 100644
@@ -26,7 +26,7 @@ static const u8 a523_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
 static struct sunxi_pinctrl_desc a523_pinctrl_data = {
 	.irq_banks = ARRAY_SIZE(a523_irq_bank_map),
 	.irq_bank_map = a523_irq_bank_map,
-	.io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+	.io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL_INV,
 };
 
 static int a523_pinctrl_probe(struct platform_device *pdev)
drivers/pinctrl/sunxi/pinctrl-sunxi.c +6 -0
index 93e396041456a..6099ae93e1536 100644
@@ -699,6 +699,7 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
 {
 	unsigned short bank;
 	unsigned long flags;
+	bool inverted = false;
 	u32 val, reg;
 	int uV;
 
@@ -737,6 +738,9 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
 		reg &= ~IO_BIAS_MASK;
 		writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
 		return 0;
+	case BIAS_VOLTAGE_PIO_POW_MODE_CTL_INV:
+		inverted = true;
+		fallthrough;
 	case BIAS_VOLTAGE_PIO_POW_MODE_CTL:
 		val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0;
 
@@ -751,6 +755,8 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
 		fallthrough;
 	case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
 		val = uV <= 1800000 ? 1 : 0;
+		if (inverted)
+			val = !val;
 
 		raw_spin_lock_irqsave(&pctl->lock, flags);
 		reg = readl(pctl->membase + pctl->pow_mod_sel_offset);
drivers/pinctrl/sunxi/pinctrl-sunxi.h +2 -0
index ad26e4de16a85..418c0508eb18a 100644
@@ -114,8 +114,10 @@ enum sunxi_desc_bias_voltage {
 	 * Bias voltage is set through PIO_POW_MOD_SEL_REG
 	 * and PIO_POW_MOD_CTL_REG register, as seen on
 	 * A100 and D1 SoC, for example.
+	 * Some SoCs invert the encoding for 1.8V vs. 3.3V.
 	 */
 	BIAS_VOLTAGE_PIO_POW_MODE_CTL,
+	BIAS_VOLTAGE_PIO_POW_MODE_CTL_INV,
 };
 
 struct sunxi_desc_function {
Signature · 1 line
2.53.0
author maintainer
#45 lore raw

PATCH 45/395 Bluetooth: SMP: reject Security Request over BR/EDR

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christiano Amora <[email protected]>

[ Upstream commit f033482d76a9f18080c7a40c5f9c678bd7adc8f3 ]

Bose QC Ultra Headphones (dual-mode, same public address on both transports) occasionally send an SMP Security Request on the BR/EDR SMP fixed channel right after the ACL link is encrypted. The kernel handles it as if it were an LE link: smp_cmd_security_req() has no transport check, smp_ltk_encrypt() looks up an LTK with the ACL connection's dst_type, and hci_find_ltk() matches the peer's LE LTK because the LE public address type is stored as ADDR_LE_DEV_PUBLIC (0), the same value as BDADDR_BREDR. HCI_OP_LE_START_ENC is then issued on the ACL handle, the controller rejects it with Invalid HCI Command Parameters, and hci_cs_le_start_enc() disconnects the link with HCI_ERROR_AUTH_FAILURE. The headphones drop within a second of connecting, before any profile is up; a manual reconnect works.

btmon (MediaTek MT7922, kernel 7.0.12):

Quoted 1 line

HCI Event: Encryption Change (0x08) plen 4

        Status: Success (0x00)
        Handle: 50 Address: BC:87:FA:47:73:5E (Bose Corporation)
        Encryption: Enabled with AES-CCM (0x02)
Quoted 1 line

ACL Data RX: Handle 50 flags 0x02 dlen 6

        BR/EDR SMP: Security Request (0x0b) len 1
        Authentication requirement: No bonding, No MITM, SC (0x08)
  < HCI Command: LE Start Encryption (0x08|0x0019) plen 28
        Handle: 50 Address: BC:87:FA:47:73:5E (Bose Corporation)
Quoted 1 line

HCI Event: Command Status (0x0f) plen 4

        LE Start Encryption (0x08|0x0019) ncmd 1
        Status: Invalid HCI Command Parameters (0x12)
  < HCI Command: Disconnect (0x01|0x0006) plen 3
        Handle: 50 Address: BC:87:FA:47:73:5E (Bose Corporation)
        Reason: Authentication Failure (0x05)

SMP over BR/EDR is limited to cross-transport key derivation; the Security Request procedure (Core Specification Vol 3, Part H, Section 2.4.6, PDU in Section 3.6.7) has no BR/EDR counterpart. Reply with Pairing Failed / Command Not Supported on a non-LE link, before the PDU is parsed, and keep the connection. The reply is sent directly rather than through smp_failure(): rejecting a command on the wrong transport is not an authentication failure, and MGMT_EV_AUTH_FAILED would make bluetoothd disconnect the device.

Tested on the affected host (kernel 7.0.12, MediaTek MT7922, Bose QC Ultra) with the patched module built out of tree: 7 days and 49 reconnects without a drop, against 2 drops in the 3 days before the patch. Every disconnect in that week had a userspace or remote reason.

Fixes b5ae344d4c0f ("Bluetooth: Add full SMP BR/EDR support")
Assisted-by LLM
---
 net/bluetooth/smp.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
net/bluetooth/smp.c +17 -0
index 1172df9b7004d..51e0545a9e240 100644
@@ -2301,6 +2301,23 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	bt_dev_dbg(hdev, "conn %p", conn);
 
+	/* SMP over BR/EDR only covers cross-transport key derivation; the
+	 * Security Request procedure has no BR/EDR counterpart. Reject it
+	 * here, otherwise smp_ltk_encrypt() finds the peer's LE LTK
+	 * (ADDR_LE_DEV_PUBLIC and BDADDR_BREDR are both 0) and issues
+	 * HCI_OP_LE_START_ENC on the ACL handle, which the controller
+	 * rejects and hci_cs_le_start_enc() turns into a disconnect. Reply
+	 * without smp_failure(): this is not an authentication failure, and
+	 * MGMT_EV_AUTH_FAILED would make bluetoothd drop the device.
+	 */
+	if (hcon->type != LE_LINK) {
+		u8 reason = SMP_CMD_NOTSUPP;
+
+		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
+			     &reason);
+		return 0;
+	}
+
 	if (skb->len < sizeof(*rp))
 		return SMP_INVALID_PARAMS;
 
Signature · 1 line
2.53.0
author maintainer
#46 lore raw

PATCH 46/395 Bluetooth: btnxpuart: Fix skb leak in nxp_process_fw_dump()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zijun Hu <[email protected]>

[ Upstream commit f2bbb36426581045a8bf7793da5419b9375e4348 ]

When CONFIG_DEV_COREDUMP=n, hci_devcd_append() returns -EOPNOTSUPP without freeing its skb argument. This leaks the cloned skb and also prevents nxp_set_ind_reset() from being called to perform recovery.

Fix by guarding the hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC)) call with IS_ENABLED(CONFIG_DEV_COREDUMP).

Fixes 998e447f443f ("Bluetooth: btnxpuart: Add support for HCI coredump feature")
---
 drivers/bluetooth/btnxpuart.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/bluetooth/btnxpuart.c +5 -3
index 509d837e353e6..c7acf6c7efcf6 100644
@@ -1397,9 +1397,11 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb)
 				      msecs_to_jiffies(20000));
 	}
 
-	err = hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
-	if (err < 0)
-		goto free_skb;
+	if (IS_ENABLED(CONFIG_DEV_COREDUMP)) {
+		err = hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
+		if (err < 0)
+			goto free_skb;
+	}
 
 	if (buf_len == 0) {
 		bt_dev_warn(hdev, "==== FW dump complete ===");
Signature · 1 line
2.53.0
author maintainer
#47 lore raw

PATCH 47/395 Bluetooth: mgmt: Dequeue pending mesh_send_sync entries on cancel

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lee Jones <[email protected]>

[ Upstream commit 71af682ba4692c2ed9ace4c3d4ca462ae368c029 ]

In send_cancel(), pending mesh_tx objects are removed from the hdev->mesh_pending list and freed via mesh_send_complete(). However, if a mesh transmission was already queued onto hdev->cmd_sync_work_list via mesh_next(), the queued entry retains a raw pointer to mesh_tx.

When hci_cmd_sync_work later processes the entry, it attempts to execute mesh_send_sync and its destroy callback mesh_send_start_complete using the already freed mesh_tx pointer, leading to a use-after-free.

Fix this by invoking hci_cmd_sync_dequeue() for mesh_send_sync on the target mesh_tx before completing it. If the entry is found and dequeued, its destroy callback will complete and free the object; otherwise, mesh_send_complete() is called directly.

Additionally, ensure the transmission queue advances after cancellation or errors. In mesh_send_start_complete(), call mesh_next() on error unless err is -ECANCELED, because hci_cmd_sync_dequeue() holds hdev->cmd_sync_work_lock and calling mesh_next() synchronously would deadlock. Instead, advance the queue in send_cancel() once the lock is released and if no transmission is in progress.

Fixes b338d91703fa ("Bluetooth: Implement support for Mesh")
---
 net/bluetooth/mgmt.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
net/bluetooth/mgmt.c +15 -4
index 01f46a985e2b3..3ab39becb07cb 100644
@@ -2313,6 +2313,8 @@ static void mesh_send_start_complete(struct hci_dev *hdev, void *data, int err)
 		hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
 		/* Send Complete Error Code for handle */
 		mesh_send_complete(hdev, mesh_tx, false);
+		if (err != -ECANCELED)
+			mesh_next(hdev, NULL, 0);
 		return;
 	}
 
@@ -2422,19 +2424,28 @@ static int send_cancel(struct hci_dev *hdev, void *data)
 		do {
 			mesh_tx = mgmt_mesh_next(hdev, cmd->sk);
 
-			if (mesh_tx)
-				mesh_send_complete(hdev, mesh_tx, false);
+			if (mesh_tx) {
+				if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync,
+							  mesh_tx, NULL))
+					mesh_send_complete(hdev, mesh_tx, false);
+			}
 		} while (mesh_tx);
 	} else {
 		mesh_tx = mgmt_mesh_find(hdev, cancel->handle);
 
-		if (mesh_tx && mesh_tx->sk == cmd->sk)
-			mesh_send_complete(hdev, mesh_tx, false);
+		if (mesh_tx && mesh_tx->sk == cmd->sk) {
+			if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync,
+						  mesh_tx, NULL))
+				mesh_send_complete(hdev, mesh_tx, false);
+		}
 	}
 
 	mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
 			  0, NULL, 0);
 
+	if (!hci_dev_test_flag(hdev, HCI_MESH_SENDING))
+		mesh_next(hdev, NULL, 0);
+
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#48 lore raw

PATCH 48/395 selftests: cgroup: give the O_TMPFILE open in get_temp_fd() a mode

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eva Kurchatova <[email protected]>

[ Upstream commit c774ec8f0a5d02a06d34c27f5a7de7e333b91265 ]

O_TMPFILE, like O_CREAT, needs the third argument. Without it glibc refuses the call at compile time as soon as fortification is on:

In function 'open',
inlined from 'get_temp_fd' at test_memcontrol.c:33:9:
/usr/include/bits/fcntl2.h:52:11: error: call to '__open_missing_mode'
declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments

The fortify checks take effect only once the compiler optimises, and cgroup/Makefile builds with "-Wall -pthread" alone, so this goes unnoticed in a plain build. Building the tests with the flags distributions commonly use, -O2 -D_FORTIFY_SOURCE=3, loses test_memcontrol entirely.

Fixes 84092dbcf901 ("selftests: cgroup: add memory controller self-tests")
---
 tools/testing/selftests/cgroup/test_memcontrol.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/cgroup/test_memcontrol.c +1 -1
index 1f64db1afa212..e383fad6e5bb3 100644
@@ -26,7 +26,7 @@ static bool has_recursiveprot;
 
 int get_temp_fd(void)
 {
-	return open(".", O_TMPFILE | O_RDWR | O_EXCL);
+	return open(".", O_TMPFILE | O_RDWR | O_EXCL, 0600);
 }
 
 int alloc_pagecache(int fd, size_t size)
Signature · 1 line
2.53.0
author maintainer
#49 lore raw

PATCH 49/395 scsi: megaraid_sas: Protect megasas_get_ctrl_info() in megasas_resume()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bart Van Assche <[email protected]>

[ Upstream commit 42d1221d321e55afc7bba9109a77aaf5a817c8a3 ]

Protect the megasas_get_ctrl_info() call in megasas_resume() with instance->reset_mutex using scoped_guard().

megasas_get_ctrl_info() may release and reacquire instance->reset_mutex. Hence, calling this function without holding instance->reset_mutex is not safe.

Fixes c3b10a55abc9 ("scsi: megaraid_sas: Update controller info during resume")
Cc Kashyap Desai <[email protected]>
Cc Sumit Saxena <[email protected]>
Cc Shivasharan S <[email protected]>
Cc Chandrakanth patil <[email protected]>
---
 drivers/scsi/megaraid/megaraid_sas_base.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/scsi/megaraid/megaraid_sas_base.c +3 -1
index d578b476d9797..116b5ecf15d6f 100644
@@ -7887,7 +7887,9 @@ megasas_resume(struct device *dev)
 			goto fail_init_mfi;
 	}
 
-	if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS)
+	scoped_guard(mutex, &instance->reset_mutex)
+		rval = megasas_get_ctrl_info(instance);
+	if (rval != DCMD_SUCCESS)
 		goto fail_init_mfi;
 
 	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
Signature · 1 line
2.53.0
author maintainer
#50 lore raw

PATCH 50/395 docs: s390/pci: Improve and update PCI documentation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Niklas Schnelle <[email protected]>

[ Upstream commit 737c4f4a241ca85c597ca2ef1a6f8446bf681ab5 ]

Update the s390 specific PCI documentation to better reflect current behavior and terms such as the handling of Isolated VFs via commit 25f39d3dcb48 ("s390/pci: Ignore RID for isolated VFs").

Add a descriptions for /sys/firmware/clp/uid_checking which was added in commit b043a81ce3ee ("s390/pci: Expose firmware provided UID Checking state in sysfs") but missed documentation.

Similarly add documentation for the fidparm attribute added by commit 99ad39306a62 ("s390/pci: Expose FIDPARM attribute in sysfs") and add a list of pft values and their names.

Finally improve formatting of the different attribute descriptions by adding a separating colon.

Stable-dep-of: 4525a9110495 ("s390/pci/docs: Fix sriov_numvfs attribute name")

---
 Documentation/arch/s390/pci.rst | 152 +++++++++++++++++++++-----------
 1 file changed, 101 insertions(+), 51 deletions(-)
Documentation/arch/s390/pci.rst +101 -51
index d5755484d8e75..c3476de4f0327 100644
@@ -6,6 +6,7 @@ S/390 PCI
 
 Authors:
         - Pierre Morel
+        - Niklas Schnelle
 
 Copyright, IBM Corp. 2020
 
@@ -27,14 +28,16 @@ Command line parameters
 debugfs entries
 ---------------
 
-The S/390 debug feature (s390dbf) generates views to hold various debug results in sysfs directories of the form:
+The S/390 debug feature (s390dbf) generates views to hold various debug results
+in sysfs directories of the form:
 
  * /sys/kernel/debug/s390dbf/pci_*/
 
 For example:
 
   - /sys/kernel/debug/s390dbf/pci_msg/sprintf
-    Holds messages from the processing of PCI events, like machine check handling
+
+    holds messages from the processing of PCI events, like machine check handling
     and setting of global functionality, like UID checking.
 
   Change the level of logging to be more or less verbose by piping
@@ -47,87 +50,134 @@ Sysfs entries
 
 Entries specific to zPCI functions and entries that hold zPCI information.
 
-* /sys/bus/pci/slots/XXXXXXXX
+* /sys/bus/pci/slots/XXXXXXXX:
 
-  The slot entries are set up using the function identifier (FID) of the
-  PCI function. The format depicted as XXXXXXXX above is 8 hexadecimal digits
-  with 0 padding and lower case hexadecimal digits.
+  The slot entries are set up using the function identifier (FID) of the PCI
+  function as slot name. The format depicted as XXXXXXXX above is 8 hexadecimal
+  digits with 0 padding and lower case hexadecimal digits.
 
   - /sys/bus/pci/slots/XXXXXXXX/power
 
   A physical function that currently supports a virtual function cannot be
   powered off until all virtual functions are removed with:
-  echo 0 > /sys/bus/pci/devices/XXXX:XX:XX.X/sriov_numvf
+  echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
 
-* /sys/bus/pci/devices/XXXX:XX:XX.X/
+* /sys/bus/pci/devices/DDDD:BB:dd.f/:
 
-  - function_id
-    A zPCI function identifier that uniquely identifies the function in the Z server.
+  - function_id:
+    The zPCI function identifier (FID) is a 32-bit hexadecimal value that
+    uniquely identifies the PCI function. Unless the hypervisor provides
+    a virtual FID e.g. on KVM this identifier is unique across the machine even
+    between different partitions.
 
-  - function_handle
-    Low-level identifier used for a configured PCI function.
-    It might be useful for debugging.
+  - function_handle:
+    This 32-bit hexadecimal value is a low-level identifier used for a PCI
+    function. Note that the function handle may be changed and become invalid
+    on PCI events and when enabling/disabling the PCI function.
 
-  - pchid
-    Model-dependent location of the I/O adapter.
+  - pchid:
+    This 16-bit hexadecimal value encodes a model-dependent location for
+    the PCI function.
 
-  - pfgid
-    PCI function group ID, functions that share identical functionality
+  - pfgid:
+    PCI function group ID; functions that share identical functionality
     use a common identifier.
     A PCI group defines interrupts, IOMMU, IOTLB, and DMA specifics.
 
-  - vfn
+  - vfn:
     The virtual function number, from 1 to N for virtual functions,
     0 for physical functions.
 
-  - pft
-    The PCI function type
-
-  - port
-    The port corresponds to the physical port the function is attached to.
-    It also gives an indication of the physical function a virtual function
-    is attached to.
-
-  - uid
-    The user identifier (UID) may be defined as part of the machine
-    configuration or the z/VM or KVM guest configuration. If the accompanying
-    uid_is_unique attribute is 1 the platform guarantees that the UID is unique
-    within that instance and no devices with the same UID can be attached
-    during the lifetime of the system.
-
-  - uid_is_unique
-    Indicates whether the user identifier (UID) is guaranteed to be and remain
-    unique within this Linux instance.
-
-  - pfip/segmentX
+  - pft:
+    The PCI function type is an s390-specific type attribute. It indicates
+    a more general, usage oriented, type than PCI Specification
+    class/vendor/device identifiers. That is PCI functions with the same pft
+    value may be backed by different hardware implementations. At the same time
+    apart from unclassified functions (pft is 0x00) the same pft value
+    generally implies a similar usage model. At the same time the same
+    PCI hardware device may appear with different pft values when in a
+    different usage model. For example NETD and NETH VFs may be implemented
+    by the same PCI hardware device but in NETD the parent Physical Function
+    is user managed while with NETH it is platform managed.
+
+    Currently the following PFT values are defined:
+
+    - 0x00 (UNC): Unclassified
+    - 0x02 (ROCE): RoCE Express
+    - 0x05 (ISM): Internal Shared Memory
+    - 0x0a (ROC2): RoCE Express 2
+    - 0x0b (NVMe): NVMe
+    - 0x0c (NETH): Network Express hybrid
+    - 0x0d (CNW): Cloud Network Adapter
+    - 0x0f (NETD): Network Express direct
+
+  - port:
+    The port is a decimal value corresponding to the physical port the function
+    is attached to. Virtual Functions (VFs) share the port with their parent
+    Physical Function (PF). A value of 0 indicates that the port attribute is
+    not applicable for that PCI function type.
+
+  - uid:
+    The user-defined identifier (UID) for a PCI function is a 32-bit
+    hexadecimal value. It is defined on a per instance basis as part of the
+    partition, KVM guest, or z/VM guest configuration. If UID Checking is
+    enabled the platform ensures that the UID is unique within that instance
+    and no two PCI functions with the same UID will be visible to the instance.
+
+    Independent of this guarantee and unlike the function ID (FID) the UID may
+    be the same in different partitions within the same machine. This allows to
+    create PCI configurations in multiple partitions to be identical in the
+    UID-namespace.
+
+  - uid_is_unique:
+    A 0 or 1 flag indicating whether the user-defined identifier (UID) is
+    guaranteed to be and remain unique within this Linux instance. This
+    platform feature is called UID Checking.
+
+  - pfip/segmentX:
     The segments determine the isolation of a function.
     They correspond to the physical path to the function.
     The more the segments are different, the more the functions are isolated.
 
+  - fidparm:
+    Contains an 8-bit-per-PCI function parameter field in hexadecimal provided
+    by the platform. The meaning of this field is PCI function type specific.
+    For NETH VFs a value of 0x01 indicates that the function supports
+    promiscuous mode.
+
+* /sys/firmware/clp/uid_checking:
+
+  In addition to the per-device uid_is_unique attribute this presents a
+  global indication of whether UID Checking is enabled. This allows users
+  to check for UID Checking even when no PCI functions are configured.
+
 Enumeration and hotplug
 =======================
 
 The PCI address consists of four parts: domain, bus, device and function,
-and is of this form: DDDD:BB:dd.f
+and is of this form: DDDD:BB:dd.f.
 
-* When not using multi-functions (norid is set, or the firmware does not
-  support multi-functions):
+* For a PCI function for which the platform does not expose the RID, the
+  pci=norid kernel parameter is used, or a so-called isolated Virtual Function
+  which does have RID information but is used without its parent Physical
+  Function being part of the same PCI configuration:
 
   - There is only one function per domain.
 
-  - The domain is set from the zPCI function's UID as defined during the
-    LPAR creation.
+  - The domain is set from the zPCI function's UID if UID Checking is on;
+    otherwise the domain ID is generated dynamically and is not stable
+    across reboots or hot plug.
 
-* When using multi-functions (norid parameter is not set),
-  zPCI functions are addressed differently:
+* For a PCI function for which the platform exposes the RID and which
+  is not an Isolated Virtual Function:
 
   - There is still only one bus per domain.
 
-  - There can be up to 256 functions per bus.
+  - There can be up to 256 PCI functions per bus.
 
-  - The domain part of the address of all functions for
-    a multi-Function device is set from the zPCI function's UID as defined
-    in the LPAR creation for the function zero.
+  - The domain part of the address of all functions within the same topology is
+    that of the configured PCI function with the lowest devfn within that
+    topology.
 
-  - New functions will only be ready for use after the function zero
-    (the function with devfn 0) has been enumerated.
+  - Virtual Functions generated by an SR-IOV capable Physical Function only
+    become visible once SR-IOV is enabled.
Signature · 1 line
2.53.0
author maintainer
#51 lore raw

PATCH 51/395 s390/pci/docs: Fix sriov_numvfs attribute name

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Karl Mehltretter <[email protected]>

[ Upstream commit 4525a911049543c23885a540a788d13be318a486 ]

The attribute is sriov_numvfs (drivers/pci/iov.c); the document names it sriov_numvf, which does not exist.

Use sriov_numvfs.

Fixes de267a7c71ba ("s390/pci: Documentation for zPCI")
Assisted-by LLM
---
 Documentation/arch/s390/pci.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/arch/s390/pci.rst +1 -1
index c3476de4f0327..8dc09634163ba 100644
@@ -60,7 +60,7 @@ Entries specific to zPCI functions and entries that hold zPCI information.
 
   A physical function that currently supports a virtual function cannot be
   powered off until all virtual functions are removed with:
-  echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
+  echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvfs
 
 * /sys/bus/pci/devices/DDDD:BB:dd.f/:
 
Signature · 1 line
2.53.0
author maintainer
#52 lore raw

PATCH 52/395 s390/cio: Fix cio_update_schib() to not cache invalid schib

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vineeth Vijayan <[email protected]>

[ Upstream commit 29d9e5835d89223aa913dcf7b942cc1c148bdd25 ]

When pmcw.dnv is 0, the contents of all SCHIB fields are unpredictable. Zero sch->schib in that case to prevent subsequent code from making decisions based on unpredictable data.

Fixes 8c58a229688c ("s390/cio: Do not unregister the subchannel based on DNV")
---
 drivers/s390/cio/cio.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/s390/cio/cio.c +7 -4
index 21508e4606d59..20ebe0d883c64 100644
@@ -454,7 +454,8 @@ EXPORT_SYMBOL_GPL(cio_commit_config);
 /**
  * cio_update_schib - Perform stsch and update schib if subchannel is valid.
  * @sch: subchannel on which to perform stsch
- * Return zero on success, -ENODEV otherwise.
+ * Return zero on success, -ENODEV if the subchannel is not operational,
+ * -EACCES if the subchannel has no valid device.
  */
 int cio_update_schib(struct subchannel *sch)
 {
@@ -463,10 +464,12 @@ int cio_update_schib(struct subchannel *sch)
 	if (stsch(sch->schid, &schib))
 		return -ENODEV;
 
-	memcpy(&sch->schib, &schib, sizeof(schib));
-
-	if (!css_sch_is_valid(&schib))
+	if (!css_sch_is_valid(&schib)) {
+		memset(&sch->schib, 0, sizeof(sch->schib));
 		return -EACCES;
+	}
+
+	memcpy(&sch->schib, &schib, sizeof(schib));
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#53 lore raw

PATCH 53/395 s390/cio: Check pmcw.dnv before pmcw.ena in I/O entry points

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vineeth Vijayan <[email protected]>

[ Upstream commit f6f2985eabdb2bfdc82ce90a1ea3ec53ba795f34 ]

The device number valid (dnv) bit in the PMCW must be checked before acting on any other PMCW fields for IO-type subchannels. A subchannel with dnv=0 has no valid device number associated, making it meaningless to evaluate the enabled (ena) state or issue any I/O instruction against it.

Fixes 8c58a229688c ("s390/cio: Do not unregister the subchannel based on DNV")
---
 drivers/s390/cio/device_ops.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/s390/cio/device_ops.c +12 -0
index 61c07b4a0fe89..c1ba4a19368f2 100644
@@ -142,6 +142,8 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
@@ -198,6 +200,8 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
 	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
@@ -379,6 +383,8 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
@@ -413,6 +419,8 @@ int ccw_device_resume(struct ccw_device *cdev)
 	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
@@ -548,6 +556,8 @@ int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
 	int rc;
 
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_VERIFY) {
@@ -694,6 +704,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
 {
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 	if (cdev->private->state != DEV_STATE_ONLINE)
Signature · 1 line
2.53.0
author maintainer
#54 lore raw

PATCH 54/395 s390/cio: Guard PMCW field accesses with dnv check

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vineeth Vijayan <[email protected]>

[ Upstream commit 9590f4d83880dfb5a81906e48e72779248fbe8f0 ]

When PMCW.DNV is 0, no I/O device is associated with the subchannel. However, several code paths access PMCW fields directly from the cached sch->schib without first invoking the update helper. Add explicit DNV validation before accessing PMCW fields from the cached SCHIB to avoid using invalid data.

Fixes 8c58a229688c ("s390/cio: Do not unregister the subchannel based on DNV")
---
 drivers/s390/cio/chp.c          | 3 +++
 drivers/s390/cio/device.c       | 9 +++++----
 drivers/s390/cio/device_fsm.c   | 3 +++
 drivers/s390/cio/device_ops.c   | 9 +++++++++
 drivers/s390/cio/vfio_ccw_fsm.c | 2 +-
 5 files changed, 21 insertions(+), 5 deletions(-)
drivers/s390/cio/chp.c +3 -0
index caa300160b175..1c7b9a39b6f80 100644
@@ -78,6 +78,9 @@ u8 chp_get_sch_opm(struct subchannel *sch)
 	int opm;
 	int i;
 
+	if (!sch->schib.pmcw.dnv)
+		return 0;
+
 	opm = 0;
 	chp_id_init(&chpid);
 	for (i = 0; i < 8; i++) {
drivers/s390/cio/device.c +5 -4
index 7f8f78b1f8aea..dc6084f1d0f9b 100644
@@ -923,7 +923,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
 
 	if (!sch_is_pseudo_sch(old_sch)) {
 		spin_lock_irq(&old_sch->lock);
-		old_enabled = old_sch->schib.pmcw.ena;
+		old_enabled = old_sch->schib.pmcw.dnv && old_sch->schib.pmcw.ena;
 		rc = 0;
 		if (old_enabled)
 			rc = cio_disable_subchannel(old_sch);
@@ -942,7 +942,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
 		CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
 			      cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schib.pmcw.dev, rc);
+			      sch->schid.sch_no, rc);
 		if (old_enabled) {
 			/* Try to re-enable the old subchannel. */
 			spin_lock_irq(&old_sch->lock);
@@ -1208,7 +1208,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
 	cdev = sch_get_cdev(sch);
 	if (cio_is_console(sch->schid))
 		goto out_unlock;
-	if (!sch->schib.pmcw.ena)
+	if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
 		goto out_unlock;
 	ret = cio_disable_subchannel(sch);
 	if (ret != -EBUSY)
@@ -1255,7 +1255,8 @@ static int recovery_check(struct device *dev, void *data)
 	switch (cdev->private->state) {
 	case DEV_STATE_ONLINE:
 		sch = to_subchannel(cdev->dev.parent);
-		if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm)
+		if (sch->schib.pmcw.dnv &&
+		    (sch->schib.pmcw.pam & sch->opm) == sch->vpm)
 			break;
 		fallthrough;
 	case DEV_STATE_DISCONNECTED:
drivers/s390/cio/device_fsm.c +3 -0
index ab419d40a8a7a..b5686c25c83c7 100644
@@ -170,6 +170,9 @@ __recover_lost_chpids(struct subchannel *sch, int old_lpm)
 	int mask, i;
 	struct chp_id chpid;
 
+	if (!sch->schib.pmcw.dnv)
+		return;
+
 	chp_id_init(&chpid);
 	for (i = 0; i<8; i++) {
 		mask = 0x80 >> i;
drivers/s390/cio/device_ops.c +9 -0
index c1ba4a19368f2..f2f7f8cba410b 100644
@@ -490,6 +490,8 @@ struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev,
 	struct chp_id chpid;
 
 	sch = to_subchannel(cdev->dev.parent);
+	if (!sch->schib.pmcw.dnv)
+		return NULL;
 	chp_id_init(&chpid);
 	chpid.id = sch->schib.pmcw.chpid[chp_idx];
 	return chp_get_chp_desc(chpid);
@@ -510,6 +512,8 @@ u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx)
 	struct chp_id chpid;
 	u8 *util_str;
 
+	if (!sch->schib.pmcw.dnv)
+		return NULL;
 	chp_id_init(&chpid);
 	chpid.id = sch->schib.pmcw.chpid[chp_idx];
 	chp = chpid_to_chp(chpid);
@@ -662,6 +666,9 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
 	struct chp_id chpid;
 	int mdc = 0, i;
 
+	if (!sch->schib.pmcw.dnv)
+		return 0;
+
 	/* Adjust requested path mask to excluded varied off paths. */
 	if (mask)
 		mask &= sch->lpm;
@@ -798,6 +805,8 @@ int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid)
 
 	if ((chp_idx < 0) || (chp_idx > 7))
 		return -EINVAL;
+	if (!sch->schib.pmcw.dnv)
+		return -ENODEV;
 	mask = 0x80 >> chp_idx;
 	if (!(sch->schib.pmcw.pim & mask))
 		return -ENODEV;
drivers/s390/cio/vfio_ccw_fsm.c +1 -1
index 5fd94e9d5c618..9a000b0231d60 100644
@@ -399,7 +399,7 @@ static void fsm_close(struct vfio_ccw_private *private,
 
 	spin_lock_irq(&sch->lock);
 
-	if (!sch->schib.pmcw.ena)
+	if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
 		goto err_unlock;
 
 	ret = cio_disable_subchannel(sch);
Signature · 1 line
2.53.0
author maintainer
#55 lore raw

PATCH 55/395 fs: avoid repeated scans in evict_inodes()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Sun <[email protected]>

[ Upstream commit 7459c021874246c196f397686e100702f059b9e7 ]

We observed hung tasks when users attempted to unmount a filesystem after its disk had been removed while still in use. During device removal, fs_bdev_mark_dead() calls evict_inodes() while holding s_umount.

Each time evict_inodes() drops s_inode_list_lock to reschedule, it restarts the walk from the head of s_inodes. With many referenced inodes at the head of the list, these restarts repeatedly scan the same inodes without reclaiming them. This can keep s_umount held for a long time, blocking concurrent umount attempts and triggering hung-task reports.

Keep the current inode, already marked I_FREEING, out of the disposal batch until s_inode_list_lock is reacquired. Resume the walk from this inode and dispose of it in a later batch or at the end of the walk.

The zero-refcount and state checks under i_lock allow this walker to claim the inode by setting I_FREEING and removing it from the LRU. Other reclaimers skip the inode, leaving this walker responsible for eviction. Only evict() removes it from s_inodes, so keeping it out of the disposal batch ensures that it remains on the list while the lock is dropped. After reacquiring the lock, reading its current next pointer accounts for concurrent removal of following inodes.

The existing inode lifetime rules prohibit acquiring a reference to an inode marked I_FREEING or I_WILL_FREE. __iget() requires its caller to hold i_lock and establish that taking a reference is valid. Inode lookup and igrab() check these flags under i_lock when acquiring a reference from zero. ihold() requires an existing reference, which would keep i_count nonzero and prevent this walker from claiming the inode. These rules already allow iput_final() and the inode shrinker to release i_lock after setting I_FREEING and before eviction completes.

A temporary __iget() reference would also keep the inode on the list, but its release must preserve last-reference handling. Another user can acquire a reference, update lazy timestamps and drop its reference while the pin is held. If the pin becomes the last reference, dropping it with atomic_dec_and_test() and evicting directly bypasses iput()'s lazytime handling and can lose those timestamp updates.

Releasing the pin with iput() preserves that handling, but does not guarantee eviction. fs_bdev_mark_dead() runs with SB_ACTIVE set, so iput() may retain the inode in cache, whereas evict_inodes() must evict eligible zero-reference inodes. The inode may also have been freed when iput() returns, so the walker cannot then use it to force eviction. Using I_FREEING preserves the existing eviction behavior without introducing an additional last-reference transition.

The xfstests auto group passed on ext4 and XFS with known unrelated failures excluded. No new issues were observed, and the previously reproducible hung task no longer occurs with this patch.

---
 fs/inode.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
fs/inode.c +5 -6
index a931126398ced..44891fb7cd436 100644
@@ -868,7 +868,6 @@ void evict_inodes(struct super_block *sb)
 	struct inode *inode;
 	LIST_HEAD(dispose);
 
-again:
 	spin_lock(&sb->s_inode_list_lock);
 	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
 		if (icount_read(inode))
@@ -887,19 +886,19 @@ void evict_inodes(struct super_block *sb)
 		inode->i_state |= I_FREEING;
 		inode_lru_list_del(inode);
 		spin_unlock(&inode->i_lock);
-		list_add(&inode->i_lru, &dispose);
 
 		/*
-		 * We can have a ton of inodes to evict at unmount time given
-		 * enough memory, check to see if we need to go to sleep for a
-		 * bit so we don't livelock.
+		 * Keep this inode out of dispose so it stays on s_inodes while
+		 * the list lock is dropped. I_FREEING prevents new references
+		 * and leaves eviction to us, so we can resume the walk from it.
 		 */
 		if (need_resched()) {
 			spin_unlock(&sb->s_inode_list_lock);
 			cond_resched();
 			dispose_list(&dispose);
-			goto again;
+			spin_lock(&sb->s_inode_list_lock);
 		}
+		list_add(&inode->i_lru, &dispose);
 	}
 	spin_unlock(&sb->s_inode_list_lock);
 
Signature · 1 line
2.53.0
author maintainer
#56 lore raw

PATCH 56/395 xsk: Use a 32-bit compare in xsk_map_gen_lookup

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhiling Zou <[email protected]>

[ Upstream commit 70504de0bb627848667207bec7ccfd647deb8814 ]

xsk_map_gen_lookup() loads a u32 key and compares it with max_entries using BPF_JMP_IMM. BPF immediates are sign-extended to 64 bits, so a max_entries value of 0x80000000 or higher becomes a threshold larger than every zero-extended 32-bit key. An out-of-range index then skips the bounds check and the generated lookup reads past xsk_map[].

Compare with BPF_JMP32_IMM so the check stays in 32-bit unsigned range.

---
 net/xdp/xskmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/xdp/xskmap.c +1 -1
index afa457506274c..607f8b7e16d96 100644
@@ -124,7 +124,7 @@ static int xsk_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
 	struct bpf_insn *insn = insn_buf;
 
 	*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0);
-	*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5);
+	*insn++ = BPF_JMP32_IMM(BPF_JGE, ret, map->max_entries, 5);
 	*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(sizeof(struct xsk_sock *)));
 	*insn++ = BPF_ALU64_IMM(BPF_ADD, mp, offsetof(struct xsk_map, xsk_map));
 	*insn++ = BPF_ALU64_REG(BPF_ADD, ret, mp);
Signature · 1 line
2.53.0
author maintainer
#57 lore raw

PATCH 57/395 bpf: Skip unsettled links in link iterator

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Weiming Shi <[email protected]>

[ Upstream commit 50e80e2bb5e2be8515205b9c496b9640ddefa434 ]

bpf_link_prime() inserts a link into link_idr before anon_inode_getfile() succeeds and before bpf_link_settle() publishes the ID in link->id. bpf_link_by_id() treats such an ID-zero link as unsettled, but the link iterator takes a reference without this check.

If anon_inode_getfile() then fails, the creator removes the ID and frees its still-private link directly. The iterator is left with a dangling reference and its next bpf_link_put() accesses freed memory.

Treat ID-zero entries as transient in bpf_link_get_curr_or_next(), just as bpf_link_by_id() does.

  BUG: KASAN: slab-use-after-free in bpf_link_put
  Write of size 8 by task exp/384
  Call Trace:
  bpf_link_put                    kernel/bpf/syscall.c:3372
  bpf_link_seq_next               kernel/bpf/link_iter.c:33
  bpf_seq_read                    kernel/bpf/bpf_iter.c:158
  vfs_read                        fs/read_write.c:572
  ksys_read                       fs/read_write.c:716
  do_syscall_64                   arch/x86/entry/syscall_64.c:84
  entry_SYSCALL_64_after_hwframe  arch/x86/entry/entry_64.S:121
  Kernel panic - not syncing: KASAN: panic_on_warn set ...
---
 kernel/bpf/syscall.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
kernel/bpf/syscall.c +4 -1
index bab472152d64d..dec993c90dc33 100644
@@ -5941,7 +5941,10 @@ struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
 again:
 	link = idr_get_next(&link_idr, id);
 	if (link) {
-		link = bpf_link_inc_not_zero(link);
+		if (link->id)
+			link = bpf_link_inc_not_zero(link);
+		else
+			link = ERR_PTR(-EAGAIN);
 		if (IS_ERR(link)) {
 			(*id)++;
 			goto again;
Signature · 1 line
2.53.0
author maintainer
#58 lore raw

PATCH 58/395 eth: fbnic: Fix payload page pool error cleanup

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Björn Töpel <[email protected]>

[ Upstream commit 8e0b235bd918d06f54ba8fddd2c3ddc36ca59c15 ]

The payload page pool pointer contains an error pointer when its allocation fails. The cleanup path passes that error pointer to page_pool_destroy() instead of destroying the header page pool. This can dereference the error pointer and leave the header page pool allocated.

Destroy the header page pool instead.

---
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +1 -1
index 0ea861ff40f56..7fc7761e8f2e0 100644
@@ -1620,7 +1620,7 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
 	return 0;
 
 err_destroy_sub0:
-	page_pool_destroy(pp);
+	page_pool_destroy(qt->sub0.page_pool);
 	return PTR_ERR(pp);
 }
 
Signature · 1 line
2.53.0
author maintainer
#59 lore raw

PATCH 59/395 net/sched: cls_u32: fix manual hash table handle IDR aliasing

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit 0a5f5d9e94dead312d32c366b917c64e552b72f7 ]

A u32 hash table created with an explicit handle ('tc filter add ... handle 801: u32 divisor N') keys its IDR entry on the raw handle, while the destroy paths free it under handle2id(handle). The two key domains disagree for handles in the 0x800..0xFFF htid range:
handle2id() folds them back into the auto-allocated id space (1..0x7FF).

A manual table therefore leaves its raw-keyed IDR entry unreachable on delete (a permanent leak), and its delete can drop the idr entry of an unrelated live auto table. A later auto allocation can then hand out a handle that aliases the live manual table; u32_lookup_ht() first-match routes lookups and TCA_U32_LINK for that htid to the wrong table.

Key the divisor-path alloc on handle2id(handle) so allocation and removal share one key domain. A manual handle that maps onto an id already in use is rejected with -ENOSPC, and auto allocation skips ids held by live manual tables.

Conditions to recreate:
ip link add test0 type dummy
tc qdisc add dev test0 clsact
tc filter add dev test0 ingress protocol ip pref 1 \

          handle 801: u32 divisor 16
  tc filter add dev test0 ingress protocol ip pref 2 u32 divisor 16
  tc -d filter show dev test0 ingress | grep 'fh 801:'
  # unpatched: two live tables with handle 0x80100000 (the pref 2 root
  # hnode is auto-allocated id 1); patched: the auto hnode takes id 2.

Also tested with a poc with a live u32 table on the block, add/delete a manual table 'handle 901: u32 divisor 1' twice; unpatched, the re-add fails with -ENOSPC because the raw key leaked on the first delete.

---
 net/sched/cls_u32.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
net/sched/cls_u32.c +10 -2
index 83a60698cc009..e5e5533f866dc 100644
@@ -1000,8 +1000,16 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
 				return -ENOMEM;
 			}
 		} else {
-			err = idr_alloc_u32(&tp_c->handle_idr, ht, &handle,
-					    handle, GFP_KERNEL);
+			/* The IDR is keyed on the mapped id, and that is
+			 * what the destroy paths remove. Ask for it here,
+			 * so a manual handle colliding with the
+			 * auto-allocated id space is rejected (-ENOSPC)
+			 * instead of aliasing a future auto id.
+			 */
+			u32 id = handle2id(handle);
+
+			err = idr_alloc_u32(&tp_c->handle_idr, ht, &id, id,
+					    GFP_KERNEL);
 			if (err) {
 				kfree(ht);
 				return err;
Signature · 1 line
2.53.0
author maintainer
#60 lore raw

PATCH 60/395 net: pcs: rzn1-miic: Fix config array initialization

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kyle Hendry <[email protected]>

[ Upstream commit daf677c2c6449011ee695d55b48b5b2977a36f88 ]

Fix memset parameters to initialize the entire DT value array

---
 drivers/net/pcs/pcs-rzn1-miic.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/pcs/pcs-rzn1-miic.c +2 -1
index 885f17c32643b..cea350745a7b6 100644
@@ -594,7 +594,8 @@ static int miic_parse_dt(struct miic *miic, u32 *mode_cfg)
 	if (!dt_val)
 		return -ENOMEM;
 
-	memset(dt_val, MIIC_MODCTRL_CONF_NONE, sizeof(*dt_val));
+	memset(dt_val, MIIC_MODCTRL_CONF_NONE,
+	       sizeof(*dt_val) * miic->of_data->conf_conv_count);
 
 	if (of_property_read_u32(np, "renesas,miic-switch-portin", &conf) == 0)
 		dt_val[0] = conf;
Signature · 1 line
2.53.0
author maintainer
#61 lore raw

PATCH 61/395 octeontx2-af: use seq_file for rsrc_alloc debugfs

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Heyang Tan <[email protected]>

[ Upstream commit 39c6580765dad6477fb2637f6f616e0d276aae65 ]

The rsrc_alloc debugfs reader writes rows directly to userspace without respecting the caller's read count. It also uses the current row length as the userspace stride, which can corrupt output when rows have different widths.

Use seq_file to handle userspace buffer sizes, offsets, and partial reads, and write output columns directly to the seq_file buffer.

Fixes 23205e6d06d4 ("octeontx2-af: Dump current resource provisioning status")
---
 .../marvell/octeontx2/af/rvu_debugfs.c        | 104 ++++++------------
 1 file changed, 33 insertions(+), 71 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +33 -71
index 0a1c778d14b69..f7033765ed3fb 100644
@@ -710,110 +710,72 @@ static int get_max_column_width(struct rvu *rvu)
 }
 
 /* Dumps current provisioning status of all RVU block LFs */
-static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp,
-					  char __user *buffer,
-					  size_t count, loff_t *ppos)
+static int rvu_dbg_rsrc_attach_status(struct seq_file *filp, void *unused)
 {
-	int index, off = 0, flag = 0, len = 0, i = 0;
-	struct rvu *rvu = filp->private_data;
-	int bytes_not_copied = 0;
+	struct rvu *rvu = filp->private;
+	int index, pf, vf, pcifunc;
 	struct rvu_block block;
-	int pf, vf, pcifunc;
-	int buf_size = 2048;
 	int lf_str_size;
 	char *lfs;
-	char *buf;
-
-	/* don't allow partial reads */
-	if (*ppos != 0)
-		return 0;
-
-	buf = kzalloc(buf_size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
 
-	/* Get the maximum width of a column */
 	lf_str_size = get_max_column_width(rvu);
+	if (lf_str_size < 0)
+		return lf_str_size;
 
 	lfs = kzalloc(lf_str_size, GFP_KERNEL);
-	if (!lfs) {
-		kfree(buf);
+	if (!lfs)
 		return -ENOMEM;
-	}
-	off +=	scnprintf(&buf[off], buf_size - 1 - off, "%-*s", lf_str_size,
-			  "pcifunc");
-	for (index = 0; index < BLK_COUNT; index++)
-		if (strlen(rvu->hw->block[index].name)) {
-			off += scnprintf(&buf[off], buf_size - 1 - off,
-					 "%-*s", lf_str_size,
-					 rvu->hw->block[index].name);
-		}
 
-	off += scnprintf(&buf[off], buf_size - 1 - off, "\n");
-	bytes_not_copied = copy_to_user(buffer + (i * off), buf, off);
-	if (bytes_not_copied)
-		goto out;
+	seq_printf(filp, "%-*s", lf_str_size, "pcifunc");
+	for (index = 0; index < BLK_COUNT; index++)
+		if (strlen(rvu->hw->block[index].name))
+			seq_printf(filp, "%-*s", lf_str_size,
+				   rvu->hw->block[index].name);
 
-	i++;
-	*ppos += off;
+	seq_putc(filp, '\n');
 	for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
 		for (vf = 0; vf <= rvu->hw->total_vfs; vf++) {
-			off = 0;
-			flag = 0;
 			pcifunc = rvu_make_pcifunc(rvu->pdev, pf, vf);
 			if (!pcifunc)
 				continue;
 
-			if (vf) {
+			for (index = 0; index < BLK_COUNT; index++) {
+				block = rvu->hw->block[index];
+				if (!strlen(block.name))
+					continue;
+				lfs[0] = '\0';
+				get_lf_str_list(&block, pcifunc, lfs);
+				if (strlen(lfs))
+					break;
+			}
+			if (index == BLK_COUNT)
+				continue;
+
+			if (vf)
 				sprintf(lfs, "PF%d:VF%d", pf, vf - 1);
-				off = scnprintf(&buf[off],
-						buf_size - 1 - off,
-						"%-*s", lf_str_size, lfs);
-			} else {
+			else
 				sprintf(lfs, "PF%d", pf);
-				off = scnprintf(&buf[off],
-						buf_size - 1 - off,
-						"%-*s", lf_str_size, lfs);
-			}
+			seq_printf(filp, "%-*s", lf_str_size, lfs);
 
 			for (index = 0; index < BLK_COUNT; index++) {
 				block = rvu->hw->block[index];
 				if (!strlen(block.name))
 					continue;
-				len = 0;
-				lfs[len] = '\0';
-				get_lf_str_list(&block, pcifunc, lfs);
-				if (strlen(lfs))
-					flag = 1;
 
-				off += scnprintf(&buf[off], buf_size - 1 - off,
-						 "%-*s", lf_str_size, lfs);
-			}
-			if (flag) {
-				off +=	scnprintf(&buf[off],
-						  buf_size - 1 - off, "\n");
-				bytes_not_copied = copy_to_user(buffer +
-								(i * off),
-								buf, off);
-				if (bytes_not_copied)
-					goto out;
-
-				i++;
-				*ppos += off;
+				lfs[0] = '\0';
+				get_lf_str_list(&block, pcifunc, lfs);
+				seq_printf(filp, "%-*s", lf_str_size, lfs);
 			}
+			seq_putc(filp, '\n');
 		}
 	}
 
-out:
 	kfree(lfs);
-	kfree(buf);
-	if (bytes_not_copied)
-		return -EFAULT;
 
-	return *ppos;
+	return 0;
 }
 
-RVU_DEBUG_FOPS(rsrc_status, rsrc_attach_status, NULL);
+RVU_DEBUG_SEQ_FOPS(rsrc_status, rsrc_attach_status, NULL);
 
 static int rvu_dbg_rvu_pf_cgx_map_display(struct seq_file *filp, void *unused)
 {
Signature · 1 line
2.53.0
author maintainer
#62 lore raw

PATCH 62/395 net/mlx5: devcom, Base component size on linked devices

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shay Drory <[email protected]>

[ Upstream commit d09e8f64653c93da5793c16be19330968f2a32e6 ]

mlx5_devcom_comp_get_size() returns the component's kref count. That kref is bumped in mlx5_devcom_register_component() under comp_list_lock, before the comp_dev is linked onto comp_dev_list_head under comp->sem. The event broadcast (mlx5_devcom_locked_send_event()) walks that list.

Hence, a caller can read the expected size, but send_event won't be sent to all peers. In the SD group registration path, this lets a member broadcast its role-election event over an incomplete list, electing a primary that never completes the group, is never marked ready, and leaves the group with a stale primary.

Track the number of linked comp_devs in a dedicated counter, maintained under comp->sem together with the list add/remove, and return it from mlx5_devcom_comp_get_size().

---
 drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +4 -1
index e749618229bc0..8946ba5e30bf1 100644
@@ -36,6 +36,7 @@ struct mlx5_devcom_comp {
 	struct mlx5_devcom_key key;
 	mlx5_devcom_event_handler_t handler;
 	struct kref ref;
+	int nr_devs;
 	bool ready;
 	struct rw_semaphore sem;
 	struct lock_class_key lock_key;
@@ -169,6 +170,7 @@ devcom_alloc_comp_dev(struct mlx5_devcom_dev *devc,
 
 	down_write(&comp->sem);
 	list_add_tail(&devcom->list, &comp->comp_dev_list_head);
+	WRITE_ONCE(comp->nr_devs, comp->nr_devs + 1);
 	up_write(&comp->sem);
 
 	return devcom;
@@ -181,6 +183,7 @@ devcom_free_comp_dev(struct mlx5_devcom_comp_dev *devcom)
 
 	down_write(&comp->sem);
 	list_del(&devcom->list);
+	WRITE_ONCE(comp->nr_devs, comp->nr_devs - 1);
 	up_write(&comp->sem);
 
 	kref_put(&devcom->devc->ref, mlx5_devcom_dev_release);
@@ -283,7 +286,7 @@ int mlx5_devcom_comp_get_size(struct mlx5_devcom_comp_dev *devcom)
 {
 	struct mlx5_devcom_comp *comp = devcom->comp;
 
-	return kref_read(&comp->ref);
+	return READ_ONCE(comp->nr_devs);
 }
 
 int mlx5_devcom_send_event(struct mlx5_devcom_comp_dev *devcom,
Signature · 1 line
2.53.0
author maintainer
#63 lore raw

PATCH 63/395 bpf: Restrict CO-RE poisoning to relocatable instructions

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit 394ae398337c5f87e567f6cd63b937fc2b2f6ddc ]

CO-RE relocation records can name any instruction offset. When a relocation cannot be resolved, bpf_core_patch_insn() currently poisons its target before checking whether that instruction is a valid relocation target. Malformed metadata can therefore replace jumps, calls, exits, register-source arithmetic, or non-immediate loads instead of failing at the relocation step.

Handle poisoning only after the instruction has passed the same class and operand-form checks used for a resolved relocation. Route invalid forms through the existing diagnostic and return a hard error. Keep poisoning supported instructions, including both halves of a plain ldimm64, so an unresolved relocation in dead code remains valid.

Extend bpf_core_poison_insn() to poison both halves of ldimm64, and return its status directly from each validated instruction case. This avoids routing the success path through a common label and leaves the helper free to report errors.

The shared relocation code applies this restriction to both libbpf and in-kernel CO-RE.

---
 tools/lib/bpf/relo_core.c | 58 +++++++++++++++++++++------------------
 1 file changed, 31 insertions(+), 27 deletions(-)
tools/lib/bpf/relo_core.c +31 -27
index 0ccc8f548cbaa..a6a88e1cad270 100644
@@ -980,23 +980,30 @@ static int bpf_core_calc_relo(const char *prog_name,
 }
 
 /*
- * Turn instruction for which CO_RE relocation failed into invalid one with
+ * Turn instruction for which CO-RE relocation failed into invalid one with
  * distinct signature.
  */
-static void bpf_core_poison_insn(const char *prog_name, int relo_idx,
-				 int insn_idx, struct bpf_insn *insn)
+static int bpf_core_poison_insn(const char *prog_name, int relo_idx,
+				struct bpf_insn *insn, int insn_idx)
 {
-	pr_debug("prog '%s': relo #%d: substituting insn #%d w/ invalid insn\n",
-		 prog_name, relo_idx, insn_idx);
-	insn->code = BPF_JMP | BPF_CALL;
-	insn->dst_reg = 0;
-	insn->src_reg = 0;
-	insn->off = 0;
-	/* if this instruction is reachable (not a dead code),
-	 * verifier will complain with the following message:
-	 * invalid func unknown#195896080
-	 */
-	insn->imm = 195896080; /* => 0xbad2310 => "bad relo" */
+	int insn_cnt = is_ldimm64_insn(insn) ? 2 : 1;
+	int i;
+
+	for (i = 0; i < insn_cnt; i++) {
+		pr_debug("prog '%s': relo #%d: substituting insn #%d w/ invalid insn\n",
+			 prog_name, relo_idx, insn_idx + i);
+		insn[i].code = BPF_JMP | BPF_CALL;
+		insn[i].dst_reg = 0;
+		insn[i].src_reg = 0;
+		insn[i].off = 0;
+		/*
+		 * If this instruction is reachable (not dead code), the verifier
+		 * will complain with "invalid func unknown#195896080".
+		 */
+		insn[i].imm = 195896080; /* => 0xbad2310 => "bad relo" */
+	}
+
+	return 0;
 }
 
 static int insn_bpf_size_to_bytes(struct bpf_insn *insn)
@@ -1047,17 +1054,6 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 
 	class = BPF_CLASS(insn->code);
 
-	if (res->poison) {
-poison:
-		/* poison second part of ldimm64 to avoid confusing error from
-		 * verifier about "unknown opcode 00"
-		 */
-		if (is_ldimm64_insn(insn))
-			bpf_core_poison_insn(prog_name, relo_idx, insn_idx + 1, insn + 1);
-		bpf_core_poison_insn(prog_name, relo_idx, insn_idx, insn);
-		return 0;
-	}
-
 	orig_val = res->orig_val;
 	new_val = res->new_val;
 
@@ -1065,7 +1061,9 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 	case BPF_ALU:
 	case BPF_ALU64:
 		if (BPF_SRC(insn->code) != BPF_K)
-			return -EINVAL;
+			goto bad_insn;
+		if (res->poison)
+			return bpf_core_poison_insn(prog_name, relo_idx, insn, insn_idx);
 		if (res->validate && insn->imm != orig_val) {
 			pr_warn("prog '%s': relo #%d: unexpected insn #%d (ALU/ALU64) value: got %u, exp %llu -> %llu\n",
 				prog_name, relo_idx,
@@ -1082,6 +1080,8 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 	case BPF_LDX:
 	case BPF_ST:
 	case BPF_STX:
+		if (res->poison)
+			return bpf_core_poison_insn(prog_name, relo_idx, insn, insn_idx);
 		if (res->validate && insn->off != orig_val) {
 			pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDX/ST/STX) value: got %u, exp %llu -> %llu\n",
 				prog_name, relo_idx, insn_idx, insn->off, (unsigned long long)orig_val,
@@ -1097,7 +1097,7 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 			pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) accesses field incorrectly. "
 				"Make sure you are accessing pointers, unsigned integers, or fields of matching type and size.\n",
 				prog_name, relo_idx, insn_idx);
-			goto poison;
+			return bpf_core_poison_insn(prog_name, relo_idx, insn, insn_idx);
 		}
 
 		orig_val = insn->off;
@@ -1140,6 +1140,9 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 			return -EINVAL;
 		}
 
+		if (res->poison)
+			return bpf_core_poison_insn(prog_name, relo_idx, insn, insn_idx);
+
 		imm = (__u32)insn[0].imm | ((__u64)insn[1].imm << 32);
 		if (res->validate && imm != orig_val) {
 			pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDIMM64) value: got %llu, exp %llu -> %llu\n",
@@ -1157,6 +1160,7 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
 		break;
 	}
 	default:
+bad_insn:
 		pr_warn("prog '%s': relo #%d: trying to relocate unrecognized insn #%d, code:0x%x, src:0x%x, dst:0x%x, off:0x%x, imm:0x%x\n",
 			prog_name, relo_idx, insn_idx, insn->code,
 			insn->src_reg, insn->dst_reg, insn->off, insn->imm);
Signature · 1 line
2.53.0
author maintainer
#64 lore raw

PATCH 64/395 libbpf: Reject truncated ldimm64 CO-RE relocations

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit b4e875d397da451fb4e9c573ff4b86db53caba05 ]

CO-RE relocation of an ldimm64 instruction operates on two instruction slots. A malformed BPF ELF can end a function after the first slot and attach a CO-RE relocation to it. libbpf allocates the instruction array according to the function symbol size, so the shared relocation code would then access beyond the allocation.

Reject a terminal ldimm64 in libbpf's relocation loop, where the program length is available, before resolving or applying the relocation. Both resolved and unresolved relocations validate the absent second slot, and unresolved relocation poisoning would additionally write past the array.

The in-kernel caller is protected by the verifier's early instruction-stream check before it applies CO-RE relocations.

---
 tools/lib/bpf/libbpf.c | 7 +++++++
 1 file changed, 7 insertions(+)
tools/lib/bpf/libbpf.c +7 -0
index 94ee5f52b8661..b21d2f842579f 100644
@@ -6051,6 +6051,13 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path)
 				return -EINVAL;
 			insn = &prog->insns[insn_idx];
 
+			if (is_ldimm64_insn(insn) && (size_t)insn_idx + 1 >= prog->insns_cnt) {
+				pr_warn("prog '%s': relo #%d: insn #%d (LDIMM64) is truncated\n",
+					prog->name, i, insn_idx);
+				err = -EINVAL;
+				goto out;
+			}
+
 			err = record_relo_core(prog, rec, insn_idx);
 			if (err) {
 				pr_warn("prog '%s': relo #%d: failed to record relocation: %s\n",
Signature · 1 line
2.53.0
author maintainer
#65 lore raw

PATCH 65/395 ipv4: fib: fix data-race and stale genid check around nh->nh_saddr

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Linkui Xiao <[email protected]>

[ Upstream commit 46bc52d13594848023e681860df8700c8db14354 ]

fib_select_multipath() compares nexthop_nh->nh_saddr against the flow source address with no lock held, while fib_info_update_nhc_saddr() stores a new value from another CPU as soon as the preferred source address of the egress device changes.

Commit 195374d89368 ("ipv4: fib: annotate races around nh->nh_saddr_genid and nh->nh_saddr") added WRITE_ONCE() on the store side and READ_ONCE() in fib_result_prefsrc() after syzbot reported

	BUG: KCSAN: data-race in fib_select_path / fib_select_path

but it only covered that reader. fib_select_multipath(), reached from fib_select_path(), is a second lockless reader of nh->nh_saddr and was left bare.

Moreover, nh_saddr is only meaningful when nh_saddr_genid matches dev_addr_genid, as established by commit 436c3b66ec98 ("ipv4: Invalidate nexthop cache nh_saddr more correctly."). fib_select_multipath() skips that validation, so it can score a nexthop using a stale source address and skew the ECMP selection.

Annotate both reads with READ_ONCE() and refresh the cached source address via fib_info_update_nhc_saddr() when the genid does not match, mirroring fib_result_prefsrc().

Fixes 32607a332cfe ("ipv4: prefer multipath nexthop that matches source address")
---
 net/ipv4/fib_semantics.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
net/ipv4/fib_semantics.c +12 -1
index 2aba8c0b9b2b5..5ab23a1fa45f6 100644
@@ -2181,6 +2181,15 @@ static bool fib_good_nh(const struct fib_nh *nh)
 	return !!(state & NUD_VALID);
 }
 
+static __be32 fib_nh_saddr(struct net *net, const struct fib_info *fi,
+			   struct fib_nh *nh, int genid)
+{
+	if (READ_ONCE(nh->nh_saddr_genid) == genid)
+		return READ_ONCE(nh->nh_saddr);
+
+	return fib_info_update_nhc_saddr(net, &nh->nh_common, fi->fib_scope);
+}
+
 void fib_select_multipath(struct fib_result *res, int hash,
 			  const struct flowi4 *fl4)
 {
@@ -2189,6 +2198,7 @@ void fib_select_multipath(struct fib_result *res, int hash,
 	bool use_neigh;
 	int score = -1;
 	__be32 saddr;
+	int genid;
 
 	if (unlikely(res->fi->nh)) {
 		nexthop_path_fib_result(res, hash);
@@ -2197,6 +2207,7 @@ void fib_select_multipath(struct fib_result *res, int hash,
 
 	use_neigh = READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh);
 	saddr = fl4 ? fl4->saddr : 0;
+	genid = saddr ? atomic_read(&net->ipv4.dev_addr_genid) : 0;
 
 	change_nexthops(fi) {
 		int nh_upper_bound, nh_score = 0;
@@ -2209,7 +2220,7 @@ void fib_select_multipath(struct fib_result *res, int hash,
 		    (use_neigh && !fib_good_nh(nexthop_nh)))
 			continue;
 
-		if (saddr && nexthop_nh->nh_saddr == saddr)
+		if (saddr && fib_nh_saddr(net, fi, nexthop_nh, genid) == saddr)
 			nh_score += 2;
 		if (hash <= nh_upper_bound)
 			nh_score++;
Signature · 1 line
2.53.0
author maintainer
#66 lore raw

PATCH 66/395 netfilter: flowtable: publish HW_DEAD after worker is done

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jérémy Jean <[email protected]>

[ Upstream commit d644b23afe1ef509c9961a6d84a093c2587edf02 ]

flow_offload_work_del() sets NF_FLOW_HW_DEAD before the work handler clears NF_FLOW_HW_PENDING. Once a flow is both HW_DYING and HW_DEAD, a concurrent garbage collection pass can remove it and schedule it for RCU freeing.

The offload worker holds neither an RCU read lock nor a reference to the flow. If it is preempted after publishing HW_DEAD, the RCU callback can free the flow before the worker resumes and clears HW_PENDING, resulting in a use-after-free.

Move HW_DEAD publication to the common worker epilogue after the pending bit is cleared, making it the final flow access by destroy work. Order all preceding flow accesses before publishing the bit that allows garbage collection to free the object.

Fixes 2c8897953f3b ("netfilter: flowtable: Add pending bit for offload work")
Assisted-by Codex:gpt-5
---
 net/netfilter/nf_flow_table_offload.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
net/netfilter/nf_flow_table_offload.c +6 -1
index 4f346f51d7d74..8e3edc7c37b38 100644
@@ -993,7 +993,6 @@ static void flow_offload_work_del(struct flow_offload_work *offload)
 	flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_ORIGINAL);
 	if (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags))
 		flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_REPLY);
-	set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);
 }
 
 static void flow_offload_tuple_stats(struct flow_offload_work *offload,
@@ -1057,6 +1056,12 @@ static void flow_offload_work_handler(struct work_struct *work)
 	}
 
 	clear_bit(NF_FLOW_HW_PENDING, &offload->flow->flags);
+	if (offload->cmd == FLOW_CLS_DESTROY) {
+		/* Publish after the worker's last flow access. */
+		smp_mb__before_atomic();
+		set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);
+	}
+
 	kfree(offload);
 }
 
Signature · 1 line
2.53.0
author maintainer
#67 lore raw

PATCH 67/395 netfilter: nfnetlink_queue: hold nfnl mutex in event notifier

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Westphal <[email protected]>

[ Upstream commit 9461613afc59acef44a0071b0dd5075f6e993ffe ]

We must serialize the release notifier and the config netlink function. A concurrent thread can issue close() which can call the release function while unrelated socket processes UNBIND request for same portid:

Oops: general protection fault, [..]
RIP: 0010:__instance_destroy+0x60/0x210 [nfnetlink_queue]
Call Trace:
 nfqnl_recv_config+0x9b0/0xdc0 [nfnetlink_queue]
 nfnetlink_rcv_msg+0x7c2/0xeb0
 ? __pfx_nfnetlink_rcv_msg+0x10/0x10

After this, parallel UNBIND and URELEASE events are impossible.

This change isn't nice, but its the shortest fix given instances are not refcounted and the nfnetlink config callback drops the rcu read lock early due to need for sleeping allocations.

Fixes 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink")
---
 net/netfilter/nfnetlink_queue.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
net/netfilter/nfnetlink_queue.c +5 -3
index a65d9a5cb0f06..82187ddd26c18 100644
@@ -1340,6 +1340,7 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
 	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
 		int i;
 
+		nfnl_lock(NFNL_SUBSYS_QUEUE);
 		/* destroy all instances for this portid */
 		spin_lock(&q->instances_lock);
 		for (i = 0; i < INSTANCE_BUCKETS; i++) {
@@ -1353,6 +1354,7 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
 			}
 		}
 		spin_unlock(&q->instances_lock);
+		nfnl_unlock(NFNL_SUBSYS_QUEUE);
 	}
 	return NOTIFY_DONE;
 }
@@ -1674,9 +1676,9 @@ static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
 
 	/* Lookup queue under RCU. After peer_portid check (or for new queue
 	 * in BIND case), the queue is owned by the socket sending this message.
-	 * A socket cannot simultaneously send a message and close, so while
-	 * processing this CONFIG message, nfqnl_rcv_nl_event() (triggered by
-	 * socket close) cannot destroy this queue. Safe to use without RCU.
+	 * nfqnl_rcv_nl_event() will block on the nfnl subsys mutex that is
+	 * held by the caller, so the queue cannot be destroyed in parallel,
+	 * even after we drop the RCU read lock.
 	 */
 	rcu_read_lock();
 	queue = instance_lookup(q, queue_num);
Signature · 1 line
2.53.0
author maintainer
#68 lore raw

PATCH 68/395 netfilter: nft_synproxy: use the family-aware checksum helper

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Karl Mehltretter <[email protected]>

[ Upstream commit a311a898172743558b82f6035ef2aa8c310a4223 ]

nft_synproxy_do_eval() verifies the TCP checksum before it switches on skb->protocol. It uses nf_ip_checksum(), which constructs an IPv4 pseudo header and relies on the IPv4 header checksum when folding the whole skb. Neither operation is valid for an IPv6 packet.

A correctly checksummed IPv6 segment can therefore fail verification when it reaches the hook as CHECKSUM_NONE or, at NF_INET_LOCAL_IN, CHECKSUM_COMPLETE. nft_synproxy_do_eval() returns NF_DROP before nft_synproxy_eval_v6() can send a SYN-ACK.

nft_synproxy_validate() deliberately admits NFPROTO_IPV6 and NFPROTO_INET, and the xtables counterpart ip6t_SYNPROXY.c already calls nf_ip6_checksum().

Use nf_checksum() with nft_pf() so the checksum helper dispatches to the packet family's implementation.

Fixes ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support")
Assisted-by LLM
---
 net/netfilter/nft_synproxy.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/netfilter/nft_synproxy.c +2 -1
index a80bdce38546f..a6253595a1676 100644
@@ -117,7 +117,8 @@ static void nft_synproxy_do_eval(const struct nft_synproxy *priv,
 		return;
 	}
 
-	if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
+	if (nf_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP,
+			nft_pf(pkt))) {
 		regs->verdict.code = NF_DROP;
 		return;
 	}
Signature · 1 line
2.53.0
author maintainer
#69 lore raw

PATCH 69/395 ipvs: revalidate ihl before icmp_send

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Anastasov <[email protected]>

[ Upstream commit e290145564886d6a3038810c621f738c1fe9fa51 ]

While the outer IP header is already pulled into the skb head, we must be careful and revalidate the embedded headers after reading them from the skb frags to prevent possible out-of-bounds access.

One such place reported by Sashiko is ip_vs_in_icmp() where local process can change the ihl field and after pskb_may_pull() we can see larger value. Even if icmp_send() has checks to prevent out-of-bounds access, play safe and add check to drop the packet if the ihl field is changed. As the outer headers are pulled, make sure the transport header is updated too, it was used before commit 7fcc2fe39fed ("net:
icmp: avoid invalid transport header access in icmp_send tracepoint")

Fixes f2edb9f7706d ("ipvs: implement passive PMTUD for IPIP packets")
---
 net/netfilter/ipvs/ip_vs_core.c | 6 ++++++
 1 file changed, 6 insertions(+)
net/netfilter/ipvs/ip_vs_core.c +6 -0
index 1f62ca2f73309..4e30a903f4bdc 100644
@@ -1776,6 +1776,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
 		/* Ensure the IP header is present in headroom */
 		if (!pskb_may_pull(skb, hlen_orig))
 			goto ignore_tunnel;
+		skb_set_transport_header(skb, hlen_orig);
+		/* Before now we may used ihl from skb frag, revalidate it after
+		 * copying it into skb head to prevent out-of-bounds access
+		 */
+		if (ip_hdr(skb)->ihl * 4 != hlen_orig)
+			goto ignore_tunnel;
 		IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n",
 			&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
 			type, code, ntohl(info));
Signature · 1 line
2.53.0
author maintainer
#70 lore raw

PATCH 70/395 netfilter: ctnetlink: fix suspicious RCU usage in expect_iter_name

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Naman Gulati <[email protected]>

[ Upstream commit 207d591c353201f3bd3e0c89bb7d44a849c8fd59 ]

expect_iter_name() is invoked by nf_ct_expect_iterate_net() under spin_lock_bh(&nf_conntrack_expect_lock). It does not hold rcu_read_lock().

When accessing exp->helper with rcu_dereference() in syzbot's report, lockdep warns:

=============================
WARNING: suspicious RCU usage
syzkaller #0 Not tainted
-----------------------------
net/netfilter/nf_conntrack_netlink.c:3393 suspicious rcu_dereference_check() usage!

locks held by syz-executor381/5628: 2, last CPU#1:
#0: ffffffff9aee42a0 (nfnl_subsys_ctnetlink_exp){+.+.}-{4:4},

       at: nfnetlink_rcv_msg+0xa69/0x12b0
   #1: ffffffff8ea74d58 (nf_conntrack_expect_lock){+...}-{3:3},
       at: nf_ct_expect_iterate_net+0x38/0x180
  Call Trace:
   <TASK>
   dump_stack_lvl+0xe8/0x150
   lockdep_rcu_suspicious+0x140/0x1d0
   expect_iter_name+0xfb/0x100
   nf_ct_expect_iterate_net+0xf2/0x180
   ctnetlink_del_expect+0x45d/0x640
   nfnetlink_rcv_msg+0xcc2/0x12b0
   netlink_rcv_skb+0x226/0x4a0
   nfnetlink_rcv+0x2b9/0x28c0
   netlink_unicast+0x7bd/0x940
   netlink_sendmsg+0x813/0xb40
   ____sys_sendmsg+0x54e/0x850
   ___sys_sendmsg+0x2a5/0x360
   __sys_sendmsg+0x2a5/0x360
   do_syscall_64+0x166/0x520
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

Use rcu_dereference_protected() with lockdep_is_held() on nf_conntrack_expect_lock instead, similar to expect_iter_me() in nf_conntrack_helper.c.

Fixes f01794106042 ("netfilter: nf_conntrack_expect: use expect->helper")
Reported-by [email protected]
---
 net/netfilter/nf_conntrack_netlink.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/netfilter/nf_conntrack_netlink.c +2 -1
index 48cf3dad61bdb..5211599357189 100644
@@ -3395,7 +3395,8 @@ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
 	struct nf_conntrack_helper *helper;
 	const char *name = data;
 
-	helper = rcu_dereference(exp->helper);
+	helper = rcu_dereference_protected(exp->helper,
+					   lockdep_is_held(&nf_conntrack_expect_lock));
 	if (!helper)
 		return false;
 
Signature · 1 line
2.53.0
author maintainer
#71 lore raw

PATCH 71/395 arm64: io: Reject non-user protection in ioremap_prot()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zeng Heng <[email protected]>

[ Upstream commit bb756b11ad63832ebee58caf9e8f9381eaecff9f ]

Mapping a stack-top page via /dev/mem with PROT_NONE and then reading that process's /proc/<pid>/cmdline triggers a spurious WARN in ioremap_prot() through generic_access_phys():

  WARNING: ./arch/arm64/include/asm/io.h:275 at generic_access_phys
  Call trace:
    generic_access_phys+0x1c8/0x228 (P)
    __access_remote_vm+0x2b4/0x398
    access_remote_vm+0x14/0x30
    get_mm_cmdline+0xf8/0x2a0
    proc_pid_cmdline_read+0x68/0x120

generic_access_phys() passes the protection derived from the user PTE to ioremap_prot(). On arm64, a PROT_NONE mapping is represented by a present-invalid PTE, so pte_present() still returns true and the protection reaches ioremap_prot().

A PROT_NONE mapping does not have PTE_USER, causing the existing WARN_ON_ONCE() in ioremap_prot() to fire even though this is a valid user mapping. Execute-only mappings have the same issue and must not be readable through this path either.

ioremap_prot() should therefore reject protection values without PTE_USER without warning. This makes the access fail cleanly for PROT_NONE and execute-only mappings while retaining the existing user-protection contract.

Fixes 8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()")
---
 arch/arm64/include/asm/io.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/include/asm/io.h +2 -1
index 8cbd1e96fd50b..a8507de4f84c3 100644
@@ -272,7 +272,8 @@ static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
 	pgprot_t prot;
 	ptdesc_t user_prot_val = pgprot_val(user_prot);
 
-	if (WARN_ON_ONCE(!(user_prot_val & PTE_USER)))
+	/* Reject PROT_NONE and exec-only */
+	if (!(user_prot_val & PTE_USER))
 		return NULL;
 
 	prot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,
Signature · 1 line
2.53.0
author maintainer
#72 lore raw

PATCH 72/395 ocfs2: make ocfs2_calc_xattr_init() return void

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Joseph Qi <[email protected]>

[ Upstream commit 525c0edc032b3297d0c1056cf1fa20cf1f9e6184 ]

ocfs2_calc_xattr_init() used to read the default ACL off the parent inode itself, so it could return an error from ocfs2_xattr_get_nolock(). Commit bd7c05fb4a47 ("ocfs2: fix circular locking dependency in ocfs2_init_acl()") moved that lookup before the transaction starts and deleted the error path, but left the now vestigial 'int ret = 0' declaration and both 'return ret' statements behind, along with an unreachable error branch in ocfs2_mknod().

Drop the leftover variable and convert the return type to void, so the callee states that it always succeeds and the caller no longer carries a check that can never trigger.

No functional change.

Fixes bd7c05fb4a47 ("ocfs2: fix circular locking dependency in ocfs2_init_acl()")
Cc Mark Fasheh <[email protected]>
Cc Joel Becker <[email protected]>
Cc Junxiao Bi <[email protected]>
Cc Changwei Ge <[email protected]>
Cc Jun Piao <[email protected]>
Cc Heming Zhao <[email protected]>
---
 fs/ocfs2/namei.c |  9 ++-------
 fs/ocfs2/xattr.c | 13 +++++--------
 fs/ocfs2/xattr.h |  8 ++++----
 3 files changed, 11 insertions(+), 19 deletions(-)
fs/ocfs2/namei.c +2 -7
index 20276ad6e17e2..42afc21324d4d 100644
@@ -335,13 +335,8 @@ static int ocfs2_mknod(struct mnt_idmap *idmap,
 		goto leave;
 
 	/* calculate meta data/clusters for setting security and acl xattr */
-	status = ocfs2_calc_xattr_init(dir, mode, &si, &want_clusters,
-				       &xattr_credits, &want_meta,
-				       &acl_state);
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
+	ocfs2_calc_xattr_init(dir, mode, &si, &want_clusters, &xattr_credits,
+			      &want_meta, &acl_state);
 
 	/* Reserve a cluster if creating an extent based directory. */
 	if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
fs/ocfs2/xattr.c +5 -8
index 3a796d9159d8e..b5029c4e3784e 100644
@@ -607,12 +607,11 @@ int ocfs2_calc_security_init(struct inode *dir,
 	return ret;
 }
 
-int ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
-			  struct ocfs2_security_xattr_info *si,
-			  int *want_clusters, int *xattr_credits,
-			  int *want_meta, struct ocfs2_acl_state *acl_state)
+void ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
+			   struct ocfs2_security_xattr_info *si,
+			   int *want_clusters, int *xattr_credits,
+			   int *want_meta, struct ocfs2_acl_state *acl_state)
 {
-	int ret = 0;
 	struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
 	int s_size = 0, a_size = 0, acl_len = 0, new_clusters;
 
@@ -634,7 +633,7 @@ int ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
 	}
 
 	if (!(s_size + a_size))
-		return ret;
+		return;
 
 	/*
 	 * The max space of security xattr taken inline is
@@ -700,8 +699,6 @@ int ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
 			}
 		}
 	}
-
-	return ret;
 }
 
 static int ocfs2_xattr_extend_allocation(struct inode *inode,
fs/ocfs2/xattr.h +4 -4
index 5cdd6c6b40064..aeba323e14b3c 100644
@@ -57,10 +57,10 @@ int ocfs2_calc_security_init(struct inode *,
 			     int *, int *, struct ocfs2_alloc_context **);
 
 struct ocfs2_acl_state;
-int ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
-			  struct ocfs2_security_xattr_info *si,
-			  int *want_clusters, int *xattr_credits,
-			  int *want_meta, struct ocfs2_acl_state *acl_state);
+void ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
+			   struct ocfs2_security_xattr_info *si,
+			   int *want_clusters, int *xattr_credits,
+			   int *want_meta, struct ocfs2_acl_state *acl_state);
 
 /*
  * xattrs can live inside an inode, as part of an external xattr block,
Signature · 1 line
2.53.0
author maintainer
#73 lore raw

PATCH 73/395 drm/nouveau/clk: fix list cursor use after loop in nvkm_clk_ustate_update

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dan Carpenter <[email protected]>

[ Upstream commit aff09d9e37e02dc60bde79035ac15b136d602259 ]

If list_for_each_entry() exits without hitting a break then "pstate" is not a valid pstate pointer. Introduce a "found" variable instead.

The check is reachable from userspace: nvkm_clk_ustate_update() takes the pstate id straight from the 'pstate' debugfs file, so requesting an id that is not in clk->states - or any id at all when the perf tables are broken and the list is empty - makes the pstate->pstate != req test dereference the list head cast to a struct nvkm_pstate, which is an out-of-bounds read.

Fixes 7c8565220697 ("drm/nouveau/clk: implement power state and engine clock control in core")
[Francesco: rebased on drm-misc-next, expanded the commit message]
---
 drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +5 -2
index 71420f81714b3..8d1874dc3d7f2 100644
@@ -473,6 +473,7 @@ static int
 nvkm_clk_ustate_update(struct nvkm_clk *clk, int req)
 {
 	struct nvkm_pstate *pstate;
+	bool found = false;
 	int i = 0;
 
 	if (!clk->allow_reclock)
@@ -480,12 +481,14 @@ nvkm_clk_ustate_update(struct nvkm_clk *clk, int req)
 
 	if (req != -1 && req != -2) {
 		list_for_each_entry(pstate, &clk->states, head) {
-			if (pstate->pstate == req)
+			if (pstate->pstate == req) {
+				found = true;
 				break;
+			}
 			i++;
 		}
 
-		if (pstate->pstate != req)
+		if (!found)
 			return -EINVAL;
 		req = i;
 	}
Signature · 1 line
2.53.0
author maintainer
#74 lore raw

PATCH 74/395 drm/nouveau/clk: dont clobber reclock status when restoring volt/fan

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Francesco Magazzu <[email protected]>

[ Upstream commit e5cccdafc855cd5f96f4b51d38114a0360b075d7 ]

nvkm_cstate_prog() reuses 'ret' for the voltage and fan-speed restore calls it makes after reprogramming the clocks. Those calls almost always succeed, so the status of the reclock itself is overwritten and the function reports success even when clk->func->calc() or clk->func->prog() failed. The converse is also true: a successful reclock is reported as an error if the final restore call fails, even though that failure is only logged and otherwise ignored.

The only consumer of the return value is the error message in nvkm_pstate_work(), so in practice a failing reclock is simply never reported. Nothing else changes, but a function that returns success on failure is a trap for the next caller.

Keep the calc/prog status in 'ret' and use a separate local for the restore calls.

---
 drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +9 -7
index 8d1874dc3d7f2..ecde72a4f2ee1 100644
@@ -199,16 +199,18 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
 	}
 
 	if (volt) {
-		ret = nvkm_volt_set_id(volt, cstate->voltage,
-				       pstate->base.voltage, clk->temp, -1);
-		if (ret && ret != -ENODEV)
-			nvkm_error(subdev, "failed to lower voltage: %d\n", ret);
+		int err = nvkm_volt_set_id(volt, cstate->voltage,
+					   pstate->base.voltage, clk->temp, -1);
+
+		if (err && err != -ENODEV)
+			nvkm_error(subdev, "failed to lower voltage: %d\n", err);
 	}
 
 	if (therm) {
-		ret = nvkm_therm_cstate(therm, pstate->fanspeed, -1);
-		if (ret && ret != -ENODEV)
-			nvkm_error(subdev, "failed to lower fan speed: %d\n", ret);
+		int err = nvkm_therm_cstate(therm, pstate->fanspeed, -1);
+
+		if (err && err != -ENODEV)
+			nvkm_error(subdev, "failed to lower fan speed: %d\n", err);
 	}
 
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#75 lore raw

PATCH 75/395 drm/nouveau/disp: dont reject HDMI config on cards without SCDC

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Giuseppe Ranieri <[email protected]>

[ Upstream commit 1717fcc5be575d4768279148ae9465a8b13d4339 ]

nv50_hdmi_enable() passes the sink's SCDC capability from its EDID straight through to nvif_outp_hdmi(). On pre-Maxwell-2 cards there is no hdmi->scdc callback, so nvkm_uoutp_mthd_hdmi() rejects the whole configuration with -EINVAL, and nv50_hdmi_enable() returns before hdmi->ctrl() runs and before the AVI and VSI infoframes are sent.

The result on such a card driving an SCDC-capable HDMI 2.0 sink is that HDMI audio silently stops working. Video is unaffected, and nothing is logged, which makes the failure hard to attribute.

SCDC is optional, and the hdmi->scdc() call further down is already guarded against a missing callback. Requesting it on a card that cannot do it need not invalidate the rest of the HDMI configuration, so drop that term from the condition and let the existing guard skip SCDC alone.

---
 drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +1 -2
index 377d0e0cef848..9887b3898505b 100644
@@ -253,8 +253,7 @@ nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
 
 	if (!ior->func->hdmi ||
 	    args->v0.max_ac_packet > 0x1f ||
-	    args->v0.rekey > 0x7f ||
-	    (args->v0.scdc && !ior->func->hdmi->scdc))
+	    args->v0.rekey > 0x7f)
 		return -EINVAL;
 
 	if (!args->v0.enable) {
Signature · 1 line
2.53.0
author maintainer
#76 lore raw

PATCH 76/395 net/sched: act_ct: dont WARN on benign flow_offload_alloc() failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nguyen Ngoc Thang <[email protected]>

[ Upstream commit 47abe7a5c4eb53269aca3506446f851572a059a3 ]

flow_offload_alloc() returns NULL when the conntrack entry is dying (e.g. raced with a conntrack flush) or when the GFP_ATOMIC allocation fails; both are expected under load and neither is a kernel bug. This path runs from softirq on every committed packet, so with panic_on_warn=1 an unprivileged user can panic the box just by racing a conntrack flush against a tc ... action ct commit classifier.

Reproduced with a custom repro under QEMU: a small, fixed set of UDP flows through tc filter ... action ct commit on lo, raced against threads flooding bare ctnetlink CT_DELETE (flush) requests. Hits

WARNING: net/sched/act_ct.c:437 (tcf_ct_flow_table_add(), inlined

into tcf_ct_act() in this build) within ~15s on the unpatched kernel; same setup is clean on the patched kernel. The fix itself is
behavior-preserving: both branches already did goto err_alloc before and after, only the WARN is removed.

---
 net/sched/act_ct.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
net/sched/act_ct.c +2 -3
index cbac27ba76afc..14d16956451dc 100644
@@ -430,11 +430,10 @@ static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
 	if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
 		return;
 
+	/* NULL if ct is dying (raced flush) or the atomic alloc failed. */
 	entry = flow_offload_alloc(ct);
-	if (!entry) {
-		WARN_ON_ONCE(1);
+	if (!entry)
 		goto err_alloc;
-	}
 
 	if (tcp) {
 		ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
Signature · 1 line
2.53.0
author maintainer
#77 lore raw

PATCH 77/395 net: gue: reject invalid REMCSUM offsets

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jérémy Jean <[email protected]>

[ Upstream commit 2566866fc30965d915d0b52b5c3323b362619f0e ]

The REMCSUM option carries an absolute checksum start and checksum field offset. gue_remcsum() passes them to skb_remcsum_process(), whose partial path stores offset - start in the u16 skb->csum_offset variable. If offset is less than start, this underflows.

A forwarded packet can retain CHECKSUM_PARTIAL and reach a NETIF_F_HW_CSUM driver which trusts the metadata, leading skb_copy_and_csum_dev() to write two bytes about 64 KiB beyond the destination buffer.

Reject reversed tuples in validate_gue_flags(), after the existing length validation, so all GUE parsers enforce the ordering in one place.

Fixes fe881ef11cf0 ("gue: Use checksum partial with remote checksum offload")
---
 include/net/gue.h | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
include/net/gue.h +15 -4
index caefd6da86939..d377155fd0b31 100644
@@ -84,8 +84,9 @@ static inline size_t guehdr_priv_flags_len(__be32 flags)
 }
 
 /* Validate standard and private flags. Returns non-zero (meaning invalid)
- * if there is an unknown standard or private flags, or the options length for
- * the flags exceeds the options length specific in hlen of the GUE header.
+ * if there is an unknown standard or private flags, if the options length for
+ * the flags exceeds the options length specified in hlen of the GUE header, or
+ * if a private option contains invalid data.
  */
 static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
 {
@@ -103,8 +104,8 @@ static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
 		/* Private flags are last four bytes accounted in
 		 * guehdr_flags_len
 		 */
-		__be32 pflags = *(__be32 *)((void *)&guehdr[1] +
-					    len - GUE_LEN_PRIV);
+		void *data = (void *)&guehdr[1] + len;
+		__be32 pflags = *(__be32 *)(data - GUE_LEN_PRIV);
 
 		if (pflags & ~GUE_PFLAGS_ALL)
 			return 1;
@@ -112,6 +113,16 @@ static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
 		len += guehdr_priv_flags_len(pflags);
 		if (len > optlen)
 			return 1;
+
+		if (pflags & GUE_PFLAG_REMCSUM) {
+			__be16 *pd = data;
+
+			/* The field offset pd[1] must not be less
+			 * than the start pd[0].
+			 */
+			if (ntohs(pd[1]) < ntohs(pd[0]))
+				return 1;
+		}
 	}
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#78 lore raw

PATCH 78/395 net: ethernet: mtk_eth_soc: unregister net_devices in case of probe failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lorenzo Bianconi <[email protected]>

[ Upstream commit 310d1ac61a4d5a2ca8356a3a48d263acf54503ce ]

If register_netdev() fails for one of the MTK_MAX_DEVS devices in mtk_probe(), the error path jumps to err_deinit_ppe, skipping mtk_unreg_dev(). The previously registered net_devices are then freed by mtk_free_dev() while still in NETREG_REGISTERED state, hitting the BUG_ON(dev->reg_state != NETREG_UNREGISTERED).

Route the register_netdev() failure to err_unreg_netdev so the net_devices registered so far are properly unregistered before being freed.

---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +5 -1
index 31eee8739c575..3f43e487d8875 100644
@@ -4509,6 +4509,10 @@ static int mtk_unreg_dev(struct mtk_eth *eth)
 		mac = netdev_priv(eth->netdev[i]);
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
 			unregister_netdevice_notifier(&mac->device_notifier);
+
+		if (eth->netdev[i]->reg_state != NETREG_REGISTERED)
+			continue;
+
 		unregister_netdev(eth->netdev[i]);
 	}
 
@@ -5340,7 +5344,7 @@ static int mtk_probe(struct platform_device *pdev)
 		err = register_netdev(eth->netdev[i]);
 		if (err) {
 			dev_err(eth->dev, "error bringing up device\n");
-			goto err_deinit_ppe;
+			goto err_unreg_netdev;
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
Signature · 1 line
2.53.0
author maintainer
#79 lore raw

PATCH 79/395 ip6_gre: Call ip6erspan_tunnel_unlink_md() in ip6erspan_changelink().

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit dd47bcf279f1083f09bf5266890b26263361022b ]

The cited commit accidentally added ip6gre_tunnel_unlink_md() in ip6erspan_changelink().

Let's correct it to ip6erspan_tunnel_unlink_md().

---
 net/ipv6/ip6_gre.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/ip6_gre.c +1 -1
index 81792c940d296..ebd0198458cd3 100644
@@ -2279,7 +2279,7 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
 		return PTR_ERR(t);
 
 	ip6erspan_set_version(data, &p);
-	ip6gre_tunnel_unlink_md(ign, t);
+	ip6erspan_tunnel_unlink_md(ign, t);
 	ip6gre_tunnel_unlink(ign, t);
 	ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]);
 	ip6erspan_tunnel_link_md(ign, t);
Signature · 1 line
2.53.0
author maintainer
#80 lore raw

PATCH 80/395 eth: fbnic: Handle maximum standalone channels

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Björn Töpel <[email protected]>

[ Upstream commit 1f4c73064a50f53d596c6f1d06d2d700f43c4b32 ]

Standalone channels use one NAPI vector for each Tx and Rx queue. fbnic's allocation path excludes FBNIC_MAX_TXQS from that layout. A 64-Tx/64-Rx configuration therefore records 128 vectors but allocates only 64, leaving NULL entries that resource setup dereferences.

Include the maximum vector count in standalone allocation.

---
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +1 -1
index 7fc7761e8f2e0..946c2997d2122 100644
@@ -1789,7 +1789,7 @@ int fbnic_alloc_napi_vectors(struct fbnic_net *fbn)
 	int err;
 
 	/* Allocate 1 Tx queue per napi vector */
-	if (num_napi < FBNIC_MAX_TXQS && num_napi == num_tx + num_rx) {
+	if (num_napi <= FBNIC_MAX_TXQS && num_napi == num_tx + num_rx) {
 		while (num_tx) {
 			err = fbnic_alloc_napi_vector(fbd, fbn,
 						      num_napi, v_idx,
Signature · 1 line
2.53.0
author maintainer
#81 lore raw

PATCH 81/395 eth: fbnic: reset num_napi when the napi vectors are freed

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexander Duyck <[email protected]>

[ Upstream commit 4bcc4a92c603fe7f062cea22e20da2e0ad6b12c3 ]

fbn->num_napi is the count of live napi vectors, each of which owns an IRQ. The PM path had freed them without clearing the count. fbnic_pm_suspend() tears the datapath down via ndo_stop() and frees the IRQs, but leaves netif_running() true so resume knows to re-open. Resume rebuilds the datapath in __fbnic_pm_resume() and fbnic_reset_queues() sets num_napi and __fbnic_open() re-allocates the vectors.

When the datapath is torn down but never rebuilt, num_napi is left pointing at freed vectors under 2 different scenarios:
- a PCIe error recovery that fails (fbnic_err_slot_reset() -> __fbnic_pm_resume() returns an error -> PCI_ERS_RESULT_DISCONNECT), so .resume never runs; or
- an __fbnic_open() that fails partway on resume and unwinds, freeing the vectors after fbnic_reset_queues() has already set num_napi.

The netdev is then running with num_napi > 0 but napi[] freed, and the eventual remove/unbind close re-enters fbnic_down() -> fbnic_dbg_down() and dereferences the freed vectors:

  BUG: kernel NULL pointer dereference, address: 0000000000000210
  RIP: fbnic_dbg_down+0x28

Clear num_napi when the vectors are freed: in the suspend teardown (a good resume re-establishes it before __fbnic_open()) and on the resume open failure. A redundant ndo_stop() then walks an empty napi[]. The normal ndo_stop() down/up cycle is untouched and keeps num_napi for the next ndo_open().

---
 drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_pci.c +14 -4
index 99b7c0718e80e..cabbc88bb92db 100644
@@ -414,6 +414,7 @@ static int fbnic_pm_suspend(struct device *dev)
 {
 	struct fbnic_dev *fbd = dev_get_drvdata(dev);
 	struct net_device *netdev = fbd->netdev;
+	struct fbnic_net *fbn;
 
 	if (fbnic_init_failure(fbd))
 		goto null_uc_addr;
@@ -421,11 +422,16 @@ static int fbnic_pm_suspend(struct device *dev)
 	rtnl_lock();
 	netdev_lock(netdev);
 
+	fbn = netdev_priv(netdev);
+
 	netif_device_detach(netdev);
 
 	if (netif_running(netdev))
 		netdev->netdev_ops->ndo_stop(netdev);
 
+	/* The IRQs are about to be freed, so drop the napi vector count */
+	fbn->num_napi = 0;
+
 	netdev_unlock(netdev);
 	rtnl_unlock();
 
@@ -488,16 +494,20 @@ static int __fbnic_pm_resume(struct device *dev)
 	if (fbnic_init_failure(fbd))
 		return 0;
 
+	rtnl_lock();
+	netdev_lock(netdev);
+
 	fbn = netdev_priv(netdev);
 
 	/* Reset the queues if needed */
 	fbnic_reset_queues(fbn, fbn->num_tx_queues, fbn->num_rx_queues);
 
-	rtnl_lock();
-	netdev_lock(netdev);
-
-	if (netif_running(netdev))
+	if (netif_running(netdev)) {
 		err = __fbnic_open(fbn);
+		/* On failure the vectors are freed, so drop the count */
+		if (err)
+			fbn->num_napi = 0;
+	}
 
 	netdev_unlock(netdev);
 	rtnl_unlock();
Signature · 1 line
2.53.0
author maintainer
#82 lore raw

PATCH 82/395 eth: fbnic: Set AW_FLUSH_MODE alongside AW_FLUSH when flushing the mailbox

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexander Duyck <[email protected]>

[ Upstream commit 8947f13e436a4ff5eed9f8f019b2865a07af4bb2 ]

When tearing down the FW mailbox Rx ring, fbnic_mbx_reset_desc_ring() writes AW_CFG with FLUSH set and everything else, BME included, cleared. Clearing BME halts the device's writes to the host but leaves the staged requests parked in the PUL write pipeline rather than draining them, so on the write path FLUSH alone never terminates the outstanding requests and the flush the firmware waits on never completes.

Add the FLUSH_MODE definition and set both bits so the staged writes drain out of the pipeline on their own. BME stays cleared, so nothing lands on the host; it is restored later in fbnic_mbx_init_desc_ring() when the ring is rebuilt, once the outstanding writes are gone.

The read path is unaffected. AR_CFG has no equivalent mode bit and AR_FLUSH terminates the outstanding reads by itself, so it is left as is.

Both writes remain plain stores rather than read-modify-writes. That is
deliberate: the matching write in fbnic_mbx_init_desc_ring() restores BME and the TLP attributes, and clears both flush bits as a side effect.

---
 drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 1 +
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c  | 9 ++++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/net/ethernet/meta/fbnic/fbnic_csr.h +1 -0
index d3a7ad921f18c..3e070f57df6e5 100644
@@ -958,6 +958,7 @@ enum {
 /* PUL User Registers */
 #define FBNIC_CSR_START_PUL_USER	0x31000	/* CSR section delimiter */
 #define FBNIC_PUL_OB_TLP_HDR_AW_CFG	0x3103d		/* 0xc40f4 */
+#define FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH_MODE	CSR_BIT(20)
 #define FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH	CSR_BIT(19)
 #define FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME		CSR_BIT(18)
 #define FBNIC_PUL_OB_TLP_HDR_AR_CFG	0x3103e		/* 0xc40f8 */
drivers/net/ethernet/meta/fbnic/fbnic_fw.c +8 -1
index 1204c12ea0fa2..9e5de01698fc4 100644
@@ -60,8 +60,15 @@ static void fbnic_mbx_reset_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
 	 */
 	switch (mbx_idx) {
 	case FBNIC_IPC_MBX_RX_IDX:
+		/* Clearing BME blocks the device from writing to the host
+		 * but leaves the requests parked in the write pipeline. The
+		 * write path only clears outstanding requests when both FLUSH
+		 * and FLUSH_MODE are set; FLUSH_MODE lets them drain without
+		 * landing on the host.
+		 */
 		wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
-		     FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH);
+		     FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH |
+		     FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH_MODE);
 		break;
 	case FBNIC_IPC_MBX_TX_IDX:
 		wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
Signature · 1 line
2.53.0
author maintainer
#83 lore raw

PATCH 83/395 eth: fbnic: Reuse RX mailbox pages

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mohsin Bashir <[email protected]>

[ Upstream commit 301ae0d5391a19d9897c342c874240b36f7bc85f ]

Currently, the RX mailbox frees and reallocates a page for each received message. Since FW Rx messages are processed synchronously, and nothing hold these pages (unlike skbs which we hand over to the stack), reuse the pages and put them back on the Rx ring. Now that we ensure the ring is always fully populated we don't have to worry about filling it up after partial population during init, either. Update fbnic_mbx_process_rx_msgs() to recycle pages after message processing.

Stable-dep-of: 1b97a269a5bd ("eth: fbnic: Handle FW mailbox completions flagged with an error")

---
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 25 ++++++++++++++--------
 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_fw.c +16 -9
index 9e5de01698fc4..6edd01e58bf06 100644
@@ -1598,7 +1598,7 @@ static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
 static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
 {
 	struct fbnic_fw_mbx *rx_mbx = &fbd->mbx[FBNIC_IPC_MBX_RX_IDX];
-	u8 head = rx_mbx->head;
+	u8 head = rx_mbx->head, tail = rx_mbx->tail;
 	u64 desc, length;
 
 	while (head != rx_mbx->tail) {
@@ -1609,8 +1609,8 @@ static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
 		if (!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL))
 			break;
 
-		dma_unmap_single(fbd->dev, rx_mbx->buf_info[head].addr,
-				 PAGE_SIZE, DMA_FROM_DEVICE);
+		dma_sync_single_for_cpu(fbd->dev, rx_mbx->buf_info[head].addr,
+					FBNIC_RX_PAGE_SIZE, DMA_FROM_DEVICE);
 
 		msg = rx_mbx->buf_info[head].msg;
 
@@ -1643,19 +1643,26 @@ static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
 
 		dev_dbg(fbd->dev, "Parsed msg type %d\n", msg->hdr.type);
 next_page:
+		fw_wr32(fbd, FBNIC_IPC_MBX(FBNIC_IPC_MBX_RX_IDX, head), 0);
 
-		free_page((unsigned long)rx_mbx->buf_info[head].msg);
+		rx_mbx->buf_info[tail] = rx_mbx->buf_info[head];
 		rx_mbx->buf_info[head].msg = NULL;
+		rx_mbx->buf_info[head].addr = 0;
 
-		head++;
-		head %= FBNIC_IPC_MBX_DESC_LEN;
+		__fbnic_mbx_wr_desc(fbd, FBNIC_IPC_MBX_RX_IDX, tail,
+				    FIELD_PREP(FBNIC_IPC_MBX_DESC_LEN_MASK,
+					       FBNIC_RX_PAGE_SIZE) |
+				    (rx_mbx->buf_info[tail].addr &
+				     FBNIC_IPC_MBX_DESC_ADDR_MASK) |
+				    FBNIC_IPC_MBX_DESC_HOST_CMPL);
+
+		head = (head + 1) & (FBNIC_IPC_MBX_DESC_LEN - 1);
+		tail = (tail + 1) & (FBNIC_IPC_MBX_DESC_LEN - 1);
 	}
 
 	/* Record head for next interrupt */
 	rx_mbx->head = head;
-
-	/* Make sure we have at least one page for the FW to write to */
-	fbnic_mbx_alloc_rx_msgs(fbd);
+	rx_mbx->tail = tail;
 }
 
 void fbnic_mbx_poll(struct fbnic_dev *fbd)
Signature · 1 line
2.53.0
author maintainer
#84 lore raw

PATCH 84/395 eth fbnic: Add debugfs hooks for firmware mailbox

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mike Marciniszyn (Meta) <[email protected]>

[ Upstream commit ac7b803c2dd57938cbf1e9a3ada23471925a5d46 ]

This patch adds reporting the Rx and Tx information interfacing with the firmware.

The result of reading fbnic/fw_mbx is:

Rx
Rdy: 1 Head: 11 Tail: 10
Idx Len E Addr F H Raw
----------------------------------

 00  4096 0 000101fea000 0 1   1000000101fea001
 01  4096 0 000101feb000 0 1   1000000101feb001

.
.
.
15 4096 0 000101fe9000 0 1 1000000101fe9001

Tx
Rdy: 1 Head: 4 Tail: 4
Idx Len E Addr F H Raw
----------------------------------

 00  0004 1 00010321b000 1 1   000440010321b003
 01  0004 1 00010228d000 1 1   000440010228d003

.
.
.
15 0004 1 00010321b000 1 1 000440010321b003

Stable-dep-of: 1b97a269a5bd ("eth: fbnic: Handle FW mailbox completions flagged with an error")

---
 .../net/ethernet/meta/fbnic/fbnic_debugfs.c   | 48 +++++++++++++++++++
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c    |  2 +-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.h    |  1 +
 3 files changed, 50 insertions(+), 1 deletion(-)
drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c +48 -0
index b7238dd967fe4..9cdd03bfec340 100644
@@ -170,6 +170,52 @@ static int fbnic_dbg_ipo_dst_show(struct seq_file *s, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ipo_dst);
 
+static void fbnic_dbg_fw_mbx_display(struct seq_file *s,
+				     struct fbnic_dev *fbd, int mbx_idx)
+{
+	struct fbnic_fw_mbx *mbx = &fbd->mbx[mbx_idx];
+	char hdr[80];
+	int i;
+
+	/* Generate header */
+	seq_puts(s, mbx_idx == FBNIC_IPC_MBX_RX_IDX ? "Rx\n" : "Tx\n");
+
+	seq_printf(s, "Rdy: %d Head: %d Tail: %d\n",
+		   mbx->ready, mbx->head, mbx->tail);
+
+	snprintf(hdr, sizeof(hdr), "%3s %-4s %s %-12s %s %-3s %-16s\n",
+		 "Idx", "Len", "E", "Addr", "F", "H", "Raw");
+	seq_puts(s, hdr);
+	fbnic_dbg_desc_break(s, strnlen(hdr, sizeof(hdr)));
+
+	for (i = 0; i < FBNIC_IPC_MBX_DESC_LEN; i++) {
+		u64 desc = __fbnic_mbx_rd_desc(fbd, mbx_idx, i);
+
+		seq_printf(s, "%-3.2d %04lld %d %012llx %d %-3d %016llx\n",
+			   i, FIELD_GET(FBNIC_IPC_MBX_DESC_LEN_MASK, desc),
+			   !!(desc & FBNIC_IPC_MBX_DESC_EOM),
+			   desc & FBNIC_IPC_MBX_DESC_ADDR_MASK,
+			   !!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL),
+			   !!(desc & FBNIC_IPC_MBX_DESC_HOST_CMPL),
+			   desc);
+	}
+}
+
+static int fbnic_dbg_fw_mbx_show(struct seq_file *s, void *v)
+{
+	struct fbnic_dev *fbd = s->private;
+
+	fbnic_dbg_fw_mbx_display(s, fbd, FBNIC_IPC_MBX_RX_IDX);
+
+	/* Add blank line between Rx and Tx */
+	seq_puts(s, "\n");
+
+	fbnic_dbg_fw_mbx_display(s, fbd, FBNIC_IPC_MBX_TX_IDX);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_fw_mbx);
+
 static int fbnic_dbg_fw_log_show(struct seq_file *s, void *v)
 {
 	struct fbnic_dev *fbd = s->private;
@@ -249,6 +295,8 @@ void fbnic_dbg_fbd_init(struct fbnic_dev *fbd)
 			    &fbnic_dbg_ipo_src_fops);
 	debugfs_create_file("ipo_dst", 0400, fbd->dbg_fbd, fbd,
 			    &fbnic_dbg_ipo_dst_fops);
+	debugfs_create_file("fw_mbx", 0400, fbd->dbg_fbd, fbd,
+			    &fbnic_dbg_fw_mbx_fops);
 	debugfs_create_file("fw_log", 0400, fbd->dbg_fbd, fbd,
 			    &fbnic_dbg_fw_log_fops);
 }
drivers/net/ethernet/meta/fbnic/fbnic_fw.c +1 -1
index 6edd01e58bf06..69b9bd03d00e0 100644
@@ -40,7 +40,7 @@ static void __fbnic_mbx_invalidate_desc(struct fbnic_dev *fbd, int mbx_idx,
 	fw_wr32(fbd, desc_offset + 1, 0);
 }
 
-static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
+u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
 {
 	u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
 	u64 desc;
drivers/net/ethernet/meta/fbnic/fbnic_fw.h +1 -0
index 1ecd777aaadab..30e74ccd40e9a 100644
@@ -92,6 +92,7 @@ struct fbnic_fw_completion {
 	} u;
 };
 
+u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx);
 void fbnic_mbx_init(struct fbnic_dev *fbd);
 void fbnic_mbx_clean(struct fbnic_dev *fbd);
 int fbnic_mbx_set_cmpl(struct fbnic_dev *fbd,
Signature · 1 line
2.53.0
author maintainer
#85 lore raw

PATCH 85/395 eth: fbnic: Handle FW mailbox completions flagged with an error

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexander Duyck <[email protected]>

[ Upstream commit 1b97a269a5bdde20d4e69511f27649c9cb82b7c7 ]

The firmware can complete a mailbox descriptor while also setting FW_ERR to indicate it could not process the request, for example on a mailbox DMA error. The completion carries no valid data.

The driver did not check FW_ERR. On the Rx mailbox it would sync and parse the stale page as a normal message, and on the Tx mailbox it silently freed the request. If the initial capabilities exchange in fbnic_mbx_poll_tx_ready() hit FW_ERR -- on the Tx request or on the Rx response descriptor -- no response was parsed and the poll spun until it timed out even though the ring was healthy.

Check FW_ERR on both mailboxes. Count it per-mailbox in fbnic_fw_mbx.resp_error, which is also shown in debugfs, warn (rate limited, since the bit is firmware controlled), and drop the Rx page instead of parsing it.

In fbnic_mbx_poll_tx_ready() re-issue the capabilities request when either the Tx or the Rx resp_error counter advances, so a FW_ERR on the request or on its response triggers a retry rather than a timeout. A valid capabilities response is honored before the retry check, so a response parsed in the same poll as an unrelated FW_ERR is not discarded. The counters are mailbox-wide rather than keyed to the capabilities request; that is sufficient here because the exchange runs during bring-up before any other mailbox traffic, and any spurious retry is bounded by the existing 10s timeout.

---
 drivers/net/ethernet/meta/fbnic/fbnic_csr.h   |  4 ++
 .../net/ethernet/meta/fbnic/fbnic_debugfs.c   |  4 +-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c    | 38 ++++++++++++++++++-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.h    |  1 +
 4 files changed, 44 insertions(+), 3 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_csr.h +4 -0
index 3e070f57df6e5..00c76708f2335 100644
@@ -1176,6 +1176,10 @@ enum {
 #define FBNIC_IPC_MBX_DESC_LEN_MASK	DESC_GENMASK(63, 48)
 #define FBNIC_IPC_MBX_DESC_EOM		DESC_BIT(46)
 #define FBNIC_IPC_MBX_DESC_ADDR_MASK	DESC_GENMASK(45, 3)
+/* Set with FW_CMPL when the FW completed a descriptor without successfully
+ * processing it (e.g. a mailbox DMA error); the completion has no valid data.
+ */
+#define FBNIC_IPC_MBX_DESC_FW_ERR	DESC_BIT(2)
 #define FBNIC_IPC_MBX_DESC_FW_CMPL	DESC_BIT(1)
 #define FBNIC_IPC_MBX_DESC_HOST_CMPL	DESC_BIT(0)
 
drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c +2 -2
index 9cdd03bfec340..3a98b28380d87 100644
@@ -180,8 +180,8 @@ static void fbnic_dbg_fw_mbx_display(struct seq_file *s,
 	/* Generate header */
 	seq_puts(s, mbx_idx == FBNIC_IPC_MBX_RX_IDX ? "Rx\n" : "Tx\n");
 
-	seq_printf(s, "Rdy: %d Head: %d Tail: %d\n",
-		   mbx->ready, mbx->head, mbx->tail);
+	seq_printf(s, "Rdy: %d Head: %d Tail: %d resp_error: %llu\n",
+		   mbx->ready, mbx->head, mbx->tail, mbx->resp_error);
 
 	snprintf(hdr, sizeof(hdr), "%3s %-4s %s %-12s %s %-3s %-16s\n",
 		 "Idx", "Len", "E", "Addr", "F", "H", "Raw");
drivers/net/ethernet/meta/fbnic/fbnic_fw.c +37 -1
index 69b9bd03d00e0..645408a04a4c0 100644
@@ -293,6 +293,12 @@ static void fbnic_mbx_process_tx_msgs(struct fbnic_dev *fbd)
 		if (!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL))
 			break;
 
+		if (desc & FBNIC_IPC_MBX_DESC_FW_ERR) {
+			tx_mbx->resp_error++;
+			dev_warn_ratelimited(fbd->dev,
+					     "FW completed a Tx mailbox request with an error\n");
+		}
+
 		fbnic_mbx_unmap_and_free_msg(fbd, FBNIC_IPC_MBX_TX_IDX, head);
 
 		head++;
@@ -1609,6 +1615,13 @@ static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
 		if (!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL))
 			break;
 
+		if (desc & FBNIC_IPC_MBX_DESC_FW_ERR) {
+			rx_mbx->resp_error++;
+			dev_warn_ratelimited(fbd->dev,
+					     "FW reported an error on an Rx mailbox message; dropping\n");
+			goto next_page;
+		}
+
 		dma_sync_single_for_cpu(fbd->dev, rx_mbx->buf_info[head].addr,
 					FBNIC_RX_PAGE_SIZE, DMA_FROM_DEVICE);
 
@@ -1676,7 +1689,9 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd)
 int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
 {
 	struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
+	struct fbnic_fw_mbx *rx_mbx = &fbd->mbx[FBNIC_IPC_MBX_RX_IDX];
 	unsigned long timeout = jiffies + 10 * HZ + 1;
+	u64 tx_resp_error, rx_resp_error;
 	int err, i;
 
 	do {
@@ -1704,6 +1719,9 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
 	 * mgmt.version once we get the actual version from the firmware
 	 * in the capabilities request message.
 	 */
+send_cap_req:
+	tx_resp_error = tx_mbx->resp_error;
+	rx_resp_error = rx_mbx->resp_error;
 	err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
 	if (err)
 		goto clean_mbx;
@@ -1721,9 +1739,27 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
 		msleep(20);
 		fbnic_mbx_poll(fbd);
 
+		/* A valid capabilities response ends the poll. Check it
+		 * before the FW_ERR retry below so a response parsed in the
+		 * same poll as an unrelated FW_ERR is not discarded.
+		 */
+		if (fbd->fw_cap.running.mgmt.version >= MIN_FW_VER_CODE)
+			break;
+
 		/* set err, but wait till mgmt.version check to report it */
-		if (!time_is_after_jiffies(timeout))
+		if (!time_is_after_jiffies(timeout)) {
 			err = -ETIMEDOUT;
+			continue;
+		}
+
+		/* The FW can flag our capabilities request (Tx) or its
+		 * response (Rx) with FW_ERR, in which case it produced no
+		 * usable response. The ring is not wedged, so re-issue the
+		 * request instead of spinning until the timeout.
+		 */
+		if (tx_mbx->resp_error != tx_resp_error ||
+		    rx_mbx->resp_error != rx_resp_error)
+			goto send_cap_req;
 	}
 
 	return 0;
drivers/net/ethernet/meta/fbnic/fbnic_fw.h +1 -0
index 30e74ccd40e9a..57ab3a5450be0 100644
@@ -12,6 +12,7 @@ struct fbnic_tlv_msg;
 
 struct fbnic_fw_mbx {
 	u8 ready, head, tail;
+	u64 resp_error;
 	struct {
 		struct fbnic_tlv_msg	*msg;
 		dma_addr_t		addr;
Signature · 1 line
2.53.0
author maintainer
#86 lore raw

PATCH 86/395 sctp: avoid livelock while updating retransmit path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yiqi Sun <[email protected]>

[ Upstream commit d2c31b837406395e576afeb25958c98e9938f3f6 ]

sctp_assoc_update_retran_path() can loop forever when every remaining transport, including retran_path, is SCTP_UNCONFIRMED: the state check runs before the wraparound test, so the loop cannot observe that it has completed a full pass.

Fix this by considering a transport only when it is not UNCONFIRMED, then checking whether the walk has returned to retran_path. This makes the full-pass termination independent of the transport state while preserving the existing fallback selection semantics.

Also restore the NULL guard around the retran_path assignment. In the all-UNCONFIRMED case there is no eligible replacement transport, and installing NULL would leave later retransmit-path users and the debug print with a NULL path.

Fixes 4c47af4d5eb2 ("net: sctp: rework multihoming retransmission path selection to rfc4960")
---
 net/sctp/associola.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
net/sctp/associola.c +8 -7
index febb8a076f803..ca55be94e8d4d 100644
@@ -1285,18 +1285,19 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
 		/* Manually skip the head element. */
 		if (&trans->transports == &asoc->peer.transport_addr_list)
 			continue;
-		if (trans->state == SCTP_UNCONFIRMED)
-			continue;
-		trans_next = sctp_trans_elect_best(trans, trans_next);
-		/* Active is good enough for immediate return. */
-		if (trans_next->state == SCTP_ACTIVE)
-			break;
+		if (trans->state != SCTP_UNCONFIRMED) {
+			trans_next = sctp_trans_elect_best(trans, trans_next);
+			/* Active is good enough for immediate return. */
+			if (trans_next->state == SCTP_ACTIVE)
+				break;
+		}
 		/* We've reached the end, time to update path. */
 		if (trans == asoc->peer.retran_path)
 			break;
 	}
 
-	asoc->peer.retran_path = trans_next;
+	if (trans_next)
+		asoc->peer.retran_path = trans_next;
 
 	pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
 		 __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
Signature · 1 line
2.53.0
author maintainer
#87 lore raw

PATCH 87/395 bpf: Bound ownership depth through local kptrs and graph roots

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit bfc888f04588f591851e95c974954cfca58e6c19 ]

Program-allocated objects can own other local objects through referenced kptrs. bpf_obj_free_fields() follows those pointers through __bpf_obj_drop_impl() synchronously, before the object storage is freed through RCU. A self-referential local kptr type therefore permits arbitrarily deep object chains, and dropping the head can exhaust the kernel stack. Long acyclic type chains have the same problem.

btf_check_and_fixup_fields() still assumes referenced kptrs only point to kernel types and checks ownership through list and rbtree roots only. Its existing rule is sufficient for graph-only cycles: the target of each graph edge must contain a node, so every type in a cycle has both a root and a node. The rule rejects such a type owning another root, breaking every cycle. It also limits graph-only chains to three types, or two if the first type contains a node, and conservatively rejects longer acyclic chains. The missing local-kptr edges, rather than a missed graph-only cycle, are the bug introduced by support for bpf_kptr_xchg() into local kptrs.

Replace that restriction with one bounded ownership walk covering graph roots and local referenced kptrs. Run it after all BTF records have been fixed up, reject cycles and paths deeper than eight record-bearing types, and cache each type's suffix depth while checking it against the remaining budget. This also permits the longer acyclic graph-only layouts rejected by the old rule; update their existing BTF tests accordingly.

Keep the bound independent of MAX_CALL_FRAMES because recursive destruction can run below a BPF call chain. A plain local pointee without special-field metadata adds only a final non-recursing drop. Non-owning kptrs and kernel-BTF kptrs do not recurse through local records and remain outside the walk. Include local percpu-kptr edges too, although allocation of percpu objects with special fields is currently forbidden, so that relaxing that restriction cannot bypass the ownership bound.

btf_check_and_fixup_fields() continues to initialize graph_root.value_rec, including for separately allocated map records. The ownership relationships belong to immutable program BTF and only need validation at BTF load time.

---
 kernel/bpf/btf.c                              | 134 +++++++++++-------
 .../selftests/bpf/prog_tests/linked_list.c    |   4 +-
 2 files changed, 88 insertions(+), 50 deletions(-)
kernel/bpf/btf.c +86 -48
index 86a4f76e79403..3509bbe39efaa 100644
@@ -4104,13 +4104,10 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec)
 {
 	int i;
 
-	/* There are three types that signify ownership of some other type:
-	 *  kptr_ref, bpf_list_head, bpf_rb_root.
-	 * kptr_ref only supports storing kernel types, which can't store
-	 * references to program allocated local types.
-	 *
-	 * Hence we only need to ensure that bpf_{list_head,rb_root} ownership
-	 * does not form cycles.
+	/*
+	 * Check fields which require the complete BTF and initialize runtime
+	 * metadata. Ownership relationships are validated after every record has
+	 * been fixed up.
 	 */
 	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & (BPF_GRAPH_ROOT | BPF_UPTR)))
 		return 0;
@@ -4141,51 +4138,88 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec)
 		if (!meta)
 			return -EFAULT;
 		rec->fields[i].graph_root.value_rec = meta->record;
+	}
+	return 0;
+}
 
-		/* We need to set value_rec for all root types, but no need
-		 * to check ownership cycle for a type unless it's also a
-		 * node type.
-		 */
-		if (!(rec->field_mask & BPF_GRAPH_NODE))
+static int btf_owned_type_idx(const struct btf *btf, struct btf_struct_metas *tab,
+			      const struct btf_field *field)
+{
+	struct btf_struct_meta *meta;
+	u32 btf_id;
+
+	if (field->type & BPF_GRAPH_ROOT) {
+		btf_id = field->graph_root.value_btf_id;
+	} else if (field->type == BPF_KPTR_REF || field->type == BPF_KPTR_PERCPU) {
+		if (btf_is_kernel(field->kptr.btf))
+			return -ENOENT;
+		btf_id = field->kptr.btf_id;
+	} else {
+		return -ENOENT;
+	}
+
+	meta = btf_find_struct_meta(btf, btf_id);
+	if (!meta)
+		return field->type & BPF_GRAPH_ROOT ? -EFAULT : -ENOENT;
+	return meta - tab->types;
+}
+
+/*
+ * Each ownership edge adds kernel frames through bpf_obj_free_fields() and
+ * __bpf_obj_drop_impl(). Keep the bound deliberately small because object
+ * destruction can itself run below a BPF call chain. A final pointee without
+ * special fields is not present in the struct metadata table and adds only a
+ * non-recursing drop.
+ */
+#define BTF_MAX_OWNERSHIP_DEPTH 8
+
+static int btf_ownership_depth(const struct btf *btf,
+			       struct btf_struct_metas *tab, u8 *depth,
+			       int idx, int depth_left)
+{
+	const struct btf_record *rec = tab->types[idx].record;
+	int i, ret, max_depth = 0;
+
+	if (!depth_left)
+		return -ELOOP;
+	if (depth[idx])
+		goto done;
+
+	for (i = 0; i < rec->cnt; i++) {
+		ret = btf_owned_type_idx(btf, tab, &rec->fields[i]);
+		if (ret == -ENOENT)
 			continue;
+		if (ret < 0)
+			return ret;
+		ret = btf_ownership_depth(btf, tab, depth, ret, depth_left - 1);
+		if (ret < 0)
+			return ret;
+		max_depth = max(max_depth, ret);
+	}
+	depth[idx] = max_depth + 1;
+done:
+	return depth[idx] > depth_left ? -ELOOP : depth[idx];
+}
 
-		/* We need to ensure ownership acyclicity among all types. The
-		 * proper way to do it would be to topologically sort all BTF
-		 * IDs based on the ownership edges, since there can be multiple
-		 * bpf_{list_head,rb_node} in a type. Instead, we use the
-		 * following resaoning:
-		 *
-		 * - A type can only be owned by another type in user BTF if it
-		 *   has a bpf_{list,rb}_node. Let's call these node types.
-		 * - A type can only _own_ another type in user BTF if it has a
-		 *   bpf_{list_head,rb_root}. Let's call these root types.
-		 *
-		 * We ensure that if a type is both a root and node, its
-		 * element types cannot be root types.
-		 *
-		 * To ensure acyclicity:
-		 *
-		 * When A is an root type but not a node, its ownership
-		 * chain can be:
-		 *	A -> B -> C
-		 * Where:
-		 * - A is an root, e.g. has bpf_rb_root.
-		 * - B is both a root and node, e.g. has bpf_rb_node and
-		 *   bpf_list_head.
-		 * - C is only an root, e.g. has bpf_list_node
-		 *
-		 * When A is both a root and node, some other type already
-		 * owns it in the BTF domain, hence it can not own
-		 * another root type through any of the ownership edges.
-		 *	A -> B
-		 * Where:
-		 * - A is both an root and node.
-		 * - B is only an node.
-		 */
-		if (meta->record->field_mask & BPF_GRAPH_ROOT)
-			return -ELOOP;
+static int btf_check_ownership_depth(const struct btf *btf,
+				     struct btf_struct_metas *tab)
+{
+	u8 *depth;
+	int i, ret = 0;
+
+	depth = kvcalloc(tab->cnt, sizeof(*depth), GFP_KERNEL | __GFP_NOWARN);
+	if (!depth)
+		return -ENOMEM;
+
+	for (i = 0; i < tab->cnt; i++) {
+		ret = btf_ownership_depth(btf, tab, depth, i,
+					  BTF_MAX_OWNERSHIP_DEPTH);
+		if (ret < 0)
+			break;
+		ret = 0;
 	}
-	return 0;
+	kvfree(depth);
+	return ret;
 }
 
 static void __btf_struct_show(const struct btf *btf, const struct btf_type *t,
@@ -5864,6 +5898,10 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
 			if (err < 0)
 				goto errout_meta;
 		}
+
+		err = btf_check_ownership_depth(btf, struct_meta_tab);
+		if (err < 0)
+			goto errout_meta;
 	}
 
 	err = finalize_log(&env->log, uattr, uattr_size);
tools/testing/selftests/bpf/prog_tests/linked_list.c +2 -2
index 14c5a7ef0e87d..6c3942e6cfaff 100644
@@ -712,7 +712,7 @@ static void test_btf(void)
 			break;
 
 		err = btf__load_into_kernel(btf);
-		ASSERT_EQ(err, -ELOOP, "check btf");
+		ASSERT_EQ(err, 0, "check btf");
 		btf__free(btf);
 		break;
 	}
@@ -771,7 +771,7 @@ static void test_btf(void)
 			break;
 
 		err = btf__load_into_kernel(btf);
-		ASSERT_EQ(err, -ELOOP, "check btf");
+		ASSERT_EQ(err, 0, "check btf");
 		btf__free(btf);
 		break;
 	}
Signature · 1 line
2.53.0
author maintainer
#88 lore raw

PATCH 88/395 net: usb: catc: bound the RX packet length in catc_rx_done()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aamir Ahmed <[email protected]>

[ Upstream commit 9d565b6b72fe3f41fd43636e143072848105189f ]

catc_rx_done() walks a multi-packet URB, reading a two-byte length from each packet header. Its bound, pkt_len > urb->actual_length, ignores the header offset and compares against the whole transfer rather than the bytes left from pkt_start, so a crafted packet header makes skb_copy_to_linear_data() read past the buffer.

A length below ETH_HLEN is also accepted, including zero, and eth_type_trans() then reads a MAC header from the uninitialised tailroom of a shorter skb. The is_f5u011 branch takes its length straight from the transfer, so a zero-length URB reaches the same path.

Track the bytes remaining from the current packet, and reject a header that does not fit, a length past what is left, and a length below an Ethernet header.

A transfer shorter than an Ethernet header, including a zero-length one, previously became a runt skb passed to netif_rx() and counted as received; it is now counted in rx_length_errors and ends the walk.

---
 drivers/net/usb/catc.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/net/usb/catc.c +12 -3
index 3c824340ffb06..a2fce08432055 100644
@@ -239,17 +239,26 @@ static void catc_rx_done(struct urb *urb)
 	}
 
 	do {
-		if(!catc->is_f5u011) {
-			pkt_len = le16_to_cpup((__le16*)pkt_start);
-			if (pkt_len > urb->actual_length) {
+		int remaining = urb->actual_length -
+				(pkt_start - (u8 *)urb->transfer_buffer);
+
+		if (!catc->is_f5u011) {
+			if (remaining < pkt_offset) {
 				catc->netdev->stats.rx_length_errors++;
 				catc->netdev->stats.rx_errors++;
 				break;
 			}
+			pkt_len = le16_to_cpup((__le16 *)pkt_start);
 		} else {
 			pkt_len = urb->actual_length;
 		}
 
+		if (pkt_len < ETH_HLEN || pkt_len + pkt_offset > remaining) {
+			catc->netdev->stats.rx_length_errors++;
+			catc->netdev->stats.rx_errors++;
+			break;
+		}
+
 		if (!(skb = dev_alloc_skb(pkt_len)))
 			return;
 
Signature · 1 line
2.53.0
author maintainer
#89 lore raw

PATCH 89/395 bpf: Check params size before reading reserved fields

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yuqi Xu <[email protected]>

[ Upstream commit a11212910cf09b2fe8db9afa41ef60c4f81879c5 ]

bpf_crypto_ctx_create() is a kfunc whose second argument is declared with the __sz annotation, so the verifier only guarantees that params__sz bytes of params are valid. The function nevertheless reads params->reserved[0] and params->reserved[1] (offsets 14 and 15) before comparing params__sz against the size of struct bpf_crypto_params, so a BPF program can pass a shorter buffer and have the kernel read past the region that was validated for it.

Move the size check in front of the reserved field reads.

---
 kernel/bpf/crypto.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/bpf/crypto.c +3 -2
index 1d024fe7248ac..3837d4dcf48d5 100644
@@ -149,8 +149,9 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
 	const struct bpf_crypto_type *type;
 	struct bpf_crypto_ctx *ctx;
 
-	if (!params || params->reserved[0] || params->reserved[1] ||
-	    params__sz != sizeof(struct bpf_crypto_params)) {
+	if (!params ||
+	    params__sz != sizeof(struct bpf_crypto_params) ||
+	    params->reserved[0] || params->reserved[1]) {
 		*err = -EINVAL;
 		return NULL;
 	}
Signature · 1 line
2.53.0
author maintainer
#90 lore raw

PATCH 90/395 net/sched: sch_hfsc: bound the classify inner-filter walk with a drift budget

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit 8a60ade2277e1f0e0d0578d565354e52292fa46d ]

hfsc_classify() applies the "filter may only point downwards" level check only when the filter result carries no bound class. A filter created with a flowid gets res.class set once at bind time, so the check never runs for it during classification. hfsc_adjust_levels() can later raise a class's level without revalidating existing bindings, leaving two binds that were each legal at bind time pointing at each other; the classify walk then bounces between two interior classes forever with the qdisc lock held and BH disabled — a soft lockup from a single packet. The stuck walk trips the watchdog:

  watchdog: BUG: soft lockup - CPU#3 stuck for 13s! [ping:444]
  RIP: 0010:u32_classify+0x542/0x17f0
  ...
  tcf_classify+0x66/0xa0
  hfsc_enqueue+0x166/0xdf0

Bound the traversal with a budget of non-descending hops, the only way a configured walk can move without descending the class tree once levels drift after bind time. The budget is cumulative over the whole walk and is deliberately not reset on a descending hop: a chain that alternates a descent with a lateral hop would return the budget every lap and never trip. Descending hops never decrement it, so legitimately deep trees are unaffected and a terminating lateral chain still classifies normally. Drop the packet with a rate-limited warning once the budget is exhausted, mirroring the merged HTB fix.

This is a follow-up to commit 729c4896ab82 ("net/sched: sch_htb: limit htb_classify inner-class filter hops"), which bounded the same classify loop on the HTB side but left the HFSC walk unbounded.

Conditions to recreate the bug:
- CONFIG_NET_SCHED, CONFIG_NET_SCH_HFSC, CONFIG_NET_CLS_U32, CONFIG_LOCKUP_DETECTOR.
- Build a cycle with two legal-at-bind-time flowid binds and a level
drift: class X 1:1 (child of root) with leaf child 1:10; class Y 1:2 (sibling of X) with children 1:20 and 1:200; root u32 filter flowid 1:1; filter on X flowid 1:2 (legal when Y is a leaf); after Y's level rises to 2, filter on Y flowid 1:1 (legal then). Send one packet (ping on the device). Unfixed kernel: classify spins with the qdisc lock held; with softlockup_panic=1 it panics.
- Reachable from unprivileged user via unshare -Urn (CAP_NET_ADMIN).

---
 net/sched/sch_hfsc.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
net/sched/sch_hfsc.c +22 -0
index 601f99dd989ae..df3501dfe01a8 100644
@@ -386,6 +386,15 @@ cftree_update(struct hfsc_class *cl)
 #define	SM_MASK		((1ULL << SM_SHIFT) - 1)
 #define	ISM_MASK	((1ULL << ISM_SHIFT) - 1)
 
+/*
+ * Cap on the non-descending hops a classify walk may take before its
+ * filter chain is treated as misconfigured. A flowid binding that was
+ * legal at bind time can become lateral once hfsc_adjust_levels()
+ * raises a class level; a few such hops are legitimate, an unbounded
+ * run means the chain cycles.
+ */
+#define	HFSC_CLASSIFY_MAX_DRIFT	8
+
 static inline u64
 seg_x2y(u64 x, u64 sm)
 {
@@ -1133,6 +1142,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 	struct hfsc_class *head, *cl;
 	struct tcf_result res;
 	struct tcf_proto *tcf;
+	unsigned int drift;
 	int result;
 
 	if (TC_H_MAJ(skb->priority ^ sch->handle) == 0 &&
@@ -1142,6 +1152,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 
 	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
 	head = &q->root;
+	drift = HFSC_CLASSIFY_MAX_DRIFT;
 	tcf = rcu_dereference_bh(q->root.filter_list);
 	while (tcf && (result = tcf_classify(skb, NULL, tcf, &res, false)) >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
@@ -1167,6 +1178,17 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 		if (cl->level == 0)
 			return cl; /* hit leaf class */
 
+		/*
+		 * flowid binds skip the level check above (res.class is set
+		 * at bind time and levels drift after), so a walk can follow
+		 * lateral hops without descending; a bounded number of them
+		 * is legal, more means the chain cycles.
+		 */
+		if (cl->level >= head->level && drift-- == 0) {
+			pr_warn_ratelimited("hfsc: classify hop budget exhausted, dropping packet\n");
+			return NULL;
+		}
+
 		/* apply inner filter chain */
 		tcf = rcu_dereference_bh(cl->filter_list);
 		head = cl;
Signature · 1 line
2.53.0
author maintainer
#91 lore raw

PATCH 91/395 drm/virtio: fix object leak when drm_gem_handle_create() fails

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Junrui Luo <[email protected]>

[ Upstream commit 36570ef2244cc4d7563b1f0157bc0f032498638c ]

virtio_gpu_gem_create() owns the reference taken by virtio_gpu_object_create(). On the drm_gem_handle_create() error path it calls drm_gem_object_release() instead of dropping that reference.

drm_gem_object_release() is the inverse of drm_gem_object_init() and does not touch the reference count or call obj->funcs->free(), so it is only correct as the last step of a destructor, as in virtio_gpu_cleanup_object(). Using it here leaves the bo at refcount 1 with no remaining reference, so virtio_gpu_free_object() never runs and the shmem pages, sg table and virtio_gpu_object are leaked. Since virtio_gpu_object_create() has already set bo->created, VIRTIO_GPU_CMD_RESOURCE_UNREF is not queued either, leaking the host-side resource and the resource id.

drm_gem_handle_create_tail() drops the handle reference on all of its internal error paths, so the caller only has to drop its own. Use drm_gem_object_put(), matching the success path below.

Fixes dc5698e80cf7 ("Add virtio gpu driver.")
Assisted-by Claude:claude-opus-5
---
 drivers/gpu/drm/virtio/virtgpu_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_gem.c +1 -1
index 7174086119c51..aea5e1b60e7f3 100644
@@ -45,7 +45,7 @@ static int virtio_gpu_gem_create(struct drm_file *file,
 
 	ret = drm_gem_handle_create(file, &obj->base.base, &handle);
 	if (ret) {
-		drm_gem_object_release(&obj->base.base);
+		drm_gem_object_put(&obj->base.base);
 		return ret;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#92 lore raw

PATCH 92/395 drm/virtio: fix object leak in virtio_gpu_resource_create_ioctl()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Junrui Luo <[email protected]>

[ Upstream commit 477bc3068fc3777b9d8ffd79e265b0dfdf2d3a6b ]

virtio_gpu_resource_create_ioctl() calls drm_gem_object_release() on the drm_gem_handle_create() error path instead of dropping the reference it owns, so obj->funcs->free() never runs and the virtio_gpu_object, its pages and sg table, the resource id and the host-side resource are leaked.

Use drm_gem_object_put() instead.

Fixes 62fb7a5e1096 ("virtio-gpu: add 3d/virgl support")
Assisted-by Claude:claude-opus-5
---
 drivers/gpu/drm/virtio/virtgpu_ioctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_ioctl.c +1 -1
index c33c057365f85..2d5cd7fb70e22 100644
@@ -180,7 +180,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
 
 	ret = drm_gem_handle_create(file, obj, &handle);
 	if (ret) {
-		drm_gem_object_release(obj);
+		drm_gem_object_put(obj);
 		return ret;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#93 lore raw

PATCH 93/395 drm/virtio: fix object leaks in virtio_gpu_resource_create_blob_ioctl()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Junrui Luo <[email protected]>

[ Upstream commit 24b6d5c7641412c9ebef0d4c8b888d49a0e6b880 ]

virtio_gpu_resource_create_blob_ioctl() calls drm_gem_object_release() on both the virtio_gpu_resource_assign_uuid() and drm_gem_handle_create() error paths instead of dropping the reference it owns, so obj->funcs->free() never runs and the virtio_gpu_object, the resource id and the host-side resource are leaked.

Use drm_gem_object_put() instead.

Fixes 897b4d1acaf5 ("drm/virtio: implement blob resources: resource create blob ioctl")
Assisted-by Claude:claude-opus-5
---
 drivers/gpu/drm/virtio/virtgpu_ioctl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/virtio/virtgpu_ioctl.c +2 -2
index 2d5cd7fb70e22..bb3f8ebcf4dc1 100644
@@ -546,14 +546,14 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
 	if (params.blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) {
 		ret = virtio_gpu_resource_assign_uuid(vgdev, bo);
 		if (ret) {
-			drm_gem_object_release(obj);
+			drm_gem_object_put(obj);
 			return ret;
 		}
 	}
 
 	ret = drm_gem_handle_create(file, obj, &handle);
 	if (ret) {
-		drm_gem_object_release(obj);
+		drm_gem_object_put(obj);
 		return ret;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#94 lore raw

PATCH 94/395 drm/virtio: release the GEM object on virtio_gpu_vram_create() errors

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Junrui Luo <[email protected]>

[ Upstream commit 036d28db1818af2f9d80db771f5405da84d7732d ]

virtio_gpu_vram_create() frees the object with a bare kfree(vram) on both error paths after drm_gem_private_object_init() has run, and on the second one after drm_gem_create_mmap_offset() has linked obj->vma_node into the device's VMA offset manager. The freed object stays in that interval tree, so a later lookup or insertion walks freed memory, and the dma_resv and gpuva lock are never destroyed.

Call drm_gem_object_release() before kfree() on both paths.

Fixes 16845c5d5409 ("drm/virtio: implement blob resources: implement vram object")
Assisted-by Claude:claude-opus-5
---
 drivers/gpu/drm/virtio/virtgpu_vram.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/gpu/drm/virtio/virtgpu_vram.c +9 -8
index 5ad3b7c6f73c3..f955779d5ea0e 100644
@@ -205,16 +205,12 @@ int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev,
 
 	/* Create fake offset */
 	ret = drm_gem_create_mmap_offset(obj);
-	if (ret) {
-		kfree(vram);
-		return ret;
-	}
+	if (ret)
+		goto err_release_obj;
 
 	ret = virtio_gpu_resource_id_get(vgdev, &vram->base.hw_res_handle);
-	if (ret) {
-		kfree(vram);
-		return ret;
-	}
+	if (ret)
+		goto err_release_obj;
 
 	virtio_gpu_cmd_resource_create_blob(vgdev, &vram->base, params, NULL,
 					    0);
@@ -228,4 +224,9 @@ int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev,
 
 	*bo_ptr = &vram->base;
 	return 0;
+
+err_release_obj:
+	drm_gem_object_release(obj);
+	kfree(vram);
+	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#95 lore raw

PATCH 95/395 Revert "drm/virtio: Allow importing prime buffers when 3D is enabled"

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dmitry Osipenko <[email protected]>

[ Upstream commit 1e3b08de63274d0b009e99ef51cd6a9c0c6bf08c ]

Guest userspace may import udmabuf to vrend. Vrend doesn't support guest blobs, and thus, further 3d operations with the imported blob are failing. Typical scenario of the problem shown with mouse cursor RGBA image imported into virtio-gpu, which previously was rejected by virtio-gpu driver. Revert enabling guest blobs importing into vrend to fix the regression.

---
 drivers/gpu/drm/virtio/virtgpu_prime.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_prime.c +1 -1
index 2fedd5d3bd62c..ce49282198cbf 100644
@@ -312,7 +312,7 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
 		}
 	}
 
-	if (!vgdev->has_resource_blob)
+	if (!vgdev->has_resource_blob || vgdev->has_virgl_3d)
 		return drm_gem_prime_import(dev, buf);
 
 	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
Signature · 1 line
2.53.0
author maintainer
#96 lore raw

PATCH 96/395 drm/virtio: sync shmem backing on guest-bound transfers

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Benjamin Leggett <[email protected]>

[ Upstream commit 598c1c3e895590f845e04455d5580ea28ffde666 ]

virtio_gpu_cmd_transfer_to_host_{2d,3d}() sync the shmem backing for the device before the transfer, but nothing syncs for the CPU when a transfer runs the other way. That breaks two ways. Where the DMA layer bounces, the device writes into the bounce buffer while the guest keeps reading the original pages. Where DMA is not coherent, the device writes memory while the CPU keeps stale cache lines, because nothing reaches arch_sync_dma_for_cpu(). Either way DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST hands back stale data.

Sashiko originally found this in
https://lore.kernel.org/dri-devel/[email protected]
but the suggestion there to fix this with dma_sync_sgtable_for_cpu() isn't a sufficient fix, for two reasons.

- The transfer is asynchronous. virtio_gpu_cmd_transfer_from_host_3d() only queues the command, so a sync there would run before the device had written anything. It belongs on completion, and ahead of any fence signalling. A waiter woken by the fence would otherwise race the sync and read the backing pages regardless. It needs its own pass over the reclaim list rather than a step inside the existing one, because virtio_gpu_fence_event_process() also signals every earlier fence in the same context, so any entry in that loop may signal an earlier entry's fence.

- The transfer is also partial, carrying an offset, a level and a box. Where the mapping bounces, a sync for the CPU copies the whole mapping back, so unless the mapping is primed first the regions the device did not write come back holding whatever the bounce buffer contained, discarding data the guest owned.

So the fix: Prime the mapping before queueing, tag the vbuffer, and sync for the CPU on completion before the fence is signalled.

A second transfer must not snapshot the mapping while an earlier one is still in flight, or the snapshot would predate whatever the CPU wrote once the earlier fence signalled and the later sync would discard it.

To mitigate this, wait for outstanding fences under the reservation before priming.

Neither sync copies anything unless the mapping genuinely bounces:
swiotlb_sync_single_for_cpu() and its Xen counterpart look the address up in the bounce pool and return early when it is absent. On a platform with non-coherent DMA they still perform the necessary cache maintenance.

The range cannot be narrowed to the box, since for a non-blob resource virtio_gpu_transfer_from_host_ioctl() rejects a caller-supplied stride and layer_stride, leaving the layout to the host and the guest with no way to work out which bytes the device writes. A host3d guest blob does carry both, so its extent could be bounded, but the sync is left whole there too rather than special-cased: priming makes the untouched regions round-trip unchanged either way.

Behaviour changes worth noting:

- TRANSFER_FROM_HOST can now block, where before it returned as soon as the command was queued. Repeated readbacks of one resource serialise, and a readback can wait behind an earlier queued command that touched it, since virtio_gpu_array_add_fence() tags uploads, execbufs and plane flushes alike with DMA_RESV_USAGE_WRITE. -ERESTARTSYS was already possible here via dma_resv_lock_interruptible().

- A CPU write racing an in-flight transfer to the same resource is now lost, where before it survived and the transfer was lost instead. Priming captures the pages as of queueing, so a write landing before completion is overwritten by the sync.

- TRANSFER_TO_HOST can also block now, but only while a guest-bound transfer on the same resource is outstanding, which happens only for callers that issue both without waiting.

- Where a batch of completions contains a guest-bound transfer, the sync pass delays fence signalling for the whole batch. Only bounced pages are copied and the swiotlb pool bounds it. A batch with no such transfer is unaffected.

Tested under QEMU on x86 with swiotlb=force and virtio-vga-gl iommu_platform=on, which forces both preconditions required to hit the original bug.

---
 drivers/gpu/drm/virtio/virtgpu_drv.h   |  5 +++
 drivers/gpu/drm/virtio/virtgpu_ioctl.c | 43 ++++++++++++++++++++++++
 drivers/gpu/drm/virtio/virtgpu_vq.c    | 46 ++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
drivers/gpu/drm/virtio/virtgpu_drv.h +5 -0
index 00c609c3b53a8..8575c7787fc36 100644
@@ -113,6 +113,8 @@ struct virtio_gpu_object {
 	bool dumb;
 	bool created;
 	bool attached;
+	/* a guest-bound transfer is queued and its mapping not yet synced */
+	bool from_host_pending;
 	bool host3d_blob, guest_blob;
 	uint32_t blob_mem, blob_flags;
 
@@ -191,6 +193,9 @@ struct virtio_gpu_vbuffer {
 	struct list_head list;
 
 	uint32_t seqno;
+
+	/* guest-bound transfer whose shmem backing needs a CPU sync */
+	bool sync_for_cpu;
 };
 
 struct virtio_gpu_output {
drivers/gpu/drm/virtio/virtgpu_ioctl.c +43 -0

55 lines not on this page · raw message

drivers/gpu/drm/virtio/virtgpu_vq.c +46 -0

64 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#97 lore raw

PATCH 97/395 drm/bridge: samsung-dsim: fix TE GPIO lifetime for host attach

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Li Youhong <[email protected]>

[ Upstream commit ada667890773e033d2f40dc94176e3beb930b516 ]

When the Exynos DSI driver was generalized into samsung-dsim, the TE GPIO acquisition was switched from gpiod_get_optional() to devm_gpiod_get_optional() while keeping the matching gpiod_put() calls. That combination is wrong for a managed descriptor.

However, dropping the puts and keeping the managed get is also wrong:
samsung_dsim_register_te_irq() runs from the DSI host attach callback, and host detach/reattach can happen without destroying the device that owns the managed action. A second attach would then request the GPIO again without having released it.

Switch back to a non-managed gpiod_get_optional() and keep the explicit gpiod_put() on the request_irq() error path and in samsung_dsim_unregister_te_irq().

Fixes e7447128ca4a ("drm: bridge: Generalize Exynos-DSI driver into a Samsung DSIM bridge")
[Luca: remove unnecessary comment]
---
 drivers/gpu/drm/bridge/samsung-dsim.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/bridge/samsung-dsim.c +1 -1
index ad8c6aa49d48a..272e6255c7322 100644
@@ -1862,7 +1862,7 @@ static int samsung_dsim_register_te_irq(struct samsung_dsim *dsi, struct device
 	int te_gpio_irq;
 	int ret;
 
-	dsi->te_gpio = devm_gpiod_get_optional(dev, "te", GPIOD_IN);
+	dsi->te_gpio = gpiod_get_optional(dev, "te", GPIOD_IN);
 	if (!dsi->te_gpio)
 		return 0;
 	else if (IS_ERR(dsi->te_gpio))
Signature · 1 line
2.53.0
author maintainer
#98 lore raw

PATCH 98/395 ovpn: preserve IPv6 scope id for netlink peer endpoints

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 7a6d08ee0f0e30023d18779bb314db8fd9a3b6d4 ]

ovpn accepts OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID and reports bind->remote.in6.sin6_scope_id in peer dumps, but the netlink endpoint parser never copied the attribute into the sockaddr_in6 used to create or update the peer bind.

As a result, an IPv6 link-local remote endpoint configured through netlink loses its interface scope, unlike on the peer float path where ipv6_iface_scope_id populates the field. The UDPv6 output path then builds a flow with flowi6_oif set to zero and route lookup can fail or select the wrong interface.

Copy the scope id when parsing non-v4-mapped IPv6 remote endpoints. The existing precheck already rejects the scope-id attribute for IPv4 and v4-mapped IPv6 remotes.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/net/ovpn/netlink.c +6 -0
index 0051166c59c75..deddf8e1e81ef 100644
@@ -100,6 +100,8 @@ static bool ovpn_nl_attr_sockaddr_remote(struct nlattr **attrs,
 	struct sockaddr_in6 *sin6;
 	struct sockaddr_in *sin;
 	struct in6_addr *in6;
+	struct nlattr *scope;
+	u32 scope_id = 0;
 	__be16 port = 0;
 	__be32 *in;
 
@@ -114,6 +116,9 @@ static bool ovpn_nl_attr_sockaddr_remote(struct nlattr **attrs,
 	} else if (attrs[OVPN_A_PEER_REMOTE_IPV6]) {
 		ss->ss_family = AF_INET6;
 		in6 = nla_data(attrs[OVPN_A_PEER_REMOTE_IPV6]);
+		scope = attrs[OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID];
+		if (scope)
+			scope_id = nla_get_u32(scope);
 	} else {
 		return false;
 	}
@@ -126,6 +131,7 @@ static bool ovpn_nl_attr_sockaddr_remote(struct nlattr **attrs,
 		if (!ipv6_addr_v4mapped(in6)) {
 			sin6 = (struct sockaddr_in6 *)ss;
 			sin6->sin6_port = port;
+			sin6->sin6_scope_id = scope_id;
 			memcpy(&sin6->sin6_addr, in6, sizeof(*in6));
 			break;
 		}
Signature · 1 line
2.53.0
author maintainer
#99 lore raw

PATCH 99/395 ovpn: skip UDP source validation for unspecified addresses

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 77393b4d72dfeb764b2af2b848acc659f6fcfd0a ]

ovpn validates the cached local UDP source address before reusing or refreshing a peer dst cache. This is only meaningful when a concrete source address is selected.

For IPv6, calling ipv6_chk_addr with :: checks whether the unspecified address itself is configured on the host. A peer may legitimately have bind->local.ipv6 set to :: when no local endpoint was configured or after a stale learned address was cleared. In that case the source should be left unspecified and selected by ip6_dst_lookup_flow().

For IPv4, inet_confirm_addr(..., local = 0, ...) asks for local address autoselection rather than validating a chosen source. Skip the precheck there as well and let ip_route_output_flow select or reject the source.

Only validate non-zero/non-any source addresses.

Fixes 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
---
 drivers/net/ovpn/udp.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ovpn/udp.c +4 -3
index 367563d84472f..a8185f39a8def 100644
@@ -162,8 +162,8 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 	if (rt)
 		goto transmit;
 
-	if (unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0, fl.saddr,
-					RT_SCOPE_HOST))) {
+	if (fl.saddr && unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0,
+						    fl.saddr, RT_SCOPE_HOST))) {
 		/* we may end up here when the cached address is not usable
 		 * anymore. In this case we reset address/cache and perform a
 		 * new look up
@@ -239,7 +239,8 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 	if (dst)
 		goto transmit;
 
-	if (unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) {
+	if (!ipv6_addr_any(&fl.saddr) &&
+	    unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) {
 		/* we may end up here when the cached address is not usable
 		 * anymore. In this case we reset address/cache and perform a
 		 * new look up
Signature · 1 line
2.53.0
author maintainer
#100 lore raw

PATCH 100/395 ovpn: track UDP socket route key for peer dst cache

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 7c66b7a4ae80a9309e6dc1d24b7b6b897e6348eb ]

ovpn stores the route used to transmit UDP packets in a per-peer dst cache. A cached dst is only valid for the route lookup inputs used when it was resolved.

Some of those inputs are mutable while userspace still owns the UDP socket. In particular, changes to the socket mark or UDP source port do not invalidate ovpn's peer dst cache, so ovpn can keep using a route selected with an old socket route key.

Replace the cached mark with a route key containing the socket-owned lookup inputs currently used by ovpn, and reset the peer dst cache when the key changes. Before storing a newly looked-up dst, recheck the route key under the peer lock so a dst resolved for stale socket state is not published.

Fixes 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
---
 drivers/net/ovpn/peer.c |  1 +
 drivers/net/ovpn/peer.h | 19 ++++++++-
 drivers/net/ovpn/udp.c  | 90 +++++++++++++++++++++++++++++++++++------
 3 files changed, 95 insertions(+), 15 deletions(-)
drivers/net/ovpn/peer.c +1 -0
index 6b9f5f12fc5a8..58b0248ae3a7c 100644
@@ -109,6 +109,7 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id)
 	RCU_INIT_POINTER(peer->bind, NULL);
 	ovpn_crypto_state_init(&peer->crypto);
 	spin_lock_init(&peer->lock);
+	seqcount_spinlock_init(&peer->route_key_seq, &peer->lock);
 	kref_init(&peer->refcount);
 	ovpn_peer_stats_init(&peer->vpn_stats);
 	ovpn_peer_stats_init(&peer->link_stats);
drivers/net/ovpn/peer.h +17 -2
index 9a05a278e1cd0..693175712f7af 100644
@@ -10,6 +10,7 @@
 #ifndef _NET_OVPN_OVPNPEER_H_
 #define _NET_OVPN_OVPNPEER_H_
 
+#include <linux/seqlock.h>
 #include <net/dst_cache.h>
 #include <net/strparser.h>
 
@@ -17,6 +18,16 @@
 #include "socket.h"
 #include "stats.h"
 
+/**
+ * struct ovpn_route_key - route key used for the peer dst cache
+ * @mark: fwmark used for route lookup
+ * @sport: UDP source port used for route lookup
+ */
+struct ovpn_route_key {
+	u32 mark;
+	__be16 sport;
+};
+
 /**
  * struct ovpn_peer - the main remote peer object
  * @ovpn: main openvpn instance this peer belongs to
@@ -44,6 +55,8 @@
  * @tcp.sk_cb.ops: pointer to the original prot_ops object (TCP only)
  * @crypto: the crypto configuration (ciphers, keys, etc..)
  * @dst_cache: cache for dst_entry used to send to peer
+ * @route_key: route key matching the current dst cache contents
+ * @route_key_seq: seqcount protecting lockless route_key reads
  * @bind: remote peer binding
  * @keepalive_interval: seconds after which a new keepalive should be sent
  * @keepalive_xmit_exp: future timestamp when next keepalive should be sent
@@ -54,7 +67,7 @@
  * @vpn_stats: per-peer in-VPN TX/RX stats
  * @link_stats: per-peer link/transport TX/RX stats
  * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..)
- * @lock: protects binding to peer (bind) and keepalive* fields
+ * @lock: protects binding to peer (bind), route_key and keepalive* fields
  * @refcount: reference counter
  * @rcu: used to free peer in an RCU safe way
  * @release_entry: entry for the socket release list
@@ -97,6 +110,8 @@ struct ovpn_peer {
 	} tcp;
 	struct ovpn_crypto_state crypto;
 	struct dst_cache dst_cache;
+	struct ovpn_route_key route_key;
+	seqcount_spinlock_t route_key_seq;
 	struct ovpn_bind __rcu *bind;
 	unsigned long keepalive_interval;
 	unsigned long keepalive_xmit_exp;
@@ -107,7 +122,7 @@ struct ovpn_peer {
 	struct ovpn_peer_stats vpn_stats;
 	struct ovpn_peer_stats link_stats;
 	enum ovpn_del_peer_reason delete_reason;
-	spinlock_t lock; /* protects bind  and keepalive* */
+	spinlock_t lock; /* protects bind, route_key and keepalive* */
 	struct kref refcount;
 	struct rcu_head rcu;
 	struct llist_node release_entry;
drivers/net/ovpn/udp.c +77 -13

179 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#101 lore raw

PATCH 101/395 ovpn: validate peer state before caching UDP dst

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit fa603710bdb9aea33c0d9cc2c05ed24d84f58753 ]

UDP route lookup runs without peer->lock while the bind is protected by RCU. The route key is snapshotted separately. Either can change while the lookup is in progress.

The TX path currently checks only the route key before publishing the looked-up dst. If the bind changes but the route key does not, a dst resolved from the old endpoint can be installed in the cache after the bind replacement.

Compare both the bind pointer and the route key under peer->lock before updating the cache. The RCU read-side critical section keeps the old bind alive throughout the lookup, so pointer identity is sufficient to detect a replacement.

Fixes f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
---
 drivers/net/ovpn/udp.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)
drivers/net/ovpn/udp.c +31 -2
index 8be5f64e0a1fa..6ca482144dc4f 100644
@@ -174,6 +174,35 @@ static void ovpn_dst_cache_check_key(struct ovpn_peer *peer,
 	spin_unlock_bh(&peer->lock);
 }
 
+/**
+ * ovpn_dst_cache_current - check whether a route lookup matches peer state
+ * @peer: the peer owning the bind and dst cache
+ * @bind: the RCU bind used for the route lookup
+ * @key: the route key used for the route lookup
+ *
+ * Check that @bind is still the current peer bind and that @key still matches
+ * the peer route key. The caller must hold @peer->lock. The TX path keeps
+ * @bind inside an RCU read-side critical section, so pointer identity is enough
+ * to detect whether the bind was replaced while the route lookup was running.
+ *
+ * Return: true if the lookup result still matches the current peer state and
+ * may update the dst cache.
+ */
+static bool ovpn_dst_cache_current(const struct ovpn_peer *peer,
+				   const struct ovpn_bind *bind,
+				   const struct ovpn_route_key *key)
+{
+	const struct ovpn_bind *curr_bind;
+
+	lockdep_assert_held(&peer->lock);
+
+	curr_bind = rcu_dereference_protected(peer->bind,
+					      lockdep_is_held(&peer->lock));
+
+	return curr_bind == bind &&
+	       ovpn_route_key_equal(key, &peer->route_key);
+}
+
 /**
  * ovpn_udp4_output - send IPv4 packet over udp socket
  * @peer: the destination peer
@@ -241,7 +270,7 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 
 	/* avoid storing a stale cache */
 	spin_lock_bh(&peer->lock);
-	if (likely(ovpn_route_key_equal(key, &peer->route_key)))
+	if (likely(ovpn_dst_cache_current(peer, bind, key)))
 		dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
 	spin_unlock_bh(&peer->lock);
 
@@ -314,7 +343,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 
 	/* avoid storing a stale cache */
 	spin_lock_bh(&peer->lock);
-	if (likely(ovpn_route_key_equal(key, &peer->route_key)))
+	if (likely(ovpn_dst_cache_current(peer, bind, key)))
 		dst_cache_set_ip6(cache, dst, &fl.saddr);
 	spin_unlock_bh(&peer->lock);
 
Signature · 1 line
2.53.0
author maintainer
#102 lore raw

PATCH 102/395 ovpn: replace bind when learning local endpoint

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit aea934a221ec6a867221e5b765f65f1857befd53 ]

struct ovpn_bind is published through peer->bind with RCU, but local endpoint learning updates bind->local in place under peer->lock. UDP TX reads the field without that lock. In particular, a concurrent IPv6 update can therefore result in a torn address read.

Use ovpn_peer_reset_sockaddr to publish a replacement bind when learning a new local endpoint, just as a remote endpoint change does. Preserve the current remote address and reset the dst cache only after the new bind has been published successfully.

Track remote endpoint changes separately so that float notification and transport-address rehashing remain limited to actual peer floats.

Fixes f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
---
 drivers/net/ovpn/peer.c | 43 ++++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 20 deletions(-)
drivers/net/ovpn/peer.c +23 -20
index 58b0248ae3a7c..6f7c55ff91fbc 100644
@@ -196,13 +196,12 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
  */
 void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 {
+	const void *local_ip = NULL;
 	struct sockaddr_storage ss;
 	struct sockaddr_in6 *sa6;
-	bool reset_cache = false;
 	struct sockaddr_in *sa;
 	struct ovpn_bind *bind;
-	const void *local_ip;
-	size_t salen = 0;
+	bool floated = false;
 
 	spin_lock_bh(&peer->lock);
 	bind = rcu_dereference_protected(peer->bind,
@@ -229,8 +228,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 				.sin_addr.s_addr = ip_hdr(skb)->saddr,
 				.sin_port = udp_hdr(skb)->source,
 			};
-			salen = sizeof(*sa);
-			reset_cache = true;
+			floated = true;
 			break;
 		}
 
@@ -242,10 +240,12 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 					    netdev_name(peer->ovpn->dev),
 					    peer->id, &bind->local.ipv4.s_addr,
 					    &ip_hdr(skb)->daddr);
-			bind->local.ipv4.s_addr = ip_hdr(skb)->daddr;
-			reset_cache = true;
+			local_ip = &ip_hdr(skb)->daddr;
+			memcpy(&ss, &bind->remote, sizeof(struct sockaddr_in));
+			break;
 		}
-		break;
+		/* nothing changed */
+		goto unlock;
 	case htons(ETH_P_IPV6):
 		/* float check */
 		if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) {
@@ -267,8 +267,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 					ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
 							    skb->skb_iif),
 			};
-			salen = sizeof(*sa6);
-			reset_cache = true;
+			floated = true;
 			break;
 		}
 
@@ -281,26 +280,30 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 					    netdev_name(peer->ovpn->dev),
 					    peer->id, &bind->local.ipv6,
 					    &ipv6_hdr(skb)->daddr);
-			bind->local.ipv6 = ipv6_hdr(skb)->daddr;
-			reset_cache = true;
+			local_ip = &ipv6_hdr(skb)->daddr;
+			memcpy(&ss, &bind->remote, sizeof(struct sockaddr_in6));
+			break;
 		}
-		break;
+		/* nothing changed */
+		goto unlock;
 	default:
 		goto unlock;
 	}
 
-	if (unlikely(reset_cache))
-		dst_cache_reset(&peer->dst_cache);
-
-	/* if the peer did not float, we can bail out now */
-	if (likely(!salen))
-		goto unlock;
-
 	if (unlikely(ovpn_peer_reset_sockaddr(peer,
 					      (struct sockaddr_storage *)&ss,
 					      local_ip) < 0))
 		goto unlock;
 
+	/* reset the cache only after a successful bind update to avoid useless
+	 * cache misses on concurrent TX
+	 */
+	dst_cache_reset(&peer->dst_cache);
+
+	/* if only the local address changed, bail out now */
+	if (!floated)
+		goto unlock;
+
 	net_dbg_ratelimited("%s: peer %d floated to %pIScp",
 			    netdev_name(peer->ovpn->dev), peer->id, &ss);
 
Signature · 1 line
2.53.0
author maintainer
#103 lore raw

PATCH 103/395 ovpn: replace bind when clearing stale local source

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 7d8104988f423572df1f3347ce578037b1043f34 ]

The UDP output fallback clears bind->local in place when the remembered source address is no longer usable. The bind is RCU-published and read locklessly by concurrent TX, so an IPv6 reader can observe a torn address.

Retry the route lookup with source address autoselection without modifying the bind. After a successful lookup, revalidate the bind and route key under peer->lock, reset the dst cache, and best-effort publish a replacement bind with a wildcard local address.

Do not cache the resolved dst when clearing the local source. Replacing the source invalidates all per-CPU cache entries, while dst_cache_set_ip4 and dst_cache_set_ip6 update only the current CPU slot. The current packet can still use the resolved route; if bind allocation fails, a later cache miss retries the repair.

Fixes 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
---
 drivers/net/ovpn/udp.c | 81 +++++++++++++++++++++++++++++-------------
 1 file changed, 56 insertions(+), 25 deletions(-)
drivers/net/ovpn/udp.c +56 -25
index 6ca482144dc4f..0b620c6cc64dd 100644
@@ -186,7 +186,7 @@ static void ovpn_dst_cache_check_key(struct ovpn_peer *peer,
  * to detect whether the bind was replaced while the route lookup was running.
  *
  * Return: true if the lookup result still matches the current peer state and
- * may update the dst cache.
+ * may update the dst cache or replace the bind.
  */
 static bool ovpn_dst_cache_current(const struct ovpn_peer *peer,
 				   const struct ovpn_bind *bind,
@@ -219,6 +219,9 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 			    struct sk_buff *skb,
 			    const struct ovpn_route_key *key)
 {
+	struct sockaddr_storage remote;
+	struct in_addr local = {};
+	bool reset_local = false;
 	struct rtable *rt;
 	struct flowi4 fl = {
 		.saddr = bind->local.ipv4.s_addr,
@@ -237,24 +240,17 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 
 	if (fl.saddr && unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0,
 						    fl.saddr, RT_SCOPE_HOST))) {
-		/* we may end up here when the cached address is not usable
-		 * anymore. In this case we reset address/cache and perform a
-		 * new look up
+		/* The learned local address is not usable anymore.
+		 * Retry with source address autoselection.
 		 */
 		fl.saddr = 0;
-		spin_lock_bh(&peer->lock);
-		bind->local.ipv4.s_addr = 0;
-		spin_unlock_bh(&peer->lock);
-		dst_cache_reset(cache);
+		reset_local = true;
 	}
 
 	rt = ip_route_output_flow(sock_net(sk), &fl, sk);
 	if (IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) {
 		fl.saddr = 0;
-		spin_lock_bh(&peer->lock);
-		bind->local.ipv4.s_addr = 0;
-		spin_unlock_bh(&peer->lock);
-		dst_cache_reset(cache);
+		reset_local = true;
 
 		rt = ip_route_output_flow(sock_net(sk), &fl, sk);
 	}
@@ -268,10 +264,28 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 		goto err;
 	}
 
-	/* avoid storing a stale cache */
+	/* avoid storing a stale cache or local address */
 	spin_lock_bh(&peer->lock);
-	if (likely(ovpn_dst_cache_current(peer, bind, key)))
-		dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+	if (likely(ovpn_dst_cache_current(peer, bind, key))) {
+		if (!reset_local) {
+			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+			spin_unlock_bh(&peer->lock);
+			goto transmit;
+		}
+
+		/* invalidate per-CPU dst entries that may still carry
+		 * the stale source
+		 */
+		dst_cache_reset(cache);
+
+		/* preserve the current remote */
+		memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in));
+		/* The current packet already has a valid wildcard-source route.
+		 * If replacing the bind fails, leave the stale local in place;
+		 * a later cache miss will retry the repair.
+		 */
+		ovpn_peer_reset_sockaddr(peer, &remote, &local);
+	}
 	spin_unlock_bh(&peer->lock);
 
 transmit:
@@ -301,6 +315,9 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 			    struct sk_buff *skb,
 			    const struct ovpn_route_key *key)
 {
+	struct in6_addr local = in6addr_any;
+	struct sockaddr_storage remote;
+	bool reset_local = false;
 	struct dst_entry *dst;
 	int ret;
 
@@ -321,15 +338,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 
 	if (!ipv6_addr_any(&fl.saddr) &&
 	    unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) {
-		/* we may end up here when the cached address is not usable
-		 * anymore. In this case we reset address/cache and perform a
-		 * new look up
+		/* The learned local address is not usable anymore.
+		 * Retry with source address autoselection.
 		 */
 		fl.saddr = in6addr_any;
-		spin_lock_bh(&peer->lock);
-		bind->local.ipv6 = in6addr_any;
-		spin_unlock_bh(&peer->lock);
-		dst_cache_reset(cache);
+		reset_local = true;
 	}
 
 	dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
@@ -341,10 +354,28 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 		goto err;
 	}
 
-	/* avoid storing a stale cache */
+	/* avoid storing a stale cache or local address */
 	spin_lock_bh(&peer->lock);
-	if (likely(ovpn_dst_cache_current(peer, bind, key)))
-		dst_cache_set_ip6(cache, dst, &fl.saddr);
+	if (likely(ovpn_dst_cache_current(peer, bind, key))) {
+		if (!reset_local) {
+			dst_cache_set_ip6(cache, dst, &fl.saddr);
+			spin_unlock_bh(&peer->lock);
+			goto transmit;
+		}
+
+		/* invalidate per-CPU dst entries that may still carry
+		 * the stale source
+		 */
+		dst_cache_reset(cache);
+
+		/* preserve the current remote */
+		memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in6));
+		/* The current packet already has a valid wildcard-source route.
+		 * If replacing the bind fails, leave the stale local in place;
+		 * a later cache miss will retry the repair.
+		 */
+		ovpn_peer_reset_sockaddr(peer, &remote, &local);
+	}
 	spin_unlock_bh(&peer->lock);
 
 transmit:
Signature · 1 line
2.53.0
author maintainer
#104 lore raw

PATCH 104/395 ovpn: always unhash old VPN addresses before rehashing

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit b43beccb3713fafada57814b0a652f4a876eb75f ]

ovpn_peer_hash_vpn_ip updates the per-peer VPN address hash entries after userspace changes a peer VPN address. The current code removes an old hash entry only when the new address for that family is not the unspecified address.

When an address is cleared to 0.0.0.0 or ::, its hash node therefore remains linked in the bucket selected by the old address. The address comparison performed during lookup prevents the old address from matching, but the table retains a stale entry until the peer is removed or another address is configured for that family.

Always remove both old VPN address hash entries before conditionally adding the currently configured addresses back. This ensures that a cleared address leaves its hash node unhashed.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/peer.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/net/ovpn/peer.c +4 -6
index 6f7c55ff91fbc..03ec043a123b4 100644
@@ -989,10 +989,11 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
 	if (hlist_unhashed(&peer->hash_entry_id))
 		return;
 
-	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
-		/* remove potential old hashing */
-		hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+	/* remove potential old hashing */
+	hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+	hlist_nulls_del_init_rcu(&peer->hash_entry_addr6);
 
+	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
 		nhead = ovpn_get_hash_head(peer->ovpn->peers->by_vpn_addr4,
 					   &peer->vpn_addrs.ipv4,
 					   sizeof(peer->vpn_addrs.ipv4));
@@ -1000,9 +1001,6 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
 	}
 
 	if (!ipv6_addr_any(&peer->vpn_addrs.ipv6)) {
-		/* remove potential old hashing */
-		hlist_nulls_del_init_rcu(&peer->hash_entry_addr6);
-
 		nhead = ovpn_get_hash_head(peer->ovpn->peers->by_vpn_addr6,
 					   &peer->vpn_addrs.ipv6,
 					   sizeof(peer->vpn_addrs.ipv6));
Signature · 1 line
2.53.0
author maintainer
#105 lore raw

PATCH 105/395 ovpn: reject duplicate peer VPN addresses

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit d25e885b31a0f2808d936f95c9a558a8a792669b ]

In MP mode, ovpn uses the peer VPN addresses as lookup keys for selecting the peer that should receive an outgoing tunnel packet. However, the netlink peer configuration path does not currently reject duplicate VPN addresses.

If two peers are configured with the same VPN address, both can be inserted in the VPN address hash table and lookups return whichever peer is found first. This makes peer selection ambiguous and dependent on hash insertion order.

Reject peer creation or update when the resulting VPN address is already assigned to another peer. Ignore unspecified addresses because those are not inserted in the VPN address hash tables.

This changes such configurations from being accepted to being rejected, but they have never worked reliably because peer selection is ambiguous.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 37 ++++++++++++++++-----
 drivers/net/ovpn/peer.c    | 67 +++++++++++++++++++++++++++++++++++++-
 drivers/net/ovpn/peer.h    |  6 ++++
 3 files changed, 101 insertions(+), 9 deletions(-)
drivers/net/ovpn/netlink.c +29 -8
index deddf8e1e81ef..67542b811ba11 100644
@@ -473,8 +473,10 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 
 int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
 	struct ovpn_priv *ovpn = info->user_ptr[0];
+	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
+	struct in6_addr vpn_addr6;
+	struct in_addr vpn_addr4;
 	struct ovpn_socket *sock;
 	struct ovpn_peer *peer;
 	u32 peer_id;
@@ -521,28 +523,47 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 	rcu_read_unlock();
 
 	spin_lock_bh(&ovpn->lock);
-	ret = ovpn_nl_peer_modify(peer, info, attrs);
-	if (ret < 0) {
-		spin_unlock_bh(&ovpn->lock);
-		ovpn_peer_put(peer);
-		return ret;
+
+	/* reject peer with conflicting VPN address */
+	if (attrs[OVPN_A_PEER_VPN_IPV4]) {
+		vpn_addr4.s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
+		if (ovpn_peer_vpn_addr_conflict4(ovpn, peer, &vpn_addr4))
+			goto addr_conflict;
 	}
+	if (attrs[OVPN_A_PEER_VPN_IPV6]) {
+		vpn_addr6 = nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
+		if (ovpn_peer_vpn_addr_conflict6(ovpn, peer, &vpn_addr6))
+			goto addr_conflict;
+	}
+
+	ret = ovpn_nl_peer_modify(peer, info, attrs);
+	if (ret < 0)
+		goto unlock;
 
 	/* ret == 1 means that VPN IPv4/6 has been modified and rehashing
 	 * is required
 	 */
-	if (ret > 0)
+	if (ret > 0) {
 		ovpn_peer_hash_vpn_ip(peer);
+		ret = 0;
+	}
 	/* if the remote endpoint was updated, the by_transp_addr hash bucket
 	 * also needs to be refreshed, otherwise incoming packets from the new
 	 * remote address would fail the lockless lookup
 	 */
 	if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
 		ovpn_peer_hash_transp_addr(peer);
+
+unlock:
 	spin_unlock_bh(&ovpn->lock);
 	ovpn_peer_put(peer);
 
-	return 0;
+	return ret;
+addr_conflict:
+	NL_SET_ERR_MSG_FMT_MOD(info->extack,
+			       "VPN IP is already assigned to another peer");
+	ret = -EADDRINUSE;
+	goto unlock;
 }
 
 static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info,
drivers/net/ovpn/peer.c +66 -1

85 lines not on this page · raw message

drivers/net/ovpn/peer.h +6 -0
index 693175712f7af..2306b84929bb1 100644
@@ -162,6 +162,12 @@ struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn,
 struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
 struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
 				       struct sk_buff *skb);
+bool ovpn_peer_vpn_addr_conflict4(struct ovpn_priv *ovpn,
+				  const struct ovpn_peer *peer,
+				  const struct in_addr *addr);
+bool ovpn_peer_vpn_addr_conflict6(struct ovpn_priv *ovpn,
+				  const struct ovpn_peer *peer,
+				  const struct in6_addr *addr);
 void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
 void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
 bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
Signature · 1 line
2.53.0
author maintainer
#106 lore raw

PATCH 106/395 ovpn: reject multipeer peers without VPN addresses

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 025af3a0a892514f9f27f186338ba3d44365547a ]

In MP mode, ovpn uses the peer VPN addresses to select the peer for outgoing tunnel packets. Peer creation currently requires a VPN IPv4 or IPv6 attribute, but it only checks for the presence of the attribute and not for a usable address value.

This allows userspace to create an MP peer with only unspecified VPN addresses, or to update an existing peer so that both VPN address families become unspecified. Such a peer cannot be selected through the VPN address hash tables.

Reject MP peer creation or update when the resulting peer would not have at least one VPN address configured.

This changes such configurations from being accepted to being rejected, but they have never been usable because the peer cannot be selected through the VPN address hash tables.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)
drivers/net/ovpn/netlink.c +30 -6
index 67542b811ba11..45fa69d9c951f 100644
@@ -346,8 +346,10 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
 
 int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
+	struct in_addr vpn_addr4 = { .s_addr = htonl(INADDR_ANY) };
+	struct in6_addr vpn_addr6 = IN6ADDR_ANY_INIT;
 	struct ovpn_priv *ovpn = info->user_ptr[0];
+	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
 	struct ovpn_socket *ovpn_sock;
 	struct socket *sock = NULL;
 	struct ovpn_peer *peer;
@@ -371,11 +373,20 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 
 	/* in MP mode VPN IPs are required for selecting the right peer */
-	if (ovpn->mode == OVPN_MODE_MP && !attrs[OVPN_A_PEER_VPN_IPV4] &&
-	    !attrs[OVPN_A_PEER_VPN_IPV6]) {
-		NL_SET_ERR_MSG_FMT_MOD(info->extack,
-				       "VPN IP must be provided in MP mode");
-		return -EINVAL;
+	if (ovpn->mode == OVPN_MODE_MP) {
+		if (attrs[OVPN_A_PEER_VPN_IPV4])
+			vpn_addr4.s_addr =
+				nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
+		if (attrs[OVPN_A_PEER_VPN_IPV6])
+			vpn_addr6 =
+				nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
+
+		if (vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+		    ipv6_addr_any(&vpn_addr6)) {
+			NL_SET_ERR_MSG_FMT_MOD(info->extack,
+					       "at least one VPN IP must be configured in MP mode");
+			return -EINVAL;
+		}
 	}
 
 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
@@ -524,6 +535,9 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 
 	spin_lock_bh(&ovpn->lock);
 
+	vpn_addr4 = peer->vpn_addrs.ipv4;
+	vpn_addr6 = peer->vpn_addrs.ipv6;
+
 	/* reject peer with conflicting VPN address */
 	if (attrs[OVPN_A_PEER_VPN_IPV4]) {
 		vpn_addr4.s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
@@ -536,6 +550,16 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 			goto addr_conflict;
 	}
 
+	/* in MP mode VPN IPs are required for selecting the right peer */
+	if (ovpn->mode == OVPN_MODE_MP &&
+	    vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+	    ipv6_addr_any(&vpn_addr6)) {
+		NL_SET_ERR_MSG_FMT_MOD(info->extack,
+				       "at least one VPN IP must be configured in MP mode");
+		ret = -EINVAL;
+		goto unlock;
+	}
+
 	ret = ovpn_nl_peer_modify(peer, info, attrs);
 	if (ret < 0)
 		goto unlock;
Signature · 1 line
2.53.0
author maintainer
#107 lore raw

PATCH 107/395 ovpn: reject invalid peer VPN addresses

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 5940f3407b78062442cb01f541ef6eed709fc380 ]

In MP mode, ovpn uses peer VPN addresses as lookup keys for selecting the peer that should receive outgoing tunnel packets. The netlink configuration path currently accepts address values that cannot sensibly identify a VPN peer, such as multicast, broadcast or loopback addresses.

Reject invalid peer VPN addresses when creating or updating an MP peer. Keep accepting the unspecified address as the internal unset value, provided that at least one VPN address family remains configured.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 55 +++++++++++++++++++++++++++++---------
 1 file changed, 42 insertions(+), 13 deletions(-)
drivers/net/ovpn/netlink.c +42 -13
index 45fa69d9c951f..15664cde85e0b 100644
@@ -185,6 +185,39 @@ static sa_family_t ovpn_nl_family_get(struct nlattr *addr4,
 	return AF_UNSPEC;
 }
 
+static int ovpn_nl_peer_check_vpn_addrs(const struct in_addr *addr4,
+					const struct in6_addr *addr6,
+					struct genl_info *info)
+{
+	int addr6_type;
+
+	if (addr4->s_addr == htonl(INADDR_ANY) && ipv6_addr_any(addr6)) {
+		NL_SET_ERR_MSG_MOD(info->extack,
+				   "at least one VPN IP must be configured in MP mode");
+		return -EINVAL;
+	}
+
+	if (ipv4_is_multicast(addr4->s_addr) || ipv4_is_lbcast(addr4->s_addr) ||
+	    ipv4_is_loopback(addr4->s_addr)) {
+		NL_SET_ERR_MSG_MOD(info->extack,
+				   "VPN IPv4 address must be valid unicast or any");
+		return -EADDRNOTAVAIL;
+	}
+
+	if (!ipv6_addr_any(addr6)) {
+		addr6_type = ipv6_addr_type(addr6);
+
+		if (!(addr6_type & IPV6_ADDR_UNICAST) ||
+		    (addr6_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_COMPATv4))) {
+			NL_SET_ERR_MSG_MOD(info->extack,
+					   "VPN IPv6 address must be valid unicast or any");
+			return -EADDRNOTAVAIL;
+		}
+	}
+
+	return 0;
+}
+
 static int ovpn_nl_peer_precheck(struct ovpn_priv *ovpn,
 				 struct genl_info *info,
 				 struct nlattr **attrs)
@@ -381,12 +414,10 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 			vpn_addr6 =
 				nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
 
-		if (vpn_addr4.s_addr == htonl(INADDR_ANY) &&
-		    ipv6_addr_any(&vpn_addr6)) {
-			NL_SET_ERR_MSG_FMT_MOD(info->extack,
-					       "at least one VPN IP must be configured in MP mode");
-			return -EINVAL;
-		}
+		ret = ovpn_nl_peer_check_vpn_addrs(&vpn_addr4, &vpn_addr6,
+						   info);
+		if (ret < 0)
+			return ret;
 	}
 
 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
@@ -551,13 +582,11 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	/* in MP mode VPN IPs are required for selecting the right peer */
-	if (ovpn->mode == OVPN_MODE_MP &&
-	    vpn_addr4.s_addr == htonl(INADDR_ANY) &&
-	    ipv6_addr_any(&vpn_addr6)) {
-		NL_SET_ERR_MSG_FMT_MOD(info->extack,
-				       "at least one VPN IP must be configured in MP mode");
-		ret = -EINVAL;
-		goto unlock;
+	if (ovpn->mode == OVPN_MODE_MP) {
+		ret = ovpn_nl_peer_check_vpn_addrs(&vpn_addr4, &vpn_addr6,
+						   info);
+		if (ret < 0)
+			goto unlock;
 	}
 
 	ret = ovpn_nl_peer_modify(peer, info, attrs);
Signature · 1 line
2.53.0
author maintainer
#108 lore raw

PATCH 108/395 Bluetooth: bnep: fix out-of-bounds reads on short RX/TX frames and control fallthrough

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

[ Upstream commit f0ca020cbb9bb7f3f4ea8ba1dfcf30a282aec91e ]

Fix multiple out-of-bounds reads in Bluetooth BNEP frame processing:

1. In bnep_rx_frame() and bnep_ctrl_frame() (net/bluetooth/bnep/core.c), use pskb_may_pull() to verify the BNEP header, control type byte, filter count, and extension headers exist before reading them, and return 0 after handling BNEP_CONTROL instead of falling through to Ethernet frame submission when no extension headers follow.
2. In bnep_net_xmit() (net/bluetooth/bnep/netdev.c), verify skb->len >= ETH_HLEN with pskb_may_pull() before reading the 14-byte Ethernet header to prevent an out-of-bounds heap read and infoleak on short AF_PACKET TX frames.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by LLM
---
 net/bluetooth/bnep/core.c   | 17 ++++++++++++++++-
 net/bluetooth/bnep/netdev.c |  8 +++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)
net/bluetooth/bnep/core.c +16 -1
index ed3ca38d8a6e1..e93c79982abcc 100644
@@ -273,9 +273,14 @@ static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
 
 		BT_DBG("type 0x%x len %u", h->type, h->len);
 
+		if (skb->len < h->len) {
+			err = -EILSEQ;
+			break;
+		}
+
 		switch (h->type & BNEP_TYPE_MASK) {
 		case BNEP_EXT_CONTROL:
-			bnep_rx_control(s, skb->data, skb->len);
+			bnep_rx_control(s, skb->data, h->len);
 			break;
 
 		default:
@@ -376,6 +381,11 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 			goto badframe;
 	}
 
+	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	/* Strip 802.1p header */
 	if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
 		if (!skb_pull(skb, 4))
@@ -454,6 +464,11 @@ static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 		goto send;
 	}
 
+	if (skb->len < ETH_HLEN) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	iv[il++] = (struct kvec) { &type, 1 };
 	len++;
 
net/bluetooth/bnep/netdev.c +7 -1
index cc1cff63194f0..5d9d851db926f 100644
@@ -169,6 +169,12 @@ static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
 
 	BT_DBG("skb %p, dev %p", skb, dev);
 
+	if (!pskb_may_pull(skb, ETH_HLEN)) {
+		dev->stats.tx_dropped++;
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
 #ifdef CONFIG_BT_BNEP_MC_FILTER
 	if (bnep_net_mc_filter(skb, s)) {
 		kfree_skb(skb);
@@ -221,7 +227,7 @@ void bnep_net_setup(struct net_device *dev)
 	dev->addr_len = ETH_ALEN;
 
 	ether_setup(dev);
-	dev->min_mtu = 0;
+	dev->min_mtu = ETH_MIN_MTU;
 	dev->max_mtu = ETH_MAX_MTU;
 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	dev->netdev_ops = &bnep_netdev_ops;
Signature · 1 line
2.53.0
author maintainer
#109 lore raw

PATCH 109/395 Bluetooth: btintel_pcie: validate device-supplied DMA indices

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ravindra <[email protected]>

[ Upstream commit 37a11129345337efd6eef8e62b03b6348cd0dd8b ]

In btintel_pcie_msix_rx_handle(), the driver processes RX completion descriptors (urbd1) written by the PCIe device into DMA-coherent memory. urbd1->frbd_tag (a 16-bit field fully controlled by the device firmware via DMA) is used directly as an array index into rxq->bufs[] without any bounds check. rxq->bufs[] has only BTINTEL_PCIE_RX_DESCS_COUNT (64) entries, while frbd_tag can be any value 0-65535. A malicious or malfunctioning device can write an out-of-range frbd_tag, causing the driver to dereference an out-of-bounds data_buf pointer.

Additionally, cr_hia is read from a DMA-shared index array also writable by the device; if the device sets cr_hia >= rxq->count, the while-loop never terminates because cr_tia is wrapped via modulo rxq->count and can never equal an out-of-range cr_hia.

Add bounds validation for cr_hia and frbd_tag in the RX path, and cr_hia in the TX path. Log invalid values with bt_dev_err before returning.

Fixes c2b636b3f788 ("Bluetooth: btintel_pcie: Add support for PCIe transport")
---
 drivers/bluetooth/btintel_pcie.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
drivers/bluetooth/btintel_pcie.c +16 -0
index 8d3129aa2a1a3..3d1ed8568877c 100644
@@ -1018,6 +1018,11 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
 
 	txq = &data->txq;
 
+	if (cr_hia >= txq->count) {
+		bt_dev_err(data->hdev, "TXQ: invalid cr_hia %u", cr_hia);
+		return;
+	}
+
 	while (cr_tia != cr_hia) {
 		data->tx_wait_done = true;
 		wake_up(&data->tx_wait_q);
@@ -1416,6 +1421,11 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
 
 	rxq = &data->rxq;
 
+	if (cr_hia >= rxq->count) {
+		bt_dev_err(hdev, "RXQ: invalid cr_hia %u", cr_hia);
+		return;
+	}
+
 	/* The firmware sends multiple CD in a single MSI-X and it needs to
 	 * process all received CDs in this interrupt.
 	 */
@@ -1423,6 +1433,12 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
 		urbd1 = &rxq->urbd1s[cr_tia];
 		ipc_print_urbd1(data->hdev, urbd1, cr_tia);
 
+		if (urbd1->frbd_tag >= rxq->count) {
+			bt_dev_err(hdev, "RXQ: invalid frbd_tag %u",
+				   urbd1->frbd_tag);
+			return;
+		}
+
 		buf = &rxq->bufs[urbd1->frbd_tag];
 		if (!buf) {
 			bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d",
Signature · 1 line
2.53.0
author maintainer
#110 lore raw

PATCH 110/395 Bluetooth: RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

[ Upstream commit 6d91041bb38b97e2feb625123cc0529d7b83a0e1 ]

While rfcomm_recv_frame() verifies that skb->len is at least sizeof(*hdr) + 1 (4 bytes: 3-byte header + 1-byte FCS), an RFCOMM frame with an extended 2-byte length field (!__test_ea(hdr->len)) has a 4-byte header plus a 1-byte FCS (5 bytes minimum, sizeof(*hdr) + 2).

When a 4-byte RFCOMM frame with EA == 0 arrives:
1. The initial skb->len < sizeof(*hdr) + 1 check passes (4 < 4 is false).
2. Trimming the FCS byte decrements skb->len to 3.
3. If __check_fcs() succeeds, skb_pull(skb, 4) fails (4 > 3) and returns NULL without advancing skb->data.
4. Because the return value of skb_pull() is ignored, the un-pulled 3-byte struct rfcomm_hdr remains at skb->data and is either queued as application payload via rfcomm_recv_data() or parsed as a multiplexer control command via rfcomm_recv_mcc() on DLCI 0.

Fix this by extending the length check in rfcomm_recv_frame() to also require skb->len >= sizeof(*hdr) + 2 when !__test_ea(hdr->len).

Fixes b230e5bf501c ("Bluetooth: RFCOMM: validate skb length in rfcomm_recv_frame")
Assisted-by LLM
---
 net/bluetooth/rfcomm/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/bluetooth/rfcomm/core.c +2 -1
index 45f8cfebcc6a6..99c295b9f666b 100644
@@ -1817,7 +1817,8 @@ static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
 		return s;
 	}
 
-	if (skb->len < sizeof(*hdr) + 1) {
+	if (skb->len < sizeof(*hdr) + 1 ||
+	    (!__test_ea(hdr->len) && skb->len < sizeof(*hdr) + 2)) {
 		kfree_skb(skb);
 		return s;
 	}
Signature · 1 line
2.53.0
author maintainer
#111 lore raw

PATCH 111/395 octeontx2-af: Fix memory scaling limitation in SR-IOV mode

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ratheesh Kannoth <[email protected]>

[ Upstream commit d06f2ebf67ff2962fe00d687e4f0d4703eb41a12 ]

The original code used DMA_ATTR_FORCE_CONTIGUOUS, which could exhaust the CMA pool when a large number of VFs were requested.

Fix this by switching to the DMA streaming API. This is equivalent on Octeon platforms, which provide full I/O coherency via the SMMU.

Cc Leon Romanovsky <[email protected]>
Fixes 73d33dbc0723 ("octeontx2-af: Use DMA_ATTR_FORCE_CONTIGUOUS attribute in DMA alloc")
---
 .../ethernet/marvell/octeontx2/af/common.h    | 45 ++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/common.h +39 -6
index 8a08bebf08c2c..e6c6e03c3f293 100644
@@ -7,6 +7,10 @@
 #ifndef COMMON_H
 #define COMMON_H
 
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
 #include "rvu_struct.h"
 
 #define OTX2_ALIGN			128  /* Align to cacheline */
@@ -44,6 +48,33 @@ struct qmem {
 	u32		qsize;
 };
 
+static inline void *otx2_dma_alloc_coherent(struct device *dev, size_t size,
+					    dma_addr_t *dma_handle)
+{
+	dma_addr_t dma_addr;
+	void *vaddr;
+
+	vaddr = kzalloc(size, GFP_KERNEL);
+	if (!vaddr)
+		return NULL;
+
+	dma_addr = dma_map_single(dev, vaddr, size, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, dma_addr)) {
+		kfree(vaddr);
+		return NULL;
+	}
+
+	*dma_handle = dma_addr;
+	return vaddr;
+}
+
+static inline void otx2_dma_free_coherent(struct device *dev, size_t size,
+					  void *vaddr, dma_addr_t dma_handle)
+{
+	dma_unmap_single(dev, dma_handle, size, DMA_BIDIRECTIONAL);
+	kfree(vaddr);
+}
+
 static inline int qmem_alloc(struct device *dev, struct qmem **q,
 			     int qsize, int entry_sz)
 {
@@ -60,8 +91,11 @@ static inline int qmem_alloc(struct device *dev, struct qmem **q,
 
 	qmem->entry_sz = entry_sz;
 	qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN;
-	qmem->base = dma_alloc_attrs(dev, qmem->alloc_sz, &qmem->iova,
-				     GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
+
+	if (get_order(PAGE_ALIGN(qmem->alloc_sz)) > MAX_PAGE_ORDER)
+		return -ENOMEM;
+
+	qmem->base = otx2_dma_alloc_coherent(dev, qmem->alloc_sz, &qmem->iova);
 	if (!qmem->base)
 		return -ENOMEM;
 
@@ -80,10 +114,9 @@ static inline void qmem_free(struct device *dev, struct qmem *qmem)
 		return;
 
 	if (qmem->base)
-		dma_free_attrs(dev, qmem->alloc_sz,
-			       qmem->base - qmem->align,
-			       qmem->iova - qmem->align,
-			       DMA_ATTR_FORCE_CONTIGUOUS);
+		otx2_dma_free_coherent(dev, qmem->alloc_sz,
+				       qmem->base - qmem->align,
+				       qmem->iova - qmem->align);
 	devm_kfree(dev, qmem);
 }
 
Signature · 1 line
2.53.0
author maintainer
#112 lore raw

PATCH 112/395 ipv6: Prevent rt6_insert_exception() for dying fib6_info.

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit 0346ec2f080b40d95ed05b853bb9226289e75212 ]

Before the cited commit, fib6_nh_flush_exceptions() always set from->exception_bucket_flushed = 1 under rt6_exception_lock to prevent rt6_insert_exception() from inserting a new exception for a dying fib6_info.

The flag was replaced with the FIB6_EXCEPTION_BUCKET_FLUSHED bit stored in nh->rt6i_exception_bucket.

The problem is that now the bit is only set when the bucket is not NULL and fib6_nh_flush_exceptions() is called from fib6_nh_release() after fib6_ref has already reached zero.

If rt6_insert_exception() is called while the target fib6_info is being removed via fib6_purge_rt(), a new exception could be created successfully because rt6_flush_exceptions() no longer sets the bit.

This creates a reference cycle between the fib6_info and the exception route, leaking the fib6_info, its nexthop device, and all per-CPU routes in fib6_nh->rt6i_pcpu, which stalls netdev unregistration.

[   34.680602] unregister_netdevice: waiting for gre6 to become free. Usage count = 68
[   44.920675] unregister_netdevice: waiting for gre6 to become free. Usage count = 68
[   55.176582] unregister_netdevice: waiting for gre6 to become free. Usage count = 68

Let's call fib6_drop_pcpu_from() before rt6_flush_exceptions(), to set fib6_destroying before rt6_exception_lock, and check f6i->fib6_destroying in rt6_insert_exception().

Note that FIB6_EXCEPTION_BUCKET_FLUSHED logic is dead and we can clean it up in net-next.

---
 net/ipv6/ip6_fib.c | 2 +-
 net/ipv6/route.c   | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)
net/ipv6/ip6_fib.c +1 -1
index 75875e4a1edea..9fc2d2677b747 100644
@@ -1033,8 +1033,8 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
 	struct fib6_table *table = rt->fib6_table;
 
 	/* Flush all cached dst in exception table */
-	rt6_flush_exceptions(rt);
 	fib6_drop_pcpu_from(rt);
+	rt6_flush_exceptions(rt);
 
 	if (rt->nh) {
 		spin_lock(&rt->nh->lock);
net/ipv6/route.c +5 -0
index 71a38034f5ca8..c71e93e17017e 100644
@@ -1725,6 +1725,11 @@ static int rt6_insert_exception(struct rt6_info *nrt,
 
 	spin_lock_bh(&rt6_exception_lock);
 
+	if (f6i->fib6_destroying) {
+		err = -ENOENT;
+		goto out;
+	}
+
 	bucket = rcu_dereference_protected(nh->rt6i_exception_bucket,
 					  lockdep_is_held(&rt6_exception_lock));
 	if (!bucket) {
Signature · 1 line
2.53.0
author maintainer
#113 lore raw

PATCH 113/395 dpll: use exact lookup for reference sync pin id

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ivan Vecera <[email protected]>

[ Upstream commit 7cce782d8327b7291334c4a304cf3fd909a74d9d ]

dpll_pin_ref_sync_state_set() looks up the reference sync pin in the pin->ref_sync_pins xarray, which is keyed by the sync pin's id (see dpll_pin_ref_sync_pair_add() using xa_insert() with ref_sync_pin->id). The pin id to operate on is supplied by userspace via DPLL_A_PIN_ID.

The lookup however used xa_find() with a ULONG_MAX limit, which returns the first present entry with an index greater than or equal to the requested id, not the entry stored exactly at that id. If userspace passes an id that is not paired as a reference sync pin, but another pin with a higher id is present in the xarray, xa_find() silently returns that wrong pin and the subsequent ref_sync_set() operates on it. The request only fails when the given id is larger than every present key.

Use xa_load() for an exact-key lookup instead, mirroring the deletion path in dpll_pin_ref_sync_pair_del().

Fixes 58256a26bfb3 ("dpll: add reference sync get/set")
---
 drivers/dpll/dpll_netlink.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/dpll/dpll_netlink.c +1 -2
index eb23ee401aaef..d8917150477ee 100644
@@ -1059,8 +1059,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
 	unsigned long i;
 	int ret;
 
-	ref_sync_pin = xa_find(&pin->ref_sync_pins, &ref_sync_pin_idx,
-			       ULONG_MAX, XA_PRESENT);
+	ref_sync_pin = xa_load(&pin->ref_sync_pins, ref_sync_pin_idx);
 	if (!ref_sync_pin) {
 		NL_SET_ERR_MSG(extack, "reference sync pin not found");
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#114 lore raw

PATCH 114/395 net: usb: sr9700: include receive overhead in the length check

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit c06bde80ae7a7b595732f7cabcb92cf08db9d56a ]

The receive fixup subtracts the Ethernet CRC from the reported packet length, but compares that payload length against the whole remaining receive buffer. The following copy starts after the three-byte header, and the cursor advance consumes both that header and the four-byte CRC.

Require the payload to fit after SR_RX_OVERHEAD before copying it or advancing to the next packet. The loop already ensures that the remaining buffer is larger than the overhead, so the subtraction is safe.

The issue was found by our static-analysis tool.

Fixes c9b37458e956 ("USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700Device Driver Support")
---
 drivers/net/usb/sr9700.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/usb/sr9700.c +2 -1
index a5d364fbc3639..f71bd2d5a274c 100644
@@ -403,7 +403,8 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 		/* ignore the CRC length */
 		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
-		if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
+		if (len > ETH_FRAME_LEN || len < 0 ||
+		    len > skb->len - SR_RX_OVERHEAD)
 			return 0;
 
 		/* the last packet of current skb */
Signature · 1 line
2.53.0
author maintainer
#115 lore raw

PATCH 115/395 ipv6: Fix dst leak for uncached routes.

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit be31fe6333f534155e6b408f1ef6d77974bb41aa ]

ip6_route_output_flags(), ip6_rt_put_flags(), and ip6_dst_check() detect an uncached route by list_empty(&rt->dst.rt_uncached), which replaced the static DST_NOCACHE flag check in commit a4c2fd7f7891 ("net: remove DST_NOCACHE flag").

When a device is unregistered, rt6_uncached_list_flush_dev() unlinks uncached routes tied to the device from rt6_uncached_list.

Previously, they were moved to another list with list_move() (__list_del_entry() + list_add()), and since commit 98aa546af5e4 ("inet: remove (struct uncached_list)->quarantine"), the routes are just unlinked with list_del_init().

If list_del_init() runs concurrently, list_empty() evaluates to true; ip6_route_output_flags() calls dst_hold_safe() incorrectly and ip6_rt_put_flags() skips ip6_rt_put(), leaking dst, and thus dev tied via rt->from as well.

The same race is partially fixed by commit 9a6f0c4d5796 ("dst:
fix races in rt6_uncached_list_del() and rt_del_uncached_list()").

Let's check rt6->dst.rt_uncached_list instead.

Note that IPv4 does not have the same issue.

---
 include/net/ip6_route.h | 4 ++--
 net/ipv6/route.c        | 7 ++++---
 2 files changed, 6 insertions(+), 5 deletions(-)
include/net/ip6_route.h +2 -2
index 2e8ca123d1465..4137bdf05baae 100644
@@ -94,12 +94,12 @@ static inline struct dst_entry *ip6_route_output(struct net *net,
 }
 
 /* Only conditionally release dst if flags indicates
- * !RT6_LOOKUP_F_DST_NOREF or dst is in uncached_list.
+ * !RT6_LOOKUP_F_DST_NOREF or dst is uncached.
  */
 static inline void ip6_rt_put_flags(struct rt6_info *rt, int flags)
 {
 	if (!(flags & RT6_LOOKUP_F_DST_NOREF) ||
-	    !list_empty(&rt->dst.rt_uncached))
+	    rt->dst.rt_uncached_list)
 		ip6_rt_put(rt);
 }
 
net/ipv6/route.c +4 -3
index c71e93e17017e..e99b4901091a2 100644
@@ -139,6 +139,7 @@ void rt6_uncached_list_add(struct rt6_info *rt)
 {
 	struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
 
+	/* Set once and never cleared: non-NULL marks an uncached route. */
 	rt->dst.rt_uncached_list = ul;
 
 	spin_lock_bh(&ul->lock);
@@ -2721,8 +2722,8 @@ struct dst_entry *ip6_route_output_flags(struct net *net,
 	rcu_read_lock();
 	dst = ip6_route_output_flags_noref(net, sk, fl6, flags);
 	rt6 = dst_rt6_info(dst);
-	/* For dst cached in uncached_list, refcnt is already taken. */
-	if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) {
+	/* For an uncached dst, refcnt is already taken. */
+	if (!rt6->dst.rt_uncached_list && !dst_hold_safe(dst)) {
 		dst = &net->ipv6.ip6_null_entry->dst;
 		dst_hold(dst);
 	}
@@ -2831,7 +2832,7 @@ INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst,
 	from = rcu_dereference(rt->from);
 
 	if (from && (rt->rt6i_flags & RTF_PCPU ||
-	    unlikely(!list_empty(&rt->dst.rt_uncached))))
+	    unlikely(rt->dst.rt_uncached_list)))
 		dst_ret = rt6_dst_from_check(rt, from, cookie);
 	else
 		dst_ret = rt6_check(rt, from, cookie);
Signature · 1 line
2.53.0
author maintainer
#116 lore raw

PATCH 116/395 udp: relocate a connected socket in the 4-tuple hash table on re-connect

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shardul Bankar <[email protected]>

[ Upstream commit 5fd0783b99d4af98f65cd58b56ec203d1d426104 ]

A connected UDP socket that connects again to a different peer is not re-filed in the 4-tuple hash table:

    sk binds to 127.0.0.1:21001
    sk connects to 127.0.0.2:20001	// filed under hash(sk, peer1)
    sk connects to 127.0.0.3:20002	// still filed under hash(sk, peer1)
    packet from 127.0.0.3:20002		// hash(sk, peer2) misses, so the
					// lookup falls back to scoring the
					// hash2 chain for this address
					// and port

udp_lib_hash4() returns early when the socket is already hashed, assuming ->rehash() relocates it. ->rehash() runs from __ip{4,6}_datagram_connect() only while the receive address is unset, which a second connect never is:
the first connect assigns it, whether the socket was bound to a specific address or to the wildcard. commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()") added that early return and named connect(AF_UNSPEC) as the way around it. That workaround does not help a socket with both SOCK_BINDADDR_LOCK and SOCK_BINDPORT_LOCK set, because __udp_disconnect() skips ->rehash() for the first and ->unhash() for the second.

Delivery is correct either way.

Relocate the socket when the hash it is filed under differs from the one requested, which is what commit 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket") did before the early return became unconditional. It is done here under hslot->lock, which that version did not take, to match udp_lib_rehash() and udp_lib_unhash(). hslot2 is unchanged, so hash4_cnt needs no adjustment, as in udp_lib_rehash(). A first connect is unaffected, and IPv6 shares the code.

With 500 sockets on the port, a re-connected socket measured 522,553 pps without this change and 2,055,078 with it. The UDP side was noted as remaining work in [1].

---
 net/ipv4/udp.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
net/ipv4/udp.c +14 -5
index ea7585f6ec32a..ec16eb6a479fb 100644
@@ -624,14 +624,23 @@ void udp_lib_hash4(struct sock *sk, u16 hash)
 	struct net *net = sock_net(sk);
 	struct udp_table *udptable;
 
-	/* Connected udp socket can re-connect to another remote address, which
-	 * will be handled by rehash. Thus no need to redo hash4 here.
+	udptable = net->ipv4.udp_table;
+	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
+
+	/* A connected socket can re-connect to another address. rehash()
+	 * relocates it, but only runs when the local address changes, so a
+	 * socket bound to a specific address would stay filed under the
+	 * previous peer's hash. Move it here.
 	 */
-	if (udp_hashed4(sk))
+	if (udp_hashed4(sk)) {
+		if (udp_sk(sk)->udp_lrpa_hash != hash) {
+			spin_lock_bh(&hslot->lock);
+			udp_rehash4(udptable, sk, hash);
+			spin_unlock_bh(&hslot->lock);
+		}
 		return;
+	}
 
-	udptable = net->ipv4.udp_table;
-	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
 	hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
 	hslot4 = udp_hashslot4(udptable, hash);
 	udp_sk(sk)->udp_lrpa_hash = hash;
Signature · 1 line
2.53.0
author maintainer
#117 lore raw

PATCH 117/395 udp: remove a disconnected socket from the 4-tuple hash table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shardul Bankar <[email protected]>

[ Upstream commit 9e95b1a94c9c49b4ba722251bbca2759b9c51737 ]

A UDP socket bound to a specific address and port keeps its entry in the 4-tuple hash table after it is disconnected:

    sk binds to 127.0.0.1:21001
    sk connects to 127.0.0.2:20001	// filed in the 4-tuple table
    sk disconnects, connect(AF_UNSPEC)	// still filed, peer now 0.0.0.0:0

__udp_disconnect() takes a socket out of that table only as a side effect of ->rehash() or ->unhash(), and it skips ->rehash() when SOCK_BINDADDR_LOCK is set and ->unhash() when SOCK_BINDPORT_LOCK is set. commit 6996a2d2d0a6 ("udp: Unhash auto-bound connected sk from 4-tuple hash table when disconnected.") fixed the same end state for a wildcard-bound socket, by a path this one does not take.

The entry is counted whether or not anything hits it. hash4_cnt on the hash2 slot stays raised for as long as the socket lives, so udp_has_hash4() keeps sending every packet for that address and port through the 4-tuple lookup first.

On IPv6 it can also be hit. __udp_disconnect() does not clear sk_v6_daddr, so udp_v6_rehash() files the entry under the peer the socket was connected to with a zero dport, and inet6_match() compares that same
field: a datagram from the former peer with a zero source port matches, and source port zero is accepted on receive. On IPv4 the peer is cleared, so a match would need a zero source address as well, which the routing layer rejects as martian. The stale sk_v6_daddr is a separate defect, not addressed here; removing the entry closes this path either way.

The entry can also be relocated. __udp_disconnect() clears sk_bound_dev_if, so a subsequent SO_BINDTODEVICE calls ->rehash(), and because the receive address is still specific udp_lib_rehash() moves the entry instead of removing it, into the bucket that (rcv_saddr, num, 0, 0) hashes to -- a pure function of the address and port, so every socket reaching this state on one address and port collects in one bucket. The bucket cannot be chosen from outside, as udp_ehashfn() is seeded with a per-boot secret. This last one became reachable only with commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()"), which moved the hash4 handling out of a branch a disconnected socket does not take; the stale entry itself dates from the commit in Fixes.

Take the socket out of the table before __udp_disconnect() runs, while it still matches how it was filed. This also reaches the wildcard case ahead of udp_lib_rehash()'s udp_unhash4() branch, leaving that branch unreachable from udp_disconnect(); removing it belongs in net-next. udp_disconnect() and udp_abort() are the only UDP entries into __udp_disconnect(), which is shared with raw, ping and l2tp sockets that are not struct udp_sock:
ping_prot.obj_size is sizeof(struct inet_sock), so udp_hashed4() on one would read past the allocation.

Fixes 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket")
Assisted-by LLM
---
 net/ipv4/udp.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
net/ipv4/udp.c +23 -0
index ec16eb6a479fb..341786983d42e 100644
@@ -2229,9 +2229,31 @@ int __udp_disconnect(struct sock *sk, int flags)
 }
 EXPORT_SYMBOL(__udp_disconnect);
 
+/* __udp_disconnect() takes a socket out of the 4-tuple hash table only via
+ * ->rehash() or ->unhash(), and neither runs for a socket bound to a
+ * specific address and port. Remove it here, before its peer is cleared.
+ */
+static void udp_unhash4_on_disconnect(struct sock *sk)
+{
+	struct net *net = sock_net(sk);
+	struct udp_table *udptable;
+	struct udp_hslot *hslot;
+
+	if (!udp_hashed4(sk))
+		return;
+
+	udptable = net->ipv4.udp_table;
+	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
+
+	spin_lock_bh(&hslot->lock);
+	udp_unhash4(udptable, sk);
+	spin_unlock_bh(&hslot->lock);
+}
+
 int udp_disconnect(struct sock *sk, int flags)
 {
 	lock_sock(sk);
+	udp_unhash4_on_disconnect(sk);
 	__udp_disconnect(sk, flags);
 	release_sock(sk);
 	return 0;
@@ -3246,6 +3268,7 @@ int udp_abort(struct sock *sk, int err)
 
 	sk->sk_err = err;
 	sk_error_report(sk);
+	udp_unhash4_on_disconnect(sk);
 	__udp_disconnect(sk, 0);
 
 out:
Signature · 1 line
2.53.0
author maintainer
#118 lore raw

PATCH 118/395 tg3: clean up PHYLIB resources on probe failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Myeonghun Pak <[email protected]>

[ Upstream commit a92e1a412c53dc0d9ad639e7abf8b3fc70a5b6ad ]

tg3_get_invariants() can register an MDIO bus and connect a PHY for USE_PHYLIB devices. If tg3_init_one() later fails, its common error path releases the mappings and netdev without undoing those PHYLIB resources.

Disconnect the PHY and unregister the MDIO bus before the remaining teardown. Guard PHY cleanup with USE_PHYLIB to match tg3_phy_init(), and call tg3_mdio_fini() unconditionally to match tg3_mdio_init(). The existing IS_CONNECTED and MDIOBUS_INITED flags make both helpers safe when initialization only completed partially.

This issue was identified during our ongoing static-analysis research while reviewing kernel code.

Fixes 158d7abdae85 ("tg3: Add mdio bus registration")
Assisted-by OpenAI:GPT-5.6
---
 drivers/net/ethernet/broadcom/tg3.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/ethernet/broadcom/tg3.c +4 -0
index af21952373ea1..e212afe53e0b7 100644
@@ -18060,6 +18060,10 @@ static int tg3_init_one(struct pci_dev *pdev,
 	return 0;
 
 err_out_apeunmap:
+	if (tg3_flag(tp, USE_PHYLIB))
+		tg3_phy_fini(tp);
+	tg3_mdio_fini(tp);
+
 	if (tp->aperegs) {
 		iounmap(tp->aperegs);
 		tp->aperegs = NULL;
Signature · 1 line
2.53.0
author maintainer
#119 lore raw

PATCH 119/395 drm/i915/psr: Clear stale sel fetch enable bits on sel fetch disable

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nemesa Garg <[email protected]>

[ Upstream commit 2777ec9852277a06ae68fee0c4f1a32783e4a999 ]

Selective fetch is dropped while pipe CRC is active, and the planes keep their SEL_FETCH_PLANE_CTL / SEL_FETCH_CUR_CTL enable bit set in hardware over that. A plane disabled while selective fetch is off never gets the bit cleared, as the disable path is guarded by enable_psr2_sel_fetch. Once selective fetch comes back the hardware resumes fetching for a plane that is no longer enabled and keeps its DDB range reserved.

Clear the bits as selective fetch is turned off instead. Atomic check has both the old and the new crtc state, so record the transition there and let the plane and cursor arm paths write the registers to 0 for that commit.

v2: Drop the old_crtc_state->hw.active check. [Jouni]

Fixes b1f5279b5981 ("drm/i915/psr: Move plane sel fetch configuration into plane source files")
Assisted-by Copilot:Claude-Opus-5
(cherry picked from commit a4c0e7f80429eda6990960971aebd4e4b9533cc6)
---
 drivers/gpu/drm/i915/display/intel_cursor.c       |  7 +++++--
 .../gpu/drm/i915/display/intel_display_types.h    |  2 ++
 drivers/gpu/drm/i915/display/intel_psr.c          | 15 +++++++++++++++
 .../gpu/drm/i915/display/skl_universal_plane.c    |  9 ++++-----
 4 files changed, 26 insertions(+), 7 deletions(-)
drivers/gpu/drm/i915/display/intel_cursor.c +5 -2
index d4d181f9dca5f..c83cfb6b763a5 100644
@@ -536,7 +536,8 @@ static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch &&
+	    !crtc_state->clear_psr2_sel_fetch)
 		return;
 
 	intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
@@ -569,8 +570,10 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch) {
+		i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
 		return;
+	}
 
 	if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) {
 		if (crtc_state->enable_psr2_su_region_et) {
drivers/gpu/drm/i915/display/intel_display_types.h +2 -0
index 0496b3263ed19..9af08181bda39 100644
@@ -1120,6 +1120,8 @@ struct intel_crtc_state {
 	bool has_sel_update;
 	bool enable_psr2_sel_fetch;
 	bool enable_psr2_su_region_et;
+	/* Drop the stale selective fetch enable bits as selective fetch is turned off */
+	bool clear_psr2_sel_fetch;
 	bool req_psr2_sdp_prior_scanline;
 	bool has_panel_replay;
 	bool wm_level_disabled;
drivers/gpu/drm/i915/display/intel_psr.c +15 -0
index 1eeae3243bd5d..912a05dcf37b4 100644
@@ -2756,6 +2756,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
 {
 	struct intel_display *display = to_intel_display(state);
+	const struct intel_crtc_state *old_crtc_state =
+		intel_atomic_get_old_crtc_state(state, crtc);
 	struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 	struct intel_plane_state *new_plane_state, *old_plane_state;
 	struct intel_plane *plane;
@@ -2768,6 +2770,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 	bool full_update = false, su_area_changed;
 	int i, ret;
 
+	/*
+	 * Selective fetch is not always usable, for instance it is dropped
+	 * while pipe CRC is active. The planes keep their selective fetch
+	 * enable bit set in hardware over that, and a plane disabled while
+	 * selective fetch is off never gets the bit cleared. Once selective
+	 * fetch comes back the hardware would resume fetching for a plane that
+	 * is no longer enabled and keep its DDB range reserved, so have the
+	 * plane update drop the bit for every plane of the pipe as selective
+	 * fetch is turned off.
+	 */
+	crtc_state->clear_psr2_sel_fetch = old_crtc_state->enable_psr2_sel_fetch &&
+		!crtc_state->enable_psr2_sel_fetch;
+
 	if (!crtc_state->enable_psr2_sel_fetch)
 		return 0;
 
drivers/gpu/drm/i915/display/skl_universal_plane.c +4 -5
index e13fb781e7b20..62bca23e51321 100644
@@ -892,7 +892,8 @@ static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch &&
+	    !crtc_state->clear_psr2_sel_fetch)
 		return;
 
 	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
@@ -1606,10 +1607,8 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
-		return;
-
-	if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
+	if (crtc_state->enable_psr2_sel_fetch &&
+	    drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
 		intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
 				   SEL_FETCH_PLANE_CTL_ENABLE);
 	else
Signature · 1 line
2.53.0
author maintainer
#120 lore raw

PATCH 120/395 s390/debug: Do not register views for failed static debug areas

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mikhail Zaslonko <[email protected]>

[ Upstream commit 28e29992b034acffc9342df216c06097825ce610 ]

__REGISTER_STATIC_DEBUG_INFO() calls debug_register_view() unconditionally, even when debug_register_static() has failed. In that case _debug_register() was never reached and id->debugfs_root_entry is still NULL, so debugfs_create_file() places the view file in the debugfs root directory. For sclp_err this leaves a /sys/kernel/debug/hex_ascii file with nothing to indicate which debug log it belongs to.

debug_register_static() is not exported and the macro is its only caller, so let it return an error code and skip the view registration when it fails. No debugfs files are created for such an area then.

Reproduce by booting with s390dbf=sclp_err::100000000. The sclp_err registration fails, no s390dbf/sclp_err/ directory is created, and a hex_ascii file appears in the debugfs root instead.

Fixes d72541f94512 ("s390/debug: add early tracing support")
---
 arch/s390/include/asm/debug.h |  8 ++++++--
 arch/s390/kernel/debug.c      | 12 +++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)
arch/s390/include/asm/debug.h +6 -2
index 6375276d94eaa..293f194201653 100644
@@ -460,7 +460,11 @@ static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
 #define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view)	\
 static int __init VNAME(var, reg)(void)					\
 {									\
-	debug_register_static(&var, (pages), (areas));			\
+	int rc;								\
+									\
+	rc = debug_register_static(&var, (pages), (areas));		\
+	if (rc)								\
+		return rc;						\
 	debug_register_view(&var, (view));				\
 	return 0;							\
 }									\
@@ -492,7 +496,7 @@ static debug_info_t __refdata var =					\
 	__DEBUG_INFO_INIT(var, (name), (buf_size));			\
 __REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
 
-void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
+int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
 
 #endif /* MODULE */
 
arch/s390/kernel/debug.c +9 -3
index f5359b0100517..4cbad08453edc 100644
@@ -862,8 +862,12 @@ EXPORT_SYMBOL(debug_register);
  *
  * Note: This function is called automatically via an initcall generated by
  *	 DEFINE_STATIC_DEBUG_INFO.
+ *
+ * Return:
+ * - 0 on success
+ * - negative error code on failure
  */
-void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
+int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 {
 	unsigned long flags;
 	debug_info_t *copy;
@@ -871,7 +875,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 	if (!initialized) {
 		pr_err("Tried to register debug feature %s too early\n",
 		       id->name);
-		return;
+		return -EINVAL;
 	}
 
 	copy = debug_info_alloc("", pages_per_area, nr_areas, id->buf_size,
@@ -886,7 +890,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 		id->active_entries = NULL;
 		spin_unlock_irqrestore(&id->lock, flags);
 
-		return;
+		return -ENOMEM;
 	}
 
 	/* Replace static trace area with dynamic copy. */
@@ -904,6 +908,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 	mutex_lock(&debug_mutex);
 	_debug_register(id);
 	mutex_unlock(&debug_mutex);
+
+	return 0;
 }
 
 /* Remove debugfs entries. */
Signature · 1 line
2.53.0
author maintainer
#121 lore raw

PATCH 121/395 s390/debug: Fix NULL pointer dereference in debug_info_copy()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mikhail Zaslonko <[email protected]>

[ Upstream commit 012bfcd5a51082d5a65f096dfb9ca652b5267965 ]

When debug_register_static() fails, it clears areas, active_pages and active_entries but leaves the area bounds unchanged. Copying such an area, either by opening its view file or via debug_dump(), makes debug_info_copy() dereference the NULL pointers.

Skip the copy loop when the source has no areas.

---
 arch/s390/kernel/debug.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/s390/kernel/debug.c +2 -1
index 4cbad08453edc..c4db346688ed8 100644
@@ -346,7 +346,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
 		debug_info_free(rc);
 	} while (1);
 
-	if (mode == NO_AREAS)
+	/* debug_register_static() failure leaves areas NULL, bounds intact */
+	if (mode == NO_AREAS || !in->areas)
 		goto out;
 
 	for (i = 0; i < in->nr_areas; i++) {
Signature · 1 line
2.53.0
author maintainer
#122 lore raw

PATCH 122/395 net: spacemit: clear TX descriptor on fragment mapping failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Muhammad Bilal <[email protected]>

[ Upstream commit 2d14720beb58870b15a52b236c3ab0be0e06e915 ]

emac_tx_mem_map() writes TX_DESC_0_OWN into the ring descriptor for every slot beyond old_head as soon as that slot's memset()'d local copy is committed with "*tx_desc_addr = tx_desc", i.e. before the buffers for that slot have necessarily all been mapped successfully. If emac_tx_map_frag() then fails on a later fragment, the err_free_skb path calls emac_free_tx_buf() to unmap and drop the skb, but leaves the already-written descriptor memory untouched, and tx_ring->head is never advanced past old_head (the "tx_ring->head = head" store is skipped by the goto).

So a slot between old_head and the rolled-back head can be left with TX_DESC_0_OWN set and buffer_addr_{1,2} pointing at DMA mappings that emac_free_tx_buf() just tore down, while software considers that slot free again. The next successful emac_tx_mem_map() call only rebuilds old_head itself; if the DMA engine auto-advances into the following descriptor once it finishes old_head's packet, it will fetch that stale, already-unmapped address.

emac_tx_clean_desc() already treats emac_free_tx_buf() and clearing the descriptor as a pair when reclaiming completed descriptors; do the same in the mapping failure path.

---
 drivers/net/ethernet/spacemit/k1_emac.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/spacemit/k1_emac.c +3 -0
index d64ca7bbda9ea..170e657e1de07 100644
@@ -823,6 +823,9 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
 	while (i != head) {
 		emac_free_tx_buf(priv, i);
 
+		tx_desc_addr = &((struct emac_desc *)tx_ring->desc_addr)[i];
+		memset(tx_desc_addr, 0, sizeof(*tx_desc_addr));
+
 		if (++i == tx_ring->total_cnt)
 			i = 0;
 	}
Signature · 1 line
2.53.0
author maintainer
#123 lore raw

PATCH 123/395 net: ethernet: ti: netcp: fix pm_runtime usage counter leak on error

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: bui duc phuc <[email protected]>

[ Upstream commit ac4334522e4ba4a3b6710dd5d4cc98092824b8ca ]

pm_runtime_get_sync() leaves the runtime PM usage counter incremented even when it fails, but the error path in netcp_probe() does not call pm_runtime_put_noidle() to balance it, leaking a reference each time resume fails.

Use pm_runtime_resume_and_get() instead, which automatically drops the usage counter on failure, fixing the leak.

Fixes 84640e27f230 ("net: netcp: Add Keystone NetCP core ethernet driver")
---
 drivers/net/ethernet/ti/netcp_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/ti/netcp_core.c +1 -1
index 5ee13db568f08..269d81192089f 100644
@@ -2167,7 +2167,7 @@ static int netcp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	pm_runtime_enable(&pdev->dev);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0) {
 		dev_err(dev, "Failed to enable NETCP power-domain\n");
 		pm_runtime_disable(&pdev->dev);
Signature · 1 line
2.53.0
author maintainer
#124 lore raw

PATCH 124/395 genetlink: report the real command id for dump-only ops in policy dumps

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <[email protected]>

[ Upstream commit 261e8a37ecbaf462cdf9c336d2b2f5056088401a ]

The op-to-policy map a CTRL_CMD_GETPOLICY dump returns is the only way for userspace to find out which policy index belongs to which command. ctrl_dumppolicy_put_op() tags the nest with doit->cmd, but an op which only has a dumpit has no doit and every path which fills the split ops in zeroes it out, so those entries all claim to be command 0. nlctrl's own CTRL_CMD_GETPOLICY and NETDEV_CMD_QSTATS_GET are both in that group:

[{'family-id': 16, 'op-policy': {'do': 0, 'dump': 0, 'op-id': 3}},
{'family-id': 16, 'op-policy': {'dump': 1, 'op-id': 0}},

ctrl_fill_info() gets this right - it uses the iterator's cmd for CTRL_ATTR_OP_ID - so the two introspection interfaces of the same family contradict each other today.

Pass the command in rather than reconstructing it from doit->cmd | dumpit->cmd inside the helper, both callers already have it.

Fixes 26588edbef60 ("genetlink: support split policies in ctrl_dumppolicy_put_op()")
---
 net/netlink/genetlink.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
net/netlink/genetlink.c +5 -3
index 81b4494e2db74..7925a7913bc4f 100644
@@ -1657,7 +1657,7 @@ static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
 }
 
 static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
-				  struct netlink_callback *cb,
+				  struct netlink_callback *cb, u32 cmd,
 				  struct genl_split_ops *doit,
 				  struct genl_split_ops *dumpit)
 {
@@ -1678,7 +1678,7 @@ static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
 	if (!nest_pol)
 		goto err;
 
-	nest_op = nla_nest_start(skb, doit->cmd);
+	nest_op = nla_nest_start(skb, cmd);
 	if (!nest_op)
 		goto err;
 
@@ -1722,7 +1722,8 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 						      &doit, &dumpit)))
 				return -ENOENT;
 
-			if (ctrl_dumppolicy_put_op(skb, cb, &doit, &dumpit))
+			if (ctrl_dumppolicy_put_op(skb, cb, ctx->op,
+						   &doit, &dumpit))
 				return skb->len;
 
 			/* done with the per-op policy index list */
@@ -1731,6 +1732,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 
 		while (ctx->dump_map) {
 			if (ctrl_dumppolicy_put_op(skb, cb,
+						   ctx->op_iter->cmd,
 						   &ctx->op_iter->doit,
 						   &ctx->op_iter->dumpit))
 				return skb->len;
Signature · 1 line
2.53.0
author maintainer
#125 lore raw

PATCH 125/395 net: pcs: xpcs: fix clock reference leak on xpcs_init_clks failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Coia Prant <[email protected]>

[ Upstream commit 9892d71cf0ce3ff3d4fed2d9a3968fd4feb1c918 ]

xpcs_init_clks() takes references with clk_bulk_get_optional() and then enables them with clk_bulk_prepare_enable(). If the enable step fails, the function returns without dropping the references.

xpcs_create() handles the failure through out_free_data, which calls xpcs_free_data() but never xpcs_clear_clks(), so the clk references are leaked.

Add the missing clk_bulk_put() on the enable failure path. The prepare/enable side is already rolled back by clk_bulk_prepare_enable() itself.

Fixes f6bb3e9d98c2 ("net: pcs: xpcs: Add Synopsys DW xPCS platform device driver")
---
 drivers/net/pcs/pcs-xpcs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/pcs/pcs-xpcs.c +3 -1
index 14c4b10fee74c..495068c3642c6 100644
@@ -1430,8 +1430,10 @@ static int xpcs_init_clks(struct dw_xpcs *xpcs)
 		return dev_err_probe(dev, ret, "Failed to get clocks\n");
 
 	ret = clk_bulk_prepare_enable(DW_XPCS_NUM_CLKS, xpcs->clks);
-	if (ret)
+	if (ret) {
+		clk_bulk_put(DW_XPCS_NUM_CLKS, xpcs->clks);
 		return dev_err_probe(dev, ret, "Failed to enable clocks\n");
+	}
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#126 lore raw

PATCH 126/395 thermal: gov_step_wise: Fix stale mitigation vote with non-zero lower bounds

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Manaf Meethalavalappu Pallikunhi <[email protected]>

[ Upstream commit ec0d89150a9381d591344a9f6f5428655c227a7f ]

When two or more thermal zones bind to a common cooling device and one zone uses a non-zero instance->lower value, there is a bug where the instance holds a stale mitigation vote even after its trip is cleared.

Problem scenario:
- thermal-zone1: Trip at 50°C, cooling-map with lower=0
- thermal-zone2: Trip at 55°C, cooling-map with lower=2
- Both zones share the same cooling device (e.g., CPU)

Issue flow:
1. Both trips trigger, zone1 requests state 5, zone2 also mitigates
2. Zone2 trip clears (temp < 53°C due to hysteresis)
3. When throttle=false and trend=THERMAL_TREND_DROPPING:
- Current code checks: if (cur_state <= instance->lower) return THERMAL_NO_TARGET
- Since cur_state (5) > instance->lower (2),

     it returns instance->lower (2)

- This is the BUG where it returns instance->lower even though trip is cleared
4. Zone2's passive polling stops (tz->passive reaches 0) - no more updates for zone2
5. Zone2's stale vote of 2 persists indefinitely
6. Even when zone1 wants to reduce cooling to state, the cooling device cannot go below state 2 due to zone2's stale vote

When a trip is cleared (throttle == false), always return THERMAL_NO_TARGET instead of instance->lower. Remove the unnecessary check comparing cur_state with instance->lower. Since passive polling is already deactivated when the trip is cleared, the instance should always be deactivated regardless of its current cooling state. This ensures that instances with non-zero lower bounds do not retain stale mitigation votes after their trips are cleared.

---
 drivers/thermal/gov_step_wise.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/thermal/gov_step_wise.c +4 -6
index ea277c466d8d2..4fa4377f0d428 100644
@@ -65,14 +65,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
 				     min(instance->lower + 1, instance->upper),
 				     instance->upper);
 	} else if (trend == THERMAL_TREND_DROPPING) {
-		if (cur_state <= instance->lower)
-			return THERMAL_NO_TARGET;
-
 		/*
-		 * If 'throttle' is false, no mitigation is necessary, so
-		 * request the lower state for this instance.
+		 * If 'throttle' is false, no mitigation is necessary and
+		 * passive polling is already deactivated, so clear this
+		 * instance state by returning THERMAL_NO_TARGET.
 		 */
-		return instance->lower;
+		return THERMAL_NO_TARGET;
 	}
 
 	return instance->target;
Signature · 1 line
2.53.0
author maintainer
#127 lore raw

PATCH 127/395 bpf: Fix bounds check for skb-backed dynptrs

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emil Tsalapatis <[email protected]>

[ Upstream commit ed6eec97b534979dcf28b40c389cee57bd6561d4 ]

The skb_pointer_if_linear() function checks whether a memory region of length len starting at offset off into the skb is in the linear area, and returns a pointer to the region if so. The check currently subtracts between skb_headlen and offset of the check, and since skb_headlen is unsigned the subtraction can underflow. This causes the bounds check to spuriously pass and generate an arbitrary pointer of the form *(skb->data + off).

The only user of this helper is currently skb-backed BPF dynptr code. Returning the wrong pointer leads to the dynptr erroneously being backed with invalid memory.

Ensure the subtraction cannot underflow, and fail the check if it would. Use u64 arithmetic to also prevent overflow when calculating (skb_headlen(skb) - off) since off is unsigned.

---
 include/linux/skbuff.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
include/linux/skbuff.h +4 -1
index c9abf7e3accf4..b335f34921169 100644
@@ -4345,7 +4345,10 @@ skb_header_pointer_careful(const struct sk_buff *skb, int offset,
 static inline void * __must_check
 skb_pointer_if_linear(const struct sk_buff *skb, int offset, int len)
 {
-	if (likely(skb_headlen(skb) - offset >= len))
+	unsigned int uoffset = (unsigned int)offset;
+
+	if (likely(uoffset <= skb_headlen(skb) &&
+		   (unsigned int)len <= skb_headlen(skb) - uoffset))
 		return skb->data + offset;
 	return NULL;
 }
Signature · 1 line
2.53.0
author maintainer
#128 lore raw

PATCH 128/395 bpf: Fix bpf_sock context code generation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emil Tsalapatis <[email protected]>

[ Upstream commit 4a4852376e3a2727ea40e61143d6d7c22bb6dfad ]

Currently, the ctx access code reads the rx_queue_mapping field with either a 4-byte or 2-byte load. The rest of the bits in the register are marked known zero by the verifier. However, the emitted ctx access code places in the register on certain the special value (-1) using BPF_MOV_IMM64, which gets sign-extended to turn on all the bits in the register. By shifting this value right, the program ends up with a value at runtime above what the verifier assumes is possible.

Fix this by ensuring the read value is as wide as the assumed size. Use MOV32 instructions instead of MOV64 instructions to keep the upper bits zero as assumed by the verifier. Also properly report the size of the destination variable (the bpf_sock field, 4 bytes) instead of the source (the socket field, 2 bytes).

---
 net/core/filter.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
net/core/filter.c +4 -3
index dea8dd48d4aa6..308b86abe4608 100644
@@ -10247,11 +10247,12 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
 				       target_size));
 		*insn++ = BPF_JMP_IMM(BPF_JNE, si->dst_reg, NO_QUEUE_MAPPING,
 				      1);
-		*insn++ = BPF_MOV64_IMM(si->dst_reg, -1);
+		*insn++ = BPF_MOV32_IMM(si->dst_reg, -1);
 #else
-		*insn++ = BPF_MOV64_IMM(si->dst_reg, -1);
-		*target_size = 2;
+		*insn++ = BPF_MOV32_IMM(si->dst_reg, -1);
 #endif
+		*target_size = sizeof_field(struct bpf_sock, rx_queue_mapping);
+
 		break;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#129 lore raw

PATCH 129/395 bpf, sockmap: Reject max_entries > INT_MAX in sock_map_alloc

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhao Gongyi <[email protected]>

[ Upstream commit 814a81c842bd88f6bd8a4ce550d560df071a5d03 ]

sock_map_alloc() only rejects max_entries == 0 and otherwise allows any u32 value. sock_map_free() then walks the sks[] array with a signed int iterator:

	int i;
	for (i = 0; i < stab->map.max_entries; i++)
		struct sock **psk = &stab->sks[i];

When a SOCKMAP is created with max_entries = 0xffffffff (UINT_MAX), the allocation of 32 GiB can succeed on large-memory hosts. During free the counter reaches 0x80000000, wraps to INT_MIN, is sign-extended by movslq and turned into a ~16 GiB negative offset from stab->sks, pointing far below the allocation.

The faulting access is an xchg() write in sock_map_free(). Without KASAN, the same out-of-bounds write can fault on an unmapped vmalloc page or corrupt an unrelated allocation if that vmalloc address is populated. On a KASAN kernel with CONFIG_KASAN_VMALLOC=y, the shadow check for that address hits an unmapped shadow page and oopses first:

  BUG: unable to handle page fault for address: fffff521b59c5a00
  RIP: 0010:kasan_check_range+0x107/0x190
  Call Trace:
   sock_map_free+0x93/0x190
   map_create+0x68d/0xb30
   __sys_bpf+0x21e/0x2e70

Vmcore confirmed stab->map.max_entries == 0xffffffff, stab->sks == 0xffffc911ace2d000, and the faulting address sks + (s64)INT_MIN * 8 exactly at 0xffffc90dace2d000. The same buggy path is reached on the normal close()/bpf_map_free_deferred() path whenever such a map is destroyed.

sock_map_alloc() used to bound its allocation size through bpf_map_charge_init(), but the bound was dropped when rlimit-based memory accounting was removed. Reject max_entries > INT_MAX at creation time so the signed iterator in sock_map_free() never sees a value that would overflow.

Triggered by syzkaller and reproduced on both a 6.6-based KASAN kernel and the upstream v7.3-rc2 kernel.

Fixes 0d2c4f964050 ("bpf: Eliminate rlimit-based memory accounting for sockmap and sockhash maps")
---
 net/core/sock_map.c | 1 +
 1 file changed, 1 insertion(+)
net/core/sock_map.c +1 -0
index 70bbc78fb079f..ebe8e166b6a73 100644
@@ -41,6 +41,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 	struct bpf_stab *stab;
 
 	if (attr->max_entries == 0 ||
+	    attr->max_entries > INT_MAX ||
 	    attr->key_size    != 4 ||
 	    (attr->value_size != sizeof(u32) &&
 	     attr->value_size != sizeof(u64)) ||
Signature · 1 line
2.53.0