Skip to contentSkip to conversation

6.12.103-rc1 review

PATCH In review Greg Kroah-Hartman 15 participants 357 messages Aug 7 – Aug 21 Page 1 of 3

Subsystems (2)
lore
Share & tools
lore

Greg Kroah-Hartman

author maintainer
#0 lore raw

cover 6.12.103-rc1 review

This is the start of the stable review cycle for the 6.12.103 release. There are 337 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 Sun, 09 Aug 2026 14:33:46 +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.12.103-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.12.y
and the diffstat can be found below.

thanks,

greg k-h

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

Greg Kroah-Hartman <[email protected]>

    Linux 6.12.103-rc1

Thomas Zimmermann <[email protected]>
drm/tegra: fbdev: Do not assign to struct drm_fb_helper.info

Bart Van Assche <[email protected]>
drm/fb-helper: Fix a locking bug in an error path

Andrei Kuchynski <[email protected]>
usb: typec: ucsi: Correct teardown ordering in ucsi_init() error path

Oliver Hartkopp <[email protected]>
can: isotp: fix timer drain order, wakeup handling and tx_gen ordering

Oliver Hartkopp <[email protected]>
can: use skb hash instead of private variable in headroom

David Howells <[email protected]>
rxrpc: Fix irq-disabled in local_bh_enable()

David Howells <[email protected]>
rxrpc: Manage RTT per-call rather than per-peer

David Howells <[email protected]>
rxrpc: Fix the calculation and use of RTO

David Howells <[email protected]>
rxrpc: Adjust the rxrpc_rtt_rx tracepoint

David Howells <[email protected]>
rxrpc: Generate rtt_min

Zongyao Bai <[email protected]>
drm/xe/pt: Reset current_op in xe_pt_update_ops_init()

Matthew Brost <[email protected]>
drm/xe: Stub out new pagefault layer

Jani Nikula <[email protected]>

    drm/i915/hdcp: check streams[] bounds before overflow

Suraj Kandpal <[email protected]>
drm/i915/hdcp: Skip inactive MST connectors when building stream list

Jani Nikula <[email protected]>
drm/i915/hdcp: require monotonically increasing seq_num_v

Suraj Kandpal <[email protected]>
drm/i915/hdcp: Move to using intel_display in intel_hdcp

Nitin Gote <[email protected]>
drm/xe: Hold a dma-buf reference for imported BOs

Thomas Hellström <[email protected]>

    drm/xe: Rename ___xe_bo_create_locked()

Jani Nikula <[email protected]>
drm/i915/vrr: require valid min/max vfreq for VRR

Ville Syrjälä <[email protected]>
drm/i915/vrr: Check HAS_VRR() first in intel_vrr_is_capable()

Matthew Brost <[email protected]>
drm/xe: Wait on external BO kernel fences in exec IOCTL

Thomas Hellström <[email protected]>
drm/exec: Remove the index parameter from drm_exec_for_each_locked_obj[_reverse]

Thomas Zimmermann <[email protected]>
drm/tegra: fbdev: Remove offset into framebuffer memory

Thomas Zimmermann <[email protected]>
drm/fb-helper: Allocate and release fb_info in single place

Asad Kamal <[email protected]>
drm/amdgpu/gfx: fix cleaner shader IB buffer overflow

Pierre-Eric Pelloux-Prayer <[email protected]>
drm/amdgpu: give each kernel job a unique id

Pierre-Eric Pelloux-Prayer <[email protected]>
drm/sched: Store the drm client_id in drm_sched_fence

Tvrtko Ursulin <[email protected]>
drm/amdgpu: Fix context pstate override handling

Timur Kristóf <[email protected]>
drm/amdgpu: Respect placement requirements in amdgpu_gtt_mgr functions

Breno Leitao <[email protected]>
mm/kmemleak: fix checksum computation for per-cpu objects

Catalin Marinas <[email protected]>
kmemleak: iommu/iova: fix transient kmemleak false positive

Geliang Tang <[email protected]>
mptcp: pm: userspace: fix use-after-free in get_local_id

Geliang Tang <[email protected]>
mptcp: pm: use addr entry for get_local_id

Geliang Tang <[email protected]>
mptcp: add mptcp_userspace_pm_lookup_addr helper

Geliang Tang <[email protected]>
mptcp: pm: avoid code duplication to lookup endp

Kai Vehmanen <[email protected]>
ALSA: hda: codecs: hdmi: disable keep-alive before audio format change

LiangCheng Wang <[email protected]>
wifi: brcmfmac: set F2 blocksize to 256 for BCM43752

Gokul Sivakumar <[email protected]>
wifi: brcmfmac: fix 43752 SDIO FWVID incorrectly labelled as Cypress (CYW)

Daniel Hodges <[email protected]>
wifi: ath6kl: fix use-after-free in aggr_reset_state()

Fan Wu <[email protected]>
wifi: brcmfmac: drain bus_reset work on device removal

Niklas Söderlund <[email protected]>
media: uapi: rkisp: Correct name version enum

Jackson Lee <[email protected]>
media: chips-media: wave5: Support CBP profile

Sakari Ailus <[email protected]>
media: imx219: Fix maximum frame length in lines

Jai Luthra <[email protected]>
media: i2c: imx219: Rename VTS to FRM_LENGTH

Andrei Kuchynski <[email protected]>
usb: typec: ucsi: Fix race condition and ordering in port unregistration

Sergey Senozhatsky <[email protected]>
usb: typec: ucsi: split connector lock classes

Cen Zhang <[email protected]>
usb: gadget: f_tcm: synchronize delayed set_alt with teardown

Junjie Cao <[email protected]>
gpio: pch: use raw_spinlock_t for the register lock

Harry Yoo (Oracle) <[email protected]>
mm/slab: prevent unbounded recursion in free path with new kmalloc type

Harry Yoo (Oracle) <[email protected]>
lib/alloc_tag: introduce mem_alloc_profiling_permanently_disabled()

Kiryl Shutsemau (Meta) <[email protected]>
mm/huge_memory: unlock i_mmap_rwsem before releasing after-split folios

Kiryl Shutsemau (Meta) <[email protected]>
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes

Kiryl Shutsemau (Meta) <[email protected]>
mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Ensure locking/ref counting for OA whitelists

Ashutosh Dixit <[email protected]>
drm/xe/oa: (De-)whitelist OA registers on OA stream open/release

Ashutosh Dixit <[email protected]>
drm/xe/rtp: (De-)whitelist OA registers for all hwe's for a gt

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Toggle 'deny' bit to (de-)whitelist OA regs

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Save OA nonpriv registers to register save/restore lists

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Generalize whitelist_apply_to_hwe

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Keep track of non-OA nonpriv slots

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Maintain OA whitelists separately

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Add RING_FORCE_TO_NONPRIV_DENY to OA whitelists

Lucas De Marchi <[email protected]>
drm/xe: Apply whitelist to engine save-restore

Michal Wajdeczko <[email protected]>
drm/xe: Introduce xe_gt_dbg_printer()

Ashutosh Dixit <[email protected]>
drm/xe/rtp: Refactor OAG MMIO trigger register whitelisting

Pauli Virtanen <[email protected]>

    Bluetooth: ISO: fix CONNECTED -> CLOSED transition on shutdown/release

Wandun Chen <[email protected]>
of: reserved_mem: avoid post-init UAF when alloc_reserved_mem_array() fails

Niklas Cassel <[email protected]>
ata: ahci: Make ahci_ignore_port() handle empty mask_port_map

Damien Le Moal <[email protected]>
ata: libahci_platform: Do not set mask_port_map when not needed

HyeongJun An <[email protected]>
HID: logitech-dj: Fix maxfield check in DJ short report validation

Jun Guo <[email protected]>
spi: spi-cadence: enable SPI_CONTROLLER_MUST_TX

Zack Rusin <[email protected]>
drm/vmwgfx: validate external BO copy bounds for both stride paths

Zack Rusin <[email protected]>
drm/vmwgfx: use check_add_overflow for shader size+offset bound

Zack Rusin <[email protected]>
drm/vmwgfx: avoid destroy_workqueue(NULL) on vkms init failure

Zack Rusin <[email protected]>
drm/vmwgfx: bound DMA command body size against suffix pointer

Zack Rusin <[email protected]>
drm/vmwgfx: validate DRAW_PRIMITIVES header size before division

Zack Rusin <[email protected]>
drm/vmwgfx: drop dma_buf reference on foreign-fd prime import

Zack Rusin <[email protected]>
drm/vmwgfx: reject DX_BIND_QUERY without a DX context

Zack Rusin <[email protected]>
drm/vmwgfx: fix guest_memory_dirty bitfield clobbered as size

William Palacek <[email protected]>
drm/amdkfd: hold event_mutex while checkpointing CRIU events

David Francis <[email protected]>
drm/amdkfd: Handle invalid event type in CRIU event restore

William Palacek <[email protected]>
drm/amdkfd: fix uint32_t overflow in EOP ring buffer size alignment

Vladimir Marioukhine <[email protected]>
drm/amdkfd: fix QID bit leak in pqm_create_queue()

Gang Ba <[email protected]>
drm/amdkfd: Fix missing authorization check in KFD_IOC_DBG_TRAP_DISABLE

Jiri Slaby (SUSE) <[email protected]>
drm/amd/display: use proper context for logging

Ray Wu <[email protected]>
drm/amd/display: Increase HDMI AV mute wait from 2 to 3 frames

Harkirat Gill <[email protected]>
drm/amdgpu: cap GTT size to physical RAM on APUs

Candice Li <[email protected]>
drm/amdgpu: restore UMD profile pstate after runtime resume

Myeonghun Pak <[email protected]>
drm/mediatek: ovl_adaptor: balance component registrations

Osama Abdelkader <[email protected]>
drm/panthor: validate firmware interface structure sizes

Osama Abdelkader <[email protected]>
drm/panthor: reject firmware sections with oversized data

Maíra Canal <[email protected]>
drm/vc4: Zero the tile state data array before each BIN job

Jose Maria Casanova Crespo <[email protected]>
drm/vc4: Supply the overflow slot size in BPOS, not the whole bin BO size

Alexander Kaplan <[email protected]>
drm/dp: Read the PCON max FRL bandwidth only for HDMI DFPs

Avi Weiss <[email protected]>
can: ctucanfd: mark error-active controller status valid

Avi Weiss <[email protected]>
can: ctucanfd: handle bus error interrupts

Avi Weiss <[email protected]>
can: ctucanfd: unmap BAR0 using base address

Avi Weiss <[email protected]>
can: ctucanfd: use self-test mode for PRESUME_ACK

Pengpeng Hou <[email protected]>
can: ctucanfd: add missing MODULE_DEVICE_TABLE()

Pengpeng Hou <[email protected]>
can: peak_usb: validate uCAN receive record lengths

Maoyi Xie <[email protected]>
can: peak_usb: peak_usb_start(): fix double free of transfer buffer on URB submit error

James Gao <[email protected]>
can: peak_usb: add bounds check for USB channel index

Pengpeng Hou <[email protected]>
can: softing: fw_parse(): validate firmware record spans

Pengpeng Hou <[email protected]>
can: kvaser_usb_leaf: kvaser_usb_leaf_wait_cmd(): validate received command extents

Abdun Nihaal <[email protected]>
can: kvaser_usb: kvaser_usb_hydra_get_busparams(): fix memory leak in kvaser_usb_hydra_get_busparams()

Tetsuo Handa <[email protected]>
can: j1939: use netdevice_tracker for j1939_{priv,session,ecu} tracking

Oleksij Rempel <[email protected]>
can: j1939: transport: j1939_session_fresh_new(): initialize receive buffer

Marc Kleine-Budde <[email protected]>
can: gs_usb: gs_usb_receive_bulk_callback(): resubmit URB on skb allocation failure

Guangshuo Li <[email protected]>
can: etas_es58x: es58x_read_bulk_callback(): fix RX buffer leak on URB resubmit failure

Pengpeng Hou <[email protected]>
can: ems_usb: validate CPC message lengths

Lucas Martins Alves <[email protected]>
can: c_can: c_can_chip_config(): keep controller in init mode until bittiming is configured

Liem <[email protected]>
i2c: imx: Cancel hrtimer before clearing slave pointer

Liem <[email protected]>
i2c: imx: Fix slave registration race and error handling

Jonas Gorski <[email protected]>
i2c: iproc: reset bus after timeout if START_BUSY is stuck

H. Nikolaus Schaller <[email protected]>
i2c: jz4780: Cache host clock rate at probe to prevent CCF prepare_lock deadlock

Dawei Feng <[email protected]>
ice: fix memory leak in ice_lbtest_prepare_rings()

Aaron Ma <[email protected]>
ice: wait for reset completion in ice_resume()

Ilya Maximets <[email protected]>
net: openvswitch: fix skb leak on flow key update failure during ct

Ilya Maximets <[email protected]>
net: openvswitch: fix skb leak on flow key update failure during recirculation

Ilya Maximets <[email protected]>
net: openvswitch: fix potential UAF on meter attach failure

Nava kishore Manne <[email protected]>
phy: zynqmp: keep SERDES scrambler and 8b/10b enabled for USB

Nava kishore Manne <[email protected]>
phy: zynqmp: use read-modify-write for SERDES scrambler bypass

Nava kishore Manne <[email protected]>
phy: zynqmp: fix L0_TM_DISABLE_SCRAMBLE_ENCODER mask

Holger Dengler <[email protected]>
s390/zcrypt: Validate length for CCA ECC private key requests

Holger Dengler <[email protected]>
s390/zcrypt: Validate length for CCA AES cipher key requests

Harald Freudenberger <[email protected]>
s390/zcrypt: Fix wrong domain value verification with EP11 CPRBs

Stefan Haberland <[email protected]>
s390/dasd: Fix undersized format-check buffer

Jan Höppner <[email protected]>
s390/dasd: Fix potential NULL pointer dereference

Aswin Karuvally <[email protected]>
s390/qeth: Check CAP_NET_ADMIN for private ioctls

Niklas Schnelle <[email protected]>
s390/pci: Fix s390_pci_mmio_write syscall error return without MIO

Jianing Li <[email protected]>
power: supply: max17040: handle missing status supplier

Xu Rao <[email protected]>
power: supply: bq25890: fix the -10 C NTC lookup entry

Zhongqiu Han <[email protected]>
cpufreq: schedutil: Publish util hooks only after all sg_cpu are initialized

Abdun Nihaal <[email protected]>
cpufreq: powernow-k8: Fix possible memory leak in powernowk8_cpu_init()

bui duc phuc <[email protected]>
gpio: pca953x: fix cache_only and IRQ state on restore_context() failure

Myeonghun Pak <[email protected]>
i2c: amd-mp2: Unregister callback on adapter add failure

Vincent Jardin <[email protected]>
hwmon: (pmbus/core) notify on the hwmon device, not the i2c client

Hongyan Xu <[email protected]>
hwmon: (npcm750-pwm-fan): stop fan timer on device detach

Asim Viladi Oglu Manizada <[email protected]>
sctp: prevent peer transport count overflow

Yuxiang Yang <[email protected]>
sctp: reject stale cookies with mismatched verification tags

Ibrahim Hashimov <[email protected]>
scsi: scsi_debug: Fix REPORT ZONES alloc_len underflow OOB write

Chris Gellermann <[email protected]>
selftests/clone3: fix wild pointer access of getline due to missing init

Chris Gellermann <[email protected]>
selftests/mm: fix potential wild pointer access of getline due to missing init

Vijaya Krishna Nivarthi <[email protected]>
spi: qcom-qspi: Correct max DMA length to avoid 64K boundary failure

Masami Hiramatsu (Google) <[email protected]>
tracing/filters: Fix false positive match in regex_match_full()

Masami Hiramatsu (Google) <[email protected]>
tracing: Check return value of __register_event() in trace_module_add_events()

Ming Lei <[email protected]>
ublk: reset kernel-owned dev_info fields in ublk_ctrl_add_dev()

Eric Dumazet <[email protected]>
vxlan: use pskb_network_may_pull() in route_shortcircuit()

Eric Dumazet <[email protected]>
vxlan: use neigh_ha_snapshot() in route_shortcircuit()

Eric Dumazet <[email protected]>
vxlan: unclone skb head before modifying eth header in route_shortcircuit()

Eric Dumazet <[email protected]>
vxlan: re-fetch eth header after route_shortcircuit()

Matt Fleming <[email protected]>
veth: convert frag_list skbs before running XDP

Michael Bommarito <[email protected]>
um: vector: fix use-after-free in vector_mmsg_rx()

Thorsten Blum <[email protected]>
powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()

Zhiling Zou <[email protected]>
net: ipv6: clear suppressed fib6 rule result

Zhiling Zou <[email protected]>
net: bridge: stop fast-leave after deleting a port group

Breno Leitao <[email protected]>
mm: memcg: initialize *locked in memcg1_oom_prepare() stub

Link Lin <[email protected]>
mm/page_reporting: use system_freezable_wq to fix UAF during suspend

Christian Brauner <[email protected]>
binfmt_misc: don't let an 'F' entry pin its own instance

Christian Brauner <[email protected]>
binfmt_misc: reject a flag character as the field delimiter

Zhao Li <[email protected]>
wifi: mwifiex: use the subframe length when parsing A-MSDU TDLS frames

Zihan Xi <[email protected]>
tipc: avoid use-after-free in poll trace queue dumps

David Lee <[email protected]>
netfilter: ipset: do not update comments from kernel-side hash adds

Xuanqiang Luo <[email protected]>
net/smc: fix socket use-after-free during link group termination

Zhiling Zou <[email protected]>
ipvs: do not propagate one-packet flag to synced conns

Matt Vollrath <[email protected]>
igbvf: Fix leak in TX DMA error cleanup

Dawei Feng <[email protected]>

    e1000: fix memory leak in e1000_probe()

Md Sadre Alam <[email protected]>
dmaengine: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+

Sonali Pradhan <[email protected]>
ALSA: usb-audio: Clamp frame size in implicit-feedback mode

Sonali Pradhan <[email protected]>
ALSA: usb-audio: Fix DMA buffer out-of-bounds write when fill_max is set

Baul Lee <[email protected]>
ALSA: usb-audio: fix OOB write in snd_usbmidi_akai_output()

Baul Lee <[email protected]>
ALSA: usb-audio: fix stack info leak in RME Digiface status

Baul Lee <[email protected]>
ALSA: usb-audio: fix use-after-free in ump_to_endpoint()

Niklas Cassel <[email protected]>
ata: libata-sata: fix ata_scsi_lpm_supported() iteration

Matt Vollrath <[email protected]>
ata: libata-eh: Increase STANDBY IMMEDIATE timeout

Haidar Lee <[email protected]>
ASoC: tas2562: fix broken entries in the volume lookup table

Haidar Lee <[email protected]>
ASoC: tas2562: fix DVC coefficient write order

Baul Lee <[email protected]>
ALSA: ump: fix double free of out_cvts on rawmidi error

Norbert Szetei <[email protected]>
ALSA: timer: Clear SNDRV_TIMER_IFLG_DEAD once the close completes

Norbert Szetei <[email protected]>
ALSA: seq: Fix division by zero in initialize_timer()

Norbert Szetei <[email protected]>
ALSA: pcm: wake linked drain waiters on unlink

Xu Rao <[email protected]>
ALSA: lx6464es: fix period byte count for 16-bit streams

Takashi Iwai <[email protected]>
ALSA: 6fire: Fix UAF at error handling during probe

Xuanqiang Luo <[email protected]>
bpf: lwt: Fix dst reference leak on reroute failure

Sangho Lee <[email protected]>
Bluetooth: HIDP: validate numbered report payloads

Sangho Lee <[email protected]>
Bluetooth: HIDP: reject frames without a transaction header

Chengfeng Ye <[email protected]>
Bluetooth: hci_sync: Fix advertising data UAFs

Zihan Xi <[email protected]>
Bluetooth: mgmt: fix UAF in pair command cancellation

Zihan Xi <[email protected]>
Bluetooth: mgmt: fix pending command UAF in EIR updates

Greg Kroah-Hartman <[email protected]>
Bluetooth: btmtk: Fix short read errors in btmtk_usb_uhw_reg_read()

Greg Kroah-Hartman <[email protected]>
Bluetooth: btusb: Fix short read errors in btusb_qca_send_vendor_req()

Luxiao Xu <[email protected]>
audit: fix potential use-after-free in audit_del_rule()

Zhan Xusheng <[email protected]>
audit: fix potential integer overflow in audit_log_n_string()

Charles Vosburgh <[email protected]>
sctp: validate Adaptation Indication parameter length

Farhan Ali <[email protected]>
KVM: s390: pci: Validate AIBV and AISB before pinning guest pages

Farhan Ali <[email protected]>
KVM: s390: pci: Fix NULL dereference on AIBV allocation failure

Farhan Ali <[email protected]>
KVM: s390: pci: Reject adapter interrupt forwarding if already enabled

Sean Christopherson <[email protected]>
KVM: SVM: Update x2APIC MSR intercepts if AVIC is inhibited while L2 is active

Raushan Patel <[email protected]>
tracing/probes: Reject $arg0 in meta argument expansion

Gregory Price <[email protected]>
mm/vmstat: fold stranded per-cpu node stats when a node comes online

Xiangfeng Cai <[email protected]>
mm/hugetlb: fix list corruption in allocate_file_region_entries()

Zi Yan <[email protected]>
mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()

Kiryl Shutsemau (Meta) <[email protected]>
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes

Kefeng Wang <[email protected]>
mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE

Nathan Chancellor <[email protected]>
fortify: Disable -Wstringop-overread in tests

Benjamin Boortz <[email protected]>
pinctrl: bm1880: add missing select GENERIC_PINCONF

Michael Bommarito <[email protected]>
erofs: cap LZMA stream pool size

Karl Mehltretter <[email protected]>
pinctrl: devicetree: don't free uninitialized dev_name on error path

Benjamin Boortz <[email protected]>
pinctrl: microchip-sgpio: add missing select REGMAP_MMIO

Cen Zhang (Microsoft) <[email protected]>

    rhashtable: clear stale iter->p on table restart

Namjae Jeon <[email protected]>
ksmbd: fix use-after-free in __close_file_table_ids()

Namjae Jeon <[email protected]>
ksmbd: return success for deferred final close

Denis V. Lunev <[email protected]>
qede: sync udp_tunnel ports outside qede_lock in the recovery path

Gabriele Monaco <[email protected]>
sched/deadline: Use revised wakeup rule only for running dl_server

Suman Ghosh <[email protected]>
octeontx2-pf: Set correct sequence for carrier off and tx queue stop

Jiawen Wu <[email protected]>
net: libwx: fix FDIR ATR queue mismatch for software VLAN packets

Daniel Golle <[email protected]>
net: dsa: mt7530: error out on failed reads in MT7531 PHY polling

Daniel Golle <[email protected]>

    net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend

Karl Mehltretter <[email protected]>
riscv: mm: Fix out-of-bounds page-table walk during memory hot-remove

Muhammad Bilal <[email protected]>
accel/qaic: use sizeof(*trans_hdr) for transaction length check

Masami Hiramatsu (Google) <[email protected]>
tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions

Zheng Yejian <[email protected]>
tracing: Remove TRACE_EVENT_FL_FILTERED logic

Masami Hiramatsu (Google) <[email protected]>
tracing/mmiotrace: Reset dropped_count in mmio_reset_data()

Minhong He <[email protected]>
can: isotp: check register_netdevice_notifier() error in module init

Chenguang Zhao <[email protected]>
net: sxgbe: check descriptor ring allocation failures

Chenguang Zhao <[email protected]>
net: sxgbe: free TX rings on RX allocation failure

Leon Romanovsky <[email protected]>
scsi: target: Clear cmd_cnt when initial counter enrollment fails

Benjamin Block <[email protected]>
scsi: zfcp: Fix memory leak during adapter release by destroying gid_pn_req

Guangshuo Li <[email protected]>
scsi: ufs: core: Cancel RTC work in active-active suspend

TanZheng <[email protected]>
scsi: target: iblock: Fix wrong PR ops NULL check for PREEMPT/RELEASE

Christian Marangi <[email protected]>
net: phylink: put link_gpio if phylink_create fails

Pauli Virtanen <[email protected]>
Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync

Pauli Virtanen <[email protected]>
Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync

Pauli Virtanen <[email protected]>
Bluetooth: hci_conn: hold conn reference in abort_conn_sync()

Pauli Virtanen <[email protected]>
Bluetooth: hci_sync: make hci_cmd_sync_run_once return -EEXIST if exists

Zijun Hu <[email protected]>
Bluetooth: btintel: Validate length before parsing diagnostics TLV

Pauli Virtanen <[email protected]>
Bluetooth: ISO: avoid deadlocks in iso_sock_timeout

Pauli Virtanen <[email protected]>
Bluetooth: ISO: fix leaking sk after socket release

Pauli Virtanen <[email protected]>
Bluetooth: ISO: validate sockaddr_iso first in iso_sock_rebind_bis()

Pauli Virtanen <[email protected]>
Bluetooth: ISO: fix timeout vs sync_timeout typo in check_bcast_qos

Jiale Yao <[email protected]>
Bluetooth: L2CAP: fix UAF in l2cap_le_connect_rsp

Pauli Virtanen <[email protected]>
Bluetooth: ISO: clear iso_data always when detaching conn from hcon

Yuho Choi <[email protected]>
idpf: Fix mailbox IRQ name leak on request failure

Joshua Hay <[email protected]>
idpf: adjust TxQ ring count minimum

Guenter Roeck <[email protected]>
hwmon: (pmbus) Fix return value from pmbus_update_byte_data()

Chenguang Zhao <[email protected]>
net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller

Frank Wunderlich <[email protected]>
net: ethernet: mtk_eth_soc: add consts for irq index

Frank Wunderlich <[email protected]>
net: ethernet: mtk_eth_soc: support named IRQs

Zhao Li <[email protected]>
wifi: mac80211: validate individual TWT params before driver setup

Eric Dumazet <[email protected]>
net: udp_tunnel: fix memory leak in udp_tunnel_nic_unregister()

Thorsten Blum <[email protected]>
powerpc/boot: Fix treeboot-akebono CPU node lookup check

Thorsten Blum <[email protected]>
powerpc/boot: Fix treeboot-currituck CPU node lookup check

Thorsten Blum <[email protected]>
powerpc/boot: Fix simpleboot CPU node lookup check

Yun Lu <[email protected]>
rtase: fix double free of multi-frag skb on DMA map failure

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix PWM auto temp state array and bounds check

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix divide-by-zero TOCTOU crash in fan speed read

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Use cached PWM frequency value

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix swapped PWM3 and PWM4 auto mode masks

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix temperature alarm logic in hwmon_temp_read()

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix busy-loop and I2C flooding in update thread

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix cache updated before hardware write on I2C error

Luiz Angelo Daros de Luca <[email protected]>
hwmon: (adt7470) Fix fans stuck in manual mode on I2C errors

Chenguang Zhao <[email protected]>
forcedeth: fix UAF of txrx_stats in nv_remove

David Corvaglia <[email protected]>
net: bridge: mrp: fix Option TLV length in MRP_Test frames

Guenter Roeck <[email protected]>
hwmon: (nct6775-core) Prevent access to unsupported weight registers

Eric Dumazet <[email protected]>
net: do not send ICMP/NDISC Redirects when peer allocation fails

Guenter Roeck <[email protected]>
hwmon: (nzxt-smart2) DMA-align output buffer

Guenter Roeck <[email protected]>
hwmon: (lm90) Only report alarms if driver is ready

Guenter Roeck <[email protected]>
hwmon: (sht3x) Fix unaligned accesses

Guenter Roeck <[email protected]>
hwmon: (ltc4282) Fix reading the minimum alarm voltage

Guenter Roeck <[email protected]>
hwmon: (ina2xx) Fix various overflow issues

Jonas Rebmann <[email protected]>
hwmon: (ina2xx) Shift INA234 shunt and current registers

Ian Ray <[email protected]>
hwmon: (ina2xx) Add support for INA234

Ian Ray <[email protected]>
hwmon: (ina2xx) Make it easier to add more devices

Wenliang Yan <[email protected]>

    hwmon: (ina226) Add support for SY24655

Guenter Roeck <[email protected]>
hwmon: (ina2xx) Add support for INA260

Guenter Roeck <[email protected]>
hwmon: (ina2xx) Add support for has_alerts configuration flag

Guenter Roeck <[email protected]>
hwmon: (nct6775-core) Fix number of temperature registers for NCT6116

Srikanth Boyapally <[email protected]>
spi: spi-cadence: Move TX FIFO full busy-wait into FIFO

Jun Guo <[email protected]>
spi: spi-cadence: supports transmission with bits_per_word of 16 and 32

Dawei Feng <[email protected]>
smb: client: fix buffer leaks in SMB1 read and write

Xingui Yang <[email protected]>
scsi: libsas: Fix HA resume deadlock and hisi_sas disk-wake race

HyeongJun An <[email protected]>
scsi: libiscsi_tcp: Bound SCSI Response data segment to the connection buffer

HyeongJun An <[email protected]>
scsi: libiscsi: Fix stale-data leak into the SCSI sense buffer

Mario Limonciello <[email protected]>
pinctrl-amd: Don't clear S4 wake bits at probe

Xiang Mei <[email protected]>
rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()

Ilia Gavrilov <[email protected]>
rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled

Xiang Mei (Microsoft) <[email protected]>
netfilter: nft_payload: fix mask build for partial field offload

Julian Anastasov <[email protected]>
ipvs: do not mangle ICMP replies for non-first fragments

Julian Anastasov <[email protected]>
ipvs: fix places with wrong packet offsets

Julian Anastasov <[email protected]>
ipvs: fix the checksum validations

Pablo Neira Ayuso <[email protected]>
netfilter: xt_hashlimit: validate hashtable supports XT_HASHLIMIT_RATE_MATCH

Pablo Neira Ayuso <[email protected]>
netfilter: nf_tables: make nft_object rhltable per table

Michael Bommarito <[email protected]>
assoc_array: trim the final shortcut word using the current chunk end

Michael Bommarito <[email protected]>
keys: make keyring key-chunk byte order agree with keyring_diff_objects()

Michael Bommarito <[email protected]>
keys: fix out-of-bounds read in keyring_get_key_chunk()

Fabrice Derepas <[email protected]>
KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type

Sebastian Andrzej Siewior <[email protected]>
Drivers: hv: vmbus: Replace lockdep_hardirq_threaded() with lockdep annotation

Ruoyu Wang <[email protected]>
drm/mediatek: Check CRTC state before freeing

Xiang Mei <[email protected]>
netfilter: nf_conntrack_sip: widen NAT rewrite delta to s32 in sip_help_tcp()

Radhey Shyam Pandey <[email protected]>
phy: zynqmp: fix runtime PM leak on probe allocation failure

Radhey Shyam Pandey <[email protected]>
phy: zynqmp: fix clock error handling in xpsgtr_phy_init()

Mike Looijmans <[email protected]>
phy-zynqmp: Postpone getting clock rate until actually needed

Johannes Thumshirn <[email protected]>
btrfs: zoned: fix deadlock between metadata writeback and transaction commit

Qu Wenruo <[email protected]>
btrfs: fix leaking BTRFS_FS_STATE_REMOUNTING flag

Sang-Heon Jeon <[email protected]>
of: reserved_mem: prevent OOB when too many dynamic regions are defined

Oreoluwa Babatunde <[email protected]>
of: reserved_mem: Add code to dynamically allocate reserved_mem array

Uday Khare <[email protected]>
ASoC: max98090: fix missing IS_ERR() before PTR_ERR() on mclk lookup

Uday Khare <[email protected]>
ASoC: max98095: fix missing IS_ERR() before PTR_ERR() on mclk lookup

Radhey Shyam Pandey <[email protected]>
ata: ahci_ceva: fix error paths in ceva_ahci_platform_enable_resources()

Damien Le Moal <[email protected]>
ahci: Introduce ahci_ignore_port() helper

Josua Mayer <[email protected]>
ata: libahci_platform: support non-consecutive port numbers

Rosen Penev <[email protected]>
ata: sata_mv: accept 1 or 2 resources in platform probe

Abdun Nihaal <[email protected]>
gpio: sloppy-logic-analyzer: Fix memory leak in gpio_la_poll_probe()

Yuho Choi <[email protected]>
dmaengine: idxd: fix fdev setup failure cleanup in idxd_cdev_open()

Hongling Zeng <[email protected]>
dmaengine: sun6i-dma: Fix reclaim descriptors while terminating DMA

Konrad Dybcio <[email protected]>

    pinctrl: qcom: sc8280xp: Add missing wakeup entries for GPIO143/151

Sneh Mankad <[email protected]>
pinctrl: qcom: Unconditionally mark gpio as wakeup enable

Michael Bommarito <[email protected]>
thunderbolt: Prevent XDomain delayed work use-after-free on disconnect

Jakub Kicinski <[email protected]>
netconsole: avoid OOB reads, msg is not nul-terminated

Tristan Madani <[email protected]>
bpf: Reset register bounds before narrowing retval range in check_mem_access()

Benjamin Tissoires <[email protected]>
HID: logitech-dj: fix wrong detection of bad DJ_SHORT output report

Lee Jones <[email protected]>
HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write

Lee Jones <[email protected]>
HID: logitech-dj: Standardise hid_report_enum variable nomenclature

Yehyeong Lee <[email protected]>
net: mpls: initialize rtm_tos in mpls_getroute()

Wayen.Yan <[email protected]>
net: airoha: Fix register index for Tx-fwd counter configuration

Lorenzo Bianconi <[email protected]>
netfilter: br_netfilter: Reallocate headroom if necessary in neigh_hh_bridge()

Tiwei Bie <[email protected]>
um: Preserve errno within signal handler

Shuvam Pandey <[email protected]>
kunit: tool: skip stty when stdin is not a tty

David Gow <[email protected]>
kunit: tool: Terminate kernel under test on SIGINT

Benjamin Berg <[email protected]>
um: Set parent death signal for userspace process

Tiwei Bie <[email protected]>
um: Set parent-death signal for write_sigio thread/process

Tiwei Bie <[email protected]>
um: Set parent-death signal for ubd io thread/process

Tiwei Bie <[email protected]>
um: Use os_set_pdeathsig helper in winch thread/process

Benjamin Berg <[email protected]>
um: Set parent death signal for winch thread/process

Tiwei Bie <[email protected]>
um: Add os_set_pdeathsig helper function

Pablo Neira Ayuso <[email protected]>
netfilter: nf_conntrack_expect: restore helper propagation via expectation

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

Diffstat:

 Documentation/dev-tools/kmemleak.rst               |   1 +
 Documentation/hwmon/ina2xx.rst                     |  67 +-
 Makefile                                           |   4 +-
 arch/powerpc/boot/simpleboot.c                     |   2 +-
 arch/powerpc/boot/treeboot-akebono.c               |   2 +-
 arch/powerpc/boot/treeboot-currituck.c             |   2 +-
 arch/powerpc/platforms/ps3/mm.c                    |   1 +
 arch/riscv/mm/init.c                               |   4 +-
 arch/s390/kvm/pci.c                                |  28 +-
 arch/s390/pci/pci_mmio.c                           |   1 +
 arch/um/drivers/chan_user.c                        |   2 +
 arch/um/drivers/ubd_kern.c                         |   1 +
 arch/um/drivers/vector_kern.c                      |   3 +
 arch/um/include/shared/os.h                        |   2 +
 arch/um/os-Linux/process.c                         |   6 +
 arch/um/os-Linux/sigio.c                           |   1 +
 arch/um/os-Linux/signal.c                          |   3 +
 arch/um/os-Linux/skas/process.c                    |   3 +
 arch/x86/kvm/svm/avic.c                            |   8 -
 drivers/accel/qaic/qaic_control.c                  |   2 +-
 drivers/ata/ahci.h                                 |  17 +-
 drivers/ata/ahci_brcm.c                            |   3 +
 drivers/ata/ahci_ceva.c                            |  24 +-
 drivers/ata/libahci.c                              |   1 +
 drivers/ata/libahci_platform.c                     |  38 +-
 drivers/ata/libata-eh.c                            |   8 +
 drivers/ata/libata-sata.c                          |   2 +-
 drivers/ata/sata_mv.c                              |   2 +-
 drivers/block/ublk_drv.c                           |   9 +
 drivers/bluetooth/btintel.c                        |   3 +
 drivers/bluetooth/btmtk.c                          |  50 +-
 drivers/bluetooth/btusb.c                          |  30 +-
 drivers/cpufreq/powernow-k8.c                      |   1 +
 drivers/dma/idxd/cdev.c                            |   4 +-
 drivers/dma/sun6i-dma.c                            |  11 +-
 drivers/gpio/gpio-pca953x.c                        |  15 +-
 drivers/gpio/gpio-pch.c                            |  28 +-
 drivers/gpio/gpio-sloppy-logic-analyzer.c          |  10 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c             |  12 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c            |  73 ++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c            |  15 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c            |  11 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c            |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c        |  30 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_job.c            |  11 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_job.h            |  22 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c           |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c         |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c            |  40 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h            |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c            |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c            |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c            |   8 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c             |   6 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h             |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c          |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c        |  12 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c              |   6 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c              |   6 +-
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c           |  10 +-
 drivers/gpu/drm/amd/amdkfd/kfd_events.c            |  23 +-
 drivers/gpu/drm/amd/amdkfd/kfd_migrate.c           |   3 +-
 .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c |   2 +-
 drivers/gpu/drm/amd/amdkfd/kfd_queue.c             |   2 +-
 .../gpu/drm/amd/display/dc/dce/dce_clock_source.c  |  20 +-
 .../drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c    |  16 +-
 drivers/gpu/drm/armada/armada_fbdev.c              |  12 +-
 drivers/gpu/drm/display/drm_dp_helper.c            |  12 +
 drivers/gpu/drm/drm_exec.c                         |   6 +-
 drivers/gpu/drm/drm_fb_helper.c                    |  41 +-
 drivers/gpu/drm/drm_fbdev_dma.c                    |  12 +-
 drivers/gpu/drm/drm_fbdev_shmem.c                  |  12 +-
 drivers/gpu/drm/drm_fbdev_ttm.c                    |  12 +-
 drivers/gpu/drm/drm_gpuvm.c                        |   3 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c       |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c          |   9 +-
 drivers/gpu/drm/gma500/fbdev.c                     |  13 +-
 drivers/gpu/drm/i915/display/intel_fbdev.c         |   9 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c          | 699 +++++++++++----------
 drivers/gpu/drm/i915/display/intel_hdcp_gsc.c      |   9 +-
 drivers/gpu/drm/i915/display/intel_hdcp_gsc.h      |   5 +-
 .../gpu/drm/i915/display/intel_hdcp_gsc_message.h  |   3 +-
 drivers/gpu/drm/i915/display/intel_vrr.c           |  10 +-
 drivers/gpu/drm/imagination/pvr_job.c              |   2 +-
 drivers/gpu/drm/imagination/pvr_queue.c            |   5 +-
 drivers/gpu/drm/imagination/pvr_queue.h            |   2 +-
 drivers/gpu/drm/lima/lima_gem.c                    |   2 +-
 drivers/gpu/drm/lima/lima_sched.c                  |   6 +-
 drivers/gpu/drm/lima/lima_sched.h                  |   3 +-
 drivers/gpu/drm/mediatek/mtk_crtc.c                |   6 +-
 drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c    |   7 +-
 drivers/gpu/drm/msm/msm_fbdev.c                    |   9 +-
 drivers/gpu/drm/msm/msm_gem_submit.c               |   8 +-
 drivers/gpu/drm/nouveau/nouveau_sched.c            |   3 +-
 drivers/gpu/drm/omapdrm/omap_fbdev.c               |   9 +-
 drivers/gpu/drm/panfrost/panfrost_drv.c            |   2 +-
 drivers/gpu/drm/panthor/panthor_drv.c              |   3 +-
 drivers/gpu/drm/panthor/panthor_fw.c               |  47 +-
 drivers/gpu/drm/panthor/panthor_mmu.c              |   2 +-
 drivers/gpu/drm/panthor/panthor_sched.c            |   5 +-
 drivers/gpu/drm/panthor/panthor_sched.h            |   3 +-
 drivers/gpu/drm/radeon/radeon_fbdev.c              |  13 +-
 drivers/gpu/drm/scheduler/sched_fence.c            |   4 +-
 drivers/gpu/drm/scheduler/sched_main.c             |   7 +-
 drivers/gpu/drm/tegra/fbdev.c                      |  18 +-
 drivers/gpu/drm/v3d/v3d_submit.c                   |   2 +-
 drivers/gpu/drm/vc4/vc4_irq.c                      |   2 +-
 drivers/gpu/drm/vc4/vc4_validate.c                 |  29 +-
 drivers/gpu/drm/vmwgfx/ttm_object.c                |   7 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_blit.c               |  39 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c            |  20 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_resource.c           |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_shader.c             |  13 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c               |  17 +-
 drivers/gpu/drm/xe/Makefile                        |   1 +
 drivers/gpu/drm/xe/display/xe_hdcp_gsc.c           |   7 +-
 drivers/gpu/drm/xe/xe_bo.c                         |  33 +-
 drivers/gpu/drm/xe/xe_bo.h                         |  10 +-
 drivers/gpu/drm/xe/xe_bo_types.h                   |   2 +
 drivers/gpu/drm/xe/xe_dma_buf.c                    |   6 +-
 drivers/gpu/drm/xe/xe_exec.c                       |  22 +-
 drivers/gpu/drm/xe/xe_gt.c                         |   4 +-
 drivers/gpu/drm/xe/xe_gt_debugfs.c                 |   4 +-
 drivers/gpu/drm/xe/xe_gt_printk.h                  |  31 +
 drivers/gpu/drm/xe/xe_hw_engine.c                  |   3 +-
 drivers/gpu/drm/xe/xe_hw_engine_types.h            |   8 +
 drivers/gpu/drm/xe/xe_oa.c                         |   7 +
 drivers/gpu/drm/xe/xe_oa_types.h                   |   3 +
 drivers/gpu/drm/xe/xe_pagefault.c                  |  65 ++
 drivers/gpu/drm/xe/xe_pagefault.h                  |  19 +
 drivers/gpu/drm/xe/xe_pagefault_types.h            | 136 ++++
 drivers/gpu/drm/xe/xe_pt.c                         |   3 +
 drivers/gpu/drm/xe/xe_reg_sr.c                     |  53 --
 drivers/gpu/drm/xe/xe_reg_whitelist.c              | 147 ++++-
 drivers/gpu/drm/xe/xe_reg_whitelist.h              |   4 +
 drivers/gpu/drm/xe/xe_sched_job.c                  |   3 +-
 drivers/gpu/drm/xe/xe_vm.c                         |   3 +-
 drivers/hid/hid-logitech-dj.c                      |  28 +-
 drivers/hv/vmbus_drv.c                             |  13 +-
 drivers/hwmon/Kconfig                              |   5 +-
 drivers/hwmon/adt7470.c                            | 131 ++--
 drivers/hwmon/ina2xx.c                             | 251 ++++++--
 drivers/hwmon/lm90.c                               |   4 +-
 drivers/hwmon/ltc4282.c                            |   4 +-
 drivers/hwmon/nct6775-core.c                       |  20 +-
 drivers/hwmon/npcm750-pwm-fan.c                    |  11 +
 drivers/hwmon/nzxt-smart2.c                        |   2 +-
 drivers/hwmon/pmbus/pmbus_core.c                   |   7 +-
 drivers/hwmon/sht3x.c                              |   9 +-
 drivers/i2c/busses/i2c-amd-mp2-plat.c              |   4 +-
 drivers/i2c/busses/i2c-bcm-iproc.c                 |  11 +
 drivers/i2c/busses/i2c-imx.c                       |   9 +-
 drivers/i2c/busses/i2c-jz4780.c                    |   5 +-
 drivers/iommu/iova.c                               |   6 +
 drivers/media/i2c/imx219.c                         |  31 +-
 .../media/platform/chips-media/wave5/wave5-hw.c    |   3 +
 .../platform/chips-media/wave5/wave5-vpu-enc.c     |   5 +-
 .../platform/chips-media/wave5/wave5-vpuapi.h      |   1 +
 drivers/net/can/c_can/c_can_main.c                 |   8 +-
 drivers/net/can/ctucanfd/ctucanfd_base.c           |  14 +-
 drivers/net/can/ctucanfd/ctucanfd_pci.c            |   3 +-
 drivers/net/can/dev/skb.c                          |   2 -
 drivers/net/can/softing/softing_fw.c               |  46 +-
 drivers/net/can/usb/ems_usb.c                      |  43 ++
 drivers/net/can/usb/etas_es58x/es58x_core.c        |   1 -
 drivers/net/can/usb/gs_usb.c                       |   4 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  |   1 +
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   |  13 +-
 drivers/net/can/usb/peak_usb/pcan_usb_core.c       |   1 -
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c         |  40 +-
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c        |  20 +-
 drivers/net/dsa/mt7530-mdio.c                      |  11 +-
 drivers/net/dsa/mt7530.c                           |  58 +-
 drivers/net/ethernet/airoha/airoha_eth.c           |   2 +-
 drivers/net/ethernet/intel/e1000/e1000_main.c      |   2 +-
 drivers/net/ethernet/intel/ice/ice_ethtool.c       |  10 +-
 drivers/net/ethernet/intel/ice/ice_main.c          |  10 +
 drivers/net/ethernet/intel/idpf/idpf_lib.c         |   2 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.c        |   5 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.h        |   2 +-
 drivers/net/ethernet/intel/igbvf/netdev.c          |   2 -
 .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c   |   2 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  58 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |   7 +-
 drivers/net/ethernet/nvidia/forcedeth.c            |   4 +-
 drivers/net/ethernet/qlogic/qede/qede_main.c       |  44 +-
 drivers/net/ethernet/realtek/rtase/rtase_main.c    |   3 +
 drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c    |  14 +-
 drivers/net/ethernet/wangxun/libwx/wx_lib.c        |   2 +
 drivers/net/netconsole.c                           |   3 +-
 drivers/net/phy/phylink.c                          |  29 +-
 drivers/net/veth.c                                 |   4 +-
 drivers/net/vxlan/vxlan_core.c                     |  15 +-
 drivers/net/wireless/ath/ath6kl/txrx.c             |   2 +-
 .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c  |  16 +-
 .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |   6 +
 .../wireless/broadcom/brcm80211/brcmfmac/chip.c    |   4 +-
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |  46 +-
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  14 +-
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.h    |   1 +
 .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |   3 +
 .../broadcom/brcm80211/include/brcm_hw_ids.h       |   2 +-
 .../net/wireless/marvell/mwifiex/11n_rxreorder.c   |   2 +-
 drivers/of/of_reserved_mem.c                       |  87 ++-
 drivers/phy/xilinx/phy-zynqmp.c                    | 130 ++--
 drivers/pinctrl/Kconfig                            |   2 +
 drivers/pinctrl/devicetree.c                       |   4 +
 drivers/pinctrl/pinctrl-amd.c                      |   3 +-
 drivers/pinctrl/qcom/pinctrl-msm.c                 |   8 +-
 drivers/pinctrl/qcom/pinctrl-sc8280xp.c            |  21 +-
 drivers/power/supply/bq25890_charger.c             |   2 +-
 drivers/power/supply/max17040_battery.c            |   6 +-
 drivers/s390/block/dasd_eckd.c                     |  11 +-
 drivers/s390/block/dasd_ioctl.c                    |   2 +-
 drivers/s390/crypto/zcrypt_api.c                   |   2 +-
 drivers/s390/crypto/zcrypt_ccamisc.c               |   6 +
 drivers/s390/net/qeth_core_main.c                  |   3 +
 drivers/s390/scsi/zfcp_aux.c                       |   1 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c             |  10 +-
 drivers/scsi/libiscsi.c                            |   2 +-
 drivers/scsi/libiscsi_tcp.c                        |   8 +-
 drivers/scsi/libsas/sas_init.c                     |  37 +-
 drivers/scsi/scsi_debug.c                          |   8 +-
 drivers/spi/spi-cadence.c                          | 129 +++-
 drivers/spi/spi-qcom-qspi.c                        |   3 +-
 drivers/target/target_core_iblock.c                |   6 +-
 drivers/target/target_core_transport.c             |  12 +-
 drivers/thunderbolt/xdomain.c                      |  40 +-
 drivers/ufs/core/ufshcd.c                          |   6 +-
 drivers/usb/gadget/function/f_tcm.c                | 192 +++++-
 drivers/usb/gadget/function/tcm.h                  |  13 +
 drivers/usb/typec/ucsi/ucsi.c                      |  88 +--
 drivers/usb/typec/ucsi/ucsi.h                      |   1 +
 fs/binfmt_misc.c                                   |   8 +
 fs/btrfs/super.c                                   |   8 +-
 fs/btrfs/zoned.c                                   |   6 +-
 fs/erofs/Kconfig                                   |  14 +
 fs/erofs/decompressor_lzma.c                       |   3 +-
 fs/proc/task_mmu.c                                 |  33 +-
 fs/smb/client/cifssmb.c                            |  12 +-
 fs/smb/server/vfs_cache.c                          |   6 +-
 include/drm/drm_exec.h                             |  20 +-
 include/drm/drm_fb_helper.h                        |  12 -
 include/drm/gpu_scheduler.h                        |  12 +-
 include/linux/alloc_tag.h                          |   3 +
 include/linux/can/core.h                           |   1 +
 include/linux/can/skb.h                            |   2 -
 include/linux/dma/qcom_bam_dma.h                   |  21 +-
 include/linux/kmemleak.h                           |   4 +
 include/linux/libata.h                             |   2 +-
 include/linux/mmc/sdio_ids.h                       |   2 +-
 include/linux/netfilter/nf_conntrack_sip.h         |   2 +-
 include/linux/slab.h                               |   8 +-
 include/linux/thunderbolt.h                        |   3 +
 include/linux/trace_events.h                       |   4 -
 include/net/ip_vs.h                                |  45 +-
 include/net/neighbour.h                            |   8 +-
 include/net/netfilter/nf_conntrack_expect.h        |   5 +-
 include/net/netfilter/nf_tables.h                  |   4 +-
 include/scsi/libsas.h                              |   1 -
 include/trace/events/rxrpc.h                       |  14 +-
 include/uapi/linux/rkisp1-config.h                 |   6 +-
 kernel/audit.c                                     |  11 +-
 kernel/auditfilter.c                               |   6 +-
 kernel/bpf/verifier.c                              |   1 +
 kernel/sched/cpufreq_schedutil.c                   |  11 +
 kernel/sched/deadline.c                            |   3 +-
 kernel/trace/trace.c                               |  44 +-
 kernel/trace/trace.h                               |   4 -
 kernel/trace/trace_branch.c                        |   4 +-
 kernel/trace/trace_events.c                        |   6 +-
 kernel/trace/trace_events_filter.c                 |   3 +
 kernel/trace/trace_functions_graph.c               |   8 +-
 kernel/trace/trace_hwlat.c                         |   4 +-
 kernel/trace/trace_mmiotrace.c                     |  21 +-
 kernel/trace/trace_osnoise.c                       |  12 +-
 kernel/trace/trace_probe.c                         |   6 +-
 kernel/trace/trace_sched_wakeup.c                  |   8 +-
 lib/alloc_tag.c                                    |   9 +
 lib/assoc_array.c                                  |   3 +-
 lib/rhashtable.c                                   |   1 +
 lib/test_fortify/Makefile                          |   1 +
 lib/win_minmax.c                                   |   1 +
 mm/huge_memory.c                                   |  16 +-
 mm/hugetlb.c                                       |  12 +-
 mm/kmemleak.c                                      |  44 +-
 mm/memcontrol-v1.h                                 |   6 +-
 mm/migrate_device.c                                |   5 +-
 mm/mm_init.c                                       |  15 +-
 mm/page_reporting.c                                |   6 +-
 mm/percpu-km.c                                     |   2 +-
 mm/slab.h                                          |  28 +-
 mm/slab_common.c                                   |  13 +
 mm/slub.c                                          |  34 +-
 net/bluetooth/hci_conn.c                           |  14 +-
 net/bluetooth/hci_sync.c                           | 154 +++--
 net/bluetooth/hidp/core.c                          |  30 +-
 net/bluetooth/iso.c                                | 113 ++--
 net/bluetooth/l2cap_core.c                         |   5 +
 net/bluetooth/mgmt.c                               |  84 ++-
 net/bridge/br_mrp.c                                |   2 +-
 net/bridge/br_multicast.c                          |   1 +
 net/bridge/br_netfilter_hooks.c                    |   6 +-
 net/can/af_can.c                                   |  14 +-
 net/can/bcm.c                                      |   2 -
 net/can/isotp.c                                    | 337 +++++++---
 net/can/j1939/bus.c                                |   2 +
 net/can/j1939/j1939-priv.h                         |   3 +
 net/can/j1939/main.c                               |   8 +-
 net/can/j1939/socket.c                             |   1 -
 net/can/j1939/transport.c                          |   6 +-
 net/can/raw.c                                      |   7 +-
 net/core/lwt_bpf.c                                 |   4 +-
 net/core/skbuff.c                                  |  18 +-
 net/ipv4/route.c                                   |   2 -
 net/ipv4/udp_tunnel_nic.c                          |  32 +-
 net/ipv6/fib6_rules.c                              |   1 +
 net/ipv6/ip6_output.c                              |   2 +-
 net/ipv6/ndisc.c                                   |   2 +
 net/mac80211/s1g.c                                 |   4 +
 net/mpls/af_mpls.c                                 |   1 +
 net/mptcp/pm.c                                     |   9 +-
 net/mptcp/pm_netlink.c                             |  29 +-
 net/mptcp/pm_userspace.c                           |  87 ++-
 net/mptcp/protocol.h                               |   6 +-
 net/netfilter/ipset/ip_set_hash_gen.h              |   2 +-
 net/netfilter/ipvs/ip_vs_app.c                     |   4 +-
 net/netfilter/ipvs/ip_vs_conn.c                    |   3 +
 net/netfilter/ipvs/ip_vs_core.c                    | 180 +++---
 net/netfilter/ipvs/ip_vs_proto_sctp.c              |  19 +-
 net/netfilter/ipvs/ip_vs_proto_tcp.c               |  48 +-
 net/netfilter/ipvs/ip_vs_proto_udp.c               |  54 +-
 net/netfilter/ipvs/ip_vs_xmit.c                    |  42 +-
 net/netfilter/nf_conntrack_broadcast.c             |   1 +
 net/netfilter/nf_conntrack_core.c                  |   7 +-
 net/netfilter/nf_conntrack_expect.c                |   1 +
 net/netfilter/nf_conntrack_h323_main.c             |  12 +-
 net/netfilter/nf_conntrack_helper.c                |   5 +
 net/netfilter/nf_conntrack_netlink.c               |  18 +-
 net/netfilter/nf_conntrack_sip.c                   |   4 +-
 net/netfilter/nf_nat_sip.c                         |   2 +-
 net/netfilter/nf_tables_api.c                      |  34 +-
 net/netfilter/nft_payload.c                        |  12 +-
 net/netfilter/xt_hashlimit.c                       |  16 +-
 net/openvswitch/actions.c                          |  12 +-
 net/openvswitch/meter.c                            |  33 +-
 net/rds/ib.c                                       |   4 +
 net/rds/ib_cm.c                                    |   4 +
 net/rds/tcp.c                                      |  14 +-
 net/rxrpc/ar-internal.h                            |  38 +-
 net/rxrpc/call_accept.c                            |   1 +
 net/rxrpc/call_event.c                             |  19 +-
 net/rxrpc/call_object.c                            |   2 +
 net/rxrpc/input.c                                  |  12 +-
 net/rxrpc/output.c                                 |  14 +-
 net/rxrpc/peer_object.c                            |  20 +-
 net/rxrpc/proc.c                                   |   6 +-
 net/rxrpc/rtt.c                                    | 103 +--
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sctp/associola.c                               |   3 +
 net/sctp/sm_make_chunk.c                           |  17 +-
 net/smc/smc_core.c                                 |   2 +-
 net/tipc/socket.c                                  |   2 +-
 security/keys/keyring.c                            |  14 +-
 security/keys/trusted-keys/trusted_dcp.c           |  15 +-
 sound/core/pcm_native.c                            |   7 +
 sound/core/seq/seq_timer.c                         |   9 +-
 sound/core/timer.c                                 |   2 +
 sound/core/ump.c                                   |   1 +
 sound/pci/hda/patch_hdmi.c                         |  48 +-
 sound/pci/lx6464es/lx6464es.c                      |   5 +-
 sound/pci/lx6464es/lx_core.c                       |   5 +-
 sound/soc/codecs/max98090.c                        |   5 +-
 sound/soc/codecs/max98095.c                        |   5 +-
 sound/soc/codecs/tas2562.c                         |  30 +-
 sound/usb/6fire/chip.c                             |   4 +
 sound/usb/endpoint.c                               |  14 +-
 sound/usb/midi.c                                   |   2 +
 sound/usb/midi2.c                                  |   4 +-
 sound/usb/mixer_quirks.c                           |   2 +-
 tools/testing/kunit/kunit_kernel.py                |  39 +-
 tools/testing/kunit/kunit_tool_test.py             |  42 ++
 tools/testing/selftests/clone3/clone3_set_tid.c    |   2 +-
 tools/testing/selftests/mm/mlock-random-test.c     |   2 +-
 387 files changed, 4750 insertions(+), 2372 deletions(-)

From [email protected] Fri Aug 7 16:34:18 2026
Message-ID: <[email protected]>
User-Agent: quilt/0.69
Date: Fri, 07 Aug 2026 16:34:19 +0200
From: Greg Kroah-Hartman <[email protected]>
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected],
Ilya Maximets <[email protected]>,
Pablo Neira Ayuso <[email protected]>,
Sasha Levin <[email protected]>
X-stable: review
X-Patchwork-Hint: ignore
Subject: [PATCH 6.12 001/337] netfilter: nf_conntrack_expect: restore helper propagation via
expectation
MIME-Version: 1.0

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

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

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ]

A recent series to fix expectations broke helper propagation via expectation, this mechanism is used by the sip and h323 helper. This also propagates the conntrack helper to expected connections. I changed semantics of exp->helper which now tells us the actual helper that created the expectation.

Add an explicit assign_helper field to expectations for this purpose and update helpers to use it.

Restore this feature for userspace conntrack helper via ctnetlink nfqueue integration so it is again possible to attach a helper to an expectation, where it makes sense. This is not restored via ctnetlink expectation creation as there is no client for such feature. Use the expectation layer 4 protocol number for the helper lookup for consistency.

Make sure the expectation using this helper propagation mechanism also go away when the helper is unregistered.

Fixes 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field")
Fixes 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
---
 include/net/netfilter/nf_conntrack_expect.h |  5 ++++-
 net/netfilter/nf_conntrack_broadcast.c      |  1 +
 net/netfilter/nf_conntrack_core.c           |  7 +++++--
 net/netfilter/nf_conntrack_expect.c         |  1 +
 net/netfilter/nf_conntrack_h323_main.c      | 12 ++++++------
 net/netfilter/nf_conntrack_helper.c         |  5 +++++
 net/netfilter/nf_conntrack_netlink.c        | 18 ++++++++++++++++--
 net/netfilter/nf_conntrack_sip.c            |  2 +-
 8 files changed, 39 insertions(+), 12 deletions(-)
include/net/netfilter/nf_conntrack_expect.h +4 -1
index e9a8350e7ccf..80f50fd0f7ad 100644
@@ -45,9 +45,12 @@ struct nf_conntrack_expect {
 	void (*expectfn)(struct nf_conn *new,
 			 struct nf_conntrack_expect *this);
 
-	/* Helper to assign to new connection */
+	/* Helper that created this expectation */
 	struct nf_conntrack_helper __rcu *helper;
 
+	/* Helper to assign to new connection */
+	struct nf_conntrack_helper __rcu *assign_helper;
+
 	/* The conntrack of the master connection */
 	struct nf_conn *master;
 
net/netfilter/nf_conntrack_broadcast.c +1 -0
index f9528d4db0a8..93c501d9d399 100644
@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
 	exp->flags                = NF_CT_EXPECT_PERMANENT;
 	exp->class		  = NF_CT_EXPECT_CLASS_DEFAULT;
 	rcu_assign_pointer(exp->helper, helper);
+	rcu_assign_pointer(exp->assign_helper, NULL);
 	write_pnet(&exp->net, net);
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 	exp->zone = ct->zone;
net/netfilter/nf_conntrack_core.c +5 -2
index 423080cf86a4..0c457e159727 100644
@@ -1773,14 +1773,17 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
 		spin_lock_bh(&nf_conntrack_expect_lock);
 		exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl));
 		if (exp) {
+			struct nf_conntrack_helper *assign_helper;
+
 			/* Welcome, Mr. Bond.  We've been expecting you... */
 			__set_bit(IPS_EXPECTED_BIT, &ct->status);
 			/* exp->master safe, refcnt bumped in nf_ct_find_expectation */
 			ct->master = exp->master;
-			if (exp->helper) {
+			assign_helper = rcu_dereference(exp->assign_helper);
+			if (assign_helper) {
 				help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
 				if (help)
-					rcu_assign_pointer(help->helper, exp->helper);
+					rcu_assign_pointer(help->helper, assign_helper);
 			}
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
net/netfilter/nf_conntrack_expect.c +1 -0
index bb8b87f9ee50..a8929885485b 100644
@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
 		helper = rcu_dereference(help->helper);
 
 	rcu_assign_pointer(exp->helper, helper);
+	rcu_assign_pointer(exp->assign_helper, NULL);
 	write_pnet(&exp->net, net);
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 	exp->zone = ct->zone;
net/netfilter/nf_conntrack_h323_main.c +6 -6
index 791aafe9f396..c42547284f35 100644
@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
 			  &ct->tuplehash[!dir].tuple.src.u3,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_TCP, NULL, &port);
-	rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+	rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245);
 
 	nathook = rcu_dereference(nfct_h323_nat_hook);
 	if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
 	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
-	rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+	rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
 
 	nathook = rcu_dereference(nfct_h323_nat_hook);
 	if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 				&ct->tuplehash[!dir].tuple.src.u3 : NULL,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_TCP, NULL, &port);
-	rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+	rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
 	exp->flags = NF_CT_EXPECT_PERMANENT;	/* Accept multiple calls */
 
 	nathook = rcu_dereference(nfct_h323_nat_hook);
@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
 	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_UDP, NULL, &port);
-	rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+	rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras);
 
 	if (nf_ct_expect_related(exp, 0) == 0) {
 		pr_debug("nf_ct_ras: expect RAS ");
@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
 	exp->flags = NF_CT_EXPECT_PERMANENT;
-	rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+	rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
 
 	if (nf_ct_expect_related(exp, 0) == 0) {
 		pr_debug("nf_ct_ras: expect Q.931 ");
@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
 	exp->flags = NF_CT_EXPECT_PERMANENT;
-	rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+	rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
 
 	if (nf_ct_expect_related(exp, 0) == 0) {
 		pr_debug("nf_ct_ras: expect Q.931 ");
net/netfilter/nf_conntrack_helper.c +5 -0
index 9150bcfd7ca8..ea0cdb7ec915 100644
@@ -419,6 +419,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
 
 	this = rcu_dereference_protected(exp->helper,
 					 lockdep_is_held(&nf_conntrack_expect_lock));
+	if (this == me)
+		return true;
+
+	this = rcu_dereference_protected(exp->assign_helper,
+					 lockdep_is_held(&nf_conntrack_expect_lock));
 	return this == me;
 }
 
net/netfilter/nf_conntrack_netlink.c +16 -2
index eacbbc342c3f..80fdb875c977 100644
@@ -2630,6 +2630,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
 
 static struct nf_conntrack_expect *
 ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+		       const struct nf_conntrack_helper *assign_helper,
 		       struct nf_conntrack_tuple *tuple,
 		       struct nf_conntrack_tuple *mask);
 
@@ -2856,6 +2857,7 @@ static int
 ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
 			     u32 portid, u32 report)
 {
+	struct nf_conntrack_helper *assign_helper = NULL;
 	struct nlattr *cda[CTA_EXPECT_MAX+1];
 	struct nf_conntrack_tuple tuple, mask;
 	struct nf_conntrack_expect *exp;
@@ -2871,8 +2873,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
 	if (err < 0)
 		return err;
 
+	if (cda[CTA_EXPECT_HELP_NAME]) {
+		const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+
+		assign_helper = __nf_conntrack_helper_find(helpname,
+							   nf_ct_l3num(ct),
+							   tuple.dst.protonum);
+		if (!assign_helper)
+			return -EOPNOTSUPP;
+	}
+
 	exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
-				     &tuple, &mask);
+				     assign_helper, &tuple, &mask);
 	if (IS_ERR(exp))
 		return PTR_ERR(exp);
 
@@ -3511,6 +3523,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
 
 static struct nf_conntrack_expect *
 ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+		       const struct nf_conntrack_helper *assign_helper,
 		       struct nf_conntrack_tuple *tuple,
 		       struct nf_conntrack_tuple *mask)
 {
@@ -3564,6 +3577,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
 	exp->zone = ct->zone;
 #endif
 	rcu_assign_pointer(exp->helper, helper);
+	rcu_assign_pointer(exp->assign_helper, assign_helper);
 	exp->tuple = *tuple;
 	exp->mask.src.u3 = mask->src.u3;
 	exp->mask.src.u.all = mask->src.u.all;
@@ -3619,7 +3633,7 @@ ctnetlink_create_expect(struct net *net,
 	ct = nf_ct_tuplehash_to_ctrack(h);
 
 	rcu_read_lock();
-	exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+	exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask);
 	if (IS_ERR(exp)) {
 		err = PTR_ERR(exp);
 		goto err_rcu;
net/netfilter/nf_conntrack_sip.c +1 -1
index bd91b8b47f4b..852c0b74b8a7 100644
@@ -1386,7 +1386,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
 	nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
 			  saddr, &daddr, proto, NULL, &port);
 	exp->timeout.expires = sip_timeout * HZ;
-	rcu_assign_pointer(exp->helper, helper);
+	rcu_assign_pointer(exp->assign_helper, helper);
 	exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
 
 	hooks = rcu_dereference(nf_nat_sip_hooks);
Signature · 1 line
2.53.0
author maintainer
#1 lore raw

PATCH 2/337 um: Add os_set_pdeathsig helper function

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

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

From: Tiwei Bie <[email protected]>

commit 4e5adbe447db382cc76e05613581f96aef4f91d2 upstream.

This helper can be used to set the parent-death signal of the calling process to SIGKILL to ensure that the process will be killed if the UML kernel dies unexpectedly without proper cleanup. This helper will be used in the follow-up patches.

---
 arch/um/include/shared/os.h | 2 ++
 arch/um/os-Linux/process.c  | 6 ++++++
 2 files changed, 8 insertions(+)
arch/um/include/shared/os.h +2 -0
index 77a8593f219a..2a0843cc2208 100644
@@ -219,6 +219,8 @@ extern int os_unmap_memory(void *addr, int len);
 extern int os_drop_memory(void *addr, int length);
 extern int can_drop_memory(void);
 
+void os_set_pdeathsig(void);
+
 /* execvp.c */
 extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
 /* helper.c */
arch/um/os-Linux/process.c +6 -0
index 2686120ab232..4015d3dc3958 100644
@@ -12,6 +12,7 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/ptrace.h>
+#include <sys/prctl.h>
 #include <sys/wait.h>
 #include <asm/unistd.h>
 #include <init.h>
@@ -234,3 +235,8 @@ void init_new_thread_signals(void)
 	set_handler(SIGIO);
 	signal(SIGWINCH, SIG_IGN);
 }
+
+void os_set_pdeathsig(void)
+{
+	prctl(PR_SET_PDEATHSIG, SIGKILL);
+}
Signature · 1 line
2.53.0
author maintainer
#2 lore raw

PATCH 3/337 um: Set parent death signal for winch thread/process

In reply to Greg Kroah-Hartman

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

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

From: Benjamin Berg <[email protected]>

commit fdb2ecd35d327a1fc6bba69b97f85b494e1f4b6b upstream.

The winch "thread" is really a separate process. Using prctl to set PR_SET_PDEATHSIG ensures that this separate thread will be killed if the UML kernel itself dies unexpectedly and does not perform proper cleanup.

---
 arch/um/drivers/chan_user.c | 3 +++
 1 file changed, 3 insertions(+)
arch/um/drivers/chan_user.c +3 -0
index a66e556012c4..1434114b2f34 100644
@@ -10,6 +10,7 @@
 #include <signal.h>
 #include <termios.h>
 #include <sys/ioctl.h>
+#include <sys/prctl.h>
 #include "chan_user.h"
 #include <os.h>
 #include <um_malloc.h>
@@ -161,6 +162,8 @@ static __noreturn int winch_thread(void *arg)
 	int count;
 	char c = 1;
 
+	prctl(PR_SET_PDEATHSIG, SIGKILL);
+
 	pty_fd = data->pty_fd;
 	pipe_fd = data->pipe_fd;
 	count = write(pipe_fd, &c, sizeof(c));
Signature · 1 line
2.53.0
author maintainer
#3 lore raw

PATCH 4/337 um: Use os_set_pdeathsig helper in winch thread/process

In reply to Greg Kroah-Hartman

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

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

From: Tiwei Bie <[email protected]>

commit 42b8b00c8ab1ac18fccde3f29ee589626a561ea7 upstream.

Since we have a helper now, let's switch to using it. It will make the code slightly more consistent.

---
 arch/um/drivers/chan_user.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/um/drivers/chan_user.c +1 -2
index 1434114b2f34..35f9beeb19b3 100644
@@ -10,7 +10,6 @@
 #include <signal.h>
 #include <termios.h>
 #include <sys/ioctl.h>
-#include <sys/prctl.h>
 #include "chan_user.h"
 #include <os.h>
 #include <um_malloc.h>
@@ -162,7 +161,7 @@ static __noreturn int winch_thread(void *arg)
 	int count;
 	char c = 1;
 
-	prctl(PR_SET_PDEATHSIG, SIGKILL);
+	os_set_pdeathsig();
 
 	pty_fd = data->pty_fd;
 	pipe_fd = data->pipe_fd;
Signature · 1 line
2.53.0
author maintainer
#4 lore raw

PATCH 5/337 um: Set parent-death signal for ubd io thread/process

In reply to Greg Kroah-Hartman

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

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

From: Tiwei Bie <[email protected]>

commit 9b5e6c0f5a9199c69af81ac5bedc512ee7dc20b3 upstream.

The ubd io thread is not really a traditional thread. Set the parent-death signal for it to ensure that it will be killed if the UML kernel dies unexpectedly without proper cleanup.

---
 arch/um/drivers/ubd_kern.c | 1 +
 1 file changed, 1 insertion(+)
arch/um/drivers/ubd_kern.c +1 -0
index 2bfb17373244..66c1a8835e36 100644
@@ -1501,6 +1501,7 @@ int io_thread(void *arg)
 {
 	int n, count, written, res;
 
+	os_set_pdeathsig();
 	os_fix_helper_signals();
 
 	while(1){
Signature · 1 line
2.53.0
author maintainer
#5 lore raw

PATCH 6/337 um: Set parent-death signal for write_sigio thread/process

In reply to Greg Kroah-Hartman

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

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

From: Tiwei Bie <[email protected]>

commit c6c4adee65969218b0b7b13f568fd2c6f2333373 upstream.

The write_sigio thread is not really a traditional thread. Set the parent-death signal for it to ensure that it will be killed if the UML kernel dies unexpectedly without proper cleanup.

---
 arch/um/os-Linux/sigio.c | 1 +
 1 file changed, 1 insertion(+)
arch/um/os-Linux/sigio.c +1 -0
index 9e71794839e8..9aac8def4d63 100644
@@ -55,6 +55,7 @@ static int write_sigio_thread(void *unused)
 	int i, n, respond_fd;
 	char c;
 
+	os_set_pdeathsig();
 	os_fix_helper_signals();
 	fds = &current_poll;
 	while (1) {
Signature · 1 line
2.53.0
author maintainer
#6 lore raw

PATCH 7/337 um: Set parent death signal for userspace process

In reply to Greg Kroah-Hartman

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

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

From: Benjamin Berg <[email protected]>

commit 801e00d3a1b78b7f71675fae79946ff4aa3ee070 upstream.

Enable PR_SET_PDEATHSIG so that the UML userspace process will be killed when the kernel exits unexpectedly.

[florian: upstream applies os_set_pdeathsig() in stub_exe.c, a file introduced in v6.13 that does not exist in 6.12; applied instead to userspace_tramp() in arch/um/os-Linux/skas/process.c, which is the equivalent entry-point for the userspace process in 6.12]

---
 arch/um/os-Linux/skas/process.c | 3 +++
 1 file changed, 3 insertions(+)
arch/um/os-Linux/skas/process.c +3 -0
index b6f656bcffb1..cca016b0b29b 100644
@@ -214,6 +214,9 @@ static int userspace_tramp(void *stack)
 				     (unsigned long) stub_segv_handler -
 				     (unsigned long) __syscall_stub_start;
 
+	/* Make sure this process dies if the kernel dies */
+	os_set_pdeathsig();
+
 	ptrace(PTRACE_TRACEME, 0, 0, 0);
 
 	signal(SIGTERM, SIG_DFL);
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 8/337 kunit: tool: Terminate kernel under test on SIGINT

In reply to Greg Kroah-Hartman

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

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

From: David Gow <[email protected]>

commit 8f260b02eeeffbf2263c2b82b6e3e32fd73cde2b upstream.

kunit.py will attempt to catch SIGINT / ^C in order to ensure the TTY isn't messed up, but never actually attempts to terminate the running kernel (be it UML or QEMU). This can lead to a bit of frustration if the kernel has crashed or hung.

Terminate the kernel process in the signal handler, if it's running. This requires plumbing through the process handle in a few more places (and having some checks to see if the kernel is still running in places where it may have already been killed).

[florian: resolved conflict in signal_handler(): upstream references _restore_terminal_if_tty() which is introduced by the following commit; retained subprocess.call(['stty', 'sane']) until that helper is available]

---
 tools/testing/kunit/kunit_kernel.py | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)
tools/testing/kunit/kunit_kernel.py +19 -9
index 12b0f2ee5665..3f2979f2f6ea 100644
@@ -15,7 +15,7 @@ import shlex
 import shutil
 import signal
 import threading
-from typing import Iterator, List, Optional, Tuple
+from typing import Iterator, List, Optional, Tuple, Any
 from types import FrameType
 
 import kunit_config
@@ -252,6 +252,7 @@ class LinuxSourceTree:
 		if kconfig_add:
 			kconfig = kunit_config.parse_from_string('\n'.join(kconfig_add))
 			self._kconfig.merge_in_entries(kconfig)
+		self._process : Optional[subprocess.Popen[Any]] = None
 
 	def arch(self) -> str:
 		return self._arch
@@ -345,36 +346,45 @@ class LinuxSourceTree:
 			args.append('kunit.filter_action=' + filter_action)
 		args.append('kunit.enable=1')
 
-		process = self._ops.start(args, build_dir)
-		assert process.stdout is not None  # tell mypy it's set
+		self._process = self._ops.start(args, build_dir)
+		assert self._process is not None # tell mypy it's set
+		assert self._process.stdout is not None  # tell mypy it's set
 
 		# Enforce the timeout in a background thread.
 		def _wait_proc() -> None:
 			try:
-				process.wait(timeout=timeout)
+				if self._process:
+					self._process.wait(timeout=timeout)
 			except Exception as e:
 				print(e)
-				process.terminate()
-				process.wait()
+				if self._process:
+					self._process.terminate()
+					self._process.wait()
 		waiter = threading.Thread(target=_wait_proc)
 		waiter.start()
 
 		output = open(get_outfile_path(build_dir), 'w')
 		try:
 			# Tee the output to the file and to our caller in real time.
-			for line in process.stdout:
+			for line in self._process.stdout:
 				output.write(line)
 				yield line
 		# This runs even if our caller doesn't consume every line.
 		finally:
 			# Flush any leftover output to the file
-			output.write(process.stdout.read())
+			if self._process:
+				if self._process.stdout:
+					output.write(self._process.stdout.read())
+					self._process.stdout.close()
+				self._process = None
 			output.close()
-			process.stdout.close()
 
 			waiter.join()
 			subprocess.call(['stty', 'sane'])
 
 	def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
 		logging.error('Build interruption occurred. Cleaning console.')
+		if self._process:
+				self._process.terminate()
+				self._process.wait()
 		subprocess.call(['stty', 'sane'])
Signature · 1 line
2.53.0
author maintainer
#8 lore raw

PATCH 9/337 kunit: tool: skip stty when stdin is not a tty

In reply to Greg Kroah-Hartman

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

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

From: Shuvam Pandey <[email protected]>

commit e42c349f4cdfa43cb39a68c8f764f8cafc23a9a9 upstream.

run_kernel() cleanup and signal_handler() invoke stty unconditionally. When stdin is not a tty (for example in CI or unit tests), this writes noise to stderr.

Call stty only when stdin is a tty.

Add regression tests for these paths:
- run_kernel() with non-tty stdin
- signal_handler() with non-tty stdin
- signal_handler() with tty stdin

[florian: add missing 'import sys' required by sys.stdin.isatty(); the module was already present in the mainline tree before this commit but was absent from the 6.12 base of kunit_kernel.py]

---
 tools/testing/kunit/kunit_kernel.py    | 11 +++++--
 tools/testing/kunit/kunit_tool_test.py | 42 ++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 2 deletions(-)
tools/testing/kunit/kunit_kernel.py +9 -2
index 3f2979f2f6ea..c09b66ba734b 100644
@@ -14,6 +14,7 @@ import os
 import shlex
 import shutil
 import signal
+import sys
 import threading
 from typing import Iterator, List, Optional, Tuple, Any
 from types import FrameType
@@ -333,6 +334,12 @@ class LinuxSourceTree:
 			return False
 		return self.validate_config(build_dir)
 
+	def _restore_terminal_if_tty(self) -> None:
+		# stty requires a controlling terminal; skip headless runs.
+		if sys.stdin is None or not sys.stdin.isatty():
+			return
+		subprocess.call(['stty', 'sane'])
+
 	def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]:
 		# Copy to avoid mutating the caller-supplied list. exec_tests() reuses
 		# the same args across repeated run_kernel() calls (e.g. --run_isolated),
@@ -380,11 +387,11 @@ class LinuxSourceTree:
 			output.close()
 
 			waiter.join()
-			subprocess.call(['stty', 'sane'])
+			self._restore_terminal_if_tty()
 
 	def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
 		logging.error('Build interruption occurred. Cleaning console.')
 		if self._process:
 				self._process.terminate()
 				self._process.wait()
-		subprocess.call(['stty', 'sane'])
+		self._restore_terminal_if_tty()
tools/testing/kunit/kunit_tool_test.py +42 -0

48 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#9 lore raw

PATCH 10/337 um: Preserve errno within signal handler

In reply to Greg Kroah-Hartman

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

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

From: Tiwei Bie <[email protected]>

commit f68b2d5a907b53eed99cf2efcaaae116df73c298 upstream.

We rely on errno to determine whether a syscall has failed, so we need to ensure that accessing errno is async-signal-safe. Currently, we preserve the errno in sig_handler_common(), but it doesn't cover every possible case. Let's do it in hard_handler() instead, which is the signal handler we actually register.

[florian: hard_handler() in 6.12 retains the to_irq_stack/from_irq_stack loop from before the upstream SMP refactoring; errno save/restore is wrapped around that loop rather than replacing sig_handler_common's existing save/restore]

---
 arch/um/os-Linux/signal.c | 3 +++
 1 file changed, 3 insertions(+)
arch/um/os-Linux/signal.c +3 -0
index b11ed66c8bb0..94abc9e3ec7e 100644
@@ -190,6 +190,7 @@ static void hard_handler(int sig, siginfo_t *si, void *p)
 {
 	ucontext_t *uc = p;
 	mcontext_t *mc = &uc->uc_mcontext;
+	int save_errno = errno;
 	unsigned long pending = 1UL << sig;
 
 	do {
@@ -227,6 +228,8 @@ static void hard_handler(int sig, siginfo_t *si, void *p)
 		if (!nested)
 			pending = from_irq_stack(nested);
 	} while (pending);
+
+	errno = save_errno;
 }
 
 void set_handler(int sig)
Signature · 1 line
2.53.0
author maintainer
#10 lore raw

PATCH 11/337 netfilter: br_netfilter: Reallocate headroom if necessary in neigh_hh_bridge()

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Bianconi <[email protected]>

[ Upstream commit b2870fc21601db9133bc70c48c603b487614fa3b ]

neigh_hh_bridge() assumes the skb always has sufficient headroom to copy the aligned L2 header. This assumption can trigger the crash reported below using the following netfilter setup:

$modprobe br_netfilter
$sysctl -w net.bridge.bridge-nf-call-iptables=1

$root@OpenWrt:~# nft list ruleset
table ip nat {
        chain prerouting {
                type nat hook prerouting priority dstnat; policy accept;
                ip daddr 192.168.83.123 dnat to 192.168.83.120
        }
}

- iperf3 client (192.168.83.119) --> bridge (192.168.83.118) --> iperf3 server (192.168.83.120)

the iperf3 client is sending packet for 192.168.83.123 to the bridge device.

[ 1579.036575] Unable to handle kernel write to read-only memory at virtual address ffffff8004d76ffe
[ 1579.045482] Mem abort info:
[ 1579.048273]   ESR = 0x000000009600004f
[ 1579.052024]   EC = 0x25: DABT (current EL), IL = 32 bits
[ 1579.057363]   SET = 0, FnV = 0
[ 1579.060417]   EA = 0, S1PTW = 0
[ 1579.063550]   FSC = 0x0f: level 3 permission fault
[ 1579.068345] Data abort info:
[ 1579.071224]   ISV = 0, ISS = 0x0000004f, ISS2 = 0x00000000
[ 1579.076720]   CM = 0, WnR = 1, TnD = 0, TagAccess = 0
[ 1579.081770]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 1579.087092] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000080dc4000
[ 1579.093794] [ffffff8004d76ffe] pgd=180000009ffff003, p4d=180000009ffff003, pud=180000009ffff003, pmd=180000009ffe3003, pte=0060000084d76787
[ 1579.106343] Internal error: Oops: 000000009600004f [#1] SMP
[ 1579.193824] CPU: 0 UID: 0 PID: 235 Comm: napi/qdma_eth-3 Tainted: G           O       6.12.57 #0
[ 1579.202614] Tainted: [O]=OOT_MODULE
[ 1579.206102] Hardware name: Airoha AN7581 Evaluation Board (DT)
[ 1579.211929] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 1579.218889] pc : br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter]
[ 1579.225859] lr : br_nf_pre_routing_finish_bridge+0x18c/0xcc8 [br_netfilter]
[ 1579.232822] sp : ffffffc0817cba20
[ 1579.236128] x29: ffffffc0817cba20 x28: 0000000000000000 x27: ffffff8002b89000
[ 1579.243273] x26: ffffff8004d7700e x25: 0000000000000008 x24: 0000000000000000
[ 1579.250416] x23: ffffffc08179d4c0 x22: 0000000000000000 x21: ffffffc08179d4c0
[ 1579.257561] x20: ffffff8004d9b800 x19: ffffff8015010000 x18: 0000000000000014
[ 1579.264704] x17: ffffffbf9e930000 x16: ffffffc0817c8000 x15: 0000000000000070
[ 1579.271848] x14: 0000000000000080 x13: 0000000000000001 x12: 0000000000000000
[ 1579.278993] x11: ffffffc0798caae0 x10: ffffff8014db6fd8 x9 : 0000000000000000
[ 1579.286136] x8 : 0000000000000003 x7 : ffffffc08171f628 x6 : 000000001a3b83d3
[ 1579.293281] x5 : 0000000000000000 x4 : 1beb76f22fee0000 x3 : ffffff8004d7700e
[ 1579.300425] x2 : 0000000000000000 x1 : ffffff8004d9b8bc x0 : ffffff80026ed000
[ 1579.307570] Call trace:
[ 1579.310018]  br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter]
[ 1579.316632]  br_nf_hook_thresh+0xd4/0x14bc [br_netfilter]
[ 1579.322032]  br_nf_hook_thresh+0x250/0x14bc [br_netfilter]
[ 1579.327517]  br_nf_hook_thresh+0x76c/0x14bc [br_netfilter]
[ 1579.333003]  br_handle_frame+0x180/0x480
[ 1579.336935]  __netif_receive_skb_core.constprop.0+0x540/0xf40
[ 1579.342682]  __netif_receive_skb_one_core+0x28/0x50
[ 1579.347561]  process_backlog+0x98/0x1e0
[ 1579.351398]  __napi_poll+0x34/0x1c4
[ 1579.354887]  net_rx_action+0x178/0x330
[ 1579.358638]  handle_softirqs+0x108/0x2d4
[ 1579.362560]  __do_softirq+0x10/0x18
[ 1579.366051]  ____do_softirq+0xc/0x20
[ 1579.369627]  call_on_irq_stack+0x30/0x4c
[ 1579.373550]  do_softirq_own_stack+0x18/0x20
[ 1579.377734]  do_softirq+0x4c/0x60
[ 1579.381050]  __local_bh_enable_ip+0x88/0x98
[ 1579.385234]  napi_threaded_poll_loop+0x188/0x21c
[ 1579.389853]  napi_threaded_poll+0x70/0x80
[ 1579.393863]  kthread+0xd8/0xdc
[ 1579.396918]  ret_from_fork+0x10/0x20
[ 1579.400499] Code: 88dffc22 3707ffc2 f9406663 f9406684 (f81f0064)
[ 1579.406589] ---[ end trace 0000000000000000 ]---
[ 1579.411209] Kernel panic - not syncing: Oops: Fatal exception in interrupt
[ 1579.418083] SMP: stopping secondary CPUs
[ 1579.422012] Kernel Offset: disabled

Fix the issue reallocating the skb headroom if necessary in neigh_hh_bridge routine.

Fixes e179e6322ac33 ("netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT")
---
 include/net/neighbour.h         | 8 ++++++--
 net/bridge/br_netfilter_hooks.c | 6 +++++-
 2 files changed, 11 insertions(+), 3 deletions(-)
include/net/neighbour.h +6 -2
index cb5f835a5d61..0272d0f0e89d 100644
@@ -476,11 +476,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 {
-	unsigned int seq, hh_alen;
+	unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN);
+	int err;
+
+	err = skb_cow_head(skb, hh_alen);
+	if (err)
+		return err;
 
 	do {
 		seq = read_seqbegin(&hh->hh_lock);
-		hh_alen = HH_DATA_ALIGN(ETH_HLEN);
 		memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN);
 	} while (read_seqretry(&hh->hh_lock, seq));
 	return 0;
net/bridge/br_netfilter_hooks.c +5 -1
index 5ad3f3ef4ca7..c550907b92dd 100644
@@ -296,7 +296,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
 				goto free_skb;
 			}
 
-			neigh_hh_bridge(&neigh->hh, skb);
+			if (neigh_hh_bridge(&neigh->hh, skb)) {
+				neigh_release(neigh);
+				goto free_skb;
+			}
+
 			skb->dev = br_indev;
 
 			ret = br_handle_frame_finish(net, sk, skb);
Signature · 1 line
2.53.0
author maintainer
#11 lore raw

PATCH 12/337 net: airoha: Fix register index for Tx-fwd counter configuration

In reply to Greg Kroah-Hartman

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

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

From: Wayen.Yan <[email protected]>

[ Upstream commit 1402ecccf5630a0b7fa4749d7d2e72abc3f3d73d ]

In airoha_qdma_init_qos_stats(), the Tx-fwd counter configuration register uses the same index (i << 1) as the Tx-cpu counter, which overwrites the Tx-cpu configuration. The Tx-fwd counter value register correctly uses (i << 1) + 1, so the configuration register should use the same index.

Fix the REG_CNTR_CFG index from (i << 1) to ((i << 1) + 1) so that the Tx-fwd counter is properly configured instead of clobbering the Tx-cpu counter config.

---
 drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/airoha/airoha_eth.c +1 -1
index 58e5791e9cd4..9ebc9788ded7 100644
@@ -2022,7 +2022,7 @@ static void airoha_qdma_init_qos_stats(struct airoha_qdma *qdma)
 			       FIELD_PREP(CNTR_CHAN_MASK, i));
 		/* Tx-fwd transferred count */
 		airoha_qdma_wr(qdma, REG_CNTR_VAL((i << 1) + 1), 0);
-		airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1),
+		airoha_qdma_wr(qdma, REG_CNTR_CFG((i << 1) + 1),
 			       CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK |
 			       CNTR_ALL_DSCP_RING_EN_MASK |
 			       FIELD_PREP(CNTR_SRC_MASK, 1) |
Signature · 1 line
2.53.0
author maintainer
#12 lore raw

PATCH 13/337 net: mpls: initialize rtm_tos in mpls_getroute()

In reply to Greg Kroah-Hartman

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

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

From: Yehyeong Lee <[email protected]>

[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ]

mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE request by filling a struct rtmsg allocated from an skb whose data area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every field of the header except rtm_tos:

	r = nlmsg_data(nlh);
	r->rtm_family	 = AF_MPLS;
	r->rtm_dst_len	= 20;
	r->rtm_src_len	= 0;
	r->rtm_table	= RT_TABLE_MAIN;
	r->rtm_type	= RTN_UNICAST;
	r->rtm_scope	= RT_SCOPE_UNIVERSE;
	r->rtm_protocol = rt->rt_protocol;
	r->rtm_flags	= 0;

struct rtmsg has no padding, so the one uninitialised byte rtm_tos (offset 3) is copied straight to user space on recvmsg(), leaking a byte of uninitialised heap memory. This is in contrast to mpls_dump_route(), which fills the very same header and does set rtm_tos = 0.

Initialize rtm_tos to 0, matching mpls_dump_route().

Reproduced with KMSAN by adding an MPLS route and issuing a non-RTM_F_FIB_MATCH RTM_GETROUTE for its label:

  BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0
   _copy_to_iter+0x36c/0x33f0
   __skb_datagram_iter+0x196/0x12c0
   skb_copy_datagram_iter+0x5b/0x210
   netlink_recvmsg+0x37b/0xef0
   ...
  Uninit was created at:
   __alloc_skb+0x8ca/0x10e0
   mpls_getroute+0x1280/0x3a40
   rtnetlink_rcv_msg+0x1138/0x15a0
   ...
  Byte 19 of 64 is uninitialized

(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos)

---
 net/mpls/af_mpls.c | 1 +
 1 file changed, 1 insertion(+)
net/mpls/af_mpls.c +1 -0
index 98816e51e01a..0379540d601a 100644
@@ -2468,6 +2468,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
 	r->rtm_family	 = AF_MPLS;
 	r->rtm_dst_len	= 20;
 	r->rtm_src_len	= 0;
+	r->rtm_tos	= 0;
 	r->rtm_table	= RT_TABLE_MAIN;
 	r->rtm_type	= RTN_UNICAST;
 	r->rtm_scope	= RT_SCOPE_UNIVERSE;
Signature · 1 line
2.53.0
author maintainer
#13 lore raw

PATCH 14/337 HID: logitech-dj: Standardise hid_report_enum variable nomenclature

In reply to Greg Kroah-Hartman

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

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

From: Lee Jones <[email protected]>

[ Upstream commit a940aee176437046598dfc786b719bd96db3c74c ]

Since we will need to differentiate between the two report_enum types soon, let's unify the naming conventions now to save confusion and/or unnecessary/unrelated changes in upcoming commits.

{input,output}_report_enum is used in other places to let's conform.

---
 drivers/hid/hid-logitech-dj.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/hid/hid-logitech-dj.c +6 -6
index 3b5412541c925..d6fb7015f0d77 100644
@@ -1749,7 +1749,7 @@ static int logi_dj_raw_event(struct hid_device *hdev,
 static int logi_dj_probe(struct hid_device *hdev,
 			 const struct hid_device_id *id)
 {
-	struct hid_report_enum *rep_enum;
+	struct hid_report_enum *input_report_enum;
 	struct hid_report *rep;
 	struct dj_receiver_dev *djrcv_dev;
 	struct usb_interface *intf;
@@ -1793,10 +1793,10 @@ static int logi_dj_probe(struct hid_device *hdev,
 		}
 	}
 
-	rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
+	input_report_enum = &hdev->report_enum[HID_INPUT_REPORT];
 
 	/* no input reports, bail out */
-	if (list_empty(&rep_enum->report_list))
+	if (list_empty(&input_report_enum->report_list))
 		return -ENODEV;
 
 	/*
@@ -1804,7 +1804,7 @@ static int logi_dj_probe(struct hid_device *hdev,
 	 * Note: we should theoretically check for HID++ and DJ
 	 * collections, but this will do.
 	 */
-	list_for_each_entry(rep, &rep_enum->report_list, list) {
+	list_for_each_entry(rep, &input_report_enum->report_list, list) {
 		if (rep->application == 0xff000001)
 			has_hidpp = true;
 	}
@@ -1817,7 +1817,7 @@ static int logi_dj_probe(struct hid_device *hdev,
 		return -ENODEV;
 
 	/* get the current application attached to the node */
-	rep = list_first_entry(&rep_enum->report_list, struct hid_report, list);
+	rep = list_first_entry(&input_report_enum->report_list, struct hid_report, list);
 	djrcv_dev = dj_get_receiver_dev(hdev, id->driver_data,
 					rep->application, has_hidpp);
 	if (!djrcv_dev) {
@@ -1825,7 +1825,7 @@ static int logi_dj_probe(struct hid_device *hdev,
 		return -ENOMEM;
 	}
 
-	if (!rep_enum->numbered)
+	if (!input_report_enum->numbered)
 		djrcv_dev->unnumbered_application = rep->application;
 
 	/* Starts the usb device and connects to upper interfaces hiddev and
Signature · 1 line
2.53.0
author maintainer
#14 lore raw

PATCH 15/337 HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write

In reply to Greg Kroah-Hartman

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

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

From: Lee Jones <[email protected]>

[ Upstream commit b6a57912854e7ea36f3b270032661140cc4209cd ]

logi_dj_recv_send_report() assumes that all incoming REPORT_ID_DJ_SHORT reports are 14 Bytes (DJREPORT_SHORT_LENGTH - 1) long. It uses that assumption to load the associated field's 'value' array with 14 Bytes of data. However, if a malicious user only sends say 1 Byte of data, 'report_count' will be 1 and only 1 Byte of memory will be allocated to the 'value' Byte array. When we come to populate 'value[1-13]' we will experience an OOB write.

---
 drivers/hid/hid-logitech-dj.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/hid/hid-logitech-dj.c +10 -0
index d6fb7015f0d77..3a37d61616293 100644
@@ -1750,6 +1750,7 @@ static int logi_dj_probe(struct hid_device *hdev,
 			 const struct hid_device_id *id)
 {
 	struct hid_report_enum *input_report_enum;
+	struct hid_report_enum *output_report_enum;
 	struct hid_report *rep;
 	struct dj_receiver_dev *djrcv_dev;
 	struct usb_interface *intf;
@@ -1793,6 +1794,15 @@ static int logi_dj_probe(struct hid_device *hdev,
 		}
 	}
 
+	output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
+	rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
+
+	if (rep->maxfield < 1 || rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1) {
+		hid_err(hdev, "Expected size of DJ short report is %d, but got %d",
+			DJREPORT_SHORT_LENGTH - 1, rep->field[0]->report_count);
+		return -EINVAL;
+	}
+
 	input_report_enum = &hdev->report_enum[HID_INPUT_REPORT];
 
 	/* no input reports, bail out */
Signature · 1 line
2.53.0
author maintainer
#15 lore raw

PATCH 16/337 HID: logitech-dj: fix wrong detection of bad DJ_SHORT output report

In reply to Greg Kroah-Hartman

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

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

From: Benjamin Tissoires <[email protected]>

[ Upstream commit 8b9a097eb2fc37b486afd81388c693bf3ab44466 ]

commit b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write") assumed that all HID devices attached to the logitech-dj driver was having an output report of DJ_SHORT.

However, on the receiver itself, we have 2 other HID device we attach
here: the mouse emulation and the keyboard emulation. For those devices the value of rep is NULL and we are triggered a segfault here.

This is doubly required because logitech-dj also handles non DJ devices that might not have the DJ collection.

Fixes b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write")
---
 drivers/hid/hid-logitech-dj.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hid/hid-logitech-dj.c +2 -1
index 3a37d61616293..f1e923ed9d1c5 100644
@@ -1797,7 +1797,8 @@ static int logi_dj_probe(struct hid_device *hdev,
 	output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
 	rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
 
-	if (rep->maxfield < 1 || rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1) {
+	if (rep && (rep->maxfield < 1 ||
+		    rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1)) {
 		hid_err(hdev, "Expected size of DJ short report is %d, but got %d",
 			DJREPORT_SHORT_LENGTH - 1, rep->field[0]->report_count);
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#16 lore raw

PATCH 17/337 bpf: Reset register bounds before narrowing retval range in check_mem_access()

In reply to Greg Kroah-Hartman

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

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

From: Tristan Madani <[email protected]>

[ Upstream commit 5e0b273e0a62cc04ec338c7b502797c66c2ed42a ]

When the BPF verifier processes a context load of an LSM hook return value, it calls __mark_reg_s32_range() to narrow the register to the hook's valid range. However, __mark_reg_s32_range() intersects the new range with the register's existing bounds using max_t()/min_t() rather than replacing them.

If the destination register carries stale bounds from a prior instruction (e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than reality. The verifier then believes it knows the register's exact value, while at runtime the actual hook return value is loaded, creating a verifier/runtime mismatch that can be used to bypass BPF memory safety checks.

The else branch already calls mark_reg_unknown() to reset register state before any narrowing. Apply the same reset in the is_retval path so stale bounds are cleared before __mark_reg_s32_range() intersects.

---
 kernel/bpf/verifier.c | 1 +
 1 file changed, 1 insertion(+)
kernel/bpf/verifier.c +1 -0
index 8c3c4ab989a05..77183b436da5e 100644
@@ -7234,6 +7234,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
 			 */
 			if (reg_type == SCALAR_VALUE) {
 				if (is_retval && get_func_retval_range(env->prog, &range)) {
+					mark_reg_unknown(env, regs, value_regno);
 					err = __mark_reg_s32_range(env, regs, value_regno,
 								   range.minval, range.maxval);
 					if (err)
Signature · 1 line
2.53.0
author maintainer
#17 lore raw

PATCH 18/337 netconsole: avoid OOB reads, msg is not nul-terminated

In reply to Greg Kroah-Hartman

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

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

From: Jakub Kicinski <[email protected]>

[ Upstream commit 82aec772fca2223bc5774bd9af486fd95766e578 ]

msg passed to netconsole from the console subsystem is not guaranteed to be nul-terminated. Before recent
commit 7eab73b18630 ("netconsole: convert to NBCON console infrastructure") the message would be placed in printk_shared_pbufs, a static global buffer, so KASAN had harder time catching OOB accesses. Now we see:

    printk: console [netcon_ext0] enabled
    BUG: KASAN: slab-out-of-bounds in string+0x1f7/0x240
    Read of size 1 at addr ffff88813b6d4c00 by task pr/netcon_ext0/594

    CPU: 65 UID: 0 PID: 594 Comm: pr/netcon_ext0 Not tainted 6.19.0-11754-g4246fd6547c9
    Call Trace:
     kasan_report+0xe4/0x120
     string+0x1f7/0x240
     vsnprintf+0x655/0xba0
     scnprintf+0xba/0x120
     netconsole_write+0x3fe/0xa10
     nbcon_emit_next_record+0x46e/0x860
     nbcon_kthread_func+0x623/0x750

    Allocated by task 1:
     nbcon_alloc+0x1ea/0x450
     register_console+0x26b/0xe10
     init_netconsole+0xbb0/0xda0

    The buggy address belongs to the object at ffff88813b6d4000
                which belongs to the cache kmalloc-4k of size 4096
    The buggy address is located 0 bytes to the right of
                allocated 3072-byte region [ffff88813b6d4000, ffff88813b6d4c00)
Fixes c62c0a17f9b7 ("netconsole: Append kernel version to message")

[ mb: adjusted context; in 6.12 the affected code lives in
send_ext_msg_udp() and writes to a static buffer instead of nt->buf ]

---
 drivers/net/netconsole.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/netconsole.c +2 -1
index 60375bb814a1e..3b76ec3cd49b8 100644
@@ -1103,7 +1103,8 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
 	if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) {
 		/* No fragmentation needed */
 		if (nt->release) {
-			scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg);
+			scnprintf(buf, MAX_PRINT_CHUNK, "%s,%.*s", release,
+				  msg_len, msg);
 			msg_len += release_len;
 		} else {
 			memcpy(buf, msg, msg_len);
Signature · 1 line
2.53.0
author maintainer
#18 lore raw

PATCH 19/337 thunderbolt: Prevent XDomain delayed work use-after-free on disconnect

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ]

tb_xdp_handle_request() runs on system_wq and queues xd->state_work via queue_delayed_work() in three request handlers:
PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues xd->properties_changed_work when local properties change.

Concurrently, tb_xdomain_remove() calls stop_handshake() which does cancel_delayed_work_sync() on both delayed works. Later, tb_xdomain_unregister() calls device_unregister() which eventually frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") moved the request handler off tb->wq, the handler and the remove path are no longer serialized. If queue_delayed_work() executes after cancel_delayed_work_sync() but before the xdomain is freed, the delayed work fires on a freed object.

Add xd->removing that tb_xdomain_remove() sets under xd->lock before calling stop_handshake(). Each external queue site holds the same lock and checks removing before calling queue_delayed_work(). This provides the mutual exclusion needed:
either the queue site acquires the lock first and queues work that the subsequent cancel will see, or the remove path acquires the lock first and the queue site observes removing == true and skips the queue.

Fixes 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue")
Assisted-by Claude:claude-opus-4-7
---
 drivers/thunderbolt/xdomain.c | 40 ++++++++++++++++++++++++++---------
 include/linux/thunderbolt.h   |  3 +++
 2 files changed, 33 insertions(+), 10 deletions(-)
drivers/thunderbolt/xdomain.c +30 -10
index 06357073f4ab8..ffe7ce0737491 100644
@@ -783,9 +783,13 @@ static void tb_xdp_handle_request(struct work_struct *work)
 		 * the xdomain related to this connection as well in
 		 * case there is a change in services it offers.
 		 */
-		if (xd && device_is_registered(&xd->dev))
-			queue_delayed_work(tb->wq, &xd->state_work,
-					   msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+		if (xd) {
+			mutex_lock(&xd->lock);
+			if (!xd->removing && device_is_registered(&xd->dev))
+				queue_delayed_work(tb->wq, &xd->state_work,
+						   msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+			mutex_unlock(&xd->lock);
+		}
 		break;
 
 	case UUID_REQUEST_OLD:
@@ -798,8 +802,12 @@ static void tb_xdp_handle_request(struct work_struct *work)
 		 * received UUID request from the remote host.
 		 */
 		if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
-			dev_dbg(&xd->dev, "restarting handshake\n");
-			start_handshake(xd);
+			mutex_lock(&xd->lock);
+			if (!xd->removing) {
+				dev_dbg(&xd->dev, "restarting handshake\n");
+				start_handshake(xd);
+			}
+			mutex_unlock(&xd->lock);
 		}
 		break;
 
@@ -827,9 +835,13 @@ static void tb_xdp_handle_request(struct work_struct *work)
 
 			ret = tb_xdp_link_state_change_response(ctl, route,
 								sequence, 0);
-			xd->target_link_width = lsc->tlw;
-			queue_delayed_work(tb->wq, &xd->state_work,
-					   msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+			mutex_lock(&xd->lock);
+			if (!xd->removing) {
+				xd->target_link_width = lsc->tlw;
+				queue_delayed_work(tb->wq, &xd->state_work,
+						   msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+			}
+			mutex_unlock(&xd->lock);
 		} else {
 			tb_xdp_error_response(ctl, route, sequence,
 					      ERROR_NOT_READY);
@@ -2068,6 +2080,10 @@ void tb_xdomain_remove(struct tb_xdomain *xd)
 {
 	tb_xdomain_debugfs_remove(xd);
 
+	mutex_lock(&xd->lock);
+	xd->removing = true;
+	mutex_unlock(&xd->lock);
+
 	stop_handshake(xd);
 
 	device_for_each_child_reverse(&xd->dev, xd, unregister_service);
@@ -2464,8 +2480,12 @@ static int update_xdomain(struct device *dev, void *data)
 
 	xd = tb_to_xdomain(dev);
 	if (xd) {
-		queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
-				   msecs_to_jiffies(50));
+		mutex_lock(&xd->lock);
+		if (!xd->removing)
+			queue_delayed_work(xd->tb->wq,
+					   &xd->properties_changed_work,
+					   msecs_to_jiffies(50));
+		mutex_unlock(&xd->lock);
 	}
 
 	return 0;
include/linux/thunderbolt.h +3 -0
index 7d902d8c054b2..4ef9c43026569 100644
@@ -202,6 +202,8 @@ enum tb_link_width {
  * @link_width: Width of the downstream facing link
  * @link_usb4: Downstream link is USB4
  * @is_unplugged: The XDomain is unplugged
+ * @removing: Set by tb_xdomain_remove() under @lock to prevent
+ *	      concurrent delayed work queueing
  * @needs_uuid: If the XDomain does not have @remote_uuid it will be
  *		queried first
  * @service_ids: Used to generate IDs for the services
@@ -250,6 +252,7 @@ struct tb_xdomain {
 	enum tb_link_width link_width;
 	bool link_usb4;
 	bool is_unplugged;
+	bool removing;
 	bool needs_uuid;
 	struct ida service_ids;
 	struct ida in_hopids;
Signature · 1 line
2.53.0
author maintainer
#19 lore raw

PATCH 20/337 pinctrl: qcom: Unconditionally mark gpio as wakeup enable

In reply to Greg Kroah-Hartman

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

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

From: Sneh Mankad <[email protected]>

[ Upstream commit 859e02a369ab328a77dfcabf59562100e55f9c5c ]

GPIO interrupts that are wakeup capable need to be forwarded to wakeup capable parent irqchip. This is done via writing to it's wakeup_enable bit.

Currently the bit is set only for PDC irqchip by checking skip_wake_irqs. skip_wake_irqs is set to differentiate between parent irqchips MPM and PDC. It is set when the parent irqchip is PDC to inform pinctrl about skipping the IRQ setting up at TLMM.

However, the functionality to forward GPIO interrupts during SoC low power mode is needed regardless of which parent irqchip it is. Without the functionality it is impossible for MPM irqchip to detect the GPIO interrupt during SoC low power mode since for MPM irqchip the skip_wake_irqs is always false.

Remove skip_wake_irqs condition when setting wakeup enable bit to allow forwarding GPIO interrupts for SoCs using MPM irqchip too.

---
 drivers/pinctrl/qcom/pinctrl-msm.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/pinctrl/qcom/pinctrl-msm.c +4 -4
index 27eb585bf42df..994f46c4c3b6b 100644
@@ -1247,12 +1247,12 @@ static int msm_gpio_irq_reqres(struct irq_data *d)
 	/*
 	 * If the wakeup_enable bit is present and marked as available for the
 	 * requested GPIO, it should be enabled when the GPIO is marked as
-	 * wake irq in order to allow the interrupt event to be transfered to
-	 * the PDC HW.
+	 * wake irq in order to allow the interrupt event to be transferred to
+	 * the PDC/MPM HW.
 	 * While the name implies only the wakeup event, it's also required for
 	 * the interrupt event.
 	 */
-	if (test_bit(d->hwirq, pctrl->skip_wake_irqs) && g->intr_wakeup_present_bit) {
+	if (g->intr_wakeup_present_bit) {
 		u32 intr_cfg;
 
 		raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -1280,7 +1280,7 @@ static void msm_gpio_irq_relres(struct irq_data *d)
 	unsigned long flags;
 
 	/* Disable the wakeup_enable bit if it has been set in msm_gpio_irq_reqres() */
-	if (test_bit(d->hwirq, pctrl->skip_wake_irqs) && g->intr_wakeup_present_bit) {
+	if (g->intr_wakeup_present_bit) {
 		u32 intr_cfg;
 
 		raw_spin_lock_irqsave(&pctrl->lock, flags);
Signature · 1 line
2.53.0
author maintainer
#20 lore raw

PATCH 21/337 pinctrl: qcom: sc8280xp: Add missing wakeup entries for GPIO143/151

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit 437a8d2aa1aa442c4a176fdf4700a9b3bb0c8794 ]

Pins 143 and 151 were not included in the PDC wakeup map. They are normally used for PCIe2A and PCIe3a PERST# respectively, so they're unlikely to be excercised in practice, but still add them for the sake of completeness.

---
 drivers/pinctrl/qcom/pinctrl-sc8280xp.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
drivers/pinctrl/qcom/pinctrl-sc8280xp.c +11 -10
index 4b1c49697698d..67945ce867fa1 100644
@@ -1884,16 +1884,17 @@ static const struct msm_gpio_wakeirq_map sc8280xp_pdc_map[] = {
 	{ 126, 200 }, { 127, 225 }, { 128, 262 }, { 129, 201 },
 	{ 130, 209 }, { 131, 173 }, { 132, 202 }, { 136, 210 },
 	{ 138, 171 }, { 139, 226 }, { 140, 227 }, { 142, 228 },
-	{ 144, 229 }, { 145, 230 }, { 146, 231 }, { 148, 232 },
-	{ 149, 233 }, { 150, 234 }, { 152, 235 }, { 154, 212 },
-	{ 157, 213 }, { 161, 219 }, { 170, 236 }, { 171, 221 },
-	{ 174, 222 }, { 175, 237 }, { 176, 223 }, { 177, 170 },
-	{ 180, 238 }, { 181, 239 }, { 182, 240 }, { 183, 241 },
-	{ 184, 242 }, { 185, 243 }, { 190, 178 }, { 193, 184 },
-	{ 196, 185 }, { 198, 186 }, { 200, 174 }, { 201, 175 },
-	{ 205, 176 }, { 206, 177 }, { 208, 187 }, { 210, 198 },
-	{ 211, 199 }, { 212, 204 }, { 215, 205 }, { 220, 188 },
-	{ 221, 194 }, { 223, 195 }, { 225, 196 }, { 227, 197 },
+	{ 143, 261 }, { 144, 229 }, { 145, 230 }, { 146, 231 },
+	{ 148, 232 }, { 149, 233 }, { 150, 234 }, { 151, 264 },
+	{ 152, 235 }, { 154, 212 }, { 157, 213 }, { 161, 219 },
+	{ 170, 236 }, { 171, 221 }, { 174, 222 }, { 175, 237 },
+	{ 176, 223 }, { 177, 170 }, { 180, 238 }, { 181, 239 },
+	{ 182, 240 }, { 183, 241 }, { 184, 242 }, { 185, 243 },
+	{ 190, 178 }, { 193, 184 }, { 196, 185 }, { 198, 186 },
+	{ 200, 174 }, { 201, 175 }, { 205, 176 }, { 206, 177 },
+	{ 208, 187 }, { 210, 198 }, { 211, 199 }, { 212, 204 },
+	{ 215, 205 }, { 220, 188 }, { 221, 194 }, { 223, 195 },
+	{ 225, 196 }, { 227, 197 },
 };
 
 static struct msm_pinctrl_soc_data sc8280xp_pinctrl = {
Signature · 1 line
2.53.0
author maintainer
#21 lore raw

PATCH 22/337 dmaengine: sun6i-dma: Fix reclaim descriptors while terminating DMA

In reply to Greg Kroah-Hartman

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

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

From: Hongling Zeng <[email protected]>

[ Upstream commit ab1150115e68a46b687eb38c1ab92782018c9f2c ]

When terminating DMA transfers, active descriptors are not properly reclaimed. Only cyclic descriptors were handled, leaving non-cyclic descriptors and their LLI chains to be permanently leaked.

Fix by using vchan_terminate_vdesc() which handles both cyclic and non-cyclic descriptors by adding them to desc_terminated queue for proper cleanup.

Add pchan->desc != pchan->done check to prevent double-adding completed descriptors, which would corrupt the list.

Fixes 555859308723 ("dmaengine: sun6i: Add driver for the Allwinner A31 DMA controller")
---
 drivers/dma/sun6i-dma.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/dma/sun6i-dma.c +4 -7
index c97027379263d..1f1e21d48ad76 100644
@@ -934,16 +934,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
 
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
-	if (vchan->cyclic) {
-		vchan->cyclic = false;
-		if (pchan && pchan->desc) {
-			struct virt_dma_desc *vd = &pchan->desc->vd;
-			struct virt_dma_chan *vc = &vchan->vc;
+	if (pchan && pchan->desc && pchan->desc != pchan->done) {
+		struct virt_dma_desc *vd = &pchan->desc->vd;
 
-			list_add_tail(&vd->node, &vc->desc_completed);
-		}
+		vchan_terminate_vdesc(vd);
 	}
 
+	vchan->cyclic = false;
 	vchan_get_all_descriptors(&vchan->vc, &head);
 
 	if (pchan) {
Signature · 1 line
2.53.0
author maintainer
#22 lore raw

PATCH 23/337 dmaengine: idxd: fix fdev setup failure cleanup in idxd_cdev_open()

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit ee1d7274102285d78a53161fc705a8d8cd40b066 ]

The failed_dev_add and failed_dev_name paths drop the file-device reference while wq->wq_lock is still held. If put_device(fdev) drops the last reference, idxd_file_dev_release() runs synchronously and tries to take wq->wq_lock again, deadlocking.

Those paths also fall through into the later ctx cleanup labels even though idxd_file_dev_release() owns that cleanup and frees ctx. This can make idxd_xa_pasid_remove(ctx) and kfree(ctx) operate on a freed context.

Move idxd_wq_get() before file-device setup can fail, since the release callback always calls idxd_wq_put(). Then unlock wq->wq_lock before put_device(fdev) and return directly from the file-device setup failure path, leaving ctx cleanup to the release callback.

Fixes e6fd6d7e5f0fe ("dmaengine: idxd: add a device to represent the file opened")
---
 drivers/dma/idxd/cdev.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/dma/idxd/cdev.c +3 -1
index 8dcd2331bb1ac..14b322ac6e6c6 100644
@@ -293,6 +293,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
 	fdev->parent = cdev_dev(idxd_cdev);
 	fdev->bus = &dsa_bus_type;
 	fdev->type = &idxd_cdev_file_type;
+	idxd_wq_get(wq);
 
 	rc = dev_set_name(fdev, "file%d", ctx->id);
 	if (rc < 0) {
@@ -306,13 +307,14 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
 		goto failed_dev_add;
 	}
 
-	idxd_wq_get(wq);
 	mutex_unlock(&wq->wq_lock);
 	return 0;
 
 failed_dev_add:
 failed_dev_name:
+	mutex_unlock(&wq->wq_lock);
 	put_device(fdev);
+	return rc;
 failed_ida:
 failed_set_pasid:
 	if (device_user_pasid_enabled(idxd))
Signature · 1 line
2.53.0
author maintainer
#23 lore raw

PATCH 24/337 gpio: sloppy-logic-analyzer: Fix memory leak in gpio_la_poll_probe()

In reply to Greg Kroah-Hartman

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

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

From: Abdun Nihaal <[email protected]>

[ Upstream commit 7a7baebd9f23ba4f24796775472b2fd00dcd95d9 ]

The memory allocated for priv->blob.data is not freed in the error paths that follow the fops_buf_size_set() call in gpio_la_poll_probe(), as well as in the remove function. Fix that by using device managed action to free the memory on remove.

Fixes 7828b7bbbf20 ("gpio: add sloppy logic analyzer using polling")
---
 drivers/gpio/gpio-sloppy-logic-analyzer.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/gpio/gpio-sloppy-logic-analyzer.c +10 -0
index 59a8f3a5c4e48..9c526aeadeba5 100644
@@ -161,6 +161,13 @@ static int fops_buf_size_get(void *data, u64 *val)
 	return 0;
 }
 
+static void fops_buf_release(void *data)
+{
+	struct gpio_la_poll_priv *priv = data;
+
+	vfree(priv->blob.data);
+}
+
 static int fops_buf_size_set(void *data, u64 val)
 {
 	struct gpio_la_poll_priv *priv = data;
@@ -239,6 +246,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
 		return ret;
 
 	fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);
+	ret = devm_add_action_or_reset(dev, fops_buf_release, priv);
+	if (ret)
+		return ret;
 
 	priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN);
 	if (IS_ERR(priv->descs))
Signature · 1 line
2.53.0
author maintainer
#24 lore raw

PATCH 25/337 ata: sata_mv: accept 1 or 2 resources in platform probe

In reply to Greg Kroah-Hartman

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

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

From: Rosen Penev <[email protected]>

[ Upstream commit ef19a9cf037957fe3a35df8355c76ff0a63a0436 ]

Board files in arch/arm/plat-orion, arch/arm/mach-dove, arch/arm/mach-mv78xx0 and arch/arm/mach-orion5x still register the "sata_mv" device with two resources (IORESOURCE_MEM plus IORESOURCE_IRQ). Those devices are rejected with -EINVAL, so SATA no longer probes on legacy Marvell Orion/Kirkwood-style boards.

Accept both 1 resource (DT, IRQ fetched via platform_get_irq()) and 2 resources (legacy, IRQ supplied as a second resource) so both probing paths work.

Fixes b3b2bec9646e ("ata: sata_mv: Fixes expected number of resources now IRQs are gone")
Assisted-by opencode:big-pickle
---
 drivers/ata/sata_mv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ata/sata_mv.c +1 -1
index 05c905827dc5c..40fdc422940dd 100644
@@ -4026,7 +4026,7 @@ static int mv_platform_probe(struct platform_device *pdev)
 	/*
 	 * Simple resource validation ..
 	 */
-	if (unlikely(pdev->num_resources != 1)) {
+	if (unlikely(pdev->num_resources != 1 && pdev->num_resources != 2)) {
 		dev_err(&pdev->dev, "invalid number of resources\n");
 		return -EINVAL;
 	}
Signature · 1 line
2.53.0
author maintainer
#25 lore raw

PATCH 26/337 ata: libahci_platform: support non-consecutive port numbers

In reply to Greg Kroah-Hartman

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

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

From: Josua Mayer <[email protected]>

[ Upstream commit 8c87215dd3a2c814dcffc0bafe8c80c8f98f2574 ]

So far ahci_platform relied on number of child nodes in firmware to allocate arrays and expected port numbers to start from 0 without holes. This number of ports is then set in private structure for use when configuring phys and regulators.

Some platforms may not use every port of an ahci controller. E.g. SolidRUN CN9130 Clearfog uses only port 1 but not port 0, leading to the following errors during boot:

[    1.719476] ahci f2540000.sata: invalid port number 1
[    1.724562] ahci f2540000.sata: No port enabled

Update all accessesors of ahci_host_priv phys and target_pwrs arrays to support holes. Access is gated by hpriv->mask_port_map which has a bit set for each enabled port.

Update ahci_platform_get_resources to ignore holes in the port numbers and enable ports defined in firmware by their reg property only.

When firmware does not define children it is assumed that there is exactly one port, using index 0.

Stable-dep-of: 4d99a91574c4 ("ata: ahci_ceva: fix error paths in ceva_ahci_platform_enable_resources()")

---
 drivers/ata/ahci_brcm.c        |  3 +++
 drivers/ata/ahci_ceva.c        |  6 +++++
 drivers/ata/libahci_platform.c | 40 +++++++++++++++++++++++++++++-----
 3 files changed, 43 insertions(+), 6 deletions(-)
drivers/ata/ahci_brcm.c +3 -0
index 2f16524c25262..60505e1e247ab 100644
@@ -288,6 +288,9 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev,
 
 	/* Re-initialize and calibrate the PHY */
 	for (i = 0; i < hpriv->nports; i++) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		rc = phy_init(hpriv->phys[i]);
 		if (rc)
 			goto disable_phys;
drivers/ata/ahci_ceva.c +6 -0
index 11a2c199a7c24..6e115da23d3f0 100644
@@ -206,6 +206,9 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 		goto disable_clks;
 
 	for (i = 0; i < hpriv->nports; i++) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		rc = phy_init(hpriv->phys[i]);
 		if (rc)
 			goto disable_rsts;
@@ -215,6 +218,9 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 	ahci_platform_deassert_rsts(hpriv);
 
 	for (i = 0; i < hpriv->nports; i++) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		rc = phy_power_on(hpriv->phys[i]);
 		if (rc) {
 			phy_exit(hpriv->phys[i]);
drivers/ata/libahci_platform.c +34 -6
index 7a8064520a35b..b68777841f7a5 100644
@@ -49,6 +49,9 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
 	int rc, i;
 
 	for (i = 0; i < hpriv->nports; i++) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		rc = phy_init(hpriv->phys[i]);
 		if (rc)
 			goto disable_phys;
@@ -70,6 +73,9 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
 
 disable_phys:
 	while (--i >= 0) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		phy_power_off(hpriv->phys[i]);
 		phy_exit(hpriv->phys[i]);
 	}
@@ -88,6 +94,9 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
 	int i;
 
 	for (i = 0; i < hpriv->nports; i++) {
+		if (!(hpriv->mask_port_map & (1 << i)))
+			continue;
+
 		phy_power_off(hpriv->phys[i]);
 		phy_exit(hpriv->phys[i]);
 	}
@@ -432,6 +441,20 @@ static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
 	return 0;
 }
 
+static u32 ahci_platform_find_max_port_id(struct device *dev)
+{
+	u32 max_port = 0;
+
+	for_each_child_of_node_scoped(dev->of_node, child) {
+		u32 port;
+
+		if (!of_property_read_u32(child, "reg", &port))
+			max_port = max(max_port, port);
+	}
+
+	return max_port;
+}
+
 /**
  * ahci_platform_get_resources - Get platform resources
  * @pdev: platform device to get resources for
@@ -458,6 +481,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 	struct device *dev = &pdev->dev;
 	struct ahci_host_priv *hpriv;
 	u32 mask_port_map = 0;
+	u32 max_port;
 
 	if (!devres_open_group(dev, NULL, GFP_KERNEL))
 		return ERR_PTR(-ENOMEM);
@@ -549,15 +573,17 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		goto err_out;
 	}
 
+	/* find maximum port id for allocating structures */
+	max_port = ahci_platform_find_max_port_id(dev);
 	/*
-	 * If no sub-node was found, we still need to set nports to
-	 * one in order to be able to use the
+	 * Set nports according to maximum port id. Clamp at
+	 * AHCI_MAX_PORTS, warning message for invalid port id
+	 * is generated later.
+	 * When DT has no sub-nodes max_port is 0, nports is 1,
+	 * in order to be able to use the
 	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
 	 */
-	if (child_nodes)
-		hpriv->nports = child_nodes;
-	else
-		hpriv->nports = 1;
+	hpriv->nports = min(AHCI_MAX_PORTS, max_port + 1);
 
 	hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
 	if (!hpriv->phys) {
@@ -625,6 +651,8 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		 * If no sub-node was found, keep this for device tree
 		 * compatibility
 		 */
+		hpriv->mask_port_map |= BIT(0);
+
 		rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
 		if (rc)
 			goto err_out;
Signature · 1 line
2.53.0
author maintainer
#26 lore raw

PATCH 27/337 ahci: Introduce ahci_ignore_port() helper

In reply to Greg Kroah-Hartman

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

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

From: Damien Le Moal <[email protected]>

[ Upstream commit c9b5be909e6595547ed5d45aef39fd65948aa342 ]

libahci and AHCI drivers may ignore some ports if the port is invalid (its ID does not correspond to a valid physical port) or if the user explicitly requested the port to be ignored with the mask_port_map ahci module parameter. Such port that shall be ignored can be identified by checking that the bit corresponding to the port ID is not set in the mask_port_map field of struct ahci_host_priv. E.g. code such as:
"if (!(hpriv->mask_port_map & (1 << portid)))".

Replace all direct use of the mask_port_map field to detect such port with the new helper inline function ahci_ignore_port() to make the code more readable/easier to understand.

The comment describing the mask_port_map field of struct ahci_host_priv is also updated to be more accurate.

Stable-dep-of: 4d99a91574c4 ("ata: ahci_ceva: fix error paths in ceva_ahci_platform_enable_resources()")

---
 drivers/ata/ahci.h             | 13 ++++++++++++-
 drivers/ata/ahci_brcm.c        |  2 +-
 drivers/ata/ahci_ceva.c        |  4 ++--
 drivers/ata/libahci_platform.c |  6 +++---
 4 files changed, 18 insertions(+), 7 deletions(-)
drivers/ata/ahci.h +12 -1
index 10a5fe02f0a45..5814245e43ceb 100644
@@ -329,7 +329,7 @@ struct ahci_port_priv {
 struct ahci_host_priv {
 	/* Input fields */
 	unsigned int		flags;		/* AHCI_HFLAG_* */
-	u32			mask_port_map;	/* mask out particular bits */
+	u32			mask_port_map;	/* Mask of valid ports */
 
 	void __iomem *		mmio;		/* bus-independent mem map */
 	u32			cap;		/* cap to use */
@@ -380,6 +380,17 @@ struct ahci_host_priv {
 						  int port);
 };
 
+/*
+ * Return true if a port should be ignored because it is excluded from
+ * the host port map.
+ */
+static inline bool ahci_ignore_port(struct ahci_host_priv *hpriv,
+				    unsigned int portid)
+{
+	return portid >= hpriv->nports ||
+		!(hpriv->mask_port_map & (1 << portid));
+}
+
 extern int ahci_ignore_sss;
 
 extern const struct attribute_group *ahci_shost_groups[];
drivers/ata/ahci_brcm.c +1 -1
index 60505e1e247ab..12bb0c2f914e7 100644
@@ -288,7 +288,7 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev,
 
 	/* Re-initialize and calibrate the PHY */
 	for (i = 0; i < hpriv->nports; i++) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		rc = phy_init(hpriv->phys[i]);
drivers/ata/ahci_ceva.c +2 -2
index 6e115da23d3f0..93275b1b48898 100644
@@ -206,7 +206,7 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 		goto disable_clks;
 
 	for (i = 0; i < hpriv->nports; i++) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		rc = phy_init(hpriv->phys[i]);
@@ -218,7 +218,7 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 	ahci_platform_deassert_rsts(hpriv);
 
 	for (i = 0; i < hpriv->nports; i++) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		rc = phy_power_on(hpriv->phys[i]);
drivers/ata/libahci_platform.c +3 -3
index b68777841f7a5..53b2c7719dc51 100644
@@ -49,7 +49,7 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
 	int rc, i;
 
 	for (i = 0; i < hpriv->nports; i++) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		rc = phy_init(hpriv->phys[i]);
@@ -73,7 +73,7 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
 
 disable_phys:
 	while (--i >= 0) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		phy_power_off(hpriv->phys[i]);
@@ -94,7 +94,7 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
 	int i;
 
 	for (i = 0; i < hpriv->nports; i++) {
-		if (!(hpriv->mask_port_map & (1 << i)))
+		if (ahci_ignore_port(hpriv, i))
 			continue;
 
 		phy_power_off(hpriv->phys[i]);
Signature · 1 line
2.53.0
author maintainer
#27 lore raw

PATCH 28/337 ata: ahci_ceva: fix error paths in ceva_ahci_platform_enable_resources()

In reply to Greg Kroah-Hartman

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

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

From: Radhey Shyam Pandey <[email protected]>

[ Upstream commit 4d99a91574c420decab56cc880fad0dc15b8a7a3 ]

On phy_init() failure the error path fallsthrough to disable_rsts, which deasserts the controller reset and then enters disable_phys calling phy_power_off() on PHYs that were never powered on. That corrupts the PHY power_count and triggers an extra runtime PM put.

Use a separate exit_phys path that unwinds with phy_exit() only and falls through to disable_clks while the controller remains in reset. Reserve phy_power_off() for the phy_power_on() failure path only, and skip masked-out ports in both unwind loops.

On phy_power_on() failure re-assert the controller reset before disabling clocks and regulators, matching the teardown order used by ahci_platform_enable_resources() and ahci_platform_disable_resources().

Fixes 26c8404e162b ("ata: ahci_ceva: fix error handling for Xilinx GT PHY support")
---
 drivers/ata/ahci_ceva.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/ata/ahci_ceva.c +14 -4
index 93275b1b48898..b2918ad8e7e05 100644
@@ -211,7 +211,7 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 
 		rc = phy_init(hpriv->phys[i]);
 		if (rc)
-			goto disable_rsts;
+			goto exit_phys;
 	}
 
 	/* De-assert the controller reset */
@@ -230,14 +230,24 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 
 	return 0;
 
-disable_rsts:
-	ahci_platform_deassert_rsts(hpriv);
-
 disable_phys:
 	while (--i >= 0) {
+		if (ahci_ignore_port(hpriv, i))
+			continue;
+
 		phy_power_off(hpriv->phys[i]);
 		phy_exit(hpriv->phys[i]);
 	}
+	ahci_platform_assert_rsts(hpriv);
+	goto disable_clks;
+
+exit_phys:
+	while (--i >= 0) {
+		if (ahci_ignore_port(hpriv, i))
+			continue;
+
+		phy_exit(hpriv->phys[i]);
+	}
 
 disable_clks:
 	ahci_platform_disable_clks(hpriv);
Signature · 1 line
2.53.0
author maintainer
#28 lore raw

PATCH 29/337 ASoC: max98095: fix missing IS_ERR() before PTR_ERR() on mclk lookup

In reply to Greg Kroah-Hartman

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

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

From: Uday Khare <[email protected]>

[ Upstream commit 317e21532e6ffa1de026bdbce5ba98e1b70ca5c6 ]

In max98095_probe(), the -EPROBE_DEFER check after devm_clk_get() is broken due to a missing IS_ERR() guard.

The code intends to return -EPROBE_DEFER only when the clock lookup fails with that specific error. However, without IS_ERR() the check:

    if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)

is called unconditionally, including when devm_clk_get() succeeds and returns a valid pointer. Calling PTR_ERR() on a valid pointer reinterprets its address as a signed long; the result is arbitrary and is almost never equal to -EPROBE_DEFER, so the check silently does nothing in the success case. When devm_clk_get() fails with any error other than -EPROBE_DEFER the check is also skipped, leaving max98095->mclk holding an error pointer with no indication to the caller.

This means a deferred probe will never actually be triggered for this device, and any non-EPROBE_DEFER clock error is silently swallowed with the error pointer left in the mclk field.

Fix this by adding the missing IS_ERR() guard around the PTR_ERR() call, matching the pattern already used in the sibling max98088 and wm8960 drivers.

Fixes e3048c3d2be5 ("ASoC: max98095: Add master clock handling")
---
 sound/soc/codecs/max98095.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
sound/soc/codecs/max98095.c +3 -2
index 7e525d49328d2..3b37f4c4235e6 100644
@@ -1984,8 +1984,9 @@ static int max98095_probe(struct snd_soc_component *component)
 	int ret = 0;
 
 	max98095->mclk = devm_clk_get(component->dev, "mclk");
-	if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
+	if (IS_ERR(max98095->mclk))
+		if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
 
 	/* reset the codec, the DSP core, and disable all interrupts */
 	max98095_reset(component);
Signature · 1 line
2.53.0
author maintainer
#29 lore raw

PATCH 30/337 ASoC: max98090: fix missing IS_ERR() before PTR_ERR() on mclk lookup

In reply to Greg Kroah-Hartman

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

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

From: Uday Khare <[email protected]>

[ Upstream commit a792ce0fad61a70793ec565743f11d6ca534de59 ]

In max98090_probe(), the -EPROBE_DEFER check after devm_clk_get() is broken due to a missing IS_ERR() guard.

The code intends to return -EPROBE_DEFER only when the clock lookup fails with that specific error. However, without IS_ERR() the check:

    if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)

is called unconditionally, including when devm_clk_get() succeeds and returns a valid pointer. Calling PTR_ERR() on a valid pointer reinterprets its address as a signed long; the result is arbitrary and is almost never equal to -EPROBE_DEFER, so the check silently does nothing in the success case. When devm_clk_get() fails with any error other than -EPROBE_DEFER the check is also skipped, leaving max98090->mclk holding an error pointer with no indication to the caller.

This means a deferred probe will never actually be triggered for this device, and any non-EPROBE_DEFER clock error is silently swallowed with the error pointer left in the mclk field.

Fix this by adding the missing IS_ERR() guard around the PTR_ERR() call, matching the pattern already used in the sibling max98088 and wm8960 drivers.

Fixes b10ab7b838bd ("ASoC: max98090: Add master clock handling")
---
 sound/soc/codecs/max98090.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
sound/soc/codecs/max98090.c +3 -2
index 4023b88e7bc13..9253707bccde9 100644
@@ -2388,8 +2388,9 @@ static int max98090_probe(struct snd_soc_component *component)
 	dev_dbg(component->dev, "max98090_probe\n");
 
 	max98090->mclk = devm_clk_get(component->dev, "mclk");
-	if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
+	if (IS_ERR(max98090->mclk))
+		if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
 
 	max98090->component = component;
 
Signature · 1 line
2.53.0
author maintainer
#30 lore raw

PATCH 31/337 of: reserved_mem: Add code to dynamically allocate reserved_mem array

In reply to Greg Kroah-Hartman

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

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

From: Oreoluwa Babatunde <[email protected]>

[ Upstream commit 00c9a452a235c61f099504783badd9a7675ff5a5 ]

The reserved_mem array is statically allocated with a size of MAX_RESERVED_REGIONS(64). Therefore, if the number of reserved_mem regions exceeds this size, there will not be enough space to store all the data.

Hence, extend the use of the static array by introducing a dynamically allocated array based on the number of reserved memory regions specified in the DT.

On architectures such as arm64, memblock allocated memory is not writable until after the page tables have been setup. Hence, the dynamic allocation of the reserved_mem array will need to be done only after the page tables have been setup.

As a result, a temporary static array is still needed in the initial stages to store the information of the dynamically-placed reserved memory regions because the start address is selected only at run-time and is not stored anywhere else.
It is not possible to wait until the reserved_mem array is allocated because this is done after the page tables are setup and the reserved memory regions need to be initialized before then.

After the reserved_mem array is allocated, all entries from the static array is copied over to the new array, and the rest of the information for the statically-placed reserved memory regions are read in from the DT and stored in the new array as well.

Once the init process is completed, the temporary static array is released back to the system because it is no longer needed. This is achieved by marking it as __initdata.

Stable-dep-of: db3dbdfea1b8 ("of: reserved_mem: prevent OOB when too many dynamic regions are defined")

---
 drivers/of/of_reserved_mem.c | 63 +++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)
drivers/of/of_reserved_mem.c +59 -4
index 7b5d6562fe4a0..02d3c3284f886 100644
@@ -28,7 +28,9 @@
 
 #include "of_private.h"
 
-static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static struct reserved_mem reserved_mem_array[MAX_RESERVED_REGIONS] __initdata;
+static struct reserved_mem *reserved_mem __refdata = reserved_mem_array;
+static int total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
 static int reserved_mem_count;
 
 static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
@@ -57,6 +59,50 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
 	return err;
 }
 
+/*
+ * alloc_reserved_mem_array() - allocate memory for the reserved_mem
+ * array using memblock
+ *
+ * This function is used to allocate memory for the reserved_mem
+ * array according to the total number of reserved memory regions
+ * defined in the DT.
+ * After the new array is allocated, the information stored in
+ * the initial static array is copied over to this new array and
+ * the new array is used from this point on.
+ */
+static void __init alloc_reserved_mem_array(void)
+{
+	struct reserved_mem *new_array;
+	size_t alloc_size, copy_size, memset_size;
+
+	alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
+	if (alloc_size == SIZE_MAX) {
+		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
+		return;
+	}
+
+	new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
+	if (!new_array) {
+		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
+		return;
+	}
+
+	copy_size = array_size(reserved_mem_count, sizeof(*new_array));
+	if (copy_size == SIZE_MAX) {
+		memblock_free(new_array, alloc_size);
+		total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
+		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
+		return;
+	}
+
+	memset_size = alloc_size - copy_size;
+
+	memcpy(new_array, reserved_mem, copy_size);
+	memset(new_array + reserved_mem_count, 0, memset_size);
+
+	reserved_mem = new_array;
+}
+
 static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem);
 /*
  * fdt_reserved_mem_save_node() - save fdt node for second pass initialization
@@ -66,7 +112,7 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un
 {
 	struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
 
-	if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
+	if (reserved_mem_count == total_reserved_mem_cnt) {
 		pr_err("not enough space for all defined regions.\n");
 		return;
 	}
@@ -199,6 +245,9 @@ void __init fdt_scan_reserved_mem_reg_nodes(void)
 		return;
 	}
 
+	/* Attempt dynamic allocation of a new reserved_mem array */
+	alloc_reserved_mem_array();
+
 	if (__reserved_mem_check_root(node)) {
 		pr_err("Reserved memory: unsupported node format, ignoring\n");
 		return;
@@ -243,7 +292,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam
 int __init fdt_scan_reserved_mem(void)
 {
 	int node, child;
-	int dynamic_nodes_cnt = 0;
+	int dynamic_nodes_cnt = 0, count = 0;
 	int dynamic_nodes[MAX_RESERVED_REGIONS];
 	const void *fdt = initial_boot_params;
 
@@ -266,6 +315,8 @@ int __init fdt_scan_reserved_mem(void)
 		uname = fdt_get_name(fdt, child, NULL);
 
 		err = __reserved_mem_reserve_reg(child, uname);
+		if (!err)
+			count++;
 		/*
 		 * Save the nodes for the dynamically-placed regions
 		 * into an array which will be used for allocation right
@@ -280,11 +331,15 @@ int __init fdt_scan_reserved_mem(void)
 	}
 	for (int i = 0; i < dynamic_nodes_cnt; i++) {
 		const char *uname;
+		int err;
 
 		child = dynamic_nodes[i];
 		uname = fdt_get_name(fdt, child, NULL);
-		__reserved_mem_alloc_size(child, uname);
+		err = __reserved_mem_alloc_size(child, uname);
+		if (!err)
+			count++;
 	}
+	total_reserved_mem_cnt = count;
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#31 lore raw

PATCH 32/337 of: reserved_mem: prevent OOB when too many dynamic regions are defined

In reply to Greg Kroah-Hartman

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

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

From: Sang-Heon Jeon <[email protected]>

[ Upstream commit db3dbdfea1b8f38774419c5c2c14e4b81c48708d ]

On boot, fdt_scan_reserved_mem() saves each dynamically-placed /reserved-memory subnode into a local array of size MAX_RESERVED_REGIONS.

If the device tree defines more than MAX_RESERVED_REGIONS dynamically-placed regions, fdt_scan_reserved_mem() writes past the end of the local array.

Add a bounds check that logs an error and skips the excess regions, restoring the original behavior.

Fixes 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed")
---
 drivers/of/of_reserved_mem.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/of/of_reserved_mem.c +11 -3
index 02d3c3284f886..9f4f0306b834f 100644
@@ -317,6 +317,7 @@ int __init fdt_scan_reserved_mem(void)
 		err = __reserved_mem_reserve_reg(child, uname);
 		if (!err)
 			count++;
+
 		/*
 		 * Save the nodes for the dynamically-placed regions
 		 * into an array which will be used for allocation right
@@ -324,10 +325,17 @@ int __init fdt_scan_reserved_mem(void)
 		 * or marked as no-map. This is done to avoid dynamically
 		 * allocating from one of the statically-placed regions.
 		 */
-		if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) {
-			dynamic_nodes[dynamic_nodes_cnt] = child;
-			dynamic_nodes_cnt++;
+		if (err != -ENOENT || !of_get_flat_dt_prop(child, "size", NULL))
+			continue;
+
+		if (dynamic_nodes_cnt == MAX_RESERVED_REGIONS) {
+			pr_err("too many defined dynamic regions, skip '%s'\n",
+			       uname);
+			continue;
 		}
+
+		dynamic_nodes[dynamic_nodes_cnt] = child;
+		dynamic_nodes_cnt++;
 	}
 	for (int i = 0; i < dynamic_nodes_cnt; i++) {
 		const char *uname;
Signature · 1 line
2.53.0
author maintainer
#32 lore raw

PATCH 33/337 btrfs: fix leaking BTRFS_FS_STATE_REMOUNTING flag

In reply to Greg Kroah-Hartman

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

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

From: Qu Wenruo <[email protected]>

[ Upstream commit 6881f45d0eb541f2cee8c37c84b3860a23823bb3 ]

[BUG]
The following script can lead to unexpected qgroup rescan failure:

  # mkfs.btrfs -f -O quota $dev
  # mount $dev $mnt
  # mount -o remount,rescue=ibadroots $mnt
    ^^^^^ This above command is expected to fail
  # btrfs quota rescan -w $mnt
    ^^^^^ The above qgroup rescan is not expected to fail
  # btrfs qgroup show $mnt
  WARNING: qgroup data inconsistent, rescan recommended
  Qgroupid    Referenced    Exclusive   Path
  --------    ----------    ---------   ----
  0/5           16.00KiB     16.00KiB   <toplevel>

The above short script will be converted to a proper fstests case.

[CAUSE]
Inside btrfs_reconfigure(), if either btrfs_check_options() or btrfs_check_features() failed, we will always have BTRFS_FS_STATE_REMOUNTING set for the fs until the next successful remount.

That BTRFS_FS_STATE_REMOUNTING flag will interrupt several operations, including:

- Qgroup rescan
- Auto defrag
- Space reclaim

[FIX]
Change the error handling of btrfs_check_options() and btrfs_check_features() to goto restore label.

Fixes eddb1a433f26 ("btrfs: add reconfigure callback for fs_context")
---
 fs/btrfs/super.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
fs/btrfs/super.c +5 -3
index 21419bc33863b..c8ad43f94db0d 100644
@@ -1509,12 +1509,14 @@ static int btrfs_reconfigure(struct fs_context *fc)
 	sync_filesystem(sb);
 	set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
 
-	if (!btrfs_check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
-		return -EINVAL;
+	if (!btrfs_check_options(fs_info, &ctx->mount_opt, fc->sb_flags)) {
+		ret = -EINVAL;
+		goto restore;
+	}
 
 	ret = btrfs_check_features(fs_info, !(fc->sb_flags & SB_RDONLY));
 	if (ret < 0)
-		return ret;
+		goto restore;
 
 	btrfs_ctx_to_info(fs_info, ctx);
 	btrfs_remount_begin(fs_info, old_ctx.mount_opt, fc->sb_flags);
Signature · 1 line
2.53.0
author maintainer
#33 lore raw

PATCH 34/337 btrfs: zoned: fix deadlock between metadata writeback and transaction commit

In reply to Greg Kroah-Hartman

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

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

From: Johannes Thumshirn <[email protected]>

[ Upstream commit 1ebe51c29fa9755d5b2fea28727c051117907cf8 ]

When writing out metadata extent buffers in a zoned filesystem, btree_writepages() holds fs_info->zoned_meta_io_lock across the whole writeback loop, including the call to btrfs_check_meta_write_pointer() -> check_bg_is_active().

For the tree-log block group, check_bg_is_active() may fail to activate the zone and fall back to btrfs_zone_finish_one_bg() to free an active zone. That path waits for the running transaction to commit while still holding zoned_meta_io_lock, but the committer needs that same lock to write out the tree extents, so the two tasks deadlock:

  Task A (kworker, metadata writeback)      Task B (fsstress, transaction commit)
  ------------------------------------      -------------------------------------
  wb_workfn()                               btrfs_commit_transaction(T)

btree_writepages() btrfs_write_and_wait_transaction()
btrfs_zoned_meta_io_lock() btrfs_write_marked_extents()
btrfs_check_meta_write_pointer() btree_writepages()
check_bg_is_active() [treelog_bg] btrfs_zoned_meta_io_lock()
btrfs_zone_finish_one_bg() <blocks on zoned_meta_io_lock,
btrfs_zone_finish() held by Task A>
do_zone_finish()
btrfs_inc_block_group_ro()
btrfs_wait_for_commit()
<blocks waiting for commit
of transaction T, done by
Task B>

The sibling branch in check_bg_is_active() already drops zoned_meta_io_lock around do_zone_finish() for this exact reason. Do the same in the tree-log
branch: release the lock around btrfs_zone_finish_one_bg() and re-acquire it afterwards. The lock only protects fs_info->active_{meta,system}_bg, which this branch does not touch, and ctx->zoned_bg keeps a reference to the block group across the unlock, so nothing is lost while the lock is dropped.

This hang occasionally reproduces with fstests generic/475 on a zoned btrfs filesystem.

Fixes 13bb483d32ab ("btrfs: zoned: activate metadata block group on write time")
---
 fs/btrfs/zoned.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
fs/btrfs/zoned.c +5 -1
index d9c26f4be6634..c64840b155974 100644
@@ -2122,7 +2122,11 @@ static bool check_bg_is_active(struct btrfs_eb_write_context *ctx,
 
 	if (fs_info->treelog_bg == block_group->start) {
 		if (!btrfs_zone_activate(block_group)) {
-			int ret_fin = btrfs_zone_finish_one_bg(fs_info);
+			int ret_fin;
+
+			btrfs_zoned_meta_io_unlock(fs_info);
+			ret_fin = btrfs_zone_finish_one_bg(fs_info);
+			btrfs_zoned_meta_io_lock(fs_info);
 
 			if (ret_fin != 1 || !btrfs_zone_activate(block_group))
 				return false;
Signature · 1 line
2.53.0
author maintainer
#34 lore raw

PATCH 35/337 phy-zynqmp: Postpone getting clock rate until actually needed

In reply to Greg Kroah-Hartman

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

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

From: Mike Looijmans <[email protected]>

[ Upstream commit 065d5885f6180c534b7b176847b3e008f4e11850 ]

At probe time the driver would display the following error and abort:
xilinx-psgtr fd400000.phy: Invalid rate 0 for reference clock 0

At probe time, the associated GTR driver (e.g. SATA or PCIe) hasn't initialized the clock yet, so clk_get_rate() likely returns 0 if the clock is programmable. So this driver only works if the clock is fixed.

The PHY driver doesn't need to know the clock frequency at probe yet, so wait until the associated driver initializes the lane before requesting the clock rate setting.

In addition to allowing the driver to be used with programmable clocks, this also reduces the driver's runtime memory footprint by removing an array of pointers from struct xpsgtr_phy.

Stable-dep-of: e4779e2a16d6 ("phy: zynqmp: fix clock error handling in xpsgtr_phy_init()")

---
 drivers/phy/xilinx/phy-zynqmp.c | 70 +++++++++++++++++----------------
 1 file changed, 37 insertions(+), 33 deletions(-)
drivers/phy/xilinx/phy-zynqmp.c +37 -33
index e6579002f1146..6fcbdff760b32 100644
@@ -222,7 +222,6 @@ struct xpsgtr_phy {
  * @siou: siou base address
  * @gtr_mutex: mutex for locking
  * @phys: PHY lanes
- * @refclk_sscs: spread spectrum settings for the reference clocks
  * @clk: reference clocks
  * @tx_term_fix: fix for GT issue
  * @saved_icm_cfg0: stored value of ICM CFG0 register
@@ -235,7 +234,6 @@ struct xpsgtr_dev {
 	void __iomem *siou;
 	struct mutex gtr_mutex; /* mutex for locking */
 	struct xpsgtr_phy phys[NUM_LANES];
-	const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
 	struct clk *clk[NUM_LANES];
 	bool tx_term_fix;
 	unsigned int saved_icm_cfg0;
@@ -398,13 +396,40 @@ static int xpsgtr_wait_pll_lock(struct phy *phy)
 	return ret;
 }
 
+/* Get the spread spectrum (SSC) settings for the reference clock rate */
+static const struct xpsgtr_ssc *xpsgtr_find_sscs(struct xpsgtr_phy *gtr_phy)
+{
+	unsigned long rate;
+	struct clk *clk;
+	unsigned int i;
+
+	clk = gtr_phy->dev->clk[gtr_phy->refclk];
+	rate = clk_get_rate(clk);
+
+	for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
+		/* Allow an error of 100 ppm */
+		unsigned long error = ssc_lookup[i].refclk_rate / 10000;
+
+		if (abs(rate - ssc_lookup[i].refclk_rate) < error)
+			return &ssc_lookup[i];
+	}
+
+	dev_err(gtr_phy->dev->dev, "Invalid rate %lu for reference clock %u\n",
+		rate, gtr_phy->refclk);
+
+	return NULL;
+}
+
 /* Configure PLL and spread-sprectrum clock. */
-static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
+static int xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
 {
 	const struct xpsgtr_ssc *ssc;
 	u32 step_size;
 
-	ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk];
+	ssc = xpsgtr_find_sscs(gtr_phy);
+	if (!ssc)
+		return -EINVAL;
+
 	step_size = ssc->step_size;
 
 	xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane),
@@ -446,6 +471,8 @@ static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB,
 			   STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) |
 			   FORCE_STEP_SIZE | FORCE_STEPS);
+
+	return 0;
 }
 
 /* Configure the lane protocol. */
@@ -658,7 +685,10 @@ static int xpsgtr_phy_init(struct phy *phy)
 	 * Configure the PLL, the lane protocol, and perform protocol-specific
 	 * initialization.
 	 */
-	xpsgtr_configure_pll(gtr_phy);
+	ret = xpsgtr_configure_pll(gtr_phy);
+	if (ret)
+		goto out;
+
 	xpsgtr_lane_set_protocol(gtr_phy);
 
 	switch (gtr_phy->protocol) {
@@ -823,8 +853,7 @@ static struct phy *xpsgtr_xlate(struct device *dev,
 	}
 
 	refclk = args->args[3];
-	if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) ||
-	    !gtr_dev->refclk_sscs[refclk]) {
+	if (refclk >= ARRAY_SIZE(gtr_dev->clk)) {
 		dev_err(dev, "Invalid reference clock number %u\n", refclk);
 		return ERR_PTR(-EINVAL);
 	}
@@ -928,9 +957,7 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
 {
 	unsigned int refclk;
 
-	for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
-		unsigned long rate;
-		unsigned int i;
+	for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->clk); ++refclk) {
 		struct clk *clk;
 		char name[8];
 
@@ -946,29 +973,6 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
 			continue;
 
 		gtr_dev->clk[refclk] = clk;
-
-		/*
-		 * Get the spread spectrum (SSC) settings for the reference
-		 * clock rate.
-		 */
-		rate = clk_get_rate(clk);
-
-		for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
-			/* Allow an error of 100 ppm */
-			unsigned long error = ssc_lookup[i].refclk_rate / 10000;
-
-			if (abs(rate - ssc_lookup[i].refclk_rate) < error) {
-				gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i];
-				break;
-			}
-		}
-
-		if (i == ARRAY_SIZE(ssc_lookup)) {
-			dev_err(gtr_dev->dev,
-				"Invalid rate %lu for reference clock %u\n",
-				rate, refclk);
-			return -EINVAL;
-		}
 	}
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#35 lore raw

PATCH 36/337 phy: zynqmp: fix clock error handling in xpsgtr_phy_init()

In reply to Greg Kroah-Hartman

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

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

From: Radhey Shyam Pandey <[email protected]>

[ Upstream commit e4779e2a16d600892aaf743438f6ce8cc4eb3c4c ]

Propagate clk_prepare_enable() failures to the caller instead of returning success, and disable the reference clock on initialization error paths to avoid leaking clock references when phy_exit() is not called.

Fixes 25d700833513 ("phy: xilinx: phy-zynqmp: dynamic clock support for power-save")
---
 drivers/phy/xilinx/phy-zynqmp.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/phy/xilinx/phy-zynqmp.c +9 -4
index 6fcbdff760b32..5039b0e89cba4 100644
@@ -658,12 +658,13 @@ static int xpsgtr_phy_init(struct phy *phy)
 {
 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
-	int ret = 0;
+	int ret;
 
 	mutex_lock(&gtr_dev->gtr_mutex);
 
 	/* Configure and enable the clock when peripheral phy_init call */
-	if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
+	ret = clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]);
+	if (ret)
 		goto out;
 
 	/* Skip initialization if not required. */
@@ -673,7 +674,7 @@ static int xpsgtr_phy_init(struct phy *phy)
 	if (gtr_dev->tx_term_fix) {
 		ret = xpsgtr_phy_tx_term_fix(gtr_phy);
 		if (ret < 0)
-			goto out;
+			goto out_disable_clk;
 
 		gtr_dev->tx_term_fix = false;
 	}
@@ -687,7 +688,7 @@ static int xpsgtr_phy_init(struct phy *phy)
 	 */
 	ret = xpsgtr_configure_pll(gtr_phy);
 	if (ret)
-		goto out;
+		goto out_disable_clk;
 
 	xpsgtr_lane_set_protocol(gtr_phy);
 
@@ -705,6 +706,10 @@ static int xpsgtr_phy_init(struct phy *phy)
 		break;
 	}
 
+	goto out;
+
+out_disable_clk:
+	clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
 out:
 	mutex_unlock(&gtr_dev->gtr_mutex);
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#36 lore raw

PATCH 37/337 phy: zynqmp: fix runtime PM leak on probe allocation failure

In reply to Greg Kroah-Hartman

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

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

From: Radhey Shyam Pandey <[email protected]>

[ Upstream commit f3506e15cf72e94f62d5f2d173e5b7008f644cde ]

Allocate saved_regs before pm_runtime_resume_and_get() so a devm_kmalloc() failure does not leave an unreleased runtime PM usage counter.

Fixes 5af9b304bc60 ("phy: xilinx: phy-zynqmp: Fix SGMII linkup failure on resume")
---
 drivers/phy/xilinx/phy-zynqmp.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/phy/xilinx/phy-zynqmp.c +6 -6
index 5039b0e89cba4..1ec5722ac427c 100644
@@ -1044,6 +1044,12 @@ static int xpsgtr_probe(struct platform_device *pdev)
 		return PTR_ERR(provider);
 	}
 
+	gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
+					   sizeof(save_reg_address),
+					   GFP_KERNEL);
+	if (!gtr_dev->saved_regs)
+		return -ENOMEM;
+
 	pm_runtime_set_active(gtr_dev->dev);
 	pm_runtime_enable(gtr_dev->dev);
 
@@ -1053,12 +1059,6 @@ static int xpsgtr_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
-					   sizeof(save_reg_address),
-					   GFP_KERNEL);
-	if (!gtr_dev->saved_regs)
-		return -ENOMEM;
-
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#37 lore raw

PATCH 38/337 netfilter: nf_conntrack_sip: widen NAT rewrite delta to s32 in sip_help_tcp()

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei <[email protected]>

[ Upstream commit db3d0e0e5d4bc5ab4fe445b9f413d1b486508ca5 ]

sip_help_tcp() stores the size change of each NAT-rewritten SIP message in s16 diff and accumulates it in s16 tdiff, but a single message can grow by more than S16_MAX while the packet stays under the 65535 enlarge_skb() limit: nf_nat_sip() rewrites every matching URI, and a long Contact list expands the message by tens of kilobytes. diff then wraps, and "datalen = datalen + diff - msglen" yields a huge unsigned datalen, so the next iteration's ct_sip_get_header() reads past the linearized skb tail.

Widen diff, tdiff and the seq_adjust hook to s32. Both are bounded by the 65535 byte packet limit, and the seqadj core is already s32 (nf_ct_seqadj_set() takes s32), so no previously accepted input is rejected.

  BUG: KASAN: use-after-free in ct_sip_get_header (net/netfilter/nf_conntrack_sip.c:464)
  Read of size 1 at addr ffff888010800000 by task ksoftirqd/1/25
   ct_sip_get_header (net/netfilter/nf_conntrack_sip.c:464)
   sip_help_tcp (net/netfilter/nf_conntrack_sip.c:1694)
   nf_confirm (net/netfilter/nf_conntrack_proto.c:183)
   nf_hook_slow (net/netfilter/core.c:619)
   ip6_output (net/ipv6/ip6_output.c:246)
   ip6_forward (net/ipv6/ip6_output.c:690)
   ipv6_rcv (net/ipv6/ip6_input.c:351)
   __netif_receive_skb_one_core (net/core/dev.c:6212)
   process_backlog (net/core/dev.c:6676)
   __napi_poll (net/core/dev.c:7735)
   net_rx_action (net/core/dev.c:7955)
   handle_softirqs (kernel/softirq.c:622)
   run_ksoftirqd (kernel/softirq.c:1076)
   ...
Fixes f5b321bd37fb ("netfilter: nf_conntrack_sip: add TCP support")
Assisted-by Claude:claude-opus-4-8
---
 include/linux/netfilter/nf_conntrack_sip.h | 2 +-
 net/netfilter/nf_conntrack_sip.c           | 2 +-
 net/netfilter/nf_nat_sip.c                 | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
include/linux/netfilter/nf_conntrack_sip.h +1 -1
index dbc614dfe0d56..aafa0c04f917e 100644
@@ -115,7 +115,7 @@ struct nf_nat_sip_hooks {
 			    unsigned int *datalen);
 
 	void (*seq_adjust)(struct sk_buff *skb,
-			   unsigned int protoff, s16 off);
+			   unsigned int protoff, s32 off);
 
 	unsigned int (*expect)(struct sk_buff *skb,
 			       unsigned int protoff,
net/netfilter/nf_conntrack_sip.c +1 -1
index 852c0b74b8a77..4f975b83c84f6 100644
@@ -1629,7 +1629,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
 	unsigned int matchoff, matchlen;
 	unsigned int msglen, origlen;
 	const char *dptr, *end;
-	s16 diff, tdiff = 0;
+	s32 diff, tdiff = 0;
 	int ret = NF_ACCEPT;
 	unsigned long clen;
 	bool term;
net/netfilter/nf_nat_sip.c +1 -1
index f7be30c69b5c8..a1c41defaf22d 100644
@@ -315,7 +315,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
 }
 
 static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
-				  s16 off)
+				  s32 off)
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Signature · 1 line
2.53.0
author maintainer
#38 lore raw

PATCH 39/337 drm/mediatek: Check CRTC state before freeing

In reply to Greg Kroah-Hartman

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

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

From: Ruoyu Wang <[email protected]>

[ Upstream commit 233a4d3a39fc1585f5e271b2adab43c6af025ae0 ]

mtk_crtc_reset() destroys the current CRTC state only when crtc->state is non-NULL, but it always converts crtc->state to struct mtk_crtc_state and passes the result to kfree().

When reset is called without an existing state, container_of(NULL, ...) does not produce NULL. Keep the mtk state free in the same crtc->state guard as the helper state destruction.

This issue was found by a static analysis checker and confirmed by manual source review.

---
 drivers/gpu/drm/mediatek/mtk_crtc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/mediatek/mtk_crtc.c +3 -3
index c4c6d0249df56..aa8e6f6ddcd32 100644
@@ -153,10 +153,10 @@ static void mtk_crtc_reset(struct drm_crtc *crtc)
 {
 	struct mtk_crtc_state *state;
 
-	if (crtc->state)
+	if (crtc->state) {
 		__drm_atomic_helper_crtc_destroy_state(crtc->state);
-
-	kfree(to_mtk_crtc_state(crtc->state));
+		kfree(to_mtk_crtc_state(crtc->state));
+	}
 	crtc->state = NULL;
 
 	state = kzalloc(sizeof(*state), GFP_KERNEL);
Signature · 1 line
2.53.0
author maintainer
#39 lore raw

PATCH 40/337 Drivers: hv: vmbus: Replace lockdep_hardirq_threaded() with lockdep annotation

In reply to Greg Kroah-Hartman

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

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

From: Sebastian Andrzej Siewior <[email protected]>

[ Upstream commit 8c7ab779c8850f4dab8473463cca9a7d52fdaecc ]

lockdep_hardirq_threaded() is supposed to be used within IRQ core code and not within drivers. It is not obvious from within the driver, that this is the only interrupt service routing and that it is not shared handler.

Replace lockdep_hardirq_threaded() with a lockdep annotation limiting threaded context on PREEMPT_RT to __vmbus_isr().

Fixes f8e6343b7a89c ("Drivers: hv: vmbus: Use kthread for vmbus interrupts on PREEMPT_RT")
---
 drivers/hv/vmbus_drv.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/hv/vmbus_drv.c +12 -1
index 83f3215bc5bd5..db1c71832f2a8 100644
@@ -1320,8 +1320,19 @@ static void vmbus_isr(void)
 	if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
 		vmbus_irqd_wake();
 	} else {
-		lockdep_hardirq_threaded();
+		static DEFINE_WAIT_OVERRIDE_MAP(vmbus_map, LD_WAIT_CONFIG);
+
+		/*
+		 * vmbus_isr is never force-threaded and always invoked at hard
+		 * IRQ level. __vmbus_isr() below can acquire a spinlock_t
+		 * which becomes a sleeping lock and must not be acquired in
+		 * this context. Therefore on PREEMPT_RT this will be threaded
+		 * via vmbus_irqd_wake(). On non-PREEMPT the annotation lets
+		 * lockdep know that acquiring a spinlock_t is not an issue.
+		 */
+		lock_map_acquire_try(&vmbus_map);
 		__vmbus_isr();
+		lock_map_release(&vmbus_map);
 	}
 }
 
Signature · 1 line
2.53.0
author maintainer
#40 lore raw

PATCH 41/337 KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type

In reply to Greg Kroah-Hartman

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

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

From: Fabrice Derepas <[email protected]>

[ Upstream commit 35d661c98fe4733490f20b4311616a3c2c30abc0 ]

Two correctness and type-hygiene issues exist in the DCP trusted keys implementation.

First, trusted_dcp_unseal() reads p->key_len from a user-supplied blob without checking if it exceeds MAX_KEY_SIZE. If a crafted blob provides a payload_len larger than 128, the subsequent do_aead_crypto() call writes past the end of the p->key array into the adjacent p->blob buffer within the same struct trusted_key_payload -- the caller's own input, not unrelated kernel memory. While not exploitable, this violates strict array bounds and triggers static analyzers. Fix this by adding a validation check against MIN_KEY_SIZE and MAX_KEY_SIZE immediately after reading the length, matching the checks already done in trusted_core.c.

Second, calc_blob_len() calculates a sum in size_t that truncates to unsigned int on 64-bit platforms. Because the DCP hardware is only present on 32-bit i.MX SoC platforms, size_t and unsigned int are functionally equivalent in production, making this truncation harmless in practice. Nevertheless, updating the return type to size_t (and subsequently updating 'blen' in the seal/unseal paths) resolves type-narrowing warnings and improves overall code hygiene.

---
 security/keys/trusted-keys/trusted_dcp.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
security/keys/trusted-keys/trusted_dcp.c +11 -4
index 7b6eb655df0cb..c078adebe190e 100644
@@ -69,7 +69,7 @@ static bool skip_zk_test;
 module_param_named(dcp_skip_zk_test, skip_zk_test, bool, 0);
 MODULE_PARM_DESC(dcp_skip_zk_test, "Don't test whether device keys are zero'ed");
 
-static unsigned int calc_blob_len(unsigned int payload_len)
+static size_t calc_blob_len(unsigned int payload_len)
 {
 	return sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN;
 }
@@ -200,7 +200,8 @@ static int encrypt_blob_key(u8 *plain_key, u8 *encrypted_key)
 static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
 {
 	struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
-	int blen, ret;
+	size_t blen;
+	int ret;
 	u8 *plain_blob_key;
 
 	blen = calc_blob_len(p->key_len);
@@ -242,7 +243,8 @@ static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
 static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
 {
 	struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
-	int blen, ret;
+	size_t blen;
+	int ret;
 	u8 *plain_blob_key = NULL;
 
 	if (b->fmt_version != DCP_BLOB_VERSION) {
@@ -253,9 +255,14 @@ static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
 	}
 
 	p->key_len = le32_to_cpu(b->payload_len);
+	if (p->key_len < MIN_KEY_SIZE || p->key_len > MAX_KEY_SIZE) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	blen = calc_blob_len(p->key_len);
 	if (blen != p->blob_len) {
-		pr_err("DCP blob has bad length: %i != %i\n", blen,
+		pr_err("DCP blob has bad length: %zu != %u\n", blen,
 		       p->blob_len);
 		ret = -EINVAL;
 		goto out;
Signature · 1 line
2.53.0
author maintainer
#41 lore raw

PATCH 42/337 keys: fix out-of-bounds read in keyring_get_key_chunk()

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit 63918731f9ae25b5deb022f118e941e6dddfcef4 ]

For description-level chunks keyring_get_key_chunk() advances the read pointer by level * sizeof(long) past the inline prefix but only bounds-checks the prefix, so a long enough key description is read past its kmemdup(desc, desc_len + 1) allocation. Compute the full byte offset and bounds-check the description against it before reading.

The walk only reaches a description-level chunk when two keys collide through the hash, x, type and domain_tag chunks, so this is reached from an unprivileged add_key(2) with a crafted pair of same-type keys whose index hashes collide; KASAN reports a slab-out-of-bounds read.

Fixes f771fde82051 ("keys: Simplify key description management")
Assisted-by Claude:claude-opus-4-8
---
 security/keys/keyring.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
security/keys/keyring.c +5 -4
index e105349794f23..b9ca9dc9b0c3f 100644
@@ -271,6 +271,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
 	unsigned long chunk = 0;
 	const u8 *d;
 	int desc_len = index_key->desc_len, n = sizeof(chunk);
+	unsigned int offset;
 
 	level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
 	switch (level) {
@@ -284,12 +285,12 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
 		return (unsigned long)index_key->domain_tag;
 	default:
 		level -= 4;
-		if (desc_len <= sizeof(index_key->desc))
+		offset = sizeof(index_key->desc) + level * sizeof(long);
+		if (desc_len <= offset)
 			return 0;
 
-		d = index_key->description + sizeof(index_key->desc);
-		d += level * sizeof(long);
-		desc_len -= sizeof(index_key->desc);
+		d = index_key->description + offset;
+		desc_len -= offset;
 		if (desc_len > n)
 			desc_len = n;
 		do {
Signature · 1 line
2.53.0
author maintainer
#42 lore raw

PATCH 43/337 keys: make keyring key-chunk byte order agree with keyring_diff_objects()

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit 58565eef0f8d861aae92abfb7658458d661cee17 ]

keyring_get_key_chunk() loads description bytes into the index chunk low address first, while keyring_diff_objects() numbers the first differing bit from the low end and folds the absolute byte index into the level without removing the inline-prefix offset the level already carries. The two disagree on byte order and bit position, so the array can be told two keys first differ at a bit that does not differ in the chunk the walker uses, letting crafted descriptions collide into one node.

Load the chunk in the order keyring_diff_objects() assumes and drop the inline-prefix length when folding the byte index into the level. This only changes the in-memory ordering used to place keys within a keyring; add, search and read of non-colliding keys are unaffected.

Fixes f771fde82051 ("keys: Simplify key description management")
Assisted-by Claude:claude-opus-4-8
---
 security/keys/keyring.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
security/keys/keyring.c +3 -2
index b9ca9dc9b0c3f..fd95a0eb7a466 100644
@@ -293,9 +293,10 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
 		desc_len -= offset;
 		if (desc_len > n)
 			desc_len = n;
+		d += desc_len;
 		do {
 			chunk <<= 8;
-			chunk |= *d++;
+			chunk |= *--d;
 		} while (--desc_len > 0);
 		return chunk;
 	}
@@ -376,7 +377,7 @@ static int keyring_diff_objects(const void *object, const void *data)
 	return -1;
 
 differ_plus_i:
-	level += i;
+	level += i - (int)sizeof(a->desc);
 differ:
 	i = level * 8 + __ffs(seg_a ^ seg_b);
 	return i;
Signature · 1 line
2.53.0
author maintainer
#43 lore raw

PATCH 44/337 assoc_array: trim the final shortcut word using the current chunk end

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit a82c8a05e86f3f84e09698f65b4515b5d04633f6 ]

assoc_array_walk() masks off the bits past shortcut->skip_to_level in the word that contains skip_to_level, gated on
round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > skip_to_level.

That guard is wrong in two opposite ways:

- When sc_level is word-aligned (every word after the first) round_up() is a no-op, so the guard is sc_level > skip_to_level and never fires for the word that holds skip_to_level. A shortcut that spans more than one word and ends in the middle of its last word leaves that word untrimmed, and its stale high bits leak into the dissimilarity word and can steer the walk down the wrong descendant.

- When sc_level is unaligned (the first word) and skip_to_level sits on the next chunk boundary, sc_level + CHUNK would exceed skip_to_level and fire the trim with shift = skip_to_level & CHUNK_MASK == 0, which clears the whole dissimilarity word and makes a differing shortcut compare equal.

Use the end of the chunk that contains sc_level instead:

skip_to_level < round_down(sc_level, CHUNK) + CHUNK

For an aligned sc_level whose word holds skip_to_level this now fires (the first bug); for an unaligned sc_level with skip_to_level on the following boundary it does not, so shift is never 0 when the branch runs and the trim never clears the whole word.

Fixes 3cb989501c26 ("Add a generic associative array implementation.")
Assisted-by Claude:claude-opus-4-8
---
 lib/assoc_array.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
lib/assoc_array.c +2 -1
index 388e656ac9743..01619e88a52c9 100644
@@ -255,7 +255,8 @@ assoc_array_walk(const struct assoc_array *array,
 		sc_segments = shortcut->index_key[sc_level >> ASSOC_ARRAY_KEY_CHUNK_SHIFT];
 		dissimilarity = segments ^ sc_segments;
 
-		if (round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > shortcut->skip_to_level) {
+		if (shortcut->skip_to_level < round_down(sc_level,
+				ASSOC_ARRAY_KEY_CHUNK_SIZE) + ASSOC_ARRAY_KEY_CHUNK_SIZE) {
 			/* Trim segments that are beyond the shortcut */
 			int shift = shortcut->skip_to_level & ASSOC_ARRAY_KEY_CHUNK_MASK;
 			dissimilarity &= ~(ULONG_MAX << shift);
Signature · 1 line
2.53.0
author maintainer
#44 lore raw

PATCH 45/337 netfilter: nf_tables: make nft_object rhltable per table

In reply to Greg Kroah-Hartman

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

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

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit f4f699790590bd0896c48a71e9232a65198f92f0 ]

The nft_object rhltable is global, this allows for accessing objects that are being dismangled from lookup path by other existing netns. Given the nft_obj_destroy() releases the object inmediately, this might lead to use-after-free of these objects that are being released. Make the existing rhltable per table to address this issue to deal with with the nft_rcv_nl_event() path too.

Update nft_obj_lookup() to take the table as non-const, otherwise, compiler complains when passing the objname_ht to rhltable_lookup().

Fixes 4d44175aa5bb ("netfilter: nf_tables: handle nft_object lookups via rhltable")
---
 include/net/netfilter/nf_tables.h |  4 +++-
 net/netfilter/nf_tables_api.c     | 34 +++++++++++++++----------------
 2 files changed, 19 insertions(+), 19 deletions(-)
include/net/netfilter/nf_tables.h +3 -1
index 032b649658be9..f4b59915a49c5 100644
@@ -1274,6 +1274,7 @@ static inline void nft_use_inc_restore(u32 *use)
  *	@sets: sets in the table
  *	@objects: stateful objects in the table
  *	@flowtables: flow tables in the table
+ *	@objname_ht: hashtable for objects lookup by name
  *	@hgenerator: handle generator state
  *	@handle: table handle
  *	@use: number of chain references to this table
@@ -1293,6 +1294,7 @@ struct nft_table {
 	struct list_head		sets;
 	struct list_head		objects;
 	struct list_head		flowtables;
+	struct rhltable			objname_ht;
 	u64				hgenerator;
 	u64				handle;
 	u32				use;
@@ -1380,7 +1382,7 @@ static inline void *nft_obj_data(const struct nft_object *obj)
 #define nft_expr_obj(expr)	*((struct nft_object **)nft_expr_priv(expr))
 
 struct nft_object *nft_obj_lookup(const struct net *net,
-				  const struct nft_table *table,
+				  struct nft_table *table,
 				  const struct nlattr *nla, u32 objtype,
 				  u8 genmask);
 
net/netfilter/nf_tables_api.c +16 -18
index 4cf565686a51f..03dd9d1db12fc 100644
@@ -41,8 +41,6 @@ enum {
 	NFT_VALIDATE_DO,
 };
 
-static struct rhltable nft_objname_ht;
-
 static u32 nft_chain_hash(const void *data, u32 len, u32 seed);
 static u32 nft_chain_hash_obj(const void *data, u32 len, u32 seed);
 static int nft_chain_hash_cmp(struct rhashtable_compare_arg *, const void *);
@@ -1457,6 +1455,10 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
 	if (err)
 		goto err_chain_ht;
 
+	err = rhltable_init(&table->objname_ht, &nft_objname_ht_params);
+	if (err < 0)
+		goto err_obj_ht;
+
 	INIT_LIST_HEAD(&table->chains);
 	INIT_LIST_HEAD(&table->sets);
 	INIT_LIST_HEAD(&table->objects);
@@ -1475,6 +1477,8 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
 	list_add_tail_rcu(&table->list, &nft_net->tables);
 	return 0;
 err_trans:
+	rhltable_destroy(&table->objname_ht);
+err_obj_ht:
 	rhltable_destroy(&table->chains_ht);
 err_chain_ht:
 	kfree(table->udata);
@@ -1641,6 +1645,7 @@ static void nf_tables_table_destroy(struct nft_table *table)
 		return;
 
 	rhltable_destroy(&table->chains_ht);
+	rhltable_destroy(&table->objname_ht);
 	kfree(table->name);
 	kfree(table->udata);
 	kfree(table);
@@ -7578,7 +7583,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type)
 EXPORT_SYMBOL_GPL(nft_unregister_obj);
 
 struct nft_object *nft_obj_lookup(const struct net *net,
-				  const struct nft_table *table,
+				  struct nft_table *table,
 				  const struct nlattr *nla, u32 objtype,
 				  u8 genmask)
 {
@@ -7594,7 +7599,7 @@ struct nft_object *nft_obj_lookup(const struct net *net,
 		     !lockdep_commit_lock_is_held(net));
 
 	rcu_read_lock();
-	list = rhltable_lookup(&nft_objname_ht, &k, nft_objname_ht_params);
+	list = rhltable_lookup(&table->objname_ht, &k, nft_objname_ht_params);
 	if (!list)
 		goto out;
 
@@ -7873,7 +7878,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
 	if (err < 0)
 		goto err_trans;
 
-	err = rhltable_insert(&nft_objname_ht, &obj->rhlhead,
+	err = rhltable_insert(&table->objname_ht, &obj->rhlhead,
 			      nft_objname_ht_params);
 	if (err < 0)
 		goto err_obj_ht;
@@ -8052,8 +8057,8 @@ nf_tables_getobj_single(u32 portid, const struct nfnl_info *info,
 	struct netlink_ext_ack *extack = info->extack;
 	u8 genmask = nft_genmask_cur(info->net);
 	u8 family = info->nfmsg->nfgen_family;
-	const struct nft_table *table;
 	struct net *net = info->net;
+	struct nft_table *table;
 	struct nft_object *obj;
 	struct sk_buff *skb2;
 	u32 objtype;
@@ -9782,9 +9787,9 @@ static void nf_tables_commit_chain(struct net *net, struct nft_chain *chain)
 		nf_tables_commit_chain_free_rules_old(g0);
 }
 
-static void nft_obj_del(struct nft_object *obj)
+static void nft_obj_del(struct nft_table *table, struct nft_object *obj)
 {
-	rhltable_remove(&nft_objname_ht, &obj->rhlhead, nft_objname_ht_params);
+	rhltable_remove(&table->objname_ht, &obj->rhlhead, nft_objname_ht_params);
 	list_del_rcu(&obj->list);
 }
 
@@ -10480,7 +10485,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			break;
 		case NFT_MSG_DELOBJ:
 		case NFT_MSG_DESTROYOBJ:
-			nft_obj_del(nft_trans_obj(trans));
+			nft_obj_del(table, nft_trans_obj(trans));
 			nf_tables_obj_notify(&ctx, nft_trans_obj(trans),
 					     trans->msg_type);
 			break;
@@ -10780,7 +10785,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 				nft_trans_destroy(trans);
 			} else {
 				nft_use_dec_restore(&table->use);
-				nft_obj_del(nft_trans_obj(trans));
+				nft_obj_del(table, nft_trans_obj(trans));
 			}
 			break;
 		case NFT_MSG_DELOBJ:
@@ -11447,7 +11452,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
 		nft_set_destroy(&ctx, set);
 	}
 	list_for_each_entry_safe(obj, ne, &table->objects, list) {
-		nft_obj_del(obj);
+		nft_obj_del(table, obj);
 		nft_use_dec(&table->use);
 		nft_obj_destroy(&ctx, obj);
 	}
@@ -11629,10 +11634,6 @@ static int __init nf_tables_module_init(void)
 	if (err < 0)
 		goto err_netdev_notifier;
 
-	err = rhltable_init(&nft_objname_ht, &nft_objname_ht_params);
-	if (err < 0)
-		goto err_rht_objname;
-
 	err = nft_offload_init();
 	if (err < 0)
 		goto err_offload;
@@ -11655,8 +11656,6 @@ static int __init nf_tables_module_init(void)
 err_netlink_notifier:
 	nft_offload_exit();
 err_offload:
-	rhltable_destroy(&nft_objname_ht);
-err_rht_objname:
 	unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
 err_netdev_notifier:
 	nf_tables_core_module_exit();
@@ -11678,7 +11677,6 @@ static void __exit nf_tables_module_exit(void)
 	unregister_pernet_subsys(&nf_tables_net_ops);
 	cancel_work_sync(&trans_gc_work);
 	rcu_barrier();
-	rhltable_destroy(&nft_objname_ht);
 	nf_tables_core_module_exit();
 }
 
Signature · 1 line
2.53.0
author maintainer
#45 lore raw

PATCH 46/337 netfilter: xt_hashlimit: validate hashtable supports XT_HASHLIMIT_RATE_MATCH

In reply to Greg Kroah-Hartman

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

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

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit 305b63e1402267459fdabb183af4527f6799eebf ]

The XT_HASHLIMIT_RATE_MATCH flag mode changes the semantics of the dsthash_ent structure which represents an entry in the hashtable. There is a union area which uses a different layout to express the rate match mode.

Update .checkentry path to validate the XT_HASHLIMIT_RATE_MATCH mode flag is requested by two or more different rules that refer to the same hashtable. Otherwise, uninitialized access to the burst field in the union is possible.

Reject the use of the XT_HASHLIMIT_RATE_MATCH mode flag if set on by revision less than 3 too.

Fixes bea74641e378 ("netfilter: xt_hashlimit: add rate match mode")
---
 net/netfilter/xt_hashlimit.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
net/netfilter/xt_hashlimit.c +15 -1
index 0859b8f767645..61813010cd319 100644
@@ -118,6 +118,7 @@ struct xt_hashlimit_htable {
 	refcount_t use;
 	u_int8_t family;
 	bool rnd_initialized;
+	bool ratematch;
 
 	struct hashlimit_cfg3 cfg;	/* config */
 
@@ -325,6 +326,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,
 		vfree(hinfo);
 		return -ENOMEM;
 	}
+	hinfo->ratematch = !!(cfg->mode & XT_HASHLIMIT_RATE_MATCH);
 	spin_lock_init(&hinfo->lock);
 
 	switch (revision) {
@@ -868,7 +870,10 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
 	}
 
 	/* Check for overflow. */
-	if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
+	if (cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
+		if (revision < 3)
+			return -EINVAL;
+
 		if (cfg->avg == 0 || cfg->avg > U32_MAX) {
 			pr_info_ratelimited("invalid rate\n");
 			return -ERANGE;
@@ -901,6 +906,15 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
 			mutex_unlock(&hashlimit_mutex);
 			return ret;
 		}
+	} else {
+		if ((cfg->mode & XT_HASHLIMIT_RATE_MATCH &&
+		     !(*hinfo)->ratematch) ||
+		    (!(cfg->mode & XT_HASHLIMIT_RATE_MATCH) &&
+		      (*hinfo)->ratematch)) {
+			mutex_unlock(&hashlimit_mutex);
+			htable_put(*hinfo);
+			return -EINVAL;
+		}
 	}
 	mutex_unlock(&hashlimit_mutex);
 
Signature · 1 line
2.53.0
author maintainer
#46 lore raw

PATCH 47/337 ipvs: fix the checksum validations

In reply to Greg Kroah-Hartman

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

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

From: Julian Anastasov <[email protected]>

[ Upstream commit e876b75b9020a97bbdc79721e7fc749024891c65 ]

ip_vs_in_icmp_v6() is missing checksum validation for ICMPv6 packets from clients. In fact, as for TCP/UDP we should validate the checksum for ICMP packets only when we mangle the packets on MASQ or on reply for tunnel.

Also, Sashiko points out that handle_response_icmp() being common for IPv4 and IPv6 is missing the pseudo-header calculation while validating ICMPv6 messages from real servers which is a problem if checksum is not validated by the hardware.

Fix the problems by creating ip_vs_checksum_common_check() helper and use it for TCP/UDP/ICMP both for IPv4 and IPv6. Rely on the nf_checksum() for validating the ICMP messages but use it also for TCP and UDP.

Use correct IP offset for IP_VS_DBG_RL_PKT for TCP/UDP/SCTP.

IPVS packets (TCP/UDP/SCTP/ICMP) do not need checksum validation on LOCAL_OUT (local clients or local real servers) and on FORWARD (traffic from servers on LAN). Do it only on LOCAL_IN, in case nf_checksum() is not called on PRE_ROUTING.

Also, ip_vs_checksum_complete() can be marked static.

Fixes 2a3b791e6e11 ("IPVS: Add/adjust Netfilter hook functions and helpers for v6")
---
 include/net/ip_vs.h                   | 31 +++++++++++++++--
 net/netfilter/ipvs/ip_vs_core.c       | 20 +++++++++--
 net/netfilter/ipvs/ip_vs_proto_sctp.c | 15 ++++----
 net/netfilter/ipvs/ip_vs_proto_tcp.c  | 44 +++++------------------
 net/netfilter/ipvs/ip_vs_proto_udp.c  | 50 ++++++---------------------
 5 files changed, 74 insertions(+), 86 deletions(-)
include/net/ip_vs.h +29 -2
index 08b90d33acdc6..aef042039cb00 100644
@@ -24,7 +24,9 @@
 #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
@@ -1711,8 +1713,6 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		       struct ip_vs_conn *cp, int dir);
 #endif
 
-__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
-
 static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
 {
 	__be32 diff[2] = { ~old, new };
@@ -1738,6 +1738,33 @@ 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)
+{
+	/* Checksum unnecessary or already validated? */
+	if (skb_csum_unnecessary(skb))
+		return false;
+	/* LOCAL_OUT ? */
+	if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
+		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))
+		return true;
+	return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+}
+
 /* Forget current conntrack (unconfirmed) and attach notrack entry */
 static inline void ip_vs_notrack(struct sk_buff *skb)
 {
net/netfilter/ipvs/ip_vs_core.c +17 -3
index 90619453cb6f0..306a8227d300e 100644
@@ -689,7 +689,7 @@ static int sysctl_nat_icmp_send(struct netns_ipvs *ipvs) { return 0; }
 
 #endif
 
-__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
+static __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
 {
 	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
 }
@@ -860,13 +860,14 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
 				unsigned int offset, unsigned int ihl,
 				unsigned int hooknum)
 {
+	int iproto = af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
 	unsigned int verdict = NF_DROP;
 
 	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
 		goto after_nat;
 
 	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+	if (!ip_vs_checksum_common_check(skb, ihl, iproto, af)) {
 		/* Failed checksum! */
 		IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
 			      IP_VS_DBG_ADDR(af, snet));
@@ -1720,7 +1721,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
 	verdict = NF_DROP;
 
 	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+	if ((IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ || tunnel) &&
+	    !ip_vs_checksum_common_check(skb, ihl, IPPROTO_ICMP, AF_INET)) {
 		/* Failed checksum! */
 		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n",
 			  &iph->saddr);
@@ -1886,6 +1888,18 @@ static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
 		goto out;
 	}
 
+	verdict = NF_DROP;
+
+	/* Ensure the checksum is correct */
+	if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ &&
+	    !ip_vs_checksum_common_check(skb, iph->len, IPPROTO_ICMPV6,
+					 AF_INET6)) {
+		/* Failed checksum! */
+		IP_VS_DBG(1, "Incoming ICMPv6: failed checksum from %pI6c!\n",
+			  &iph->saddr);
+		goto out;
+	}
+
 	/* do the statistics and put it back */
 	ip_vs_in_stats(cp, skb);
 
net/netfilter/ipvs/ip_vs_proto_sctp.c +9 -6
index c67317be17dfa..f6f732b7dfa86 100644
@@ -11,7 +11,7 @@
 
 static int
 sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
-		unsigned int sctphoff);
+		struct ip_vs_iphdr *iph);
 
 static int
 sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -109,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
+		if (!sctp_csum_check(cp->af, skb, pp, iph))
 			return 0;
 
 		/* Call application helper if needed */
@@ -157,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
+		if (!sctp_csum_check(cp->af, skb, pp, iph))
 			return 0;
 
 		/* Call application helper if needed */
@@ -187,19 +187,22 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 static int
 sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
-		unsigned int sctphoff)
+		struct ip_vs_iphdr *iph)
 {
+	unsigned int sctphoff = iph->len;
 	struct sctphdr *sh;
 	__le32 cmp, val;
 
+	if (!ip_vs_checksum_needed(skb, af))
+		return 1;
 	sh = (struct sctphdr *)(skb->data + sctphoff);
 	cmp = sh->checksum;
 	val = sctp_compute_cksum(skb, sctphoff);
 
 	if (val != cmp) {
 		/* CRC failure, dump it. */
-		IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
-				"Failed checksum for");
+		IP_VS_DBG_RL_PKT(0, af, pp, skb, iph->off,
+				 "Failed checksum for");
 		return 0;
 	}
 	return 1;
net/netfilter/ipvs/ip_vs_proto_tcp.c +8 -36

70 lines not on this page · raw message

net/netfilter/ipvs/ip_vs_proto_udp.c +11 -39

80 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#47 lore raw

PATCH 48/337 ipvs: fix places with wrong packet offsets

In reply to Greg Kroah-Hartman

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

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

From: Julian Anastasov <[email protected]>

[ Upstream commit 15cab31a3730e05f0767b922a7450e5d784b2607 ]

The offsets we use to packet headers and payloads should be based on skb->data. We even already respect non-zero network offset in ip_vs_fill_iph_skb() but some places do it wrongly and support only zero offset which is expected for the IP layer where IPVS has hooks.

Change all places that instead of skb->data use offsets based on the network header (skb_network_header, ip_hdr, etc) because this doubles the network offset as noted by Sashiko.

For ip_vs_nat_icmp_v6() we can even rely on the IPv6 header parsing done by the caller.

---
 include/net/ip_vs.h                   |  15 +--
 net/netfilter/ipvs/ip_vs_app.c        |   4 +-
 net/netfilter/ipvs/ip_vs_core.c       | 133 +++++++++++++-------------
 net/netfilter/ipvs/ip_vs_proto_sctp.c |   4 +-
 net/netfilter/ipvs/ip_vs_proto_tcp.c  |   4 +-
 net/netfilter/ipvs/ip_vs_proto_udp.c  |   4 +-
 net/netfilter/ipvs/ip_vs_xmit.c       |  26 ++---
 7 files changed, 97 insertions(+), 93 deletions(-)
include/net/ip_vs.h +9 -6
index aef042039cb00..a44979db80134 100644
@@ -1626,8 +1626,9 @@ int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		  struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph);
 int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		    struct ip_vs_protocol *pp, int offset,
-		    unsigned int hooknum, struct ip_vs_iphdr *iph);
+		    struct ip_vs_protocol *pp, unsigned int toff,
+		    unsigned int wlen, unsigned int hooknum,
+		    struct ip_vs_iphdr *ciph);
 void ip_vs_dest_dst_rcu_free(struct rcu_head *head);
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -1640,8 +1641,9 @@ int ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 int ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		     struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph);
 int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
-		       struct ip_vs_protocol *pp, int offset,
-		       unsigned int hooknum, struct ip_vs_iphdr *iph);
+		       struct ip_vs_protocol *pp, unsigned int toff,
+		       unsigned int wlen, unsigned int hooknum,
+		       struct ip_vs_iphdr *ciph);
 #endif
 
 #ifdef CONFIG_SYSCTL
@@ -1706,11 +1708,12 @@ 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);
+		    struct ip_vs_conn *cp, int dir, unsigned int toff);
 
 #ifdef CONFIG_IP_VS_IPV6
 void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		       struct ip_vs_conn *cp, int dir);
+		       struct ip_vs_conn *cp, int dir, unsigned int toff,
+		       struct ip_vs_iphdr *ciph);
 #endif
 
 static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
net/netfilter/ipvs/ip_vs_app.c +2 -2
index f9132b359f0c6..0c690a30a85dc 100644
@@ -368,7 +368,7 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
 	if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
 		return 0;
 
-	th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
+	th = (struct tcphdr *)(skb->data + ipvsh->len);
 
 	/*
 	 *	Remember seq number in case this pkt gets resized
@@ -444,7 +444,7 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
 	if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
 		return 0;
 
-	th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
+	th = (struct tcphdr *)(skb->data + ipvsh->len);
 
 	/*
 	 *	Remember seq number in case this pkt gets resized
net/netfilter/ipvs/ip_vs_core.c +66 -67

332 lines not on this page · raw message

net/netfilter/ipvs/ip_vs_proto_sctp.c +2 -2
index f6f732b7dfa86..3dbd3096e1637 100644
@@ -121,7 +121,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	sctph = (void *) skb_network_header(skb) + sctphoff;
+	sctph = (void *)skb->data + sctphoff;
 
 	/* Only update csum if we really have to */
 	if (sctph->source != cp->vport || payload_csum ||
@@ -169,7 +169,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	sctph = (void *) skb_network_header(skb) + sctphoff;
+	sctph = (void *)skb->data + sctphoff;
 
 	/* Only update csum if we really have to */
 	if (sctph->dest != cp->dport || payload_csum ||
net/netfilter/ipvs/ip_vs_proto_tcp.c +2 -2
index bf31127338aa0..1ac9c233537d3 100644
@@ -180,7 +180,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	tcph = (void *)skb_network_header(skb) + tcphoff;
+	tcph = (void *)skb->data + tcphoff;
 	tcph->source = cp->vport;
 
 	/* Adjust TCP checksums */
@@ -261,7 +261,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	tcph = (void *)skb_network_header(skb) + tcphoff;
+	tcph = (void *)skb->data + tcphoff;
 	tcph->dest = cp->dport;
 
 	/*
net/netfilter/ipvs/ip_vs_proto_udp.c +2 -2
index 40d30649b3048..96ac882df15c1 100644
@@ -171,7 +171,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	udph = (void *)skb_network_header(skb) + udphoff;
+	udph = (void *)skb->data + udphoff;
 	udph->source = cp->vport;
 
 	/*
@@ -255,7 +255,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			payload_csum = true;
 	}
 
-	udph = (void *)skb_network_header(skb) + udphoff;
+	udph = (void *)skb->data + udphoff;
 	udph->dest = cp->dport;
 
 	/*
net/netfilter/ipvs/ip_vs_xmit.c +14 -12
index fa1b03c3201f1..05e6164c45039 100644
@@ -1499,8 +1499,9 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
  */
 int
 ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		struct ip_vs_protocol *pp, int offset, unsigned int hooknum,
-		struct ip_vs_iphdr *iph)
+		struct ip_vs_protocol *pp, unsigned int toff,
+		unsigned int wlen, unsigned int hooknum,
+		struct ip_vs_iphdr *ciph)
 {
 	struct rtable	*rt;	/* Route to the other host */
 	int rc;
@@ -1512,7 +1513,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	   translate address/port back */
 	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
 		if (cp->packet_xmit)
-			rc = cp->packet_xmit(skb, cp, pp, iph);
+			rc = cp->packet_xmit(skb, cp, pp, ciph);
 		else
 			rc = NF_ACCEPT;
 		/* do not touch skb anymore */
@@ -1530,7 +1531,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		  IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
 		  IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
 	local = __ip_vs_get_out_rt(cp->ipvs, cp->af, skb, cp->dest, cp->daddr.ip, rt_mode,
-				   NULL, iph);
+				   NULL, ciph);
 	if (local < 0)
 		goto tx_error;
 	rt = skb_rtable(skb);
@@ -1562,13 +1563,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	}
 
 	/* copy-on-write the packet before mangling it */
-	if (skb_ensure_writable(skb, offset))
+	if (skb_ensure_writable(skb, wlen))
 		goto tx_error;
 
 	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error;
 
-	ip_vs_nat_icmp(skb, pp, cp, 0);
+	ip_vs_nat_icmp(skb, pp, cp, 0, toff);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->ignore_df = 1;
@@ -1584,8 +1585,9 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 #ifdef CONFIG_IP_VS_IPV6
 int
 ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
-		struct ip_vs_protocol *pp, int offset, unsigned int hooknum,
-		struct ip_vs_iphdr *ipvsh)
+		struct ip_vs_protocol *pp, unsigned int toff,
+		unsigned int wlen, unsigned int hooknum,
+		struct ip_vs_iphdr *ciph)
 {
 	struct rt6_info	*rt;	/* Route to the other host */
 	int rc;
@@ -1597,7 +1599,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 	   translate address/port back */
 	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
 		if (cp->packet_xmit)
-			rc = cp->packet_xmit(skb, cp, pp, ipvsh);
+			rc = cp->packet_xmit(skb, cp, pp, ciph);
 		else
 			rc = NF_ACCEPT;
 		/* do not touch skb anymore */
@@ -1614,7 +1616,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		  IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
 		  IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
 	local = __ip_vs_get_out_rt_v6(cp->ipvs, cp->af, skb, cp->dest,
-				      &cp->daddr.in6, NULL, ipvsh, 0, rt_mode);
+				      &cp->daddr.in6, NULL, ciph, 0, rt_mode);
 	if (local < 0)
 		goto tx_error;
 	rt = dst_rt6_info(skb_dst(skb));
@@ -1646,13 +1648,13 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 	}
 
 	/* copy-on-write the packet before mangling it */
-	if (skb_ensure_writable(skb, offset))
+	if (skb_ensure_writable(skb, wlen))
 		goto tx_error;
 
 	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error;
 
-	ip_vs_nat_icmp_v6(skb, pp, cp, 0);
+	ip_vs_nat_icmp_v6(skb, pp, cp, 0, toff, ciph);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->ignore_df = 1;
Signature · 1 line
2.53.0
author maintainer
#48 lore raw

PATCH 49/337 ipvs: do not mangle ICMP replies for non-first fragments

In reply to Greg Kroah-Hartman

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

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

From: Julian Anastasov <[email protected]>

[ Upstream commit 342e24a339b90e8e339a0f8c151ca479b8565661 ]

Sashiko warns that ip_vs_nat_icmp() unconditionally mangles the payload for embedded non-first IPv4 fragments. The problem is in the very old inverted pp->dont_defrag check which should not continue when embedded is a non-first TCP/UDP/SCTP fragment.

Check for embedded non-first fragment is also missing from ip_vs_out_icmp_v6(), it is needed before any connection lookups that expect ports after the network headers.

Drop the blocking code from ip_vs_in_icmp_v6() which prevents ICMPv6 from local clients to use non-MASQ forwarding.

---
 include/net/ip_vs.h             | 11 +++---
 net/netfilter/ipvs/ip_vs_core.c | 61 ++++++++++++---------------------
 net/netfilter/ipvs/ip_vs_xmit.c | 28 +++++++++++----
 3 files changed, 48 insertions(+), 52 deletions(-)
include/net/ip_vs.h +5 -6
index a44979db80134..6935ec09af24d 100644
@@ -1627,8 +1627,7 @@ int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		  struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph);
 int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		    struct ip_vs_protocol *pp, unsigned int toff,
-		    unsigned int wlen, unsigned int hooknum,
-		    struct ip_vs_iphdr *ciph);
+		    unsigned int hooknum, struct ip_vs_iphdr *ciph);
 void ip_vs_dest_dst_rcu_free(struct rcu_head *head);
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -1642,8 +1641,7 @@ int ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		     struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph);
 int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		       struct ip_vs_protocol *pp, unsigned int toff,
-		       unsigned int wlen, unsigned int hooknum,
-		       struct ip_vs_iphdr *ciph);
+		       unsigned int hooknum, struct ip_vs_iphdr *ciph);
 #endif
 
 #ifdef CONFIG_SYSCTL
@@ -1708,12 +1706,13 @@ 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);
+		    struct ip_vs_conn *cp, int dir, unsigned int toff,
+		    bool has_ports);
 
 #ifdef CONFIG_IP_VS_IPV6
 void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		       struct ip_vs_conn *cp, int dir, unsigned int toff,
-		       struct ip_vs_iphdr *ciph);
+		       bool has_ports, struct ip_vs_iphdr *ciph);
 #endif
 
 static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
net/netfilter/ipvs/ip_vs_core.c +21 -40

161 lines not on this page · raw message

net/netfilter/ipvs/ip_vs_xmit.c +22 -6
index 05e6164c45039..b85420a3a14ce 100644
@@ -1500,13 +1500,14 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 int
 ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		struct ip_vs_protocol *pp, unsigned int toff,
-		unsigned int wlen, unsigned int hooknum,
-		struct ip_vs_iphdr *ciph)
+		unsigned int hooknum, struct ip_vs_iphdr *ciph)
 {
 	struct rtable	*rt;	/* Route to the other host */
 	int rc;
 	int local;
 	int rt_mode, was_input;
+	bool has_ports = false;
+	unsigned int wlen;
 
 	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
 	   forwarded directly here, because there is no need to
@@ -1562,6 +1563,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		goto tx_error;
 	}
 
+	wlen = ciph->len;
+	if (ciph->protocol == IPPROTO_TCP || ciph->protocol == IPPROTO_UDP ||
+	    ciph->protocol == IPPROTO_SCTP) {
+		wlen += 2 * sizeof(__u16); /* Also mangle ports */
+		has_ports = true;
+	}
+
 	/* copy-on-write the packet before mangling it */
 	if (skb_ensure_writable(skb, wlen))
 		goto tx_error;
@@ -1569,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);
+	ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->ignore_df = 1;
@@ -1586,10 +1594,11 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 int
 ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		struct ip_vs_protocol *pp, unsigned int toff,
-		unsigned int wlen, unsigned int hooknum,
-		struct ip_vs_iphdr *ciph)
+		unsigned int hooknum, struct ip_vs_iphdr *ciph)
 {
+	bool has_ports = false;
 	struct rt6_info	*rt;	/* Route to the other host */
+	unsigned int wlen;
 	int rc;
 	int local;
 	int rt_mode;
@@ -1647,6 +1656,13 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		goto tx_error;
 	}
 
+	wlen = ciph->len;
+	if (ciph->protocol == IPPROTO_TCP || ciph->protocol == IPPROTO_UDP ||
+	    ciph->protocol == IPPROTO_SCTP) {
+		wlen += 2 * sizeof(__u16); /* Also mangle ports */
+		has_ports = true;
+	}
+
 	/* copy-on-write the packet before mangling it */
 	if (skb_ensure_writable(skb, wlen))
 		goto tx_error;
@@ -1654,7 +1670,7 @@ ip_vs_icmp_xmit_v6(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_v6(skb, pp, cp, 0, toff, ciph);
+	ip_vs_nat_icmp_v6(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
#49 lore raw

PATCH 50/337 netfilter: nft_payload: fix mask build for partial field offload

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit 39e88f28fb32bf02bd4b525c24c842c9cff5663d ]

nft_payload_offload_mask() builds the offload match mask for a payload expression that covers only part of a header field. For a partial IPv6 address match (field_len = 16, priv_len = 1) that shift is 1 << 120, which is undefined on the 32-bit int operand. It also trims only one word, so the remaining words stay 0xffffffff (and when priv_len is a multiple of 4 the trim is skipped entirely), leaving the mask covering more bytes than the rule matches.

  UBSAN: shift-out-of-bounds in net/netfilter/nft_payload.c:278:20
  shift exponent 120 is too large for 32-bit type 'int'
  ...

The match is byte-granular and struct nft_data is zero-initialised, so the correct mask is simply the first priv_len bytes set to 0xff. Set those bytes directly and drop the word/shift trimming; this removes the undefined shift and no longer over-masks the trailing bytes.

Fixes a5d45bc0dc50 ("netfilter: nftables_offload: build mask based from the matching bytes")
Reported-by [email protected]
---
 net/netfilter/nft_payload.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)
net/netfilter/nft_payload.c +1 -11
index 36c31ad2d64c1..15feb49e0b663 100644
@@ -253,9 +253,7 @@ static int nft_payload_dump(struct sk_buff *skb,
 static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
 				     u32 priv_len, u32 field_len)
 {
-	unsigned int remainder, delta, k;
 	struct nft_data mask = {};
-	__be32 remainder_mask;
 
 	if (priv_len == field_len) {
 		memset(&reg->mask, 0xff, priv_len);
@@ -264,15 +262,7 @@ static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
 		return false;
 	}
 
-	memset(&mask, 0xff, field_len);
-	remainder = priv_len % sizeof(u32);
-	if (remainder) {
-		k = priv_len / sizeof(u32);
-		delta = field_len - priv_len;
-		remainder_mask = htonl(~((1 << (delta * BITS_PER_BYTE)) - 1));
-		mask.data[k] = (__force u32)remainder_mask;
-	}
-
+	memset(&mask, 0xff, priv_len);
 	memcpy(&reg->mask, &mask, field_len);
 
 	return true;
Signature · 1 line
2.53.0
author maintainer
#50 lore raw

PATCH 51/337 rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled

In reply to Greg Kroah-Hartman

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

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

From: Ilia Gavrilov <[email protected]>

[ Upstream commit 9c805e592a29be9e4e61ff1bd567da04aa8fd6f9 ]

When booting with the 'ipv6.disable=1' parameter, inet6_addr_lst is never initialized because inet6_init() exits before addrconf_init() is called to initialize it. An attempt to bind an RDS socket to an ipv6 address results in a crash in __ipv6_chk_addr_and_flags()

KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
RIP: 0010:__ipv6_chk_addr_and_flags+0x1df/0x7e0
Call Trace:
 <TASK>
 ipv6_chk_addr+0x3b/0x50
 rds_tcp_laddr_check+0x155/0x3b0 [rds_tcp]
 rds_trans_get_preferred+0x15d/0x2d0 [rds]
 ? trace_hardirqs_on+0x2d/0x110
 rds_bind+0x1433/0x1d60 [rds]
 ? rds_remove_bound+0xd50/0xd50 [rds]
 ? aa_af_perm+0x250/0x250
 ? __might_fault+0xde/0x190
 ? __sys_bind+0x1dc/0x210
 __sys_bind+0x1dc/0x210
 ? __ia32_sys_socketpair+0x100/0x100
 ? restore_fpregs_from_fpstate+0x53/0x100
 __x64_sys_bind+0x73/0xb0
 ? syscall_enter_from_user_mode+0x1c/0x50
 do_syscall_64+0x34/0x80
 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
RIP: 0033:0x7f47f8269ea9
 </TASK>

The following code reproduces the issue:

struct sockaddr_in6 addr;
s = socket(PF_RDS, SOCK_SEQPACKET, 0);

memset(&addr, 0, sizeof(addr));
inet_pton(AF_INET6, ADDRESS, &addr.sin6_addr);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(PORT);

bind(s, &addr, sizeof(addr));

Found by InfoTeCS on behalf of Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes eee2fa6ab322 ("rds: Changing IP address internal representation to struct in6_addr")
Fixes 1e2b44e78eea ("rds: Enable RDS IPv6 support")

Stable-dep-of: 78f75d632f74 ("rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()")

---
 net/rds/ib.c    | 4 ++++
 net/rds/ib_cm.c | 4 ++++
 net/rds/tcp.c   | 8 +++++---
 3 files changed, 13 insertions(+), 3 deletions(-)
net/rds/ib.c +4 -0
index ce5be43c5fbac..1061bcf7d1315 100644
@@ -431,6 +431,10 @@ static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
 		sa = (struct sockaddr *)&sin;
 	} else {
 #if IS_ENABLED(CONFIG_IPV6)
+		if (!ipv6_mod_enabled()) {
+			ret = -EADDRNOTAVAIL;
+			goto out;
+		}
 		memset(&sin6, 0, sizeof(sin6));
 		sin6.sin6_family = AF_INET6;
 		sin6.sin6_addr = *addr;
net/rds/ib_cm.c +4 -0
index 5289afbb61aa7..e50e01abb0799 100644
@@ -810,6 +810,10 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
 	dp = event->param.conn.private_data;
 	if (isv6) {
 #if IS_ENABLED(CONFIG_IPV6)
+		if (!ipv6_mod_enabled()) {
+			err = -EOPNOTSUPP;
+			goto out;
+		}
 		dp_cmn = &dp->ricp_v6.dp_cmn;
 		saddr6 = &dp->ricp_v6.dp_saddr;
 		daddr6 = &dp->ricp_v6.dp_daddr;
net/rds/tcp.c +5 -3
index 06a2d8d48bbac..87e6ab0e93b71 100644
@@ -342,9 +342,11 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
 		rcu_read_unlock();
 	}
 #if IS_ENABLED(CONFIG_IPV6)
-	ret = ipv6_chk_addr(net, addr, dev, 0);
-	if (ret)
-		return 0;
+	if (ipv6_mod_enabled()) {
+		ret = ipv6_chk_addr(net, addr, dev, 0);
+		if (ret)
+			return 0;
+	}
 #endif
 	return -EADDRNOTAVAIL;
 }
Signature · 1 line
2.53.0
author maintainer
#51 lore raw

PATCH 52/337 rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei <[email protected]>

[ Upstream commit 78f75d632f74b8de0f081a128588f7c37d0d1164 ]

rds_tcp_laddr_check() looks up a scoped IPv6 interface with dev_get_by_index_rcu(), drops the RCU read-side lock, and only then passes the bare struct net_device * into ipv6_chk_addr().

dev_get_by_index_rcu() only keeps the device alive within the same RCU read-side section. After rcu_read_unlock(), a concurrent RTM_DELLINK can free the net_device; ipv6_chk_addr() then dereferences the stale pointer in __ipv6_chk_addr_and_flags() (e.g. l3mdev_master_dev_rcu(dev)), reading freed memory.

Keep the RCU read-side lock held across the ipv6_chk_addr() call instead of dropping it right after the lookup, so the device cannot be freed while it is in use.

  BUG: KASAN: slab-use-after-free in __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
  Read of size 8 at addr ffff8880106ec000 by task exploit/153
  Call Trace:
   ...
   kasan_report (mm/kasan/report.c:595)
   __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
   ipv6_chk_addr (net/ipv6/addrconf.c:2031 net/ipv6/addrconf.c:1972)
   rds_tcp_laddr_check (net/rds/tcp.c:370)
   rds_bind (net/rds/bind.c:248)
   __sys_bind (net/socket.c:1920)
   __x64_sys_bind (net/socket.c:1956)
   do_syscall_64 (arch/x86/entry/syscall_64.c:63)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Fixes eee2fa6ab322 ("rds: Changing IP address internal representation to struct in6_addr")
---
 net/rds/tcp.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
net/rds/tcp.c +5 -3
index 87e6ab0e93b71..1980a197034ba 100644
@@ -331,23 +331,25 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
 	/* If the scope_id is specified, check only those addresses
 	 * hosted on the specified interface.
 	 */
+	rcu_read_lock();
 	if (scope_id != 0) {
-		rcu_read_lock();
 		dev = dev_get_by_index_rcu(net, scope_id);
 		/* scope_id is not valid... */
 		if (!dev) {
 			rcu_read_unlock();
 			return -EADDRNOTAVAIL;
 		}
-		rcu_read_unlock();
 	}
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6_mod_enabled()) {
 		ret = ipv6_chk_addr(net, addr, dev, 0);
-		if (ret)
+		if (ret) {
+			rcu_read_unlock();
 			return 0;
+		}
 	}
 #endif
+	rcu_read_unlock();
 	return -EADDRNOTAVAIL;
 }
 
Signature · 1 line
2.53.0
author maintainer
#52 lore raw

PATCH 53/337 pinctrl-amd: Dont clear S4 wake bits at probe

In reply to Greg Kroah-Hartman

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

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

From: Mario Limonciello <[email protected]>

[ Upstream commit ffe8a0c6b55285ceaf2f42fc20c3a0594d14f1e9 ]

commit 6bc3462a0f5e ("pinctrl: amd: Mask wake bits on probe again") introduced a regression where Wake-on-LAN no longer works after suspend or shutdown on some AMD platforms.

Firmware-programmed S4 wake bits for devices like PCIe NICs using PCI PME are cleared at probe, but nothing restores them. Unlike S0i3/S3 wake sources that use enable_irq_wake() -> amd_gpio_irq_set_wake(), PCIe PME does not use GPIO IRQ infrastructure and relies on firmware configuration.

The original intent of commit 6bc3462a0f5e ("pinctrl: amd: Mask wake bits on probe again") was to clear spurious wake bits left by firmware to prevent unwanted wakeups. However, S4 wake bits are used for hardware-level wake sources like WoL that bypass the kernel's IRQ wake API.

Fix by preserving S4 wake bits at probe and only clearing S0i3/S3 bits:
- Firmware-configured S4 wake sources (WoL) continue working
- Kernel maintains control of S3/S0i3 wake policy via set_wake()
- S3-only wake sources work correctly per commit f31f33dbb3ba ("pinctrl:
amd: Take suspend type into consideration which pins are non-wake")

The trade-off is that firmware-programmed spurious S4 wake bits remain set, but this is less problematic than breaking WoL.

Fixes 6bc3462a0f5e ("pinctrl: amd: Mask wake bits on probe again")
---
 drivers/pinctrl/pinctrl-amd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/pinctrl/pinctrl-amd.c +1 -2
index debf36ce57857..65006eceaf399 100644
@@ -869,8 +869,7 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
 	u32 pin_reg, mask;
 	int i;
 
-	mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) |
-		BIT(WAKE_CNTRL_OFF_S4);
+	mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3);
 
 	for (i = 0; i < desc->npins; i++) {
 		int pin = desc->pins[i].number;
Signature · 1 line
2.53.0
author maintainer
#53 lore raw

PATCH 54/337 scsi: libiscsi: Fix stale-data leak into the SCSI sense buffer

In reply to Greg Kroah-Hartman

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

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

From: HyeongJun An <[email protected]>

[ Upstream commit 98b87885de4b7f605533a2860685f5689fce8e82 ]

iscsi_scsi_cmd_rsp() copies the sense data of a SCSI Response from the target-supplied data segment. The segment carries a 2-byte sense length followed by the sense bytes, so it must hold 2 + senselen bytes, but the bounds check only requires datalen >= senselen:

	senselen = get_unaligned_be16(data);
	if (datalen < senselen)
		goto invalid_datalen;
	memcpy(sc->sense_buffer, data + 2,
	       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));

A target that returns a SCSI Response whose datalen equals senselen (with senselen <= SCSI_SENSE_BUFFERSIZE) makes the memcpy() from data + 2 read up to two bytes past the received data. Those bytes are stale conn->data contents and end up in the command's sense buffer, which is returned to userspace.

Account for the 2-byte sense length prefix in the check.

Fixes 7996a778ff8c ("[SCSI] iscsi: add libiscsi")
Assisted-by Claude:claude-opus-4-8
---
 drivers/scsi/libiscsi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/libiscsi.c +1 -1
index 29af3722ea220..0f169f243475f 100644
@@ -918,7 +918,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		}
 
 		senselen = get_unaligned_be16(data);
-		if (datalen < senselen)
+		if (datalen < senselen + 2)
 			goto invalid_datalen;
 
 		memcpy(sc->sense_buffer, data + 2,
Signature · 1 line
2.53.0
author maintainer
#54 lore raw

PATCH 55/337 scsi: libiscsi_tcp: Bound SCSI Response data segment to the connection buffer

In reply to Greg Kroah-Hartman

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

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

From: HyeongJun An <[email protected]>

[ Upstream commit c1dea15f819cded9b3faf58f8bec72323568b6e6 ]

iscsi_tcp_hdr_dissect() receives the data segment of several PDU types into the fixed-size conn->data buffer, which is allocated for ISCSI_DEF_MAX_RECV_SEG_LEN (8192) bytes. For the LOGIN_RSP, TEXT_RSP, REJECT and ASYNC_EVENT opcodes the dissect path already rejects a PDU whose DataSegmentLength exceeds that buffer.

The SCSI Command Response (ISCSI_OP_SCSI_CMD_RSP) path also copies its data segment (sense/response data) into conn->data via iscsi_tcp_data_recv_prep(), but it does so without the same check. The only upstream bound on in.datalen is conn->max_recv_dlength, the initiator's advertised MaxRecvDataSegmentLength, which is commonly negotiated well above 8192 (open-iscsi defaults to 262144). A target that returns a SCSI Response with a DataSegmentLength between 8193 and max_recv_dlength therefore overflows the 8192-byte conn->data buffer.

Once the same bound applies, ISCSI_OP_SCSI_CMD_RSP is handled exactly like those responses: bound the data segment, receive it into conn->data when present, and otherwise complete the PDU with no data. Fold the opcode into that case group rather than duplicating the check.

Fixes a081c13e39b5 ("[SCSI] iscsi_tcp: split module into lib and lld")
Assisted-by Claude:claude-opus-4-8
---
 drivers/scsi/libiscsi_tcp.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/scsi/libiscsi_tcp.c +1 -7
index c182aa83f2c93..4d23205129432 100644
@@ -763,13 +763,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
 		spin_unlock(&conn->session->back_lock);
 		break;
-	case ISCSI_OP_SCSI_CMD_RSP:
-		if (tcp_conn->in.datalen) {
-			iscsi_tcp_data_recv_prep(tcp_conn);
-			return 0;
-		}
-		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
-		break;
 	case ISCSI_OP_R2T:
 		if (ahslen) {
 			rc = ISCSI_ERR_AHSLEN;
@@ -777,6 +770,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 		}
 		rc = iscsi_tcp_r2t_rsp(conn, hdr);
 		break;
+	case ISCSI_OP_SCSI_CMD_RSP:
 	case ISCSI_OP_LOGIN_RSP:
 	case ISCSI_OP_TEXT_RSP:
 	case ISCSI_OP_REJECT:
Signature · 1 line
2.53.0
author maintainer
#55 lore raw

PATCH 56/337 scsi: libsas: Fix HA resume deadlock and hisi_sas disk-wake race

In reply to Greg Kroah-Hartman

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

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

From: Xingui Yang <[email protected]>

[ Upstream commit 3dbbbf656b850c9c8de05df6ad4a1dfc6ff02845 ]

Commit fbefe22811c3 ("scsi: libsas: Don't always drain event workqueue for HA resume") introduced sas_resume_ha_no_sync() to avoid a deadlock:
the PHYE_RESUME_TIMEOUT handler, running on the HA event workqueue, calls sas_deform_port() -> sas_destruct_devices(), which removes SCSI devices and waits for the host to become runtime-active. But the host cannot resume until sas_resume_ha() -> sas_drain_work() returns, and the drain is blocked on that very handler.

However skipping the drain reintroduces a race: hisi_sas returns from resume before all PHY UP work and libsas discovery work finish. The controller may then autosuspend while disks are still waking up. The disks issue IO to a suspended controller, the IO fails, and the disks get disabled.

Fix the deadlock at its source by moving the PHYE_RESUME_TIMEOUT notification to after sas_drain_work(). By then the host resume is about to complete, so device removal through device_link no longer blocks on the resume and the cycle is broken.

With the deadlock gone, restore sas_resume_ha() (the draining variant) in hisi_sas and remove sas_resume_ha_no_sync().

The reorder is safe for the other libsas consumers (isci, pm8001, aic94xx, mvsas). During suspend, sas_suspend_devices() calls sas_notify_lldd_dev_gone() for each device, which sets dev->lldd_dev to NULL. When scsi_unblock_requests re-enables I/O in resume, any I/O to a timed-out phy's disk is immediately rejected by the LLDD before reaching
hardware: isci returns SAS_DEVICE_UNKNOWN (mapped to DID_BAD_TARGET), and pm8001 returns SAS_PHY_DOWN (mapped to DID_NO_CONNECT). Both complete directly via scsi_done() without entering SCSI EH. This is identical in both the old and new ordering since lldd_dev_gone runs during suspend, before resume. The reorder only affects when the PHYE_RESUME_TIMEOUT handler runs (synchronized by sas_drain_work() vs. asynchronous after resume returns), not whether I/O can reach the device. aic94xx and mvsas do not register any PM ops and never reach this code path.

Fixes fbefe22811c3 ("scsi: libsas: Don't always drain event workqueue for HA resume")
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +------
 drivers/scsi/libsas/sas_init.c         | 37 +++++++++++++-------------
 include/scsi/libsas.h                  |  1 -
 3 files changed, 19 insertions(+), 29 deletions(-)
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +1 -9
index e958b588d078f..b7dd4efca0c7f 100644
@@ -5219,15 +5219,7 @@ static int _resume_v3_hw(struct device *device)
 		return rc;
 	}
 	phys_init_v3_hw(hisi_hba);
-
-	/*
-	 * If a directly-attached disk is removed during suspend, a deadlock
-	 * may occur, as the PHYE_RESUME_TIMEOUT processing will require the
-	 * hisi_hba->device to be active, which can only happen when resume
-	 * completes. So don't wait for the HA event workqueue to drain upon
-	 * resume.
-	 */
-	sas_resume_ha_no_sync(sha);
+	sas_resume_ha(sha);
 	clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags);
 
 	dev_warn(dev, "end of resuming controller\n");
drivers/scsi/libsas/sas_init.c +18 -19
index 8566bb1208a05..ac157ab6a3011 100644
@@ -409,7 +409,7 @@ static void sas_resume_insert_broadcast_ha(struct sas_ha_struct *ha)
 	}
 }
 
-static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
+void sas_resume_ha(struct sas_ha_struct *ha)
 {
 	const unsigned long tmo = msecs_to_jiffies(25000);
 	int i;
@@ -425,6 +425,23 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
 		dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
 			 i, i > 1 ? "s" : "");
 	wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
+
+	/*
+	 * All phys are back up or timed out. Turn on I/O and drain
+	 * pending work.
+	 */
+	scsi_unblock_requests(ha->shost);
+	sas_drain_work(ha);
+
+	/*
+	 * Send PHYE_RESUME_TIMEOUT after sas_drain_work(). The handler
+	 * calls sas_deform_port() -> sas_destruct_devices(), which removes
+	 * SCSI devices and, for LLDDs using device_link() PM sync, waits
+	 * for the host to be runtime-active. Sending it before the drain
+	 * would deadlock: the drain waits for the handler, the handler
+	 * waits for host resume, and host resume waits for the drain to
+	 * finish.
+	 */
 	for (i = 0; i < ha->num_phys; i++) {
 		struct asd_sas_phy *phy = ha->sas_phy[i];
 
@@ -435,12 +452,6 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
 		}
 	}
 
-	/* all phys are back up or timed out, turn on i/o so we can
-	 * flush out disks that did not return
-	 */
-	scsi_unblock_requests(ha->shost);
-	if (drain)
-		sas_drain_work(ha);
 	clear_bit(SAS_HA_RESUMING, &ha->state);
 
 	sas_queue_deferred_work(ha);
@@ -449,20 +460,8 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
 	 */
 	sas_resume_insert_broadcast_ha(ha);
 }
-
-void sas_resume_ha(struct sas_ha_struct *ha)
-{
-	_sas_resume_ha(ha, true);
-}
 EXPORT_SYMBOL(sas_resume_ha);
 
-/* A no-sync variant, which does not call sas_drain_ha(). */
-void sas_resume_ha_no_sync(struct sas_ha_struct *ha)
-{
-	_sas_resume_ha(ha, false);
-}
-EXPORT_SYMBOL(sas_resume_ha_no_sync);
-
 void sas_suspend_ha(struct sas_ha_struct *ha)
 {
 	int i;
include/scsi/libsas.h +0 -1
index 1324068dd950f..2e3fcae62e27e 100644
@@ -676,7 +676,6 @@ extern int sas_register_ha(struct sas_ha_struct *);
 extern int sas_unregister_ha(struct sas_ha_struct *);
 extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
 extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
-extern void sas_resume_ha_no_sync(struct sas_ha_struct *sas_ha);
 extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
 
 int sas_phy_reset(struct sas_phy *phy, int hard_reset);
Signature · 1 line
2.53.0
author maintainer
#56 lore raw

PATCH 57/337 smb: client: fix buffer leaks in SMB1 read and write

In reply to Greg Kroah-Hartman

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

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

From: Dawei Feng <[email protected]>

[ Upstream commit 6a3e16d60e81a4aa3056ab15617036cfbea2e07d ]

CIFSSMBRead(), CIFSSMBWrite() and CIFSSMBWrite2() allocate a request buffer before checking whether tcon->ses->server is NULL. If that defensive check ever fails, the helper returns -ECONNABORTED without releasing the request buffer.

Fix these leaks by releasing the allocated request buffer before returning from these error paths. Use cifs_small_buf_release() for the buffers allocated by small_smb_init() and cifs_buf_release() for the buffer allocated by smb_init().

The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.

An x86_64 allyesconfig build showed no new warnings.

Runtime validation used a temporary fault-injection hook to force tcon->ses->server to NULL after request-buffer initialization. On the unfixed kernel, the harness observed two leaked small request buffers and one leaked large request buffer, with directed kmemleak dumps confirming the CIFS buffer allocation stacks. After the fix, no CIFS request-buffer deltas remained.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
---
 fs/smb/client/cifssmb.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
fs/smb/client/cifssmb.c +9 -3
index 81a1c116e9031..882d535d17a4c 100644
@@ -1436,8 +1436,10 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
 
 	/* tcon and ses pointer are checked in smb_init */
-	if (tcon->ses->server == NULL)
+	if (!tcon->ses->server) {
+		cifs_small_buf_release(pSMB);
 		return -ECONNABORTED;
+	}
 
 	pSMB->AndXCommand = 0xFF;       /* none */
 	pSMB->Fid = netfid;
@@ -1549,8 +1551,10 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
 
 	/* tcon and ses pointer are checked in smb_init */
-	if (tcon->ses->server == NULL)
+	if (!tcon->ses->server) {
+		cifs_buf_release(pSMB);
 		return -ECONNABORTED;
+	}
 
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
@@ -1816,8 +1820,10 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
 
 	/* tcon and ses pointer are checked in smb_init */
-	if (tcon->ses->server == NULL)
+	if (!tcon->ses->server) {
+		cifs_small_buf_release(pSMB);
 		return -ECONNABORTED;
+	}
 
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
Signature · 1 line
2.53.0
author maintainer
#57 lore raw

PATCH 58/337 spi: spi-cadence: supports transmission with bits_per_word of 16 and 32

In reply to Greg Kroah-Hartman

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

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

From: Jun Guo <[email protected]>

[ Upstream commit 4e00135b2dd1d7924a58bffa551b6ceb3bd836f2 ]

The default FIFO data width of the Cadence SPI IP is 8 bits, but the hardware supports configurations of 16 bits and 32 bits. This patch enhances the driver to support communication with both 16-bits and 32-bits FIFO data widths.

Stable-dep-of: d9eadfce2fac ("spi: spi-cadence: Move TX FIFO full busy-wait into FIFO")

---
 drivers/spi/spi-cadence.c | 106 +++++++++++++++++++++++++++++++++-----
 1 file changed, 93 insertions(+), 13 deletions(-)
drivers/spi/spi-cadence.c +93 -13
index 914384348448d..fee908b7f327e 100644
@@ -109,6 +109,7 @@
  * @rxbuf:		Pointer to the RX buffer
  * @tx_bytes:		Number of bytes left to transfer
  * @rx_bytes:		Number of bytes requested
+ * @n_bytes:		Number of bytes per word
  * @dev_busy:		Device busy flag
  * @is_decoded_cs:	Flag for decoder property set or not
  * @tx_fifo_depth:	Depth of the TX FIFO
@@ -120,16 +121,24 @@ struct cdns_spi {
 	struct clk *pclk;
 	unsigned int clk_rate;
 	u32 speed_hz;
-	const u8 *txbuf;
-	u8 *rxbuf;
+	const void *txbuf;
+	void *rxbuf;
 	int tx_bytes;
 	int rx_bytes;
+	u8 n_bytes;
 	u8 dev_busy;
 	u32 is_decoded_cs;
 	unsigned int tx_fifo_depth;
 	struct reset_control *rstc;
 };
 
+enum cdns_spi_frame_n_bytes {
+	CDNS_SPI_N_BYTES_NULL = 0,
+	CDNS_SPI_N_BYTES_U8 = 1,
+	CDNS_SPI_N_BYTES_U16 = 2,
+	CDNS_SPI_N_BYTES_U32 = 4
+};
+
 /* Macros for the SPI controller read/write */
 static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset)
 {
@@ -305,6 +314,78 @@ static int cdns_spi_setup_transfer(struct spi_device *spi,
 	return 0;
 }
 
+static u8 cdns_spi_n_bytes(struct spi_transfer *transfer)
+{
+	if (transfer->bits_per_word <= 8)
+		return CDNS_SPI_N_BYTES_U8;
+	else if (transfer->bits_per_word <= 16)
+		return CDNS_SPI_N_BYTES_U16;
+	else
+		return CDNS_SPI_N_BYTES_U32;
+}
+
+static inline void cdns_spi_reader(struct cdns_spi *xspi)
+{
+	u32 rxw = 0;
+
+	if (xspi->rxbuf && !IS_ALIGNED((uintptr_t)xspi->rxbuf, xspi->n_bytes)) {
+		pr_err("%s: rxbuf address is not aligned for %d bytes\n",
+		       __func__, xspi->n_bytes);
+		return;
+	}
+
+	rxw = cdns_spi_read(xspi, CDNS_SPI_RXD);
+	if (xspi->rxbuf) {
+		switch (xspi->n_bytes) {
+		case CDNS_SPI_N_BYTES_U8:
+			*(u8 *)xspi->rxbuf = rxw;
+			break;
+		case CDNS_SPI_N_BYTES_U16:
+			*(u16 *)xspi->rxbuf = rxw;
+			break;
+		case CDNS_SPI_N_BYTES_U32:
+			*(u32 *)xspi->rxbuf = rxw;
+			break;
+		default:
+			pr_err("%s invalid n_bytes %d\n", __func__,
+			       xspi->n_bytes);
+			return;
+		}
+		xspi->rxbuf = (u8 *)xspi->rxbuf + xspi->n_bytes;
+	}
+}
+
+static inline void cdns_spi_writer(struct cdns_spi *xspi)
+{
+	u32 txw = 0;
+
+	if (xspi->txbuf && !IS_ALIGNED((uintptr_t)xspi->txbuf, xspi->n_bytes)) {
+		pr_err("%s: txbuf address is not aligned for %d bytes\n",
+		       __func__, xspi->n_bytes);
+		return;
+	}
+
+	if (xspi->txbuf) {
+		switch (xspi->n_bytes) {
+		case CDNS_SPI_N_BYTES_U8:
+			txw = *(u8 *)xspi->txbuf;
+			break;
+		case CDNS_SPI_N_BYTES_U16:
+			txw = *(u16 *)xspi->txbuf;
+			break;
+		case CDNS_SPI_N_BYTES_U32:
+			txw = *(u32 *)xspi->txbuf;
+			break;
+		default:
+			pr_err("%s invalid n_bytes %d\n", __func__,
+			       xspi->n_bytes);
+			return;
+		}
+		cdns_spi_write(xspi, CDNS_SPI_TXD, txw);
+		xspi->txbuf = (u8 *)xspi->txbuf + xspi->n_bytes;
+	}
+}
+
 /**
  * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
  * @xspi:	Pointer to the cdns_spi structure
@@ -321,23 +402,14 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
 
 	while (ntx || nrx) {
 		if (nrx) {
-			u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);
-
-			if (xspi->rxbuf)
-				*xspi->rxbuf++ = data;
-
+			cdns_spi_reader(xspi);
 			nrx--;
 		}
 
 		if (ntx) {
-			if (xspi->txbuf)
-				cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
-			else
-				cdns_spi_write(xspi, CDNS_SPI_TXD, 0);
-
+			cdns_spi_writer(xspi);
 			ntx--;
 		}
-
 	}
 }
 
@@ -454,6 +526,10 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
 	if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
 		udelay(10);
 
+	xspi->n_bytes = cdns_spi_n_bytes(transfer);
+	xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes);
+	xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes);
+
 	cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
 
 	cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
@@ -654,6 +730,9 @@ static int cdns_spi_probe(struct platform_device *pdev)
 	ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
 	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
 
+	if (of_device_is_compatible(pdev->dev.of_node, "cix,sky1-spi-r1p6"))
+		ctlr->bits_per_word_mask |= SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+
 	if (!spi_controller_is_target(ctlr)) {
 		ctlr->mode_bits |=  SPI_CS_HIGH;
 		ctlr->set_cs = cdns_spi_chipselect;
@@ -809,6 +888,7 @@ static const struct dev_pm_ops cdns_spi_dev_pm_ops = {
 
 static const struct of_device_id cdns_spi_of_match[] = {
 	{ .compatible = "xlnx,zynq-spi-r1p6" },
+	{ .compatible = "cix,sky1-spi-r1p6" },
 	{ .compatible = "cdns,spi-r1p6" },
 	{ /* end of table */ }
 };
Signature · 1 line
2.53.0
author maintainer
#58 lore raw

PATCH 59/337 spi: spi-cadence: Move TX FIFO full busy-wait into FIFO

In reply to Greg Kroah-Hartman

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

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

From: Srikanth Boyapally <[email protected]>

[ Upstream commit d9eadfce2fac49445db40808fe4d8259f20a9d2b ]

SPI host transfers could intermittently stall with spi_transfer timeouts. The TXFULL condition was checked only once in cdns_transfer_one() before cdns_spi_process_fifo(), so if the FIFO became full again during refill, writes could be dropped and the transfer would never complete.

Move the TXFULL busy-wait into the TX path of cdns_spi_process_fifo() so the 10µs back-off is applied per FIFO entry during filling, ensuring forward progress and eliminating spurious timeouts.

Restrict the delay to host mode using spi_controller_is_target(), the controller is passed into cdns_spi_process_fifo() so the check is made at the point of use. In target mode this delay must not run as it causes the target to miss its transfer window and corrupt data.

Fixes 49530e641178 ("spi: cadence: Add usleep_range() for cdns_spi_fill_tx_fifo()")
---
 drivers/spi/spi-cadence.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/spi/spi-cadence.c +16 -10
index fee908b7f327e..015dce7fc9d81 100644
@@ -388,11 +388,13 @@ static inline void cdns_spi_writer(struct cdns_spi *xspi)
 
 /**
  * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
+ * @ctlr:	Pointer to the spi_controller structure
  * @xspi:	Pointer to the cdns_spi structure
  * @ntx:	Number of bytes to pack into the TX FIFO
  * @nrx:	Number of bytes to drain from the RX FIFO
  */
-static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
+static void cdns_spi_process_fifo(struct spi_controller *ctlr,
+				  struct cdns_spi *xspi, int ntx, int nrx)
 {
 	ntx = clamp(ntx, 0, xspi->tx_bytes);
 	nrx = clamp(nrx, 0, xspi->rx_bytes);
@@ -407,6 +409,16 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
 		}
 
 		if (ntx) {
+			/* When xspi in busy condition, bytes may send failed,
+			 * then spi control didn't work thoroughly, add one byte
+			 * delay. Only in host mode; in target mode this delay
+			 * causes data corruption as the target fails to prepare
+			 * data in time.
+			 */
+			if (!spi_controller_is_target(ctlr) &&
+			    (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL))
+				udelay(10);
+
 			cdns_spi_writer(xspi);
 			ntx--;
 		}
@@ -460,14 +472,14 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
 			cdns_spi_write(xspi, CDNS_SPI_THLD, 1);
 
 		if (xspi->tx_bytes) {
-			cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
+			cdns_spi_process_fifo(ctlr, xspi, trans_cnt, trans_cnt);
 		} else {
 			/* Fixed delay due to controller limitation with
 			 * RX_NEMPTY incorrect status
 			 * Xilinx AR:65885 contains more details
 			 */
 			udelay(10);
-			cdns_spi_process_fifo(xspi, 0, trans_cnt);
+			cdns_spi_process_fifo(ctlr, xspi, 0, trans_cnt);
 			cdns_spi_write(xspi, CDNS_SPI_IDR,
 				       CDNS_SPI_IXR_DEFAULT);
 			spi_finalize_current_transfer(ctlr);
@@ -520,17 +532,11 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
 			cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
 	}
 
-	/* When xspi in busy condition, bytes may send failed,
-	 * then spi control didn't work thoroughly, add one byte delay
-	 */
-	if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
-		udelay(10);
-
 	xspi->n_bytes = cdns_spi_n_bytes(transfer);
 	xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes);
 	xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes);
 
-	cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
+	cdns_spi_process_fifo(ctlr, xspi, xspi->tx_fifo_depth, 0);
 
 	cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
 	return transfer->len;
Signature · 1 line
2.53.0
author maintainer
#59 lore raw

PATCH 60/337 hwmon: (nct6775-core) Fix number of temperature registers for NCT6116

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit b0e8adb2ccb43009796897ced09f91636685c9d3 ]

Unlike NCT6106, NCT6116 only has three temperature registers, and with it only three temperature source and temperature source configuration registers. The register addresses match those of NCT6106 and can be re-used.

The code used a separate array to list the temperature source registers for NCT6116, but used the size of the NCT6106 register array to set the number of registers. The NCT6106 register array provides six addresses, while the temperature source register array for NCT6116 only provides three addresses. This causes a KASAN report.

BUG: KASAN: global-out-of-bounds in nct6775_probe+0x936/0x46f0 [nct6775]
Read of size 2 at addr ffffffffc19561a6 by task modprobe/954
...
Call Trace:
 dump_stack+0x7d/0xa7
 print_address_description.constprop.0+0x1c/0x220
 ? __kasan_kmalloc.constprop.0+0xc9/0xd0
 ? __kmalloc_node_track_caller+0x194/0x5b0
 ? nct6775_probe+0x936/0x46f0 [nct6775]
 ? nct6775_probe+0x936/0x46f0 [nct6775]

...

Fix the problem by hard-coding the number of temperature and temperature configuration registers to three for NCT6116. Drop the unnecessary NCT6116_REG_TEMP_SOURCE array and re-use NCT6106_REG_TEMP_SOURCE.

Fixes 29c7cb485b32 ("hwmon: (nct6775) Integrate new model nct6116")
Cc Björn Gerhart <[email protected]>
---
 drivers/hwmon/nct6775-core.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/hwmon/nct6775-core.c +3 -5
index 79bc67ffb9986..506d57025c3bd 100644
@@ -846,8 +846,6 @@ static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
 static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
 static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
 static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
-static const u16 NCT6116_REG_TEMP_SOURCE[] = {
-	0xb0, 0xb1, 0xb2 };
 
 static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
 	0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
@@ -3650,7 +3648,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
 		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
 		data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
 		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
-		data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
+		data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
 		data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
 		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
 		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
@@ -3664,13 +3662,13 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
 
 		reg_temp = NCT6106_REG_TEMP;
 		reg_temp_mon = NCT6106_REG_TEMP_MON;
-		num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+		num_reg_temp = 3;
 		num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
 		num_reg_tsi_temp = ARRAY_SIZE(NCT6116_REG_TSI_TEMP);
 		reg_temp_over = NCT6106_REG_TEMP_OVER;
 		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
 		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
-		num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
+		num_reg_temp_config = 3;
 		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
 		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
 		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
Signature · 1 line
2.53.0
author maintainer
#60 lore raw

PATCH 61/337 hwmon: (ina2xx) Add support for has_alerts configuration flag

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit de0da6ae1908b43b23782d64b4564b5ca3119f7f ]

Add configuration flag indicating if the chip supports alerts and limits to prepare for adding INA260 support.

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 drivers/hwmon/ina2xx.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)
drivers/hwmon/ina2xx.c +11 -7
index f0fa6d073627f..03a011c9b73da 100644
@@ -129,6 +129,7 @@ enum ina2xx_ids { ina219, ina226 };
 
 struct ina2xx_config {
 	u16 config_default;
+	bool has_alerts;	/* chip supports alerts and limits */
 	int calibration_value;
 	int shunt_div;
 	int bus_voltage_shift;
@@ -155,6 +156,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.bus_voltage_shift = 3,
 		.bus_voltage_lsb = 4000,
 		.power_lsb_factor = 20,
+		.has_alerts = false,
 	},
 	[ina226] = {
 		.config_default = INA226_CONFIG_DEFAULT,
@@ -163,6 +165,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
 		.power_lsb_factor = 25,
+		.has_alerts = true,
 	},
 };
 
@@ -624,6 +627,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 				 u32 attr, int channel)
 {
 	const struct ina2xx_data *data = _data;
+	bool has_alerts = data->config->has_alerts;
 	enum ina2xx_ids chip = data->chip;
 
 	switch (type) {
@@ -633,12 +637,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 			return 0444;
 		case hwmon_in_lcrit:
 		case hwmon_in_crit:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0644;
 			break;
 		case hwmon_in_lcrit_alarm:
 		case hwmon_in_crit_alarm:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0444;
 			break;
 		default:
@@ -651,12 +655,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 			return 0444;
 		case hwmon_curr_lcrit:
 		case hwmon_curr_crit:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0644;
 			break;
 		case hwmon_curr_lcrit_alarm:
 		case hwmon_curr_crit_alarm:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0444;
 			break;
 		default:
@@ -668,11 +672,11 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 		case hwmon_power_input:
 			return 0444;
 		case hwmon_power_crit:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0644;
 			break;
 		case hwmon_power_crit_alarm:
-			if (chip == ina226)
+			if (has_alerts)
 				return 0444;
 			break;
 		default:
@@ -802,7 +806,7 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data)
 	if (ret < 0)
 		return ret;
 
-	if (data->chip == ina226) {
+	if (data->config->has_alerts) {
 		bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high");
 
 		regmap_update_bits(regmap, INA226_MASK_ENABLE,
Signature · 1 line
2.53.0
author maintainer
#61 lore raw

PATCH 62/337 hwmon: (ina2xx) Add support for INA260

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 70fb84a109c639637f0636281dbdb21ed8ffb000 ]

INA260 is similar to other chips of the series, except it has an internal shunt resistor. The calibration register is therefore not present. Also, the current register address was changed, though that does not matter for the driver since the shunt voltage register (which is now the current register) value is already used to read the current.

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 Documentation/hwmon/ina2xx.rst | 23 +++++++++++++++----
 drivers/hwmon/Kconfig          |  5 ++--
 drivers/hwmon/ina2xx.c         | 42 ++++++++++++++++++++++++++++++----
 3 files changed, 59 insertions(+), 11 deletions(-)
Documentation/hwmon/ina2xx.rst +18 -5
index 7f1939b40f74f..1ce161e6c0bf0 100644
@@ -53,6 +53,16 @@ Supported chips:
 
 	       https://www.ti.com/
 
+  * Texas Instruments INA260
+
+    Prefix: 'ina260'
+
+    Addresses: I2C 0x40 - 0x4f
+
+    Datasheet: Publicly available at the Texas Instruments website
+
+	       https://www.ti.com/
+
 Author: Lothar Felten <[email protected]>
 
 Description
@@ -72,6 +82,9 @@ INA230 and INA231 are high or low side current shunt and power monitors
 with an I2C interface. The chips monitor both a shunt voltage drop and
 bus supply voltage.
 
+INA260 is a high or low side current and power monitor with integrated shunt
+resistor.
+
 The shunt value in micro-ohms can be set via platform data or device tree at
 compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
 refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings
@@ -87,16 +100,16 @@ The actual programmed interval may vary from the desired value.
 General sysfs entries
 ---------------------
 
-======================= ===============================
+======================= ===============================================
 in0_input		Shunt voltage(mV) channel
 in1_input		Bus voltage(mV) channel
 curr1_input		Current(mA) measurement channel
 power1_input		Power(uW) measurement channel
-shunt_resistor		Shunt resistance(uOhm) channel
-======================= ===============================
+shunt_resistor		Shunt resistance(uOhm) channel (not for ina260)
+======================= ===============================================
 
-Sysfs entries for ina226, ina230 and ina231 only
-------------------------------------------------
+Additional sysfs entries for ina226, ina230, ina231, and ina260
+---------------------------------------------------------------
 
 ======================= ====================================================
 curr1_lcrit		Critical low current
drivers/hwmon/Kconfig +3 -2
index acd0f86cb9b38..681722626bc48 100644
@@ -2170,11 +2170,12 @@ config SENSORS_INA2XX
 	select REGMAP_I2C
 	help
 	  If you say yes here you get support for INA219, INA220, INA226,
-	  INA230, and INA231 power monitor chips.
+	  INA230, INA231, and INA260 power monitor chips.
 
 	  The INA2xx driver is configured for the default configuration of
 	  the part as described in the datasheet.
-	  Default value for Rshunt is 10 mOhms.
+	  Default value for Rshunt is 10 mOhms except for INA260 which has an
+	  internal 2 mOhm shunt resistor.
 	  This driver can also be built as a module. If so, the module
 	  will be called ina2xx.
 
drivers/hwmon/ina2xx.c +38 -4

118 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#62 lore raw

PATCH 63/337 hwmon: (ina226) Add support for SY24655

In reply to Greg Kroah-Hartman

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

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

From: Wenliang Yan <[email protected]>

[ Upstream commit 52172ad87a22ed6e687ca678da21d3c949bc89a1 ]

SY24655: Support for current and voltage detection as well as power calculation.

Message-ID: <[email protected]> [groeck: Changed order of compatible entries;
dropped spurious extra return statement in is_visible(); fixed code problems]

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 Documentation/hwmon/ina2xx.rst | 27 +++++++++-
 drivers/hwmon/Kconfig          |  2 +-
 drivers/hwmon/ina2xx.c         | 94 ++++++++++++++++++++++++++++++++--
 3 files changed, 116 insertions(+), 7 deletions(-)
Documentation/hwmon/ina2xx.rst +25 -2
index 1ce161e6c0bf0..a3860aae444c0 100644
@@ -63,6 +63,17 @@ Supported chips:
 
 	       https://www.ti.com/
 
+  * Silergy SY24655
+
+    Prefix: 'sy24655'
+
+    Addresses: I2C 0x40 - 0x4f
+
+    Datasheet: Publicly available at the Silergy website
+
+	       https://us1.silergy.com/
+
+
 Author: Lothar Felten <[email protected]>
 
 Description
@@ -85,6 +96,11 @@ bus supply voltage.
 INA260 is a high or low side current and power monitor with integrated shunt
 resistor.
 
+The SY24655 is a high- and low-side current shunt and power monitor with an I2C
+interface. The SY24655 supports both shunt drop and supply voltage, with
+programmable calibration value and conversion times. The SY24655 can also
+calculate average power for use in energy conversion.
+
 The shunt value in micro-ohms can be set via platform data or device tree at
 compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
 refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings
@@ -108,8 +124,8 @@ power1_input		Power(uW) measurement channel
 shunt_resistor		Shunt resistance(uOhm) channel (not for ina260)
 ======================= ===============================================
 
-Additional sysfs entries for ina226, ina230, ina231, and ina260
----------------------------------------------------------------
+Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655
+------------------------------------------------------------------------
 
 ======================= ====================================================
 curr1_lcrit		Critical low current
@@ -130,6 +146,13 @@ update_interval		data conversion time; affects number of samples used
 			to average results for shunt and bus voltages.
 ======================= ====================================================
 
+Sysfs entries for sy24655 only
+------------------------------
+
+======================= ====================================================
+power1_average		average power from last reading to the present.
+======================= ====================================================
+
 .. note::
 
    - Configure `shunt_resistor` before configure `power1_crit`, because power
drivers/hwmon/Kconfig +1 -1
index 681722626bc48..195c7b505a853 100644
@@ -2170,7 +2170,7 @@ config SENSORS_INA2XX
 	select REGMAP_I2C
 	help
 	  If you say yes here you get support for INA219, INA220, INA226,
-	  INA230, INA231, and INA260 power monitor chips.
+	  INA230, INA231, INA260, and SY24655 power monitor chips.
 
 	  The INA2xx driver is configured for the default configuration of
 	  the part as described in the datasheet.
drivers/hwmon/ina2xx.c +90 -4

205 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#63 lore raw

PATCH 64/337 hwmon: (ina2xx) Make it easier to add more devices

In reply to Greg Kroah-Hartman

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

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

From: Ian Ray <[email protected]>

[ Upstream commit f6e14b5bcabf4ee97a2d535c3c2d7e72c8da4c15 ]

* Make sysfs entries documentation easier to maintain.
* Use multi-line enum.
* Correct "has_power_average" comment.

Create a new "has_update_interval" member for chips which support averaging.

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 Documentation/hwmon/ina2xx.rst | 12 ++++++++++--
 drivers/hwmon/ina2xx.c         | 18 ++++++++++++++----
 2 files changed, 24 insertions(+), 6 deletions(-)
Documentation/hwmon/ina2xx.rst +10 -2
index a3860aae444c0..a4ddf4bd2b081 100644
@@ -124,8 +124,16 @@ power1_input		Power(uW) measurement channel
 shunt_resistor		Shunt resistance(uOhm) channel (not for ina260)
 ======================= ===============================================
 
-Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655
-------------------------------------------------------------------------
+Additional sysfs entries
+------------------------
+
+Additional entries are available for the following chips:
+
+  * ina226
+  * ina230
+  * ina231
+  * ina260
+  * sy24655
 
 ======================= ====================================================
 curr1_lcrit		Critical low current
drivers/hwmon/ina2xx.c +14 -4
index 345fe7db9de94..97ec0e0218307 100644
@@ -135,13 +135,19 @@ static const struct regmap_config ina2xx_regmap_config = {
 	.writeable_reg = ina2xx_writeable_reg,
 };
 
-enum ina2xx_ids { ina219, ina226, ina260, sy24655 };
+enum ina2xx_ids {
+	ina219,
+	ina226,
+	ina260,
+	sy24655
+};
 
 struct ina2xx_config {
 	u16 config_default;
 	bool has_alerts;	/* chip supports alerts and limits */
 	bool has_ishunt;	/* chip has internal shunt resistor */
-	bool has_power_average;	/* chip has internal shunt resistor */
+	bool has_power_average;	/* chip supports average power */
+	bool has_update_interval;
 	int calibration_value;
 	int shunt_div;
 	int bus_voltage_shift;
@@ -172,6 +178,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.has_alerts = false,
 		.has_ishunt = false,
 		.has_power_average = false,
+		.has_update_interval = false,
 	},
 	[ina226] = {
 		.config_default = INA226_CONFIG_DEFAULT,
@@ -183,6 +190,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.has_alerts = true,
 		.has_ishunt = false,
 		.has_power_average = false,
+		.has_update_interval = true,
 	},
 	[ina260] = {
 		.config_default = INA260_CONFIG_DEFAULT,
@@ -193,6 +201,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.has_alerts = true,
 		.has_ishunt = true,
 		.has_power_average = false,
+		.has_update_interval = true,
 	},
 	[sy24655] = {
 		.config_default = SY24655_CONFIG_DEFAULT,
@@ -204,6 +213,7 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.has_alerts = true,
 		.has_ishunt = false,
 		.has_power_average = true,
+		.has_update_interval = false,
 	},
 };
 
@@ -713,7 +723,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 	const struct ina2xx_data *data = _data;
 	bool has_alerts = data->config->has_alerts;
 	bool has_power_average = data->config->has_power_average;
-	enum ina2xx_ids chip = data->chip;
+	bool has_update_interval = data->config->has_update_interval;
 
 	switch (type) {
 	case hwmon_in:
@@ -775,7 +785,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
 	case hwmon_chip:
 		switch (attr) {
 		case hwmon_chip_update_interval:
-			if (chip == ina226 || chip == ina260)
+			if (has_update_interval)
 				return 0644;
 			break;
 		default:
Signature · 1 line
2.53.0
author maintainer
#64 lore raw

PATCH 65/337 hwmon: (ina2xx) Add support for INA234

In reply to Greg Kroah-Hartman

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

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

From: Ian Ray <[email protected]>

[ Upstream commit 88a928eebccdc5445d874ddcbf1683b76c9f1431 ]

INA234 is register compatible to INA226 (excepting manufacturer and die or device id registers) but has different scaling.

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 Documentation/hwmon/ina2xx.rst | 13 ++++++++++++-
 drivers/hwmon/Kconfig          |  2 +-
 drivers/hwmon/ina2xx.c         | 18 ++++++++++++++++++
 3 files changed, 31 insertions(+), 2 deletions(-)
Documentation/hwmon/ina2xx.rst +12 -1
index a4ddf4bd2b081..d64e7af46a124 100644
@@ -74,6 +74,16 @@ Supported chips:
 	       https://us1.silergy.com/
 
 
+  * Texas Instruments INA234
+
+    Prefix: 'ina234'
+
+    Addresses: I2C 0x40 - 0x43
+
+    Datasheet: Publicly available at the Texas Instruments website
+
+	       https://www.ti.com/
+
 Author: Lothar Felten <[email protected]>
 
 Description
@@ -89,7 +99,7 @@ interface. The INA220 monitors both shunt drop and supply voltage.
 The INA226 is a current shunt and power monitor with an I2C interface.
 The INA226 monitors both a shunt voltage drop and bus supply voltage.
 
-INA230 and INA231 are high or low side current shunt and power monitors
+INA230, INA231, and INA234 are high or low side current shunt and power monitors
 with an I2C interface. The chips monitor both a shunt voltage drop and
 bus supply voltage.
 
@@ -132,6 +142,7 @@ Additional entries are available for the following chips:
   * ina226
   * ina230
   * ina231
+  * ina234
   * ina260
   * sy24655
 
drivers/hwmon/Kconfig +1 -1
index 195c7b505a853..848b9cfcb1d87 100644
@@ -2170,7 +2170,7 @@ config SENSORS_INA2XX
 	select REGMAP_I2C
 	help
 	  If you say yes here you get support for INA219, INA220, INA226,
-	  INA230, INA231, INA260, and SY24655 power monitor chips.
+	  INA230, INA231, INA234, INA260, and SY24655 power monitor chips.
 
 	  The INA2xx driver is configured for the default configuration of
 	  the part as described in the datasheet.
drivers/hwmon/ina2xx.c +18 -0
index 97ec0e0218307..be6e214fae21f 100644
@@ -138,6 +138,7 @@ static const struct regmap_config ina2xx_regmap_config = {
 enum ina2xx_ids {
 	ina219,
 	ina226,
+	ina234,
 	ina260,
 	sy24655
 };
@@ -192,6 +193,18 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.has_power_average = false,
 		.has_update_interval = true,
 	},
+	[ina234] = {
+		.config_default = INA226_CONFIG_DEFAULT,
+		.calibration_value = 2048,
+		.shunt_div = 400, /* 2.5 µV/LSB raw ADC reading from INA2XX_SHUNT_VOLTAGE */
+		.bus_voltage_shift = 4,
+		.bus_voltage_lsb = 25600,
+		.power_lsb_factor = 32,
+		.has_alerts = true,
+		.has_ishunt = false,
+		.has_power_average = false,
+		.has_update_interval = true,
+	},
 	[ina260] = {
 		.config_default = INA260_CONFIG_DEFAULT,
 		.shunt_div = 400,
@@ -996,6 +1009,7 @@ static const struct i2c_device_id ina2xx_id[] = {
 	{ "ina226", ina226 },
 	{ "ina230", ina226 },
 	{ "ina231", ina226 },
+	{ "ina234", ina234 },
 	{ "ina260", ina260 },
 	{ "sy24655", sy24655 },
 	{ }
@@ -1027,6 +1041,10 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = {
 		.compatible = "ti,ina231",
 		.data = (void *)ina226
 	},
+	{
+		.compatible = "ti,ina234",
+		.data = (void *)ina234
+	},
 	{
 		.compatible = "ti,ina260",
 		.data = (void *)ina260
Signature · 1 line
2.53.0
author maintainer
#65 lore raw

PATCH 66/337 hwmon: (ina2xx) Shift INA234 shunt and current registers

In reply to Greg Kroah-Hartman

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

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

From: Jonas Rebmann <[email protected]>

[ Upstream commit eeca1114d1e2cc0eacaebb80f3f2afbaebfc60be ]

The INA219 has the lowest three bits of the bus voltage register zero-reserved, the bus_voltage_shift ina2xx_config field was introduced to accommodate for that.

The INA234 has four bits of the bus voltage, of the shunt voltage, and of the current registers zero-reserved but the latter two were implemented by choosing a 16x higher shunt_div instead of a separate field specifying a bit shift.

This is possible because shunt voltage and current are divided by shunt_div, hence a 16x higher shunt_div results in a 16x smaller LSB for both the shunt voltage and the current register, perfectly accounting for the missing bit shift.

For consistency and correctness, account for the reserved bits via shunt_voltage_shift and current_shift configuration fields as already done for voltage registers and use the conversion constants given in the INA234 datasheet.

Stable-dep-of: e6c80061ca23 ("hwmon: (ina2xx) Fix various overflow issues")

---
 drivers/hwmon/ina2xx.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)
drivers/hwmon/ina2xx.c +19 -3
index be6e214fae21f..d671d546b2054 100644
@@ -151,9 +151,11 @@ struct ina2xx_config {
 	bool has_update_interval;
 	int calibration_value;
 	int shunt_div;
+	int shunt_voltage_shift;
 	int bus_voltage_shift;
 	int bus_voltage_lsb;	/* uV */
 	int power_lsb_factor;
+	int current_shift;
 };
 
 struct ina2xx_data {
@@ -173,59 +175,69 @@ static const struct ina2xx_config ina2xx_config[] = {
 		.config_default = INA219_CONFIG_DEFAULT,
 		.calibration_value = 4096,
 		.shunt_div = 100,
+		.shunt_voltage_shift = 0,
 		.bus_voltage_shift = 3,
 		.bus_voltage_lsb = 4000,
 		.power_lsb_factor = 20,
 		.has_alerts = false,
 		.has_ishunt = false,
 		.has_power_average = false,
+		.current_shift = 0,
 		.has_update_interval = false,
 	},
 	[ina226] = {
 		.config_default = INA226_CONFIG_DEFAULT,
 		.calibration_value = 2048,
 		.shunt_div = 400,
+		.shunt_voltage_shift = 0,
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
 		.power_lsb_factor = 25,
 		.has_alerts = true,
 		.has_ishunt = false,
 		.has_power_average = false,
+		.current_shift = 0,
 		.has_update_interval = true,
 	},
 	[ina234] = {
 		.config_default = INA226_CONFIG_DEFAULT,
 		.calibration_value = 2048,
-		.shunt_div = 400, /* 2.5 µV/LSB raw ADC reading from INA2XX_SHUNT_VOLTAGE */
+		.shunt_div = 25, /* 2.5 µV/LSB raw ADC reading from INA2XX_SHUNT_VOLTAGE */
+		.shunt_voltage_shift = 4,
 		.bus_voltage_shift = 4,
 		.bus_voltage_lsb = 25600,
 		.power_lsb_factor = 32,
 		.has_alerts = true,
 		.has_ishunt = false,
 		.has_power_average = false,
+		.current_shift = 4,
 		.has_update_interval = true,
 	},
 	[ina260] = {
 		.config_default = INA260_CONFIG_DEFAULT,
 		.shunt_div = 400,
+		.shunt_voltage_shift = 0,
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
 		.power_lsb_factor = 8,
 		.has_alerts = true,
 		.has_ishunt = true,
 		.has_power_average = false,
+		.current_shift = 0,
 		.has_update_interval = true,
 	},
 	[sy24655] = {
 		.config_default = SY24655_CONFIG_DEFAULT,
 		.calibration_value = 4096,
 		.shunt_div = 400,
+		.shunt_voltage_shift = 0,
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
 		.power_lsb_factor = 25,
 		.has_alerts = true,
 		.has_ishunt = false,
 		.has_power_average = true,
+		.current_shift = 0,
 		.has_update_interval = false,
 	},
 };
@@ -279,7 +291,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
 	switch (reg) {
 	case INA2XX_SHUNT_VOLTAGE:
 		/* signed register */
-		val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div);
+		val = (s16)regval >> data->config->shunt_voltage_shift;
+		val = DIV_ROUND_CLOSEST(val, data->config->shunt_div);
 		break;
 	case INA2XX_BUS_VOLTAGE:
 		val = (regval >> data->config->bus_voltage_shift) *
@@ -291,7 +304,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
 		break;
 	case INA2XX_CURRENT:
 		/* signed register, result in mA */
-		val = (s16)regval * data->current_lsb_uA;
+		val = ((s16)regval >> data->config->current_shift) *
+		  data->current_lsb_uA;
 		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_CALIBRATION:
@@ -385,6 +399,7 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
 	case INA2XX_SHUNT_VOLTAGE:
 		val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div);
 		val *= data->config->shunt_div;
+		val <<= data->config->shunt_voltage_shift;
 		return clamp_val(val, 0, SHRT_MAX);
 	case INA2XX_BUS_VOLTAGE:
 		val = clamp_val(val, 0, 200000);
@@ -399,6 +414,7 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
 		val = clamp_val(val, INT_MIN / 1000, INT_MAX / 1000);
 		/* signed register, result in mA */
 		val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_uA);
+		val <<= data->config->current_shift;
 		return clamp_val(val, SHRT_MIN, SHRT_MAX);
 	default:
 		/* programmer goofed */
Signature · 1 line
2.53.0
author maintainer
#66 lore raw

PATCH 67/337 hwmon: (ina2xx) Fix various overflow issues

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit e6c80061ca239f45c0eaf7e47a91d6d6df9bd636 ]

Sashiko reports several integer overflow problems in the ina2xx driver caused by unbounded multiplications and inadequate types for intermediate calculations.

Specifically:
- In ina2xx_get_value(), the return type is changed from int to long. Intermediate calculations for current are now performed using 64-bit types to prevent 32-bit integer overflow before the division by 1000.
- When calculating power in ina2xx_get_value() and sy24655_average_power_read(), interim values are cast to u64 and clamped to LONG_MAX. This prevents overflow when regval or accumulator_24 is multiplied by power_lsb_uW.
- In ina226_alert_to_reg(), the clamping logic is rewritten using min_t(). This safely avoids integer overflows when scaling user-provided values for shunt voltage, bus voltage, power, and current limits.

Cc Loic Poulain <[email protected]>
Fixes ab7fbee452be ("hwmon: (ina2xx) Fix various overflow issues")
---
 drivers/hwmon/ina2xx.c | 61 ++++++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 26 deletions(-)
drivers/hwmon/ina2xx.c +35 -26
index d671d546b2054..c504bb43a2ca3 100644
@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/limits.h>
 #include <linux/module.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
@@ -283,30 +284,34 @@ static u16 ina226_interval_to_reg(long interval)
 	return FIELD_PREP(INA226_AVG_RD_MASK, avg_bits);
 }
 
-static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
-			    unsigned int regval)
+static long ina2xx_get_value(struct ina2xx_data *data, u8 reg,
+			     unsigned int regval)
 {
-	int val;
+	s64 val64;
+	long val;
 
 	switch (reg) {
 	case INA2XX_SHUNT_VOLTAGE:
 		/* signed register */
-		val = (s16)regval >> data->config->shunt_voltage_shift;
-		val = DIV_ROUND_CLOSEST(val, data->config->shunt_div);
+		val = DIV_ROUND_CLOSEST((s16)regval >> data->config->shunt_voltage_shift,
+					data->config->shunt_div);
 		break;
 	case INA2XX_BUS_VOLTAGE:
-		val = (regval >> data->config->bus_voltage_shift) *
-		  data->config->bus_voltage_lsb;
-		val = DIV_ROUND_CLOSEST(val, 1000);
+		val = DIV_ROUND_CLOSEST((regval >> data->config->bus_voltage_shift) *
+					data->config->bus_voltage_lsb, 1000);
 		break;
 	case INA2XX_POWER:
-		val = regval * data->power_lsb_uW;
+		val = min_t(u64, (u64)regval * data->power_lsb_uW, LONG_MAX);
 		break;
 	case INA2XX_CURRENT:
 		/* signed register, result in mA */
-		val = ((s16)regval >> data->config->current_shift) *
+		val64 = (s64)((s16)regval >> data->config->current_shift) *
 		  data->current_lsb_uA;
-		val = DIV_ROUND_CLOSEST(val, 1000);
+		if (val64 < 0)
+			val64 = -DIV_ROUND_CLOSEST_ULL(-val64, 1000);
+		else
+			val64 = DIV_ROUND_CLOSEST_ULL(val64, 1000);
+		val = clamp_val(val64, LONG_MIN, LONG_MAX);
 		break;
 	case INA2XX_CALIBRATION:
 		val = regval;
@@ -395,27 +400,29 @@ static int ina2xx_read_init(struct device *dev, int reg, long *val)
  */
 static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
 {
+	long limit;
+
 	switch (reg) {
 	case INA2XX_SHUNT_VOLTAGE:
-		val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div);
-		val *= data->config->shunt_div;
-		val <<= data->config->shunt_voltage_shift;
-		return clamp_val(val, 0, SHRT_MAX);
+		val = min_t(long, val, DIV_ROUND_CLOSEST(SHRT_MAX, data->config->shunt_div));
+		return min_t(long, (val * data->config->shunt_div) << data->config->shunt_voltage_shift,
+			     SHRT_MAX);
 	case INA2XX_BUS_VOLTAGE:
-		val = clamp_val(val, 0, 200000);
-		val = (val * 1000) << data->config->bus_voltage_shift;
-		val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb);
-		return clamp_val(val, 0, USHRT_MAX);
+		val = min_t(long, val, 130000);
+		return min_t(long,
+			     DIV_ROUND_CLOSEST((val * 1000) << data->config->bus_voltage_shift,
+					       data->config->bus_voltage_lsb),
+			     USHRT_MAX);
 	case INA2XX_POWER:
-		val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
-		val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW);
-		return clamp_val(val, 0, USHRT_MAX);
+		val = min_t(long, val, LONG_MAX - data->power_lsb_uW);
+		return min_t(long, DIV_ROUND_CLOSEST(val, data->power_lsb_uW), USHRT_MAX);
 	case INA2XX_CURRENT:
-		val = clamp_val(val, INT_MIN / 1000, INT_MAX / 1000);
+		limit = (LONG_MAX - (data->current_lsb_uA / 2)) / 1000;
+		val = min_t(long, val, limit);
 		/* signed register, result in mA */
 		val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_uA);
-		val <<= data->config->current_shift;
-		return clamp_val(val, SHRT_MIN, SHRT_MAX);
+		limit = SHRT_MAX >> data->config->current_shift;
+		return (u16)(min_t(long, val, limit) << data->config->current_shift);
 	default:
 		/* programmer goofed */
 		WARN_ON_ONCE(1);
@@ -560,6 +567,7 @@ static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *va
 	u8 template[6];
 	int ret;
 	long accumulator_24, sample_count;
+	u64 val64;
 
 	/* 48-bit register read */
 	ret = i2c_smbus_read_i2c_block_data(data->client, reg, 6, template);
@@ -578,7 +586,8 @@ static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *va
 		return 0;
 	}
 
-	*val = DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW;
+	val64 = (u64)DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW;
+	*val = min_t(u64, val64, LONG_MAX);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#67 lore raw

PATCH 68/337 hwmon: (ltc4282) Fix reading the minimum alarm voltage

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 00feb1cce93dab948a299b69753d99c681d45a0b ]

Coverity reports an out-of-bounds access when reading the minimum alarm voltage for the VGPIO channel. Add the missing return statement to fix the problem.

Fixes cbc29538dbf7 ("hwmon: Add driver for LTC4282")
Cc Nuno Sa <[email protected]>
---
 drivers/hwmon/ltc4282.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/ltc4282.c +2 -2
index d98c57918ce33..e1c0d02b564b7 100644
@@ -382,8 +382,8 @@ static int ltc4282_read_in(struct ltc4282_state *st, u32 attr, long *val,
 						   channel, val);
 	case hwmon_in_min_alarm:
 		if (channel == LTC4282_CHAN_VGPIO)
-			ltc4282_read_alarm(st, LTC4282_ADC_ALERT_LOG,
-					   LTC4282_GPIO_ALARM_L_MASK, val);
+			return ltc4282_read_alarm(st, LTC4282_ADC_ALERT_LOG,
+						  LTC4282_GPIO_ALARM_L_MASK, val);
 
 		return ltc4282_vdd_source_read_alm(st,
 						   LTC4282_VSOURCE_ALARM_L_MASK,
Signature · 1 line
2.53.0
author maintainer
#68 lore raw

PATCH 69/337 hwmon: (sht3x) Fix unaligned accesses

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit f46d5ab43a572b84773015a76966f5da56fc1748 ]

Sashiko reports:

In sht3x_update_client(), the 16-bit temperature and humidity values are extracted from a stack-allocated byte array using be16_to_cpup(). The pointers passed to this function are calculated as buf and buf + 3. Since the difference between the two pointers is an odd number of bytes, at least one of them is guaranteed to be at an unaligned offset.

This will trigger an alignment fault on strict-alignment architectures such as ARMv5 or SPARC, resulting in a kernel panic.

Fix the problem by using get_unaligned_be16() instead of be16_to_cpup(), and put_unaligned_be16() instead of cpu_to_be16().

Fixes 7c84f7f80d6f ("hwmon: add support for Sensirion SHT3x sensors")
---
 drivers/hwmon/sht3x.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/hwmon/sht3x.c +5 -4
index 94466e28dc56f..1f63c07cfb085 100644
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
+#include <linux/unaligned.h>
 
 /* commands (high repeatability mode) */
 static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 };
@@ -279,9 +280,9 @@ static struct sht3x_data *sht3x_update_client(struct device *dev)
 		if (ret)
 			goto out;
 
-		val = be16_to_cpup((__be16 *)buf);
+		val = get_unaligned_be16(buf);
 		data->temperature = sht3x_extract_temperature(val);
-		val = be16_to_cpup((__be16 *)(buf + 3));
+		val = get_unaligned_be16(buf + 3);
 		data->humidity = sht3x_extract_humidity(val);
 		data->last_update = jiffies;
 	}
@@ -339,7 +340,7 @@ static int limits_update(struct sht3x_data *data)
 		if (ret)
 			return ret;
 
-		raw = be16_to_cpup((__be16 *)buffer);
+		raw = get_unaligned_be16(buffer);
 		temperature = sht3x_extract_temperature((raw & 0x01ff) << 7);
 		humidity = sht3x_extract_humidity(raw & 0xfe00);
 		data->temperature_limits[index] = temperature;
@@ -392,7 +393,7 @@ static size_t limit_write(struct device *dev,
 	raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7);
 	raw |= ((humidity * 42950) >> 16) & 0xfe00;
 
-	*((__be16 *)position) = cpu_to_be16(raw);
+	put_unaligned_be16(raw, position);
 	position += SHT3X_WORD_LEN;
 	*position = crc8(sht3x_crc8_table,
 			 position - SHT3X_WORD_LEN,
Signature · 1 line
2.53.0
author maintainer
#69 lore raw

PATCH 70/337 hwmon: (lm90) Only report alarms if driver is ready

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit aa9429edf9fc0e90d6f4da19ea4b5495a54ab117 ]

Userspace can read sysfs attributes before driver registration is complete, immediately after devm_hwmon_device_register_with_info() has been called. At that time, data->hwmon_dev is not yet initialized. This can trigger a NULL pointer access since lm90_update_device() and with it lm90_update_alarms_locked() will be called. This call schedules report_work and lm90_report_alarms(), which passes the still-NULL data->hwmon_dev to hwmon_notify_event() and triggers a NULL pointer dereference.

Fix the problem by only scheduling the report and alert workers data->hwmon_dev is set.

Fixes f6d0775119fb9 ("hwmon: (lm90) Rework alarm/status handling")
---
 drivers/hwmon/lm90.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/lm90.c +2 -2
index 511d95a0efb36..45d5a2427dcb1 100644
@@ -1149,7 +1149,7 @@ static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
 		check_enable = (client->irq || !(data->config_orig & 0x80)) &&
 			(data->config & 0x80);
 
-		if (force || check_enable)
+		if (data->hwmon_dev && (force || check_enable))
 			schedule_work(&data->report_work);
 
 		/*
@@ -1157,7 +1157,7 @@ static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
 		 * alarms are all clear, and alerts are currently disabled.
 		 * Otherwise (re)schedule worker if needed.
 		 */
-		if (check_enable) {
+		if (check_enable && data->hwmon_dev) {
 			if (!(data->current_alarms & data->alert_alarms)) {
 				dev_dbg(&client->dev, "Re-enabling ALERT#\n");
 				lm90_update_confreg(data, data->config & ~0x80);
Signature · 1 line
2.53.0
author maintainer
#70 lore raw

PATCH 71/337 hwmon: (nzxt-smart2) DMA-align output buffer

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit 080bbf42faf77e6489ab30d5114c5f8f6ccbb1b8 ]

Sashiko reports:

When send_output_report() calls hid_hw_output_report(), the underlying USB HID core calls usb_interrupt_msg() which maps this buffer directly for DMA.

When the DMA mapping flushes or invalidates the cacheline, it will corrupt the adjacent variables (mutex, update_interval) that were modified concurrently by the CPU. This causes memory corruption due to cacheline sharing on non-coherent CPU architectures (such as ARM or MIPS). The DMA API debugging tool (CONFIG_DMA_API_DEBUG) will trigger runtime warnings for this violation.

Any operation that triggers send_output_report() (like setting a fan speed or updating the interval) causes the USB DMA mapping. On systems with non-coherent caches, this structural bug causes immediate and deterministic memory corruption.

Align the output buffer to ARCH_DMA_MINALIGN to fix the problem.

Fixes 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
Cc Aleksandr Mezin <[email protected]>
---
 drivers/hwmon/nzxt-smart2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/nzxt-smart2.c +1 -1
index 6f8febda4277c..66c5886f411a6 100644
@@ -203,7 +203,7 @@ struct drvdata {
 	 */
 	struct mutex mutex;
 	long update_interval;
-	u8 output_buffer[OUTPUT_REPORT_SIZE];
+	u8 output_buffer[OUTPUT_REPORT_SIZE] __aligned(ARCH_DMA_MINALIGN);
 };
 
 static long scale_pwm_value(long val, long orig_max, long new_max)
Signature · 1 line
2.53.0
author maintainer
#71 lore raw

PATCH 72/337 net: do not send ICMP/NDISC Redirects when peer allocation fails

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit dbc3791e3b2472e1ccc08947e0f83b443470ff4f ]

When inet_getpeer_v4() or inet_getpeer_v6() fails to allocate a peer entry under memory pressure or tree size caps, redirect handlers previously fell back to sending un-rate-limited ICMP/NDISC Redirect messages.

In IPv4, ip_rt_send_redirect() called icmp_send() directly when peer == NULL. In IPv6, ip6_forward() and ndisc_send_redirect() passed a NULL peer into inet_peer_xrlim_allow(), which returned true when peer == NULL.

Because ICMP/NDISC Redirects are not part of the default global rate limit mask (sysctl_icmp_ratemask), sending redirects when peer == NULL creates an un-rate-limited ICMP packet storm.

Fix this by failing closed in ip_rt_send_redirect(), ip6_forward(), and ndisc_send_redirect() when peer is NULL.

Fixes 92d868292634 ("inetpeer: Move ICMP rate limiting state into inet_peer entries.")
---
 net/ipv4/route.c      | 2 --
 net/ipv6/ip6_output.c | 2 +-
 net/ipv6/ndisc.c      | 2 ++
 3 files changed, 3 insertions(+), 3 deletions(-)
net/ipv4/route.c +0 -2
index 4dce0de6ab898..2b8c29a29c4ae 100644
@@ -890,8 +890,6 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 	peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif);
 	if (!peer) {
 		rcu_read_unlock();
-		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
-			  rt_nexthop(rt, ip_hdr(skb)->daddr));
 		return;
 	}
 
net/ipv6/ip6_output.c +1 -1
index 50b41be5d38d0..5d17982cb9946 100644
@@ -627,7 +627,7 @@ int ip6_forward(struct sk_buff *skb)
 		/* Limit redirects both by destination (here)
 		   and by source (inside ndisc_send_redirect)
 		 */
-		if (inet_peer_xrlim_allow(peer, 1*HZ))
+		if (peer && inet_peer_xrlim_allow(peer, 1*HZ))
 			ndisc_send_redirect(skb, target);
 		rcu_read_unlock();
 	} else {
net/ipv6/ndisc.c +2 -0
index 73e2e457e30be..1a759519a90f9 100644
@@ -1739,6 +1739,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
 	rcu_read_lock();
 	peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr);
+	if (!peer)
+		goto release;
 	ret = inet_peer_xrlim_allow(peer, 1*HZ);
 	rcu_read_unlock();
 
Signature · 1 line
2.53.0
author maintainer
#72 lore raw

PATCH 73/337 hwmon: (nct6775-core) Prevent access to unsupported weight registers

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit d0b704e569ac3b8416d8e02270cdc9bf830ed395 ]

Sashiko reports:

During initialization of the nct6116 chip, the driver sets data->pwm_num to 5. However, it assigns several NCT6106 register arrays (such as NCT6106_REG_WEIGHT_DUTY_STEP, NCT6106_REG_WEIGHT_TEMP_SEL, and NCT6106_REG_WEIGHT_TEMP_*) to data->REG_PWM and data->REG_WEIGHT_TEMP. These arrays only contain 3 elements.

In nct6775_update_pwm(), the driver iterates up to data->pwm_num. If data->has_pwm has bits 3 or 4 set (which is structurally possible for nct6116), the loop attempts to read elements at index 3 and 4 from these 3-element arrays. This results in a global out-of-bounds read, which can be caught by KASAN.

Furthermore, the driver uses these garbage out-of-bounds values as hardware register addresses for subsequent read and write operations. This leads to invalid hardware register access, potentially causing hardware misconfiguration or system crashes.

The underlying problem is that the chip does support up to five fan control channels, but only the first three support weight control. Fix the problem by extending the affected weight register arrays with zeroed fields. The driver uses zeroed register addresses to determine if a register is supported or not, and skips accesses for unsupported registers.

Fixes 29c7cb485b32 ("hwmon: (nct6775) Integrate new model nct6116")
Cc Björn Gerhart <[email protected]>
Cc Florian Bezdeka <[email protected]>
---
 drivers/hwmon/nct6775-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/hwmon/nct6775-core.c +6 -6
index 506d57025c3bd..ce2cf1f229004 100644
@@ -791,12 +791,12 @@ static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
 
 static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
 
-static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
-static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
-static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
-static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
-static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
-static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d, 0, 0 };
 
 static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
 static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
Signature · 1 line
2.53.0
author maintainer
#73 lore raw

PATCH 74/337 net: bridge: mrp: fix Option TLV length in MRP_Test frames

In reply to Greg Kroah-Hartman

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

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

From: David Corvaglia <[email protected]>

[ Upstream commit 5546da86894d5906f131b05890705a7abf949d84 ]

oui is a pointer, so sizeof(oui) is the pointer size. The MRA Option TLV thus advertises a wrong length (15 vs 10 on x86_64), causing misparsing of the frame on peers. Fix is to replace with sizeof(*oui).

---
 net/bridge/br_mrp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bridge/br_mrp.c +1 -1
index fd2de35ffb3cf..5fd22bb4f5b60 100644
@@ -215,7 +215,7 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp,
 		struct br_mrp_oui_hdr *oui = NULL;
 		u8 length;
 
-		length = sizeof(*sub_opt) + sizeof(*sub_tlv) + sizeof(oui) +
+		length = sizeof(*sub_opt) + sizeof(*sub_tlv) + sizeof(*oui) +
 			MRP_OPT_PADDING;
 		br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_OPTION, length);
 
Signature · 1 line
2.53.0
author maintainer
#74 lore raw

PATCH 75/337 forcedeth: fix UAF of txrx_stats in nv_remove

In reply to Greg Kroah-Hartman

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

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

From: Chenguang Zhao <[email protected]>

[ Upstream commit 22666ba1420164753d7b0f5a841986b25ace5435 ]

nv_remove() frees the per-CPU txrx_stats before unregister_netdev(). Until unregister completes, ndo_get_stats64, the NAPI/xmit data path, and nv_close()/drain may still access txrx_stats, leading to a use-after-free.

Free the stats only after unregister_netdev().

Fixes f4b633b911fd ("forcedeth: use per cpu to collect xmit/recv statistics")
---
 drivers/net/ethernet/nvidia/forcedeth.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +2 -2
index 720f577929dbf..11eb3751ad27b 100644
@@ -6199,10 +6199,10 @@ static void nv_remove(struct pci_dev *pci_dev)
 	struct net_device *dev = pci_get_drvdata(pci_dev);
 	struct fe_priv *np = netdev_priv(dev);
 
-	free_percpu(np->txrx_stats);
-
 	unregister_netdev(dev);
 
+	free_percpu(np->txrx_stats);
+
 	nv_restore_mac_addr(pci_dev);
 
 	/* restore any phy related changes */
Signature · 1 line
2.53.0
author maintainer
#75 lore raw

PATCH 76/337 hwmon: (adt7470) Fix fans stuck in manual mode on I2C errors

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 625a2c02a1c04571232a746fe188b4d9a8d63edd ]

During adt7470_read_temperatures(), the driver temporarily switches the PWM channels to manual mode, performs the temperature collection, and then restores the original configuration registers.

However, if an I2C transaction fails at any point after entering manual mode, the function aborts and returns immediately. This leaves the configuration registers un-restored, permanently trapping the fans in manual mode.

Introduce a recovery path to ensure that the original PWM configuration registers are always restored, even when intermediate I2C operations fail.

---
 drivers/hwmon/adt7470.c | 40 +++++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)
drivers/hwmon/adt7470.c +29 -11
index dbee6926fa055..ef8f411df61be 100644
@@ -205,11 +205,12 @@ static inline int adt7470_write_word_data(struct adt7470_data *data, unsigned in
 /* Probe for temperature sensors.  Assumes lock is held */
 static int adt7470_read_temperatures(struct adt7470_data *data)
 {
-	unsigned long res;
+	struct device *dev = regmap_get_device(data->regmap);
+	u8 pwm[ADT7470_FAN_COUNT];
 	unsigned int pwm_cfg[2];
-	int err;
+	unsigned long res;
+	int err, err2;
 	int i;
-	u8 pwm[ADT7470_FAN_COUNT];
 
 	/* save pwm[1-4] config register */
 	err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(0), &pwm_cfg[0]);
@@ -233,19 +234,19 @@ static int adt7470_read_temperatures(struct adt7470_data *data)
 	err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(2),
 				 ADT7470_PWM_AUTO_MASK, 0);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* write pwm control to whatever it was */
 	err = regmap_bulk_write(data->regmap, ADT7470_REG_PWM(0), &pwm[0],
 				ADT7470_PWM_COUNT);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* start reading temperature sensors */
 	err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
 				 ADT7470_T05_STB_MASK, ADT7470_T05_STB_MASK);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* Delay is 200ms * number of temp sensors. */
 	res = msleep_interruptible((data->num_temp_sensors >= 0 ?
@@ -256,13 +257,30 @@ static int adt7470_read_temperatures(struct adt7470_data *data)
 	err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
 				 ADT7470_T05_STB_MASK, 0);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
+out_restore:
 	/* restore pwm[1-4] config registers */
-	err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
-	if (err < 0)
-		return err;
-	err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+	err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
+	if (err2 < 0) {
+		dev_warn_ratelimited(dev,
+				     "failed to restore PWM{1,2} config (%d)\n",
+				     err2);
+
+		if (!err)
+			err = err2;
+	}
+
+	err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+	if (err2 < 0) {
+		dev_warn_ratelimited(dev,
+				     "failed to restore PWM{3,4} config (%d)\n",
+				     err2);
+
+		if (!err)
+			err = err2;
+	}
+
 	if (err < 0)
 		return err;
 
Signature · 1 line
2.53.0
author maintainer
#76 lore raw

PATCH 77/337 hwmon: (adt7470) Fix cache updated before hardware write on I2C error

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 05270bd38d9bf88a2f4c212246a8fa29f4032078 ]

adt7470_temp_write() and adt7470_pwm_write() update the driver's cached values (temp_min, temp_max, pwm_input, pwm_enable) before issuing the corresponding regmap_write(), and never check whether the write succeeded before committing that update. If the I2C transaction fails, the function correctly propagates the error to the caller, but the cache silently keeps the new value, which was never actually applied to the hardware. Subsequent reads then report a value that does not match the device state.

Reorder both write paths to update the cache only after a successful regmap_write(), so the cache always reflects what was actually written to the hardware.

---
 drivers/hwmon/adt7470.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/hwmon/adt7470.c +9 -5
index ef8f411df61be..06b19fd382457 100644
@@ -589,14 +589,16 @@ static int adt7470_temp_write(struct device *dev, u32 attr, int channel, long va
 	switch (attr) {
 	case hwmon_temp_min:
 		mutex_lock(&data->lock);
-		data->temp_min[channel] = val;
 		err = regmap_write(data->regmap, ADT7470_TEMP_MIN_REG(channel), val);
+		if (!err)
+			data->temp_min[channel] = val;
 		mutex_unlock(&data->lock);
 		break;
 	case hwmon_temp_max:
 		mutex_lock(&data->lock);
-		data->temp_max[channel] = val;
 		err = regmap_write(data->regmap, ADT7470_TEMP_MAX_REG(channel), val);
+		if (!err)
+			data->temp_max[channel] = val;
 		mutex_unlock(&data->lock);
 		break;
 	default:
@@ -831,9 +833,10 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val
 	case hwmon_pwm_input:
 		val = clamp_val(val, 0, 255);
 		mutex_lock(&data->lock);
-		data->pwm[channel] = val;
 		err = regmap_write(data->regmap, ADT7470_REG_PWM(channel),
-				   data->pwm[channel]);
+				   val);
+		if (!err)
+			data->pwm[channel] = val;
 		mutex_unlock(&data->lock);
 		break;
 	case hwmon_pwm_enable:
@@ -847,10 +850,11 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val
 		val--;
 
 		mutex_lock(&data->lock);
-		data->pwm_automatic[channel] = val;
 		err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(channel),
 					 pwm_auto_reg_mask,
 					 val ? pwm_auto_reg_mask : 0);
+		if (!err)
+			data->pwm_automatic[channel] = val;
 		mutex_unlock(&data->lock);
 		break;
 	case hwmon_pwm_freq:
Signature · 1 line
2.53.0
author maintainer
#77 lore raw

PATCH 78/337 hwmon: (adt7470) Fix busy-loop and I2C flooding in update thread

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit cb0b7f9c43b0abbd422a7e4c2c85e91db429207c ]

When userspace configures 'auto_update_interval' to 0 via sysfs, the background kthread executes schedule_timeout_interruptible(0), which returns immediately.

If 'num_temp_sensors' is concurrently or previously set to 0, the msleep_interruptible() delay inside adt7470_read_temperatures() also becomes 0. This combination forces the background thread into a tight, unbounded busy-loop, hogging the CPU and flooding the I2C bus with a continuous stream of transactions.

Fix this vulnerability by raising the lower limit of the clamp_val in auto_update_interval_store() from 0 to 500 milliseconds. This guarantees a reasonable minimum sleep window between sensor updates, protecting the system from intentional or accidental I2C bus denial of service.

---
 drivers/hwmon/adt7470.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/adt7470.c +1 -1
index 06b19fd382457..a927e0b6d3319 100644
@@ -509,7 +509,7 @@ static ssize_t auto_update_interval_store(struct device *dev,
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = clamp_val(temp, 0, 60000);
+	temp = clamp_val(temp, 500, 60000);
 
 	mutex_lock(&data->lock);
 	data->auto_update_interval = temp;
Signature · 1 line
2.53.0
author maintainer
#78 lore raw

PATCH 79/337 hwmon: (adt7470) Fix temperature alarm logic in hwmon_temp_read()

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 1a18c79c4bc44cc5349c60e16b0b744dc6ec5f77 ]

During the conversion the alarm callback started interpreting the channel index as an alarm bitmask, resulting in incorrect alarm reporting. Compute the proper alarm bit instead.

Reported-by [email protected]
Fixes fc958a61ff6d ("hwmon: (adt7470) Convert to devm_hwmon_device_register_with_info API")
---
 drivers/hwmon/adt7470.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
drivers/hwmon/adt7470.c +17 -2
index a927e0b6d3319..41fa6a0e8b937 100644
@@ -110,6 +110,21 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
 
 #define ALARM2(x)		((x) << 8)
 
+/* TEMP1..TEMP7 (ch 0..6) are, respectively BIT(0)..BIT(6) of reg 0x41 and
+ * 0x72, or BIT(0)..BIT(6) of data->alarm.
+ * TEMP8..TEMP9 (ch 7..9) are, respectively BIT(0)..BIT(2) of reg 0x42 and
+ * 0x73, or BIT(8)..BIT(10) of data->alarm.
+ */
+#define TEMP_ALARM_BIT(ch)	({		\
+	typeof(ch) _ch = (ch);			\
+	(1 << (_ch < 7 ? _ch : _ch + 1));	\
+})
+
+/* FAN1..FAN4 (ch 0..3) are respectively BIT(4)..BIT(7) in
+ * reg 0x42 and 0x73 or BIT(12)..BIT(15) in data->alarm.
+ */
+#define FAN_ALARM_BIT(ch)	(1 << (12 + (ch)))
+
 #define ADT7470_VENDOR		0x41
 #define ADT7470_DEVICE		0x70
 /* datasheet only mentions a revision 2 */
@@ -569,7 +584,7 @@ static int adt7470_temp_read(struct device *dev, u32 attr, int channel, long *va
 		*val = 1000 * data->temp_max[channel];
 		break;
 	case hwmon_temp_alarm:
-		*val = !!(data->alarm & channel);
+		*val = !!(data->alarm & TEMP_ALARM_BIT(channel));
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -668,7 +683,7 @@ static int adt7470_fan_read(struct device *dev, u32 attr, int channel, long *val
 			*val = 0;
 		break;
 	case hwmon_fan_alarm:
-		*val = !!(data->alarm & (1 << (12 + channel)));
+		*val = !!(data->alarm & FAN_ALARM_BIT(channel));
 		break;
 	default:
 		return -EOPNOTSUPP;
Signature · 1 line
2.53.0
author maintainer
#79 lore raw

PATCH 80/337 hwmon: (adt7470) Fix swapped PWM3 and PWM4 auto mode masks

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit a3850231521b06bbbb18c8ebea100320c14a08be ]

The ADT7470_PWM3_AUTO_MASK and ADT7470_PWM4_AUTO_MASK macros are currently defined with swapped bit values.

According to Table 22 of the ADT7470 datasheet, the Fan Control Mode Configuration for register 0x69 follows the exact same bit position layout as register 0x68:
- 0x68 Bit[7] corresponds to BHVR1 (PWM1) -> 0x80
- 0x68 Bit[6] corresponds to BHVR2 (PWM2) -> 0x40
- 0x69 Bit[7] corresponds to BHVR3 (PWM3) -> 0x80
- 0x69 Bit[6] corresponds to BHVR4 (PWM4) -> 0x40

Consequently, PWM3 should use mask 0x80 and PWM4 should use 0x40.

This typo did not cause any functional bugs because these specific macros are never referenced in the driver code. Instead, the driver correctly applies the configuration by relying on the modulo parity of the channel index (e.g., channel % 2) to selectively apply either ADT7470_PWM1_AUTO_MASK (0x80) or ADT7470_PWM2_AUTO_MASK (0x40). Since the bit layout is identical between the two configuration registers, the hardware is currently configured correctly.

Fix the macro definitions to reflect the datasheet accurately and prevent future bugs or confusion during code review and refactoring. As this is a purely cosmetic fix with no functional impact, a backport to stable kernels is not necessary.

---
 drivers/hwmon/adt7470.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/adt7470.c +2 -2
index 41fa6a0e8b937..f0a45538ded6d 100644
@@ -70,8 +70,8 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
 #define		ADT7470_PWM1_AUTO_MASK		0x80
 #define		ADT7470_PWM_AUTO_MASK		0xC0
 #define ADT7470_REG_PWM34_CFG			0x69
-#define		ADT7470_PWM3_AUTO_MASK		0x40
-#define		ADT7470_PWM4_AUTO_MASK		0x80
+#define		ADT7470_PWM4_AUTO_MASK		0x40
+#define		ADT7470_PWM3_AUTO_MASK		0x80
 #define	ADT7470_REG_PWM_MIN_BASE_ADDR		0x6A
 #define ADT7470_REG_PWM_MIN_MAX_ADDR		0x6D
 #define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR	0x6E
Signature · 1 line
2.53.0
author maintainer
#80 lore raw

PATCH 81/337 hwmon: (adt7470) Use cached PWM frequency value

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 60677cd4c28f44d5b307d3029dccece38fcce90f ]

adt7470_pwm_read() currently ignores failures returned by pwm1_freq_get(). If the register read fails, the negative error code is returned through *val while the function itself reports success, potentially exposing a negative PWM frequency through sysfs.

Fix this by using the cached PWM frequency maintained by the driver, eliminating the register access from the read path.

Apart from the corrected error propagation and using the cached value, no functional change is intended.

---
 drivers/hwmon/adt7470.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)
drivers/hwmon/adt7470.c +18 -2
index f0a45538ded6d..43c0130342622 100644
@@ -182,6 +182,7 @@ struct adt7470_data {
 	u8			pwm_min[ADT7470_PWM_COUNT];
 	s8			pwm_tmin[ADT7470_PWM_COUNT];
 	u8			pwm_auto_temp[ADT7470_PWM_COUNT];
+	u32			pwm_freq;
 
 	struct task_struct	*auto_update;
 	unsigned int		auto_update_interval;
@@ -756,7 +757,7 @@ static ssize_t force_pwm_max_store(struct device *dev,
 }
 
 /* These are the valid PWM frequencies to the nearest Hz */
-static const int adt7470_freq_map[] = {
+static const u32 adt7470_freq_map[] = {
 	11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
 };
 
@@ -796,7 +797,7 @@ static int adt7470_pwm_read(struct device *dev, u32 attr, int channel, long *val
 		*val = 1 + data->pwm_automatic[channel];
 		break;
 	case hwmon_pwm_freq:
-		*val = pwm1_freq_get(dev);
+		*val = data->pwm_freq;
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -809,12 +810,14 @@ static int pwm1_freq_set(struct device *dev, long freq)
 {
 	struct adt7470_data *data = dev_get_drvdata(dev);
 	unsigned int low_freq = ADT7470_CFG_LF;
+	u32 closest_freq;
 	int index;
 	int err;
 
 	/* Round the user value given to the closest available frequency */
 	index = find_closest(freq, adt7470_freq_map,
 			     ARRAY_SIZE(adt7470_freq_map));
+	closest_freq = adt7470_freq_map[index];
 
 	if (index >= 8) {
 		index -= 8;
@@ -832,6 +835,10 @@ static int pwm1_freq_set(struct device *dev, long freq)
 	err = regmap_update_bits(data->regmap, ADT7470_REG_CFG_2,
 				 ADT7470_FREQ_MASK,
 				 index << ADT7470_FREQ_SHIFT);
+	if (err < 0)
+		goto out;
+
+	data->pwm_freq = closest_freq;
 out:
 	mutex_unlock(&data->lock);
 
@@ -1285,6 +1292,7 @@ static int adt7470_probe(struct i2c_client *client)
 	struct device *dev = &client->dev;
 	struct adt7470_data *data;
 	struct device *hwmon_dev;
+	int freq_val;
 	int err;
 
 	data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL);
@@ -1309,6 +1317,14 @@ static int adt7470_probe(struct i2c_client *client)
 	if (err < 0)
 		return err;
 
+	freq_val = pwm1_freq_get(dev);
+	if (freq_val <= 0) {
+		err = freq_val < 0 ? freq_val : -EINVAL;
+		return err;
+	}
+
+	data->pwm_freq = (u32)freq_val;
+
 	/* Register sysfs hooks */
 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
 							 &adt7470_chip_info,
Signature · 1 line
2.53.0
author maintainer
#81 lore raw

PATCH 82/337 hwmon: (adt7470) Fix divide-by-zero TOCTOU crash in fan speed read

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 1b46fe9dc8f8de59310f37e6c5e5c0e05ded46c3 ]

If the fan data becomes 0 between the FAN_DATA_VALID() check and the FAN_PERIOD_TO_RPM() conversion, it will result in a divide-by-zero crash due to a race with a concurrent update of the cached fan value.

Fix a TOCTOU issue by reading fan data once.

Reported-by [email protected]
Fixes fc958a61ff6d ("hwmon: (adt7470) Convert to devm_hwmon_device_register_with_info API")
---
 drivers/hwmon/adt7470.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)
drivers/hwmon/adt7470.c +10 -13
index 43c0130342622..3a2d408a45be8 100644
@@ -660,36 +660,33 @@ static ssize_t alarm_mask_store(struct device *dev,
 static int adt7470_fan_read(struct device *dev, u32 attr, int channel, long *val)
 {
 	struct adt7470_data *data = adt7470_update_device(dev);
+	u16 fan_data;
 
 	if (IS_ERR(data))
 		return PTR_ERR(data);
 
 	switch (attr) {
 	case hwmon_fan_input:
-		if (FAN_DATA_VALID(data->fan[channel]))
-			*val = FAN_PERIOD_TO_RPM(data->fan[channel]);
-		else
-			*val = 0;
+		fan_data = READ_ONCE(data->fan[channel]);
 		break;
 	case hwmon_fan_min:
-		if (FAN_DATA_VALID(data->fan_min[channel]))
-			*val = FAN_PERIOD_TO_RPM(data->fan_min[channel]);
-		else
-			*val = 0;
+		fan_data = READ_ONCE(data->fan_min[channel]);
 		break;
 	case hwmon_fan_max:
-		if (FAN_DATA_VALID(data->fan_max[channel]))
-			*val = FAN_PERIOD_TO_RPM(data->fan_max[channel]);
-		else
-			*val = 0;
+		fan_data = READ_ONCE(data->fan_max[channel]);
 		break;
 	case hwmon_fan_alarm:
 		*val = !!(data->alarm & FAN_ALARM_BIT(channel));
-		break;
+		return 0;
 	default:
 		return -EOPNOTSUPP;
 	}
 
+	if (FAN_DATA_VALID(fan_data))
+		*val = FAN_PERIOD_TO_RPM(fan_data);
+	else
+		*val = 0;
+
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#82 lore raw

PATCH 83/337 hwmon: (adt7470) Fix PWM auto temp state array and bounds check

In reply to Greg Kroah-Hartman

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

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

From: Luiz Angelo Daros de Luca <[email protected]>

[ Upstream commit 92413f439d1ec5e55b73ede8d66a7b971cbd1ced ]

In pwm_auto_temp_store(), the parsed user input was missing bounds checks, allowing values > 0xF to overflow into the adjacent channel's bits. Furthermore, the value was being incorrectly written to the pwm_automatic state array instead of pwm_auto_temp.

Fix this by rejecting values > 0xF with -EINVAL, and assigning the value to the correct array only after a successful I2C write.

---
 drivers/hwmon/adt7470.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/hwmon/adt7470.c +6 -1
index 3a2d408a45be8..0fad4bfe53df6 100644
@@ -1049,8 +1049,10 @@ static ssize_t pwm_auto_temp_store(struct device *dev,
 	if (temp < 0)
 		return temp;
 
+	if (temp > 0xF)
+		return -EINVAL;
+
 	mutex_lock(&data->lock);
-	data->pwm_automatic[attr->index] = temp;
 
 	if (!(attr->index % 2)) {
 		mask = 0xF0;
@@ -1061,6 +1063,9 @@ static ssize_t pwm_auto_temp_store(struct device *dev,
 	}
 
 	err = regmap_update_bits(data->regmap, pwm_auto_reg, mask, val);
+	if (!err)
+		data->pwm_auto_temp[attr->index] = temp;
+
 	mutex_unlock(&data->lock);
 
 	return err < 0 ? err : count;
Signature · 1 line
2.53.0
author maintainer
#83 lore raw

PATCH 84/337 rtase: fix double free of multi-frag skb on DMA map failure

In reply to Greg Kroah-Hartman

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

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

From: Yun Lu <[email protected]>

[ Upstream commit 6fb7b769d6ed6d1d2e02af4a80e57a2477f35086 ]

In rtase_start_xmit(), when the head buffer DMA mapping fails after rtase_xmit_frags() has mapped all fragments, the error path clears the fragment descriptors with rtase_tx_clear_range(), which frees the skb through the last-frag slot and accounts tx_dropped. Control then falls through to the common error label, which frees the same skb a second time and counts it again.

Return right after clearing the fragments when the skb owns frags; the no-frag case still drops through and frees the head skb once.

---
 drivers/net/ethernet/realtek/rtase/rtase_main.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/realtek/rtase/rtase_main.c +3 -0
index a565d5fb6b85c..afae19cc99314 100644
@@ -1609,6 +1609,9 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
 err_dma_1:
 	ring->skbuff[entry] = NULL;
 	rtase_tx_clear_range(ring, ring->cur_idx + 1, frags);
+	if (frags)
+		/* the frags were cleared above, along with the skb */
+		return NETDEV_TX_OK;
 
 err_dma_0:
 	tp->stats.tx_dropped++;
Signature · 1 line
2.53.0
author maintainer
#84 lore raw

PATCH 85/337 powerpc/boot: Fix simpleboot CPU node lookup check

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit c824ab65685bb119c6c6a3a200b3428c72862d5a ]

fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.

Fixes d2477b5cc8ca ("[POWERPC] bootwrapper: Add a firmware-independent simpleboot target.")
---
 arch/powerpc/boot/simpleboot.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/simpleboot.c +1 -1
index c80691d83880b..27591df41e9e8 100644
@@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	/* finally, setup the timebase */
 	node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
 					     "cpu", sizeof("cpu"));
-	if (!node)
+	if (node < 0)
 		fatal("Cannot find cpu node\n");
 	timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
 	if (timebase && (size == 4))
Signature · 1 line
2.53.0
author maintainer
#85 lore raw

PATCH 86/337 powerpc/boot: Fix treeboot-currituck CPU node lookup check

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit 43863f6575d2211e8c5157fefb83ad0ad046aab4 ]

fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.

Fixes 228d55053397 ("powerpc/47x: Add support for the new IBM currituck platform")
---
 arch/powerpc/boot/treeboot-currituck.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/treeboot-currituck.c +1 -1
index d53e8a592f816..5b5363b74f9f3 100644
@@ -102,7 +102,7 @@ void platform_init(void)
 
 	node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
 	                                     "cpu", sizeof("cpu"));
-	if (!node)
+	if (node < 0)
 		fatal("Cannot find cpu node\n");
 	timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
 	if (timebase && (size == 4))
Signature · 1 line
2.53.0
author maintainer
#86 lore raw

PATCH 87/337 powerpc/boot: Fix treeboot-akebono CPU node lookup check

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit b24fc8278b70a9d27ec801a427ab4de9b769d69a ]

fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.

---
 arch/powerpc/boot/treeboot-akebono.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/treeboot-akebono.c +1 -1
index e3cc2599869cc..1b529037480fb 100644
@@ -146,7 +146,7 @@ void platform_init(char *userdata)
 
 	node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
 					     "cpu", sizeof("cpu"));
-	if (!node)
+	if (node < 0)
 		fatal("Cannot find cpu node\n");
 	timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
 	if (timebase && (size == 4))
Signature · 1 line
2.53.0
author maintainer
#87 lore raw

PATCH 88/337 net: udp_tunnel: fix memory leak in udp_tunnel_nic_unregister()

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit 080695e6f005e2396f1207fd69d24c442cb230c6 ]

syzbot reported a memory leak [1] in the UDP tunnel NIC offload code.

When device registration fails (e.g. in register_netdevice()), netdev core unwinds by sending a single NETDEV_UNREGISTER notification. If work was queued during NETDEV_REGISTER (utn->work_pending is set), udp_tunnel_nic_unregister() returns early:

	if (utn->work_pending)
		return;

Because failed registrations do not enter netdev_wait_allrefs_any(), no subsequent NETDEV_UNREGISTER rebroadcast will ever occur. As a result, the struct udp_tunnel_nic allocated in udp_tunnel_nic_alloc() is leaked permanently.

Fix this by removing the early return. Instead, synchronously cancel any pending work with cancel_delayed_work_sync() before freeing @utn.

To be able to call cancel_delayed_work_sync() while holding RTNL (the work also needs RTNL), switch udp_tunnel_nic_device_sync_work() to rtnl_trylock(). If RTNL is contended, requeue the work with a 1 jiffy delay (via queue_delayed_work()) to prevent high CPU contention while waiting for RTNL lock.

The utn->work_pending bookkeeping is no longer needed and is removed, as the workqueue core already tracks the pending/running state of the work.

[1]

BUG: memory leak
unreferenced object 0xffff888127d5f840 (size 96):
  comm "syz-executor", pid 5806, jiffies 4294942188
  backtrace (crc 99fdb6c8):
    __kmalloc_noprof+0x3bf/0x550
    udp_tunnel_nic_alloc net/ipv4/udp_tunnel_nic.c:756 [inline]
    udp_tunnel_nic_register net/ipv4/udp_tunnel_nic.c:833 [inline]
    udp_tunnel_nic_netdevice_event+0x804/0xab0 net/ipv4/udp_tunnel_nic.c:931
    notifier_call_chain+0x59/0x160 kernel/notifier.c:85
    call_netdevice_notifiers_info+0x7d/0xb0 net/core/dev.c:2250
    register_netdevice+0xc10/0xeb0 net/core/dev.c:11478
---
 net/ipv4/udp_tunnel_nic.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)
net/ipv4/udp_tunnel_nic.c +17 -15
index b13e8f7092f46..4360d159ee8a7 100644
@@ -32,13 +32,12 @@ struct udp_tunnel_nic_table_entry {
  * @lock:	protects all fields
  * @need_sync:	at least one port start changed
  * @need_replay: space was freed, we need a replay of all ports
- * @work_pending: @work is currently scheduled
  * @n_tables:	number of tables under @entries
  * @missed:	bitmap of tables which overflown
  * @entries:	table of tables of ports currently offloaded
  */
 struct udp_tunnel_nic {
-	struct work_struct work;
+	struct delayed_work work;
 
 	struct net_device *dev;
 
@@ -46,7 +45,6 @@ struct udp_tunnel_nic {
 
 	u8 need_sync:1;
 	u8 need_replay:1;
-	u8 work_pending:1;
 
 	unsigned int n_tables;
 	unsigned long missed;
@@ -301,11 +299,10 @@ __udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn)
 static void
 udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn)
 {
-	if (!utn->need_sync || utn->work_pending)
+	if (!utn->need_sync)
 		return;
 
-	queue_work(udp_tunnel_nic_workqueue, &utn->work);
-	utn->work_pending = 1;
+	queue_delayed_work(udp_tunnel_nic_workqueue, &utn->work, 0);
 }
 
 static bool
@@ -731,12 +728,17 @@ udp_tunnel_nic_replay(struct net_device *dev, struct udp_tunnel_nic *utn)
 static void udp_tunnel_nic_device_sync_work(struct work_struct *work)
 {
 	struct udp_tunnel_nic *utn =
-		container_of(work, struct udp_tunnel_nic, work);
+		container_of(work, struct udp_tunnel_nic, work.work);
 
-	rtnl_lock();
+	/* We cannot block on RTNL here, otherwise we would deadlock with
+	 * udp_tunnel_nic_unregister() calling cancel_delayed_work_sync()
+	 * while holding RTNL. Requeue with 1 jiffy delay if RTNL is contended.
+	 */
+	if (!rtnl_trylock()) {
+		queue_delayed_work(udp_tunnel_nic_workqueue, &utn->work, 1);
+		return;
+	}
 	mutex_lock(&utn->lock);
-
-	utn->work_pending = 0;
 	__udp_tunnel_nic_device_sync(utn->dev, utn);
 
 	if (utn->need_replay)
@@ -757,7 +759,7 @@ udp_tunnel_nic_alloc(const struct udp_tunnel_nic_info *info,
 	if (!utn)
 		return NULL;
 	utn->n_tables = n_tables;
-	INIT_WORK(&utn->work, udp_tunnel_nic_device_sync_work);
+	INIT_DELAYED_WORK(&utn->work, udp_tunnel_nic_device_sync_work);
 	mutex_init(&utn->lock);
 
 	for (i = 0; i < n_tables; i++) {
@@ -901,11 +903,11 @@ udp_tunnel_nic_unregister(struct net_device *dev, struct udp_tunnel_nic *utn)
 	udp_tunnel_nic_flush(dev, utn);
 	udp_tunnel_nic_unlock(dev);
 
-	/* Wait for the work to be done using the state, netdev core will
-	 * retry unregister until we give up our reference on this device.
+	/* Make sure no work is running or queued before freeing @utn.
+	 * The work handler uses rtnl_trylock(), so it will not deadlock
+	 * against the RTNL we are holding here.
 	 */
-	if (utn->work_pending)
-		return;
+	cancel_delayed_work_sync(&utn->work);
 
 	udp_tunnel_nic_free(utn);
 release_dev:
Signature · 1 line
2.53.0
author maintainer
#88 lore raw

PATCH 89/337 wifi: mac80211: validate individual TWT params before driver setup

In reply to Greg Kroah-Hartman

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

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

From: Zhao Li <[email protected]>

[ Upstream commit 0502d5077e419427d80f4d46ba95d0067f5fb916 ]

ieee80211_process_rx_twt_action() only partially validates a received S1G TWT setup frame before queueing it.

An individual agreement can therefore reach ieee80211_s1g_rx_twt_setup() with twt->length too short for the full struct ieee80211_twt_params.

The individual path passes twt to drv_add_twt_setup(). Both the tracepoint and the driver callback consume the complete parameters block, not merely req_type. Do not pass a short individual agreement to the driver. Broadcast agreements remain unchanged because they are rejected locally after accessing only req_type.

Fixes f5a4c24e689f ("mac80211: introduce individual TWT support in AP mode")
Assisted-by Codex:gpt-5
Assisted-by Claude:opus-4.8

[edit commit message to not overclaim lack of validation nor
understate driver impact]

---
 net/mac80211/s1g.c | 4 ++++
 1 file changed, 4 insertions(+)
net/mac80211/s1g.c +4 -0
index d4ed0c0a335ca..2a23e431cbb5a 100644
@@ -101,6 +101,10 @@ ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
 
+	if (!(twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) &&
+	    twt->length < sizeof(twt->control) + sizeof(*twt_agrt))
+		return;
+
 	twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST);
 
 	/* broadcast TWT not supported yet */
Signature · 1 line
2.53.0
author maintainer
#89 lore raw

PATCH 90/337 net: ethernet: mtk_eth_soc: support named IRQs

In reply to Greg Kroah-Hartman

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

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

From: Frank Wunderlich <[email protected]>

[ Upstream commit ee85b483fefbbebe1e6e61c53169f864bbdd8f13 ]

Add named interrupts and keep index based fallback for existing devicetrees.

Currently only rx and tx IRQs are defined to be used with mt7988, but later extended with RSS/LRO support.

Stable-dep-of: e095f249e220 ("net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller")

---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 46 ++++++++++++++++-----
 1 file changed, 35 insertions(+), 11 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +35 -11
index ebf5432cb328d..4305779459efd 100644
@@ -3210,6 +3210,37 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
 	schedule_work(&eth->pending_work);
 }
 
+static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+{
+	int i;
+
+	/* future SoCs beginning with MT7988 should use named IRQs in dts */
+	eth->irq[1] = platform_get_irq_byname(pdev, "fe1");
+	eth->irq[2] = platform_get_irq_byname(pdev, "fe2");
+	if (eth->irq[1] >= 0 && eth->irq[2] >= 0)
+		return 0;
+
+	/* legacy way:
+	 * On MTK_SHARED_INT SoCs (MT7621 + MT7628) the first IRQ is taken
+	 * from devicetree and used for both RX and TX - it is shared.
+	 * On SoCs with non-shared IRQs the first entry is not used,
+	 * the second is for TX, and the third is for RX.
+	 */
+	for (i = 0; i < 3; i++) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0)
+			eth->irq[i] = eth->irq[0];
+		else
+			eth->irq[i] = platform_get_irq(pdev, i);
+
+		if (eth->irq[i] < 0) {
+			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
 static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
 {
 	struct mtk_eth *eth = _eth;
@@ -4986,17 +5017,10 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
-	for (i = 0; i < 3; i++) {
-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0)
-			eth->irq[i] = eth->irq[0];
-		else
-			eth->irq[i] = platform_get_irq(pdev, i);
-		if (eth->irq[i] < 0) {
-			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
-			err = -ENXIO;
-			goto err_wed_exit;
-		}
-	}
+	err = mtk_get_irqs(pdev, eth);
+	if (err)
+		goto err_wed_exit;
+
 	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
 		eth->clks[i] = devm_clk_get(eth->dev,
 					    mtk_clks_source_name[i]);
Signature · 1 line
2.53.0
#90 lore raw

Re: [PATCH 6.12 090/337] net: ethernet: mtk_eth_soc: support named IRQs

Hi, this patch caused the following errors on non MT7988 SoCs:

[    7.071127] mtk_soc_eth 1e100000.ethernet: error -ENXIO: IRQ fe1 not found
[    7.078022] mtk_soc_eth 1e100000.ethernet: error -ENXIO: IRQ fe2 not found

Please backport these patches to fix it:
070e98dd4e26279280e15db8f37077a001ca1b4c ("net: ethernet: mtk_eth_soc: only use legacy mode on missing IRQ name") e81d36d48880ab3f2b351ce3df799acaa8b11c4f ("net: ethernet: mtk_eth_soc: improve support for named interrupts")

Regards,
Shiji Yang

author maintainer
#91 lore raw

Re: [PATCH 6.12 090/337] net: ethernet: mtk_eth_soc: support named IRQs

Quoted 7 lines · Shiji Yang

Hi, this patch caused the following errors on non MT7988 SoCs:

[    7.071127] mtk_soc_eth 1e100000.ethernet: error -ENXIO: IRQ fe1 not found
[    7.078022] mtk_soc_eth 1e100000.ethernet: error -ENXIO: IRQ fe2 not found

Please backport these patches to fix it:
070e98dd4e26279280e15db8f37077a001ca1b4c ("net: ethernet: mtk_eth_soc: only use legacy mode on missing IRQ name") e81d36d48880ab3f2b351ce3df799acaa8b11c4f ("net: ethernet: mtk_eth_soc: improve support for named interrupts")

Why did neither of these have Fixes: tags?

Anyway, I'll go queue both of these up now, thanks.

greg k-h

author maintainer
#92 lore raw

PATCH 91/337 net: ethernet: mtk_eth_soc: add consts for irq index

In reply to Greg Kroah-Hartman

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

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

From: Frank Wunderlich <[email protected]>

[ Upstream commit 4981901009923c8889a635a928d55b8f7f8b31ec ]

Use consts instead of fixed integers for accessing IRQ array.

Stable-dep-of: e095f249e220 ("net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller")

---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++-----------
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  7 ++++++-
 2 files changed, 17 insertions(+), 12 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +11 -11
index 4305779459efd..c18d4a143aac9 100644
@@ -3215,9 +3215,9 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	int i;
 
 	/* future SoCs beginning with MT7988 should use named IRQs in dts */
-	eth->irq[1] = platform_get_irq_byname(pdev, "fe1");
-	eth->irq[2] = platform_get_irq_byname(pdev, "fe2");
-	if (eth->irq[1] >= 0 && eth->irq[2] >= 0)
+	eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname(pdev, "fe1");
+	eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname(pdev, "fe2");
+	if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
 		return 0;
 
 	/* legacy way:
@@ -3226,9 +3226,9 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	 * On SoCs with non-shared IRQs the first entry is not used,
 	 * the second is for TX, and the third is for RX.
 	 */
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0)
-			eth->irq[i] = eth->irq[0];
+			eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
 		else
 			eth->irq[i] = platform_get_irq(pdev, i);
 
@@ -3294,7 +3294,7 @@ static void mtk_poll_controller(struct net_device *dev)
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
 	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[2], dev);
+	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
 	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
 }
@@ -4787,7 +4787,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->features |= eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
-	eth->netdev[id]->irq = eth->irq[0];
+	eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
 	eth->netdev[id]->dev.of_node = np;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5064,17 +5064,17 @@ static int mtk_probe(struct platform_device *pdev)
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
-		err = devm_request_irq(eth->dev, eth->irq[0],
+		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
 				       mtk_handle_irq, 0,
 				       dev_name(eth->dev), eth);
 	} else {
-		err = devm_request_irq(eth->dev, eth->irq[1],
+		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
 				       mtk_handle_irq_tx, 0,
 				       dev_name(eth->dev), eth);
 		if (err)
 			goto err_free_dev;
 
-		err = devm_request_irq(eth->dev, eth->irq[2],
+		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
 				       mtk_handle_irq_rx, 0,
 				       dev_name(eth->dev), eth);
 	}
@@ -5120,7 +5120,7 @@ static int mtk_probe(struct platform_device *pdev)
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
-				   eth->netdev[i]->base_addr, eth->irq[0]);
+				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
 	}
 
 	/* we run 2 devices on the same DMA ring so we need a dummy device
drivers/net/ethernet/mediatek/mtk_eth_soc.h +6 -1
index 0570623e569d5..76d60b6a23b2b 100644
@@ -611,6 +611,11 @@
 
 #define MTK_MAC_FSM(x)		(0x1010C + ((x) * 0x100))
 
+#define MTK_FE_IRQ_SHARED	0
+#define MTK_FE_IRQ_TX		1
+#define MTK_FE_IRQ_RX		2
+#define MTK_FE_IRQ_NUM		(MTK_FE_IRQ_RX + 1)
+
 struct mtk_rx_dma {
 	unsigned int rxd1;
 	unsigned int rxd2;
@@ -1248,7 +1253,7 @@ struct mtk_eth {
 	struct net_device		*dummy_dev;
 	struct net_device		*netdev[MTK_MAX_DEVS];
 	struct mtk_mac			*mac[MTK_MAX_DEVS];
-	int				irq[3];
+	int				irq[MTK_FE_IRQ_NUM];
 	u32				msg_enable;
 	unsigned long			sysclk;
 	struct regmap			*ethsys;
Signature · 1 line
2.53.0
author maintainer
#93 lore raw

PATCH 92/337 net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller

In reply to Greg Kroah-Hartman

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

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

From: Chenguang Zhao <[email protected]>

[ Upstream commit e095f249e2209674f6366f6db0383a2b96e19239 ]

mtk_handle_irq_rx expects a struct mtk_eth * (matching the request_irq cookie), but mtk_poll_controller incorrectly passed the net_device *. Calling ndo_poll_controller with CONFIG_NET_POLL_CONTROLLER enabled would then crash.

Fixes 8186f6e382d8 ("net-next: mediatek: fix compile error inside mtk_poll_controller()")
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +1 -1
index c18d4a143aac9..0d3346baa84e7 100644
@@ -3294,7 +3294,7 @@ static void mtk_poll_controller(struct net_device *dev)
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
 	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], eth);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
 	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
 }
Signature · 1 line
2.53.0
author maintainer
#94 lore raw

PATCH 93/337 hwmon: (pmbus) Fix return value from pmbus_update_byte_data()

In reply to Greg Kroah-Hartman

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

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

From: Guenter Roeck <[email protected]>

[ Upstream commit a19038a200f18d9e74ac30081797917d0886e16b ]

pmbus_update_byte_data() is supposed to return a negative error code or 0. However, if no change is made to the register, it actually returns the register value. This can result in problems if the calling code explicitly expects to see an error code or 0.

Fix it to return 0 on success or the error code as expected.

Fixes 11c119986f270 ("hwmon: (pmbus) add helpers for byte write and read modify write")
---
 drivers/hwmon/pmbus/pmbus_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/pmbus_core.c +1 -1
index a431cce336034..e08e30f288130 100644
@@ -508,7 +508,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
 	if (tmp != rv)
 		rv = _pmbus_write_byte_data(client, page, reg, tmp);
 
-	return rv;
+	return rv < 0 ? rv : 0;
 }
 EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, PMBUS);
 
Signature · 1 line
2.53.0
author maintainer
#95 lore raw

PATCH 94/337 idpf: adjust TxQ ring count minimum

In reply to Greg Kroah-Hartman

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

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

From: Joshua Hay <[email protected]>

[ Upstream commit bef152db47debcd14cbacefc5767f6f026c4bc89 ]

Set the TxQ ring count minimum to 128 descriptors. Any lower than this, and the queue will stall and trigger Tx timeouts in flow based scheduling mode. This is because next_to_clean might never be updated.

In flow based scheduling mode, next_to_clean is only updated after a descriptor completion is processed, i.e. after the RE bit is set in the last descriptor of a Tx packet. This will never happen with a ring size of 64 and an IDPF_TX_SPLITQ_RE_MIN_GAP of 64. No matter what the value of last_re is initialized/set to, the calculated gap will be at most 63 and never trigger the RE bit.

Even a ring size of 96 does not solve this. Because of how infrequent next_to_clean is updated and how small the ring is, IDPF_DESC_UNUSED will be much smaller on average. This increases the chance the queue will be stopped because a multi-descriptor packet, e.g. a large LSO packet, does not see enough resources on the ring. In this case, the queue will trigger the stop logic. The queue permanently stalls because there is no chance for a descriptor completion to update next_to_clean since it is dependent on a packet being sent.

Fixes 5f417d551324 ("idpf: replace flow scheduling buffer ring with buffer pool")
---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c | 5 +----
 drivers/net/ethernet/intel/idpf/idpf_txrx.h | 2 +-
 2 files changed, 2 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +1 -4
index 82a927265b9cf..afb922e8704d0 100644
@@ -2507,10 +2507,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
 
 		tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE;
 		tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP;
-		/* Set the RE bit to periodically "clean" the descriptor ring.
-		 * MIN_GAP is set to MIN_RING size to ensure it will be set at
-		 * least once each time around the ring.
-		 */
+		/* Set the RE bit periodically to "clean" the descriptor ring */
 		if (idpf_tx_splitq_need_re(tx_q)) {
 			tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE;
 			tx_q->txq_grp->num_completions_pending++;
drivers/net/ethernet/intel/idpf/idpf_txrx.h +1 -1
index a34c791c46088..2d9960dd51ad5 100644
@@ -19,7 +19,7 @@
 /* Mailbox Queue */
 #define IDPF_MAX_MBXQ				1
 
-#define IDPF_MIN_TXQ_DESC			64
+#define IDPF_MIN_TXQ_DESC			128
 #define IDPF_MIN_RXQ_DESC			64
 #define IDPF_MIN_TXQ_COMPLQ_DESC		256
 #define IDPF_MAX_QIDS				256
Signature · 1 line
2.53.0
author maintainer
#96 lore raw

PATCH 95/337 idpf: Fix mailbox IRQ name leak on request failure

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 9bff30482c10f70d9e56c0633a6616e07140e217 ]

idpf_mb_intr_req_irq() allocates the mailbox IRQ name before calling request_irq(). On success, the name is released later through kfree(free_irq()), but request_irq() failure returns without freeing it.

Free the allocated name on the request_irq() failure path.

Fixes 4930fbf419a7 ("idpf: add core init and interrupt request")
---
 drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/idpf/idpf_lib.c +1 -1
index 4973135c346a2..c2101f7f6e1bf 100644
@@ -134,7 +134,7 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
 	if (err) {
 		dev_err(&adapter->pdev->dev,
 			"IRQ request for mailbox failed, error: %d\n", err);
-
+		kfree(name);
 		return err;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#97 lore raw

PATCH 96/337 Bluetooth: ISO: clear iso_data always when detaching conn from hcon

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit d57e506f6a1e3929611340fae87c1e4823f4d85c ]

When setting conn->hcon = NULL, also conn->hcon->iso_data = NULL is necessary, otherwise later iso_conn_free() will UAF.

Fix clearing of iso_data in iso_sock_disconn()

Fixes KASAN: slab-use-after-free in iso_conn_hold_unless_zero on iso_sock_release() followed by hci_abort_conn_sync().

Fixes fbdc4bc47268 ("Bluetooth: ISO: Use defer setup to separate PA sync and BIG sync")
---
 net/bluetooth/iso.c | 1 +
 1 file changed, 1 insertion(+)
net/bluetooth/iso.c +1 -0
index 12a01dc6dbde3..1d3e4616ee700 100644
@@ -811,6 +811,7 @@ static void iso_sock_disconn(struct sock *sk)
 	sk->sk_state = BT_DISCONN;
 	iso_conn_lock(iso_pi(sk)->conn);
 	hci_conn_drop(iso_pi(sk)->conn->hcon);
+	iso_pi(sk)->conn->hcon->iso_data = NULL;
 	iso_pi(sk)->conn->hcon = NULL;
 	iso_conn_unlock(iso_pi(sk)->conn);
 }
Signature · 1 line
2.53.0
author maintainer
#98 lore raw

PATCH 97/337 Bluetooth: L2CAP: fix UAF in l2cap_le_connect_rsp

In reply to Greg Kroah-Hartman

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

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

From: Jiale Yao <[email protected]>

[ Upstream commit c4740e7f23ff9a8210198d8b4703259e21b9f69d ]

l2cap_le_connect_rsp() obtains a channel via __l2cap_get_chan_by_ident() but neither holds a reference nor uses l2cap_chan_hold_unless_zero() before locking and operating on it. A concurrent l2cap_chan_del() triggered by a remote disconnect can free the channel between the lookup and l2cap_chan_lock(), causing a use-after-free.

The BR/EDR counterpart l2cap_connect_rsp() and the sibling handler l2cap_le_command_rej() already use l2cap_chan_hold_unless_zero() to safely hold a reference, but l2cap_le_connect_rsp() was left unprotected.

Fix by adding l2cap_chan_hold_unless_zero() after the ident lookup and l2cap_chan_put() on the exit path, consistent with other L2CAP response handlers.

Fixes f1496dee9cbd ("Bluetooth: Add initial code for LE L2CAP Connect Request")
Assisted-by Claude:deepseek-v4-pro
---
 net/bluetooth/l2cap_core.c | 5 +++++
 1 file changed, 5 insertions(+)
net/bluetooth/l2cap_core.c +5 -0
index 56337f164d306..c876f986b27f5 100644
@@ -4796,6 +4796,10 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
 	if (!chan)
 		return -EBADSLT;
 
+	chan = l2cap_chan_hold_unless_zero(chan);
+	if (!chan)
+		return -EBADSLT;
+
 	err = 0;
 
 	l2cap_chan_lock(chan);
@@ -4841,6 +4845,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
 	}
 
 	l2cap_chan_unlock(chan);
+	l2cap_chan_put(chan);
 
 	return err;
 }
Signature · 1 line
2.53.0
author maintainer
#99 lore raw

PATCH 98/337 Bluetooth: ISO: fix timeout vs sync_timeout typo in check_bcast_qos

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit e9cb51813d79fc9aae4a2098aab3ab6ebd7fb6c8 ]

In iso.c check_bcast_qos(), missing bcast.timeout is not set to its default value, and appears typoed as bcast.sync_timeout.

Fix the typo.

Fixes b37cab587aa3 ("Bluetooth: ISO: Don't reject BT_ISO_QOS if parameters are unset")
---
 net/bluetooth/iso.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/iso.c +1 -1
index 1d3e4616ee700..c54e42ab6947b 100644
@@ -1636,7 +1636,7 @@ static bool check_bcast_qos(struct bt_iso_qos *qos)
 		return false;
 
 	if (!qos->bcast.timeout)
-		qos->bcast.sync_timeout = BT_ISO_SYNC_TIMEOUT;
+		qos->bcast.timeout = BT_ISO_SYNC_TIMEOUT;
 
 	if (qos->bcast.timeout < 0x000a || qos->bcast.timeout > 0x4000)
 		return false;
Signature · 1 line
2.53.0
author maintainer
#100 lore raw

PATCH 99/337 Bluetooth: ISO: validate sockaddr_iso first in iso_sock_rebind_bis()

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit 4e20192d46a685d73e590a60a4a2419a0a8afcbf ]

iso_sock_rebind_bis() updates socket iso_pi(sk)->bc_num_bis before validating the BIS values, so it's possible to end up with bc_num_bis inconsistent.

Assign to iso_pi(sk)->bc_num_bis only after validation.

Fixes 80837140c1f2 ("Bluetooth: ISO: Allow binding a PA sync socket")
---
 net/bluetooth/iso.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
net/bluetooth/iso.c +3 -3
index c54e42ab6947b..06c68e053b423 100644
@@ -1014,15 +1014,15 @@ static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
 		goto done;
 	}
 
-	iso_pi(sk)->bc_num_bis = sa->iso_bc->bc_num_bis;
-
-	for (int i = 0; i < iso_pi(sk)->bc_num_bis; i++)
+	for (int i = 0; i < sa->iso_bc->bc_num_bis; i++)
 		if (sa->iso_bc->bc_bis[i] < 0x01 ||
 		    sa->iso_bc->bc_bis[i] > 0x1f) {
 			err = -EINVAL;
 			goto done;
 		}
 
+	iso_pi(sk)->bc_num_bis = sa->iso_bc->bc_num_bis;
+
 	memcpy(iso_pi(sk)->bc_bis, sa->iso_bc->bc_bis,
 	       iso_pi(sk)->bc_num_bis);
 
Signature · 1 line
2.53.0
author maintainer
#101 lore raw

PATCH 100/337 Bluetooth: ISO: fix leaking sk after socket release

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit ce57442a379212fe3fda59c9437ee8217eceb5b1 ]

iso_sock_kill() tests !sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket || sock_flag(sk, SOCK_DEAD) for early return, but this is always true since sock_orphan(sk) sets SOCK_DEAD, so the sk reference released by socket always leaks, iso_sock_destruct is never called.

The socket reference also leaks when __iso_sock_close() does not set SOCK_ZAPPED, since iso_conn_del() does not call iso_sock_kill() after zapping.

Fix by replacing SOCK_DEAD by BT_SK_KILLED flag that is not used for something else, and lock_sock to ensure iso_sock_kill() puts sk only after socket release only once. Release and iso_conn_del may run concurrently. Call iso_sock_kill() from iso_conn_del() to clean sk up after zapping.

Remove call to iso_sock_kill() from iso_sock_close(), as it's generally no-op there.

Fixes ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type")
---
 net/bluetooth/iso.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)
net/bluetooth/iso.c +18 -2
index 06c68e053b423..a1c350defcb3a 100644
@@ -55,6 +55,7 @@ static void iso_sock_kill(struct sock *sk);
 enum {
 	BT_SK_BIG_SYNC,
 	BT_SK_PA_SYNC,
+	BT_SK_KILLED,
 };
 
 struct iso_pinfo {
@@ -286,6 +287,7 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
 	iso_sock_clear_timer(sk);
 	iso_chan_del(sk, err);
 	release_sock(sk);
+	iso_sock_kill(sk);
 	sock_put(sk);
 }
 
@@ -764,9 +766,13 @@ static void iso_sock_cleanup_listen(struct sock *parent)
  */
 static void iso_sock_kill(struct sock *sk)
 {
+	lock_sock(sk);
+
 	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
-	    sock_flag(sk, SOCK_DEAD))
+	    test_bit(BT_SK_KILLED, &iso_pi(sk)->flags)) {
+		release_sock(sk);
 		return;
+	}
 
 	BT_DBG("sk %p state %d", sk, sk->sk_state);
 
@@ -780,6 +786,9 @@ static void iso_sock_kill(struct sock *sk)
 	/* Kill poor orphan */
 	bt_sock_unlink(&iso_sk_list, sk);
 	sock_set_flag(sk, SOCK_DEAD);
+	set_bit(BT_SK_KILLED, &iso_pi(sk)->flags);
+
+	release_sock(sk);
 	sock_put(sk);
 }
 
@@ -859,7 +868,6 @@ static void iso_sock_close(struct sock *sk)
 	iso_sock_clear_timer(sk);
 	__iso_sock_close(sk);
 	release_sock(sk);
-	iso_sock_kill(sk);
 }
 
 static void iso_sock_init(struct sock *sk, struct sock *parent)
@@ -1867,8 +1875,16 @@ static int iso_sock_release(struct socket *sock)
 		release_sock(sk);
 	}
 
+	/* Make sure sk is valid even if iso_conn_del() is concurrent */
+	sock_hold(sk);
+
+	lock_sock(sk);
 	sock_orphan(sk);
+	release_sock(sk);
+
 	iso_sock_kill(sk);
+
+	sock_put(sk);
 	return err;
 }
 
Signature · 1 line
2.53.0
author maintainer
#102 lore raw

PATCH 101/337 Bluetooth: ISO: avoid deadlocks in iso_sock_timeout

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit 200fa1629c57a3ca2b03d3ca63fd3a9bfd910c43 ]

iso_sock_timeout() takes lock_sock, so sync disabling the timer while holding that lock may deadlock.

iso_sock_timeout() may also run concurrently with iso_conn_del(), which leads to UAF

        [Task 1]                      [Task hdev->workqueue]
        iso_sock_timeout              iso_conn_del
          iso_conn_hold_unless_zero     iso_chan_del
                           `------------> iso_conn_put
                                      caller frees hcon
          iso_conn_put
            iso_conn_free
              conn->hcon->iso_data = NULL; /* UAF */

Fix the deadlock by removing the disable from the lock_sock sections. Move the timer from iso_conn to iso_pinfo to decouple it from iso_conn which may need to be freed in lock_sock section. Convert some of the clear_timer to disable_timer.

Fixes dc26097bdb86 ("Bluetooth: ISO: Use kref to track lifetime of iso_conn")
---
 net/bluetooth/iso.c | 60 ++++++++++++++++++++++-----------------------
 1 file changed, 29 insertions(+), 31 deletions(-)
net/bluetooth/iso.c +29 -31
index a1c350defcb3a..5b53de4589471 100644
@@ -30,8 +30,6 @@ struct iso_conn {
 	spinlock_t	lock;
 	struct sock	*sk;
 
-	struct delayed_work	timeout_work;
-
 	struct sk_buff	*rx_skb;
 	__u32		rx_len;
 	__u16		tx_sn;
@@ -74,6 +72,7 @@ struct iso_pinfo {
 	__u8			base_len;
 	__u8			base[BASE_MAX_LENGTH];
 	struct iso_conn		*conn;
+	struct delayed_work	timeout_work;
 };
 
 static struct bt_iso_qos default_qos;
@@ -109,9 +108,6 @@ static void iso_conn_free(struct kref *ref)
 		hci_conn_drop(conn->hcon);
 	}
 
-	/* Ensure no more work items will run since hci_conn has been dropped */
-	disable_delayed_work_sync(&conn->timeout_work);
-
 	kfree_skb(conn->rx_skb);
 
 	kfree(conn);
@@ -152,48 +148,45 @@ static struct sock *iso_sock_hold(struct iso_conn *conn)
 
 static void iso_sock_timeout(struct work_struct *work)
 {
-	struct iso_conn *conn = container_of(work, struct iso_conn,
-					     timeout_work.work);
-	struct sock *sk;
-
-	conn = iso_conn_hold_unless_zero(conn);
-	if (!conn)
-		return;
-
-	iso_conn_lock(conn);
-	sk = iso_sock_hold(conn);
-	iso_conn_unlock(conn);
-	iso_conn_put(conn);
-
-	if (!sk)
-		return;
+	struct iso_pinfo *pi = container_of(work, struct iso_pinfo,
+					    timeout_work.work);
+	struct sock *sk = &pi->bt.sk;
 
 	BT_DBG("sock %p state %d", sk, sk->sk_state);
 
 	lock_sock(sk);
-	sk->sk_err = ETIMEDOUT;
-	sk->sk_state_change(sk);
+	if (!sock_flag(sk, SOCK_ZAPPED)) {
+		sk->sk_err = ETIMEDOUT;
+		sk->sk_state_change(sk);
+	}
 	release_sock(sk);
-	sock_put(sk);
 }
 
 static void iso_sock_set_timer(struct sock *sk, long timeout)
 {
+	lockdep_assert(lockdep_sock_is_held(sk));
+
+	cancel_delayed_work(&iso_pi(sk)->timeout_work);
+
 	if (!iso_pi(sk)->conn)
 		return;
 
 	BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
-	cancel_delayed_work(&iso_pi(sk)->conn->timeout_work);
-	schedule_delayed_work(&iso_pi(sk)->conn->timeout_work, timeout);
+	schedule_delayed_work(&iso_pi(sk)->timeout_work, timeout);
 }
 
 static void iso_sock_clear_timer(struct sock *sk)
 {
-	if (!iso_pi(sk)->conn)
-		return;
+	BT_DBG("sock %p state %d", sk, sk->sk_state);
+	cancel_delayed_work(&iso_pi(sk)->timeout_work);
+}
+
+static void iso_sock_disable_timer(struct sock *sk)
+{
+	lockdep_assert(!lockdep_sock_is_held(sk));
 
 	BT_DBG("sock %p state %d", sk, sk->sk_state);
-	cancel_delayed_work(&iso_pi(sk)->conn->timeout_work);
+	disable_delayed_work_sync(&iso_pi(sk)->timeout_work);
 }
 
 /* ---- ISO connections ---- */
@@ -218,7 +211,6 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon)
 
 	kref_init(&conn->ref);
 	spin_lock_init(&conn->lock);
-	INIT_DELAYED_WORK(&conn->timeout_work, iso_sock_timeout);
 
 	hcon->iso_data = conn;
 	conn->hcon = hcon;
@@ -283,8 +275,9 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
 		return;
 	}
 
+	iso_sock_disable_timer(sk);
+
 	lock_sock(sk);
-	iso_sock_clear_timer(sk);
 	iso_chan_del(sk, err);
 	release_sock(sk);
 	iso_sock_kill(sk);
@@ -766,6 +759,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)
  */
 static void iso_sock_kill(struct sock *sk)
 {
+	iso_sock_disable_timer(sk);
+
 	lock_sock(sk);
 
 	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
@@ -864,8 +859,9 @@ static void __iso_sock_close(struct sock *sk)
 /* Must be called on unlocked socket. */
 static void iso_sock_close(struct sock *sk)
 {
+	iso_sock_disable_timer(sk);
+
 	lock_sock(sk);
-	iso_sock_clear_timer(sk);
 	__iso_sock_close(sk);
 	release_sock(sk);
 }
@@ -934,6 +930,8 @@ static struct sock *iso_sock_alloc(struct net *net, struct socket *sock,
 	iso_pi(sk)->qos = default_qos;
 	iso_pi(sk)->sync_handle = -1;
 
+	INIT_DELAYED_WORK(&iso_pi(sk)->timeout_work, iso_sock_timeout);
+
 	bt_sock_link(&iso_sk_list, sk);
 	return sk;
 }
Signature · 1 line
2.53.0
author maintainer
#103 lore raw

PATCH 102/337 Bluetooth: btintel: Validate length before parsing diagnostics TLV

In reply to Greg Kroah-Hartman

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

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

From: Zijun Hu <[email protected]>

[ Upstream commit b640ff9af3c809ff5ea2077fbba17df1594ec1e4 ]

btintel_diagnostics() accesses tlv->val[0] without first validating that the diagnostics VSE is long enough to contain that field, so may cause reading data beyond the received frame.

Fix by validating the length before access.

Fixes af395330abed ("Bluetooth: btintel: Add Intel devcoredump support")
---
 drivers/bluetooth/btintel.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/bluetooth/btintel.c +3 -0
index 6e3e4a817e727..cb948423a9bd8 100644
@@ -3335,6 +3335,9 @@ int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct intel_tlv *tlv = (void *)&skb->data[5];
 
+	if (skb->len < 5 + sizeof(*tlv) + sizeof(tlv->val[0]))
+		goto recv_frame;
+
 	/* The first event is always an event type TLV */
 	if (tlv->type != INTEL_TLV_TYPE_ID)
 		goto recv_frame;
Signature · 1 line
2.53.0
author maintainer
#104 lore raw

PATCH 103/337 Bluetooth: hci_sync: make hci_cmd_sync_run_once return -EEXIST if exists

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit d288f4db0909c22342eb50cd1632b4d850517281 ]

hci_cmd_sync_run_once() needs to indicate whether a queue item was added, so caller can know if callbacks are called, so it can avoid leaking resources.

Change the function to return -EEXIST if queue item already exists.

Modify all callsites vs. the changes. The only callsite is hci_abort_conn().

Stable-dep-of: 5761d003daa9 ("Bluetooth: hci_conn: hold conn reference in abort_conn_sync()")

---
 net/bluetooth/hci_conn.c | 4 +++-
 net/bluetooth/hci_sync.c | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)
net/bluetooth/hci_conn.c +3 -1
index ac98e3f2344e2..93c14e2d66c8a 100644
@@ -2928,6 +2928,7 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)
 int hci_abort_conn(struct hci_conn *conn, u8 reason)
 {
 	struct hci_dev *hdev = conn->hdev;
+	int err;
 
 	/* If abort_reason has already been set it means the connection is
 	 * already being aborted so don't attempt to overwrite it.
@@ -2949,5 +2950,6 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
 	 * as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
 	 * already queue its callback on cmd_sync_work.
 	 */
-	return hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
+	err = hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
+	return (err == -EEXIST) ? 0 : err;
 }
net/bluetooth/hci_sync.c +1 -1
index d2e8543b5a51e..111b8f3c77296 100644
@@ -825,7 +825,7 @@ int hci_cmd_sync_run_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
 			  void *data, hci_cmd_sync_work_destroy_t destroy)
 {
 	if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
-		return 0;
+		return -EEXIST;
 
 	return hci_cmd_sync_run(hdev, func, data, destroy);
 }
Signature · 1 line
2.53.0
author maintainer
#105 lore raw

PATCH 104/337 Bluetooth: hci_conn: hold conn reference in abort_conn_sync()

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit 5761d003daa987ac81463f570713ce9c9dd204e5 ]

There is theoretical UAF if the conn is freed while the hci_sync task is running.

Hold refcount to avoid that.

Fixes 227a0cdf4a02 ("Bluetooth: MGMT: Fix not generating command complete for MGMT_OP_DISCONNECT")
---
 net/bluetooth/hci_conn.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
net/bluetooth/hci_conn.c +11 -1
index 93c14e2d66c8a..c5b006d9d974a 100644
@@ -2925,6 +2925,13 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)
 	return hci_abort_conn_sync(hdev, conn, conn->abort_reason);
 }
 
+static void abort_conn_destroy(struct hci_dev *hdev, void *data, int err)
+{
+	struct hci_conn *conn = data;
+
+	hci_conn_put(conn);
+}
+
 int hci_abort_conn(struct hci_conn *conn, u8 reason)
 {
 	struct hci_dev *hdev = conn->hdev;
@@ -2950,6 +2957,9 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
 	 * as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
 	 * already queue its callback on cmd_sync_work.
 	 */
-	err = hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
+	err = hci_cmd_sync_run_once(hdev, abort_conn_sync, hci_conn_get(conn),
+				    abort_conn_destroy);
+	if (err)
+		hci_conn_put(conn);
 	return (err == -EEXIST) ? 0 : err;
 }
Signature · 1 line
2.53.0
author maintainer
#106 lore raw

PATCH 105/337 Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit 2c1e4e00613dfd105f978be2276e5e265801ec9f ]

hci_conn_del() caller must hold hdev->lock, check the conn was not concurrently deleted, and usually inform socket the conn is going to be deleted.

Use hci_abort_conn_sync() instead of calling hci_conn_del() without locks etc.

Fixes 8e8b92ee60de5 ("Bluetooth: hci_sync: Add hci_le_create_conn_sync")
---
 net/bluetooth/hci_sync.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
net/bluetooth/hci_sync.c +3 -1
index 111b8f3c77296..8c48d459a5415 100644
@@ -6593,7 +6593,9 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
 		if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
 		    hdev->le_scan_type == LE_SCAN_ACTIVE &&
 		    !hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
-			hci_conn_del(conn);
+			conn->state = BT_OPEN;
+			hci_abort_conn_sync(hdev, conn,
+					    HCI_ERROR_REJ_LIMITED_RESOURCES);
 			hci_conn_put(conn);
 			return -EBUSY;
 		}
Signature · 1 line
2.53.0
author maintainer
#107 lore raw

PATCH 106/337 Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync

In reply to Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

[ Upstream commit c0a9dcd2be398eee505d4b254ec3a845aa8ab189 ]

hci_conn_get() without already held reference is data race against concurrent deletion.

In previous patches, the refcount has been changed to be taken before starting the hci_sync task, so remove these extra get() + put() as they are not needed.

Fixes 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
---
 net/bluetooth/hci_sync.c | 13 -------------
 1 file changed, 13 deletions(-)
net/bluetooth/hci_sync.c +0 -13
index 8c48d459a5415..03bbf4c1d6e5a 100644
@@ -6577,11 +6577,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
 
 	bt_dev_dbg(hdev, "conn %p", conn);
 
-	/* Hold a reference so conn stays valid for the HCI_CONN_CREATE
-	 * clear_bit() at done.
-	 */
-	hci_conn_get(conn);
-
 	clear_bit(HCI_CONN_SCANNING, &conn->flags);
 	conn->state = BT_CONNECT;
 
@@ -6596,7 +6591,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
 			conn->state = BT_OPEN;
 			hci_abort_conn_sync(hdev, conn,
 					    HCI_ERROR_REJ_LIMITED_RESOURCES);
-			hci_conn_put(conn);
 			return -EBUSY;
 		}
 
@@ -6690,7 +6684,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
 
 	/* Re-enable advertising after the connection attempt is finished. */
 	hci_resume_advertising_sync(hdev);
-	hci_conn_put(conn);
 	return err;
 }
 
@@ -6965,11 +6958,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
 	else
 		cp.role_switch = 0x00;
 
-	/* Hold a reference so conn stays valid for the HCI_CONN_CREATE
-	 * clear_bit() below.
-	 */
-	hci_conn_get(conn);
-
 	/* Mark create connection in flight so hci_cancel_connect_sync() can
 	 * cancel it while blocking on the connection complete event.
 	 */
@@ -6981,7 +6969,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
 				       conn->conn_timeout, NULL);
 
 	clear_bit(HCI_CONN_CREATE, &conn->flags);
-	hci_conn_put(conn);
 
 	return err;
 }
Signature · 1 line
2.53.0
#108 lore raw

Re: [PATCH 6.12 106/337] Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync

Hi Greg/Sasha

Quoted 6 lines · Greg Kroah-Hartman

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

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

From: Pauli Virtanen <[email protected]>

Quoted 9 lines

[ Upstream commit c0a9dcd2be398eee505d4b254ec3a845aa8ab189 ]

hci_conn_get() without already held reference is data race against concurrent deletion.

In previous patches, the refcount has been changed to be taken before starting the hci_sync task, so remove these extra get() + put() as they are not needed.

I have run an AI assisted backport review and it spotted an issue; I checked 6.12.y tree and the prerequisite change is missing.

Upstream first changed the callers to queue a held reference:

err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync,

			      hci_conn_get(conn),
			      hci_acl_create_conn_sync_complete);
if (err)
	hci_conn_put(conn);

The posted 6.12.y state still queues the raw pointer:

return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,

			       NULL);

This backport nevertheless removes the worker-side get/put pairs. That leaves the queued work without a reference if connection deletion races it. I think 6.12.y misses commit: 2f5d635ad5906 ("Bluetooth:
hci_sync: hold conn in hci_connect_acl/le_sync() callbacks"); I think we have to either queue this prerequisite or drop this, thoughts ?

Also this is part of the series: https://lore.kernel.org/all/178517880663.1372023.9123649060094265539.git-patchwork-notify@kernel.org/

thanks,
Harshit

Quoted 27 lines
Fixes 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
---
  net/bluetooth/hci_sync.c | 13 -------------
  1 file changed, 13 deletions(-)
net/bluetooth/hci_sync.c +0 -5
index 8c48d459a5415..03bbf4c1d6e5a 100644
@@ -6577,11 +6577,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
 
  	bt_dev_dbg(hdev, "conn %p", conn);
 
-	/* Hold a reference so conn stays valid for the HCI_CONN_CREATE
-	 * clear_bit() at done.
-	 */
-	hci_conn_get(conn);
-
  	clear_bit(HCI_CONN_SCANNING, &conn->flags);
  	conn->state = BT_CONNECT;
 
@@ -6596,7 +6591,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
  			conn->state = BT_OPEN;
  			hci_abort_conn_sync(hdev, conn,
maintainer
#109 lore raw

Re: [PATCH 6.12 106/337] Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync

Quoted 5 lines · Harshit Mogalapalli

This backport nevertheless removes the worker-side get/put pairs. That leaves the queued work without a reference if connection deletion races it. I think 6.12.y misses commit: 2f5d635ad5906 ("Bluetooth:
hci_sync: hold conn in hci_connect_acl/le_sync() callbacks"); I think we have to either queue this prerequisite or drop this, thoughts ?

Good catch, thank you. The same problem is in 6.18.y and 6.6.y, not just 6.12.y. I've dropped it from the 6.18, 6.12 and 6.6 queues.

Signature · 2 lines
Thanks,
Sasha
author maintainer
#110 lore raw

PATCH 107/337 net: phylink: put link_gpio if phylink_create fails

In reply to Greg Kroah-Hartman

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

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

From: Christian Marangi <[email protected]>

[ Upstream commit 0fe1e3e8f3380d7862296a73b528d164e96c76b8 ]

In phylink_create() if phylink_register_sfp() returns an error, link_gpio obtained by phylink_parse_fixedlink() is never released. While this is a very unlikely scenario, it's worth to fix/handle this.

This was present from the very first implementation of phylink but got relevant only with the introduction of ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages") where additional function were added after phylink_parse_fixedlink() making the release of link_gpio needed if such additional function errored out.

While at it, restructure the exit condition of phylink_create() with the goto pattern to reduce code duplication on handling error conditions.

Fixes ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages")
---
 drivers/net/phy/phylink.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/net/phy/phylink.c +15 -14
index b78dfcbec936c..e6f3963739ad6 100644
@@ -1728,8 +1728,8 @@ struct phylink *phylink_create(struct phylink_config *config,
 	} else if (config->type == PHYLINK_DEV) {
 		pl->dev = config->dev;
 	} else {
-		kfree(pl);
-		return ERR_PTR(-EINVAL);
+		ret = -EINVAL;
+		goto free_pl;
 	}
 
 	pl->using_mac_select_pcs = using_mac_select_pcs;
@@ -1753,28 +1753,29 @@ struct phylink *phylink_create(struct phylink_config *config,
 	phylink_validate(pl, pl->supported, &pl->link_config);
 
 	ret = phylink_parse_mode(pl, fwnode);
-	if (ret < 0) {
-		kfree(pl);
-		return ERR_PTR(ret);
-	}
+	if (ret < 0)
+		goto free_pl;
 
 	if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
 		ret = phylink_parse_fixedlink(pl, fwnode);
-		if (ret < 0) {
-			kfree(pl);
-			return ERR_PTR(ret);
-		}
+		if (ret < 0)
+			goto release_link_gpio;
 	}
 
 	pl->cur_link_an_mode = pl->cfg_link_an_mode;
 
 	ret = phylink_register_sfp(pl, fwnode);
-	if (ret < 0) {
-		kfree(pl);
-		return ERR_PTR(ret);
-	}
+	if (ret < 0)
+		goto release_link_gpio;
 
 	return pl;
+
+release_link_gpio:
+	if (pl->link_gpio)
+		gpiod_put(pl->link_gpio);
+free_pl:
+	kfree(pl);
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(phylink_create);
 
Signature · 1 line
2.53.0
author maintainer
#111 lore raw

PATCH 108/337 scsi: target: iblock: Fix wrong PR ops NULL check for PREEMPT/RELEASE

In reply to Greg Kroah-Hartman

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

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

From: TanZheng <[email protected]>

[ Upstream commit 9c33222bd387312874fbe36ca8002e5c945b9653 ]

In the iblock_execute_pr_out() function, PRO_PREEMPT, PRO_PREEMPT_AND_ABORT, and PRO_RELEASE all perform callback capability checks through ops->pr_clear. The error check allows unimplemented hooks to pass through the gate, resulting dereferencing a NULL function pointer.

Check whether the hooks that need to be called are supported.

Fixes 394f81184882 ("scsi: target: Add block PR support to iblock")
---
 drivers/target/target_core_iblock.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/target/target_core_iblock.c +3 -3
index c8dc92a7d63e6..0a232abee8f58 100644
@@ -891,7 +891,7 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
 		break;
 	case PRO_PREEMPT:
 	case PRO_PREEMPT_AND_ABORT:
-		if (!ops->pr_clear) {
+		if (!ops->pr_preempt) {
 			pr_err("block_device does not support pr_preempt.\n");
 			return TCM_UNSUPPORTED_SCSI_OPCODE;
 		}
@@ -901,8 +901,8 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
 				      sa == PRO_PREEMPT_AND_ABORT);
 		break;
 	case PRO_RELEASE:
-		if (!ops->pr_clear) {
-			pr_err("block_device does not support pr_pclear.\n");
+		if (!ops->pr_release) {
+			pr_err("block_device does not support pr_release.\n");
 			return TCM_UNSUPPORTED_SCSI_OPCODE;
 		}
 
Signature · 1 line
2.53.0
author maintainer
#112 lore raw

PATCH 109/337 scsi: ufs: core: Cancel RTC work in active-active suspend

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

[ Upstream commit f71b4a30983b846b4075bf544e835121e70e6a43 ]

UFS RTC support schedules ufs_rtc_update_work to periodically update the device RTC. The work can issue query commands and access the UFS host controller.

A previous change moved the RTC work cancellation before the PRE_CHANGE vendor suspend callback to close a race in the common suspend path. However, the active-active path jumps directly to vops_suspend after flushing exception handling work and therefore bypasses the cancellation.

If the RTC work runs while the vendor suspend callback is gating or otherwise changing hardware state, it can access the controller during suspend and trigger an SError.

Cancel the RTC work before entering the vendor suspend callback in the active-active path. Since this path now cancels the work, move the RTC work scheduling outside the device and link state restoration block in the resume path. This restarts RTC updates after an active-active suspend and resume cycle.

Fixes b0bd84c39289 ("scsi: ufs: core: Fix SError in ufshcd_rtc_work() during UFS suspend")
---
 drivers/ufs/core/ufshcd.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/ufs/core/ufshcd.c +4 -2
index 205427f6c4651..98bf5bc6f383e 100644
@@ -9761,6 +9761,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 			req_link_state == UIC_LINK_ACTIVE_STATE) {
 		ufshcd_disable_auto_bkops(hba);
 		flush_work(&hba->eeh_work);
+		cancel_delayed_work_sync(&hba->ufs_rtc_update_work);
 		goto vops_suspend;
 	}
 
@@ -9970,10 +9971,11 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 		if (ret)
 			goto set_old_link_state;
 		ufshcd_set_timestamp_attr(hba);
-		schedule_delayed_work(&hba->ufs_rtc_update_work,
-				      msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
 	}
 
+	schedule_delayed_work(&hba->ufs_rtc_update_work,
+			      msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
+
 	if (ufshcd_keep_autobkops_enabled_except_suspend(hba))
 		ufshcd_enable_auto_bkops(hba);
 	else
Signature · 1 line
2.53.0
author maintainer
#113 lore raw

PATCH 110/337 scsi: zfcp: Fix memory leak during adapter release by destroying gid_pn_req

In reply to Greg Kroah-Hartman

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

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

From: Benjamin Block <[email protected]>

[ Upstream commit b601fa590e667bd9643feed8c869b6b3e418480d ]

When releasing an adapter we don't free the mempool 'gid_pn_req' that is allocated during the enqueue. This leaks memory:

unreferenced object 0xd8d29297de700 (size 256):

    comm "(udev-worker)", pid 2105, jiffies 4294945794
    hex dump (first 32 bytes):
      00 00 00 00 de ad 4e ad ff ff ff ff 00 00 00 00  ......N.........
      ff ff ff ff ff ff ff ff 00 0d c4 5f 67 9d 99 e0  ..........._g...
    backtrace (crc 4a5b5da2):
      [<000dc45f64da418c>] kmemleak_alloc+0x6c/0xa0
      [<000dc45f62b430aa>] __kmalloc_cache_node_noprof+0x36a/0x4d0
      [<000dc45f629a535a>] mempool_create_node_noprof+0xaa/0x150
      [<000dc45ee2c065e6>] zfcp_allocate_low_mem_buffers+0x96/0x370 [zfcp]
      [<000dc45ee2c070f8>] zfcp_adapter_enqueue+0x598/0xd40 [zfcp]
      [<000dc45ee2c08eb0>] zfcp_ccw_set_online+0x160/0x210 [zfcp]
      [<000dc45f643d4762>] ccw_device_set_online+0x232/0xd80
      [<000dc45f643d53d4>] online_store_recog_and_online+0x124/0x390
      [<000dc45f643d8238>] online_store+0x298/0x5b0
      [<000dc45f62eb0a04>] kernfs_fop_write_iter+0x2c4/0x480
      [<000dc45f62c81150>] new_sync_write+0x370/0x4b0
      [<000dc45f62c87abe>] vfs_write+0x43e/0x5b0
      [<000dc45f62c87ff4>] ksys_write+0x114/0x1f0
      [<000dc45f621c4a16>] do_syscall+0x2f6/0x430
      [<000dc45f64d9d5d8>] __do_syscall+0xc8/0x1c0
      [<000dc45f64dc2224>] system_call+0x74/0xa0

Fix this by destroying the mempool during the adapter's release.

---
 drivers/s390/scsi/zfcp_aux.c | 1 +
 1 file changed, 1 insertion(+)
drivers/s390/scsi/zfcp_aux.c +1 -0
index ab2f35bc294da..d3cc884ccd599 100644
@@ -254,6 +254,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
 static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
 {
 	mempool_destroy(adapter->pool.erp_req);
+	mempool_destroy(adapter->pool.gid_pn_req);
 	mempool_destroy(adapter->pool.scsi_req);
 	mempool_destroy(adapter->pool.scsi_abort);
 	mempool_destroy(adapter->pool.qtcb_pool);
Signature · 1 line
2.53.0
author maintainer
#114 lore raw

PATCH 111/337 scsi: target: Clear cmd_cnt when initial counter enrollment fails

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit a8ddfd2425bbbafadae8700d63ed8a61a4109878 ]

When target_get_sess_cmd() fails during session shutdown because percpu_ref_tryget_live() returns false, the command keeps the se_cmd->cmd_cnt pointer that __target_init_cmd() assigned earlier without owning a reference. Final release through target_release_cmd_kref() then issues an unmatched percpu_ref_put().

Commit 8e288be8606a ("scsi: target: Pass in cmd counter to use during cmd setup") moved the cmd_cnt assignment ahead of the reference acquisition. Clear se_cmd->cmd_cnt whenever the initial target_get_sess_cmd() fails in target_init_cmd() and target_submit_tmr(), so release performs exactly one matching put per acquired reference.

---
 drivers/target/target_core_transport.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/target/target_core_transport.c +10 -2
index cf9834f958c9c..3dc49f6c7832e 100644
@@ -1691,6 +1691,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
 		    u32 data_length, int task_attr, int data_dir, int flags)
 {
 	struct se_portal_group *se_tpg;
+	int ret;
 
 	se_tpg = se_sess->se_tpg;
 	BUG_ON(!se_tpg);
@@ -1720,7 +1721,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
 	 * necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
 	 * kref_put() to happen during fabric packet acknowledgement.
 	 */
-	return target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+	ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+	if (ret)
+		se_cmd->cmd_cnt = NULL;
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(target_init_cmd);
 
@@ -1996,8 +2001,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 	 * allocation failure.
 	 */
 	ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp);
-	if (ret < 0)
+	if (ret < 0) {
+		se_cmd->cmd_cnt = NULL;
 		return -ENOMEM;
+	}
 
 	if (tm_type == TMR_ABORT_TASK)
 		se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2005,6 +2012,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 	/* See target_submit_cmd for commentary */
 	ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
 	if (ret) {
+		se_cmd->cmd_cnt = NULL;
 		core_tmr_release_req(se_cmd->se_tmr_req);
 		return ret;
 	}
Signature · 1 line
2.53.0
author maintainer
#115 lore raw

PATCH 112/337 net: sxgbe: free TX rings on RX allocation failure

In reply to Greg Kroah-Hartman

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

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

From: Chenguang Zhao <[email protected]>

[ Upstream commit c870f7e2890b9f78ac84515a9809cc5c183c975e ]

When RX descriptor ring allocation fails, init_dma_desc_rings() only frees the partially allocated RX rings and returns. The TX rings that were allocated earlier in the same function are leaked.

Rearrange error labels to clean up TX rings upon RX failures.

Fixes 1edb9ca69e8a ("net: sxgbe: add basic framework for Samsung 10Gb ethernet driver")
---
 drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -5
index d2ba283f6123f..a4f457fa570d9 100644
@@ -598,14 +598,13 @@ static int init_dma_desc_rings(struct net_device *netd)
 
 	return 0;
 
-txalloc_err:
-	while (queue_num--)
-		free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
-	return ret;
-
 rxalloc_err:
 	while (queue_num--)
 		free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+	queue_num = SXGBE_TX_QUEUES;
+txalloc_err:
+	while (queue_num--)
+		free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#116 lore raw

PATCH 113/337 net: sxgbe: check descriptor ring allocation failures

In reply to Greg Kroah-Hartman

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

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

From: Chenguang Zhao <[email protected]>

[ Upstream commit 51b093a7ba27476e1f639455f005e8d2e75390e4 ]

sxgbe_open() ignores the return value of init_dma_desc_rings() and continues to program DMA with invalid ring addresses when allocation fails. Check the return value and disconnect the PHY on failure.

Fixes 1edb9ca69e8a ("net: sxgbe: add basic framework for Samsung 10Gb ethernet driver")
---
 drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -1
index a4f457fa570d9..4afa2b2c67b47 100644
@@ -1079,7 +1079,9 @@ static int sxgbe_open(struct net_device *dev)
 	priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE);
 	priv->tx_tc = TC_DEFAULT;
 	priv->rx_tc = TC_DEFAULT;
-	init_dma_desc_rings(dev);
+	ret = init_dma_desc_rings(dev);
+	if (ret)
+		goto init_phy_error;
 
 	/* DMA initialization and SW reset */
 	ret = sxgbe_init_dma_engine(priv);
@@ -1188,6 +1190,7 @@ static int sxgbe_open(struct net_device *dev)
 
 init_error:
 	free_dma_desc_resources(priv);
+init_phy_error:
 	if (dev->phydev)
 		phy_disconnect(dev->phydev);
 phy_error:
Signature · 1 line
2.53.0
author maintainer
#117 lore raw

PATCH 114/337 can: isotp: check register_netdevice_notifier() error in module init

In reply to Greg Kroah-Hartman

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

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

From: Minhong He <[email protected]>

[ Upstream commit ef09a13c5afac41a3c4b5f22b8572820d9e7518c ]

Register the netdevice notifier before can_proto_register() and check the return value. If protocol registration fails, unregister the notifier before returning the error.

Align isotp_module_init() with the reordering already done for raw.c (commit c28b3bffe49e ("can: raw: process optimization in raw_init()")) and bcm.c (commit edd1a7e42f1d ("can: bcm: registration process optimization in bcm_module_init()")).

Fixes 8d0caedb7596 ("can: bcm/raw/isotp: use per module netdevice notifier")
---
 net/can/isotp.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
net/can/isotp.c +9 -4
index b2622c881aa32..7e3d6afbb24f9 100644
@@ -1885,13 +1885,18 @@ static __init int isotp_module_init(void)
 
 	pr_info("can: isotp protocol (max_pdu_size %d)\n", max_pdu_size);
 
+	err = register_netdevice_notifier(&canisotp_notifier);
+	if (err)
+		return err;
+
 	err = can_proto_register(&isotp_can_proto);
-	if (err < 0)
+	if (err < 0) {
 		pr_err("can: registration of isotp protocol failed %pe\n", ERR_PTR(err));
-	else
-		register_netdevice_notifier(&canisotp_notifier);
+		unregister_netdevice_notifier(&canisotp_notifier);
+		return err;
+	}
 
-	return err;
+	return 0;
 }
 
 static __exit void isotp_module_exit(void)
Signature · 1 line
2.53.0
author maintainer
#118 lore raw

PATCH 115/337 tracing/mmiotrace: Reset dropped_count in mmio_reset_data()

In reply to Greg Kroah-Hartman

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

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

From: Masami Hiramatsu (Google) <[email protected]>

[ Upstream commit c786d2bdf1f3964deee192ad942dee2a741c1e2c ]

mmio_reset_data() is called during tracer initialization, reset, and start. While it resets overrun_detected and prev_overruns, it neglects to reset dropped_count. Consequently, dropped event counts from prior tracing sessions persist in dropped_count and corrupt overrun reports in subsequent runs.

Fix this by explicitly calling atomic_set(&dropped_count, 0) in mmio_reset_data().

Fixes 173ed24ee2d6 ("mmiotrace: count events lost due to not recording")
Assisted-by Antigravity:gemini-3.6-flash
---
 kernel/trace/trace_mmiotrace.c | 1 +
 1 file changed, 1 insertion(+)
kernel/trace/trace_mmiotrace.c +1 -0
index 4d9e5c830dbe1..c523ce5aa4958 100644
@@ -29,6 +29,7 @@ static void mmio_reset_data(struct trace_array *tr)
 {
 	overrun_detected = false;
 	prev_overruns = 0;
+	atomic_set(&dropped_count, 0);
 
 	tracing_reset_online_cpus(&tr->array_buffer);
 }
Signature · 1 line
2.53.0
author maintainer
#119 lore raw

PATCH 116/337 tracing: Remove TRACE_EVENT_FL_FILTERED logic

In reply to Greg Kroah-Hartman

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

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

From: Zheng Yejian <[email protected]>

[ Upstream commit 49e4154f4b16345da5e219b23ed9737a6e735bc1 ]

After commit dcb0b5575d24 ("tracing: Remove TRACE_EVENT_FL_USE_CALL_FILTER
logic"), no one's going to set the TRACE_EVENT_FL_FILTERED or change the
call->filter, so remove related logic.

Stable-dep-of: 12b80cdbc54c ("tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions")

---
 include/linux/trace_events.h         |  4 ---
 kernel/trace/trace.c                 | 44 ++++++----------------------
 kernel/trace/trace.h                 |  4 ---
 kernel/trace/trace_branch.c          |  4 +--
 kernel/trace/trace_events.c          |  2 --
 kernel/trace/trace_functions_graph.c |  8 ++---
 kernel/trace/trace_hwlat.c           |  4 +--
 kernel/trace/trace_mmiotrace.c       |  8 ++---
 kernel/trace/trace_osnoise.c         | 12 ++------
 kernel/trace/trace_sched_wakeup.c    |  8 ++---
 10 files changed, 20 insertions(+), 78 deletions(-)
include/linux/trace_events.h +0 -4
index 54ba231ded519..98ee10b417e67 100644
@@ -327,7 +327,6 @@ void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
 void trace_event_buffer_commit(struct trace_event_buffer *fbuffer);
 
 enum {
-	TRACE_EVENT_FL_FILTERED_BIT,
 	TRACE_EVENT_FL_CAP_ANY_BIT,
 	TRACE_EVENT_FL_NO_SET_FILTER_BIT,
 	TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
@@ -343,7 +342,6 @@ enum {
 
 /*
  * Event flags:
- *  FILTERED	  - The event has a filter attached
  *  CAP_ANY	  - Any user can enable for perf
  *  NO_SET_FILTER - Set when filter has error and is to be ignored
  *  IGNORE_ENABLE - For trace internal events, do not enable with debugfs file
@@ -359,7 +357,6 @@ enum {
  *  TEST_STR      - The event has a "%s" that points to a string outside the event
  */
 enum {
-	TRACE_EVENT_FL_FILTERED		= (1 << TRACE_EVENT_FL_FILTERED_BIT),
 	TRACE_EVENT_FL_CAP_ANY		= (1 << TRACE_EVENT_FL_CAP_ANY_BIT),
 	TRACE_EVENT_FL_NO_SET_FILTER	= (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT),
 	TRACE_EVENT_FL_IGNORE_ENABLE	= (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
@@ -385,7 +382,6 @@ struct trace_event_call {
 	};
 	struct trace_event	event;
 	char			*print_fmt;
-	struct event_filter	*filter;
 	/*
 	 * Static events can disappear with modules,
 	 * where as dynamic ones need their own ref count.
kernel/trace/trace.c +9 -35

110 lines not on this page · raw message

kernel/trace/trace.h +0 -4
index ed4fcc438a0bf..baa39009a25d1 100644
@@ -1440,10 +1440,6 @@ struct trace_subsystem_dir {
 	int				nr_events;
 };
 
-extern int call_filter_check_discard(struct trace_event_call *call, void *rec,
-				     struct trace_buffer *buffer,
-				     struct ring_buffer_event *event);
-
 void trace_buffer_unlock_commit_regs(struct trace_array *tr,
 				     struct trace_buffer *buffer,
 				     struct ring_buffer_event *event,
kernel/trace/trace_branch.c +1 -3
index 30f72e0ecb5d4..138f69521eb4a 100644
@@ -30,7 +30,6 @@ static struct trace_array *branch_tracer;
 static void
 probe_likely_condition(struct ftrace_likely_data *f, int val, int expect)
 {
-	struct trace_event_call *call = &event_branch;
 	struct trace_array *tr = branch_tracer;
 	struct trace_buffer *buffer;
 	struct trace_array_cpu *data;
@@ -82,8 +81,7 @@ probe_likely_condition(struct ftrace_likely_data *f, int val, int expect)
 	entry->line = f->data.line;
 	entry->correct = val == expect;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 
  out:
 	current->trace_recursion &= ~TRACE_BRANCH_BIT;
kernel/trace/trace_events.c +0 -2
index d07b8062ded30..14feebea4f000 100644
@@ -3319,8 +3319,6 @@ static void __trace_remove_event_call(struct trace_event_call *call)
 {
 	event_remove(call);
 	trace_destroy_fields(call);
-	free_event_filter(call->filter);
-	call->filter = NULL;
 }
 
 static int probe_remove_event_call(struct trace_event_call *call)
kernel/trace/trace_functions_graph.c +2 -6
index 47ea114ca9f46..04d403a38f04f 100644
@@ -102,7 +102,6 @@ int __trace_graph_entry(struct trace_array *tr,
 				struct ftrace_graph_ent *trace,
 				unsigned int trace_ctx)
 {
-	struct trace_event_call *call = &event_funcgraph_entry;
 	struct ring_buffer_event *event;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ftrace_graph_ent_entry *entry;
@@ -113,8 +112,7 @@ int __trace_graph_entry(struct trace_array *tr,
 		return 0;
 	entry	= ring_buffer_event_data(event);
 	entry->graph_ent			= *trace;
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 
 	return 1;
 }
@@ -223,7 +221,6 @@ void __trace_graph_return(struct trace_array *tr,
 				struct ftrace_graph_ret *trace,
 				unsigned int trace_ctx)
 {
-	struct trace_event_call *call = &event_funcgraph_exit;
 	struct ring_buffer_event *event;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ftrace_graph_ret_entry *entry;
@@ -234,8 +231,7 @@ void __trace_graph_return(struct trace_array *tr,
 		return;
 	entry	= ring_buffer_event_data(event);
 	entry->ret				= *trace;
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 }
 
 void trace_graph_return(struct ftrace_graph_ret *trace,
kernel/trace/trace_hwlat.c +1 -3
index bc437b6ce8969..8703eb86a20c8 100644
@@ -130,7 +130,6 @@ static bool hwlat_busy;
 static void trace_hwlat_sample(struct hwlat_sample *sample)
 {
 	struct trace_array *tr = hwlat_trace;
-	struct trace_event_call *call = &event_hwlat;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ring_buffer_event *event;
 	struct hwlat_entry *entry;
@@ -148,8 +147,7 @@ static void trace_hwlat_sample(struct hwlat_sample *sample)
 	entry->nmi_count		= sample->nmi_count;
 	entry->count			= sample->count;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 }
 
 /* Macros to encapsulate the time capturing infrastructure */
kernel/trace/trace_mmiotrace.c +2 -6
index c523ce5aa4958..6b964471265e1 100644
@@ -295,7 +295,6 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
 				struct trace_array_cpu *data,
 				struct mmiotrace_rw *rw)
 {
-	struct trace_event_call *call = &event_mmiotrace_rw;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ring_buffer_event *event;
 	struct trace_mmiotrace_rw *entry;
@@ -311,8 +310,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
 	entry	= ring_buffer_event_data(event);
 	entry->rw			= *rw;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
+	trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
 }
 
 void mmio_trace_rw(struct mmiotrace_rw *rw)
@@ -326,7 +324,6 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
 				struct trace_array_cpu *data,
 				struct mmiotrace_map *map)
 {
-	struct trace_event_call *call = &event_mmiotrace_map;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ring_buffer_event *event;
 	struct trace_mmiotrace_map *entry;
@@ -342,8 +339,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
 	entry	= ring_buffer_event_data(event);
 	entry->map			= *map;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
+	trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
 }
 
 void mmio_trace_mapping(struct mmiotrace_map *map)
kernel/trace/trace_osnoise.c +3 -9
index 4daedf8debdc5..549ac1916dc39 100644
@@ -501,7 +501,6 @@ static void print_osnoise_headers(struct seq_file *s)
 static void
 __trace_osnoise_sample(struct osnoise_sample *sample, struct trace_buffer *buffer)
 {
-	struct trace_event_call *call = &event_osnoise;
 	struct ring_buffer_event *event;
 	struct osnoise_entry *entry;
 
@@ -519,8 +518,7 @@ __trace_osnoise_sample(struct osnoise_sample *sample, struct trace_buffer *buffe
 	entry->softirq_count	= sample->softirq_count;
 	entry->thread_count	= sample->thread_count;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 }
 
 /*
@@ -580,7 +578,6 @@ static void print_timerlat_headers(struct seq_file *s)
 static void
 __trace_timerlat_sample(struct timerlat_sample *sample, struct trace_buffer *buffer)
 {
-	struct trace_event_call *call = &event_osnoise;
 	struct ring_buffer_event *event;
 	struct timerlat_entry *entry;
 
@@ -593,8 +590,7 @@ __trace_timerlat_sample(struct timerlat_sample *sample, struct trace_buffer *buf
 	entry->context			= sample->context;
 	entry->timer_latency		= sample->timer_latency;
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 }
 
 /*
@@ -656,7 +652,6 @@ static void timerlat_save_stack(int skip)
 static void
 __timerlat_dump_stack(struct trace_buffer *buffer, struct trace_stack *fstack, unsigned int size)
 {
-	struct trace_event_call *call = &event_osnoise;
 	struct ring_buffer_event *event;
 	struct stack_entry *entry;
 
@@ -670,8 +665,7 @@ __timerlat_dump_stack(struct trace_buffer *buffer, struct trace_stack *fstack, u
 	entry->size = fstack->nr_entries;
 	memcpy(&entry->caller, fstack->calls, size);
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit_nostack(buffer, event);
+	trace_buffer_unlock_commit_nostack(buffer, event);
 }
 
 /*
kernel/trace/trace_sched_wakeup.c +2 -6
index 039382576bc16..59e30d897a9da 100644
@@ -376,7 +376,6 @@ tracing_sched_switch_trace(struct trace_array *tr,
 			   struct task_struct *next,
 			   unsigned int trace_ctx)
 {
-	struct trace_event_call *call = &event_context_switch;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
 	struct ring_buffer_event *event;
 	struct ctx_switch_entry *entry;
@@ -394,8 +393,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
 	entry->next_state		= task_state_index(next);
 	entry->next_cpu	= task_cpu(next);
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
+	trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
 }
 
 static void
@@ -404,7 +402,6 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
 			   struct task_struct *curr,
 			   unsigned int trace_ctx)
 {
-	struct trace_event_call *call = &event_wakeup;
 	struct ring_buffer_event *event;
 	struct ctx_switch_entry *entry;
 	struct trace_buffer *buffer = tr->array_buffer.buffer;
@@ -422,8 +419,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
 	entry->next_state		= task_state_index(wakee);
 	entry->next_cpu			= task_cpu(wakee);
 
-	if (!call_filter_check_discard(call, entry, buffer, event))
-		trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
+	trace_buffer_unlock_commit(tr, buffer, event, trace_ctx);
 }
 
 static void notrace
Signature · 1 line
2.53.0
author maintainer
#120 lore raw

PATCH 117/337 tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions

In reply to Greg Kroah-Hartman

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

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

From: Masami Hiramatsu (Google) <[email protected]>

[ Upstream commit 12b80cdbc54cf615b4717a4e8180063408091ea2 ]

mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.

Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().

Fixes f984b51e0779 ("ftrace: add mmiotrace plugin")
Assisted-by Antigravity:gemini-3.6-flash
---
 kernel/trace/trace_mmiotrace.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +10 -2
index 6b964471265e1..251ed7051e409 100644
@@ -295,11 +295,15 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
 				struct trace_array_cpu *data,
 				struct mmiotrace_rw *rw)
 {
-	struct trace_buffer *buffer = tr->array_buffer.buffer;
+	struct trace_buffer *buffer;
 	struct ring_buffer_event *event;
 	struct trace_mmiotrace_rw *entry;
 	unsigned int trace_ctx;
 
+	if (!tr)
+		return;
+
+	buffer = tr->array_buffer.buffer;
 	trace_ctx = tracing_gen_ctx_flags(0);
 	event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_RW,
 					  sizeof(*entry), trace_ctx);
@@ -324,11 +328,15 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
 				struct trace_array_cpu *data,
 				struct mmiotrace_map *map)
 {
-	struct trace_buffer *buffer = tr->array_buffer.buffer;
+	struct trace_buffer *buffer;
 	struct ring_buffer_event *event;
 	struct trace_mmiotrace_map *entry;
 	unsigned int trace_ctx;
 
+	if (!tr)
+		return;
+
+	buffer = tr->array_buffer.buffer;
 	trace_ctx = tracing_gen_ctx_flags(0);
 	event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_MAP,
 					  sizeof(*entry), trace_ctx);
Signature · 1 line
2.53.0
#121 lore raw

Re: [PATCH 6.12 117/337] tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions

Hi Greg/Sasha,

Quoted 32 lines · Greg Kroah-Hartman

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

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

From: Masami Hiramatsu (Google) <[email protected]>

[ Upstream commit 12b80cdbc54cf615b4717a4e8180063408091ea2 ]

mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.

Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().

Fixes f984b51e0779 ("ftrace: add mmiotrace plugin")
Assisted-by Antigravity:gemini-3.6-flash
---
  kernel/trace/trace_mmiotrace.c | 12 ++++++++++--
  1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +0 -0
index 6b964471265e1..251ed7051e409 100644

kernel/trace/trace_mmiotrace.c static void __trace_mmiotrace_rw(struct trace_array *tr, · line 295

Quoted 1 line
kernel/trace/trace_mmiotrace.c +0 -0
@@ -295,11 +295,15 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
  				struct trace_array_cpu *data,

^^^ lets keep this in mind

kernel/trace/trace_mmiotrace.c static void __trace_mmiotrace_rw(struct trace_array *tr, · line 306

Quoted 12 lines
kernel/trace/trace_mmiotrace.c +5 -1
  				struct mmiotrace_rw *rw)
  {
-	struct trace_buffer *buffer = tr->array_buffer.buffer;
+	struct trace_buffer *buffer;
  	struct ring_buffer_event *event;
  	struct trace_mmiotrace_rw *entry;
  	unsigned int trace_ctx;
 
+	if (!tr)
+		return;
+
+	buffer = tr->array_buffer.buffer;

I ran an AI-assisted backport review and then checked the 6.12.y code. I think this backport is missing a small prerequisite.

Upstream's wrappers pass tr directly to __trace_mmiotrace_rw() and __trace_mmiotrace_map().Each function checks tr before dereferencing it:

if (!tr)

	return;

buffer = tr->array_buffer.buffer;

The upstream fix follows commit: 6936298393d8 ("tracing/mmiotrace: Remove reference to unused per CPU data pointer"), which removes the unused data argument.

6.12.y does not have that commit, so both functions still have that argument and their wrappers compute it first:

struct trace_array *tr = mmio_trace_array;
struct trace_array_cpu *data =

	per_cpu_ptr(tr->array_buffer.data, smp_processor_id());

__trace_mmiotrace_rw(tr, data, rw);

Consequently, if mmio_trace_array is NULL, the dereference in per_cpu_ptr(tr->array_buffer.data, ...) occurs before either function's new NULL check.

I think 6.12.y needs commit: 6936298393d8 ("tracing/mmiotrace: Remove reference to unused per CPU data pointer") before this fix.

Thoughts?

thanks,
Harshit

Quoted 20 lines
kernel/trace/trace_mmiotrace.c +5 -1
  	trace_ctx = tracing_gen_ctx_flags(0);
  	event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_RW,
  					  sizeof(*entry), trace_ctx);
@@ -324,11 +328,15 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
  				struct trace_array_cpu *data,
  				struct mmiotrace_map *map)
  {
-	struct trace_buffer *buffer = tr->array_buffer.buffer;
+	struct trace_buffer *buffer;
  	struct ring_buffer_event *event;
  	struct trace_mmiotrace_map *entry;
  	unsigned int trace_ctx;
 
+	if (!tr)
+		return;
+
+	buffer = tr->array_buffer.buffer;
  	trace_ctx = tracing_gen_ctx_flags(0);
  	event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_MAP,
  					  sizeof(*entry), trace_ctx);
#122 lore raw

Re: [PATCH 6.12 117/337] tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions

Quoted 24 lines · On Sat, 8 Aug 2026 22:53:31 +0530 Harshit Mogalapalli…

I ran an AI-assisted backport review and then checked the 6.12.y code. I think this backport is missing a small prerequisite.

Upstream's wrappers pass tr directly to __trace_mmiotrace_rw() and __trace_mmiotrace_map().Each function checks tr before dereferencing it:

if (!tr)

	return;

buffer = tr->array_buffer.buffer;

The upstream fix follows commit: 6936298393d8 ("tracing/mmiotrace:
Remove reference to unused per CPU data pointer"), which removes the unused data argument.

6.12.y does not have that commit, so both functions still have that argument and their wrappers compute it first:

struct trace_array *tr = mmio_trace_array;
struct trace_array_cpu *data =

	per_cpu_ptr(tr->array_buffer.data, smp_processor_id());

__trace_mmiotrace_rw(tr, data, rw);

Quoted 9 lines

Consequently, if mmio_trace_array is NULL, the dereference in per_cpu_ptr(tr->array_buffer.data, ...) occurs before either function's new NULL check.

I think 6.12.y needs commit: 6936298393d8 ("tracing/mmiotrace: Remove reference to unused per CPU data pointer") before this fix.

Thoughts?

Yeah, it looks like the kernel could crash for the same reasons without commit 6936298393d8.

Greg, care to backport that one too?

Thanks,

-- Steve

author maintainer
#123 lore raw

PATCH 118/337 accel/qaic: use sizeof(*trans_hdr) for transaction length check

In reply to Greg Kroah-Hartman

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

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

From: Muhammad Bilal <[email protected]>

[ Upstream commit d6c075f797a672a6e3bd2fd44aee713801698ec2 ]

In encode_message() the per-transaction lower-bound check compares trans_hdr->len against sizeof(trans_hdr), i.e. the size of the pointer, instead of sizeof(*trans_hdr), the size of struct qaic_manage_trans_hdr.

Every other length check in this file (encode_message() at the loop guard, decode_message(), etc.) correctly uses sizeof(*trans_hdr), so this is an inconsistency. On 64-bit builds the pointer and the struct are both 8 bytes, so the check is correct by coincidence and there is no behavioural change. On 32-bit builds the pointer is 4 bytes, which weakens the minimum-length check below the 8-byte header size.

Use sizeof(*trans_hdr) so the check validates against the actual transaction header size on all builds.

Fixes ea33cb6fc278 ("accel/qaic: tighten bounds checking in encode_message()")
---
 drivers/accel/qaic/qaic_control.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/accel/qaic/qaic_control.c +1 -1
index 8eae30fe14f98..8759b53ba38eb 100644
@@ -782,7 +782,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
 			break;
 		}
 		trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
-		if (trans_hdr->len < sizeof(trans_hdr) ||
+		if (trans_hdr->len < sizeof(*trans_hdr) ||
 		    size_add(user_len, trans_hdr->len) > user_msg->len) {
 			ret = -EINVAL;
 			break;
Signature · 1 line
2.53.0
author maintainer
#124 lore raw

PATCH 119/337 riscv: mm: Fix out-of-bounds page-table walk during memory hot-remove

In reply to Greg Kroah-Hartman

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

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

From: Karl Mehltretter <[email protected]>

[ Upstream commit a0188cc133696627857d16054e43f9ebc7efc821 ]

remove_pud_mapping() and remove_p4d_mapping() obtain a child table base with pud_offset(p4dp, 0) and p4d_offset(pgd, 0), then add the index for addr.

RISC-V folds page-table levels at runtime. When a level is folded, its offset helper returns the parent entry itself, but the index can still be nonzero. Adding it walks past the parent table. Sv48 folds P4D, while Sv39 folds both P4D and PUD, so memory hot-remove can descend into unrelated memory and pass an invalid page to __free_pages(). This can trigger:

kernel BUG at include/linux/mm.h:1810!
VM_BUG_ON_PAGE(page_ref_count(page) == 0)

  arch_remove_memory+0x1e/0x5c
  try_remove_memory+0x15e/0x200
  remove_memory+0x24/0x3c

Only add the index when the corresponding page-table level is enabled, matching p4d_offset() and pud_offset().

Fixes c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
Assisted-by Claude:claude-fable-5
---
 arch/riscv/mm/init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/mm/init.c +2 -2
index 4594f77a06ee3..e52f7dabb370c 100644
@@ -1726,7 +1726,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un
 
 	for (; addr < end; addr = next) {
 		next = pud_addr_end(addr, end);
-		pudp = pud_base + pud_index(addr);
+		pudp = pgtable_l4_enabled ? pud_base + pud_index(addr) : pud_base;
 		pud = pudp_get(pudp);
 		if (!pud_present(pud))
 			continue;
@@ -1757,7 +1757,7 @@ static void __meminit remove_p4d_mapping(p4d_t *p4d_base, unsigned long addr, un
 
 	for (; addr < end; addr = next) {
 		next = p4d_addr_end(addr, end);
-		p4dp = p4d_base + p4d_index(addr);
+		p4dp = pgtable_l5_enabled ? p4d_base + p4d_index(addr) : p4d_base;
 		p4d = p4dp_get(p4dp);
 		if (!p4d_present(p4d))
 			continue;
Signature · 1 line
2.53.0
author maintainer
#125 lore raw

PATCH 120/337 net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend

In reply to Greg Kroah-Hartman

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

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

From: Daniel Golle <[email protected]>

[ Upstream commit b4ce102b2cd88424c5860fbbb20b9eb343a93bf4 ]

bus->read() returns a negative errno on failure, but mt7530_regmap_read() assigns it to a u16, truncating e.g. -ETIMEDOUT into 0xff92, and returns success. The garbage word is then consumed as register data, and read-modify-write cycles write it back to the switch. Check both reads and propagate their errors.

The same defect existed in mt7530_mii_read() since the driver was introduced and moved into the regmap backend unchanged.

---
 drivers/net/dsa/mt7530-mdio.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/dsa/mt7530-mdio.c +9 -2
index 51df42ccdbe62..e19b46449ffe6 100644
@@ -55,8 +55,15 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
 	if (ret < 0)
 		return ret;
 
-	lo = bus->read(bus, priv->mdiodev->addr, r);
-	hi = bus->read(bus, priv->mdiodev->addr, 0x10);
+	ret = bus->read(bus, priv->mdiodev->addr, r);
+	if (ret < 0)
+		return ret;
+	lo = ret;
+
+	ret = bus->read(bus, priv->mdiodev->addr, 0x10);
+	if (ret < 0)
+		return ret;
+	hi = ret;
 
 	*val = (hi << 16) | (lo & 0xffff);
 
Signature · 1 line
2.53.0
author maintainer
#126 lore raw

PATCH 121/337 net: dsa: mt7530: error out on failed reads in MT7531 PHY polling

In reply to Greg Kroah-Hartman

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

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

From: Daniel Golle <[email protected]>

[ Upstream commit 77a9ebe8818cf6dd1699bd6728cb5d66307801d7 ]

The MT7531 indirect PHY access functions poll MT7531_PHY_IAC through a helper which returns 0 when the underlying read fails, so a failed bus transaction clears MT7531_PHY_ACS_ST and the access carries on, returning garbage PHY register data to phylib.

Poll using regmap_read_poll_timeout(), which stops on read errors and propagates them. These functions hold the MDIO bus lock across the whole sequence, so the unlocked regmap accesses remain correct. Remove the now-unused _mt7530_unlocked_read().

---
 drivers/net/dsa/mt7530.c | 58 ++++++++++++++--------------------------
 1 file changed, 20 insertions(+), 38 deletions(-)
drivers/net/dsa/mt7530.c +20 -38
index 21437ce57b64f..b13e905833c3f 100644
@@ -219,12 +219,6 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
 	mt7530_mutex_unlock(priv);
 }
 
-static u32
-_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
-{
-	return mt7530_mii_read(p->priv, p->reg);
-}
-
 static u32
 _mt7530_read(struct mt7530_dummy_poll *p)
 {
@@ -577,16 +571,13 @@ static int
 mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
 			int regnum)
 {
-	struct mt7530_dummy_poll p;
 	u32 reg, val;
 	int ret;
 
-	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
 	mt7530_mutex_lock(priv);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -596,8 +587,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
 	      MT7531_MDIO_DEV_ADDR(devad) | regnum;
 	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -607,8 +598,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
 	      MT7531_MDIO_DEV_ADDR(devad);
 	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -625,16 +616,13 @@ static int
 mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
 			 int regnum, u16 data)
 {
-	struct mt7530_dummy_poll p;
 	u32 val, reg;
 	int ret;
 
-	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
 	mt7530_mutex_lock(priv);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -644,8 +632,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
 	      MT7531_MDIO_DEV_ADDR(devad) | regnum;
 	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -655,8 +643,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
 	      MT7531_MDIO_DEV_ADDR(devad) | data;
 	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -671,16 +659,13 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
 static int
 mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
 {
-	struct mt7530_dummy_poll p;
 	int ret;
 	u32 val;
 
-	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
 	mt7530_mutex_lock(priv);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -691,8 +676,8 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
 
 	mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+				       !(val & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -709,16 +694,13 @@ static int
 mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
 			 u16 data)
 {
-	struct mt7530_dummy_poll p;
 	int ret;
 	u32 reg;
 
-	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
 	mt7530_mutex_lock(priv);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+				       !(reg & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
@@ -729,8 +711,8 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
 
 	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
 
-	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+	ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+				       !(reg & MT7531_PHY_ACS_ST), 20, 100000);
 	if (ret < 0) {
 		dev_err(priv->dev, "poll timeout\n");
 		goto out;
Signature · 1 line
2.53.0
author maintainer
#127 lore raw

PATCH 122/337 net: libwx: fix FDIR ATR queue mismatch for software VLAN packets

In reply to Greg Kroah-Hartman

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

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

From: Jiawen Wu <[email protected]>

[ Upstream commit 732ed8f75ce583d115716f668dc80d730f3ad610 ]

When TX VLAN hardware offload is disabled, VLAN tags are embedded in the packet payload (software VLAN). Previously, the driver failed to set the WX_TX_FLAGS_SW_VLAN flag for these packets during transmission.

This missing flag caused the txgbe FDIR ATR logic to fall through to the default hash calculation path. This resulted in asymmetric hash values for Tx and Rx flows, preventing return packets from being steered to the same queue as the transmit packets.

Fix this by detecting software VLANs via eth_type_vlan(skb->protocol) and setting WX_TX_FLAGS_SW_VLAN. This ensures the ATR feature selects the correct hashing algorithm to maintain Tx/Rx queue symmetry.

---
 drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/ethernet/wangxun/libwx/wx_lib.c +2 -0
index 4c203f4afd689..3666302e3401b 100644
@@ -1481,6 +1481,8 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb,
 	if (skb_vlan_tag_present(skb)) {
 		tx_flags |= skb_vlan_tag_get(skb) << WX_TX_FLAGS_VLAN_SHIFT;
 		tx_flags |= WX_TX_FLAGS_HW_VLAN;
+	} else if (eth_type_vlan(skb->protocol)) {
+		tx_flags |= WX_TX_FLAGS_SW_VLAN;
 	}
 
 	/* record initial flags and protocol */
Signature · 1 line
2.53.0
author maintainer
#128 lore raw

PATCH 123/337 octeontx2-pf: Set correct sequence for carrier off and tx queue stop

In reply to Greg Kroah-Hartman

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

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

From: Suman Ghosh <[email protected]>

[ Upstream commit 16809472409d998afcda402e32b8229b389337c4 ]

During link down event, we were doing netif_tx_stop_all_queues() first and then netif_carrier_off(). This can cause a potential race since carrier is still on during down event. This patch reverse the calling order to fix the issue.

Fixes 50fe6c02e5ad ("octeontx2-pf: Register and handle link notifications")
---
 drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -1
index c314139e0d781..d03399585d01d 100644
@@ -838,8 +838,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
 		netif_carrier_on(netdev);
 		netif_tx_start_all_queues(netdev);
 	} else {
-		netif_tx_stop_all_queues(netdev);
 		netif_carrier_off(netdev);
+		netif_tx_stop_all_queues(netdev);
 	}
 }
 
Signature · 1 line
2.53.0
author maintainer
#129 lore raw

PATCH 124/337 sched/deadline: Use revised wakeup rule only for running dl_server

In reply to Greg Kroah-Hartman

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

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

From: Gabriele Monaco <[email protected]>

[ Upstream commit 1842bf97af109f5ebf830175c9725bf81ebb78b1 ]

Commit 14a857056466 ("sched/deadline: Use revised wakeup rule for dl_server") applies the revised wakeup rule to any server, as a result servers that are not running (dl_defer_running == 0) and start with a deadline overflow get enqueued and can boost tasks as if they were running, invalidating the defer rule and the documented state model.

Apply the revised wakeup rule only for deferrable servers that are marked as running.

---
 kernel/sched/deadline.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched/deadline.c +2 -1
index cb8eff0ebd228..f5c64d1a019d5 100644
@@ -1079,7 +1079,8 @@ static void update_dl_entity(struct sched_dl_entity *dl_se)
 	if (dl_time_before(dl_se->deadline, rq_clock(rq)) ||
 	    dl_entity_overflow(dl_se, rq_clock(rq))) {
 
-		if (unlikely((!dl_is_implicit(dl_se) || dl_se->dl_defer) &&
+		if (unlikely((!dl_is_implicit(dl_se) ||
+			      (dl_se->dl_defer && dl_se->dl_defer_running)) &&
 			     !dl_time_before(dl_se->deadline, rq_clock(rq)) &&
 			     !is_dl_boosted(dl_se))) {
 			update_dl_revised_wakeup(dl_se, rq);
Signature · 1 line
2.53.0
author maintainer
#130 lore raw

PATCH 125/337 qede: sync udp_tunnel ports outside qede_lock in the recovery path

In reply to Greg Kroah-Hartman

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

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

From: Denis V. Lunev <[email protected]>

[ Upstream commit 451c9075d6c53f2438d110addbeeeea6fac18567 ]

A TX timeout on a qede NIC that has VXLAN/GENEVE tunnel ports configured wedges the rtnetlink control plane of the whole machine:

NETDEV WATCHDOG: ens6f1 (qede): transmit queue 2 timed out 10226 ms [qede_tx_timeout:586(ens6f1)]TX timeout on queue 2! [qede_recovery_handler:2665(ens6f0)]Starting a recovery process

The recovery path deadlocks on the driver's own mutex:

qede_sp_task
rtnl_lock()
mutex_lock(&edev->qede_lock) <- taken
qede_recovery_handler

    qede_load
    udp_tunnel_nic_reset_ntf
     __udp_tunnel_nic_device_sync
      info->sync_table == qede_udp_tunnel_sync
       mutex_lock(&edev->qede_lock)    <- same task: deadlock

The mutex is not recursive, so the kworker blocks on itself with rtnl_lock held, and neither lock is ever released. Every task that calls rtnl_lock() afterwards (ip, ovs-vswitchd, lldpad, IPv6 addrconf, sshd) blocks forever while the node still answers ping. In a vmcore from an affected production node rtnl_mutex.owner decodes to the very kworker blocked at the innermost mutex_lock() above.

Re-sync the tunnel ports from qede_sp_task() after the internal lock is dropped, still under rtnl_lock as the udp_tunnel API requires. This mirrors qede_open(), which calls udp_tunnel_nic_reset_ntf() under rtnl without the internal lock.

qede_recovery_handler() now returns whether it has successfully reloaded an open device, and the caller re-syncs the ports only in that case. This keeps the old gating exactly: a device that was down or a failed recovery returns false, as those paths never reached the udp_tunnel_nic_reset_ntf() call before either.

This was the only user of the qede_lock()/qede_unlock() helpers, so remove them.

Fixes 8cd160a29415 ("qede: convert to new udp_tunnel_nic infra")
CC Andrew Lunn <[email protected]>
CC "David S. Miller" <[email protected]>
CC Eric Dumazet <[email protected]>
CC Jakub Kicinski <[email protected]>
CC Paolo Abeni <[email protected]>
---
 drivers/net/ethernet/qlogic/qede/qede_main.c | 44 ++++++++++----------
 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/net/ethernet/qlogic/qede/qede_main.c +22 -22
index b5d744d2586f7..59a80f7193723 100644
@@ -107,7 +107,7 @@ static void qede_remove(struct pci_dev *pdev);
 static void qede_shutdown(struct pci_dev *pdev);
 static void qede_link_update(void *dev, struct qed_link_output *link);
 static void qede_schedule_recovery_handler(void *dev);
-static void qede_recovery_handler(struct qede_dev *edev);
+static bool qede_recovery_handler(struct qede_dev *edev);
 static void qede_schedule_hw_err_handler(void *dev,
 					 enum qed_hw_err_type err_type);
 static void qede_get_eth_tlv_data(void *edev, void *data);
@@ -1065,21 +1065,6 @@ void __qede_unlock(struct qede_dev *edev)
 	mutex_unlock(&edev->qede_lock);
 }
 
-/* This version of the lock should be used when acquiring the RTNL lock is also
- * needed in addition to the internal qede lock.
- */
-static void qede_lock(struct qede_dev *edev)
-{
-	rtnl_lock();
-	__qede_lock(edev);
-}
-
-static void qede_unlock(struct qede_dev *edev)
-{
-	__qede_unlock(edev);
-	rtnl_unlock();
-}
-
 static void qede_periodic_task(struct work_struct *work)
 {
 	struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1116,6 +1101,8 @@ static void qede_sp_task(struct work_struct *work)
 	 */
 
 	if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) {
+		bool reloaded;
+
 		cancel_delayed_work_sync(&edev->periodic_task);
 #ifdef CONFIG_QED_SRIOV
 		/* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1124,9 +1111,17 @@ static void qede_sp_task(struct work_struct *work)
 		if (pci_num_vf(edev->pdev))
 			qede_sriov_configure(edev->pdev, 0);
 #endif
-		qede_lock(edev);
-		qede_recovery_handler(edev);
-		qede_unlock(edev);
+		rtnl_lock();
+		__qede_lock(edev);
+		reloaded = qede_recovery_handler(edev);
+		__qede_unlock(edev);
+
+		/* The udp_tunnel core synchronously calls back into
+		 * qede_udp_tunnel_sync(), which takes the qede lock.
+		 */
+		if (reloaded)
+			udp_tunnel_nic_reset_ntf(edev->ndev);
+		rtnl_unlock();
 	}
 
 	__qede_lock(edev);
@@ -2667,9 +2662,13 @@ static void qede_recovery_failed(struct qede_dev *edev)
 		edev->ops->common->set_power_state(edev->cdev, PCI_D3hot);
 }
 
-static void qede_recovery_handler(struct qede_dev *edev)
+/* Returns true if an open device was successfully reloaded and its
+ * udp_tunnel ports need to be re-synced by the caller.
+ */
+static bool qede_recovery_handler(struct qede_dev *edev)
 {
 	u32 curr_state = edev->state;
+	bool reloaded = false;
 	int rc;
 
 	DP_NOTICE(edev, "Starting a recovery process\n");
@@ -2699,17 +2698,18 @@ static void qede_recovery_handler(struct qede_dev *edev)
 			goto err;
 
 		qede_config_rx_mode(edev->ndev);
-		udp_tunnel_nic_reset_ntf(edev->ndev);
+		reloaded = true;
 	}
 
 	edev->state = curr_state;
 
 	DP_NOTICE(edev, "Recovery handling is done\n");
 
-	return;
+	return reloaded;
 
 err:
 	qede_recovery_failed(edev);
+	return false;
 }
 
 static void qede_atomic_hw_err_handler(struct qede_dev *edev)
Signature · 1 line
2.53.0
author maintainer
#131 lore raw

PATCH 126/337 ksmbd: return success for deferred final close

In reply to Greg Kroah-Hartman

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

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

From: Namjae Jeon <[email protected]>

[ Upstream commit c5db4de8988f1a621556ca5c4537f77b766ca07d ]

ksmbd_close_fd() marks an open file as FP_CLOSED and drops the file table reference. If another in-flight request still holds a reference, the final close is deferred until that request drops its reference.

The function currently returns -EINVAL in that deferred-final-close case because fp is cleared when the reference count does not reach zero. That turns a valid close into STATUS_FILE_CLOSED.

smb2.compound_find.compound_find_close sends QUERY_DIRECTORY and then closes the same directory handle before receiving the find response. The query holds a reference while it builds the response, so close must mark the handle closed and return success even though final teardown is delayed. Track whether the handle was successfully transitioned to FP_CLOSED and return success when only the final close is deferred.

Stable-dep-of: e7188199eff4 ("ksmbd: fix use-after-free in __close_file_table_ids()")

---
 fs/smb/server/vfs_cache.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
fs/smb/server/vfs_cache.c +3 -1
index 5b6d8bb8edb27..0d3341927b483 100644
@@ -487,6 +487,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
 {
 	struct ksmbd_file	*fp;
 	struct ksmbd_file_table	*ft;
+	bool closed = false;
 
 	if (!has_file_id(id))
 		return 0;
@@ -501,6 +502,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
 			fp = NULL;
 		else {
 			fp->f_state = FP_CLOSED;
+			closed = true;
 			if (!atomic_dec_and_test(&fp->refcount))
 				fp = NULL;
 		}
@@ -508,7 +510,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
 	write_unlock(&ft->lock);
 
 	if (!fp)
-		return -EINVAL;
+		return closed ? 0 : -EINVAL;
 
 	__put_fd_final(work, fp);
 	return 0;
Signature · 1 line
2.53.0