Skip to contentSkip to conversation

6.12.109-rc1 review

PATCH In review Greg Kroah-Hartman 11 participants 429 messages Sep 4 – Sep 8 Stable branch Page 1 of 4

lore
Share & tools
lore

Greg Kroah-Hartman

author maintainer
#0 lore raw

cover 6.12.109-rc1 review

This is the start of the stable review cycle for the 6.12.109 release. There are 403 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, 06 Sep 2026 04:56:59 +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.109-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.109-rc1

Tzung-Bi Shih <[email protected]>
platform/chrome: sensorhub: Fix dropped timestamp events and log spam

Zhan Xusheng <[email protected]>
udf: Fix i_lenExtents truncation on 32-bit kernels

Thomas Gleixner <[email protected]>
timer: Keep debugobjects state consistent in migrate_timer_list()

Bradley Morgan <[email protected]>
taskstats: fix cpumask parsing cutting off the last character

Jann Horn <[email protected]>
smack: fix cred UAF in smack_file_send_sigiotask()

Bradley Morgan <[email protected]>
signal: avoid shared siginfo namespace rewrites

Helge Deller <[email protected]>
sticon/parisc: Detect default STI graphics card for console output

Myeonghun Pak <[email protected]>
tpm: tpm_i2c_nuvoton: disable IRQ on wait timeout

Zi Yan <[email protected]>
xarray: honor XA_FLAGS_ACCOUNT in xas_split_alloc()

Maoyi Xie <[email protected]>
w1: ds28e17: reject an oversize length on an I2C block read

Chengfeng Ye <[email protected]>
vsock/virtio: flush works in dependency order

Runyu Xiao <[email protected]>
wifi: mt76: mt7615: avoid waiting for mac work under the mt76 mutex

Dawei Feng <[email protected]>
wifi: rtw88: pci: fix resource leak on failed NAPI setup

Abdun Nihaal <[email protected]>
wifi: rtw88: Fix potential memory leak in rtw_txq_push_skb()

Abdun Nihaal <[email protected]>
wifi: rtlwifi: rtl8192du: Fix possible memory leak in rtl92du_init_sw_vars()

Runyu Xiao <[email protected]>
wifi: rtlwifi: rtl8192du: check QoS TID before indexing tids

Stanislaw Gruszka <[email protected]>
wifi: rtl818x: initialize eeprom_93cx6 struct to zero

Fabio Estevam <[email protected]>
wifi: mwifiex: Detach sync cmd buffer on interrupted wait

Eric Biggers <[email protected]>
crypto: sun8i-ss - Remove crypto_rng interface

Eric Biggers <[email protected]>
crypto: sun8i-ce - Remove crypto_rng interface

Fan Wu <[email protected]>
wifi: rtl8xxxu: fix use-after-free from rx_urb_wq on stop

Abdun Nihaal <[email protected]>
wifi: brcmfmac: Fix memory leak in brcmf_sdio_read_control()

Adrian Hunter <[email protected]>
i3c: master: Fix potential UAF in i3c_device_uevent()

Maoyi Xie <[email protected]>
i3c: master: svc: bound IBI payload to the requested max_payload_len

Adrian Hunter <[email protected]>
i3c: master: Fix info leak and UAF in device unregister path

Haotian Zhang <[email protected]>
dm-switch: use WRITE_ONCE() in switch_region_table_write()

Mikulas Patocka <[email protected]>
dm-stats: fix a crash if allocation of per-cpu data fails

Nathan Chancellor <[email protected]>
arch_numa: avoid false positive fortify warning in setup_node_to_cpumask_map()

Naman Jain <[email protected]>
PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip

Sean Christopherson <[email protected]>
KVM: selftests: Remove duplicate LAUNCH_UPDATE_VMSA call in SEV-ES migrate test

Miguel Ojeda <[email protected]>

    rust: rust_is_available: warn for `bindgen` < 0.72.1 && libclang >= 22

Ashish Kalra <[email protected]>
x86/sev: Fix broken SNP support with KVM module built-in

Gao Shiyuan <[email protected]>
iommu/amd: remove return value of amd_iommu_detect

Vincent Donnefort <[email protected]>
ring-buffer: Fix subbuf resize race with ring buffer readers

Takashi Iwai <[email protected]>
ALSA: virmidi: Check card index validity at probe

Takashi Iwai <[email protected]>
ALSA: serial-u16550: Check card index validity at probe

Takashi Iwai <[email protected]>
ALSA: portman2x4: Check card index validity at probe

Runyu Xiao <[email protected]>
ALSA: pcxhr: initialize mutexes before requesting threaded IRQ

Takashi Iwai <[email protected]>
ALSA: mts64: Check card index validity at probe

Takashi Iwai <[email protected]>
ALSA: mpu401: Check card index validity at probe

Baul Lee <[email protected]>
ALSA: bcd2000: clear the URB pointers on disconnect

Takashi Iwai <[email protected]>
ALSA: aloop: Check card index validity at probe

Baul Lee <[email protected]>
ALSA: 6fire: bound the MIDI event length from the device

Abdun Nihaal <[email protected]>
mfd: sm501: Fix potential memory leaks during remove

Zhiling Zou <[email protected]>
seg6: reset IP6CB after IPv6 decapsulation

Norbert Szetei <[email protected]>
net: skbuff: don't touch shared zerocopy state in skb_tx_error()

Breno Leitao <[email protected]>
net: fix spurious TX timeout after dev_activate()

Zhiling Zou <[email protected]>
net: cap advertised IP tunnel headroom

Bryam Vargas <[email protected]>
net/smc: unregister the connection before draining the rx tasklet

Hidayath Khan <[email protected]>
net/smc: fix use-after-free in smc_rx_pipe_buf_release()

Hidayath Khan <[email protected]>
net/smc: fix socket refcount leak in smc_switch_conns()

Bryam Vargas <[email protected]>
net/smc: do not dereference an unset send buffer on the SMC-D teardown path

Koichiro Den <[email protected]>
net: ntb_netdev: Count packets dropped on RX refill failure

Koichiro Den <[email protected]>
net: ntb_netdev: Avoid double-accounting netif_rx() drops

Koichiro Den <[email protected]>
NTB: ntb_transport: Reject oversized TX buffers

Koichiro Den <[email protected]>
NTB: ntb_transport: Fail TX enqueue when the QP link is down

Koichiro Den <[email protected]>
NTB: ntb_transport: Recycle TX entries before client callbacks

Fan Ye <[email protected]>
net: thunderbolt: Mark the connection down when bringing it up fails

Fan Ye <[email protected]>
net: thunderbolt: Release the Rx HopID that was handed out on mismatch

Xuanqiang Luo <[email protected]>
net: ravb: serialize PTP clock teardown

Xuanqiang Luo <[email protected]>
net: ravb: avoid dereferencing an invalid PTP clock

Ruoyu Wang <[email protected]>
net: openvswitch: fix nf_connlabels leak in ovs_ct_init

Ilya Maximets <[email protected]>
net: openvswitch: fix flow mask use-after-free on flow deletion

Zihan Xi <[email protected]>
net: l2tp: do not propagate multicast notification errors

Jorijn van der Graaf <[email protected]>
net: ipa: fix stalled modem TX queue after runtime resume

Ahmad Fatoum <[email protected]>
net: dsa: realtek: use gpiod_set_value_cansleep for reset GPIO

Asim Viladi Oglu Manizada <[email protected]>
net: tun: bound receive headroom

Fabio Porcedda <[email protected]>
net: usb: qmi_wwan: add Telit Cinterion FE990D50 composition

Aleksandr Khromov <[email protected]>
slip: fix use-after-free in sl_sync()

Weiming Shi <[email protected]>
xdp: fix zero-copy frame layout

Alexandra Winter <[email protected]>
net/iucv: filter frames in afiucv_hs_rcv() by ingress device

Seiji Nishikawa <[email protected]>
ipmi: si: Fix NULL pointer dereference after failed registration

Yousef Alhouseen <[email protected]>
ipmi: ipmb: validate write message length

Kuan-Wei Chiu <[email protected]>
interconnect: Fix use after free in icc_get() and of_icc_get_by_index()

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: warn on element type mismatch instead of failing

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: pass validated element count to package parsers

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: fix ORD_LIST_ELEMENTS never being parsed

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: fix off-by-one write in hp_get_string_from_buffer()

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: fix new_password_store() overwriting current_password

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: fix heap OOB read on empty password write

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: fix heap OOB read in sk_store() and kek_store()

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: bound ordered-list parsing by the package count

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: advance elem past consumed array elements

Muhammad Bilal <[email protected]>
platform/x86: hp-bioscfg: accept reduced ACPI packages from older HP BIOS

Bryam Vargas <[email protected]>
platform/chrome: sensorhub: Bound the EC-reported sensor number

Ma Ke <[email protected]>
platform/x86: ishtp_eclite: Fix ACPI device reference leak in probe error path

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Return error during profile addition

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Validate parameter for frequency and priority

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Validate parameter for core power state

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Validate logical CPU id and clos id

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Use PP level enable mask

Srinivas Pandruvada <[email protected]>
platform/x86: ISST: Just allow 2 bits for SST feature enable

Srinivas Pandruvada <[email protected]>

    platform/x86: ISST: Add a NULL check for sst_inst[]

Fan Wu <[email protected]>
mmc: via-sdmmc: stop card-detect handling on probe failure

HyeongJun An <[email protected]>
platform/x86: ISST: Validate socket ID in clos_assoc ioctl

HyeongJun An <[email protected]>
platform/x86: ISST: Validate level in perf mask ioctls

HyeongJun An <[email protected]>
platform/x86: dell-wmi-sysman: Don't hex dump attribute security buffer

Kevin Tian <[email protected]>
iommu/vt-d: Force requesting ACS when tboot is enabled

Kevin Tian <[email protected]>
iommu/vt-d: Fix no_iommu to disable platform opt-in

Shameer Kolothum <[email protected]>
iommu/arm-smmu-v3: Manage teardown with devm

Shuai Xue <[email protected]>

    iommu/sva: Set handle->dev before the SVA handle is visible

Shuai Xue <[email protected]>
iommu/amd: Put PCI device after handling PPR faults

Krzysztof Wilczyński <[email protected]>
PCI/proc: Warn on writes to kernel-exclusive config space regions

Krzysztof Wilczyński <[email protected]>
PCI/proc: Use file_ns_capable() when checking config space read access

Krzysztof Wilczyński <[email protected]>
PCI/proc: Avoid spurious runtime PM wakeup on config space accesses

Farhan Ali <[email protected]>
PCI/MSI: Enable memory decoding before restoring MSI-X messages

Darshit Shah <[email protected]>
PCI/DPC: Allow DPC on all Downstream Ports when OS controls AER

Max Lee <[email protected]>
PCI/ASPM: Avoid L0s for Realtek RTS525A

Krzysztof Wilczyński <[email protected]>
PCI/sysfs: Avoid spurious runtime PM wakeup on config space accesses

Krzysztof Wilczyński <[email protected]>
PCI/sysfs: Fix read byte order in pci_read_legacy_io()

Tim Harvey <[email protected]>

    PCI: Add ACS quirk for Pericom PI7C9X2G608 switches [12d8:2608]

Ali Tariq <[email protected]>
PCI: plda: Fix IRQ domain leaks in the error paths of plda_init_interrupts()

Ali Tariq <[email protected]>
PCI: plda: Fix use-after-free of event IRQs during teardown

Ronald Claveau <[email protected]>
PCI: meson: Fix GPIO state while requesting PERST#

Mohamad Raizudeen <[email protected]>
PCI: Fix 32-bit config write in Intel PCH Root Port MPC ACS quirk

Stefan Haberland <[email protected]>
s390/dasd: Propagate partial completion length across ERP recovery

Stefan Haberland <[email protected]>
s390/dasd: Guard sysfs discipline callbacks against unallocated private data

Stefan Haberland <[email protected]>
s390/dasd: Do not complete a failed ESE read as successful

Thomas Richter <[email protected]>
s390/cpum_cf: Handle CPU hotplug via prepare/dead callbacks

Jianing Li <[email protected]>
power: supply: max17040: synchronize work cancellation on suspend

Jianing Li <[email protected]>
power: supply: max17040: drop incorrect I2C functionality check

Jianing Li <[email protected]>
power: supply: max17040: propagate register read errors

Fan Wu <[email protected]>
power: supply: ucs1002: fix use-after-free on remove

Maoyi Xie <[email protected]>
power: supply: twl4030_charger: cancel workers via devm

Fan Wu <[email protected]>
power: supply: rt9455: quiesce delayed work before teardown

HyeongJun An <[email protected]>
power: supply: qcom_battmgr: terminate the strings from firmware

Fan Wu <[email protected]>
power: supply: lp8788-charger: fix use-after-free on remove

Fan Wu <[email protected]>

    power: supply: lp8727: fix use-after-free in lp8727_release_irq()

Jameson Thies <[email protected]>
power: supply: cros_usbpd: Limit port counts to EC_USB_PD_MAX_PORTS

Bryam Vargas <[email protected]>
power: supply: cros_usbpd-charger: bound the EC-reported port count

Fan Wu <[email protected]>
power: supply: charger-manager: register regulators before exposing sysfs

Ma Ke <[email protected]>
power: supply: bq25890: Fix power_supply reference leak

Fan Wu <[email protected]>
power: supply: bq256xx: drain usb_work before freeing the charger

Fan Wu <[email protected]>
power: supply: bq24257: fix use-after-free on remove

Jun Yang <[email protected]>

    sctp: fix stream->outcnt underflow on duplicate RECONF responses

Jun Yang <[email protected]>
sctp: distinguish sequence zero from wildcard in reconf lookup

Weiming Shi <[email protected]>
sctp: fix NULL deref on untransmitted RECONF completion

Hyunwoo Kim <[email protected]>
sctp: drop a chunk if its transport was removed

Hyunwoo Kim <[email protected]>
sctp: stop processing a packet once its association is deleted

Yehyeong Lee <[email protected]>
nvme-tcp: reject a read that transferred too few bytes

Yehyeong Lee <[email protected]>
nvme-tcp: fix host memory disclosure on R2T for a read command

Yehyeong Lee <[email protected]>
nvme-tcp: do not accept C2HData based on blk_rq_payload_bytes() alone

Myeonghun Pak <[email protected]>
nvme-pci: disable controller on admin queue IRQ setup failure

Yehyeong Lee <[email protected]>
nvme: zero the discard fallback page

Ewan D. Milne <[email protected]>
nvme: nvme-fc: Fix nvme_fc_create_hw_io_queues() queue deletion in error path

Shuangpeng Bai <[email protected]>
lockd: fix NULL dereference on lockowner allocation failure

Michael Bommarito <[email protected]>
lockd: pin next file across nlm_inspect_file lock-drop

Cong Nguyen <[email protected]>
hwmon: (max6621) fix temperature clamp range

Cong Nguyen <[email protected]>
hwmon: (max6621) fix negative temperature offset and crit readings

Christopher Tolang <[email protected]>
ASoC: amd: yc: Add DMI entry for MSI Thin A15 B7UC

Karl Mehltretter <[email protected]>
arm64: compat: Fix decrementing LDM/STM alignment emulation

HyeongJun An <[email protected]>
ALSA: ump: Fix corrupted data bytes at MIDI 1.0 SysEx to UMP conversion

Norbert Szetei <[email protected]>
openvswitch: only skb_tx_error() a packet we are about to drop

Ali Ahmet Memis <[email protected]>
openrisc: fix arbitrary kernel memory access via or1k_atomic syscall

Zhan Xusheng <[email protected]>
ocfs2: fix readdir position truncation on 32-bit kernels

Joseph Qi <[email protected]>
ocfs2: cluster: fix o2hb_dependent_users leak on pin failure

Joseph Qi <[email protected]>
ocfs2: cluster: avoid lock order inversion in o2hb_region_pin() from drop_item

Joseph Qi <[email protected]>
ocfs2: cluster: don't sleep while holding o2hb_live_lock in o2hb_region_pin()

Ibrahim Hashimov <[email protected]>
ocfs2: validate rl_used against rl_count in refcount block validator

Bryam Vargas <[email protected]>
ocfs2: validate lengths in dlm_mig_lockres_handler

Bryam Vargas <[email protected]>
ocfs2: bound namelen in dlm_migrate_request_handler

Dmitry Antipov <[email protected]>
ocfs2: always run deallocs on copy-on-write completion

Zhiling Zou <[email protected]>
orangefs: skip leading spaces before parsing client debug masks

Yifei Gao <[email protected]>
orangefs: fix double-free of trailer_buf on readdir copy failure

Vincent Donnefort <[email protected]>
ring-buffer: Hold cpu_buffer::lock when resizing a subbuf

Vincent Donnefort <[email protected]>
ring-buffer: Free cpu_buffer::free_page with subbuf_order

Kathiravan Thirumoorthy <[email protected]>
regulator: qcom-refgen: correct the regulator type to CURRENT

WenTao Liang <[email protected]>
regulator: max8998_pmic_dt_parse_pdata: of_node_put on reg_np after ownership transferred to rdata

WenTao Liang <[email protected]>
regulator: as3722_get_regulator_dt_data: fix premature of_node_put leaving dangling of_node pointer

Norbert Szetei <[email protected]>
RDMA/ucma: Lock the handler in ucma_set_ib_path()

Fan Wu <[email protected]>
RDMA/cxgb4: Cancel reg_work before freeing device on remove

Vaibhav Nagare <[email protected]>
qede: Fix NULL pointer dereference in TPA fragment processing

Johan Hovold <[email protected]>
remoteproc: scp: Fix device reference leak on failed lookup

Peixin Xie <[email protected]>
riscv: acpi: Handle LPI architectural context loss flags

Fabio Estevam <[email protected]>
arm64: dts: rockchip: Fix rk3399-roc-pc-plus analog audio

Quentin Schulz <[email protected]>
arm64: dts: rockchip: fix eMMC reset polarity on PX30 Ringneck

Krzysztof Kozlowski <[email protected]>
arm64: dts: qcom: sm6115-pro1x: Correct touchscreen GPIO flags

Chunkai Deng <[email protected]>
rpmsg: glink: smem: order FIFO read after availability check

Petr Vaganov <[email protected]>
scsi: core: Fill in DMA padding bytes in scsi_alloc_sgtables()

Hao-Qun Huang <[email protected]>
staging: media: tegra-video: vi: fix probe failure on skipped last port

Hao-Qun Huang <[email protected]>
staging: media: tegra-video: fix of_node_put() on VIP parse errors

Doruk Tan Ozturk <[email protected]>
wifi: ath6kl: clamp assoc request/response lengths before subtracting IE offsets

David Lee <[email protected]>
udf: reject VAT indexes equal to the entry count

Chuck Lever <[email protected]>
svcrdma: Validate Read chunk positions before reconstruction

Chuck Lever <[email protected]>
svcrdma: Use svc_xprt_put to free listener on create failure

Chuck Lever <[email protected]>
svcrdma: Reject inline replies that overflow the pull-up buffer

Chuck Lever <[email protected]>
svcrdma: Reject connection when transport allocation fails

Chris Mason <[email protected]>
svcrdma: Fix unmatched rn_unregister on failed accept

Chris Mason <[email protected]>
svcrdma: Fix pcl_for_each_segment for empty chunks

Chris Mason <[email protected]>
svcrdma: Fix offset arithmetic in read_chunk_range

Jérémy Jean <[email protected]>
SUNRPC: wait for in-flight client TLS handshake callback

Chuck Lever <[email protected]>
SUNRPC: Reject krb5 v2 wrap tokens with oversized ec field

Chris Mason <[email protected]>
SUNRPC: reject duplicate CREDS_VALUE options

Chris Mason <[email protected]>
sunrpc: init gssp_lock before publishing proc entry

Chris Mason <[email protected]>
SUNRPC: harden gss_unwrap_resp_priv length checks

Chris Mason <[email protected]>
SUNRPC: harden gss_krb5_unwrap_v2 against short tokens

Chris Mason <[email protected]>
SUNRPC: Guard svcauth_gss_release() dispatch on rq_auth_stat

Chuck Lever <[email protected]>
SUNRPC: Check svc pool percpu counter allocation

Jeff Layton <[email protected]>
SUNRPC: always drain cache_cleaner before destroying a cache_detail

Jeff Layton <[email protected]>
sunrpc: route to a populated pool in svc_pool_for_cpu()

Chris Mason <[email protected]>
SUNRPC: svcauth_gss: enforce krb5 token minimum length

Chris Mason <[email protected]>
SUNRPC: Zero rpc_gss_wire_cred at svcauth_gss_decode_credbody() entry

Chris Mason <[email protected]>

    SUNRPC: xdr_buf_trim: clamp buf->len to avoid underflow

Jiacheng Yu <[email protected]>
params: fix charp corruption on allocation failure

Dave Airlie <[email protected]>
nouveau/gem: reserve the bo in the info ioctl around the vma lookup

Harshit Varu <[email protected]>
mptcp: fix uninitialized local_id in syncookie MP_JOIN reconstruction

Qing Ming <[email protected]>
mpls: reload header after pskb_may_pull()

Coly Li <[email protected]>

    md: do overflow check for sb->bblog_shift in super_1_load()

Yunye Zhao <[email protected]>
md/raid10: fix still_degraded being inverted in raid10_sync_request()

Anup Vishwakarma <[email protected]>
mailbox: qcom-ipcc: fix duplicate channel allocation across holes

Bryam Vargas <[email protected]>
libnvdimm/labels: Prevent integer overflow in __nd_label_validate()

Yuyang Huang <[email protected]>
ipv6: use RCU iterator to dump route exceptions

Zhiling Zou <[email protected]>
ip6_gre: fix hardware header length for NBMA tunnels

Zhiling Zou <[email protected]>
ip6_tunnel: use skb_cow_head() in ip6_tnl_xmit()

Anton Danilov <[email protected]>
ipip: fix skb leak in collect_md mode when metadata_dst allocation fails

Max Kellermann <[email protected]>
jbd2: check need_resched() when skipping busy checkpoint buffers

Max Kellermann <[email protected]>
jbd2: bound shrinker scans by examined checkpoint buffers

Hui Su <[email protected]>
kasan: fix cache shrink race with CPU hotplug

Ibrahim Abdelkader <[email protected]>
Bluetooth: hci_sync: Clear HCI_CMD_PENDING when dropping the last request

Guangshuo Li <[email protected]>
Bluetooth: hci_intel: fix usage_count leak when autosuspend_delay is negative

Guangshuo Li <[email protected]>
Bluetooth: hci_h5: fix usage_count leak when autosuspend_delay is negative

Valentin Kindschi <[email protected]>
Bluetooth: hci_event: clear HCI_LE_ADV only on a created connection

Xin Chen <[email protected]>
Bluetooth: hci_core: use skb_get() instead of skb_clone() for req_skb

Valentin Kindschi <[email protected]>
Bluetooth: hci_conn: re-enable advertising only for peripheral role

Chengfeng Ye <[email protected]>
Bluetooth: RFCOMM: serialize security confirmation handling

Hang Nan <[email protected]>
Bluetooth: ISO: fix use-after-free of listener socket in iso_conn_ready

Gongwei Li <[email protected]>
Bluetooth: hci_uart: Fix false success return in hci_uart_setup()

Guangshuo Li <[email protected]>
Bluetooth: hci_bcm: fix usage_count leak when autosuspend_delay is negative

Lorenzo Stoakes (ARM) <[email protected]>
Bluetooth: hci_bcm4377: Ignore reserved PHY in ext adv reports on BCM4378

Alison Schofield <[email protected]>
cxl/pmem: Format the nvdimm serial number as unsigned decimal

Hui Su <[email protected]>
cpufreq: schedutil: Fix rate limit overflow

Kuan-Wei Chiu <[email protected]>
coresight: etm3x: Fix cntr_val_show() to match cntr_val_store() behavior

Bryam Vargas <[email protected]>
dm array: reject an array block whose value size is not the caller's

Bryam Vargas <[email protected]>
dm array: validate array block headers on read

Ilya Krutskih <[email protected]>
dm raid1: reserve space for NUL-terminator in build_constructor_string()

liyouhong <[email protected]>
dm-era: fix shadowed superblock leak on take-snap failure

Jérémy Jean <[email protected]>
bpf: Harden bloom filter sizing and indexing on 32-bit kernels

Daniel Borkmann <[email protected]>
bpf: Disable preemption in __bpf_get_stack

Vineet Gupta <[email protected]>
bpf, x86: Fix per-CPU address resolution into an extended register

Jiangshan Yi <[email protected]>
bnx2x: fix double free in bnx2x_init_firmware() error path

HyeongJun An <[email protected]>
Bluetooth: eir: Fix OOB read in eir_get_service_data()

Christoph Zwerschke <[email protected]>
Bluetooth: btusb: Add ASUS USB-BT600 for Realtek 8761CU

Christoph Zwerschke <[email protected]>
Bluetooth: btusb: Add ASUS USB-BT540 for Realtek 8761CU

胡连勤 <[email protected]>
block: set QUEUE_FLAG_DYING unconditionally in blk_mark_disk_dead()

Hongyan Xu <[email protected]>
auxdisplay: charlcd: cancel backlight work on registration failure

Niklas Cassel <[email protected]>
ata: libata-scsi: fix DSM TRIM for sector sizes larger than 2048 bytes

Ethan Nelson-Moore <[email protected]>
ARM: 9477/1: Disable broken eBPF JIT on the Risc PC

Matt Turner <[email protected]>
alpha: marvel: Fix lock ordering in init_io7_irqs()

Matt Turner <[email protected]>
alpha: marvel: Fix irq_set_status_flags to use correct IRQ number

Krzysztof Wilczyński <[email protected]>
alpha/PCI: Fix I/O port accessor argument order in pci_legacy_write()

Anirudh Prasad <[email protected]>
ACPI: pfr_update: fix stack buffer overflow in query_capability()

TanZheng <[email protected]>
ACPI: APEI: GHES: fix ARM section length accounting after header

Nirmoy Das <[email protected]>
ACPI: APEI: Fix ERST timeout unit conversion

Ivaylo Dimitrov <[email protected]>
hsi: omap_ssi_core: fix missing DMA mask setup for SSI controller device

Tien Sung Ang <[email protected]>
fpga: stratix10-soc: Fix SVC mailbox handling during reconfiguration

Marek Czernohous <[email protected]>
forcedeth: fix off-by-one when saving/restoring non-PCI config space

Myeonghun Pak <[email protected]>
fbdev: uvesafb: unregister connector callback on init failure

Hui Su <[email protected]>
fbdev: ssd1307fb: defer I2C transfers from damage callbacks

Florian Fuchs <[email protected]>
fbdev: pvr2fb: correct user pointer annotation and sentinel initializer

Runyu Xiao <[email protected]>
fbdev: omapfb: panel-dsi-cm: initialize lock before registering display

Yemu Lu <[email protected]>
fat: restore original value when fat_ent_write failed

Ard Biesheuvel <[email protected]>
efivarfs: Rate limit statfs() handler

Yichong Chen <[email protected]>
ecryptfs: show filename encryption options

Yichong Chen <[email protected]>
ecryptfs: release message context on send failure

Yichong Chen <[email protected]>
ecryptfs: reject too-small tag 70 packets

HanQuan <[email protected]>
ecryptfs: reject oversized encrypted_key_size in parse_tag_3_packet

Yichong Chen <[email protected]>
ecryptfs: pass packet set buffer size to parser

Yichong Chen <[email protected]>
ecryptfs: hold msg ctx list lock when cleaning daemon queue

Yichong Chen <[email protected]>
ecryptfs: fix tag 11 packet exact-fit size check

Pengpeng Hou <[email protected]>
eCryptfs: bound the packet-length peek to the user buffer

Konstantin Komarov <[email protected]>

    fs/ntfs3: bound page_lcns[] index by the log record

Samuel Page <[email protected]>
fs/ntfs3: fix info-leak on partial LZNT decompress in ni_read_frame()

Xiang Mei <[email protected]>
fs/ntfs3: validate dirty page table on log replay

Deepanshu Kartikey <[email protected]>

    eventfs: Initialize ei->children and ei->list in init_ei()

Jiangshan Yi <[email protected]>
HID: mcp2221: validate report size in mcp2221_raw_event()

Jiangshan Yi <[email protected]>
HID: mcp2221: stop device IO before hid_hw_stop

Haoxiang Li <[email protected]>
HID: sensor: custom: Fix field sysfs group cleanup on failure

Xu Rao <[email protected]>
HID: roccat: free buffered reports when destroying device

Ibrahim Hashimov <[email protected]>
HID: picolcd: clamp eeprom debugfs read to bytes actually received

Fredric Cover <[email protected]>
smb: client: harden DFS cache against invalid target hints

Frank Sorenson <[email protected]>
smb: client: fix copy-paste error in WSL EA length accounting for $LXDEV

Frank Sorenson <[email protected]>
smb: client: fix ALIGN() overflow in symlink_data() error context loop

Fredric Cover <[email protected]>

    smb: client: clear ce->tgthint in free_tgts()

Frank Sorenson <[email protected]>

    cifs: fix loff_t underflow in cifs_remap_file_range() when len == 0

Jérémy Jean <[email protected]>
audit: avoid dropping live tree ref on fsnotify rule autoremove

Guanghui Yang <[email protected]>
btrfs: drop recovered reloc root refs on recovery failure

Max Kellermann <[email protected]>
ceph: do not repeat ceph_trim_dentries() if no progress possible

Michael Bommarito <[email protected]>
ceph: bound xattr value length in __build_xattrs()

Michael Bommarito <[email protected]>
ceph: bound num_export_targets array for mds info v2/v3

Michael Bommarito <[email protected]>
ceph: bound MDSCapAuth path and fs_name decode in handle_session()

Michael Bommarito <[email protected]>
ceph: bound copied dentry name length in NFS export get_name

Jérémy Jean <[email protected]>
ceph: reject export_targets ranks >= CEPH_MAX_MDS in mdsmap decode

Xiubo Li <[email protected]>
ceph: fix UAF in __kick_flushing_caps() on cf entry freed during unlock

Jérémy Jean <[email protected]>
libceph: reject buckets with mismatched CRUSH ids

Michael Bommarito <[email protected]>
libceph: validate OSD extent maps before cursor advance

Chuck Lever <[email protected]>
NFSD: Prevent client use-after-free during NFSv4.0 revoked-state cleanup

Chuck Lever <[email protected]>
NFSD: Prevent lock owner use-after-free during client teardown

Jeff Layton <[email protected]>
nfsd: revoke copy-notify stateids before dropping their reference

Jeff Layton <[email protected]>
nfsd: reject reclaim LOCK after RECLAIM_COMPLETE

Robbie Ko <[email protected]>
nfsd: reject out-of-range useconds in NFSv2 SETATTR/CREATE

Robbie Ko <[email protected]>
nfsd: reject out-of-range nseconds in NFSv3 SETATTR and create ops

Jeff Layton <[email protected]>
nfsd: initialize DRC hash table before registering shrinker

Jeff Layton <[email protected]>
nfsd: initialize copy-notify stateid before publishing it

Chris Mason <[email protected]>

    nfsd: gate nfs3 setacl by argp->mask

Chuck Lever <[email protected]>

    nfsd: gate nfs2 setacl by argp->mask

Jeff Layton <[email protected]>
nfsd: fix XDR padding calculation in ff_encode_getdeviceinfo

Jeff Layton <[email protected]>
nfsd: fix XDR length calculation in nfsd4_ff_encode_layoutget

Jeff Layton <[email protected]>
nfsd: fix version mismatch loops in nfsd_acl_init_request()

Jeff Layton <[email protected]>
nfsd: fix reply size estimate for GET_DIR_DELEGATION

Jeff Layton <[email protected]>
nfsd: fix nfsd_file leak on inter-server COPY setup failure

Jeff Layton <[email protected]>
nfsd: fix dentry ref leak on V4ROOT export filehandle lookup

Chris Mason <[email protected]>
nfsd: fix cpntf publish race in nfs4_init_cp_state

Jeff Layton <[email protected]>
nfsd: fix BUG_ON in nfsd4_alloc_layout_stateid on racing delegation revoke

Jeff Layton <[email protected]>
nfsd: drop the stateid, not the stateowner, on seqid_op replay retry

Jeff Layton <[email protected]>
nfsd: defer vfree of compound ops to fix rpc_status UAF

Jeff Layton <[email protected]>
nfsd: clear opcnt on compound arg release to prevent OOB read

Jeff Layton <[email protected]>
nfsd: check client ownership when cancelling a copy-notify stateid

Jeff Layton <[email protected]>
nfsd: block non-SAVEFH ops after FOREIGN PUTFH to prevent NULL deref

Jeff Layton <[email protected]>
nfsd: add missing read barrier to rpc_status_get dumpit seqcount retry

Jeff Layton <[email protected]>
nfsd: add filehandle match check to nfsd4_delegreturn()

Jeff Layton <[email protected]>
nfsd: add fh_want_write() for early-verified SETATTR in nfsd_proc_setattr()

Jeff Layton <[email protected]>
nfsd: validate symlink target length in NFSv4 CREATE

Chris Mason <[email protected]>
nfsd: size fh_verify server sockaddr slot by xpt_locallen

Zhenghang Xiao <[email protected]>
nfsd: set SC_STATUS_FREED in nfsd4_drop_revoked_stid for delegations

Chuck Lever <[email protected]>
nfsd: sample writeback error cursor before async COPY loop

Jeff Layton <[email protected]>
nfsd: return NFS4ERR_NOTSUPP for unsupported netloc4 types

Chuck Lever <[email protected]>
nfsd: Reset write verifier when async COPY writeback fails

Chris Mason <[email protected]>
nfsd: release path refs on follow_down() error

Tim Menninger <[email protected]>
pNFS: Fix EBUSY check in pnfs_layout_need_return

Junrui Luo <[email protected]>
NFSv4.1: fix layout segment leak on the pnfs_layout_process() forget path

Chris Mason <[email protected]>
nfsd: guard nfsd_serv deref in nfsd_file_net_dispose

Mike Snitzer <[email protected]>
NFSD: remove flawed WARN_ON_ONCE from nfsd_mode_check

Michael Bommarito <[email protected]>
NFSD: restart ssc_expire_umount walk after dropping nfsd_ssc_lock

Chuck Lever <[email protected]>
NFSD: Fix off-by-one in DRC bucket pruning limit

Chuck Lever <[email protected]>
NFSD: Encode only the status in NFS-ACL v2 GETACL error replies

Chuck Lever <[email protected]>
NFSD: check truncate permission under inode lock

Longlong Xia <[email protected]>
zsmalloc: account for handle size in class lookup

Ibrahim Hashimov <[email protected]>
ubifs: fix out-of-bounds read in signature length check

Krzysztof Wilczyński <[email protected]>
PCI/sysfs: Fix out-of-bounds read in pci_write_legacy_io()

Abdurrahman Hussain <[email protected]>
of: fix out-of-bounds read in of_alias_scan() stem parser

Ryusuke Konishi <[email protected]>
nilfs2: fix slab-out-of-bounds in nilfs_direct_propagate after truncation

Junrui Luo <[email protected]>
media: vicodec: fix out-of-bounds write in FWHT encoder

Weigang He <[email protected]>
media: cec: stm32: prevent out-of-bounds write on RX overflow

Vincent Mailhol <[email protected]>
lib/ucs2_string.c: fix out-of-bounds read in ucs2_strnlen()

Xingrui Li <[email protected]>
HID: sensor-hub: Fix out-of-bounds write in sensor_hub_get_feature

Daisuke Matsuda <[email protected]>
fpga: altera-cvp: Avoid out-of-bounds read in trailing byte write

Neill Kapron <[email protected]>
usb: gadget: f_fs: Prevent deadlock during ep0 read loop

Jeffin Philip <[email protected]>
usb: gadget: uvc: fix dangling pointers in uvc_function_bind() and uvc_function_unbind()

Yun Zhou <[email protected]>
usb: gadget: f_tcm: fix deadlock in usbg_make_tpg()

Joshua Crofts <[email protected]>
usb: gadget: midi2: remove default configfs groups on teardown

Myeonghun Pak <[email protected]>
usb: gadget: snps_udc_plat: clean up PHY on probe deferral

Sonali Pradhan <[email protected]>
usb: gadget: u_audio: Fix use-after-free on sound card disconnect

Huang Wei <[email protected]>
usb: typec: ucsi: use UCSI_TIMEOUT_MS for sync command completion

Xu Yang <[email protected]>
usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive()

Johan Hovold <[email protected]>
USB: phy: fsl-usb: fix missing static keywords

Fan Wu <[email protected]>
usb: gadget: at91_udc: drain polled-VBUS timer/work before udc is freed

Francesco Lavra <[email protected]>
usb: dwc2: gadget: Exit partial power down state when changing USB pull-up

Hao-Qun Huang <[email protected]>
staging: greybus: hid: fix SET_REPORT return value

Karl Mehltretter <[email protected]>

    serial: imx: serialize imx_uart_ports[] lifetime

Hans Verkuil <[email protected]>
Revert "media: v4l2-dev: fix error handling in __video_register_device()"

James Kim <[email protected]>
rapidio: mport_cdev: fix use-after-free in dma_req_free()

Bartosz Golaszewski <[email protected]>
powerpc/powermac: fix OF node refcount

Bryam Vargas <[email protected]>
misc: nsm: bound the device-reported response length

Xu Yang <[email protected]>
device property: fix infinite loop in fwnode_for_each_child_node()

Prasanna Kumar T S M <[email protected]>
cdx: Fix double free when sysfs file creation fails

Hui Su <[email protected]>
tracing: Fix use-after-free with same-name named triggers

Deepanshu Kartikey <[email protected]>
tracing: Fix use-after-free in trace_pipe read on sub-buffer order change

Vincent Donnefort <[email protected]>
tracing: Fix logged instance name on creation failure

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

Jérémy Jean <[email protected]>
tracing/user_events: Clear copied tracing state before fork duplication

Sanman Pradhan <[email protected]>
hwtracing: hisi_ptt: Propagate DMA reset timeout in trace_start()

Kiryl Shutsemau (Meta) <[email protected]>
x86/tdx: Fix zero-extension for 32-bit port I/O

Kiryl Shutsemau (Meta) <[email protected]>
x86/insn-eval: Move assign_register() out of KVM as insn_assign_reg()

Kiryl Shutsemau (Meta) <[email protected]>
x86/tdx: Fix off-by-one in port I/O handling

Joy H.J. Lee <[email protected]>
tools/compiler: match glibc 2.42 definition of __attribute_const__

Johannes Weiner <[email protected]>
mm: mempolicy: fix automatic numa balancing for shmem

Guopeng Zhang <[email protected]>
mm: memcg: stop reclaim when a limit update is superseded

Hao Jia <[email protected]>
mm/zswap: fix global shrinker when memory cgroup is disabled

Breno Leitao <[email protected]>
mm/vmscan: report RCU-tasks quiescent states in shrink_lruvec()

Dev Jain <[email protected]>
mm/page_vma_mapped: use huge_ptep_get() for hugetlb

Ye Liu <[email protected]>
mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()

Dev Jain <[email protected]>
mm/migrate: use huge_ptep_get() in remove_migration_pte()

Breno Leitao <[email protected]>
mm/migrate: report RCU-tasks quiescent states in migrate_pages_batch()

Breno Leitao <[email protected]>
mm/kmemleak: avoid soft lockup when scanning task stacks

Jordan R Abrahams-Whitehead <[email protected]>
include/linux/list.h: mark list_add and __list_add as __always_inline

Hyunwoo Kim <[email protected]>
apparmor: fix out-of-bounds write when null terminating a label vec

Jann Horn <[email protected]>
apparmor: fix cred UAF caused by begin_current_label_crit_section()

Gary Guo <[email protected]>
rust: cfi: disable function merging if CFI is enabled

Jérémy Jean <[email protected]>
timers/itimer: Zero-init old itimerval before copy to userspace

Gaurav Batra <[email protected]>
powerpc/pseries/iommu: switch to Default DMA window during kdump

Baokun Li <[email protected]>
fs: fix user path of nested backing files

Felix Yan <[email protected]>
clocksource/drivers/timer-sun4i: Advertise a real minimum delta

Matt Turner <[email protected]>
alpha: don't leak hardware-fabricated FP exception bits to user space

Matt Turner <[email protected]>
alpha: fix ieee_swcr_to_fpcr setting FPCR_DNOD unconditionally

Srinivasan Shanmugam <[email protected]>
drm/amd/display: Avoid NULL dereference in dc_dmub_srv error paths

Zilin Guan <[email protected]>
wifi: ath11k: fix memory leaks in beacon template setup

Zilin Guan <[email protected]>
wifi: mt76: Fix memory leak after mt76_connac_mcu_alloc_sta_req()

Zide Chen <[email protected]>
perf/x86/intel/uncore: Fix die ID init and look up bugs

Mario Limonciello <[email protected]>
drm/amd/display: Avoid divide by zero by initializing dummy pitch to 1

Ming Lei <[email protected]>

    block: mark GFP_NOIO around sysfs ->store()

Chao Yu <[email protected]>
f2fs: fix potential deadloop in prepare_compress_overwrite()

Yang Erkun <[email protected]>
md: make rdev_addable usable for rcu mode

Michael Chan <[email protected]>
bnxt_en: Mask the bd_cnt field in the TX BD properly

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

Diffstat:

 Documentation/ABI/testing/sysfs-bus-nvdimm         |   3 +-
 Makefile                                           |   7 +-
 arch/alpha/include/uapi/asm/fpu.h                  |   8 +-
 arch/alpha/kernel/pci-sysfs.c                      |   6 +-
 arch/alpha/kernel/sys_marvel.c                     |  25 ++-
 arch/alpha/kernel/traps.c                          |   6 +-
 arch/alpha/math-emu/math.c                         |  88 +++++++-
 arch/arm/Kconfig                                   |   2 +-
 arch/arm64/boot/dts/qcom/sm6115-fxtec-pro1x.dts    |   2 +-
 arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi    |   2 +-
 .../arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts |  12 ++
 arch/arm64/kernel/compat_alignment.c               |   4 +-
 arch/openrisc/kernel/entry.S                       |  43 +++-
 arch/powerpc/kernel/pci-common.c                   |   9 +-
 arch/powerpc/platforms/powermac/low_i2c.c          |   2 +-
 arch/powerpc/platforms/pseries/iommu.c             |  23 ++-
 arch/riscv/include/asm/acpi.h                      |  19 ++
 arch/s390/kernel/perf_cpum_cf.c                    | 221 ++++++++++++++-------
 arch/x86/coco/tdx/tdx.c                            |  10 +-
 arch/x86/events/intel/uncore.c                     |   1 +
 arch/x86/events/intel/uncore_snbep.c               |  13 +-
 arch/x86/include/asm/insn-eval.h                   |  36 ++++
 arch/x86/include/asm/sev.h                         |   2 +
 arch/x86/kvm/emulate.c                             |  26 +--
 arch/x86/net/bpf_jit_comp.c                        |   2 +-
 arch/x86/virt/svm/sev.c                            |  21 +-
 block/blk-sysfs.c                                  |   3 +
 block/genhd.c                                      |   1 +
 drivers/acpi/apei/erst.c                           |   2 +-
 drivers/acpi/apei/ghes.c                           |   2 +-
 drivers/acpi/pfr_update.c                          |  45 +++--
 drivers/ata/libata-scsi.c                          |  28 +--
 drivers/auxdisplay/charlcd.c                       |  21 +-
 drivers/base/arch_numa.c                           |  12 ++
 drivers/base/property.c                            |  19 +-
 drivers/bluetooth/btusb.c                          |   6 +
 drivers/bluetooth/hci_bcm.c                        |   1 +
 drivers/bluetooth/hci_bcm4377.c                    |   1 +
 drivers/bluetooth/hci_h5.c                         |   4 +-
 drivers/bluetooth/hci_intel.c                      |   1 +
 drivers/bluetooth/hci_ldisc.c                      |   2 +-
 drivers/bluetooth/hci_serdev.c                     |   2 +-
 drivers/cdx/cdx.c                                  |   7 +-
 drivers/char/ipmi/ipmb_dev_int.c                   |   5 +-
 drivers/char/ipmi/ipmi_msghandler.c                |   1 +
 drivers/char/tpm/tpm_i2c_nuvoton.c                 |   6 +-
 drivers/clocksource/timer-sun4i.c                  |   2 +-
 drivers/crypto/allwinner/Kconfig                   |  16 --
 drivers/crypto/allwinner/sun8i-ce/Makefile         |   1 -
 drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c  |  57 ------
 drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c  | 159 ---------------
 drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h       |  29 ---
 drivers/crypto/allwinner/sun8i-ss/Makefile         |   1 -
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c  |  39 ----
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c  | 177 -----------------
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h       |  23 ---
 drivers/cxl/core/pmem.c                            |  10 +-
 drivers/cxl/cxl.h                                  |   3 +-
 drivers/cxl/pmem.c                                 |   2 +-
 drivers/fpga/altera-cvp.c                          |  10 +-
 drivers/fpga/stratix10-soc.c                       |  21 +-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c       |  10 +-
 .../amd/display/dc/dml2/dml2_translation_helper.c  |   2 +-
 drivers/gpu/drm/nouveau/nouveau_gem.c              |  11 +-
 drivers/hid/hid-mcp2221.c                          |   9 +
 drivers/hid/hid-picolcd_debugfs.c                  |   9 +
 drivers/hid/hid-roccat.c                           |  13 +-
 drivers/hid/hid-sensor-custom.c                    |   9 +-
 drivers/hid/hid-sensor-hub.c                       |  46 +++--
 drivers/hsi/controllers/omap_ssi_core.c            |   6 +
 drivers/hwmon/max6621.c                            |   8 +-
 .../hwtracing/coresight/coresight-etm3x-sysfs.c    |  15 +-
 drivers/hwtracing/ptt/hisi_ptt.c                   |  20 +-
 drivers/i3c/master.c                               |  12 +-
 drivers/i3c/master/svc-i3c-master.c                |  10 +-
 drivers/infiniband/core/ucma.c                     |   5 +-
 drivers/infiniband/hw/cxgb4/device.c               |   6 +
 drivers/interconnect/core.c                        |   7 +-
 drivers/iommu/amd/init.c                           |  36 +++-
 drivers/iommu/amd/ppr.c                            |   3 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c        |  56 ++++--
 drivers/iommu/intel/dmar.c                         |  15 +-
 drivers/iommu/intel/iommu.c                        |   8 +-
 drivers/iommu/intel/iommu.h                        |   2 +
 drivers/iommu/iommu-sva.c                          |   2 +-
 drivers/mailbox/qcom-ipcc.c                        |  17 +-
 drivers/md/dm-era-target.c                         |   5 +
 drivers/md/dm-log-userspace-base.c                 |   1 +
 drivers/md/dm-stats.c                              |   6 +-
 drivers/md/dm-switch.c                             |   2 +-
 drivers/md/md.c                                    |  15 +-
 drivers/md/persistent-data/dm-array.c              |  53 ++++-
 drivers/md/raid10.c                                |   2 +-
 drivers/media/cec/platform/stm32/stm32-cec.c       |   3 +-
 drivers/media/test-drivers/vicodec/vicodec-core.c  |   4 +-
 drivers/media/v4l2-core/v4l2-dev.c                 |  14 +-
 drivers/mfd/sm501.c                                |   2 +
 drivers/misc/nsm.c                                 |   2 +-
 drivers/mmc/host/via-sdmmc.c                       |   8 +-
 drivers/net/dsa/realtek/rtl83xx.c                  |   4 +-
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c   |   3 +
 drivers/net/ethernet/broadcom/bnxt/bnxt.c          |   4 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt.h          |   2 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c      |   3 +-
 drivers/net/ethernet/nvidia/forcedeth.c            |   4 +-
 drivers/net/ethernet/qlogic/qede/qede.h            |   8 +-
 drivers/net/ethernet/qlogic/qede/qede_fp.c         |   1 +
 drivers/net/ethernet/renesas/ravb.h                |   3 +
 drivers/net/ethernet/renesas/ravb_main.c           |   9 +-
 drivers/net/ethernet/renesas/ravb_ptp.c            |  44 +++-
 drivers/net/ipa/ipa_modem.c                        |  18 +-
 drivers/net/ntb_netdev.c                           |  11 +-
 drivers/net/slip/slip.c                            |  11 +-
 drivers/net/thunderbolt/main.c                     |  12 ++
 drivers/net/tun.c                                  |  21 +-
 drivers/net/usb/qmi_wwan.c                         |   1 +
 drivers/net/wireless/ath/ath11k/mac.c              |  28 ++-
 drivers/net/wireless/ath/ath6kl/cfg80211.c         |   5 +
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   3 +-
 drivers/net/wireless/marvell/mwifiex/sta_ioctl.c   |  12 ++
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |   5 +-
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.c   |  16 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c    |   4 +-
 drivers/net/wireless/mediatek/mt76/mt7925/mcu.c    |   4 +-
 drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c |   2 +-
 drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c |   2 +-
 drivers/net/wireless/realtek/rtl8xxxu/core.c       |  19 +-
 .../net/wireless/realtek/rtlwifi/rtl8192du/sw.c    |  12 +-
 .../net/wireless/realtek/rtlwifi/rtl8192du/trx.c   |   3 +-
 drivers/net/wireless/realtek/rtw88/pci.c           |   4 +-
 drivers/net/wireless/realtek/rtw88/tx.c            |   1 +
 drivers/ntb/ntb_transport.c                        |  38 ++--
 drivers/nvdimm/label.c                             |   2 +-
 drivers/nvme/host/core.c                           |   2 +-
 drivers/nvme/host/fc.c                             |   2 +-
 drivers/nvme/host/pci.c                            |   1 +
 drivers/nvme/host/tcp.c                            |  45 ++++-
 drivers/of/base.c                                  |   2 +-
 drivers/pci/controller/dwc/pci-meson.c             |   2 +-
 drivers/pci/controller/pci-hyperv.c                |   1 +
 drivers/pci/controller/plda/pcie-plda-host.c       |  52 ++++-
 drivers/pci/msi/msi.c                              |  10 +
 drivers/pci/pci-sysfs.c                            |  42 +++-
 drivers/pci/pcie/portdrv.c                         |   2 +-
 drivers/pci/proc.c                                 |  16 +-
 drivers/pci/quirks.c                               |   9 +-
 drivers/platform/chrome/cros_ec_sensorhub_ring.c   |  19 +-
 .../x86/dell/dell-wmi-sysman/biosattr-interface.c  |   1 -
 drivers/platform/x86/hp/hp-bioscfg/bioscfg.c       |  18 +-
 drivers/platform/x86/hp/hp-bioscfg/bioscfg.h       |   8 +
 .../platform/x86/hp/hp-bioscfg/enum-attributes.c   |  15 +-
 .../platform/x86/hp/hp-bioscfg/int-attributes.c    |   6 +-
 .../x86/hp/hp-bioscfg/order-list-attributes.c      |  14 +-
 .../x86/hp/hp-bioscfg/passwdobj-attributes.c       |  14 +-
 .../platform/x86/hp/hp-bioscfg/spmobj-attributes.c |   4 +-
 .../platform/x86/hp/hp-bioscfg/string-attributes.c |   6 +-
 drivers/platform/x86/intel/ishtp_eclite.c          |   5 +-
 .../x86/intel/speed_select_if/isst_tpmi_core.c     |  77 ++++++-
 drivers/power/supply/bq24257_charger.c             |  16 +-
 drivers/power/supply/bq256xx_charger.c             |  29 +--
 drivers/power/supply/bq25890_charger.c             |  12 ++
 drivers/power/supply/charger-manager.c             |  54 +++--
 drivers/power/supply/cros_usbpd-charger.c          |  17 +-
 drivers/power/supply/lp8727_charger.c              |   4 +-
 drivers/power/supply/lp8788-charger.c              |   2 +-
 drivers/power/supply/max17040_battery.c            |  32 ++-
 drivers/power/supply/qcom_battmgr.c                |   2 +-
 drivers/power/supply/rt9455_charger.c              |  21 +-
 drivers/power/supply/twl4030_charger.c             |  12 +-
 drivers/power/supply/ucs1002_power.c               |   6 +-
 drivers/rapidio/devices/rio_mport_cdev.c           |  10 +-
 drivers/regulator/as3722-regulator.c               |   1 -
 drivers/regulator/max8998.c                        |   1 -
 drivers/regulator/qcom-refgen-regulator.c          |   4 +-
 drivers/remoteproc/mtk_scp.c                       |   9 +-
 drivers/rpmsg/qcom_glink_smem.c                    |   7 +
 drivers/s390/block/dasd.c                          |   6 +-
 drivers/s390/block/dasd_eckd.c                     |  40 +++-
 drivers/s390/block/dasd_erp.c                      |   3 +
 drivers/scsi/scsi_lib.c                            |   2 +
 drivers/staging/greybus/hid.c                      |   2 +-
 drivers/staging/media/tegra-video/vi.c             |   9 +-
 drivers/staging/media/tegra-video/vip.c            |  10 +-
 drivers/tty/serial/imx.c                           |  20 +-
 drivers/usb/dwc2/gadget.c                          |  11 +-
 drivers/usb/gadget/function/f_fs.c                 |  14 +-
 drivers/usb/gadget/function/f_midi2.c              |   2 +
 drivers/usb/gadget/function/f_tcm.c                |  23 ++-
 drivers/usb/gadget/function/f_uvc.c                |   7 +-
 drivers/usb/gadget/function/u_audio.c              |  24 ++-
 drivers/usb/gadget/udc/at91_udc.c                  |  20 +-
 drivers/usb/gadget/udc/snps_udc_plat.c             |   5 +-
 drivers/usb/phy/phy-fsl-usb.c                      |  52 ++---
 drivers/usb/phy/phy-fsl-usb.h                      |   6 +-
 drivers/usb/typec/tcpm/tcpci.c                     |  12 +-
 drivers/usb/typec/ucsi/ucsi.c                      |   3 +-
 .../fbdev/omap2/omapfb/displays/panel-dsi-cm.c     |   4 +-
 drivers/video/fbdev/pvr2fb.c                       |   4 +-
 drivers/video/fbdev/ssd1307fb.c                    |  72 ++++++-
 drivers/video/fbdev/uvesafb.c                      |   2 +
 drivers/video/sticore.c                            |  22 +-
 drivers/w1/slaves/w1_ds28e17.c                     |   8 +
 fs/backing-file.c                                  |   2 +-
 fs/btrfs/relocation.c                              |  31 ++-
 fs/ceph/caps.c                                     |  11 +-
 fs/ceph/dir.c                                      |  10 +-
 fs/ceph/export.c                                   |  26 ++-
 fs/ceph/mds_client.c                               |   8 +-
 fs/ceph/mdsmap.c                                   |  11 +-
 fs/ceph/xattr.c                                    |   1 +
 fs/ecryptfs/crypto.c                               |   2 +-
 fs/ecryptfs/ecryptfs_kernel.h                      |   3 +-
 fs/ecryptfs/keystore.c                             |  45 ++++-
 fs/ecryptfs/messaging.c                            |  11 +-
 fs/ecryptfs/miscdev.c                              |   5 +-
 fs/ecryptfs/super.c                                |   7 +
 fs/efivarfs/super.c                                |  30 ++-
 fs/f2fs/compress.c                                 |   1 +
 fs/f2fs/data.c                                     |  10 +-
 fs/fat/misc.c                                      |   4 +
 fs/jbd2/checkpoint.c                               |  28 +--
 fs/lockd/clntproc.c                                |   3 +
 fs/lockd/svcsubs.c                                 |  53 ++---
 fs/nfs/pnfs.c                                      |   3 +-
 fs/nfsd/filecache.c                                |  15 +-
 fs/nfsd/flexfilelayoutxdr.c                        |  20 +-
 fs/nfsd/nfs2acl.c                                  |  52 ++---
 fs/nfsd/nfs3acl.c                                  |  17 +-
 fs/nfsd/nfs3proc.c                                 |  40 ++++
 fs/nfsd/nfs4layouts.c                              |  12 +-
 fs/nfsd/nfs4proc.c                                 |  51 +++--
 fs/nfsd/nfs4state.c                                | 215 +++++++++++++++-----
 fs/nfsd/nfs4xdr.c                                  |  22 +-
 fs/nfsd/nfscache.c                                 |   6 +-
 fs/nfsd/nfsctl.c                                   |  11 +-
 fs/nfsd/nfsfh.c                                    |  12 +-
 fs/nfsd/nfsproc.c                                  |   7 +
 fs/nfsd/nfssvc.c                                   |   4 +-
 fs/nfsd/nfsxdr.c                                   |  32 ++-
 fs/nfsd/trace.h                                    |   4 +-
 fs/nfsd/vfs.c                                      |  34 ++--
 fs/nilfs2/bmap.c                                   |   2 +-
 fs/nilfs2/bmap.h                                   |   2 +-
 fs/nilfs2/btree.c                                  |  39 +++-
 fs/nilfs2/direct.c                                 |   4 +-
 fs/ntfs3/frecord.c                                 |   9 +
 fs/ntfs3/fslog.c                                   |  34 ++++
 fs/ocfs2/cluster/heartbeat.c                       | 150 +++++++++++---
 fs/ocfs2/cluster/nodemanager.c                     |   6 +
 fs/ocfs2/cluster/nodemanager.h                     |   1 +
 fs/ocfs2/dir.c                                     |   2 +-
 fs/ocfs2/dlm/dlmmaster.c                           |   6 +
 fs/ocfs2/dlm/dlmrecovery.c                         |   9 +
 fs/ocfs2/refcounttree.c                            |  47 +++--
 fs/ocfs2/xattr.c                                   |   5 +-
 fs/orangefs/devorangefs-req.c                      |   1 +
 fs/orangefs/orangefs-debugfs.c                     |   1 +
 fs/smb/client/cifsfs.c                             |  15 +-
 fs/smb/client/dfs_cache.c                          |  33 ++-
 fs/smb/client/smb1ops.c                            |   2 +-
 fs/smb/client/smb2file.c                           |   5 +-
 fs/tracefs/event_inode.c                           |   7 +-
 fs/ubifs/auth.c                                    |   2 +-
 fs/udf/inode.c                                     |   2 +-
 fs/udf/partition.c                                 |   2 +-
 include/linux/amd-iommu.h                          |   4 +-
 include/linux/list.h                               |  15 +-
 include/linux/sunrpc/svc_rdma_pcl.h                |   2 +-
 include/linux/usb/tcpci.h                          |   1 +
 include/net/ip_tunnels.h                           |  11 +-
 include/net/sctp/structs.h                         |   2 +-
 kernel/auditfilter.c                               |   6 +-
 kernel/bpf/bloom_filter.c                          |  19 +-
 kernel/bpf/stackmap.c                              |   3 +
 kernel/params.c                                    |  14 +-
 kernel/sched/cpufreq_schedutil.c                   |  15 +-
 kernel/signal.c                                    |   4 +
 kernel/taskstats.c                                 |   3 +-
 kernel/time/itimer.c                               |   2 +-
 kernel/time/timer.c                                |   1 +
 kernel/trace/ring_buffer.c                         | 170 ++++++++++------
 kernel/trace/trace.c                               |   6 +-
 kernel/trace/trace_events.c                        |   2 +
 kernel/trace/trace_events_hist.c                   |   4 +-
 kernel/trace/trace_events_user.c                   |   3 +
 lib/ucs2_string.c                                  |   2 +-
 lib/xarray.c                                       |   3 +
 mm/kasan/quarantine.c                              |   7 +-
 mm/kmemleak.c                                      |  51 +++--
 mm/memcontrol.c                                    |   6 +
 mm/mempolicy.c                                     |  21 +-
 mm/migrate.c                                       |   8 +-
 mm/page_owner.c                                    |  10 +-
 mm/page_vma_mapped.c                               |   8 +-
 mm/vmscan.c                                        |   2 +-
 mm/zsmalloc.c                                      |  11 +-
 mm/zswap.c                                         |  13 +-
 net/bluetooth/eir.c                                |   3 +-
 net/bluetooth/hci_conn.c                           |   3 +-
 net/bluetooth/hci_core.c                           |   2 +-
 net/bluetooth/hci_event.c                          |   7 +-
 net/bluetooth/hci_sync.c                           |   2 +
 net/bluetooth/iso.c                                |   8 +
 net/bluetooth/rfcomm/core.c                        |   8 +-
 net/ceph/osd_client.c                              |  30 +++
 net/ceph/osdmap.c                                  |   2 +
 net/core/skbuff.c                                  |   5 +-
 net/core/xdp.c                                     |   4 +-
 net/ipv4/ip_tunnel.c                               |   2 +-
 net/ipv4/ipip.c                                    |   2 +-
 net/ipv6/ip6_gre.c                                 |  14 +-
 net/ipv6/ip6_tunnel.c                              |  22 +-
 net/ipv6/route.c                                   |   2 +-
 net/ipv6/seg6_local.c                              |   9 +
 net/ipv6/sit.c                                     |   2 +-
 net/iucv/af_iucv.c                                 |   2 +
 net/l2tp/l2tp_netlink.c                            |  16 +-
 net/mpls/af_mpls.c                                 |   2 +
 net/mptcp/syncookies.c                             |   1 +
 net/openvswitch/conntrack.c                        |   8 +-
 net/openvswitch/datapath.c                         |  50 ++---
 net/sched/sch_generic.c                            |   2 +-
 net/sctp/inqueue.c                                 |   7 +-
 net/sctp/sm_sideeffect.c                           |   4 +
 net/sctp/stream.c                                  |  48 +++--
 net/smc/af_smc.c                                   |   3 +-
 net/smc/smc_core.c                                 |  27 +--
 net/smc/smc_rx.c                                   |  11 +-
 net/smc/smc_tx.h                                   |   6 +-
 net/sunrpc/auth_gss/auth_gss.c                     |   6 +-
 net/sunrpc/auth_gss/gss_krb5_wrap.c                |  13 +-
 net/sunrpc/auth_gss/gss_rpc_upcall.c               |   6 -
 net/sunrpc/auth_gss/gss_rpc_upcall.h               |   1 -
 net/sunrpc/auth_gss/gss_rpc_xdr.c                  |   6 +
 net/sunrpc/auth_gss/svcauth_gss.c                  |   8 +-
 net/sunrpc/cache.c                                 |   7 +-
 net/sunrpc/sunrpc_syms.c                           |   1 +
 net/sunrpc/svc.c                                   |  74 ++++++-
 net/sunrpc/xdr.c                                   |   2 +-
 net/sunrpc/xprtrdma/ib_client.c                    |  24 ++-
 net/sunrpc/xprtrdma/svc_rdma_rw.c                  |  47 ++++-
 net/sunrpc/xprtrdma/svc_rdma_sendto.c              |  47 +++--
 net/sunrpc/xprtrdma/svc_rdma_transport.c           |  52 +++--
 net/sunrpc/xprtsock.c                              |  12 +-
 net/vmw_vsock/virtio_transport.c                   |   2 +-
 scripts/rust_is_available.sh                       |  14 ++
 scripts/rust_is_available_bindgen_libclang_22.h    |   5 +
 scripts/rust_is_available_test.py                  |  30 ++-
 security/apparmor/include/cred.h                   |   6 +-
 security/apparmor/include/label.h                  |   6 +-
 security/apparmor/include/task.h                   |  15 +-
 security/apparmor/task.c                           |  27 +++
 security/smack/smack_lsm.c                         |   2 +-
 sound/core/ump_convert.c                           |   1 +
 sound/drivers/aloop.c                              |   6 +
 sound/drivers/mpu401/mpu401.c                      |   6 +
 sound/drivers/mts64.c                              |   6 +
 sound/drivers/portman2x4.c                         |   6 +
 sound/drivers/serial-u16550.c                      |   6 +
 sound/drivers/virmidi.c                            |   6 +
 sound/pci/pcxhr/pcxhr.c                            |  14 +-
 sound/soc/amd/yc/acp6x-mach.c                      |   7 +
 sound/usb/6fire/comm.c                             |   9 +-
 sound/usb/bcd2000/bcd2000.c                        |  11 +-
 tools/include/linux/compiler.h                     |   2 +-
 .../selftests/kvm/x86_64/sev_migrate_tests.c       |   2 -
 366 files changed, 3709 insertions(+), 1854 deletions(-)
author maintainer
#1 lore raw

PATCH 1/403 bnxt_en: Mask the bd_cnt field in the TX BD properly

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

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

From: Michael Chan <[email protected]>

[ Upstream commit 107b25db61122d8f990987895c2912927b8b6e3f ]

The bd_cnt field in the TX BD specifies the total number of BDs for the TX packet. The bd_cnt field has 5 bits and the maximum number supported is 32 with the value 0.

CONFIG_MAX_SKB_FRAGS can be modified and the total number of SKB fragments can approach or exceed the maximum supported by the chip. Add a macro to properly mask the bd_cnt field so that the value 32 will be properly masked and set to 0 in the bd_cnd field.

Without this patch, the out-of-range bd_cnt value will corrupt the TX BD and may cause TX timeout.

The next patch will check for values exceeding 32.

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c     | 4 ++--
 drivers/net/ethernet/broadcom/bnxt/bnxt.h     | 2 ++
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 3 +--
 3 files changed, 5 insertions(+), 4 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +2 -2
index 2356b7ba7fcfb..e14e2a0bf89ce 100644
@@ -553,7 +553,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
 					TX_BD_FLAGS_LHINT_512_AND_SMALLER |
 					TX_BD_FLAGS_COAL_NOW |
 					TX_BD_FLAGS_PACKET_END |
-					(2 << TX_BD_FLAGS_BD_CNT_SHIFT));
+					TX_BD_CNT(2));
 
 		if (skb->ip_summed == CHECKSUM_PARTIAL)
 			tx_push1->tx_bd_hsize_lflags =
@@ -628,7 +628,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	dma_unmap_addr_set(tx_buf, mapping, mapping);
 	flags = (len << TX_BD_LEN_SHIFT) | TX_BD_TYPE_LONG_TX_BD |
-		((last_frag + 2) << TX_BD_FLAGS_BD_CNT_SHIFT);
+		TX_BD_CNT(last_frag + 2);
 
 	txbd->tx_bd_haddr = cpu_to_le64(mapping);
 	txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2 + last_frag);
drivers/net/ethernet/broadcom/bnxt/bnxt.h +2 -0
index f50fe72f83ac6..67a82b3262d58 100644
@@ -79,6 +79,8 @@ struct tx_bd {
 #define TX_OPAQUE_PROD(bp, opq)	((TX_OPAQUE_IDX(opq) + TX_OPAQUE_BDS(opq)) &\
 				 (bp)->tx_ring_mask)
 
+#define TX_BD_CNT(n)	(((n) << TX_BD_FLAGS_BD_CNT_SHIFT) & TX_BD_FLAGS_BD_CNT)
+
 struct tx_bd_ext {
 	__le32 tx_bd_hsize_lflags;
 	#define TX_BD_FLAGS_TCP_UDP_CHKSUM			(1 << 0)
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +1 -2
index fa3c6515cc4d6..850dabebdbf22 100644
@@ -48,8 +48,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
 		tx_buf->page = virt_to_head_page(xdp->data);
 
 	txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
-	flags = (len << TX_BD_LEN_SHIFT) |
-		((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) |
+	flags = (len << TX_BD_LEN_SHIFT) | TX_BD_CNT(num_frags + 1) |
 		bnxt_lhint_arr[len >> 9];
 	txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
 	txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 1 + num_frags);
Signature · 1 line
2.53.0
author maintainer
#2 lore raw

PATCH 2/403 md: make rdev_addable usable for rcu mode

In reply to Greg Kroah-Hartman

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

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

From: Yang Erkun <[email protected]>

[ Upstream commit 13017b427118f4311471ee47df74872372ca8482 ]

Our testcase trigger panic:

BUG: kernel NULL pointer dereference, address: 00000000000000e0
...
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 2 UID: 0 PID: 85 Comm: kworker/2:1 Not tainted 6.16.0+ #94
PREEMPT(none)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.16.1-2.fc37 04/01/2014
Workqueue: md_misc md_start_sync
RIP: 0010:rdev_addable+0x4d/0xf0
...
Call Trace:
 <TASK>
 md_start_sync+0x329/0x480
 process_one_work+0x226/0x6d0
 worker_thread+0x19e/0x340
 kthread+0x10f/0x250
 ret_from_fork+0x14d/0x180
 ret_from_fork_asm+0x1a/0x30
 </TASK>
Modules linked in: raid10
CR2: 00000000000000e0
---[ end trace 0000000000000000 ]---
RIP: 0010:rdev_addable+0x4d/0xf0

md_spares_need_change in md_start_sync will call rdev_addable which protected by rcu_read_lock/rcu_read_unlock. This rcu context will help protect rdev won't be released, but rdev->mddev will be set to NULL before we call synchronize_rcu in md_kick_rdev_from_array. Fix this by using READ_ONCE and check does rdev->mddev still alive.

Fixes bc08041b32ab ("md: suspend array in md_start_sync() if array need reconfiguration")
Fixes 570b9147deb6 ("md: use RCU lock to protect traversal in md_spares_need_change()")
---
 drivers/md/md.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/md/md.c +7 -1
index 1aff3e541ceb5..60a07d7264d83 100644
@@ -9373,6 +9373,12 @@ static bool rdev_is_spare(struct md_rdev *rdev)
 
 static bool rdev_addable(struct md_rdev *rdev)
 {
+	struct mddev *mddev;
+
+	mddev = READ_ONCE(rdev->mddev);
+	if (!mddev)
+		return false;
+
 	/* rdev is already used, don't add it again. */
 	if (test_bit(Candidate, &rdev->flags) || rdev->raid_disk >= 0 ||
 	    test_bit(Faulty, &rdev->flags))
@@ -9383,7 +9389,7 @@ static bool rdev_addable(struct md_rdev *rdev)
 		return true;
 
 	/* Allow to add if array is read-write. */
-	if (md_is_rdwr(rdev->mddev))
+	if (md_is_rdwr(mddev))
 		return true;
 
 	/*
Signature · 1 line
2.53.0
author maintainer
#3 lore raw

PATCH 3/403 f2fs: fix potential deadloop in prepare_compress_overwrite()

In reply to Greg Kroah-Hartman

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

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

From: Chao Yu <[email protected]>

[ Upstream commit 3147ee567dd9004a49826ddeaf0a4b12865d4409 ]

Jan Prusakowski reported a kernel hang issue as below:

When running xfstests on linux-next kernel (6.14.0-rc3, 6.12) I encountered a problem in generic/475 test where fsstress process gets blocked in __f2fs_write_data_pages() and the test hangs. The options I used are:

MKFS_OPTIONS -- -O compression -O extra_attr -O project_quota -O quota /dev/vdc MOUNT_OPTIONS -- -o acl,user_xattr -o discard,compress_extension=* /dev/vdc /vdc

INFO: task kworker/u8:0:11 blocked for more than 122 seconds.
      Not tainted 6.14.0-rc3-xfstests-lockdep #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/u8:0    state:D stack:0     pid:11    tgid:11    ppid:2      task_flags:0x4208160 flags:0x00004000
Workqueue: writeback wb_workfn (flush-253:0)
Call Trace:
 <TASK>
 __schedule+0x309/0x8e0
 schedule+0x3a/0x100
 schedule_preempt_disabled+0x15/0x30
 __mutex_lock+0x59a/0xdb0
 __f2fs_write_data_pages+0x3ac/0x400
 do_writepages+0xe8/0x290
 __writeback_single_inode+0x5c/0x360
 writeback_sb_inodes+0x22f/0x570
 wb_writeback+0xb0/0x410
 wb_do_writeback+0x47/0x2f0
 wb_workfn+0x5a/0x1c0
 process_one_work+0x223/0x5b0
 worker_thread+0x1d5/0x3c0
 kthread+0xfd/0x230
 ret_from_fork+0x31/0x50
 ret_from_fork_asm+0x1a/0x30
 </TASK>

The root cause is: once generic/475 starts toload error table to dm device, f2fs_prepare_compress_overwrite() will loop reading compressed cluster pages due to IO error, meanwhile it has held .writepages lock, it can block all other writeback tasks.

Let's fix this issue w/ below changes:
- add f2fs_handle_page_eio() in prepare_compress_overwrite() to detect IO error.
- detect cp_error earler in f2fs_read_multi_pages().

Fixes 4c8ff7095bef ("f2fs: support data compression")
---
 fs/f2fs/compress.c |  1 +
 fs/f2fs/data.c     | 10 ++++++----
 2 files changed, 7 insertions(+), 4 deletions(-)
fs/f2fs/compress.c +1 -0
index c2ec80c82b6de..9e7fb8d883099 100644
@@ -1141,6 +1141,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
 		f2fs_compress_ctx_add_page(cc, page_folio(page));
 
 		if (!PageUptodate(page)) {
+			f2fs_handle_page_eio(sbi, page_folio(page), DATA);
 release_and_retry:
 			f2fs_put_rpages(cc);
 			f2fs_unlock_rpages(cc, i + 1);
fs/f2fs/data.c +6 -4
index 16c15360605b0..ec816df4887cc 100644
@@ -2250,6 +2250,12 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
 	int i;
 	int ret = 0;
 
+	if (unlikely(f2fs_cp_error(sbi))) {
+		ret = -EIO;
+		from_dnode = false;
+		goto out_put_dnode;
+	}
+
 	f2fs_bug_on(sbi, f2fs_cluster_is_empty(cc));
 
 	last_block_in_file = F2FS_BYTES_TO_BLK(f2fs_readpage_limit(inode) +
@@ -2293,10 +2299,6 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
 	if (ret)
 		goto out;
 
-	if (unlikely(f2fs_cp_error(sbi))) {
-		ret = -EIO;
-		goto out_put_dnode;
-	}
 	f2fs_bug_on(sbi, dn.data_blkaddr != COMPRESS_ADDR);
 
 skip_reading_dnode:
Signature · 1 line
2.53.0
author maintainer
#4 lore raw

PATCH 4/403 block: mark GFP_NOIO around sysfs ->store()

In reply to Greg Kroah-Hartman

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

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

From: Ming Lei <[email protected]>

[ Upstream commit 7c0be4ead1f8f5f8be0803f347de0de81e3b8e1c ]

sysfs ->store is called with queue freezed, meantime we have several ->store() callbacks(update_nr_requests, wbt, scheduler) to allocate memory with GFP_KERNEL which may run into direct reclaim code path, then potential deadlock can be caused.

Fix the issue by marking NOIO around sysfs ->store()

---
 block/blk-sysfs.c | 3 +++
 1 file changed, 3 insertions(+)
block/blk-sysfs.c +3 -0
index a5b6bcdfb9aa0..d53ffff112ff2 100644
@@ -668,6 +668,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
 	struct queue_sysfs_entry *entry = to_queue(attr);
 	struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
 	struct request_queue *q = disk->queue;
+	unsigned int noio_flag;
 	ssize_t res;
 
 	if (!entry->store_limit && !entry->store)
@@ -701,7 +702,9 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
 
 	mutex_lock(&q->sysfs_lock);
 	blk_mq_freeze_queue(q);
+	noio_flag = memalloc_noio_save();
 	res = entry->store(disk, page, length);
+	memalloc_noio_restore(noio_flag);
 	blk_mq_unfreeze_queue(q);
 	mutex_unlock(&q->sysfs_lock);
 	return res;
Signature · 1 line
2.53.0
author maintainer
#5 lore raw

PATCH 5/403 drm/amd/display: Avoid divide by zero by initializing dummy pitch to 1

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 7e40f64896e8e3dca471e287672db5ace12ea0be ]

[Why]
If the dummy values in populate_dummy_dml_surface_cfg() aren't updated then they can lead to a divide by zero in downstream callers like CalculateVMAndRowBytes()

[How]
Initialize dummy value to a value to avoid divide by zero.

---
 drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +1 -1
index 405aefd14d9b4..c768306ca69e8 100644
@@ -852,7 +852,7 @@ static void populate_dummy_dml_surface_cfg(struct dml_surface_cfg_st *out, unsig
 	out->SurfaceWidthC[location] = in->timing.h_addressable;
 	out->SurfaceHeightC[location] = in->timing.v_addressable;
 	out->PitchY[location] = ((out->SurfaceWidthY[location] + 127) / 128) * 128;
-	out->PitchC[location] = 0;
+	out->PitchC[location] = 1;
 	out->DCCEnable[location] = false;
 	out->DCCMetaPitchY[location] = 0;
 	out->DCCMetaPitchC[location] = 0;
Signature · 1 line
2.53.0
author maintainer
#6 lore raw

PATCH 6/403 perf/x86/intel/uncore: Fix die ID init and look up bugs

In reply to Greg Kroah-Hartman

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

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

From: Zide Chen <[email protected]>

[ Upstream commit a16d1ec4dd0cdcf689f324adde6067083bce9099 ]

In snbep_pci2phy_map_init(), in the nr_node_ids > 8 path, uncore_device_to_die() may return -1 when all CPUs associated with the UBOX device are offline.

Remove the WARN_ON_ONCE(die_id == -1) check for two reasons:

- The current code breaks out of the loop. This is incorrect because pci_get_device() does not guarantee iteration in domain or bus order, so additional UBOX devices may be skipped during the scan.

- Returning -EINVAL is incorrect, since marking offline buses with die_id == -1 is expected and should not be treated as an error.

Separately, when NUMA is disabled on a NUMA-capable platform, pcibus_to_node() returns NUMA_NO_NODE, causing uncore_device_to_die() to return -1 for all PCI devices. As a result, spr_update_device_location(), used on Intel SPR and EMR, ignores the corresponding PMON units and does not add them to the RB tree.

Fix this by using uncore_pcibus_to_dieid(), which retrieves topology from the UBOX GIDNIDMAP register and works regardless of whether NUMA is enabled in Linux. This requires snbep_pci2phy_map_init() to be added in spr_uncore_pci_init().

Keep uncore_device_to_die() only for the nr_node_ids > 8 case, where NUMA is expected to be enabled.

Fixes 9a7832ce3d92 ("perf/x86/intel/uncore: With > 8 nodes, get pci bus die id from NUMA info")
Fixes 65248a9a9ee1 ("perf/x86/uncore: Add a quirk for UPI on SPR")
---
 arch/x86/events/intel/uncore.c       |  1 +
 arch/x86/events/intel/uncore_snbep.c | 13 ++++++-------
 2 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/events/intel/uncore.c +1 -0
index e7aba7349231d..96607174a0a93 100644
@@ -66,6 +66,7 @@ int uncore_die_to_segment(int die)
 	return bus ? pci_domain_nr(bus) : -EINVAL;
 }
 
+/* Note: This API can only be used when NUMA information is available. */
 int uncore_device_to_die(struct pci_dev *dev)
 {
 	int node = pcibus_to_node(dev->bus);
arch/x86/events/intel/uncore_snbep.c +6 -7
index c453ee7a52074..ca0193cbbe924 100644
@@ -1474,13 +1474,7 @@ static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool
 			}
 
 			map->pbus_to_dieid[bus] = die_id = uncore_device_to_die(ubox_dev);
-
 			raw_spin_unlock(&pci2phy_map_lock);
-
-			if (WARN_ON_ONCE(die_id == -1)) {
-				err = -EINVAL;
-				break;
-			}
 		}
 	}
 
@@ -6530,7 +6524,7 @@ static void spr_update_device_location(int type_id)
 
 	while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, dev)) != NULL) {
 
-		die = uncore_device_to_die(dev);
+		die = uncore_pcibus_to_dieid(dev->bus);
 		if (die < 0)
 			continue;
 
@@ -6554,6 +6548,11 @@ static void spr_update_device_location(int type_id)
 
 int spr_uncore_pci_init(void)
 {
+	int ret = snbep_pci2phy_map_init(0x3250, SKX_CPUNODEID, SKX_GIDNIDMAP, true);
+
+	if (ret)
+		return ret;
+
 	/*
 	 * The discovery table of UPI on some SPR variant is broken,
 	 * which impacts the detection of both UPI and M3UPI uncore PMON.
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 7/403 wifi: mt76: Fix memory leak after mt76_connac_mcu_alloc_sta_req()

In reply to Greg Kroah-Hartman

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

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

From: Zilin Guan <[email protected]>

[ Upstream commit c41075ce8cf05ed8c0e7b7efef000dce548ffc42 ]

mt76_connac_mcu_alloc_sta_req() allocates an skb which is expected to be freed eventually by mt76_mcu_skb_send_msg(). However, currently if an intermediate function fails before sending, the allocated skb is leaked.

Specifically, mt76_connac_mcu_sta_wed_update() and mt76_connac_mcu_sta_key_tlv() may fail, leading to an immediate memory leak in the error path.

Fix this by explicitly freeing the skb in these error paths. Commit 7c0f63fe37a5 ("wifi: mt76: mt7996: fix memory leak on mt7996_mcu_sta_key_tlv error") made a similar change.

Compile tested only. Issue found using a prototype static analysis tool and code review.

Fixes d1369e515efe ("wifi: mt76: connac: introduce mt76_connac_mcu_sta_wed_update utility routine")
Fixes 6683d988089c ("mt76: connac: move mt76_connac_mcu_add_key in connac module")
Fixes 4f831d18d12d ("wifi: mt76: mt7915: enable WED RX support")
Fixes c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
---
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 16 ++++++++++++----
 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c  |  4 +++-
 drivers/net/wireless/mediatek/mt76/mt7925/mcu.c  |  4 +++-
 3 files changed, 18 insertions(+), 6 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +12 -4
index b1a7fbedffac5..f60fe27ab3f9d 100644
@@ -1289,8 +1289,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
 				    wtbl_hdr);
 
 	ret = mt76_connac_mcu_sta_wed_update(dev, skb);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true);
 	if (ret)
@@ -1303,8 +1305,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
 
 	ret = mt76_connac_mcu_sta_wed_update(dev, skb);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	return mt76_mcu_skb_send_msg(dev, skb, cmd, true);
 }
@@ -2697,12 +2701,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
 		return PTR_ERR(skb);
 
 	ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	ret = mt76_connac_mcu_sta_wed_update(dev, skb);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
 }
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +3 -1
index d622d7c7bee41..32e9c0960657a 100644
@@ -1729,8 +1729,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 	}
 out:
 	ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +3 -1
index 1fc1116d9becc..910775a2c39fe 100644
@@ -1239,8 +1239,10 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
 		return PTR_ERR(skb);
 
 	ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta);
-	if (ret)
+	if (ret) {
+		dev_kfree_skb(skb);
 		return ret;
+	}
 
 	return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
 }
Signature · 1 line
2.53.0
author maintainer
#8 lore raw

PATCH 8/403 wifi: ath11k: fix memory leaks in beacon template setup

In reply to Greg Kroah-Hartman

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

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

From: Zilin Guan <[email protected]>

[ Upstream commit ff49eba595df500e4ddccc593088c8a4ab5f2c27 ]

The functions ath11k_mac_setup_bcn_tmpl_ema() and ath11k_mac_setup_bcn_tmpl_mbssid() allocate memory for beacon templates but fail to free it when parameter setup returns an error.

Since beacon templates must be released during normal execution, they must also be released in the error handling paths to prevent memory leaks.

Fix this by using unified exit paths with proper cleanup in the respective error paths.

Compile tested only. Issue found using a prototype static analysis tool and code review.

Fixes 3a415daa3e8b ("wifi: ath11k: add P2P IE in beacon template")
Fixes 335a92765d30 ("wifi: ath11k: MBSSID beacon support")
---
 drivers/net/wireless/ath/ath11k/mac.c | 28 ++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)
drivers/net/wireless/ath/ath11k/mac.c +17 -11
index dd5690a4996f3..c4856480fffe7 100644
@@ -1545,12 +1545,15 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
 	if (!beacons || !beacons->cnt) {
 		ath11k_warn(arvif->ar->ab,
 			    "failed to get ema beacon templates from mac80211\n");
-		return -EPERM;
+		ret = -EPERM;
+		goto free;
 	}
 
 	if (tx_arvif == arvif) {
-		if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb))
-			return -EINVAL;
+		if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) {
+			ret = -EINVAL;
+			goto free;
+		}
 	} else {
 		arvif->wpaie_present = tx_arvif->wpaie_present;
 	}
@@ -1577,11 +1580,11 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
 		}
 	}
 
-	ieee80211_beacon_free_ema_list(beacons);
-
 	if (tx_arvif != arvif && !nontx_vif_params_set)
-		return -EINVAL; /* Profile not found in the beacons */
+		ret = -EINVAL; /* Profile not found in the beacons */
 
+free:
+	ieee80211_beacon_free_ema_list(beacons);
 	return ret;
 }
 
@@ -1613,19 +1616,22 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
 	}
 
 	if (tx_arvif == arvif) {
-		if (ath11k_mac_set_vif_params(tx_arvif, bcn))
-			return -EINVAL;
+		if (ath11k_mac_set_vif_params(tx_arvif, bcn)) {
+			ret = -EINVAL;
+			goto free;
+		}
 	} else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) {
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free;
 	}
 
 	ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0);
-	kfree_skb(bcn);
-
 	if (ret)
 		ath11k_warn(ab, "failed to submit beacon template command: %d\n",
 			    ret);
 
+free:
+	kfree_skb(bcn);
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#9 lore raw

PATCH 9/403 drm/amd/display: Avoid NULL dereference in dc_dmub_srv error paths

In reply to Greg Kroah-Hartman

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

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

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit 4ae3e16f4b3bf64140f773629b765d605ee079a9 ]

In dc_dmub_srv_log_diagnostic_data() and
dc_dmub_srv_enable_dpia_trace().

Both functions check:

  if (!dc_dmub_srv || !dc_dmub_srv->dmub)

and then call DC_LOG_ERROR() inside that block.

DC_LOG_ERROR() uses dc_dmub_srv->ctx internally. So if dc_dmub_srv is NULL, the logging itself can dereference a NULL pointer and cause a crash.

Fix this by splitting the checks.

First check if dc_dmub_srv is NULL and return immediately. Then check dc_dmub_srv->dmub and log the error only when dc_dmub_srv is valid.

Fixes the below:
../display/dc/dc_dmub_srv.c:962 dc_dmub_srv_log_diagnostic_data() error: we previously assumed 'dc_dmub_srv' could be null (see line 961) ../display/dc/dc_dmub_srv.c:1167 dc_dmub_srv_enable_dpia_trace() error: we previously assumed 'dc_dmub_srv' could be null (see line 1166)

Fixes 2631ac1ac328 ("drm/amd/display: add DMUB registers to crash dump diagnostic data.")
Fixes 71ba6b577a35 ("drm/amd/display: Add interface to enable DPIA trace")
Cc Roman Li <[email protected]>
Cc Alex Hung <[email protected]>
Cc Tom Chung <[email protected]>
Cc Dan Carpenter <[email protected]>
Cc Aurabindo Pillai <[email protected]>
---
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +8 -2
index 19b8d46ce848d..abc376f5cd9c9 100644
@@ -935,7 +935,10 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
 	struct dmub_diagnostic_data diag_data = {0};
 	uint32_t i;
 
-	if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
+	if (!dc_dmub_srv)
+		return;
+
+	if (!dc_dmub_srv->dmub) {
 		DC_LOG_ERROR("%s: invalid parameters.", __func__);
 		return;
 	}
@@ -1179,7 +1182,10 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)
 {
 	struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
 
-	if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
+	if (!dc_dmub_srv)
+		return;
+
+	if (!dc_dmub_srv->dmub) {
 		DC_LOG_ERROR("%s: invalid parameters.", __func__);
 		return;
 	}
Signature · 1 line
2.53.0
author maintainer
#10 lore raw

PATCH 10/403 alpha: fix ieee_swcr_to_fpcr setting FPCR_DNOD unconditionally

In reply to Greg Kroah-Hartman

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

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

From: Matt Turner <[email protected]>

commit 49672d026cc4773608e1222b69b29fd70f41336b upstream.

ieee_swcr_to_fpcr() converts the software IEEE trap-enable and status bits kept in thread_info.ieee_state into the hardware FPCR format. It contained:

	fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;

FPCR_DNOD (bit 47) disables denormal operand traps: with it set the hardware handles a denormal operand itself, treating it as zero, instead of trapping for software completion. The intent was to set DNOD when the user has not asked for SIGFPE on denormal operands, but IEEE_TRAP_ENABLE_DNO is clear by default, so ieee_swcr_to_fpcr(0) always set DNOD.

Instructions built with the software completion suffix therefore never trapped on a denormal operand. The hardware silently substituted zero and produced wrong results, affecting every program compiled with -mieee and default FPU settings, glibc included.

Set FPCR_DNOD only when IEEE_MAP_DMZ is requested, which is exactly the case where flushing denormal inputs to zero is what the user asked for. DNOD then encodes MAP_DMZ, which ieee_fpcr_to_swcr() already recovers from FPCR_DNZ, so drop its attempt to recover IEEE_TRAP_ENABLE_DNO from DNOD; the DNO trap enable lives solely in ieee_state.

Both functions are in a uapi header, so the encoding change is visible to userspace, but nothing outside the kernel is known to depend on DNOD carrying the DNO trap enable, and the kernel is the only writer of the FPCR.

This must not be backported on its own. Re-enabling denormal operand traps exposes a second bug, fixed in the following patch: those traps usually find an exact result, and for an exact result the emulator did not write the FPCR back, leaving hardware-fabricated exception bits visible to user space. Taken alone this change would make spurious exception flags more common.

The bug predates the git history, so there is no commit to reference in a Fixes tag.

---
 arch/alpha/include/uapi/asm/fpu.h |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
arch/alpha/include/uapi/asm/fpu.h +6 -2
@@ -101,7 +101,12 @@ ieee_swcr_to_fpcr(unsigned long sw)
 		      | IEEE_TRAP_ENABLE_OVF)) << 48;
 	fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
 	fp |= (sw & IEEE_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
-	fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;
+	/*
+	 * Disable denormal operand traps only when denormal inputs are to be
+	 * flushed to zero.  Otherwise they must keep trapping, so that /S
+	 * instructions reach the kernel emulation handler.
+	 */
+	fp |= (sw & IEEE_MAP_DMZ ? FPCR_DNOD : 0);
 	return fp;
 }
 
@@ -116,7 +121,6 @@ ieee_fpcr_to_swcr(unsigned long fp)
 			     | IEEE_TRAP_ENABLE_OVF);
 	sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
 	sw |= (fp >> 47) & IEEE_MAP_UMZ;
-	sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO;
 	return sw;
 }
 
author maintainer
#11 lore raw

PATCH 11/403 alpha: dont leak hardware-fabricated FP exception bits to user space

In reply to Greg Kroah-Hartman

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

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

From: Matt Turner <[email protected]>

commit bcfe3187412e342b4619efb92c945f073855ebc0 upstream.

On EV6 and later the hardware records exception status bits in the FPCR before delivering a software completion trap, and those bits can be wrong for the instruction that trapped. Converting a double that is exactly representable as a subnormal float sets FPCR_UNF even though the result is exact, and an underflow trap additionally sets FPCR_INE even when the emulated operation turns out to be exact.

alpha_fp_emul() only wrote the FPCR when soft-fp raised an exception, so whenever it determined that the instruction was exact the fabricated bits stayed in the FPCR and were reported to user space by fetestexcept().

Pass the exception summary register down from do_entArith() so the handler can tell which exceptions the hardware attributed to the trapping instruction, and always write the FPCR. Clear the exceptions that the trap reported but that soft-fp did not raise. EXC_SUM reports only the underflow or overflow when the hardware also set INE, so treat INE as a candidate in that case, and treat a trap with no reported exception as a denormal operand trap, for which the hardware can fabricate INE and UNF as well. Bits that software has already confirmed in ieee_state belong to this or an earlier instruction and are never cleared.

The imprecise path passes no summary. There the trap was taken somewhere in the trap shadow, so EXC_SUM is not attribution for the instruction being re-executed -- and only EV6, which traps precisely and so never takes that path, has fabricated bits to clear. For the same reason the clearing is guarded by implver(), matching swcr_update_status().

On an UP1500 (EV68) this takes the glibc math testsuite from 831 failures to 28, the remainder being unrelated to exception status.

This belongs with the preceding fix to ieee_swcr_to_fpcr(), and should not be backported without it -- nor it without this. That fix stops FPCR_DNOD being set unconditionally, so denormal operand traps start firing again. Those traps very often find an exact result, which is precisely the case where the old code left the FPCR unwritten and the fabricated bits visible. Applied alone it would make spurious exception flags more common, not less.

One case cannot be resolved here: an inexact instruction without the software completion suffix never traps, so its INE reaches the FPCR without being recorded anywhere else. Such a bit is indistinguishable from an INE the hardware fabricated for a trapping instruction, and is lost if an underflow or overflow trap with an exact result follows it. The FPCR is the only record of those instructions and it carries no attribution.

The bug predates the git history, so there is no commit to reference in a Fixes tag.

---
 arch/alpha/kernel/traps.c  |    6 +--
 arch/alpha/math-emu/math.c |   88 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 80 insertions(+), 14 deletions(-)
arch/alpha/kernel/traps.c +3 -3
@@ -166,12 +166,12 @@ static long dummy_emul(void) { return 0;
 long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)
   = (void *)dummy_emul;
 EXPORT_SYMBOL_GPL(alpha_fp_emul_imprecise);
-long (*alpha_fp_emul) (unsigned long pc)
+long (*alpha_fp_emul) (unsigned long pc, unsigned long summary)
   = (void *)dummy_emul;
 EXPORT_SYMBOL_GPL(alpha_fp_emul);
 #else
 long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
-long alpha_fp_emul (unsigned long pc);
+long alpha_fp_emul (unsigned long pc, unsigned long summary);
 #endif
 
 asmlinkage void
@@ -185,7 +185,7 @@ do_entArith(unsigned long summary, unsig
 		   emulate the instruction.  If the processor supports
 		   precise exceptions, we don't have to search.  */
 		if (!amask(AMASK_PRECISE_TRAP))
-			si_code = alpha_fp_emul(regs->pc - 4);
+			si_code = alpha_fp_emul(regs->pc - 4, summary);
 		else
 			si_code = alpha_fp_emul_imprecise(regs, write_mask);
 		if (si_code == 0)
arch/alpha/math-emu/math.c +77 -11

125 lines not on this page · raw message

author maintainer
#12 lore raw

PATCH 12/403 clocksource/drivers/timer-sun4i: Advertise a real minimum delta

In reply to Greg Kroah-Hartman

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

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

From: Felix Yan <[email protected]>

commit d21808328225ab8cee46885bf9a0dffcefbe630e upstream.

sun4i_clkevt_next_event() compensates for the timer stop/start synchronization delay by programming evt - TIMER_SYNC_TICKS into the hardware interval register. The clockevent device currently advertises TIMER_SYNC_TICKS as min_delta_ticks, so the clockevents core is allowed to call set_next_event() with evt == TIMER_SYNC_TICKS.

That programs a zero-tick interval. With oneshot/highres/nohz timer operation this can leave the next event stuck, which was observed as a boot hang on Allwinner D1 after the clockevents core started reusing forced minimum-delta events.

Advertise one extra tick instead, so the smallest event accepted by the core still programs at least one hardware tick after the synchronization compensation.

---
 drivers/clocksource/timer-sun4i.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/timer-sun4i.c +1 -1
@@ -208,7 +208,7 @@ static int __init sun4i_timer_init(struc
 	sun4i_timer_clear_interrupt(timer_of_base(&to));
 
 	clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
-					TIMER_SYNC_TICKS, 0xffffffff);
+					TIMER_SYNC_TICKS + 1, 0xffffffff);
 
 	/* Enable timer0 interrupt */
 	val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG);
author maintainer
#13 lore raw

PATCH 13/403 fs: fix user path of nested backing files

In reply to Greg Kroah-Hartman

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

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

From: Baokun Li <[email protected]>

commit f2381b546e7e6a35c9fcee0d0ccb6c042a9aeb5d upstream.

backing_file_open() derives the path to be stored in the new backing file from user_file->f_path. This is incorrect when user_file itself is a backing file, which is the case for nested stacking filesystems, e.g. overlayfs mounts where the lowerdir of one overlayfs is the merged directory of another. Since commit def3ae83da02 ("fs: store real path instead of fake path in backing file f_path") the f_path of a backing file holds the real path of the intermediate layer, not the path that the user opened.

Commit 924577e4f6ca ("ovl: Fix nested backing file paths") fixed this for such configurations by passing file_user_path() from ovl_open_realfile(). However, commit 6af36aeb147a ("lsm: add backing_file LSM hooks") changed the first argument of backing_file_open() from the user path back to the user file and derived the path from user_file->f_path again, silently re-introducing the problem.

As a result, files mapped through a nested overlayfs show the wrong path in /proc/<pid>/maps and in perf/ftrace mmap records. For example, with two nested overlayfs mounts:

mkdir -p /ovl/{lower,upper,work,merged} /ovl/nested echo hello > /ovl/lower/foo

  mount -t overlay overlay \
	-o lowerdir=/ovl/lower,upperdir=/ovl/upper,workdir=/ovl/work \
	/ovl/merged
  # at least two lowerdirs are needed when upperdir is nonexistent
  mount -t overlay overlay \
	-o lowerdir=/ovl/merged:/ovl/lower /ovl/nested

mapping /ovl/nested/foo shows a disconnected path instead of the user path:

  # readlink /proc/self/fd/3
  /ovl/nested/foo
  # grep foo /proc/self/maps
  7f6e2c100000-7f6e2c101000 r--s 00000000 00:24 15813027 /foo

The bogus path is derived from the f_path of the intermediate backing file, whose mount is a private clone that d_path() cannot resolve.

Fix this by using file_user_path(), which returns the outermost user-visible path for backing files and falls back to &user_file->f_path for regular files. This restores the behavior of commit 924577e4f6ca ("ovl: Fix nested backing file paths") for overlayfs and also fixes the same problem for the other backing_file_open() callers, fuse passthrough and erofs ishare, when their user file is itself a backing file.

backing_tmpfile_open() has the same pattern but is not affected: it is only called by ovl_create_tmpfile() for the upper layer, and another overlayfs is rejected as upperdir by the DCACHE_OP_REAL check in ovl_mount_dir_check(), so its user_file can never be a backing file.

---
 fs/backing-file.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/backing-file.c +1 -1
@@ -34,7 +34,7 @@ struct file *backing_file_open(const str
 			       const struct path *real_path,
 			       const struct cred *cred)
 {
-	const struct path *user_path = &user_file->f_path;
+	const struct path *user_path = file_user_path(user_file);
 	struct file *f;
 	int error;
 
author maintainer
#14 lore raw

PATCH 14/403 powerpc/pseries/iommu: switch to Default DMA window during kdump

In reply to Greg Kroah-Hartman

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

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

From: Gaurav Batra <[email protected]>

commit 1304643a1c20badbb91b86a5084dd76cb7620c05 upstream.

In PowerPC (pseries) a non-virtualized adapter will have 2 DMA windows - 2GB default and a larger Dynamic DMA Window (DDW). DDW is large enough to map total RAM to a device.

During normal functioning of OS, since RAM is pre-mapped, 2GB default window is not used. The only scenario it might get used is when buffers in pmemory are mapped to the device for DMA.

As of today, during kdump, during early device discovery, pci_dma_find() finds that the device has 2 DMA windows. It selects to use DDW. This is a kdump path and DMA window is needed for IO to the device.

Although commit 09a3c1e46142 ("powerpc/pseries/iommu: IOMMU table is not initialized for kdump over SR-IOV") fixed an issue during kdump with SR-IOV case, but this also made the kdump prefer DDW over the default DMA window when both are present (dedicated adapter case). Since the DDW is fully mapped by the previous kernel, iommu_table_clear() can free only KDUMP_MIN_TCE_ENTRIES (2048) TCEs for use by kdump kernel.

This is not enough when the dump device is NVMe over Fibre Channel. Because nvme-fc driver DMA-maps the cmds and resp IUs of every pre-allocated request and each such mapping consumes roughly:

32 (IO queues, one per cpus = nr_cpus) *
64 (queue_depth, blk-mq kdump limit) *
2 (cmd+resp) = 4096

This is already double of what we have without counting admin queues and lpfc driver's own allocations / mapping requirement. Hence this results into iommu_alloc failures like -

lpfc 0153:70:00.0: iommu_alloc failed,
tbl 0000000034ebcf5e vaddr 00000000d814df0b npages 1 lpfc 0153:70:00.0: FCP Op failed - cmdiu dma mapping failed. lpfc 0153:70:00.0: iommu_alloc failed,
tbl 0000000034ebcf5e vaddr 000000009779e4d2 npages 1 lpfc 0153:70:00.0: FCP Op failed - cmdiu dma mapping failed.

iommu_map_phys+0x1c4/0x1f0 (unreliable)
dma_iommu_map_phys+0x54/0xa0
dma_map_phys+0x3f8/0x590
__nvme_fc_init_request+0x110/0x300 [nvme_fc]
nvme_fc_init_request+0x60/0xb8 [nvme_fc]
blk_mq_alloc_map_and_rqs+0x388/0x510
blk_mq_alloc_tag_set+0x2a4/0x5f0
nvme_alloc_io_tag_set+0xe0/0x1e0 [nvme_core]
nvme_fc_connect_ctrl_work+0x85c/0xdac [nvme_fc]
process_one_work+0x1e4/0x5a0
worker_thread+0x1ec/0x3e0

Increasing the number of free TCE entries in iommu_table_clear() will increase the probability of hitting EEH since there could still be some active IOs from the previous life of the kernel.

Hence this patch partially reverts the previous fixes commit and switches the kdump's default back to 2GB default DMA window instead of DDW window. This window will mostly be empty. Or, could be slightly used if buffers in pmemory were mapped for IO.

Fixes 09a3c1e46142 ("powerpc/pseries/iommu: IOMMU table is not initialized for kdump over SR-IOV")
---
 arch/powerpc/platforms/pseries/iommu.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
arch/powerpc/platforms/pseries/iommu.c +12 -11
@@ -812,18 +812,11 @@ static struct device_node *pci_dma_find(
 
 	/* parse DMA window property. During normal system boot, only default
 	 * DMA window is passed in OF. But, for kdump, a dedicated adapter might
-	 * have both default and DDW in FDT. In this scenario, DDW takes precedence
-	 * over default window.
+	 * have both default and DDW in FDT. In this scenario, default window
+	 * takes precedence over DDW. For a dedicated adapter, default window will
+	 * potentially have more unused TCEs.
 	 */
-	if (ddw_win) {
-		struct dynamic_dma_window_prop *p;
-
-		p = (struct dynamic_dma_window_prop *)ddw_prop;
-		prop->liobn = p->liobn;
-		prop->dma_base = p->dma_base;
-		prop->tce_shift = p->tce_shift;
-		prop->window_shift = p->window_shift;
-	} else if (default_win) {
+	if (default_win) {
 		unsigned long offset, size, liobn;
 
 		of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size);
@@ -832,6 +825,14 @@ static struct device_node *pci_dma_find(
 		prop->dma_base = cpu_to_be64(offset);
 		prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K);
 		prop->window_shift = cpu_to_be32(order_base_2(size));
+	} else {
+		struct dynamic_dma_window_prop *p;
+
+		p = (struct dynamic_dma_window_prop *)ddw_prop;
+		prop->liobn = p->liobn;
+		prop->dma_base = p->dma_base;
+		prop->tce_shift = p->tce_shift;
+		prop->window_shift = p->window_shift;
 	}
 
 	return rdn;
author maintainer
#15 lore raw

PATCH 15/403 timers/itimer: Zero-init old itimerval before copy to userspace

In reply to Greg Kroah-Hartman

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

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

From: Jérémy Jean <[email protected]>

commit 18c7d85864e554adc8fad1e8d2e9d2cb6c3911c8 upstream.

On native sparc64, struct __kernel_old_timeval contains a four-byte hole after tv_usec because tv_sec is 64-bit while __kernel_suseconds_t is 32-bit. put_itimerval() fills only the named fields in a stack-allocated __kernel_old_itimerval and copies the entire object to userspace, so getitimer() can expose the two padding holes.

Zero-initialize the aggregate before assigning the fields so implicit padding is deterministic before it crosses the user/kernel boundary.

---
 kernel/time/itimer.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/itimer.c +1 -1
@@ -100,7 +100,7 @@ static int do_getitimer(int which, struc
 static int put_itimerval(struct __kernel_old_itimerval __user *o,
 			 const struct itimerspec64 *i)
 {
-	struct __kernel_old_itimerval v;
+	struct __kernel_old_itimerval v = {};
 
 	v.it_interval.tv_sec = i->it_interval.tv_sec;
 	v.it_interval.tv_usec = i->it_interval.tv_nsec / NSEC_PER_USEC;
author maintainer
#16 lore raw

PATCH 16/403 rust: cfi: disable function merging if CFI is enabled

In reply to Greg Kroah-Hartman

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

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

From: Gary Guo <[email protected]>

commit 29b03d1de967a177176d12811d970cac7882afcf upstream.

In Rust doc tests, there is a dummy __module_firmware_test_init function generated by the example in module_firmware!'s documentation, which just returns zero. Many other documentation examples generate functions that produce zero. LKP test robot reports [1] a Flags::zeroed instance; my local reproduction has a Bounded::new::<0>.

LLVM's MergeFunctionsPass incorrectly merges functions with different KCFI types, causing __module_firmware_test_init to be merged into one of the zero-returning functions. As module init is invoked via an indirect function call, KCFI is checked and this produces a KCFI failure.

I've reported this bug to upstream LLVM [2]; in the meantime, disable function merging if CFI is enabled. No separate treatment is needed for CONFIG_RUST_INLINE_HELPERS, as Clang does not enable function merging by default.

[ LLVM already has a pending PR:

    https://github.com/llvm/llvm-project/pull/217665

which solves the issue. In addition, I asked upstream Rust if the unstable -Zmerge-functions=disabled flag will remain around:

    https://rust-lang.zulipchat.com/#narrow/channel/425075-rust-for-linux/topic/.60-Zmerge-functions.3Ddisabled.60/

and it does indeed look like that will be the case. - Miguel ]

Fixes ca627e636551 ("rust: cfi: add support for CFI_CLANG with Rust")
[ Fixed typos as discussed. Reworded slightly for other typos. - Miguel ]
---
 Makefile |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Makefile +2 -1
@@ -977,7 +977,8 @@ endif
 ifdef CONFIG_RUST
 	# Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
 	# CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
-	RUSTC_FLAGS_CFI   := -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+	# Disable function merging as LLVM incorrectly merges functions with different KCFI types.
+	RUSTC_FLAGS_CFI   := -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zmerge-functions=disabled
 	KBUILD_RUSTFLAGS += $(RUSTC_FLAGS_CFI)
 	export RUSTC_FLAGS_CFI
 endif
author maintainer
#17 lore raw

PATCH 17/403 apparmor: fix cred UAF caused by begin_current_label_crit_section()

In reply to Greg Kroah-Hartman

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

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

From: Jann Horn <[email protected]>

commit 3f4ae5fab613dca01d6a2a8210dd832e009fcf47 upstream.

AppArmor's begin_current_label_crit_section() is a scary function called from lots of LSM hooks (in particular VFS/socket-related ones) that checks if the label referenced by the current creds is marked FLAG_STALE, and if so, attempts to use aa_replace_current_label() to replace the creds with an updated version that uses a new label.

The first problem with this is that it would directly lead to UAF of struct cred if anything in the kernel takes a pointer to the current creds and accesses these past a security hook invocation that replaces creds, like so:

```
const struct cred *cred = current_cred();
alloc_file_pseudo(...);
uid_t uid = cred->euid;
```

I don't know if anything in the kernel actually does this, but I think it is very surprising that this pattern could lead to UAF.

The second problem is that things go wrong when aa_replace_current_label() runs with overridden credentials. aa_replace_current_label() bails out if current_cred() != current_real_cred() (mirroring the check in proc_pid_attr_write()), but this check can't actually reliably detect overridden credentials because the overridden creds can be the same as the objective creds.

So in approximately the following scenario, things go wrong:

1. task begins with <creds A> (as both objective and subjective creds), with refcount=2
2. task grabs an extra reference on <creds A> for overriding
3. task calls override_creds(<creds A>), which returns a pointer to the old subjective creds (<creds A>)
4. task enters AppArmor LSM hook
5. AppArmor checks that objective/subjective creds are equal
6. AppArmor replaces both cred pointers with <creds B> and drops 2 refs on <creds A>
7. task leaves AppArmor LSM hook
8. task calls revert_creds(<creds A>)
9. now task->cred is <creds A> while task->real_cred is <creds B>, but the task_struct logically holds two references to <creds B>
10. another task drops the extra reference on <creds A> that was used for overriding, refcount drops to 0
11. now task->real_cred points to freed creds

At this point, any access to current_cred() will be UAF.

I have a test case where I run aa-disable on a profile while a process using that profile is blocked on splice() from a FUSE passthrough file into a full pipe; after the profile update, the pipe becomes empty, splice() resumes, the credentials go out of sync, and a subsequent getuid() syscall results in a KASAN UAF splat.

To fix this, instead of directly replacing creds, do it via task_work that will run at the end of the current syscall. (The point in time at which the cred replacement happens should have no correctness impact; it is just a performance optimization to avoid unnecessarily touching the refcount of the new label.)

Note that AppArmor still performs direct cred replacements in the sb_pivotroot LSM hook after this change, and that direct cred replacements can still happen in VFS ->write() callbacks via proc_pid_attr_write().

There are two options for what to do with aa_dup_task_ctx(): Either explicitly reset new->label_replacement_pending after the entire aa_task_ctx has been copied, or switch to manually copying members over. I am switching to manually copying members over because that should make bugs more obvious.

Fixes c75afcd153f6 ("AppArmor: contexts used in attaching policy to system objects")
---
 security/apparmor/include/cred.h |    6 +-----
 security/apparmor/include/task.h |   15 +++++++++++----
 security/apparmor/task.c         |   27 +++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 9 deletions(-)
security/apparmor/include/cred.h +1 -5
@@ -168,13 +168,9 @@ static inline struct aa_label *begin_cur
 {
 	struct aa_label *label = aa_current_raw_label();
 
-	might_sleep();
-
 	if (label_is_stale(label)) {
 		label = aa_get_newest_label(label);
-		if (aa_replace_current_label(label) == 0)
-			/* task cred will keep the reference */
-			aa_put_label(label);
+		aa_schedule_stale_label_replacement();
 	}
 
 	return label;
security/apparmor/include/task.h +11 -4
@@ -21,15 +21,22 @@ static inline struct aa_task_ctx *task_c
  * @onexec: profile to transition to on next exec  (MAY BE NULL)
  * @previous: profile the task may return to     (MAY BE NULL)
  * @token: magic value the task must know for returning to @previous_profile
+ * @label_replacement_tw: for aa_schedule_stale_label_replacement()
+ * @label_replacement_pending: is @label_replacement_tw pending?
+ *
+ * When changing this, check if aa_dup_task_ctx() needs to be updated.
  */
 struct aa_task_ctx {
 	struct aa_label *nnp;
 	struct aa_label *onexec;
 	struct aa_label *previous;
 	u64 token;
+	struct callback_head label_replacement_tw;
+	bool label_replacement_pending;
 };
 
 int aa_replace_current_label(struct aa_label *label);
+void aa_schedule_stale_label_replacement(void);
 void aa_set_current_onexec(struct aa_label *label, bool stack);
 int aa_set_current_hat(struct aa_label *label, u64 token);
 int aa_restore_previous_label(u64 cookie);
@@ -56,10 +63,10 @@ static inline void aa_free_task_ctx(stru
 static inline void aa_dup_task_ctx(struct aa_task_ctx *new,
 				   const struct aa_task_ctx *old)
 {
-	*new = *old;
-	aa_get_label(new->nnp);
-	aa_get_label(new->previous);
-	aa_get_label(new->onexec);
+	new->nnp = aa_get_label(old->nnp);
+	new->onexec = aa_get_label(old->onexec);
+	new->previous = aa_get_label(old->previous);
+	new->token = old->token;
 }
 
 /**
security/apparmor/task.c +27 -0
@@ -14,6 +14,7 @@
 
 #include <linux/gfp.h>
 #include <linux/ptrace.h>
+#include <linux/task_work.h>
 
 #include "include/audit.h"
 #include "include/cred.h"
@@ -88,6 +89,32 @@ int aa_replace_current_label(struct aa_l
 	return 0;
 }
 
+static void aa_replace_stale_label_tw_func(struct callback_head *tw)
+{
+	struct aa_task_ctx *ctx = task_ctx(current);
+	struct aa_label *label;
+
+	ctx->label_replacement_pending = false;
+	label = aa_current_raw_label();
+	if (!label_is_stale(label))
+		return;
+	label = aa_get_newest_label(label);
+	aa_replace_current_label(label);
+	aa_put_label(label);
+}
+
+/* replace the current task's stale label on syscall return */
+void aa_schedule_stale_label_replacement(void)
+{
+	struct aa_task_ctx *ctx = task_ctx(current);
+
+	if (ctx->label_replacement_pending)
+		return;
+	init_task_work(&ctx->label_replacement_tw, aa_replace_stale_label_tw_func);
+	if (task_work_add(current, &ctx->label_replacement_tw, TWA_RESUME) == 0)
+		ctx->label_replacement_pending = true;
+}
+
 
 /**
  * aa_set_current_onexec - set the tasks change_profile to happen onexec
author maintainer
#18 lore raw

PATCH 18/403 apparmor: fix out-of-bounds write when null terminating a label vec

In reply to Greg Kroah-Hartman

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

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

From: Hyunwoo Kim <[email protected]>

commit 9f1e40193eef7f047e6b77cfb4b4cafdecd7a123 upstream.

aa_vec_unique() null terminates at vec[n - dups] when VEC_FLAG_TERMINATE is passed. If the components are all distinct no duplicates are dropped, dups is 0 and the terminator goes to vec[n], so the caller has to provide room for n + 1 entries.

aa_label_strn_parse() sets up its vector with vec_setup(profile, vec, len, gfp) and then calls aa_vec_unique(vec, len, VEC_FLAG_TERMINATE), but vec_setup() does not reserve the terminator entry. Up to LOCAL_VEC_ENTRIES it uses the local array of LOCAL_VEC_ENTRIES pointers, above that it allocates exactly len pointers. The terminator therefore lands one entry past the end of the local array when len is LOCAL_VEC_ENTRIES, and one entry past the end of the allocation when len is larger.

len comes from the number of "//&" separated components in the label name and label_count_strn_entries() does not bound it. An unprivileged task reaches the parse by writing to /proc/self/attr/apparmor/current or through lsm_set_self_attr(2), both of which go through do_setattr(), and the name is parsed before the change_profile permission is checked.
The query_label() path behind the securityfs .access file, which is mode 0666, performs no permission check at all. Every component has to resolve to a loaded profile, so a system with policy loaded is required.

The other two VEC_FLAG_TERMINATE users work on a label vec that aa_label_alloc() has already sized with "+ 1 for null terminator entry on vec". Reserve the same entry in vec_setup() and DEFINE_VEC(). Passing len + 1 from the caller instead would move len == LOCAL_VEC_ENTRIES out of the local array and into kzalloc().

Fixes f1bd904175e8 ("apparmor: add the base fns() for domain labels")
---
 security/apparmor/include/label.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
security/apparmor/include/label.h +3 -3
@@ -22,7 +22,7 @@ struct aa_ns;
 
 #define LOCAL_VEC_ENTRIES 8
 #define DEFINE_VEC(T, V)						\
-	struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES];	\
+	struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES + 1];	\
 	struct aa_ ## T **(V)
 
 #define vec_setup(T, V, N, GFP)						\
@@ -30,10 +30,10 @@ struct aa_ns;
 	if ((N) <= LOCAL_VEC_ENTRIES) {					\
 		typeof(N) i;						\
 		(V) = (_ ## V ## _localtmp);				\
-		for (i = 0; i < (N); i++)				\
+		for (i = 0; i <= (N); i++)				\
 			(V)[i] = NULL;					\
 	} else								\
-		(V) = kzalloc(sizeof(struct aa_ ## T *) * (N), (GFP));	\
+		(V) = kzalloc_objs(struct aa_ ## T *, (N) + 1, (GFP));	\
 	(V) ? 0 : -ENOMEM;						\
 })
 
author maintainer
#19 lore raw

PATCH 19/403 include/linux/list.h: mark list_add and __list_add as __always_inline

In reply to Greg Kroah-Hartman

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

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

From: Jordan R Abrahams-Whitehead <[email protected]>

commit 2780860eddecba9ffe210bb9436eee3cf22bfcdd upstream.

This commit resolves an issue where modpost section verification fails due to section mismatches between list_add and its callers.

At present, list_add (and its internal __list_add) are called from both .text and .init code sections. Since inlining can vary per call site, list_add can be 4 different states:

list_add in text with arguments to non-.init.data values list_add in init with arguments to static .init.data values list_add in init with arguments to non-.init.data values list_add in text with arguments to static .init.data values

It is last instance that ends up causing the section mismatch caused by constant propagation of the address of static libs inside the dir_add as seen below (with the dir_list being defined statically in initramfs.c, resting in .init.data).

WARNING: modpost: vmlinux.o: section mismatch in reference: __list_add (section: .text.unlikely.) -> dir_list (section: .init.data)

Because of these section matching requirements, semantically, __list_add and list_add MUST be inlined. This will then ensure callers inside .init will receive a list_add that exists and refers to only .init data, and list_add code in .text sections will only refer to non-init data.

This issue manifests predominently in AutoFDO with clang, which is very hesitant to inline cold functions such as list_add even when marked inline. Marking them as __always_inline therefore matches the existing semantic constraints imposed by modpost's section mismatch checks.

---
 include/linux/list.h |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
include/linux/list.h +11 -4
@@ -142,10 +142,13 @@ static inline bool __list_del_entry_vali
  *
  * This is only for internal list manipulation where we know
  * the prev/next entries already!
+ *
+ * Must be inlined to ensure it can be safely called
+ * with initdata arguments.
  */
-static inline void __list_add(struct list_head *new,
-			      struct list_head *prev,
-			      struct list_head *next)
+static __always_inline void __list_add(struct list_head *new,
+				       struct list_head *prev,
+				       struct list_head *next)
 {
 	if (!__list_add_valid(new, prev, next))
 		return;
@@ -163,8 +166,12 @@ static inline void __list_add(struct lis
  *
  * Insert a new entry after the specified head.
  * This is good for implementing stacks.
+ *
+ * Must be inlined to ensure it can be safely called
+ * with initdata arguments.
  */
-static inline void list_add(struct list_head *new, struct list_head *head)
+static __always_inline void list_add(struct list_head *new,
+				     struct list_head *head)
 {
 	__list_add(new, head, head->next);
 }
author maintainer
#20 lore raw

PATCH 20/403 mm/kmemleak: avoid soft lockup when scanning task stacks

In reply to Greg Kroah-Hartman

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

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

From: Breno Leitao <[email protected]>

commit 5d10d4e19e6daa487f0cd0ea6cba472325de92f9 upstream.

Patch series "mm/kmemleak: avoid soft lockup when scanning task", v3.

kmemleak_scan() scans every task stack under one rcu_read_lock() with no reschedule point, which can trip the soft lockup watchdog on hosts with very many threads.

That prints the following message, depending on the workload+host configuration:

      watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
       scan_block
       kmemleak_scan
       kmemleak_scan_thread
       kthread

Patch 1 walks the tasks with find_ge_pid() so the scan reschedules between tasks

Patches 2-3 let the scan loops stop early once a scan is interrupted.

This patch (of 3):

kmemleak_scan() walks every thread and scans its kernel stack under a single rcu_read_lock() with no reschedule point. On a host with very many threads -- amplified by KASAN/lockdep in debug builds -- this loop can hog a CPU long enough to trip the soft lockup watchdog:

  watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
   scan_block
   kmemleak_scan
   kmemleak_scan_thread
   kthread

A cond_resched() cannot be added directly: the loop runs inside an RCU read-side critical section.

Walk the tasks one PID at a time with find_ge_pid(), taking the RCU read lock only to look up and pin each task. The stack is then scanned with no lock held, so cond_resched() runs between tasks and the scan stops early on scan_should_stop(). This follows the next_tgid()/task_seq_get_next() iteration pattern and keeps each RCU critical section short.

---
 mm/kmemleak.c |   51 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 13 deletions(-)
mm/kmemleak.c +38 -13
@@ -1671,6 +1671,42 @@ unlock_put:
 }
 
 /*
+ * Scan all task kernel stacks, rescheduling between tasks. Each task is looked
+ * up and pinned within its own RCU read-side section, so no lock is held across
+ * the scan and the walk cannot trip the soft lockup watchdog.
+ */
+static void kmemleak_scan_task_stacks(void)
+{
+	struct pid *pid;
+	int nr = 1;
+
+	do {
+		struct task_struct *p = NULL;
+
+		rcu_read_lock();
+		pid = find_ge_pid(nr, &init_pid_ns);
+		if (pid) {
+			nr = pid_nr(pid) + 1;
+			p = pid_task(pid, PIDTYPE_PID);
+			if (p)
+				get_task_struct(p);
+		}
+		rcu_read_unlock();
+
+		if (p) {
+			void *stack = try_get_task_stack(p);
+
+			if (stack) {
+				scan_block(stack, stack + THREAD_SIZE, NULL);
+				put_task_stack(p);
+			}
+			put_task_struct(p);
+		}
+		cond_resched();
+	} while (pid && !scan_should_stop());
+}
+
+/*
  * Scan data sections and all the referenced memory blocks allocated via the
  * kernel's standard allocators. This function must be called with the
  * scan_mutex held.
@@ -1761,19 +1797,8 @@ static void kmemleak_scan(void)
 	/*
 	 * Scanning the task stacks (may introduce false negatives).
 	 */
-	if (kmemleak_stack_scan) {
-		struct task_struct *p, *g;
-
-		rcu_read_lock();
-		for_each_process_thread(g, p) {
-			void *stack = try_get_task_stack(p);
-			if (stack) {
-				scan_block(stack, stack + THREAD_SIZE, NULL);
-				put_task_stack(p);
-			}
-		}
-		rcu_read_unlock();
-	}
+	if (kmemleak_stack_scan)
+		kmemleak_scan_task_stacks();
 
 	/*
 	 * Scan the objects already referenced from the sections scanned
author maintainer
#21 lore raw

PATCH 21/403 mm/migrate: report RCU-tasks quiescent states in migrate_pages_batch()

In reply to Greg Kroah-Hartman

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

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

From: Breno Leitao <[email protected]>

commit efe8f86c0916f0f74eea74ae21a3b37f728c6bad upstream.

migrate_pages_batch() unmaps each folio before moving it, and every unmap runs the mmu_notifier invalidate callbacks. On KVM hosts try_to_migrate() ends up in kvm_mmu_notifier_invalidate_range_start() -> tdp_mmu_zap_leafs(), which is expensive, so unmapping a large batch keeps the CPU busy for a long time.

The loop already calls cond_resched(), but on PREEMPTION kernels that is a no-op, and involuntary preemption is not a Tasks-RCU quiescent state.

A long batch therefore never reports a quiescent state, and the migrating task (e.g. kcompactd) becomes a Tasks-RCU holdout, stalling the Tasks-RCU grace period for minutes, which is common at Meta fleet:

  INFO: rcu_tasks detected stalls on tasks:
  0000000055349ecc: .. nvcsw: 1157401/1157401 holdout: 1 idle_cpu: -1/56 task:kcompactd0      state:R  running task
  Call Trace:
   tdp_mmu_zap_leafs
   tdp_mmu_next_root
   gfn_to_pfn_cache_invalidate_start
   kvm_mmu_notifier_invalidate_range_start
   __mmu_notifier_invalidate_range_start
   try_to_migrate_one
   try_to_migrate
   migrate_pages_batch
   migrate_pages
   compact_zone
   compact_node
   kcompactd
   kthread

Use cond_resched_tasks_rcu_qs() so a quiescent state is reported even when cond_resched() does nothing.

This has also been discussed at [1]

---
 mm/migrate.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/migrate.c +1 -1
@@ -1743,7 +1743,7 @@ static int migrate_pages_batch(struct li
 			is_thp = is_large && folio_test_pmd_mappable(folio);
 			nr_pages = folio_nr_pages(folio);
 
-			cond_resched();
+			cond_resched_tasks_rcu_qs();
 
 			/*
 			 * The rare folio on the deferred split list should
author maintainer
#22 lore raw

PATCH 22/403 mm/migrate: use huge_ptep_get() in remove_migration_pte()

In reply to Greg Kroah-Hartman

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

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

From: Dev Jain <[email protected]>

commit ac1ec50d71b953524100ddc09057ee61a3dfaff3 upstream.

remove_migration_pte() converts migration entries back to present PTEs after folio migration completes. For hugetlb folios, page_vma_mapped_walk() returns the pte pointer to the hugetlb folio in pvmw.pte, but the code reads it with ptep_get().

On arches which provide their own huge_ptep_get() to dereference a huge pte pointer, accessing via ptep_get() would cause pte_pfn(), pte_present() etc to misbehave.

It is not clear whether this has a trivially visible effect to userspace.

Use huge_ptep_get() to dereference a huge pte pointer.

Fixes 290408d4a250 ("hugetlb: hugepage migration core")
Cc Alistair Popple <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Anshuman Khandual <[email protected]>
Cc Byungchul Park <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Gregory Price <[email protected]>
Cc Harry Yoo <[email protected]>
Cc "Huang, Ying" <[email protected]>
Cc Jann Horn <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Joshua Hahn <[email protected]>
Cc Jun'ichi "Nick" Nomura <[email protected]>
Cc Kiryl Shutsemau <[email protected]>
Cc Lance Yang <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Matthew Brost <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Naoya Horiguchi <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Rakie Kim <[email protected]>
Cc Ralph Campbell <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
Cc Zi Yan <[email protected]>
---
 mm/migrate.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
mm/migrate.c +5 -1
@@ -313,7 +313,11 @@ static bool remove_migration_pte(struct
 			continue;
 		}
 #endif
-		old_pte = ptep_get(pvmw.pte);
+		if (folio_test_hugetlb(folio))
+			old_pte = huge_ptep_get(vma->vm_mm, pvmw.address,
+						pvmw.pte);
+		else
+			old_pte = ptep_get(pvmw.pte);
 		if (rmap_walk_arg->map_unused_to_zeropage &&
 		    try_to_map_unused_to_zeropage(&pvmw, folio, old_pte, idx))
 			continue;
author maintainer
#23 lore raw

PATCH 23/403 mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()

In reply to Greg Kroah-Hartman

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

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

From: Ye Liu <[email protected]>

commit 90f095b816e25c6a9e4446d299bac5007fdcb3df upstream.

print_page_owner_memcg() reads page->memcg_data via READ_ONCE() at the start to guard against tail pages and NULL data. However, it later re-reads page->memcg_data locklessly in two places:

1: page_memcg_check(page)

2: PageMemcgKmem(page) (via folio_memcg_kmem(), which includes
VM_BUG_ON assertions for tail pages and MEMCG_DATA_OBJEXTS)

If the page is concurrently freed and reallocated as a THP tail page or slab page between these calls, the VM_BUG_ON assertions can trigger on CONFIG_DEBUG_VM=y builds, crashing the kernel.

Fix both TOCTOU issues by using the memcg_data snapshot throughout.

Fixes fcf8935832b8 ("mm/page_owner: print memcg information")
Cc Brendan Jackman <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc David Hildenbrand (Arm) <[email protected]>
---
 mm/page_owner.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
mm/page_owner.c +7 -3
@@ -501,6 +501,7 @@ static inline int print_page_owner_memcg
 {
 #ifdef CONFIG_MEMCG
 	unsigned long memcg_data;
+	struct obj_cgroup *objcg;
 	struct mem_cgroup *memcg;
 	bool online;
 	char name[80];
@@ -510,11 +511,14 @@ static inline int print_page_owner_memcg
 	if (!memcg_data)
 		goto out_unlock;
 
-	if (memcg_data & MEMCG_DATA_OBJEXTS)
+	if (memcg_data & MEMCG_DATA_OBJEXTS) {
 		ret += scnprintf(kbuf + ret, count - ret,
 				"Slab cache page\n");
+		goto out_unlock;
+	}
 
-	memcg = page_memcg_check(page);
+	objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
+	memcg = objcg ? obj_cgroup_memcg(objcg) : NULL;
 	if (!memcg)
 		goto out_unlock;
 
@@ -522,7 +526,7 @@ static inline int print_page_owner_memcg
 	cgroup_name(memcg->css.cgroup, name, sizeof(name));
 	ret += scnprintf(kbuf + ret, count - ret,
 			"Charged %sto %smemcg %s\n",
-			PageMemcgKmem(page) ? "(via objcg) " : "",
+			(memcg_data & MEMCG_DATA_KMEM) ? "(via objcg) " : "",
 			online ? "" : "offline ",
 			name);
 out_unlock:
#24 lore raw

Re: [PATCH 6.12 023/403] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()

Hi Greg/Sasha,

Quoted 3 lines · Greg Kroah-Hartman

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

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

...

Quoted 21 lines
---
  mm/page_owner.c |   10 +++++++---
  1 file changed, 7 insertions(+), 3 deletions(-)
mm/page_owner.c +1 -0
@@ -501,6 +501,7 @@ static inline int print_page_owner_memcg
  {
  #ifdef CONFIG_MEMCG
  	unsigned long memcg_data;
+	struct obj_cgroup *objcg;
  	struct mem_cgroup *memcg;
  	bool online;
  	char name[80];
@@ -510,11 +511,14 @@ static inline int print_page_owner_memcg
  	if (!memcg_data)
  		goto out_unlock;
 

mm/page_owner.c static inline int print_page_owner_memcg · line 521

Quoted 10 lines
mm/page_owner.c +5 -2
-	if (memcg_data & MEMCG_DATA_OBJEXTS)
+	if (memcg_data & MEMCG_DATA_OBJEXTS) {
  		ret += scnprintf(kbuf + ret, count - ret,
  				"Slab cache page\n");
+		goto out_unlock;
+	}
 
-	memcg = page_memcg_check(page);
+	objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
+	memcg = objcg ? obj_cgroup_memcg(objcg) : NULL;

I have run an AI-assisted backport review and it spotted an issue.
I checked the finding against stablerc/linux-6.12.y and the report looks reasonable to me.

Upstream commit: 90f095b816e2 ("mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()") can decode every non-slab memcg_data value as an obj_cgroup pointer because earlier commit:
f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of dying memory cgroup for LRU folios") changed the representation for LRU folios.

The 6.12.y representation is different. commit_charge() stores a struct mem_cgroup pointer for an non-kmem folio, while only MEMCG_DATA_KMEM denotes a struct obj_cgroup pointer. The backport does:

    objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
    memcg = objcg ? obj_cgroup_memcg(objcg) : NULL;

It therefore interprets a normal struct mem_cgroup as struct obj_cgroup and dereferences the wrong layout. A page_owner read can report bogus data or fault.

The missing commit: f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of dying memory cgroup for LRU folios") is a large memcg representation change and is not suitable as an implicit dependency for this small fix. I would suggest dropping commit:
5672bba8d5d6 ("mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()") and replacing it with a 6.12-specific decoder that tests MEMCG_DATA_KMEM. Thoughts?

thanks,
Harshit

Quoted 15 lines
mm/page_owner.c +1 -1
  	if (!memcg)
  		goto out_unlock;
 
@@ -522,7 +526,7 @@ static inline int print_page_owner_memcg
  	cgroup_name(memcg->css.cgroup, name, sizeof(name));
  	ret += scnprintf(kbuf + ret, count - ret,
  			"Charged %sto %smemcg %s\n",
-			PageMemcgKmem(page) ? "(via objcg) " : "",
+			(memcg_data & MEMCG_DATA_KMEM) ? "(via objcg) " : "",
  			online ? "" : "offline ",
  			name);
  out_unlock:
maintainer
#25 lore raw

Re: [PATCH 6.12 023/403] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()

Quoted 4 lines

I would suggest dropping commit: 5672bba8d5d6 ("mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()") and replacing it with a 6.12-specific decoder that tests MEMCG_DATA_KMEM. Thoughts?

Dropped from 6.12 and 6.18, thanks. Kept in 7.2, which already has f1cf8d2f36dc so the obj_cgroup decoding is correct there.

Signature · 2 lines
Thanks,
Sasha
author maintainer
#26 lore raw

PATCH 24/403 mm/page_vma_mapped: use huge_ptep_get() for hugetlb

In reply to Greg Kroah-Hartman

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

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

From: Dev Jain <[email protected]>

commit e87df0d5d6962bde50f55f6d02b779daa394f894 upstream.

check_pte() is the final validation step in page_vma_mapped_walk(). It reads pvmw->pte with ptep_get() to decide whether the entry maps the PFN range being walked. For hugetlb VMAs, that pointer refers to a hugetlb entry.

On arches which provide their own huge_ptep_get() to dereference a huge pte pointer, accessing via ptep_get() would cause pte_pfn(), pte_present() etc to misbehave.

It is not clear whether this has a trivially visible effect to userspace.

Use huge_ptep_get() to dereference a huge pte pointer.

Fixes ace71a19cec5 ("mm: introduce page_vma_mapped_walk()")
Cc Alistair Popple <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Anshuman Khandual <[email protected]>
Cc Byungchul Park <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Gregory Price <[email protected]>
Cc Harry Yoo <[email protected]>
Cc "Huang, Ying" <[email protected]>
Cc Jann Horn <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Joshua Hahn <[email protected]>
Cc Jun'ichi "Nick" Nomura <[email protected]>
Cc Kiryl Shutsemau <[email protected]>
Cc Lance Yang <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Matthew Brost <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Naoya Horiguchi <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Rakie Kim <[email protected]>
Cc Ralph Campbell <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
Cc Zi Yan <[email protected]>
---
 mm/page_vma_mapped.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
mm/page_vma_mapped.c +7 -1
@@ -97,7 +97,13 @@ static bool map_pte(struct page_vma_mapp
 static bool check_pte(struct page_vma_mapped_walk *pvmw, unsigned long pte_nr)
 {
 	unsigned long pfn;
-	pte_t ptent = ptep_get(pvmw->pte);
+	pte_t ptent;
+
+	if (is_vm_hugetlb_page(pvmw->vma))
+		ptent = huge_ptep_get(pvmw->vma->vm_mm, pvmw->address,
+				      pvmw->pte);
+	else
+		ptent = ptep_get(pvmw->pte);
 
 	if (pvmw->flags & PVMW_MIGRATION) {
 		swp_entry_t entry;
author maintainer
#27 lore raw

PATCH 25/403 mm/vmscan: report RCU-tasks quiescent states in shrink_lruvec()

In reply to Greg Kroah-Hartman

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

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

From: Breno Leitao <[email protected]>

commit 25f52e81216884a7444bf07a606691feb09a94e3 upstream.

I am seeing some rcu_tasks stalls in the Meta fleet during reclaim.

  INFO: rcu_tasks detected stalls on tasks:
	0000000088620d09: .. nvcsw: 6735/6735 holdout: 1 idle_cpu: -1/8
	task:GlobalCPUThread state:R  running task  pid:2552016 tgid:2524552
  Call Trace:
   shrink_lruvec
   mem_cgroup_iter
   shrink_node
   do_try_to_free_pages
   try_to_free_pages
   __alloc_frozen_pages_noprof
   alloc_pages_noprof
   pte_alloc_one
   __pte_alloc
   handle_mm_fault

Nothing promises direct reclaim returns in bounded time, and the scan loop in shrink_lruvec() only calls cond_resched(), which is a no-op on PREEMPTION kernels. Involuntary preemption is not a Tasks-RCU quiescent state, so the reclaiming task never reports one and becomes a holdout.

Upgrade it to cond_resched_tasks_rcu_qs(), which reports a quiescent state even when cond_resched() does nothing.

PS: This has been discussed in [1]

---
 mm/vmscan.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/vmscan.c +1 -1
@@ -5761,7 +5761,7 @@ static void shrink_lruvec(struct lruvec
 			}
 		}
 
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 
 		if (nr_reclaimed < nr_to_reclaim || proportional_reclaim)
 			continue;
author maintainer
#28 lore raw

PATCH 26/403 mm/zswap: fix global shrinker when memory cgroup is disabled

In reply to Greg Kroah-Hartman

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

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

From: Hao Jia <[email protected]>

commit dc8458f43fe964d8ade74c9b0fce54fe71d156de upstream.

Patch series "mm/zswap: Fixes and improves the zswap shrink", v4.

This series fixes and improves the zswap global shrinker (shrink_worker()): Patch 1: Fix missing global shrinker when memory cgroup is disabled. Patch 2: Extend shrink_memcg() to support batch writeback and thereby improving the writeback efficiency in the shrink_worker() and zswap_store() paths.

This patch (of 2):

Zswap writeback when the global pool limit is hit fails when memory cgroup is disabled. The pool remains full until it is organically drained by swapins or memory freeing, leading to zswap store failures and pages bypassing getting written directly to the backing swap device, causing LRU inversion (hotter pages with higher fault latency).

This happens because mem_cgroup_iter() always returns NULL when memory cgroups are disabled. As a result, the global shrinker shrink_worker() repeatedly takes empty walks. After MAX_RECLAIM_RETRIES failed attempts, the worker gives up without writing back any pages.

Therefore, when memory cgroup is disabled, fall through with the !memcg branch and shrink the root memcg directly.

With memcg disabled, shrink_memcg() only returns -ENOENT when the root LRU is empty, which means the total pages are already below thr. In the absence of heavy concurrent zswap stores, the loop then safely bails out via the zswap_total_pages() <= thr check; otherwise, it will resume shrinking the memcg after processing the reschedule check. For any other return value from shrink_memcg(), the loop is guaranteed to terminate, either after MAX_RECLAIM_RETRIES failures or once the threshold is met.

This is a potential performance regression for people using zswap without memcg that was introduced by the commit in "Fixes".

---
 mm/zswap.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
mm/zswap.c +7 -6
@@ -1417,11 +1417,12 @@ static void shrink_worker(struct work_st
 		} while (memcg && !mem_cgroup_tryget_online(memcg));
 		spin_unlock(&zswap_shrink_lock);
 
-		if (!memcg) {
-			/*
-			 * Continue shrinking without incrementing failures if
-			 * we found candidate memcgs in the last tree walk.
-			 */
+		/*
+		 * A NULL memcg ends a full hierarchy pass (except when memcg is
+		 * disabled, where it is always NULL: fall through to the root LRU).
+		 * Count a failure only if the last pass found no candidates.
+		 */
+		if (!memcg && !mem_cgroup_disabled()) {
 			if (!attempts && ++failures == MAX_RECLAIM_RETRIES)
 				break;
 
@@ -1440,7 +1441,7 @@ static void shrink_worker(struct work_st
 		 * and failures.
 		 */
 		if (ret == -ENOENT)
-			continue;
+			goto resched;
 		++attempts;
 
 		if (ret && ++failures == MAX_RECLAIM_RETRIES)
author maintainer
#29 lore raw

PATCH 27/403 mm: memcg: stop reclaim when a limit update is superseded

In reply to Greg Kroah-Hartman

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

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

From: Guopeng Zhang <[email protected]>

commit 9477820c63cbf4d97114238f3d1ff10dfd6bee3f upstream.

kernfs serializes file operations only per open file, so separate open files can update the same memory.high or memory.max file concurrently. Both handlers store the new limit before synchronous reclaim, but continue to use the writer's local target in the reclaim loop. If another writer raises or removes the limit, the first writer can continue reclaiming toward a stale target.

For memory.max, this can leave the writer looping indefinitely once reclaim retries are exhausted. The OOM path sees sufficient margin under the current limit and returns true without killing, while the writer still compares usage against its stale target and records another OOM event.

Check the current limit at the start of each reclaim iteration and stop if it no longer matches the writer's target.

Reproducer:

Populate a cgroup with anonymous memory and disable swapping. Lower memory.max from one open file, then restore it to "max" through another open file after the new limit becomes visible.

Without the patch, the first writer remains blocked and repeatedly increments the OOM event counter. With the patch, it returns normally.

This was not motivated by a reported production workload. We found it through automated randomized testing for our cgroup observability work and reduced it to the reproducer above.

Fixes 8c8c383c04f6 ("mm: memcontrol: try harder to set a new memory.high")
Fixes b6e6edcfa405 ("mm: memcontrol: reclaim and OOM kill when shrinking memory.max below usage")
Cc Michal Hocko <[email protected]>
Cc Muchun Song <[email protected]>
Cc Roman Gushchin <[email protected]>
Cc Shakeel Butt <[email protected]>
---
 mm/memcontrol.c |    6 ++++++
 1 file changed, 6 insertions(+)
mm/memcontrol.c +6 -0
@@ -4090,6 +4090,9 @@ static ssize_t memory_high_write(struct
 		unsigned long nr_pages = page_counter_read(&memcg->memory);
 		unsigned long reclaimed;
 
+		if (high != READ_ONCE(memcg->memory.high))
+			break;
+
 		if (nr_pages <= high)
 			break;
 
@@ -4138,6 +4141,9 @@ static ssize_t memory_max_write(struct k
 	for (;;) {
 		unsigned long nr_pages = page_counter_read(&memcg->memory);
 
+		if (max != READ_ONCE(memcg->memory.max))
+			break;
+
 		if (nr_pages <= max)
 			break;
 
author maintainer
#30 lore raw

PATCH 28/403 mm: mempolicy: fix automatic numa balancing for shmem

In reply to Greg Kroah-Hartman

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

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

From: Johannes Weiner <[email protected]>

commit d230991493b521eeff39f32434fddcbcdb109eb0 upstream.

Neha reports that mapped shmem aren't considered for NUMA balancing, noting convergence problems and bandwidth bottlenecking for cachelib based workloads on tiered memory systems.

Looking at the code and going through the git history, this doesn't actually seem intentional:

Commit fc3147245d19 ("mm: numa: Limit NUMA scanning to migrate-on-fault VMAs") added a vma_policy_mof() gate to task_numa_work() so VMAs whose policy lacks MPOL_F_MOF are skipped from NUMA balancing scans. The motivation was a real usecase: Oracle was pinning shared segments with mbind(MPOL_BIND) so trapping faults was both expensive and pointless.

The handling of NULL from vm_ops->get_policy, however, treated "user explicitly opted out" the same as "user never specified anything." For VMAs whose shared policy is absent - the common case for shmem - the scan was disabled too.

This issue is old. It probably hurts less in conventional NUMA. But it's very noticeable on tiered systems, where entire tmpfs workingsets can get stuck on lower-bandwidth memory.

Fix this by having vma_policy_mof() use __get_vma_policy() directly, and thereby handle the fallback to task policy (-> preferred_node_policy() has MPOL_F_MOF per default). Every other consumer of vm_ops->get_policy already handles it this way, the scan-eligibility check was the outlier.

This preserves Mel's intended fix: don't scan stuff the user explicitly pinned. But allow default policy vmas to participate in balancing.

---
 mm/mempolicy.c |   21 ++++++---------------
 1 file changed, 6 insertions(+), 15 deletions(-)
mm/mempolicy.c +6 -15
@@ -1838,24 +1838,15 @@ struct mempolicy *get_vma_policy(struct
 bool vma_policy_mof(struct vm_area_struct *vma)
 {
 	struct mempolicy *pol;
+	pgoff_t ilx;
+	bool mof;
 
-	if (vma->vm_ops && vma->vm_ops->get_policy) {
-		bool ret = false;
-		pgoff_t ilx;		/* ignored here */
-
-		pol = vma->vm_ops->get_policy(vma, vma->vm_start, &ilx);
-		if (pol && (pol->flags & MPOL_F_MOF))
-			ret = true;
-		mpol_cond_put(pol);
-
-		return ret;
-	}
-
-	pol = vma->vm_policy;
+	pol = __get_vma_policy(vma, vma->vm_start, &ilx);
 	if (!pol)
 		pol = get_task_policy(current);
-
-	return pol->flags & MPOL_F_MOF;
+	mof = pol->flags & MPOL_F_MOF;
+	mpol_cond_put(pol);
+	return mof;
 }
 
 bool apply_policy_zone(struct mempolicy *policy, enum zone_type zone)
author maintainer
#31 lore raw

PATCH 29/403 tools/compiler: match glibc 2.42 definition of __attribute_const__

In reply to Greg Kroah-Hartman

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

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

From: Joy H.J. Lee <[email protected]>

commit 8700a4761beb219873956666cf91776a2c61e698 upstream.

glibc 2.42 added __attribute_const__ to sys/cdefs.h:

    # define __attribute_const__ __attribute__ ((__const__))

GCC 15 warns when a macro is redefined to a different replacement list (-Wbuiltin-macro-redefined). Since host tool Makefiles (resolve_btfids, objtool) pass -Werror, this conflict becomes fatal.

The warning is suppressed on standard native builds because GCC treats /usr/include as a system header path (-isystem), and macro-redefinition warnings from system headers are silently suppressed by GCC. It fires when glibc headers are on a regular include path (-I) instead, which is the case in cross-compilation setups such as NixOS, where the sysroot's glibc is passed explicitly via -I rather than -isystem.

Per (C11 6.10.3), identical replacement lists are accepted silently. Match the glibc definition exactly, including the space before "((", so the redefinition is accepted without warning regardless of whether glibc headers are treated as system or non-system includes.

---
 tools/include/linux/compiler.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/include/linux/compiler.h +1 -1
@@ -97,7 +97,7 @@
 #define __read_mostly
 
 #ifndef __attribute_const__
-# define __attribute_const__
+# define __attribute_const__ __attribute__ ((__const__))
 #endif
 
 #ifndef __maybe_unused
author maintainer
#32 lore raw

PATCH 30/403 x86/tdx: Fix off-by-one in port I/O handling

In reply to Greg Kroah-Hartman

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

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

From: Kiryl Shutsemau (Meta) <[email protected]>

commit 0f63e656b1c679d32ac595de29d10c03efca6a25 upstream.

handle_in() and handle_out() in arch/x86/coco/tdx/tdx.c use:

    u64 mask = GENMASK(BITS_PER_BYTE * size, 0);

GENMASK(h, l) includes bit h. For size=1 (INB), this produces GENMASK(8, 0) = 0x1FF (9 bits) instead of GENMASK(7, 0) = 0xFF (8 bits). The mask is one bit too wide for all I/O sizes.

Fix the mask calculation.

---
 arch/x86/coco/tdx/tdx.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/coco/tdx/tdx.c +2 -2
@@ -606,7 +606,7 @@ static bool handle_in(struct pt_regs *re
 		.r13 = PORT_READ,
 		.r14 = port,
 	};
-	u64 mask = GENMASK(BITS_PER_BYTE * size, 0);
+	u64 mask = GENMASK(BITS_PER_BYTE * size - 1, 0);
 	bool success;
 
 	/*
@@ -626,7 +626,7 @@ static bool handle_in(struct pt_regs *re
 
 static bool handle_out(struct pt_regs *regs, int size, int port)
 {
-	u64 mask = GENMASK(BITS_PER_BYTE * size, 0);
+	u64 mask = GENMASK(BITS_PER_BYTE * size - 1, 0);
 
 	/*
 	 * Emulate the I/O write via hypercall. More info about ABI can be found
author maintainer
#33 lore raw

PATCH 31/403 x86/insn-eval: Move assign_register() out of KVM as insn_assign_reg()

In reply to Greg Kroah-Hartman

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

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

From: Kiryl Shutsemau (Meta) <[email protected]>

commit 1fe104b048d77d6cb25bd938e6a67450fb50e61d upstream.

KVM's instruction emulator has a small helper, assign_register(), that writes a value into a register following the x86 rules for writes to general-purpose registers: an 8- or 16-bit write leaves the rest of the register untouched, a 32-bit write zero-extends the result to 64 bits, and a 64-bit write replaces the whole register.

The TDX guest #VE handler needs the same logic for port I/O emulation to get 32-bit zero-extension right. Rather than add a third copy of the same switch, move the helper verbatim to <asm/insn-eval.h>, rename it to insn_assign_reg(), and route KVM's callers through it.

Add <asm/insn.h> to the header's includes so it builds standalone in callers that have not pulled it in transitively.

No functional change.

---
 arch/x86/include/asm/insn-eval.h |   36 ++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/emulate.c           |   26 ++++----------------------
 2 files changed, 40 insertions(+), 22 deletions(-)
arch/x86/include/asm/insn-eval.h +36 -0
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/bug.h>
 #include <linux/err.h>
+#include <asm/insn.h>
 #include <asm/ptrace.h>
 
 #define INSN_CODE_SEG_ADDR_SZ(params) ((params >> 4) & 0xf)
@@ -44,4 +45,39 @@ enum insn_mmio_type {
 
 enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes);
 
+/*
+ * Write @val into *@reg following the x86 rules for writes to
+ * general-purpose registers (Intel SDM Vol. 1, "General-Purpose
+ * Registers in 64-Bit Mode"): an 8- or 16-bit write leaves the rest of
+ * the register untouched, a 32-bit write zero-extends the result into
+ * the upper 32 bits, and a 64-bit write replaces the whole register.
+ *
+ * @bytes is the width of the write, not a property of the instruction:
+ * an instruction that, say, sign-extends a 32-bit immediate into a
+ * 64-bit register does a 64-bit write here.
+ *
+ * @reg need not be 8-byte aligned: KVM's instruction emulator offsets
+ * the pointer by one byte to address the high-byte registers (AH, CH,
+ * DH, BH).  Use narrow stores for the sub-word cases so the access
+ * width matches @bytes and the adjacent bytes are left alone.
+ */
+static inline void insn_assign_reg(unsigned long *reg, u64 val, int bytes)
+{
+	switch (bytes) {
+	case 1:
+		*(u8 *)reg = (u8)val;
+		break;
+	case 2:
+		*(u16 *)reg = (u16)val;
+		break;
+	case 4:
+		/* A 32-bit write zero-extends into the upper 32 bits. */
+		*reg = (u32)val;
+		break;
+	case 8:
+		*reg = val;
+		break;
+	}
+}
+
 #endif /* _ASM_X86_INSN_EVAL_H */
arch/x86/kvm/emulate.c +4 -22
@@ -24,6 +24,7 @@
 #include "kvm_emulate.h"
 #include <linux/stringify.h>
 #include <asm/debugreg.h>
+#include <asm/insn-eval.h>
 #include <asm/nospec-branch.h>
 #include <asm/ibt.h>
 
@@ -489,25 +490,6 @@ static void assign_masked(ulong *dest, u
 	*dest = (*dest & ~mask) | (src & mask);
 }
 
-static void assign_register(unsigned long *reg, u64 val, int bytes)
-{
-	/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
-	switch (bytes) {
-	case 1:
-		*(u8 *)reg = (u8)val;
-		break;
-	case 2:
-		*(u16 *)reg = (u16)val;
-		break;
-	case 4:
-		*reg = (u32)val;
-		break;	/* 64b: zero-extend */
-	case 8:
-		*reg = val;
-		break;
-	}
-}
-
 static inline unsigned long ad_mask(struct x86_emulate_ctxt *ctxt)
 {
 	return (1UL << (ctxt->ad_bytes << 3)) - 1;
@@ -555,7 +537,7 @@ register_address_increment(struct x86_em
 {
 	ulong *preg = reg_rmw(ctxt, reg);
 
-	assign_register(preg, *preg + inc, ctxt->ad_bytes);
+	insn_assign_reg(preg, *preg + inc, ctxt->ad_bytes);
 }
 
 static void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc)
@@ -1781,7 +1763,7 @@ static int load_segment_descriptor(struc
 
 static void write_register_operand(struct operand *op)
 {
-	return assign_register(op->addr.reg, op->val, op->bytes);
+	return insn_assign_reg(op->addr.reg, op->val, op->bytes);
 }
 
 static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
@@ -2014,7 +1996,7 @@ static int em_popa(struct x86_emulate_ct
 		rc = emulate_pop(ctxt, &val, ctxt->op_bytes);
 		if (rc != X86EMUL_CONTINUE)
 			break;
-		assign_register(reg_rmw(ctxt, reg), val, ctxt->op_bytes);
+		insn_assign_reg(reg_rmw(ctxt, reg), val, ctxt->op_bytes);
 		--reg;
 	}
 	return rc;
author maintainer
#34 lore raw

PATCH 32/403 x86/tdx: Fix zero-extension for 32-bit port I/O

In reply to Greg Kroah-Hartman

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

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

From: Kiryl Shutsemau (Meta) <[email protected]>

commit 941370fc93cc3474e26811f4d3b062903eefe2cf upstream.

According to x86 architecture rules, 32-bit operations zero-extend the result to 64 bits. The current implementation of handle_in() only masks the lower 32 bits, which preserves the upper 32 bits of RAX when a 32-bit port IN instruction is emulated.

Use insn_assign_reg() to write the result back into RAX with proper partial-register-write semantics: 1- and 2-byte forms leave the upper bits untouched, the 4-byte form zero-extends to the full register.

---
 arch/x86/coco/tdx/tdx.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
arch/x86/coco/tdx/tdx.c +3 -5
@@ -606,8 +606,8 @@ static bool handle_in(struct pt_regs *re
 		.r13 = PORT_READ,
 		.r14 = port,
 	};
-	u64 mask = GENMASK(BITS_PER_BYTE * size - 1, 0);
 	bool success;
+	u64 val;
 
 	/*
 	 * Emulate the I/O read via hypercall. More info about ABI can be found
@@ -615,11 +615,9 @@ static bool handle_in(struct pt_regs *re
 	 * "TDG.VP.VMCALL<Instruction.IO>".
 	 */
 	success = !__tdx_hypercall(&args);
+	val = success ? args.r11 : 0;
 
-	/* Update part of the register affected by the emulated instruction */
-	regs->ax &= ~mask;
-	if (success)
-		regs->ax |= args.r11 & mask;
+	insn_assign_reg(&regs->ax, val, size);
 
 	return success;
 }
author maintainer
#35 lore raw

PATCH 33/403 hwtracing: hisi_ptt: Propagate DMA reset timeout in trace_start()

In reply to Greg Kroah-Hartman

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

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

From: Sanman Pradhan <[email protected]>

commit 75d42d990335322852ed5f7ce324b701c0949d79 upstream.

hisi_ptt_wait_dma_reset_done() discards the return value of readl_poll_timeout_atomic(). If the DMA engine does not complete its reset within the timeout, hisi_ptt_trace_start() proceeds to start tracing regardless.

Return a bool from hisi_ptt_wait_dma_reset_done(), consistent with the other wait helpers in this driver. On timeout, log an error, de-assert the reset bit, and return -ETIMEDOUT. Move ctrl->started to the successful path so a failed start does not leave the trace marked as active.

Fixes ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device")
---
 drivers/hwtracing/ptt/hisi_ptt.c |   20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/hwtracing/ptt/hisi_ptt.c +13 -7
@@ -171,13 +171,13 @@ static bool hisi_ptt_wait_trace_hw_idle(
 					  HISI_PTT_WAIT_TRACE_TIMEOUT_US);
 }
 
-static void hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt)
+static bool hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt)
 {
 	u32 val;
 
-	readl_poll_timeout_atomic(hisi_ptt->iobase + HISI_PTT_TRACE_WR_STS,
-				  val, !val, HISI_PTT_RESET_POLL_INTERVAL_US,
-				  HISI_PTT_RESET_TIMEOUT_US);
+	return !readl_poll_timeout_atomic(hisi_ptt->iobase + HISI_PTT_TRACE_WR_STS,
+					  val, !val, HISI_PTT_RESET_POLL_INTERVAL_US,
+					  HISI_PTT_RESET_TIMEOUT_US);
 }
 
 static void hisi_ptt_trace_end(struct hisi_ptt *hisi_ptt)
@@ -202,14 +202,18 @@ static int hisi_ptt_trace_start(struct h
 		return -EBUSY;
 	}
 
-	ctrl->started = true;
-
 	/* Reset the DMA before start tracing */
 	val = readl(hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
 	val |= HISI_PTT_TRACE_CTRL_RST;
 	writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
 
-	hisi_ptt_wait_dma_reset_done(hisi_ptt);
+	if (!hisi_ptt_wait_dma_reset_done(hisi_ptt)) {
+		pci_err(hisi_ptt->pdev, "timed out waiting for DMA reset\n");
+		val = readl(hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
+		val &= ~HISI_PTT_TRACE_CTRL_RST;
+		writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
+		return -ETIMEDOUT;
+	}
 
 	val = readl(hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
 	val &= ~HISI_PTT_TRACE_CTRL_RST;
@@ -234,6 +238,8 @@ static int hisi_ptt_trace_start(struct h
 	if (!hisi_ptt->trace_ctrl.is_port)
 		val |= HISI_PTT_TRACE_CTRL_FILTER_MODE;
 
+	ctrl->started = true;
+
 	/* Start the Trace */
 	val |= HISI_PTT_TRACE_CTRL_EN;
 	writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
author maintainer
#36 lore raw

PATCH 34/403 tracing/user_events: Clear copied tracing state before fork duplication

In reply to Greg Kroah-Hartman

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

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

From: Jérémy Jean <[email protected]>

commit 390f6bd8583d177029d9df4bea6667509e55a765 upstream.

dup_task_struct() copies user_event_mm from the parent into the child, without grabbing a reference to it. user_event_mm_dup() should replace it, but it leaves that copied pointer unmodified if user_event_mm_alloc() fails.

When the child exits, user_event_mm_remove() decrements a reference the child never owned, which ultimately frees user_event_mm, while the parent still as a stale pointer to it. This creates a UAF, which KASAN reports as:

    BUG: KASAN: slab-use-after-free in
    current_user_event_mm+0x51/0x1d0 Write of size 4 at addr
    ffff888005010d30 by task init/44

    Call Trace:
     <TASK>
     kasan_report+0xce/0x100
     kasan_check_range+0x10f/0x1e0
     current_user_event_mm+0x51/0x1d0
     user_events_ioctl+0x82e/0x15c0
     __x64_sys_ioctl+0x139/0x1c0
     do_syscall_64+0xce/0x450
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    Allocated by task 44:
     __kasan_kmalloc+0x8f/0xa0
     __kmalloc_cache_noprof+0x180/0x3a0
     user_event_mm_alloc+0x3c/0x1f0
     current_user_event_mm+0x88/0x1d0

    Freed by task 42:
     __kasan_slab_free+0x43/0x70
     kfree+0x13a/0x390
     process_one_work+0x696/0xf90
     worker_thread+0x420/0xba0

The fix simply clears the copied pointer before any possible failure. In case of failure, the child then has nothing to free.

Fixes 7235759084a4 ("tracing/user_events: Use remote writes for event enablement")
Assisted-by Codex:gpt-5
---
 kernel/trace/trace_events_user.c |    3 +++
 1 file changed, 3 insertions(+)
kernel/trace/trace_events_user.c +3 -0
@@ -868,6 +868,9 @@ void user_event_mm_dup(struct task_struc
 	struct user_event_mm *mm = user_event_mm_alloc(t);
 	struct user_event_enabler *enabler;
 
+	/* On failure, do not free parent's copy */
+	t->user_event_mm = NULL;
+
 	if (!mm)
 		return;
 
author maintainer
#37 lore raw

PATCH 35/403 tracing: Fix crash passing ERR_PTR to kthread_stop()

In reply to Greg Kroah-Hartman

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

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

From: Hui Su <[email protected]>

commit 649bc7df3e5d7be6f7996a95084037dbf3cad1e5 upstream.

event_test_stuff() calls kthread_run() and unconditionally passes the returned task_struct pointer to kthread_stop(). kthread_run() returns an error pointer such as ERR_PTR(-ENOMEM) when kthread creation fails, for example under memory pressure during the boot-time event self-test. kthread_stop() then dereferences the invalid pointer, crashing the kernel.

Check the result of kthread_run() before passing it to kthread_stop(). Use WARN_ON() so that a failure to create the self-test thread does not go unnoticed, matching the ring-buffer self-test fix in commit 91542863abad ("ring-buffer: Fix crash passing ERR_PTR to kthread_stop()").

Fixes e6187007d6c3 ("tracing/events: add startup tests for events")
---
 kernel/trace/trace_events.c |    2 ++
 1 file changed, 2 insertions(+)
kernel/trace/trace_events.c +2 -0
@@ -4385,6 +4385,8 @@ static __init void event_test_stuff(void
 	struct task_struct *test_thread;
 
 	test_thread = kthread_run(event_test_thread, NULL, "test-events");
+	if (WARN_ON(IS_ERR(test_thread)))
+		return;
 	msleep(1);
 	kthread_stop(test_thread);
 }
author maintainer
#38 lore raw

PATCH 36/403 tracing: Fix logged instance name on creation failure

In reply to Greg Kroah-Hartman

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

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

From: Vincent Donnefort <[email protected]>

commit a9a01be2834a529cbd490ccbab02643f0c1735f2 upstream.

When boot instance creation fails, the kernel incorrectly logs "(null)" as the instance name because strsep() consumes curr_str entirely during parsing.

Print the properly parsed name variable instead. And while at it log the error code.

---
 kernel/trace/trace.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/trace.c +2 -1
@@ -10431,7 +10431,8 @@ __init static void enable_instances(void
 
 		tr = trace_array_create_systems(name, NULL, addr, size);
 		if (IS_ERR(tr)) {
-			pr_warn("Tracing: Failed to create instance buffer %s\n", curr_str);
+			pr_warn("Tracing: Failed to create instance buffer '%s' (%ld)\n", name,
+				PTR_ERR(tr));
 			continue;
 		}
 
author maintainer
#39 lore raw

PATCH 37/403 tracing: Fix use-after-free in trace_pipe read on sub-buffer order change

In reply to Greg Kroah-Hartman

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

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

From: Deepanshu Kartikey <[email protected]>

commit 372f8534244d632ad5118e8a87a11291b01712d3 upstream.

Writing to buffer_subbuf_size_kb calls ring_buffer_subbuf_order_set(), which frees every sub-buffer of the ring buffer, including the reader page, and replaces them with newly allocated ones.

Readers of trace_pipe hold pointers into those pages. ring_buffer_peek() looks up an event under cpu_buffer->reader_lock but returns the event pointer after dropping the lock, and peek_next_entry() then calls ring_buffer_event_length() and ring_buffer_event_data() on it. If the sub-buffer order is changed in that window, the reader dereferences freed memory:

  BUG: KASAN: use-after-free in ring_buffer_peek+0x3e0/0x430
  Read of size 1 at addr ffff88802a4cf010 by task syz-executor989/6002

Freed by:

   free_buffer_page kernel/trace/ring_buffer.c:398 [inline]
   ring_buffer_subbuf_order_set+0x1325/0x18e0 kernel/trace/ring_buffer.c:7444
   buffer_subbuf_size_write+0x182/0x280 kernel/trace/trace.c:8221

Take trace_access_lock(RING_BUFFER_ALL_CPUS) around the order change. This is the lock trace_pipe readers already hold across their entire peek-and-print loop, so the swap can no longer race with a reader that is dereferencing a peeked event.

---
 kernel/trace/trace.c |    3 +++
 1 file changed, 3 insertions(+)
kernel/trace/trace.c +3 -0
@@ -9148,6 +9148,8 @@ buffer_subbuf_size_write(struct file *fi
 	/* Do not allow tracing while changing the order of the ring buffer */
 	tracing_stop_tr(tr);
 
+	trace_access_lock(RING_BUFFER_ALL_CPUS);
+
 	old_order = ring_buffer_subbuf_order_get(tr->array_buffer.buffer);
 	if (old_order == order)
 		goto out;
@@ -9187,6 +9189,7 @@ buffer_subbuf_size_write(struct file *fi
 #endif
 	(*ppos)++;
  out:
+	trace_access_unlock(RING_BUFFER_ALL_CPUS);
 	if (ret)
 		cnt = ret;
 	tracing_start_tr(tr);
author maintainer
#40 lore raw

PATCH 38/403 tracing: Fix use-after-free with same-name named triggers

In reply to Greg Kroah-Hartman

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

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

From: Hui Su <[email protected]>

commit a7318172aa332a161fb9618286e64454c827f8fd upstream.

When two hist triggers on different events are registered with the same name=, the second one reuses the first as named_data. Both are added to tr->hist_vars by save_hist_vars() during event_hist_trigger_parse(), because save_hist_vars() is called before event_trigger_register() while the named reuse is only detected later, in hist_register_trigger().

In the named-data branch hist_register_trigger() then frees the second histogram's hist_data via destroy_hist_data(), but never removes its tr->hist_vars list entry, leaving a dangling pointer and leaking the trace_array reference it holds.

A later hist trigger that references a variable makes find_var_file() walk tr->hist_vars and dereference the freed hist_data. The bug is reproducible from userspace by writing three hist triggers to tracefs:

cd /sys/kernel/tracing
echo 'hist:keys=common_pid:x=common_pid:name=mh' > events/sched/sched_switch/trigger echo 'hist:keys=common_pid:x=common_pid:name=mh' > events/sched/sched_process_fork/trigger echo 'hist:keys=common_pid:vals=$x' > events/sched/sched_process_exit/trigger

The third write panics the kernel:

  BUG: KASAN: slab-use-after-free in find_var_file.part.0+0x272/0x290
  Read of size 8 at addr ffff888001f8a0e0 by task sh/1
  CPU: 1 UID: 0 PID: 1 Comm: sh Tainted: G      D          N
  Call Trace:
    find_var_file.part.0
    find_event_var
    parse_atom
    parse_expr
    __create_val_field
    event_hist_trigger_parse
    trigger_process_regex
    event_trigger_write
    vfs_write
    ksys_write
    do_syscall_64
    entry_SYSCALL_64_after_hwframe
  Allocated by task 1:
    event_hist_trigger_parse
  Freed by task 1:
    hist_register_trigger+0x618/0xa30
    event_hist_trigger_parse
  The buggy address belongs to freed 2048-byte region
  Oops: general protection fault ... RIP: find_var_file.part.0
  Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

Fix by removing the hist_data from tr->hist_vars and releasing the trace_array reference in the named-data branch of hist_register_trigger() before freeing the hist_data.

Fixes 6f86bdeab633 ("tracing: Fix bad hist from corrupting named_triggers list")
---
 kernel/trace/trace_events_hist.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +3 -1
@@ -6585,8 +6585,10 @@ static int hist_register_trigger(char *g
 		tracing_set_filter_buffering(file->tr, true);
 	}
 
-	if (named_data)
+	if (named_data) {
+		remove_hist_vars(hist_data);
 		destroy_hist_data(hist_data);
+	}
  out:
 	return ret;
 }
author maintainer
#41 lore raw

PATCH 39/403 cdx: Fix double free when sysfs file creation fails

In reply to Greg Kroah-Hartman

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

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

From: Prasanna Kumar T S M <[email protected]>

commit 6f4acc3a3c300e174e3f586b97b04ed8f5948c36 upstream.

In cdx_create_res_attr(), if sysfs_create_bin_file() fails, the code frees res_attr but doesn't set cdx_dev->res_attr[num] to NULL. This leaves a dangling pointer in the array. Then cdx_destroy_res_attr() frees the already-freed memory. Fix the double free by initializing cdx_dev->res_attr[num] after sysfs_create_bin_file() completes.

---
 drivers/cdx/cdx.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/cdx/cdx.c +5 -2
@@ -741,7 +741,6 @@ static int cdx_create_res_attr(struct cd
 
 	sysfs_bin_attr_init(res_attr);
 
-	cdx_dev->res_attr[num] = res_attr;
 	sprintf(res_attr_name, "resource%d", num);
 
 	res_attr->mmap = cdx_mmap_resource;
@@ -750,8 +749,12 @@ static int cdx_create_res_attr(struct cd
 	res_attr->size = cdx_resource_len(cdx_dev, num);
 	res_attr->private = (void *)(unsigned long)num;
 	ret = sysfs_create_bin_file(&cdx_dev->dev.kobj, res_attr);
-	if (ret)
+	if (ret) {
 		kfree(res_attr);
+		return ret;
+	}
+
+	cdx_dev->res_attr[num] = res_attr;
 
 	return ret;
 }
author maintainer
#42 lore raw

PATCH 40/403 device property: fix infinite loop in fwnode_for_each_child_node()

In reply to Greg Kroah-Hartman

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

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

From: Xu Yang <[email protected]>

commit 1900692555826753adab8799a1a8d50bb1ee200c upstream.

When iterate over children of a fwnode that has a secondary fwnode, fwnode_get_next_child_node() can enter an infinite loop if the secondary fwnode has more than one child.

                       Parent        Child
      (Primary fwnode)   FWa:   {FWa1, FWa2, FWa3}
    (Secondary fwnode)   FWb:   {FWb1, FWb2}

In this case:

 ┌─> fwnode_get_next_child_node(FWa, FWa1)
 │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWa1) returns FWa2
 │
 │   ...
 │
 │   fwnode_get_next_child_node(FWa, FWa3)
 │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWa3) returns NULL
 │    - fwnode_call_ptr_op(FWb, get_next_child_node, FWa3) returns FWb1
 │
 │   fwnode_get_next_child_node(FWa, FWb1)
 │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWb1) returns FWa1
 └────┘

This cause fwnode_for_each_child_node() to loop indefinitely, reapeatedly output {FWa1, FWa2, FWa3, FWb1, FWa1, ...}.

The root cause is that when the current child (FWb1) belongs to the secondary fwnode, calling get_next_child_node() on the parimary fwnode incorrectly returns the first child (FWa1) again instead of NULL.

Fix this by dynamically checking the parent fwnode of the current child before calling get_next_child_node(). This approach follows the pattern established in commit b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()").

Fixes 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()")
---
 drivers/base/property.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/base/property.c +16 -3
@@ -759,18 +759,31 @@ struct fwnode_handle *
 fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
 			   struct fwnode_handle *child)
 {
+	const struct fwnode_handle *parent;
+	struct fwnode_handle *child_parent __free(fwnode_handle) = NULL;
 	struct fwnode_handle *next;
 
-	if (IS_ERR_OR_NULL(fwnode))
+	/*
+	 * If this function is in a loop and the previous iteration returned
+	 * an child from fwnode->secondary, then we need to use the secondary
+	 * as parent rather than @fwnode.
+	 */
+	if (child) {
+		child_parent = fwnode_get_parent(child);
+		parent = child_parent;
+	} else {
+		parent = fwnode;
+	}
+	if (IS_ERR_OR_NULL(parent))
 		return NULL;
 
 	/* Try to find a child in primary fwnode */
-	next = fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+	next = fwnode_call_ptr_op(parent, get_next_child_node, child);
 	if (next)
 		return next;
 
 	/* When no more children in primary, continue with secondary */
-	return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child);
+	return fwnode_get_next_child_node(parent->secondary, NULL);
 }
 EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
 
author maintainer
#43 lore raw

PATCH 41/403 misc: nsm: bound the device-reported response length

In reply to Greg Kroah-Hartman

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

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

From: Bryam Vargas <[email protected]>

commit 808e530654a5354e6df78863a5d61e4d44e67235 upstream.

nsm_sendrecv_msg_locked() stores the virtqueue used-ring length reported by the NSM device into msg->resp.len without bounding it to the response buffer. A malicious or buggy backend can report a length larger than the response buffer; parse_resp_raw() then copies that many bytes out of the fixed buffer to user space, disclosing adjacent kernel heap (an out-of-bounds read). The request path already floors its length in fill_req_raw(); the response path lacks the symmetric check.

Clamp the stored length to the size of the response buffer. Well-behaved devices report no more than the posted buffer size, so conforming traffic is unaffected.

---
 drivers/misc/nsm.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/nsm.c +1 -1
@@ -243,7 +243,7 @@ static int nsm_sendrecv_msg_locked(struc
 		goto cleanup;
 	}
 
-	msg->resp.len = len;
+	msg->resp.len = min_t(unsigned int, len, sizeof(msg->resp.data));
 
 	rc = 0;
 
author maintainer
#44 lore raw

PATCH 42/403 powerpc/powermac: fix OF node refcount

In reply to Greg Kroah-Hartman

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

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

From: Bartosz Golaszewski <[email protected]>

commit bd0abfe6b013aeb2a1aebc5fbc7ceeb50355bda3 upstream.

Platform devices created with platform_device_alloc() call platform_device_release() when the last reference to the device's kobject is dropped. This function calls of_node_put() unconditionally. This works fine for devices created with platform_device_register_full() but users of the split approach (platform_device_alloc() + platform_device_add()) must bump the reference of the of_node they assign manually. Add the missing call to of_node_get().

---
 arch/powerpc/platforms/powermac/low_i2c.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/platforms/powermac/low_i2c.c +1 -1
@@ -1504,7 +1504,7 @@ static int __init pmac_i2c_create_platfo
 		if (bus->platform_dev == NULL)
 			return -ENOMEM;
 		bus->platform_dev->dev.platform_data = bus;
-		bus->platform_dev->dev.of_node = bus->busnode;
+		bus->platform_dev->dev.of_node = of_node_get(bus->busnode);
 		platform_device_add(bus->platform_dev);
 	}
 
author maintainer
#45 lore raw

PATCH 43/403 rapidio: mport_cdev: fix use-after-free in dma_req_free()

In reply to Greg Kroah-Hartman

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

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

From: James Kim <[email protected]>

commit 5cbef379a94b161726c5f504598bf4791d45cedc upstream.

dma_req_free() acquires buf_mutex through req->map, drops the mapping reference with kref_put(), and then dereferences req->map again to unlock the mutex.

If kref_put() drops the last reference, mport_release_mapping() frees the mapping, and the subsequent mutex_unlock() dereferences a freed object. This is a use-after-free.

Fix this by caching map and md before kref_put(), clearing req->map while holding buf_mutex, and using the cached md for mutex unlocking.

The bug is reachable from userspace via the RapidIO mport character device interface.

Fixes e8de370188d0 ("rapidio: add mport char device driver")
Cc Alexandre Bounine <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Matt Porter <[email protected]>
---
 drivers/rapidio/devices/rio_mport_cdev.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/rapidio/devices/rio_mport_cdev.c +7 -3
@@ -584,9 +584,13 @@ static void dma_req_free(struct kref *re
 	}
 
 	if (req->map) {
-		mutex_lock(&req->map->md->buf_mutex);
-		kref_put(&req->map->ref, mport_release_mapping);
-		mutex_unlock(&req->map->md->buf_mutex);
+		struct rio_mport_mapping *map = req->map;
+		struct mport_dev *md = map->md;
+
+		mutex_lock(&md->buf_mutex);
+		req->map = NULL;
+		kref_put(&map->ref, mport_release_mapping);
+		mutex_unlock(&md->buf_mutex);
 	}
 
 	kref_put(&priv->dma_ref, mport_release_dma);
author maintainer
#46 lore raw

PATCH 44/403 Revert "media: v4l2-dev: fix error handling in __video_register_device()"

In reply to Greg Kroah-Hartman

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

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

From: Hans Verkuil <[email protected]>

commit e7600f5cee5de14065f950807931d6e6d40fb2d7 upstream.

This reverts commit 2a934fdb01db6458288fc9386d3d8ceba6dd551a.

The intentions of that patch were good, but it doesn't work.

The idea is that if device_register fails, you have to do a put_device to let the ref counter release resources.

However, the V4L2 API says that if video_register_device() fails, then you have to call video_device_release(), which kfree()s the video_device struct.

But the put_device() will already have freed the struct, so you end up in a double-free scenario.

There is not really a good way of fixing this without breaking video_register_device() into two parts, one that initializes everything, and one that does the actual device_register, and then converting all V4L2 drivers to this new model.

That is a massive job, and it is very unlikely that device_register will fail.

So rather than ending up in a double-free scenario, just revert this patch, and in that case we'll have a small memory leak. Which is a lot more robust.

---
 drivers/media/v4l2-core/v4l2-dev.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/media/v4l2-core/v4l2-dev.c +7 -7
@@ -1052,25 +1052,25 @@ int __video_register_device(struct video
 	vdev->dev.class = &video_class;
 	vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
 	vdev->dev.parent = vdev->dev_parent;
-	vdev->dev.release = v4l2_device_release;
 	dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
-
-	/* Increase v4l2_device refcount */
-	v4l2_device_get(vdev->v4l2_dev);
-
 	mutex_lock(&videodev_lock);
 	ret = device_register(&vdev->dev);
 	if (ret < 0) {
 		mutex_unlock(&videodev_lock);
 		pr_err("%s: device_register failed\n", __func__);
-		put_device(&vdev->dev);
-		return ret;
+		goto cleanup;
 	}
+	/* Register the release callback that will be called when the last
+	   reference to the device goes away. */
+	vdev->dev.release = v4l2_device_release;
 
 	if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
 		pr_warn("%s: requested %s%d, got %s\n", __func__,
 			name_base, nr, video_device_node_name(vdev));
 
+	/* Increase v4l2_device refcount */
+	v4l2_device_get(vdev->v4l2_dev);
+
 	/* Part 5: Register the entity. */
 	ret = video_register_media_controller(vdev);
 
author maintainer
#47 lore raw

PATCH 45/403 serial: imx: serialize imx_uart_ports[] lifetime

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

commit 8b0b29fdcb47907ae0296b8fe829e918e05e300f upstream.

imx_uart_probe() publishes its devm-allocated port in imx_uart_ports[] before uart_add_one_port() because console setup uses the table. The entry is not cleared when adding the port fails or after removal, leaving a dangling pointer.

A sibling probe can register the shared console through that stale entry. This was reproduced under KASAN on QEMU mcimx6ul-evk by unbinding a sibling UART, unbinding the console UART and rebinding the sibling.

Keep the entry valid through uart_remove_one_port(), then clear it. Protect port addition and removal together with their table updates so sibling operations cannot interleave. Reject an occupied slot rather than clobbering an active port during a duplicate-line probe.

Fixes dbff4e9ea2e8 ("IMX UART: remove statically initialized tables")
Fixes 9f322ad064f9 ("imx: serial: handle initialisation failure correctly")
Assisted-by Claude:claude-fable-5
---
 drivers/tty/serial/imx.c |   20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/tty/serial/imx.c +17 -3
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/ktime.h>
+#include <linux/mutex.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
@@ -2067,6 +2068,9 @@ static const struct uart_ops imx_uart_po
 
 static struct imx_port *imx_uart_ports[UART_NR];
 
+/* Held across uart_add/remove_one_port(); console callbacks must not take it. */
+static DEFINE_MUTEX(imx_uart_ports_lock);
+
 #if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
 static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
 {
@@ -2539,11 +2543,19 @@ static int imx_uart_probe(struct platfor
 		}
 	}
 
-	imx_uart_ports[sport->port.line] = sport;
-
 	platform_set_drvdata(pdev, sport);
 
-	ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port);
+	scoped_guard(mutex, &imx_uart_ports_lock) {
+		if (imx_uart_ports[sport->port.line]) {
+			ret = -EBUSY;
+		} else {
+			imx_uart_ports[sport->port.line] = sport;
+			ret = uart_add_one_port(&imx_uart_uart_driver,
+						&sport->port);
+			if (ret)
+				imx_uart_ports[sport->port.line] = NULL;
+		}
+	}
 
 err_clk:
 	clk_disable_unprepare(sport->clk_ipg);
@@ -2555,7 +2567,9 @@ static void imx_uart_remove(struct platf
 {
 	struct imx_port *sport = platform_get_drvdata(pdev);
 
+	guard(mutex)(&imx_uart_ports_lock);
 	uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+	imx_uart_ports[sport->port.line] = NULL;
 }
 
 static void imx_uart_restore_context(struct imx_port *sport)
author maintainer
#48 lore raw

PATCH 46/403 staging: greybus: hid: fix SET_REPORT return value

In reply to Greg Kroah-Hartman

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

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

From: Hao-Qun Huang <[email protected]>

commit 6d45195a9626d8aaaaed212c55638829a9c624a3 upstream.

__gb_hid_output_raw_report() stores the result of gb_hid_set_report() in ret and even adjusts it to account for the report ID byte, but then always returns 0.

This hides Greybus transport errors from HID_REQ_SET_REPORT callers, and makes hidraw report zero bytes written to user space on success, although hid_hw_raw_request() is expected to return the number of bytes transferred or a negative errno. The sibling GET_REPORT path, __gb_hid_get_raw_report(), already follows this convention.

Return ret like the other HID transport drivers do.

Fixes 96eab779e198 ("greybus: hid: add HID class driver")
Assisted-by Claude:claude-fable-5
---
 drivers/staging/greybus/hid.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/greybus/hid.c +1 -1
@@ -256,7 +256,7 @@ static int __gb_hid_output_raw_report(st
 	if (report_id && ret >= 0)
 		ret++; /* add report_id to the number of transferred bytes */
 
-	return 0;
+	return ret;
 }
 
 static int gb_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
author maintainer
#49 lore raw

PATCH 47/403 usb: dwc2: gadget: Exit partial power down state when changing USB pull-up

In reply to Greg Kroah-Hartman

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

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

From: Francesco Lavra <[email protected]>

commit bf1e90189a98ca4a824fd64b4f3c6043d13c98ea upstream.

When a USB host suspends a connected device, the DWC2 USB device controller enters a partial power down state where controller registers are not accessible. If the USB gadget is then disconnected or deactivated (e.g. when a gadget function is unbound from the controller), the pullup callback in struct usb_gadget_ops is invoked; if the controller is kept in partial power down, the register write in dwc2_hsotg_core_disconnect() does not take effect; as a result, the USB host keeps seeing the device as connected, even though the device is disabled.

Properly exit partial power down state in the pullup callback, so that the USB host detects a device disconnection as intended.

Fixes 97861781daff ("usb: dwc2: Allow entering hibernation from USB_SUSPEND interrupt")
---
 drivers/usb/dwc2/gadget.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/usb/dwc2/gadget.c +10 -1
@@ -4680,6 +4680,7 @@ static int dwc2_hsotg_pullup(struct usb_
 {
 	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
 	unsigned long flags;
+	int ret = 0;
 
 	dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on,
 		hsotg->op_state);
@@ -4691,6 +4692,13 @@ static int dwc2_hsotg_pullup(struct usb_
 	}
 
 	spin_lock_irqsave(&hsotg->lock, flags);
+	if (hsotg->in_ppd) {
+		ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+		if (ret) {
+			dev_err(hsotg->dev, "exit partial_power_down failed\n");
+			goto exit;
+		}
+	}
 	if (is_on) {
 		hsotg->enabled = 1;
 		dwc2_hsotg_core_init_disconnected(hsotg, false);
@@ -4704,9 +4712,10 @@ static int dwc2_hsotg_pullup(struct usb_
 	}
 
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+exit:
 	spin_unlock_irqrestore(&hsotg->lock, flags);
 
-	return 0;
+	return ret;
 }
 
 static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
author maintainer
#50 lore raw

PATCH 48/403 usb: gadget: at91_udc: drain polled-VBUS timer/work before udc is freed

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit c27d13ce4bab80fbdf6523928071b6c24b37606c upstream.

In polled-VBUS mode (board.vbus_pin && board.vbus_polled), probe arms a self-restarting cycle: at91_vbus_timer() schedules vbus_timer_work, and at91_vbus_timer_work() calls at91_vbus_update() and re-arms the timer via mod_timer(). Both recover the same udc through container_of and dereference it on every iteration.

Neither teardown path cancels this cycle. udc is devm-allocated, so it is freed after at91udc_remove() returns, and is likewise freed when probe fails and devres runs. A timer callback or work item that is pending or running at either point dereferences the freed udc.

Add at91_udc_shutdown_vbus_timer() and call it from at91udc_remove() and from the usb_add_gadget_udc() failure path in probe; the remaining probe error paths fail before the timer is armed. timer_shutdown_sync() waits for a running callback and clears timer->function, which makes the work handler's mod_timer() a permanent no-op; cancel_work_sync() then drains any pending or running work whose re-arm attempt now does nothing. The timer must be shut down first, since cancelling the work alone would let the timer re-queue it. The guard mirrors probe: in IRQ mode the timer and work_struct are never initialized.

This does not require a fault; a normal driver unbind can interleave with an already queued work item.

This issue was found by an in-house static analysis tool.

Fixes 4037242c4f5f ("ARM: 6209/3: at91_udc: Add vbus polarity and polling mode")
Assisted-by Codex:gpt-5.6
---
 drivers/usb/gadget/udc/at91_udc.c |   20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)
drivers/usb/gadget/udc/at91_udc.c +19 -1
@@ -1794,6 +1794,19 @@ static void at91udc_of_init(struct at91_
 		udc->caps = match->data;
 }
 
+/*
+ * The work handler re-arms this timer, so shut the timer down before
+ * draining the work; otherwise it restarts the polling cycle.
+ */
+static void at91_udc_shutdown_vbus_timer(struct at91_udc *udc)
+{
+	if (!(udc->board.vbus_pin && udc->board.vbus_polled))
+		return;
+
+	timer_shutdown_sync(&udc->vbus_timer);
+	cancel_work_sync(&udc->vbus_timer_work);
+}
+
 static int at91udc_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
@@ -1907,7 +1920,7 @@ static int at91udc_probe(struct platform
 	}
 	retval = usb_add_gadget_udc(dev, &udc->gadget);
 	if (retval)
-		goto err_unprepare_iclk;
+		goto err_shutdown_vbus;
 	dev_set_drvdata(dev, udc);
 	device_init_wakeup(dev, 1);
 	create_debug_file(udc);
@@ -1915,6 +1928,8 @@ static int at91udc_probe(struct platform
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	return 0;
 
+err_shutdown_vbus:
+	at91_udc_shutdown_vbus_timer(udc);
 err_unprepare_iclk:
 	clk_unprepare(udc->iclk);
 err_unprepare_fclk:
@@ -1933,6 +1948,9 @@ static void at91udc_remove(struct platfo
 	DBG("remove\n");
 
 	usb_del_gadget_udc(&udc->gadget);
+
+	at91_udc_shutdown_vbus_timer(udc);
+
 	if (udc->driver) {
 		dev_err(&pdev->dev,
 			"Driver still in use but removing anyhow\n");
author maintainer
#51 lore raw

PATCH 49/403 USB: phy: fsl-usb: fix missing static keywords

In reply to Greg Kroah-Hartman

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

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

From: Johan Hovold <[email protected]>

commit 80574c40598aedbc1751c528e414d7e224bc6313 upstream.

A recent change enabling compile testing of a Freescale dual-role controller indirectly enabled a USB PHY driver to be built. That driver in turn is missing a bunch of static keywords which results in warnings like:

drivers/usb/phy/phy-fsl-usb.c:105:5: error: no previous prototype for 'write_ulpi' [-Werror=missing-prototypes]
105 | int write_ulpi(u8 addr, u8 data)

        |     ^~~~~~~~~~

which consequently breaks -Werror builds.

Add the missing static keywords.

---
 drivers/usb/phy/phy-fsl-usb.c |   52 +++++++++++++++++++++---------------------
 drivers/usb/phy/phy-fsl-usb.h |    6 ++--
 2 files changed, 29 insertions(+), 29 deletions(-)
drivers/usb/phy/phy-fsl-usb.c +26 -26
@@ -45,7 +45,7 @@
 
 static const char driver_name[] = "fsl-usb2-otg";
 
-const pm_message_t otg_suspend_state = {
+static const pm_message_t otg_suspend_state = {
 	.event = 1,
 };
 
@@ -56,11 +56,11 @@ static struct fsl_otg *fsl_otg_dev;
 static int srp_wait_done;
 
 /* FSM timers */
-struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr,
+static struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr,
 	*b_ase0_brst_tmr, *b_se0_srp_tmr;
 
 /* Driver specific timers */
-struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr,
+static struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr,
 	*b_srp_wait_tmr, *a_wait_enum_tmr;
 
 static struct list_head active_timers;
@@ -101,7 +101,7 @@ static void (*_fsl_writel)(u32 v, unsign
 #define fsl_writel(val, addr)	writel(val, addr)
 #endif /* CONFIG_PPC32 */
 
-int write_ulpi(u8 addr, u8 data)
+static int write_ulpi(u8 addr, u8 data)
 {
 	u32 temp;
 
@@ -114,7 +114,7 @@ int write_ulpi(u8 addr, u8 data)
 /* Operations that will be called from OTG Finite State Machine */
 
 /* Charge vbus for vbus pulsing in SRP */
-void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
+static void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -132,7 +132,7 @@ void fsl_otg_chrg_vbus(struct otg_fsm *f
 }
 
 /* Discharge vbus through a resistor to ground */
-void fsl_otg_dischrg_vbus(int on)
+static void fsl_otg_dischrg_vbus(int on)
 {
 	u32 tmp;
 
@@ -150,7 +150,7 @@ void fsl_otg_dischrg_vbus(int on)
 }
 
 /* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
+static void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -168,7 +168,7 @@ void fsl_otg_drv_vbus(struct otg_fsm *fs
  * Pull-up D+, signalling connect by periperal. Also used in
  * data-line pulsing in SRP
  */
-void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
+static void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -187,7 +187,7 @@ void fsl_otg_loc_conn(struct otg_fsm *fs
  * port.  In host mode, controller will automatically send SOF.
  * Suspend will block the data on the port.
  */
-void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
+static void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -202,7 +202,7 @@ void fsl_otg_loc_sof(struct otg_fsm *fsm
 }
 
 /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
-void fsl_otg_start_pulse(struct otg_fsm *fsm)
+static void fsl_otg_start_pulse(struct otg_fsm *fsm)
 {
 	u32 tmp;
 
@@ -218,7 +218,7 @@ void fsl_otg_start_pulse(struct otg_fsm
 	fsl_otg_add_timer(fsm, b_data_pulse_tmr);
 }
 
-void b_data_pulse_end(unsigned long foo)
+static void b_data_pulse_end(unsigned long foo)
 {
 #ifdef HA_DATA_PULSE
 #else
@@ -229,7 +229,7 @@ void b_data_pulse_end(unsigned long foo)
 	fsl_otg_pulse_vbus();
 }
 
-void fsl_otg_pulse_vbus(void)
+static void fsl_otg_pulse_vbus(void)
 {
 	srp_wait_done = 0;
 	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1);
@@ -237,7 +237,7 @@ void fsl_otg_pulse_vbus(void)
 	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr);
 }
 
-void b_vbus_pulse_end(unsigned long foo)
+static void b_vbus_pulse_end(unsigned long foo)
 {
 	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0);
 
@@ -250,7 +250,7 @@ void b_vbus_pulse_end(unsigned long foo)
 	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr);
 }
 
-void b_srp_end(unsigned long foo)
+static void b_srp_end(unsigned long foo)
 {
 	fsl_otg_dischrg_vbus(0);
 	srp_wait_done = 1;
@@ -265,7 +265,7 @@ void b_srp_end(unsigned long foo)
  * a_host will start by SRP.  It needs to set b_hnp_enable before
  * actually suspending to start HNP
  */
-void a_wait_enum(unsigned long foo)
+static void a_wait_enum(unsigned long foo)
 {
 	VDBG("a_wait_enum timeout\n");
 	if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
@@ -275,13 +275,13 @@ void a_wait_enum(unsigned long foo)
 }
 
 /* The timeout callback function to set time out bit */
-void set_tmout(unsigned long indicator)
+static void set_tmout(unsigned long indicator)
 {
 	*(int *)indicator = 1;
 }
 
 /* Initialize timers */
-int fsl_otg_init_timers(struct otg_fsm *fsm)
+static int fsl_otg_init_timers(struct otg_fsm *fsm)
 {
 	/* FSM used timers */
 	a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
@@ -338,7 +338,7 @@ int fsl_otg_init_timers(struct otg_fsm *
 }
 
 /* Uninitialize timers */
-void fsl_otg_uninit_timers(void)
+static void fsl_otg_uninit_timers(void)
 {
 	/* FSM used timers */
 	kfree(a_wait_vrise_tmr);
@@ -390,7 +390,7 @@ static struct fsl_otg_timer *fsl_otg_get
 }
 
 /* Add timer to timer list */
-void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)
+static void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)
 {
 	struct fsl_otg_timer *timer = gtimer;
 	struct fsl_otg_timer *tmp_timer;
@@ -420,7 +420,7 @@ static void fsl_otg_fsm_add_timer(struct
 }
 
 /* Remove timer from the timer list; clear timeout status */
-void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)
+static void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)
 {
 	struct fsl_otg_timer *timer = gtimer;
 	struct fsl_otg_timer *tmp_timer, *del_tmp;
@@ -442,7 +442,7 @@ static void fsl_otg_fsm_del_timer(struct
 }
 
 /* Reset controller, not reset the bus */
-void otg_reset_controller(void)
+static void otg_reset_controller(void)
 {
 	u32 command;
 
@@ -454,7 +454,7 @@ void otg_reset_controller(void)
 }
 
 /* Call suspend/resume routines in host driver */
-int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+static int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 {
 	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
@@ -521,7 +521,7 @@ end:
  * Call suspend and resume function in udc driver
  * to stop and start udc driver.
  */
-int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
+static int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
 {
 	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
@@ -703,7 +703,7 @@ static int fsl_otg_start_hnp(struct usb_
  * intact.  It needs to have knowledge of some USB interrupts
  * such as port change.
  */
-irqreturn_t fsl_otg_isr(int irq, void *dev_id)
+static irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 {
 	struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
 	struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
@@ -829,7 +829,7 @@ err:
 }
 
 /* OTG Initialization */
-int usb_otg_start(struct platform_device *pdev)
+static int usb_otg_start(struct platform_device *pdev)
 {
 	struct fsl_otg *p_otg;
 	struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
@@ -1001,7 +1001,7 @@ static void fsl_otg_remove(struct platfo
 		pdata->exit(pdev);
 }
 
-struct platform_driver fsl_otg_driver = {
+static struct platform_driver fsl_otg_driver = {
 	.probe = fsl_otg_probe,
 	.remove_new = fsl_otg_remove,
 	.driver = {
drivers/usb/phy/phy-fsl-usb.h +3 -3
@@ -373,6 +373,6 @@ struct fsl_otg_config {
 
 #define FSL_OTG_NAME		"fsl-usb2-otg"
 
-void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer);
-void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer);
-void fsl_otg_pulse_vbus(void);
+static void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer);
+static void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer);
+static void fsl_otg_pulse_vbus(void);
author maintainer
#52 lore raw

PATCH 50/403 usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive()

In reply to Greg Kroah-Hartman

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

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

From: Xu Yang <[email protected]>

commit b691a07c5f644080374ddd24de6a0e05f5d28744 upstream.

Previously, tcpci_irq() always passed TCPC_TX_SOP as the receive type to tcpm_pd_receive(), ignoring the actual frame type reported by the TCPC_RX_BUF_FRAME_TYPE register.

Cache the TCPC_RX_DETECT register value in rx_type_mask variable. When a PD messageis received, read TCPC_RX_BUF_FRAME_TYPE register and handle the message only if its frame type is enabled in mask.

The TCPC_RX_BUF_FRAME_TYPE register records the received message type, which has a 1:1 mapping to enum tcpm_transmit_type.

---
 drivers/usb/typec/tcpm/tcpci.c |   12 +++++++++++-
 include/linux/usb/tcpci.h      |    1 +
 2 files changed, 12 insertions(+), 1 deletion(-)
drivers/usb/typec/tcpm/tcpci.c +11 -1
@@ -36,6 +36,7 @@ struct tcpci {
 
 	struct regmap *regmap;
 	unsigned int alert_mask;
+	unsigned int rx_type_mask;
 
 	bool controls_vbus;
 
@@ -484,6 +485,8 @@ static int tcpci_set_pd_rx(struct tcpc_d
 		if (tcpci->data->cable_comm_capable)
 			reg |= TCPC_RX_DETECT_SOP1;
 	}
+
+	tcpci->rx_type_mask = reg;
 	ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg);
 	if (ret < 0)
 		return ret;
@@ -745,6 +748,7 @@ process_status:
 	if (status & TCPC_ALERT_RX_STATUS) {
 		struct pd_message msg;
 		unsigned int cnt, payload_cnt;
+		enum tcpm_transmit_type rx_type;
 		u16 header;
 
 		regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
@@ -769,10 +773,16 @@ process_status:
 			regmap_raw_read(tcpci->regmap, TCPC_RX_DATA,
 					&msg.payload, payload_cnt);
 
+		ret = regmap_read(tcpci->regmap, TCPC_RX_BUF_FRAME_TYPE, &rx_type);
+		if (ret)
+			return ret;
+
 		/* Read complete, clear RX status alert bit */
 		tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
 
-		tcpm_pd_receive(tcpci->port, &msg, TCPC_TX_SOP);
+		rx_type &= TCPC_RX_BUF_FRAME_TYPE_MASK;
+		if (tcpci->rx_type_mask & BIT(rx_type))
+			tcpm_pd_receive(tcpci->port, &msg, rx_type);
 	}
 
 	if (tcpci->data->vbus_vsafe0v && (status & TCPC_ALERT_EXTENDED_STATUS)) {
include/linux/usb/tcpci.h +1 -0
@@ -144,6 +144,7 @@
 #define TCPC_RX_BUF_FRAME_TYPE		0x31
 #define TCPC_RX_BUF_FRAME_TYPE_SOP	0
 #define TCPC_RX_BUF_FRAME_TYPE_SOP1	1
+#define TCPC_RX_BUF_FRAME_TYPE_MASK	GENMASK(2, 0)
 #define TCPC_RX_HDR			0x32
 #define TCPC_RX_DATA			0x34 /* through 0x4f */
 
author maintainer
#53 lore raw

PATCH 51/403 usb: typec: ucsi: use UCSI_TIMEOUT_MS for sync command completion

In reply to Greg Kroah-Hartman

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

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

From: Huang Wei <[email protected]>

commit eb4573cf2fd860b20adfae050c3f6ec6ddc3abdb upstream.

The synchronous command completion path in ucsi_sync_control_common() hardcodes a 5 second (5 * HZ) timeout when waiting for the PPM to signal command completion via ACPI notification. This value matched UCSI_TIMEOUT_MS when it was still 5000 ms, but it was not updated when that macro was later raised to 10000 ms to fix PPM reset timeouts.

As a result, the two PPM communication paths are now inconsistent: the polling path in ucsi_reset_ppm() respects the 10 second timeout, while the event-driven completion path still uses 5 seconds. On machines where the firmware is slow to respond during boot (e.g. some Lenovo ThinkPad models such as the E14 Gen 7), commands sent after the PPM reset, such as SET_NOTIFICATION_ENABLE and GET_CAPABILITY, can exceed 5 seconds and cause UCSI initialization to fail with:

ucsi_acpi USBC000:00: error -ETIMEDOUT: PPM init failed

Once UCSI init aborts, USB-C PD negotiation never completes, which in turn blocks USB-C dock enumeration since the dock depends on a successful PD contract.

Replace the hardcoded 5 * HZ with msecs_to_jiffies(UCSI_TIMEOUT_MS) so that both communication paths share a single, consistent timeout value, and future adjustments to UCSI_TIMEOUT_MS are picked up automatically.

---
 drivers/usb/typec/ucsi/ucsi.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/typec/ucsi/ucsi.c +2 -1
@@ -77,7 +77,8 @@ int ucsi_sync_control_common(struct ucsi
 	if (ret)
 		goto out_clear_bit;
 
-	if (!wait_for_completion_timeout(&ucsi->complete, 5 * HZ))
+	if (!wait_for_completion_timeout(&ucsi->complete,
+					 msecs_to_jiffies(UCSI_TIMEOUT_MS)))
 		ret = -ETIMEDOUT;
 
 out_clear_bit:
author maintainer
#54 lore raw

PATCH 52/403 usb: gadget: u_audio: Fix use-after-free on sound card disconnect

In reply to Greg Kroah-Hartman

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

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

From: Sonali Pradhan <[email protected]>

commit 858965947081d10d41d9a1010a540d3d5eea958b upstream.

g_audio_cleanup() invokes snd_card_free_when_closed() to initiate sound card teardown and immediately frees the underlying struct snd_uac_chip context. However, snd_card_free_when_closed() returns asynchronously while ALSA control elements (kctls) remain open in userspace.

When userspace control applications access or close these open file descriptors, kctl callbacks attempt to dereference kctl->private_data pointing to &uac->c_prm or &uac->p_prm within the freed uac structure, resulting in a use-after-free (UAF) memory corruption.

Fix this issue by deferring the destruction of struct snd_uac_chip until all references to the ALSA sound card are released. Register a custom card->private_free callback (u_audio_card_free) during g_audio_setup() that frees uac and its associated playback/capture request and ring buffers only when the sound card reference count drops to zero.

Fixes 6c67ed9ad9b8 ("usb: gadget: u_audio: don't let userspace block driver unbind")
---
 drivers/usb/gadget/function/u_audio.c |   24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/usb/gadget/function/u_audio.c +18 -6
@@ -1177,6 +1177,20 @@ static struct snd_kcontrol_new u_audio_c
 	},
 };
 
+static void u_audio_card_free(struct snd_card *card)
+{
+	struct snd_uac_chip *uac = card->private_data;
+
+	if (!uac)
+		return;
+
+	kfree(uac->p_prm.reqs);
+	kfree(uac->c_prm.reqs);
+	kfree(uac->p_prm.rbuf);
+	kfree(uac->c_prm.rbuf);
+	kfree(uac);
+}
+
 int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
 					const char *card_name)
 {
@@ -1258,6 +1272,8 @@ int g_audio_setup(struct g_audio *g_audi
 		goto fail;
 
 	uac->card = card;
+	card->private_data = uac;
+	card->private_free = u_audio_card_free;
 
 	/*
 	 * Create first PCM device
@@ -1426,6 +1442,8 @@ int g_audio_setup(struct g_audio *g_audi
 
 snd_fail:
 	snd_card_free(card);
+	return err;
+
 fail:
 	kfree(uac->p_prm.reqs);
 	kfree(uac->c_prm.reqs);
@@ -1451,12 +1469,6 @@ void g_audio_cleanup(struct g_audio *g_a
 	card = uac->card;
 	if (card)
 		snd_card_free_when_closed(card);
-
-	kfree(uac->p_prm.reqs);
-	kfree(uac->c_prm.reqs);
-	kfree(uac->p_prm.rbuf);
-	kfree(uac->c_prm.rbuf);
-	kfree(uac);
 }
 EXPORT_SYMBOL_GPL(g_audio_cleanup);
 
author maintainer
#55 lore raw

PATCH 53/403 usb: gadget: snps_udc_plat: clean up PHY on probe deferral

In reply to Greg Kroah-Hartman

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

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

From: Myeonghun Pak <[email protected]>

commit 886338ea7d40e4ba5123c58204d7f7e53d825825 upstream.

When the referenced extcon device has not registered yet, extcon_get_edev_by_phandle() returns -EPROBE_DEFER after the driver has initialized and powered on the PHY. The direct return bypasses the common cleanup path and leaves both operations unbalanced.

Store the lookup error first and route deferred probing through exit_phy, while retaining the existing behavior of suppressing the error message for deferral.

This issue was identified during our ongoing static-analysis research while reviewing kernel code.

Fixes 1b9f35adb0ff ("usb: gadget: udc: Add Synopsys UDC Platform driver")
---
 drivers/usb/gadget/udc/snps_udc_plat.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/usb/gadget/udc/snps_udc_plat.c +2 -3
@@ -159,10 +159,9 @@ static int udc_plat_probe(struct platfor
 	if (of_property_present(dev->of_node, "extcon")) {
 		udc->edev = extcon_get_edev_by_phandle(dev, 0);
 		if (IS_ERR(udc->edev)) {
-			if (PTR_ERR(udc->edev) == -EPROBE_DEFER)
-				return -EPROBE_DEFER;
-			dev_err(dev, "Invalid or missing extcon\n");
 			ret = PTR_ERR(udc->edev);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "Invalid or missing extcon\n");
 			goto exit_phy;
 		}
 
author maintainer
#56 lore raw

PATCH 54/403 usb: gadget: midi2: remove default configfs groups on teardown

In reply to Greg Kroah-Hartman

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

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

From: Joshua Crofts <[email protected]>

commit 0f6bffb5008f0cba9cad5ded2caccc64466a6e54 upstream.

f_midi2_alloc_inst() creates default configfs child groups for the default endpoint and default block using configfs_add_default_group(), setting their internal refcount to 1.

However, during function teardown in f_midi2_free_inst() or EP cleanup in f_midi2_ep_opts_release(), configfs_remove_default_groups() is never called, therefore never dropping the refcount and leaking struct f_midi2_ep_opts and f_midi2_block_opts.

Add the missing configfs_remove_default_groups() in the afformentioned functions to free the structs properly.

---
 drivers/usb/gadget/function/f_midi2.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/usb/gadget/function/f_midi2.c +2 -0
@@ -2476,6 +2476,7 @@ static void f_midi2_ep_opts_release(stru
 {
 	struct f_midi2_ep_opts *opts = to_f_midi2_ep_opts(item);
 
+	configfs_remove_default_groups(&opts->group);
 	kfree(opts->info.ep_name);
 	kfree(opts->info.product_id);
 	kfree(opts);
@@ -2642,6 +2643,7 @@ static void f_midi2_free_inst(struct usb
 
 	opts = container_of(f, struct f_midi2_opts, func_inst);
 
+	configfs_remove_default_groups(&opts->func_inst.group);
 	kfree(opts->info.iface_name);
 	kfree(opts);
 }
author maintainer
#57 lore raw

PATCH 55/403 usb: gadget: f_tcm: fix deadlock in usbg_make_tpg()

In reply to Greg Kroah-Hartman

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

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

From: Yun Zhou <[email protected]>

commit 9dbf74f4022f80f7669d2b3c22c5deb46c1b5674 upstream.

usbg_make_tpg() held dep_lock while calling configfs_depend_item_unlocked(), which acquires the configfs root inode lock when operating across subsystems. This creates a circular lock dependency with configfs_rmdir():

dep_lock -> configfs root inode lock -> su_mutex -> dep_lock

In usbg_make_tpg(), dep_lock only serialized the read of opts->ready, which is a monotonic flag that transitions from false to true exactly once (in tcm_set_name()) and never reverts. Remove dep_lock from usbg_make_tpg() entirely and use READ_ONCE/WRITE_ONCE to access opts->ready locklessly instead.

---
 drivers/usb/gadget/function/f_tcm.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/usb/gadget/function/f_tcm.c +12 -11
@@ -1330,19 +1330,25 @@ static struct se_portal_group *usbg_make
 
 	opts = container_of(tpg_instances[i].func_inst, struct f_tcm_opts,
 		func_inst);
-	mutex_lock(&opts->dep_lock);
-	if (!opts->ready)
-		goto unlock_dep;
+	if (!READ_ONCE(opts->ready))
+		goto unlock_inst;
 
 	if (opts->has_dep) {
 		if (!try_module_get(opts->dependent))
-			goto unlock_dep;
+			goto unlock_inst;
 	} else {
+		/*
+		 * configfs_depend_item_unlocked() may acquire the configfs
+		 * root inode lock when the target belongs to a different
+		 * subsystem. Calling it under dep_lock would create a
+		 * circular dependency:
+		 *   dep_lock -> configfs inode lock -> su_mutex -> dep_lock
+		 */
 		ret = configfs_depend_item_unlocked(
 			wwn->wwn_group.cg_subsys,
 			&opts->func_inst.group.cg_item);
 		if (ret)
-			goto unlock_dep;
+			goto unlock_inst;
 	}
 
 	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
@@ -1368,7 +1374,6 @@ static struct se_portal_group *usbg_make
 
 	tpg_instances[i].tpg = tpg;
 	tpg->fi = tpg_instances[i].func_inst;
-	mutex_unlock(&opts->dep_lock);
 	mutex_unlock(&tpg_instances_lock);
 	return &tpg->se_tpg;
 
@@ -1381,8 +1386,6 @@ unref_dep:
 		module_put(opts->dependent);
 	else
 		configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
-unlock_dep:
-	mutex_unlock(&opts->dep_lock);
 unlock_inst:
 	mutex_unlock(&tpg_instances_lock);
 
@@ -2317,9 +2320,7 @@ static int tcm_set_name(struct usb_funct
 
 	pr_debug("tcm: Activating %s\n", name);
 
-	mutex_lock(&opts->dep_lock);
-	opts->ready = true;
-	mutex_unlock(&opts->dep_lock);
+	WRITE_ONCE(opts->ready, true);
 
 	return 0;
 }
author maintainer
#58 lore raw

PATCH 56/403 usb: gadget: uvc: fix dangling pointers in uvc_function_bind() and uvc_function_unbind()

In reply to Greg Kroah-Hartman

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

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

From: Jeffin Philip <[email protected]>

commit bdab5605259ba5d6ff927c1a85cc83eb3ecfdacc upstream.

In uvc_function_bind() error path, we use usb_ep_free_request which uses uvc->control_req but does not set it to NULL afterwards. Thus, uvc->control_req is a dangling pointer causing a UAF. Also we do not set the uvc->control_buf pointer to NULL after freeing it, which is another dangling pointer. Fix it by setting uvc->control_req to NULL after we run usb_ep_free_request() and uvc->control_buf to NULL after kfree. Do the same for uvc_function_unbind().

Reported-by [email protected]
Fixes 0f9df9393855 ("usb: gadget: uvc: fix error path in uvc_function_bind()")
Fixes 6d11ed76c45d ("usb: gadget: f_uvc: convert f_uvc to new function interface")
---
 drivers/usb/gadget/function/f_uvc.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/usb/gadget/function/f_uvc.c +6 -1
@@ -885,9 +885,12 @@ error_unlock:
 v4l2_error:
 	v4l2_device_unregister(&uvc->v4l2_dev);
 error:
-	if (uvc->control_req)
+	if (uvc->control_req) {
 		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+		uvc->control_req = NULL;
+	}
 	kfree(uvc->control_buf);
+	uvc->control_buf = NULL;
 
 	usb_free_all_descriptors(f);
 	return ret;
@@ -1069,7 +1072,9 @@ static void uvc_function_unbind(struct u
 	uvc->vdev_release_done = NULL;
 
 	usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+	uvc->control_req = NULL;
 	kfree(uvc->control_buf);
+	uvc->control_buf = NULL;
 
 	usb_free_all_descriptors(f);
 }
author maintainer
#59 lore raw

PATCH 57/403 usb: gadget: f_fs: Prevent deadlock during ep0 read loop

In reply to Greg Kroah-Hartman

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

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

From: Neill Kapron <[email protected]>

commit 569dd7e5dcffe1e1c6b26ca2cd3be57eb433e082 upstream.

Currently, ffs_ep0_read() holds ffs->mutex when it prepares to go to sleep waiting for an event. When no setup events are pending, it calls wait_event_interruptible_exclusive_locked_irq() with the mutex still held. The wait macro deliberately drops the waitqueue spinlock before sleeping but does not drop the mutex.

If a userspace daemon is polling ep0 via read() and the gadget is asynchronously torn down via configfs (e.g., echo "" > UDC), a deadlock can occur:

1. The configfs teardown calls functionfs_unbind(), which queues a FUNCTIONFS_UNBIND event.
2. The daemon wakes up, consumes the event, and drops the mutex.
3. However, if the daemon loops and immediately issues another read() before exiting, it reacquires ffs->mutex and again goes into an interruptible sleep.
4. Meanwhile, functionfs_unbind() continues execution and attempts to acquire ffs->mutex to tear down ep0req.
5. The kernel deadlocks because the configfs thread is stuck in an uninterruptible sleep waiting for the mutex, while the userspace daemon is in an interruptible sleep holding the mutex forever because no more events will arrive.

To fix this, we drop both the waitqueue spinlock and ffs->mutex before going to sleep, and use wait_event_interruptible_exclusive() instead. Upon waking up, we jump back to the retry label to safely reacquire the mutex and re-evaluate the state machine. By not sleeping with ffs->mutex held, we natively decouple gadget teardowns (which require the mutex) from userspace polling.

Fixes ddf8abd25994 ("USB: f_fs: the FunctionFS driver")
Assisted-by Antigravity:gemini-3.1-pro
---
 drivers/usb/gadget/function/f_fs.c |   14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/usb/gadget/function/f_fs.c +10 -4
@@ -551,6 +551,7 @@ static ssize_t ffs_ep0_read(struct file
 	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
 		return -EIDRM;
 
+retry:
 	/* Acquire mutex */
 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
 	if (ret < 0)
@@ -585,10 +586,15 @@ static ssize_t ffs_ep0_read(struct file
 			break;
 		}
 
-		if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
-							ffs->ev.count)) {
-			ret = -EINTR;
-			break;
+		if (!ffs->ev.count) {
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+			mutex_unlock(&ffs->mutex);
+
+			if (wait_event_interruptible_exclusive(ffs->ev.waitq,
+							       ffs->ev.count))
+				return -EINTR;
+
+			goto retry;
 		}
 
 		/* unlocks spinlock */
author maintainer
#60 lore raw

PATCH 58/403 fpga: altera-cvp: Avoid out-of-bounds read in trailing byte write

In reply to Greg Kroah-Hartman

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

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

From: Daisuke Matsuda <[email protected]>

commit 9da70a43b5fea60d758137f7f0ccfe19356cb5bb upstream.

The trailing byte path in altera_cvp_send_block() dereferences a u32 pointer even when only 1-3 bytes remain in the input buffer. If the buffer ends at a page or scatterlist boundary, this can read past the valid image data and fault.

Copy the remaining bytes into a zero-initialized u32 before writing the final word so only valid bytes are read from the input buffer.

---
 drivers/fpga/altera-cvp.c |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/fpga/altera-cvp.c +6 -4
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sizes.h>
+#include <linux/string.h>
 
 #define CVP_BAR		0	/* BAR used for data transfer in memory mode */
 #define CVP_DUMMY_WR	244	/* dummy writes to clear CvP state machine */
@@ -264,7 +265,7 @@ static int altera_cvp_v2_wait_for_credit
 static int altera_cvp_send_block(struct altera_cvp_conf *conf,
 				 const u32 *data, size_t len)
 {
-	u32 mask, words = len / sizeof(u32);
+	u32 words = len / sizeof(u32);
 	int i, remainder;
 
 	for (i = 0; i < words; i++)
@@ -273,9 +274,10 @@ static int altera_cvp_send_block(struct
 	/* write up to 3 trailing bytes, if any */
 	remainder = len % sizeof(u32);
 	if (remainder) {
-		mask = BIT(remainder * 8) - 1;
-		if (mask)
-			conf->write_data(conf, *data & mask);
+		u32 word = 0;
+
+		memcpy(&word, data, remainder);
+		conf->write_data(conf, word);
 	}
 
 	return 0;
author maintainer
#61 lore raw

PATCH 59/403 HID: sensor-hub: Fix out-of-bounds write in sensor_hub_get_feature

In reply to Greg Kroah-Hartman

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

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

From: Xingrui Li <[email protected]>

commit c92693f3ed099401d0383ef35ca1fe1e6ba033de upstream.

sensor_hub_get_feature() clamps its return value to the caller's buffer size, but the copy loop still copies field->report_size / 8 bytes for each report value. A malicious HID descriptor can advertise a large feature field size while an IIO caller supplies a small stack buffer, such as a single s32, causing an out-of-bounds write.

HID core stores parsed report values in __s32 slots and clamps extracted values to 32 bits. Reject feature fields that require more than one slot per value, guard the total byte count calculation, and clamp each per-value copy to the remaining caller buffer.

Fixes 5459ada2b3cd69 ("HID: sensor-hub: Fix packing of result buffer for feature report")
Assisted-by OpenAI:GPT-5.5-Cyber
---
 drivers/hid/hid-sensor-hub.c |   44 +++++++++++++++++++++++++------------------
 1 file changed, 26 insertions(+), 18 deletions(-)
drivers/hid/hid-sensor-hub.c +26 -18
@@ -239,12 +239,17 @@ int sensor_hub_get_feature(struct hid_se
 			   u32 field_index, int buffer_size, void *buffer)
 {
 	struct hid_report *report;
+	struct hid_field *field;
 	struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
-	int report_size;
+	size_t field_size;
+	size_t report_size;
+	size_t copied = 0;
+	size_t to_copy;
 	int ret = 0;
-	u8 *val_ptr;
-	int buffer_index = 0;
-	int i;
+	unsigned int i;
+
+	if (!buffer || buffer_size <= 0)
+		return -EINVAL;
 
 	memset(buffer, 0, buffer_size);
 
@@ -258,26 +263,29 @@ int sensor_hub_get_feature(struct hid_se
 	hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
 	hid_hw_wait(hsdev->hdev);
 
+	field = report->field[field_index];
+
 	/* calculate number of bytes required to read this field */
-	report_size = DIV_ROUND_UP(report->field[field_index]->report_size,
-				   8) *
-				   report->field[field_index]->report_count;
-	if (!report_size) {
+	field_size = DIV_ROUND_UP(field->report_size, 8);
+	/* HID core stores each parsed report value in a __s32 slot. */
+	if (!field_size || field_size > sizeof(field->value[0])) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	if (field->report_count > SIZE_MAX / field_size) {
 		ret = -EINVAL;
 		goto done_proc;
 	}
-	ret = min(report_size, buffer_size);
 
-	val_ptr = (u8 *)report->field[field_index]->value;
-	for (i = 0; i < report->field[field_index]->report_count; ++i) {
-		if (buffer_index >= ret)
-			break;
-
-		memcpy(&((u8 *)buffer)[buffer_index], val_ptr,
-		       report->field[field_index]->report_size / 8);
-		val_ptr += sizeof(__s32);
-		buffer_index += (report->field[field_index]->report_size / 8);
+	report_size = field_size * field->report_count;
+	report_size = min_t(size_t, report_size, buffer_size);
+
+	for (i = 0; i < field->report_count && copied < report_size; ++i) {
+		to_copy = min(field_size, report_size - copied);
+		memcpy(&((u8 *)buffer)[copied], &field->value[i], to_copy);
+		copied += to_copy;
 	}
+	ret = copied;
 
 done_proc:
 	mutex_unlock(&data->mutex);
author maintainer
#62 lore raw

PATCH 60/403 lib/ucs2_string.c: fix out-of-bounds read in ucs2_strnlen()

In reply to Greg Kroah-Hartman

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

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

From: Vincent Mailhol <[email protected]>

commit cec0d03fe785380540dc1b4d07c80f67ae2ffc78 upstream.

Patch series "lib/ucs2_string.c: fix out-of-bounds read in ucs2_strnlen()", v2.

This series fixes an off-by-one out-of-bounds read in ucs2_strnlen().

The first patch is the real fix, the second patch comes as a bonus and fixes the code indentation.

This patch (of 2):

ucs2_strnlen() checks the current character before checking whether the caller-provided maximum length has been reached. If the input is not NUL-terminated within that bound, the loop can read one ucs2_char_t past the limit.

Test the length before dereferencing to prevent an off-by-one out-of-bounds read.

---
 lib/ucs2_string.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/ucs2_string.c +1 -1
@@ -8,7 +8,7 @@ ucs2_strnlen(const ucs2_char_t *s, size_
 {
         unsigned long length = 0;
 
-        while (*s++ != 0 && length < maxlength)
+	while (length < maxlength && *s++ != 0)
                 length++;
         return length;
 }
author maintainer
#63 lore raw

PATCH 61/403 media: cec: stm32: prevent out-of-bounds write on RX overflow

In reply to Greg Kroah-Hartman

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

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

From: Weigang He <[email protected]>

commit fb9dda38d4b9e90db07ed9a0ee2d35bf85494035 upstream.

stm32_rx_done() appends each received CEC byte to rx_msg.msg[] using rx_msg.len as the write index, incrementing it on every RXBR (receive-byte-ready) interrupt without checking it against the buffer size:

	cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;

rx_msg.msg[] is a fixed CEC_MAX_MSG_SIZE (16) byte array in struct cec_msg, and rx_msg.len is only reset on RXACKE/RXOVR or after a completed message (RXEND). The number of bytes received before RXEND is decided by the remote CEC device (it sets EOM), not by the driver. A peer that keeps sending bytes without ending the message drives RXBR repeatedly, pushing rx_msg.len past 16 and writing peer-controlled bytes out of bounds into the surrounding memory. This is reachable in normal operation once the driver has probed and receiving is enabled, from the IRQ thread, without any local privilege.

The length check in the CEC core runs on the consumer side, after the byte has been stored, so it does not prevent the overflow. Bound the index in the driver before the store, as the other platform CEC drivers already do (e.g. tegra_cec), dropping the excess bytes of an overlong frame.

Found by static analysis tool CodeQL.

Fixes d69ae57453c8 ("[media] cec: add STM32 cec driver")
---
 drivers/media/cec/platform/stm32/stm32-cec.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/cec/platform/stm32/stm32-cec.c +2 -1
@@ -132,7 +132,8 @@ static void stm32_rx_done(struct stm32_c
 		u32 val;
 
 		regmap_read(cec->regmap, CEC_RXDR, &val);
-		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
+		if (cec->rx_msg.len < CEC_MAX_MSG_SIZE)
+			cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
 	}
 
 	if (cec->irq_status & RXEND) {
author maintainer
#64 lore raw

PATCH 62/403 media: vicodec: fix out-of-bounds write in FWHT encoder

In reply to Greg Kroah-Hartman

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

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

From: Junrui Luo <[email protected]>

commit cf4500ebf6fb57bf4ab83c3dd349a40257dbe2a9 upstream.

vidioc_s_fmt_vid_out() sizes the encoder CAPTURE buffer from the compressed descriptor pixfmt_fwht, whose sizeimage_mult is 3:
coded_w * coded_h * 3 + sizeof(struct fwht_cframe_hdr). fwht_encode_frame() encodes one plane per component, and an incompressible plane takes the FWHT_FRAME_UNENCODED path in encode_plane(), copying the plane verbatim.

For a 4-component pixel format all four planes are full resolution (width_div == height_div == 1), so a frame that forces every plane through the unencoded fallback writes
sizeof(struct fwht_cframe_hdr) + 4 * coded_w * coded_h bytes, overrunning the plane by coded_w * coded_h, which can result in corruption of adjacent kernel heap memory.

Bump pixfmt_fwht.sizeimage_mult from 3 to 4, matching the largest components_num among the supported raw formats, so the capture buffer is always large enough for the unencoded fallback.

Fixes 16ecf6dff97c ("media: vicodec: Add support for 4 planes formats")
---
 drivers/media/test-drivers/vicodec/vicodec-core.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/test-drivers/vicodec/vicodec-core.c +2 -2
@@ -61,11 +61,11 @@ struct pixfmt_info {
 };
 
 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
-	V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
+	V4L2_PIX_FMT_FWHT, 0, 4, 1, 1, 1, 1, 1, 0, 1
 };
 
 static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = {
-	V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1
+	V4L2_PIX_FMT_FWHT_STATELESS, 0, 4, 1, 1, 1, 1, 1, 0, 1
 };
 
 static void vicodec_dev_release(struct device *dev)
author maintainer
#65 lore raw

PATCH 63/403 nilfs2: fix slab-out-of-bounds in nilfs_direct_propagate after truncation

In reply to Greg Kroah-Hartman

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

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

From: Ryusuke Konishi <[email protected]>

commit 45662dedb8f272ef7f16e69f13424c4bd0399240 upstream.

Shuangpeng Bai reported that KASAN detected a slab-out-of-bounds error in nilfs_direct_propagate() during testing.

Analysis revealed that after truncating a file, a node block immediately below the B-tree root was not deleted. Instead, it remained in the B-tree node cache in a dirty state. The log writer subsequently detected this block and incorrectly invoked nilfs_direct_propagate() on it, which is designed to handle only data blocks in direct mapping.

B-tree nodes in the cache are managed by virtual block numbers, and their logical keys typically exceed the range expected by direct mapping. Consequently, processing such a node as a direct mapping entry triggers a slab-out-of-bounds access.

The root cause is that when a B-tree mapping collapses into a direct mapping during truncation, an intermediate node block pointed to by the root node is left behind as garbage instead of being explicitly deleted.

This resolves the issue by adding a nilfs_btree_discard() operation to delete the remaining intermediate node block during the conversion. A 'deform' flag is added to the bop_delete interface to explicitly signal that the deletion is part of a mapping transformation. This allows the B-tree mapping implementation to perform the necessary cleanup and discarding of the residual node structure that would be otherwise be left orphaned after the transition.

---
 fs/nilfs2/bmap.c   |    2 +-
 fs/nilfs2/bmap.h   |    2 +-
 fs/nilfs2/btree.c  |   39 ++++++++++++++++++++++++++++++++-------
 fs/nilfs2/direct.c |    4 ++--
 4 files changed, 36 insertions(+), 11 deletions(-)
fs/nilfs2/bmap.c +1 -1
@@ -181,7 +181,7 @@ static int nilfs_bmap_do_delete(struct n
 			return ret;
 	}
 
-	return bmap->b_ops->bop_delete(bmap, key);
+	return bmap->b_ops->bop_delete(bmap, key, false);
 }
 
 /**
fs/nilfs2/bmap.h +1 -1
@@ -63,7 +63,7 @@ struct nilfs_bmap_operations {
 	int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *,
 				 unsigned int);
 	int (*bop_insert)(struct nilfs_bmap *, __u64, __u64);
-	int (*bop_delete)(struct nilfs_bmap *, __u64);
+	int (*bop_delete)(struct nilfs_bmap *bmap, __u64 key, bool deform);
 	void (*bop_clear)(struct nilfs_bmap *);
 
 	int (*bop_propagate)(struct nilfs_bmap *, struct buffer_head *);
fs/nilfs2/btree.c +32 -7
@@ -1426,6 +1426,28 @@ static void nilfs_btree_shrink(struct ni
 	path[level].bp_bh = NULL;
 }
 
+/**
+ * nilfs_btree_discard - discard the last node for the mapping transformation
+ * @btree: bmap struct of btree
+ * @path: array of nilfs_btree_path struct
+ * @level: level of the B-tree node being operated on
+ * @keyp: argument for passing a key (unused)
+ * @ptrp: argument for passing a pointer (unused)
+ */
+static void nilfs_btree_discard(struct nilfs_bmap *btree,
+				struct nilfs_btree_path *path, int level,
+				__u64 *keyp, __u64 *ptrp)
+{
+	struct nilfs_btree_node *root = nilfs_btree_get_root(btree);
+
+	nilfs_btree_node_delete(root, 0, NULL, NULL,
+				NILFS_BTREE_ROOT_NCHILDREN_MAX);
+	nilfs_btree_node_set_level(root, level);
+
+	nilfs_btnode_delete(path[level].bp_bh);
+	path[level].bp_bh = NULL;
+}
+
 static void nilfs_btree_nop(struct nilfs_bmap *btree,
 			    struct nilfs_btree_path *path,
 			    int level, __u64 *keyp, __u64 *ptrp)
@@ -1436,7 +1458,7 @@ static int nilfs_btree_prepare_delete(st
 				      struct nilfs_btree_path *path,
 				      int *levelp,
 				      struct nilfs_bmap_stats *stats,
-				      struct inode *dat)
+				      struct inode *dat, bool deform)
 {
 	struct buffer_head *bh;
 	struct nilfs_btree_node *node, *parent, *sib;
@@ -1523,15 +1545,17 @@ static int nilfs_btree_prepare_delete(st
 			if (nilfs_btree_node_get_nchildren(node) - 1 <=
 			    NILFS_BTREE_ROOT_NCHILDREN_MAX) {
 				path[level].bp_op = nilfs_btree_shrink;
-				stats->bs_nblocks += 2;
-				level++;
-				path[level].bp_op = nilfs_btree_nop;
-				goto shrink_root_child;
+			} else if (deform) {
+				path[level].bp_op = nilfs_btree_discard;
 			} else {
 				path[level].bp_op = nilfs_btree_do_delete;
 				stats->bs_nblocks++;
 				goto out;
 			}
+			stats->bs_nblocks += 2;
+			level++;
+			path[level].bp_op = nilfs_btree_nop;
+			goto shrink_root_child;
 		}
 	}
 
@@ -1582,7 +1606,7 @@ static void nilfs_btree_commit_delete(st
 		nilfs_bmap_set_dirty(btree);
 }
 
-static int nilfs_btree_delete(struct nilfs_bmap *btree, __u64 key)
+static int nilfs_btree_delete(struct nilfs_bmap *btree, __u64 key, bool deform)
 
 {
 	struct nilfs_btree_path *path;
@@ -1602,7 +1626,8 @@ static int nilfs_btree_delete(struct nil
 
 	dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
 
-	ret = nilfs_btree_prepare_delete(btree, path, &level, &stats, dat);
+	ret = nilfs_btree_prepare_delete(btree, path, &level, &stats, dat,
+			deform);
 	if (ret < 0)
 		goto out;
 	nilfs_btree_commit_delete(btree, path, level, dat);
fs/nilfs2/direct.c +2 -2
@@ -144,7 +144,7 @@ static int nilfs_direct_insert(struct ni
 	return ret;
 }
 
-static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
+static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key, bool deform)
 {
 	union nilfs_bmap_ptr_req req;
 	struct inode *dat;
@@ -234,7 +234,7 @@ int nilfs_direct_delete_and_convert(stru
 	/* no need to allocate any resource for conversion */
 
 	/* delete */
-	ret = bmap->b_ops->bop_delete(bmap, key);
+	ret = bmap->b_ops->bop_delete(bmap, key, true);
 	if (ret < 0)
 		return ret;
 
author maintainer
#66 lore raw

PATCH 64/403 of: fix out-of-bounds read in of_alias_scan() stem parser

In reply to Greg Kroah-Hartman

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

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

From: Abdurrahman Hussain <[email protected]>

commit 5bb01c657ff9fc807c2c592ca18af34c4fc3bc6f upstream.

The stem parser tests isdigit(*(end - 1)) before checking end > start and so reads one byte before the property name when the name is empty or all digits. Check the bound first.

Fixes 611cad720148 ("dt: add of_alias_scan and of_alias_get_id")
Assisted-by Claude:claude-fable-5 [Claude Code]
---
 drivers/of/base.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/of/base.c +1 -1
@@ -1818,7 +1818,7 @@ void of_alias_scan(void * (*dt_alloc)(u6
 
 		/* walk the alias backwards to extract the id and work out
 		 * the 'stem' string */
-		while (isdigit(*(end-1)) && end > start)
+		while (end > start && isdigit(*(end - 1)))
 			end--;
 		len = end - start;
 
author maintainer
#67 lore raw

PATCH 65/403 PCI/sysfs: Fix out-of-bounds read in pci_write_legacy_io()

In reply to Greg Kroah-Hartman

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

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

From: Krzysztof Wilczyński <[email protected]>

commit dc76258d0132df1d831a5a29758bd448ca9c566e upstream.

pci_write_legacy_io() loads 4 bytes from the kernfs write buffer regardless of how many bytes userspace wrote:

  if (count != 1 && count != 2 && count != 4)
          return -EINVAL;

  return pci_legacy_write(bus, off, *(u32 *)buf, count);

kernfs_fop_write_iter() allocates the buffer with kmalloc(len + 1), so a 1-byte write to the legacy_io sysfs file allocates 2 bytes and the unconditional u32 load reads up to 2 bytes past the end of the allocation, which KASAN reports as a slab-out-of-bounds read. Similarly, a 2-byte write overreads by 1 byte.

Thus, read only the number of bytes requested using get_unaligned_le16() and get_unaligned_le32() for the 2 and 4 byte cases, interpreting the buffer as little-endian to match the byte ordering of PCI I/O port space.

The PowerPC implementation previously compensated for the generic code's native-endian 32-bit load by shifting the value into place for the 1 and 2 byte cases. The shifts were only correct on big-endian kernels.

On little-endian PowerPC (POWER8 and later), they extracted the wrong bytes, so a 1-byte write wrote an out-of-bounds byte instead of the requested value. On big-endian, the native load also caused out_le16() and out_le32() to reverse the user's bytes on the wire for 2 and 4 byte writes. The little-endian helpers resolve both issues, so the shifts are removed.

No changes are needed for the Alpha platform.

The legacy_io file is root-only and exists only on Alpha and PowerPC, the two architectures that define HAVE_PCI_LEGACY.

---
 arch/powerpc/kernel/pci-common.c |    9 ++-------
 drivers/pci/pci-sysfs.c          |   18 +++++++++++++++---
 2 files changed, 17 insertions(+), 10 deletions(-)
arch/powerpc/kernel/pci-common.c +2 -7
@@ -626,19 +626,14 @@ int pci_legacy_write(struct pci_bus *bus
 		return -ENXIO;
 	addr = hose->io_base_virt + port;
 
-	/* WARNING: The generic code is idiotic. It gets passed a pointer
-	 * to what can be a 1, 2 or 4 byte quantity and always reads that
-	 * as a u32, which means that we have to correct the location of
-	 * the data read within those 32 bits for size 1 and 2
-	 */
 	switch(size) {
 	case 1:
-		out_8(addr, val >> 24);
+		out_8(addr, val);
 		return 1;
 	case 2:
 		if (port & 1)
 			return -EINVAL;
-		out_le16(addr, val >> 16);
+		out_le16(addr, val);
 		return 2;
 	case 4:
 		if (port & 3)
drivers/pci/pci-sysfs.c +15 -3
@@ -907,12 +907,24 @@ static ssize_t pci_write_legacy_io(struc
 				   loff_t off, size_t count)
 {
 	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
+	u32 val;
 
-	/* Only support 1, 2 or 4 byte accesses */
-	if (count != 1 && count != 2 && count != 4)
+	/* Only support 1, 2 or 4 byte accesses. */
+	switch (count) {
+	case 1:
+		val = *(u8 *)buf;
+		break;
+	case 2:
+		val = get_unaligned_le16(buf);
+		break;
+	case 4:
+		val = get_unaligned_le32(buf);
+		break;
+	default:
 		return -EINVAL;
+	}
 
-	return pci_legacy_write(bus, off, *(u32 *)buf, count);
+	return pci_legacy_write(bus, off, val, count);
 }
 
 /**
author maintainer
#68 lore raw

PATCH 66/403 ubifs: fix out-of-bounds read in signature length check

In reply to Greg Kroah-Hartman

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

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

From: Ibrahim Hashimov <[email protected]>

commit 95d27c1708bb6e8823c8e7c623f9abc2a91bf4bf upstream.

ubifs_sb_verify_signature() bounds the on-disk ubifs_sig_node->len field before handing the signature payload to verify_pkcs7_signature(), but the check has the wrong sign:

	if (le32_to_cpu(signode->len) > snod->len + sizeof(struct ubifs_sig_node))

The signature bytes start sizeof(struct ubifs_sig_node) (UBIFS_SIG_NODE_SZ, 64 bytes) into the node, so the payload is at most

	snod->len - sizeof(struct ubifs_sig_node)

bytes long. Adding the header size instead of subtracting it accepts a declared length up to 2 * UBIFS_SIG_NODE_SZ larger than the node actually holds -- past the end of c->sbuf, which is vmalloc(c->leb_size). verify_pkcs7_signature() -> pkcs7_parse_message() -> asn1_ber_decoder() is then handed that inflated length and reads beyond the allocation while walking the DER headers. The node length comes straight from the mounted image, so a crafted signed UBIFS image reaches this via ubifs_read_superblock() before the signature is cryptographically checked.

snod->len is guaranteed to be >= UBIFS_SIG_NODE_SZ by the node scanner (c->ranges[UBIFS_SIG_NODE].min_len == UBIFS_SIG_NODE_SZ), so the corrected subtraction cannot underflow. Legitimately signed images are unaffected: a correct superblock never declares a signature longer than the node it is embedded in.

Fixes 817aa094842d ("ubifs: support offline signed images")
Assisted-by AuditCode-AI:2026.07
---
 fs/ubifs/auth.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ubifs/auth.c +1 -1
@@ -217,7 +217,7 @@ int ubifs_sb_verify_signature(struct ubi
 
 	signode = snod->node;
 
-	if (le32_to_cpu(signode->len) > snod->len + sizeof(struct ubifs_sig_node)) {
+	if (le32_to_cpu(signode->len) > snod->len - sizeof(struct ubifs_sig_node)) {
 		ubifs_err(c, "invalid signature len %d", le32_to_cpu(signode->len));
 		err = -EINVAL;
 		goto out_destroy;
author maintainer
#69 lore raw

PATCH 67/403 zsmalloc: account for handle size in class lookup

In reply to Greg Kroah-Hartman

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

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

From: Longlong Xia <[email protected]>

commit f7bf5cd5b5f2b13fe2361860880c4e214c08b440 upstream.

zs_lookup_class_index() lets zram recompression decide whether a newly compressed object would use a smaller size class. It currently classifies the payload size directly, while zs_malloc() adds ZS_HANDLE_SIZE before selecting the class.

This makes lookup disagree with allocation near size-class boundaries. With 4 KiB pages, CONFIG_ZSMALLOC_CHAIN_SIZE=8, and 64-bit handles, a 1025-to-1024-byte recompression appears to move from class 64 to class 62 although both allocations use class 64. Conversely, a 1049-to-1025-byte recompression appears to stay in class 64 although the allocations move from class 65 to class 64.

As a result, zram can accept replacements with no allocation benefit or reject ones that would save memory, potentially marking the object incompressible.

Factor size-class selection into lookup_size_class(), account for the handle there, and use the helper for both lookup and allocation.

Fixes 7c2af309abd2 ("zram: add size class equals check into recompression")
Assisted-by Codex:gpt-5.6-sol
Cc Minchan Kim <[email protected]>
---
 mm/zsmalloc.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
mm/zsmalloc.c +7 -4
@@ -515,6 +515,11 @@ static int get_size_class_index(int size
 	return min_t(int, ZS_SIZE_CLASSES - 1, idx);
 }
 
+static struct size_class *lookup_size_class(struct zs_pool *pool, size_t size)
+{
+	return pool->size_class[get_size_class_index(size + ZS_HANDLE_SIZE)];
+}
+
 static inline void class_stat_add(struct size_class *class, int type,
 				  unsigned long cnt)
 {
@@ -1156,7 +1161,7 @@ unsigned int zs_lookup_class_index(struc
 {
 	struct size_class *class;
 
-	class = pool->size_class[get_size_class_index(size)];
+	class = lookup_size_class(pool, size);
 
 	return class->index;
 }
@@ -1368,9 +1373,7 @@ unsigned long zs_malloc(struct zs_pool *
 	if (!handle)
 		return (unsigned long)ERR_PTR(-ENOMEM);
 
-	/* extra space in chunk to keep the handle */
-	size += ZS_HANDLE_SIZE;
-	class = pool->size_class[get_size_class_index(size)];
+	class = lookup_size_class(pool, size);
 
 	/* class->lock effectively protects the zpage migration */
 	spin_lock(&class->lock);
author maintainer
#70 lore raw

PATCH 68/403 NFSD: check truncate permission under inode lock

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit b778e0e0a16759f22a70579c3cf8d254a40d4a7f upstream.

nfsd_setattr() checks whether a size update needs NFSD_MAY_TRUNC before it takes inode_lock(). The comparison uses the file size sampled by that unlocked read, but the actual ATTR_SIZE update is applied later under inode_lock() by notify_change().

This leaves a TOCTOU window for append-only files. If a client sends a SETATTR that does not shrink the file at the time of the unlocked sample, a concurrent append can extend the file before nfsd_setattr() takes inode_lock(). notify_change() then applies a real truncation without the NFSD_MAY_TRUNC check that rejects IS_APPEND(inode). The VFS truncate syscall paths perform their own append-only checks before calling notify_change(), so NFSD must make this decision against the locked size it is about to change.

Split the write-count acquisition from the truncation permission check. Keep get_write_access() before the locked setattr work, then recheck whether the requested size is below i_size_read(inode) after inode_lock() has been acquired and before notify_change(ATTR_SIZE). This also avoids the plain unlocked inode->i_size load.

Fixes 783112f7401f ("nfsd: special case truncates some more")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/vfs.c |   30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)
fs/nfsd/vfs.c +18 -12
@@ -414,21 +414,22 @@ nfsd_sanitize_attrs(struct inode *inode,
 }
 
 static __be32
-nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
-		struct iattr *iap)
+nfsd_may_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp,
+		  struct iattr *iap)
 {
 	struct inode *inode = d_inode(fhp->fh_dentry);
 
-	if (iap->ia_size < inode->i_size) {
-		__be32 err;
+	if (iap->ia_size >= i_size_read(inode))
+		return nfs_ok;
 
-		err = nfsd_permission(&rqstp->rq_cred,
-				      fhp->fh_export, fhp->fh_dentry,
-				      NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
-		if (err)
-			return err;
-	}
-	return nfserrno(get_write_access(inode));
+	return nfsd_permission(&rqstp->rq_cred, fhp->fh_export, fhp->fh_dentry,
+			       NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
+}
+
+static __be32
+nfsd_get_write_access(struct svc_fh *fhp)
+{
+	return nfserrno(get_write_access(d_inode(fhp->fh_dentry)));
 }
 
 static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap)
@@ -545,12 +546,17 @@ nfsd_setattr(struct svc_rqst *rqstp, str
 	 * setattr call.
 	 */
 	if (size_change) {
-		err = nfsd_get_write_access(rqstp, fhp, iap);
+		err = nfsd_get_write_access(fhp);
 		if (err)
 			return err;
 	}
 
 	inode_lock(inode);
+	if (size_change) {
+		err = nfsd_may_truncate(rqstp, fhp, iap);
+		if (err)
+			goto out_unlock;
+	}
 	err = fh_fill_pre_attrs(fhp);
 	if (err)
 		goto out_unlock;
author maintainer
#71 lore raw

PATCH 69/403 NFSD: Encode only the status in NFS-ACL v2 GETACL error replies

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit ed4edddad19babf76b56882ad9600f5646b167a0 upstream.

The NFSv2 ACL GETACL reply is a union that carries file attributes and ACL data only when the status is NFS_OK. All error cases are void results. However, currently the NFSv2 ACL GETACL result encoder decides whether to append the "OK" body by testing only whether the file handle resolved to a positive dentry, not the actual reply status.

A GETACL request that resolves its file handle but then fails for another reason (an unsupported mask value, a getattr failure, or an ACL retrieval error) therefore appends file attributes and ACL data after the error status on the wire. Worse, when the mask is rejected, fh_getattr() hasn't been called at all, so those attributes are serialized from a zero-filled kstat and are junk.

The logic before the xdr_stream conversion used the reply status. Revert to that approach (but keep the xdr_stream conversion in place).

Fixes f8cba47344f7 ("NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream")
---
 fs/nfsd/nfs2acl.c |   31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)
fs/nfsd/nfs2acl.c +15 -16
@@ -248,22 +248,21 @@ nfsaclsvc_encode_getaclres(struct svc_rq
 
 	if (!svcxdr_encode_stat(xdr, resp->status))
 		return false;
-
-	if (dentry == NULL || d_really_is_negative(dentry))
-		return true;
-	inode = d_inode(dentry);
-
-	if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
-		return false;
-	if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
-		return false;
-
-	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
-				   resp->mask & NFS_ACL, 0))
-		return false;
-	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
-				   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
-		return false;
+	switch (resp->status) {
+	case nfs_ok:
+		inode = d_inode(dentry);
+		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+			return false;
+		if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
+			return false;
+		if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
+					   resp->mask & NFS_ACL, 0))
+			return false;
+		if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
+					   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
+			return false;
+		break;
+	}
 
 	return true;
 }
author maintainer
#72 lore raw

PATCH 70/403 NFSD: Fix off-by-one in DRC bucket pruning limit

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit d0728723c80dcb3432effd67c7e919b596004b1d upstream.

nfsd_prune_bucket_locked() evicts an entry before checking the freed count against @max. The check uses "++freed > max", which does not break until freed exceeds max, resulting in max + 1 evictions. Use ">=" so the limit stated in the function comment is honored.

---
 fs/nfsd/nfscache.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfscache.c +1 -1
@@ -286,7 +286,7 @@ nfsd_prune_bucket_locked(struct nfsd_net
 		nfsd_cacherep_unlink_locked(nn, b, rp);
 		list_add(&rp->c_lru, dispose);
 
-		if (max && ++freed > max)
+		if (max && ++freed >= max)
 			break;
 	}
 }
author maintainer
#73 lore raw

PATCH 71/403 NFSD: restart ssc_expire_umount walk after dropping nfsd_ssc_lock

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

commit 036c1b182f4da65363e79ec0ac276edc6b7296e5 upstream.

nfsd4_ssc_expire_umount() walks nn->nfsd_ssc_mount_list with list_for_each_entry_safe(ni, tmp, ...). For each expired entry it sets nsui_busy = true, drops nfsd_ssc_lock to run mntput() on the source vfsmount, then reacquires the lock to list_del + kfree the entry and continue iterating via the macro's saved tmp pointer.

The nsui_busy flag protects the current ni from concurrent nfsd4_ssc_setup_dul() finders during the lock-drop window, but it does not pin tmp. Another nfsd RPC thread that fails its source- server mount and reaches nfsd4_ssc_cancel_dul() will, during that same window, take nfsd_ssc_lock, list_del + kfree its own ssc_umount item, and release the lock. If that item is the saved tmp of the expire walk, the next iteration dereferences a freed nfsd4_ssc_umount_item.

Restart the walk from the head after the mntput() unlock window so no saved next pointer survives the lock-drop. The list is bounded by the number of active inter-server source mounts (typically small) and the expire delayed-work runs periodically rather than per-IO, so the restart is cheap.

Fixes f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.")
Assisted-by Claude:claude-opus-4-7
---
 fs/nfsd/nfs4state.c |   44 +++++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 19 deletions(-)
fs/nfsd/nfs4state.c +25 -19
@@ -6448,30 +6448,36 @@ static void nfsd4_ssc_shutdown_umount(st
 static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
 {
 	bool do_wakeup = false;
-	struct nfsd4_ssc_umount_item *ni = NULL;
-	struct nfsd4_ssc_umount_item *tmp;
+	struct nfsd4_ssc_umount_item *ni;
 
+restart:
 	spin_lock(&nn->nfsd_ssc_lock);
-	list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
-		if (time_after(jiffies, ni->nsui_expire)) {
-			if (refcount_read(&ni->nsui_refcnt) > 1)
-				continue;
+	list_for_each_entry(ni, &nn->nfsd_ssc_mount_list, nsui_list) {
+		if (!time_after(jiffies, ni->nsui_expire))
+			break;
+		if (refcount_read(&ni->nsui_refcnt) > 1)
+			continue;
 
-			/* mark being unmount */
-			ni->nsui_busy = true;
-			spin_unlock(&nn->nfsd_ssc_lock);
-			mntput(ni->nsui_vfsmount);
-			spin_lock(&nn->nfsd_ssc_lock);
+		/* Prevent concurrent setup during unmount */
+		ni->nsui_busy = true;
+		spin_unlock(&nn->nfsd_ssc_lock);
+		mntput(ni->nsui_vfsmount);
+		spin_lock(&nn->nfsd_ssc_lock);
 
-			/* waiters need to start from begin of list */
-			list_del(&ni->nsui_list);
-			kfree(ni);
+		/* Force concurrent scanners to restart */
+		list_del(&ni->nsui_list);
+		kfree(ni);
 
-			/* wakeup ssc_connect waiters */
-			do_wakeup = true;
-			continue;
-		}
-		break;
+		/* wakeup ssc_connect waiters */
+		do_wakeup = true;
+		/*
+		 * Concurrent nfsd4_ssc_cancel_dul() can free any item
+		 * on the list under nfsd_ssc_lock while mntput() runs
+		 * above.  Restart from the head; the list is short and
+		 * the expire worker is periodic, so this is cheap.
+		 */
+		spin_unlock(&nn->nfsd_ssc_lock);
+		goto restart;
 	}
 	if (do_wakeup)
 		wake_up_all(&nn->nfsd_ssc_waitq);
author maintainer
#74 lore raw

PATCH 72/403 NFSD: remove flawed WARN_ON_ONCE from nfsd_mode_check

In reply to Greg Kroah-Hartman

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

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

From: Mike Snitzer <[email protected]>

commit aa0cf48a448c5a9fe1a1e880899ecd589ce39e6e upstream.

The header for commit e75b23f9e323 ("nfsd: check d_can_lookup in fh_verify of directories") details the assumption that justified adding the WARN_ON_ONCE to nfsd_mode_check(), that assumption is invalid (in the case of NFS reexport).

When NFSD exports an NFS filesystem it is very possible for nfsd_mode_check() to encounter a @dentry that doesn't have i_op->lookup (see nfs_fhget()'s NFS_ATTR_FATTR_MOUNTPOINT and NFS_ATTR_FATTR_V4_REFERRAL handling, and d_flags_for_inode()).

So remove nfsd_mode_check()'s WARN_ON_ONCE(). The nfserr_notdir return on that branch must stay. It guards the subsequent lookup_one_unlocked() -> __lookup_slow() path, which calls inode->i_op->lookup() with no NULL check, so returning nfserr_notdir is what keeps a client LOOKUP into such a @dentry from dereferencing a NULL method pointer.

Fixes e75b23f9e323 ("nfsd: check d_can_lookup in fh_verify of directories")
---
 fs/nfsd/nfsfh.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
fs/nfsd/nfsfh.c +1 -3
@@ -69,10 +69,8 @@ nfsd_mode_check(struct dentry *dentry, u
 	if (requested == 0) /* the caller doesn't care */
 		return nfs_ok;
 	if (mode == requested) {
-		if (mode == S_IFDIR && !d_can_lookup(dentry)) {
-			WARN_ON_ONCE(1);
+		if (mode == S_IFDIR && !d_can_lookup(dentry))
 			return nfserr_notdir;
-		}
 		return nfs_ok;
 	}
 	if (mode == S_IFLNK) {
author maintainer
#75 lore raw

PATCH 73/403 nfsd: guard nfsd_serv deref in nfsd_file_net_dispose

In reply to Greg Kroah-Hartman

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

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

From: Chris Mason <[email protected]>

commit 9f1ddfc8cb9076592401a611eb3a44d36186d014 upstream.

nfsd_file_net_dispose() is the consumer side of l->freeme: the nfsd service thread loop calls it to drain entries that the filecache garbage collector and shrinker append via nfsd_file_dispose_list_delayed(). During per-net teardown, nn->nfsd_serv is cleared before the filecache laundrette is shut down, so the service thread can still run a dispose pass that finds more than eight entries on l->freeme and dereferences a NULL svc_serv:

    nfsd service thread loop
      nfsd_file_net_dispose(nn)
        if (!list_empty(&l->freeme)) {
            ...
            svc_wake_up(nn->nfsd_serv);   /* nn->nfsd_serv == NULL */
        }

The sibling helper nfsd_file_dispose_list_delayed() already documents this ordering and caches nn->nfsd_serv into a local before testing it for NULL. nfsd_file_net_dispose() was introduced with the same raw svc_wake_up(nn->nfsd_serv) call and never picked up the guard.

Fix by loading nn->nfsd_serv into a local svc_serv pointer and only calling svc_wake_up() when it is non-NULL, matching the pattern in nfsd_file_dispose_list_delayed().

Fixes ffb402596147 ("nfsd: Don't leave work of closing files to a work queue")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/filecache.c |   15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
fs/nfsd/filecache.c +12 -3
@@ -483,11 +483,20 @@ void nfsd_file_net_dispose(struct nfsd_n
 		for (i = 0; i < 8 && !list_empty(&l->freeme); i++)
 			list_move(l->freeme.next, &dispose);
 		spin_unlock(&l->lock);
-		if (!list_empty(&l->freeme))
-			/* Wake up another thread to share the work
+		if (!list_empty(&l->freeme)) {
+			/*
+			 * Wake up another thread to share the work
 			 * *before* doing any actual disposing.
+			 *
+			 * The filecache laundrette is shut down after
+			 * the nn->nfsd_serv pointer is cleared, but
+			 * before the svc_serv is freed.
 			 */
-			svc_wake_up(nn->nfsd_serv);
+			struct svc_serv *serv = nn->nfsd_serv;
+
+			if (serv)
+				svc_wake_up(serv);
+		}
 		nfsd_file_dispose_list(&dispose);
 	}
 }
author maintainer
#76 lore raw

PATCH 74/403 NFSv4.1: fix layout segment leak on the pnfs_layout_process() forget path

In reply to Greg Kroah-Hartman

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

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

From: Junrui Luo <[email protected]>

commit ee5a386cfe60f3f8286de16a9db8e1a08f0bc124 upstream.

When the server returns a new layout stateid while a valid one is still held, pnfs_layout_process() calls pnfs_mark_matching_lsegs_return() on the on-stack free_me list and jumps to out_forget. Segments whose reference count drops to zero are unlinked from lo->plh_segs and moved to free_me by mark_lseg_invalid(); for an idle cached segment the layout header holds the only reference, so this happens on the first decrement.

out_forget never drains free_me -- only the success path calls pnfs_free_lseg_list().

Commit 814b84971388 ("pNFS/NFSv4: Fix a layout segment leak in pnfs_layout_process()") added the drain; commit 08bd8dbe8882 ("pNFS/NFSv4: Try to return invalid layout in pnfs_layout_process()") removed it while switching the destination to lo->plh_return_segs, which is drained elsewhere. Commit fb700ef02676 ("NFSv4.1: Simplify layout return in pnfs_layout_process()") switched the destination back to free_me without restoring the drain.

Restore the pnfs_free_lseg_list() call.

Fixes fb700ef02676 ("NFSv4.1: Simplify layout return in pnfs_layout_process()")
Assisted-by Claude:claude-opus-5
---
 fs/nfs/pnfs.c |    1 +
 1 file changed, 1 insertion(+)
fs/nfs/pnfs.c +1 -0
@@ -2631,6 +2631,7 @@ out_forget:
 	spin_unlock(&ino->i_lock);
 	lseg->pls_layout = lo;
 	NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
+	pnfs_free_lseg_list(&free_me);
 	return ERR_PTR(-EAGAIN);
 }
 
author maintainer
#77 lore raw

PATCH 75/403 pNFS: Fix EBUSY check in pnfs_layout_need_return

In reply to Greg Kroah-Hartman

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

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

From: Tim Menninger <[email protected]>

commit 20358201777496fd0bb7b4336fcb4d3fc13cad28 upstream.

Commit 41d0a8ead9720 ("NFSv4/pnfs: Add support for the PNFS_LAYOUT_FILE_BULK_RETURN flag") replaced pnfs_layout_segments_returnable() in pnfs_layout_need_return() with a direct call to pnfs_mark_layout_stateid_return().

The old helper checked the return value against -EBUSY, but the replacement compares against EBUSY. Since pnfs_mark_layout_stateid_return() returns negative errno values, the -EBUSY case is never detected.

Fix the comparison in pnfs_layout_need_return() to check against -EBUSY.

Fixes 41d0a8ead9720 ("NFSv4/pnfs: Add support for the PNFS_LAYOUT_FILE_BULK_RETURN flag")
---
 fs/nfs/pnfs.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/pnfs.c +1 -1
@@ -1402,7 +1402,7 @@ pnfs_layout_need_return(struct pnfs_layo
 		return false;
 	return pnfs_mark_layout_stateid_return(lo, &lo->plh_return_segs,
 					       lo->plh_return_iomode,
-					       lo->plh_return_seq) != EBUSY;
+					       lo->plh_return_seq) != -EBUSY;
 }
 
 static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
author maintainer
#78 lore raw

PATCH 76/403 nfsd: release path refs on follow_down() error

In reply to Greg Kroah-Hartman

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

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

From: Chris Mason <[email protected]>

commit 6cba08dc1922140d260cfeb30bbda4ee1bf869d8 upstream.

nfsd_cross_mnt() initializes a local struct path with mntget() and dget() before calling follow_down(). On a negative return the error arm jumps to out without releasing those references:

    err = follow_down(&path, follow_flags);
    if (err < 0)
            goto out;

follow_down() never drops the caller's entry-time refs on any error sub-case; for example a pre-cross d_manage() failure leaves path untouched, so the mntget()/dget() taken on entry survive the call.

Every other early-exit arm in nfsd_cross_mnt() (other-namespace return, IS_ERR(exp2), and the success tail after the swap) already calls path_put(&path); the err < 0 arm is the lone omission. The leak inflates mnt_count and d_count on each failed cross-mount, blocking umount and pinning dentries against the shrinker, and is reachable by any authenticated NFS client through nfsd_lookup_dentry or the NFSv4 READDIR encode path.

Fix by calling path_put(&path) before the goto out in the err < 0 arm so the entry-time refs are released on all follow_down() error returns.

Fixes cc53ce53c869 ("Add a dentry op to allow processes to be held during pathwalk transit")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/vfs.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfsd/vfs.c +3 -1
@@ -133,8 +133,10 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
 		follow_flags = LOOKUP_AUTOMOUNT;
 
 	err = follow_down(&path, follow_flags);
-	if (err < 0)
+	if (err < 0) {
+		path_put(&path);
 		goto out;
+	}
 	if (path.mnt == exp->ex_path.mnt && path.dentry == dentry &&
 	    nfsd_mountpoint(dentry, exp) == 2) {
 		/* This is only a mountpoint in some other namespace */
author maintainer
#79 lore raw

PATCH 77/403 nfsd: Reset write verifier when async COPY writeback fails

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit f5cb2276954cb80987a93ef9f9dfbfdbfc0f10b9 upstream.

Async COPY captures nn->writeverf at request time and reports it to the client via CB_OFFLOAD after the worker kthread completes. When the post-copy vfs_fsync_range() or filemap_check_wb_err() in _nfsd_copy_file_range() reports an error, the worker correctly leaves NFSD4_COPY_F_COMMITTED clear so that CB_OFFLOAD encodes wr_stable_how as NFS_UNSTABLE, but the server's write verifier is not rotated.

A client that receives NFS_UNSTABLE in CB_OFFLOAD follows up with COMMIT to make the copied data durable. With the verifier unchanged, COMMIT returns the same value the client just received via CB_OFFLOAD, and the client concludes the copy is durable -- silently dropping the data whose writeback in fact failed. This violates the UNSTABLE+COMMIT durability contract (RFC 7862 section 15.1, RFC 8881 section 18.32) and matches the bug just fixed in nfsd_vfs_write() and nfsd_commit().

Rotate nn->writeverf at the writeback-failure site. The async COPY worker has no svc_rqst, so commit_reset_write_verifier() is not available here; calling nfsd_reset_write_verifier() directly mirrors the trace-less reset already used by nfsd_file_check_write_error() for the same purpose. Filter out -EAGAIN and -ESTALE, matching commit_reset_write_verifier(), since neither indicates a durable-storage failure.

Fixes eac0b17a77fb ("NFSD add vfs_fsync after async copy is done")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfs4proc.c |    2 ++
 1 file changed, 2 insertions(+)
fs/nfsd/nfs4proc.c +2 -0
@@ -1667,6 +1667,8 @@ static ssize_t _nfsd_copy_file_range(str
 			status = filemap_check_wb_err(dst->f_mapping, since);
 		if (!status)
 			set_bit(NFSD4_COPY_F_COMMITTED, &copy->cp_flags);
+		else if (status != -EAGAIN && status != -ESTALE)
+			nfsd_reset_write_verifier(copy->cp_nn);
 	}
 	return bytes_copied;
 }
author maintainer
#80 lore raw

PATCH 78/403 nfsd: return NFS4ERR_NOTSUPP for unsupported netloc4 types

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 45b06a75086f331f52cbb81223a59421d43f8809 upstream.

nfsd4_decode_nl4_server() handled only NL4_NETADDR and returned nfserr_bad_xdr for NL4_NAME and NL4_URL. Those forms are well-formed XDR, so BADXDR is misleading -- the request is unsupported, not malformed.

Decode and discard the utf8str_cis for NL4_NAME and NL4_URL to keep the stream consistent, and return nfserr_notsupp. nfsd4_proc_compound() honors a decode-time op->status, so the op fails without executing.

---
 fs/nfsd/nfs4xdr.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
fs/nfsd/nfs4xdr.c +13 -0
@@ -1946,6 +1946,7 @@ static __be32 nfsd4_decode_nl4_server(st
 {
 	struct nfs42_netaddr *naddr;
 	__be32 *p;
+	u32 str_len;
 
 	if (xdr_stream_decode_u32(argp->xdr, &ns->nl4_type) < 0)
 		return nfserr_bad_xdr;
@@ -1975,6 +1976,18 @@ static __be32 nfsd4_decode_nl4_server(st
 			return nfserr_bad_xdr;
 		memcpy(naddr->addr, p, naddr->addr_len);
 		break;
+	case NL4_NAME:
+	case NL4_URL:
+		/*
+		 * Well-formed XDR, but only NL4_NETADDR is supported. Consume
+		 * the utf8str_cis to keep the stream aligned, then return
+		 * NFS4ERR_NOTSUPP rather than the misleading NFS4ERR_BADXDR.
+		 */
+		if (xdr_stream_decode_u32(argp->xdr, &str_len) < 0)
+			return nfserr_bad_xdr;
+		if (!xdr_inline_decode(argp->xdr, str_len))
+			return nfserr_bad_xdr;
+		return nfserr_notsupp;
 	default:
 		return nfserr_bad_xdr;
 	}
author maintainer
#81 lore raw

PATCH 79/403 nfsd: sample writeback error cursor before async COPY loop

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit 20a67a7d18221af736f124770c2c5e859b479046 upstream.

_nfsd_copy_file_range() samples dst->f_wb_err into "since" after the copy loop, then uses it to detect writeback errors via filemap_check_wb_err() once vfs_fsync_range() returns. Because the nfsd_file cache reuses a single struct file across requests targeting the same inode, a concurrent COMMIT or stable WRITE on dst advances dst->f_wb_err to the current mapping->wb_err via file_check_and_advance_wb_err() during its own vfs_fsync_range(). If that advancement lands between the writeback error appearing in mapping->wb_err and the COPY worker sampling "since", the worker captures the already-advanced cursor, errseq_check() sees cur == since and returns zero, and NFSD4_COPY_F_COMMITTED is set even though writeback failed. CB_OFFLOAD then encodes wr_stable_how = FILE_SYNC4, the client treats the copied data as durable, and the failure becomes silent data loss.

Sample since once at the start of the function. The cursor then reflects state in effect before this COPY issues any writes, and filemap_check_wb_err() detects any error that occurs during the copy regardless of which thread first observes it. This matches the pattern used by nfsd_vfs_write() and nfsd4_clone_file_range().

---
 fs/nfsd/nfs4proc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4proc.c +1 -1
@@ -1645,6 +1645,7 @@ static ssize_t _nfsd_copy_file_range(str
 	/* See RFC 7862 p.67: */
 	if (bytes_total == 0)
 		bytes_total = ULLONG_MAX;
+	since = READ_ONCE(dst->f_wb_err);
 	do {
 		/* Only async copies can be stopped here */
 		if (kthread_should_stop())
@@ -1660,7 +1661,6 @@ static ssize_t _nfsd_copy_file_range(str
 	} while (bytes_total > 0 && nfsd4_copy_is_async(copy));
 	/* for a non-zero asynchronous copy do a commit of data */
 	if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) {
-		since = READ_ONCE(dst->f_wb_err);
 		end = copy->cp_dst_pos + copy->cp_res.wr_bytes_written - 1;
 		status = vfs_fsync_range(dst, copy->cp_dst_pos, end, 0);
 		if (!status)
author maintainer
#82 lore raw

PATCH 80/403 nfsd: set SC_STATUS_FREED in nfsd4_drop_revoked_stid for delegations

In reply to Greg Kroah-Hartman

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

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

From: Zhenghang Xiao <[email protected]>

commit 650d370cfbc66a96dd14d517bd704689b5bda4e5 upstream.

nfsd4_drop_revoked_stid() handles FREE_STATEID for admin-revoked delegations but does not set SC_STATUS_FREED before releasing cl_lock. revoke_delegation() uses this flag to detect whether FREE_STATEID has already processed the delegation -- without it, the freed delegation is added to cl_revoked via list_add(), producing a use-after-free when cl_revoked is later traversed in __destroy_client().

The SC_STATUS_REVOKED path in nfsd4_free_stateid() (line 7983) already sets SC_STATUS_FREED correctly. Apply the same pattern to the SC_STATUS_ADMIN_REVOKED path in nfsd4_drop_revoked_stid().

---
 fs/nfsd/nfs4state.c |    1 +
 1 file changed, 1 insertion(+)
fs/nfsd/nfs4state.c +1 -0
@@ -4881,6 +4881,7 @@ static void nfsd4_drop_revoked_stid(stru
 	case SC_TYPE_DELEG:
 		dp = delegstateid(s);
 		list_del_init(&dp->dl_recall_lru);
+		s->sc_status |= SC_STATUS_FREED;
 		spin_unlock(&cl->cl_lock);
 		nfs4_put_stid(s);
 		break;
author maintainer
#83 lore raw

PATCH 81/403 nfsd: size fh_verify server sockaddr slot by xpt_locallen

In reply to Greg Kroah-Hartman

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

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

From: Chris Mason <[email protected]>

commit 71d068490098b1d23c63b2345e40675d3a1ca763 upstream.

The nfsd_fh_verify and nfsd_fh_verify_err tracepoints declare the server sockaddr slot sized by xpt_remotelen but fill it from xpt_local using xpt_locallen:

    TP_STRUCT__entry(
            ...
            __sockaddr(server, rqstp->rq_xprt->xpt_remotelen)
            ...
    )
    TP_fast_assign(
            ...
            __assign_sockaddr(server, &rqstp->rq_xprt->xpt_local,
                              rqstp->rq_xprt->xpt_locallen);
            ...
    )

When xpt_locallen exceeds xpt_remotelen, __assign_sockaddr's memcpy writes past the reserved ring-buffer slot. In the reverse direction (xpt_locallen < xpt_remotelen) the slot is oversized and the unwritten tail leaks prior ring-buffer contents to trace consumers.

The write-past-end case is reachable on NFS/UDP. svc_xprt_set_remote() is only called from svc_tcp_accept() (net/sunrpc/svcsock.c) and from the RDMA connect path; svc_create_socket() for UDP calls only svc_xprt_set_local(), so xpt_remotelen stays 0 for the xprt's lifetime. Every fh_verify trace for an NFSv2/v3-over-UDP request then copies 16 or 28 bytes from xpt_local into a zero-byte slot.

The other NFSD tracepoints that record the server address (NFSD_TRACE_PROC_CALL_FIELDS, NFSD_TRACE_PROC_RES_FIELDS, SVC_RQST_ENDPOINT_FIELDS) already size the server slot by xpt_locallen; nfsd_fh_verify and nfsd_fh_verify_err were the only exceptions.

Fix by sizing the server slot with xpt_locallen so the declared slot matches the copy length. The client slot and its assignment already agree on xpt_remotelen and are left untouched.

Fixes 051382885552 ("NFSD: Instrument fh_verify()")
Fixes 948755efc951 ("NFSD: Replace dprintk() call site in fh_verify()")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/trace.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/trace.h +2 -2
@@ -205,7 +205,7 @@ TRACE_EVENT_CONDITION(nfsd_fh_verify,
 	TP_CONDITION(rqstp != NULL),
 	TP_STRUCT__entry(
 		__field(unsigned int, netns_ino)
-		__sockaddr(server, rqstp->rq_xprt->xpt_remotelen)
+		__sockaddr(server, rqstp->rq_xprt->xpt_locallen)
 		__sockaddr(client, rqstp->rq_xprt->xpt_remotelen)
 		__field(u32, xid)
 		__field(u32, fh_hash)
@@ -244,7 +244,7 @@ TRACE_EVENT_CONDITION(nfsd_fh_verify_err
 	TP_CONDITION(rqstp != NULL && error),
 	TP_STRUCT__entry(
 		__field(unsigned int, netns_ino)
-		__sockaddr(server, rqstp->rq_xprt->xpt_remotelen)
+		__sockaddr(server, rqstp->rq_xprt->xpt_locallen)
 		__sockaddr(client, rqstp->rq_xprt->xpt_remotelen)
 		__field(u32, xid)
 		__field(u32, fh_hash)
author maintainer
#84 lore raw

PATCH 82/403 nfsd: validate symlink target length in NFSv4 CREATE

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 041f57056e5fb9c80adc088269322d2c61074406 upstream.

nfsd4_decode_create() accepts an unbounded cr_datalen from the wire for NF4LNK symlink targets, allowing a client to force a kmalloc of up to the maximum RPC payload size (several MiB) per COMPOUND op that persists until compound teardown. The VFS rejects oversized targets with ENAMETOOLONG, but the allocation has already occurred.

Reject cr_datalen == 0 early with nfserr_inval and cr_datalen greater than NFS4_MAXPATHLEN (PATH_MAX) with nfserr_nametoolong to bound the allocation.

---
 fs/nfsd/nfs4xdr.c |    4 ++++
 1 file changed, 4 insertions(+)
fs/nfsd/nfs4xdr.c +4 -0
@@ -800,6 +800,10 @@ nfsd4_decode_create(struct nfsd4_compoun
 	case NF4LNK:
 		if (xdr_stream_decode_u32(argp->xdr, &create->cr_datalen) < 0)
 			return nfserr_bad_xdr;
+		if (create->cr_datalen == 0)
+			return nfserr_inval;
+		if (create->cr_datalen > NFS4_MAXPATHLEN)
+			return nfserr_nametoolong;
 		p = xdr_inline_decode(argp->xdr, create->cr_datalen);
 		if (!p)
 			return nfserr_bad_xdr;
author maintainer
#85 lore raw

PATCH 83/403 nfsd: add fh_want_write() for early-verified SETATTR in nfsd_proc_setattr()

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 4e475be769aa9f7a2c1ce55a2b8592cfccacddcc upstream.

The BOTH_TIME_SET branch calls fh_verify() early so setattr_prepare() can inspect the dentry. This causes nfsd_setattr() to skip fh_want_write(), so notify_change() runs without a mount write reference.

Add the missing fh_want_write() call after the early fh_verify().

Fixes cc265089ce1b ("nfsd: Disable NFSv2 timestamp workaround for NFSv3+")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfsproc.c |    7 +++++++
 1 file changed, 7 insertions(+)
fs/nfsd/nfsproc.c +7 -0
@@ -81,6 +81,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp
 		.na_iattr	= iap,
 	};
 	struct svc_fh *fhp;
+	int hosterr;
 
 	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
 		SVCFH_fmt(&argp->fh),
@@ -116,6 +117,12 @@ nfsd_proc_setattr(struct svc_rqst *rqstp
 		if (resp->status != nfs_ok)
 			goto out;
 
+		hosterr = fh_want_write(fhp);
+		if (hosterr) {
+			resp->status = nfserrno(hosterr);
+			goto out;
+		}
+
 		if (delta < 0)
 			delta = -delta;
 		if (delta < MAX_TOUCH_TIME_ERROR &&
author maintainer
#86 lore raw

PATCH 84/403 nfsd: add filehandle match check to nfsd4_delegreturn()

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 04cce9d79f2b1a114f7128e08bf60a473e10f1ec upstream.

nfsd4_delegreturn() is the only stateful NFSv4 operation that does not call nfs4_check_fh() to verify the delegation's file matches cstate->current_fh. A client can DELEGRETURN with a mismatched filehandle, destroying the correct delegation but waking the wrong inode's waiters.

Add the missing nfs4_check_fh() call after the generation check.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfs4state.c |    4 ++++
 1 file changed, 4 insertions(+)
fs/nfsd/nfs4state.c +4 -0
@@ -7643,6 +7643,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp
 	if (status)
 		goto put_stateid;
 
+	status = nfs4_check_fh(&cstate->current_fh, &dp->dl_stid);
+	if (status)
+		goto put_stateid;
+
 	trace_nfsd_deleg_return(stateid);
 	destroy_delegation(dp);
 	smp_mb__after_atomic();
author maintainer
#87 lore raw

PATCH 85/403 nfsd: add missing read barrier to rpc_status_get dumpit seqcount retry

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit a71f161a857117e8e0264deb7d14fff5c98adcf5 upstream.

The hand-rolled seqcount-like protocol in nfsd_nl_rpc_status_get_dumpit() is missing a read memory barrier (smp_rmb) before its second counter check. The standard kernel read_seqcount_retry() includes smp_rmb() to ensure that all data reads complete before the counter is re-checked.

Without this barrier, on weakly-ordered architectures (ARM, POWER), the CPU may reorder field reads past the second counter check, making the retry logic ineffective: it could observe a consistent counter pair while reading fields that have been concurrently modified by the writer.

Add smp_rmb() before the second counter check to order the field reads ahead of it, matching the barrier semantics of the standard seqcount read-side. The begin-side smp_load_acquire() already pairs with the smp_store_release() in nfsd_dispatch(); with the smp_rmb() now ordering the field reads, the retry check no longer needs acquire semantics and reads the counter with a plain READ_ONCE(), as read_seqcount_retry() does.

Fixes bd9d6a3efa97 ("NFSD: add rpc_status netlink support")
Assisted-by Claude:claude-opus-4-8
[ cel: Use READ_ONCE instead of smp_load_acquire() ]
---
 fs/nfsd/nfsctl.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
fs/nfsd/nfsctl.c +7 -4
@@ -1635,11 +1635,14 @@ int nfsd_nl_rpc_status_get_dumpit(struct
 #endif /* CONFIG_NFSD_V4 */
 
 			/*
-			 * Acquire rq_status_counter before reporting the rqst
-			 * fields to the user.
+			 * Read-side load-load fence: order the field reads
+			 * above before the counter re-read below, mirroring
+			 * the smp_rmb() in the standard seqcount retry. The
+			 * begin-side smp_load_acquire() above pairs with the
+			 * smp_store_release() in nfsd_dispatch().
 			 */
-			if (smp_load_acquire(&rqstp->rq_status_counter) !=
-			    status_counter)
+			smp_rmb();
+			if (READ_ONCE(rqstp->rq_status_counter) != status_counter)
 				continue;
 
 			ret = nfsd_genl_rpc_status_compose_msg(skb, cb,
author maintainer
#88 lore raw

PATCH 86/403 nfsd: block non-SAVEFH ops after FOREIGN PUTFH to prevent NULL deref

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit c59738a00aa51b16adc1b5ceb7c80877168efb4d upstream.

When CONFIG_NFSD_V4_2_INTER_SSC is enabled, nfsd4_putfh() can return success with fh_dentry and fh_export both NULL if fh_verify() returns nfserr_stale and putfh->no_verify is true. The NFSD4_FH_FOREIGN flag is set, but the compound dispatch loop only uses this flag to bypass the nfserr_nofilehandle check -- it does not prevent subsequent ops from running with a NULL fh_dentry.

A remote client can exploit this by crafting a COMPOUND that includes an inter-SSC COPY (which causes check_if_stalefh_allowed() to set no_verify=true on the saved PUTFH) with an additional op inserted between the source PUTFH and SAVEFH. For example, SETATTR calls fh_want_write() which dereferences fh_export->ex_path.mnt without calling fh_verify() first, causing a NULL pointer dereference in the nfsd kthread.

Fix this by gating the dispatch loop: when NFSD4_FH_FOREIGN is set and fh_dentry is NULL, only OP_SAVEFH (needed for the inter-SSC flow) and ops with ALLOWED_WITHOUT_FH (which don't need a resolved filehandle) may proceed. All other ops receive nfserr_stale, per RFC 7862 Section 15.2.3 which specifies that foreign filehandle validation is deferred to the consuming operation and NFS4ERR_STALE returned at that point.

Fixes b9e8638e3d9e ("NFSD: allow inter server COPY to have a STALE source server fh")
Assisted-by Claude:claude-opus-4-6
---
 fs/nfsd/nfs4proc.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)
fs/nfsd/nfs4proc.c +16 -3
@@ -2743,9 +2743,22 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 				op->status = nfsd4_open_omfg(rqstp, cstate, op);
 			goto encode_op;
 		}
-		if (!current_fh->fh_dentry &&
-				!HAS_FH_FLAG(current_fh, NFSD4_FH_FOREIGN)) {
-			if (!(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
+		if (!current_fh->fh_dentry) {
+			if (HAS_FH_FLAG(current_fh, NFSD4_FH_FOREIGN)) {
+				/*
+				 * FOREIGN fh from inter-SSC PUTFH: only
+				 * SAVEFH may proceed with a NULL fh_dentry.
+				 * Per RFC 7862 S15.2.3, validation of a
+				 * foreign fh is deferred to the operation
+				 * that consumes it, and NFS4ERR_STALE is
+				 * returned at that point.
+				 */
+				if (op->opnum != OP_SAVEFH &&
+				    !(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
+					op->status = nfserr_stale;
+					goto encode_op;
+				}
+			} else if (!(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
 				op->status = nfserr_nofilehandle;
 				goto encode_op;
 			}
author maintainer
#89 lore raw

PATCH 87/403 nfsd: check client ownership when cancelling a copy-notify stateid

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 6bdbfab96e0cf25e5f57dac5c09dc1749751a4bf upstream.

On the OFFLOAD_CANCEL path (clp != NULL), manage_cpntf_state() freed the target cpntf state without checking ownership. The lookup key st->si_opaque.so_id is allocated cyclically (guessable) and the embedded clientid is the fixed per-net nn->s2s_cp_cl_id, so any authenticated NFSv4.2 client could cancel and free another client's copy-notify stateid.

Compare the creating clientid recorded in state->cp_p_clid against the requesting client's cl_clientid and return nfserr_bad_stateid on a mismatch instead of freeing the entry.

Fixes ce0887ac96d3 ("NFSD add nfs4 inter ssc to nfsd4_copy")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfs4state.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +12 -2
@@ -7105,10 +7105,20 @@ __be32 manage_cpntf_state(struct nfsd_ne
 			state = NULL;
 			goto unlock;
 		}
-		if (!clp)
+		if (!clp) {
 			refcount_inc(&state->cp_stateid.cs_count);
-		else
+		} else if (memcmp(&clp->cl_clientid, &state->cp_p_clid,
+				  sizeof(clientid_t))) {
+			/*
+			 * OFFLOAD_CANCEL: only the creating client may cancel.
+			 * so_id is guessable, so without this check any client
+			 * could free another's cpntf state.
+			 */
+			state = NULL;
+			goto unlock;
+		} else {
 			_free_cpntf_state_locked(nn, state);
+		}
 	}
 unlock:
 	spin_unlock(&nn->s2s_cp_lock);
author maintainer
#90 lore raw

PATCH 88/403 nfsd: clear opcnt on compound arg release to prevent OOB read

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit ae4c38555e81563b8dc5eae55ffd70f0ea97aa5a upstream.

nfsd4_release_compoundargs() resets args->ops to the inline iops[8] array when the dynamically-allocated ops buffer is freed, but leaves args->opcnt at its original value (which can be up to 200 for NFSv4.1+ compounds).

If rq_status_counter is stuck at an odd value (which can happen when nfsd_dispatch() hits an error path after setting it odd), the RPC status dumpit handler reads min(opcnt, 16) entries from args->ops[]. Since iops only has 8 elements and is the last field in struct nfsd4_compoundargs, reading indices 8-15 accesses adjacent slab memory and leaks it to userspace via netlink.

Zero opcnt unconditionally in nfsd4_release_compoundargs() so stale compound metadata is never exposed through the status interface.

Fixes bd9d6a3efa97 ("NFSD: add rpc_status netlink support")
Assisted-by Claude:claude-opus-4-8
[ cel: Remove the kvfree_rcu_mightsleep() sleep from the exposure window ]
---
 fs/nfsd/nfs4xdr.c |    1 +
 1 file changed, 1 insertion(+)
fs/nfsd/nfs4xdr.c +1 -0
@@ -5876,6 +5876,7 @@ void nfsd4_release_compoundargs(struct s
 {
 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
 
+	args->opcnt = 0;
 	if (args->ops != args->iops) {
 		vfree(args->ops);
 		args->ops = args->iops;
author maintainer
#91 lore raw

PATCH 89/403 nfsd: defer vfree of compound ops to fix rpc_status UAF

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit fca26a3fc19ed02278aa2a150af82d43db0302cb upstream.

The rpc_status netlink dumpit walks every in-flight svc_rqst under rcu_read_lock and, for NFSv4 requests, reads opnums out of args->ops[]. But args->ops is a separate vmalloc buffer freed synchronously by vfree() in nfsd4_release_compoundargs() at the end of every compound. The dumpit's rcu_read_lock pins the svc_rqst struct itself (freed via kfree_rcu), but nothing defers the vfree of the ops buffer across the RCU grace period. A concurrent compound completion can therefore free the buffer while the dumpit is reading it — a use-after-free on vmalloc memory.

The trailing seqcount recheck (smp_load_acquire of rq_status_counter) cannot undo a load that already retired against freed memory.

Fix by replacing vfree(args->ops) with kvfree_rcu_mightsleep(), which defers the free until after an RCU grace period. This makes the existing rcu_read_lock in the dumpit sufficient to protect the read. The tradeoff is that completed compound ops buffers (up to 200 * sizeof(struct nfsd4_op)) persist in memory slightly longer, across one grace period, before being reclaimed.

Fixes bd9d6a3efa97 ("NFSD: add rpc_status netlink support")
Assisted-by Claude:claude-opus-4-6
---
 fs/nfsd/nfs4xdr.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfsd/nfs4xdr.c +3 -1
@@ -5878,8 +5878,10 @@ void nfsd4_release_compoundargs(struct s
 
 	args->opcnt = 0;
 	if (args->ops != args->iops) {
-		vfree(args->ops);
+		void *old_ops = args->ops;
+
 		args->ops = args->iops;
+		kvfree_rcu_mightsleep(old_ops);
 	}
 	while (args->to_free) {
 		struct svcxdr_tmpbuf *tb = args->to_free;
author maintainer
#92 lore raw

PATCH 90/403 nfsd: drop the stateid, not the stateowner, on seqid_op replay retry

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 5e4627d3513e60accfce9d5f4c7fa95251ef93d6 upstream.

In nfs4_preprocess_seqid_op() the stateid is obtained from nfsd4_lookup_stateid(), which holds a reference on the nfs4_stid (sc_count) but takes no reference on the stateowner. openlockstateid() merely casts that stid and likewise takes no reference.

When nfsd4_cstate_assign_replay() returns -EAGAIN (the replay owner is being torn down, RP_UNHASHED) it has not taken a stateowner reference on that path. The error handling nevertheless called nfs4_put_stateowner(stp->st_stateowner), dropping an so_count reference the function never acquired -- risking a stateowner refcount underflow and use-after-free -- while leaking the sc_count reference held on the stid. The leaked stid reference can also stall a concurrent nfsd4_close_open_stateid() waiting for sc_count to drop.

Drop the reference actually held -- the stid -- before retrying. The stateowner stays alive through the reference held by the stid. This mirrors the open path in nfsd4_process_open1(), where the put balances a reference that path explicitly holds on the stateowner.

Fixes eec762080008 ("nfsd: replace rp_mutex to avoid deadlock in move_to_close_lru()")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfs4state.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4state.c +1 -1
@@ -7405,7 +7405,7 @@ retry:
 		return status;
 	stp = openlockstateid(s);
 	if (nfsd4_cstate_assign_replay(cstate, stp->st_stateowner) == -EAGAIN) {
-		nfs4_put_stateowner(stp->st_stateowner);
+		nfs4_put_stid(&stp->st_stid);
 		goto retry;
 	}
 
author maintainer
#93 lore raw

PATCH 91/403 nfsd: fix BUG_ON in nfsd4_alloc_layout_stateid on racing delegation revoke

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit ca94ba36172046be6a694a7986f6931e47ed4d51 upstream.

nfsd4_alloc_layout_stateid reads fp->fi_deleg_file without holding fi_lock when the parent stateid is a delegation. A concurrent delegation revoke via the laundromat can clear fi_deleg_file under fi_lock, causing nfsd_file_get() to return NULL and triggering the BUG_ON.

This race is client-reachable: two NFS clients can trigger it by having one hold a delegation while another opens the same file to force a recall. When the first client doesn't respond to the recall, the laundromat revokes it. A concurrent LAYOUTGET from any client using the delegation stateid hits the race window.

Fix this by taking fi_lock around the fi_deleg_file read in the SC_TYPE_DELEG path, matching the locking discipline of the find_any_file() arm, and replacing the BUG_ON with a graceful error return that cleans up the partially-initialized layout stateid.

Fixes c5c707f96fc9 ("nfsd: implement pNFS layout recalls")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfs4layouts.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
fs/nfsd/nfs4layouts.c +9 -3
@@ -249,11 +249,17 @@ nfsd4_alloc_layout_stateid(struct nfsd4_
 	nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops,
 			NFSPROC4_CLNT_CB_LAYOUT);
 
-	if (parent->sc_type == SC_TYPE_DELEG)
+	if (parent->sc_type == SC_TYPE_DELEG) {
+		spin_lock(&fp->fi_lock);
 		ls->ls_file = nfsd_file_get(fp->fi_deleg_file);
-	else
+		spin_unlock(&fp->fi_lock);
+	} else {
 		ls->ls_file = find_any_file(fp);
-	BUG_ON(!ls->ls_file);
+	}
+	if (!ls->ls_file) {
+		nfs4_put_stid(stp);
+		return NULL;
+	}
 
 	if (nfsd4_layout_setlease(ls)) {
 		nfs4_put_stid(stp);
author maintainer
#94 lore raw

PATCH 92/403 nfsd: fix cpntf publish race in nfs4_init_cp_state

In reply to Greg Kroah-Hartman

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

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

From: Chris Mason <[email protected]>

commit be3a5c1d857b0dcbc11796cea603ef25834f75b2 upstream.

nfs4_alloc_init_cpntf_state() published the new cpntf entry into the s2s_cp_stateids IDR (with cs_type set) in one s2s_cp_lock section, then took the lock again to list_add() it onto p_stid->sc_cp_list. In the gap the entry is reachable by so_id but cp_list is still {NULL,NULL} from kzalloc. A racing OFFLOAD_CANCEL (so_id is echoed to the client as cnr_stateid, so any NFSv4.2 client can drive it) reaches manage_cpntf_state() -> _free_cpntf_state_locked() and does list_del() on the zeroed list_head, oopsing the server.

Fold the cs_type assignment and the list_add() into the same critical section as idr_alloc_cyclic(), so a concurrent lookup either misses the entry or sees a fully linked cp_list. INIT_LIST_HEAD() the entry after allocation and switch _free_cpntf_state_locked() to list_del_init() so a stale unlink is a no-op. nfs4_init_copy_state() passes NULL p_stid and skips the list_add, preserving NFS4_COPY_STID semantics.

Fixes 624322f1adc5 ("NFSD add COPY_NOTIFY operation")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfs4state.c |   35 +++++++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 10 deletions(-)
fs/nfsd/nfs4state.c +25 -10
@@ -972,7 +972,7 @@ out_free:
  * Create a unique stateid_t to represent each COPY.
  */
 static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid,
-			      unsigned char cs_type)
+			      unsigned char cs_type, struct nfs4_stid *p_stid)
 {
 	int new_id;
 
@@ -982,19 +982,34 @@ static int nfs4_init_cp_state(struct nfs
 	idr_preload(GFP_KERNEL);
 	spin_lock(&nn->s2s_cp_lock);
 	new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT);
-	stid->cs_stid.si_opaque.so_id = new_id;
-	stid->cs_stid.si_generation = 1;
+	if (new_id >= 0) {
+		stid->cs_stid.si_opaque.so_id = new_id;
+		stid->cs_stid.si_generation = 1;
+		/*
+		 * Set cs_type and link onto sc_cp_list under the same lock
+		 * that installed the IDR entry, so a concurrent
+		 * manage_cpntf_state() sees either no entry or a fully
+		 * linked cp_list.
+		 */
+		stid->cs_type = cs_type;
+		if (p_stid) {
+			struct nfs4_cpntf_state *cps =
+				container_of(stid, struct nfs4_cpntf_state,
+					     cp_stateid);
+
+			list_add(&cps->cp_list, &p_stid->sc_cp_list);
+		}
+	}
 	spin_unlock(&nn->s2s_cp_lock);
 	idr_preload_end();
 	if (new_id < 0)
 		return 0;
-	stid->cs_type = cs_type;
 	return 1;
 }
 
 int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
 {
-	return nfs4_init_cp_state(nn, &copy->cp_stateid, NFS4_COPY_STID);
+	return nfs4_init_cp_state(nn, &copy->cp_stateid, NFS4_COPY_STID, NULL);
 }
 
 struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
@@ -1005,13 +1020,13 @@ struct nfs4_cpntf_state *nfs4_alloc_init
 	cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL);
 	if (!cps)
 		return NULL;
+	/* So a stale list_del_init() before linking is a no-op. */
+	INIT_LIST_HEAD(&cps->cp_list);
 	cps->cpntf_time = ktime_get_boottime_seconds();
 	refcount_set(&cps->cp_stateid.cs_count, 1);
-	if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID))
+	if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID,
+				p_stid))
 		goto out_free;
-	spin_lock(&nn->s2s_cp_lock);
-	list_add(&cps->cp_list, &p_stid->sc_cp_list);
-	spin_unlock(&nn->s2s_cp_lock);
 	return cps;
 out_free:
 	kfree(cps);
@@ -7077,7 +7092,7 @@ _free_cpntf_state_locked(struct nfsd_net
 	WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID);
 	if (!refcount_dec_and_test(&cps->cp_stateid.cs_count))
 		return;
-	list_del(&cps->cp_list);
+	list_del_init(&cps->cp_list);
 	idr_remove(&nn->s2s_cp_stateids,
 		   cps->cp_stateid.cs_stid.si_opaque.so_id);
 	kfree(cps);
author maintainer
#95 lore raw

PATCH 93/403 nfsd: fix dentry ref leak on V4ROOT export filehandle lookup

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 6247023fbbec1325029f2d5f2a7cdc0f9f9ea15a upstream.

nfsd_set_fh_dentry() leaks the dentry reference from exportfs_decode_fh_raw() when the NFS3_FHSIZE or NFS_FHSIZE switch cases detect NFSEXP_V4ROOT and goto out. The out: label calls exp_put() but never dput(dentry), and fhp->fh_dentry was never assigned so fh_put() cannot compensate.

A crafted NFSv3 filehandle targeting a V4ROOT export's fsid triggers the leak on every request.

Fixes ef7f6c4904d0 ("nfsd: move V4ROOT version check to nfsd_set_fh_dentry()")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfsfh.c |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/nfsd/nfsfh.c +6 -2
@@ -276,15 +276,19 @@ static __be32 nfsd_set_fh_dentry(struct
 		if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOWCC)
 			fhp->fh_no_wcc = true;
 		fhp->fh_64bit_cookies = true;
-		if (exp->ex_flags & NFSEXP_V4ROOT)
+		if (exp->ex_flags & NFSEXP_V4ROOT) {
+			dput(dentry);
 			goto out;
+		}
 		break;
 	case NFS_FHSIZE:
 		fhp->fh_no_wcc = true;
 		if (EX_WGATHER(exp))
 			fhp->fh_use_wgather = true;
-		if (exp->ex_flags & NFSEXP_V4ROOT)
+		if (exp->ex_flags & NFSEXP_V4ROOT) {
+			dput(dentry);
 			goto out;
+		}
 	}
 
 	fhp->fh_dentry = dentry;
author maintainer
#96 lore raw

PATCH 94/403 nfsd: fix nfsd_file leak on inter-server COPY setup failure

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 88a76145451d703eedd867b5989bf73d17340399 upstream.

When nfsd4_setup_inter_ssc() fails, nfsd4_copy() returns nfserr_offload_denied directly, bypassing the out: label where release_copy_files() would drop the nf_dst reference taken by nfs4_preprocess_stateid_op(). Each failed inter-server COPY leaks one nfsd_file, pinning file/inode/dentry/vfsmount.

Fix by setting status and jumping to out: instead of returning directly.

Fixes ce0887ac96d3 ("NFSD add nfs4 inter ssc to nfsd4_copy")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfs4proc.c |   10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
fs/nfsd/nfs4proc.c +4 -6
@@ -1828,16 +1828,14 @@ nfsd4_copy(struct svc_rqst *rqstp, struc
 		}
 		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy);
 		if (status) {
-			trace_nfsd_copy_done(copy, status);
-			return nfserr_offload_denied;
+			status = nfserr_offload_denied;
+			goto out;
 		}
 	} else {
 		trace_nfsd_copy_intra(copy);
 		status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
-		if (status) {
-			trace_nfsd_copy_done(copy, status);
-			return status;
-		}
+		if (status)
+			goto out;
 	}
 
 	memcpy(&copy->fh, &cstate->current_fh.fh_handle,
author maintainer
#97 lore raw

PATCH 95/403 nfsd: fix reply size estimate for GET_DIR_DELEGATION

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 46f929b907b3bc488593c006f0c97e35baba9ea4 upstream.

nfsd4_get_dir_delegation_rsize() returns its estimate in XDR words, but the COMPOUND reply-size machinery works in bytes: every other op's _rsize helper multiplies its word count by sizeof(__be32). Since GET_DIR_DELEGATION is OP_MODIFIES_SOMETHING, this estimate is consulted before the op executes to ensure the reply will fit. The ~4x too-small estimate lets a compound near the session/reply limit pass the check, grant a directory delegation, and then fail to encode the reply with NFS4ERR_RESOURCE/REP_TOO_BIG, leaving the client without the returned stateid.

Multiply the estimate by sizeof(__be32) like the other _rsize helpers.

---
 fs/nfsd/nfs4proc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4proc.c +1 -1
@@ -3141,7 +3141,7 @@ static u32 nfsd4_get_dir_delegation_rsiz
 		op_encode_stateid_maxsz +
 		2 /* gddr_notification */ +
 		2 /* gddr_child_attributes */ +
-		2 /* gddr_dir_attributes */);
+		2 /* gddr_dir_attributes */) * sizeof(__be32);
 }
 
 #ifdef CONFIG_NFSD_PNFS
author maintainer
#98 lore raw

PATCH 96/403 nfsd: fix version mismatch loops in nfsd_acl_init_request()

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 9bc761051dcd9a4a8b59e64b2b185172d13c716d upstream.

The loops that compute the supported version range for PROG_MISMATCH test nfsd_support_acl_version(rqstp->rq_vers) instead of nfsd_support_acl_version(i), so every iteration fails and the function returns rpc_prog_unavail instead of rpc_prog_mismatch.

Replace rqstp->rq_vers with the loop variable i, matching the pattern used by the sibling nfsd_init_request() function.

Fixes e333f3bbefe3 ("nfsd: Allow containers to set supported nfs versions")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfssvc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/nfssvc.c +2 -2
@@ -871,7 +871,7 @@ nfsd_acl_init_request(struct svc_rqst *r
 
 	ret->mismatch.lovers = NFSD_ACL_NRVERS;
 	for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
-		if (nfsd_support_acl_version(rqstp->rq_vers) &&
+		if (nfsd_support_acl_version(i) &&
 		    nfsd_vers(nn, i, NFSD_TEST)) {
 			ret->mismatch.lovers = i;
 			break;
@@ -881,7 +881,7 @@ nfsd_acl_init_request(struct svc_rqst *r
 		return rpc_prog_unavail;
 	ret->mismatch.hivers = NFSD_ACL_MINVERS;
 	for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) {
-		if (nfsd_support_acl_version(rqstp->rq_vers) &&
+		if (nfsd_support_acl_version(i) &&
 		    nfsd_vers(nn, i, NFSD_TEST)) {
 			ret->mismatch.hivers = i;
 			break;
author maintainer
#99 lore raw

PATCH 97/403 nfsd: fix XDR length calculation in nfsd4_ff_encode_layoutget

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit f9868174af49d207fbaf0c5e055d088a983684af upstream.

The XDR buffer size calculation in nfsd4_ff_encode_layoutget() has multiple errors that can result in either an out-of-bounds write or leaking uninitialized kernel memory to the client:

- fh_len doesn't account for XDR padding on the file handle data
- uid and gid lengths use "8 + len" but xdr_encode_opaque() actually writes "4 + xdr_align_size(len)" bytes
- ds_len omits the flags and stats_collect_hint fields (8 bytes), while len's header constant overestimates by 8 bytes -- these partially cancel but leave a net mismatch

The worst case occurs with short strings (e.g. uid=0, gid=0 with an odd-sized file handle), where the function writes up to 5 bytes past the reserved XDR buffer. Conversely, when string lengths happen to be 4-byte aligned, the reservation is too large and stale buffer content is sent to the client.

Fix this by breaking out every encoded field explicitly in the ds_len calculation, using xdr_align_size() for all variable-length opaque fields, and correcting the header constants.

Fixes 9b9960a0ca47 ("nfsd: Add a super simple flex file server")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/flexfilelayoutxdr.c |   17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
fs/nfsd/flexfilelayoutxdr.c +11 -6
@@ -30,19 +30,24 @@ nfsd4_ff_encode_layoutget(struct xdr_str
 	struct ff_idmap uid;
 	struct ff_idmap gid;
 
-	fh_len = 4 + fl->fh.size;
+	fh_len = 4 + xdr_align_size(fl->fh.size);
 
 	uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
 	gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
 
-	/* 8 + len for recording the length, name, and padding */
-	ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len +
-		 8 + uid.len + 8 + gid.len;
+	/* data server entry: deviceid + efficiency + stateid + fh list +
+	 * user + group + flags + stats_collect_hint
+	 */
+	ds_len = 16 + 4 + 4 + sizeof(stateid_opaque_t) + 4 + fh_len +
+		 4 + xdr_align_size(uid.len) +
+		 4 + xdr_align_size(gid.len) +
+		 4 + 4;
 
+	/* mirror: ds_count + ds */
 	mirror_len = 4 + ds_len;
 
-	/* The layout segment */
-	len = 20 + mirror_len;
+	/* stripe_unit + mirror_count + mirror */
+	len = 12 + mirror_len;
 
 	p = xdr_reserve_space(xdr, sizeof(__be32) + len);
 	if (!p)
author maintainer
#100 lore raw

PATCH 98/403 nfsd: fix XDR padding calculation in ff_encode_getdeviceinfo

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 8b989aaec85e1293a871d602590c951fe44b8647 upstream.

nfsd4_ff_encode_getdeviceinfo() computes the da_addr_body reservation as 16 + netid_len + addr_len, but the subsequent xdr_encode_opaque() calls emit 8 + round_up(netid_len, 4) + round_up(addr_len, 4) bytes. The mismatch means the declared da_addr_body length exceeds the actual encoded data by 2-8 bytes on every flexfile GETDEVICEINFO reply, leaking stale reply-page content to the client and mis-aligning the subsequent version list decode.

Use xdr_align_size() for each string length to match what xdr_encode_opaque() actually writes.

Fixes efcae97fa425 ("NFSD: da_addr_body field missing in some GETDEVICEINFO replies")
Assisted-by kres:claude-opus-4-6
---
 fs/nfsd/flexfilelayoutxdr.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
fs/nfsd/flexfilelayoutxdr.c +2 -1
@@ -99,7 +99,8 @@ nfsd4_ff_encode_getdeviceinfo(struct xdr
 	}
 
 	/* len + padding for two strings */
-	addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len;
+	addr_len = 8 + xdr_align_size(da->netaddr.netid_len) +
+		   xdr_align_size(da->netaddr.addr_len);
 	ver_len = 20;
 
 	len = 4 + ver_len + 4 + addr_len;
author maintainer
#101 lore raw

PATCH 99/403 nfsd: gate nfs2 setacl by argp->mask

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit a3a7e20ed66d3f04d37883c398da8a113b430769 upstream.

The NFSACL v2 SETACL path shares the decoder convention used by its v3 sibling: nfsaclsvc_decode_setaclargs() fills in argp->acl_access only when NFS_ACL is set in the request mask and argp->acl_default only when NFS_DFACL is set, leaving the other pointer NULL because the argument buffer is zeroed up to pc_argzero before decode.

nfsacld_proc_setacl() then hands both pointers to set_posix_acl() unconditionally. set_posix_acl(idmap, dentry, type, NULL) is the VFS "remove this ACL type" operation, so an omitted arm is indistinguishable from an explicit request to delete that ACL. A SETACL carrying only NFS_ACL silently strips the directory's default ACL; mask=0 strips both.

This is the same defect just fixed in nfsd3_proc_setacl(); apply the same remedy. Gate each set_posix_acl() call on its mask bit and initialize error to 0 so that a request with neither bit set leaves the on-disk ACLs untouched and returns success. The out_drop_lock path and the unconditional posix_acl_release() in nfsaclsvc_release_setacl() already tolerate the skipped arms.

Fixes a257cdd0e217 ("[PATCH] NFSD: Add server support for NFSv3 ACLs.")
---
 fs/nfsd/nfs2acl.c |   21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
fs/nfsd/nfs2acl.c +13 -8
@@ -115,14 +115,19 @@ static __be32 nfsacld_proc_setacl(struct
 
 	inode_lock(inode);
 
-	error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_ACCESS,
-			      argp->acl_access);
-	if (error)
-		goto out_drop_lock;
-	error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_DEFAULT,
-			      argp->acl_default);
-	if (error)
-		goto out_drop_lock;
+	error = 0;
+	if (argp->mask & NFS_ACL) {
+		error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry,
+				      ACL_TYPE_ACCESS, argp->acl_access);
+		if (error)
+			goto out_drop_lock;
+	}
+	if (argp->mask & NFS_DFACL) {
+		error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry,
+				      ACL_TYPE_DEFAULT, argp->acl_default);
+		if (error)
+			goto out_drop_lock;
+	}
 
 	inode_unlock(inode);
 
author maintainer
#102 lore raw

PATCH 100/403 nfsd: gate nfs3 setacl by argp->mask

In reply to Greg Kroah-Hartman

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

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

From: Chris Mason <[email protected]>

commit 453d7198a0ab07a12d46e0575861ac7b932da17e upstream.

nfsd3_proc_setacl() calls set_posix_acl() unconditionally for both ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT, passing argp->acl_access and argp->acl_default verbatim. The NFSv3 ACL decoder only populates those pointers when the corresponding mask bit is set:

    nfs3svc_decode_setaclargs()
      if (args->mask & NFS_ACL)    decode into acl_access
      if (args->mask & NFS_DFACL)  decode into acl_default
      /* otherwise the pointer stays NULL (pc_argzero) */

    nfsd3_proc_setacl()
      set_posix_acl(.., ACL_TYPE_ACCESS,  argp->acl_access)
      set_posix_acl(.., ACL_TYPE_DEFAULT, argp->acl_default)

set_posix_acl(idmap, dentry, type, NULL) is the VFS "remove this ACL type" operation. A NULL pointer that means "the client did not send this arm" is therefore indistinguishable from "the client asked to remove this ACL". A SETACL with mask=NFS_ACL silently drops the directory's default ACL; mask=0 drops both.

The sibling nfsd3_proc_getacl() already consults argp->mask before touching each arm; mirror that in setacl.

Fix by wrapping each set_posix_acl() call in the matching mask bit check and initializing error to 0 before inode_lock so that a request with neither bit set leaves the on-disk ACLs untouched and returns nfs_ok. The out_drop_lock path and the unconditional posix_acl_release() at out: are preserved; both NULL-tolerate the skipped arms.

Fixes a257cdd0e217 ("[PATCH] NFSD: Add server support for NFSv3 ACLs.")
Assisted-by kres:claude-opus-4-7
---
 fs/nfsd/nfs3acl.c |   17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
fs/nfsd/nfs3acl.c +11 -6
@@ -105,12 +105,17 @@ static __be32 nfsd3_proc_setacl(struct s
 
 	inode_lock(inode);
 
-	error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_ACCESS,
-			      argp->acl_access);
-	if (error)
-		goto out_drop_lock;
-	error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_DEFAULT,
-			      argp->acl_default);
+	error = 0;
+	if (argp->mask & NFS_ACL) {
+		error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry,
+				      ACL_TYPE_ACCESS, argp->acl_access);
+		if (error)
+			goto out_drop_lock;
+	}
+	if (argp->mask & NFS_DFACL) {
+		error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry,
+				      ACL_TYPE_DEFAULT, argp->acl_default);
+	}
 
 out_drop_lock:
 	inode_unlock(inode);
author maintainer
#103 lore raw

PATCH 101/403 nfsd: initialize copy-notify stateid before publishing it

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 129643893b79f8a3c6b72045f933fbab5ee424ca upstream.

nfsd4_copy_notify() finished initializing the cpntf state after nfs4_alloc_init_cpntf_state() had already linked it into the s2s_cp_stateids IDR and the parent's sc_cp_list, with cs_count == 1 (the membership reference) and none held for the caller. A racing OFFLOAD_CANCEL (crafted cl_id == nn->s2s_cp_cl_id plus the guessable so_id) could reach manage_cpntf_state() and free the entry, turning the caller's subsequent cpn_cnr_stateid read and cp_p_stateid/cp_p_clid writes into use-after-free. The owning clientid was also only recorded after publication, so it could not gate an ownership check in that window.

Record cp_p_stateid and cp_p_clid inside nfs4_alloc_init_cpntf_state() before nfs4_init_cp_state() publishes the entry, and return it with an extra reference. The caller reads the stateid under that reference and drops it with nfs4_put_cpntf_state(); on a late error the laundromat reaps the entry.

Fixes 624322f1adc5 ("NFSD add COPY_NOTIFY operation")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfs4proc.c  |   16 +++++++++-------
 fs/nfsd/nfs4state.c |   10 +++++++++-
 2 files changed, 18 insertions(+), 8 deletions(-)
fs/nfsd/nfs4proc.c +9 -7
@@ -1949,7 +1949,6 @@ nfsd4_copy_notify(struct svc_rqst *rqstp
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 	struct nfs4_stid *stid = NULL;
 	struct nfs4_cpntf_state *cps;
-	struct nfs4_client *clp = cstate->clp;
 
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
 					&cn->cpn_src_stateid, RD_STATE, NULL,
@@ -1963,12 +1962,14 @@ nfsd4_copy_notify(struct svc_rqst *rqstp
 	cn->cpn_lease_time.tv_nsec = 0;
 
 	status = nfserrno(-ENOMEM);
+	/*
+	 * The returned cps is published and fully initialized, and carries an
+	 * extra reference for us; drop it once we are done with it.
+	 */
 	cps = nfs4_alloc_init_cpntf_state(nn, stid);
 	if (!cps)
 		goto out;
 	memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.cs_stid, sizeof(stateid_t));
-	memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t));
-	memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t));
 
 	/* For now, only return one server address in cpn_src, the
 	 * address used by the client to connect to this server.
@@ -1977,10 +1978,11 @@ nfsd4_copy_notify(struct svc_rqst *rqstp
 	status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
 				 &cn->cpn_src->u.nl4_addr);
 	WARN_ON_ONCE(status);
-	if (status) {
-		nfs4_put_cpntf_state(nn, cps);
-		goto out;
-	}
+	/*
+	 * Drop our extra reference. The membership reference keeps the entry
+	 * alive for a later inter-server READ, or until the laundromat reaps it.
+	 */
+	nfs4_put_cpntf_state(nn, cps);
 out:
 	nfs4_put_stid(stid);
 	return status;
fs/nfsd/nfs4state.c +9 -1
@@ -1023,7 +1023,15 @@ struct nfs4_cpntf_state *nfs4_alloc_init
 	/* So a stale list_del_init() before linking is a no-op. */
 	INIT_LIST_HEAD(&cps->cp_list);
 	cps->cpntf_time = ktime_get_boottime_seconds();
-	refcount_set(&cps->cp_stateid.cs_count, 1);
+	/*
+	 * Fully initialize the entry before nfs4_init_cp_state() publishes it,
+	 * since a concurrent OFFLOAD_CANCEL could then free it. Take an extra
+	 * reference for the caller (dropped with nfs4_put_cpntf_state()).
+	 */
+	memcpy(&cps->cp_p_stateid, &p_stid->sc_stateid, sizeof(stateid_t));
+	memcpy(&cps->cp_p_clid, &p_stid->sc_client->cl_clientid,
+	       sizeof(clientid_t));
+	refcount_set(&cps->cp_stateid.cs_count, 2);
 	if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID,
 				p_stid))
 		goto out_free;
author maintainer
#104 lore raw

PATCH 102/403 nfsd: initialize DRC hash table before registering shrinker

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit b0c58934f5cc4f05b63ef6605dd10c1d0d489e88 upstream.

shrinker_register() precedes the INIT_LIST_HEAD loop and the drc_hashsize store. On weakly-ordered architectures (arm64, ppc), a shrinker scan can observe drc_hashsize before the bucket list heads are initialized, causing a NULL deref in the DRC shrinker callback.

Move bucket initialization and the drc_hashsize store before shrinker_register() so the hash table is fully initialized before it becomes visible to the shrinker.

Fixes 8eea99a81c6f ("nfsd: dynamically allocate the nfsd-reply shrinker")
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfscache.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/nfscache.c +2 -2
@@ -200,14 +200,14 @@ int nfsd_reply_cache_init(struct nfsd_ne
 	nn->nfsd_reply_cache_shrinker->seeks = 1;
 	nn->nfsd_reply_cache_shrinker->private_data = nn;
 
-	shrinker_register(nn->nfsd_reply_cache_shrinker);
-
 	for (i = 0; i < hashsize; i++) {
 		INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head);
 		spin_lock_init(&nn->drc_hashtbl[i].cache_lock);
 	}
 	nn->drc_hashsize = hashsize;
 
+	shrinker_register(nn->nfsd_reply_cache_shrinker);
+
 	return 0;
 out_shrinker:
 	kvfree(nn->drc_hashtbl);
author maintainer
#105 lore raw

PATCH 103/403 nfsd: reject out-of-range nseconds in NFSv3 SETATTR and create ops

In reply to Greg Kroah-Hartman

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

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

From: Robbie Ko <[email protected]>

commit eb0eca7720662ba5847df1510e73801f7f473094 upstream.

A client can send an NFSv3 SETATTR, CREATE, MKDIR, SYMLINK or MKNOD carrying an atime or mtime whose nseconds field is out of range. The value is well-formed on the wire and decodes cleanly into a valid uint32, but it is not a valid timespec64: tv_nsec must be less than NSEC_PER_SEC.

Nothing in the setattr path clamps it. notify_change() runs the time through timestamp_truncate(), which does not reduce tv_nsec below NSEC_PER_SEC when the filesystem supports nanosecond granularity (s_time_gran == 1), and the inode atime/mtime setters store it verbatim (only ctime is normalized, via inode_set_ctime_to_ts()). The un-normalized value then corrupts on-disk metadata: ext4's ext4_encode_extra_time() shifts tv_nsec left by EXT4_EPOCH_BITS, which overflows the 32-bit extra field and clobbers the seconds-epoch bits, so the stored seconds (and thus the year) are wrong on read-back. XFS with bigtime mis-stores the timestamp for the same reason.

Validate the client-supplied atime/mtime in the proc handlers and return NFS3ERR_INVAL before anything is changed. RFC 1813 lists NFS3ERR_INVAL for SETATTR and describes it as the error for a value the server 'can not store ... in its own representation'; the client maps it to EINVAL.

Checking in the proc handlers, rather than in nfsd_setattr(), keeps the rejection in front of object creation. The create operations create the object before nfsd_create_setattr() runs, so a late failure would leave the new object behind and turn a non-idempotent request into a namespace change that reports failure. The check is therefore done up front, for the create operations before the object is created.

tv_nsec is a long, so the comparison casts it to unsigned long (the same width) rather than to u32, matching timespec64_valid(). A u32 cast would truncate on 64-bit; the unsigned long cast also rejects a value that became negative when an out-of-range u32 wire nseconds was assigned to a 32-bit long.

Only client-supplied times are checked: SET_TO_SERVER_TIME requests carry no client value. The sattrguard3 ctime is deliberately left alone:
an out-of-range guard simply never matches the object's ctime and yields NFS3ERR_NOT_SYNC via the existing guardtime comparison, which is the protocol-correct outcome rather than rejecting the request.

---
 fs/nfsd/nfs3proc.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
fs/nfsd/nfs3proc.c +40 -0
@@ -28,6 +28,25 @@ static int	nfs3_ftypes[] = {
 	S_IFIFO,		/* NF3FIFO */
 };
 
+/*
+ * Reject a client-supplied atime or mtime whose nanoseconds field is out
+ * of range. Such a value is well-formed on the wire but is not a valid
+ * timespec64, and storing it verbatim can corrupt on-disk timestamps.
+ * tv_nsec is a long, so it is cast to unsigned long (the same width) to
+ * catch both an over-large value and one that became negative when an
+ * out-of-range u32 wire nseconds was assigned to a 32-bit long.
+ */
+static bool nfsd3_time_in_range(const struct iattr *iap)
+{
+	if ((iap->ia_valid & ATTR_ATIME_SET) &&
+	    (unsigned long)iap->ia_atime.tv_nsec >= NSEC_PER_SEC)
+		return false;
+	if ((iap->ia_valid & ATTR_MTIME_SET) &&
+	    (unsigned long)iap->ia_mtime.tv_nsec >= NSEC_PER_SEC)
+		return false;
+	return true;
+}
+
 static __be32 nfsd3_map_status(__be32 status)
 {
 	switch (status) {
@@ -101,9 +120,14 @@ nfsd3_proc_setattr(struct svc_rqst *rqst
 				SVCFH_fmt(&argp->fh));
 
 	fh_copy(&resp->fh, &argp->fh);
+	if (!nfsd3_time_in_range(&argp->attrs)) {
+		resp->status = nfserr_inval;
+		goto out;
+	}
 	if (argp->check_guard)
 		guardtime = &argp->guardtime;
 	resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, guardtime);
+out:
 	resp->status = nfsd3_map_status(resp->status);
 	return rpc_success;
 }
@@ -266,6 +290,8 @@ nfsd3_create_file(struct svc_rqst *rqstp
 	__be32 status;
 	int host_err;
 
+	if (!nfsd3_time_in_range(iap))
+		return nfserr_inval;
 	if (isdotent(argp->name, argp->len))
 		return nfserr_exist;
 	if (!(iap->ia_valid & ATTR_MODE))
@@ -413,8 +439,13 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
 	argp->attrs.ia_valid &= ~ATTR_SIZE;
 	fh_copy(&resp->dirfh, &argp->fh);
 	fh_init(&resp->fh, NFS3_FHSIZE);
+	if (!nfsd3_time_in_range(&argp->attrs)) {
+		resp->status = nfserr_inval;
+		goto out;
+	}
 	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 				   &attrs, S_IFDIR, 0, &resp->fh);
+out:
 	resp->status = nfsd3_map_status(resp->status);
 	return rpc_success;
 }
@@ -428,6 +459,10 @@ nfsd3_proc_symlink(struct svc_rqst *rqst
 		.na_iattr	= &argp->attrs,
 	};
 
+	if (!nfsd3_time_in_range(&argp->attrs)) {
+		resp->status = nfserr_inval;
+		goto out;
+	}
 	if (argp->tlen == 0) {
 		resp->status = nfserr_inval;
 		goto out;
@@ -494,6 +529,11 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
 		goto out;
 	}
 
+	if (!nfsd3_time_in_range(&argp->attrs)) {
+		resp->status = nfserr_inval;
+		goto out;
+	}
+
 	type = nfs3_ftypes[argp->ftype];
 	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 				   &attrs, type, rdev, &resp->fh);
author maintainer
#106 lore raw

PATCH 104/403 nfsd: reject out-of-range useconds in NFSv2 SETATTR/CREATE

In reply to Greg Kroah-Hartman

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

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

From: Robbie Ko <[email protected]>

commit 26709c8ffe73772eb69e68d553ac71d91228dccc upstream.

The NFSv2 sattr decoder converts the wire useconds to nanoseconds in svcxdr_decode_sattr():

	iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC;

tmp2 is a u32 and NSEC_PER_USEC is 1000, so the product is computed in unsigned long. On ILP32 that is 32 bits, and an out-of-range useconds value such as 4294968 wraps to tv_nsec == 704. The corruption therefore happens during decode, before any proc function can inspect the value, and a later range check on tv_nsec would see an in-range result and accept it. Rejecting in the decoder yields an RPC GARBAGE_ARGS reply. NFSv2 defines no NFSERR_INVAL, so there is no NFS-level status to return for a malformed time argument, and the check cannot move to the proc function the way the v3/v4 nsec range checks do.

Guard the raw useconds before the multiplication and reject values greater than 1000000. useconds == 1000000 is kept: it is the Sun convention for "set to the current server time", and the in-tree Linux NFSv2 client emits it in both the atime and the mtime field for a plain touch / utimes(file, NULL) (see encode_sattr() and xdr_encode_current_server_time() in fs/nfs/nfs2xdr.c). Rejecting 1000000 would turn that common operation into a hard decode failure for both SETATTR and CREATE. 1000000 * NSEC_PER_USEC is 10^9, which does not wrap on ILP32, so the Sun convention value passes through safely. Only genuinely out-of-range values (> 1000000) are rejected. The atime and mtime guards are therefore symmetric.

The decoder only applied the Sun convention in the mtime block, which clears ATTR_ATIME_SET|ATTR_MTIME_SET when mtime useconds == 1000000. If a client puts 1000000 in the atime field but not in the mtime field, the atime block stored an out-of-range tv_nsec (10^9) and left ATTR_ATIME_SET set, so the bogus value reached the filesystem. Apply the convention in the atime block as well, clearing ATTR_ATIME_SET so the server uses its current time and ignores the value. Only ATTR_ATIME_SET is cleared there. The mtime block keeps its existing behavior, where 1000000 means "set both atime and mtime to now".

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
[ cel: various tweaks, addenda, and clean-ups ]
---
 fs/nfsd/nfsxdr.c |   32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)
fs/nfsd/nfsxdr.c +22 -10
@@ -10,6 +10,16 @@
 #include "auth.h"
 
 /*
+ * Sun convention: a sattr time-useconds field of one full second (an
+ * otherwise out-of-range value) means "set this time to the current
+ * server time." It's needed to make permissions checks for the "touch"
+ * program across NFSv2 mounts work correctly. See description of
+ * sattr in section 6.1 of "NFS Illustrated" by Brent Callaghan,
+ * Addison-Wesley, ISBN 0-201-32750-5
+ */
+#define NFS2_SATTR_SET_TO_SERVER_TIME	(1000000)
+
+/*
  * Mapping of S_IF* types to NFS file types
  */
 static const u32 nfs_ftypes[] = {
@@ -172,27 +182,29 @@ svcxdr_decode_sattr(struct svc_rqst *rqs
 	tmp1 = be32_to_cpup(p++);
 	tmp2 = be32_to_cpup(p++);
 	if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
+		/*
+		 * Range test here to prevent the multiplication from
+		 * wrapping to a valid (but incorrect) value on 32-bit
+		 * platforms.
+		 */
+		if (tmp2 > NFS2_SATTR_SET_TO_SERVER_TIME)
+			return false;
 		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 		iap->ia_atime.tv_sec = tmp1;
 		iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC;
+		if (tmp2 == NFS2_SATTR_SET_TO_SERVER_TIME)
+			iap->ia_valid &= ~ATTR_ATIME_SET;
 	}
 
 	tmp1 = be32_to_cpup(p++);
 	tmp2 = be32_to_cpup(p++);
 	if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
+		if (tmp2 > NFS2_SATTR_SET_TO_SERVER_TIME)
+			return false;
 		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 		iap->ia_mtime.tv_sec = tmp1;
 		iap->ia_mtime.tv_nsec = tmp2 * NSEC_PER_USEC;
-		/*
-		 * Passing the invalid value useconds=1000000 for mtime
-		 * is a Sun convention for "set both mtime and atime to
-		 * current server time".  It's needed to make permissions
-		 * checks for the "touch" program across v2 mounts to
-		 * Solaris and Irix boxes work correctly. See description of
-		 * sattr in section 6.1 of "NFS Illustrated" by
-		 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
-		 */
-		if (tmp2 == 1000000)
+		if (tmp2 == NFS2_SATTR_SET_TO_SERVER_TIME)
 			iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
 	}
 
author maintainer
#107 lore raw

PATCH 105/403 nfsd: reject reclaim LOCK after RECLAIM_COMPLETE

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 2327ba1d9546727a35b17888777e991f68a9b305 upstream.

nfsd4_lock() only checks the namespace-wide grace flag when deciding whether to accept a reclaim LOCK. It does not check the per-client NFSD4_CLIENT_RECLAIM_COMPLETE bit. An NFSv4.1+ client that has already sent RECLAIM_COMPLETE can submit lk_reclaim=1 while grace is still active (e.g. lockd holds the grace list open), and the server accepts it instead of returning NFS4ERR_NO_GRACE as required by RFC 8881 section 18.51.3.

The OPEN path already enforces both tiers: the grace check plus the per-client RECLAIM_COMPLETE check in nfs4_check_open_reclaim(). Add the equivalent per-client check to the LOCK path.

Fixes 3b3e7b72239a ("nfsd: reject reclaim request when client has already sent RECLAIM_COMPLETE")
Assisted-by Claude:claude-opus-4-8
[ cel: Correct the RFC citations in the commit message ]
---
 fs/nfsd/nfs4state.c |    3 +++
 1 file changed, 3 insertions(+)
fs/nfsd/nfs4state.c +3 -0
@@ -8145,6 +8145,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 	status = nfserr_no_grace;
 	if (!locks_in_grace(net) && lock->lk_reclaim)
 		goto out;
+	if (lock->lk_reclaim &&
+	    test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags))
+		goto out;
 
 	if (lock->lk_reclaim)
 		flags |= FL_RECLAIM;
author maintainer
#108 lore raw

PATCH 106/403 nfsd: revoke copy-notify stateids before dropping their reference

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit 3b0c3595db99bb4bebd7c8aa8a36f3c50e411bb7 upstream.

Copy-notify stateids live in the s2s_cp_stateids IDR and on their parent stid's sc_cp_list, pinned by a single membership reference. _free_cpntf_state_locked() only unlinks an entry once its refcount reaches zero, so any revoke path that runs while a concurrent find_cpntf_state()/manage_cpntf_state() holder has elevated cs_count drops the reference without unlinking, leaving the entry discoverable with its membership reference already consumed. A second revoke or a laundromat tick then frees it while the reader still holds the pointer -- a KASAN-detectable use-after-free at the reader's nfs4_put_cpntf_state().

This affected all three revoke paths:

- The parent-stid drain (nfs4_free_cpntf_statelist()) repeatedly called _free_cpntf_state_locked() on the first list entry; a holder that had bumped cs_count made it return early, so the next iteration re-decremented and burned the holder's reference.

- OFFLOAD_CANCEL (manage_cpntf_state()) and laundromat expiry likewise

    used _free_cpntf_state_locked() and could drop 2->1 without unlinking.

Add revoke_cpntf_state_locked(), which unhashes the entry from the IDR and sc_cp_list first (deferring the final free to any holder), and use it from all three revoke paths. The drain now walks with list_for_each_entry_safe() and revokes each entry unconditionally, so it terminates in one pass per entry regardless of cs_count. The unhash is gated on !list_empty(&cps->cp_list); the idr_remove() gate matters because idr_alloc_cyclic() may have recycled the so_id by then. Keep _free_cpntf_state_locked() for the reference-holder put path only, where a concurrent revoke may already have unlinked the entry (its list_del_init() then a no-op).

Fixes 624322f1adc5 ("NFSD add COPY_NOTIFY operation")
Assisted-by Claude:claude-opus-4-7
Assisted-by Claude:claude-opus-4-8
---
 fs/nfsd/nfs4state.c |   78 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 62 insertions(+), 16 deletions(-)
fs/nfsd/nfs4state.c +62 -16
@@ -1054,18 +1054,66 @@ void nfs4_free_copy_state(struct nfsd4_c
 	spin_unlock(&nn->s2s_cp_lock);
 }
 
+/*
+ * Drop the parent's reference on an already-unlinked cpntf entry. If a
+ * concurrent holder still owns a reference, its nfs4_put_cpntf_state() does
+ * the final free.
+ *
+ * nn->s2s_cp_lock must be held.
+ */
+static void put_cpntf_state_unlinked_locked(struct nfs4_cpntf_state *cps)
+{
+	WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID);
+	WARN_ON_ONCE(!list_empty(&cps->cp_list));
+
+	if (refcount_dec_and_test(&cps->cp_stateid.cs_count))
+		kfree(cps);
+}
+
+/*
+ * Unhash from the IDR and sc_cp_list. Gated on list_empty() to avoid
+ * evicting a recycled so_id.
+ */
+static void nfsd4_unhash_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
+{
+	lockdep_assert_held(&nn->s2s_cp_lock);
+
+	if (!list_empty(&cps->cp_list)) {
+		list_del_init(&cps->cp_list);
+		idr_remove(&nn->s2s_cp_stateids, cps->cp_stateid.cs_stid.si_opaque.so_id);
+	}
+}
+
+/*
+ * Revoke a copy-notify stateid: unlink it from the IDR and sc_cp_list first
+ * so no new finder can discover it, then drop the membership reference. Every
+ * revoke path (cancel, laundromat, drain) must use this rather than
+ * _free_cpntf_state_locked(), which unlinks only at refcount zero and so could
+ * let a second revoke free the entry under a concurrent reader.
+ *
+ * nn->s2s_cp_lock must be held.
+ */
+static void revoke_cpntf_state_locked(struct nfsd_net *nn,
+				      struct nfs4_cpntf_state *cps)
+{
+	nfsd4_unhash_cpntf_state(nn, cps);
+	put_cpntf_state_unlinked_locked(cps);
+}
+
 static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid)
 {
-	struct nfs4_cpntf_state *cps;
+	struct nfs4_cpntf_state *cps, *tmp;
 	struct nfsd_net *nn;
 
 	nn = net_generic(net, nfsd_net_id);
 	spin_lock(&nn->s2s_cp_lock);
-	while (!list_empty(&stid->sc_cp_list)) {
-		cps = list_first_entry(&stid->sc_cp_list,
-				       struct nfs4_cpntf_state, cp_list);
-		_free_cpntf_state_locked(nn, cps);
-	}
+	/*
+	 * Revoke unlinks each entry before dropping the parent's reference, so
+	 * the drain terminates in one pass per entry regardless of cs_count; a
+	 * concurrent holder does the final kfree via nfs4_put_cpntf_state().
+	 */
+	list_for_each_entry_safe(cps, tmp, &stid->sc_cp_list, cp_list)
+		revoke_cpntf_state_locked(nn, cps);
 	spin_unlock(&nn->s2s_cp_lock);
 }
 
@@ -6695,7 +6743,7 @@ nfs4_laundromat(struct nfsd_net *nn)
 		cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
 		if (cps->cp_stateid.cs_type == NFS4_COPYNOTIFY_STID &&
 				state_expired(&lt, cps->cpntf_time))
-			_free_cpntf_state_locked(nn, cps);
+			revoke_cpntf_state_locked(nn, cps);
 	}
 	spin_unlock(&nn->s2s_cp_lock);
 	nfs4_get_client_reaplist(nn, &reaplist, &lt);
@@ -7094,16 +7142,14 @@ nfs4_check_file(struct svc_rqst *rqstp,
 out:
 	return status;
 }
-static void
-_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
+
+static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
 {
 	WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID);
-	if (!refcount_dec_and_test(&cps->cp_stateid.cs_count))
-		return;
-	list_del_init(&cps->cp_list);
-	idr_remove(&nn->s2s_cp_stateids,
-		   cps->cp_stateid.cs_stid.si_opaque.so_id);
-	kfree(cps);
+	if (refcount_dec_and_test(&cps->cp_stateid.cs_count)) {
+		nfsd4_unhash_cpntf_state(nn, cps);
+		kfree(cps);
+	}
 }
 /*
  * A READ from an inter server to server COPY will have a
@@ -7140,7 +7186,7 @@ __be32 manage_cpntf_state(struct nfsd_ne
 			state = NULL;
 			goto unlock;
 		} else {
-			_free_cpntf_state_locked(nn, state);
+			revoke_cpntf_state_locked(nn, state);
 		}
 	}
 unlock:
author maintainer
#109 lore raw

PATCH 107/403 NFSD: Prevent lock owner use-after-free during client teardown

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit 5e2fa29d223a9a1e6a948e40b109d09081d1decd upstream.

__destroy_client() releases a client's open owners, but a lock owner whose only reference is a blocked lock (nbl) stays on cl_ownerstr_hashtbl. client_has_state() does not count a bare owner, so DESTROY_CLIENTID can reach __destroy_client() with such owners present.

__destroy_client() then walks the table, calling remove_blocked_locks() on each owner without a reference. Freeing a blocked lock drops the owner reference held via flc_owner. The per-net laundromat reaps blocked locks from nn->blocked_locks_lru independently of client state. The two paths share blocked_locks_lock only for the list splice, not the owner's lifetime. The laundromat therefore frees the owner as __destroy_client() dereferences it, a NULL dereference in remove_blocked_locks().

nfsd4_release_lockowner() holds a reference across the same call; __destroy_client() does not. Hold cl_lock across the walk, taking a reference and unhashing each owner, then drop it before remove_blocked_locks() and nfs4_put_stateowner(), which take blocked_locks_lock and cl_lock.

---
 fs/nfsd/nfs4state.c |   16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +13 -3
@@ -2522,14 +2522,24 @@ __destroy_client(struct nfs4_client *clp
 		release_openowner(oo);
 	}
 	for (i = 0; i < OWNER_HASH_SIZE; i++) {
-		struct nfs4_stateowner *so, *tmp;
+		struct nfs4_stateowner *so;
 
-		list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i],
-					 so_strhash) {
+		spin_lock(&clp->cl_lock);
+		while (!list_empty(&clp->cl_ownerstr_hashtbl[i])) {
+			so = list_first_entry(&clp->cl_ownerstr_hashtbl[i],
+					      struct nfs4_stateowner, so_strhash);
 			/* Should be no openowners at this point */
 			WARN_ON_ONCE(so->so_is_open_owner);
+			nfs4_get_stateowner(so);
+			unhash_lockowner_locked(lockowner(so));
+			spin_unlock(&clp->cl_lock);
+
 			remove_blocked_locks(lockowner(so));
+			nfs4_put_stateowner(so);
+
+			spin_lock(&clp->cl_lock);
 		}
+		spin_unlock(&clp->cl_lock);
 	}
 	nfsd4_return_all_client_layouts(clp);
 	nfsd4_shutdown_copy(clp);
author maintainer
#110 lore raw

PATCH 108/403 NFSD: Prevent client use-after-free during NFSv4.0 revoked-state cleanup

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

commit 7b4f8a1586c42d3afc3c0ac779af2db7ab1a5c55 upstream.

nfs40_clean_admin_revoked() takes a stateid reference under clp->cl_lock, drops nn->client_lock, and calls nfsd4_drop_revoked_stid(), which dereferences the stateid's client through s->sc_client->cl_lock. The stateid reference does not pin the client, so a teardown racing the dropped lock can free the client while nfsd4_drop_revoked_stid() is still using it.

This cleanup runs from the laundromat, so a periodic sweep can race force_expire_client() driven by a write to the clients/<id>/ctl file.

Skip a client that is already expiring and otherwise pin it with cl_rpc_users under client_lock before dropping the lock, matching nfsd4_revoke_states().

Fixes d688d8585e6b ("nfsd: allow admin-revoked NFSv4.0 state to be freed.")
---
 fs/nfsd/nfs4state.c |    6 ++++++
 1 file changed, 6 insertions(+)
fs/nfsd/nfs4state.c +6 -0
@@ -6709,16 +6709,22 @@ retry:
 
 		if (atomic_read(&clp->cl_admin_revoked) == 0)
 			continue;
+		if (is_client_expired(clp))
+			continue;
 
 		spin_lock(&clp->cl_lock);
 		idr_for_each_entry_ul(&clp->cl_stateids, stid, tmp, id)
 			if (stid->sc_status & SC_STATUS_ADMIN_REVOKED) {
 				refcount_inc(&stid->sc_count);
+				atomic_inc(&clp->cl_rpc_users);
 				spin_unlock(&nn->client_lock);
 				/* this function drops ->cl_lock */
 				nfsd4_drop_revoked_stid(stid);
 				nfs4_put_stid(stid);
 				spin_lock(&nn->client_lock);
+				if (atomic_dec_and_test(&clp->cl_rpc_users) &&
+				    is_client_expired(clp))
+					wake_up_all(&expiry_wq);
 				goto retry;
 			}
 		spin_unlock(&clp->cl_lock);
author maintainer
#111 lore raw

PATCH 109/403 libceph: validate OSD extent maps before cursor advance

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

commit 9ec08b7499a62c6d4afa93d36ab47a43fcad57d1 upstream.

net/ceph/osd_client.c:osd_sparse_read() validates that the sparse-read data length matches the summed extent lengths, but it does not validate that each OSD-supplied extent is monotonic and lies inside the original request range. A malformed authenticated OSD reply can advertise a far-forward nonzero extent offset with a matching data length and make the client advance the message-data cursor beyond the request buffer. This reaches the BUG_ON(!*length) assertion in ceph_msg_data_next() from the client receive path.

Impact: A malicious or compromised authenticated Ceph OSD peer can crash a kernel Ceph client via a malformed sparse-read reply.

Reject sparse extent maps that overflow, move backwards, overlap, or extend outside the original sparse-read request before advancing the cursor.

[ idryomov: perform sparse_extent_map_valid() check a bit earlier,
in CEPH_SPARSE_READ_DATA_LEN instead of CEPH_SPARSE_READ_DATA_PRE state ]

Fixes f628d7999727 ("libceph: add sparse read support to OSD client")
Assisted-by Codex:gpt-5-5-xhigh
---
 net/ceph/osd_client.c |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
net/ceph/osd_client.c +30 -0
@@ -6,6 +6,7 @@
 #include <linux/err.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
+#include <linux/overflow.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
@@ -5862,6 +5863,31 @@ static inline void convert_extent_map(st
 }
 #endif
 
+static bool sparse_extent_map_valid(struct ceph_sparse_read *sr)
+{
+	u64 req_end, pos;
+	int i;
+
+	if (check_add_overflow(sr->sr_req_off, sr->sr_req_len, &req_end))
+		return false;
+
+	pos = sr->sr_req_off;
+	for (i = 0; i < sr->sr_count; i++) {
+		struct ceph_sparse_extent *ext = &sr->sr_extent[i];
+		u64 end;
+
+		if (ext->off < pos)
+			return false;
+		if (check_add_overflow(ext->off, ext->len, &end))
+			return false;
+		if (end > req_end)
+			return false;
+		pos = end;
+	}
+
+	return true;
+}
+
 static int osd_sparse_read(struct ceph_connection *con,
 			   struct ceph_msg_data_cursor *cursor,
 			   char **pbuf)
@@ -5913,6 +5939,10 @@ next_op:
 		fallthrough;
 	case CEPH_SPARSE_READ_DATA_LEN:
 		convert_extent_map(sr);
+		if (!sparse_extent_map_valid(sr)) {
+			pr_warn_ratelimited("invalid sparse extent map\n");
+			return -EREMOTEIO;
+		}
 		ret = sizeof(sr->sr_datalen);
 		*pbuf = (char *)&sr->sr_datalen;
 		sr->sr_state = CEPH_SPARSE_READ_DATA_PRE;
author maintainer
#112 lore raw

PATCH 110/403 libceph: reject buckets with mismatched CRUSH ids

In reply to Greg Kroah-Hartman

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

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

From: Jérémy Jean <[email protected]>

commit 3cde4a8302301679937474a5f7a851394cc1bd11 upstream.

crush_decode() stores bucket data by array slot, and the mapper later derives the per-bucket workspace index from the decoded bucket id. A malformed map can therefore make one bucket reuse another bucket's workspace by encoding an id different from -1 - slot.

For uniform buckets, the second replica selection expands the source bucket's permutation into that aliased workspace buffer. If the source bucket is larger than the aliased bucket, the write runs past the smaller permutation array and can escape the kvmalloc'd CRUSH workspace. KASAN reports a slab OOB write of 4 bytes in bucket_perm_choose().

Reject buckets whose encoded id does not match their array slot. Valid CRUSH maps already use the canonical negative id corresponding to the bucket slot, so this restores the invariant expected by work->work[-1 - in->id] without changing valid map behavior.

Fixes 66a0e2d579db ("crush: remove mutable part of CRUSH map")
Assisted-by Codex:gpt-5
---
 net/ceph/osdmap.c |    2 ++
 1 file changed, 2 insertions(+)
net/ceph/osdmap.c +2 -0
@@ -519,6 +519,8 @@ static struct crush_map *crush_decode(vo
 
 		ceph_decode_need(p, end, 4*sizeof(u32), bad);
 		b->id = ceph_decode_32(p);
+		if (b->id != -1 - i)
+			goto bad;
 		b->type = ceph_decode_16(p);
 		if (b->type == 0)
 			goto bad;
author maintainer
#113 lore raw

PATCH 111/403 ceph: fix UAF in __kick_flushing_caps() on cf entry freed during unlock

In reply to Greg Kroah-Hartman

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

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

From: Xiubo Li <[email protected]>

commit 7af4c4f01305b0935adf6d4301b1ec407025485d upstream.

list_for_each_entry() iterates ci->i_cap_flush_list but drops i_ceph_lock to send cap messages. During the unlock window, handle_cap_flush_ack() can acquire i_ceph_lock, detach cf entries with tid <= flush_tid from the list, release i_ceph_lock, and free them via ceph_free_cap_flush() outside any lock. When the original thread reacquires i_ceph_lock and the for-loop macro advances via cf = list_next_entry(cf, i_list), it dereferences cf->i_list.next on freed memory.

The race timeline:

__kick_flushing_caps() handle_cap_flush_ack()
----------------------- -----------------------
holds i_ceph_lock <---
iterates to cf (tid=10)
prepares FLUSH message
drops i_ceph_lock <---
__send_cap() ── FLUSH(tid=10)
MDS sends FLUSH_ACK(tid=10)
---> acquires i_ceph_lock
cf->tid(10) <= flush_tid(10), detaches cf from i_cap_flush_list drops i_ceph_lock ceph_free_cap_flush(cf) <- frees it!
acquires i_ceph_lock <---
for-loop advances:
cf = list_next_entry(cf, i_list)
-- UAF on freed cf->i_list.next

The cf was just sent by __kick_flushing_caps itself via __send_cap(). The MDS may respond with FLUSH_ACK quickly enough that handle_cap_flush_ack() frees cf before __kick_flushing_caps can finish the iteration.

Fix by converting to a manual while loop: save the next pointer under i_ceph_lock before dropping it, then use the saved pointer after reacquiring, so the potentially-freed cf is never accessed again.

---
 fs/ceph/caps.c |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
fs/ceph/caps.c +9 -2
@@ -2599,9 +2599,14 @@ static void __kick_flushing_caps(struct
 		}
 	}
 
-	list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) {
-		if (cf->tid < first_tid)
+	cf = list_first_entry(&ci->i_cap_flush_list, struct ceph_cap_flush, i_list);
+	while (&cf->i_list != &ci->i_cap_flush_list) {
+		struct ceph_cap_flush *next;
+
+		if (cf->tid < first_tid) {
+			cf = list_next_entry(cf, i_list);
 			continue;
+		}
 
 		cap = ci->i_auth_cap;
 		if (!(cap && cap->session == session)) {
@@ -2611,6 +2616,7 @@ static void __kick_flushing_caps(struct
 		}
 
 		first_tid = cf->tid + 1;
+		next = list_next_entry(cf, i_list);
 
 		if (!cf->is_capsnap) {
 			struct cap_msg_args arg;
@@ -2651,6 +2657,7 @@ static void __kick_flushing_caps(struct
 		}
 
 		spin_lock(&ci->i_ceph_lock);
+		cf = next;
 	}
 }
 
author maintainer
#114 lore raw

PATCH 112/403 ceph: reject export_targets ranks >= CEPH_MAX_MDS in mdsmap decode

In reply to Greg Kroah-Hartman

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

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

From: Jérémy Jean <[email protected]>

commit aedc9053d909508a5f56c3f49f885fc030df4730 upstream.

MDSMap export_targets entries are monitor controlled. check_new_map() uses each entry as a bit number in a fixed stack bitmap, so a rank outside the protocol namespace can make set_bit() write past the end of the array.

Reject ranks outside CEPH_MAX_MDS while decoding the map. Do not validate against possible_max_rank here because maps may legitimately reference ranks beyond a temporarily reduced max_mds.

Fixes d517b3983dd3 ("ceph: reconnect to the export targets on new mdsmaps")
---
 fs/ceph/mdsmap.c |    4 ++++
 1 file changed, 4 insertions(+)
fs/ceph/mdsmap.c +4 -0
@@ -264,6 +264,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(s
 				goto nomem;
 			for (j = 0; j < num_export_targets; j++) {
 				target = ceph_decode_32(&pexport_targets);
+				if (target >= CEPH_MAX_MDS) {
+					err = -EIO;
+					goto corrupt;
+				}
 				info->export_targets[j] = target;
 			}
 		} else {
author maintainer
#115 lore raw

PATCH 113/403 ceph: bound copied dentry name length in NFS export get_name

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

commit eff8013c5a8916613c742ae5a2cc341cb605c0ae upstream.

ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way.

Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS.

Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name().

Fixes 19913b4eac4a ("ceph: add get_name() NFS export callback")
Assisted-by Claude:claude-opus-4-8
---
 fs/ceph/export.c |   26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)
fs/ceph/export.c +17 -9
@@ -437,6 +437,16 @@ static struct dentry *ceph_fh_to_parent(
 	return dentry;
 }
 
+static int ceph_export_copy_name(char *name, const char *src, u32 len)
+{
+	if (len > NAME_MAX)
+		return -ENAMETOOLONG;
+
+	memcpy(name, src, len);
+	name[len] = '\0';
+	return 0;
+}
+
 static int __get_snap_name(struct dentry *parent, char *name,
 			   struct dentry *child)
 {
@@ -502,9 +512,8 @@ static int __get_snap_name(struct dentry
 			BUG_ON(!rde->inode.in);
 			if (ceph_snap(inode) ==
 			    le64_to_cpu(rde->inode.in->snapid)) {
-				memcpy(name, rde->name, rde->name_len);
-				name[rde->name_len] = '\0';
-				err = 0;
+				err = ceph_export_copy_name(name, rde->name,
+							    rde->name_len);
 				goto out;
 			}
 		}
@@ -569,8 +578,8 @@ static int ceph_get_name(struct dentry *
 
 	rinfo = &req->r_reply_info;
 	if (!IS_ENCRYPTED(dir)) {
-		memcpy(name, rinfo->dname, rinfo->dname_len);
-		name[rinfo->dname_len] = 0;
+		err = ceph_export_copy_name(name, rinfo->dname,
+					    rinfo->dname_len);
 	} else {
 		struct fscrypt_str oname = FSTR_INIT(NULL, 0);
 		struct ceph_fname fname = { .dir	= dir,
@@ -584,10 +593,9 @@ static int ceph_get_name(struct dentry *
 			goto out;
 
 		err = ceph_fname_to_usr(&fname, NULL, &oname, NULL);
-		if (!err) {
-			memcpy(name, oname.name, oname.len);
-			name[oname.len] = 0;
-		}
+		if (!err)
+			err = ceph_export_copy_name(name, oname.name,
+						    oname.len);
 		ceph_fname_free_buffer(dir, &oname);
 	}
 out:
author maintainer
#116 lore raw

PATCH 114/403 ceph: bound MDSCapAuth path and fs_name decode in handle_session()

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

commit 77933e22adfe813be2bd10be08d6e950103c3967 upstream.

handle_session() decodes the MDSCapAuth records carried by a CEPH_SESSION_OPEN message (msg_version >= 6). For each record the match.path and match.fs_name byte strings are read by first decoding a 32-bit length and then copying that many bytes with the bare ceph_decode_copy(). Unlike the surrounding fields, which all use the _safe decode variants, these two copies are not preceded by a ceph_decode_need() bounds check, and the enclosing MDSCapAuth and MDSCapMatch struct_len fields are skipped rather than enforced as an upper bound. A length larger than the bytes remaining in the message front makes ceph_decode_copy() read past the end of the front buffer.

The message front is a dedicated allocation (ceph_msg_new2() -> kvmalloc), so the over-read runs off that object. A malicious or compromised MDS can trigger this with the first post-connect message on mount, with no client-side user interaction; under KASAN it is reported as a slab-out-of-bounds read in handle_session().

Impact: a malicious MDS can force the kernel client to read up to 4 GiB past the message front allocation during session setup, crashing the client (out-of-bounds read).

Switch both copies to ceph_decode_copy_safe(), which performs the ceph_decode_need() bounds check before the copy and branches to the existing bad label, matching the rest of the decoder and the error path that frees the partially decoded cap_auths array.

Fixes 1d17de9534cb ("ceph: save cap_auths in MDS client when session is opened")
Assisted-by Claude:claude-opus-4-8
---
 fs/ceph/mds_client.c |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ceph/mds_client.c +6 -2
@@ -4268,7 +4268,9 @@ static void handle_session(struct ceph_m
 					pr_err_client(cl, "No memory for path\n");
 					goto fail;
 				}
-				ceph_decode_copy(&p, cap_auths[i].match.path, _len);
+				ceph_decode_copy_safe(&p, end,
+						      cap_auths[i].match.path,
+						      _len, bad);
 
 				/* Remove the tailing '/' */
 				while (_len && cap_auths[i].match.path[_len - 1] == '/') {
@@ -4285,7 +4287,9 @@ static void handle_session(struct ceph_m
 					pr_err_client(cl, "No memory for fs_name\n");
 					goto fail;
 				}
-				ceph_decode_copy(&p, cap_auths[i].match.fs_name, _len);
+				ceph_decode_copy_safe(&p, end,
+						      cap_auths[i].match.fs_name,
+						      _len, bad);
 			}
 
 			ceph_decode_8_safe(&p, end, cap_auths[i].match.root_squash, bad);
author maintainer
#117 lore raw

PATCH 115/403 ceph: bound num_export_targets array for mds info v2/v3

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

commit a3eb169ee297aa99670ba927c659990bd1e453f3 upstream.

ceph_mdsmap_decode() in fs/ceph/mdsmap.c reads num_export_targets from each per-mds info record and advances the decode cursor by num_export_targets * sizeof(u32) without first checking that many bytes remain. The only upper-bound check that catches a runaway cursor (*p > info_end) is gated on info_v >= 4, because info_end is left NULL for info_v 2 and 3. When the monitor sends an MDS map whose per-mds info version is 2 or 3 with an oversized num_export_targets, the cursor moves past the message front buffer and the later export-targets loop calls the unchecked ceph_decode_32() on out-of-bounds memory.

A kernel client processes CEPH_MSG_MDS_MAP from its monitor session (net/ceph/mon_client.c dispatches it; fs/ceph/super.c routes it to ceph_mdsc_handle_mdsmap(), which sets end to the front buffer bound and calls ceph_mdsmap_decode()). A malicious or compromised monitor, or an on-path attacker on an unsigned/unencrypted messenger session, can therefore drive an out-of-bounds read in the client kernel; on x86_64 with KASAN it is reported as a slab-out-of-bounds read in ceph_mdsmap_decode(). The decoded values land in the internal info->export_targets[] array, so the consequence is a kernel out-of-bounds read, not an information leak to the attacker.

Impact: a malicious or compromised Ceph monitor sending an MDS map with a per-mds info version of 2 or 3 and an oversized num_export_targets field triggers an out-of-bounds read in the CephFS client kernel.

Add a ceph_decode_need() for the export-targets array before advancing the cursor, so the bound is enforced for every info_v >= 2, not only info_v >= 4. This mirrors the count-then-need idiom already used for m_data_pg_pools later in the same function.

Compute the export-targets byte count with size_mul() and reuse that checked length when advancing the cursor, so the attacker-controlled num_export_targets multiplication fails closed on overflow rather than relying on the later kcalloc() guard.

Fixes d463a43d69f4 ("ceph: CEPH_FEATURE_MDSENC support")
Assisted-by Claude:claude-opus-4-8
---
 fs/ceph/mdsmap.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
fs/ceph/mdsmap.c +6 -1
@@ -3,6 +3,7 @@
 
 #include <linux/bug.h>
 #include <linux/err.h>
+#include <linux/overflow.h>
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -126,6 +127,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(s
 	u8 mdsmap_v;
 	u16 mdsmap_ev;
 	u32 target;
+	size_t export_targets_len;
 
 	m = kzalloc(sizeof(*m), GFP_NOFS);
 	if (!m)
@@ -224,8 +226,11 @@ struct ceph_mdsmap *ceph_mdsmap_decode(s
 		*p += namelen;
 		if (info_v >= 2) {
 			ceph_decode_32_safe(p, end, num_export_targets, bad);
+			export_targets_len = size_mul(num_export_targets,
+						      sizeof(u32));
+			ceph_decode_need(p, end, export_targets_len, bad);
 			pexport_targets = *p;
-			*p += num_export_targets * sizeof(u32);
+			*p += export_targets_len;
 		} else {
 			num_export_targets = 0;
 		}
author maintainer
#118 lore raw

PATCH 116/403 ceph: bound xattr value length in __build_xattrs()

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

commit 68d541754d6cd3bb98d1fd8314f57e5eb533557d upstream.

__build_xattrs() decodes the MDS-supplied xattr blob one attribute at a time. For each attribute it reads a 32-bit name length, advances past the name bytes, reads a 32-bit value length, records the value pointer, and advances past the value bytes. The two length fields are read with ceph_decode_32_safe(), but the value bytes themselves are advanced over with a bare "p += len" and no ceph_decode_need() check that "len" bytes remain in the blob.

For every attribute except the last, the next iteration's ceph_decode_32_safe() on the following name length implicitly verifies that the previous value did not run past the blob end. The final attribute has no successor, so its decoded value length is never checked against the blob bounds. A malicious or compromised metadata server can set the last attribute's value length larger than the bytes actually present in the blob.

The blob is a dedicated kvmalloc() allocation sized to the wire length (ceph_buffer_new() in ceph_fill_inode()). __set_xattr() records the oversized length in xattr->val_len verbatim, and a later getxattr(2) runs memcpy(value, xattr->val, xattr->val_len) into a user-supplied buffer, copying bytes past the end of the allocation back to user space.

Impact: a malicious metadata server discloses adjacent kernel heap bytes to a local user via getxattr(2) on a CephFS file. Add the missing ceph_decode_need() so an out-of-bounds value length on the final attribute fails the decode and returns -EIO instead of being stored.

Fixes 355da1eb7a1f ("ceph: inode operations")
Assisted-by Claude:claude-opus-4-8
---
 fs/ceph/xattr.c |    1 +
 1 file changed, 1 insertion(+)
fs/ceph/xattr.c +1 -0
@@ -850,6 +850,7 @@ start:
 			name = p;
 			p += len;
 			ceph_decode_32_safe(&p, end, len, bad);
+			ceph_decode_need(&p, end, len, bad);
 			val = p;
 			p += len;
 
author maintainer
#119 lore raw

PATCH 117/403 ceph: do not repeat ceph_trim_dentries() if no progress possible

In reply to Greg Kroah-Hartman

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

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

From: Max Kellermann <[email protected]>

commit e7d7aa7b730178278109c41fa1b17b06873065d5 upstream.

ceph_cap_reclaim_work() re-queues itself for as long as ceph_trim_dentries() returns -EAGAIN, which happens whenever a lease walk exhausts its nr_to_scan budget. This creates a busy loop that consumes CPU without making any progress when there is nothing to
reclaim: with no cap pressure (count==0) and every scanned lease still valid, each pass runs the full scan budget down to zero and returns -EAGAIN, only to be queued again immediately.

The dir-lease walk made this worse. When expire_dir_lease is false (i.e. we have no intention of reclaiming dir leases), __dir_lease_check() returned TOUCH for every valid lease. TOUCH moves the dentry to the tail of the list and resets di->time via __dentry_dir_lease_touch(), so a walk over N valid leases pointlessly rewrote the list, refreshed the timestamps (preventing them from ever aging out) and always drained nr_to_scan, guaranteeing the -EAGAIN requeue.

Fix this in three steps:

- Return KEEP instead of TOUCH when expire_dir_lease is false. If we are not going to reclaim the lease, leave it in place instead of churning the list and resetting its timestamp; the walk then terminates naturally (or via STOP at the first fresh lease).

- Only return -EAGAIN from the first (dentry-lease) walk when something was actually freed. A full batch that frees nothing means retrying the same list immediately is futile; fall through to the dir-lease walk instead.

- After both walks, bail out with success (0) when nothing was freed and there is no cap pressure (count==0). There is no reason to keep retrying when we are not over the cap limit and made no progress.

Under real cap pressure (count>0) the reclaim path is unchanged and still retries via -EAGAIN.

Without this patch, I saw 500 ceph_trim_dentries() calls per second on our web servers. This is very visible in /proc/lock_stat (5 minute capture):

class name con-bounces contentions waittime-min waittime-max waittime-total waittime-avg acq-bounces acquisitions holdtime-min holdtime-max holdtime-total holdtime-avg

&mdsc->dentry_list_lock: 126180 128218 0.04 8063.44 15986965.20 124.69 1573354 5296812 0.04 8291.28 74164526.48 14.00
-----------------------

 &mdsc->dentry_list_lock         111736          [<000000007b11e319>] __ceph_dentry_dir_lease_touch+0x7c/0xa8
 &mdsc->dentry_list_lock           2631          [<0000000050597999>] __dentry_leases_walk+0x64/0x2c8
 &mdsc->dentry_list_lock           3878          [<00000000c0022f62>] __ceph_dentry_lease_touch+0x5c/0xa8
 &mdsc->dentry_list_lock           9973          [<000000002f27cb6f>] __dentry_lease_unlist+0x50/0xa0
 -----------------------
 &mdsc->dentry_list_lock         123621          [<0000000050597999>] __dentry_leases_walk+0x64/0x2c8
 &mdsc->dentry_list_lock           1822          [<000000007b11e319>] __ceph_dentry_dir_lease_touch+0x7c/0xa8
 &mdsc->dentry_list_lock           2720          [<000000002f27cb6f>] __dentry_lease_unlist+0x50/0xa0
 &mdsc->dentry_list_lock             55          [<00000000c0022f62>] __ceph_dentry_lease_touch+0x5c/0xa8

With this patch:

class name con-bounces contentions waittime-min waittime-max waittime-total waittime-avg acq-bounces acquisitions holdtime-min holdtime-max holdtime-total holdtime-avg

&mdsc->dentry_list_lock: 1203 1215 0.16 408.88 33082.88 27.23 4320501 7357389 0.04 500.64 1961578.00 0.27
-----------------------

 &mdsc->dentry_list_lock           1029          [<000000003c9aea8a>] __ceph_dentry_dir_lease_touch+0x7c/0xa8
 &mdsc->dentry_list_lock            169          [<000000002038c577>] __dentry_lease_unlist+0x50/0xa0
 &mdsc->dentry_list_lock             16          [<00000000c991106d>] __ceph_dentry_lease_touch+0x5c/0xa8
 &mdsc->dentry_list_lock              1          [<00000000612fe15f>] __dentry_leases_walk+0x64/0x2c8
 -----------------------
 &mdsc->dentry_list_lock            158          [<000000002038c577>] __dentry_lease_unlist+0x50/0xa0
 &mdsc->dentry_list_lock            858          [<000000003c9aea8a>] __ceph_dentry_dir_lease_touch+0x7c/0xa8
 &mdsc->dentry_list_lock            182          [<00000000612fe15f>] __dentry_leases_walk+0x64/0x2c8
 &mdsc->dentry_list_lock             17          [<00000000c991106d>] __ceph_dentry_lease_touch+0x5c/0xa8

__dentry_leases_walk() is almost gone. The total wait time is reduced by a factor of 483. That will give some latency gains to ceph_readdir().

Fixes 37c4efc1ddf9 ("ceph: periodically trim stale dentries")
---
 fs/ceph/dir.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
fs/ceph/dir.c +7 -3
@@ -1755,11 +1755,11 @@ static int __dir_lease_check(const struc
 	if (ret > 0) {
 		if (time_before(jiffies, di->time + lwc->dir_lease_ttl))
 			return STOP;
+		if (!lwc->expire_dir_lease)
+			return KEEP;
 		/* Move dentry to tail of dir lease list if we don't want
 		 * to delete it. So dentries in the list are checked in a
 		 * round robin manner */
-		if (!lwc->expire_dir_lease)
-			return TOUCH;
 		if (dentry->d_lockref.count > 0 ||
 		    (di->flags & CEPH_DENTRY_REFERENCED))
 			return TOUCH;
@@ -1786,7 +1786,7 @@ int ceph_trim_dentries(struct ceph_mds_c
 	lwc.dir_lease = false;
 	lwc.nr_to_scan  = CEPH_CAPS_PER_RELEASE * 2;
 	freed = __dentry_leases_walk(mdsc, &lwc);
-	if (!lwc.nr_to_scan) /* more invalid leases */
+	if (freed > 0 && !lwc.nr_to_scan) /* more invalid leases */
 		return -EAGAIN;
 
 	if (lwc.nr_to_scan < CEPH_CAPS_PER_RELEASE)
@@ -1796,6 +1796,10 @@ int ceph_trim_dentries(struct ceph_mds_c
 	lwc.expire_dir_lease = freed < count;
 	lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ;
 	freed +=__dentry_leases_walk(mdsc, &lwc);
+	if (freed == 0 && count == 0)
+		/* no progress possible currently, retry futile */
+		return 0;
+
 	if (!lwc.nr_to_scan) /* more to check */
 		return -EAGAIN;
 
author maintainer
#120 lore raw

PATCH 118/403 btrfs: drop recovered reloc root refs on recovery failure

In reply to Greg Kroah-Hartman

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

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

From: Guanghui Yang <[email protected]>

commit 6d8ba4572922e336f0b59a80751b018e1e135164 upstream.

During relocation recovery, each fs root gets a reference to its relocation root. If loading or adding a later root fails, or if the first transaction commit fails, btrfs_recover_relocation() jumps to out_unset before merge_reloc_roots() and clean_dirty_subvols().

put_reloc_control() drops the list-owned relocation root references, but it does not clear fs_root->reloc_root or drop the references owned by those pointers. Mount cleanup only drops them when BTRFS_FS_ERROR is set, so an error such as -ENOMEM while processing a later root can leave references behind.

Keep temporary references to the fs roots associated during recovery. On failure, clear their reloc_root pointers and drop the corresponding references. Once the first transaction commit succeeds, drop only the temporary fs root references and let the normal merge and cleanup paths handle the relocation roots.

Fault injection on a pending-relocation image confirmed the cleanup gap. With an injected first-commit failure, 25 fs roots had reloc_root set with fs_error=0. With this fix, the same failure path drops that count to 0 before mount fails.

Fixes f44deb7442ed ("btrfs: hold a ref on the root->reloc_root")
---
 fs/btrfs/relocation.c |   31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)
fs/btrfs/relocation.c +27 -4
@@ -4192,6 +4192,24 @@ static noinline_for_stack int mark_garba
 	return ret;
 }
 
+static void release_recovered_fs_roots(struct list_head *roots, bool drop_reloc_refs)
+{
+	struct btrfs_root *root;
+	struct btrfs_root *next;
+
+	list_for_each_entry_safe(root, next, roots, reloc_dirty_list) {
+		list_del_init(&root->reloc_dirty_list);
+		if (drop_reloc_refs) {
+			struct btrfs_root *reloc_root = root->reloc_root;
+
+			ASSERT(reloc_root);
+			root->reloc_root = NULL;
+			btrfs_put_root(reloc_root);
+		}
+		btrfs_put_root(root);
+	}
+}
+
 /*
  * recover relocation interrupted by system crash.
  *
@@ -4201,6 +4219,7 @@ static noinline_for_stack int mark_garba
 int btrfs_recover_relocation(struct btrfs_fs_info *fs_info)
 {
 	LIST_HEAD(reloc_roots);
+	LIST_HEAD(recovered_roots);
 	struct btrfs_key key;
 	struct btrfs_root *fs_root;
 	struct btrfs_root *reloc_root;
@@ -4313,7 +4332,7 @@ int btrfs_recover_relocation(struct btrf
 			ret = PTR_ERR(fs_root);
 			list_add_tail(&reloc_root->root_list, &reloc_roots);
 			btrfs_end_transaction(trans);
-			goto out_unset;
+			goto out_drop_reloc_refs;
 		}
 
 		ret = __add_reloc_root(reloc_root);
@@ -4322,15 +4341,17 @@ int btrfs_recover_relocation(struct btrf
 			list_add_tail(&reloc_root->root_list, &reloc_roots);
 			btrfs_put_root(fs_root);
 			btrfs_end_transaction(trans);
-			goto out_unset;
+			goto out_drop_reloc_refs;
 		}
+		ASSERT(list_empty(&fs_root->reloc_dirty_list));
 		fs_root->reloc_root = btrfs_grab_root(reloc_root);
-		btrfs_put_root(fs_root);
+		list_add_tail(&fs_root->reloc_dirty_list, &recovered_roots);
 	}
 
 	ret = btrfs_commit_transaction(trans);
 	if (ret)
-		goto out_unset;
+		goto out_drop_reloc_refs;
+	release_recovered_fs_roots(&recovered_roots, false);
 
 	merge_reloc_roots(rc);
 
@@ -4346,6 +4367,8 @@ out_clean:
 	ret2 = clean_dirty_subvols(rc);
 	if (ret2 < 0 && !ret)
 		ret = ret2;
+out_drop_reloc_refs:
+	release_recovered_fs_roots(&recovered_roots, true);
 out_unset:
 	unset_reloc_control(rc);
 	reloc_chunk_end(fs_info);
author maintainer
#121 lore raw

PATCH 119/403 audit: avoid dropping live tree ref on fsnotify rule autoremove

In reply to Greg Kroah-Hartman

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

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

From: Jérémy Jean <[email protected]>

commit 783f0f0974c156aca630f4ffff248671082a098d upstream.

audit_del_rule() is used for both netlink deletion templates and internal fsnotify autoremove. The former passes a parsed template which owns a temporary tree reference; the latter passes the installed entry itself.

The unconditional audit_put_tree() at the end of audit_del_rule() assumes the template case. For mixed AUDIT_DIR plus AUDIT_EXE rules, an fsnotify autoremove event therefore drops the installed rule's live tree reference. Repeating this across rules sharing the same tree can free the tree while another rule still references it, and a later autoremove dereferences the freed pathname while comparing rules.

Move the temporary-tree put to audit_rule_change(), the caller that owns deletion templates. Keep it in the AUDIT_DEL_RULE cleanup so both successful deletion and -ENOENT still release the parser-owned tree.

Fixes 34d99af52ad4 ("audit: implement audit by executable")
Assisted-by Codex:gpt-5
[PM: dropped unnecessary comment for line length reasons]
---
 kernel/auditfilter.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/auditfilter.c +2 -4
@@ -1025,7 +1025,6 @@ static inline int audit_add_rule(struct
 int audit_del_rule(struct audit_entry *entry)
 {
 	struct audit_entry  *e;
-	struct audit_tree *tree = entry->rule.tree;
 	struct list_head *list;
 	int ret = 0;
 #ifdef CONFIG_AUDITSYSCALL
@@ -1073,9 +1072,6 @@ int audit_del_rule(struct audit_entry *e
 out:
 	mutex_unlock(&audit_filter_mutex);
 
-	if (tree)
-		audit_put_tree(tree);	/* that's the temporary one */
-
 	return ret;
 }
 
@@ -1160,6 +1156,8 @@ int audit_rule_change(int type, int seq,
 	}
 
 	if (err || type == AUDIT_DEL_RULE) {
+		if (type == AUDIT_DEL_RULE && entry->rule.tree)
+			audit_put_tree(entry->rule.tree);
 		if (entry->rule.exe)
 			audit_remove_mark(entry->rule.exe);
 		audit_free_rule(entry);
author maintainer
#122 lore raw

PATCH 120/403 cifs: fix loff_t underflow in cifs_remap_file_range() when len == 0

In reply to Greg Kroah-Hartman

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

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

From: Frank Sorenson <[email protected]>

commit 6c322f5cf7476ded7a9a20f7be72462065a03c68 upstream.

With len == 0 (clone to EOF), the effective length is computed as:

    len = src_inode->i_size - off;

If off > i_size, this is a negative loff_t, corrupting the ByteCount in the FSCTL_DUPLICATE_EXTENTS_TO_FILE request and inverting the range in filemap_write_and_wait_range(). The existing off >= i_size check fires only after the ioctl has already been sent.

Snapshot i_size_read() once for both the bounds check and the length calculation, eliminating the TOCTOU and 32-bit torn-read risk. Reject off > src_size with -EINVAL. Treat off == src_size as a no-op, consistent with __generic_remap_file_range_prep().

Fixes 04b38d601239 ("vfs: pull btrfs clone API to vfs layer")
---
 fs/smb/client/cifsfs.c |   15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
fs/smb/client/cifsfs.c +13 -2
@@ -1314,8 +1314,19 @@ static loff_t cifs_remap_file_range(stru
 	 */
 	lock_two_nondirectories(target_inode, src_inode);
 
-	if (len == 0)
-		len = src_inode->i_size - off;
+	if (len == 0) {
+		loff_t src_size = i_size_read(src_inode);
+
+		if (off > src_size) {
+			rc = -EINVAL;
+			goto unlock;
+		}
+		len = src_size - off;
+		if (!len) {
+			rc = 0;
+			goto unlock;
+		}
+	}
 
 	cifs_dbg(FYI, "clone range\n");
 
author maintainer
#123 lore raw

PATCH 121/403 smb: client: clear ce->tgthint in free_tgts()

In reply to Greg Kroah-Hartman

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

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

From: Fredric Cover <[email protected]>

commit b1b741cf8e7ce1b91d937e23decd3d3358748700 upstream.

When free_tgts() frees all structures in ce->tlist, ce->tgthint is left pointing to one of the freed cache_dfs_tgt structures.

If ce->tgthint is not reset before it is used later, it results in a use-after-free.

Set ce->tgthint to NULL in free_tgts() after the elements are freed to reflect that no elements remain.

Fixes 54be1f6c1c37 ("cifs: Add DFS cache routines")
Cc [email protected] # depends on: smb: client: harden DFS cache against invalid target hints
---
 fs/smb/client/dfs_cache.c |    2 ++
 1 file changed, 2 insertions(+)
fs/smb/client/dfs_cache.c +2 -0
@@ -122,6 +122,8 @@ static inline void free_tgts(struct cach
 		kfree(t->name);
 		kfree(t);
 	}
+
+	WRITE_ONCE(ce->tgthint, NULL);
 }
 
 static inline void flush_cache_ent(struct cache_entry *ce)
author maintainer
#124 lore raw

PATCH 122/403 smb: client: fix ALIGN() overflow in symlink_data() error context loop

In reply to Greg Kroah-Hartman

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

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

From: Frank Sorenson <[email protected]>

commit 62656b024efc21c3230eade1a847f25871c3d2bb upstream.

The check added by commit 7d9a7f1f96cd ("smb/client: fix possible infinite loop and oob read in symlink_data()") compared the post-ALIGN length against the remaining buffer, but ALIGN() itself can overflow:
for ErrorDataLength near UINT32_MAX (e.g. 0xFFFFFFF9), ALIGN(x, 8) wraps to 0, so the subsequent bounds check passes, and the loop advances by zero bytes leaving 'p' pointing into stale data.

Fix by checking the raw ErrorDataLength against the remaining space before applying ALIGN(), then checking again after. Since raw_len is bounded by the buffer, raw_len + 7 cannot overflow, so the second check is an exact post-alignment bounds guard.

Fixes 76894f3e2f71 ("cifs: improve symlink handling for smb2+")
---
 fs/smb/client/smb2file.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
fs/smb/client/smb2file.c +4 -1
@@ -48,7 +48,10 @@ static struct smb2_symlink_err_rsp *syml
 			cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n",
 				 __func__, le32_to_cpu(p->ErrorId));
 
-			len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
+			len = le32_to_cpu(p->ErrorDataLength);
+			if (len > end - ((u8 *)p + sizeof(*p)))
+				return ERR_PTR(-EINVAL);
+			len = ALIGN(len, 8);
 			if (len > end - ((u8 *)p + sizeof(*p)))
 				return ERR_PTR(-EINVAL);
 
author maintainer
#125 lore raw

PATCH 123/403 smb: client: fix copy-paste error in WSL EA length accounting for $LXDEV

In reply to Greg Kroah-Hartman

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

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

From: Frank Sorenson <[email protected]>

commit 5d14030b46af1a958fd104b020fbb93631c98822 upstream.

The LXDEV block in cifs_query_path_info() uses SMB2_WSL_XATTR_MODE_SIZE
(4) instead of SMB2_WSL_XATTR_DEV_SIZE (8), undercounting eas_len by 4 bytes per $LXDEV EA.

eas_len is used only as a zero/non-zero presence flag so there is no current functional impact, but the value is incorrect and misleading.

Fixes 97db41604555 ("smb: client: parse uid, gid, mode and dev from WSL reparse points")
Cc Paulo Alcantara <[email protected]>
---
 fs/smb/client/smb1ops.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/smb/client/smb1ops.c +1 -1
@@ -747,7 +747,7 @@ static int cifs_query_path_info(const un
 			ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
 			memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
 			data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
-						   SMB2_WSL_XATTR_MODE_SIZE, 4);
+						   SMB2_WSL_XATTR_DEV_SIZE, 4);
 			rc = 0;
 		} else if (rc >= 0) {
 			/* It is an error if EA $LXDEV has wrong size. */
author maintainer
#126 lore raw

PATCH 124/403 smb: client: harden DFS cache against invalid target hints

In reply to Greg Kroah-Hartman

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

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

From: Fredric Cover <[email protected]>

commit bf86c08123c6ab8c61cc0be1dad7540db93738ff upstream.

Currently, get_tgt_name() returns ERR_PTR(-ENOENT) when ce->tgthint is NULL, and dfs_cache_noreq_update_tgthint() assumes ce->tgthint is always valid.

In preparation for clearing ce->tgthint in free_tgts(), harden callers of get_tgt_name() against ERR_PTR results and harden dfs_cache_noreq_update_tgthint() against NULL pointer dereferences.

---
 fs/smb/client/dfs_cache.c |   31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
fs/smb/client/dfs_cache.c +24 -7
@@ -871,13 +871,22 @@ int dfs_cache_find(const unsigned int xi
 		goto out_free_path;
 	}
 
-	if (ref)
-		rc = setup_referral(path, ce, ref, get_tgt_name(ce));
-	else
+	if (ref) {
+		char *target = get_tgt_name(ce);
+
+		if (IS_ERR(target)) {
+			rc = PTR_ERR(target);
+			goto out_unlock;
+		}
+		rc = setup_referral(path, ce, ref, target);
+	} else {
 		rc = 0;
+	}
+
 	if (!rc && tgt_list)
 		rc = get_targets(ce, tgt_list);
 
+out_unlock:
 	up_read(&htable_rw_lock);
 
 out_free_path:
@@ -917,10 +926,17 @@ int dfs_cache_noreq_find(const char *pat
 		goto out_unlock;
 	}
 
-	if (ref)
-		rc = setup_referral(path, ce, ref, get_tgt_name(ce));
-	else
+	if (ref) {
+		char *target = get_tgt_name(ce);
+
+		if (IS_ERR(target)) {
+			rc = PTR_ERR(target);
+			goto out_unlock;
+		}
+		rc = setup_referral(path, ce, ref, target);
+	} else {
 		rc = 0;
+	}
 	if (!rc && tgt_list)
 		rc = get_targets(ce, tgt_list);
 
@@ -961,7 +977,8 @@ void dfs_cache_noreq_update_tgthint(cons
 
 	t = READ_ONCE(ce->tgthint);
 
-	if (unlikely(!strcasecmp(it->it_name, t->name)))
+	/* Check 't' in case ce->tgthint was cleared by free_tgts() */
+	if (t && unlikely(!strcasecmp(it->it_name, t->name)))
 		goto out_unlock;
 
 	list_for_each_entry(t, &ce->tlist, list) {
author maintainer
#127 lore raw

PATCH 125/403 HID: picolcd: clamp eeprom debugfs read to bytes actually received

In reply to Greg Kroah-Hartman

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

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

From: Ibrahim Hashimov <[email protected]>

commit e9c667395ac1f8024f623250b32bae4c7af9caa0 upstream.

picolcd_debug_eeprom_read() trusts resp->raw_data[2] -- a length byte supplied by the device in its REPORT_EE_DATA reply -- clamped only to the caller's read() count:

	ret = resp->raw_data[2];
	if (ret > s)
		ret = s;
	if (copy_to_user(u, resp->raw_data+3, ret))

It never checks resp->raw_size, the number of bytes picolcd_raw_event() actually copied into the 64-byte raw_data[] of the kmalloc'd struct picolcd_pending. A device (or a spoofed picoLCD) returning a length byte of 0xff, read with a count >= 255, makes copy_to_user() read past raw_data[] into adjacent slab memory and return it to userspace through the debugfs "eeprom" file:

	BUG: KASAN: slab-out-of-bounds in _copy_to_user
	Read of size 255 ... picolcd_debug_eeprom_read+0x214/0x2f0 [hid_picolcd]

The debug-dump path in the same file already validates the device length byte against the received size before trusting it; this read does not. The file is created S_IRUSR (root-only) and a crafted device is needed, so it is neither unprivileged- nor remotely-triggerable.

Clamp the copy length to resp->raw_size - 3 (the payload actually received, minus the 3-byte header), floored at 0 for short replies.

Fixes 9bbf2b98ba11 ("HID: add experimental access to PicoLCD device's EEPROM and FLASH")
Assisted-by AuditCode-AI:2026.07
---
 drivers/hid/hid-picolcd_debugfs.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/hid/hid-picolcd_debugfs.c +9 -0
@@ -98,6 +98,15 @@ static ssize_t picolcd_debug_eeprom_read
 		ret = resp->raw_data[2];
 		if (ret > s)
 			ret = s;
+		/*
+		 * raw_data[2] is a device-supplied length; also clamp it to
+		 * what picolcd_raw_event() actually stored (raw_size), or a
+		 * hostile device overruns the raw_data[] buffer.
+		 */
+		if (ret > resp->raw_size - 3)
+			ret = resp->raw_size - 3;
+		if (ret < 0)
+			ret = 0;
 		if (copy_to_user(u, resp->raw_data+3, ret))
 			ret = -EFAULT;
 		else
author maintainer
#128 lore raw

PATCH 126/403 HID: roccat: free buffered reports when destroying device

In reply to Greg Kroah-Hartman

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

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

From: Xu Rao <[email protected]>

commit bbff0ccbff360a5498075525005f6a913239a3d7 upstream.

roccat_report_event() duplicates each report with kmemdup() and stores the allocation in a circular-buffer slot. The allocation is released only when that slot is reused.

The device destruction paths free struct roccat_device without releasing reports still stored in cbuf[]. This makes those allocations unreachable and leaks up to ROCCAT_CBUF_SIZE report buffers per device.

Add a small destructor that frees every buffered report before freeing the device, and use it in both paths that can destroy a registered device.

Fixes 206f5f2fcb5f ("HID: roccat: propagate special events of roccat hardware to userspace")
---
 drivers/hid/hid-roccat.c |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/hid/hid-roccat.c +11 -2
@@ -70,6 +70,15 @@ static struct roccat_device *devices[ROC
 /* protects modifications of devices array */
 static DEFINE_MUTEX(devices_lock);
 
+static void roccat_free_device(struct roccat_device *device)
+{
+	int i;
+
+	for (i = 0; i < ROCCAT_CBUF_SIZE; i++)
+		kfree(device->cbuf[i].value);
+	kfree(device);
+}
+
 static ssize_t roccat_read(struct file *file, char __user *buffer,
 		size_t count, loff_t *ppos)
 {
@@ -226,7 +235,7 @@ static int roccat_release(struct inode *
 			hid_hw_power(device->hid, PM_HINT_NORMAL);
 			hid_hw_close(device->hid);
 		} else {
-			kfree(device);
+			roccat_free_device(device);
 		}
 	}
 
@@ -374,7 +383,7 @@ void roccat_disconnect(int minor)
 		hid_hw_close(device->hid);
 		wake_up_interruptible(&device->wait);
 	} else {
-		kfree(device);
+		roccat_free_device(device);
 	}
 }
 EXPORT_SYMBOL_GPL(roccat_disconnect);
author maintainer
#129 lore raw

PATCH 127/403 HID: sensor: custom: Fix field sysfs group cleanup on failure

In reply to Greg Kroah-Hartman

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

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

From: Haoxiang Li <[email protected]>

commit 3789d0802ddb4b3be04062caf4bfadd23496e9a7 upstream.

hid_sensor_custom_add_attributes() creates one sysfs group for each custom sensor field. If sysfs_create_group() fails after some groups have already been created, the function returns the error without removing the previously created groups.

Add a local unwind path to remove the groups that were already created. With enable_sensor exposed only after the field attributes are ready, this path can free sensor_inst->fields without leaving enable_sensor able to access pointers into that array.

Fixes 4a7de0519df5 ("HID: sensor: Custom and Generic sensor support")
---
 drivers/hid/hid-sensor-custom.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/hid/hid-sensor-custom.c +8 -1
@@ -609,7 +609,7 @@ static int hid_sensor_custom_add_attribu
 					 &sensor_inst->fields[i].
 					 hid_custom_attribute_group);
 		if (ret)
-			break;
+			goto err_remove_groups;
 
 		/* For power or report field store indexes */
 		if (sensor_inst->fields[i].attribute.attrib_id ==
@@ -621,6 +621,13 @@ static int hid_sensor_custom_add_attribu
 	}
 
 	return ret;
+
+err_remove_groups:
+	while (--i >= 0)
+		sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
+				   &sensor_inst->fields[i].hid_custom_attribute_group);
+	kfree(sensor_inst->fields);
+	return ret;
 }
 
 static void hid_sensor_custom_remove_attributes(struct hid_sensor_custom *
author maintainer
#130 lore raw

PATCH 128/403 HID: mcp2221: stop device IO before hid_hw_stop

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

commit dca151633c0fde90935311c60e7cfc064aa56134 upstream.

Quiesce device IO at the start of the devm cleanup callback mcp2221_hid_unregister() so that incoming HID reports cannot race with hardware teardown during probe failure or device removal, addressing a potential use-after-free.

Guard the call to hid_device_io_stop() with io_started. On normal removal hid_device_remove() has already cleared io_started before the devres group is released, so an unconditional call would otherwise hit the !io_started path and emit a spurious "io already stopped" warning on every removal. The guard preserves the probe-failure balancing, where io_started is still set after hid_device_io_start(), while staying silent on the normal removal path.

Fixes d4b50ac06ea6 ("HID: mcp2221: Allow IO to start during probe")
---
 drivers/hid/hid-mcp2221.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/hid/hid-mcp2221.c +2 -0
@@ -943,6 +943,8 @@ static void mcp2221_hid_unregister(void
 {
 	struct hid_device *hdev = ptr;
 
+	if (hdev->io_started)
+		hid_device_io_stop(hdev);
 	hid_hw_close(hdev);
 	hid_hw_stop(hdev);
 }
author maintainer
#131 lore raw

PATCH 129/403 HID: mcp2221: validate report size in mcp2221_raw_event()

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

commit 2c9a6998c19503626c57a2267bf279e204113079 upstream.

mcp2221_raw_event() never validates the size of incoming HID reports. In the MCP2221_I2C_GET_DATA path it trusts the device-supplied data[3] as the copy length without checking that 4 + data[3] bytes actually exist in the received report. A malicious or misbehaving USB device can send a short report with a large data[3], causing the memcpy to read past the valid report data in the HID transfer buffer and leak uninitialized kernel memory back to userspace through the I2C/SMBus read path.

Add a minimum size check at entry and validate that the source range fits within the received report before the copy.

Fixes 67a95c21463d ("HID: mcp2221: add usb to i2c-smbus host bridge")
---
 drivers/hid/hid-mcp2221.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/hid/hid-mcp2221.c +7 -0
@@ -759,6 +759,9 @@ static int mcp2221_raw_event(struct hid_
 	u8 *buf;
 	struct mcp2221 *mcp = hid_get_drvdata(hdev);
 
+	if (size < 4)
+		return 0;
+
 	switch (data[0]) {
 
 	case MCP2221_I2C_WR_DATA:
@@ -820,6 +823,10 @@ static int mcp2221_raw_event(struct hid_
 					mcp->status = -EINVAL;
 					break;
 				}
+				if (4 + data[3] > size) {
+					mcp->status = -EINVAL;
+					break;
+				}
 				buf = mcp->rxbuf;
 				memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
 				mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
author maintainer
#132 lore raw

PATCH 130/403 eventfs: Initialize ei->children and ei->list in init_ei()

In reply to Greg Kroah-Hartman

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

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

From: Deepanshu Kartikey <[email protected]>

commit 1704aaaf5d22bc765c168402350d191e24e245bc upstream.

eventfs_create_dir() allocates the eventfs_inode and initializes it with init_ei(). But this does not initialize the eventfs_inode list_heads. If the eventfs_create_dir() fails due to memory pressure, it will call free_ei() before it initialized the lists, and that checks to make sure the eventfs_inode has no children. But because the list wasn't initialized, it will give a false warning.

Fix it by moving the list initialization into init_ei().

---
 fs/tracefs/event_inode.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
fs/tracefs/event_inode.c +2 -5
@@ -436,6 +436,8 @@ static inline struct eventfs_inode *init
 	if (!ei->name)
 		return NULL;
 	kref_init(&ei->kref);
+	INIT_LIST_HEAD(&ei->children);
+	INIT_LIST_HEAD(&ei->list);
 	return ei;
 }
 
@@ -727,8 +729,6 @@ struct eventfs_inode *eventfs_create_dir
 	ei->entries = entries;
 	ei->nr_entries = size;
 	ei->data = data;
-	INIT_LIST_HEAD(&ei->children);
-	INIT_LIST_HEAD(&ei->list);
 
 	mutex_lock(&eventfs_mutex);
 	if (!parent->is_freed)
@@ -801,9 +801,6 @@ struct eventfs_inode *eventfs_create_eve
 	ei->attr.uid = uid;
 	ei->attr.gid = gid;
 
-	INIT_LIST_HEAD(&ei->children);
-	INIT_LIST_HEAD(&ei->list);
-
 	ti = get_tracefs(inode);
 	ti->flags |= TRACEFS_EVENT_INODE;
 	ti->private = ei;
author maintainer
#133 lore raw

PATCH 131/403 fs/ntfs3: validate dirty page table on log replay

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

commit 006cb7713dec10368e699abc4367e5faa334c9a5 upstream.

Each DIR_PAGE_ENTRY ends in a page_lcns[] array whose length is the on-disk lcns_follow field. check_rstbl() validates the table bookkeeping but never checks that this array fits in the entry, so a crafted lcns_follow lets the v0->v1 conversion memmove and later replay passes run off the entry.

Add check_dp_table() to reject, right after check_rstbl(), any entry larger than its size claims via struct_size() (the same expression used to allocate these entries, so the check is overflow-safe by construction). All consumers can then trust lcns_follow as the real capacity. This covers every page_lcns[] access whose index is bounded by the entry itself (the conversion memmove, the HotFix store via find_dp(), and the self-bounded scan loops). Accesses whose index comes from the log record need a separate bound and are handled in a follow-up patch.

Fixes b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Assisted-by Claude:claude-opus-4-8
---
 fs/ntfs3/fslog.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
fs/ntfs3/fslog.c +19 -0
@@ -789,6 +789,20 @@ static bool check_rstbl(const struct RES
 	return true;
 }
 
+static bool check_dp_table(const struct RESTART_TABLE *dptbl)
+{
+	u32 rsize = le16_to_cpu(dptbl->size);
+	struct DIR_PAGE_ENTRY *dp = NULL;
+
+	while ((dp = enum_rstbl((struct RESTART_TABLE *)dptbl, dp))) {
+		if (struct_size(dp, page_lcns, le32_to_cpu(dp->lcns_follow)) >
+		    rsize)
+			return false;
+	}
+
+	return true;
+}
+
 /*
  * free_rsttbl_idx - Free a previously allocated index a Restart Table.
  */
@@ -4281,6 +4295,11 @@ check_dirty_page_table:
 		err = -EINVAL;
 		goto out;
 	}
+
+	if (!check_dp_table(rt)) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	dptbl = kmemdup(rt, t32, GFP_NOFS);
 	if (!dptbl) {
author maintainer
#134 lore raw

PATCH 132/403 fs/ntfs3: fix info-leak on partial LZNT decompress in ni_read_frame()

In reply to Greg Kroah-Hartman

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

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

From: Samuel Page <[email protected]>

commit 35d1ea92c7d946e2ebdbe36cdb2c969c8704bebd upstream.

ni_read_frame() decompresses an LZNT $DATA frame into the vmapped target pages and then trusts decompress_lznt()'s return value:

  unc_size = decompress_lznt(frame_ondisk, ondisk_size, frame_mem,
                             frame_size);
  if ((ssize_t)unc_size < 0)        err = unc_size;
  else if (!unc_size || unc_size > frame_size)  err = -EINVAL;

decompress_lznt() stops as soon as the compressed stream is exhausted (e.g. a zero chunk header) and returns the number of bytes it actually wrote, which may be far less than frame_size. The bytes between unc_size and frame_size are never written. The only memset() that follows zeroes the region beyond i_valid; when the frame lies entirely within the file's valid size that memset() does not run, so the gap retains whatever was in the just-vmapped pages. All pages are then marked uptodate and returned to userspace, disclosing uninitialized (recently-freed) kernel page memory. A crafted compressed file whose stream decompresses to only a few bytes leaks the remainder of every frame on a plain read(2), which is enough to recover kernel pointers and defeat KASLR.

Zero the [unc_size, frame_size) tail immediately after a successful LZNT decompress so the remainder reads back as zero.

Fixes 4342306f0f0d ("fs/ntfs3: Add file operations and implementation")
Assisted-by Bynario AI
---
 fs/ntfs3/frecord.c |    9 +++++++++
 1 file changed, 9 insertions(+)
fs/ntfs3/frecord.c +9 -0
@@ -2707,6 +2707,15 @@ int ni_read_frame(struct ntfs_inode *ni,
 			err = unc_size;
 		else if (!unc_size || unc_size > frame_size)
 			err = -EINVAL;
+		else if (unc_size < frame_size) {
+			/*
+			 * Partial decompress: zero the [unc_size, frame_size)
+			 * tail.  decompress_lznt() leaves it untouched, so
+			 * without this the freshly vmapped pages would expose
+			 * uninitialized kernel memory to userspace.
+			 */
+			memset(frame_mem + unc_size, 0, frame_size - unc_size);
+		}
 	}
 	if (!err && valid_size < frame_vbo + frame_size) {
 		size_t ok = valid_size - frame_vbo;
author maintainer
#135 lore raw

PATCH 133/403 fs/ntfs3: bound page_lcns[] index by the log record

In reply to Greg Kroah-Hartman

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

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

From: Konstantin Komarov <[email protected]>

commit 6f7b9dbdc1b7520206abce0049bdd143eb536e75 upstream.

The copy_lcns loop and the redo shorten loop index page_lcns[] at j + i, where i runs up to the log record's lcns_follow. That count is checked only against the record's own length, not the target entry, so check_dp_table() (which validates the entry's lcns_follow) does not cover it: the copy_lcns entry may even be freshly allocated after that check, and find_dp() bounds j but not i. A crafted record thus overflows page_lcns[] of an otherwise valid entry.

Add dp_range_ok() and reject, before each loop, any record whose run does not fit the entry. These are the only two page_lcns[] accesses indexed by the record rather than the entry, so together with the entry validation every access is now bounded.

Fixes b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Assisted-by Claude:claude-opus-4-8
[[email protected]: original patch contained changes to the problem already handled, applied partly]
---
 fs/ntfs3/fslog.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
fs/ntfs3/fslog.c +15 -0
@@ -648,6 +648,14 @@ static inline void *enum_rstbl(struct RE
 }
 
 /*
+ * dp_range_ok - true if [j, j + count) fits in a page_lcns[cap] array.
+ */
+static inline bool dp_range_ok(size_t j, u32 count, u32 cap)
+{
+	return j < cap && count <= cap - j;
+}
+
+/*
  * find_dp - Search for a @vcn in Dirty Page Table.
  */
 static inline struct DIR_PAGE_ENTRY *find_dp(struct RESTART_TABLE *dptbl,
@@ -5093,6 +5101,13 @@ find_dirty_page:
 	/* Shorten length by any Lcns which were deleted. */
 	saved_len = dlen;
 
+	if (!dp_range_ok(le64_to_cpu(lrh->target_vcn) - le64_to_cpu(dp->vcn),
+			 le16_to_cpu(lrh->lcns_follow),
+			 le32_to_cpu(dp->lcns_follow))) {
+		err = -EINVAL;
+		goto out;
+	}
+
 	for (i = le16_to_cpu(lrh->lcns_follow); i; i--) {
 		size_t j;
 		u32 alen, voff;
author maintainer
#136 lore raw

PATCH 134/403 eCryptfs: bound the packet-length peek to the user buffer

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

commit 95540462e630edbc8504e9537d16453d6942d143 upstream.

ecryptfs_miscdev_write() accepts the minimum one-byte packet-length encoding, but always copies the maximum two-byte encoding from userspace before parsing it. A six-byte message therefore reads one byte beyond the submitted user buffer.

Zero-initialize the peek buffer and copy only the packet-length bytes present. The existing exact packet-size check still rejects truncated two-byte encodings after the parser determines their encoded length.

Fixes 8bf2debd5f7b ("eCryptfs: introduce device handle for userspace daemon communications")
---
 fs/ecryptfs/miscdev.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
fs/ecryptfs/miscdev.c +3 -2
@@ -357,7 +357,7 @@ ecryptfs_miscdev_write(struct file *file
 	u32 seq;
 	size_t packet_size, packet_size_length;
 	char *data;
-	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
+	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE] = { };
 	ssize_t rc;
 
 	if (count == 0) {
@@ -373,7 +373,8 @@ ecryptfs_miscdev_write(struct file *file
 	}
 
 	if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
-			   sizeof(packet_size_peek))) {
+			   min_t(size_t, count - PKT_LEN_OFFSET,
+				 sizeof(packet_size_peek)))) {
 		printk(KERN_WARNING "%s: Error while inspecting packet size\n",
 		       __func__);
 		return -EFAULT;
author maintainer
#137 lore raw

PATCH 135/403 ecryptfs: fix tag 11 packet exact-fit size check

In reply to Greg Kroah-Hartman

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

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

From: Yichong Chen <[email protected]>

commit 8b2ec0f56f55477f547d332526c9ae2a8fabc0a5 upstream.

parse_tag_11_packet() rejects a packet when the already-consumed tag and length bytes plus the packet body exceed the caller supplied maximum packet size. The check currently adds one extra byte, even though *packet_size already includes the tag byte before the length is parsed.

Remove the extra byte so a tag 11 packet that exactly fits the available buffer is accepted while oversized packets are still rejected.

Fixes 237fead61998 ("[PATCH] ecryptfs: fs/Makefile and fs/Kconfig")
---
 fs/ecryptfs/keystore.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ecryptfs/keystore.c +1 -1
@@ -1576,7 +1576,7 @@ parse_tag_11_packet(unsigned char *data,
 	}
 	(*packet_size) += length_size;
 	(*tag_11_contents_size) = (body_size - 14);
-	if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
+	if (unlikely((*packet_size) + body_size > max_packet_size)) {
 		printk(KERN_ERR "Packet size exceeds max\n");
 		rc = -EINVAL;
 		goto out;
author maintainer
#138 lore raw

PATCH 136/403 ecryptfs: hold msg ctx list lock when cleaning daemon queue

In reply to Greg Kroah-Hartman

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

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

From: Yichong Chen <[email protected]>

commit 779972513c2fa8c7938e54976f686091dafff22f upstream.

ecryptfs_exorcise_daemon() drops queued messages from a dying daemon without holding ecryptfs_msg_ctx_lists_mux, but ecryptfs_msg_ctx_alloc_to_free() requires that lock.

Take the list lock while moving the queued contexts back to the free list to avoid racing with other global msg ctx list users.

Fixes f66e883eb618 ("eCryptfs: integrate eCryptfs device handle into the module.")
---
 fs/ecryptfs/messaging.c |    2 ++
 1 file changed, 2 insertions(+)
fs/ecryptfs/messaging.c +2 -0
@@ -165,6 +165,7 @@ int ecryptfs_exorcise_daemon(struct ecry
 		mutex_unlock(&daemon->mux);
 		goto out;
 	}
+	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
 	list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
 				 &daemon->msg_ctx_out_queue, daemon_out_list) {
 		list_del(&msg_ctx->daemon_out_list);
@@ -173,6 +174,7 @@ int ecryptfs_exorcise_daemon(struct ecry
 		       "the out queue of a dying daemon\n", __func__);
 		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
 	}
+	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
 	hlist_del(&daemon->euid_chain);
 	mutex_unlock(&daemon->mux);
 	kfree_sensitive(daemon);