Skip to contentSkip to conversation

6.18.45-rc1 review

PATCH In review Greg Kroah-Hartman 13 participants 264 messages Aug 17 – Aug 20 Stable branch Page 1 of 2

lore
Share & tools
lore

Greg Kroah-Hartman

author maintainer
#0 lore raw

cover 6.18.45-rc1 review

This is the start of the stable review cycle for the 6.18.45 release. There are 250 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Responses should be made by Wed, 19 Aug 2026 13:23:44 +0000. Anything received after that time might be too late.

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

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

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

thanks,

greg k-h

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

Greg Kroah-Hartman <[email protected]>

    Linux 6.18.45-rc1

Pablo Neira Ayuso <[email protected]>
netfilter: flowtable: ensure sufficient headroom in xmit path

Lorenzo Bianconi <[email protected]>
netfilter: always set route tuple out ifindex

Xu Rao <[email protected]>
thunderbolt: Fix bandwidth group reservation indexing

Bryam Vargas <[email protected]>

    thunderbolt: Bound the DROM dual link port number before indexing sw->ports

Qing Ming <[email protected]>
sctp: clear new_transport when removing a peer

Yuxiang Yang <[email protected]>
sctp: fix use-after-free of cached ASCONF chunk

Baul Lee <[email protected]>

    sctp: keep chunk->transport in step with the list it is queued on

Xu Rao <[email protected]>
scsi: scsi_debug: Negate wrapped memcmp() result

Chengfeng Ye <[email protected]>
bpf, sockmap: Fix sk_redir use-after-free in send verdict

Eric Biggers <[email protected]>
fsverity: Fix silent truncation in bpf_get_fsverity_digest()

Eric Biggers <[email protected]>
fsverity: Fix bpf_get_fsverity_digest() dynptr assumptions

Hugh Dickins <[email protected]>
mm/filemap: __filemap_add_folio() restore index before retrying

Mimi Zohar <[email protected]>
ima: Instantiate file_truncate and path_truncate hooks

Tejun Heo <[email protected]>
sched/psi: Create the psimon kthread outside of cgroup_mutex

Tejun Heo <[email protected]>
sched/psi: Shut down rtpoll_timer in psi_cgroup_free()

Zhan Xusheng <[email protected]>
fscrypt: use the mount idmap for the owner check in fscrypt_ioctl_set_policy()

Zhiling Zou <[email protected]>

    ip6_tunnel: clear skb2->cb[] in ip6ip6_err()

Yuejie Shi <[email protected]>
ipv6: fix Route Information option length validation

Lorenzo Stoakes (ARM) <[email protected]>
mm/ptdump: always stabilise against page table freeing using init_mm

Tengda Wu <[email protected]>
ring-buffer: Use current_context for safe per-CPU buffer swap

Vincent Donnefort <[email protected]>
ring-buffer: Initialise reader page order in rb_allocate_cpu_buffer()

Ahmad Byagowi <[email protected]>
ptp: ocp: Fix board ID over-read

Rafael J. Wysocki <[email protected]>
Revert "thermal/drivers/hwmon: Cleanup coding style a bit"

Steven Rostedt <[email protected]>
eventfs: Use children field for rcu head and add memory barriers

Shuangpeng Bai <[email protected]>
eventfs: Fix use-after-free in eventfs_remove_rec()

Sean Christopherson <[email protected]>
KVM: x86/mmu: WARN and clear role.invalid when creating a child shadow page

Paolo Bonzini <[email protected]>
KVM: SVM: Serialize accesses to the owner and mirror list with separate lock

Shuangpeng Bai <[email protected]>
smb: client: Fix use-after-free in cifs_try_adding_channels()

Jun Yang <[email protected]>

    tipc: read le->link under the node lock in tipc_node_link_down()

chanyoung <[email protected]>
tls: don't leave a full plaintext sk_msg ring unpushed

Jérémy Jean <[email protected]>
tls: rx: restore msg_iter before TLS 1.3 optimistic retry

Jun Yang <[email protected]>
vhost: reset the vring metadata cache on vring reconfiguration

Sun Jian <[email protected]>
veth: fix skb length accounting after XDP frag adjustment

Weiming Shi <[email protected]>
vsock/virtio: avoid refilling the RX queue after teardown

Weiming Shi <[email protected]>
vsock/virtio: read virtqueues under worker locks

Baul Lee <[email protected]>
vxlan: do not arm the ageing timer on a device that is down

Zhiling Zou <[email protected]>
xdp: reject clones that overrun skb_shared_info tailroom

Breno Leitao <[email protected]>
x86/mce: Set up the polling timer before CMCI discovery

Rik van Riel <[email protected]>
x86/CPU: Add a tlbi= cmdline switch

Lorenzo Stoakes (ARM) <[email protected]>
arm64: remove redundant concurrent ptdump UAF mitigation

Hidayath Khan <[email protected]>

    dibs: initialise dibs->lock in dibs_dev_alloc()

Asad Kamal <[email protected]>
Revert "drm/amdgpu: fix aperture mapping leak"

Christian Brauner <[email protected]>
binfmt_misc: don't warn when the mount is completed from another user namespace

Christian Brauner <[email protected]>
ovl: don't warn when the mount is completed from another user namespace

Hyunjung Ko <[email protected]>
net/sched: act_gact, act_police: range check the fallback control action

Hyunjung Ko <[email protected]>
net/sched: act_ct: fix sk_buff leak when the header checks reject a packet

Yangyu Chen <[email protected]>
net: atlantic: free RX pages of consumed but not refilled buffers

Yangyu Chen <[email protected]>
net: atlantic: free stranded TX buffers on ring deinit

Zihan Xi <[email protected]>
netfilter: nf_conntrack: defer invalid log until after unlock

Zhiling Zou <[email protected]>
netfilter: bridge: release template ct on non-IP path

Pavel Begunkov <[email protected]>
net: devmem: prevent net-iov / page mixing

Baul Lee <[email protected]>
net/x25: fix use-after-free of the socket by its timers

Alexandra Winter <[email protected]>
net/dibs: Correct freeing of dmb_clientid_arr

Kyle Zeng <[email protected]>
ipv6: prevent in6_dev_get() from resurrecting inet6_dev

Daming Li <[email protected]>
net: smc: fix splice entry lifetime imbalance in smc_rx_splice

Ahmed Naseef <[email protected]>
net: phy: mediatek: fix TX blink masks using the RX bits

Lorenzo Stoakes (ARM) <[email protected]>
mm/huge_memory: fix huge_zero_pfn race

Hui Su <[email protected]>
tracing: Fix NULL pointer dereference in module event cache removal

Vincent Donnefort <[email protected]>
ring-buffer: Prevent subbuf order change when resizing is disabled

Rik van Riel <[email protected]>
fbdev: bitblit: bound-check glyph index in bit_cursor()

Michael Wu <[email protected]>
tracing: Fix race between update_event_fields and, event_define_fields

Aditya Chillara <[email protected]>
perf/core: Fix group leader use-after-free after sibling detach

Maíra Canal <[email protected]>
drm/v3d: Serialize the scheduler timeout handlers

Baul Lee <[email protected]>
ALSA: us144mkii: re-anchor capture URBs on resubmission

Xu Rao <[email protected]>
ALSA: hda/tas2781: fix ACPI reference handling

Baul Lee <[email protected]>
ALSA: FCP: fix OOB write in fcp_meter_ctl_get()

Baul Lee <[email protected]>
ALSA: usx2y: bound the hwdep mmap fault offset

Takashi Iwai <[email protected]>
ALSA: usb: Fix UAF at delayed release of MIDI2 EPs

SJ Park <[email protected]>

    mm/damon: adjust isolated pages stat for DAMOS_MIGRATE_{HOT,COLD}

SJ Park <[email protected]>
samples/damon/mtier: error out for zero quota goal target values

liyouhong <[email protected]>
mm/damon/ops-common: putback folios on invalid migrate nid

Hui Su <[email protected]>
ring-buffer: Fix crash passing ERR_PTR to kthread_stop()

Eddie Lin <[email protected]>
misc: fastrpc: fix memory leak in fastrpc_channel_ctx_free

Junrui Luo <[email protected]>

    misc: fastrpc: take fl->lock when moving mmaps on interrupted invoke

Ekansh Gupta <[email protected]>
misc: fastrpc: Remove buffer from list prior to unmap operation

Anandu Krishnan E <[email protected]>
misc: fastrpc: fix channel ctx ref leak when session alloc fails

Ekansh Gupta <[email protected]>
misc: fastrpc: Fix initial memory allocation for Audio PD memory pool

Mariano Baragiola <[email protected]>
staging: rtl8723bs: validate monitor transmit frame lengths

Panagiotis Petrakopoulos <[email protected]>
staging: rtl8723bs: fix missing shared-key auth challenge length check

Muhammad Bilal <[email protected]>
staging: rtl8723bs: fix OOB read in WMM_param_handler()

Muhammad Bilal <[email protected]>
staging: rtl8723bs: fix OOB read in rtw_get_wpa_ie()

Fan Wu <[email protected]>
serial: amba-pl011: synchronize DMA teardown

Fan Wu <[email protected]>
serial: amba-pl011: cancel RS485 hrtimers after freeing IRQ

Fan Wu <[email protected]>
serial: amba-pl011: fix indefinite RS485 post-send delay

Ryan Wilbur <[email protected]>
serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx

Cunhao Lu <[email protected]>
serial: 8250_dma: Clear stale RX state on shutdown

Jan Sebastian Götte <[email protected]>
serial: qcom-geni: fix TX DMA buffer flush

Alice Ryhl <[email protected]>
rust_binder: do not query current thread for all ioctls

Mathieu Dubois-Briand <[email protected]>
nvmem: layouts: Add fixed-layout driver

Aelin Reidel <[email protected]>
nvmem: apple-spmi-nvmem: wrap regmap calls to satisfy CFI

Alexander Usyskin <[email protected]>
mei: pull kvfree out of spinlock

Chengfeng Ye <[email protected]>
ipv4: fix use-after-free in fib_nhc_update_mtu()

Zihan Xi <[email protected]>
ipv4: Fix fib_nlmsg_size() for RTA_VIA nexthops

Michal Luczaj <[email protected]>
selftests/bpf: Adapt sockmap update error handling

Michal Luczaj <[email protected]>
selftests/bpf: Ensure UDP sockets are bound

Nils Helmig <[email protected]>
Bluetooth: btusb: Add TP-Link UB600 for Realtek 8761BUV

Alexej Sidorenko <[email protected]>
Bluetooth: btrtl: fix RTL8761B/BU broken LE extended scan

Florian Westphal <[email protected]>
netfilter: nf_tables: avoid softlockup warnings in nft_chain_validate

Keno Fischer <[email protected]>
futex: Prevent robust futex exit race some more

Jose Fernandez (Anthropic) <[email protected]>
iommu/vt-d: Gather the unmapped range before freeing its page tables

Harshal Dev <[email protected]>
dt-bindings: crypto: qcom,ice: Fix missing power-domain and iface clk

Matthew Rosato <[email protected]>
KVM: s390: pci: Fix aisb calculation

Keith Busch <[email protected]>
blk-mq: reinsert cached request to the list

Keith Busch <[email protected]>
blk-mq: pop cached request if it is usable

Alex Deucher <[email protected]>
Revert "drm/amd/display: Fix backlight max_brightness to match exported range"

Baul Lee <[email protected]>
net: bridge: mrp: fix uninitialised bytes on the wire

Chengfeng Ye <[email protected]>
netfilter: ebt_nflog: pin the NFLOG backend

Philipp David <[email protected]>
igc: fix netdev not re-attached after resume if interface is down

Zihan Xi <[email protected]>
mac802154: fix netdev use-after-free in beacon worker

Zhiling Zou <[email protected]>
inet: frags: publish queues before arming timer

Qihang Tang <[email protected]>
net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header

Sergey V. Frolov <[email protected]>
net: octeontx2-pf: Fix UB in shift operation

Zijie Huang <[email protected]>
net/sched: reject overly deep qdisc hierarchies

Zhiling Zou <[email protected]>
net: openvswitch: reallocate update replies for mismatched IDs

Sun Jian <[email protected]>
net: fix skb length accounting after generic XDP frag adjustment

Zihan Xi <[email protected]>
packet: synchronize pressure clearing with ring reconfiguration

Doruk Tan Ozturk <[email protected]>
net/packet: reset the MAC header on the packet-socket transmit path

Qihang Tang <[email protected]>
packet: use consistent hard_header_len in TX_RING send path

Qihang Tang <[email protected]>
packet: use consistent hard_header_len in non-ring send paths

Kyle Zeng <[email protected]>
ipvs: clear IPv4 options after rebasing tunnel ICMP errors

Julian Anastasov <[email protected]>
ipvs: properly update the overload flag on dest edit

Julian Anastasov <[email protected]>
ipvs: add totalconns for dest

Zhiling Zou <[email protected]>
ipvs: stop estimator after disabled calc phase

Lincoln Wallace <[email protected]>
ima: fix out-of-bounds read in xattr_verify()

Lorenzo Stoakes (ARM) <[email protected]>
mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF

Dmitry Torokhov <[email protected]>
Input: evdev - fix information leak in evdev_pass_values()

Joshua Rogers <[email protected]>
vt: stabilize tty reference in kbd_keycode with tty_port_tty_get

Joshua Rogers <[email protected]>
vt: add permission check for KDSKBMETA ioctl

Doruk Tan Ozturk <[email protected]>
net: usb: ipheth: fix carrier_work UAF on disconnect

Yi Cong <[email protected]>

    net: usb: ax88179_178a: fix skb leak in ax88179_tx_fixup()

Sonali Pradhan <[email protected]>
usb: gadget: f_ncm: Use unsigned int for ndp_index

Pawel Laszczak <[email protected]>
usb: cdnsp: fix incorrect endian conversions for APB timeout register

Xu Rao <[email protected]>
thunderbolt: icm: Preserve USB4 proxy data-valid bit

Aleksandr Nogikh <[email protected]>
usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm()

Jiangshan Yi <[email protected]>
usb: misc: usbio: check ibuf_len against rxbuf_len in bulk msg

Ishaan Dandekar <[email protected]>
usb: quirks: Add ShanWan gamepad to quirk list

Nikhil Solanke <[email protected]>
usb: core: Add quirk for 255-bytes initial config read

Baul Lee <[email protected]>
ALSA: usb-audio: fix OOB write on Type II inbound URBs

Dmitry Torokhov <[email protected]>
Input: evdev - sanitize event type index when fetching event masks

Dongli Zhang <[email protected]>

    net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()

Mehmet Fide <[email protected]>
net: fec: do not release NULL pages when RX buffer allocation fails

Guenter Roeck <[email protected]>
hwmon: (ltc4282) Fix parsing adi,current-limit-sense-microvolt

Guenter Roeck <[email protected]>
hwmon: (ltc4282) Clamp negative current limits

Guenter Roeck <[email protected]>
hwmon: (ltc4282) Avoid overflow in maximum power calculation

Qingshuang Fu <[email protected]>
hwmon: (ads7828) Fix external VREF regulator handling

Wilken Gottwalt <[email protected]>
hwmon: (corsair-psu) fix possible out-of-bounds access on missing string termination

Hongyan Xu <[email protected]>
watchdog: at91sam9_wdt: prevent timer rearm during teardown

Maximilian Immanuel Brandtner <[email protected]>
tls: don't abort the connection on signal-interrupted sends

Xin Long <[email protected]>
sctp: clear control chunk transport if it is being removed

Eric Dumazet <[email protected]>
net/atm: fix slab-out-of-bounds read in vcc_setsockopt()

Alexandra Winter <[email protected]>
s390/ism: Fix UAF of sba and ieq during ism_dev_exit()

Bhargava Marreddy <[email protected]>
bnge: Fix resource leak in bnge_init_nic() error path

Hongyan Xu <[email protected]>
ata: pata_sl82c105: fix bridge revision use-after-free

Fan XinRan <[email protected]>
net: thunderbolt: Tear down DMA paths before stopping the rings

Sidraya Jayagond <[email protected]>
net/smc: fix TOCTOU race between smc_listen_out() and listener close

Eric Dumazet <[email protected]>
net: remove WARN_ON_ONCE() from sk_mc_loop()

Pengpeng Hou <[email protected]>
net: prestera: validate firmware header length

Henry Martin <[email protected]>
net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length

Eric Dumazet <[email protected]>
netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()

Pablo Neira Ayuso <[email protected]>
netfilter: flowtable: consolidate xmit path

Jiayuan Chen <[email protected]>
tcp: fix TFO max_qlen accounting across reuseport migration

Qing Luo <[email protected]>
sctp: fix addip_serial increment on ASCONF_ACK allocation failure

Keegan Freyhof <[email protected]>
bnxt_en: Fix PTP PPS setting bug

Michael Chan <[email protected]>
bnxt_en: Disable EOP for TPA on all chips to prevent data corruption

Shravya KN <[email protected]>
bnxt_en: Refresh VNIC default ring on queue restart if needed

Shravya KN <[email protected]>
bnxt_en: Determine and store default RX ring in vnic structure

Shravya KN <[email protected]>
bnxt_en: Move RSS table fill outside __bnxt_hwrm_vnic_set_rss()

Bobby Eshleman <[email protected]>
net/mlx5e: fix BQL reset on SQ re-activation

Alok Tiwari <[email protected]>
bnge: use int for bnge_fix_rings_count() return value

Stefan Agner <[email protected]>
net: stmmac: resume PHY before hardware setup when opening the interface

Martin Kaiser <[email protected]>
selftests/ftrace: refactor eprobes test to fix argument checks

Guenter Roeck <[email protected]>
hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations

Qingshuang Fu <[email protected]>
hwmon: (nzxt-smart2) Check return value of init_device() in probe

Marcin Bernatowicz <[email protected]>
drm/xe/uc: Apply RCS/CCS yield policy to SR-IOV VFs

Jamal Hadi Salim <[email protected]>
net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers

Cen Zhang (Microsoft) <[email protected]>
net/openvswitch: check Ethernet header length in key_extract()

Jia Jia <[email protected]>
vhost-scsi: reject feature changes after endpoint

Linfeng Sun <[email protected]>
vhost-scsi: Validate T10 PI scatterlist counts

Toke Høiland-Jørgensen <[email protected]>
net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK filter

Xuanqiang Luo <[email protected]>
udp: fix potential use-after-free in tunnel segmentation

Stanislav Fomichev <[email protected]>
xsk: validate metadata when processing requests

Stanislav Fomichev <[email protected]>
xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h

Stanislav Fomichev <[email protected]>
xsk: validate launch-time metadata size

Stanislav Fomichev <[email protected]>
xsk: clear metadata pointer when no timestamp is requested

Stanislav Fomichev <[email protected]>
xsk: pass TX metadata pointer by reference

Stanislav Fomichev <[email protected]>
xsk: require at least 16 bytes of TX metadata

Will Chen <[email protected]>
bnxt: fix memory leak in bnxt_queue_mem_alloc error cases

Pavel Begunkov <[email protected]>
eth: bnxt: support qcfg provided rx page size

Pavel Begunkov <[email protected]>
eth: bnxt: store rx buffer size per queue

Pavel Begunkov <[email protected]>
net: pass queue rx page size from memory provider

Pavel Begunkov <[email protected]>
net: add bare bone queue configs

Jakub Kicinski <[email protected]>
net: reduce indent of struct netdev_queue_mgmt_ops members

Michael Chan <[email protected]>
bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips

Nathan Gao <[email protected]>
tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()

Guenter Roeck <[email protected]>
hwmon: (pmbus) Fix type confusion in notification logic

Guenter Roeck <[email protected]>
hwmon: (pmbus_core) Use guard() for mutex protection

Christian Borntraeger <[email protected]>
vdpa/mlx5: Fix buffer length in create_direct_keys()

Yousef Alhouseen <[email protected]>
vhost/vdpa: reject overflowing PA map page counts on 32-bit

Jose Fernandez (Anthropic) <[email protected]>
bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()

Babanpreet Singh <[email protected]>
counter: microchip-tcb-capture: Fix DT channel validation

Michael Guralnik <[email protected]>
net/mlx5: fw_tracer, return NULL on create error

Or Har-Toov <[email protected]>
devlink: fix net namespace reference leak in reload

Jiawen Liu <[email protected]>
net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete

Jamal Hadi Salim <[email protected]>
net/sched: cls_route: fix fastmap use-after-free on filter

Mahanta Jambigi <[email protected]>
net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in smc_llc_event_handler()

Yiyang Chen <[email protected]>
bpf: Propagate untrusted pointer state in commuted arithmetic

Eduard Zingerman <[email protected]>
bpf: split check_reg_sane_offset() in two parts

Yiyang Chen <[email protected]>
bpf: Preserve pointer state for commuted arithmetic

Dmitry Antipov <[email protected]>
btrfs: fix memory leak in btrfs_do_encoded_write()

Matti Vaittinen <[email protected]>
watchdog: bd96801_wdt: Fix timeout for enabled WDG

Julian Anastasov <[email protected]>
ipvs: return the csum validation for forward hook

Julian Anastasov <[email protected]>
ipvs: avoid out-of-bounds write in ip_vs_nat_icmp

Jozsef Kadlecsik <[email protected]>
netfilter: ipset: switch ext_size to atomic64_t

Nikhil P. Rao <[email protected]>
pds_core: cancel pending PCI reset work on AER recovery

Nikhil P. Rao <[email protected]>
pds_core: keep the health thread stopped during reset

Shay Drory <[email protected]>
net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock

Satish Kharat <[email protected]>
enic: fix tx_hang_reset use-after-free on device removal

Xiang Mei (Microsoft) <[email protected]>
bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor

Fan Ye <[email protected]>
Revert "net: thunderbolt: Enable end-to-end flow control also in transmit"

Jijie Shao <[email protected]>
net: hns3: fix speed configuration residue after driver reload

Pengpeng Hou <[email protected]>
drm/bridge: ps8640: propagate AUX transfer register errors

Qingfang Deng <[email protected]>
ovpn: fix incorrect use of rcu_access_pointer()

Antonio Quartulli <[email protected]>
ovpn: ensure TCP vars are initialized first

Antonio Quartulli <[email protected]>
ovpn: disable IPv4 redirects on MP interfaces

Antonio Quartulli <[email protected]>
ovpn: hash floated peer by transport identity only

Antonio Quartulli <[email protected]>
ovpn: zero-initialize sockaddr before learning a floated endpoint

Antonio Quartulli <[email protected]>
ovpn: ensure socket is owned by ovpn before deref sk_user_data

Antonio Quartulli <[email protected]>
ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET

Antonio Quartulli <[email protected]>
ovpn: skip rehash for peers already removed from by_id

Rosen Penev <[email protected]>
ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt

Ralf Lici <[email protected]>

    ovpn: add missing rtnl_link_ops->get_size callback

Hans Ulli Kroll <[email protected]>
pinctrl: qcom: ipq806x: mark pci reset as a GPIO pin function

Hans Ulli Kroll <[email protected]>
pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function

Kuba Piecuch <[email protected]>
selftests/sched_ext: Handle sleeping task affinity changes in numa test

Yuho Choi <[email protected]>
ARM: npcm: Fix OF node refcount leaks in SMP setup

Yun Zhou <[email protected]>
xfs: handle NULL b_addr in xfs_buf_free

Daniel Drake <[email protected]>
arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual timer

Anna Schumaker <[email protected]>
NFS: Pin the 'struct nfs_server' during a FREE_STATEID call

Dmitry Baryshkov <[email protected]>
arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle

Akhil P Oommen <[email protected]>
arm64: dts: qcom: purwa: Fix GPU IOMMU property

Dmitry Baryshkov <[email protected]>

    arm64: dts: qcom: rename x1p42100 to purwa

Aleksandrs Vinarskis <[email protected]>
arm64: dts: qcom: Rework X1-based Asus Zenbook A14's displays

Dmitry Baryshkov <[email protected]>

    arm64: dts: qcom: rename x1e80100 to hamoa

Ray Wu <[email protected]>
drm/amd/display: Check for tg ops in dce110_set_avmute

Ray Wu <[email protected]>
drm/amd/display: Add AV mute wait frames to dce110_set_avmute

Michal Luczaj <[email protected]>
selftests/bpf: Fail unbound UDP on sockmap update

Peter Zijlstra <[email protected]>
sched/fair: Revert 6d71a9c61604 ("sched/fair: Fix EEVDF entity placement bug causing scheduling lag")

Ingo Molnar <[email protected]>

    sched/fair: Separate se->vlag from se->vprot

Al Viro <[email protected]>
mount: honour SB_NOUSER in the new mount API

Farhan Ali <[email protected]>
KVM: s390: pci: Fix resource leak on IRQ registration failure

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

Diffstat:

 Documentation/admin-guide/kernel-parameters.txt    |   9 +
 .../bindings/crypto/qcom,inline-crypto-engine.yaml |  16 +-
 MAINTAINERS                                        |   5 +
 Makefile                                           |   4 +-
 arch/arm/boot/dts/broadcom/bcm-ns.dtsi             |   2 +-
 arch/arm/mach-npcm/platsmp.c                       |   2 +
 arch/arm64/boot/dts/broadcom/bcm2712.dtsi          |   2 -
 arch/arm64/boot/dts/qcom/Makefile                  |   2 +
 arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi        |   4 +-
 .../qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} |   0
 .../boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi}    |   0
 .../boot/dts/qcom/{x1p42100.dtsi => purwa.dtsi}    |   6 +-
 .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts      |   4 +
 arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi  |   9 +-
 arch/arm64/boot/dts/qcom/x1-crd.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi        |   2 +-
 arch/arm64/boot/dts/qcom/x1e001de-devkit.dts       |   4 +-
 .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi    |   4 +-
 .../boot/dts/qcom/x1e80100-asus-vivobook-s15.dts   |   4 +-
 .../boot/dts/qcom/x1e80100-asus-zenbook-a14.dts    |  10 +-
 arch/arm64/boot/dts/qcom/x1e80100-crd.dts          |   2 +-
 .../qcom/x1e80100-dell-inspiron-14-plus-7441.dts   |   2 +-
 .../boot/dts/qcom/x1e80100-dell-latitude-7455.dts  |   2 +-
 .../boot/dts/qcom/x1e80100-dell-xps13-9345.dts     |   4 +-
 .../boot/dts/qcom/x1e80100-hp-omnibook-x14.dts     |   4 +-
 .../boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts  |   4 +-
 .../boot/dts/qcom/x1e80100-microsoft-romulus.dtsi  |   4 +-
 arch/arm64/boot/dts/qcom/x1e80100-qcp.dts          |   4 +-
 .../dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts     |  62 ++++
 .../boot/dts/qcom/x1p42100-asus-zenbook-a14.dts    | 133 +-------
 .../boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi   | 138 +++++++++
 arch/arm64/boot/dts/qcom/x1p42100-crd.dts          |   2 +-
 .../boot/dts/qcom/x1p42100-hp-omnibook-x14.dts     |   4 +-
 .../boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts |   4 +-
 arch/arm64/include/asm/ptdump.h                    |   2 -
 arch/arm64/mm/mmu.c                                |  43 +--
 arch/arm64/mm/ptdump.c                             |  11 +-
 arch/s390/kvm/pci.c                                |  31 +-
 arch/x86/kernel/cpu/common.c                       |  10 +
 arch/x86/kernel/cpu/mce/core.c                     |   2 +-
 arch/x86/kvm/mmu/mmu.c                             |   3 +
 arch/x86/kvm/svm/sev.c                             |  34 ++-
 arch/x86/kvm/svm/svm.h                             |   1 +
 block/blk-mq.c                                     |  34 +--
 drivers/android/binder/process.rs                  |  12 +-
 drivers/ata/pata_sl82c105.c                        |   4 +-
 drivers/bluetooth/btrtl.c                          |  13 +
 drivers/bluetooth/btusb.c                          |   2 +
 drivers/counter/microchip-tcb-capture.c            |   4 +-
 drivers/dibs/dibs_loopback.c                       |   1 -
 drivers/dibs/dibs_main.c                           |  16 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   2 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c            |  35 ++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |   6 +-
 .../drm/amd/display/dc/hwss/dce110/dce110_hwseq.c  |  24 +-
 drivers/gpu/drm/bridge/parade-ps8640.c             |  27 +-
 drivers/gpu/drm/v3d/v3d_drv.h                      |   6 +
 drivers/gpu/drm/v3d/v3d_sched.c                    |   9 +-
 drivers/gpu/drm/xe/xe_uc.c                         |   7 +-
 drivers/hwmon/ads7828.c                            |  11 +-
 drivers/hwmon/corsair-psu.c                        |   4 +-
 drivers/hwmon/ltc4282.c                            |  20 +-
 drivers/hwmon/nzxt-smart2.c                        |   6 +-
 drivers/hwmon/pmbus/lm25066.c                      |   5 +-
 drivers/hwmon/pmbus/pmbus_core.c                   | 340 +++++++++------------
 drivers/input/evdev.c                              |  27 +-
 drivers/iommu/intel/iommu.c                        |  11 +-
 drivers/misc/fastrpc.c                             |  27 +-
 drivers/misc/mei/client.c                          |  25 +-
 drivers/net/bonding/bond_alb.c                     |  10 +-
 drivers/net/ethernet/amd/pds_core/core.h           |   1 +
 drivers/net/ethernet/amd/pds_core/main.c           |  14 +-
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |  51 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_ring.h   |   1 +
 drivers/net/ethernet/aquantia/atlantic/aq_vec.c    |   2 +-
 drivers/net/ethernet/broadcom/bnge/bnge_netdev.c   |   2 -
 drivers/net/ethernet/broadcom/bnge/bnge_resc.c     |   3 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt.c          | 163 +++++++---
 drivers/net/ethernet/broadcom/bnxt/bnxt.h          |   4 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c      |   7 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c      |   6 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h      |   2 +-
 drivers/net/ethernet/cisco/enic/enic_main.c        |   5 +-
 drivers/net/ethernet/freescale/fec_main.c          |  11 +-
 drivers/net/ethernet/google/gve/gve_main.c         |   9 +-
 drivers/net/ethernet/hisilicon/hix5hd2_gmac.c      |   1 -
 .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c    |   6 +-
 drivers/net/ethernet/intel/igc/igc_main.c          |  10 +-
 .../net/ethernet/marvell/octeontx2/nic/otx2_tc.c   |   6 +-
 .../net/ethernet/marvell/prestera/prestera_pci.c   |   3 +
 .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c   |  16 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |   2 +-
 .../net/ethernet/mellanox/mlx5/core/en/tc_priv.h   |   1 +
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c   |  15 +-
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h   |   4 +-
 .../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c    |   2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |  14 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c    |   4 +-
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c       |   8 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |  13 +-
 drivers/net/netdevsim/netdev.c                     |   7 +-
 drivers/net/ovpn/main.c                            |  64 ++--
 drivers/net/ovpn/netlink.c                         |   6 +
 drivers/net/ovpn/peer.c                            | 172 ++++++++---
 drivers/net/ovpn/peer.h                            |   1 +
 drivers/net/ovpn/socket.c                          |   9 +
 drivers/net/phy/mediatek/mtk.h                     |   8 +-
 drivers/net/tap.c                                  |  24 +-
 drivers/net/thunderbolt/main.c                     |  33 +-
 drivers/net/usb/ax88179_178a.c                     |   4 +-
 drivers/net/usb/ipheth.c                           |  11 +-
 drivers/net/veth.c                                 |  22 +-
 drivers/net/vxlan/vxlan_core.c                     |   2 +-
 drivers/nvmem/apple-spmi-nvmem.c                   |  20 +-
 drivers/nvmem/core.c                               |  24 +-
 drivers/nvmem/internals.h                          |   2 +
 drivers/nvmem/layouts.c                            |  11 -
 drivers/nvmem/layouts/Makefile                     |   1 +
 drivers/nvmem/layouts/fixed-layout.c               |  58 ++++
 drivers/pinctrl/qcom/pinctrl-ipq8064.c             |   8 +-
 drivers/pinctrl/qcom/pinctrl-msm.h                 |   5 +
 drivers/ptp/ptp_ocp.c                              |   4 +-
 drivers/s390/net/ism_drv.c                         |  19 +-
 drivers/scsi/scsi_debug.c                          |   4 +-
 drivers/staging/rtl8723bs/core/rtw_ieee80211.c     |   3 +
 drivers/staging/rtl8723bs/core/rtw_mlme_ext.c      |   2 +-
 drivers/staging/rtl8723bs/core/rtw_wlan_util.c     |   3 +
 drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c  |   4 +
 drivers/thermal/thermal_hwmon.c                    |   3 +-
 drivers/thunderbolt/eeprom.c                       |   9 +-
 drivers/thunderbolt/icm.c                          |   2 +-
 drivers/thunderbolt/tb.c                           |   2 +-
 drivers/tty/serial/8250/8250_dma.c                 |  12 +-
 drivers/tty/serial/8250/8250_of.c                  |  38 +++
 drivers/tty/serial/amba-pl011.c                    |  86 ++++--
 drivers/tty/serial/qcom_geni_serial.c              |  43 +--
 drivers/tty/vt/keyboard.c                          |   5 +-
 drivers/tty/vt/vt_ioctl.c                          |   2 +
 drivers/usb/atm/cxacru.c                           |   2 +
 drivers/usb/cdns3/cdnsp-gadget.c                   |   4 +-
 drivers/usb/core/config.c                          |  32 +-
 drivers/usb/core/quirks.c                          |   7 +
 drivers/usb/gadget/function/f_ncm.c                |   2 +-
 drivers/usb/misc/usbio.c                           |   2 +-
 drivers/vdpa/mlx5/core/mr.c                        |   3 +-
 drivers/vhost/scsi.c                               |  17 ++
 drivers/vhost/vdpa.c                               |   9 +-
 drivers/vhost/vhost.c                              |   8 +
 drivers/video/fbdev/core/bitblit.c                 |   9 +-
 drivers/watchdog/at91sam9_wdt.c                    |   4 +-
 drivers/watchdog/bd96801_wdt.c                     |   5 +-
 fs/binfmt_misc.c                                   |   3 +-
 fs/btrfs/inode.c                                   |   1 +
 fs/crypto/policy.c                                 |   2 +-
 fs/namespace.c                                     |   5 +
 fs/nfs/nfs4proc.c                                  |   5 +
 fs/overlayfs/super.c                               |   3 +-
 fs/smb/client/sess.c                               |   2 +-
 fs/tracefs/event_inode.c                           |  28 +-
 fs/tracefs/internal.h                              |   4 +-
 fs/verity/measure.c                                |  15 +-
 fs/xfs/xfs_buf.c                                   |   2 +-
 include/linux/dibs.h                               |   2 +-
 include/linux/mmap_lock.h                          |   1 +
 include/linux/netdevice.h                          |  11 +-
 include/linux/netfilter/ipset/ip_set.h             |   2 +-
 include/linux/nvmem-provider.h                     |   6 +
 include/linux/psi.h                                |   4 +-
 include/linux/sched.h                              |  13 +-
 include/linux/usb/quirks.h                         |   3 +
 include/net/act_api.h                              |  19 ++
 include/net/addrconf.h                             |   4 +-
 include/net/ip_vs.h                                |  41 +--
 include/net/libeth/xsk.h                           |   2 +-
 include/net/netdev_queues.h                        |  47 ++-
 include/net/netdev_rx_queue.h                      |   2 +
 include/net/netfilter/nf_flow_table.h              |   1 +
 include/net/page_pool/types.h                      |   1 +
 include/net/route.h                                |   2 +
 include/net/sch_generic.h                          |   1 +
 include/net/xdp_sock.h                             |  47 +--
 include/net/xdp_sock_drv.h                         |  77 ++++-
 kernel/bpf/verifier.c                              |  68 +++--
 kernel/cgroup/cgroup.c                             |  23 +-
 kernel/events/core.c                               |  67 ++--
 kernel/futex/core.c                                |  85 ++++--
 kernel/sched/fair.c                                | 148 +++++++--
 kernel/sched/psi.c                                 |  75 ++++-
 kernel/trace/ring_buffer.c                         |  13 +-
 kernel/trace/trace_events.c                        |   4 +-
 mm/damon/ops-common.c                              |  13 +-
 mm/damon/paddr.c                                   |   2 +
 mm/damon/vaddr.c                                   |   3 +-
 mm/filemap.c                                       |   6 +
 mm/huge_memory.c                                   |  49 +--
 mm/pagewalk.c                                      |  36 ++-
 mm/ptdump.c                                        |   7 +
 mm/vmalloc.c                                       |  40 ++-
 net/atm/common.c                                   |  14 +-
 net/bridge/br_mrp.c                                |   6 +-
 net/bridge/netfilter/ebt_nflog.c                   |  17 +-
 net/bridge/netfilter/nf_conntrack_bridge.c         |   1 +
 net/core/datagram.c                                |   3 +
 net/core/dev.c                                     |  27 +-
 net/core/netdev_rx_queue.c                         |  21 +-
 net/core/sock.c                                    |   1 -
 net/core/xdp.c                                     |   2 +-
 net/devlink/dev.c                                  |   1 +
 net/ipv4/fib_semantics.c                           | 101 +++---
 net/ipv4/inet_connection_sock.c                    |  20 +-
 net/ipv4/inet_fragment.c                           |  10 +-
 net/ipv4/route.c                                   |  29 ++
 net/ipv4/tcp_bpf.c                                 |   2 +
 net/ipv4/tcp_input.c                               |   2 +-
 net/ipv4/tcp_ipv4.c                                |  43 +--
 net/ipv4/udp_offload.c                             |   4 +-
 net/ipv6/ip6_tunnel.c                              |   3 +
 net/ipv6/route.c                                   |   8 +-
 net/mac802154/scan.c                               |   4 +
 net/ncsi/ncsi-netlink.c                            |   4 +
 net/netfilter/ipset/ip_set_bitmap_gen.h            |   4 +-
 net/netfilter/ipset/ip_set_core.c                  |   6 +-
 net/netfilter/ipset/ip_set_hash_gen.h              |   2 +-
 net/netfilter/ipset/ip_set_list_set.c              |   4 +-
 net/netfilter/ipvs/ip_vs_conn.c                    |  41 +--
 net/netfilter/ipvs/ip_vs_core.c                    |  70 ++---
 net/netfilter/ipvs/ip_vs_ctl.c                     |  77 ++++-
 net/netfilter/ipvs/ip_vs_est.c                     |  10 +-
 net/netfilter/ipvs/ip_vs_lc.c                      |   4 +-
 net/netfilter/ipvs/ip_vs_proto_sctp.c              |   4 +-
 net/netfilter/ipvs/ip_vs_proto_tcp.c               |   2 -
 net/netfilter/ipvs/ip_vs_sync.c                    |   7 +-
 net/netfilter/ipvs/ip_vs_xmit.c                    |   2 +-
 net/netfilter/nf_conntrack_proto.c                 |   6 +
 net/netfilter/nf_conntrack_proto_sctp.c            |  12 +-
 net/netfilter/nf_conntrack_proto_tcp.c             | 132 +++++---
 net/netfilter/nf_flow_table_core.c                 |   1 +
 net/netfilter/nf_flow_table_ip.c                   |  95 ++++--
 net/netfilter/nf_flow_table_path.c                 |   9 +-
 net/netfilter/nf_tables_api.c                      |   4 +-
 net/openvswitch/datapath.c                         |  29 +-
 net/openvswitch/flow.c                             |  11 +-
 net/packet/af_packet.c                             |  72 +++--
 net/sched/act_ct.c                                 |  29 +-
 net/sched/act_gact.c                               |   5 +
 net/sched/act_police.c                             |   6 +
 net/sched/cls_api.c                                |  17 +-
 net/sched/cls_route.c                              |  35 ++-
 net/sched/sch_api.c                                |   9 +
 net/sched/sch_cake.c                               |   1 -
 net/sctp/associola.c                               |  11 +-
 net/sctp/outqueue.c                                |   1 +
 net/sctp/sm_make_chunk.c                           |   3 +-
 net/sctp/sm_statefuns.c                            |   6 +-
 net/smc/af_smc.c                                   |   3 +-
 net/smc/smc_llc.c                                  |   3 +-
 net/smc/smc_rx.c                                   |  19 +-
 net/tipc/node.c                                    |  15 +-
 net/tls/tls_sw.c                                   |  18 +-
 net/vmw_vsock/virtio_transport.c                   |  14 +-
 net/x25/af_x25.c                                   |   4 +-
 net/x25/x25_timer.c                                |  25 +-
 net/xdp/xdp_umem.c                                 |   2 +
 net/xdp/xsk.c                                      |  11 +-
 net/xdp/xsk_buff_pool.c                            |   6 +-
 samples/damon/mtier.c                              |   3 +
 security/integrity/ima/ima_appraise.c              |   9 +-
 security/integrity/ima/ima_main.c                  |  39 +++
 sound/hda/codecs/side-codecs/tas2781_hda_spi.c     |   3 +-
 sound/usb/endpoint.c                               |   6 +-
 sound/usb/fcp.c                                    |  10 +-
 sound/usb/midi2.c                                  |   9 +
 sound/usb/usx2y/us144mkii_capture.c                |   1 +
 sound/usb/usx2y/usX2Yhwdep.c                       |   2 +
 sound/usb/usx2y/usx2yhwdeppcm.c                    |   2 +
 .../selftests/bpf/prog_tests/sockmap_basic.c       |   6 +-
 .../selftests/bpf/prog_tests/sockmap_listen.c      |  21 +-
 tools/testing/selftests/bpf/test_maps.c            |  13 +-
 .../ftrace/test.d/dynevent/add_remove_eprobe.tc    |  16 +-
 tools/testing/selftests/net/tls.c                  |  57 ++++
 tools/testing/selftests/sched_ext/numa.bpf.c       |  13 +-
 281 files changed, 3279 insertions(+), 1604 deletions(-)
author maintainer
#1 lore raw

PATCH 1/250 KVM: s390: pci: Fix resource leak on IRQ registration failure

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

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

From: Farhan Ali <[email protected]>

[ Upstream commit 5580c9858f1e00f60191eb09c3add359836d60b6 ]

Currently if kvm_zpci_set_airq() fails, kvm_s390_pci_aif_enable() returns the error code but doesn't do any resource cleanup thus leaking resources. Fix this by cleaning up all the resources such as the GAITE, AIBV, AISB and unpinning any pinned pages. While at it, remove dead code that stored FIB values that were never referenced.

As part of the cleanup, we are also holding the aift_lock a bit longer, as we hold the lock while executing the MPCIFC instruction. Though this is not strictly necessary, it means we don't have to drop and re-acquire in the error case.

Fixes 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
---
 arch/s390/kvm/pci.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)
arch/s390/kvm/pci.c +21 -8
index 4cc554c9d3283..b729457d30167 100644
@@ -359,19 +359,32 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
 	aift->kzdev[zdev->aisb] = zdev->kzdev;
 	spin_unlock_irq(&aift->gait_lock);
 
-	/* Update guest FIB for re-issue */
-	fib->fmt0.aisbo = zdev->aisb & 63;
-	fib->fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8);
-	fib->fmt0.isc = gisc;
-
 	/* Save some guest fib values in the host for later use */
-	zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
+	zdev->kzdev->fib.fmt0.isc = gisc;
 	zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
-	mutex_unlock(&aift->aift_lock);
 
 	/* Issue the clp to setup the irq now */
 	rc = kvm_zpci_set_airq(zdev);
-	return rc;
+	if (!rc) {
+		mutex_unlock(&aift->aift_lock);
+		return rc;
+	}
+
+	/* Start cleanup */
+	zdev->kzdev->fib.fmt0.isc = 0;
+	zdev->kzdev->fib.fmt0.aibv = 0;
+
+	spin_lock_irq(&aift->gait_lock);
+	gaite->count--;
+	gaite->aisb = 0;
+	gaite->gisc = 0;
+	gaite->aisbo = 0;
+	gaite->gisa = 0;
+	aift->kzdev[zdev->aisb] = NULL;
+	spin_unlock_irq(&aift->gait_lock);
+
+	airq_iv_release(zdev->aibv);
+	zdev->aibv = NULL;
 
 free_aisb:
 	airq_iv_free_bit(aift->sbv, zdev->aisb);
Signature · 1 line
2.53.0
author maintainer
#2 lore raw

PATCH 2/250 mount: honour SB_NOUSER in the new mount API

In reply to Greg Kroah-Hartman

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

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

From: Al Viro <[email protected]>

[ Upstream commit 6dd3c6884cd9defb511284b566cef5ac8f657dbf ]

One should *not* be allowed to mount one of those, new API or not.

[Denis: rename new_mnt -> newmount.mnt]
[Denis: use goto err_unlock instead of direct return]
---
 fs/namespace.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/namespace.c +5 -0
index 5fd8b021785a4..d886ae255e40a 100644
@@ -4352,6 +4352,11 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
 		ret = PTR_ERR(newmount.mnt);
 		goto err_unlock;
 	}
+	if (newmount.mnt->mnt_sb->s_flags & SB_NOUSER) {
+		mntput(newmount.mnt);
+		ret = -EINVAL;
+		goto err_unlock;
+	}
 	newmount.dentry = dget(fc->root);
 	newmount.mnt->mnt_flags = mnt_flags;
 
Signature · 1 line
2.53.0
author maintainer
#3 lore raw

PATCH 3/250 sched/fair: Separate se->vlag from se->vprot

In reply to Greg Kroah-Hartman

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

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

From: Ingo Molnar <[email protected]>

[ Upstream commit 80390ead2080071cbd6f427ff8deb94d10a4a50f ]

There's no real space concerns here and keeping these fields in a union makes reading (and tracing) the scheduler code harder.

---
 include/linux/sched.h | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)
include/linux/sched.h +4 -9
index 5dea369fcfc96..fa02b2254905c 100644
@@ -587,15 +587,10 @@ struct sched_entity {
 	u64				sum_exec_runtime;
 	u64				prev_sum_exec_runtime;
 	u64				vruntime;
-	union {
-		/*
-		 * When !@on_rq this field is vlag.
-		 * When cfs_rq->curr == se (which implies @on_rq)
-		 * this field is vprot. See protect_slice().
-		 */
-		s64                     vlag;
-		u64                     vprot;
-	};
+	/* Approximated virtual lag: */
+	s64				vlag;
+	/* 'Protected' deadline, to give out minimum quantums: */
+	u64				vprot;
 	u64				slice;
 
 	u64				nr_migrations;
Signature · 1 line
2.53.0
author maintainer
#4 lore raw

PATCH 4/250 sched/fair: Revert 6d71a9c61604 ("sched/fair: Fix EEVDF entity placement bug causing scheduling lag")

In reply to Greg Kroah-Hartman

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

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

From: Peter Zijlstra <[email protected]>

[ Upstream commit 101f3498b4bdfef97152a444847948de1543f692 ]

Zicheng Qu reported that, because avg_vruntime() always includes cfs_rq->curr, when ->on_rq, place_entity() doesn't work right.

Specifically, the lag scaling in place_entity() relies on avg_vruntime() being the state *before* placement of the new entity. However in this case avg_vruntime() will actually already include the entity, which breaks things.

Also, Zicheng Qu argues that avg_vruntime should be invariant under reweight. IOW commit 6d71a9c61604 ("sched/fair: Fix EEVDF entity placement bug causing scheduling lag") was wrong!

The issue reported in 6d71a9c61604 could possibly be explained by rounding artifacts -- notably the extreme weight '2' is outside of the range of avg_vruntime/sum_w_vruntime, since that uses scale_load_down(). By scaling vruntime by the real weight, but accounting it in vruntime with a factor 1024 more, the average moves significantly. However, that is now cured.

Tested by reverting 66951e4860d3 ("sched/fair: Fix update_cfs_group() vs DELAY_DEQUEUE") and tracing vruntime and vlag figures again.

(cherry picked from commit 101f3498b4bdfef97152a444847948de1543f692)
[jstultz: Resolved minor collision in the revert against 6.18-stable]
---
 kernel/sched/fair.c | 148 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 124 insertions(+), 24 deletions(-)
kernel/sched/fair.c +124 -24
index ac5f08cd01a83..aed035aaece1d 100644
@@ -764,17 +764,22 @@ static inline u64 cfs_rq_max_slice(struct cfs_rq *cfs_rq);
  *
  *   -r_max < lag < max(r_max, q)
  */
-static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static s64 entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 avruntime)
 {
 	u64 max_slice = cfs_rq_max_slice(cfs_rq) + TICK_NSEC;
 	s64 vlag, limit;
 
-	WARN_ON_ONCE(!se->on_rq);
-
-	vlag = avg_vruntime(cfs_rq) - se->vruntime;
+	vlag = avruntime - se->vruntime;
 	limit = calc_delta_fair(max_slice, se);
 
-	se->vlag = clamp(vlag, -limit, limit);
+	return clamp(vlag, -limit, limit);
+}
+
+static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	WARN_ON_ONCE(!se->on_rq);
+
+	se->vlag = entity_lag(cfs_rq, se, avg_vruntime(cfs_rq));
 }
 
 /*
@@ -3838,23 +3843,125 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 					  cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
 }
 
-static void place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags);
+static void
+rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
+{
+	unsigned long old_weight = se->load.weight;
+
+	/*
+	 * VRUNTIME
+	 * --------
+	 *
+	 * COROLLARY #1: The virtual runtime of the entity needs to be
+	 * adjusted if re-weight at !0-lag point.
+	 *
+	 * Proof: For contradiction assume this is not true, so we can
+	 * re-weight without changing vruntime at !0-lag point.
+	 *
+	 *             Weight	VRuntime   Avg-VRuntime
+	 *     before    w          v            V
+	 *      after    w'         v'           V'
+	 *
+	 * Since lag needs to be preserved through re-weight:
+	 *
+	 *	lag = (V - v)*w = (V'- v')*w', where v = v'
+	 *	==>	V' = (V - v)*w/w' + v		(1)
+	 *
+	 * Let W be the total weight of the entities before reweight,
+	 * since V' is the new weighted average of entities:
+	 *
+	 *	V' = (WV + w'v - wv) / (W + w' - w)	(2)
+	 *
+	 * by using (1) & (2) we obtain:
+	 *
+	 *	(WV + w'v - wv) / (W + w' - w) = (V - v)*w/w' + v
+	 *	==> (WV-Wv+Wv+w'v-wv)/(W+w'-w) = (V - v)*w/w' + v
+	 *	==> (WV - Wv)/(W + w' - w) + v = (V - v)*w/w' + v
+	 *	==>	(V - v)*W/(W + w' - w) = (V - v)*w/w' (3)
+	 *
+	 * Since we are doing at !0-lag point which means V != v, we
+	 * can simplify (3):
+	 *
+	 *	==>	W / (W + w' - w) = w / w'
+	 *	==>	Ww' = Ww + ww' - ww
+	 *	==>	W * (w' - w) = w * (w' - w)
+	 *	==>	W = w	(re-weight indicates w' != w)
+	 *
+	 * So the cfs_rq contains only one entity, hence vruntime of
+	 * the entity @v should always equal to the cfs_rq's weighted
+	 * average vruntime @V, which means we will always re-weight
+	 * at 0-lag point, thus breach assumption. Proof completed.
+	 *
+	 *
+	 * COROLLARY #2: Re-weight does NOT affect weighted average
+	 * vruntime of all the entities.
+	 *
+	 * Proof: According to corollary #1, Eq. (1) should be:
+	 *
+	 *	(V - v)*w = (V' - v')*w'
+	 *	==>    v' = V' - (V - v)*w/w'		(4)
+	 *
+	 * According to the weighted average formula, we have:
+	 *
+	 *	V' = (WV - wv + w'v') / (W - w + w')
+	 *	   = (WV - wv + w'(V' - (V - v)w/w')) / (W - w + w')
+	 *	   = (WV - wv + w'V' - Vw + wv) / (W - w + w')
+	 *	   = (WV + w'V' - Vw) / (W - w + w')
+	 *
+	 *	==>  V'*(W - w + w') = WV + w'V' - Vw
+	 *	==>	V' * (W - w) = (W - w) * V	(5)
+	 *
+	 * If the entity is the only one in the cfs_rq, then reweight
+	 * always occurs at 0-lag point, so V won't change. Or else
+	 * there are other entities, hence W != w, then Eq. (5) turns
+	 * into V' = V. So V won't change in either case, proof done.
+	 *
+	 *
+	 * So according to corollary #1 & #2, the effect of re-weight
+	 * on vruntime should be:
+	 *
+	 *	v' = V' - (V - v) * w / w'		(4)
+	 *	   = V  - (V - v) * w / w'
+	 *	   = V  - vl * w / w'
+	 *	   = V  - vl'
+	 */
+	se->vlag = div64_long(se->vlag * old_weight, weight);
+
+	/*
+	 * DEADLINE
+	 * --------
+	 *
+	 * When the weight changes, the virtual time slope changes and
+	 * we should adjust the relative virtual deadline accordingly.
+	 *
+	 *	d' = v' + (d - v)*w/w'
+	 *	   = V' - (V - v)*w/w' + (d - v)*w/w'
+	 *	   = V  - (V - v)*w/w' + (d - v)*w/w'
+	 *	   = V  + (d - V)*w/w'
+	 */
+	if (se->rel_deadline)
+		se->deadline = div64_long(se->deadline * old_weight, weight);
+
+	if (rel_vprot)
+		se->vprot = div64_long(se->vprot * old_weight, weight);
+}
 
 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 			    unsigned long weight)
 {
 	bool curr = cfs_rq->curr == se;
 	bool rel_vprot = false;
-	u64 vprot;
+	u64 avruntime = 0;
 
 	if (se->on_rq) {
 		/* commit outstanding execution time */
 		update_curr(cfs_rq);
-		update_entity_lag(cfs_rq, se);
-		se->deadline -= se->vruntime;
+		avruntime = avg_vruntime(cfs_rq);
+		se->vlag = entity_lag(cfs_rq, se, avruntime);
+		se->deadline -= avruntime;
 		se->rel_deadline = 1;
 		if (curr && protect_slice(se)) {
-			vprot = se->vprot - se->vruntime;
+			se->vprot -= avruntime;
 			rel_vprot = true;
 		}
 
@@ -3865,30 +3972,23 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 	}
 	dequeue_load_avg(cfs_rq, se);
 
-	/*
-	 * Because we keep se->vlag = V - v_i, while: lag_i = w_i*(V - v_i),
-	 * we need to scale se->vlag when w_i changes.
-	 */
-	se->vlag = div_s64(se->vlag * se->load.weight, weight);
-	if (se->rel_deadline)
-		se->deadline = div_s64(se->deadline * se->load.weight, weight);
-
-	if (rel_vprot)
-		vprot = div_s64(vprot * se->load.weight, weight);
+	rescale_entity(se, weight, rel_vprot);
 
 	update_load_set(&se->load, weight);
 
 	do {
 		u32 divider = get_pelt_divider(&se->avg);
-
 		se->avg.load_avg = div_u64(se_weight(se) * se->avg.load_sum, divider);
 	} while (0);
 
 	enqueue_load_avg(cfs_rq, se);
 	if (se->on_rq) {
-		place_entity(cfs_rq, se, 0);
 		if (rel_vprot)
-			se->vprot = se->vruntime + vprot;
+			se->vprot += avruntime;
+		se->deadline += avruntime;
+		se->rel_deadline = 0;
+		se->vruntime = avruntime - se->vlag;
+
 		update_load_add(&cfs_rq->load, se->load.weight);
 		if (!curr)
 			__enqueue_entity(cfs_rq, se);
@@ -5288,7 +5388,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 
 	se->vruntime = vruntime - lag;
 
-	if (se->rel_deadline) {
+	if (sched_feat(PLACE_REL_DEADLINE) && se->rel_deadline) {
 		se->deadline += se->vruntime;
 		se->rel_deadline = 0;
 		return;
Signature · 1 line
2.53.0
author maintainer
#5 lore raw

PATCH 5/250 selftests/bpf: Fail unbound UDP on sockmap update

In reply to Greg Kroah-Hartman

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

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

From: Michal Luczaj <[email protected]>

[ Upstream commit 203b06932777b9ad5085319389dea566f5c2ca63 ]

sockmap now rejects unbound UDP sockets. Adjust test_maps. While at it, check socket()'s return value.

This effectively reverts commit c39aa2159974 ("bpf, selftests: Fix test_maps now that sockmap supports UDP").

---
 tools/testing/selftests/bpf/test_maps.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
tools/testing/selftests/bpf/test_maps.c +6 -7
index 3fae9ce46ca9b..cea33b94d06f8 100644
@@ -748,16 +748,15 @@ static void test_sockmap(unsigned int tasks, void *data)
 		goto out_sockmap;
 	}
 
-	/* Test update with unsupported UDP socket */
+	/* Test update with unsupported unbound UDP socket */
 	udp = socket(AF_INET, SOCK_DGRAM, 0);
-	i = 0;
-	err = bpf_map_update_elem(fd, &i, &udp, BPF_ANY);
-	if (err) {
-		printf("Failed socket update SOCK_DGRAM '%i:%i'\n",
-		       i, udp);
+	CHECK(udp < 0, "socket(AF_INET, SOCK_DGRAM)", "errno:%d\n", errno);
+	err = bpf_map_update_elem(fd, &(int){0}, &udp, BPF_ANY);
+	close(udp);
+	if (!err) {
+		printf("Unexpectedly succeeded unbound UDP update '0:%i'\n", udp);
 		goto out_sockmap;
 	}
-	close(udp);
 
 	/* Test update without programs */
 	for (i = 0; i < 6; i++) {
Signature · 1 line
2.53.0
author maintainer
#6 lore raw

PATCH 6/250 drm/amd/display: Add AV mute wait frames to dce110_set_avmute

In reply to Greg Kroah-Hartman

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

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

From: Ray Wu <[email protected]>

[ Upstream commit 443290d70b01e9c35830c300e3247c06581b594c ]

Port the three-frame wait logic from dcn30_set_avmute to dce110_set_avmute so that older DCN versions (1.0, 2.0) also wait for GCP packets to be sent out before proceeding.

This ensures HDMI sinks properly process the mute state, preventing garbled display after link re-establishment.

---
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 21 ++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +20 -1
index 8f86177de48dc..13ae93b945a33 100644
@@ -1266,8 +1266,27 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
 
 void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
 {
-	if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL)
+	if (pipe_ctx == NULL || pipe_ctx->stream_res.stream_enc == NULL)
+		return;
+
+	if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
 		pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable);
+
+		/* Wait for three frames to make sure AV mute is sent out.
+		 * Some HDMI sinks need additional GCP packets to properly
+		 * process the mute state, especially after link re-establishment
+		 * with HDMI 2.0 scrambling enabled.
+		 */
+		if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
+			int i;
+
+			pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+			for (i = 0; i < 3; i++) {
+				pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+				pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+			}
+		}
+	}
 }
 
 enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 7/250 drm/amd/display: Check for tg ops in dce110_set_avmute

In reply to Greg Kroah-Hartman

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

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

From: Ray Wu <[email protected]>

[ Upstream commit 3141e3d61469bba2624a91c5e2407f110b33b29e ]

Some older DCE timing generators do not implement is_tg_enabled in their ops table. Calling it unconditionally when waiting for AV mute frames causes a NULL pointer dereference on Southern Islands dGPUs when turning the display off over HDMI.

Check that tg and the required ops exist before waiting for frames.

Fixes 414da24137ac ("drm/amd/display: Add AV mute wait frames to dce110_set_avmute")
(cherry picked from commit 2686a0c0aaa07bec2e24131835cf27b5fd4935a5)
---
 drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +4 -1
index 13ae93b945a33..fe02dc4e97e4a 100644
@@ -1277,7 +1277,10 @@ void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
 		 * process the mute state, especially after link re-establishment
 		 * with HDMI 2.0 scrambling enabled.
 		 */
-		if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
+		if (enable && pipe_ctx->stream_res.tg &&
+		    pipe_ctx->stream_res.tg->funcs->is_tg_enabled &&
+		    pipe_ctx->stream_res.tg->funcs->wait_for_state &&
+		    pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
 			int i;
 
 			pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
Signature · 1 line
2.53.0
author maintainer
#8 lore raw

PATCH 8/250 arm64: dts: qcom: rename x1e80100 to hamoa

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Baryshkov <[email protected]>

[ Upstream commit 8c0b058ab5983a4be6690a76be9b0294853e8e55 ]

The X1E80100 and several other similar names (X1E78100, X1E001DE) all belong to the platform now known as 'hamoa'. Follow the example of 'lemans' and rename the x1e80100.dtsi to hamoa.dtsi and x1e80100-pmics.dtsi to hamoa-pmics.dtsi.

Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")

---
 arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi                   | 4 ++--
 .../boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi}   | 0
 arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi}        | 0
 arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi             | 2 +-
 arch/arm64/boot/dts/qcom/x1-crd.dtsi                          | 2 +-
 arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi                   | 2 +-
 arch/arm64/boot/dts/qcom/x1e001de-devkit.dts                  | 4 ++--
 arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi   | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts       | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts        | 2 +-
 arch/arm64/boot/dts/qcom/x1e80100-crd.dts                     | 2 +-
 .../boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts     | 2 +-
 arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts      | 2 +-
 arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts         | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts         | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts      | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi      | 4 ++--
 arch/arm64/boot/dts/qcom/x1e80100-qcp.dts                     | 4 ++--
 arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts         | 2 +-
 arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts     | 2 +-
 arch/arm64/boot/dts/qcom/x1p42100.dtsi                        | 4 ++--
 21 files changed, 29 insertions(+), 29 deletions(-)
 rename arch/arm64/boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} (100%)
 rename arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi} (100%)
arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi +2 -2
index 1aead50b8920b..4de7c0abb25a1 100644
@@ -3,8 +3,8 @@
  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi renamed from arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi +0 -0
similarity index 100%
rename from arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi
rename to arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi
arch/arm64/boot/dts/qcom/hamoa.dtsi renamed from arch/arm64/boot/dts/qcom/x1e80100.dtsi +0 -0
similarity index 100%
rename from arch/arm64/boot/dts/qcom/x1e80100.dtsi
rename to arch/arm64/boot/dts/qcom/hamoa.dtsi
arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi +1 -1
index ee3c8c5e2c50c..69eccad1a09c2 100644
@@ -11,7 +11,7 @@
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100-pmics.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "ASUS Zenbook A14";
arch/arm64/boot/dts/qcom/x1-crd.dtsi +1 -1
index 3c9455fede5c0..5e324f35547a4 100644
@@ -9,7 +9,7 @@
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100-pmics.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. X1E80100 CRD";
arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +1 -1
index 5b5a10a31a253..aee3fafbe7fcc 100644
@@ -12,7 +12,7 @@
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100-pmics.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	chassis-type = "laptop";
arch/arm64/boot/dts/qcom/x1e001de-devkit.dts +2 -2
index bfc649d4b643c..701f35af7d5cd 100644
@@ -8,8 +8,8 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. X1E001DE Snapdragon Devkit for Windows";
arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +2 -2
index 654cbce9d6ecb..169726984d3b0 100644
@@ -12,8 +12,8 @@
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Lenovo ThinkPad T14s Gen 6";
arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts +2 -2
index 0113d856b3ad4..f2960953e608f 100644
@@ -11,8 +11,8 @@
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "ASUS Vivobook S 15";
arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts +1 -1
index 0d0bcc50207d7..c3cd04c9703d3 100644
@@ -6,7 +6,7 @@
 
 /dts-v1/;
 
-#include "x1e80100.dtsi"
+#include "hamoa.dtsi"
 #include "x1-asus-zenbook-a14.dtsi"
 
 / {
arch/arm64/boot/dts/qcom/x1e80100-crd.dts +1 -1
index dfc378e1a056a..429deffcf3e9d 100644
@@ -5,7 +5,7 @@
 
 /dts-v1/;
 
-#include "x1e80100.dtsi"
+#include "hamoa.dtsi"
 #include "x1-crd.dtsi"
 
 / {
arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts +1 -1
index cf2a7c2628881..75e10d97c3867 100644
@@ -4,7 +4,7 @@
  */
 /dts-v1/;
 
-#include "x1e80100.dtsi"
+#include "hamoa.dtsi"
 #include "x1-dell-thena.dtsi"
 
 / {
arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts +1 -1
index 32ad9679550ef..a8ff7ef258a13 100644
@@ -4,7 +4,7 @@
  */
 /dts-v1/;
 
-#include "x1e80100.dtsi"
+#include "hamoa.dtsi"
 #include "x1-dell-thena.dtsi"
 
 / {
arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts +2 -2
index 58f8caaa72580..c1f49cba61fc4 100644
@@ -12,8 +12,8 @@
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Dell XPS 13 9345";
arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts +2 -2
index e5a839d458402..b79e59e1c413a 100644
@@ -6,8 +6,8 @@
 
 /dts-v1/;
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 #include "x1-hp-omnibook-x14.dtsi"
 
 / {
arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts +2 -2
index e0642fe8343f6..56e4d13cca111 100644
@@ -9,8 +9,8 @@
 #include <dt-bindings/input/gpio-keys.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Lenovo Yoga Slim 7x";
arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi +2 -2
index ed468b93ba50e..3b319f65dde1e 100644
@@ -9,8 +9,8 @@
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	aliases {
arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +2 -2
index 4a9b6d791e7f4..5a121fc449401 100644
@@ -8,8 +8,8 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1e80100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. X1E80100 QCP";
arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts +1 -1
index 6696cab2de3ec..47ab0c5b30341 100644
@@ -3,7 +3,7 @@
 /dts-v1/;
 
 #include "x1p42100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa-pmics.dtsi"
 #include "x1-hp-omnibook-x14.dtsi"
 /delete-node/ &pmc8380_6;
 /delete-node/ &pmc8380_6_thermal;
arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts +1 -1
index 1ac46cdc43861..f7d372d2e9612 100644
@@ -14,7 +14,7 @@
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
 #include "x1p42100.dtsi"
-#include "x1e80100-pmics.dtsi"
+#include "hamoa-pmics.dtsi"
 
 /delete-node/ &pmc8380_6;
 /delete-node/ &pmc8380_6_thermal;
arch/arm64/boot/dts/qcom/x1p42100.dtsi +2 -2
index 10d26958d3c66..2cecd2dd0de8c 100644
@@ -3,8 +3,8 @@
  * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
-/* X1P42100 is heavily based on X1E80100, with some meaningful differences */
-#include "x1e80100.dtsi"
+/* X1P42100 is heavily based on hamoa, with some meaningful differences */
+#include "hamoa.dtsi"
 
 /delete-node/ &bwmon_cluster0;
 /delete-node/ &cluster_pd2;
Signature · 1 line
2.53.0
author maintainer
#9 lore raw

PATCH 9/250 arm64: dts: qcom: Rework X1-based Asus Zenbook A14s displays

In reply to Greg Kroah-Hartman

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

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

From: Aleksandrs Vinarskis <[email protected]>

[ Upstream commit 462b39931cab3415ffc47863a58372399e600f4f ]

The laptop comes in two variants:

* UX3407RA, higher end, FHD+ OLED or WOXGA+ OLED panels
* UX3407QA, lower end, FHD+ OLED or FHD+ LCD panels

Even though all three panels work with "edp-panel", unfortunately the brightness adjustmenet of LCD panel is PWM based, requiring a dedicated device-tree. Convert "x1p42100-asus-zenbook-a14.dts" into ".dtsi" to allow for this split, introduce new LCD variant. Leave current variant without postfix and with the unchanged model name, as some distros (eg. Ubuntu) rely on this for automatic device-tree detection during kernel installation/upgrade.

As dedicated device-tree is required, update compatibles of OLED variants to correct ones. Keep "edp-panel" as fallback, since it is enough to make the panels work.

While at it moving .dts, .dtsi around, drop 'model' from the top level x1-asus-zenbook-a14.dtsi as well.

Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")

---
 arch/arm64/boot/dts/qcom/Makefile             |   2 +
 .../boot/dts/qcom/x1-asus-zenbook-a14.dtsi    |   7 +-
 .../dts/qcom/x1e80100-asus-zenbook-a14.dts    |   8 +
 .../qcom/x1p42100-asus-zenbook-a14-lcd.dts    |  62 ++++++++
 .../dts/qcom/x1p42100-asus-zenbook-a14.dts    | 133 +----------------
 .../dts/qcom/x1p42100-asus-zenbook-a14.dtsi   | 138 ++++++++++++++++++
 6 files changed, 218 insertions(+), 132 deletions(-)
 create mode 100644 arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts
 create mode 100644 arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
arch/arm64/boot/dts/qcom/Makefile +2 -0
index 296688f7cb265..dffdb219f33dc 100644
@@ -344,6 +344,8 @@ x1e80100-qcp-el2-dtbs	:= x1e80100-qcp.dtb x1-el2.dtbo
 dtb-$(CONFIG_ARCH_QCOM)	+= x1e80100-qcp.dtb x1e80100-qcp-el2.dtb
 x1p42100-asus-zenbook-a14-el2-dtbs	:= x1p42100-asus-zenbook-a14.dtb x1-el2.dtbo
 dtb-$(CONFIG_ARCH_QCOM)	+= x1p42100-asus-zenbook-a14.dtb x1p42100-asus-zenbook-a14-el2.dtb
+x1p42100-asus-zenbook-a14-lcd-el2-dtbs	:= x1p42100-asus-zenbook-a14-lcd.dtb x1-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM)	+= x1p42100-asus-zenbook-a14-lcd.dtb x1p42100-asus-zenbook-a14-lcd-el2.dtb
 x1p42100-crd-el2-dtbs	:= x1p42100-crd.dtb x1-el2.dtbo
 dtb-$(CONFIG_ARCH_QCOM)	+= x1p42100-crd.dtb x1p42100-crd-el2.dtb
 x1p42100-hp-omnibook-x14-el2-dtbs := x1p42100-hp-omnibook-x14.dtb x1-el2.dtbo
arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi +1 -6
index 69eccad1a09c2..8e5c5575a5320 100644
@@ -14,7 +14,6 @@
 #include "hamoa-pmics.dtsi"
 
 / {
-	model = "ASUS Zenbook A14";
 	chassis-type = "laptop";
 
 	aliases {
@@ -1005,14 +1004,10 @@ &mdss_dp3 {
 	status = "okay";
 
 	aux-bus {
-		panel {
+		panel: panel {
 			compatible = "edp-panel";
-			enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
 			power-supply = <&vreg_edp_3p3>;
 
-			pinctrl-0 = <&edp_bl_en>;
-			pinctrl-names = "default";
-
 			port {
 				edp_panel_in: endpoint {
 					remote-endpoint = <&mdss_dp3_out>;
arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts +8 -0
index c3cd04c9703d3..49b12a0a7cb1e 100644
@@ -22,6 +22,14 @@ &gpu_zap_shader {
 	firmware-name = "qcom/x1e80100/ASUSTeK/zenbook-a14/qcdxkmsuc8380.mbn";
 };
 
+&panel {
+	compatible = "samsung,atna40cu11", "samsung,atna33xc20";
+	enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
+
+	pinctrl-0 = <&edp_bl_en>;
+	pinctrl-names = "default";
+};
+
 &remoteproc_adsp {
 	firmware-name = "qcom/x1e80100/ASUSTeK/zenbook-a14/qcadsp8380.mbn",
 			"qcom/x1e80100/ASUSTeK/zenbook-a14/adsp_dtbs.elf";
arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts new file +62 -0

62 lines not on this page · raw message

arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dts +7 -126

143 lines not on this page · raw message

arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi new file +138 -0

138 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#10 lore raw

PATCH 10/250 arm64: dts: qcom: rename x1p42100 to purwa

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Baryshkov <[email protected]>

[ Upstream commit ef659a5bd91bed7fae2c2a150f8ecca06599ac03 ]

Follow the example of other platforms and rename X1P42100 to purwa.dtsi.

Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")

---
 arch/arm64/boot/dts/qcom/{x1p42100.dtsi => purwa.dtsi}    | 0
 arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi   | 2 +-
 arch/arm64/boot/dts/qcom/x1p42100-crd.dts                 | 2 +-
 arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts     | 2 +-
 arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 2 +-
 5 files changed, 4 insertions(+), 4 deletions(-)
 rename arch/arm64/boot/dts/qcom/{x1p42100.dtsi => purwa.dtsi} (100%)
arch/arm64/boot/dts/qcom/purwa.dtsi renamed from arch/arm64/boot/dts/qcom/x1p42100.dtsi +0 -0
similarity index 100%
rename from arch/arm64/boot/dts/qcom/x1p42100.dtsi
rename to arch/arm64/boot/dts/qcom/purwa.dtsi
arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi +1 -1
index 7ccb2076bab66..22470a97e1e39 100644
@@ -6,7 +6,7 @@
 
 /dts-v1/;
 
-#include "x1p42100.dtsi"
+#include "purwa.dtsi"
 #include "x1-asus-zenbook-a14.dtsi"
 
 /delete-node/ &pmc8380_6;
arch/arm64/boot/dts/qcom/x1p42100-crd.dts +1 -1
index cf999c2cf8d4e..7ed4116b95904 100644
@@ -5,7 +5,7 @@
 
 /dts-v1/;
 
-#include "x1p42100.dtsi"
+#include "purwa.dtsi"
 #include "x1-crd.dtsi"
 
 /delete-node/ &pmc8380_6;
arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts +1 -1
index 47ab0c5b30341..0f338e457abda 100644
@@ -2,7 +2,7 @@
 
 /dts-v1/;
 
-#include "x1p42100.dtsi"
+#include "purwa.dtsi"
 #include "hamoa-pmics.dtsi"
 #include "x1-hp-omnibook-x14.dtsi"
 /delete-node/ &pmc8380_6;
arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts +1 -1
index f7d372d2e9612..3186e79e862de 100644
@@ -13,7 +13,7 @@
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
-#include "x1p42100.dtsi"
+#include "purwa.dtsi"
 #include "hamoa-pmics.dtsi"
 
 /delete-node/ &pmc8380_6;
Signature · 1 line
2.53.0
author maintainer
#11 lore raw

PATCH 11/250 arm64: dts: qcom: purwa: Fix GPU IOMMU property

In reply to Greg Kroah-Hartman

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

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

From: Akhil P Oommen <[email protected]>

[ Upstream commit 4cd774c1feb3f720265c512174c5c3312eca1be2 ]

Purwa's GPU does not support SID 1, which is typically used for LPAC-related traffic. Remove SID 1 from the GPU node's iommus property to accurately describe the hardware. This fixes the splat below, seen with some versions of Gunyah hypervisor:

  Internal error: synchronous external abort: 0000000096000010 [#1]  SMP
  CPU: 0 UID: 0 PID: 80 Comm: kworker/u33:2 Tainted: G   M
  Tainted: [M]=MACHINE_CHECK
  Hardware name: Qualcomm Technologies, Inc. Purwa IoT EVK (DT)
  Workqueue: events_unbound deferred_probe_work_func
  pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
  pc : arm_smmu_write_s2cr+0x9c/0xbc
  lr : arm_smmu_master_install_s2crs+0x78/0xa4
  sp : ffff80008039b570
  x29: ffff80008039b570 x28: 0000000000000000 x27: ffffaddd62f1ab78
  x26: ffff00080a4ff280 x25: 0000000000000018 x24: ffff00080b896480
  x23: ffff00080ba9b7a0 x22: ffff00080bb05160 x21: 0000000000000000
  x20: 0000000000000000 x19: 0000000000000001 x18: 00000000ffffffff
  x17: 0000000000000000 x16: 0000000000000000 x15: ffff80008039b1d0
  x14: ffff80010039b37d x13: 00746c7561662d74 x12: 0000000000000000
  x11: ffff00080b7fbd98 x10: ffffffffffffffc0 x9 : ffffffffffffffff
  x8 : 0000000000000228 x7 : 0000000000000e87 x6 : 0000000000000000
  x5 : 0000000000000000 x4 : ffff00080a4ff280 x3 : 0000000000000000
  x2 : ffff800082a40c04 x1 : 0000000000000000 x0 : ffff800082a40000
  Call trace:
   arm_smmu_write_s2cr+0x9c/0xbc (P)
   arm_smmu_master_install_s2crs+0x78/0xa4
   arm_smmu_attach_dev+0xb0/0x1d8
   __iommu_device_set_domain+0x84/0x11c
   __iommu_group_set_domain_internal+0x60/0x120
   __iommu_attach_group+0x88/0x9c
   iommu_attach_device+0x6c/0xa0
   msm_iommu_new.part.0+0x84/0xe4 [msm]
   msm_iommu_gpu_new+0x3c/0x104 [msm]
   adreno_iommu_create_vm+0x24/0xc8 [msm]
   a6xx_create_vm+0x48/0x78 [msm]
   msm_gpu_init+0x2d8/0x508 [msm]
   adreno_gpu_init+0x208/0x324 [msm]
   a6xx_gpu_init+0x604/0x8cc [msm]
   adreno_bind+0xb4/0x124 [msm]
   component_bind_all+0x114/0x23c
   msm_drm_init+0x1b0/0x1ec [msm]
   msm_drm_bind+0x30/0x3c [msm]
   try_to_bring_up_aggregate_device+0x164/0x1d0
   __component_add+0xa4/0x16c
   component_add+0x14/0x20
   msm_dp_display_probe_tail+0x4c/0xac [msm]
   msm_dp_auxbus_done_probe+0x14/0x20 [msm]
   dp_aux_ep_probe+0x4c/0xf4 [drm_dp_aux_bus]
   really_probe+0xbc/0x29c
   __driver_probe_device+0x78/0x12c
   driver_probe_device+0x3c/0x15c
   __device_attach_driver+0xb8/0x134
   bus_for_each_drv+0x88/0xe8
   __device_attach+0xa0/0x190
   device_initial_probe+0x50/0x54
   bus_probe_device+0x38/0xa4
   deferred_probe_work_func+0x88/0xc0
   process_one_work+0x148/0x28c
   worker_thread+0x2cc/0x3d4
   kthread+0x12c/0x204
   ret_from_fork+0x10/0x20
  ---[ end trace 0000000000000000 ]---
---
 arch/arm64/boot/dts/qcom/purwa.dtsi | 2 ++
 1 file changed, 2 insertions(+)
arch/arm64/boot/dts/qcom/purwa.dtsi +2 -0
index 2cecd2dd0de8c..a02b39f98f0b2 100644
@@ -33,6 +33,8 @@ &gmu {
 &gpu {
 	compatible = "qcom,adreno-43030c00", "qcom,adreno";
 
+	iommus = <&adreno_smmu 0 0x0>;
+
 	nvmem-cells = <&gpu_speed_bin>;
 	nvmem-cell-names = "speed_bin";
 
Signature · 1 line
2.53.0
author maintainer
#12 lore raw

PATCH 12/250 arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Baryshkov <[email protected]>

[ Upstream commit 07db10de262f4150e24fd631a7a6c428f7bf80c9 ]

With the default PSCI suspend value for cluster idle state Lenovo Yoga C630 isn't stable enough. For example it might reset if display device isn't probed early enough. Drop the bit 0x4000 from the PSCI suspend value to make C630 work in stable way. The bit was found by expertimenting with the cluster idle PSCI value. Most likely it results in the less deep sleep and more energy beign spent in the suspend state, but it's better than the non-stable system behaviour.

Fixes a1ade6cac5a2 ("arm64: dts: qcom: sdm845: Switch PSCI cpu idle states from PC to OSI")
---
 arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 4 ++++
 1 file changed, 4 insertions(+)
arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +4 -0
index 90efbb7e3799b..bead957cf83b4 100644
@@ -347,6 +347,10 @@ &cdsp_pas {
 	status = "okay";
 };
 
+&cluster_sleep_0 {
+	arm,psci-suspend-param = <0x41008244>;
+};
+
 &gcc {
 	protected-clocks = <GCC_QSPI_CORE_CLK>,
 			   <GCC_QSPI_CORE_CLK_SRC>,
Signature · 1 line
2.53.0
author maintainer
#13 lore raw

PATCH 13/250 NFS: Pin the struct nfs_server during a FREE_STATEID call

In reply to Greg Kroah-Hartman

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

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

From: Anna Schumaker <[email protected]>

[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]

Dan Aloni reports that he was able to hit a use-after-free bug if a FREE_STATEID operation gets delayed for whatever reason. Fix this by bumping the refcount of the 'struct nfs_server' object for the duration of the FREE_STATEID so it doesn't get cleaned up from underneath us while operations are still in flight.

Fixes 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
---
 fs/nfs/nfs4proc.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/nfs/nfs4proc.c +5 -0
index 403f7f8dfea2b..66b8da741a06f 100644
@@ -10634,6 +10634,7 @@ static void nfs41_free_stateid_release(void *calldata)
 	struct nfs_free_stateid_data *data = calldata;
 	struct nfs_client *clp = data->server->nfs_client;
 
+	nfs_sb_deactive(data->server->super);
 	nfs_put_client(clp);
 	kfree(calldata);
 }
@@ -10675,6 +10676,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
 
 	if (!refcount_inc_not_zero(&clp->cl_count))
 		return -EIO;
+	if (!nfs_sb_active(server->super)) {
+		nfs_put_client(clp);
+		return -EIO;
+	}
 
 	nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
 		&task_setup.rpc_client, &msg);
Signature · 1 line
2.53.0
author maintainer
#14 lore raw

PATCH 14/250 arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual timer

In reply to Greg Kroah-Hartman

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

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

From: Daniel Drake <[email protected]>

[ Upstream commit 75952cfc7752c52a2b692b59d34ce160d3edabb2 ]

Commit d87773de9efe1 ("clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE") causes boot to hang on Raspberry Pi 5. The newly-selected EL2 virtual timer does not generate any interrupts, even though the GIC_DIST_ENABLE_SET flag has been confirmed set via readback.

It is highly unusual that this timer interrupt is non-operational because this is a standard GIC interrupt corresponding to a standard Cortex-A76 CPU timer. However, Broadcom have confirmed for this SoC:

Quoted 2 lines

the interrupt line was never connected in the first place as this was not identified as being a requirement

Remove the corresponding DeviceTree entry.

---
 arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 --
 1 file changed, 2 deletions(-)
arch/arm64/boot/dts/broadcom/bcm2712.dtsi +0 -2
index d771694787b28..45a382f75b5ec 100644
@@ -651,8 +651,6 @@ IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
 					  IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-					  IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(4) |
 					  IRQ_TYPE_LEVEL_LOW)>;
 	};
 
Signature · 1 line
2.53.0
author maintainer
#15 lore raw

PATCH 15/250 xfs: handle NULL b_addr in xfs_buf_free

In reply to Greg Kroah-Hartman

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

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

From: Yun Zhou <[email protected]>

[ Upstream commit d852729c5f4f830fbe7413df032e29459b3daf83 ]

When xfs_buf_alloc_backing_mem() fails, xfs_buf_free() is called with bp->b_addr still NULL. The code falls through to the folio_put path which calls virt_to_folio(NULL), dereferencing an invalid address and causing a kernel crash.

 Call Trace:
  xfs_buf_free+0x25f/0x510
  xfs_buf_alloc+0xc98/0x19b0
  xfs_buf_find_insert+0x55/0x14d0
  xfs_buf_get_map+0x122b/0x17c0
  xfbtree_init_leaf_block+0x11c/0x4a0
  xfbtree_init+0x1bb/0x460
  xrep_rmap_setup_scan+0x100/0x1f0
  xrep_rmapbt+0x41/0xc0

Fix this by skipping folio_put() when bp->b_addr is NULL.

---
 fs/xfs/xfs_buf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_buf.c +1 -1
index 1ca95ef46a73d..441631c736c1c 100644
@@ -117,7 +117,7 @@ xfs_buf_free(
 		vfree(bp->b_addr);
 	else if (bp->b_flags & _XBF_KMEM)
 		kfree(bp->b_addr);
-	else
+	else if (bp->b_addr)
 		folio_put(virt_to_folio(bp->b_addr));
 
 	call_rcu(&bp->b_rcu, xfs_buf_free_callback);
Signature · 1 line
2.53.0
author maintainer
#16 lore raw

PATCH 16/250 ARM: npcm: Fix OF node refcount leaks in SMP setup

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]

npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up the GCR and SCU nodes with of_find_compatible_node(). The returned nodes are used for of_iomap(), but the node references are never released.

of_iomap() does not consume the device node reference, and iounmap() only releases the MMIO mapping. Drop each node reference after the corresponding mapping attempt.

Fixes 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
---
 arch/arm/mach-npcm/platsmp.c | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/mach-npcm/platsmp.c +2 -0
index 41891d3aa1247..4c1fc9983746c 100644
@@ -32,6 +32,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
 		goto out;
 	}
 	gcr_base = of_iomap(gcr_np, 0);
+	of_node_put(gcr_np);
 	if (!gcr_base) {
 		pr_err("could not iomap gcr");
 		ret = -ENOMEM;
@@ -60,6 +61,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
 		return;
 	}
 	scu_base = of_iomap(scu_np, 0);
+	of_node_put(scu_np);
 	if (!scu_base) {
 		pr_err("could not iomap scu");
 		return;
Signature · 1 line
2.53.0
author maintainer
#17 lore raw

PATCH 17/250 selftests/sched_ext: Handle sleeping task affinity changes in numa test

In reply to Greg Kroah-Hartman

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

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

From: Kuba Piecuch <[email protected]>

[ Upstream commit d4a00d61a5c2c24973175ace5368d1f6acf9bb0a ]

When a sleeping task's affinity is changed, task_cpu(p) can be outside of p->cpus_ptr until after select_task_rq() selects a new runqueue for the task during wakeup.

Thus, the task's NUMA node determined by numa_select_cpu() can be completely outside of the task's cpumask, leading to scx_pick_{idle,any}_cpu_node() failing to find an eligible CPU and returning -EBUSY. This leads to the numa.bpf.c scheduler abnormally exiting with the following message in dmesg:

sched_ext: numa: invalid CPU -16

   scx_bpf_cpu_node+0x120/0x190
   bpf_prog_0a34b8e0f515771f_numa_select_cpu+0x108/0x14e
   bpf__sched_ext_ops_select_cpu+0x4f/0xb4
   select_task_rq_scx+0xb0/0x210
   select_task_rq+0xa0/0xd0
   __try_to_wake_up+0x196/0x650
   complete_all+0x76/0x100
   migration_cpu_stop+0x22b/0x300
   cpu_stopper_thread+0xc1/0x180
   smpboot_thread_fn+0x16b/0x230
   kthread+0x2d7/0x350
   ret_from_fork+0x1c2/0x350
   ret_from_fork_asm+0x1a/0x30

Make numa_select_cpu() robust against this case by returning @prev_cpu if no CPU could be found in the selected NUMA node _and_ we have reason to believe that the task's affinity was changed while it was sleeping.

Fixes 5ae5161820e5 ("selftests/sched_ext: Add NUMA-aware scheduler test")
---
 tools/testing/selftests/sched_ext/numa.bpf.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
tools/testing/selftests/sched_ext/numa.bpf.c +12 -1
index a79d86ed54a1b..0ebb6170331bf 100644
@@ -34,7 +34,8 @@ static bool is_cpu_idle(s32 cpu, int node)
 s32 BPF_STRUCT_OPS(numa_select_cpu,
 		   struct task_struct *p, s32 prev_cpu, u64 wake_flags)
 {
-	int node = __COMPAT_scx_bpf_cpu_node(scx_bpf_task_cpu(p));
+	s32 task_cpu = scx_bpf_task_cpu(p);
+	int node = __COMPAT_scx_bpf_cpu_node(task_cpu);
 	s32 cpu;
 
 	/*
@@ -48,6 +49,16 @@ s32 BPF_STRUCT_OPS(numa_select_cpu,
 		cpu = __COMPAT_scx_bpf_pick_any_cpu_node(p->cpus_ptr, node,
 						__COMPAT_SCX_PICK_IDLE_IN_NODE);
 
+	/*
+	 * @task_cpu may be outside of p->cpus_ptr if @p's affinity
+	 * changed while it was sleeping. This means it's possible for
+	 * p->cpus_ptr to not include any CPUs from @node.
+	 * If we failed to find a cpu in @node, check if @task_cpu
+	 * is outside of p->cpus_ptr and just return @prev_cpu if it is.
+	 */
+	if (cpu < 0 && !bpf_cpumask_test_cpu(task_cpu, p->cpus_ptr))
+		return prev_cpu;
+
 	if (is_cpu_idle(cpu, node))
 		scx_bpf_error("CPU %d should be marked as busy", cpu);
 
Signature · 1 line
2.53.0
author maintainer
#18 lore raw

PATCH 18/250 pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function

In reply to Greg Kroah-Hartman

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

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

From: Hans Ulli Kroll <[email protected]>

[ Upstream commit 687f39faccba29ab26de965411db37e849af8ec2 ]

The qcom pinctrl core supports marking functions that represent GPIO mode via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject GPIO requests for pins that are muxed to the GPIO function.

Add a IPQ_GPIO_PIN_FUNCTION() helper and use it for the ipq806x gpio function, matching how the msm-based qcom drivers handle this.

This allows ipq806x to keep the GPIO-related configuration in DTS without tripping over strict pinmux ownership
checks.

---
 drivers/pinctrl/qcom/pinctrl-ipq8064.c | 2 +-
 drivers/pinctrl/qcom/pinctrl-msm.h     | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)
drivers/pinctrl/qcom/pinctrl-ipq8064.c +1 -1
index 0a9e357e64c60..c1651f112950e 100644
@@ -480,7 +480,7 @@ static const char * const ps_hold_groups[] = {
 };
 
 static const struct pinfunction ipq8064_functions[] = {
-	IPQ_PIN_FUNCTION(gpio),
+	IPQ_GPIO_PIN_FUNCTION(gpio),
 	IPQ_PIN_FUNCTION(mdio),
 	IPQ_PIN_FUNCTION(ssbi),
 	IPQ_PIN_FUNCTION(spmi),
drivers/pinctrl/qcom/pinctrl-msm.h +5 -0
index 120217012a9f6..33d8b17f2e559 100644
@@ -24,6 +24,11 @@ struct pinctrl_pin_desc;
 					fname##_groups,		\
 					ARRAY_SIZE(fname##_groups))
 
+#define IPQ_GPIO_PIN_FUNCTION(fname)					\
+	[IPQ_MUX_##fname] = PINCTRL_GPIO_PINFUNCTION(#fname,		\
+					fname##_groups,		\
+					ARRAY_SIZE(fname##_groups))
+
 #define MSM_PIN_FUNCTION(fname) 				\
 	[msm_mux_##fname] = PINCTRL_PINFUNCTION(#fname,		\
 					fname##_groups,		\
Signature · 1 line
2.53.0
author maintainer
#19 lore raw

PATCH 19/250 pinctrl: qcom: ipq806x: mark pci reset as a GPIO pin function

In reply to Greg Kroah-Hartman

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

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

From: Hans Ulli Kroll <[email protected]>

[ Upstream commit fd46760956509f580f7d3d25db4de10e7c6f949b ]

The qcom pinctrl core supports marking functions that represent GPIO mode via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject GPIO requests for pins that are muxed to the GPIO function.

Mark PCIe reset as GPIO pin function

This allows ipq806x to keep the PCIe-reset related configuration in DTS without tripping over strict pinmux ownership checks.

---
 drivers/pinctrl/qcom/pinctrl-ipq8064.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/pinctrl/qcom/pinctrl-ipq8064.c +3 -3
index c1651f112950e..f35dbe07ab6fe 100644
@@ -507,19 +507,19 @@ static const struct pinfunction ipq8064_functions[] = {
 	IPQ_PIN_FUNCTION(usb2_hsic),
 	IPQ_PIN_FUNCTION(rgmii2),
 	IPQ_PIN_FUNCTION(sata),
-	IPQ_PIN_FUNCTION(pcie1_rst),
+	IPQ_GPIO_PIN_FUNCTION(pcie1_rst),
 	IPQ_PIN_FUNCTION(pcie1_prsnt),
 	IPQ_PIN_FUNCTION(pcie1_pwren_n),
 	IPQ_PIN_FUNCTION(pcie1_pwren),
 	IPQ_PIN_FUNCTION(pcie1_pwrflt),
 	IPQ_PIN_FUNCTION(pcie1_clk_req),
-	IPQ_PIN_FUNCTION(pcie2_rst),
+	IPQ_GPIO_PIN_FUNCTION(pcie2_rst),
 	IPQ_PIN_FUNCTION(pcie2_prsnt),
 	IPQ_PIN_FUNCTION(pcie2_pwren_n),
 	IPQ_PIN_FUNCTION(pcie2_pwren),
 	IPQ_PIN_FUNCTION(pcie2_pwrflt),
 	IPQ_PIN_FUNCTION(pcie2_clk_req),
-	IPQ_PIN_FUNCTION(pcie3_rst),
+	IPQ_GPIO_PIN_FUNCTION(pcie3_rst),
 	IPQ_PIN_FUNCTION(pcie3_prsnt),
 	IPQ_PIN_FUNCTION(pcie3_pwren_n),
 	IPQ_PIN_FUNCTION(pcie3_pwren),
Signature · 1 line
2.53.0
author maintainer
#20 lore raw

PATCH 20/250 ovpn: add missing rtnl_link_ops->get_size callback

In reply to Greg Kroah-Hartman

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

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

From: Ralf Lici <[email protected]>

[ Upstream commit 6e9f539e4f01153651dd77609b5ccadd44b74df8 ]

ovpn_fill_info emits IFLA_OVPN_MODE inside IFLA_INFO_DATA, but ovpn_link_ops does not provide a get_size callback. Consequently, rtnetlink's size estimate for ovpn link messages does not include the nested mode attribute.

Available skb tailroom may hide this mismatch. When the remaining space is insufficient, however, ovpn_fill_info returns -EMSGSIZE and message construction fails.

Add the callback and account for IFLA_OVPN_MODE.

Fixes c2d950c4672a ("ovpn: add basic interface creation/destruction/management routines")
---
 drivers/net/ovpn/main.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/net/ovpn/main.c +7 -0
index 3f76b1b0e5f60..47859e1e3ef12 100644
@@ -210,6 +210,12 @@ static int ovpn_newlink(struct net_device *dev,
 	return register_netdevice(dev);
 }
 
+static size_t ovpn_get_size(const struct net_device *dev)
+{
+	/* IFLA_OVPN_MODE */
+	return nla_total_size(sizeof(u8));
+}
+
 static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
 	struct ovpn_priv *ovpn = netdev_priv(dev);
@@ -228,6 +234,7 @@ static struct rtnl_link_ops ovpn_link_ops = {
 	.policy = ovpn_policy,
 	.maxtype = IFLA_OVPN_MAX,
 	.newlink = ovpn_newlink,
+	.get_size = ovpn_get_size,
 	.fill_info = ovpn_fill_info,
 };
 
Signature · 1 line
2.53.0
author maintainer
#21 lore raw

PATCH 21/250 ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt

In reply to Greg Kroah-Hartman

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

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

From: Rosen Penev <[email protected]>

[ Upstream commit bab4d538f8485e0d48538fcb82b285df3779278e ]

PCIe controller 2 has interrupts 0-4 mapping to GIC SPI 138-142. The mapping for interrupt 1 was incorrectly set to 138 due to a copy-paste error. Fix it to 139.

Assisted-by opencode:big-pickle
Fixes 3b3e35b279be ("ARM: dts: BCM5301X: Relicense AXI interrupts code to the GPL 2.0+ / MIT")
---
 arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/broadcom/bcm-ns.dtsi +1 -1
index d0d5f7e52a917..f08d0a27de0b4 100644
@@ -138,7 +138,7 @@ axi@18000000 {
 
 			/* PCIe Controller 2 */
 			<0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-			<0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+			<0x00014000 1 &gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
 			<0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
 			<0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
 			<0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
Signature · 1 line
2.53.0
author maintainer
#22 lore raw

PATCH 22/250 ovpn: skip rehash for peers already removed from by_id

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit 33ec10567fe14456063daf549fdf1a4f53448e4c ]

ovpn_nl_peer_set_doit() resolves the target peer via ovpn_peer_get_by_id() before taking ovpn->lock. In the window between the lookup (which only takes a refcount) and the subsequent spin_lock_bh(&ovpn->lock), a concurrent OVPN_CMD_PEER_DEL, keepalive expiry, or socket teardown can take ovpn->lock first, run ovpn_peer_remove() to unhash the peer from all four tables (by_id, by_vpn_addr4/6, by_transp_addr) and release the lock. set_doit then acquires ovpn->lock and calls ovpn_peer_hash_vpn_ip(), which re-inserts the now-removed peer back into the rehashing tables.

The same race affects the float path: ovpn_peer_endpoints_update() holds only a refcount and acquires ovpn->lock very late (after async AEAD decrypt and a netlink notification), then rehashes the peer in the by_transp_addr table.

The resurrected peer becomes reachable again from the RX lookup (ovpn_peer_get_by_transp_addr) and the TX VPN-IP lookup, even though userspace believes it is gone. Once the data-path refcount drops the peer is freed via call_rcu while the hash entries embedded in it remain linked, opening a UAF window.

Bail out of the rehash when hash_entry_id is unhashed, mirroring the sentinel already used by ovpn_peer_remove() to detect the already-removed state. The check is safe under ovpn->lock, which serializes every mutation of hash_entry_id, and is a no-op for the add path because ovpn_peer_add_mp() inserts hash_entry_id before calling ovpn_peer_hash_vpn_ip().

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/peer.c | 73 ++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 30 deletions(-)
drivers/net/ovpn/peer.c +43 -30
index 85fa9bd475f45..6b7e368f63f3a 100644
@@ -291,40 +291,46 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 	/* rehashing is required only in MP mode as P2P has one peer
 	 * only and thus there is no hashtable
 	 */
-	if (peer->ovpn->mode == OVPN_MODE_MP) {
-		spin_lock_bh(&peer->ovpn->lock);
-		spin_lock_bh(&peer->lock);
-		bind = rcu_dereference_protected(peer->bind,
-						 lockdep_is_held(&peer->lock));
-		if (unlikely(!bind)) {
-			spin_unlock_bh(&peer->lock);
-			spin_unlock_bh(&peer->ovpn->lock);
-			return;
-		}
+	if (peer->ovpn->mode != OVPN_MODE_MP)
+		return;
 
-		/* This function may be invoked concurrently, therefore another
-		 * float may have happened in parallel: perform rehashing
-		 * using the peer->bind->remote directly as key
-		 */
+	spin_lock_bh(&peer->ovpn->lock);
+	spin_lock_bh(&peer->lock);
+	bind = rcu_dereference_protected(peer->bind,
+					 lockdep_is_held(&peer->lock));
+	if (unlikely(!bind))
+		goto unlock2;
 
-		switch (bind->remote.in4.sin_family) {
-		case AF_INET:
-			salen = sizeof(*sa);
-			break;
-		case AF_INET6:
-			salen = sizeof(*sa6);
-			break;
-		}
+	/* peer may have been concurrently removed between the caller's
+	 * initial lookup and our acquisition of ovpn->lock; skip the
+	 * rehash so we don't re-insert a removed peer
+	 */
+	if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+		goto unlock2;
 
-		/* remove old hashing */
-		hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
-		/* re-add with new transport address */
-		nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
-					   &bind->remote, salen);
-		hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
-		spin_unlock_bh(&peer->lock);
-		spin_unlock_bh(&peer->ovpn->lock);
+	/* This function may be invoked concurrently, therefore another
+	 * float may have happened in parallel: perform rehashing
+	 * using the peer->bind->remote directly as key
+	 */
+
+	switch (bind->remote.in4.sin_family) {
+	case AF_INET:
+		salen = sizeof(*sa);
+		break;
+	case AF_INET6:
+		salen = sizeof(*sa6);
+		break;
 	}
+
+	/* remove old hashing */
+	hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+	/* re-add with new transport address */
+	nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+				   &bind->remote, salen);
+	hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+unlock2:
+	spin_unlock_bh(&peer->lock);
+	spin_unlock_bh(&peer->ovpn->lock);
 	return;
 unlock:
 	spin_unlock_bh(&peer->lock);
@@ -901,6 +907,13 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
 	if (peer->ovpn->mode != OVPN_MODE_MP)
 		return;
 
+	/* peer may have been concurrently removed between the caller's
+	 * initial lookup and our acquisition of ovpn->lock; skip the
+	 * rehash so we don't re-insert a removed peer
+	 */
+	if (hlist_unhashed(&peer->hash_entry_id))
+		return;
+
 	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
 		/* remove potential old hashing */
 		hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
Signature · 1 line
2.53.0
author maintainer
#23 lore raw

PATCH 23/250 ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit cc12f7240c8c4dee557749d33237542613992f14 ]

When userspace updates a peer's remote endpoint via OVPN_CMD_PEER_SET, ovpn_nl_peer_modify() installs a new ovpn_bind through ovpn_peer_reset_sockaddr(), but ovpn_nl_peer_set_doit() only calls ovpn_peer_hash_vpn_ip() to refresh the VPN-IP hashtables. The peer is left in the bucket of peers->by_transp_addr corresponding to its old remote address.

As a consequence, datagrams arriving at the UDP RX path from the newly configured remote hash to a different slot and the lockless lookup in ovpn_peer_get_by_transp_addr() (called from ovpn_udp_encap_recv()) does not find the peer, until either a float event or a peer re-add fixes the bucket.

Introduce ovpn_peer_hash_transp_addr() (modeled after ovpn_peer_hash_vpn_ip()) and invoke it from ovpn_nl_peer_set_doit() whenever the request carried a new remote address. The helper bails out in P2P mode and on peers without a bind (TCP), and relies on hlist_nulls_del_init_rcu()'s pprev==NULL short-circuit to handle the case of an entry not currently linked in the table.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c |   6 +++
 drivers/net/ovpn/peer.c    | 105 +++++++++++++++++++++++++------------
 drivers/net/ovpn/peer.h    |   1 +
 3 files changed, 79 insertions(+), 33 deletions(-)
drivers/net/ovpn/netlink.c +6 -0
index bdb56ef0c9040..0051166c59c75 100644
@@ -527,6 +527,12 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 	 */
 	if (ret > 0)
 		ovpn_peer_hash_vpn_ip(peer);
+	/* if the remote endpoint was updated, the by_transp_addr hash bucket
+	 * also needs to be refreshed, otherwise incoming packets from the new
+	 * remote address would fail the lockless lookup
+	 */
+	if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
+		ovpn_peer_hash_transp_addr(peer);
 	spin_unlock_bh(&ovpn->lock);
 	ovpn_peer_put(peer);
 
drivers/net/ovpn/peer.c +72 -33

137 lines not on this page · raw message

drivers/net/ovpn/peer.h +1 -0
index 4de5aeae33f7d..9a05a278e1cd0 100644
@@ -148,6 +148,7 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
 struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
 				       struct sk_buff *skb);
 void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
+void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
 bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
 			    struct ovpn_peer *peer);
 
Signature · 1 line
2.53.0
author maintainer
#24 lore raw

PATCH 24/250 ovpn: ensure socket is owned by ovpn before deref sk_user_data

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit 59aed1eb60d70678a53acccb0cb337a26ce6680e ]

Some subsystems, like BPF SOCKMAP, set sk_user_data without actually setting the encap_type.

For this reason, we must make sure that the type is the one ovpn expects before dereferencing sk_user_data.

Failing to do so may lead to out-of-bounds reads.

Fixes f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
---
 drivers/net/ovpn/socket.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/net/ovpn/socket.c +9 -0
index 448cee3b3f9fa..e40e320a6abf5 100644
@@ -162,6 +162,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
 		rcu_read_lock();
 		ovpn_sock = rcu_dereference_sk_user_data(sk);
 		if (ovpn_sock) {
+			/* something else filled the sk_user_data without
+			 * setting the encap_type. Reject the socket.
+			 */
+			if (!type) {
+				ovpn_sock = ERR_PTR(-EBUSY);
+				rcu_read_unlock();
+				goto sock_release;
+			}
+
 			/* socket owned by another ovpn instance, we can't use it */
 			if (ovpn_sock->ovpn != peer->ovpn) {
 				ovpn_sock = ERR_PTR(-EBUSY);
Signature · 1 line
2.53.0
author maintainer
#25 lore raw

PATCH 25/250 ovpn: zero-initialize sockaddr before learning a floated endpoint

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit 3f012bdbabe211ccbc0c50ea5a1dbc60f8af1532 ]

ovpn_peer_endpoints_update() builds the new remote endpoint in an on-stack struct sockaddr_storage that is left uninitialized. For IPv4 only sin_family/sin_addr/sin_port are written, leaving the 8-byte sin_zero padding as stack garbage (for IPv6, sin6_flowinfo is left uninitialized likewise).

ovpn_peer_reset_sockaddr() -> ovpn_bind_from_sockaddr() then memcpy()s sizeof(struct sockaddr_in)/sizeof(struct sockaddr_in6) bytes - padding included - into bind->remote. That buffer is later hashed with jhash() over the same length to place the peer in the by_transp_addr table, so the garbage padding lands the floated peer in an essentially random bucket. Lockless lookups in ovpn_peer_get_by_transp_addr() build their key from a zero-initialized sockaddr_storage, compute a different bucket and fail to find the peer.

This is also a plain use of uninitialized stack memory in jhash().

Build the floated endpoint with a designated initializer so the padding (sin_zero for IPv4, sin6_flowinfo for IPv6) is zeroed as part of the assignment. This keeps the padding out of the by_transp_addr hash key without memset-ing the whole sockaddr_storage on every received packet.

Fixes f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
---
 drivers/net/ovpn/peer.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)
drivers/net/ovpn/peer.c +23 -8
index f502f9c576f8f..3824ee1c2e40a 100644
@@ -218,9 +218,16 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 			 */
 			local_ip = &ip_hdr(skb)->daddr;
 			sa = (struct sockaddr_in *)&ss;
-			sa->sin_family = AF_INET;
-			sa->sin_addr.s_addr = ip_hdr(skb)->saddr;
-			sa->sin_port = udp_hdr(skb)->source;
+			/* use a designated initializer so the sin_zero padding
+			 * is zeroed (it ends up in the by_transp_addr hash key)
+			 * without memset-ing the whole sockaddr_storage on the
+			 * RX fast path
+			 */
+			*sa = (struct sockaddr_in) {
+				.sin_family = AF_INET,
+				.sin_addr.s_addr = ip_hdr(skb)->saddr,
+				.sin_port = udp_hdr(skb)->source,
+			};
 			salen = sizeof(*sa);
 			reset_cache = true;
 			break;
@@ -246,11 +253,19 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
 			 */
 			local_ip = &ipv6_hdr(skb)->daddr;
 			sa6 = (struct sockaddr_in6 *)&ss;
-			sa6->sin6_family = AF_INET6;
-			sa6->sin6_addr = ipv6_hdr(skb)->saddr;
-			sa6->sin6_port = udp_hdr(skb)->source;
-			sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
-								 skb->skb_iif);
+			/* use a designated initializer so the sin6_flowinfo
+			 * padding is zeroed (it ends up in the by_transp_addr
+			 * hash key) without memset-ing the whole
+			 * sockaddr_storage on the RX fast path
+			 */
+			*sa6 = (struct sockaddr_in6) {
+				.sin6_family = AF_INET6,
+				.sin6_addr = ipv6_hdr(skb)->saddr,
+				.sin6_port = udp_hdr(skb)->source,
+				.sin6_scope_id =
+					ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
+							    skb->skb_iif),
+			};
 			salen = sizeof(*sa6);
 			reset_cache = true;
 			break;
Signature · 1 line
2.53.0
author maintainer
#26 lore raw

PATCH 26/250 ovpn: hash floated peer by transport identity only

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit b47a52dcd598a50207a33df304acdf45348a690f ]

The by_transp_addr table is keyed on the peer's remote transport address, but the float rehash hashed bind->remote directly, while the two other sites that touch the table build a clean key first:
ovpn_peer_add_mp() and the lookup in ovpn_peer_get_by_transp_addr() both hash a sockaddr holding only family/address/port.

For a link-local IPv6 peer, bind->remote carries sin6_scope_id (set from ipv6_iface_scope_id() when the endpoint is learned), and that field is folded into the jhash() over sizeof(struct sockaddr_in6). The lookup never sets sin6_scope_id, so after such a peer floats it is rehashed into a scope_id-dependent bucket that lookups (scope_id 0) never visit, making the peer unreachable through the by_transp_addr fallback. ovpn_peer_transp_match() only compares address and port, so the hash was keying on a field the match ignores.

sin6_scope_id must stay in bind->remote because the TX path uses it as flowi6_oif, so it cannot just be cleared there. Instead build the hash key from family/address/port only, exactly like ovpn_peer_add_mp() and the lookup, so all three sites agree on the bucket.

Fixes f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
---
 drivers/net/ovpn/peer.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)
drivers/net/ovpn/peer.c +21 -4
index 3824ee1c2e40a..9b647a327c468 100644
@@ -899,7 +899,10 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
 static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
 					 const struct ovpn_bind *bind)
 {
+	struct sockaddr_storage sa = {};
 	struct hlist_nulls_head *nhead;
+	struct sockaddr_in6 *sa6;
+	struct sockaddr_in *sa4;
 	size_t salen;
 
 	lockdep_assert_held(&peer->ovpn->lock);
@@ -915,12 +918,26 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
 	if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
 		return;
 
+	/* Build the hash key from the transport identity only
+	 * (family/address/port), matching ovpn_peer_add_mp() and the lookup
+	 * in ovpn_peer_get_by_transp_addr(). Hashing bind->remote directly
+	 * would fold in sin6_scope_id (set on the float path but never by the
+	 * lookup), scattering the peer into a bucket lookups cannot reach.
+	 */
 	switch (bind->remote.in4.sin_family) {
 	case AF_INET:
-		salen = sizeof(struct sockaddr_in);
+		sa4 = (struct sockaddr_in *)&sa;
+		sa4->sin_family = AF_INET;
+		sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr;
+		sa4->sin_port = bind->remote.in4.sin_port;
+		salen = sizeof(*sa4);
 		break;
 	case AF_INET6:
-		salen = sizeof(struct sockaddr_in6);
+		sa6 = (struct sockaddr_in6 *)&sa;
+		sa6->sin6_family = AF_INET6;
+		sa6->sin6_addr = bind->remote.in6.sin6_addr;
+		sa6->sin6_port = bind->remote.in6.sin6_port;
+		salen = sizeof(*sa6);
 		break;
 	default:
 		return;
@@ -929,8 +946,8 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
 	/* remove old hashing (no-op if entry is not currently linked) */
 	hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
 	/* re-add with current transport address */
-	nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
-				   &bind->remote, salen);
+	nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, &sa,
+				   salen);
 	hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
 }
 
Signature · 1 line
2.53.0
author maintainer
#27 lore raw

PATCH 27/250 ovpn: disable IPv4 redirects on MP interfaces

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit 0301aa324941698bec3dd455df1c5abc7afb10db ]

ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer interface, but it runs from ovpn_net_init() (->ndo_init), which register_netdevice() invokes before the NETDEV_REGISTER notifier chain. The IPv4 in_device is only created when that notifier reaches inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always returned NULL at ndo_init time and the whole redirect-disabling block (both the per-device and the per-netns IPV4_DEVCONF_ALL write) was dead. MP interfaces therefore kept emitting ICMP redirects.

Disabling redirects only once is not enough either: the IPv4 in_device is destroyed and recreated when the interface is moved to a different network namespace (NETDEV_UNREGISTER/NETDEV_REGISTER), and the newly created in_device inherits the destination namespace defaults, silently re-enabling SEND_REDIRECTS.

Disable redirects from ovpn_net_open() (->ndo_open) instead: it runs every time the interface is brought up, including after the in_device has been recreated, so the setting is always re-applied. This mirrors what wireguard does in wg_open(). RTNL is held on the ndo_open() path, so __in_dev_get_rtnl() is safe.

Fixes 05003b408c20 ("ovpn: implement multi-peer support")
---
 drivers/net/ovpn/main.c | 50 ++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 15 deletions(-)
drivers/net/ovpn/main.c +35 -15
index 47859e1e3ef12..a3c15fc301d0d 100644
@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
 
 static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
 {
-	struct in_device *dev_v4;
 	int i;
 
 	if (ovpn->mode != OVPN_MODE_MP)
 		return 0;
 
-	dev_v4 = __in_dev_get_rtnl(ovpn->dev);
-	if (dev_v4) {
-		/* disable redirects as Linux gets confused by ovpn
-		 * handling same-LAN routing.
-		 * This happens because a multipeer interface is used as
-		 * relay point between hosts in the same subnet, while
-		 * in a classic LAN this would not be needed because the
-		 * two hosts would be able to talk directly.
-		 */
-		IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
-		IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
-	}
-
 	/* the peer container is fairly large, therefore we allocate it only in
 	 * MP mode
 	 */
@@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev)
 	gro_cells_destroy(&ovpn->gro_cells);
 }
 
+static int ovpn_net_open(struct net_device *dev)
+{
+	struct ovpn_priv *ovpn = netdev_priv(dev);
+	struct in_device *dev_v4;
+
+	/* the IPv4 in_device (and thus its config) is recreated whenever the
+	 * interface is moved to a new netns, so redirects must be disabled on
+	 * every bring-up rather than once at creation time, otherwise the
+	 * setting is silently lost after such a move
+	 */
+	if (ovpn->mode == OVPN_MODE_MP) {
+		dev_v4 = __in_dev_get_rtnl(dev);
+		if (dev_v4) {
+			/* disable redirects as Linux gets confused by ovpn
+			 * handling same-LAN routing.
+			 * This happens because a multipeer interface is used as
+			 * relay point between hosts in the same subnet, while
+			 * in a classic LAN this would not be needed because the
+			 * two hosts would be able to talk directly.
+			 */
+			IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+			IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
+		}
+	}
+
+	return 0;
+}
+
 static const struct net_device_ops ovpn_netdev_ops = {
 	.ndo_init		= ovpn_net_init,
 	.ndo_uninit		= ovpn_net_uninit,
+	.ndo_open		= ovpn_net_open,
 	.ndo_start_xmit		= ovpn_net_xmit,
 };
 
@@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev,
 	struct ovpn_priv *ovpn = netdev_priv(dev);
 	struct nlattr **data = params->data;
 	enum ovpn_mode mode = OVPN_MODE_P2P;
+	int ret;
 
 	if (data && data[IFLA_OVPN_MODE]) {
 		mode = nla_get_u8(data[IFLA_OVPN_MODE]);
@@ -207,7 +223,11 @@ static int ovpn_newlink(struct net_device *dev,
 	else
 		netif_carrier_off(dev);
 
-	return register_netdevice(dev);
+	ret = register_netdevice(dev);
+	if (ret < 0)
+		return ret;
+
+	return 0;
 }
 
 static size_t ovpn_get_size(const struct net_device *dev)
Signature · 1 line
2.53.0
author maintainer
#28 lore raw

PATCH 28/250 ovpn: ensure TCP vars are initialized first

In reply to Greg Kroah-Hartman

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

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

From: Antonio Quartulli <[email protected]>

[ Upstream commit 4680c0ebd958fc18e53c8b91d80436b236a8fc09 ]

Netlink calls may access TCP global vars (i.e. when attaching a TCP socket), therefore we need to make sure the latters are initialized beforehand.

For this reason move the global TCP initialization at the top of the module init function.

Fixes 11851cbd60ea ("ovpn: implement TCP transport")
---
 drivers/net/ovpn/main.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ovpn/main.c +4 -3
index a3c15fc301d0d..0262926449f2e 100644
@@ -260,8 +260,11 @@ static struct rtnl_link_ops ovpn_link_ops = {
 
 static int __init ovpn_init(void)
 {
-	int err = rtnl_link_register(&ovpn_link_ops);
+	int err;
 
+	ovpn_tcp_init();
+
+	err = rtnl_link_register(&ovpn_link_ops);
 	if (err) {
 		pr_err("ovpn: can't register rtnl link ops: %d\n", err);
 		return err;
@@ -273,8 +276,6 @@ static int __init ovpn_init(void)
 		goto unreg_rtnl;
 	}
 
-	ovpn_tcp_init();
-
 	return 0;
 
 unreg_rtnl:
Signature · 1 line
2.53.0
author maintainer
#29 lore raw

PATCH 29/250 ovpn: fix incorrect use of rcu_access_pointer()

In reply to Greg Kroah-Hartman

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

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

From: Qingfang Deng <[email protected]>

[ Upstream commit 26ba17d845193dac4921ae1ab280d28d1938052e ]

rcu_access_pointer() should only be used to test the value of a pointer, not to dereference it. As it's in a spin_lock_bh() critical section, use rcu_dereference_bh() instead, avoiding an extra rcu_read_lock().

Fixes f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
---
 drivers/net/ovpn/peer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ovpn/peer.c +1 -1
index 9b647a327c468..412ef09abd5e7 100644
@@ -1244,7 +1244,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
 	}
 
 	if (sk) {
-		ovpn_sock = rcu_access_pointer(peer->sock);
+		ovpn_sock = rcu_dereference_bh(peer->sock);
 		if (!ovpn_sock || ovpn_sock->sk != sk) {
 			spin_unlock_bh(&ovpn->lock);
 			return;
Signature · 1 line
2.53.0
author maintainer
#30 lore raw

PATCH 30/250 drm/bridge: ps8640: propagate AUX transfer register errors

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit 20697ecb299cd77b4cf8b28f655e56606b0472d8 ]

ps8640_aux_transfer_msg() programs the AUX address registers, starts the AUX transfer, waits for SWAUX_SEND to clear, and reads the AUX status register. Several of those regmap operations have return values, but the function only checks a stale ret after the status read.

Propagate failures from the address write, transfer start, completion poll, and status read. This avoids returning a transfer length when the bridge register transaction or AUX completion wait failed.

Fixes 13afcdd7277e ("drm/bridge: parade-ps8640: Add support for AUX channel")
---
 drivers/gpu/drm/bridge/parade-ps8640.c | 27 ++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)
drivers/gpu/drm/bridge/parade-ps8640.c +21 -6
index 825777a5758f6..db8e5889dc7f1 100644
@@ -257,8 +257,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
 	addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
 					      ((len - 1) & SWAUX_LENGTH_MASK);
 
-	regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
-			  ARRAY_SIZE(addr_len));
+	ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
+				ARRAY_SIZE(addr_len));
+	if (ret) {
+		DRM_DEV_ERROR(dev,
+			      "failed to write AUX address %#x, len %zu: %d\n",
+			      msg->address, len, ret);
+		return ret;
+	}
 
 	if (len && (request == DP_AUX_NATIVE_WRITE ||
 		    request == DP_AUX_I2C_WRITE)) {
@@ -274,13 +280,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
 		}
 	}
 
-	regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
+	ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
+		return ret;
+	}
 
 	/* Zero delay loop because i2c transactions are slow already */
-	regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
-				 !(data & SWAUX_SEND), 0, 50 * 1000);
+	ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
+				       !(data & SWAUX_SEND), 0, 50 * 1000);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
+			      ret);
+		return ret;
+	}
 
-	regmap_read(map, PAGE0_SWAUX_STATUS, &data);
+	ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
 			      ret);
Signature · 1 line
2.53.0
author maintainer
#31 lore raw

PATCH 31/250 net: hns3: fix speed configuration residue after driver reload

In reply to Greg Kroah-Hartman

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

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

From: Jijie Shao <[email protected]>

[ Upstream commit 3860d8748af315bfee6fe669fddc1fc17d3214db ]

After setting a 100G optical port to 40G via ethtool and reloading the driver, the port remains at 40G instead of reverting to the firmware default speed of 100G.

The commit referenced in Fixes: added two overwrites in hclge_init_ae_dev() for non-copper media, so that optical ports connected to forced-mode remotes inherit the firmware-preset autoneg and speed instead of the hardcoded defaults:

req_autoneg = mac.autoneg
req_speed = mac.speed (when autoneg disabled)

The autoneg overwrite keeps existing behavior:
hclge_set_autoneg_speed_dup() already uses mac.autoneg (not req_autoneg) since it was introduced, so autoneg inheritance from firmware was already in place. This part is kept.

The speed overwrite, however, introduces the residue: mac.speed reflects whatever was last programmed into the MAC, and after unload firmware does not restore the MAC speed to the flash default. So if the user changed speed via ethtool in a prior load, mac.speed still carries that value on reload and req_speed inherits it.

Fix by dropping the req_speed overwrite only. req_speed keeps the firmware default value set in hclge_configure() (cfg.default_speed), so a reload reverts the speed to default, matching the expectation that a driver reload resets link configuration.

Trade-off: on optical ports whose firmware default speed does not match a forced-mode remote, reload now drops the link and the user must re-apply ethtool configuration. This is acceptable: a driver reload is expected to reset link configuration, not to inherit runtime state from before unload. The autoneg inheritance is left in place as established behavior; changing it is out of scope for this patch and would itself be a user-perceivable behavior change.

Fixes d9d349c4e8a0 ("net: hns3: differentiate autoneg default values between copper and fiber")
---
 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +1 -5
index 7f174453928c1..02fee71c20886 100644
@@ -11930,12 +11930,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 	if (ret)
 		goto err_ptp_uninit;
 
-	if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) {
+	if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER)
 		hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg;
-		if (hdev->hw.mac.autoneg == AUTONEG_DISABLE &&
-		    hdev->hw.mac.speed != SPEED_UNKNOWN)
-			hdev->hw.mac.req_speed = hdev->hw.mac.speed;
-	}
 
 	ret = hclge_set_autoneg_speed_dup(hdev);
 	if (ret) {
Signature · 1 line
2.53.0
author maintainer
#32 lore raw

PATCH 32/250 Revert "net: thunderbolt: Enable end-to-end flow control also in transmit"

In reply to Greg Kroah-Hartman

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

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

From: Fan Ye <[email protected]>

[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]

This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.

Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control disabled does not require any credits to be available before the Host Interface Adapter Layer transmits a tunneled packet from it. Once E2E is enabled on that ring the controller must first obtain end-to-end credits.

The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers those credits. The controller does accept the configuration: reading the ring OPTIONS register back right after tb_ring_start() returns exactly what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the E2E HopID field. No credit ever arrives though, so the Tx ring's hardware consumer index never advances and the link carries no traffic at all.

Measured on two hosts connected point to point, onboard ASM4242 on MSI X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only this revert applied on top:

before: 100% packet loss to the peer; thunderbolt0 is up and the
XDomain handshake completes ("new host found"), but iperf3 fails with "No route to host" once the neighbour entry expires
after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1 retransmit in 10 s

An instrumented build additionally showed a frozen-Tx-consumer watchdog firing ~30k times in a 10 s window before this change.

Rx-side E2E is not touched by this revert, so peers that do return credits keep receive-side flow control.

ASMedia does not look like an isolated case. The out-of-tree thunderbolt-ibverbs project disables native E2E on AMD NHI by default, noting that "Strix Halo has reproduced TX completion wedges with multiple native E2E rings active" -- the same failure mode, on a different vendor. Since the driver has no way to tell in advance which host router returns the credits, going back to the previous behaviour looks safer than adding a quirk per affected part; Tx-side E2E can be reintroduced as an opt-in for controllers that are known to implement the credit return.

Note that the reverted commit was not fixing a reported problem, it was derived from the spec wording alone, so this revert is not expected to regress a known workload. Cc'ing the original author in case there was one.

Fixes a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
Cc zhangjianrong <[email protected]>
---
 drivers/net/thunderbolt/main.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/net/thunderbolt/main.c +7 -6
index 5d7d11d75b0b8..960839a651e51 100644
@@ -928,12 +928,8 @@ static int tbnet_open(struct net_device *dev)
 
 	netif_carrier_off(dev);
 
-	flags = RING_FLAG_FRAME;
-	/* Only enable full E2E if the other end supports it too */
-	if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
-		flags |= RING_FLAG_E2E;
-
-	ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
+	ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
+				RING_FLAG_FRAME);
 	if (!ring) {
 		netdev_err(dev, "failed to allocate Tx ring\n");
 		return -ENOMEM;
@@ -952,6 +948,11 @@ static int tbnet_open(struct net_device *dev)
 	sof_mask = BIT(TBIP_PDF_FRAME_START);
 	eof_mask = BIT(TBIP_PDF_FRAME_END);
 
+	flags = RING_FLAG_FRAME;
+	/* Only enable full E2E if the other end supports it too */
+	if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+		flags |= RING_FLAG_E2E;
+
 	ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
 				net->tx_ring.ring->hop, sof_mask,
 				eof_mask, tbnet_start_poll, net);
Signature · 1 line
2.53.0
author maintainer
#33 lore raw

PATCH 33/250 bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei (Microsoft) <[email protected]>

[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]

bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the active slave. In that window the active slave can change under RTNL (RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()), which already drops the promiscuity and clears primary_is_promisc. The monitor still acts on the stale decision: if the slave was removed with no failover, curr_active_slave is now NULL and the deref faults; if it failed over, the stale dev_set_promiscuity(-1) underflows the new slave's promiscuity counter and pins it in IFF_PROMISC.

  Oops: general protection fault, probably for non-canonical address ...
  KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
  Workqueue: b42 bond_alb_monitor
  RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
   process_one_work (kernel/workqueue.c:3322)
   worker_thread (kernel/workqueue.c:3486)
   kthread (kernel/kthread.c:436)
   ret_from_fork (arch/x86/kernel/process.c:158)
  Kernel panic - not syncing: Fatal exception

Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so the monitor only undoes an increment it still owns. The other bonding monitors already re-read state under RTNL in their commit phase (bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only one acting on the pre-trylock decision.

---
 drivers/net/bonding/bond_alb.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/bonding/bond_alb.c +6 -4
index 2d37b07c8215c..839f7482dc182 100644
@@ -1534,8 +1534,8 @@ void bond_alb_monitor(struct work_struct *work)
 	struct bonding *bond = container_of(work, struct bonding,
 					    alb_work.work);
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+	struct slave *slave, *curr;
 	struct list_head *iter;
-	struct slave *slave;
 
 	if (!bond_has_slaves(bond)) {
 		atomic_set(&bond_info->tx_rebalance_counter, 0);
@@ -1597,9 +1597,11 @@ void bond_alb_monitor(struct work_struct *work)
 			 * because a slave was disabled then
 			 * it can now leave promiscuous mode.
 			 */
-			dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
-					    -1);
-			bond_info->primary_is_promisc = 0;
+			curr = rtnl_dereference(bond->curr_active_slave);
+			if (bond_info->primary_is_promisc && curr) {
+				dev_set_promiscuity(curr->dev, -1);
+				bond_info->primary_is_promisc = 0;
+			}
 
 			rtnl_unlock();
 			rcu_read_lock();
Signature · 1 line
2.53.0
author maintainer
#34 lore raw

PATCH 34/250 enic: fix tx_hang_reset use-after-free on device removal

In reply to Greg Kroah-Hartman

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

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

From: Satish Kharat <[email protected]>

[ Upstream commit ec680ea4ba1bca92a767fb7e7869758bfdd886e3 ]

enic_remove() cancels the reset and change_mtu_work items but does not cancel tx_hang_reset. A TX timeout that fires while the device is being removed can schedule enic_tx_hang_reset() so that it runs after free_netdev(), resulting in a use-after-free.

cancel_work_sync() alone is not sufficient here: the still-live watchdog and notify paths can re-schedule these work items in the window between the cancel and unregister_netdev(). Use disable_work_sync(), which cancels the work and blocks any subsequent schedule_work() from requeuing it, and apply it to the reset and change_mtu_work items as well so the same requeue race is closed for all teardown work.

Fixes 937317c7c109 ("enic: do hang reset only in case of tx timeout")
---
 drivers/net/ethernet/cisco/enic/enic_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ethernet/cisco/enic/enic_main.c +3 -2
index 6bc8dfdb3d4be..2a8b41d8eb883 100644
@@ -2959,8 +2959,9 @@ static void enic_remove(struct pci_dev *pdev)
 	if (netdev) {
 		struct enic *enic = netdev_priv(netdev);
 
-		cancel_work_sync(&enic->reset);
-		cancel_work_sync(&enic->change_mtu_work);
+		disable_work_sync(&enic->reset);
+		disable_work_sync(&enic->tx_hang_reset);
+		disable_work_sync(&enic->change_mtu_work);
 		unregister_netdev(netdev);
 		enic_dev_deinit(enic);
 		vnic_dev_close(enic->vdev);
Signature · 1 line
2.53.0
author maintainer
#35 lore raw

PATCH 35/250 net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock

In reply to Greg Kroah-Hartman

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

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

From: Shay Drory <[email protected]>

[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]

In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring ESW devcom lock without condition. In addition, in case of peer_flow, __mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock. This results in an AA deadlock.

To fix this, introduce a new PEER flag that is set on flows created as peer flows (the duplicate flows on peer devices), and check it in mlx5e_tc_del_flow() before acquiring ESW devcom lock.

Lockdep splat:
============================================
WARNING: possible recursive locking detected
============================================

 Possible unsafe locking scenario:
       CPU0
       ----
  lock(&comp->lock_key#2);
  lock(&comp->lock_key#2);
 *** DEADLOCK ***
Call Trace:
 <TASK>
 dump_stack_lvl+0x69/0xa0
 print_deadlock_bug.cold+0xbd/0xca
 __lock_acquire+0x1671/0x2ec0
 lock_acquire+0x10e/0x2e0
 down_read+0x95/0x430
 mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
 mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
 mlx5e_flow_put+0x99/0x100 [mlx5_core]
 __mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
 mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
 mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
 mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
 tc_setup_cb_add+0x1dc/0x470
 fl_change+0x2f4d/0x626d [cls_flower]
 tc_new_tfilter+0x79b/0x2310
 rtnetlink_rcv_msg+0x778/0xad0
 do_syscall_64+0x70/0x960
 entry_SYSCALL_64_after_hwframe+0x4b/0x53
 </TASK>
Fixes 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows")
---
 drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 +
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c      | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +1 -0
index efb34de4cb7ad..692ac2f21d94e 100644
@@ -30,6 +30,7 @@ enum {
 	MLX5E_TC_FLOW_FLAG_FAILED                = MLX5E_TC_FLOW_BASE + 9,
 	MLX5E_TC_FLOW_FLAG_SAMPLE                = MLX5E_TC_FLOW_BASE + 10,
 	MLX5E_TC_FLOW_FLAG_USE_ACT_STATS         = MLX5E_TC_FLOW_BASE + 11,
+	MLX5E_TC_FLOW_FLAG_PEER                  = MLX5E_TC_FLOW_BASE + 12,
 };
 
 struct mlx5e_tc_flow_parse_attr {
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +3 -1
index ebea43c235cc3..e2de3a9a647c3 100644
@@ -2165,7 +2165,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
 	if (mlx5e_is_eswitch_flow(flow)) {
 		struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
 
-		if (!mlx5_devcom_for_each_peer_begin(devcom)) {
+		if (flow_flag_test(flow, PEER) ||
+		    !mlx5_devcom_for_each_peer_begin(devcom)) {
 			mlx5e_tc_del_fdb_flow(priv, flow);
 			return;
 		}
@@ -4609,6 +4610,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
 	else
 		in_mdev = priv->mdev;
 
+	flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER);
 	parse_attr = flow->attr->parse_attr;
 	peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
 					 parse_attr->filter_dev,
Signature · 1 line
2.53.0
author maintainer
#36 lore raw

PATCH 36/250 pds_core: keep the health thread stopped during reset

In reply to Greg Kroah-Hartman

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

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

From: Nikhil P. Rao <[email protected]>

[ Upstream commit cd09971dcc1c499ae0879010a00e9dba87abdc4f ]

Commit d9407ff11809 ("pds_core: Prevent health thread from running during reset/remove") stops the health thread with cancel_work_sync() before a reset, but a devcmd timeout during pdsc_fw_down() re-queues health_work, so pdsc_health_thread() runs again mid-reset and double allocates the core DMA queues via pdsc_fw_up().

Only the reset path is affected: on remove PDSC_S_STOPPING_DRIVER gates the health thread and the workqueue is destroyed.

Use disable_work_sync() to cancel health_work and block further queue_work() on it, and enable_work() in pdsc_restart_health_thread() to re-allow it after the reset.

disable_work_sync() keeps a disable depth, so every disable must be matched by one enable. pdsc_reset_prepare() stops the health thread and pdsc_reset_done() restarts it. On the AER path pdsc_pci_error_detected() calls pdsc_reset_prepare(), then pdsc_pci_error_resume() re-inits via pci_reset_function_locked() (pds_core has no .slot_reset handler), which runs the pair again - stopping the thread twice but restarting it once. Gate the disable and enable on a health_stopped flag so each fires at most once per stopped/running transition.

---
 drivers/net/ethernet/amd/pds_core/core.h |  1 +
 drivers/net/ethernet/amd/pds_core/main.c | 10 ++++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)
drivers/net/ethernet/amd/pds_core/core.h +1 -0
index 0b53a1fab46d0..e2a86ef581dfc 100644
@@ -171,6 +171,7 @@ struct pdsc {
 	struct timer_list wdtimer;
 	unsigned int wdtimer_period;
 	struct work_struct health_work;
+	bool health_stopped;
 	struct devlink_health_reporter *fw_reporter;
 	u32 fw_recoveries;
 
drivers/net/ethernet/amd/pds_core/main.c +8 -2
index a4962dba3140b..dad7fd03287db 100644
@@ -471,8 +471,10 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc)
 		return;
 
 	timer_shutdown_sync(&pdsc->wdtimer);
-	if (pdsc->health_work.func)
-		cancel_work_sync(&pdsc->health_work);
+	if (pdsc->health_work.func && !pdsc->health_stopped) {
+		disable_work_sync(&pdsc->health_work);
+		pdsc->health_stopped = true;
+	}
 }
 
 static void pdsc_restart_health_thread(struct pdsc *pdsc)
@@ -480,6 +482,10 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc)
 	if (pdsc->pdev->is_virtfn)
 		return;
 
+	if (pdsc->health_stopped) {
+		enable_work(&pdsc->health_work);
+		pdsc->health_stopped = false;
+	}
 	timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
 	mod_timer(&pdsc->wdtimer, jiffies + 1);
 }
Signature · 1 line
2.53.0
author maintainer
#37 lore raw

PATCH 37/250 pds_core: cancel pending PCI reset work on AER recovery

In reply to Greg Kroah-Hartman

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

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

From: Nikhil P. Rao <[email protected]>

[ Upstream commit 57d635329d799b79096155cdf47ee0013d6780d1 ]

pdsc_check_pci_health() queues pci_reset_work when it sees a broken PCI connection, and nothing cancels it. When the PCI core starts AER recovery, pdsc_pci_error_detected() runs pdsc_reset_prepare() and recovers the device, but a pci_reset_work queued just before is left pending. If it runs after recovery released the device lock, it resets a device the driver now considers healthy, bouncing the link for no reason.

Cancel pci_reset_work in pdsc_pci_error_detected() after pdsc_reset_prepare(), which has already stopped the health thread so it cannot requeue the work. cancel_work_sync() is safe under the device lock here because pdsc_pci_reset_thread() uses pci_try_reset_function(), which returns instead of blocking on the lock. Only PFs initialize pci_reset_work, so guard the cancel with !is_virtfn.

---
 drivers/net/ethernet/amd/pds_core/main.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/ethernet/amd/pds_core/main.c +4 -0
index dad7fd03287db..61be6def50b1c 100644
@@ -562,7 +562,11 @@ static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev,
 						pci_channel_state_t error)
 {
 	if (error == pci_channel_io_frozen) {
+		struct pdsc *pdsc = pci_get_drvdata(pdev);
+
 		pdsc_reset_prepare(pdev);
+		if (!pdev->is_virtfn)
+			cancel_work_sync(&pdsc->pci_reset_work);
 		return PCI_ERS_RESULT_NEED_RESET;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#38 lore raw

PATCH 38/250 netfilter: ipset: switch ext_size to atomic64_t

In reply to Greg Kroah-Hartman

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

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

From: Jozsef Kadlecsik <[email protected]>

[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]

The hash types do not acquire set->lock, they use 'region locking' where only part of the hash table is locked. Parallel inserts and deletes are possible and CPUs can race on ->ext_size update. Switch to atomic64_t.

This leaves another bug unresolved: there still can be a race on comment extension re-init. This will be handled in a later commit when converting to rhashtable backend.

Fixes f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
---
 include/linux/netfilter/ipset/ip_set.h  | 2 +-
 net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
 net/netfilter/ipset/ip_set_core.c       | 6 +++---
 net/netfilter/ipset/ip_set_hash_gen.h   | 2 +-
 net/netfilter/ipset/ip_set_list_set.c   | 4 ++--
 5 files changed, 9 insertions(+), 9 deletions(-)
include/linux/netfilter/ipset/ip_set.h +1 -1
index b98331572ad29..cadae9b2578f1 100644
@@ -273,7 +273,7 @@ struct ip_set {
 	/* Number of elements (vs timeout) */
 	u32 elements;
 	/* Size of the dynamic extensions (vs timeout) */
-	size_t ext_size;
+	atomic64_t ext_size;
 	/* Element data size */
 	size_t dsize;
 	/* Offsets to extensions in elements */
net/netfilter/ipset/ip_set_bitmap_gen.h +2 -2
index 798c7993635e6..d99e2e2e58559 100644
@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
 		mtype_ext_cleanup(set);
 	bitmap_zero(map->members, map->elements);
 	set->elements = 0;
-	set->ext_size = 0;
+	atomic64_set(&set->ext_size, 0);
 }
 
 /* Calculate the actual memory size of the set data */
@@ -93,7 +93,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 {
 	const struct mtype *map = set->data;
 	struct nlattr *nested;
-	size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
+	size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
 
 	nested = nla_nest_start(skb, IPSET_ATTR_DATA);
 	if (!nested)
net/netfilter/ipset/ip_set_core.c +3 -3
index f51a1af31513c..29bf5ee74fe36 100644
@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
 	size_t len = ext->comment ? strlen(ext->comment) : 0;
 
 	if (unlikely(c)) {
-		set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
+		atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
 		rcu_assign_pointer(comment->c, NULL);
 		kfree_rcu(c, rcu);
 	}
@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
 	if (unlikely(!c))
 		return;
 	strscpy(c->str, ext->comment, len + 1);
-	set->ext_size += sizeof(*c) + strlen(c->str) + 1;
+	atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
 	rcu_assign_pointer(comment->c, c);
 }
 EXPORT_SYMBOL_GPL(ip_set_init_comment);
@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
 	c = rcu_dereference_protected(comment->c, 1);
 	if (unlikely(!c))
 		return;
-	set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
+	atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
 	rcu_assign_pointer(comment->c, NULL);
 	kfree_rcu(c, rcu);
 }
net/netfilter/ipset/ip_set_hash_gen.h +1 -1
index 4c1082e38e3d1..81d7f601ed06a 100644
@@ -1289,7 +1289,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 	rcu_read_lock_bh();
 	t = rcu_dereference_bh(h->table);
 	mtype_ext_size(set, &elements, &ext_size);
-	memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
+	memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
 	htable_bits = t->htable_bits;
 	rcu_read_unlock_bh();
 
net/netfilter/ipset/ip_set_list_set.c +2 -2
index 34bb84d7b174c..7bb807b3c6282 100644
@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
 	list_for_each_entry_safe(e, n, &map->members, list)
 		list_set_del(set, e);
 	set->elements = 0;
-	set->ext_size = 0;
+	atomic64_set(&set->ext_size, 0);
 }
 
 static void
@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
 {
 	const struct list_set *map = set->data;
 	struct nlattr *nested;
-	size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
+	size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
 
 	nested = nla_nest_start(skb, IPSET_ATTR_DATA);
 	if (!nested)
Signature · 1 line
2.53.0
author maintainer
#39 lore raw

PATCH 39/250 ipvs: avoid out-of-bounds write in ip_vs_nat_icmp

In reply to Greg Kroah-Hartman

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

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

From: Julian Anastasov <[email protected]>

[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]

Sashiko warns that local attacker can modify the packet while it is processed by IPVS. Some places read the IP ihl field multiple times which can cause out-of-bounds access. One such place is ip_vs_nat_icmp where we can write after the validated area.

Fix it by providing ciph argument just like it is done for IPv6 and use ciph->len as offset to the embedded transport header.

Modify some IPv4 header checks by reading the ihl field only once.

---
 include/net/ip_vs.h             |  2 +-
 net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
 net/netfilter/ipvs/ip_vs_xmit.c |  2 +-
 3 files changed, 36 insertions(+), 35 deletions(-)
include/net/ip_vs.h +1 -1
index 17a97086b294f..cbad9c74a8868 100644
@@ -1720,7 +1720,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
 
 void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		    struct ip_vs_conn *cp, int dir, unsigned int toff,
-		    bool has_ports);
+		    bool has_ports, struct ip_vs_iphdr *ciph);
 
 #ifdef CONFIG_IP_VS_IPV6
 void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
net/netfilter/ipvs/ip_vs_core.c +34 -33

180 lines not on this page · raw message

net/netfilter/ipvs/ip_vs_xmit.c +1 -1
index ac1827ef78949..7db74b2ea358c 100644
@@ -1577,7 +1577,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error;
 
-	ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
+	ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->ignore_df = 1;
Signature · 1 line
2.53.0
author maintainer
#40 lore raw

PATCH 40/250 ipvs: return the csum validation for forward hook

In reply to Greg Kroah-Hartman

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

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

From: Julian Anastasov <[email protected]>

[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]

Sashiko notes that playing games with the skb dst and rt flags instead of providing hooknum is not a good idea when validating the checksums.

Also, skipping checksum validation for FORWARD packets risk silent data corruption, even if the only user is the FTP-CMD packets coming from the real server.

Sashiko also noticed that by using common checksum helper in the previous commit we actually fixed old bug where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE was not validated correctly.

---
 include/net/ip_vs.h                   | 19 +++++--------------
 net/netfilter/ipvs/ip_vs_proto_sctp.c |  2 +-
 2 files changed, 6 insertions(+), 15 deletions(-)
include/net/ip_vs.h +5 -14
index cbad9c74a8868..d63d6459727d6 100644
@@ -24,9 +24,7 @@
 #include <linux/netfilter.h>		/* for union nf_inet_addr */
 #include <linux/ip.h>
 #include <linux/ipv6.h>			/* for struct ipv6hdr */
-#include <net/route.h>
 #include <net/ipv6.h>
-#include <net/ip6_fib.h>
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
 #include <net/netfilter/nf_conntrack.h>
 #endif
@@ -1753,30 +1751,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
 	return csum_partial(diff, sizeof(diff), oldsum);
 }
 
-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
+static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
 {
 	/* Checksum unnecessary or already validated? */
 	if (skb_csum_unnecessary(skb))
 		return false;
-	/* LOCAL_OUT ? */
-	if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
+	/* Locally generated ? */
+	if (!skb->dev)
 		return false;
-	/* !LOCAL_IN (FORWARD) ? */
-	if (af == AF_INET6) {
-		if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
-			return false;
-	} else {
-		if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
-			return false;
-	}
 	return true;
 }
 
 static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
 					       int offset, int proto, int af)
 {
-	if (!ip_vs_checksum_needed(skb, af))
+	if (!ip_vs_checksum_needed(skb))
 		return true;
+	/* Validate csum even for FORWARD */
 	return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
 }
 
net/netfilter/ipvs/ip_vs_proto_sctp.c +1 -1
index 3dbd3096e1637..c80567c73469b 100644
@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 	struct sctphdr *sh;
 	__le32 cmp, val;
 
-	if (!ip_vs_checksum_needed(skb, af))
+	if (!ip_vs_checksum_needed(skb))
 		return 1;
 	sh = (struct sctphdr *)(skb->data + sctphoff);
 	cmp = sh->checksum;
Signature · 1 line
2.53.0
author maintainer
#41 lore raw

PATCH 41/250 watchdog: bd96801_wdt: Fix timeout for enabled WDG

In reply to Greg Kroah-Hartman

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

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

From: Matti Vaittinen <[email protected]>

[ Upstream commit 1246aa2b6ccc8944676bd24ff3e37cc56b93b51b ]

When watchdog is enabled at the probe time, the bd96801 driver retrieves the timeout configuration from the registers to set-up the heart-beat values.

As Sashiko pointed out at
https://lore.kernel.org/all/[email protected]/
the timeout values are incorrectly computed in driver, resulting wrong heartbeat. This leads to devere problems if watchdog was enabled at probe time.

According to the data-sheet, the "too fast" ping limit is configured as multiple of FASTNG_MIN. Furthermore, the "too slow" ping limit is configured as multiples of "too fast" timeout. The FASTNG_MIN is set to 11, meaning 1.1 mS and "too fast" and "too slow" limits are computed from this. Hence, converting the limits to mS should be done by dividing by 10, not by dividing by USEC_PER_MSEC.

Fix this by dividing the timeout values with correct scaling factor.

While at it, fix whitespace problem (double empty line).

Fixes 09dad69757b6 ("watchdog: ROHM BD96801 PMIC WDG driver")
[groeck: Added reference to whitespace change to description]
---
 drivers/watchdog/bd96801_wdt.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/watchdog/bd96801_wdt.c +2 -3
index 12b74fd2bc052..a25b7cf1488b2 100644
@@ -169,7 +169,6 @@ static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin,
 	int fastng, slowng, type, ret, reg, mask;
 	struct device *dev = w->dev;
 
-
 	if (hw_margin_min * 1000 > FASTNG_MAX_US) {
 		dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n",
 			hw_margin_min * 1000, FASTNG_MAX_US);
@@ -258,10 +257,10 @@ static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w,
 	fast = FASTNG_MIN << sel;
 
 	sel = (val & BD96801_WD_RATIO_MASK) + 1;
-	w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC;
+	w->wdt.max_hw_heartbeat_ms = (fast << sel) / 10;
 
 	if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN)
-		w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC;
+		w->wdt.min_hw_heartbeat_ms = fast / 10;
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#42 lore raw

PATCH 42/250 btrfs: fix memory leak in btrfs_do_encoded_write()

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Antipov <[email protected]>

[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]

Local fuzzing of 6.12.94 has found the following memory leak:

Unreferenced object 0xffff888018050a80 (size 64):
comm "syz.0.17", pid 10297, jiffies 4294953601 hex dump (first 32 bytes):

    00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00  ................
    10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff  ................
  backtrace (crc a8a6fc29):
    kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
    slab_post_alloc_hook mm/slub.c:4152 [inline]
    slab_alloc_node mm/slub.c:4197 [inline]
    __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
    kmalloc_noprof include/linux/slab.h:878 [inline]
    extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
    qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
    btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
    btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
    btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
    btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
    btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
    btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
    vfs_ioctl fs/ioctl.c:51 [inline]
    __do_sys_ioctl fs/ioctl.c:906 [inline]
    __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
    do_syscall_x64 arch/x86/entry/common.c:47 [inline]
    do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
    entry_SYSCALL_64_after_hwframe+0x77/0x7f

Unreferenced object 0xffff888018050a00 (size 64):
comm "syz.0.17", pid 10297, jiffies 4294953601 hex dump (first 32 bytes):

    00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00  ................
    90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff  ................
  backtrace (crc cb5c9580):
    kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
    slab_post_alloc_hook mm/slub.c:4152 [inline]
    slab_alloc_node mm/slub.c:4197 [inline]
    __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
    kmalloc_noprof include/linux/slab.h:878 [inline]
    kzalloc_noprof include/linux/slab.h:1014 [inline]
    ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
    extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
    __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
    set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
    qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
    btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
    btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
    btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
    btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
    btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
    btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
    vfs_ioctl fs/ioctl.c:51 [inline]
    __do_sys_ioctl fs/ioctl.c:906 [inline]
    __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
    do_syscall_x64 arch/x86/entry/common.c:47 [inline]
    do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
    entry_SYSCALL_64_after_hwframe+0x77/0x7f

Fix this by freeing an extent changeset before returning from btrfs_do_encoded_write().

Fixes 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
---
 fs/btrfs/inode.c | 1 +
 1 file changed, 1 insertion(+)
fs/btrfs/inode.c +1 -0
index 36f75c6a8344d..7af5ea0cf55fd 100644
@@ -10037,6 +10037,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
 	}
 	kvfree(folios);
 out:
+	extent_changeset_free(data_reserved);
 	if (ret >= 0)
 		iocb->ki_pos += encoded->len;
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#43 lore raw

PATCH 43/250 bpf: Preserve pointer state for commuted arithmetic

In reply to Greg Kroah-Hartman

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

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

From: Yiyang Chen <[email protected]>

[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]

When scalar += pointer is handled in adjust_ptr_min_max_vals(), the destination register inherits the pointer state from the source pointer. Copying only selected fields is fragile because pointer provenance is tracked by several bpf_reg_state fields.

Use the caller's temporary offset register to preserve the scalar operand while replacing the destination with the full pointer state. This preserves the frame number for PTR_TO_STACK registers and keeps parent identity fields consistent.

---
 kernel/bpf/verifier.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
kernel/bpf/verifier.c +8 -7
index 463455180a8e3..17c1ccff3ac20 100644
@@ -14734,11 +14734,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		return -EACCES;
 	}
 
-	/* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
-	 * The id may be overwritten later if we create a new variable offset.
+	/* For 'scalar += pointer', dst_reg inherits the complete pointer
+	 * register state. Individual fields may be adjusted later by pointer
+	 * arithmetic. Callers guarantee that below does not overwrite off_reg.
 	 */
-	dst_reg->type = ptr_reg->type;
-	dst_reg->id = ptr_reg->id;
+	if (dst_reg != ptr_reg)
+		*dst_reg = *ptr_reg;
 
 	if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
 	    !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
@@ -14800,7 +14801,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		}
 		break;
 	case BPF_SUB:
-		if (dst_reg == off_reg) {
+		if (dst_reg != ptr_reg) {
 			/* scalar -= pointer.  Creates an unknown scalar */
 			verbose(env, "R%d tried to subtract pointer from scalar\n",
 				dst);
@@ -15764,8 +15765,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
 				err = mark_chain_precision(env, insn->dst_reg);
 				if (err)
 					return err;
-				return adjust_ptr_min_max_vals(env, insn,
-							       src_reg, dst_reg);
+				off_reg = *dst_reg;
+				return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
 			}
 		} else if (ptr_reg) {
 			/* pointer += scalar */
Signature · 1 line
2.53.0
author maintainer
#44 lore raw

PATCH 44/250 bpf: split check_reg_sane_offset() in two parts

In reply to Greg Kroah-Hartman

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

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

From: Eduard Zingerman <[email protected]>

[ Upstream commit ed20a14309e09216d1fa86e12b1578fa822119b4 ]

check_reg_sane_offset() is used when verifying operations like:

dst_reg += src_reg
^ ^
| '-------- scalar
'------------------- pointer

To verify range for both dst_reg and src_reg. Split it in two parts:
- one to check a pointer offset
- another to check scalar offset

This would be useful for further refactoring.

Stable-dep-of: cdf19b1b3c01 ("bpf: Propagate untrusted pointer state in commuted arithmetic")

---
 kernel/bpf/verifier.c | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)
kernel/bpf/verifier.c +27 -12
index 17c1ccff3ac20..80710cb8421ef 100644
@@ -14291,9 +14291,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 	return 0;
 }
 
-static bool check_reg_sane_offset(struct bpf_verifier_env *env,
-				  const struct bpf_reg_state *reg,
-				  enum bpf_reg_type type)
+static bool check_reg_sane_offset_scalar(struct bpf_verifier_env *env,
+					 const struct bpf_reg_state *reg,
+					 enum bpf_reg_type type)
 {
 	bool known = tnum_is_const(reg->var_off);
 	s64 val = reg->var_off.value;
@@ -14305,12 +14305,6 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
 		return false;
 	}
 
-	if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
-		verbose(env, "%s pointer offset %d is not allowed\n",
-			reg_type_str(env, type), reg->off);
-		return false;
-	}
-
 	if (smin == S64_MIN) {
 		verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n",
 			reg_type_str(env, type));
@@ -14326,6 +14320,27 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
 	return true;
 }
 
+static bool check_reg_sane_offset_ptr(struct bpf_verifier_env *env,
+				      const struct bpf_reg_state *reg,
+				      enum bpf_reg_type type)
+{
+	s64 smin = reg->smin_value;
+
+	if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
+		verbose(env, "%s pointer offset %d is not allowed\n",
+			reg_type_str(env, type), reg->off);
+		return false;
+	}
+
+	if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) {
+		verbose(env, "%s pointer offset %lld is not allowed\n",
+			reg_type_str(env, type), smin);
+		return false;
+	}
+
+	return true;
+}
+
 enum {
 	REASON_BOUNDS	= -1,
 	REASON_TYPE	= -2,
@@ -14741,8 +14756,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 	if (dst_reg != ptr_reg)
 		*dst_reg = *ptr_reg;
 
-	if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
-	    !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+	if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
+	    !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
 		return -EINVAL;
 
 	/* pointer types do not carry 32-bit bounds at the moment. */
@@ -14871,7 +14886,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		return -EACCES;
 	}
 
-	if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
+	if (!check_reg_sane_offset_ptr(env, dst_reg, ptr_reg->type))
 		return -EINVAL;
 	reg_bounds_sync(dst_reg);
 	bounds_ret = sanitize_check_bounds(env, insn, dst_reg);
Signature · 1 line
2.53.0
author maintainer
#45 lore raw

PATCH 45/250 bpf: Propagate untrusted pointer state in commuted arithmetic

In reply to Greg Kroah-Hartman

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

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

From: Yiyang Chen <[email protected]>

[ Upstream commit cdf19b1b3c01791de074ce282089131026f52261 ]

The untrusted PTR_TO_MEM early return skips pointer offset tracking because accesses go through probe-read handling. Moving it after full pointer-state propagation ensures scalar += untrusted_pointer leaves the destination as PTR_TO_MEM instead of an unrelated scalar.

---
 kernel/bpf/verifier.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/bpf/verifier.c +7 -7
index 80710cb8421ef..459ed144542cc 100644
@@ -14713,13 +14713,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		return -EACCES;
 	}
 
-	/*
-	 * Accesses to untrusted PTR_TO_MEM are done through probe
-	 * instructions, hence no need to track offsets.
-	 */
-	if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
-		return 0;
-
 	switch (base_type(ptr_reg->type)) {
 	case PTR_TO_CTX:
 	case PTR_TO_MAP_VALUE:
@@ -14756,6 +14749,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 	if (dst_reg != ptr_reg)
 		*dst_reg = *ptr_reg;
 
+	/*
+	 * Accesses to untrusted PTR_TO_MEM are done through probe
+	 * instructions, hence no need to track offsets.
+	 */
+	if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
+		return 0;
+
 	if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
 	    !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#46 lore raw

PATCH 46/250 net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in smc_llc_event_handler()

In reply to Greg Kroah-Hartman

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

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

From: Mahanta Jambigi <[email protected]>

[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]

The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in smc_llc_event_handler() stores an incoming qentry into the local LLC flow without first checking whether a qentry is already pending. If a malicious or buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the pointer without freeing the previous allocation, leaking one kmalloc-96 object per spurious message.

The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a duplicate message when qentry is already occupied falls through to break and is freed by the kfree(qentry) at the out: label, rather than silently leaking the existing allocation.

The response direction (smc_llc_rx_response()) is unaffected: it already guards with flow->qentry at the equivalent site and drops duplicate responses correctly.

---
 net/smc/smc_llc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/smc/smc_llc.c +2 -1
index f865c58c3aa77..28873ec06e3c1 100644
@@ -1927,7 +1927,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
 		return;
 	case SMC_LLC_CONFIRM_LINK:
 	case SMC_LLC_ADD_LINK_CONT:
-		if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
+		if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
+		    !lgr->llc_flow_lcl.qentry) {
 			/* a flow is waiting for this message */
 			smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
 			wake_up(&lgr->llc_msg_waiter);
Signature · 1 line
2.53.0
author maintainer
#47 lore raw

PATCH 47/250 net/sched: cls_route: fix fastmap use-after-free on filter

In reply to Greg Kroah-Hartman

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

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

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]

The route4 classifier maintains a 16-slot fastmap cache that stores raw struct route4_filter pointers indexed by (id, iif). The reader (route4_classify) populates this cache via route4_set_fastmap() for every classified packet that hits a filter. The writer (route4_delete, route4_change) clears the cache via route4_reset_fastmap() before RCU-deferred kfree of the filter.

This creates a UAF race:
1. Reader walks the RCU-protected bucket chain, finds filter f
2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
3. Reader calls route4_set_fastmap() and writes f into the cache *after* the writer's reset, caching a pointer about to be freed
4. After the RCU grace period, kfree(f) executes
5. Next classified packet on the same (id, iif) tuple hits the stale

    fastmap entry and reads f->res from freed memory

Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a concurrent add/delete stress test (provided by both zdi and Santosh). Both triggered KASAN slab-use-after-free reports in the route4 fastmap paths.

Fix:
Introduce a per-filter boolean dying flag to suppress stale fastmap republishing by in-flight readers.

---
 net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)
net/sched/cls_route.c +26 -9
index b9c58c040c305..38469cdcb22d6 100644
@@ -52,6 +52,7 @@ struct route4_filter {
 	struct tcf_result	res;
 	struct tcf_exts		exts;
 	u32			handle;
+	bool			dying;
 	struct route4_bucket	*bkt;
 	struct tcf_proto	*tp;
 	struct rcu_work		rwork;
@@ -66,9 +67,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
 
 static DEFINE_SPINLOCK(fastmap_lock);
 static void
-route4_reset_fastmap(struct route4_head *head)
+route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
 {
 	spin_lock_bh(&fastmap_lock);
+	if (f)
+		f->dying = true;
 	memset(head->fastmap, 0, sizeof(head->fastmap));
 	spin_unlock_bh(&fastmap_lock);
 }
@@ -81,9 +84,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
 
 	/* fastmap updates must look atomic to aling id, iff, filter */
 	spin_lock_bh(&fastmap_lock);
-	head->fastmap[h].id = id;
-	head->fastmap[h].iif = iif;
-	head->fastmap[h].filter = f;
+	if (f == ROUTE4_FAILURE || !f->dying) {
+		head->fastmap[h].id = id;
+		head->fastmap[h].iif = iif;
+		head->fastmap[h].filter = f;
+	}
 	spin_unlock_bh(&fastmap_lock);
 }
 
@@ -297,6 +302,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
 					next = rtnl_dereference(f->next);
 					RCU_INIT_POINTER(b->ht[h2], next);
 					tcf_unbind_filter(tp, &f->res);
+					/* Mark the filter dying under fastmap_lock so
+					 * any in-flight reader that still holds it
+					 * will skip the republish in route4_set_fastmap().
+					 */
+					spin_lock_bh(&fastmap_lock);
+					f->dying = true;
+					spin_unlock_bh(&fastmap_lock);
 					if (tcf_exts_get_net(&f->exts))
 						route4_queue_work(f);
 					else
@@ -307,6 +319,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
 			kfree_rcu(b, rcu);
 		}
 	}
+
+	/* All filters are unlinked and marked dying, so no in-flight
+	 * reader can republish a stale entry after this reset.
+	 */
+	route4_reset_fastmap(head, NULL);
 	kfree_rcu(head, rcu);
 }
 
@@ -334,11 +351,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
 			/* unlink it */
 			RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
 
-			/* Remove any fastmap lookups that might ref filter
-			 * notice we unlink'd the filter so we can't get it
-			 * back in the fastmap.
+			/* Clear any fastmap entries that may ref this filter and
+			 * mark it dying so in-flight readers can't republish it
+			 * after the reset.
 			 */
-			route4_reset_fastmap(head);
+			route4_reset_fastmap(head, f);
 
 			/* Delete it */
 			tcf_unbind_filter(tp, &f->res);
@@ -558,7 +575,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
 		}
 	}
 
-	route4_reset_fastmap(head);
+	route4_reset_fastmap(head, fold);
 	*arg = f;
 	if (fold) {
 		tcf_unbind_filter(tp, &fold->res);
Signature · 1 line
2.53.0
author maintainer
#48 lore raw

PATCH 48/250 net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete

In reply to Greg Kroah-Hartman

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

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

From: Jiawen Liu <[email protected]>

[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]

hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev(). This is not needed because free_netdev() deletes all NAPI instances attached to the net_device.

Remove the redundant call and let the networking core tear down the NAPI instance during unregister_netdev(). The probe error path still keeps its explicit netif_napi_del(), because the device has not been registered there.

Fixes 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
---
 drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
 1 file changed, 1 deletion(-)
drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +0 -1
index e3e7f2270560c..02282dc86faf4 100644
@@ -1282,7 +1282,6 @@ static void hix5hd2_dev_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct hix5hd2_priv *priv = netdev_priv(ndev);
 
-	netif_napi_del(&priv->napi);
 	unregister_netdev(ndev);
 	mdiobus_unregister(priv->bus);
 	mdiobus_free(priv->bus);
Signature · 1 line
2.53.0
author maintainer
#49 lore raw

PATCH 49/250 devlink: fix net namespace reference leak in reload

In reply to Greg Kroah-Hartman

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

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

From: Or Har-Toov <[email protected]>

[ Upstream commit 1c4dac9bf1d2ac31da63b794bdec697777cbd0fd ]

devlink_nl_reload_doit() calls devlink_netns_get(), which returns a net with a held reference. When the requested namespace differs from the current one and the reload action is not DRIVER_REINIT, the function returns -EOPNOTSUPP without releasing the reference. Add the missing put_net() on this error path.

Fixes 2edd92570441 ("devlink: don't allow to change net namespace for FW_ACTIVATE reload action")
---
 net/devlink/dev.c | 1 +
 1 file changed, 1 insertion(+)
net/devlink/dev.c +1 -0
index 02602704bdeaa..ed442c1bed8db 100644
@@ -577,6 +577,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
 		    action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
 			NL_SET_ERR_MSG_MOD(info->extack,
 					   "Changing namespace is only supported for reinit action");
+			put_net(dest_net);
 			return -EOPNOTSUPP;
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#50 lore raw

PATCH 50/250 net/mlx5: fw_tracer, return NULL on create error

In reply to Greg Kroah-Hartman

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

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

From: Michael Guralnik <[email protected]>

[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]

Tracer creation can fail by returning either NULL or ERR_PTR. The return value is stored without a check on the device, and users treat ERR_PTR and NULL the same way.
This also causes a crash in the core dump logic, which is missing the ERR_PTR check and ends up dereferencing it, as shown in the trace below.

Switch tracer creation to return NULL on failure only, so callers only need a single NULL check.

  Internal error: Oops: 0000000096000006 [#1]  SMP
  Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
  CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
  Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
  pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
  pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
  lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
  sp : ffff800081cf3c40
  x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
  x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
  x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
  x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
  x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
  x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
  x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
  x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
  x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
  x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
  Call trace:
   mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
   mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
   devlink_health_do_dump+0x9c/0x160
   devlink_health_report+0x1c0/0x288
   mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
   process_one_work+0x15c/0x3d8
   worker_thread+0x18c/0x320
   kthread+0x148/0x228
   ret_from_fork+0x10/0x20
  Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
  ---[ end trace 0000000000000000 ]---
  Kernel panic - not syncing: Oops: Fatal exception
  SMP: stopping secondary CPUs
  Kernel Offset: disabled
  CPU features: 0x000000,00078031,75fce5a1,35fffe67
  Memory Limit: none
  ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
---
 .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +7 -9
index 0b82a6a133d6c..74f68b70ad1c1 100644
@@ -1025,13 +1025,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
 
 	tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
 	if (!tracer)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
-	if (!tracer->work_queue) {
-		err = -ENOMEM;
+	if (!tracer->work_queue)
 		goto free_tracer;
-	}
 
 	tracer->dev = dev;
 
@@ -1073,7 +1071,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
 	destroy_workqueue(tracer->work_queue);
 free_tracer:
 	kvfree(tracer);
-	return ERR_PTR(err);
+	return NULL;
 }
 
 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
@@ -1084,7 +1082,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 	struct mlx5_core_dev *dev;
 	int err;
 
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return 0;
 
 	if (!tracer->str_db.loaded)
@@ -1134,7 +1132,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 /* Stop tracer + Cleanup HW resources */
 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 {
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return;
 
 	mutex_lock(&tracer->state_lock);
@@ -1163,7 +1161,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 /* Free software resources (Buffers, etc ..) */
 void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
 {
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return;
 
 	mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
@@ -1215,7 +1213,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
 	struct mlx5_core_dev *dev;
 	int err;
 
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return 0;
 
 	dev = tracer->dev;
Signature · 1 line
2.53.0
author maintainer
#51 lore raw

PATCH 51/250 counter: microchip-tcb-capture: Fix DT channel validation

In reply to Greg Kroah-Hartman

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

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

From: Babanpreet Singh <[email protected]>

[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]

mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API contract of of_property_read_u32_index() - into a signed int, so the bounds check "channel > 2" fails to reject cell values at or above 0x80000000: reinterpreted as a negative int, they compare below 2 and pass validation.

A malformed devicetree can therefore drive a negative channel into the ATMEL_TC_REG() offset arithmetic, making the driver access syscon regmap offsets outside the TC block's register window, and into the "t%d_clk" clock-name formatting, where it truncates clk_name (sized for "t0_clk".."t2_clk").

Declare channel as u32, matching the API contract; the unsigned comparison then rejects everything except channels 0..2. Adjust the format specifier to %u accordingly, which also resolves the W=1 warning that exposed the gap:

microchip-tcb-capture.c:520:56: warning: '%d' directive output may
be truncated writing between 1 and 11 bytes into a region of size 6 [-Wformat-truncation=]
note: directive argument in the range [-2147483648, 2]

No behavior change for well-formed devicetrees: channels 0..2 take identical paths before and after.

Fixes 106b104137fd ("counter: Add microchip TCB capture counter")
Assisted-by Claude:claude-fable-5 [gcc W=1]
---
 drivers/counter/microchip-tcb-capture.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/counter/microchip-tcb-capture.c +2 -2
index 19d457ae4c3bb..e53a8390756b7 100644
@@ -483,7 +483,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
 	char clk_name[7];
 	struct regmap *regmap;
 	struct clk *clk[3];
-	int channel;
+	u32 channel;
 	int ret, i;
 
 	counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
@@ -517,7 +517,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
 
 		priv->channel[i] = channel;
 
-		snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
+		snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
 
 		clk[i] = of_clk_get_by_name(np->parent, clk_name);
 		if (IS_ERR(clk[i])) {
Signature · 1 line
2.53.0
author maintainer
#52 lore raw

PATCH 52/250 bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]

reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto the ehash chain, drops the bucket lock, and only afterwards sets rsk_refcnt to 3.

Lockless readers such as __inet_lookup_established() handle this with refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain sock_hold() while holding the bucket lock, on the assumption that the lock guarantees sk_refcnt > 0. That assumption does not hold for request_sock:

CPU 0 CPU 1
----- -----
tcp_conn_request()
reqsk_queue_hash_req()

    inet_ehash_insert(req)
     spin_lock(bucket)
     __sk_nulls_add_node_rcu(req)      // rsk_refcnt == 0
     spin_unlock(bucket)
                                       bpf_iter_tcp_established_batch()
                                        spin_lock(bucket)
                                        sock_hold(req)   <-- addition on 0
                                        spin_unlock(bucket)
    refcount_set(&req->rsk_refcnt, 3)  // clobbers saturated value

which surfaces as:

refcount_t: addition on 0; use-after-free.

  WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
  Call Trace:
   bpf_iter_tcp_established_batch+0x14e/0x170
   bpf_iter_tcp_batch+0x53/0x200
   bpf_iter_tcp_seq_next+0x27/0x70
   bpf_seq_read+0x107/0x410
   vfs_read+0xb9/0x380

The iterator's stolen reference is lost when the publishing CPU's refcount_set() overwrites the count, leaving the socket one reference short. When the last legitimate owner drops its reference the reqsk is freed while still reachable, leading to use-after-free.

This reproduces in seconds with tcp_syncookies=0, a handful of threads doing connect()/close() to a local listener while others read an iter/tcp link in a tight loop.

Use refcount_inc_not_zero() and skip the socket on failure. A skipped socket is still part of the bucket, so keep counting it in expected. The reallocations are sized from expected, and a request sock whose refcount gets published while the lock is held across the last realloc must already have room.

A skipped socket is counted in expected but never batched, so end_sk can be short of expected on a batch that is actually complete. Decide completeness by whether the walk left any socket behind instead. The WARN after the locked realloc checks the same, replacing an end_sk == expected check that could not hold on that path since commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always contains a full bucket snapshot").

If every matching socket in a bucket is mid-init (refcount 0), end_sk stays 0. Advance to the next bucket rather than returning a batch entry that was never filled this round.

Fixes 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
Assisted-by Claude:unspecified
---
 net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
 1 file changed, 24 insertions(+), 19 deletions(-)
net/ipv4/tcp_ipv4.c +24 -19
index 3463e5b964a98..708b69cc2f56c 100644
@@ -3219,24 +3219,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
 {
 	struct bpf_tcp_iter_state *iter = seq->private;
 	struct hlist_nulls_node *node;
-	unsigned int expected = 1;
-	struct sock *sk;
-
-	sock_hold(*start_sk);
-	iter->batch[iter->end_sk++].sk = *start_sk;
+	struct sock *sk = *start_sk;
+	unsigned int expected = 0;
 
-	sk = sk_nulls_next(*start_sk);
 	*start_sk = NULL;
 	sk_nulls_for_each_from(sk, node) {
-		if (seq_sk_match(seq, sk)) {
-			if (iter->end_sk < iter->max_sk) {
-				sock_hold(sk);
-				iter->batch[iter->end_sk++].sk = sk;
-			} else if (!*start_sk) {
-				/* Remember where we left off. */
-				*start_sk = sk;
-			}
-			expected++;
+		if (!seq_sk_match(seq, sk))
+			continue;
+		expected++;
+		if (iter->end_sk < iter->max_sk) {
+			/* reqsk_queue_hash_req() inserts with sk_refcnt == 0
+			 * and refcount_set()s it after the bucket lock drops.
+			 */
+			if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
+				continue;
+			iter->batch[iter->end_sk++].sk = sk;
+		} else if (!*start_sk) {
+			/* Remember where we left off. */
+			*start_sk = sk;
 		}
 	}
 
@@ -3274,12 +3274,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
 	struct sock *sk;
 	int err;
 
+again:
 	sk = bpf_iter_tcp_resume(seq);
 	if (!sk)
 		return NULL; /* Done */
 
 	expected = bpf_iter_fill_batch(seq, &sk);
-	if (likely(iter->end_sk == expected))
+	if (likely(!sk))
 		goto done;
 
 	/* Batch size was too small. */
@@ -3298,7 +3299,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
 		return NULL; /* Done */
 
 	expected = bpf_iter_fill_batch(seq, &sk);
-	if (likely(iter->end_sk == expected))
+	if (likely(!sk))
 		goto done;
 
 	/* Batch size was still too small. Hold onto the lock while we try
@@ -3311,10 +3312,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
 		return ERR_PTR(err);
 	}
 
-	expected = bpf_iter_fill_batch(seq, &sk);
-	WARN_ON_ONCE(iter->end_sk != expected);
+	bpf_iter_fill_batch(seq, &sk);
+	WARN_ON_ONCE(sk);
 done:
 	bpf_iter_tcp_unlock_bucket(seq);
+	if (unlikely(!iter->end_sk)) {
+		++iter->state.bucket;
+		goto again;
+	}
 	return iter->batch[0].sk;
 }
 
Signature · 1 line
2.53.0
author maintainer
#53 lore raw

PATCH 53/250 vhost/vdpa: reject overflowing PA map page counts on 32-bit

In reply to Greg Kroah-Hartman

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

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

From: Yousef Alhouseen <[email protected]>

[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]

vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map size before computing the number of pages to pin. On 32-bit systems, where unsigned long is narrower than u64, that addition can overflow and the code can pin and map fewer pages than the requested IOTLB range.

Reject sizes that overflow the unsigned long page-count calculation.

Fixes 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")

Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>

---
 drivers/vhost/vdpa.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/vhost/vdpa.c +8 -1
index a6c6c28bf2d9d..4c988f30a55c3 100644
@@ -1100,6 +1100,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
 	unsigned int gup_flags = FOLL_LONGTERM;
 	unsigned long npages, cur_base, map_pfn, last_pfn = 0;
 	unsigned long lock_limit, sz2pin, nchunks, i;
+	unsigned long page_offset;
 	u64 start = iova;
 	long pinned;
 	int ret = 0;
@@ -1112,7 +1113,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
 	if (perm & VHOST_ACCESS_WO)
 		gup_flags |= FOLL_WRITE;
 
-	npages = PFN_UP(size + (iova & ~PAGE_MASK));
+	page_offset = iova & ~PAGE_MASK;
+	if (size > ULONG_MAX - page_offset) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	npages = PFN_UP(size + page_offset);
 	if (!npages) {
 		ret = -EINVAL;
 		goto free;
Signature · 1 line
2.53.0
author maintainer
#54 lore raw

PATCH 54/250 vdpa/mlx5: Fix buffer length in create_direct_keys()

In reply to Greg Kroah-Hartman

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

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

From: Christian Borntraeger <[email protected]>

[ Upstream commit 727e1f569855df83579edbd73dcb4a0723543a12 ]

We have seen in our CI the following KASAN message:

BUG: KASAN: slab-out-of-bounds in cmd_exec+0x550/0xca0 [mlx5_core]
Read of size 272 at addr 0000000176795020 by task qemu-system-s39/82764
[...]
[<000011388ab3a7a0>] cmd_exec+0x550/0xca0 [mlx5_core]
[<000011388ab3b61c>] mlx5_cmd_exec_cb+0x25c/0x4f0 [mlx5_core]
[<000011388b21e82e>] mlx5_vdpa_exec_async_cmds+0x22e/0x5e0 [mlx5_vdpa]
[<000011388b21fd44>] create_direct_keys+0x954/0xef0 [mlx5_vdpa]

[...]
The buggy address is located 4128 bytes inside of allocated 4384-byte region [0000000176794000, 0000000176795120)

So in essence we read 16 bytes beyond 4384-byte allocation. create_direct_keys calculates the pointer and length for in and out buffers.
The size calculation for in includes the entire structure size (out + in + mtt[]) but the pointer passed to cmd_exec points only to the 'in' field, skipping the 'out' field.

This causes mlx5_copy_to_msg() to read beyond the allocated buffer by sizeof(out) bytes when copying command data.

Properly calculate the input size to match the pointer and allocation size.

Fixes 0071b138d44a ("vdpa/mlx5: Create direct MKEYs in parallel")

Message-ID: <[email protected]>

---
 drivers/vdpa/mlx5/core/mr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/vdpa/mlx5/core/mr.c +2 -1
index 8870a7169267e..2450440dae2e1 100644
@@ -234,7 +234,8 @@ static int create_direct_keys(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *
 		cmds[i].out = cmd_mem->out;
 		cmds[i].outlen = sizeof(cmd_mem->out);
 		cmds[i].in = cmd_mem->in;
-		cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount);
+		cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount) -
+				offsetof(struct mlx5_create_mkey_mem, in);
 
 		fill_create_direct_mr(mvdev, dmr, cmd_mem);
 
Signature · 1 line
2.53.0
author maintainer
#55 lore raw

PATCH 55/250 hwmon: (pmbus_core) Use guard() for mutex protection

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit bd1c178affd7d1ca86eaf97cf797e0d15e57eb0a ]

Simplify the code by using guard() and scoped_guard() instead of mutex_lock()/mutex_unlock() sequences.

This patch changes semantics for debugfs accesses. Previously, those used mutex_lock_interruptible() and not mutex_lock(). This change is intentional and should have little if any impact since locks should not be held for a significant amount of time and debugfs accesses are less critical than sysfs accesses (which never used interruptable locks).

Stable-dep-of: 59bd68ab05a8 ("hwmon: (pmbus) Fix type confusion in notification logic")

---
 drivers/hwmon/pmbus/pmbus_core.c | 277 ++++++++++++-------------------
 1 file changed, 107 insertions(+), 170 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +107 -170
index c9e3ec4552efd..a95ffd563018d 100644
@@ -1156,12 +1156,11 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
 	int ret, status;
 	u16 regval;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	status = pmbus_get_status(client, page, reg);
-	if (status < 0) {
-		ret = status;
-		goto unlock;
-	}
+	if (status < 0)
+		return status;
 
 	if (s1)
 		pmbus_update_sensor_data(client, s1);
@@ -1173,7 +1172,7 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
 		if (data->revision >= PMBUS_REV_12) {
 			ret = _pmbus_write_byte_data(client, page, reg, regval);
 			if (ret)
-				goto unlock;
+				return ret;
 		} else {
 			pmbus_clear_fault_page(client, page);
 		}
@@ -1181,14 +1180,10 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
 	if (s1 && s2) {
 		s64 v1, v2;
 
-		if (s1->data < 0) {
-			ret = s1->data;
-			goto unlock;
-		}
-		if (s2->data < 0) {
-			ret = s2->data;
-			goto unlock;
-		}
+		if (s1->data < 0)
+			return s1->data;
+		if (s2->data < 0)
+			return s2->data;
 
 		v1 = pmbus_reg2data(data, s1);
 		v2 = pmbus_reg2data(data, s2);
@@ -1196,8 +1191,6 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
 	} else {
 		ret = !!regval;
 	}
-unlock:
-	mutex_unlock(&data->update_lock);
 	return ret;
 }
 
@@ -1227,16 +1220,16 @@ static ssize_t pmbus_show_sensor(struct device *dev,
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
 	struct pmbus_data *data = i2c_get_clientdata(client);
-	ssize_t ret;
+	s64 val;
 
-	mutex_lock(&data->update_lock);
-	pmbus_update_sensor_data(client, sensor);
-	if (sensor->data < 0)
-		ret = sensor->data;
-	else
-		ret = sysfs_emit(buf, "%lld\n", pmbus_reg2data(data, sensor));
-	mutex_unlock(&data->update_lock);
-	return ret;
+	scoped_guard(pmbus_lock, client) {
+		pmbus_update_sensor_data(client, sensor);
+		if (sensor->data < 0)
+			return sensor->data;
+		val = pmbus_reg2data(data, sensor);
+	}
+
+	return sysfs_emit(buf, "%lld\n", val);
 }
 
 static ssize_t pmbus_set_sensor(struct device *dev,
@@ -1246,7 +1239,6 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
-	ssize_t rv = count;
 	s64 val;
 	int ret;
 	u16 regval;
@@ -1254,15 +1246,15 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 	if (kstrtos64(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	regval = pmbus_data2reg(data, sensor, val);
 	ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
 	if (ret < 0)
-		rv = ret;
-	else
-		sensor->data = -ENODATA;
-	mutex_unlock(&data->update_lock);
-	return rv;
+		return ret;
+
+	sensor->data = -ENODATA;
+	return count;
 }
 
 static ssize_t pmbus_show_label(struct device *dev,
@@ -1364,7 +1356,7 @@ static int pmbus_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 	struct pmbus_data *pmbus_data = tdata->pmbus_data;
 	struct i2c_client *client = to_i2c_client(pmbus_data->dev);
 	struct device *dev = pmbus_data->hwmon_dev;
-	int ret = 0;
+	int _temp;
 
 	if (!dev) {
 		/* May not even get to hwmon yet */
@@ -1372,15 +1364,15 @@ static int pmbus_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 		return 0;
 	}
 
-	mutex_lock(&pmbus_data->update_lock);
-	pmbus_update_sensor_data(client, sensor);
-	if (sensor->data < 0)
-		ret = sensor->data;
-	else
-		*temp = (int)pmbus_reg2data(pmbus_data, sensor);
-	mutex_unlock(&pmbus_data->update_lock);
+	scoped_guard(pmbus_lock, client) {
+		pmbus_update_sensor_data(client, sensor);
+		if (sensor->data < 0)
+			return sensor->data;
+		_temp = (int)pmbus_reg2data(pmbus_data, sensor);
+	}
 
-	return ret;
+	*temp = _temp;
+	return 0;
 }
 
 static const struct thermal_zone_device_ops pmbus_thermal_ops = {
@@ -2412,13 +2404,12 @@ static ssize_t pmbus_show_samples(struct device *dev,
 	int val;
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_samples_reg *reg = to_samples_reg(devattr);
-	struct pmbus_data *data = i2c_get_clientdata(client);
 
-	mutex_lock(&data->update_lock);
-	val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
-	mutex_unlock(&data->update_lock);
-	if (val < 0)
-		return val;
+	scoped_guard(pmbus_lock, client) {
+		val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
+		if (val < 0)
+			return val;
+	}
 
 	return sysfs_emit(buf, "%d\n", val);
 }
@@ -2431,14 +2422,13 @@ static ssize_t pmbus_set_samples(struct device *dev,
 	long val;
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_samples_reg *reg = to_samples_reg(devattr);
-	struct pmbus_data *data = i2c_get_clientdata(client);
 
 	if (kstrtol(buf, 0, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val);
-	mutex_unlock(&data->update_lock);
 
 	return ret ? : count;
 }
@@ -2950,14 +2940,9 @@ static int _pmbus_is_enabled(struct i2c_client *client, u8 page)
 
 static int __maybe_unused pmbus_is_enabled(struct i2c_client *client, u8 page)
 {
-	struct pmbus_data *data = i2c_get_clientdata(client);
-	int ret;
+	guard(pmbus_lock)(client);
 
-	mutex_lock(&data->update_lock);
-	ret = _pmbus_is_enabled(client, page);
-	mutex_unlock(&data->update_lock);
-
-	return ret;
+	return _pmbus_is_enabled(client, page);
 }
 
 #define to_dev_attr(_dev_attr) \
@@ -2988,14 +2973,13 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
 	}
 }
 
-static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
+static int _pmbus_get_flags(struct i2c_client *client, u8 page, unsigned int *flags,
 			    unsigned int *event, bool notify)
 {
+	struct pmbus_data *data = i2c_get_clientdata(client);
 	int i, status;
 	const struct pmbus_status_category *cat;
 	const struct pmbus_status_assoc *bit;
-	struct device *dev = data->dev;
-	struct i2c_client *client = to_i2c_client(dev);
 	int func = data->info->func[page];
 
 	*flags = 0;
@@ -3071,16 +3055,12 @@ static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flag
 	return 0;
 }
 
-static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
+static int __maybe_unused pmbus_get_flags(struct i2c_client *client, u8 page, unsigned int *flags,
 					  unsigned int *event, bool notify)
 {
-	int ret;
-
-	mutex_lock(&data->update_lock);
-	ret = _pmbus_get_flags(data, page, flags, event, notify);
-	mutex_unlock(&data->update_lock);
+	guard(pmbus_lock)(client);
 
-	return ret;
+	return _pmbus_get_flags(client, page, flags, event, notify);
 }
 
 #if IS_ENABLED(CONFIG_REGULATOR)
@@ -3096,17 +3076,13 @@ static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
 {
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
 	u8 page = rdev_get_id(rdev);
-	int ret;
 
-	mutex_lock(&data->update_lock);
-	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
-				     PB_OPERATION_CONTROL_ON,
-				     enable ? PB_OPERATION_CONTROL_ON : 0);
-	mutex_unlock(&data->update_lock);
+	guard(pmbus_lock)(client);
 
-	return ret;
+	return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+				      PB_OPERATION_CONTROL_ON,
+				      enable ? PB_OPERATION_CONTROL_ON : 0);
 }
 
 static int pmbus_regulator_enable(struct regulator_dev *rdev)
@@ -3123,54 +3099,41 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 {
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
 	int event;
 
-	return pmbus_get_flags(data, rdev_get_id(rdev), flags, &event, false);
+	return pmbus_get_flags(client, rdev_get_id(rdev), flags, &event, false);
 }
 
 static int pmbus_regulator_get_status(struct regulator_dev *rdev)
 {
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
 	u8 page = rdev_get_id(rdev);
 	int status, ret;
 	int event;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	status = pmbus_get_status(client, page, PMBUS_STATUS_WORD);
-	if (status < 0) {
-		ret = status;
-		goto unlock;
-	}
+	if (status < 0)
+		return status;
 
-	if (status & PB_STATUS_OFF) {
-		ret = REGULATOR_STATUS_OFF;
-		goto unlock;
-	}
+	if (status & PB_STATUS_OFF)
+		return REGULATOR_STATUS_OFF;
 
 	/* If regulator is ON & reports power good then return ON */
-	if (!(status & PB_STATUS_POWER_GOOD_N)) {
-		ret = REGULATOR_STATUS_ON;
-		goto unlock;
-	}
+	if (!(status & PB_STATUS_POWER_GOOD_N))
+		return REGULATOR_STATUS_ON;
 
-	ret = _pmbus_get_flags(data, rdev_get_id(rdev), &status, &event, false);
+	ret = _pmbus_get_flags(client, rdev_get_id(rdev), &status, &event, false);
 	if (ret)
-		goto unlock;
+		return ret;
 
 	if (status & (REGULATOR_ERROR_UNDER_VOLTAGE | REGULATOR_ERROR_OVER_CURRENT |
-	   REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP)) {
-		ret = REGULATOR_STATUS_ERROR;
-		goto unlock;
-	}
-
-	ret = REGULATOR_STATUS_UNDEFINED;
+	   REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP))
+		return REGULATOR_STATUS_ERROR;
 
-unlock:
-	mutex_unlock(&data->update_lock);
-	return ret;
+	return REGULATOR_STATUS_UNDEFINED;
 }
 
 static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
@@ -3235,19 +3198,16 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
 		.class = PSC_VOLTAGE_OUT,
 		.convert = true,
 	};
-	int ret;
+	int voltage;
 
-	mutex_lock(&data->update_lock);
-	s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
-	if (s.data < 0) {
-		ret = s.data;
-		goto unlock;
+	scoped_guard(pmbus_lock, client) {
+		s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
+		if (s.data < 0)
+			return s.data;
+		voltage = (int)pmbus_reg2data(data, &s);
 	}
 
-	ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
-unlock:
-	mutex_unlock(&data->update_lock);
-	return ret;
+	return voltage * 1000; /* unit is uV */
 }
 
 static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
@@ -3264,22 +3224,18 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
 	};
 	int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
 	int low, high;
-	int ret;
 
 	*selector = 0;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	low = pmbus_regulator_get_low_margin(client, s.page);
-	if (low < 0) {
-		ret = low;
-		goto unlock;
-	}
+	if (low < 0)
+		return low;
 
 	high = pmbus_regulator_get_high_margin(client, s.page);
-	if (high < 0) {
-		ret = high;
-		goto unlock;
-	}
+	if (high < 0)
+		return high;
 
 	/* Make sure we are within margins */
 	if (low > val)
@@ -3289,10 +3245,7 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
 
 	val = pmbus_data2reg(data, &s, val);
 
-	ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
-unlock:
-	mutex_unlock(&data->update_lock);
-	return ret;
+	return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
 }
 
 static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
@@ -3302,7 +3255,6 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	int val, low, high;
-	int ret;
 
 	if (data->flags & PMBUS_VOUT_PROTECTED)
 		return 0;
@@ -3315,29 +3267,20 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
 	val = DIV_ROUND_CLOSEST(rdev->desc->min_uV +
 				(rdev->desc->uV_step * selector), 1000); /* convert to mV */
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
 
 	low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
-	if (low < 0) {
-		ret = low;
-		goto unlock;
-	}
+	if (low < 0)
+		return low;
 
 	high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
-	if (high < 0) {
-		ret = high;
-		goto unlock;
-	}
+	if (high < 0)
+		return high;
 
-	if (val >= low && val <= high) {
-		ret = val * 1000; /* unit is uV */
-		goto unlock;
-	}
+	if (val >= low && val <= high)
+		return val * 1000; /* unit is uV */
 
-	ret = 0;
-unlock:
-	mutex_unlock(&data->update_lock);
-	return ret;
+	return 0;
 }
 
 const struct regulator_ops pmbus_regulator_ops = {
@@ -3478,16 +3421,16 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
 	struct i2c_client *client = to_i2c_client(data->dev);
 	int i, status, event;
 
-	mutex_lock(&data->update_lock);
+	guard(pmbus_lock)(client);
+
 	for (i = 0; i < data->info->pages; i++) {
-		_pmbus_get_flags(data, i, &status, &event, true);
+		_pmbus_get_flags(client, i, &status, &event, true);
 
 		if (event)
 			pmbus_regulator_notify(data, i, event);
 	}
 
 	pmbus_clear_faults(client);
-	mutex_unlock(&data->update_lock);
 
 	return IRQ_HANDLED;
 }
@@ -3543,15 +3486,13 @@ static struct dentry *pmbus_debugfs_dir;	/* pmbus debugfs directory */
 
 static int pmbus_debugfs_get(void *data, u64 *val)
 {
-	int rc;
 	struct pmbus_debugfs_entry *entry = data;
-	struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
+	struct i2c_client *client = entry->client;
+	int rc;
 
-	rc = mutex_lock_interruptible(&pdata->update_lock);
-	if (rc)
-		return rc;
-	rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg);
-	mutex_unlock(&pdata->update_lock);
+	guard(pmbus_lock)(client);
+
+	rc = _pmbus_read_byte_data(client, entry->page, entry->reg);
 	if (rc < 0)
 		return rc;
 
@@ -3564,15 +3505,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL,
 
 static int pmbus_debugfs_get_status(void *data, u64 *val)
 {
-	int rc;
 	struct pmbus_debugfs_entry *entry = data;
-	struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
+	struct i2c_client *client = entry->client;
+	struct pmbus_data *pdata = i2c_get_clientdata(client);
+	int rc;
 
-	rc = mutex_lock_interruptible(&pdata->update_lock);
-	if (rc)
-		return rc;
-	rc = pdata->read_status(entry->client, entry->page);
-	mutex_unlock(&pdata->update_lock);
+	guard(pmbus_lock)(client);
+
+	rc = pdata->read_status(client, entry->page);
 	if (rc < 0)
 		return rc;
 
@@ -3588,17 +3528,14 @@ static ssize_t pmbus_debugfs_block_read(struct file *file, char __user *buf,
 {
 	int rc;
 	struct pmbus_debugfs_entry *entry = file->private_data;
-	struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
+	struct i2c_client *client = entry->client;
 	char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
 
-	rc = mutex_lock_interruptible(&pdata->update_lock);
-	if (rc)
-		return rc;
-	rc = pmbus_read_block_data(entry->client, entry->page, entry->reg,
-				   data);
-	mutex_unlock(&pdata->update_lock);
-	if (rc < 0)
-		return rc;
+	scoped_guard(pmbus_lock, client) {
+		rc = pmbus_read_block_data(client, entry->page, entry->reg, data);
+		if (rc < 0)
+			return rc;
+	}
 
 	/* Add newline at the end of a read data */
 	data[rc] = '\n';
Signature · 1 line
2.53.0
author maintainer
#56 lore raw

PATCH 56/250 hwmon: (pmbus) Fix type confusion in notification logic

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 59bd68ab05a8f9c9a60b6ec44682084184803ff4 ]

Sashiko reports:

At the start of the loop in pmbus_notify(), the code unconditionally casts every attribute to a struct sensor_device_attribute:

drivers/hwmon/pmbus/pmbus_core.c:pmbus_notify() {
    for (i = 0; i < data->num_attributes; i++) {
        struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        int index = attr->index;

...
}

However, data->group.attrs can contain other types like struct pmbus_samples_reg or struct pmbus_sensor, which only embed a base struct device_attribute.

If da is a struct pmbus_samples_reg, dev_attr is the last member. Casting it to struct sensor_device_attribute and reading the index field appears to access memory past the end of the allocation, which might trigger a slab-out-of-bounds read.

Additionally, if da is a struct pmbus_sensor, casting it causes the index field to overlap with the page, phase, and reg fields. Could this produce a garbage mask on little-endian systems that spuriously matches the target reg, page, and flags during an alert?

Fix the problem by using struct sensor_device_attr in struct pmbus_sensor and struct pmbus_label. Since those attributes never trigger a notification, set the value of attr->index to -1 for them. Use this value to distinguish from boolean attributes which _can_ trigger a notification and use the index field to encode mask, page, and register values.

Fixes f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
Cc Vincent Jardin <[email protected]>
---
 drivers/hwmon/pmbus/pmbus_core.c | 61 +++++++++++++++++++-------------
 1 file changed, 37 insertions(+), 24 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +37 -24
index a95ffd563018d..20a26db668940 100644
@@ -46,7 +46,7 @@ module_param(wp, int, 0444);
 struct pmbus_sensor {
 	struct pmbus_sensor *next;
 	char name[PMBUS_NAME_SIZE];	/* sysfs sensor name */
-	struct device_attribute attribute;
+	struct sensor_device_attribute attribute;
 	u8 page;		/* page number */
 	u8 phase;		/* phase number, 0xff for all phases */
 	u16 reg;		/* register */
@@ -69,7 +69,7 @@ struct pmbus_boolean {
 
 struct pmbus_label {
 	char name[PMBUS_NAME_SIZE];	/* sysfs label name */
-	struct device_attribute attribute;
+	struct sensor_device_attribute attribute;
 	char label[PMBUS_NAME_SIZE];	/* label */
 };
 #define to_pmbus_label(_attr) \
@@ -1218,7 +1218,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
 				 struct device_attribute *devattr, char *buf)
 {
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	s64 val;
 
@@ -1238,7 +1239,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 {
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_data *data = i2c_get_clientdata(client);
-	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
 	s64 val;
 	int ret;
 	u16 regval;
@@ -1260,7 +1262,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 static ssize_t pmbus_show_label(struct device *dev,
 				struct device_attribute *da, char *buf)
 {
-	struct pmbus_label *label = to_pmbus_label(da);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pmbus_label *label = to_pmbus_label(attr);
 
 	return sysfs_emit(buf, "%s\n", label->label);
 }
@@ -1413,8 +1416,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
 					     bool update, bool readonly,
 					     bool writeonly, bool convert)
 {
+	struct sensor_device_attribute *a;
 	struct pmbus_sensor *sensor;
-	struct device_attribute *a;
 
 	sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
 	if (!sensor)
@@ -1438,12 +1441,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
 	sensor->update = update;
 	sensor->convert = convert;
 	sensor->data = -ENODATA;
-	pmbus_dev_attr_init(a, sensor->name,
-			    readonly ? 0444 : 0644,
-			    writeonly ? pmbus_show_zero : pmbus_show_sensor,
-			    pmbus_set_sensor);
+	pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
+			writeonly ? pmbus_show_zero : pmbus_show_sensor,
+			pmbus_set_sensor, -1);
 
-	if (pmbus_add_attribute(data, &a->attr))
+	if (pmbus_add_attribute(data, &a->dev_attr.attr))
 		return NULL;
 
 	sensor->next = data->sensors;
@@ -1460,8 +1462,8 @@ static int pmbus_add_label(struct pmbus_data *data,
 			   const char *name, int seq,
 			   const char *lstring, int index, int phase)
 {
+	struct sensor_device_attribute *a;
 	struct pmbus_label *label;
-	struct device_attribute *a;
 
 	label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
 	if (!label)
@@ -1485,8 +1487,8 @@ static int pmbus_add_label(struct pmbus_data *data,
 				 lstring, index, phase);
 	}
 
-	pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
-	return pmbus_add_attribute(data, &a->attr);
+	pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
+	return pmbus_add_attribute(data, &a->dev_attr.attr);
 }
 
 /*
@@ -2374,7 +2376,7 @@ struct pmbus_samples_attr {
 struct pmbus_samples_reg {
 	int page;
 	struct pmbus_samples_attr *attr;
-	struct device_attribute dev_attr;
+	struct sensor_device_attribute attribute;
 };
 
 static struct pmbus_samples_attr pmbus_samples_registers[] = {
@@ -2396,14 +2398,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
 	}
 };
 
-#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
+#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
 
 static ssize_t pmbus_show_samples(struct device *dev,
 				  struct device_attribute *devattr, char *buf)
 {
 	int val;
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pmbus_samples_reg *reg = to_samples_reg(attr);
 
 	scoped_guard(pmbus_lock, client) {
 		val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
@@ -2421,7 +2424,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
 	int ret;
 	long val;
 	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pmbus_samples_reg *reg = to_samples_reg(attr);
 
 	if (kstrtol(buf, 0, &val) < 0)
 		return -EINVAL;
@@ -2436,6 +2440,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
 static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
 				  struct pmbus_samples_attr *attr)
 {
+	struct sensor_device_attribute *a;
 	struct pmbus_samples_reg *reg;
 
 	reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
@@ -2445,10 +2450,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
 	reg->attr = attr;
 	reg->page = page;
 
-	pmbus_dev_attr_init(&reg->dev_attr, attr->name, 0644,
-			    pmbus_show_samples, pmbus_set_samples);
+	a = &reg->attribute;
+
+	pmbus_attr_init(a, attr->name, 0644,
+			pmbus_show_samples, pmbus_set_samples, -1);
 
-	return pmbus_add_attribute(data, &reg->dev_attr.attr);
+	return pmbus_add_attribute(data, &a->dev_attr.attr);
 }
 
 static int pmbus_add_samples_attributes(struct i2c_client *client,
@@ -2956,9 +2963,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
 		struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
 		struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 		int index = attr->index;
-		u16 smask = pb_index_to_mask(index);
-		u8 spage = pb_index_to_page(index);
-		u16 sreg = pb_index_to_reg(index);
+		u16 smask, sreg;
+		u8 spage;
+
+		if (index == -1)
+			continue;
+
+		smask = pb_index_to_mask(index);
+		spage = pb_index_to_page(index);
+		sreg = pb_index_to_reg(index);
 
 		if (reg == sreg && page == spage && (smask & flags)) {
 			dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
Signature · 1 line
2.53.0
author maintainer
#57 lore raw

PATCH 57/250 tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()

In reply to Greg Kroah-Hartman

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

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

From: Nathan Gao <[email protected]>

[ Upstream commit 0e125ecfe20c077625cf0be8d750d5c3abc0dce9 ]

Commit f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio") replaced the direct window_clamp update in tcp_measure_rcv_mss() with a call to tcp_set_window_clamp(), a helper that implements the TCP_WINDOW_CLAMP setsockopt. As a side effect, the helper also shrinks rcv_ssthresh via __tcp_adjust_rcv_ssthresh().

As a result, each scaling_ratio decrease detected by tcp_measure_rcv_mss() also cuts rcv_ssthresh. Elsewhere in TCP, rcv_ssthresh is usually cut under memory pressure and grows via tcp_grow_window().

Flows whose segment sizes vary keep scaling_ratio oscillating, which leads to an unstable rcv_ssthresh: a dip of rcv_ssthresh only recovers via tcp_grow_window(), keeping the advertised window at a relatively low level even after the ratio itself has recovered, and can even stall the sender.

Observed on a customer's proxy gateway after upgrading from kernel 6.1 to 6.12: in the worst case, rcv_ssthresh was cut in half by a scaling_ratio dip. P99 latency jumped from <10ms on 6.1 to ~100ms on 6.12, and almost returned to the 6.1 level with this patch applied.

Restore the plain WRITE_ONCE() update of window_clamp, as introduced in commit a2cbb1603943 ("tcp: Update window clamping condition"), and keep the rcvq_space.space adjustment. Now rcv_ssthresh is decoupled from scaling_ratio changes in tcp_measure_rcv_mss().

Fixes f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio")
---
 net/ipv4/tcp_input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/tcp_input.c +1 -1
index 8c74fbeb771d5..c1769031a9e93 100644
@@ -252,7 +252,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
 				struct tcp_sock *tp = tcp_sk(sk);
 
 				val = tcp_win_from_space(sk, sk->sk_rcvbuf);
-				tcp_set_window_clamp(sk, val);
+				WRITE_ONCE(tp->window_clamp, val);
 
 				if (tp->window_clamp < tp->rcvq_space.space)
 					tp->rcvq_space.space = tp->window_clamp;
Signature · 1 line
2.53.0
author maintainer
#58 lore raw

PATCH 58/250 bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips

In reply to Greg Kroah-Hartman

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

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

From: Michael Chan <[email protected]>

[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]

With End-of-Packet padding (EOP) set, the chip will disable Relaxed Ordering (RO) of TPA data packets. A TPA segment with EOP set will be padded to the next cache boundary and can potentially overwrite the beginning bytes of the next TPA segment when RO is enabled on 5760X. To prevent that, the chip disables RO for TPA when EOP is set.

To take advantge of RO and higher performance, do not set EOP on 5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP constant to make it clear that we are setting EOP.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
 drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
index 98a911eae8eac..1efd1f8776abe 100644
@@ -4495,7 +4495,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
 	ring->fw_ring_id = INVALID_HW_RING_ID;
 	if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
 		type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
-			RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
+			RX_BD_TYPE_RX_AGG_BD;
+
+		/* On P7, setting EOP will cause the chip to disable
+		 * Relaxed Ordering (RO) for TPA data.  Disable EOP for
+		 * potentially higher performance with RO.
+		 */
+		if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
+			type |= RX_BD_FLAGS_AGG_EOP;
 
 		bnxt_init_rxbd_pages(ring, type);
 	}
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
index d55987e24ad6e..b140799f07d69 100644
@@ -131,6 +131,7 @@ struct rx_bd {
 	 #define RX_BD_TYPE_48B_BD_SIZE				 (2 << 4)
 	 #define RX_BD_TYPE_64B_BD_SIZE				 (3 << 4)
 	#define RX_BD_FLAGS_SOP					(1 << 6)
+	#define RX_BD_FLAGS_AGG_EOP				(1 << 6)
 	#define RX_BD_FLAGS_EOP					(1 << 7)
 	#define RX_BD_FLAGS_BUFFERS				(3 << 8)
 	 #define RX_BD_FLAGS_1_BUFFER_PACKET			 (0 << 8)
Signature · 1 line
2.53.0
author maintainer
#59 lore raw

PATCH 59/250 net: reduce indent of struct netdev_queue_mgmt_ops members

In reply to Greg Kroah-Hartman

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

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

From: Jakub Kicinski <[email protected]>

[ Upstream commit 92d76cf96dcbc3c58daa84dbbf71a3ca8d9de53d ]

Trivial change, reduce the indent. I think the original is copied from real NDOs. It's unnecessarily deep, makes passing struct args problematic.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 include/net/netdev_queues.h | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
include/net/netdev_queues.h +14 -14
index cd00e0406cf46..541e7d9853b1b 100644
@@ -135,20 +135,20 @@ void netdev_stat_queue_sum(struct net_device *netdev,
  * be called for an interface which is open.
  */
 struct netdev_queue_mgmt_ops {
-	size_t			ndo_queue_mem_size;
-	int			(*ndo_queue_mem_alloc)(struct net_device *dev,
-						       void *per_queue_mem,
-						       int idx);
-	void			(*ndo_queue_mem_free)(struct net_device *dev,
-						      void *per_queue_mem);
-	int			(*ndo_queue_start)(struct net_device *dev,
-						   void *per_queue_mem,
-						   int idx);
-	int			(*ndo_queue_stop)(struct net_device *dev,
-						  void *per_queue_mem,
-						  int idx);
-	struct device *		(*ndo_queue_get_dma_dev)(struct net_device *dev,
-							 int idx);
+	size_t	ndo_queue_mem_size;
+	int	(*ndo_queue_mem_alloc)(struct net_device *dev,
+				       void *per_queue_mem,
+				       int idx);
+	void	(*ndo_queue_mem_free)(struct net_device *dev,
+				      void *per_queue_mem);
+	int	(*ndo_queue_start)(struct net_device *dev,
+				   void *per_queue_mem,
+				   int idx);
+	int	(*ndo_queue_stop)(struct net_device *dev,
+				  void *per_queue_mem,
+				  int idx);
+	struct device *	(*ndo_queue_get_dma_dev)(struct net_device *dev,
+						 int idx);
 };
 
 bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
Signature · 1 line
2.53.0
author maintainer
#60 lore raw

PATCH 60/250 net: add bare bone queue configs

In reply to Greg Kroah-Hartman

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

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

From: Pavel Begunkov <[email protected]>

[ Upstream commit efcb9a4d32d3d9b924642c086b868bfbb9a07c13 ]

We'll need to pass extra parameters when allocating a queue for memory providers. Define a new structure for queue configurations, and pass it to qapi callbacks. It's empty for now, actual parameters will be added in following patches.

Configurations should persist across resets, and for that they're default-initialised on device registration and stored in struct netdev_rx_queue. We also add a new qapi callback for defaulting a given config. It must be implemented if a driver wants to use queue configs and is optional otherwise.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c       |  8 ++++++--
 drivers/net/ethernet/google/gve/gve_main.c      |  9 ++++++---
 .../net/ethernet/mellanox/mlx5/core/en_main.c   | 10 ++++++----
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c    |  8 ++++++--
 drivers/net/netdevsim/netdev.c                  |  7 +++++--
 include/net/netdev_queues.h                     |  9 +++++++++
 include/net/netdev_rx_queue.h                   |  2 ++
 net/core/dev.c                                  | 17 +++++++++++++++++
 net/core/netdev_rx_queue.c                      | 12 +++++++++---
 9 files changed, 66 insertions(+), 16 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +6 -2
index 1efd1f8776abe..f3fbbf188053c 100644
@@ -15954,7 +15954,9 @@ static const struct netdev_stat_ops bnxt_stat_ops = {
 	.get_base_stats		= bnxt_get_base_stats,
 };
 
-static int bnxt_queue_mem_alloc(struct net_device *dev, void *qmem, int idx)
+static int bnxt_queue_mem_alloc(struct net_device *dev,
+				struct netdev_queue_config *qcfg,
+				void *qmem, int idx)
 {
 	struct bnxt_rx_ring_info *rxr, *clone;
 	struct bnxt *bp = netdev_priv(dev);
@@ -16120,7 +16122,9 @@ static void bnxt_copy_rx_ring(struct bnxt *bp,
 	dst->rx_agg_bmap = src->rx_agg_bmap;
 }
 
-static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
+static int bnxt_queue_start(struct net_device *dev,
+			    struct netdev_queue_config *qcfg,
+			    void *qmem, int idx)
 {
 	struct bnxt *bp = netdev_priv(dev);
 	struct bnxt_rx_ring_info *rxr, *clone;
drivers/net/ethernet/google/gve/gve_main.c +6 -3
index 030800776ead1..9751049849432 100644
@@ -2580,8 +2580,9 @@ static void gve_rx_queue_mem_free(struct net_device *dev, void *per_q_mem)
 		gve_rx_free_ring_dqo(priv, gve_per_q_mem, &cfg);
 }
 
-static int gve_rx_queue_mem_alloc(struct net_device *dev, void *per_q_mem,
-				  int idx)
+static int gve_rx_queue_mem_alloc(struct net_device *dev,
+				  struct netdev_queue_config *qcfg,
+				  void *per_q_mem, int idx)
 {
 	struct gve_priv *priv = netdev_priv(dev);
 	struct gve_rx_alloc_rings_cfg cfg = {0};
@@ -2602,7 +2603,9 @@ static int gve_rx_queue_mem_alloc(struct net_device *dev, void *per_q_mem,
 	return err;
 }
 
-static int gve_rx_queue_start(struct net_device *dev, void *per_q_mem, int idx)
+static int gve_rx_queue_start(struct net_device *dev,
+			      struct netdev_queue_config *qcfg,
+			      void *per_q_mem, int idx)
 {
 	struct gve_priv *priv = netdev_priv(dev);
 	struct gve_rx_ring *gve_per_q_mem;
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +6 -4
index 7e754b72f889f..58e255910c43e 100644
@@ -5540,8 +5540,9 @@ struct mlx5_qmgmt_data {
 	struct mlx5e_channel_param cparam;
 };
 
-static int mlx5e_queue_mem_alloc(struct net_device *dev, void *newq,
-				 int queue_index)
+static int mlx5e_queue_mem_alloc(struct net_device *dev,
+				 struct netdev_queue_config *qcfg,
+				 void *newq, int queue_index)
 {
 	struct mlx5_qmgmt_data *new = (struct mlx5_qmgmt_data *)newq;
 	struct mlx5e_priv *priv = netdev_priv(dev);
@@ -5602,8 +5603,9 @@ static int mlx5e_queue_stop(struct net_device *dev, void *oldq, int queue_index)
 	return 0;
 }
 
-static int mlx5e_queue_start(struct net_device *dev, void *newq,
-			     int queue_index)
+static int mlx5e_queue_start(struct net_device *dev,
+			     struct netdev_queue_config *qcfg,
+			     void *newq, int queue_index)
 {
 	struct mlx5_qmgmt_data *new = (struct mlx5_qmgmt_data *)newq;
 	struct mlx5e_priv *priv = netdev_priv(dev);
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +6 -2
index 14885c3d70697..dbe0855ecb575 100644
@@ -2811,7 +2811,9 @@ void fbnic_napi_depletion_check(struct net_device *netdev)
 	fbnic_wrfl(fbd);
 }
 
-static int fbnic_queue_mem_alloc(struct net_device *dev, void *qmem, int idx)
+static int fbnic_queue_mem_alloc(struct net_device *dev,
+				 struct netdev_queue_config *qcfg,
+				 void *qmem, int idx)
 {
 	struct fbnic_net *fbn = netdev_priv(dev);
 	const struct fbnic_q_triad *real;
@@ -2863,7 +2865,9 @@ static void __fbnic_nv_restart(struct fbnic_net *fbn,
 		netif_wake_subqueue(fbn->netdev, nv->qt[i].sub0.q_idx);
 }
 
-static int fbnic_queue_start(struct net_device *dev, void *qmem, int idx)
+static int fbnic_queue_start(struct net_device *dev,
+			     struct netdev_queue_config *qcfg,
+			     void *qmem, int idx)
 {
 	struct fbnic_net *fbn = netdev_priv(dev);
 	struct fbnic_napi_vector *nv;
drivers/net/netdevsim/netdev.c +5 -2
index 06446b03cd9bc..7a8e17bf46bdb 100644
@@ -760,7 +760,9 @@ struct nsim_queue_mem {
 };
 
 static int
-nsim_queue_mem_alloc(struct net_device *dev, void *per_queue_mem, int idx)
+nsim_queue_mem_alloc(struct net_device *dev,
+		     struct netdev_queue_config *qcfg,
+		     void *per_queue_mem, int idx)
 {
 	struct nsim_queue_mem *qmem = per_queue_mem;
 	struct netdevsim *ns = netdev_priv(dev);
@@ -809,7 +811,8 @@ static void nsim_queue_mem_free(struct net_device *dev, void *per_queue_mem)
 }
 
 static int
-nsim_queue_start(struct net_device *dev, void *per_queue_mem, int idx)
+nsim_queue_start(struct net_device *dev, struct netdev_queue_config *qcfg,
+		 void *per_queue_mem, int idx)
 {
 	struct nsim_queue_mem *qmem = per_queue_mem;
 	struct netdevsim *ns = netdev_priv(dev);
include/net/netdev_queues.h +9 -0
index 541e7d9853b1b..f6f1f71a24e15 100644
@@ -14,6 +14,9 @@ struct netdev_config {
 	u8	hds_config;
 };
 
+struct netdev_queue_config {
+};
+
 /* See the netdev.yaml spec for definition of each statistic */
 struct netdev_queue_stats_rx {
 	u64 bytes;
@@ -130,6 +133,8 @@ void netdev_stat_queue_sum(struct net_device *netdev,
  * @ndo_queue_get_dma_dev: Get dma device for zero-copy operations to be used
  *			   for this queue. Return NULL on error.
  *
+ * @ndo_default_qcfg:	Populate queue config struct with defaults. Optional.
+ *
  * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
  * the interface is closed. @ndo_queue_start and @ndo_queue_stop will only
  * be called for an interface which is open.
@@ -137,16 +142,20 @@ void netdev_stat_queue_sum(struct net_device *netdev,
 struct netdev_queue_mgmt_ops {
 	size_t	ndo_queue_mem_size;
 	int	(*ndo_queue_mem_alloc)(struct net_device *dev,
+				       struct netdev_queue_config *qcfg,
 				       void *per_queue_mem,
 				       int idx);
 	void	(*ndo_queue_mem_free)(struct net_device *dev,
 				      void *per_queue_mem);
 	int	(*ndo_queue_start)(struct net_device *dev,
+				   struct netdev_queue_config *qcfg,
 				   void *per_queue_mem,
 				   int idx);
 	int	(*ndo_queue_stop)(struct net_device *dev,
 				  void *per_queue_mem,
 				  int idx);
+	void	(*ndo_default_qcfg)(struct net_device *dev,
+				    struct netdev_queue_config *qcfg);
 	struct device *	(*ndo_queue_get_dma_dev)(struct net_device *dev,
 						 int idx);
 };
include/net/netdev_rx_queue.h +2 -0
index 8cdcd138b33f2..cfa72c4853876 100644
@@ -7,6 +7,7 @@
 #include <linux/sysfs.h>
 #include <net/xdp.h>
 #include <net/page_pool/types.h>
+#include <net/netdev_queues.h>
 
 /* This structure contains an instance of an RX queue. */
 struct netdev_rx_queue {
@@ -27,6 +28,7 @@ struct netdev_rx_queue {
 	struct xsk_buff_pool            *pool;
 #endif
 	struct napi_struct		*napi;
+	struct netdev_queue_config	qcfg;
 	struct pp_memory_provider_params mp_params;
 } ____cacheline_aligned_in_smp;
 
net/core/dev.c +17 -0
index a83083e8761b1..e4ea5615e81ea 100644
@@ -11223,6 +11223,21 @@ static void netdev_free_phy_link_topology(struct net_device *dev)
 	}
 }
 
+static void init_rx_queue_cfgs(struct net_device *dev)
+{
+	const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
+	struct netdev_rx_queue *rxq;
+	int i;
+
+	if (!qops || !qops->ndo_default_qcfg)
+		return;
+
+	for (i = 0; i < dev->num_rx_queues; i++) {
+		rxq = __netif_get_rx_queue(dev, i);
+		qops->ndo_default_qcfg(dev, &rxq->qcfg);
+	}
+}
+
 /**
  * register_netdevice() - register a network device
  * @dev: device to register
@@ -11268,6 +11283,8 @@ int register_netdevice(struct net_device *dev)
 	if (!dev->name_node)
 		goto out;
 
+	init_rx_queue_cfgs(dev);
+
 	/* Init, if this function is available */
 	if (dev->netdev_ops->ndo_init) {
 		ret = dev->netdev_ops->ndo_init(dev);
net/core/netdev_rx_queue.c +9 -3
index c7d9341b76307..f18147b478688 100644
@@ -22,6 +22,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 {
 	struct netdev_rx_queue *rxq = __netif_get_rx_queue(dev, rxq_idx);
 	const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
+	struct netdev_queue_config qcfg;
 	void *new_mem, *old_mem;
 	int err;
 
@@ -31,6 +32,10 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 
 	netdev_assert_locked(dev);
 
+	memset(&qcfg, 0, sizeof(qcfg));
+	if (qops->ndo_default_qcfg)
+		qops->ndo_default_qcfg(dev, &qcfg);
+
 	new_mem = kvzalloc(qops->ndo_queue_mem_size, GFP_KERNEL);
 	if (!new_mem)
 		return -ENOMEM;
@@ -41,7 +46,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 		goto err_free_new_mem;
 	}
 
-	err = qops->ndo_queue_mem_alloc(dev, new_mem, rxq_idx);
+	err = qops->ndo_queue_mem_alloc(dev, &qcfg, new_mem, rxq_idx);
 	if (err)
 		goto err_free_old_mem;
 
@@ -54,7 +59,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 		if (err)
 			goto err_free_new_queue_mem;
 
-		err = qops->ndo_queue_start(dev, new_mem, rxq_idx);
+		err = qops->ndo_queue_start(dev, &qcfg, new_mem, rxq_idx);
 		if (err)
 			goto err_start_queue;
 	} else {
@@ -66,6 +71,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 	kvfree(old_mem);
 	kvfree(new_mem);
 
+	rxq->qcfg = qcfg;
 	return 0;
 
 err_start_queue:
@@ -76,7 +82,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 	 * WARN if we fail to recover the old rx queue, and at least free
 	 * old_mem so we don't also leak that.
 	 */
-	if (qops->ndo_queue_start(dev, old_mem, rxq_idx)) {
+	if (qops->ndo_queue_start(dev, &rxq->qcfg, old_mem, rxq_idx)) {
 		WARN(1,
 		     "Failed to restart old queue in error path. RX queue %d may be unhealthy.",
 		     rxq_idx);
Signature · 1 line
2.53.0
author maintainer
#61 lore raw

PATCH 61/250 net: pass queue rx page size from memory provider

In reply to Greg Kroah-Hartman

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

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

From: Pavel Begunkov <[email protected]>

[ Upstream commit c0b709bf438ba9d197d369f55e4a97603fd4a705 ]

Allow memory providers to configure rx queues with a custom receive page size. It's passed in struct pp_memory_provider_params, which is copied into the queue, so it's preserved across queue restarts. Then, it's propagated to the driver in a new queue config parameter.

Drivers should explicitly opt into using it by setting QCFG_RX_PAGE_SIZE, in which case they should implement ndo_default_qcfg, validate the size on queue restart and honour the current config in case of a reset.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 include/net/netdev_queues.h   | 10 ++++++++++
 include/net/page_pool/types.h |  1 +
 net/core/netdev_rx_queue.c    |  9 +++++++++
 3 files changed, 20 insertions(+)
include/net/netdev_queues.h +10 -0
index f6f1f71a24e15..feca25131930b 100644
@@ -15,6 +15,7 @@ struct netdev_config {
 };
 
 struct netdev_queue_config {
+	u32	rx_page_size;
 };
 
 /* See the netdev.yaml spec for definition of each statistic */
@@ -114,6 +115,11 @@ void netdev_stat_queue_sum(struct net_device *netdev,
 			   int tx_start, int tx_end,
 			   struct netdev_queue_stats_tx *tx_sum);
 
+enum {
+	/* The queue checks and honours the page size qcfg parameter */
+	QCFG_RX_PAGE_SIZE	= 0x1,
+};
+
 /**
  * struct netdev_queue_mgmt_ops - netdev ops for queue management
  *
@@ -135,6 +141,8 @@ void netdev_stat_queue_sum(struct net_device *netdev,
  *
  * @ndo_default_qcfg:	Populate queue config struct with defaults. Optional.
  *
+ * @supported_params:	Bitmask of supported parameters, see QCFG_*.
+ *
  * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
  * the interface is closed. @ndo_queue_start and @ndo_queue_stop will only
  * be called for an interface which is open.
@@ -158,6 +166,8 @@ struct netdev_queue_mgmt_ops {
 				    struct netdev_queue_config *qcfg);
 	struct device *	(*ndo_queue_get_dma_dev)(struct net_device *dev,
 						 int idx);
+
+	unsigned int supported_params;
 };
 
 bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
include/net/page_pool/types.h +1 -0
index fb4f03ccd6156..cdd95477af7a2 100644
@@ -161,6 +161,7 @@ struct memory_provider_ops;
 struct pp_memory_provider_params {
 	void *mp_priv;
 	const struct memory_provider_ops *mp_ops;
+	u32 rx_page_size;
 };
 
 struct page_pool {
net/core/netdev_rx_queue.c +9 -0
index f18147b478688..485bdb7447b99 100644
@@ -30,12 +30,21 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
 	    !qops->ndo_queue_mem_alloc || !qops->ndo_queue_start)
 		return -EOPNOTSUPP;
 
+	if (WARN_ON_ONCE(qops->supported_params && !qops->ndo_default_qcfg))
+		return -EINVAL;
+
 	netdev_assert_locked(dev);
 
 	memset(&qcfg, 0, sizeof(qcfg));
 	if (qops->ndo_default_qcfg)
 		qops->ndo_default_qcfg(dev, &qcfg);
 
+	if (rxq->mp_params.rx_page_size) {
+		if (!(qops->supported_params & QCFG_RX_PAGE_SIZE))
+			return -EOPNOTSUPP;
+		qcfg.rx_page_size = rxq->mp_params.rx_page_size;
+	}
+
 	new_mem = kvzalloc(qops->ndo_queue_mem_size, GFP_KERNEL);
 	if (!new_mem)
 		return -ENOMEM;
Signature · 1 line
2.53.0
author maintainer
#62 lore raw

PATCH 62/250 eth: bnxt: store rx buffer size per queue

In reply to Greg Kroah-Hartman

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

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

From: Pavel Begunkov <[email protected]>

[ Upstream commit f57efb32aae1da5c0a25acf473ef4ab559894adf ]

Instead of using a constant buffer length, allow configuring the size for each queue separately. There is no way to change the length yet, and it'll be passed from memory providers in a later patch.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c     | 56 +++++++++++--------
 drivers/net/ethernet/broadcom/bnxt/bnxt.h     |  1 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c |  6 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h |  2 +-
 4 files changed, 38 insertions(+), 27 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +33 -23
index f3fbbf188053c..fddfdf807950f 100644
@@ -905,7 +905,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
 
 static bool bnxt_separate_head_pool(struct bnxt_rx_ring_info *rxr)
 {
-	return rxr->need_head_pool || PAGE_SIZE > BNXT_RX_PAGE_SIZE;
+	return rxr->need_head_pool || rxr->rx_page_size < PAGE_SIZE;
 }
 
 static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
@@ -915,9 +915,9 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
 {
 	struct page *page;
 
-	if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
+	if (rxr->rx_page_size < PAGE_SIZE) {
 		page = page_pool_dev_alloc_frag(rxr->page_pool, offset,
-						BNXT_RX_PAGE_SIZE);
+						rxr->rx_page_size);
 	} else {
 		page = page_pool_dev_alloc_pages(rxr->page_pool);
 		*offset = 0;
@@ -936,8 +936,9 @@ static netmem_ref __bnxt_alloc_rx_netmem(struct bnxt *bp, dma_addr_t *mapping,
 {
 	netmem_ref netmem;
 
-	if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
-		netmem = page_pool_alloc_frag_netmem(rxr->page_pool, offset, BNXT_RX_PAGE_SIZE, gfp);
+	if (rxr->rx_page_size < PAGE_SIZE) {
+		netmem = page_pool_alloc_frag_netmem(rxr->page_pool, offset,
+						     rxr->rx_page_size, gfp);
 	} else {
 		netmem = page_pool_alloc_netmems(rxr->page_pool, gfp);
 		*offset = 0;
@@ -1155,9 +1156,9 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
 		return NULL;
 	}
 	dma_addr -= bp->rx_dma_offset;
-	dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
+	dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
 				bp->rx_dir);
-	skb = napi_build_skb(data_ptr - bp->rx_offset, BNXT_RX_PAGE_SIZE);
+	skb = napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size);
 	if (!skb) {
 		page_pool_recycle_direct(rxr->page_pool, page);
 		return NULL;
@@ -1189,7 +1190,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
 		return NULL;
 	}
 	dma_addr -= bp->rx_dma_offset;
-	dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
+	dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
 				bp->rx_dir);
 
 	if (unlikely(!payload))
@@ -1203,7 +1204,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
 
 	skb_mark_for_recycle(skb);
 	off = (void *)data_ptr - page_address(page);
-	skb_add_rx_frag(skb, 0, page, off, len, BNXT_RX_PAGE_SIZE);
+	skb_add_rx_frag(skb, 0, page, off, len, rxr->rx_page_size);
 	memcpy(skb->data - NET_IP_ALIGN, data_ptr - NET_IP_ALIGN,
 	       payload + NET_IP_ALIGN);
 
@@ -1288,7 +1289,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
 		if (skb) {
 			skb_add_rx_frag_netmem(skb, i, cons_rx_buf->netmem,
 					       cons_rx_buf->offset,
-					       frag_len, BNXT_RX_PAGE_SIZE);
+					       frag_len, rxr->rx_page_size);
 		} else {
 			skb_frag_t *frag = &shinfo->frags[i];
 
@@ -1313,7 +1314,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
 			if (skb) {
 				skb->len -= frag_len;
 				skb->data_len -= frag_len;
-				skb->truesize -= BNXT_RX_PAGE_SIZE;
+				skb->truesize -= rxr->rx_page_size;
 			}
 
 			--shinfo->nr_frags;
@@ -1328,7 +1329,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
 		}
 
 		page_pool_dma_sync_netmem_for_cpu(rxr->page_pool, netmem, 0,
-						  BNXT_RX_PAGE_SIZE);
+						  rxr->rx_page_size);
 
 		total_frag_len += frag_len;
 		prod = NEXT_RX_AGG(prod);
@@ -2295,8 +2296,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
 			if (!skb)
 				goto oom_next_rx;
 		} else {
-			skb = bnxt_xdp_build_skb(bp, skb, agg_bufs,
-						 rxr->page_pool, &xdp);
+			skb = bnxt_xdp_build_skb(bp, skb, agg_bufs, rxr, &xdp);
 			if (!skb) {
 				/* we should be able to free the old skb here */
 				bnxt_xdp_buff_frags_free(rxr, &xdp);
@@ -3844,11 +3844,13 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
 	pp.pool_size = bp->rx_agg_ring_size / agg_size_fac;
 	if (BNXT_RX_PAGE_MODE(bp))
 		pp.pool_size += bp->rx_ring_size / rx_size_fac;
+
+	pp.order = get_order(rxr->rx_page_size);
 	pp.nid = numa_node;
 	pp.netdev = bp->dev;
 	pp.dev = &bp->pdev->dev;
 	pp.dma_dir = bp->rx_dir;
-	pp.max_len = PAGE_SIZE;
+	pp.max_len = PAGE_SIZE << pp.order;
 	pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV |
 		   PP_FLAG_ALLOW_UNREADABLE_NETMEM;
 	pp.queue_idx = rxr->bnapi->index;
@@ -3859,7 +3861,10 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
 	rxr->page_pool = pool;
 
 	rxr->need_head_pool = page_pool_is_unreadable(pool);
+	rxr->need_head_pool |= !!pp.order;
 	if (bnxt_separate_head_pool(rxr)) {
+		pp.order = 0;
+		pp.max_len = PAGE_SIZE;
 		pp.pool_size = min(bp->rx_ring_size / rx_size_fac, 1024);
 		pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
 		pool = page_pool_create(&pp);
@@ -4335,6 +4340,8 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
 		if (!rxr)
 			goto skip_rx;
 
+		rxr->rx_page_size = BNXT_RX_PAGE_SIZE;
+
 		ring = &rxr->rx_ring_struct;
 		rmem = &ring->ring_mem;
 		rmem->nr_pages = bp->rx_nr_pages;
@@ -4494,7 +4501,7 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
 	ring = &rxr->rx_agg_ring_struct;
 	ring->fw_ring_id = INVALID_HW_RING_ID;
 	if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
-		type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+		type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
 			RX_BD_TYPE_RX_AGG_BD;
 
 		/* On P7, setting EOP will cause the chip to disable
@@ -7071,6 +7078,7 @@ static void bnxt_hwrm_ring_grp_free(struct bnxt *bp)
 
 static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
 				       struct hwrm_ring_alloc_input *req,
+				       struct bnxt_rx_ring_info *rxr,
 				       struct bnxt_ring_struct *ring)
 {
 	struct bnxt_ring_grp_info *grp_info = &bp->grp_info[ring->grp_idx];
@@ -7080,7 +7088,7 @@ static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
 	if (ring_type == HWRM_RING_ALLOC_AGG) {
 		req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG;
 		req->rx_ring_id = cpu_to_le16(grp_info->rx_fw_ring_id);
-		req->rx_buf_size = cpu_to_le16(BNXT_RX_PAGE_SIZE);
+		req->rx_buf_size = cpu_to_le16(rxr->rx_page_size);
 		enables |= RING_ALLOC_REQ_ENABLES_RX_RING_ID_VALID;
 	} else {
 		req->rx_buf_size = cpu_to_le16(bp->rx_buf_use_size);
@@ -7094,6 +7102,7 @@ static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
 }
 
 static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
+				    struct bnxt_rx_ring_info *rxr,
 				    struct bnxt_ring_struct *ring,
 				    u32 ring_type, u32 map_index)
 {
@@ -7150,7 +7159,8 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
 			      cpu_to_le32(bp->rx_ring_mask + 1) :
 			      cpu_to_le32(bp->rx_agg_ring_mask + 1);
 		if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
-			bnxt_set_rx_ring_params_p5(bp, ring_type, req, ring);
+			bnxt_set_rx_ring_params_p5(bp, ring_type, req,
+						   rxr, ring);
 		break;
 	case HWRM_RING_ALLOC_CMPL:
 		req->ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL;
@@ -7298,7 +7308,7 @@ static int bnxt_hwrm_rx_ring_alloc(struct bnxt *bp,
 	u32 map_idx = bnapi->index;
 	int rc;
 
-	rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
+	rc = hwrm_ring_alloc_send_msg(bp, rxr, ring, type, map_idx);
 	if (rc)
 		return rc;
 
@@ -7318,7 +7328,7 @@ static int bnxt_hwrm_rx_agg_ring_alloc(struct bnxt *bp,
 	int rc;
 
 	map_idx = grp_idx + bp->rx_nr_rings;
-	rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
+	rc = hwrm_ring_alloc_send_msg(bp, rxr, ring, type, map_idx);
 	if (rc)
 		return rc;
 
@@ -7342,7 +7352,7 @@ static int bnxt_hwrm_cp_ring_alloc_p5(struct bnxt *bp,
 
 	ring = &cpr->cp_ring_struct;
 	ring->handle = BNXT_SET_NQ_HDL(cpr);
-	rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
+	rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, map_idx);
 	if (rc)
 		return rc;
 	bnxt_set_db(bp, &cpr->cp_db, type, map_idx, ring->fw_ring_id);
@@ -7357,7 +7367,7 @@ static int bnxt_hwrm_tx_ring_alloc(struct bnxt *bp,
 	const u32 type = HWRM_RING_ALLOC_TX;
 	int rc;
 
-	rc = hwrm_ring_alloc_send_msg(bp, ring, type, tx_idx);
+	rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, tx_idx);
 	if (rc)
 		return rc;
 	bnxt_set_db(bp, &txr->tx_db, type, tx_idx, ring->fw_ring_id);
@@ -7383,7 +7393,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
 
 		vector = bp->irq_tbl[map_idx].vector;
 		disable_irq_nosync(vector);
-		rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
+		rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, map_idx);
 		if (rc) {
 			enable_irq(vector);
 			goto err_out;
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
index b140799f07d69..9a1be6b71219d 100644
@@ -1105,6 +1105,7 @@ struct bnxt_rx_ring_info {
 
 	unsigned long		*rx_agg_bmap;
 	u16			rx_agg_bmap_size;
+	u32			rx_page_size;
 	bool                    need_head_pool;
 
 	dma_addr_t		rx_desc_mapping[MAX_RX_PAGES];
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +3 -3
index c94a391b1ba5b..85cbeb35681c2 100644
@@ -183,7 +183,7 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
 			u16 cons, u8 *data_ptr, unsigned int len,
 			struct xdp_buff *xdp)
 {
-	u32 buflen = BNXT_RX_PAGE_SIZE;
+	u32 buflen = rxr->rx_page_size;
 	struct bnxt_sw_rx_bd *rx_buf;
 	struct pci_dev *pdev;
 	dma_addr_t mapping;
@@ -460,7 +460,7 @@ int bnxt_xdp(struct net_device *dev, struct netdev_bpf *xdp)
 
 struct sk_buff *
 bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb, u8 num_frags,
-		   struct page_pool *pool, struct xdp_buff *xdp)
+		   struct bnxt_rx_ring_info *rxr, struct xdp_buff *xdp)
 {
 	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 
@@ -468,7 +468,7 @@ bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb, u8 num_frags,
 		return NULL;
 
 	xdp_update_skb_frags_info(skb, num_frags, sinfo->xdp_frags_size,
-				  BNXT_RX_PAGE_SIZE * num_frags,
+				  rxr->rx_page_size * num_frags,
 				  xdp_buff_get_skb_flags(xdp));
 	return skb;
 }
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h +1 -1
index 220285e190fcd..8933a0dec09a6 100644
@@ -32,6 +32,6 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
 void bnxt_xdp_buff_frags_free(struct bnxt_rx_ring_info *rxr,
 			      struct xdp_buff *xdp);
 struct sk_buff *bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb,
-				   u8 num_frags, struct page_pool *pool,
+				   u8 num_frags, struct bnxt_rx_ring_info *rxr,
 				   struct xdp_buff *xdp);
 #endif
Signature · 1 line
2.53.0
author maintainer
#63 lore raw

PATCH 63/250 eth: bnxt: support qcfg provided rx page size

In reply to Greg Kroah-Hartman

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

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

From: Pavel Begunkov <[email protected]>

[ Upstream commit f96e1b35779e153be266fd7de50bda0c5553ad21 ]

Implement support for qcfg provided rx page sizes. For that, implement the ndo_default_qcfg callback and validate the config on restart. Also, use the current config's value in bnxt_init_ring_struct to retain the correct size across resets.

Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 36 ++++++++++++++++++++++-
 drivers/net/ethernet/broadcom/bnxt/bnxt.h |  1 +
 2 files changed, 36 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +35 -1
index fddfdf807950f..52b356f4966ab 100644
@@ -4323,6 +4323,7 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
 		struct bnxt_rx_ring_info *rxr;
 		struct bnxt_tx_ring_info *txr;
 		struct bnxt_ring_struct *ring;
+		struct netdev_rx_queue *rxq;
 
 		if (!bnapi)
 			continue;
@@ -4340,7 +4341,8 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
 		if (!rxr)
 			goto skip_rx;
 
-		rxr->rx_page_size = BNXT_RX_PAGE_SIZE;
+		rxq = __netif_get_rx_queue(bp->dev, i);
+		rxr->rx_page_size = rxq->qcfg.rx_page_size;
 
 		ring = &rxr->rx_ring_struct;
 		rmem = &ring->ring_mem;
@@ -15964,6 +15966,29 @@ static const struct netdev_stat_ops bnxt_stat_ops = {
 	.get_base_stats		= bnxt_get_base_stats,
 };
 
+static void bnxt_queue_default_qcfg(struct net_device *dev,
+				    struct netdev_queue_config *qcfg)
+{
+	qcfg->rx_page_size = BNXT_RX_PAGE_SIZE;
+}
+
+static int bnxt_validate_qcfg(struct bnxt *bp, struct netdev_queue_config *qcfg)
+{
+	/* Older chips need MSS calc so rx_page_size is not supported */
+	if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
+	    qcfg->rx_page_size != BNXT_RX_PAGE_SIZE)
+		return -EINVAL;
+
+	if (!is_power_of_2(qcfg->rx_page_size))
+		return -ERANGE;
+
+	if (qcfg->rx_page_size < BNXT_RX_PAGE_SIZE ||
+	    qcfg->rx_page_size > BNXT_MAX_RX_PAGE_SIZE)
+		return -ERANGE;
+
+	return 0;
+}
+
 static int bnxt_queue_mem_alloc(struct net_device *dev,
 				struct netdev_queue_config *qcfg,
 				void *qmem, int idx)
@@ -15976,6 +16001,10 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
 	if (!bp->rx_ring)
 		return -ENETDOWN;
 
+	rc = bnxt_validate_qcfg(bp, qcfg);
+	if (rc < 0)
+		return rc;
+
 	rxr = &bp->rx_ring[idx];
 	clone = qmem;
 	memcpy(clone, rxr, sizeof(*rxr));
@@ -15987,6 +16016,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
 	clone->rx_sw_agg_prod = 0;
 	clone->rx_next_cons = 0;
 	clone->need_head_pool = false;
+	clone->rx_page_size = qcfg->rx_page_size;
 
 	rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
 	if (rc)
@@ -16113,6 +16143,8 @@ static void bnxt_copy_rx_ring(struct bnxt *bp,
 	src_ring = &src->rx_agg_ring_struct;
 	src_rmem = &src_ring->ring_mem;
 
+	dst->rx_page_size = src->rx_page_size;
+
 	WARN_ON(dst_rmem->nr_pages != src_rmem->nr_pages);
 	WARN_ON(dst_rmem->page_size != src_rmem->page_size);
 	WARN_ON(dst_rmem->flags != src_rmem->flags);
@@ -16267,6 +16299,8 @@ static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops = {
 	.ndo_queue_mem_free	= bnxt_queue_mem_free,
 	.ndo_queue_start	= bnxt_queue_start,
 	.ndo_queue_stop		= bnxt_queue_stop,
+	.ndo_default_qcfg	= bnxt_queue_default_qcfg,
+	.supported_params	= QCFG_RX_PAGE_SIZE,
 };
 
 static void bnxt_remove_one(struct pci_dev *pdev)
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
index 9a1be6b71219d..3ca989da0eb02 100644
@@ -760,6 +760,7 @@ struct nqe_cn {
 #endif
 
 #define BNXT_RX_PAGE_SIZE (1 << BNXT_RX_PAGE_SHIFT)
+#define BNXT_MAX_RX_PAGE_SIZE BIT(15)
 
 #define BNXT_MAX_MTU		9500
 
Signature · 1 line
2.53.0
author maintainer
#64 lore raw

PATCH 64/250 bnxt: fix memory leak in bnxt_queue_mem_alloc error cases

In reply to Greg Kroah-Hartman

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

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

From: Will Chen <[email protected]>

[ Upstream commit d1000fd7995e51deec872d154e0a40d82f7a539f ]

There is a small memory leak in bnxt_queue_mem_alloc:
when bnxt_alloc_rx_agg_bmap() succeeds
but bnxt_alloc_one_tpa_info() later fails, the rx_agg_bmap allocated by bnxt_alloc_rx_agg_bmap() is not freed in the fallthrough cleanup cases.

Free the rx_agg_bmap in the err_free_rx_agg_ring case and initialize clone->rx_agg_bmap = NULL earlier in the function to allow for safe fallthrough.

Fixes bd649c5cc958 ("bnxt_en: handle tpa_info in queue API implementation")
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +3 -0
index 52b356f4966ab..d90775c0ce0b5 100644
@@ -16017,6 +16017,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
 	clone->rx_next_cons = 0;
 	clone->need_head_pool = false;
 	clone->rx_page_size = qcfg->rx_page_size;
+	clone->rx_agg_bmap = NULL;
 
 	rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
 	if (rc)
@@ -16069,6 +16070,8 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
 	bnxt_free_one_tpa_info(bp, clone);
 err_free_rx_agg_ring:
 	bnxt_free_ring(bp, &clone->rx_agg_ring_struct.ring_mem);
+	kfree(clone->rx_agg_bmap);
+	clone->rx_agg_bmap = NULL;
 err_free_rx_ring:
 	bnxt_free_ring(bp, &clone->rx_ring_struct.ring_mem);
 err_rxq_info_unreg:
Signature · 1 line
2.53.0
author maintainer
#65 lore raw

PATCH 65/250 xsk: require at least 16 bytes of TX metadata

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit 1bb30b181d9f0484e141f8411e15ed906d5c6780 ]

AF_XDP accepts a TX metadata length as small as eight bytes, but every supported request needs the flags plus at least one eight-byte request field. Such short metadata also lets the kernel read beyond the registered area.

Require 16 bytes rather than sizeof(struct xsk_tx_metadata) to preserve compatibility with applications that do not use launch-time metadata.

---
 net/xdp/xdp_umem.c | 2 ++
 1 file changed, 2 insertions(+)
net/xdp/xdp_umem.c +2 -0
index 9ec7bd948acc7..81ffda5501078 100644
@@ -209,6 +209,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
 	if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {
 		if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
 			return -EINVAL;
+		if (mr->tx_metadata_len < 16)
+			return -EINVAL;
 		umem->tx_metadata_len = mr->tx_metadata_len;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#66 lore raw

PATCH 66/250 xsk: pass TX metadata pointer by reference

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit 19366db6dfccac9b0867a151678cd7b89fb8fd99 ]

Completion handling needs to know whether a timestamp was requested when the metadata was processed. Let xsk_tx_metadata_request() update the caller's metadata pointer so that decision can be carried forward without rereading user-controlled flags.

This only changes the interface; behavior remains unchanged.

Fixes ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
Cc Cen Zhang (Microsoft) <[email protected]>
---
 drivers/net/ethernet/intel/igc/igc_main.c          |  2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |  2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c   | 14 +++++++++-----
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h   |  4 ++--
 .../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c    |  2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |  2 +-
 include/net/libeth/xsk.h                           |  2 +-
 include/net/xdp_sock.h                             |  8 +++++---
 8 files changed, 21 insertions(+), 15 deletions(-)
drivers/net/ethernet/intel/igc/igc_main.c +1 -1
index 4ca242ebf3e34..f69523e35ac10 100644
@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 		meta_req.tx_buffer = bi;
 		meta_req.meta = meta;
 		meta_req.used_desc = 0;
-		xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops,
+		xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
 					&meta_req);
 
 		/* xsk_tx_metadata_request() may have updated next_to_use */
drivers/net/ethernet/mellanox/mlx5/core/en.h +1 -1
index 3d8276a0692fc..91653b69328ee 100644
@@ -477,7 +477,7 @@ typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
 typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
 					struct mlx5e_xmit_data *,
 					int,
-					struct xsk_tx_metadata *);
+					struct xsk_tx_metadata **);
 
 struct mlx5e_xdpsq {
 	/* data path */
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +9 -5
index 5322964214b22..e467a7b067c7a 100644
@@ -451,11 +451,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq
 
 INDIRECT_CALLABLE_SCOPE bool
 mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
-		     int check_result, struct xsk_tx_metadata *meta);
+		     int check_result, struct xsk_tx_metadata **meta);
 
 INDIRECT_CALLABLE_SCOPE bool
 mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
-			   int check_result, struct xsk_tx_metadata *meta)
+			   int check_result, struct xsk_tx_metadata **meta)
 {
 	struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
 	struct mlx5e_xdpsq_stats *stats = sq->stats;
@@ -503,7 +503,10 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
 		 * and it's safe to complete it at any time.
 		 */
 		mlx5e_xdp_mpwqe_session_start(sq);
-		xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth);
+		if (meta)
+			xsk_tx_metadata_request(meta,
+						&mlx5e_xsk_tx_metadata_ops,
+						&session->wqe->eth);
 	}
 
 	mlx5e_xdp_mpwqe_add_dseg(sq, p, stats);
@@ -534,7 +537,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)
 
 INDIRECT_CALLABLE_SCOPE bool
 mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
-		     int check_result, struct xsk_tx_metadata *meta)
+		     int check_result, struct xsk_tx_metadata **meta)
 {
 	struct mlx5e_xmit_data_frags *xdptxdf =
 		container_of(xdptxd, struct mlx5e_xmit_data_frags, xd);
@@ -648,7 +651,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
 
 	sq->pc += num_wqebbs;
 
-	xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+	if (meta)
+		xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
 
 	sq->doorbell_cseg = cseg;
 
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h +2 -2
index 46ab0a9e8cddb..1a9eb77981cc3 100644
@@ -113,11 +113,11 @@ extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops;
 INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
 							  struct mlx5e_xmit_data *xdptxd,
 							  int check_result,
-							  struct xsk_tx_metadata *meta));
+							  struct xsk_tx_metadata **meta));
 INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq,
 						    struct mlx5e_xmit_data *xdptxd,
 						    int check_result,
-						    struct xsk_tx_metadata *meta));
+						    struct xsk_tx_metadata **meta));
 INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq));
 INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq));
 
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c +1 -1
index a59199ed590da..827538d92ac23 100644
@@ -103,7 +103,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
 
 		ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
 				      mlx5e_xmit_xdp_frame, sq, &xdptxd,
-				      check_result, meta);
+				      check_result, &meta);
 		if (unlikely(!ret)) {
 			if (sq->mpwqe.wqe)
 				mlx5e_xdp_mpwqe_complete(sq);
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -1
index 3be0b79532496..3380ce960de24 100644
@@ -2574,7 +2574,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
 		meta_req.set_ic = &set_ic;
 		meta_req.tbs = tx_q->tbs;
 		meta_req.edesc = &tx_q->dma_entx[entry];
-		xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops,
+		xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
 					&meta_req);
 		if (set_ic) {
 			tx_q->tx_count_frames = 0;
include/net/libeth/xsk.h +1 -1
index 481a7b28e6f24..1a55daa32cf16 100644
@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
 	BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
 	tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
 
-	xsk_tx_metadata_request(ctx.meta, tmo, &desc);
+	xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
 
 	return desc;
 }
include/net/xdp_sock.h +5 -3
index 8a0967af8f0c4..b93d6bd368d00 100644
@@ -152,17 +152,19 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
 /**
  *  xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
  *  and call appropriate xsk_tx_metadata_ops operation.
- *  @meta: pointer to AF_XDP metadata area
+ *  @pmeta: pointer to pointer to AF_XDP metadata area
  *  @ops: pointer to struct xsk_tx_metadata_ops
  *  @priv: pointer to driver-private aread
  *
  *  This function should be called by the networking device when
  *  it prepares AF_XDP egress packet.
  */
-static inline void xsk_tx_metadata_request(const struct xsk_tx_metadata *meta,
+static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
 					   const struct xsk_tx_metadata_ops *ops,
 					   void *priv)
 {
+	const struct xsk_tx_metadata *meta = *pmeta;
+
 	if (!meta)
 		return;
 
@@ -224,7 +226,7 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
 {
 }
 
-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata *meta,
+static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
 					   const struct xsk_tx_metadata_ops *ops,
 					   void *priv)
 {
Signature · 1 line
2.53.0
author maintainer
#67 lore raw

PATCH 67/250 xsk: clear metadata pointer when no timestamp is requested

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit 9f60a67df8d3c862503bee62bada8e7089cba438 ]

User space can change metadata flags after request processing. Rereading them during completion can therefore make the kernel write a timestamp that was not requested when the packet was submitted.

Clear the metadata pointer during request processing unless timestamp completion is requested. Completion handling can then use the pointer itself instead of rereading the flags.

On the mlx5 multi-packet WQE path metadata is evaluated per batch:
xsk_tx_metadata_request() runs only for the descriptor that starts a session, just like the checksum offload that is applied once through the shared WQE. Only that descriptor's pointer is reset, so completion handling can record a timestamp for the other descriptors of the session regardless of their own XDP_TXMD_FLAGS_TIMESTAMP bit. The write stays inside the metadata area; the single-WQE, other zero-copy, and generic paths reset the pointer per descriptor and are unaffected.

Fixes ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
Cc Cen Zhang (Microsoft) <[email protected]>
---
 include/net/xdp_sock.h | 14 ++++++++++----
 net/xdp/xsk.c          |  2 ++
 2 files changed, 12 insertions(+), 4 deletions(-)
include/net/xdp_sock.h +10 -4
index b93d6bd368d00..e14e575178940 100644
@@ -140,13 +140,16 @@ void __xsk_map_flush(struct list_head *flush_list);
 static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
 					    struct xsk_tx_metadata_compl *compl)
 {
+	compl->tx_timestamp = NULL;
+
 	if (!meta)
 		return;
 
-	if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
-		compl->tx_timestamp = &meta->completion.tx_timestamp;
-	else
-		compl->tx_timestamp = NULL;
+	/* we can only arrive here if the completion timestamp has been
+	 * requested via XDP_TXMD_FLAGS_TIMESTAMP, see xsk_tx_metadata_request
+	 */
+
+	compl->tx_timestamp = &meta->completion.tx_timestamp;
 }
 
 /**
@@ -181,6 +184,9 @@ static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
 		if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
 			ops->tmo_request_checksum(meta->request.csum_start,
 						  meta->request.csum_offset, priv);
+
+	if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
+		*pmeta = NULL;
 }
 
 /**
net/xdp/xsk.c +2 -0
index 70c57c5d8e1da..3b82fb850bee3 100644
@@ -730,6 +730,8 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
 
 	if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
 		skb->skb_mstamp_ns = meta->request.launch_time;
+	if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
+		meta = NULL;
 	xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#68 lore raw

PATCH 68/250 xsk: validate launch-time metadata size

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit 439ce2dddf3d22129b9113a7881637256a35e936 ]

Launch-time metadata extends beyond the first 16 bytes of struct xsk_tx_metadata. Reject the request when the registered metadata area does not contain the complete field.

Snapshot the validated flags for the generic transmit path and use that snapshot for request and completion processing, avoiding inconsistent decisions if user space changes the flags concurrently.

Note that only xsk_skb_metadata is properly using the flags, __xsk_buff_get_metadata ignores them. Next commits address that.

Fixes ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
Cc Cen Zhang (Microsoft) <[email protected]>
---
 include/net/xdp_sock_drv.h | 17 +++++++++++++----
 net/xdp/xsk.c              | 11 ++++++-----
 2 files changed, 19 insertions(+), 9 deletions(-)
include/net/xdp_sock_drv.h +13 -4
index dd1d3a6e1b780..ce8315f049684 100644
@@ -256,21 +256,28 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
 	0)
 
 static inline bool
-xsk_buff_valid_tx_metadata(const struct xsk_tx_metadata *meta)
+xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+			   const struct xsk_tx_metadata *meta, u64 *flags)
 {
-	return !(meta->flags & ~XDP_TXMD_FLAGS_VALID);
+	*flags = READ_ONCE(meta->flags);
+	if (*flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+		if (pool->tx_metadata_len <
+		    offsetofend(struct xsk_tx_metadata, request.launch_time))
+			return false;
+	return !(*flags & ~XDP_TXMD_FLAGS_VALID);
 }
 
 static inline struct xsk_tx_metadata *
 __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
 {
 	struct xsk_tx_metadata *meta;
+	u64 flags;
 
 	if (!pool->tx_metadata_len)
 		return NULL;
 
 	meta = data - pool->tx_metadata_len;
-	if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
+	if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
 		return NULL; /* no way to signal the error to the user */
 
 	return meta;
@@ -465,7 +472,9 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
 	return (struct xdp_desc_ctx){ };
 }
 
-static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta)
+static inline bool
+xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+			   const struct xsk_tx_metadata *meta, u64 *flags)
 {
 	return false;
 }
net/xdp/xsk.c +6 -5
index 3b82fb850bee3..ff93fd7ac6317 100644
@@ -699,15 +699,16 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
 {
 	struct xsk_tx_metadata *meta = NULL;
 	u16 csum_start, csum_offset;
+	u64 flags;
 
 	if (unlikely(pool->tx_metadata_len == 0))
 		return -EINVAL;
 
 	meta = buffer - pool->tx_metadata_len;
-	if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
+	if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
 		return -EINVAL;
 
-	if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) {
+	if (flags & XDP_TXMD_FLAGS_CHECKSUM) {
 		csum_start = READ_ONCE(meta->request.csum_start);
 		csum_offset = READ_ONCE(meta->request.csum_offset);
 
@@ -728,9 +729,9 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
 		}
 	}
 
-	if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
-		skb->skb_mstamp_ns = meta->request.launch_time;
-	if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
+	if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+		skb->skb_mstamp_ns = READ_ONCE(meta->request.launch_time);
+	if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP))
 		meta = NULL;
 	xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
 
Signature · 1 line
2.53.0
author maintainer
#69 lore raw

PATCH 69/250 xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit ddd0d6c5bfe2fef7c7cf31f62265f29b7b9eb9ef ]

xsk_tx_metadata_request() must validate metadata with xsk_buff_valid_tx_metadata(), which is defined in xdp_sock_drv.h. Move the helper there before adding that dependency. All callers already include the destination header, so this has no functional effect.

Fixes ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
Cc Cen Zhang (Microsoft) <[email protected]>
---
 include/net/xdp_sock.h     | 43 --------------------------------------
 include/net/xdp_sock_drv.h | 43 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 43 deletions(-)
include/net/xdp_sock.h +0 -43
index e14e575178940..8bf17ba6c3bd7 100644
@@ -152,43 +152,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
 	compl->tx_timestamp = &meta->completion.tx_timestamp;
 }
 
-/**
- *  xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
- *  and call appropriate xsk_tx_metadata_ops operation.
- *  @pmeta: pointer to pointer to AF_XDP metadata area
- *  @ops: pointer to struct xsk_tx_metadata_ops
- *  @priv: pointer to driver-private aread
- *
- *  This function should be called by the networking device when
- *  it prepares AF_XDP egress packet.
- */
-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
-					   const struct xsk_tx_metadata_ops *ops,
-					   void *priv)
-{
-	const struct xsk_tx_metadata *meta = *pmeta;
-
-	if (!meta)
-		return;
-
-	if (ops->tmo_request_launch_time)
-		if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
-			ops->tmo_request_launch_time(meta->request.launch_time,
-						     priv);
-
-	if (ops->tmo_request_timestamp)
-		if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
-			ops->tmo_request_timestamp(priv);
-
-	if (ops->tmo_request_checksum)
-		if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
-			ops->tmo_request_checksum(meta->request.csum_start,
-						  meta->request.csum_offset, priv);
-
-	if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
-		*pmeta = NULL;
-}
-
 /**
  *  xsk_tx_metadata_complete - Evaluate AF_XDP TX metadata at completion
  *  and call appropriate xsk_tx_metadata_ops operation.
@@ -232,12 +195,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
 {
 }
 
-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
-					   const struct xsk_tx_metadata_ops *ops,
-					   void *priv)
-{
-}
-
 static inline void xsk_tx_metadata_complete(struct xsk_tx_metadata_compl *compl,
 					    const struct xsk_tx_metadata_ops *ops,
 					    void *priv)
include/net/xdp_sock_drv.h +43 -0

55 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#70 lore raw

PATCH 70/250 xsk: validate metadata when processing requests

In reply to Greg Kroah-Hartman

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

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

From: Stanislav Fomichev <[email protected]>

[ Upstream commit 849b1664dbda1cf6c63e0fd4f9dec23782b8c851 ]

The zero-copy path validates TX metadata while obtaining the descriptor context, then reads it again later when preparing the hardware request. User space can change the metadata between those operations and bypass the original validation.

Validate the metadata in xsk_tx_metadata_request() and use the resulting flags snapshot for every feature check. Read request fields once so all zero-copy drivers process only values observed after successful validation.

Fixes ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
Cc Cen Zhang (Microsoft) <[email protected]>
---
 drivers/net/ethernet/intel/igc/igc_main.c     |  2 +-
 .../net/ethernet/mellanox/mlx5/core/en/xdp.c  |  5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  4 +-
 include/net/libeth/xsk.h                      |  2 +-
 include/net/xdp_sock_drv.h                    | 51 ++++++++++---------
 net/xdp/xsk_buff_pool.c                       |  6 +--
 6 files changed, 37 insertions(+), 33 deletions(-)
drivers/net/ethernet/intel/igc/igc_main.c +1 -1
index f69523e35ac10..99a414440bcaa 100644
@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 		meta_req.tx_buffer = bi;
 		meta_req.meta = meta;
 		meta_req.used_desc = 0;
-		xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
+		xsk_tx_metadata_request(pool, &meta, &igc_xsk_tx_metadata_ops,
 					&meta_req);
 
 		/* xsk_tx_metadata_request() may have updated next_to_use */
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +3 -2
index e467a7b067c7a..2f52e04b28de2 100644
@@ -504,7 +504,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
 		 */
 		mlx5e_xdp_mpwqe_session_start(sq);
 		if (meta)
-			xsk_tx_metadata_request(meta,
+			xsk_tx_metadata_request(sq->xsk_pool, meta,
 						&mlx5e_xsk_tx_metadata_ops,
 						&session->wqe->eth);
 	}
@@ -652,7 +652,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
 	sq->pc += num_wqebbs;
 
 	if (meta)
-		xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+		xsk_tx_metadata_request(sq->xsk_pool, meta,
+					&mlx5e_xsk_tx_metadata_ops, eseg);
 
 	sq->doorbell_cseg = cseg;
 
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +2 -2
index 3380ce960de24..bca81ed28e073 100644
@@ -2574,8 +2574,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
 		meta_req.set_ic = &set_ic;
 		meta_req.tbs = tx_q->tbs;
 		meta_req.edesc = &tx_q->dma_entx[entry];
-		xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
-					&meta_req);
+		xsk_tx_metadata_request(pool, &meta,
+					&stmmac_xsk_tx_metadata_ops, &meta_req);
 		if (set_ic) {
 			tx_q->tx_count_frames = 0;
 			stmmac_set_tx_ic(priv, tx_desc);
include/net/libeth/xsk.h +1 -1
index 1a55daa32cf16..23eb240d5ba72 100644
@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
 	BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
 	tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
 
-	xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
+	xsk_tx_metadata_request(sq->pool, &ctx.meta, tmo, &desc);
 
 	return desc;
 }
include/net/xdp_sock_drv.h +27 -24

97 lines not on this page · raw message

net/xdp/xsk_buff_pool.c +3 -3
index c9688735b643c..772fe1838cfb3 100644
@@ -769,11 +769,11 @@ EXPORT_SYMBOL(xp_raw_get_dma);
  * @addr: desc address (from userspace)
  *
  * Helper for getting desc's DMA address and metadata pointer, if present.
- * Saves one call on hotpath, double calculation of the actual address,
- * and inline checks for metadata presence and sanity.
+ * Saves one call on hotpath and double calculation of the actual address.
+ * Metadata is validated later by xsk_tx_metadata_request().
  *
  * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata
- * pointer, if it is present and valid (initialized to %NULL otherwise).
+ * pointer, if it is present (initialized to %NULL otherwise).
  */
 struct xdp_desc_ctx xp_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
 {
Signature · 1 line
2.53.0
author maintainer
#71 lore raw

PATCH 71/250 udp: fix potential use-after-free in tunnel segmentation

In reply to Greg Kroah-Hartman

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

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

From: Xuanqiang Luo <[email protected]>

[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]

__skb_udp_tunnel_segment() gets the UDP header before ensuring the tunnel header is in the skb head. If the pull reallocates skb->head, the saved UDP header pointer is no longer valid.

Get the UDP header after the pull to avoid a potential use-after-free.

Fixes dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
---
 net/ipv4/udp_offload.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv4/udp_offload.c +3 -1
index 589456bd8b5f1..4f7ae02df8d3a 100644
@@ -178,17 +178,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
 	int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
 	bool remcsum, need_csum, offload_csum, gso_partial;
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	struct udphdr *uh = udp_hdr(skb);
 	u16 mac_offset = skb->mac_header;
 	__be16 protocol = skb->protocol;
 	u16 mac_len = skb->mac_len;
 	int udp_offset, outer_hlen;
+	struct udphdr *uh;
 	__wsum partial;
 	bool need_ipsec;
 
 	if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
 		goto out;
 
+	uh = udp_hdr(skb);
+
 	/* Adjust partial header checksum to negate old length.
 	 * We cannot rely on the value contained in uh->len as it is
 	 * possible that the actual value exceeds the boundaries of the
Signature · 1 line
2.53.0
author maintainer
#72 lore raw

PATCH 72/250 net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK filter

In reply to Greg Kroah-Hartman

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

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

From: Toke Høiland-Jørgensen <[email protected]>

[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]

The sch_cake ACK filter parses packets to find the TCP header and filter duplicated ACKs if the flow is backlogged. The parsing code contains a WARN_ON(1) which can be triggered by a malformed IP header in certain cases. Depending on the system configuration, this leads either to either spamming dmesg with warnings, or a panic if panic_on_warn is set.

The code already correctly skips the offending packet in the branch that triggers the warning, so the WARN_ON itself doesn't really serve any purpose. So just drop it altogether to avoid the inconvenient side effects.

---
 net/sched/sch_cake.c | 1 -
 1 file changed, 1 deletion(-)
net/sched/sch_cake.c +0 -1
index c19eeed7e7cfb..e03fe7096b357 100644
@@ -1268,7 +1268,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
 
 			seglen = ntohs(ipv6h_check->payload_len);
 		} else {
-			WARN_ON(1);  /* shouldn't happen */
 			continue;
 		}
 
Signature · 1 line
2.53.0
author maintainer
#73 lore raw

PATCH 73/250 vhost-scsi: Validate T10 PI scatterlist counts

In reply to Greg Kroah-Hartman

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

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

From: Linfeng Sun <[email protected]>

[ Upstream commit d876c493fc4b811941bfeb4c80beb2dfc4bf025e ]

When T10 PI is negotiated, vhost-scsi splits protection bytes from the data iterator before mapping the request scatterlists. A malformed request can claim protection bytes that cover or exceed the full payload length. The former leaves no data bytes to map, while the latter underflows exp_data_len before advancing the iterator. Both cases can let a zero data SGL count reach sg_alloc_table_chained(), which triggers BUG_ON(!nents).

Reject protection lengths that cover or exceed the payload before subtracting prot_bytes and advancing the iterator. Also propagate negative errors from the protection SGL calculation before calling the allocator, matching the data SGL path.

Fixes bca939d5bcd0 ("vhost-scsi: Dynamically allocate scatterlists")
Assisted-by OpenAI-Codex:GPT-5

Message-ID: <[email protected]>

---
 drivers/vhost/scsi.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/vhost/scsi.c +8 -0
index 98e4f68f4e3cb..65a57de0080ef 100644
@@ -971,6 +971,9 @@ vhost_scsi_mapal(struct vhost_scsi *vs, struct vhost_scsi_cmd *cmd,
 	if (prot_bytes) {
 		sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
 						 VHOST_SCSI_PREALLOC_PROT_SGLS);
+		if (sgl_count < 0)
+			return sgl_count;
+
 		cmd->prot_table.sgl = cmd->prot_sgl;
 		ret = sg_alloc_table_chained(&cmd->prot_table, sgl_count,
 					     cmd->prot_table.sgl,
@@ -1416,6 +1419,11 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
 			 * actual data payload length.
 			 */
 			if (prot_bytes) {
+				if (prot_bytes >= exp_data_len) {
+					vq_err(vq, "Protection data exceeds payload length\n");
+					goto err;
+				}
+
 				exp_data_len -= prot_bytes;
 				prot_iter = data_iter;
 				iov_iter_truncate(&prot_iter, prot_bytes);
Signature · 1 line
2.53.0
author maintainer
#74 lore raw

PATCH 74/250 vhost-scsi: reject feature changes after endpoint

In reply to Greg Kroah-Hartman

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

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

From: Jia Jia <[email protected]>

[ Upstream commit 42bc45df5905e2b7dccb72adaf7730f66cfbe03f ]

vhost_scsi_setup_vq_cmds() runs from VHOST_SCSI_SET_ENDPOINT and allocates each command's protection scatterlist array (prot_sgl) according to the acknowledged VIRTIO_SCSI_F_T10_PI bit. The command pools are not rebuilt when VHOST_SET_FEATURES changes that bit later.

Although virtio feature bits must not change after feature negotiation, vhost_scsi_set_features() currently accepts such a request after the endpoint is active and updates acked_features. Enabling T10-PI after endpoint setup therefore leaves prot_sgl NULL while the I/O path follows the new feature bit.

For a 129-page protection payload, vhost_scsi_mapal() passes the missing first chunk to sg_alloc_table_chained():

sg_alloc_table_chained(table, 129, first_chunk=NULL,
nents_first_chunk=inline_sg_cnt)

sg_pool_index() then hits:

BUG_ON(nents > SG_CHUNK_SIZE); /* 129 > 128 */

The kernel reported the following call trace and register state:

  Call Trace:
   <TASK>
   ? __sg_alloc_table+0x1d8/0x250
   ? __pfx_vhost_run_work_list+0x10/0x10 [vhost]
   sg_alloc_table_chained+0x59/0xf0
   ? __pfx_sg_pool_alloc+0x10/0x10
   ? vhost_scsi_calc_sgls.constprop.0+0x43/0x60 [vhost_scsi]
   vhost_scsi_handle_vq+0xf02/0x1700 [vhost_scsi]
   ? __pfx_vhost_scsi_handle_vq+0x10/0x10 [vhost_scsi]
   vhost_scsi_handle_kick+0x37/0x50 [vhost_scsi]
   vhost_run_work_list+0x8e/0xd0 [vhost]
   vhost_task_fn+0xe1/0x210
   ret_from_fork+0x348/0x540
   </TASK>

  RIP: 0010:0x4
  CR2 = 0x4
  RSP: 0018:ffffc90000dbf940 EFLAGS: 00010202
  RAX: ffffffff82396810 RBX: ffff88811dc28b80 RCX: 0000000000000000
  RDX: 0000000000000000 RSI: 0000000000000820 RDI: 0000000000000081

VHOST_F_LOG_ALL is a vhost-specific runtime feature and remains the only exception.

Reject changes to any feature other than VHOST_F_LOG_ALL while the endpoint is active. This preserves the existing runtime log toggle while preventing feature-dependent command resources and data-path state from becoming inconsistent. Userspace must clear the endpoint before changing any other negotiated feature and set the endpoint up again afterward.

Fixes bf2d650391be ("vhost-scsi: Allocate T10 PI structs only when enabled")

Message-ID: <[email protected]>

---
 drivers/vhost/scsi.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/vhost/scsi.c +9 -0
index 65a57de0080ef..29716ce714554 100644
@@ -2231,6 +2231,7 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
 {
 	struct vhost_virtqueue *vq;
 	bool is_log, was_log;
+	u64 old_features;
 	int i;
 
 	if (features & ~VHOST_SCSI_FEATURES)
@@ -2246,6 +2247,14 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
 	if (!vs->dev.nvqs)
 		goto out;
 
+	old_features = vs->vqs[0].vq.acked_features;
+	if (vs->vs_tpg &&
+	    ((features ^ old_features) &
+	     ~(1ULL << VHOST_F_LOG_ALL))) {
+		mutex_unlock(&vs->dev.mutex);
+		return -EBUSY;
+	}
+
 	is_log = features & (1 << VHOST_F_LOG_ALL);
 	/*
 	 * All VQs should have same feature.
Signature · 1 line
2.53.0
author maintainer
#75 lore raw

PATCH 75/250 net/openvswitch: check Ethernet header length in key_extract()

In reply to Greg Kroah-Hartman

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

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

From: Cen Zhang (Microsoft) <[email protected]>

[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]

When a packet arrives on an ARPHRD_NONE device (e.g. TUN), ovs_flow_key_extract() trusts the user-provided skb->protocol field: if it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes for MAC addresses and parse_ethertype() pulls 2 more, either of which triggers a kernel BUG in __skb_pull() when the linear area is too small.

kernel BUG at include/linux/skbuff.h:2848!

  RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
  ovs_flow_key_extract+0x419/0xa70
  ovs_vport_receive+0x222/0x390
  netdev_frame_hook+0x3e0/0x630
  tun_get_user+0x2d0c/0x38e0

Fixed by calling check_header() in key_extract() before accessing the Ethernet header.

---
 net/openvswitch/flow.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
net/openvswitch/flow.c +7 -4
index 66366982f6044..46c1d66aad8c3 100644
@@ -889,8 +889,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  * Ethernet header
  * @key: output flow key
  *
- * The caller must ensure that skb->len >= ETH_HLEN.
- *
  * Initializes @skb header fields as follows:
  *
  *    - skb->mac_header: the L2 header.
@@ -910,8 +908,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  */
 static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 {
-	struct ethhdr *eth;
-
 	/* Flags are always used as part of stats */
 	key->tp.flags = 0;
 
@@ -926,6 +922,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 		skb_reset_network_header(skb);
 		key->eth.type = skb->protocol;
 	} else {
+		struct ethhdr *eth;
+		int err;
+
+		err = check_header(skb, ETH_HLEN);
+		if (unlikely(err))
+			return err;
+
 		eth = eth_hdr(skb);
 		ether_addr_copy(key->eth.src, eth->h_source);
 		ether_addr_copy(key->eth.dst, eth->h_dest);
Signature · 1 line
2.53.0
author maintainer
#76 lore raw

PATCH 76/250 net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers

In reply to Greg Kroah-Hartman

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

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

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]

Another challenge with unlocked filters.
There is a short window in tc_new_tfilter where a tcf_proto can be found and briefly referenced by a totally unrelated, unlocked classifier's request and cause a race.

Feng created a poc which created this race with two threads, one creating a u32 filter and other a flower filter in the same chain/prio:

1. Both threads enter tc_new_tfilter, both find the chain empty, both drop filter_chain_lock
2. u32 finishes tcf_proto_create("u32") first, calls tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
3. flower finishes tcf_proto_create("flower") later, calls tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp already there, takes a reference on it, destroys flower's own tp_new and returns u32_tp to the caller.

Flower then hits the kind mismatch check (because it requested for kind "flower" but tp->ops->kind is "u32") and goes through the errout path which calls tcf_proto_put() on u32_tp. If the u32 thread has already gone through its own errout (its change() call failed on the PoC's empty options) and dropped its create and insert refs, flower's put is the last one and drops u32_tp's refcnt to zero.

At this point tp->ops->destroy() runs in a context that never took rtnl_lock. When that happens, it might cause a UAF like the following (illustrated by the PoC):

[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393) [ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524

  Call Trace:
   u32_init (net/sched/cls_u32.c:393)
   tc_new_tfilter (net/sched/cls_api.c:2378)

  Allocated by task 526:
   u32_init (net/sched/cls_u32.c:378)
   tc_new_tfilter (net/sched/cls_api.c:2378)

  Freed by task 522:
   kfree
   u32_destroy (net/sched/cls_u32.c:662)
   tcf_proto_destroy (net/sched/cls_api.c:446)
   tcf_proto_put (net/sched/cls_api.c:459)
   tc_new_tfilter (net/sched/cls_api.c:2459)

Fix this by having tcf_proto_destroy() take rtnl_lock around tp->ops->destroy() for locked classifiers whenever rtnl is not held.

To explain why I used a temp variable "not_lockless" I'd like to point to a semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here for future cleanup if deemed necessary):
The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are redundant sources of truth for whether rtnl_lock is held. Among the nine classifier destroy(..rtnl_held..) callbacks, only flower consults the rtnl_held parameter which it propagates to tc_setup_cb_destroy() and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic, fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy() (u32, bpf, mall) hardcode true always instead of forwarding the parameter.

A future cleanup should remove the rtnl_held parameter from the destroy callback signature entirely and have callers rely solely on their knowledge whether they are running in an unlocked context.

Fixes 12db03b65c2b ("net: sched: extend proto ops to support unlocked classifiers")
---
 net/sched/cls_api.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
net/sched/cls_api.c +16 -1
index 3b0a438977cd5..21a70cc9940ce 100644
@@ -443,7 +443,22 @@ static void tcf_chain_put(struct tcf_chain *chain);
 static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
 			      bool sig_destroy, struct netlink_ext_ack *extack)
 {
-	tp->ops->destroy(tp, rtnl_held, extack);
+	/* A locked classifier's destroy callback (e.g. u32_destroy) uses
+	 * rtnl_dereference() and mutates shared structures (e.g. the
+	 * tc_u_common hash list) that are only safe under rtnl_lock. When an
+	 * unlocked classifier's request (e.g. flower on ingress) loses the
+	 * tcf_chain_tp_insert_unique() race and ends up dropping the last
+	 * reference on a locked classifier's proto, destroy() would run
+	 * without rtnl held. Take it here in that case.
+	 */
+	bool not_lockless = !rtnl_held &&
+		!(tp->ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
+
+	if (not_lockless)
+		rtnl_lock();
+	tp->ops->destroy(tp, rtnl_held || not_lockless, extack);
+	if (not_lockless)
+		rtnl_unlock();
 	tcf_proto_count_usesw(tp, false);
 	if (sig_destroy)
 		tcf_proto_signal_destroyed(tp->chain, tp);
Signature · 1 line
2.53.0
author maintainer
#77 lore raw

PATCH 77/250 drm/xe/uc: Apply RCS/CCS yield policy to SR-IOV VFs

In reply to Greg Kroah-Hartman

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

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

From: Marcin Bernatowicz <[email protected]>

[ Upstream commit d1643db3b037b57f2af7f85c3821d6fe69c492f6 ]

VFs were missing the call to apply the global scheduling policy. Call xe_guc_submit_enable() during vf_uc_load_hw() to ensure VFs get the same policy enforcement as PF.

Fixes 26caeae9fb48 ("drm/xe/guc: Set RCS/CCS yield policy")
Cc Daniele Ceraolo Spurio <[email protected]>
Cc Michal Wajdeczko <[email protected]>
(cherry picked from commit f09360e857130f7ab7f069e2421e6b4a6e502531)
---
 drivers/gpu/drm/xe/xe_uc.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_uc.c +5 -2
index 465bda3554439..b799efc838017 100644
@@ -15,6 +15,7 @@
 #include "xe_guc.h"
 #include "xe_guc_pc.h"
 #include "xe_guc_engine_activity.h"
+#include "xe_guc_submit.h"
 #include "xe_huc.h"
 #include "xe_sriov.h"
 #include "xe_uc_fw.h"
@@ -160,12 +161,14 @@ static int vf_uc_load_hw(struct xe_uc *uc)
 	if (err)
 		goto err_out;
 
-	uc->guc.submission_state.enabled = true;
-
 	err = xe_guc_opt_in_features_enable(&uc->guc);
 	if (err)
 		goto err_out;
 
+	err = xe_guc_submit_enable(&uc->guc);
+	if (err)
+		return err;
+
 	err = xe_gt_record_default_lrcs(uc_to_gt(uc));
 	if (err)
 		goto err_out;
Signature · 1 line
2.53.0
author maintainer
#78 lore raw

PATCH 78/250 hwmon: (nzxt-smart2) Check return value of init_device() in probe

In reply to Greg Kroah-Hartman

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

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

From: Qingshuang Fu <[email protected]>

[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]

The init_device() call in nzxt_smart2_hid_probe() can fail because it sends HID output reports to the hardware to detect fans and set the update interval. If the hardware is not responding or the HID reports fail, init_device() returns a negative error code.

However, the return value was ignored, causing the probe to continue and register an hwmon device even though the device was never properly initialized. This leads to an inconsistent state where the driver reports stale data or blocks on wait queues that will never be woken.

The same function's return value is already checked in the reset_resume() handler, confirming the author's intent that errors should be propagated.

Note that this fix was not possible before commit 59d104b54b0b ("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop") because the out_hw_close error path was missing hid_device_io_stop(), which would have opened a use-after-free risk window.

Fixes 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
---
 drivers/hwmon/nzxt-smart2.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/hwmon/nzxt-smart2.c +5 -1
index ff0c0bee0e839..efc78a8f58c88 100644
@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
 
 	hid_device_io_start(hdev);
 
-	init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
+	ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
+	if (ret) {
+		dev_err(&hdev->dev, "init_device failed: %d\n", ret);
+		goto out_hw_close;
+	}
 
 	drvdata->hwmon =
 		hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
Signature · 1 line
2.53.0
author maintainer
#79 lore raw

PATCH 79/250 hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]

In lm25066_probe(), the PMBus coefficients for current and power are scaled based on the shunt resistor value. The calculation evaluates the multiplication using 32-bit arithmetic because info->m is an int and shunt is a u32:

static int lm25066_probe(struct i2c_client *client) {
    ...
    info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
    info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
    ...
}

For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device tree shunt-resistor-micro-ohms value exceeding approximately 159,000 (159 mOhm, which is physically valid for low-current applications) causes the intermediate product to exceed UINT_MAX (4,294,967,295). This results in a silent wraparound before the division by 1000.

Furthermore, if the wrapped value has the most significant bit set, converting it back to the signed int info->m results in negative coefficients. This logic error leads to drastically corrupted current and power readings, which can cause erratic thermal or power management behavior in the system.

Fix the problem by using 64-bit operations for the multiply/divide operations. This can still overflow, but only for unreasonably large shunt resistor values.

Fixes 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
---
 drivers/hwmon/pmbus/lm25066.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hwmon/pmbus/lm25066.c +3 -2
index dd7275a67a0ab..7774d678022e2 100644
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/math.h>
 #include <linux/of.h>
 #include "pmbus.h"
 
@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
 	if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
 		shunt = 1000;
 
-	info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
-	info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+	info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
+	info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
 
 #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
 	/* LM25056 doesn't support OPERATION */
Signature · 1 line
2.53.0
author maintainer
#80 lore raw

PATCH 80/250 selftests/ftrace: refactor eprobes test to fix argument checks

In reply to Greg Kroah-Hartman

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

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

From: Martin Kaiser <[email protected]>

[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]

The add/remove eprobe test installs an eprobe for the openat syscall and runs ls. It checks the filenames that were opened by ls against a whitelist and a blacklist.

Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer") fixed access to some string fields in eprobes. This triggers test failures as the blacklist does not allow relative paths for the openat parameters.

What makes this test unstable is the fact that the openat calls vary a lot between different systems.

Refactor the test to make it more robust. "cd <directory>" will issue a chdir syscall with the target directory as parameter. Set an eprobe on the sys_enter_chdir event and filter for the exact directory name. Allow (fault) as fallback.

Fixes 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
---
 .../ftrace/test.d/dynevent/add_remove_eprobe.tc  | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)
tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc +5 -11
index c300eb0202620..e2322693d0c32 100644
@@ -1,16 +1,16 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 # description: Generic dynamic event - add/remove eprobe events
-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
+# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
 
 echo 0 > events/enable
 
 clear_dynamic_events
 
 SYSTEM="syscalls"
-EVENT="sys_enter_openat"
+EVENT="sys_enter_chdir"
 FIELD="filename"
-EPROBE="eprobe_open"
+EPROBE="eprobe_chdir"
 OPTIONS="file=+0(\$filename):ustring"
 echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
 
@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
 test -d events/eprobes/$EPROBE
 
 echo 1 > events/eprobes/$EPROBE/enable
-ls
+cd /sys/kernel/tracing
 echo 0 > events/eprobes/$EPROBE/enable
 
-content=`grep '^ *ls-' trace | grep 'file='`
-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
-
+content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
 if [ -z "$content" ]; then
 	exit_fail
 fi
 
-if [ ! -z "$nocontent" ]; then
-	exit_fail
-fi
-
 echo "-:$EPROBE" >> dynamic_events
 
 ! grep -q "$EPROBE" dynamic_events
Signature · 1 line
2.53.0
author maintainer
#81 lore raw

PATCH 81/250 net: stmmac: resume PHY before hardware setup when opening the interface

In reply to Greg Kroah-Hartman

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

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

From: Stefan Agner <[email protected]>

[ Upstream commit 06232cb44bc8e81adc2f1d40a01bed830b607ea2 ]

Since the referenced commit, changing the MTU on a running interface no longer disconnects and reconnects the PHY; __stmmac_release() merely stops phylink, which also suspends the PHY (BMCR power-down) when WoL is not enabled. __stmmac_open() then performs the DMA software reset in stmmac_hw_setup() before phylink_start() resumes the PHY again.

IEEE 802.3 22.2.4.1.5 allows a PHY to stop its receive clock while powered down, and stmmac requires a running receive clock for the DMA software reset to complete (the phylink config sets mac_requires_rxc). On such setups, e.g. the RK3566-based Home Assistant Green with an RTL8211F-VD PHY in RGMII mode, any runtime MTU change now times out and leaves the interface dead:

rk_gmac-dwmac fe010000.ethernet end0: Failed to reset the dma rk_gmac-dwmac fe010000.ethernet end0: stmmac_hw_setup: DMA engine initialization failed rk_gmac-dwmac fe010000.ethernet end0: __stmmac_open: Hw setup failed rk_gmac-dwmac fe010000.ethernet end0: failed reopening the interface after MTU change

In the field this is triggered by NetworkManager applying an MTU while activating the connection, breaking networking entirely. The same regression has also been reported on i.MX8MP and reproduced on SoCFPGA based systems.

Resume the PHY in __stmmac_open() before the hardware setup, making it the counterpart of the phylink_stop() in __stmmac_release(), like stmmac_resume() already does for the same reason. phylink_start() also resumes the PHY, but only after stmmac_hw_setup(), and it cannot be moved before the hardware setup since it may bring the link up immediately from a workqueue, racing with the initialization (see the comment in stmmac_resume()). For the regular ndo_open path the PHY has just been attached and is not suspended, in which case phylink_prepare_resume() does nothing.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +9 -0
index bca81ed28e073..bf2fa56b861be 100644
@@ -3893,6 +3893,15 @@ static int __stmmac_open(struct net_device *dev,
 			dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
 	memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
 
+	/* The PHY is suspended when the interface is reopened without
+	 * disconnecting the PHY, e.g. on MTU change. IEEE 802.3 allows PHYs
+	 * to stop their receive clock while powered down, but the DMA
+	 * software reset in stmmac_hw_setup() requires a running receive
+	 * clock, and phylink_start() below resumes the PHY only after the
+	 * hardware setup. Resume a suspended PHY here first.
+	 */
+	phylink_prepare_resume(priv->phylink);
+
 	stmmac_reset_queues_param(priv);
 
 	if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
Signature · 1 line
2.53.0
author maintainer
#82 lore raw

PATCH 82/250 bnge: use int for bnge_fix_rings_count() return value

In reply to Greg Kroah-Hartman

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

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

From: Alok Tiwari <[email protected]>

[ Upstream commit 2cbd8a4e5e09aa232a1f8d56ce3d070b18ab2b10 ]

bnge_fix_rings_count() returns 0 on success or a negative errno on failure However, bnge_adjust_rings() stores its return value in a u16 variable, causing negative error codes such as -ENOMEM to be converted to a large positive value.

Use an int for the return code variable so that error values are preserved and propagated correctly.

---
 drivers/net/ethernet/broadcom/bnge/bnge_resc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnge/bnge_resc.c +2 -1
index 62ebe03a0dcf3..39cc392bd8c4b 100644
@@ -151,7 +151,8 @@ static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx,
 	u16 tx_chunks = bnge_num_tx_to_cp(bd, *tx);
 
 	if (tx_chunks != *tx) {
-		u16 tx_saved = tx_chunks, rc;
+		u16 tx_saved = tx_chunks;
+		int rc;
 
 		rc = bnge_fix_rings_count(rx, &tx_chunks, max_nq, sh);
 		if (rc)
Signature · 1 line
2.53.0
author maintainer
#83 lore raw

PATCH 83/250 net/mlx5e: fix BQL reset on SQ re-activation

In reply to Greg Kroah-Hartman

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

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

From: Bobby Eshleman <[email protected]>

[ Upstream commit e7386770be1bf810bcd6af39d1e4bfeab3408430 ]

mlx5e_queue_start() deactivates and re-activates all channels but closes only the queue being restarted. mlx5e_activate_txqsq() then unconditionally calls netdev_tx_reset_queue(), zeroing the BQL counters of channels that kept their in-flight TX WQEs. The next completion then over-charges and trips the BUG_ON() in dql_completed():

kernel BUG at lib/dynamic_queue_limits.c:99!

  RIP: 0010:dql_completed+0x23d/0x280
  Call Trace:
   <IRQ>
   mlx5e_poll_tx_cq+0x668/0xa60
   mlx5e_napi_poll+0x5b/0x7b0
   net_rx_action+0x15a/0x580

Reset BQL only when the SQ has no bytes in flight (sq->cc == sq->pc).

In the case that reset is skipped, the outstanding WQEs will eventually complete and rebalance the dql. The dql->limit is carried across the reset.

Fixes b2588ea40ec9 ("net/mlx5e: Implement queue mgmt ops and single channel swap")
---
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +3 -1
index 58e255910c43e..a7d84b540488a 100644
@@ -1926,8 +1926,10 @@ int mlx5e_open_txqsq(struct mlx5e_channel *c, u32 tisn, int txq_ix,
 void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq)
 {
 	sq->txq = netdev_get_tx_queue(sq->netdev, sq->txq_ix);
+	/* Reset BQL only when the SQ has no bytes in flight. */
+	if (sq->cc == sq->pc)
+		netdev_tx_reset_queue(sq->txq);
 	set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
-	netdev_tx_reset_queue(sq->txq);
 	netif_tx_start_queue(sq->txq);
 	netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, sq->cq.napi);
 }
Signature · 1 line
2.53.0
author maintainer
#84 lore raw

PATCH 84/250 bnxt_en: Move RSS table fill outside __bnxt_hwrm_vnic_set_rss()

In reply to Greg Kroah-Hartman

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

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

From: Shravya KN <[email protected]>

[ Upstream commit 1d0fc6c7ea49994b8ff50d02979d1e4207ec6c4f ]

This is a refactor patch with no change in behavior. The caller will now fill the RSS table before calling __bnxt_hwrm_vnic_set_rss(). In the next patch, we'll add code to determine the default ring for the VNIC when we fill the RSS table.

Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +7 -7
index d90775c0ce0b5..fba5b7f27ce7b 100644
@@ -6595,6 +6595,9 @@ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 	bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
 	u16 i, j;
 
+	if (!vnic->rss_table)
+		return;
+
 	/* Fill the RSS indirection table with ring group ids */
 	for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
 		if (!no_rss)
@@ -6634,13 +6637,8 @@ static void
 __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
 			 struct bnxt_vnic_info *vnic)
 {
-	if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
-		bnxt_fill_hw_rss_tbl_p5(bp, vnic);
-		if (bp->flags & BNXT_FLAG_CHIP_P7)
-			req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
-	} else {
-		bnxt_fill_hw_rss_tbl(bp, vnic);
-	}
+	if (bp->flags & BNXT_FLAG_CHIP_P7)
+		req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
 
 	if (bp->rss_hash_delta) {
 		req->hash_type = cpu_to_le32(bp->rss_hash_delta);
@@ -6692,6 +6690,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp,
 	if (!set_rss)
 		return hwrm_req_send(bp, req);
 
+	bnxt_fill_hw_rss_tbl_p5(bp, vnic);
 	__bnxt_hwrm_vnic_set_rss(bp, req, vnic);
 	ring_tbl_map = vnic->rss_table_dma_addr;
 	nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings);
@@ -10722,6 +10721,7 @@ static int __bnxt_setup_vnic(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 	}
 
 skip_rss_ctx:
+	bnxt_fill_hw_rss_tbl(bp, vnic);
 	/* configure default vnic, ring grp */
 	rc = bnxt_hwrm_vnic_cfg(bp, vnic);
 	if (rc) {
Signature · 1 line
2.53.0
author maintainer
#85 lore raw

PATCH 85/250 bnxt_en: Determine and store default RX ring in vnic structure

In reply to Greg Kroah-Hartman

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

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

From: Shravya KN <[email protected]>

[ Upstream commit 53f01cd594e223aabb538d5288e60111523c96f2 ]

Each VNIC has a default RX ring. The purpose of the default RX ring is to provide a destination for any packets that cannot be parsed by the RSS logic. Up until now, the default RX ring is always Ring 0.

We neglected to take care of this default RX ring when adding the queue restart feature. If ring 0 (default ring) is re-started, it may now have a new FW ring ID after freeing the old one and allocating a new one. The VNIC now may have a stale default ring and it may generate an internal exception. This exception may appear in dmesg:

FW reported unknown error type 10

The best way to resolve this issue is to use a more appropriate ring for the default ring instead of always ring 0. Ring 0 may not even be in the RSS table, especially on a new RSS context.

This patch adds the logic to determine and store the proper default RX ring for a VNIC. For an RSS VNIC, the default ring is the lowest ring number in the RSS table. The next patch will add proper logic to update the VNIC if the default ring changes after queue restart.

Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 +++++++++++++++--------
 drivers/net/ethernet/broadcom/bnxt/bnxt.h |  1 +
 2 files changed, 23 insertions(+), 11 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +22 -11
index fba5b7f27ce7b..df5fd228d84ae 100644
@@ -6593,25 +6593,36 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings)
 static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 {
 	bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
-	u16 i, j;
+	u16 i, j, min_j = bp->rx_nr_rings - 1;
 
 	if (!vnic->rss_table)
-		return;
+		goto skip_rss_tbl;
 
 	/* Fill the RSS indirection table with ring group ids */
 	for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
 		if (!no_rss)
 			j = bp->rss_indir_tbl[i];
+		min_j = min(j, min_j);
 		vnic->rss_table[i] = cpu_to_le16(vnic->fw_grp_ids[j]);
 	}
+
+skip_rss_tbl:
+	if (vnic->rss_table && !no_rss)
+		vnic->default_rx_ring = min_j;
+	else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
+		vnic->default_rx_ring = vnic->vnic_id - 1;
+	else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
+		vnic->default_rx_ring = bp->rx_nr_rings - 1;
+	else
+		vnic->default_rx_ring = 0;
 }
 
 static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
 				    struct bnxt_vnic_info *vnic)
 {
+	u16 tbl_size, i, min_j = bp->rx_nr_rings - 1;
 	__le16 *ring_tbl = vnic->rss_table;
 	struct bnxt_rx_ring_info *rxr;
-	u16 tbl_size, i;
 
 	tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
 
@@ -6624,6 +6635,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
 			j = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
 		else
 			j = bp->rss_indir_tbl[i];
+		min_j = min(j, min_j);
 		rxr = &bp->rx_ring[j];
 
 		ring_id = rxr->rx_ring_struct.fw_ring_id;
@@ -6631,6 +6643,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
 		ring_id = bnxt_cp_ring_for_rx(bp, rxr);
 		*ring_tbl++ = cpu_to_le16(ring_id);
 	}
+	vnic->default_rx_ring = min_j;
 }
 
 static void
@@ -6827,8 +6840,9 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 		return rc;
 
 	if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
-		struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
+		struct bnxt_rx_ring_info *rxr;
 
+		rxr = &bp->rx_ring[vnic->default_rx_ring];
 		req->default_rx_ring_id =
 			cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
 		req->default_cmpl_ring_id =
@@ -6861,13 +6875,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 		req->cos_rule = cpu_to_le16(0xffff);
 	}
 
-	if (vnic->flags & BNXT_VNIC_RSS_FLAG)
-		ring = 0;
-	else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
-		ring = vnic->vnic_id - 1;
-	else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
-		ring = bp->rx_nr_rings - 1;
-
+	ring = vnic->default_rx_ring;
 	grp_idx = bp->rx_ring[ring].bnapi->index;
 	req->dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id);
 	req->lb_rule = cpu_to_le16(0xffff);
@@ -11027,6 +11035,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp)
 		return rc;
 	}
 
+	/* Setup the proper default RX ring */
+	bnxt_fill_hw_rss_tbl(bp, vnic);
+
 	rc = bnxt_hwrm_vnic_cfg(bp, vnic);
 	if (rc) {
 		netdev_err(bp->dev, "Cannot allocate special vnic for NS2 A0: %x\n",
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
index 3ca989da0eb02..9d9ad2be3239b 100644
@@ -1318,6 +1318,7 @@ struct bnxt_vnic_info {
 #define BNXT_VNIC_RSSCTX_FLAG		0x40
 	struct ethtool_rxfh_context *rss_ctx;
 	u32		vnic_id;
+	u16		default_rx_ring;
 };
 
 struct bnxt_rss_ctx {
Signature · 1 line
2.53.0
author maintainer
#86 lore raw

PATCH 86/250 bnxt_en: Refresh VNIC default ring on queue restart if needed

In reply to Greg Kroah-Hartman

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

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

From: Shravya KN <[email protected]>

[ Upstream commit 0b137529a8997caf67190ca1d71ba8bbdb44fbfb ]

When a queue is restarted, refresh VNIC_CFG for all VNICs whose default RX ring is the restarted ring. This will eliminate this possible FW warning caused by a stale default ring in the VNIC:

FW reported unknown error type 10

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +5 -0
index df5fd228d84ae..0d6b6866154ab 100644
@@ -10954,6 +10954,11 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
 				   vnic->vnic_id, rc);
 			return rc;
 		}
+		if (rxr_id == vnic->default_rx_ring) {
+			rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+			if (rc)
+				return rc;
+		}
 	}
 	vnic->mru = mru;
 	bnxt_hwrm_vnic_update(bp, vnic,
Signature · 1 line
2.53.0
author maintainer
#87 lore raw

PATCH 87/250 bnxt_en: Disable EOP for TPA on all chips to prevent data corruption

In reply to Greg Kroah-Hartman

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

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

From: Michael Chan <[email protected]>

[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]

EOP (End of frame padding) on the AGG ring may cause overlapping of zero padding at the end of one segment with the next segment's data. If Relaxed Ordering (RO) is enabled, the zero padding may overwrite valid data in the next segment and corrupt the data. Older chips (P5 and older) do not automatically disable RO when EOP is enabled. On some ARM systems, data corruption was reported on 57508 (P5) chips with RO enabled.

Always disable EOP on all chips on the AGG rings when TPA is enabled to fix the data corruption.

Fixes bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +7 -4
index 0d6b6866154ab..83ddf753b8c99 100644
@@ -4506,11 +4506,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
 		type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
 			RX_BD_TYPE_RX_AGG_BD;
 
-		/* On P7, setting EOP will cause the chip to disable
-		 * Relaxed Ordering (RO) for TPA data.  Disable EOP for
-		 * potentially higher performance with RO.
+		/* Disable EOP if TPA is enabled to prevent overlapping zero
+		 * padding with the next segment's data.  On P7_PLUS, EOP will
+		 * automatically disable Relaxed Ordering (RO) to prevent
+		 * potential data corruption (and may degrade performance).  On
+		 * older chips, RO will not be automatically disabled and may
+		 * cause corruption.
 		 */
-		if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
+		if (!(bp->flags & BNXT_FLAG_TPA))
 			type |= RX_BD_FLAGS_AGG_EOP;
 
 		bnxt_init_rxbd_pages(ring, type);
Signature · 1 line
2.53.0
author maintainer
#88 lore raw

PATCH 88/250 bnxt_en: Fix PTP PPS setting bug

In reply to Greg Kroah-Hartman

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

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

From: Keegan Freyhof <[email protected]>

[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]

The existing driver logic is always turning on PTP_CLK_REQ_PPS regardless of the "on" parameter passed to bnxt_ptp_enable(). During shutdown, PTP_CLK_REQ_PPS may be turned off and this bug will do the opposite and may trigger a PCIe PTM request TLP. On some systems this can trigger a PCIe AER.

Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on" parameter.

---
 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +5 -2
index 0abaa2bbe3577..44b7afe9a6f56 100644
@@ -514,12 +514,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
 		return rc;
 	case PTP_CLK_REQ_PPS:
 		/* Configure PHC PPS IN */
-		rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
+		pin_id = 0;
+		if (!on)
+			break;
+		rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
 		if (rc)
 			return rc;
 		rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
 		if (!rc)
-			ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
+			ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
 		return rc;
 	default:
 		netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
Signature · 1 line
2.53.0
author maintainer
#89 lore raw

PATCH 89/250 sctp: fix addip_serial increment on ASCONF_ACK allocation failure

In reply to Greg Kroah-Hartman

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

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

From: Qing Luo <[email protected]>

[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]

In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate the ASCONF_ACK chunk due to memory pressure, the code jumps to the done label where asoc->peer.addip_serial is unconditionally incremented.

This leaves the peer's ASCONF (serial N) unacknowledged while the local endpoint now expects serial N+1. When the peer retransmits serial N, it falls into the serial < addip_serial + 1 branch ,
which attempts to look up a cached ACK for serial N. No cached ACK exists since the allocation failed, so the retransmission is silently discarded. The peer eventually times out and ABORTs the association.

Move the addip_serial increment inside the if (asconf_ack) block so that the serial number is only advanced when the ASCONF_ACK is successfully created and cached. This way, on allocation failure, the serial number is unchanged and the peer's retransmitted ASCONF will be correctly re-processed.

---
 net/sctp/sm_make_chunk.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
net/sctp/sm_make_chunk.c +1 -2
index 721e147091a97..757aff3e917dc 100644
@@ -3336,12 +3336,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
 			goto done;
 	}
 done:
-	asoc->peer.addip_serial++;
-
 	/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
 	 * after freeing the reference to old asconf ack if any.
 	 */
 	if (asconf_ack) {
+		asoc->peer.addip_serial++;
 		sctp_chunk_hold(asconf_ack);
 		list_add_tail(&asconf_ack->transmitted_list,
 			      &asoc->asconf_ack_list);
Signature · 1 line
2.53.0
author maintainer
#90 lore raw

PATCH 90/250 tcp: fix TFO max_qlen accounting across reuseport migration

In reply to Greg Kroah-Hartman

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

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

From: Jiayuan Chen <[email protected]>

[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]

A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through far more pending Fast Open requests than it was configured for.

This only shows up with SO_REUSEPORT listener migration, where closing a listener hands its still-pending TFO children over to a surviving one.

fastopenq.qlen is charged in tcp_fastopen_create_child() when the child is created and uncharged in reqsk_fastopen_remove() when the handshake completes. The uncharge follows rsk_listener of the request the child points at, and inet_reqsk_clone() has repointed the child at a new request owned by the new listener, so the ++ and the -- land on two different sockets. The new listener's qlen drifts negative and its limit no longer binds.

Charge the new listener during migration, like reqsk_queue_migrated() already does for queue->young and queue->qlen.

Fixes 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
---
 net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
net/ipv4/inet_connection_sock.c +16 -4
index 1679bfefa560d..5db36e323e683 100644
@@ -964,11 +964,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
 
 	nreq->rsk_listener = sk;
 
-	/* We need not acquire fastopenq->lock
-	 * because the child socket is locked in inet_csk_listen_stop().
-	 */
-	if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
+	if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
+		struct fastopen_queue *fastopenq;
+
+		/* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
+		 * that is @sk, so charge it here.  Unlike the listener
+		 * being closed, @sk is live and needs its lock.
+		 */
+		fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
+		spin_lock_bh(&fastopenq->lock);
+		fastopenq->qlen++;
+		spin_unlock_bh(&fastopenq->lock);
+
+		/* We need not acquire fastopenq->lock
+		 * because the child socket is locked in inet_csk_listen_stop().
+		 */
 		rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
+	}
 
 	return nreq;
 }
Signature · 1 line
2.53.0
author maintainer
#91 lore raw

PATCH 91/250 netfilter: flowtable: consolidate xmit path

In reply to Greg Kroah-Hartman

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

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

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit b5964aac51e0c286a50e68225e0dfcf11fb554cb ]

Use dev_queue_xmit() for the XMIT_NEIGH case. Store the interface index of the real device behind the vlan/pppoe device, this introduces an extra lookup for the real device in the xmit path because rt->dst.dev provides the vlan/pppoe device.

XMIT_NEIGH now looks more similar to XMIT_DIRECT but the check for stale dst and the neighbour lookup still remain in place which is convenient to deal with network topology changes.

Note that nft_flow_route() needs to relax the check for _XMIT_NEIGH so the existing basic xfrm offload (which only works in one direction) does not break.

Stable-dep-of: 8aecf0bbcc72 ("netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()")

---
 include/net/netfilter/nf_flow_table.h |  1 +
 net/netfilter/nf_flow_table_core.c    |  1 +
 net/netfilter/nf_flow_table_ip.c      | 87 ++++++++++++++++-----------
 net/netfilter/nf_flow_table_path.c    |  7 +--
 4 files changed, 57 insertions(+), 39 deletions(-)
include/net/netfilter/nf_flow_table.h +1 -0
index e9f72d2558e90..7c330caae52bf 100644
@@ -141,6 +141,7 @@ struct flow_offload_tuple {
 	union {
 		struct {
 			struct dst_entry *dst_cache;
+			u32		ifidx;
 			u32		dst_cookie;
 		};
 		struct {
net/netfilter/nf_flow_table_core.c +1 -0
index d3104816b7f71..595a0f19d15e7 100644
@@ -132,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
 		break;
 	case FLOW_OFFLOAD_XMIT_XFRM:
 	case FLOW_OFFLOAD_XMIT_NEIGH:
+		flow_tuple->ifidx = route->tuple[dir].out.ifindex;
 		flow_tuple->dst_cache = dst;
 		flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple);
 		break;
net/netfilter/nf_flow_table_ip.c +52 -35

139 lines not on this page · raw message

net/netfilter/nf_flow_table_path.c +3 -4
index 76d4ff1454398..da56fda2c2b39 100644
@@ -213,11 +213,11 @@ static void nft_dev_forward_path(struct nf_flow_route *route,
 	}
 	route->tuple[!dir].in.num_encaps = info.num_encaps;
 	route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
+	route->tuple[dir].out.ifindex = info.outdev->ifindex;
 
 	if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
 		memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
 		memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
-		route->tuple[dir].out.ifindex = info.outdev->ifindex;
 		route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
 		route->tuple[dir].xmit_type = info.xmit_type;
 	}
@@ -265,11 +265,10 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
 	nft_default_forward_path(route, this_dst, dir);
 	nft_default_forward_path(route, other_dst, !dir);
 
-	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
-	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH)
 		nft_dev_forward_path(route, ct, dir, ft);
+	if (route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
 		nft_dev_forward_path(route, ct, !dir, ft);
-	}
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#92 lore raw

PATCH 92/250 netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit 8aecf0bbcc72605592134c917c222207d8f63ab0 ]

Incoming skbs passing through netfilter flowtable offload hooks (or XFRM offload path) might already carry a ref-counted dst_entry assigned during earlier RX or routing steps.

Calling skb_dst_set_noref() when skb already holds a ref-counted dst overwrites skb->_skb_refdst, leaking the previous dst_entry reference count and triggering a DEBUG_NET_WARN_ON_ONCE assertion in skb_dst_check_unset():

  WARNING: at skb_dst_check_unset include/linux/skbuff.h:1170
  WARNING: at skb_dst_set_noref include/linux/skbuff.h:1234
  WARNING: at nf_flow_offload_ip_hook+0xf6c/0x2b60 net/netfilter/nf_flow_table_ip.c:864

Drop any existing dst_entry reference with skb_dst_drop(skb) before setting the non-referenced flowtable destination.

---
 net/netfilter/nf_flow_table_ip.c | 3 +++
 1 file changed, 3 insertions(+)
net/netfilter/nf_flow_table_ip.c +3 -0
index eb4f6a11e779f..4dcc30e7f9e5e 100644
@@ -272,6 +272,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
 				      struct dst_entry *dst)
 {
 	skb_orphan(skb);
+	skb_dst_drop(skb);
 	skb_dst_set_noref(skb, dst);
 	dst_output(state->net, state->sk, skb);
 	return NF_STOLEN;
@@ -464,6 +465,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 			return NF_DROP;
 		}
 		xmit.dest = neigh->ha;
+		skb_dst_drop(skb);
 		skb_dst_set_noref(skb, &rt->dst);
 		break;
 	case FLOW_OFFLOAD_XMIT_DIRECT:
@@ -768,6 +770,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 			return NF_DROP;
 		}
 		xmit.dest = neigh->ha;
+		skb_dst_drop(skb);
 		skb_dst_set_noref(skb, &rt->dst);
 		break;
 	case FLOW_OFFLOAD_XMIT_DIRECT:
Signature · 1 line
2.53.0
author maintainer
#93 lore raw

PATCH 93/250 net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length

In reply to Greg Kroah-Hartman

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

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

From: Henry Martin <[email protected]>

[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]

ncsi_send_cmd_nl() takes the number of bytes to copy from the attacker-controlled ncsi_pkt_hdr.length field of the in-band packet header, while the source buffer is the NCSI_ATTR_DATA netlink attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr). The two length sources are never cross-checked: only nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.

With hdr->length set larger than the attribute payload (up to 65535 against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies past the end of the netlink attribute buffer with unsafe_memcpy(), leaking up to ~64KB of kernel heap memory into the transmitted NCSI command packet. The destination skb is sized by the declared payload, so the write side does not overflow - this is a pure OOB read / information leak, reachable with CAP_NET_ADMIN on systems with a registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where NET_NCSI=y is standard).

Reject commands whose declared payload extends past the end of the data attribute.

The issue was found by the autokbug dynamic kernel fuzzer at Tencent Yunding Lab.

Fixes 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
---
 net/ncsi/ncsi-netlink.c | 4 ++++
 1 file changed, 4 insertions(+)
net/ncsi/ncsi-netlink.c +4 -0
index 2f872d064396d..8cc538358f6a3 100644
@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
 	nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
 	nca.info = info;
 	nca.payload = ntohs(hdr->length);
+	if (nca.payload > len - sizeof(*hdr)) {
+		ret = -EINVAL;
+		goto out_netlink;
+	}
 	nca.data = data + sizeof(*hdr);
 
 	ret = ncsi_xmit_cmd(&nca);
Signature · 1 line
2.53.0
author maintainer
#94 lore raw

PATCH 94/250 net: prestera: validate firmware header length

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]

prestera_fw_hdr_parse() reads the firmware header before checking that the firmware image contains that header.

Reject images shorter than struct prestera_fw_header before decoding the magic and version fields.

Fixes 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
---
 drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/prestera/prestera_pci.c +3 -0
index 3e13322470da6..bacc869551dfd 100644
@@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
 	struct prestera_fw_header *hdr;
 	u32 magic;
 
+	if (fw->bin->size < sizeof(*hdr))
+		return -EINVAL;
+
 	hdr = (struct prestera_fw_header *)fw->bin->data;
 
 	magic = be32_to_cpu(hdr->magic_number);
Signature · 1 line
2.53.0
author maintainer
#95 lore raw

PATCH 95/250 net: remove WARN_ON_ONCE() from sk_mc_loop()

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]

sk_mc_loop() can be called for sockets that are neither AF_INET nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet socket over virtual devices such as VRF or ipvlan).

In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls through the switch statement and triggers WARN_ON_ONCE(1).

Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP options, so loopback should default to true without generating a warning.

Fixes f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
Reported-by [email protected]
---
 net/core/sock.c | 1 -
 1 file changed, 1 deletion(-)
net/core/sock.c +0 -1
index 5a658606c50e8..b69c574c20ad3 100644
@@ -786,7 +786,6 @@ bool sk_mc_loop(const struct sock *sk)
 		return inet6_test_bit(MC6_LOOP, sk);
 #endif
 	}
-	WARN_ON_ONCE(1);
 	return true;
 }
 EXPORT_SYMBOL(sk_mc_loop);
Signature · 1 line
2.53.0
author maintainer
#96 lore raw

PATCH 96/250 net/smc: fix TOCTOU race between smc_listen_out() and listener close

In reply to Greg Kroah-Hartman

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

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

From: Sidraya Jayagond <[email protected]>

[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]

smc_listen_out() reads lsmc->sk.sk_state without the listener lock, then acquires lock_sock_nested() only after the check passes. This opens a window where smc_close_active() can transition the listener to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept queue, and release the lock, all between the lockless read and the delayed lock acquisition:

smc_listen_work (smc_hs_wq) smc_close_active()
------------------------------- -------------------------
release_sock(child)
if (sk_state == SMC_LISTEN) TRUE
lock_sock(listener) sk_state = SMC_CLOSED smc_close_cleanup_listen() release_sock(listener) flush_work(tcp_listen_work)
lock_sock_nested(listener)
smc_accept_enqueue(listener, child) /* child enqueued on dead listener */

smc_close_active() flushes only tcp_listen_work. Work items already dispatched onto smc_hs_wq for the CLC handshake continue running unguarded. smc_accept_enqueue() takes a sock_hold() on the child that is never released, so the child smc_sock, its clcsock, and the reference all leak. A remote peer that opens TCP connections while the server calls close() can exhaust kernel memory.

Move lock_sock_nested() to before the sk_state check so that the test and the enqueue are atomic under the listener lock.

---
 net/smc/af_smc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/smc/af_smc.c +2 -1
index 47963eda478f6..bc7b4a33b7261 100644
@@ -1935,11 +1935,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
 		atomic_dec(&lsmc->queued_smc_hs);
 
 	release_sock(newsmcsk); /* lock in smc_listen_work() */
+	lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
 	if (lsmc->sk.sk_state == SMC_LISTEN) {
-		lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
 		smc_accept_enqueue(&lsmc->sk, newsmcsk);
 		release_sock(&lsmc->sk);
 	} else { /* no longer listening */
+		release_sock(&lsmc->sk);
 		smc_close_non_accepted(newsmcsk);
 	}
 
Signature · 1 line
2.53.0
author maintainer
#97 lore raw

PATCH 97/250 net: thunderbolt: Tear down DMA paths before stopping the rings

In reply to Greg Kroah-Hartman

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

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

From: Fan XinRan <[email protected]>

[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]

tbnet_tear_down() stops both rings and frees their frame buffers before calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's descriptor base and tbnet_free_buffers() unmaps and frees the pages the frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's 'pending' bit, anything still in flight has nowhere to drain to.

The teardown sequence has been in this order since the driver was added. The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable DMA paths only after rings are enabled") moved the path enable to the end of tbnet_connected_work() and documented why:

/* Both logins successful so enable the rings, high-speed DMA
* paths and start the network device queue.
*
* Note we enable the DMA paths last to make sure we have primed
* the Rx ring before any incoming packets are allowed to
* arrive.
*/

Teardown was never updated to match, so the rings and the paths now come down in the same order they go up instead of in reverse.

On an ASMedia ASM4242 host router the 'pending' bit then never clears:
every teardown burns the full 500 ms timeout and __tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to 5 s does not help, so the hop is not slow to drain, it never drains at all.

The failure is invisible above the thunderbolt core. __tb_path_deactivate_hops() is void and only calls tb_port_warn(); tb_path_deactivate(), tb_tunnel_deactivate() and __tb_disconnect_xdomain_paths() are void as well, and tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So tb_xdomain_disable_paths() reports success and the netdev_warn() below it never fires. Repeated teardowns eventually take the XDomain control channel down, after which the peer node is gone and only a power cycle brings the controller back.

Deactivating the paths first fixes it. Measured with kretprobes on a stock v6.17 tree with no other patches applied, on a link that was up and had just carried traffic:

before: __tb_path_deactivate_hop() returns 0 for the first hop, then
-ETIMEDOUT for the second 500335 us later
after: 0 for both, 525 us apart

Alternating the two orderings ABBA over three load levels, four teardowns per arm: every teardown failed before the change (21 of 21 that ran), none failed after (0 of 24). The before arms ran short because the link died partway through. The same split shows up when the interface is enslaved to a bond instead of just brought down, which is how I ran into this in the first place. Throughput and latency after the change are unchanged.

Hosts whose routers drain the hop despite the stale descriptor base see no functional difference, since the paths end up deactivated either way.

Fixes e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
---
 drivers/net/thunderbolt/main.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/net/thunderbolt/main.c +15 -5
index 960839a651e51..ceaba08cd378a 100644
@@ -389,11 +389,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
 				break;
 		}
 
-		tb_ring_stop(net->rx_ring.ring);
-		tb_ring_stop(net->tx_ring.ring);
-		tbnet_free_buffers(&net->rx_ring);
-		tbnet_free_buffers(&net->tx_ring);
-
+		/* Tear the paths down before stopping the rings.  This mirrors
+		 * tbnet_connected_work(), which enables the paths last so the
+		 * Rx ring is primed before packets can arrive.  Stopping a
+		 * ring zeroes its descriptor base and tbnet_free_buffers()
+		 * unmaps and frees the frame buffers, leaving anything still
+		 * in flight with nowhere to drain to;
+		 * __tb_path_deactivate_hop() then waits for the hop's
+		 * 'pending' bit, which on some host routers never clears in
+		 * that state.
+		 */
 		ret = tb_xdomain_disable_paths(net->xd,
 					       net->local_transmit_path,
 					       net->tx_ring.ring->hop,
@@ -402,6 +407,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
 		if (ret)
 			netdev_warn(net->dev, "failed to disable DMA paths\n");
 
+		tb_ring_stop(net->rx_ring.ring);
+		tb_ring_stop(net->tx_ring.ring);
+		tbnet_free_buffers(&net->rx_ring);
+		tbnet_free_buffers(&net->tx_ring);
+
 		tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
 		net->remote_transmit_path = 0;
 	}
Signature · 1 line
2.53.0
author maintainer
#98 lore raw

PATCH 98/250 ata: pata_sl82c105: fix bridge revision use-after-free

In reply to Greg Kroah-Hartman

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

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

From: Hongyan Xu <[email protected]>

[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]

pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision") replaced a configuration-space read with direct access to the cached revision field, but left that access after pci_dev_put(). The bridge may therefore be freed before its revision is read.

Read the revision before dropping the reference.

Fixes 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
---
 drivers/ata/pata_sl82c105.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/ata/pata_sl82c105.c +3 -1
index 2d24c6b3e9d9f..25bce3fe2a101 100644
@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
 static int sl82c105_bridge_revision(struct pci_dev *pdev)
 {
 	struct pci_dev *bridge;
+	u8 revision;
 
 	/*
 	 * The bridge should be part of the same device, but function 0.
@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
 	/*
 	 * We need to find function 0's revision, not function 1
 	 */
+	revision = bridge->revision;
 	pci_dev_put(bridge);
-	return bridge->revision;
+	return revision;
 }
 
 static void sl82c105_fixup(struct pci_dev *pdev)
Signature · 1 line
2.53.0
author maintainer
#99 lore raw

PATCH 99/250 bnge: Fix resource leak in bnge_init_nic() error path

In reply to Greg Kroah-Hartman

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

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

From: Bhargava Marreddy <[email protected]>

[ Upstream commit bfec39ff1484b4e9f7d93bc4580fdb634bbc7d19 ]

If bnge_init_chip() fails, bnge_init_nic() jumps to err_free_ring_grps and returns immediately, skipping cleanup for RX ring pair buffers.

Remove the early return so execution falls through to err_free_rx_ring_pair_bufs to properly free resources on error.

---
 drivers/net/ethernet/broadcom/bnge/bnge_netdev.c | 2 --
 1 file changed, 2 deletions(-)
drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +0 -2
index 832eeb960bd2d..02be751f3d8fc 100644
@@ -2154,8 +2154,6 @@ static int bnge_init_nic(struct bnge_net *bn)
 
 err_free_ring_grps:
 	bnge_free_ring_grps(bn);
-	return rc;
-
 err_free_rx_ring_pair_bufs:
 	bnge_free_rx_ring_pair_bufs(bn);
 	return rc;
Signature · 1 line
2.53.0
author maintainer
#100 lore raw

PATCH 100/250 s390/ism: Fix UAF of sba and ieq during ism_dev_exit()

In reply to Greg Kroah-Hartman

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

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

From: Alexandra Winter <[email protected]>

[ Upstream commit b1896543ce59c4258625a35cf41e23a9a1f80ea2 ]

A ism interrupt handler can be active in parallel with ism_dev_exit(), accessing freed data structures.

No new interrupts will be generated after unregister_ieq(). Drain ongoing interrupt handlers by free_irq(), before freeing ism data structures.

Fixes 684b89bc39ce ("s390/ism: add device driver for internal shared memory")
---
 drivers/s390/net/ism_drv.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/s390/net/ism_drv.c +15 -4
index f84aa2e676e9b..b842410cf41cc 100644
@@ -149,13 +149,16 @@ static int unregister_sba(struct ism_dev *ism)
 	if (ret && ret != ISM_ERROR)
 		return -EIO;
 
+	return 0;
+}
+
+static void ism_free_sba(struct ism_dev *ism)
+{
 	dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
 			  ism->sba, ism->sba_dma_addr);
 
 	ism->sba = NULL;
 	ism->sba_dma_addr = 0;
-
-	return 0;
 }
 
 static int unregister_ieq(struct ism_dev *ism)
@@ -169,13 +172,16 @@ static int unregister_ieq(struct ism_dev *ism)
 	if (ret && ret != ISM_ERROR)
 		return -EIO;
 
+	return 0;
+}
+
+static void ism_free_ieq(struct ism_dev *ism)
+{
 	dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
 			  ism->ieq, ism->ieq_dma_addr);
 
 	ism->ieq = NULL;
 	ism->ieq_dma_addr = 0;
-
-	return 0;
 }
 
 static int ism_read_local_gid(struct dibs_dev *dibs)
@@ -574,6 +580,7 @@ static int ism_dev_init(struct ism_dev *ism)
 
 unreg_sba:
 	unregister_sba(ism);
+	ism_free_sba(ism);
 free_irq:
 	free_irq(pci_irq_vector(pdev, 0), ism);
 free_vectors:
@@ -586,9 +593,13 @@ static void ism_dev_exit(struct ism_dev *ism)
 {
 	struct pci_dev *pdev = ism->pdev;
 
+	/* ism will only generate new IRQs while ieq & sba are registered */
 	unregister_ieq(ism);
 	unregister_sba(ism);
+	/* drain ongoing irpt handlers */
 	free_irq(pci_irq_vector(pdev, 0), ism);
+	ism_free_ieq(ism);
+	ism_free_sba(ism);
 	pci_free_irq_vectors(pdev);
 }
 
Signature · 1 line
2.53.0
author maintainer
#101 lore raw

PATCH 101/250 net/atm: fix slab-out-of-bounds read in vcc_setsockopt()

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]

vcc_setsockopt() contained an ineffective optlen check:
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))

      return -EINVAL;

If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller passed a mismatched level), the length check optlen != __SO_SIZE(optname) was short-circuited and bypassed. Execution then fell through to switch(optname), calling copy_from_sockptr() assuming optval contained sufficient space.

Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(), this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the expected structure size.

Fix this by using copy_safe_from_sockptr(), which unconditionally validates that optlen is at least the expected size before copying. Also change the local 'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches its sizeof(int) ABI encoding on 64-bit systems.

---
 net/atm/common.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
net/atm/common.c +9 -5
index f4c6e0131c921..f4be6cb220861 100644
@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
 		   sockptr_t optval, unsigned int optlen)
 {
 	struct atm_vcc *vcc;
-	unsigned long value;
+	int value;
 	int error;
 
 	if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
 	{
 		struct atm_qos qos;
 
-		if (copy_from_sockptr(&qos, optval, sizeof(qos)))
-			return -EFAULT;
+		error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
+					       optlen);
+		if (error)
+			return error;
 		error = check_qos(&qos);
 		if (error)
 			return error;
@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
 		return 0;
 	}
 	case SO_SETCLP:
-		if (copy_from_sockptr(&value, optval, sizeof(value)))
-			return -EFAULT;
+		error = copy_safe_from_sockptr(&value, sizeof(value), optval,
+					       optlen);
+		if (error)
+			return error;
 		if (value)
 			vcc->atm_options |= ATM_ATMOPT_CLP;
 		else
Signature · 1 line
2.53.0
author maintainer
#102 lore raw

PATCH 102/250 sctp: clear control chunk transport if it is being removed

In reply to Greg Kroah-Hartman

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

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

From: Xin Long <[email protected]>

[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]

sctp_make_heartbeat_ack() caches the destination transport in chunk->transport without taking a reference. When src_out_of_asoc_ok is enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead of being transmitted immediately.

If the peer transport is removed while the chunk is still queued, sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing, but only clears cached transport pointers in out_chunk_list. The queued control chunk therefore retains a dangling transport pointer.

Once an ASCONF_ACK clears the suppression and the queued control chunk is transmitted, SCTP dereferences the stale transport pointer, leading to a use-after-free.

Fix this by also clearing chunk->transport for queued control chunks in control_chunk_list when removing the transport.

---
 net/sctp/associola.c | 4 ++++
 1 file changed, 4 insertions(+)
net/sctp/associola.c +4 -0
index e560f7ee4adb3..9fff11115b417 100644
@@ -573,6 +573,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
 		if (ch->transport == peer)
 			ch->transport = NULL;
 
+	list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
+		if (ch->transport == peer)
+			ch->transport = NULL;
+
 	asoc->peer.transport_count--;
 
 	sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
Signature · 1 line
2.53.0
author maintainer
#103 lore raw

PATCH 103/250 tls: dont abort the connection on signal-interrupted sends

In reply to Greg Kroah-Hartman

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

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

From: Maximilian Immanuel Brandtner <[email protected]>

[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]

When a signal interrupts a blocking send, tls_tx_records() treats the resulting -ERESTARTSYS as a transmission failure and marks the socket errored via tls_err_abort() with the raw error code. Later syscalls return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the signal it stems from is no longer pending during syscall exit and thus never translated.

An interrupted send is not a connection error: the partially sent record stays queued and is resent later. Interrupt error codes are therefore excluded from the abort in the same way as -EAGAIN.

---
 net/tls/tls_sw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/tls/tls_sw.c +1 -1
index f19b504efa5d0..0bb710c5fa601 100644
@@ -458,7 +458,7 @@ int tls_tx_records(struct sock *sk, int flags)
 	}
 
 tx_err:
-	if (rc < 0 && rc != -EAGAIN)
+	if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
 		tls_err_abort(sk, rc);
 
 	return rc;
Signature · 1 line
2.53.0
author maintainer
#104 lore raw

PATCH 104/250 watchdog: at91sam9_wdt: prevent timer rearm during teardown

In reply to Greg Kroah-Hartman

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

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

From: Hongyan Xu <[email protected]>

[ Upstream commit 8444d66aa6b6e7fe0a26fa1a00a11cb4d0523783 ]

at91_ping() rearms the watchdog timer from its callback. timer_delete() neither waits for a running callback nor prevents it from rearming the timer, so probe failure or driver removal can leave the timer accessing the devm-allocated at91wdt after it has been freed.

Use timer_shutdown_sync() on both teardown paths. It waits for a running callback and rejects any attempt by the callback to rearm the timer.

Fixes 5161b31dc39a ("watchdog: at91sam9_wdt: better watchdog support")
---
 drivers/watchdog/at91sam9_wdt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/watchdog/at91sam9_wdt.c +2 -2
index aba66b8e9d033..80ba04df54adf 100644
@@ -242,7 +242,7 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
 	return 0;
 
 out_stop_timer:
-	timer_delete(&wdt->timer);
+	timer_shutdown_sync(&wdt->timer);
 	return err;
 }
 
@@ -378,7 +378,7 @@ static void at91wdt_remove(struct platform_device *pdev)
 	watchdog_unregister_device(&wdt->wdd);
 
 	pr_warn("I quit now, hardware will probably reboot!\n");
-	timer_delete(&wdt->timer);
+	timer_shutdown_sync(&wdt->timer);
 }
 
 #if defined(CONFIG_OF)
Signature · 1 line
2.53.0
author maintainer
#105 lore raw

PATCH 105/250 hwmon: (corsair-psu) fix possible out-of-bounds access on missing string termination

In reply to Greg Kroah-Hartman

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

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

From: Wilken Gottwalt <[email protected]>

[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]

In theory it could be possible that the REPLY_SIZE sized buffers for holding the vendor and product strings could be end up missing the null termination (for example by malicious hardware built on purpose) required by the seq_printf() call. That limits the debugfs printf calls to a maximum string length of REPLY_SIZE.

Fixes d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
---
 drivers/hwmon/corsair-psu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/corsair-psu.c +2 -2
index 4681af6843596..679fb30983465 100644
@@ -709,7 +709,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
 {
 	struct corsairpsu_data *priv = seqf->private;
 
-	seq_printf(seqf, "%s\n", priv->vendor);
+	seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
 
 	return 0;
 }
@@ -719,7 +719,7 @@ static int product_show(struct seq_file *seqf, void *unused)
 {
 	struct corsairpsu_data *priv = seqf->private;
 
-	seq_printf(seqf, "%s\n", priv->product);
+	seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#106 lore raw

PATCH 106/250 hwmon: (ads7828) Fix external VREF regulator handling

In reply to Greg Kroah-Hartman

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

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

From: Qingshuang Fu <[email protected]>

[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]

The driver currently has two issues with the external VREF regulator handling in ads7828_probe():

1. All errors from devm_regulator_get_optional() are ignored, causing the driver to incorrectly fall back to internal VREF even for transient errors like -EPROBE_DEFER or genuine failures like -ENOMEM.

2. The external regulator is never enabled. The driver calls regulator_get_voltage() without first calling regulator_enable(), so the VREF pin may remain unpowered if the regulator is not configured as always-on.

Fix both issues by switching to devm_regulator_get_enable_read_voltage(), which handles regulator get, enable, and voltage read in one call. Only -ENODEV (no regulator specified in device tree) should trigger the fallback to internal VREF. All other errors are propagated to the caller.

Fixes a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
---
 drivers/hwmon/ads7828.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/hwmon/ads7828.c +6 -5
index 436637264056c..20ef4992f5bb8 100644
@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
 	struct ads7828_data *data;
 	struct device *hwmon_dev;
 	unsigned int vref_mv = ADS7828_INT_VREF_MV;
-	unsigned int vref_uv;
+	int vref_uv;
 	bool diff_input = false;
 	bool ext_vref = false;
 	unsigned int regval;
 	enum ads7828_chips chip;
-	struct regulator *reg;
 
 	data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
 	if (!data)
@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
 	} else if (dev->of_node) {
 		diff_input = of_property_read_bool(dev->of_node,
 						   "ti,differential-input");
-		reg = devm_regulator_get_optional(dev, "vref");
-		if (!IS_ERR(reg)) {
-			vref_uv = regulator_get_voltage(reg);
+		vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
+		if (vref_uv < 0) {
+			if (vref_uv != -ENODEV)
+				return vref_uv;
+		} else {
 			vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
 			if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
 			    vref_mv > ADS7828_EXT_VREF_MV_MAX)
Signature · 1 line
2.53.0
author maintainer
#107 lore raw

PATCH 107/250 hwmon: (ltc4282) Avoid overflow in maximum power calculation

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit edd11a94335747423569500a194c6eaa915f2963 ]

During device initialization in ltc4282_set_max_limits(), the calculation of the maximum power limit can suffer from a 32-bit integer overflow.

static int ltc4282_set_max_limits(struct ltc4282_state *st)

{
    ...
    st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI,
                                      st->rsense) * st->vfs_out;
    ...
}

The result of DIV_ROUND_CLOSEST() evaluates to a 32-bit unsigned integer on 32-bit architectures. This result is then multiplied by st->vfs_out, which is a 16-bit unsigned integer. According to C promotion rules, since both operands are 32-bit or smaller, the multiplication is performed in 32-bit precision.

If the device is configured with a low sense resistor value via the device tree (for example, 100 nano-ohms, resulting in st->rsense = 1) and the voltage is high, the division result can reach 343,750,000 and st->vfs_out can be 33,280. The product of these values is approximately 11.44 trillion, which exceeds the maximum capacity of a 32-bit integer and overflows before being stored in st->power_max.

This overflow causes a truncated value to be assigned to st->power_max and written to the hardware limit register. An incorrect maximum power limit can trigger spurious power-bad faults or alarms, which may lead to the shutdown of the monitored power rail.

Avoid the problem by calculating and storing the maximum power using 64-bit variables.

Fixes cbc29538dbf7d ("hwmon: Add driver for LTC4282")
Cc Nuno Sa <[email protected]>
---
 drivers/hwmon/ltc4282.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/hwmon/ltc4282.c +6 -6
index 4000bcbc7353d..e5ea1db83da47 100644
@@ -142,7 +142,7 @@ struct ltc4282_state {
 	 */
 	struct ltc4282_cache in0_1_cache[LTC4282_CHAN_VGPIO];
 	u32 vsense_max;
-	long power_max;
+	s64 power_max;
 	u32 rsense;
 	u16 vdd;
 	u16 vfs_out;
@@ -623,13 +623,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
 }
 
 static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
-				    long val)
+				    s64 val)
 {
 	u32 power;
 	u64 temp;
 
-	if (val > st->power_max)
-		val = st->power_max;
+	val = clamp(val, 0, st->power_max);
 
 	temp = val * int_pow(U8_MAX, 2) * st->rsense;
 	power = DIV64_U64_ROUND_CLOSEST(temp,
@@ -639,7 +638,7 @@ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
 }
 
 static int ltc4282_write_power_word(const struct ltc4282_state *st, u32 reg,
-				    long val)
+				    u64 val)
 {
 	u64 temp = int_pow(U16_MAX, 2) * st->rsense, temp_2;
 	__be16 __raw;
@@ -1256,7 +1255,8 @@ static int ltc4282_set_max_limits(struct ltc4282_state *st)
 		return ret;
 
 	/* Power is given by ISENSE * Vout. */
-	st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI, st->rsense) * st->vfs_out;
+	st->power_max = DIV_ROUND_CLOSEST_ULL((u64)st->vsense_max * DECA * MILLI,
+					      st->rsense) * st->vfs_out;
 	ret = ltc4282_write_power_byte(st, LTC4282_POWER_MAX, st->power_max);
 	if (ret)
 		return ret;
Signature · 1 line
2.53.0
author maintainer
#108 lore raw

PATCH 108/250 hwmon: (ltc4282) Clamp negative current limits

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit e253dd5f9f6d875a317895bf43ec9534ed7523cb ]

When a negative value is passed to ltc4282_write_curr(), the signed long val is cast directly to u64:

drivers/hwmon/ltc4282.c:ltc4282_write_curr() {
        /* need to pass it in millivolt */
        u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
        ...
}

This cast converts negative inputs into large positive values. The subsequent division result overflows the u32 in variable, truncating to a pseudo-random positive value. When this is passed to ltc4282_write_voltage_byte(), it is clamped to the maximum limit instead of zero.

Clamp val to 0 and to the maximum supported upper limit before the cast and assign the result to a 64-bit temporary variable before the division to avoid the underflow and an also possible overflow.

Fixes cbc29538dbf7d ("hwmon: Add driver for LTC4282")
Cc Nuno Sa <[email protected]>
---
 drivers/hwmon/ltc4282.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/hwmon/ltc4282.c +5 -1
index e5ea1db83da47..b45a6e128d32e 100644
@@ -15,6 +15,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/i2c.h>
 #include <linux/math.h>
+#include <linux/math64.h>
 #include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -947,8 +948,11 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
 static int ltc4282_write_curr(struct ltc4282_state *st, u32 attr,
 			      long val)
 {
+	s32 ulimit = min_t(u64, INT_MAX,
+			   div_u64((u64)INT_MAX * DECA * MICRO, st->rsense));
+	u64 val64 = clamp(val, 0, ulimit);
 	/* need to pass it in millivolt */
-	u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
+	u32 in = DIV_ROUND_CLOSEST_ULL(val64 * st->rsense, DECA * MICRO);
 
 	switch (attr) {
 	case hwmon_curr_max:
Signature · 1 line
2.53.0
author maintainer
#109 lore raw

PATCH 109/250 hwmon: (ltc4282) Fix parsing adi,current-limit-sense-microvolt

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 335698fd7f60b6707b21fda725f97f35fa956b07 ]

ltc4282_parse_dt() evaluates the wrong variable when parsing the current limit.

When the adi,current-limit-sense-microvolt property is parsed into st->vsense_max, the subsequent switch statement evaluates the unrelated val variable instead of st->vsense_max:

drivers/hwmon/ltc4282.c:ltc4282_parse_dt() {
    ...
        ret = device_property_read_u32(dev, "adi,current-limit-sense-microvolt",
                                       &st->vsense_max);
        if (!ret) {
                int reg_val;

                switch (val) {
                case 12500:
                        reg_val = 0;
                        break;
    ...
}

Because val holds a small integer representing vin_mode (from 0 to 3), it never matches any of the valid current limit cases.

This causes it to always fall through to the default error case, return -EINVAL, and aborts probe initialization for any device tree using this property.

Validate st->vsense_max instead to fix the problem.

Fixes cbc29538dbf7d ("hwmon: Add driver for LTC4282")
Cc Nuno Sa <[email protected]>
---
 drivers/hwmon/ltc4282.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/ltc4282.c +1 -1
index b45a6e128d32e..269f96738f5b3 100644
@@ -1427,7 +1427,7 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
 	if (!ret) {
 		int reg_val;
 
-		switch (val) {
+		switch (st->vsense_max) {
 		case 12500:
 			reg_val = 0;
 			break;
Signature · 1 line
2.53.0
author maintainer
#110 lore raw

PATCH 110/250 net: fec: do not release NULL pages when RX buffer allocation fails

In reply to Greg Kroah-Hartman

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

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

From: Mehmet Fide <[email protected]>

fec_enet_alloc_rxq_buffers() leaves the loop as soon as page_pool_dev_alloc_pages() returns NULL and jumps to err_alloc, which calls fec_enet_free_buffers(). That helper walks the whole ring and hands every rx_skb_info[i].page to page_pool_put_full_page(), including the entries the allocation loop never reached. Those are still NULL, because the queue was allocated with kzalloc(), and page_pool_put_full_page() dereferences the page, so an open that runs out of memory oopses instead of returning -ENOMEM:

  Unable to handle kernel NULL pointer dereference at virtual address 00000014 when read
  Internal error: Oops: 5 [#1] SMP ARM
  CPU: 0 PID: 384 Comm: connmand Not tainted 6.18.43 #1
  Hardware name: Freescale Vybrid VF5xx/VF6xx (Device Tree)
  PC is at fec_enet_free_buffers+0xb0/0x2a8
  Call trace:
   fec_enet_free_buffers from fec_enet_open+0x1e0/0x504
   fec_enet_open from __dev_open+0x114/0x238
   __dev_open from __dev_change_flags+0x190/0x208
   __dev_change_flags from netif_change_flags+0x1c/0x58
   netif_change_flags from dev_change_flags+0x44/0x74
   dev_change_flags from devinet_ioctl+0x3a4/0x768

Seen on a Colibri VF50, 128 MiB of RAM, on the first ifup after boot.

Skip the entries that hold no page, and clear the ones that do after releasing them, so that a later failed open cannot release the same page a second time.

Mainline is not affected. Commit a2ae70c0efe4 ("net: fec: add fec_alloc_rxq_buffers_pp() to allocate buffers from page pool") replaced this loop with fec_free_rxq_buffers(), which skips and clears the empty entries. That commit is part of the XDP zero copy series and is not a stable candidate, so this is the equivalent minimal fix for 6.18.y.

Fixes 95698ff6177b ("net: fec: using page pool to manage RX buffers")
---
 drivers/net/ethernet/freescale/fec_main.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/ethernet/freescale/fec_main.c +9 -2
index a2cf8cbe2539e..7699a970cb25e 100644
@@ -3341,8 +3341,15 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 
 	for (q = 0; q < fep->num_rx_queues; q++) {
 		rxq = fep->rx_queue[q];
-		for (i = 0; i < rxq->bd.ring_size; i++)
-			page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false);
+		for (i = 0; i < rxq->bd.ring_size; i++) {
+			struct page *page = rxq->rx_skb_info[i].page;
+
+			if (!page)
+				continue;
+
+			page_pool_put_full_page(rxq->page_pool, page, false);
+			rxq->rx_skb_info[i].page = NULL;
+		}
 
 		for (i = 0; i < XDP_STATS_TOTAL; i++)
 			rxq->stats[i] = 0;
Signature · 1 line
2.53.0
author maintainer
#111 lore raw

PATCH 111/250 net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()

In reply to Greg Kroah-Hartman

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

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

From: Dongli Zhang <[email protected]>

commit 3874892dd27d5387aa9a06f58d9060f18f351d24 upstream.

The commit 4f61f133f354 ("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur.

However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash.

Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit().

---
 drivers/net/tap.c |   24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/net/tap.c +14 -10
@@ -1074,10 +1074,21 @@ static int tap_get_user_xdp(struct tap_q
 	skb_reset_mac_header(skb);
 	skb->protocol = eth_hdr(skb)->h_proto;
 
+	rcu_read_lock();
+	tap = rcu_dereference(q->tap);
+	if (!tap) {
+		kfree_skb(skb);
+		rcu_read_unlock();
+		return 0;
+	}
+	skb->dev = tap->dev;
+
 	if (vnet_hdr_len) {
 		err = tun_vnet_hdr_to_skb(q->flags, skb, gso);
-		if (err)
+		if (err) {
+			rcu_read_unlock();
 			goto err_kfree;
+		}
 	}
 
 	/* Move network header to the right position for VLAN tagged packets */
@@ -1085,15 +1096,8 @@ static int tap_get_user_xdp(struct tap_q
 	    vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
 		skb_set_network_header(skb, depth);
 
-	rcu_read_lock();
-	tap = rcu_dereference(q->tap);
-	if (tap) {
-		skb->dev = tap->dev;
-		skb_probe_transport_header(skb);
-		dev_queue_xmit(skb);
-	} else {
-		kfree_skb(skb);
-	}
+	skb_probe_transport_header(skb);
+	dev_queue_xmit(skb);
 	rcu_read_unlock();
 
 	return 0;
author maintainer
#112 lore raw

PATCH 112/250 Input: evdev - sanitize event type index when fetching event masks

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Torokhov <[email protected]>

commit 3abd29c61d2ef37c4102cf755b18be53bb9dbea6 upstream.

The user-supplied event type index passed to EVIOCGMASK / EVIOCSMASK ioctls is used to index the static counts array in evdev_get_mask_cnt() and client evmasks array in evdev_get_mask().

While the event type is architecturally bounded by EV_CNT, speculative execution may mispredict bounds checks and perform out-of-bounds loads.

Sanitize the event type index in evdev_get_mask_cnt() branchlessly using array_index_mask_nospec(). This clamps the index to 0 for safe array access and forces the returned count to 0 speculatively when the index is out of bounds.

We do not need additional array_index_nospec() calls in evdev_get_mask() because evdev_get_mask_cnt() speculatively forces the count (and resulting xfer_size) to 0 for out-of-bounds types, preventing any speculative memory access to client evmasks array.

---
 drivers/input/evdev.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/input/evdev.c +4 -1
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/input/mt.h>
 #include <linux/major.h>
+#include <linux/nospec.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
 #include "input-compat.h"
@@ -67,8 +68,10 @@ static size_t evdev_get_mask_cnt(unsigne
 		[EV_SND]	= SND_CNT,
 		[EV_FF]		= FF_CNT,
 	};
+	unsigned long mask = array_index_mask_nospec(type, EV_CNT);
 
-	return (type < EV_CNT) ? counts[type] : 0;
+	/* Returns 0 for out-of-bounds types, including speculatively */
+	return counts[type & mask] & mask;
 }
 
 /* requires the buffer lock to be held */
author maintainer
#113 lore raw

PATCH 113/250 ALSA: usb-audio: fix OOB write on Type II inbound URBs

In reply to Greg Kroah-Hartman

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

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

From: Baul Lee <[email protected]>

commit 69ee44e1a23be62318189dc4b37fa4ad94053269 upstream.

data_ep_set_params() sizes each URB transfer buffer before it adds the Format Type II transfer delimiter:

	u->packets = urb_packs;
	u->buffer_size = maxsize * u->packets;

	if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
		u->packets++; /* for transfer delimiter */
	u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);

buffer_size is computed from the pre-increment packet count and never recomputed, so for a Type II endpoint the buffer is one packet short of the packet count the URB is built with.

prepare_inbound_urb() then lays out one iso frame per packet and never consults buffer_size:

	offs = 0;
	for (i = 0; i < urb_ctx->packets; i++) {
		urb->iso_frame_desc[i].offset = offs;
		urb->iso_frame_desc[i].length = ep->curpacksize;
		offs += ep->curpacksize;
	}

	urb->transfer_buffer_length = offs;
	urb->number_of_packets = urb_ctx->packets;

The last descriptor therefore points one packet past the end of the transfer buffer, where the host controller writes device data on every inbound transfer. prepare_silent_urb() and prepare_playback_urb() bound their fill loops by ctx->buffer_size, so only capture is affected.

fmt_type comes from the device's audio streaming descriptors, so any device advertising a Type II capture format hits this once userspace sets hw_params on the stream.

KASAN on 7.2.0-rc5 (arm64) with a dummy_hcd/raw-gadget device, one report per inbound transfer:

  BUG: KASAN: slab-out-of-bounds in dummy_timer
  Write of size 64 at addr ffff0000186171c0 by task cons02/166
   __asan_memcpy
   dummy_timer
   hrtimer_run_softirq
  Allocated by task 166:
   usb_alloc_coherent
   snd_usb_endpoint_set_params
  The buggy address is located 0 bytes to the right of
   allocated 64-byte region [ffff000018617180, ffff0000186171c0)

Compute buffer_size after the delimiter packet has been accounted for, and bound the fill loop by buffer_size, as prepare_silent_urb() already does on the outbound side. This grows every Type II URB allocation by one maxsize packet.

Discovered by XBOW, triaged by Baul Lee <[email protected]>

---
 sound/usb/endpoint.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
sound/usb/endpoint.c +4 -2
@@ -385,13 +385,15 @@ static int prepare_inbound_urb(struct sn
 	case SND_USB_ENDPOINT_TYPE_DATA:
 		offs = 0;
 		for (i = 0; i < urb_ctx->packets; i++) {
+			if (offs + ep->curpacksize > urb_ctx->buffer_size)
+				break;
 			urb->iso_frame_desc[i].offset = offs;
 			urb->iso_frame_desc[i].length = ep->curpacksize;
 			offs += ep->curpacksize;
 		}
 
 		urb->transfer_buffer_length = offs;
-		urb->number_of_packets = urb_ctx->packets;
+		urb->number_of_packets = i;
 		break;
 
 	case SND_USB_ENDPOINT_TYPE_SYNC:
@@ -1239,10 +1241,10 @@ static int data_ep_set_params(struct snd
 		u->index = i;
 		u->ep = ep;
 		u->packets = urb_packs;
-		u->buffer_size = maxsize * u->packets;
 
 		if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
 			u->packets++; /* for transfer delimiter */
+		u->buffer_size = maxsize * u->packets;
 		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
 		if (!u->urb)
 			goto out_of_memory;
author maintainer
#114 lore raw

PATCH 114/250 usb: core: Add quirk for 255-bytes initial config read

In reply to Greg Kroah-Hartman

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

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

From: Nikhil Solanke <[email protected]>

commit 152f174a13618bec1f842d2deb69245cb2ace51f upstream.

Certain third-party USB game controllers exposing (or spoofing) an Xbox 360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux. The device disconnects from the bus without responding to the initial GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read config index 0 descriptor/start: -71'.

The device then falls back to a secondary Android HID mode (with a different VID:PID), losing XInput functionality including rumble support. The failure reproduces across multiple machines, host controller types, and kernel versions including current mainline and LTS. The device enumerates correctly and remains in XInput mode under Windows. Notably, the device enumerates correctly in Android mode when the same 9-byte request is issued for that mode's configuration descriptor, confirming the firmware bug is specific to the XInput mode.

usbmon traces from Linux and Wireshark/USBPcap traces from Windows are identical up to the point of failure, with no visible protocol-level difference explaining the divergence. The root cause was identified when Michal Pecio discovered via a QEMU bus-level capture that Windows does not use wLength=9 for the initial config descriptor request; it uses wLength=255. Alan Stern subsequently confirmed this with a bus analyzer on a different USB 2.0 device, and Michal verified the behavior goes back to Windows 95 OSR2.1.

So, add a new quirk flag USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE which causes usb_get_configuration() to issue a 255 byte sized configuration request instead of USB_DT_CONFIG_SIZE (9) for the initial GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows behavior.

This patch intentionally does not add any new VID:PID entries using this quirk. Some affected Xbox 360-compatible controllers spoof Microsoft's VID:PID, while genuine Microsoft controllers already enumerate correctly and do not require this quirk. Other affected clone devices use their own VID:PID pairs and can be added individually as they are identified.

---
 Documentation/admin-guide/kernel-parameters.txt |    5 +++
 drivers/usb/core/config.c                       |   32 ++++++++++++++++++------
 drivers/usb/core/quirks.c                       |    4 +++
 include/linux/usb/quirks.h                      |    3 ++
 4 files changed, 36 insertions(+), 8 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +5 -0
@@ -7928,6 +7928,11 @@
 				q = USB_QUIRK_FORCE_ONE_CONFIG (Device
 					claims zero configurations,
 					forcing to 1);
+				r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device
+					fails during initialization when asked for
+					9-bytes configuration descriptor request.
+					Ask for 255-bytes request instead to mirror
+					Windows' behavior);
 			Example: quirks=0781:5580:bk,0a5c:5834:gij
 
 	usbhid.mousepoll=
drivers/usb/core/config.c +24 -8
@@ -927,6 +927,18 @@ int usb_get_configuration(struct usb_dev
 	unsigned char *bigbuffer;
 	struct usb_config_descriptor *desc;
 	int result;
+	size_t usb_config_req_size;
+
+	/*
+	 * We usually start by grabbing the first 9-bytes descriptor so we know
+	 * how long the whole configuration is. Some devices with quirky
+	 * firmware will fail enumeration, so if the quirk is set, use 255 instead,
+	 * mirroring the behavior of Windows.
+	 */
+	if (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE)
+		usb_config_req_size = 255;
+	else
+		usb_config_req_size = USB_DT_CONFIG_SIZE;
 
 	if (ncfg > USB_MAXCONFIG) {
 		dev_notice(ddev, "too many configurations: %d, "
@@ -953,15 +965,13 @@ int usb_get_configuration(struct usb_dev
 	if (!dev->rawdescriptors)
 		return -ENOMEM;
 
-	desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+	desc = kmalloc(usb_config_req_size, GFP_KERNEL);
 	if (!desc)
 		return -ENOMEM;
 
 	for (cfgno = 0; cfgno < ncfg; cfgno++) {
-		/* We grab just the first descriptor so we know how long
-		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
-		    desc, USB_DT_CONFIG_SIZE);
+		    desc, usb_config_req_size);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
 			    "descriptor/%s: %d\n", cfgno, "start", result);
@@ -971,16 +981,14 @@ int usb_get_configuration(struct usb_dev
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
 		} else if (result < 4) {
-			dev_err(ddev, "config index %d descriptor too short "
-			    "(expected %i, got %i)\n", cfgno,
-			    USB_DT_CONFIG_SIZE, result);
+			dev_err(ddev, "config index %d descriptor too short (asked for %zu, got %i)\n",
+			    cfgno, usb_config_req_size, result);
 			result = -EINVAL;
 			goto err;
 		}
 		length = max_t(int, le16_to_cpu(desc->wTotalLength),
 		    USB_DT_CONFIG_SIZE);
 
-		/* Now that we know the length, get the whole thing */
 		bigbuffer = kmalloc(length, GFP_KERNEL);
 		if (!bigbuffer) {
 			result = -ENOMEM;
@@ -990,6 +998,13 @@ int usb_get_configuration(struct usb_dev
 		if (dev->quirks & USB_QUIRK_DELAY_INIT)
 			msleep(200);
 
+		/* Skip the second read if we already got everything */
+		if (result >= length) {
+			memcpy(bigbuffer, desc, length);
+			goto store_and_parse;
+		}
+
+		/* Get the whole thing */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    bigbuffer, length);
 		if (result < 0) {
@@ -1004,6 +1019,7 @@ int usb_get_configuration(struct usb_dev
 			length = result;
 		}
 
+store_and_parse:
 		dev->rawdescriptors[cfgno] = bigbuffer;
 
 		result = usb_parse_configuration(dev, cfgno,
drivers/usb/core/quirks.c +4 -0
@@ -143,6 +143,10 @@ static int quirks_param_set(const char *
 				break;
 			case 'q':
 				flags |= USB_QUIRK_FORCE_ONE_CONFIG;
+				break;
+			case 'r':
+				flags |= USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE;
+				break;
 			/* Ignore unrecognized flag characters */
 			}
 		}
include/linux/usb/quirks.h +3 -0
@@ -81,4 +81,7 @@
 /* Device claims zero configurations, forcing to 1 */
 #define USB_QUIRK_FORCE_ONE_CONFIG		BIT(18)
 
+/* Use a 255 bytes config descriptor request mirroring windows behavior */
+#define USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE	BIT(19)
+
 #endif /* __LINUX_USB_QUIRKS_H */
author maintainer
#115 lore raw

PATCH 115/250 usb: quirks: Add ShanWan gamepad to quirk list

In reply to Greg Kroah-Hartman

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

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

From: Ishaan Dandekar <[email protected]>

commit f3988e68fc089f6a5883f4f807955a3825bb7d45 upstream.

The ShanWan Wireless Gamepad (dongle ID 2563:0575) crashes with a -71 EPROTO error during standard enumeration because it expects a 255-byte initial configuration request. Add this device to the quirk list to use the USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE flag.

---
 drivers/usb/core/quirks.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/usb/core/quirks.c +3 -0
@@ -594,6 +594,9 @@ static const struct usb_device_id usb_qu
 
 	{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
 
+	/* ShanWan Wireless Gamepad */
+	{ USB_DEVICE(0x2563, 0x0575), .driver_info = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE },
+
 	/* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */
 	{ USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS },
 
author maintainer
#116 lore raw

PATCH 116/250 usb: misc: usbio: check ibuf_len against rxbuf_len in bulk msg

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

commit 7e22c9f79b200672f3e477421b6c9050d8cf70a5 upstream.

ibuf_len is the bulk IN (receive) buffer size, but the EMSGSIZE check in usbio_bulk_msg() compares it against txbuf_len — the bulk OUT endpoint size. Both are taken independently from different endpoints in usbio_probe(), so the check is wrong when they differ.

Use rxbuf_len for the IN direction. This matches the buffer that actually holds the response data.

---
 drivers/usb/misc/usbio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/misc/usbio.c +1 -1
index 3c2474dca810..fe093e7760d5 100644
@@ -265,7 +265,7 @@ int usbio_bulk_msg(struct auxiliary_device *adev, u8 type, u8 cmd, bool last,
 	lockdep_assert_held(&usbio->bulk_mutex);
 
 	if ((obuf_len > (usbio->txbuf_len - sizeof(*bpkt))) ||
-	    (ibuf_len > (usbio->txbuf_len - sizeof(*bpkt))))
+	    (ibuf_len > (usbio->rxbuf_len - sizeof(*bpkt))))
 		return -EMSGSIZE;
 
 	if (ibuf_len)
Signature · 1 line
2.55.0
author maintainer
#117 lore raw

PATCH 117/250 usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm()

In reply to Greg Kroah-Hartman

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

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

From: Aleksandr Nogikh <[email protected]>

commit c2f811314be351d86b6ab41e9297ae80d8da6f86 upstream.

If cxacru_cm() encounters an error while submitting or waiting for snd_urb, it aborts and returns the error without killing the already submitted rcv_urb. This leaves the rcv_urb active.

When this happens during initialization (e.g., in cxacru_atm_start()), the driver may ignore the error and proceed to call cxacru_poll_status(), which invokes cxacru_cm() again. Attempting to submit the still-active rcv_urb triggers a warning in usb_submit_urb():

cxacru 1-1:1.0: send of cm 0x84 failed (-104)
ATM dev 0: cxacru_atm_start: CHIP_ADSL_LINE_START returned -104

------------[ cut here ]------------
URB ffff88812658d200 submitted while active
WARNING: drivers/usb/core/urb.c:379 at usb_submit_urb+0x79/0x18b0
drivers/usb/core/urb.c:379
...
Call Trace:
 <TASK>
 cxacru_cm+0x21a/0xf10 drivers/usb/atm/cxacru.c:631
 cxacru_cm_get_array drivers/usb/atm/cxacru.c:722 [inline]
 cxacru_poll_status+0x178/0x1110 drivers/usb/atm/cxacru.c:828
 cxacru_atm_start+0x185/0x360 drivers/usb/atm/cxacru.c:814
 usbatm_atm_init+0x144/0x3a0 drivers/usb/atm/usbatm.c:927
 usbatm_usb_probe+0x15cb/0x1db0 drivers/usb/atm/usbatm.c:1178
 cxacru_usb_probe+0x17f/0x220 drivers/usb/atm/cxacru.c:1370

...

To fix this, ensure that rcv_urb is properly killed if cxacru_cm() aborts early. We can safely call usb_kill_urb() on rcv_urb in the error path, as it is safe to call even if the URB is not active (e.g., if it failed to submit in the first place, or if it already completed).

Fixes 1b0e61465234 ("[PATCH] USB ATM: driver for the Conexant AccessRunner chipset cxacru")
Cc stable <[email protected]>
Assisted-by Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by [email protected]
---
 drivers/usb/atm/cxacru.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/usb/atm/cxacru.c +2 -0
@@ -700,6 +700,8 @@ static int cxacru_cm(struct cxacru_data
 	ret = offd;
 	usb_dbg(instance->usbatm, "cm %#x\n", cm);
 fail:
+	if (ret < 0)
+		usb_kill_urb(instance->rcv_urb);
 	mutex_unlock(&instance->cm_serialize);
 err:
 	return ret;
author maintainer
#118 lore raw

PATCH 118/250 thunderbolt: icm: Preserve USB4 proxy data-valid bit

In reply to Greg Kroah-Hartman

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

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

From: Xu Rao <[email protected]>

commit e48844ece5e3ed1d1eb865f6da2b16f62cd9f86d upstream.

The ICM USB4 switch operation request encodes two values in request.data_len_valid: bit 4 marks the data payload valid, while bits 3:0 hold the payload length in dwords. A zero length with the valid bit set represents the full 16-dword data array.

icm_usb4_switch_op() sets the valid bit when a transmit payload is present. For payloads shorter than the full 16 dwords, it then assigns the length to the whole field and clears the valid bit that was just set. The payload is still copied into the request, but the descriptor sent to firmware marks that data as invalid.

This affects USB4 router operations that send short payloads through the firmware connection manager. In particular, USB4 NVM writes can send a short final block when the image size is not aligned to the 64-byte proxy payload size. Firmware may then ignore or reject that final block, while full 16-dword blocks are unaffected because they are encoded as length 0 with the valid bit set.

OR the short payload length into data_len_valid so the valid bit is preserved.

Fixes 9039387e166e ("thunderbolt: Add USB4 router operation proxy for firmware connection manager")
---
 drivers/thunderbolt/icm.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thunderbolt/icm.c +1 -1
@@ -2325,7 +2325,7 @@ static int icm_usb4_switch_op(struct tb_
 	if (tx_data_len) {
 		request.data_len_valid |= ICM_USB4_SWITCH_DATA_VALID;
 		if (tx_data_len < ARRAY_SIZE(request.data))
-			request.data_len_valid =
+			request.data_len_valid |=
 				tx_data_len & ICM_USB4_SWITCH_DATA_LEN_MASK;
 		memcpy(request.data, tx_data, tx_data_len * sizeof(u32));
 	}
author maintainer
#119 lore raw

PATCH 119/250 usb: cdnsp: fix incorrect endian conversions for APB timeout register

In reply to Greg Kroah-Hartman

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

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

From: Pawel Laszczak <[email protected]>

commit 50b303f3d0f7de543ee90d50879970783d06da33 upstream.

readl() already returns a CPU-endian value. Passing its return value to le32_to_cpu() is therefore redundant and causes an incorrect double byte swap on big-endian systems.

Similarly, writel() expects a CPU-endian value, so passing the result of cpu_to_le32() is incorrect.

Remove the unnecessary conversions and operate on the MMIO register value as a CPU-endian u32.

---
 drivers/usb/cdns3/cdnsp-gadget.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/cdns3/cdnsp-gadget.c +2 -2
@@ -155,9 +155,9 @@ static void cdnsp_set_apb_timeout_value(
 	offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP);
 	reg = base + offset + REG_CHICKEN_BITS_3_OFFSET;
 
-	val  = le32_to_cpu(readl(reg));
+	val  = readl(reg);
 	val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout);
-	writel(cpu_to_le32(val), reg);
+	writel(val, reg);
 }
 
 static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit)
author maintainer
#120 lore raw

PATCH 120/250 usb: gadget: f_ncm: Use unsigned int for ndp_index

In reply to Greg Kroah-Hartman

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

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

From: Sonali Pradhan <[email protected]>

commit 6b1c8a9403a26cb0fed7a648916c74dc236da591 upstream.

The variable ndp_index is declared as a signed integer, but it stores the return value of get_ncm(), which is unsigned.

A malicious host can supply a large offset that overflows the signed ndp_index, making it negative. Because ndp_index is compared against unsigned bounds, this negative value bypasses sanity checks and leads to an out-of-bounds read when calculating the address of the NDP block (ntb_ptr + ndp_index).

Fix this by changing ndp_index to unsigned int to ensure consistent unsigned comparisons throughout the function.

Fixes 370af734dfaf ("usb: gadget: NCM: RX function support multiple NDPs")
Cc stable <[email protected]>
---
 drivers/usb/gadget/function/f_ncm.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_ncm.c +1 -1
@@ -1171,7 +1171,7 @@ static int ncm_unwrap_ntb(struct gether
 	unsigned char	*ntb_ptr = skb->data;
 	__le16		*tmp;
 	unsigned	index, index2;
-	int		ndp_index;
+	unsigned int	ndp_index;
 	unsigned	dg_len, dg_len2;
 	unsigned	ndp_len;
 	unsigned	block_len;
author maintainer
#121 lore raw

PATCH 121/250 net: usb: ax88179_178a: fix skb leak in ax88179_tx_fixup()

In reply to Greg Kroah-Hartman

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

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

From: Yi Cong <[email protected]>

commit 1f428e30947395d9b9aacee03e25a4e6cfcad7a4 upstream.

When the interface has NETIF_F_SG enabled and skb_linearize() fails in ax88179_tx_fixup(), the function returns NULL without freeing the skb.

usbnet_start_xmit() treats a NULL return from tx_fixup() as a drop (info->flags does not set FLAG_MULTI_PACKET for this driver), jumping to the "drop" label where it does if (skb) dev_kfree_skb_any(skb). Because tx_fixup() returned NULL, the local skb variable in usbnet_start_xmit() is NULL, so the original skb is never freed — a memory leak on every TX frame whose linearization fails (i.e. under memory pressure).

Free the skb before returning, matching the error handling already used for the pskb_expand_head() failure path in the same function.

---
 drivers/net/usb/ax88179_178a.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/usb/ax88179_178a.c +3 -1
@@ -1493,8 +1493,10 @@ ax88179_tx_fixup(struct usbnet *dev, str
 
 	headroom = skb_headroom(skb) - 8;
 
-	if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb))
+	if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb)) {
+		dev_kfree_skb_any(skb);
 		return NULL;
+	}
 
 	if ((skb_header_cloned(skb) || headroom < 0) &&
 	    pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) {
author maintainer
#122 lore raw

PATCH 122/250 net: usb: ipheth: fix carrier_work UAF on disconnect

In reply to Greg Kroah-Hartman

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

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

From: Doruk Tan Ozturk <[email protected]>

commit fde39b8a521780391fb4e5bda2c0aa4928947f12 upstream.

ipheth_sndbulk_callback() re-arms the carrier-check work on any non-zero URB status:

	else
		schedule_delayed_work(&dev->carrier_work, 0);

Nothing ties that to the interface being up, so the work can be armed again after ipheth_close() has already drained it, and stay armed until the netdev whose private area embeds it is freed.

On unplug with a TX URB in flight, ipheth_disconnect() drains the work through unregister_netdev() -> ipheth_close() -> cancel_delayed_work_sync() and only then calls ipheth_kill_urbs(). usb_kill_urb() completes the in-flight TX URB with -ENOENT, so ipheth_sndbulk_callback() runs after the drain and re-arms carrier_work.

The same completion also re-arms the work if the interface is only brought down while a TX URB is in flight, and ipheth_carrier_check_work() then keeps re-queueing itself once a second. unregister_netdev() does not call ipheth_close() for an already-down interface, so nothing drains it on the later unplug either.

In both cases free_netdev() frees the netdev while carrier_work is still pending, and ipheth_carrier_check_work() dereferences freed memory.

Tie the work to the interface state instead of chasing the completion:
disable it in ipheth_close() and enable it in ipheth_open(), so a schedule_delayed_work() from the URB completion is a no-op whenever the interface is not up. disable_delayed_work_sync() also waits for a running instance, so it fully replaces the cancel_delayed_work_sync() it takes the place of. The work starts out disabled in ipheth_probe() so the enable/disable counts balance from the first open.

Reproduced under KASAN on linux-next (next-20260731) with dummy_hcd and raw-gadget standing in for the device, driving the second path above (the interface is already down, so unregister_netdev() does not call ipheth_close()): 15 of 15 unpatched boots report a slab-use-after-free in __run_timers(), freed by ipheth_disconnect() and re-armed from ipheth_sndbulk_callback() via queue_delayed_work_on(). The same trigger on a kernel differing only by this patch reports 0 of 15, and the carrier check still functions across open/close cycles.

The reproducer needs an attached USB device that stops draining bulk OUT, plus a link down and unplug, driven as root. It is not a privilege boundary crossing and no exploit primitive was developed.

Found by 0sec (https://0sec.ai).

Fixes bb1b40c7cb86 ("usbnet: ipheth: prevent TX queue timeouts when device not ready")
---
 drivers/net/usb/ipheth.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/net/usb/ipheth.c +10 -1
@@ -490,6 +490,7 @@ static int ipheth_open(struct net_device
 	if (retval)
 		return retval;
 
+	enable_delayed_work(&dev->carrier_work);
 	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
 	return retval;
 }
@@ -499,7 +500,11 @@ static int ipheth_close(struct net_devic
 	struct ipheth_device *dev = netdev_priv(net);
 
 	netif_stop_queue(net);
-	cancel_delayed_work_sync(&dev->carrier_work);
+	/* A TX URB can still complete with an error after this point and
+	 * try to re-arm the carrier work. Disable it instead of cancelling
+	 * it, so that such a schedule_delayed_work() is a no-op.
+	 */
+	disable_delayed_work_sync(&dev->carrier_work);
 	return 0;
 }
 
@@ -633,6 +638,10 @@ static int ipheth_probe(struct usb_inter
 	}
 
 	INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
+	/* Armed only between ipheth_open() and ipheth_close(). Start out
+	 * disabled so the enable/disable counts balance from the first open.
+	 */
+	disable_delayed_work(&dev->carrier_work);
 
 	retval = ipheth_alloc_urbs(dev);
 	if (retval) {
author maintainer
#123 lore raw

PATCH 123/250 vt: add permission check for KDSKBMETA ioctl

In reply to Greg Kroah-Hartman

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

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

From: Joshua Rogers <[email protected]>

commit a7ad0034453ba4c353f9b8f810ee2569de33d283 upstream.

KDSKBMETA modifies keyboard meta mode but lacks the !perm check that all other keyboard setter ioctls in vt_k_ioctl() enforce, allowing a process to change meta mode on a non-controlling console without authorization.

---
 drivers/tty/vt/vt_ioctl.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/tty/vt/vt_ioctl.c +2 -0
@@ -406,6 +406,8 @@ static int vt_k_ioctl(struct tty_struct
 	/* this could be folded into KDSKBMODE, but for compatibility
 	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
 	case KDSKBMETA:
+		if (!perm)
+			return -EPERM;
 		return vt_do_kdskbmeta(console, arg);
 
 	case KDGKBMETA:
author maintainer
#124 lore raw

PATCH 124/250 vt: stabilize tty reference in kbd_keycode with tty_port_tty_get

In reply to Greg Kroah-Hartman

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

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

From: Joshua Rogers <[email protected]>

commit e25d47a526939ad44b75f778b8a7500562b84fc1 upstream.

kbd_keycode() reads vc->port.tty without acquiring a tty reference, racing against con_shutdown() which clears port.tty under a different lock. Use tty_port_tty_get()/tty_kref_put() to hold a proper reference for the duration the tty pointer is needed.

---
 drivers/tty/vt/keyboard.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/tty/vt/keyboard.c +4 -1
@@ -1396,7 +1396,7 @@ static void kbd_keycode(unsigned int key
 	struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
 	int rc;
 
-	tty = vc->port.tty;
+	tty = tty_port_tty_get(&vc->port);
 
 	if (tty && (!tty->driver_data)) {
 		/* No driver data? Strange. Okay we fix it then. */
@@ -1456,9 +1456,12 @@ static void kbd_keycode(unsigned int key
 		 * characters get aren't echoed locally. This makes key repeat
 		 * usable with slow applications and under heavy loads.
 		 */
+		tty_kref_put(tty);
 		return;
 	}
 
+	tty_kref_put(tty);
+
 	param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
 	param.ledstate = kbd->ledflagstate;
 	key_map = key_maps[shift_final];
author maintainer
#125 lore raw

PATCH 125/250 Input: evdev - fix information leak in evdev_pass_values()

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Torokhov <[email protected]>

commit 90f305f2c7a30257c683e13f4bf7c798eea992a0 upstream.

In evdev_pass_values(), the input_event structure is allocated on the kernel stack and populated field-by-field. However, it is never fully initialized. On architectures where struct input_event contains explicit or implicit padding (such as the 32-bit __pad field on SPARC64), these padding bytes are left uninitialized.

When this event structure is subsequently passed to the client buffer and later copied to userspace, the uninitialized padding bytes leak kernel stack memory, potentially exposing sensitive information.

Similar issues exist in __evdev_queue_syn_dropped and __pass_event.

Fix this by explicitly zeroing the entire event structure with memset() before populating its fields. This ensures all padding bytes are cleared before the data crosses the security boundary.

---
 drivers/input/evdev.c |   22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)
drivers/input/evdev.c +12 -10
@@ -149,11 +149,11 @@ static void __evdev_queue_syn_dropped(st
 	struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]);
 	struct input_event ev;
 
+	memset(&ev, 0, sizeof(ev));
 	ev.input_event_sec = ts.tv_sec;
 	ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
 	ev.type = EV_SYN;
 	ev.code = SYN_DROPPED;
-	ev.value = 0;
 
 	client->buffer[client->head++] = ev;
 	client->head &= client->bufsize - 1;
@@ -221,20 +221,20 @@ static void __pass_event(struct evdev_cl
 	client->head &= client->bufsize - 1;
 
 	if (unlikely(client->head == client->tail)) {
+		struct input_event ev;
+
+		memset(&ev, 0, sizeof(ev));
+		ev.input_event_sec = event->input_event_sec;
+		ev.input_event_usec = event->input_event_usec;
+		ev.type = EV_SYN;
+		ev.code = SYN_DROPPED;
+
 		/*
 		 * This effectively "drops" all unconsumed events, leaving
 		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
 		 */
 		client->tail = (client->head - 2) & (client->bufsize - 1);
-
-		client->buffer[client->tail] = (struct input_event) {
-			.input_event_sec = event->input_event_sec,
-			.input_event_usec = event->input_event_usec,
-			.type = EV_SYN,
-			.code = SYN_DROPPED,
-			.value = 0,
-		};
-
+		client->buffer[client->tail] = ev;
 		client->packet_head = client->tail;
 	}
 
@@ -256,6 +256,8 @@ static void evdev_pass_values(struct evd
 	if (client->revoked)
 		return;
 
+	memset(&event, 0, sizeof(event));
+
 	ts = ktime_to_timespec64(ev_time[client->clk_type]);
 	event.input_event_sec = ts.tv_sec;
 	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
author maintainer
#126 lore raw

PATCH 126/250 mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Stoakes (ARM) <[email protected]>

commit 26444eb71465c9934d9d418ef69c43f61185329b upstream.

Patch series "mm: fix UAF caused by race between ptdump and vmap pgtable freeing", v6.

Kernel page table walkers fall into two broad categories - those ranges where no exclusion is required via walk_kernel_page_table_range_lockless() and those where exclusion is required via walk_kernel_page_table_range() or walk_page_range_debug().

The former category is used only by arm64 arch code operating on ranges it both wholly owns and does not concurrently write.

The latter category consists of kernel page table walkers operating on ranges that are wholly owned (but which need exclusion against concurrent writers).

The lock used for exclusion is the mmap lock, and for kernel ranges this is the mmap lock on init_mm.

ptdump is a special case being both the only user of walk_page_range_debug(), and the only case in which it walks ranges it does not own.

This presents a problem, as page tables may be freed under ptdump. And indeed there is a use-after-free bug in the kernel as a result, which this series addresses.

vmap promotes page tables to huge leaf entries where possible, freeing the lower page table when it does. It does this with no meaningful locks held against concurrent ptdump walks.

As a result, use-after-free can currently occur. This series addresses the issue by having the vmap huge promotion logic acquire the mmap read lock while both setting the huge page table entry and freeing the prior leaf page table.

The ptdump code already acquires the mmap write lock, so by doing so we ensure that the ptdump walker only ever observes either the huge page table entry or the existing page table entry, and nothing is freed underneath it.

A mitigation for this issue was already applied for arm64 in commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump"), which this series has to deal with carefully.

This mitigation resolves the issue by acquiring the mmap read lock on init_mm on vmap page table free if a ptdump is in progress.

However the fix in this series would cause a deadlock if we were to simply apply it for arm64 without also reverting the change.

This is because vmap may acquire the read lock before ptdump attempts to acquire the write lock, which then gets queued, and rwsem starvation rules mean that the (unacknowledged) nested mmap read lock in the arm64 code would also block, meaning the original read lock is never released and thus deadlock.

This series works around this by #ifndef CONFIG_ARM64'ing the mmap read lock in vmap logic, then partially reverting commit fa93b45fd397 ("arm64:
Enable vmalloc-huge with ptdump"), keeping the enablement of huge vmap support, and removing the ifdeffery with the partial revert patch.

There are related issues that are also addressed in this series:

* x86 page attribute logic, specifically Change Page Attributes (CPA), implements a feature whereby huge ranges can be collapsed into huge leaf entries. This can similarly cause a UAF when done in parallel with a ptdump walk, so similarly acquire the init_mm mmap lock to avoid this.

* The CPA logic allows concurrent page table manipulation and CPA collapse, meaning the former risks accessing a page table the latter frees. Fix this by acquiring mmap write lock on init_mm across the whole CPA collapse operation and read lock on the page table manipulation.

* x86 and arm64 permit walks of non-kernel mm's (both allowing efi mm walks, and in x86's case arbitrary mm's), so we ensure kernel mappings remain stable by locking the init_mm as well as the mm being walked.

The ordering of patches is established for both strict dependencies (the arm64 partial revert in particular has to be done after the vmap changes) and logical ones (the non-kernel mm fix only makes sense once the vmap/CPA fixes are in place).

This patch (of 3):

Currently there is a nasty race between ptdump and vmap when attempting to map a huge P4D, PUD or PMD entry:

* ptdump walks kernel page table ranges it doesn't own.

* When vmap maps ranges it tries to promotes existing ones to huge page tables in vmap_try_huge_[p4d,pud,pmd]() at P4D, PUD and PMD level, freeing the lower page table in [p4d,pud,pmd]_free_[pud,pmd,pte]_page() when it succeeds.

Both of these things can happen at the same time and as a result ptdump can access a freed page table, resulting in a use-after-free and memory corruption.

This is possible because while ptdump_walk_pgd() holds both the mem hotplug lock and the mmap write lock before invoking walk_page_range_debug(), vmap takes no relevant locks at all.

Fix this by holding the mmap read lock in vmap_try_huge_*() when freeing page tables.

The read lock is sufficient: ptdump is the only walker that must be excluded and it holds the mmap write lock. Other holders of the read lock may run concurrently, but each exclusively owns the range it operates on and cannot reach the page tables freed here.

We also hold the lock while assigning the huge page table entry, which means page table walkers observe only the huge or non-huge page table entry.

We use a trylock to prevent ptdump from blocking vmap making forward progress. This is fine because it's an optimisation in any case, and thus the vmap can safely proceed regardless.

All other kernel page table walkers that touch vmalloc ranges either exclusively own the memory walked or acquire the mmap lock, so this correctly excludes those walkers.

One wrinkle here is commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump"), which addresses the issue for arm64 only by explicitly acquiring the mmap read lock on kernel page table freeing should a concurrent ptdump be in progress.

This is problematic as vmap may acquire the mmap read lock prior to ptdump attempting to acquire an mmap write lock, leading to a deadlock when the mmap read lock is slept upon on page table freeing due to rwsem anti-starvation.

We work around this by predicating the mmap lock being taken on !CONFIG_ARM64 for the time being.

With this patch applied, a follow up will partially revert commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump") and at that stage remove the arm64 ifdeffery.

We also update walk_page_range_debug() to assert the mmap write lock unconditionally and update the comment here to reflect this change.

The issue has existed as long as ptdump was available and vmap freed page tables when promoting to a huge leaf entry, that is, since commit b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table") for huge ioremap, and commit 121e6f3258fe ("mm/vmalloc: hugepage vmalloc mappings") for huge vmalloc.

Since the former is the earlier of the two we choose that for our Fixes tag.

We also define a guard class for mmap_read_trylock() so we can use cleanup.h to make the scope handling cleaner in the implementation.

This patch is based on work by David Carlier (linked), with gratitude!

Fixes b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table")
Reported-by [email protected]
Cc Andy Lutomirski <[email protected]>
Cc "Borah, Chaitanya Kumar" <[email protected]>
Cc "Borislav Petkov (AMD)" <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dave Hansen <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc Shakeel Butt <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Toshi Kani <[email protected]>
Cc "Uladzislau Rezki (Sony)" <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
---
 include/linux/mmap_lock.h |    1 
 mm/pagewalk.c             |   22 +++++++++++---------
 mm/vmalloc.c              |   49 +++++++++++++++++++++++++++++++++++++---------
 3 files changed, 53 insertions(+), 19 deletions(-)
include/linux/mmap_lock.h +1 -0
@@ -397,6 +397,7 @@ static inline void mmap_read_unlock(stru
 
 DEFINE_GUARD(mmap_read_lock, struct mm_struct *,
 	     mmap_read_lock(_T), mmap_read_unlock(_T))
+DEFINE_GUARD_COND(mmap_read_lock, _try, mmap_read_trylock(_T))
 
 static inline void mmap_read_unlock_non_owner(struct mm_struct *mm)
 {
mm/pagewalk.c +12 -10
@@ -678,6 +678,8 @@ int walk_kernel_page_table_range_lockles
  * will also not lock the PTEs for the pte_entry() callback.
  *
  * This is for debugging purposes ONLY.
+ *
+ * The mmap write lock must be held.
  */
 int walk_page_range_debug(struct mm_struct *mm, unsigned long start,
 			  unsigned long end, const struct mm_walk_ops *ops,
@@ -691,6 +693,16 @@ int walk_page_range_debug(struct mm_stru
 		.no_vma		= true
 	};
 
+	/*
+	 * When walking userland page tables, an mmap write lock must be held to
+	 * account for munmap() downgrading to an mmap read lock when tearing
+	 * down page tables.
+	 *
+	 * When walking kernel page tables, an mmap write lock must also be held
+	 * to account for page table freeing on vmap huge page mapping.
+	 */
+	mmap_assert_write_locked(mm);
+
 	/* For convenience, we allow traversal of kernel mappings. */
 	if (mm == &init_mm)
 		return walk_kernel_page_table_range(start, end, ops,
@@ -700,16 +712,6 @@ int walk_page_range_debug(struct mm_stru
 	if (!check_ops_valid(ops))
 		return -EINVAL;
 
-	/*
-	 * The mmap lock protects the page walker from changes to the page
-	 * tables during the walk.  However a read lock is insufficient to
-	 * protect those areas which don't have a VMA as munmap() detaches
-	 * the VMAs before downgrading to a read lock and actually tearing
-	 * down PTEs/page tables. In which case, the mmap write lock should
-	 * be held.
-	 */
-	mmap_assert_write_locked(mm);
-
 	return walk_pgd_range(start, end, &walk);
 }
 
mm/vmalloc.c +40 -9

76 lines not on this page · raw message

author maintainer
#127 lore raw

PATCH 127/250 ima: fix out-of-bounds read in xattr_verify()

In reply to Greg Kroah-Hartman

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

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

From: Lincoln Wallace <[email protected]>

commit 5ff232d31106f45ac87c3b64e1d35a0667777797 upstream.

The digest-length check in xattr_verify() mixes int and size_t:

	if (xattr_len - sizeof(xattr_value->type) - hash_start >=
			iint->ima_hash->length)

sizeof() yields size_t, so the usual arithmetic conversions promote the whole left-hand side to unsigned 64-bit before the subtraction runs. For a truncated xattr this underflows instead of going negative:
a 1-byte IMA_XATTR_DIGEST_NG xattr (xattr_len == 1, hash_start == 1) turns "1 - 1 - 1" into SIZE_MAX, which is trivially >= ima_hash->length. The check then passes and the following memcmp() reads iint->ima_hash->length bytes starting past the end of the buffer vfs_getxattr_alloc() allocated for it.

Nothing upstream clamps xattr_len back into a safe range first:
ima_get_hash_algo() only special-cases xattr_len < 2 to pick a default algorithm, and evm_verifyxattr() returns INTEGRITY_UNKNOWN rather than failing when no HMAC key is loaded, so a truncated security.ima value reaches the length check as-is.

Rewrite the comparison so every operand stays a signed int and no implicit conversion to size_t can occur.

Fixes 3ea7a56067e6 ("ima: provide hash algo info in the xattr")
---
 security/integrity/ima/ima_appraise.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
security/integrity/ima/ima_appraise.c +7 -2
@@ -303,8 +303,13 @@ static int xattr_verify(enum ima_hooks f
 		} else {
 			set_bit(IMA_DIGSIG, &iint->atomic_flags);
 		}
-		if (xattr_len - sizeof(xattr_value->type) - hash_start >=
-				iint->ima_hash->length)
+		/*
+		 * Use addition, not subtraction: sizeof() forces unsigned
+		 * math and a short xattr_len would wrap around, bypassing
+		 * this bounds check.
+		 */
+		if (xattr_len >= (int)sizeof(xattr_value->type) + hash_start +
+				(int)iint->ima_hash->length)
 			/*
 			 * xattr length may be longer. md5 hash in previous
 			 * version occupied 20 bytes in xattr, instead of 16
author maintainer
#128 lore raw

PATCH 128/250 ipvs: stop estimator after disabled calc phase

In reply to Greg Kroah-Hartman

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

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

From: Zhiling Zou <[email protected]>

commit 558f67f1340f803a346ecd14a69c49653111c5f4 upstream.

IPVS estimator kthread 0 starts with zeroed chain and tick limits until its initial calculation phase completes. If network namespace teardown clears ipvs->enable during that phase, ip_vs_est_calc_phase() can return without installing positive limits.

The kthread can then continue into its main loop and drain est_temp_list with zero chain_max, tick_max and est_max_count values. Each enqueue consumes one available tick row, but est_count never reaches the zero est_max_count value. After all rows are consumed, the row lookup returns IPVS_EST_NTICKS and ip_vs_enqueue_estimator() writes past the ticks and tick_len arrays.

Exit kthread 0 after the calculation phase if the kthread is stopping or IPVS has been disabled. That keeps temporary estimators from being drained after the limits failed to initialize.

Estimator kthreads can now self-exit before teardown or reload stops kd->task. Keep an extra task reference after creation and release it with kthread_stop_put(), so kd->task remains valid until the stop paths consume that reference.

Fixes 705dd3444081 ("ipvs: use kthreads for stats estimation")
---
 net/netfilter/ipvs/ip_vs_est.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
net/netfilter/ipvs/ip_vs_est.c +7 -3
@@ -187,8 +187,11 @@ static int ip_vs_estimation_kthread(void
 		}
 
 		/* kthread 0 will handle the calc phase */
-		if (ipvs->est_calc_phase)
+		if (ipvs->est_calc_phase) {
 			ip_vs_est_calc_phase(ipvs);
+			if (kthread_should_stop() || !READ_ONCE(ipvs->enable))
+				return 0;
+		}
 	}
 
 	while (1) {
@@ -263,6 +266,7 @@ int ip_vs_est_kthread_start(struct netns
 		kd->task = NULL;
 		goto out;
 	}
+	get_task_struct(kd->task);
 
 	set_user_nice(kd->task, sysctl_est_nice(ipvs));
 	if (sysctl_est_preferred_cpulist(ipvs))
@@ -279,7 +283,7 @@ void ip_vs_est_kthread_stop(struct ip_vs
 {
 	if (kd->task) {
 		pr_info("stopping estimator thread %d...\n", kd->id);
-		kthread_stop(kd->task);
+		kthread_stop_put(kd->task);
 		kd->task = NULL;
 	}
 }
@@ -511,7 +515,7 @@ static void ip_vs_est_kthread_destroy(st
 	if (kd) {
 		if (kd->task) {
 			pr_info("stop unused estimator thread %d...\n", kd->id);
-			kthread_stop(kd->task);
+			kthread_stop_put(kd->task);
 		}
 		ip_vs_stats_free(kd->calc_stats);
 		kfree(kd);