Skip to contentSkip to conversation

7.2.9-rc1 review

PATCH In review Greg Kroah-Hartman 12 participants 469 messages Sep 30 – Oct 2 Page 1 of 4

Subsystems (6)
lore
Share & tools
lore

Greg Kroah-Hartman

author maintainer
#0 lore raw

cover 7.2.9-rc1 review

This is the start of the stable review cycle for the 7.2.9 release. There are 457 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/v7.x/stable-review/patch-7.2.9-rc1.gz

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

thanks,

greg k-h

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

Greg Kroah-Hartman <[email protected]>

    Linux 7.2.9-rc1

Shengzhuo Wei <[email protected]>
i2c: qcom-geni: release DMA channels on probe error

Karol Wachowski <[email protected]>
accel/ivpu: Drop IRQF_ONESHOT to allow IPC IRQ threading on PREEMPT_RT

Sean Christopherson <[email protected]>
KVM: x86: Add static calls for nested virtualization ops

Sean Christopherson <[email protected]>
KVM: x86: Reject nested CAP enablement if nested virtualization is disabled

Paolo Bonzini <[email protected]>
KVM: move TSS constants from kvm_host.h to tss.h

Sean Christopherson <[email protected]>
KVM: x86/mmu: Move kvm_mmu_do_page_fault() from mmu_internal.h => mmu.c

Sean Christopherson <[email protected]>
KVM: x86/mmu: Move kvm_arch_async_page_ready() below kvm_tdp_page_fault()

Sean Christopherson <[email protected]>
KVM: x86: Move IRQ-related helper declarations from kvm_host.h => irq.h

Marc Zyngier <[email protected]>
KVM: arm64: nv: Delay freeing of shadow S2 structures until VM destruction

Marc Zyngier <[email protected]>
KVM: arm64: nv: Fix life cycle of the nested_mmus array

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

Alex Hung <[email protected]>
drm/amd/display: Relax DML frame limit with UBSAN

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

Christian Brauner <[email protected]>
super: take lock after last reference count

Christian Brauner <[email protected]>
super: convert s_count to refcount_t s_passive

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

Praveen Talari <[email protected]>
i2c: qcom-geni: Store of_device_id data in driver private struct

Praveen Talari <[email protected]>
i2c: qcom-geni: Move resource initialization to separate function

Praveen Talari <[email protected]>
i2c: qcom-geni: Isolate serial engine setup

Jakub Pawlak <[email protected]>
accel/ivpu: Use separate flag for job timeout

Karol Wachowski <[email protected]>
accel/ivpu: Use threaded IRQ for IPC callback processing

Arnd Bergmann <[email protected]>
landlock: Work around gcc-16 -Wuninitialized warning

Tangudu Tilak Tirumalesh <[email protected]>

    drm/xe: Add wa_14025941587 to xe2, xe3 and xe3p platforms

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 merge different file IO error types

Darrick J. Wong <[email protected]>
xfs: don't let memory failures leak blocks and kill repairs

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: only flag zero padding for dir3 data blocks, not dir3 block blocks

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

Adarsh Das <[email protected]>
smb: client: delete compound mids on send failure before unlock

Zihan Xi <[email protected]>
smb: client: close completed creates on compound wait errors

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

Namjae Jeon <[email protected]>
smb: client: use finish_no_open() for non-regular inodes

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: close handle after create-context parsing failure

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

Davi Chaves Azevedo <[email protected]>
sched/cache: Refresh LLC capacity across CPU hotplug, to fix capacity underestimation bug

Tim Chen <[email protected]>
sched/cache: Decouple sched_cache_group from mm to fix UAF

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

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

Xie Bo <[email protected]>
RISC-V: KVM: Release unused page after MMU invalidation

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

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

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

Fuad Tabba <[email protected]>
KVM: arm64: Don't WARN on an unknown VM ioctl in protected mode

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

Shawn Guo <[email protected]>
pinctrl: qcom: nord: Split QUP1 SE2/SE3 into lane-pair functions

Conor Dooley <[email protected]>
pinctrl: mpfs-mssio: use correct regmap function to set bank voltage

Conor Dooley <[email protected]>
pinctrl: mpfs-mssio: fix width of unused bank voltage setting

Dapeng Mi <[email protected]>
perf/x86/intel: Constrain Panther Cove UOPS_DISPATCHED events to PMCs 0-3

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

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

Dapeng Mi <[email protected]>
perf/x86/intel: Fix Panther Cove PEBS data-source snoop states

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

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: Fix CMT PEBS load/store direction for latency events, to fix sample classification

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()

Zhenghui Hao <[email protected]>
parisc: parse early parameters in setup_arch()

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

Geert Uytterhoeven <[email protected]>
scsi: ufs: pltfrm: Add quirk for R-Car S4 lacking lanes-per-direction

Stanley Jhu <[email protected]>
scsi: ufs: core: Keep internal commands dispatchable during error handling

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

Alexander Sverdlin <[email protected]>
net: phy: intel-xway: workaround 100BASE-TX Link-Up issue

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

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

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

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

Tristan Madani <[email protected]>
HID: hid-oxp: use cancel_delayed_work_sync() in remove

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

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

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

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

SJ Park <[email protected]>

    mm/damon/core: reset invalid quota->charge_target_from

Liew Rui Yan <[email protected]>
mm/damon/core: allow esz to be set to zero

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

Nathan Gao <[email protected]>
mm/damon/ops-common: use a page-aligned address in damon_ptep_mkold()

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

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

Jinjiang Tu <[email protected]>

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

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

Junrui Luo <[email protected]>
drm/nouveau/dmem: pin VRAM for the whole registered range

Prike Liang <[email protected]>
drm/amdgpu: move userq fence wait out of signalling section

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()

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

Sunil Khatri <[email protected]>
drm/amdgpu/vcn5.0.1: fix video_timeout unit mismatch in jpeg reset wait

Sunil Khatri <[email protected]>
drm/amdgpu/vcn4.0.3: fix video_timeout unit mismatch in jpeg reset wait

Sunil Khatri <[email protected]>
drm/amdgpu/userq: fix double jiffies conversion in hang detect timeout

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()

Asad Kamal <[email protected]>
drm/amdkfd: fix use-after-free and multi-container gap in kfd_dev_mapping

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

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

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()

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

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()

Andrea Parri <[email protected]>
kprobes: Fix permanent hang when flushing the kprobe optimizer

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

Hao Ge <[email protected]>
netfs: Fix missing alloc tagging of direct mempool allocations

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

David Carlier <[email protected]>
fprobe: Terminate the fgraph_data list when the reservation is not filled

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

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

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

Aldo Ariel Panzardo <[email protected]>
vsock: ignore empty child namespace mode writes

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

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

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

Matthew Brost <[email protected]>
drm/pagemap: dma-unmap pages before handling migration errors

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

Puranjay Mohan <[email protected]>
perf/core: Fill branch entries with a single assignment

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

Dapeng Mi <[email protected]>
perf/x86/intel: Delete dead NVL PEBS data-source initcall

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()

Amir Goldstein <[email protected]>
ovl: fix UAF in ovl_do_mkdir() debug print

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

Eric Dumazet <[email protected]>
net: flush skb_defer_nodes in dev_cpu_dead()

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()

Allison Henderson <[email protected]>
net/rds: size a connection's path set by the transport it ends up with

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

Jiawen Wu <[email protected]>
net: libwx: fix races in Tx timestamp handling

Jiawen Wu <[email protected]>
net: wangxun: implement soft quiesce for PCIe error recovery

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

Donggeun Yoo <[email protected]>
bpf: Zero-fill other CPUs when BPF_F_CPU creates a per-cpu hash element

Christian Lamparter <[email protected]>
net: emac: move setting of netops to fix crash

Fang Xieyan <[email protected]>
net/sched: act_ife: validate metadata length before decoding

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

Yuya Kusakabe <[email protected]>
net: ipv6: keep room for the mac header in dst_dev_overhead()

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

Jonas Jelonek <[email protected]>
net: mdio: realtek-rtl9300: fix RTL931x C22 extended page selection

Nicolo Giuliani <[email protected]>

    net: dsa: mv88e6xxx: 88E6191X and 88E6193X have no PTP

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: size the RX buffers from the frame length, not the MTU

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: Validate EEE based on the actual LPI timer value

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

Takashi Sakamoto <[email protected]>
firewire: cdev: fix back-transition for iso_resource_auto client resource

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

Emil Tsalapatis <[email protected]>
bpf: Reject pkt arguments in mutating subprogs

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

Florian Schmaus <[email protected]>
PM: hibernate: Freeze kernel threads after image preallocation

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

Nicolai Buchwitz <[email protected]>
net: don't require the hwtstamp NDOs when a PHY provides timestamping

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

Xu Yunxiang <[email protected]>
bpf: Reject non-negative offsets in stack_slot_obj_get_spi()

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

Sk Anirban <[email protected]>
drm/xe/gt_throttle: Report power brake as a throttle reason on CRI

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

Prathamesh Shete <[email protected]>
pinctrl: tegra238: Fix register bank for AON pin groups

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

Quentin Armitage <[email protected]>
net: allow IFLA_INET_CONF messages when NLA_F_NESTED unset

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

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

Alexander Duyck <[email protected]>
eth: fbnic: use the Rx queue napi pointer to find the napi vector

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

Alexander Duyck <[email protected]>
net: ethtool: keep rtnl_lock for the ioctl self test

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

hpp.iscas <[email protected]>
pinctrl: qcom: ipq5210: Publish the OF module alias

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

Frank Wunderlich <[email protected]>
gpiolib: use of_node_name if line-name is missing

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

Kumar Kartikeya Dwivedi <[email protected]>
bpf: Preserve packet pointer class displacement in regsafe()

Kumar Kartikeya Dwivedi <[email protected]>
bpf: Make post-verification instruction rewrites killable

Shay Drory <[email protected]>
net/mlx5: LAG, reload IB reps of LAG master before the rest

Shay Drory <[email protected]>
net/mlx5: SD, unload reps on shared FDB create error path

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()

David Howells <[email protected]>
netfs, afs: Fix symlink reading

David Howells <[email protected]>
netfs: Fix netfs_read_gaps() to use separate sink folios

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

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

ZHOU Jiaxiang <[email protected]>
scsi: block: Fix zones_cond out-of-bounds write on zone report

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

Sebastian Ott <[email protected]>
KVM: selftests: fix steal_time for arm64 with host page size > 4K

Fuad Tabba <[email protected]>
KVM: arm64: Match hyp text by physical address in fix_host_ownership()

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: 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

Yicong Yang <[email protected]>
RISC-V: KVM: Fix the conversion between vsip and hvip

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

Sarah Emery <[email protected]>
pinctrl: generic: serialise pinctrl_generic_dt_node_to_map()

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

Masoud Aghasi <[email protected]>
bpf: Fix u32 overflow issue in map batch operations

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

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()

Siddharth Chintamaneni <[email protected]>
bpf: Allow terminal gotox instructions

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

René Onier <[email protected]>
HID: winwing: fix use-after-free in force feedback teardown

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 race in _destroy_pages_crste()

Claudio Imbrenda <[email protected]>
KVM: s390: Fix potential races in dat skey functions

Claudio Imbrenda <[email protected]>
KVM: s390: Properly handle NULL pointer in dat_cond_set_storage_key()

Claudio Imbrenda <[email protected]>

    KVM: s390: Add missing srcu in kvm_s390_set_irq_state()

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

Claudio Imbrenda <[email protected]>

    KVM: s390: Fix _gaccess_shadow_fault()

Claudio Imbrenda <[email protected]>
KVM: s390: Fix dirty marking in adapter_indicators_set*()

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

Dominik Kaszewski <[email protected]>
drm/amd/display: Remove sink usage from DPMS

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

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

Diffstat:

 Documentation/arch/arm64/booting.rst               |   1 +
 Documentation/arch/s390/pci.rst                    |   2 +-
 .../bindings/pinctrl/qcom,nord-tlmm.yaml           |   7 +-
 Makefile                                           |   4 +-
 arch/arm64/include/asm/el2_setup.h                 |   9 +-
 arch/arm64/include/asm/io.h                        |   3 +-
 arch/arm64/include/asm/kvm_host.h                  |   2 +-
 arch/arm64/include/asm/kvm_nested.h                |   3 +-
 arch/arm64/include/asm/kvm_pkvm.h                  |   3 +-
 arch/arm64/kernel/cpu_errata.c                     |  15 +-
 arch/arm64/kvm/arm.c                               |   8 +-
 arch/arm64/kvm/emulate-nested.c                    |   2 +-
 arch/arm64/kvm/hyp/include/nvhe/mem_protect.h      |   1 +
 arch/arm64/kvm/hyp/nvhe/mem_protect.c              |   8 +
 arch/arm64/kvm/hyp/nvhe/pkvm.c                     |  25 +-
 arch/arm64/kvm/hyp/nvhe/setup.c                    |  12 +-
 arch/arm64/kvm/hypercalls.c                        |   3 +-
 arch/arm64/kvm/mmu.c                               |  15 +-
 arch/arm64/kvm/nested.c                            | 115 ++++----
 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/parisc/kernel/setup.c                         |  12 +
 arch/riscv/include/asm/csr.h                       |  20 +-
 arch/riscv/kvm/aia_imsic.c                         |  11 +-
 arch/riscv/kvm/mmu.c                               |  10 +-
 arch/riscv/kvm/nacl.c                              |  20 +-
 arch/riscv/kvm/vcpu.c                              |   3 +-
 arch/riscv/kvm/vcpu_exit.c                         |   2 +-
 arch/riscv/kvm/vcpu_onereg.c                       |   8 +-
 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/dat.c                                |  41 ++-
 arch/s390/kvm/gaccess.c                            |  13 +
 arch/s390/kvm/gmap.c                               |   6 +-
 arch/s390/kvm/interrupt.c                          | 149 ++++++-----
 arch/s390/pci/pci_event.c                          |   7 +-
 arch/s390/pci/pci_report.c                         |  32 ++-
 arch/s390/pci/pci_report.h                         |   4 +-
 arch/x86/coco/sev/svsm.c                           |  10 +-
 arch/x86/events/amd/brs.c                          |   9 +-
 arch/x86/events/amd/lbr.c                          |  16 +-
 arch/x86/events/intel/core.c                       |  80 ++++--
 arch/x86/events/intel/ds.c                         |  68 ++---
 arch/x86/events/intel/lbr.c                        |  63 +++--
 arch/x86/events/perf_event.h                       |   4 -
 arch/x86/include/asm/kvm-x86-nested-ops.h          |  36 +++
 arch/x86/include/asm/kvm_host.h                    |  22 +-
 arch/x86/kernel/cpu/mce/core.c                     |  27 +-
 arch/x86/kvm/hyperv.c                              |   6 +-
 arch/x86/kvm/irq.h                                 |   6 +
 arch/x86/kvm/mmu.h                                 |   5 +-
 arch/x86/kvm/mmu/mmu.c                             | 129 ++++++---
 arch/x86/kvm/mmu/mmu_internal.h                    |  66 -----
 arch/x86/kvm/mmu/paging_tmpl.h                     |   2 +-
 arch/x86/kvm/pmu.c                                 |   8 -
 arch/x86/kvm/svm/nested.c                          |   1 +
 arch/x86/kvm/svm/sev.c                             |  18 +-
 arch/x86/kvm/svm/svm.c                             |   1 +
 arch/x86/kvm/tss.h                                 |   7 +
 arch/x86/kvm/vmx/nested.c                          |   1 +
 arch/x86/kvm/vmx/pmu_intel.c                       |   3 +
 arch/x86/kvm/vmx/vmx.c                             |   2 +
 arch/x86/kvm/x86.c                                 |  62 +++--
 arch/x86/kvm/x86.h                                 |   2 +-
 arch/x86/pci/fixup.c                               |  99 +++++++
 block/blk-zoned.c                                  |  15 +-
 drivers/accel/ivpu/ivpu_drv.c                      |  31 ++-
 drivers/accel/ivpu/ivpu_drv.h                      |   7 +-
 drivers/accel/ivpu/ivpu_hw.c                       |   4 +
 drivers/accel/ivpu/ivpu_ipc.c                      |   8 +-
 drivers/accel/ivpu/ivpu_ipc.h                      |   2 +-
 drivers/accel/ivpu/ivpu_job.c                      |  66 ++++-
 drivers/accel/ivpu/ivpu_job.h                      |   7 +-
 drivers/accel/ivpu/ivpu_mmu.c                      |   1 -
 drivers/accel/ivpu/ivpu_pm.c                       |   1 +
 drivers/ata/libata-scsi.c                          |  10 +-
 drivers/base/cacheinfo.c                           |  11 +-
 drivers/bluetooth/btintel_pcie.c                   |  16 ++
 drivers/bluetooth/btnxpuart.c                      |   8 +-
 drivers/dpll/dpll_netlink.c                        |   3 +-
 drivers/firewire/core-cdev.c                       |   6 +-
 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/gpio/gpiolib.c                             |   7 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c           |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c        |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c |   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c           |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c          |  16 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h          |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c             |   1 +
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c            |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c            |   3 +-
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c           |  71 ++++-
 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        |   8 +-
 drivers/gpu/drm/amd/display/dc/dml2_0/Makefile     |   2 +-
 drivers/gpu/drm/amd/display/dc/link/link_dpms.c    | 180 ++++++-------
 drivers/gpu/drm/bridge/samsung-dsim.c              |   2 +-
 drivers/gpu/drm/clients/drm_fbdev_client.c         |   8 +
 drivers/gpu/drm/drm_pagemap.c                      |  12 +-
 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           |  15 ++
 drivers/gpu/drm/i915/display/intel_quirks.c        |   3 +
 drivers/gpu/drm/i915/display/skl_universal_plane.c |   9 +-
 drivers/gpu/drm/i915/gem/i915_gem_object.c         |   2 +-
 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_dmem.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/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/regs/xe_gt_regs.h               |   1 +
 drivers/gpu/drm/xe/xe_bo.c                         |   7 +
 drivers/gpu/drm/xe/xe_bo.h                         |  19 ++
 drivers/gpu/drm/xe/xe_gt_throttle.c                |   5 +-
 drivers/gpu/drm/xe/xe_guc_ads.c                    |   2 +-
 drivers/gpu/drm/xe/xe_hw_engine.c                  |  96 ++++++-
 drivers/gpu/drm/xe/xe_vm.c                         |  21 +-
 drivers/gpu/drm/xe/xe_wa_oob.rules                 |   2 +
 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                             |  25 +-
 drivers/hid/hid-ids.h                              |   3 +
 drivers/hid/hid-multitouch.c                       |  29 +-
 drivers/hid/hid-oxp.c                              |   6 +-
 drivers/hid/hid-quirks.c                           |   3 +-
 drivers/hid/hid-winwing.c                          |  10 +-
 drivers/hid/wacom_sys.c                            |   5 +-
 drivers/i2c/busses/i2c-qcom-geni.c                 | 293 +++++++++++----------
 drivers/net/bonding/bond_main.c                    |   2 +-
 drivers/net/dsa/mt7530-mdio.c                      |  18 +-
 drivers/net/dsa/mt7530.c                           |   3 -
 drivers/net/dsa/mv88e6xxx/chip.c                   |  68 ++++-
 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/bnxt/bnxt_ethtool.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_desc_dqo.h     |   5 +
 drivers/net/ethernet/google/gve/gve_tx_dqo.c       |  40 ++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c  |   3 +
 drivers/net/ethernet/ibm/emac/core.c               |  16 +-
 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 +
 drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c  |  44 +++-
 .../ethernet/mellanox/mlx5/core/lag/shared_fdb.c   |   1 +
 .../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    |   4 +-
 drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c    |  16 +-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.c         |  47 +++-
 drivers/net/ethernet/meta/fbnic/fbnic_fw.h         |   1 +
 drivers/net/ethernet/meta/fbnic/fbnic_pci.c        |  18 +-
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c       |  30 ++-
 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  |  21 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c | 153 ++++++++---
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/wangxun/libwx/wx_hw.c         |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_lib.c        |  65 ++++-
 drivers/net/ethernet/wangxun/libwx/wx_lib.h        |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_ptp.c        | 161 ++++++++---
 drivers/net/ethernet/wangxun/libwx/wx_ptp.h        |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_type.h       |   2 +
 drivers/net/ethernet/wangxun/txgbe/txgbe_fdir.c    |  13 +-
 drivers/net/ethernet/wangxun/txgbe/txgbe_main.c    |  16 ++
 drivers/net/macsec.c                               |  84 +++---
 drivers/net/mdio/mdio-realtek-rtl9300.c            |   6 +
 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/intel-xway.c                       |  29 +-
 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/perf/arm_brbe.c                            |   2 +-
 drivers/pinctrl/meson/pinctrl-meson-s4.c           |   2 +-
 drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c     |   6 +-
 drivers/pinctrl/pinctrl-generic.c                  |   4 +
 drivers/pinctrl/pinctrl-single.c                   |   3 +-
 drivers/pinctrl/qcom/pinctrl-ipq5210.c             |   1 +
 drivers/pinctrl/qcom/pinctrl-nord.c                |  34 ++-
 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/pinctrl/tegra/pinctrl-tegra238.c           | 204 +++++++-------
 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 +-
 drivers/ufs/core/ufshcd.c                          |   6 +
 drivers/ufs/host/ufshcd-pltfrm.c                   |   6 +-
 fs/autofs/inode.c                                  |   4 +
 fs/bpf_fs_kfuncs.c                                 |   4 -
 fs/fs-writeback.c                                  |  25 +-
 fs/inode.c                                         |  11 +-
 fs/kernfs/mount.c                                  |   4 +-
 fs/netfs/buffered_read.c                           |  34 +--
 fs/netfs/objects.c                                 |   4 +-
 fs/netfs/read_collect.c                            |   5 +
 fs/netfs/rolling_buffer.c                          |   2 +-
 fs/ntfs3/inode.c                                   |   7 +-
 fs/ocfs2/namei.c                                   |   9 +-
 fs/ocfs2/xattr.c                                   |  13 +-
 fs/ocfs2/xattr.h                                   |   8 +-
 fs/overlayfs/overlayfs.h                           |   4 +-
 fs/smb/client/cached_dir.c                         |  32 ++-
 fs/smb/client/dir.c                                |  52 +++-
 fs/smb/client/smb2inode.c                          |   6 +-
 fs/smb/client/smb2misc.c                           |   9 +-
 fs/smb/client/smb2ops.c                            |  28 +-
 fs/smb/client/smb2pdu.c                            |  54 +++-
 fs/smb/client/transport.c                          |  71 ++++-
 fs/squashfs/xz_wrapper.c                           |   6 +-
 fs/super.c                                         | 114 ++++----
 fs/xfs/libxfs/xfs_metafile.c                       |   8 +-
 fs/xfs/libxfs/xfs_rtrefcount_btree.c               |   4 +-
 fs/xfs/scrub/dir.c                                 |   2 +-
 fs/xfs/scrub/health.c                              |   6 +-
 fs/xfs/scrub/inode.c                               |   2 +-
 fs/xfs/scrub/inode_repair.c                        |   2 +-
 fs/xfs/scrub/newbt.c                               |   8 +-
 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_healthmon.c                             |   4 +-
 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/linux/ethtool.h                            |   2 +
 include/linux/fs/super_types.h                     |   2 +-
 include/linux/if_vlan.h                            |   3 +
 include/linux/mempool.h                            |   7 +
 include/linux/mm_types.h                           |  15 +-
 include/linux/perf_event.h                         |  17 --
 include/linux/sched.h                              |   6 +-
 include/linux/sched/topology.h                     |   4 +-
 include/linux/skbuff.h                             |  24 +-
 include/net/dst.h                                  |   3 +-
 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/tcp.h                                  |   4 +-
 kernel/bpf/btf.c                                   | 140 ++++++----
 kernel/bpf/core.c                                  |  21 +-
 kernel/bpf/crypto.c                                |   5 +-
 kernel/bpf/fixups.c                                |  24 +-
 kernel/bpf/hashtab.c                               |  43 ++-
 kernel/bpf/memalloc.c                              |  50 ++--
 kernel/bpf/offload.c                               |   2 +
 kernel/bpf/states.c                                |   3 +
 kernel/bpf/syscall.c                               |  15 +-
 kernel/bpf/verifier.c                              |  17 +-
 kernel/cgroup/cpuset.c                             |   3 +-
 kernel/cgroup/pids.c                               |   5 +
 kernel/events/core.c                               |  17 +-
 kernel/exit.c                                      |  11 +-
 kernel/kprobes.c                                   |  22 +-
 kernel/power/hibernate.c                           |  26 +-
 kernel/sched/core.c                                |   2 +-
 kernel/sched/ext/ext.c                             |   7 +-
 kernel/sched/fair.c                                | 173 ++++++++----
 kernel/sched/topology.c                            |  22 +-
 kernel/trace/fprobe.c                              |  15 ++
 kernel/workqueue.c                                 |   2 +-
 mm/backing-dev.c                                   |   5 +-
 mm/damon/core.c                                    |  39 ++-
 mm/damon/ops-common.c                              |   7 +-
 mm/damon/vaddr.c                                   |  21 +-
 mm/hugetlb.c                                       |  20 +-
 mm/rmap.c                                          |   6 +-
 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                                     |  49 +++-
 net/core/dev.h                                     |   2 +
 net/core/dev_ioctl.c                               |  25 +-
 net/core/filter.c                                  |  46 ++--
 net/core/skbuff.c                                  |  21 +-
 net/core/skmsg.c                                   |   4 +
 net/core/sock_map.c                                |   1 +
 net/ethtool/common.h                               |   2 +
 net/ipv4/arp.c                                     |   1 +
 net/ipv4/devinet.c                                 |   7 +-
 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                                |  45 ++--
 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                      |  10 +-
 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/connection.c                               |   6 +
 net/rds/ib_frmr.c                                  |  11 +-
 net/sched/act_api.c                                |   2 +-
 net/sched/act_ct.c                                 |  41 ++-
 net/sched/act_gate.c                               |  30 ++-
 net/sched/act_ife.c                                |  17 +-
 net/sched/act_meta_mark.c                          |   6 +-
 net/sched/act_meta_skbprio.c                       |   6 +-
 net/sched/act_meta_skbtcindex.c                    |   6 +-
 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/vmw_vsock/af_vsock.c                           |   3 +
 net/xdp/xskmap.c                                   |   2 +-
 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 +
 security/landlock/access.h                         |   8 +
 sound/hda/codecs/realtek/alc269.c                  |   9 +
 tools/arch/riscv/include/asm/csr.h                 |  20 +-
 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/kvm/steal_time.c           |  30 ++-
 tools/testing/selftests/nci/nci_dev.c              |  45 ++--
 virt/kvm/kvm_main.c                                |  30 ++-
 471 files changed, 5769 insertions(+), 2585 deletions(-)
author maintainer
#1 lore raw

PATCH 1/457 drm/amd/display: Atomize IRQ register read/modify/write ops

7.2-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 5ba196dd9d7ad..bd78cfcc3477d 100644
@@ -3344,7 +3344,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");
@@ -3368,7 +3368,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 797f944718108..d2602c0310b20 100644
@@ -550,6 +550,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 f47ee9937adaa..7206439ea5d52 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"
@@ -87,7 +88,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 fe5b97e6f9603..ee7140d8dda8b 100644
@@ -1378,12 +1378,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
#2 lore raw

PATCH 2/457 ALSA: hda/realtek: Limit Star Labs internal mic boost

In reply to Greg Kroah-Hartman

7.2-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 c31fed171c419..aa2a63d9a63e8 100644
@@ -4209,6 +4209,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,
@@ -6755,6 +6756,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,
@@ -8168,6 +8173,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
#3 lore raw

PATCH 3/457 ALSA: hda/realtek: Add StarFighter HDA SSID

In reply to Greg Kroah-Hartman

7.2-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 aa2a63d9a63e8..1e0612c39c89b 100644
@@ -6763,6 +6763,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,
@@ -8090,6 +8092,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
#4 lore raw

PATCH 4/457 drm/amd/display: Remove sink usage from DPMS

In reply to Greg Kroah-Hartman

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

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

From: Dominik Kaszewski <[email protected]>

[ Upstream commit 8fa813b7fd1eccbed13e126166cf764f1f11a7d3 ]

[Why]
stream->sink is optional and can be null, so should always be checked before dereference. Additionally, most of its usage in DPMS sequences is for stream->sink->link, which can be replaced with stream->link, as the two should always be the same.

[How]
* Replace stream->sink->link in DPMS on/off
* Add assert to USB4 BW allocation where sink is required
* Avoid inconsistencies in resource access, e.g. don't repeat stream->link after it was already saved to a local variable
* Pull out effective VPG calculation to helper getter
* Formatting fixes

---
 .../gpu/drm/amd/display/dc/link/link_dpms.c   | 178 +++++++++---------
 1 file changed, 90 insertions(+), 88 deletions(-)
drivers/gpu/drm/amd/display/dc/link/link_dpms.c +90 -88
index ca59977487994..f49dba6b4e426 100644
@@ -2296,6 +2296,8 @@ static enum dc_status enable_link(
 
 static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int stream_bw)
 {
+	ASSERT(stream->sink);
+
 	struct dc_link *link = stream->sink->link;
 	int req_bw = stream_bw;
 
@@ -2342,6 +2344,8 @@ static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, i
 
 static bool allocate_usb4_bandwidth(struct dc_stream_state *stream)
 {
+	ASSERT(stream->sink);
+
 	bool ret;
 
 	int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing,
@@ -2361,38 +2365,43 @@ static bool deallocate_usb4_bandwidth(struct dc_stream_state *stream)
 	return ret;
 }
 
+static struct vpg *get_vpg(struct pipe_ctx *pipe_ctx)
+{
+	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+		return pipe_ctx->stream_res.hpo_frl_stream_enc->vpg;
+	else if (dp_is_128b_132b_signal(pipe_ctx))
+		return pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
+	else
+		return pipe_ctx->stream_res.stream_enc->vpg;
+}
+
 void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 {
-	struct dc  *dc = pipe_ctx->stream->ctx->dc;
+	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
 	struct dc_stream_state *stream = pipe_ctx->stream;
-	struct dc_link *link = stream->sink->link;
-	struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+	struct dc *dc = stream->ctx->dc;
+	struct dc_link *link = stream->link;
+	struct vpg *vpg = get_vpg(pipe_ctx);
 	enum dp_panel_mode panel_mode_dp = dp_get_panel_mode(link);
 
-	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
 	ASSERT(is_master_pipe_for_link(link, pipe_ctx));
 
-	if (dp_is_128b_132b_signal(pipe_ctx))
-		vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
-		vpg = pipe_ctx->stream_res.hpo_frl_stream_enc->vpg;
-	if (dc_is_virtual_signal(pipe_ctx->stream->signal))
+	if (dc_is_virtual_signal(stream->signal))
 		return;
 
-	if (pipe_ctx->stream->sink) {
-		if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
-			pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+	if (stream->sink) {
+		if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+			stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
 			DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x link=%d sink_count=%d\n", __func__,
-			pipe_ctx->stream->sink->edid_caps.display_name,
-			pipe_ctx->stream->signal, link->link_index, link->sink_count);
+			stream->sink->edid_caps.display_name,
+			stream->signal, link->link_index, link->sink_count);
 		}
 	}
 
 	link_wait_for_unlocked(link);
 
-	if (!pipe_ctx->stream->sink->edid_caps.panel_patch.skip_avmute) {
-		if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+	if (stream->sink && !stream->sink->edid_caps.panel_patch.skip_avmute) {
+		if (dc_is_hdmi_signal(stream->signal))
 			set_avmute(pipe_ctx, true);
 	}
 
@@ -2402,15 +2411,15 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 	dc->hwss.blank_stream(pipe_ctx);
 
 	if (pipe_ctx->link_config.dp_tunnel_settings.should_use_dp_bw_allocation)
-		deallocate_usb4_bandwidth(pipe_ctx->stream);
+		deallocate_usb4_bandwidth(stream);
 
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
 		deallocate_mst_payload(pipe_ctx);
-	else if (dc_is_dp_sst_signal(pipe_ctx->stream->signal) &&
+	else if (dc_is_dp_sst_signal(stream->signal) &&
 			dp_is_128b_132b_signal(pipe_ctx))
 		update_sst_payload(pipe_ctx, false);
 
-	if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
+	if (dc_is_hdmi_signal(stream->signal)) {
 		struct ext_hdmi_settings settings = {0};
 		enum engine_id eng_id = pipe_ctx->stream_res.stream_enc->id;
 
@@ -2433,7 +2442,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 		}
 	}
 
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
 			!dp_is_128b_132b_signal(pipe_ctx)) {
 
 		/* In DP1.x SST mode, our encoder will go to TPS1
@@ -2443,18 +2452,18 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 		 * state machine.
 		 * In DP2 or MST mode, our encoder will stay video active
 		 */
-		disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
+		disable_link(link, &pipe_ctx->link_res, stream->signal);
 		dc->hwss.disable_stream(pipe_ctx);
 	} else {
 		dc->hwss.disable_stream(pipe_ctx);
-		disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
+		disable_link(link, &pipe_ctx->link_res, stream->signal);
 	}
 	edp_set_panel_assr(link, pipe_ctx, &panel_mode_dp, false);
 
-	if (pipe_ctx->stream->timing.flags.DSC) {
-		if (dc_is_dp_signal(pipe_ctx->stream->signal))
+	if (stream->timing.flags.DSC) {
+		if (dc_is_dp_signal(stream->signal))
 			link_set_dsc_enable(pipe_ctx, false);
-		else if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+		else if (dc_is_hdmi_frl_signal(stream->signal))
 			link_set_dsc_on_stream(pipe_ctx, false);
 	}
 	if (dp_is_128b_132b_signal(pipe_ctx)) {
@@ -2468,7 +2477,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 	/* for psp not exist case */
 	if (link->connector_signal == SIGNAL_TYPE_EDP && dc->debug.psp_disabled_wa) {
 		/* reset internal save state to default since eDP is  off */
-		enum dp_panel_mode panel_mode = dp_get_panel_mode(pipe_ctx->stream->link);
+		enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
 		/* since current psp not loaded, we need to reset it to default */
 		link->panel_mode = panel_mode;
 	}
@@ -2478,62 +2487,57 @@ void link_set_dpms_on(
 		struct dc_state *state,
 		struct pipe_ctx *pipe_ctx)
 {
-	struct dc *dc = pipe_ctx->stream->ctx->dc;
+	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
 	struct dc_stream_state *stream = pipe_ctx->stream;
-	struct dc_link *link = stream->sink->link;
+	struct dc *dc = stream->ctx->dc;
+	struct dc_link *link = stream->link;
 	enum dc_status status;
 	struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
 	enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
-	struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+	struct vpg *vpg = get_vpg(pipe_ctx);
 	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
 	bool apply_edp_fast_boot_optimization =
-		pipe_ctx->stream->apply_edp_fast_boot_optimization;
-
-	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+		stream->apply_edp_fast_boot_optimization;
 
 	ASSERT(is_master_pipe_for_link(link, pipe_ctx));
 
-	if (dp_is_128b_132b_signal(pipe_ctx))
-		vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
-		vpg = pipe_ctx->stream_res.hpo_frl_stream_enc->vpg;
-	if (dc_is_virtual_signal(pipe_ctx->stream->signal))
+	if (dc_is_virtual_signal(stream->signal))
 		return;
 
-	if (pipe_ctx->stream->sink) {
-		if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
-			pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+	if (stream->sink) {
+		if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+			stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
 			DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x link=%d sink_count=%d\n", __func__,
-			pipe_ctx->stream->sink->edid_caps.display_name,
-			pipe_ctx->stream->signal,
+			stream->sink->edid_caps.display_name,
+			stream->signal,
 			link->link_index,
 			link->sink_count);
 		}
 	}
 
-	link_wait_for_unlocked(stream->link);
+	link_wait_for_unlocked(link);
 	if (!dc->config.unify_link_enc_assignment)
 		link_enc = link_enc_cfg_get_link_enc(link);
 	ASSERT(link_enc);
 
-	if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
-			&& !dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)
+	if (!dc_is_virtual_signal(stream->signal)
+			&& !dc_is_hdmi_frl_signal(stream->signal)
 			&& !dp_is_128b_132b_signal(pipe_ctx)) {
 		if (link_enc)
 			link_enc->funcs->setup(
 				link_enc,
-				pipe_ctx->stream->signal);
+				stream->signal);
 	}
 
-	pipe_ctx->stream->link->link_state_valid = true;
+	link->link_state_valid = true;
 
-	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
-		hdmi_frl_decide_link_settings(stream, &stream->link->frl_link_settings, &pipe_ctx->dsc_padding_params);
+	if (dc_is_hdmi_frl_signal(stream->signal))
+		hdmi_frl_decide_link_settings(stream, &link->frl_link_settings, &pipe_ctx->dsc_padding_params);
 
 	if (pipe_ctx->stream_res.tg->funcs->set_out_mux) {
 		if (dp_is_128b_132b_signal(pipe_ctx))
 			otg_out_dest = OUT_MUX_HPO_DP;
-		else if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+		else if (dc_is_hdmi_frl_signal(stream->signal))
 			otg_out_dest = OUT_MUX_HPO_FRL;
 		else
 			otg_out_dest = OUT_MUX_DIO;
@@ -2542,7 +2546,7 @@ void link_set_dpms_on(
 
 	link_hwss->setup_stream_attribute(pipe_ctx);
 
-	pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
+	stream->apply_edp_fast_boot_optimization = false;
 
 	// Enable VPG before building infoframe
 	if (vpg && vpg->funcs->vpg_poweron)
@@ -2551,15 +2555,15 @@ void link_set_dpms_on(
 	resource_build_info_frame(pipe_ctx);
 	dc->hwss.update_info_frame(pipe_ctx);
 
-	if (dc_is_dp_signal(pipe_ctx->stream->signal))
+	if (dc_is_dp_signal(stream->signal))
 		dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
 
 	/* Do not touch link on seamless boot optimization. */
-	if (pipe_ctx->stream->apply_seamless_boot_optimization) {
-		pipe_ctx->stream->dpms_off = false;
+	if (stream->apply_seamless_boot_optimization) {
+		stream->dpms_off = false;
 
 		/* Still enable stream features & audio on seamless boot for DP external displays */
-		if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
+		if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
 			enable_stream_features(pipe_ctx);
 			dc->hwss.enable_audio_stream(pipe_ctx);
 		}
@@ -2569,11 +2573,11 @@ void link_set_dpms_on(
 	}
 
 	/* eDP lit up by bios already, no need to enable again. */
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+	if (stream->signal == SIGNAL_TYPE_EDP &&
 				apply_edp_fast_boot_optimization &&
-				!pipe_ctx->stream->timing.flags.DSC &&
+				!stream->timing.flags.DSC &&
 				!pipe_ctx->next_odm_pipe) {
-		pipe_ctx->stream->dpms_off = false;
+		stream->dpms_off = false;
 		update_psp_stream_config(pipe_ctx, false);
 
 		if (link->is_dds) {
@@ -2586,7 +2590,7 @@ void link_set_dpms_on(
 		return;
 	}
 
-	if (pipe_ctx->stream->dpms_off)
+	if (stream->dpms_off)
 		return;
 
 	/* For Dp tunneling link, a pending HPD means that we have a race condition between processing
@@ -2604,9 +2608,9 @@ void link_set_dpms_on(
 	 * will be automatically set at a later time when the video is enabled
 	 * (DP_VID_STREAM_EN = 1).
 	 */
-	if (pipe_ctx->stream->timing.flags.DSC) {
-		if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
-		    dc_is_virtual_signal(pipe_ctx->stream->signal))
+	if (stream->timing.flags.DSC) {
+		if (dc_is_dp_signal(stream->signal) ||
+		    dc_is_virtual_signal(stream->signal))
 			link_set_dsc_enable(pipe_ctx, true);
 	}
 
@@ -2617,7 +2621,7 @@ void link_set_dpms_on(
 
 	if (status != DC_OK) {
 		DC_LOG_WARNING("enabling link %u failed: %d\n",
-		pipe_ctx->stream->link->link_index,
+		link->link_index,
 		status);
 
 		/* Abort stream enable *unless* the failure was due to
@@ -2627,19 +2631,18 @@ void link_set_dpms_on(
 		 */
 			if ((status != DC_FAIL_DP_LINK_TRAINING &&
 					status != DC_FAIL_HDMI_FRL_LINK_TRAINING) ||
-					pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
-			if (false == stream->link->link_status.link_active)
-				disable_link(stream->link, &pipe_ctx->link_res,
-						pipe_ctx->stream->signal);
+					stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+			if (false == link->link_status.link_active)
+				disable_link(link, &pipe_ctx->link_res,
+						stream->signal);
 			BREAK_TO_DEBUGGER();
 			return;
 		}
 	}
 
-	if (pipe_ctx->stream->timing.flags.DSC &&
-			dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
-			//TODO: bring HDMI FRL in line with DP
-			link_set_dsc_on_stream(pipe_ctx, true);
+	if (stream->timing.flags.DSC && dc_is_hdmi_frl_signal(stream->signal))
+		//TODO: bring HDMI FRL in line with DP
+		link_set_dsc_on_stream(pipe_ctx, true);
 
 	/* turn off otg test pattern if enable */
 	if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
@@ -2651,37 +2654,37 @@ void link_set_dpms_on(
 	 * as a workaround for the incorrect value being applied
 	 * from transmitter control.
 	 */
-	if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
-			dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
+	if (!(dc_is_virtual_signal(stream->signal) ||
+			dc_is_hdmi_frl_signal(stream->signal) ||
 			dp_is_128b_132b_signal(pipe_ctx))) {
 
 			if (link_enc)
 				link_enc->funcs->setup(
 					link_enc,
-					pipe_ctx->stream->signal);
+					stream->signal);
 
 		}
 
 	dc->hwss.enable_stream(pipe_ctx);
 
 	/* Set DPS PPS SDP (AKA "info frames") */
-	if (pipe_ctx->stream->timing.flags.DSC) {
-		if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
-				dc_is_virtual_signal(pipe_ctx->stream->signal)) {
+	if (stream->timing.flags.DSC) {
+		if (dc_is_dp_signal(stream->signal) ||
+				dc_is_virtual_signal(stream->signal)) {
 			dp_set_dsc_on_rx(pipe_ctx, true);
 			link_set_dsc_pps_packet(pipe_ctx, true, true);
 		}
 	}
 
-	if (dc_is_dp_signal(pipe_ctx->stream->signal))
+	if (dc_is_dp_signal(stream->signal))
 		dp_set_hblank_reduction_on_rx(pipe_ctx);
 
 	if (pipe_ctx->link_config.dp_tunnel_settings.should_use_dp_bw_allocation)
-		allocate_usb4_bandwidth(pipe_ctx->stream);
+		allocate_usb4_bandwidth(stream);
 
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
 		allocate_mst_payload(pipe_ctx);
-	else if (dc_is_dp_sst_signal(pipe_ctx->stream->signal) &&
+	else if (dc_is_dp_sst_signal(stream->signal) &&
 			dp_is_128b_132b_signal(pipe_ctx))
 		update_sst_payload(pipe_ctx, true);
 
@@ -2690,23 +2693,22 @@ void link_set_dpms_on(
 	 * training and stream unblank resolves the corruption issue.
 	 * This is workaround.
 	 */
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+	if (stream->signal == SIGNAL_TYPE_EDP &&
 			link->is_display_mux_present)
 		msleep(20);
 
 	dc->hwss.unblank_stream(pipe_ctx,
-		&pipe_ctx->stream->link->cur_link_settings);
+		&link->cur_link_settings);
 
 	if (stream->sink_patches.delay_ignore_msa > 0)
 		msleep(stream->sink_patches.delay_ignore_msa);
 
-	if (dc_is_dp_signal(pipe_ctx->stream->signal))
+	if (dc_is_dp_signal(stream->signal))
 		enable_stream_features(pipe_ctx);
 	update_psp_stream_config(pipe_ctx, false);
 
 	dc->hwss.enable_audio_stream(pipe_ctx);
 
-	if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
+	if (dc_is_hdmi_signal(stream->signal))
 		set_avmute(pipe_ctx, false);
-	}
 }
Signature · 1 line
2.53.0
author maintainer
#5 lore raw

PATCH 5/457 remoteproc: qcom_q6v5_adsp: Fix iommu_unmap() usage

In reply to Greg Kroah-Hartman

7.2-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 c81e6c33c7479..9c5dedf0aa605 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
#6 lore raw

PATCH 6/457 KVM: s390: Fix dirty marking in adapter_indicators_set*()

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit d215f014b3526a9898d87bfb4b866287f0864cc9 ]

When the indicator and/or summary bits are set in the guest, the accessed page was only marked dirty in KVM if the access was performed using the slow path; accesses through the new kvm_arch_set_irq_inatomic fast inject path would not mark the page as dirty.

Fix by adding/moving the missing calls to mark_page_dirty(). Note that for the inatomic path set_page_dirty{,_lock}() is not needed as the page stays pinned; the unpin path correctly marks it as dirty.

Opportunistically reorder the local variables to be in reverse Christmas tree order and refactor to use guard().

Fixes 1e95e3bc6b05 ("KVM: s390: Enable adapter_indicators_set to use mapped pages")

Message-ID: <[email protected]>

---
 arch/s390/kvm/interrupt.c | 75 ++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 37 deletions(-)
arch/s390/kvm/interrupt.c +38 -37
index d33dd58f4a4fd..70431eb38aa50 100644
@@ -2976,61 +2976,58 @@ static int adapter_indicators_set(struct kvm *kvm,
 				  struct s390_io_adapter *adapter,
 				  struct kvm_s390_adapter_int *adapter_int)
 {
-	unsigned long bit;
-	int summary_set, idx;
 	struct s390_map_info *ind_info, *summary_info;
-	void *map;
 	struct page *ind_page, *summary_page;
-	unsigned long flags;
+	unsigned long bit;
+	int summary_set;
+	void *map;
 
 	ind_page = NULL;
 
-	spin_lock_irqsave(&adapter->maps_lock, flags);
-	ind_info = get_map_info(adapter, adapter_int->ind_addr);
+	scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
+		ind_info = get_map_info(adapter, adapter_int->ind_addr);
+		if (ind_info) {
+			map = page_address(ind_info->page);
+			bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
+			set_bit(bit, map);
+		}
+	}
 	if (!ind_info) {
-		spin_unlock_irqrestore(&adapter->maps_lock, flags);
 		ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0);
 		if (!ind_page)
 			return -1;
-		idx = srcu_read_lock(&kvm->srcu);
 		map = page_address(ind_page);
 		bit = get_ind_bit(adapter_int->ind_addr,
 				  adapter_int->ind_offset, adapter->swap);
 		set_bit(bit, map);
-		mark_page_dirty(kvm, adapter_int->ind_gaddr >> PAGE_SHIFT);
 		set_page_dirty_lock(ind_page);
-		srcu_read_unlock(&kvm->srcu, idx);
 		unpin_user_page(ind_page);
-	} else {
-		map = page_address(ind_info->page);
-		bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
-		set_bit(bit, map);
-		spin_unlock_irqrestore(&adapter->maps_lock, flags);
 	}
+	scoped_guard(srcu, &kvm->srcu)
+		mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
 
-	spin_lock_irqsave(&adapter->maps_lock, flags);
-	summary_info = get_map_info(adapter, adapter_int->summary_addr);
+	scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
+		summary_info = get_map_info(adapter, adapter_int->summary_addr);
+		if (summary_info) {
+			map = page_address(summary_info->page);
+			bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
+					  adapter->swap);
+			summary_set = test_and_set_bit(bit, map);
+		}
+	}
 	if (!summary_info) {
-		spin_unlock_irqrestore(&adapter->maps_lock, flags);
 		summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0);
 		if (WARN_ON_ONCE(!summary_page))
 			return -1;
-		idx = srcu_read_lock(&kvm->srcu);
 		map = page_address(summary_page);
 		bit = get_ind_bit(adapter_int->summary_addr,
 				  adapter_int->summary_offset, adapter->swap);
 		summary_set = test_and_set_bit(bit, map);
-		mark_page_dirty(kvm, adapter_int->summary_gaddr >> PAGE_SHIFT);
 		set_page_dirty_lock(summary_page);
-		srcu_read_unlock(&kvm->srcu, idx);
 		unpin_user_page(summary_page);
-	} else {
-		map = page_address(summary_info->page);
-		bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
-				  adapter->swap);
-		summary_set = test_and_set_bit(bit, map);
-		spin_unlock_irqrestore(&adapter->maps_lock, flags);
 	}
+	scoped_guard(srcu, &kvm->srcu)
+		mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
 
 	return summary_set ? 0 : 1;
 }
@@ -3040,26 +3037,29 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
 				       struct kvm_s390_adapter_int *adapter_int,
 				       int setbit)
 {
+	struct s390_map_info *ind_info, *summary_info;
 	unsigned long bit;
 	int summary_set;
-	struct s390_map_info *ind_info, *summary_info;
 	void *map;
 
-	spin_lock(&adapter->maps_lock);
+	guard(srcu)(&kvm->srcu);
+	guard(spinlock)(&adapter->maps_lock);
+
 	ind_info = get_map_info(adapter, adapter_int->ind_addr);
-	if (!ind_info) {
-		spin_unlock(&adapter->maps_lock);
+	if (!ind_info)
 		return -EWOULDBLOCK;
-	}
+
 	map = page_address(ind_info->page);
 	bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
-	if (setbit)
+	if (setbit) {
 		set_bit(bit, map);
+		mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
+	}
+
 	summary_info = get_map_info(adapter, adapter_int->summary_addr);
-	if (!summary_info) {
-		spin_unlock(&adapter->maps_lock);
+	if (!summary_info)
 		return -EWOULDBLOCK;
-	}
+
 	map = page_address(summary_info->page);
 	bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
 			  adapter->swap);
@@ -3069,7 +3069,8 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
 		summary_set = test_and_set_bit(bit, map);
 	else
 		summary_set = test_and_clear_bit(bit, map);
-	spin_unlock(&adapter->maps_lock);
+	mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
+
 	return summary_set ? 0 : 1;
 }
 
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 7/457 KVM: s390: Fix _gaccess_shadow_fault()

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit faff4c8ff3dbec6d71b89dd281a0d17c4478fa44 ]

In some circumstances, it is possible that the page of nested guest memory that is being shadowed is not present at all in the parent guest gmap. dat_entry_walk() will not find any leaf entry and return with -ENOENT, which will erroneously be propagated all the way to userspace.

Fix by manually calling gmap_link() on the memory of the nested guest that is being shadowed if the mapping was not already present.

Fixes e38c884df921 ("KVM: s390: Switch to new gmap")

Message-ID: <[email protected]>

---
 arch/s390/kvm/gaccess.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/s390/kvm/gaccess.c +13 -0
index 36102b2727fbf..7c1f614ec3146 100644
@@ -1593,12 +1593,25 @@ static inline int ___gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg
 	parent = READ_ONCE(sg->parent);
 	if (!parent)
 		return -EAGAIN;
+retry:
 	scoped_guard(spinlock, &parent->children_lock) {
 		if (READ_ONCE(sg->parent) != parent)
 			return -EAGAIN;
 		sg->invalidated = false;
 		rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk);
 	}
+	if (rc == -ENOENT) {
+		struct kvm_memory_slot *slot;
+		struct guest_fault *entries;
+
+		entries = get_entries(walk);
+		slot = kvm_vcpu_gfn_to_memslot(vcpu, entries[LEVEL_MEM].gfn);
+		if (!slot)
+			return PGM_ADDRESSING;
+		rc = gmap_link(vcpu->arch.mc, parent, entries + LEVEL_MEM, slot);
+		if (!rc)
+			goto retry;
+	}
 	if (!rc)
 		kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
 	return rc;
Signature · 1 line
2.53.0
author maintainer
#8 lore raw

PATCH 8/457 KVM: s390: Fix IRQ injection with SIGP Stop and Store Status

In reply to Greg Kroah-Hartman

7.2-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]>
Stable-dep-of: f3a557067d57 ("KVM: s390: Add missing srcu in kvm_s390_set_irq_state()")

---
 arch/s390/kvm/interrupt.c | 70 +++++++++++++++++++++------------------
 1 file changed, 38 insertions(+), 32 deletions(-)
arch/s390/kvm/interrupt.c +38 -32
index 70431eb38aa50..6397b53e33f52 100644
@@ -1550,23 +1550,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))
@@ -2102,7 +2100,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;
 
@@ -2114,7 +2112,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);
@@ -2150,11 +2148,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;
@@ -3190,7 +3193,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;
 
@@ -3198,31 +3202,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
#9 lore raw

PATCH 9/457 KVM: s390: Add missing srcu in kvm_s390_set_irq_state()

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit f3a557067d57ce6ae98d485c8009b223e16f5f36 ]

Like kvm_s390_inject_vcpu(), kvm_s390_set_irq_state() also needs the kvm->srcu or the slots lock when performing the Store status operation.

Fix by taking kvm->srcu in kvm_s390_set_irq_state().

Fixes ba5c1e9b6cee ("KVM: s390: interrupt subsystem, cpu timer, waitpsw")
Fixes 062e44a9319f ("KVM: s390: Use srcu in kvm_arch_vcpu_unlocked_ioctl()")

Message-ID: <[email protected]>

---
 arch/s390/kvm/interrupt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/kvm/interrupt.c +2 -2
index 6397b53e33f52..80f4802934df9 100644
@@ -3224,9 +3224,9 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len
 				break;
 		}
 	}
-
 	if (storestatus) {
-		n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
+		scoped_guard(srcu, &vcpu->kvm->srcu)
+			n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
 		return r ? r : n;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#10 lore raw

PATCH 10/457 KVM: s390: Properly handle NULL pointer in dat_cond_set_storage_key()

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit 88e22ffd1e46b95e40a6afabe486deb1d31a3ae1 ]

Some callers pass NULL as oldkey. Calling page_cond_set_storage_key() will cause that NULL pointer to get dereferenced.

Fix by checking for NULL and assigning the pointer to a dummy local variable to avoid crashes.

Fixes 8e03e8316eb2 ("KVM: s390: KVM page table management functions: storage keys")

Message-ID: <[email protected]>
Stable-dep-of: 27554b9505dd ("KVM: s390: Fix potential races in dat skey functions")

---
 arch/s390/kvm/dat.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/s390/kvm/dat.c +4 -1
index 3f2d6e8902d76..165c704fcf299 100644
@@ -722,9 +722,12 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
 	if (rc)
 		return rc;
 
-	if (!ptep)
+	if (!ptep) {
+		if (!oldkey)
+			oldkey = &prev;
 		return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
 						 nq, mr, mc);
+	}
 
 	old = pgste_get_lock(ptep);
 	pgste = old;
Signature · 1 line
2.53.0
author maintainer
#11 lore raw

PATCH 11/457 KVM: s390: Fix potential races in dat skey functions

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit 27554b9505ddfc0aeab466aeb60929dfa17284c7 ]

When dat_cond_set_storage_key() finds a large page, it will conditionally set the storage key in absolute memory using large_crste_to_phys() to get the absolute address.

There is a race window between dat_entry_walk() and large_crste_to_phys(): the large page could have been split concurrently, and large_crste_to_phys() might be called with a crste that does not designate a large page, leading to crashes.

Similar issues were also present in dat_set_storage_key().

dat_get_storage_key() and dat_reset_reference_bit() did instead check for a potential concurrent splitting of the large page, but then handled it incorrectly.

Fix by performing a READ_ONCE on the crste pointer, checking and using the result, instead of dereferencing the pointer again. In case a race is detacted, try dat_entry_walk() again.

Fixes 8e03e8316eb2 ("KVM: s390: KVM page table management functions: storage keys")

Message-ID: <[email protected]>

---
 arch/s390/kvm/dat.c | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)
arch/s390/kvm/dat.c +28 -8
index 165c704fcf299..a21cb3975e992 100644
@@ -620,17 +620,20 @@ int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)
 	union pte *ptep;
 	int rc;
 
+again:
 	skey->skey = 0;
 	rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
 	if (rc)
 		return rc;
 
 	if (!ptep) {
-		union crste crste;
+		union crste crste = READ_ONCE(*crstep);
 
-		crste = READ_ONCE(*crstep);
-		if (!crste.h.fc || !crste.s.fc1.pr)
+		if (!crste_leaf(crste) && !crste.h.i)
+			goto again;
+		if (!crste.s.fc1.pr)
 			return 0;
+
 		skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
 		return 0;
 	}
@@ -661,13 +664,20 @@ int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gf
 	union pte *ptep;
 	int rc;
 
+again:
 	rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
 			    &crstep, &ptep);
 	if (rc)
 		return rc;
 
 	if (!ptep) {
-		page_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);
+		union crste crste = READ_ONCE(*crstep);
+
+		/* A large page has been split concurrently, try again */
+		if (!crste_leaf(crste))
+			goto again;
+
+		page_set_storage_key(large_crste_to_phys(crste, gfn), skey.skey, !nq);
 		return 0;
 	}
 
@@ -717,15 +727,22 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
 	union pte *ptep;
 	int rc;
 
+again:
 	rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
 			    &crstep, &ptep);
 	if (rc)
 		return rc;
 
 	if (!ptep) {
+		union crste crste = READ_ONCE(*crstep);
+
+		/* A large page has been split concurrently, try again */
+		if (!crste_leaf(crste))
+			goto again;
 		if (!oldkey)
 			oldkey = &prev;
-		return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
+
+		return page_cond_set_storage_key(large_crste_to_phys(crste, gfn), skey, oldkey,
 						 nq, mr, mc);
 	}
 
@@ -766,7 +783,7 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
 	int rc;
 
 	skey->skey = 0;
-
+again:
 	rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
 	if (rc)
 		return rc;
@@ -774,9 +791,12 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
 	if (!ptep) {
 		union crste crste = READ_ONCE(*crstep);
 
-		if (!crste.h.fc || !crste.s.fc1.pr)
+		/* A large page has been split concurrently, try again */
+		if (!crste_leaf(crste) && !crste.h.i)
+			goto again;
+		if (!crste.s.fc1.pr)
 			return 0;
-		skey->skey = page_reset_referenced(large_crste_to_phys(*crstep, gfn)) << 1;
+		skey->skey = page_reset_referenced(large_crste_to_phys(crste, gfn)) << 1;
 		return 0;
 	}
 	old = pgste_get_lock(ptep);
Signature · 1 line
2.53.0
author maintainer
#12 lore raw

PATCH 12/457 KVM: s390: Fix race in _destroy_pages_crste()

In reply to Greg Kroah-Hartman

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

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

From: Claudio Imbrenda <[email protected]>

[ Upstream commit 4ca00a9154f998116fba9a32cce5bd938d228065 ]

Use READ_ONCE() in _destroy_pages_crste() to read the crste, avoid dereferencing the pointer multiple times.

Fixes a2c17f9270cc ("KVM: s390: New gmap code")

Message-ID: <[email protected]>

---
 arch/s390/kvm/gmap.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kvm/gmap.c +4 -2
index 8abb4f55b306b..f11d4ecaef7be 100644
@@ -991,11 +991,13 @@ static long _destroy_pages_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct da
 static long _destroy_pages_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
 {
 	phys_addr_t origin, cur, end;
+	union crste crste;
 
-	if (!crstep->h.fc || !crstep->s.fc1.pr)
+	crste = READ_ONCE(*crstep);
+	if (!crste.h.fc || !crste.s.fc1.pr)
 		return 0;
 
-	origin = crste_origin_large(*crstep);
+	origin = crste_origin_large(crste);
 	cur = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
 	end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
 	for ( ; cur < end; cur += PAGE_SIZE)
Signature · 1 line
2.53.0
author maintainer
#13 lore raw

PATCH 13/457 s390/uv: Fix loop condition in uv_find_secrets

In reply to Greg Kroah-Hartman

7.2-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 a284f98d97168..d970b15ef126d 100644
@@ -781,11 +781,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)
@@ -796,7 +799,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
#14 lore raw

PATCH 14/457 s390/uv: Prevent potential out-of-bounds read

In reply to Greg Kroah-Hartman

7.2-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 d970b15ef126d..e70acad09cd5f 100644
@@ -760,7 +760,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
#15 lore raw

PATCH 15/457 bpf: Fix bpf_skb_change_tail wrt csum partial skbs

In reply to Greg Kroah-Hartman

7.2-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 1e80a52ef86d0..73c6fa3d73467 100644
@@ -3871,12 +3871,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;
 }
 
@@ -3893,6 +3887,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
#16 lore raw

PATCH 16/457 bpf: Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL

In reply to Greg Kroah-Hartman

7.2-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 73c6fa3d73467..d0465db6f1c42 100644
@@ -8881,6 +8881,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
#17 lore raw

PATCH 17/457 selftests/ftrace: Fix unique symbol check in kprobe_non_uniq_symbol.tc

In reply to Greg Kroah-Hartman

7.2-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
#18 lore raw

PATCH 18/457 bpf: Fix divide-by-zero in btf_struct_walk()

In reply to Greg Kroah-Hartman

7.2-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 022d5a594dc95..ea3d50c99ec22 100644
@@ -7191,7 +7191,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
#19 lore raw

PATCH 19/457 bpf: Fix out-of-bounds read of sk_protocol in bpf_sock_destroy()

In reply to Greg Kroah-Hartman

7.2-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 d0465db6f1c42..5769fd10227f3 100644
@@ -12659,8 +12659,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)
@@ -12672,8 +12673,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
#20 lore raw

PATCH 20/457 tcp: Skip cond_resched() in inet_csk_listen_stop() under BPF context

In reply to Greg Kroah-Hartman

7.2-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 6257459bcee24..6a30f11384547 100644
@@ -1520,7 +1520,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
#21 lore raw

PATCH 21/457 HID: multitouch: Add report ID mismatch quirk for ASUS ROG Z13 Folio

In reply to Greg Kroah-Hartman

7.2-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 571166a769b90..e9da59e4bf795 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
@@ -235,6 +236,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
@@ -405,6 +407,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 |
@@ -507,6 +519,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;
@@ -528,8 +541,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;
 		}
@@ -2726,6 +2745,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
#22 lore raw

PATCH 22/457 HID: winwing: fix use-after-free in force feedback teardown

In reply to Greg Kroah-Hartman

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

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

From: René Onier <[email protected]>

[ Upstream commit a1a5ad37e50ceb192c07ac7e2d7143638cd4d110 ]

winwing_init_ff() passes the driver's private data, allocated with devm_kzalloc() in winwing_probe(), as the effect context to input_ff_create_memless(). The memoryless force-feedback core takes ownership of that pointer and frees it with kfree() from input_ff_destroy() (ml_ff_destroy()) when the input device is destroyed.

Freeing a devm-managed allocation with kfree() is an invalid free, and the same object is then released again by devres when the HID device is torn down, a double free. As the allocation also embeds the LED class devices, their timers and work item live on freed memory and the slab gets corrupted. This triggers on unbind, rmmod, hot-unplug and on system suspend, where the firmware cache walks the now-corrupt devres list. KASAN reports:

  BUG: KASAN: invalid-free in input_ff_destroy
  Allocated by task N:
    winwing_probe

Pass NULL as the memless context instead and fetch the driver data from the input device in winwing_play_effect(): the HID core already stores the hid_device as the input device's drvdata. The force-feedback core then owns nothing that it must not free.

Fixes 42d020b54edc ("HID: winwing: Enable rumble effects")
---
 drivers/hid/hid-winwing.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/hid/hid-winwing.c +8 -2
index 9cd25a77999e6..19b92c2c6579a 100644
@@ -315,7 +315,8 @@ static void winwing_haptic_rumble_cb(struct work_struct *work)
 static int winwing_play_effect(struct input_dev *dev, void *context,
 		struct ff_effect *effect)
 {
-	struct winwing_drv_data *data = (struct winwing_drv_data *) context;
+	struct hid_device *hdev = input_get_drvdata(dev);
+	struct winwing_drv_data *data = hid_get_drvdata(hdev);
 
 	if (effect->type != FF_RUMBLE)
 		return 0;
@@ -342,7 +343,12 @@ static int winwing_init_ff(struct hid_device *hdev, struct hid_input *hidinput)
 
 	input_set_capability(hidinput->input, EV_FF, FF_RUMBLE);
 
-	return input_ff_create_memless(hidinput->input, data,
+	/*
+	 * input_ff_create_memless() takes ownership of the context pointer
+	 * and frees it on teardown; do not hand it the devm-managed drvdata.
+	 * winwing_play_effect() fetches it from the input device instead.
+	 */
+	return input_ff_create_memless(hidinput->input, NULL,
 			winwing_play_effect);
 }
 
Signature · 1 line
2.53.0
author maintainer
#23 lore raw

PATCH 23/457 HID: elecom: fix bus type for M-XGL20DLBK

In reply to Greg Kroah-Hartman

7.2-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 57d8efdd9b890..0ad8ca20cb9d1 100644
@@ -422,7 +422,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
#24 lore raw

PATCH 24/457 KVM: x86/pmu: Move Intel PMU global MSRs to intel_is_valid_msr()

In reply to Greg Kroah-Hartman

7.2-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 dd1c57593f48b..7fedf25cf46fe 100644
@@ -812,14 +812,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 1944939c4139f..e65ba7e856117 100644
@@ -187,6 +187,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
#25 lore raw

PATCH 25/457 bpf: Allow terminal gotox instructions

In reply to Greg Kroah-Hartman

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

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

From: Siddharth Chintamaneni <[email protected]>

[ Upstream commit 0d7823cd4cda35f2060a685fa276ff7709915abc ]

check_subprogs() treats gotox as a direct jump and validates its reserved zero offset. When gotox is the final instruction, this produces a synthetic successor one instruction past the end of the subprogram and rejects an otherwise valid program.

Skip direct-offset validation for gotox and accept it as a non-fallthrough terminal instruction. Its actual targets remain validated from the instruction-array jump table during CFG construction.

---
 kernel/bpf/verifier.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
kernel/bpf/verifier.c +4 -1
index 1a0cd37b03cde..dc1a9ef32b78e 100644
@@ -2876,6 +2876,8 @@ static int check_subprogs(struct bpf_verifier_env *env)
 			subprog[cur_subprog].exit_idx = i;
 			goto next;
 		}
+		if (insn_is_gotox(&insn[i]))
+			goto next;
 		off = i + bpf_jmp_offset(&insn[i]) + 1;
 		if (off < subprog_start || off >= subprog_end) {
 			verbose(env, "jump out of range from insn %d to %d\n", i, off);
@@ -2889,7 +2891,8 @@ static int check_subprogs(struct bpf_verifier_env *env)
 			 */
 			if (code != (BPF_JMP | BPF_EXIT) &&
 			    code != (BPF_JMP32 | BPF_JA) &&
-			    code != (BPF_JMP | BPF_JA)) {
+			    code != (BPF_JMP | BPF_JA) &&
+			    !insn_is_gotox(&insn[i])) {
 				verbose(env, "last insn is not an exit or jmp\n");
 				return -EINVAL;
 			}
Signature · 1 line
2.53.0
author maintainer
#26 lore raw

PATCH 26/457 bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()

In reply to Greg Kroah-Hartman

7.2-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 59406da06424d..419692f41ffde 100644
@@ -1773,6 +1773,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,
@@ -1794,6 +1800,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;
 
@@ -1972,12 +1979,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();
@@ -1991,11 +2007,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
#27 lore raw

PATCH 27/457 bpf: Fix out-of-bounds read of rtt_min in sock_ops

In reply to Greg Kroah-Hartman

7.2-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 5769fd10227f3..70f19ef093ee1 100644
@@ -10943,18 +10943,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
#28 lore raw

PATCH 28/457 bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk

In reply to Greg Kroah-Hartman

7.2-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 e9662db7198fe..8a8f088e83e6f 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);
 }
 
@@ -300,7 +304,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;
@@ -535,6 +540,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);
 		}
@@ -557,7 +563,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);
 		}
@@ -609,7 +615,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
#29 lore raw

PATCH 29/457 bpf, sockmap: Fix self-redirect copied_seq double-counting

In reply to Greg Kroah-Hartman

7.2-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 2521b643fa05d..df385a5a961e8 100644
@@ -1000,6 +1000,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
#30 lore raw

PATCH 30/457 bpf: Fix u32 overflow issue in map batch operations

In reply to Greg Kroah-Hartman

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

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

From: Masoud Aghasi <[email protected]>

[ Upstream commit 953824e508b27d12837e32ef37ef6248e1f6fc7a ]

Several map batch operation implementations such as generic_map_lookup_batch() use calculations in the form of "values + cp * map->value_size" to compute the desired userspace memory address for reading or writing. This can overflow the u32 type (the result of "cp * map->value_size") when the map size exceeds 4GB.

generic_map_lookup_batch() may corrupt values for some keys in userspace memory, and in some cases it mismatches values for some keys while still reporting success.

Other batch operations may fail to delete or update some keys, or the syscall may return unexpected errors.

Add size_t casts to prevent the affected offset and size calculations from overflowing.

Fixes cb4d03ab499d ("bpf: Add generic support for lookup batch op")
Fixes aa2e93b8e58e ("bpf: Add generic support for update and delete batch ops")
Fixes 057996380a42 ("bpf: Add batch ops to all htab bpf map")
---
 kernel/bpf/hashtab.c |  8 ++++----
 kernel/bpf/syscall.c | 10 +++++-----
 2 files changed, 9 insertions(+), 9 deletions(-)
kernel/bpf/hashtab.c +4 -4
index 419692f41ffde..5117447ac291b 100644
@@ -1998,10 +1998,10 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 
 	rcu_read_unlock();
 	bpf_enable_instrumentation();
-	if (bucket_cnt && (copy_to_user(ukeys + total * key_size, keys,
-	    key_size * bucket_cnt) ||
-	    copy_to_user(uvalues + total * value_size, values,
-	    value_size * bucket_cnt))) {
+	if (bucket_cnt && (copy_to_user(ukeys + (size_t)total * key_size, keys,
+	    (size_t)key_size * bucket_cnt) ||
+	    copy_to_user(uvalues + (size_t)total * value_size, values,
+	    (size_t)value_size * bucket_cnt))) {
 		ret = -EFAULT;
 		goto after_loop;
 	}
kernel/bpf/syscall.c +5 -5
index c7cb336fb0648..57d61de03306e 100644
@@ -2033,7 +2033,7 @@ int generic_map_delete_batch(struct bpf_map *map,
 
 	for (cp = 0; cp < max_count; cp++) {
 		err = -EFAULT;
-		if (copy_from_user(key, keys + cp * map->key_size,
+		if (copy_from_user(key, keys + (size_t)cp * map->key_size,
 				   map->key_size))
 			break;
 
@@ -2095,9 +2095,9 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
 
 	for (cp = 0; cp < max_count; cp++) {
 		err = -EFAULT;
-		if (copy_from_user(key, keys + cp * map->key_size,
+		if (copy_from_user(key, keys + (size_t)cp * map->key_size,
 		    map->key_size) ||
-		    copy_from_user(value, values + cp * value_size, value_size))
+		    copy_from_user(value, values + (size_t)cp * value_size, value_size))
 			break;
 
 		err = bpf_map_update_value(map, map_file, key, value,
@@ -2176,12 +2176,12 @@ int generic_map_lookup_batch(struct bpf_map *map,
 		if (err)
 			goto free_buf;
 
-		if (copy_to_user(keys + cp * map->key_size, key,
+		if (copy_to_user(keys + (size_t)cp * map->key_size, key,
 				 map->key_size)) {
 			err = -EFAULT;
 			goto free_buf;
 		}
-		if (copy_to_user(values + cp * value_size, value, value_size)) {
+		if (copy_to_user(values + (size_t)cp * value_size, value, value_size)) {
 			err = -EFAULT;
 			goto free_buf;
 		}
Signature · 1 line
2.53.0
author maintainer
#31 lore raw

PATCH 31/457 bpf, arm64: set up the frame pointer for the exception callback

In reply to Greg Kroah-Hartman

7.2-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 d4e62484baea0..8c0c9b0fda16f 100644
@@ -600,6 +600,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
#32 lore raw

PATCH 32/457 pinctrl: meson: Fix typo in s4 group name

In reply to Greg Kroah-Hartman

7.2-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
#33 lore raw

PATCH 33/457 pinctrl: generic: serialise pinctrl_generic_dt_node_to_map()

In reply to Greg Kroah-Hartman

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

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

From: Sarah Emery <[email protected]>

[ Upstream commit 51ae99659469edba2e83931efa26b77d36ca02c2 ]

pinctrl_generic_add_group() documents that the caller must take care of locking, and pinmux_generic_add_function() needs it too, but pinctrl_generic_dt_node_to_map() calls them without holding pctldev->mutex, and the core caller in create_pinctrl() does not take it either.

The driver core calls pinctrl_bind_pins() before probing a device, so two devices that reference the same pin controller can run pinctrl_generic_dt_node_to_map() on one pctldev at the same time.

Both add functions take the new selector from pctldev->num_groups or pctldev->num_functions, and radix_tree_insert() at that index. Two racing callers can read the same selector before either has inserted, so the second insert collides and fails:

k1-pinctrl d401e000.pinctrl:
error -EEXIST: error adding function pcie2-0-cfg k1-pinctrl d401e000.pinctrl:
does not have pin group pcie0-0-cfg.pcie0-0-pins

leaving one consumer without its pin configuration.

This was hit on a SpacemiT K3 board, where PCIe devices probe in parallel against the single shared pin controller.

Take pctldev->mutex across the whole function, so that the groups and the function referring are in a single critical section.

Fixes 43722575e5cd ("pinctrl: add generic functions + pins mapper")
---
 drivers/pinctrl/pinctrl-generic.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/pinctrl/pinctrl-generic.c +4 -0
index fd6bdb74028aa..4277c87485135 100644
@@ -3,8 +3,10 @@
 #define pr_fmt(fmt) "generic pinconfig core: " fmt
 
 #include <linux/array_size.h>
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 
@@ -196,6 +198,8 @@ static int pinctrl_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
 	int ngroups = 0;
 	int ret;
 
+	guard(mutex)(&pctldev->mutex);
+
 	*maps = NULL;
 	*num_maps = 0;
 
Signature · 1 line
2.53.0
author maintainer
#34 lore raw

PATCH 34/457 HID: amd_sfh: Validate PCI BAR size before mapping

In reply to Greg Kroah-Hartman

7.2-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
#35 lore raw

PATCH 35/457 HID: bpf: fix __hid_bpf_hw_check_params report length

In reply to Greg Kroah-Hartman

7.2-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 536f6d01fd14c..b1de1dd0f21d0 100644
@@ -359,7 +359,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;
@@ -388,6 +388,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;
 
@@ -420,7 +424,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;
 
@@ -480,7 +484,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;
 
@@ -506,7 +510,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
#36 lore raw

PATCH 36/457 RISC-V: KVM: Fix the conversion between vsip and hvip

In reply to Greg Kroah-Hartman

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

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

From: Yicong Yang <[email protected]>

[ Upstream commit 52c6b7d20d3e791a9e75aa2be2a467990154c7cd ]

Per AIA spec 1.0 Section 6.3.2, the interrupt numbers 13-63 shares same bit position between related VS shadow CSRs and hypervisor CSRs. So there's a shift only for SSI, STI and SEI interrupt.

Currently the KVM always does a shift for all the interrupts (include LCOFI with number 13) when doing the conversion between vsip and hvip. Fix this by only doing shift the SSI, STI and SEI. Add wrappers for doing the conversion between vsip and hvip.

Fixes 16b0bde9a37c ("RISC-V: KVM: Add perf sampling support for guests")
---
 arch/riscv/include/asm/csr.h       | 20 ++++++++++++++++----
 arch/riscv/kvm/vcpu.c              |  3 +--
 arch/riscv/kvm/vcpu_onereg.c       |  8 +++-----
 tools/arch/riscv/include/asm/csr.h | 20 ++++++++++++++++----
 4 files changed, 36 insertions(+), 15 deletions(-)
arch/riscv/include/asm/csr.h +16 -4
index 31b8988f4488d..72ff259154e9b 100644
@@ -183,12 +183,24 @@
 #define HGATP_MODE_SHIFT	HGATP32_MODE_SHIFT
 #endif
 
-/* VSIP & HVIP relation */
+/*
+ * VSIP & HVIP relation
+ *
+ * The bit positions are same between VSIP and HVIP for interrupt
+ * numbers 13-63, where there's a shift for the SSI, STI and SEI.
+ */
 #define VSIP_TO_HVIP_SHIFT	(IRQ_VS_SOFT - IRQ_S_SOFT)
-#define VSIP_VALID_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
+#define VSIP_BIAS_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
 				 (_AC(1, UL) << IRQ_S_TIMER) | \
-				 (_AC(1, UL) << IRQ_S_EXT) | \
-				 (_AC(1, UL) << IRQ_PMU_OVF))
+				 (_AC(1, UL) << IRQ_S_EXT))
+#define VSIP_NO_BIAS_MASK	(_AC(1, UL) << IRQ_PMU_OVF)
+#define VSIP_VALID_MASK		(VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
+#define vsip_to_hvip(_vsip)	((((_vsip) & VSIP_BIAS_MASK) << \
+				  VSIP_TO_HVIP_SHIFT) | \
+				 ((_vsip) & VSIP_NO_BIAS_MASK))
+#define hvip_to_vsip(_hvip)	((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
+				  VSIP_BIAS_MASK) | \
+				 ((_hvip) & VSIP_NO_BIAS_MASK))
 
 /* AIA CSR bits */
 #define TOPI_IID_SHIFT		16
arch/riscv/kvm/vcpu.c +1 -2
index 977e36ab83d3f..468918309dff3 100644
@@ -475,8 +475,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
 	bool ret;
 
 	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
-	ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
-		<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
+	ie = vsip_to_hvip(vcpu->arch.guest_csr.vsie) & (unsigned long)mask;
 	ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
 		(unsigned long)mask;
 	ret = vcpu->arch.irqs_pending[0] & ie;
arch/riscv/kvm/vcpu_onereg.c +3 -5
index 99b9107b1ac18..9fe829eed1781 100644
@@ -272,7 +272,7 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
 
 	if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
 		kvm_riscv_vcpu_flush_interrupts(vcpu);
-		*out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK;
+		*out_val = hvip_to_vsip(csr->hvip);
 		*out_val |= csr->hvip & ~IRQ_LOCAL_MASK;
 	} else
 		*out_val = ((unsigned long *)csr)[reg_num];
@@ -293,10 +293,8 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
 
 	reg_num = array_index_nospec(reg_num, regs_max);
 
-	if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
-		reg_val &= VSIP_VALID_MASK;
-		reg_val <<= VSIP_TO_HVIP_SHIFT;
-	}
+	if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
+		reg_val = vsip_to_hvip(reg_val);
 
 	((unsigned long *)csr)[reg_num] = reg_val;
 
tools/arch/riscv/include/asm/csr.h +16 -4
index 21d8cee046383..8df64314d6131 100644
@@ -163,12 +163,24 @@
 #define HGATP_MODE_SHIFT	HGATP32_MODE_SHIFT
 #endif
 
-/* VSIP & HVIP relation */
+/*
+ * VSIP & HVIP relation
+ *
+ * The bit positions are same between VSIP and HVIP for interrupt
+ * numbers 13-63, where there's a shift for the SSI, STI and SEI.
+ */
 #define VSIP_TO_HVIP_SHIFT	(IRQ_VS_SOFT - IRQ_S_SOFT)
-#define VSIP_VALID_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
+#define VSIP_BIAS_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
 				 (_AC(1, UL) << IRQ_S_TIMER) | \
-				 (_AC(1, UL) << IRQ_S_EXT) | \
-				 (_AC(1, UL) << IRQ_PMU_OVF))
+				 (_AC(1, UL) << IRQ_S_EXT))
+#define VSIP_NO_BIAS_MASK	(_AC(1, UL) << IRQ_PMU_OVF)
+#define VSIP_VALID_MASK		(VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
+#define vsip_to_hvip(_vsip)	((((_vsip) & VSIP_BIAS_MASK) << \
+				  VSIP_TO_HVIP_SHIFT) | \
+				 ((_vsip) & VSIP_NO_BIAS_MASK))
+#define hvip_to_vsip(_hvip)	((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
+				  VSIP_BIAS_MASK) | \
+				 ((_hvip) & VSIP_NO_BIAS_MASK))
 
 /* AIA CSR bits */
 #define TOPI_IID_SHIFT		16
Signature · 1 line
2.53.0
author maintainer
#37 lore raw

PATCH 37/457 KVM: riscv: Fix NACL hfence entry update order

In reply to Greg Kroah-Hartman

7.2-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 6f9f8963e9ddc..0a2a50c6ce035 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
#38 lore raw

PATCH 38/457 RISC-V: KVM: Preserve firmware counter value across stop/start

In reply to Greg Kroah-Hartman

7.2-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 a7f948410d531..904d266a66c44 100644
@@ -675,10 +675,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 */
@@ -696,9 +698,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
#39 lore raw

PATCH 39/457 RISC-V: KVM: Report snapshot write failure to the guest

In reply to Greg Kroah-Hartman

7.2-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 904d266a66c44..a749591a675de 100644
@@ -727,9 +727,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
#40 lore raw

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

In reply to Greg Kroah-Hartman

7.2-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 a749591a675de..73d76fd19896b 100644
@@ -270,12 +270,13 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
 			return -EINVAL;
 
 		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;
 }
@@ -645,7 +646,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;
@@ -683,8 +683,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;
@@ -698,9 +701,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 indices 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
#41 lore raw

PATCH 41/457 KVM: arm64: vgic-its: Free the caches when GITS_BASER changes

In reply to Greg Kroah-Hartman

7.2-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 ed281fbf008b9..b9a6316f2e00a 100644
@@ -1658,7 +1658,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. */
@@ -1681,7 +1681,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;
 
@@ -1691,7 +1693,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) {
@@ -1702,6 +1705,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
#42 lore raw

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

In reply to Greg Kroah-Hartman

7.2-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 b9a6316f2e00a..7dc5ef5a6e33a 100644
@@ -2024,18 +2024,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)
@@ -2275,17 +2279,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) |
@@ -2384,15 +2389,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
#43 lore raw

PATCH 43/457 KVM: arm64: Validate the SVE vector length in pkvm_vcpu_init_sve()

In reply to Greg Kroah-Hartman

7.2-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 24d6f164129ac..095ebfce91b08 100644
@@ -460,14 +460,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
#44 lore raw

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

In reply to Greg Kroah-Hartman

7.2-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 095ebfce91b08..73e6ee059eebb 100644
@@ -451,7 +451,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);
@@ -462,24 +462,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
#45 lore raw

PATCH 45/457 KVM: arm64: Derive GUEST_HAS_SVE from the SVE feature bit at EL2

In reply to Greg Kroah-Hartman

7.2-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 73e6ee059eebb..53532f0c41628 100644
@@ -360,7 +360,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))
@@ -379,13 +379,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
#46 lore raw

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

In reply to Greg Kroah-Hartman

7.2-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 b11b8821c9fbc..dfa25bb6f25d4 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
#47 lore raw

PATCH 47/457 KVM: arm64: Match hyp text by physical address in fix_host_ownership()

In reply to Greg Kroah-Hartman

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

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

From: Fuad Tabba <[email protected]>

[ Upstream commit 5a8b505ede133fb30ca3b3a19d0db00c08237615 ]

On a non-hVHE host, fix_host_ownership_walker()'s test for PAGE_HYP_EXEC never matches: KVM_PGTABLE_PROT_UX is cleared at map time and only PX is reported on read-back. Hyp text is therefore donated rather than left read-only in the host stage-2, and the instruction dump in nvhe_hyp_panic_handler() reads a page the host has no access to.

Match the text by physical address instead, in a helper a later patch reuses. A test on the permissions would leave any other executable mapping host-readable too.

---
 arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 1 +
 arch/arm64/kvm/hyp/nvhe/mem_protect.c         | 8 ++++++++
 arch/arm64/kvm/hyp/nvhe/setup.c               | 2 +-
 3 files changed, 10 insertions(+), 1 deletion(-)
arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +1 -0
index 29935c7da1dec..cab27f7bd423a 100644
@@ -52,6 +52,7 @@ int __pkvm_host_test_clear_young_guest(u64 gfn, u64 nr_pages, bool mkold, struct
 int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu);
 
 bool addr_is_memory(phys_addr_t phys);
+bool addr_is_hyp_text(phys_addr_t phys);
 int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);
 int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id);
 int kvm_host_prepare_stage2(void *pgt_pool_base);
arch/arm64/kvm/hyp/nvhe/mem_protect.c +8 -0
index 4e329e39a695a..7a99361306426 100644
@@ -443,6 +443,14 @@ bool addr_is_memory(phys_addr_t phys)
 	return !!find_mem_range(phys, &range);
 }
 
+bool addr_is_hyp_text(phys_addr_t phys)
+{
+	phys_addr_t start = ALIGN_DOWN(__hyp_pa(__hyp_text_start), PAGE_SIZE);
+	phys_addr_t end = PAGE_ALIGN(__hyp_pa(__hyp_text_end));
+
+	return phys >= start && phys < end;
+}
+
 static bool is_in_mem_range(u64 addr, struct kvm_mem_range *range)
 {
 	return range->start <= addr && addr < range->end;
arch/arm64/kvm/hyp/nvhe/setup.c +1 -1
index 75b00c3233102..1bdb952c662b1 100644
@@ -217,7 +217,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
 	case PKVM_PAGE_OWNED:
 		set_hyp_state(page, PKVM_PAGE_OWNED);
 		/* hyp text is RO in the host stage-2 to be inspected on panic. */
-		if (prot == PAGE_HYP_EXEC) {
+		if (addr_is_hyp_text(phys)) {
 			set_host_state(page, PKVM_NOPAGE);
 			return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R);
 		} else {
Signature · 1 line
2.53.0
author maintainer
#48 lore raw

PATCH 48/457 KVM: selftests: fix steal_time for arm64 with host page size > 4K

In reply to Greg Kroah-Hartman

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

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

From: Sebastian Ott <[email protected]>

[ Upstream commit 96e6757cb0674acb86ee8b558ee6bffe0eec0bb0 ]

Fix the following failure when running with 16K host page size:
==== Test Assertion Failure ====
lib/kvm_util.c:991: vm_adjust_num_guest_pages(vm->mode, npages) == npages pid=873 tid=873 errno=0 - Success

     1  0x0000000000405a27: vm_mem_add at kvm_util.c:991
     2  0x000000000040241f: check_steal_time_uapi at steal_time.c:223 (discriminator 7)
     3   (inlined by) main at steal_time.c:539 (discriminator 7)
     4  0x00007fff8b57af3b: ?? ??:0
     5  0x00007fff8b57b007: ?? ??:0
     6  0x0000000000402b6f: _start at ??:?

Number of guest pages is not compatible with the host. Try npages=4

---
 tools/testing/selftests/kvm/steal_time.c | 30 ++++++++++++++++--------
 1 file changed, 20 insertions(+), 10 deletions(-)
tools/testing/selftests/kvm/steal_time.c +20 -10
index 76fcdd1fd3cb4..c00cb17f9e40b 100644
@@ -27,6 +27,9 @@
 static void *st_gva[NR_VCPUS];
 static u64 guest_stolen_time[NR_VCPUS];
 
+static struct kvm_vm *vm_create_steal_time(u32 nr_vcpus, void *guest_code,
+					   struct kvm_vcpu *vcpus[]);
+
 #if defined(__x86_64__)
 
 /* steal_time must have 64-byte alignment */
@@ -211,17 +214,14 @@ static void check_steal_time_uapi(void)
 	u64 st_ipa;
 	int ret;
 
-	vm = vm_create_with_one_vcpu(&vcpu, NULL);
-
 	struct kvm_device_attr dev = {
 		.group = KVM_ARM_VCPU_PVTIME_CTRL,
 		.attr = KVM_ARM_VCPU_PVTIME_IPA,
 		.addr = (u64)&st_ipa,
 	};
 
+	vm = vm_create_steal_time(1, NULL, &vcpu);
 	vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev);
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, 1, 0);
-	virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, 1);
 
 	st_ipa = (ulong)ST_GPA_BASE | 1;
 	ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
@@ -504,6 +504,21 @@ static void run_vcpu(struct kvm_vcpu *vcpu)
 	}
 }
 
+static struct kvm_vm *vm_create_steal_time(u32 nr_vcpus, void *guest_code,
+					   struct kvm_vcpu *vcpus[])
+{
+	unsigned int gpages;
+	struct kvm_vm *vm;
+
+	/* Create a VM and an identity mapped memslot for the steal time structure */
+	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * nr_vcpus);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+	virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages);
+
+	return vm;
+}
+
 int main(int ac, char **av)
 {
 	struct kvm_vcpu *vcpus[NR_VCPUS];
@@ -511,7 +526,6 @@ int main(int ac, char **av)
 	pthread_attr_t attr;
 	pthread_t thread;
 	cpu_set_t cpuset;
-	unsigned int gpages;
 	long stolen_time;
 	long run_delay;
 	bool verbose;
@@ -526,11 +540,7 @@ int main(int ac, char **av)
 	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
 	pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
 
-	/* Create a VM and an identity mapped memslot for the steal time structure */
-	vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
-	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * NR_VCPUS);
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
-	virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages);
+	vm = vm_create_steal_time(NR_VCPUS, guest_code, vcpus);
 
 	ksft_print_header();
 	TEST_REQUIRE(is_steal_time_supported(vcpus[0]));
Signature · 1 line
2.53.0
author maintainer
#49 lore raw

PATCH 49/457 KVM: arm64: Fix FGT mapping for HFGITR_EL2.nGCSEPP

In reply to Greg Kroah-Hartman

7.2-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 3c82f392845d1..b32742d9dd73e 100644
@@ -1432,7 +1432,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
#50 lore raw

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

In reply to Greg Kroah-Hartman

7.2-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 0a4ff3ec9c8cd..6610af2414493 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
#51 lore raw

PATCH 51/457 scsi: block: Fix zones_cond out-of-bounds write on zone report

In reply to Greg Kroah-Hartman

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

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

From: ZHOU Jiaxiang <[email protected]>

[ Upstream commit 7c431d61b69a3fd0784c20aa4cd0b8fb501b5653 ]

blk_revalidate_disk_zones() sizes the zones_cond array from the disk capacity and zone size, but the index used by blk_revalidate_zone_cond() comes from the device-driven report_zones() walk and is never checked against the array size. A device reporting more zones than fit the array makes blk_zone_set_cond() write out of bounds.

One way to reach this is a zone count exceeding 32 bits: both blk_revalidate_zone_args.nr_zones and struct zoned_disk_info.nr_zones are unsigned int, so a disk advertising more than UINT_MAX zones (e.g. 2^32 + 1024 zones of one 512-byte logical block) gets its zone count truncated to a small value, undersizing the array while the report walk keeps counting upward.

Check the index against the array size before storing the zone condition, and refuse to revalidate when the zone count does not fit 32 bits.

Fixes 6e945ffb6555 ("block: use zone condition to determine conventional zones")
---
 block/blk-zoned.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
block/blk-zoned.c +13 -2
index ca30caec838e7..dd6bc679210c8 100644
@@ -2048,12 +2048,17 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
 				struct blk_revalidate_zone_args *args)
 {
 	struct queue_limits *lim = &disk->queue->limits;
+	unsigned long long nr_zones;
 	unsigned int pool_size;
 	int ret = 0;
 
 	args->disk = disk;
-	args->nr_zones =
-		DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
+	nr_zones = DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
+	if (nr_zones > UINT_MAX) {
+		pr_warn("%s: Too many zones (%llu)\n", disk->disk_name, nr_zones);
+		return -EINVAL;
+	}
+	args->nr_zones = nr_zones;
 
 	/* Cached zone conditions: 1 byte per zone */
 	args->zones_cond = kzalloc(args->nr_zones, GFP_NOIO);
@@ -2161,6 +2166,12 @@ static int blk_revalidate_zone_cond(struct blk_zone *zone, unsigned int idx,
 {
 	enum blk_zone_cond cond = zone->cond;
 
+	if (idx >= args->nr_zones) {
+		pr_warn("%s: Zone report index %u exceeds zone count %u\n",
+			args->disk->disk_name, idx, args->nr_zones);
+		return -EINVAL;
+	}
+
 	/* Check that the zone condition is consistent with the zone type. */
 	switch (cond) {
 	case BLK_ZONE_COND_NOT_WP:
Signature · 1 line
2.53.0
author maintainer
#52 lore raw

PATCH 52/457 scsi: sd_zbc: Reject disks with too many zones

In reply to Greg Kroah-Hartman

7.2-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 56e455fb5addd..456beaf2e7690 100644
@@ -589,7 +589,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;
 
@@ -621,6 +621,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
#53 lore raw

PATCH 53/457 pinctrl: sunxi: A523: fix voltage withstand encoding

In reply to Greg Kroah-Hartman

7.2-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 25489beeb3125..7b33bcb7f840a 100644
@@ -728,6 +728,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;
 
@@ -766,6 +767,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;
 
@@ -780,6 +784,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 0daf7600e2fb0..b09df32a3073a 100644
@@ -116,8 +116,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
#54 lore raw

PATCH 54/457 Bluetooth: SMP: reject Security Request over BR/EDR

In reply to Greg Kroah-Hartman

7.2-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 c4470958b0d57..14bb2c82a5624 100644
@@ -2268,6 +2268,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
#55 lore raw

PATCH 55/457 Bluetooth: btnxpuart: Fix skb leak in nxp_process_fw_dump()

In reply to Greg Kroah-Hartman

7.2-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 e6c15bc6a30b9..73b319c7e1765 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
#56 lore raw

PATCH 56/457 Bluetooth: mgmt: Dequeue pending mesh_send_sync entries on cancel

In reply to Greg Kroah-Hartman

7.2-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 deced8a5bc2d6..9bcc35de08899 100644
@@ -2310,6 +2310,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;
 	}
 
@@ -2419,19 +2421,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
#57 lore raw

PATCH 57/457 selftests: cgroup: give the O_TMPFILE open in get_temp_fd() a mode

In reply to Greg Kroah-Hartman

7.2-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 3a84d068fbf36..0ed82347044ed 100644
@@ -30,7 +30,7 @@ static int page_size;
 
 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
#58 lore raw

PATCH 58/457 scsi: megaraid_sas: Protect megasas_get_ctrl_info() in megasas_resume()

In reply to Greg Kroah-Hartman

7.2-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 d83abded2039b..f25ed22195fa6 100644
@@ -7886,7 +7886,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
#59 lore raw

PATCH 59/457 s390/pci/docs: Fix sriov_numvfs attribute name

In reply to Greg Kroah-Hartman

7.2-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 80f4ba1931599..565434626fb5c 100644
@@ -67,7 +67,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
#60 lore raw

PATCH 60/457 s390/cio: Fix cio_update_schib() to not cache invalid schib

In reply to Greg Kroah-Hartman

7.2-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 70dc8cc765948..e1c62eb60cca7 100644
@@ -453,7 +453,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)
 {
@@ -462,10 +463,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
#61 lore raw

PATCH 61/457 s390/cio: Check pmcw.dnv before pmcw.ena in I/O entry points

In reply to Greg Kroah-Hartman

7.2-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
#62 lore raw

PATCH 62/457 s390/cio: Guard PMCW field accesses with dnv check

In reply to Greg Kroah-Hartman

7.2-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 c890f21a82ce3..eaf0527bff6cc 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 fb591118ecb2a..68dd4a62975d2 100644
@@ -922,7 +922,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);
@@ -941,7 +941,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);
@@ -1207,7 +1207,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)
@@ -1254,7 +1254,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
#63 lore raw

PATCH 63/457 netfs: Fix netfs_read_gaps() to use separate sink folios

In reply to Greg Kroah-Hartman

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

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

From: David Howells <[email protected]>

[ Upstream commit fc3ae66514ca5e87251f79044236e3e8babd24a3 ]

Fix netfs_read_gaps() to use separate folios rather than re-using a single sink folio to discard the unwanted data so that cifs checksum checking sees all the data that was fetched.

---
 fs/netfs/buffered_read.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)
fs/netfs/buffered_read.c +19 -15
index 424df70a5c30f..105194de6e13e 100644
@@ -482,15 +482,14 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 	struct netfs_group *group = netfs_folio_group(folio);
 	struct netfs_folio *finfo = netfs_folio_info(folio);
 	struct netfs_inode *ctx = netfs_inode(mapping->host);
-	struct folio *sink = NULL;
-	struct bio_vec *bvec;
+	struct bio_vec *bvec = NULL;
 	unsigned int from = finfo->dirty_offset;
 	unsigned int to = from + finfo->dirty_len;
-	unsigned int off = 0, i = 0;
+	unsigned int off = 0;
 	size_t flen = folio_size(folio);
 	size_t nr_bvec = flen / PAGE_SIZE + 2;
 	size_t part;
-	int ret;
+	int ret, i = 0, sink_from = -1, sink_to = -1;
 
 	_enter("%lx", folio->index);
 
@@ -515,24 +514,23 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 	if (!bvec)
 		goto discard;
 
-	sink = folio_alloc(GFP_KERNEL, 0);
-	if (!sink) {
-		kfree(bvec);
-		goto discard;
-	}
-
 	trace_netfs_folio(folio, netfs_folio_trace_read_gaps);
 
-	rreq->direct_bv = bvec;
-	rreq->direct_bv_count = nr_bvec;
 	if (from > 0) {
 		bvec_set_folio(&bvec[i++], folio, from, 0);
 		off = from;
 	}
+	sink_from = i;
 	while (off < to) {
+		struct folio *sink = folio_alloc(GFP_KERNEL, 0);
+
+		if (!sink)
+			goto discard;
 		part = min_t(size_t, to - off, PAGE_SIZE);
-		bvec_set_folio(&bvec[i++], sink, part, 0);
+		bvec_set_folio(&bvec[i], sink, part, 0);
 		off += part;
+		sink_to = i;
+		i++;
 	}
 	if (to < flen)
 		bvec_set_folio(&bvec[i++], folio, flen - to, to);
@@ -553,8 +551,10 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 		folio_mark_uptodate(folio);
 	}
 
-	if (sink)
-		folio_put(sink);
+	if (sink_to >= 0)
+		for (; sink_from <= sink_to; sink_from++)
+			folio_put(bvec_folio(&bvec[sink_from]));
+	kfree(bvec);
 	folio_unlock(folio);
 	netfs_put_request(rreq, netfs_rreq_trace_put_return);
 	return ret < 0 ? ret : 0;
@@ -563,6 +563,10 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 	netfs_put_failed_request(rreq);
 alloc_error:
 	folio_unlock(folio);
+	if (sink_to >= 0)
+		for (; sink_from <= sink_to; sink_from++)
+			folio_put(bvec_folio(&bvec[sink_from]));
+	kfree(bvec);
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#64 lore raw

PATCH 64/457 netfs, afs: Fix symlink reading

In reply to Greg Kroah-Hartman

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

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

From: David Howells <[email protected]>

[ Upstream commit c51e89c5b5db3e1927738fad7cd18b66dde68aed ]

Fix the reading of symlinks from the cache in afs by making netfslib trim the amount read down to i_size. The problem is that afs sets the size of the iterator to the size of the buffer (PAGE_SIZE) so that the cache can round the read size up to the cache's DIO size.

Note that this also impacts the reading of AFS mountpoints as they're just stored as symlinks with an odd file mode.

---
 fs/netfs/read_collect.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/netfs/read_collect.c +5 -0
index 5cf22087d2439..a94197ef01811 100644
@@ -435,6 +435,11 @@ static void netfs_rreq_assess_single(struct netfs_io_request *rreq)
 		netfs_single_mark_inode_dirty(rreq->inode);
 	}
 
+	/* To do DIO, the cache has to round the size up, so we need to undo
+	 * the rounding.
+	 */
+	rreq->transferred = min(rreq->transferred, rreq->i_size);
+
 	if (rreq->iocb) {
 		rreq->iocb->ki_pos += rreq->transferred;
 		if (rreq->iocb->ki_complete) {
Signature · 1 line
2.53.0
author maintainer
#65 lore raw

PATCH 65/457 fs: avoid repeated scans in evict_inodes()

In reply to Greg Kroah-Hartman

7.2-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 95e981b4e19c9..c6b08e8c5f627 100644
@@ -883,7 +883,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_once(inode))
@@ -902,19 +901,19 @@ void evict_inodes(struct super_block *sb)
 		inode_state_set(inode, 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
#66 lore raw

PATCH 66/457 xsk: Use a 32-bit compare in xsk_map_gen_lookup

In reply to Greg Kroah-Hartman

7.2-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 3bff346308d0f..bf00d6463c191 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
#67 lore raw

PATCH 67/457 bpf: Skip unsettled links in link iterator

In reply to Greg Kroah-Hartman

7.2-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 57d61de03306e..77b3252270f3e 100644
@@ -6106,7 +6106,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
#68 lore raw

PATCH 68/457 eth: fbnic: Fix payload page pool error cleanup

In reply to Greg Kroah-Hartman

7.2-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 e7918d3f6aba9..661dee1661afe 100644
@@ -1622,7 +1622,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
#69 lore raw

PATCH 69/457 net/sched: cls_u32: fix manual hash table handle IDR aliasing

In reply to Greg Kroah-Hartman

7.2-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 a3e65c8cf29ef..76ce2d124079d 100644
@@ -1003,8 +1003,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
#70 lore raw

PATCH 70/457 net: pcs: rzn1-miic: Fix config array initialization

In reply to Greg Kroah-Hartman

7.2-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 2b72fa98ddf13..cb74861e823c8 100644
@@ -683,7 +683,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
#71 lore raw

PATCH 71/457 octeontx2-af: use seq_file for rsrc_alloc debugfs

In reply to Greg Kroah-Hartman

7.2-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 904374baae6f3..2927633465d96 100644
@@ -714,110 +714,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
#72 lore raw

PATCH 72/457 net/mlx5: devcom, Base component size on linked devices

In reply to Greg Kroah-Hartman

7.2-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 64f92427602de..75855481522b1 100644
@@ -37,6 +37,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;
@@ -170,6 +171,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;
@@ -182,6 +184,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);
@@ -284,7 +287,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_locked_send_event(struct mlx5_devcom_comp_dev *devcom,
Signature · 1 line
2.53.0
author maintainer
#73 lore raw

PATCH 73/457 net/mlx5: SD, unload reps on shared FDB create error path

In reply to Greg Kroah-Hartman

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

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

From: Shay Drory <[email protected]>

[ Upstream commit e1e29ada2b938b13ba689a06a8bd8604564da2b3 ]

mlx5_lag_shared_fdb_create() sets sd_fdb_active on every group member before reloading the representors, so mlx5_lag_is_active() is already true and the guard in mlx5_esw_offloads_rep_load() does not skip the VF/SF reps. If the reload then fails, the error path clears sd_fdb_active and destroys the shared FDB, leaving the reps loaded while SD LAG is inactive - the state cited commit was written to prevent.

Unload the reps in the error path as well.

Fixes 68c2dd59a6c7 ("net/mlx5: E-Switch, Tie rep load/unload to SD LAG state")
---
 drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c +1 -0
index 6b4ad3c53f2f3..424040918fa37 100644
@@ -270,6 +270,7 @@ int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
 			pf->sd_fdb_active = false;
 		}
 		mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
+		mlx5_lag_unload_reps_from_locked(ldev, filter);
 	}
 err_add_devices:
 	mlx5_lag_add_devices_filter(ldev, filter);
Signature · 1 line
2.53.0
author maintainer
#74 lore raw

PATCH 74/457 net/mlx5: LAG, reload IB reps of LAG master before the rest

In reply to Greg Kroah-Hartman

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

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

From: Shay Drory <[email protected]>

[ Upstream commit bae23d1ae62092c7f0ec6d5f7e1be5d164822638 ]

In a shared-FDB LAG the master device creates the bond IB device; the other LAG members do not create their own, they populate a port inside the master's IB device. mlx5_lag_reload_ib_reps_unlocked() reloaded the members' IB reps in iteration order, with no guarantee the master is reloaded first. When a non-master member is reloaded before the master, it tries to populate its port in an IB device that has not been recreated yet.

Hence, reload the master's IB reps first, then every other member.

Fixes 2b204cdb1206 ("net/mlx5: LAG, use xa_alloc to manage LAG device indices")
---
 .../net/ethernet/mellanox/mlx5/core/lag/lag.c | 44 ++++++++++++++-----
 1 file changed, 32 insertions(+), 12 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +32 -12
index c655f6e32e9b0..dd14cdc378de0 100644
@@ -1266,25 +1266,45 @@ void mlx5_lag_remove_devices(struct mlx5_lag *ldev)
 	mlx5_lag_remove_devices_filter(ldev, MLX5_LAG_FILTER_PORTS);
 }
 
+static int mlx5_lag_reload_ib_reps_idx(struct mlx5_lag *ldev, int idx,
+				       u32 flags)
+{
+	struct lag_func *pf = mlx5_lag_pf(ldev, idx);
+	struct mlx5_eswitch *esw;
+	int ret;
+
+	if (pf->dev->priv.flags & flags)
+		return 0;
+
+	esw = pf->dev->priv.eswitch;
+	mlx5_esw_reps_block(esw);
+	ret = mlx5_eswitch_reload_ib_reps(esw);
+	mlx5_esw_reps_unblock(esw);
+
+	return ret;
+}
+
 static int mlx5_lag_reload_ib_reps_unlocked(struct mlx5_lag *ldev, u32 flags,
 					    u32 filter, bool cont_on_fail)
 {
-	struct lag_func *pf;
+	int master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+							     filter);
 	int ret;
 	int i;
 
+	if (master_idx < 0)
+		return -EINVAL;
+
+	ret = mlx5_lag_reload_ib_reps_idx(ldev, master_idx, flags);
+	if (ret && !cont_on_fail)
+		return ret;
+
 	mlx5_lag_for_each(i, 0, ldev, filter) {
-		pf = mlx5_lag_pf(ldev, i);
-		if (!(pf->dev->priv.flags & flags)) {
-			struct mlx5_eswitch *esw;
-
-			esw = pf->dev->priv.eswitch;
-			mlx5_esw_reps_block(esw);
-			ret = mlx5_eswitch_reload_ib_reps(esw);
-			mlx5_esw_reps_unblock(esw);
-			if (ret && !cont_on_fail)
-				return ret;
-		}
+		if (i == master_idx)
+			continue;
+		ret = mlx5_lag_reload_ib_reps_idx(ldev, i, flags);
+		if (ret && !cont_on_fail)
+			return ret;
 	}
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#75 lore raw

PATCH 75/457 bpf: Make post-verification instruction rewrites killable

In reply to Greg Kroah-Hartman

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

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

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit 261b61d3735b042ae25634f795c4540be0fc140c ]

After do_check() returns, the verifier runs several instruction rewrite passes. Some of them patch or remove one instruction at a time. Each operation moves the remaining instruction and auxiliary-data arrays and adjusts all branch offsets, making the overall work quadratic in the program length.

A privileged loader can submit 131072 unconditional jumps by zero followed by a valid return. Verification finishes quickly, but bpf_opt_remove_nops() then spends a long time removing each jump separately. Since this post-verification work neither checks for signals nor reschedules, a pending SIGKILL cannot terminate the task until the rewrite finishes.

Make bpf_patch_insn_data() and verifier_remove_insns() common cancellation and rescheduling points. These helpers run from BPF_PROG_LOAD process context, and bpf_patch_insn_data() can already sleep while reallocating auxiliary data.

Report interrupted constant blinding as -EINTR and propagate it through both JIT paths, including kernels that permit interpreter fallback. Other blinding failures retain the existing fallback behavior.

This does not reduce the quadratic cost of the rewrite passes, but it makes the work preemptible and allows a killed loader to be torn down promptly.

---
 kernel/bpf/core.c   | 21 +++++++++++++++++----
 kernel/bpf/fixups.c | 24 ++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 6 deletions(-)
kernel/bpf/core.c +17 -4
index 883cb7a800b17..71ee96a77ae26 100644
@@ -19,6 +19,7 @@
 
 #include <uapi/linux/btf.h>
 #include <linux/filter.h>
+#include <linux/sched/signal.h>
 #include <linux/skbuff.h>
 #include <linux/static_call.h>
 #include <linux/vmalloc.h>
@@ -1612,6 +1613,8 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bp
 			 * fix it up here on error.
 			 */
 			bpf_jit_prog_release_other(prog, clone);
+			if (env && fatal_signal_pending(current))
+				return ERR_PTR(-EINTR);
 			return IS_ERR(tmp) ? tmp : ERR_PTR(-ENOMEM);
 		}
 
@@ -2641,11 +2644,14 @@ static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struc
 	orig_prog = prog;
 	prog = bpf_jit_blind_constants(env, prog);
 	/*
-	 * If blinding was requested and we failed during blinding, we must fall
-	 * back to the interpreter.
+	 * Fall back to the interpreter after blinding failures, except when
+	 * the loader was killed.
 	 */
-	if (IS_ERR(prog))
+	if (IS_ERR(prog)) {
+		if (PTR_ERR(prog) == -EINTR)
+			return prog;
 		goto out_restore;
+	}
 
 	prog = bpf_int_jit_compile(env, prog);
 	if (prog->jited) {
@@ -2668,6 +2674,8 @@ static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struc
 struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
 					   int *err)
 {
+	struct bpf_prog *jit_prog;
+
 	/* In case of BPF to BPF calls, verifier did all the prep
 	 * work with regards to JITing, etc.
 	 */
@@ -2690,7 +2698,12 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct
 		if (*err)
 			return fp;
 
-		fp = bpf_prog_jit_compile(env, fp);
+		jit_prog = bpf_prog_jit_compile(env, fp);
+		if (IS_ERR(jit_prog)) {
+			*err = PTR_ERR(jit_prog);
+			return fp;
+		}
+		fp = jit_prog;
 		bpf_prog_jit_attempt_done(fp);
 		if (!fp->jited && jit_needed) {
 			*err = -ENOTSUPP;
kernel/bpf/fixups.c +22 -2
index 48acb61854ed4..19c1b8f1b317c 100644
@@ -8,6 +8,7 @@
 #include <linux/bsearch.h>
 #include <linux/sort.h>
 #include <linux/perf_event.h>
+#include <linux/sched/signal.h>
 #include <net/xdp.h>
 #include "disasm.h"
 
@@ -240,12 +241,28 @@ static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
 	}
 }
 
+/*
+ * Some post-verification instruction rewriting passes require an
+ * O(prog->len) operation per instruction. Keep their shared primitives
+ * killable and preemptible.
+ */
+static bool bpf_rewrite_must_abort(void)
+{
+	if (fatal_signal_pending(current))
+		return true;
+	cond_resched();
+	return false;
+}
+
 struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
 				     const struct bpf_insn *patch, u32 len)
 {
 	struct bpf_prog *new_prog;
 	struct bpf_insn_aux_data *new_data = NULL;
 
+	if (bpf_rewrite_must_abort())
+		return NULL;
+
 	if (len > 1) {
 		new_data = vrealloc(env->insn_aux_data,
 				    array_size(env->prog->len + len - 1,
@@ -457,6 +474,9 @@ static int verifier_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
 	unsigned int orig_prog_len = env->prog->len;
 	int err;
 
+	if (bpf_rewrite_must_abort())
+		return -EINTR;
+
 	if (bpf_prog_is_offloaded(env->prog->aux))
 		bpf_prog_offload_remove_insns(env, off, cnt);
 
@@ -1316,7 +1336,7 @@ int bpf_jit_subprogs(struct bpf_verifier_env *env)
 		}
 		prog = bpf_jit_blind_constants(env, prog);
 		if (IS_ERR(prog)) {
-			err = -ENOMEM;
+			err = PTR_ERR(prog);
 			prog = orig_prog;
 			goto out_restore;
 		}
@@ -1395,7 +1415,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
 		err = bpf_jit_subprogs(env);
 		if (err == 0)
 			return 0;
-		if (err == -EFAULT)
+		if (err == -EFAULT || err == -EINTR)
 			return err;
 	}
 #ifndef CONFIG_BPF_JIT_ALWAYS_ON
Signature · 1 line
2.53.0
author maintainer
#76 lore raw

PATCH 76/457 bpf: Preserve packet pointer class displacement in regsafe()

In reply to Greg Kroah-Hartman

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

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

From: Kumar Kartikeya Dwivedi <[email protected]>

[ Upstream commit fd16449a9b3b31a8f18944c2f0e29e4e218ca2cf ]

regsafe() maps packet pointer IDs between states and checks that each current register range is a subset of the corresponding explored register range. It does not, however, preserve the displacement between registers that share a packet pointer ID.

This is unsound because packet range is shared by ID. A bounds check on one class member updates every member, and a later access can consume the range through another member. Commit 022ac0750883 ("bpf: use reg->var_off instead of reg->off for pointers") folded the fixed pointer offset into r64 and removed the old off equality check, so two individually narrower registers can prune even when their displacement has changed. The explored path can then license an out-of-bounds packet access on the pruned path.

Require matching range bases for packet pointers with an ID. Together with the existing ID mapping, this preserves the displacement between members of each packet-pointer class without adding per-ID state. Packet pointers without an ID remain unaffected.

---
 kernel/bpf/states.c | 3 +++
 1 file changed, 3 insertions(+)
kernel/bpf/states.c +3 -0
index 66fb11b6c6a76..6c88ad95b63b7 100644
@@ -635,6 +635,9 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
 		/* id relations must be preserved */
 		if (!check_ids(rold->id, rcur->id, idmap))
 			return false;
+		/* Preserve displacements between pointers sharing an ID. */
+		if (rold->id && rold->r64.base != rcur->r64.base)
+			return false;
 		/* new val must satisfy old val knowledge */
 		return range_within(rold, rcur) &&
 		       tnum_in(rold->var_off, rcur->var_off);
Signature · 1 line
2.53.0
author maintainer
#77 lore raw

PATCH 77/457 bpf: Restrict CO-RE poisoning to relocatable instructions

In reply to Greg Kroah-Hartman

7.2-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 6ae3f2a15ad0c..4755de3f99957 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
#78 lore raw

PATCH 78/457 libbpf: Reject truncated ldimm64 CO-RE relocations

In reply to Greg Kroah-Hartman

7.2-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 1ab939dfb7f08..4f9ce4ff005b6 100644
@@ -6162,6 +6162,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
#79 lore raw

PATCH 79/457 ipv4: fib: fix data-race and stale genid check around nh->nh_saddr

In reply to Greg Kroah-Hartman

7.2-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 0483519b7fb0d..0c25f6dfb8a6f 100644
@@ -2176,6 +2176,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)
 {
@@ -2184,6 +2193,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);
@@ -2192,6 +2202,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;
@@ -2204,7 +2215,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
#80 lore raw

PATCH 80/457 gpiolib: use of_node_name if line-name is missing

In reply to Greg Kroah-Hartman

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

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

From: Frank Wunderlich <[email protected]>

[ Upstream commit d54a489c8c4b627775445d54a6cbd32f209bda8f ]

Until v7.0, GPIO hogs inherited the DT node name when no line-name property was specified. This was implemented as a fallback in of_parse_own_gpio().

Commit d1d564ec4992 ("gpio: move hogs into GPIO core") moved hog parsing into the GPIO core and removed this fallback.

Consequently, GPIO hogs without a line-name property are now displayed with a ? in /sys/kernel/debug/gpio. Restore the old fallback.

---
 drivers/gpio/gpiolib.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/gpio/gpiolib.c +7 -0
index ef8ccaf17c9ce..28f7265c5d569 100644
@@ -1029,6 +1029,13 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode)
 			ret = of_gpiochip_get_lflags(gc, &gpiospec, &lflags);
 			if (ret)
 				return ret;
+
+			/*
+			 * If no line-name property is present, fall back to the OF
+			 * node name as in the previous implementation.
+			 */
+			if (!name)
+				name = to_of_node(fwnode)->name;
 		} else {
 			/*
 			 * GPIO_ACTIVE_LOW is currently the only lookup flag
Signature · 1 line
2.53.0
author maintainer
#81 lore raw

PATCH 81/457 netfilter: flowtable: publish HW_DEAD after worker is done

In reply to Greg Kroah-Hartman

7.2-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 801a3dd9ceea3..6757fd89c1f1a 100644
@@ -995,7 +995,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,
@@ -1059,6 +1058,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
#82 lore raw

PATCH 82/457 netfilter: nfnetlink_queue: hold nfnl mutex in event notifier

In reply to Greg Kroah-Hartman

7.2-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 b8aaf39cb4d8e..ec5e7716df8b5 100644
@@ -1527,6 +1527,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++) {
@@ -1540,6 +1541,7 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
 			}
 		}
 		spin_unlock(&q->instances_lock);
+		nfnl_unlock(NFNL_SUBSYS_QUEUE);
 	}
 	return NOTIFY_DONE;
 }
@@ -1859,9 +1861,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
#83 lore raw

PATCH 83/457 netfilter: nft_synproxy: use the family-aware checksum helper

In reply to Greg Kroah-Hartman

7.2-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 9ed288c9d1688..554a96a000f40 100644
@@ -118,7 +118,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
#84 lore raw

PATCH 84/457 ipvs: revalidate ihl before icmp_send

In reply to Greg Kroah-Hartman

7.2-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 eb806813292ad..6802ce5cb1de4 100644
@@ -1961,6 +1961,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
#85 lore raw

PATCH 85/457 netfilter: ctnetlink: fix suspicious RCU usage in expect_iter_name

In reply to Greg Kroah-Hartman

7.2-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 92c3bb77d27e8..6cddfa339d71e 100644
@@ -3392,7 +3392,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
#86 lore raw

PATCH 86/457 arm64: io: Reject non-user protection in ioremap_prot()

In reply to Greg Kroah-Hartman

7.2-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 21c8e400107ca..31e67f6bd4a70 100644
@@ -272,7 +272,8 @@ static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
 	pgprot_t prot;
 	ptval_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
#87 lore raw

PATCH 87/457 ocfs2: make ocfs2_calc_xattr_init() return void

In reply to Greg Kroah-Hartman

7.2-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 ea37a50580890..4e9f8dd63dcb2 100644
@@ -336,13 +336,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 35bcbb0ff607b..bfafe059bedff 100644
@@ -635,12 +635,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;
 
@@ -662,7 +661,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
@@ -728,8 +727,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 5e18513277f18..887cc1a18b1af 100644
@@ -59,10 +59,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
#88 lore raw

PATCH 88/457 pinctrl: qcom: ipq5210: Publish the OF module alias

In reply to Greg Kroah-Hartman

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

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

From: hpp.iscas <[email protected]>

[ Upstream commit 447dcff90557748a5ac384aaf5d70b2c7e3b961d ]

The IPQ5210 TLMM platform driver can be a module and matches through ipq5210_tlmm_of_match. This table is not published for OF modalias matching.

Publish the existing table, preserving arch_initcall ordering and the shared MSM pinctrl probe.

---
 drivers/pinctrl/qcom/pinctrl-ipq5210.c | 1 +
 1 file changed, 1 insertion(+)
drivers/pinctrl/qcom/pinctrl-ipq5210.c +1 -0
index 827a4ad07a6b0..d5b4eb3e73435 100644
@@ -867,6 +867,7 @@ static const struct of_device_id ipq5210_tlmm_of_match[] = {
 	{ .compatible = "qcom,ipq5210-tlmm", },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, ipq5210_tlmm_of_match);
 
 static int ipq5210_tlmm_probe(struct platform_device *pdev)
 {
Signature · 1 line
2.53.0
author maintainer
#89 lore raw

PATCH 89/457 drm/nouveau/clk: fix list cursor use after loop in nvkm_clk_ustate_update

In reply to Greg Kroah-Hartman

7.2-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 572e638463159..5da82db71dde2 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
#90 lore raw

PATCH 90/457 drm/nouveau/clk: dont clobber reclock status when restoring volt/fan

In reply to Greg Kroah-Hartman

7.2-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 5da82db71dde2..fd2a9d64caba9 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
#91 lore raw

PATCH 91/457 drm/nouveau/disp: dont reject HDMI config on cards without SCDC

In reply to Greg Kroah-Hartman

7.2-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
#92 lore raw

PATCH 92/457 net/sched: act_ct: dont WARN on benign flow_offload_alloc() failure

In reply to Greg Kroah-Hartman

7.2-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 370085ab6ea41..aba022969553b 100644
@@ -432,11 +432,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
#93 lore raw

PATCH 93/457 net: gue: reject invalid REMCSUM offsets

In reply to Greg Kroah-Hartman

7.2-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
#94 lore raw

PATCH 94/457 net: ethernet: mtk_eth_soc: unregister net_devices in case of probe failure

In reply to Greg Kroah-Hartman

7.2-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 b2473df74dff0..efc238abb67b3 100644
@@ -4508,6 +4508,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]);
 	}
 
@@ -5339,7 +5343,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
#95 lore raw

PATCH 95/457 ip6_gre: Call ip6erspan_tunnel_unlink_md() in ip6erspan_changelink().

In reply to Greg Kroah-Hartman

7.2-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 678678fcb5da3..e6913a7f68811 100644
@@ -2280,7 +2280,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
#96 lore raw

PATCH 96/457 net: ethtool: keep rtnl_lock for the ioctl self test

In reply to Greg Kroah-Hartman

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

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

From: Alexander Duyck <[email protected]>

[ Upstream commit 1b82958f3f035df5ccaab5430a2302f08a5d5351 ]

An offline self test that brings the interface down and back up with netif_close() / netif_open() requires rtnl_lock for both. Since the ethtool IOCTL path became rtnl-optional for ops-locked drivers, the ETHTOOL_TEST ioctl runs holding only the netdev instance lock, so on an ops-locked driver the self test now tears the device down without rtnl_lock.

With lockdep this reproduces deterministically on every offline self test on such a driver; note the sole lock held is the instance lock, not rtnl:

WARNING: suspicious RCU usage
net/core/netpoll.c:207 suspicious rcu_dereference_protected() usage! 1 lock held by ethtool/107:
#0: (&dev->lock){+.+.}, at: dev_ethtool

  Call Trace:
   netpoll_poll_disable
   __dev_close_many
   netif_close_many
   netif_close
   fbnic_self_test
   dev_ethtool_locked
   dev_ethtool
   dev_ioctl
   sock_ioctl
   __x64_sys_ioctl

Without lockdep the same condition trips ASSERT_RTNL() in __dev_close_many() / __dev_open(); that check only samples the global rtnl state, so it can be masked by a concurrent rtnl holder, but the device is still being reconfigured without the lock it requires.

The ethtool self_test is a legacy ioctl-only command, so an ETHTOOL_TEST case is only needed on the ioctl path. Add an opt-in bit for drivers whose self test needs rtnl_lock and set it on the ops-locked drivers whose offline self test tears the interface down and up:

- fbnic (ops-locked via queue_mgmt_ops): fbnic_self_test() offline path uses netif_close() / netif_open().
- bnxt (ops-locked via queue_mgmt_ops): bnxt_self_test() offline path goes through bnxt_close_nic() / bnxt_half_open_nic() / bnxt_half_close_nic() / bnxt_open_nic(), which close and reopen the device.

---
 drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 ++-
 drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c   | 3 ++-
 include/linux/ethtool.h                           | 2 ++
 net/ethtool/common.h                              | 2 ++
 4 files changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +2 -1
index 62bc9cae613c3..622e89587e5db 100644
@@ -5733,7 +5733,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {
 	.op_needs_rtnl			= ETHTOOL_OP_NEEDS_RTNL_SCHANNELS |
 					  ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM |
 					  ETHTOOL_OP_NEEDS_RTNL_SCOALESCE |
-					  ETHTOOL_OP_NEEDS_RTNL_RSS,
+					  ETHTOOL_OP_NEEDS_RTNL_RSS |
+					  ETHTOOL_OP_NEEDS_RTNL_TEST,
 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
 				     ETHTOOL_COALESCE_MAX_FRAMES |
 				     ETHTOOL_COALESCE_USECS_IRQ |
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +2 -1
index 0e47088ec44ba..423f179c9d475 100644
@@ -2025,7 +2025,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
 					  ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM |
 					  ETHTOOL_OP_NEEDS_RTNL_SCHANNELS |
 					  ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM |
-					  ETHTOOL_OP_NEEDS_RTNL_GLINK,
+					  ETHTOOL_OP_NEEDS_RTNL_GLINK |
+					  ETHTOOL_OP_NEEDS_RTNL_TEST,
 	.get_drvinfo			= fbnic_get_drvinfo,
 	.get_regs_len			= fbnic_get_regs_len,
 	.get_regs			= fbnic_get_regs,
include/linux/ethtool.h +2 -0
index 12683b5d125e4..97a1adbd9eaee 100644
@@ -944,6 +944,7 @@ struct kernel_ethtool_ts_info {
 #define ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM	BIT(6)
 #define ETHTOOL_OP_NEEDS_RTNL_RSS		BIT(7)
 #define ETHTOOL_OP_NEEDS_RTNL_GLINK		BIT(8)
+#define ETHTOOL_OP_NEEDS_RTNL_TEST		BIT(9)
 
 /**
  * struct ethtool_ops - optional netdev operations
@@ -981,6 +982,7 @@ struct kernel_ethtool_ts_info {
  *	 - netdev_update_features()
  *	 - netif_set_real_num_tx_queues()
  *	 - ethtool_op_get_link() (syncs link watch under rtnl_lock)
+ *	 - netif_open() / netif_close() (used by @self_test)
  *
  * @get_drvinfo: Report driver/device information. Modern drivers no
  *	longer have to implement this callback. Most fields are
net/ethtool/common.h +2 -0
index 4e5356e26f400..ae32e7fdb563c 100644
@@ -163,6 +163,8 @@ ethtool_ioctl_needs_rtnl(const struct net_device *dev, u32 ethcmd)
 		return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_RSS;
 	case ETHTOOL_GLINK:
 		return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_GLINK;
+	case ETHTOOL_TEST:
+		return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_TEST;
 	}
 	return false;
 }
Signature · 1 line
2.53.0
author maintainer
#97 lore raw

PATCH 97/457 eth: fbnic: Handle maximum standalone channels

In reply to Greg Kroah-Hartman

7.2-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 661dee1661afe..a30aa44508487 100644
@@ -1791,7 +1791,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
#98 lore raw

PATCH 98/457 eth: fbnic: use the Rx queue napi pointer to find the napi vector

In reply to Greg Kroah-Hartman

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

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

From: Alexander Duyck <[email protected]>

[ Upstream commit b5d9e9d4d0c13bc8b60d8d97e7a07fb25fea639e ]

The queue management ndos pick the napi vector for an Rx queue with:

	nv = fbn->napi[idx % fbn->num_napi];

The issue is this is only correct in the cases where there are no standalone Tx vectors. In those cases we were allocating the Tx vectors first and then the Rx so the queues would be pointing to Tx NAPI vectors instead of the Rx ones.

The mapping the ndos want is already recorded. fbnic_set_netif_napi() publishes it with netif_queue_set_napi(), which stores the napi pointer in netdev_rx_queue.napi, and fbnic_reset_netif_napi() clears it again. Both run under the netdev instance lock that the queue management ndos also hold, so the pointer can be read directly.

Use it and drop the divide. The pointer is NULL exactly while the datapath is down, so fbnic_queue_mem_alloc() can reject that case rather than reaching into freed state: netdev_rx_queue_restart() calls it before it tests netif_running(), and fbnic_pm_suspend() leaves netif_running() true across a PCIe recovery that never completes, so a queue restart can arrive after fbnic_stop() has freed the rings and the vectors. fbnic_stop() clears the association in fbnic_reset_netif_queues() before fbnic_free_napi_vectors(), so the NULL is always published first. fbnic_queue_start() and fbnic_queue_stop() need no check of their own, as netdev_rx_queue_reconfig() only reaches them once fbnic_queue_mem_alloc() has succeeded under the same instance lock.

---
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 26 +++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +23 -3
index a30aa44508487..10caacffee0f0 100644
@@ -7,6 +7,7 @@
 #include <linux/iopoll.h>
 #include <linux/pci.h>
 #include <net/netdev_queues.h>
+#include <net/netdev_rx_queue.h>
 #include <net/page_pool/helpers.h>
 #include <net/tcp.h>
 #include <net/xdp.h>
@@ -2853,6 +2854,17 @@ void fbnic_napi_depletion_check(struct net_device *netdev)
 	fbnic_wrfl(fbd);
 }
 
+/* Returns the napi vector servicing an Rx queue, or NULL if the datapath
+ * is torn down.  The association is published by fbnic_set_netif_napi()
+ * and cleared by fbnic_reset_netif_napi(), both under the instance lock.
+ */
+static struct fbnic_napi_vector *fbnic_rxq_nv(struct net_device *dev, int idx)
+{
+	struct napi_struct *napi = __netif_get_rx_queue(dev, idx)->napi;
+
+	return napi ? container_of(napi, struct fbnic_napi_vector, napi) : NULL;
+}
+
 static int fbnic_queue_mem_alloc(struct net_device *dev,
 				 struct netdev_queue_config *qcfg,
 				 void *qmem, int idx)
@@ -2865,8 +2877,16 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,
 	if (!netif_running(dev))
 		return fbnic_alloc_qt_page_pools(fbn, qt, idx);
 
+	/* A failed PCIe recovery or resume can leave the datapath torn down
+	 * while netif_running() is still true.  This ndo runs before
+	 * netdev_rx_queue_restart() checks netif_running(), so bail out
+	 * rather than touching rings and vectors that are already freed.
+	 */
+	nv = fbnic_rxq_nv(dev, idx);
+	if (!nv)
+		return -ENETDOWN;
+
 	real = container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl);
-	nv = fbn->napi[idx % fbn->num_napi];
 
 	fbnic_ring_init(&qt->sub0, real->sub0.doorbell, real->sub0.q_idx,
 			real->sub0.flags);
@@ -2917,7 +2937,7 @@ static int fbnic_queue_start(struct net_device *dev,
 	struct fbnic_q_triad *real;
 
 	real = container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl);
-	nv = fbn->napi[idx % fbn->num_napi];
+	nv = fbnic_rxq_nv(dev, idx);
 
 	fbnic_aggregate_ring_bdq_counters(fbn, &real->sub0);
 	fbnic_aggregate_ring_bdq_counters(fbn, &real->sub1);
@@ -2939,7 +2959,7 @@ static int fbnic_queue_stop(struct net_device *dev, void *qmem, int idx)
 	int err;
 
 	real = container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl);
-	nv = fbn->napi[idx % fbn->num_napi];
+	nv = fbnic_rxq_nv(dev, idx);
 	fbnic_dbg_nv_exit(nv);
 
 	napi_disable_locked(&nv->napi);
Signature · 1 line
2.53.0
author maintainer
#99 lore raw

PATCH 99/457 eth: fbnic: reset num_napi when the napi vectors are freed

In reply to Greg Kroah-Hartman

7.2-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 8b9bc9e8ea56c..c6698e3002a13 100644
@@ -434,6 +434,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;
@@ -441,11 +442,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();
 
@@ -508,16 +514,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
#100 lore raw

PATCH 100/457 eth: fbnic: Set AW_FLUSH_MODE alongside AW_FLUSH when flushing the mailbox

In reply to Greg Kroah-Hartman

7.2-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 64b958df77744..14af30e189d6c 100644
@@ -974,6 +974,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_AW_CFG_RDE_ATTR	CSR_GENMASK(17, 15)
drivers/net/ethernet/meta/fbnic/fbnic_fw.c +8 -1
index 283d25fae79e7..59aa879798b9f 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
#101 lore raw

PATCH 101/457 eth: fbnic: Handle FW mailbox completions flagged with an error

In reply to Greg Kroah-Hartman

7.2-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 14af30e189d6c..baba3471bf5a4 100644
@@ -1216,6 +1216,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 3c4563c8f403f..6edfa0aa69f11 100644
@@ -539,8 +539,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 59aa879798b9f..6d7eb8479edf4 100644
@@ -292,6 +292,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++;
@@ -1673,6 +1679,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);
 
@@ -1740,7 +1753,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 {
@@ -1771,6 +1786,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;
@@ -1788,9 +1806,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 d84723e4cfa36..5f9969247e305 100644
@@ -13,6 +13,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
#102 lore raw

PATCH 102/457 sctp: avoid livelock while updating retransmit path

In reply to Greg Kroah-Hartman

7.2-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 5be0bed2685ee..1220ff909fbe3 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
#103 lore raw

PATCH 103/457 net: allow IFLA_INET_CONF messages when NLA_F_NESTED unset

In reply to Greg Kroah-Hartman

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

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

From: Quentin Armitage <[email protected]>

[ Upstream commit 6c096bb08de97cdca051fecddad22cac6a1fd275 ]

Commit fa8fca88714c ("ipv4: validate IPV4_DEVCONF attributes properly") added validation of IFLA_INET_CONF attributes, and in the process changed the call of nla_for_each_nested() to nla_parse_nested(). A side effect of this change is that the IFLA_INET_CONF option is now tested for NLA_F_NESTED being set, and fails if it is not. Prior to the commit there was no check of NLA_F_NESTED.

Change nla_parse_nested() to nla_parse(). This restores the previous functionality of not checking NLA_F_NESTED, thereby allowing code that (incorrectly) doesn't set NLA_F_NESTED to continue to work.

This issue was identified because keepalived started logging errors when it was configuring macvlans that it created.

Fixes fa8fca88714c ("ipv4: validate IPV4_DEVCONF attributes properly")
---
 net/ipv4/devinet.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
net/ipv4/devinet.c +4 -3
index a35b72662e431..a80896647154c 100644
@@ -2117,9 +2117,10 @@ static int inet_validate_link_af(const struct net_device *dev,
 		return err;
 
 	if (tb[IFLA_INET_CONF]) {
-		err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX,
-				       tb[IFLA_INET_CONF], inet_devconf_policy,
-				       extack);
+		err = nla_parse(nested_tb, IPV4_DEVCONF_MAX,
+				nla_data(tb[IFLA_INET_CONF]),
+				nla_len(tb[IFLA_INET_CONF]),
+				inet_devconf_policy, extack);
 
 		if (err < 0)
 			return err;
Signature · 1 line
2.53.0
author maintainer
#104 lore raw

PATCH 104/457 bpf: Bound ownership depth through local kptrs and graph roots

In reply to Greg Kroah-Hartman

7.2-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 ea3d50c99ec22..c4df013bf0066 100644
@@ -4269,13 +4269,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;
@@ -4306,51 +4303,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,
@@ -6045,6 +6079,10 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr,
 			if (err < 0)
 				goto errout_meta;
 		}
+
+		err = btf_check_ownership_depth(btf, struct_meta_tab);
+		if (err < 0)
+			goto errout_meta;
 	}
 
 	err = bpf_log_attr_finalize(attr_log, &env->log);
tools/testing/selftests/bpf/prog_tests/linked_list.c +2 -2
index 8defea0253ed9..178d133d59238 100644
@@ -713,7 +713,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;
 	}
@@ -772,7 +772,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
#105 lore raw

PATCH 105/457 net: usb: catc: bound the RX packet length in catc_rx_done()

In reply to Greg Kroah-Hartman

7.2-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 96e82f94edcf8..39b678f175dd9 100644
@@ -233,17 +233,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
#106 lore raw

PATCH 106/457 bpf: Check params size before reading reserved fields

In reply to Greg Kroah-Hartman

7.2-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 51f89cecefb4d..3f3fe2450fc6c 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
#107 lore raw

PATCH 107/457 net/sched: sch_hfsc: bound the classify inner-filter walk with a drift budget

In reply to Greg Kroah-Hartman

7.2-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 e87f5021a1995..284490fd6ca91 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_qdisc(skb, 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
#108 lore raw

PATCH 108/457 drm/virtio: fix object leak when drm_gem_handle_create() fails

In reply to Greg Kroah-Hartman

7.2-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 66c3f6f74e9c6..d2f0b8a3f172b 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
#109 lore raw

PATCH 109/457 drm/virtio: fix object leak in virtio_gpu_resource_create_ioctl()

In reply to Greg Kroah-Hartman

7.2-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 3d8e4ccdb7c1f..d16f07abb266a 100644
@@ -185,7 +185,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
#110 lore raw

PATCH 110/457 drm/virtio: fix object leaks in virtio_gpu_resource_create_blob_ioctl()

In reply to Greg Kroah-Hartman

7.2-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 d16f07abb266a..fcdb07a37972c 100644
@@ -557,14 +557,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
#111 lore raw

PATCH 111/457 drm/virtio: release the GEM object on virtio_gpu_vram_create() errors

In reply to Greg Kroah-Hartman

7.2-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 4ae3cbc35dd36..683ea17454c2e 100644
@@ -212,16 +212,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);
@@ -237,6 +233,11 @@ 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;
 }
 
 void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram)
Signature · 1 line
2.53.0
author maintainer
#112 lore raw

PATCH 112/457 Revert "drm/virtio: Allow importing prime buffers when 3D is enabled"

In reply to Greg Kroah-Hartman

7.2-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 70b3b836e1c99..c2748378a8ad6 100644
@@ -310,7 +310,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_obj(*bo);
Signature · 1 line
2.53.0
author maintainer
#113 lore raw

PATCH 113/457 drm/virtio: sync shmem backing on guest-bound transfers

In reply to Greg Kroah-Hartman

7.2-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 88fb4be92cf3e..5610add1da470 100644
@@ -114,6 +114,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;
 
@@ -192,6 +194,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
#114 lore raw

PATCH 114/457 pinctrl: tegra238: Fix register bank for AON pin groups

In reply to Greg Kroah-Hartman

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

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

From: Prathamesh Shete <[email protected]>

[ Upstream commit ae2c5bf969573708cd5b6bb6393631255d83c3fe ]

The AON pin controller has a single register region and therefore, the bank defined in the tegra238_functions[] and tegra238_aon_groups[] for the AON pin groups must be 0. However, commit 25cac7292d49 ("pinctrl: tegra: Add Tegra238 pinmux driver") incorrectly specified the bank for these pins as 1 and not 0. This means that in the tegra_pinctrl_probe() function we use an invalid index when accessing the pmx->regs[] array which causes an incorrect address to be used for accessing the pinmux registers.

Fix this by correcting the bank for the AON pin groups.

Fixes 25cac7292d49 ("pinctrl: tegra: Add Tegra238 pinmux driver")
---
 drivers/pinctrl/tegra/pinctrl-tegra238.c | 204 +++++++++++------------
 1 file changed, 102 insertions(+), 102 deletions(-)
drivers/pinctrl/tegra/pinctrl-tegra238.c +102 -102
index ec482365f14f2..40aba285944eb 100644
@@ -1744,57 +1744,57 @@ static const char * const tegra238_functions[] = {
 #define drive_sdmmc1_dat0_pu2		DRV_PINGROUP_ENTRY_Y(0x8034,	28,	2,	30,	2,	-1,	-1,	-1,	-1,	0)
 #define drive_ufs0_rst_n_pv1		DRV_PINGROUP_ENTRY_Y(0x11004,	12,	5,	24,	5,	-1,	-1,	-1,	-1,	0)
 #define drive_ufs0_ref_clk_pv0		DRV_PINGROUP_ENTRY_Y(0x1100c,	12,	5,	24,	5,	-1,	-1,	-1,	-1,	0)
-#define drive_batt_oc_paa4		    DRV_PINGROUP_ENTRY_Y(0x1024,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_bootv_ctl_n_paa0		DRV_PINGROUP_ENTRY_Y(0x102c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_vcomp_alert_paa2		DRV_PINGROUP_ENTRY_Y(0x105c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_hdmi_cec_pbb0		    DRV_PINGROUP_ENTRY_Y(0x1064,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_touch_clk_pdd3		DRV_PINGROUP_ENTRY_Y(0x106c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart3_rx_pcc6		    DRV_PINGROUP_ENTRY_Y(0x1074,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart3_tx_pcc5		    DRV_PINGROUP_ENTRY_Y(0x107c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_gen8_i2c_sda_pdd2		DRV_PINGROUP_ENTRY_Y(0x1084,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_gen8_i2c_scl_pdd1		DRV_PINGROUP_ENTRY_Y(0x108c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_spi2_mosi_pcc2		DRV_PINGROUP_ENTRY_Y(0x1094,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_gen2_i2c_scl_pcc7		DRV_PINGROUP_ENTRY_Y(0x109c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_spi2_cs0_pcc3		    DRV_PINGROUP_ENTRY_Y(0x10a4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_gen2_i2c_sda_pdd0		DRV_PINGROUP_ENTRY_Y(0x10ac,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_spi2_sck_pcc0		    DRV_PINGROUP_ENTRY_Y(0x10b4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_spi2_miso_pcc1		DRV_PINGROUP_ENTRY_Y(0x10bc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio49_pee2		DRV_PINGROUP_ENTRY_Y(0x10c4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio50_pee4		DRV_PINGROUP_ENTRY_Y(0x10cc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio82_pee3		DRV_PINGROUP_ENTRY_Y(0x10d4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio71_pff2		DRV_PINGROUP_ENTRY_Y(0x10dc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio76_pff7		DRV_PINGROUP_ENTRY_Y(0x10e4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio74_pff5		DRV_PINGROUP_ENTRY_Y(0x10ec,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio00_paa1		DRV_PINGROUP_ENTRY_Y(0x10f4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio19_pdd6		DRV_PINGROUP_ENTRY_Y(0x10fc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio86_phh3		DRV_PINGROUP_ENTRY_Y(0x1104,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio72_pff3		DRV_PINGROUP_ENTRY_Y(0x110c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio77_pgg0		DRV_PINGROUP_ENTRY_Y(0x1114,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio80_pff6		DRV_PINGROUP_ENTRY_Y(0x111c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio84_pgg1		DRV_PINGROUP_ENTRY_Y(0x1124,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio83_pee5		DRV_PINGROUP_ENTRY_Y(0x112c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio73_pff4		DRV_PINGROUP_ENTRY_Y(0x1134,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio70_pff1		DRV_PINGROUP_ENTRY_Y(0x113c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio04_paa5		DRV_PINGROUP_ENTRY_Y(0x1144,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio85_pgg6		DRV_PINGROUP_ENTRY_Y(0x114c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio69_pff0		DRV_PINGROUP_ENTRY_Y(0x1154,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio25_paa6		DRV_PINGROUP_ENTRY_Y(0x115c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_soc_gpio26_paa7		DRV_PINGROUP_ENTRY_Y(0x1164,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart5_tx_pgg7		    DRV_PINGROUP_ENTRY_Y(0x116c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart5_rx_phh0		    DRV_PINGROUP_ENTRY_Y(0x1174,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart2_tx_pgg2		    DRV_PINGROUP_ENTRY_Y(0x117c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart2_rx_pgg3		    DRV_PINGROUP_ENTRY_Y(0x1184,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart2_cts_pgg5		DRV_PINGROUP_ENTRY_Y(0x118c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart2_rts_pgg4		DRV_PINGROUP_ENTRY_Y(0x1194,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart5_cts_phh2		DRV_PINGROUP_ENTRY_Y(0x119c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_uart5_rts_phh1		DRV_PINGROUP_ENTRY_Y(0x11a4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_pwm7_pee1			    DRV_PINGROUP_ENTRY_Y(0x11ac,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_pwm2_pdd7			    DRV_PINGROUP_ENTRY_Y(0x11b4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_pwm3_pee0			    DRV_PINGROUP_ENTRY_Y(0x11bc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_pwm1_paa3			    DRV_PINGROUP_ENTRY_Y(0x11c4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_spi2_cs1_pcc4		    DRV_PINGROUP_ENTRY_Y(0x11cc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_dmic1_clk_pdd4		DRV_PINGROUP_ENTRY_Y(0x11d4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
-#define drive_dmic1_dat_pdd5		DRV_PINGROUP_ENTRY_Y(0x11dc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	1)
+#define drive_batt_oc_paa4		    DRV_PINGROUP_ENTRY_Y(0x1024,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_bootv_ctl_n_paa0		DRV_PINGROUP_ENTRY_Y(0x102c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_vcomp_alert_paa2		DRV_PINGROUP_ENTRY_Y(0x105c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_hdmi_cec_pbb0		    DRV_PINGROUP_ENTRY_Y(0x1064,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_touch_clk_pdd3		DRV_PINGROUP_ENTRY_Y(0x106c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart3_rx_pcc6		    DRV_PINGROUP_ENTRY_Y(0x1074,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart3_tx_pcc5		    DRV_PINGROUP_ENTRY_Y(0x107c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_gen8_i2c_sda_pdd2		DRV_PINGROUP_ENTRY_Y(0x1084,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_gen8_i2c_scl_pdd1		DRV_PINGROUP_ENTRY_Y(0x108c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_spi2_mosi_pcc2		DRV_PINGROUP_ENTRY_Y(0x1094,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_gen2_i2c_scl_pcc7		DRV_PINGROUP_ENTRY_Y(0x109c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_spi2_cs0_pcc3		    DRV_PINGROUP_ENTRY_Y(0x10a4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_gen2_i2c_sda_pdd0		DRV_PINGROUP_ENTRY_Y(0x10ac,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_spi2_sck_pcc0		    DRV_PINGROUP_ENTRY_Y(0x10b4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_spi2_miso_pcc1		DRV_PINGROUP_ENTRY_Y(0x10bc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio49_pee2		DRV_PINGROUP_ENTRY_Y(0x10c4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio50_pee4		DRV_PINGROUP_ENTRY_Y(0x10cc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio82_pee3		DRV_PINGROUP_ENTRY_Y(0x10d4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio71_pff2		DRV_PINGROUP_ENTRY_Y(0x10dc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio76_pff7		DRV_PINGROUP_ENTRY_Y(0x10e4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio74_pff5		DRV_PINGROUP_ENTRY_Y(0x10ec,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio00_paa1		DRV_PINGROUP_ENTRY_Y(0x10f4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio19_pdd6		DRV_PINGROUP_ENTRY_Y(0x10fc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio86_phh3		DRV_PINGROUP_ENTRY_Y(0x1104,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio72_pff3		DRV_PINGROUP_ENTRY_Y(0x110c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio77_pgg0		DRV_PINGROUP_ENTRY_Y(0x1114,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio80_pff6		DRV_PINGROUP_ENTRY_Y(0x111c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio84_pgg1		DRV_PINGROUP_ENTRY_Y(0x1124,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio83_pee5		DRV_PINGROUP_ENTRY_Y(0x112c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio73_pff4		DRV_PINGROUP_ENTRY_Y(0x1134,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio70_pff1		DRV_PINGROUP_ENTRY_Y(0x113c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio04_paa5		DRV_PINGROUP_ENTRY_Y(0x1144,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio85_pgg6		DRV_PINGROUP_ENTRY_Y(0x114c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio69_pff0		DRV_PINGROUP_ENTRY_Y(0x1154,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio25_paa6		DRV_PINGROUP_ENTRY_Y(0x115c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_soc_gpio26_paa7		DRV_PINGROUP_ENTRY_Y(0x1164,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart5_tx_pgg7		    DRV_PINGROUP_ENTRY_Y(0x116c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart5_rx_phh0		    DRV_PINGROUP_ENTRY_Y(0x1174,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart2_tx_pgg2		    DRV_PINGROUP_ENTRY_Y(0x117c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart2_rx_pgg3		    DRV_PINGROUP_ENTRY_Y(0x1184,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart2_cts_pgg5		DRV_PINGROUP_ENTRY_Y(0x118c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart2_rts_pgg4		DRV_PINGROUP_ENTRY_Y(0x1194,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart5_cts_phh2		DRV_PINGROUP_ENTRY_Y(0x119c,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_uart5_rts_phh1		DRV_PINGROUP_ENTRY_Y(0x11a4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_pwm7_pee1			    DRV_PINGROUP_ENTRY_Y(0x11ac,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_pwm2_pdd7			    DRV_PINGROUP_ENTRY_Y(0x11b4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_pwm3_pee0			    DRV_PINGROUP_ENTRY_Y(0x11bc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_pwm1_paa3			    DRV_PINGROUP_ENTRY_Y(0x11c4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_spi2_cs1_pcc4		    DRV_PINGROUP_ENTRY_Y(0x11cc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_dmic1_clk_pdd4		DRV_PINGROUP_ENTRY_Y(0x11d4,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
+#define drive_dmic1_dat_pdd5		DRV_PINGROUP_ENTRY_Y(0x11dc,	12,	5,	20,	5,	-1,	-1,	-1,	-1,	0)
 
 #define drive_sdmmc1_comp		DRV_PINGROUP_ENTRY_N
 
@@ -1961,57 +1961,57 @@ static const struct tegra_pingroup tegra238_groups[] = {
 };
 
 static const struct tegra_pingroup tegra238_aon_groups[] = {
-	PINGROUP(bootv_ctl_n_paa0,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1028,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio00_paa1,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10f0,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(vcomp_alert_paa2,	SOC_THERM_OC1,	RSVD1,			RSVD2,		RSVD3,		0x1058,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(pwm1_paa3,		GP_PWM1,	RSVD1,			RSVD2,		RSVD3,		0x11c0,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(batt_oc_paa4,		SOC_THERM_OC2,	RSVD1,			RSVD2,		RSVD3,		0x1020,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio04_paa5,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1140,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio25_paa6,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1158,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio26_paa7,	RSVD0,		SOC_THERM_OC3,		RSVD2,		RSVD3,		0x1160,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(hdmi_cec_pbb0,		HDMI_CEC,	RSVD1,			RSVD2,		RSVD3,		0x1060,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(spi2_sck_pcc0,		SPI2_SCK,	RSVD1,			RSVD2,		RSVD3,		0x10b0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(spi2_miso_pcc1,	SPI2_DIN,	RSVD1,			RSVD2,		RSVD3,		0x10b8,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(spi2_mosi_pcc2,	SPI2_DOUT,	RSVD1,			RSVD2,		RSVD3,		0x1090,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(spi2_cs0_pcc3,		SPI2_CS0,	RSVD1,			RSVD2,		RSVD3,		0x10a0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(spi2_cs1_pcc4,		SPI2_CS1,	RSVD1,			RSVD2,		RSVD3,		0x11c8,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart3_tx_pcc5,		UARTC_TXD,	RSVD1,			RSVD2,		RSVD3,		0x1078,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart3_rx_pcc6,		UARTC_RXD,	RSVD1,			RSVD2,		RSVD3,		0x1070,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(gen2_i2c_scl_pcc7,	I2C2_CLK,	RSVD1,			RSVD2,		RSVD3,		0x1098,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(gen2_i2c_sda_pdd0,	I2C2_DAT,	RSVD1,			RSVD2,		RSVD3,		0x10a8,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(gen8_i2c_scl_pdd1,	I2C8_CLK,	RSVD1,			RSVD2,		RSVD3,		0x1088,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(gen8_i2c_sda_pdd2,	I2C8_DAT,	RSVD1,			RSVD2,		RSVD3,		0x1080,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(touch_clk_pdd3,	GP_PWM4,	TOUCH_CLK,		RSVD2,		RSVD3,		0x1068,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(dmic1_clk_pdd4,	DMIC1_CLK,	RSVD1,			DMIC5_CLK,	RSVD3,		0x11d0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(dmic1_dat_pdd5,	DMIC1_DAT,	RSVD1,			DMIC5_DAT,	RSVD3,		0x11d8,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio19_pdd6,	RSVD0,		WDT_RESET_OUTB,		RSVD2,		RSVD3,		0x10f8,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio49_pee2,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10c0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio50_pee4,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10c8,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio82_pee3,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10d0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio71_pff2,	PPC_MODE_1,	RSVD1,			RSVD2,		RSVD3,		0x10d8,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio76_pff7,	RSVD0,		RSVD1,			TSC_EDGE_OUT0,	TSC_EDGE_OUT0A,	0x10e0,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio74_pff5,	PPC_READY,	PPC_I2C_DAT,		RSVD2,		RSVD3,		0x10e8,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio86_phh3,	RSVD0,		SPI5_CS1,		TSC_EDGE_OUT3,	TSC_EDGE_OUT0D,	0x1100,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio72_pff3,	PPC_MODE_2,	RSVD1,			RSVD2,		RSVD3,		0x1108,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio77_pgg0,	RSVD0,		RSVD1,			TSC_EDGE_OUT1,	TSC_EDGE_OUT0B,	0x1110,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio80_pff6,	RSVD0,		PPC_RST_N,		RSVD2,		RSVD3,		0x1118,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio84_pgg1,	RSVD0,		RSVD1,			TSC_EDGE_OUT2,	TSC_EDGE_OUT0C,	0x1120,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio83_pee5,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1128,		1,	Y,	-1,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio73_pff4,	PPC_CC,		PPC_I2C_CLK,		RSVD2,		RSVD3,		0x1130,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio70_pff1,	PPC_MODE_0,	RSVD1,			RSVD2,		RSVD3,		0x1138,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio85_pgg6,	RSVD0,		SPI4_CS1,		RSVD2,		RSVD3,		0x1148,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(soc_gpio69_pff0,	PPC_INT_N,	RSVD1,			RSVD2,		RSVD3,		0x1150,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart5_tx_pgg7,		UARTE_TXD,	SPI5_SCK,		RSVD2,		RSVD3,		0x1168,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart5_rx_phh0,		UARTE_RXD,	SPI5_MISO,		RSVD2,		RSVD3,		0x1170,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart2_tx_pgg2,		UARTB_TXD,	SPI4_SCK,		RSVD2,		RSVD3,		0x1178,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart2_rx_pgg3,		UARTB_RXD,	SPI4_MISO,		RSVD2,		RSVD3,		0x1180,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart2_cts_pgg5,	UARTB_CTS,	SPI4_CS0,		RSVD2,		RSVD3,		0x1188,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart2_rts_pgg4,	UARTB_RTS,	SPI4_MOSI,		RSVD2,		RSVD3,		0x1190,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart5_cts_phh2,	UARTE_CTS,	SPI5_CS0,		RSVD2,		RSVD3,		0x1198,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(uart5_rts_phh1,	UARTE_RTS,	SPI5_MOSI,		RSVD2,		RSVD3,		0x11a0,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(pwm2_pdd7,		GP_PWM2,	LED_BLINK,		RSVD2,		RSVD3,		0x11b0,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(pwm3_pee0,		GP_PWM3,	RSVD1,			RSVD2,		RSVD3,		0x11b8,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
-	PINGROUP(pwm7_pee1,		GP_PWM7,	RSVD1,			RSVD2,		RSVD3,		0x11a8,		1,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(bootv_ctl_n_paa0,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1028,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio00_paa1,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10f0,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(vcomp_alert_paa2,	SOC_THERM_OC1,	RSVD1,			RSVD2,		RSVD3,		0x1058,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(pwm1_paa3,		GP_PWM1,	RSVD1,			RSVD2,		RSVD3,		0x11c0,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(batt_oc_paa4,		SOC_THERM_OC2,	RSVD1,			RSVD2,		RSVD3,		0x1020,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio04_paa5,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1140,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio25_paa6,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1158,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio26_paa7,	RSVD0,		SOC_THERM_OC3,		RSVD2,		RSVD3,		0x1160,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(hdmi_cec_pbb0,		HDMI_CEC,	RSVD1,			RSVD2,		RSVD3,		0x1060,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(spi2_sck_pcc0,		SPI2_SCK,	RSVD1,			RSVD2,		RSVD3,		0x10b0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(spi2_miso_pcc1,	SPI2_DIN,	RSVD1,			RSVD2,		RSVD3,		0x10b8,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(spi2_mosi_pcc2,	SPI2_DOUT,	RSVD1,			RSVD2,		RSVD3,		0x1090,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(spi2_cs0_pcc3,		SPI2_CS0,	RSVD1,			RSVD2,		RSVD3,		0x10a0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(spi2_cs1_pcc4,		SPI2_CS1,	RSVD1,			RSVD2,		RSVD3,		0x11c8,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart3_tx_pcc5,		UARTC_TXD,	RSVD1,			RSVD2,		RSVD3,		0x1078,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart3_rx_pcc6,		UARTC_RXD,	RSVD1,			RSVD2,		RSVD3,		0x1070,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(gen2_i2c_scl_pcc7,	I2C2_CLK,	RSVD1,			RSVD2,		RSVD3,		0x1098,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(gen2_i2c_sda_pdd0,	I2C2_DAT,	RSVD1,			RSVD2,		RSVD3,		0x10a8,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(gen8_i2c_scl_pdd1,	I2C8_CLK,	RSVD1,			RSVD2,		RSVD3,		0x1088,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(gen8_i2c_sda_pdd2,	I2C8_DAT,	RSVD1,			RSVD2,		RSVD3,		0x1080,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(touch_clk_pdd3,	GP_PWM4,	TOUCH_CLK,		RSVD2,		RSVD3,		0x1068,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(dmic1_clk_pdd4,	DMIC1_CLK,	RSVD1,			DMIC5_CLK,	RSVD3,		0x11d0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(dmic1_dat_pdd5,	DMIC1_DAT,	RSVD1,			DMIC5_DAT,	RSVD3,		0x11d8,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio19_pdd6,	RSVD0,		WDT_RESET_OUTB,		RSVD2,		RSVD3,		0x10f8,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio49_pee2,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10c0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio50_pee4,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10c8,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio82_pee3,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x10d0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio71_pff2,	PPC_MODE_1,	RSVD1,			RSVD2,		RSVD3,		0x10d8,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio76_pff7,	RSVD0,		RSVD1,			TSC_EDGE_OUT0,	TSC_EDGE_OUT0A,	0x10e0,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio74_pff5,	PPC_READY,	PPC_I2C_DAT,		RSVD2,		RSVD3,		0x10e8,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio86_phh3,	RSVD0,		SPI5_CS1,		TSC_EDGE_OUT3,	TSC_EDGE_OUT0D,	0x1100,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio72_pff3,	PPC_MODE_2,	RSVD1,			RSVD2,		RSVD3,		0x1108,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio77_pgg0,	RSVD0,		RSVD1,			TSC_EDGE_OUT1,	TSC_EDGE_OUT0B,	0x1110,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio80_pff6,	RSVD0,		PPC_RST_N,		RSVD2,		RSVD3,		0x1118,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio84_pgg1,	RSVD0,		RSVD1,			TSC_EDGE_OUT2,	TSC_EDGE_OUT0C,	0x1120,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio83_pee5,	RSVD0,		RSVD1,			RSVD2,		RSVD3,		0x1128,		0,	Y,	-1,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio73_pff4,	PPC_CC,		PPC_I2C_CLK,		RSVD2,		RSVD3,		0x1130,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio70_pff1,	PPC_MODE_0,	RSVD1,			RSVD2,		RSVD3,		0x1138,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio85_pgg6,	RSVD0,		SPI4_CS1,		RSVD2,		RSVD3,		0x1148,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(soc_gpio69_pff0,	PPC_INT_N,	RSVD1,			RSVD2,		RSVD3,		0x1150,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart5_tx_pgg7,		UARTE_TXD,	SPI5_SCK,		RSVD2,		RSVD3,		0x1168,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart5_rx_phh0,		UARTE_RXD,	SPI5_MISO,		RSVD2,		RSVD3,		0x1170,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart2_tx_pgg2,		UARTB_TXD,	SPI4_SCK,		RSVD2,		RSVD3,		0x1178,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart2_rx_pgg3,		UARTB_RXD,	SPI4_MISO,		RSVD2,		RSVD3,		0x1180,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart2_cts_pgg5,	UARTB_CTS,	SPI4_CS0,		RSVD2,		RSVD3,		0x1188,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart2_rts_pgg4,	UARTB_RTS,	SPI4_MOSI,		RSVD2,		RSVD3,		0x1190,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart5_cts_phh2,	UARTE_CTS,	SPI5_CS0,		RSVD2,		RSVD3,		0x1198,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(uart5_rts_phh1,	UARTE_RTS,	SPI5_MOSI,		RSVD2,		RSVD3,		0x11a0,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(pwm2_pdd7,		GP_PWM2,	LED_BLINK,		RSVD2,		RSVD3,		0x11b0,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(pwm3_pee0,		GP_PWM3,	RSVD1,			RSVD2,		RSVD3,		0x11b8,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
+	PINGROUP(pwm7_pee1,		GP_PWM7,	RSVD1,			RSVD2,		RSVD3,		0x11a8,		0,	Y,	5,	7,	6,	8,	-1,	10,	12),
 };
 
 static const struct tegra_pinctrl_soc_data tegra238_pinctrl_aon = {
Signature · 1 line
2.53.0
author maintainer
#115 lore raw

PATCH 115/457 drm/bridge: samsung-dsim: fix TE GPIO lifetime for host attach

In reply to Greg Kroah-Hartman

7.2-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 9ee0515074c78..7e320eac2e4ad 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
#116 lore raw

PATCH 116/457 ovpn: preserve IPv6 scope id for netlink peer endpoints

In reply to Greg Kroah-Hartman

7.2-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 4dad852941982..2ba762082acc1 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
#117 lore raw

PATCH 117/457 ovpn: skip UDP source validation for unspecified addresses

In reply to Greg Kroah-Hartman

7.2-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 7f69e8890b5b5..df4750dabd1e1 100644
@@ -161,8 +161,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
@@ -238,7 +238,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
#118 lore raw

PATCH 118/457 ovpn: track UDP socket route key for peer dst cache

In reply to Greg Kroah-Hartman

7.2-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 c95656ca7c357..b400783c2efab 100644
@@ -113,6 +113,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 dfa5c0037e02b..063535699ecd8 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
@@ -45,6 +56,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
@@ -55,7 +68,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
@@ -99,6 +112,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;
@@ -109,7 +124,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
#119 lore raw

PATCH 119/457 ovpn: validate peer state before caching UDP dst

In reply to Greg Kroah-Hartman

7.2-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 c6d591cb7ff45..eeef4a7229f5b 100644
@@ -173,6 +173,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
@@ -240,7 +269,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);
 
@@ -313,7 +342,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
#120 lore raw

PATCH 120/457 ovpn: replace bind when learning local endpoint

In reply to Greg Kroah-Hartman

7.2-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 b400783c2efab..430c6cd48db87 100644
@@ -200,13 +200,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,
@@ -233,8 +232,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;
 		}
 
@@ -246,10 +244,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))) {
@@ -271,8 +271,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;
 		}
 
@@ -285,26 +284,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
#121 lore raw

PATCH 121/457 ovpn: replace bind when clearing stale local source

In reply to Greg Kroah-Hartman

7.2-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 eeef4a7229f5b..055cdb1bee13b 100644
@@ -185,7 +185,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,
@@ -218,6 +218,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,
@@ -236,24 +239,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);
 	}
@@ -267,10 +263,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:
@@ -300,6 +314,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;
 
@@ -320,15 +337,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 = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
@@ -340,10 +353,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