6.18.46-rc1 review
Greg Kroah-Hartman
maintainercover 6.18.46-rc1 review
This is the start of the stable review cycle for the 6.18.46 release. There are 217 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 Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.46-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.18.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 6.18.46-rc1
Takashi Sakamoto <[email protected]>
firewire: ohci: initialize page array to use alloc_pages_bulk() correctly
Thomas Zimmermann <[email protected]>
drm/vmwgfx: Set surface-framebuffer GEM objects
Gao Xiang <[email protected]>
erofs: fix EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS on some UP platforms
Jasper Wise <[email protected]>
spi: virtio: mark device ready before registering the controller
Shixiong Ou <[email protected]>
drm/log: Fix infinite loop when scale is too large for display
Thomas Zimmermann <[email protected]>
drm/client: Remove drm_client_framebuffer_delete()
Thomas Zimmermann <[email protected]>
drm/client: Deprecate struct drm_client_buffer.gem
Thomas Zimmermann <[email protected]>
drm/client: Inline drm_client_buffer_addfb() and _rmfb()
Thomas Zimmermann <[email protected]>
drm/client: Move dumb-buffer handling to drm_client_framebuffer_create()
Thomas Zimmermann <[email protected]>
drm/client: Remove pitch from struct drm_client_buffer
Shixiong Ou <[email protected]>
drm/log: Fix out-of-bounds read on empty message length
Linmao Li <[email protected]>
drm/xe/oa: Fix sync entry leak on OA config emit failure
Aleksandr Nogikh <[email protected]>
firewire: ohci: fix NULL pointer dereference in ar_context_release
Takashi Sakamoto <[email protected]>
firewire: ohci: split page allocation from dma mapping
Jamal Hadi Salim <[email protected]>
net/sched: cls_bpf: reject dev-bound programs bound to a different device
Lizhi Hou <[email protected]>
accel/amdxdna: Skip unmapped range in aie2_populate_range()
Siddharth Vadapalli <[email protected]>
net: ethernet: ti: am65-cpsw-nuss: Fix port_id extraction from SRC TAG
Andrey Golovko <[email protected]>
regmap: sdw-mbq: don't call an unset readable_reg callback
Uwe Kleine-König <[email protected]>
m68k: Define NR_CPUS to 1
Zhang Changzhong <[email protected]>
net/sched: cls_u32: skip hash tables in u32_bind_class()
Jamal Hadi Salim <[email protected]>
net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain
Eric Dumazet <[email protected]>
af_packet: Don't send zero-byte data in tpacket_snd().
Charles Keepax <[email protected]>
regmap: sdw-mbq: Fix swap of timeout and retry times
Rosen Penev <[email protected]>
ASoC: xilinx: formatter_pcm: pass aud_drv_data to irq handlers
Chuck Lever <[email protected]>
net/tls: Fail tls_sw_splice_read() after a failed async decrypt
Jiawen Wu <[email protected]>
net: ngbe: fix NULL pointer dereference in non-MSI-X interrupt enabling
Wei Fang <[email protected]>
net: tap: fix wrong transport_header when sending VLAN-tagged frame
Wei Fang <[email protected]>
net: packet: fix wrong transport_header when sending VLAN-tagged frame
Oleksij Rempel <[email protected]>
net: phy: realtek: fix EEE advertisement write on the internal PHY MMD path
Jiayuan Chen <[email protected]>
tcp: fix icsk_ack.ato bitfield overflow
Jonas Köppeler <[email protected]>
veth: fix queue index used to wake the peer txq in veth_poll
Eric Dumazet <[email protected]>
macvlan: inherit needed_headroom and needed_tailroom from lowerdev
Eric Dumazet <[email protected]>
ipvlan: inherit needed_headroom and needed_tailroom from phy_dev
Jakub Kicinski <[email protected]>
eth: bnxt: keep the aRFS rmap updated when TPH is enabled
Jakub Kicinski <[email protected]>
eth: bnxt: cancel IRQ notifier before freeing affinity mask
Florian Westphal <[email protected]>
netfilter: ipset: let destroy callbacks adjust ext mem size
Florian Westphal <[email protected]>
netfilter: ipset: fix list type element drift bug
Jérémy Jean <[email protected]>
netfilter: flowtable: publish GC-visible tuple last
Alexey Velichayshiy <[email protected]>
netfilter: nf_tables_offload: suppress WARN_ON_ONCE for ENOMEM in abort path
Xiang Mei (Microsoft) <[email protected]>
netfilter: ipset: fix refcount race between list:set GC and swap
Shenghao Ding <[email protected]>
ASoC: tas2781: fix clang build error for goto bypassing cleanup variable
Junjie Cao <[email protected]>
gpio: ml-ioh: share the register lock across channels
Kyle Zeng <[email protected]>
perf: Reject exited events as group leaders
Pu Lehui <[email protected]>
riscv: ftrace: Fix ftrace_modify_call failure on kprobed functions
Ralf Lici <[email protected]>
ovpn: finish crypto callback cleanup before peer release
Ralf Lici <[email protected]>
ovpn: fix NULL dereference when killing missing key
Vladislav Dronov <[email protected]>
crypto: tegra - fix rctx->cryptlen calculation in tegra_gcm_do_one_req()
Herbert Xu <[email protected]>
crypto: ccm - Set rfc4309 maxauthsize from child
Jon Hunter <[email protected]>
arm64: tegra: Add EL2 virtual timer interrupt for Tegra194
Koichiro Den <[email protected]>
NTB: ntb_netdev: Preserve RX queue depth on allocation failure
Koichiro Den <[email protected]>
net: ntb_netdev: Introduce per-queue context
Peter Ujfalusi <[email protected]>
ASoC: SOF: ipc4-topology: Refresh copier IPC payload before widget setup
Yang Wang <[email protected]>
drm/amd/pm: fix pptable use-after-free
Yang Wang <[email protected]>
drm/amd/pm: adjust the visibility of pp_table sysfs node
Zhiling Zou <[email protected]>
mm/page_table_check: skip special zero mappings
Vincent Donnefort <[email protected]>
ring-buffer: Prevent resizing of persistent ring buffer
Vincent Donnefort <[email protected]>
ring-buffer: Store bpage pointers into subbuf_ids
Steven Rostedt <[email protected]>
ring-buffer: Add helper functions for allocations
Tejun Heo <[email protected]>
sched_ext: Take cgroup_lock() first in scx_cgroup_lock()
Tejun Heo <[email protected]>
sched_ext: Reorganize enable/disable path for multi-scheduler support
Tejun Heo <[email protected]>
sched_ext: Update p->scx.disallow warning in scx_init_task()
Yao Kai <[email protected]>
futex: Fix race in futex_pivot_pending() during private hash resize
Tu Nguyen <[email protected]>
can: rcar_canfd: change the initializing flow for clocks and resets
Geert Uytterhoeven <[email protected]>
can: rcar_canfd: Extract rcar_canfd_global_{,de}init()
Biju Das <[email protected]>
can: rcar_canfd: Use devm_clk_get_optional() for RAM clk
Geert Uytterhoeven <[email protected]>
can: rcar_canfd: Invert global vs. channel teardown
Geert Uytterhoeven <[email protected]>
can: rcar_canfd: Invert reset assert order
Christian Brauner <[email protected]>
binfmt_misc: don't leak the user namespace when the mount fails
Damien Le Moal <[email protected]>
ata: libata-scsi: terminate deferred commands on time out
Mark Brown <[email protected]>
ASoC: tas2562: Validate values for volume writes
Weiming Shi <[email protected]>
KVM: x86: Cancel delayed I/O APIC EOI handling before destroying vCPUs
Usama Arif <[email protected]>
userfaultfd: wait on source PMD during UFFDIO_MOVE
Lorenzo Stoakes <[email protected]>
mm: replace pmd_to_swp_entry() with softleaf_from_pmd()
Lorenzo Stoakes <[email protected]>
fs/proc/task_mmu: refactor pagemap_pmd_range()
Guanghui Yang <[email protected]>
btrfs: zoned: fix missing chunk metadata reservation
Filipe Manana <[email protected]>
btrfs: remove fs_info argument from btrfs_zoned_activate_one_bg()
Namjae Jeon <[email protected]>
ksmbd: validate minimum PDU size for transform requests
ChenXiaoSong <[email protected]>
smb/server: fix minimum SMB2 PDU size
ChenXiaoSong <[email protected]>
smb/server: fix minimum SMB1 PDU size
Namjae Jeon <[email protected]>
ksmbd: rename smb2_get_msg to smb_get_msg
David Howells <[email protected]>
ksmbd: Fix to handle removal of rfc1002 header from smb_hdr
ChenXiaoSong <[email protected]>
smb/server: rename include guard in smb_common.h
ZhangGuoDong <[email protected]>
smb: move get_rfc1002_len() to common/smbglob.h
Aldo Ariel Panzardo <[email protected]>
net/sched: serialize qdisc_rtab_list against concurrent get/put
Pavitra Jha <[email protected]>
libceph: fix two unsafe bare decodes in decode_lockers()
Xiang Mei <[email protected]>
libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE
Andy Shevchenko <[email protected]>
libceph: Amend checking to fix make W=1 build breakage
Max Kellermann <[email protected]>
ceph: fix hanging __ceph_get_caps() with stale mds_wanted
Max Kellermann <[email protected]>
ceph: avoid fs reclaim while using current->journal_info
Christoph Hellwig <[email protected]>
xfs: check v5 superblock features early
Darrick J. Wong <[email protected]>
xfs: check xfarray iteration errors when committing unlinked inode lists
Darrick J. Wong <[email protected]>
xfs: don't ignore runtime errors in xrep_iunlink_reload_next
Long Li <[email protected]>
xfs: don't swallow dquot recovery verification errors
Lin Jiapeng <[email protected]>
xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
Darrick J. Wong <[email protected]>
xfs: avoid UAF on sc->tempip in xrep_tempfile_create
Darrick J. Wong <[email protected]>
xfs: don't return EFSCORRUPTED when scrubbing corrupt parent pointers
Darrick J. Wong <[email protected]>
xfs: fix another iunlink infinite loop bug in online fsck
Darrick J. Wong <[email protected]>
xfs: fix allocated inodes that show up in the unlinked list
Darrick J. Wong <[email protected]>
xfs: don't walk off the end of a null sc->sa.agi_bp in AGI repair
Darrick J. Wong <[email protected]>
xfs: don't zap the attr fork on repair when there are queued pptr updates
Long Li <[email protected]>
xfs: fix ilock leak on error in xfs_dq_get_next_id
Darrick J. Wong <[email protected]>
xfs: load next_agino from the correct xfarray in xrep_iunlink_relink_prev
Darrick J. Wong <[email protected]>
xfs: nlink scrub must take IOLOCK before determining ILOCK state
Darrick J. Wong <[email protected]>
xfs: pass runtime errors from xrep_iunlink_mark_ondisk_rec up to callers
Darrick J. Wong <[email protected]>
xfs: set the prev pointer when reinserting an inode on the unlinked list
Darrick J. Wong <[email protected]>
xfs: don't double-lock when deleting a self-referential directory
Darrick J. Wong <[email protected]>
xfs: only check mergeability of bnobt records
Darrick J. Wong <[email protected]>
xfs: zero i_nlink before repair puts inode on unlinked list
Darrick J. Wong <[email protected]>
xfs: fix transaction block reservation in xrep_rtbitmap
Darrick J. Wong <[email protected]>
xfs: check cowextsize in xrep_inode_cowextsize
Qiang Ma <[email protected]>
xfs: clear zapped attr fork state when bmap repair finds no attr fork
Darrick J. Wong <[email protected]>
xfs: mark nonzero sb_gquotino as corrupt on metadir filesystems
Ibrahim Hashimov <[email protected]>
xfs: bounds-check buffer log item's dirty bitmap
Xiang Mei <[email protected]>
xfs: fix off-by-one in rtrefcount btree root level validation
Guanghui Yang <[email protected]>
xfs: propagate errors from xfs_rtginode_load
Junrui Luo <[email protected]>
drm/amdgpu: disallow multiple FENCE chunks in one submit
David Rosca <[email protected]>
drm/amdgpu: Fix UVD decode image min size calculation
David Rosca <[email protected]>
drm/amdgpu: Fix UVD dpb min size calculation for H264
David Rosca <[email protected]>
drm/amdgpu: Fix UVD min buffer sizes
David Rosca <[email protected]>
drm/amdgpu: Implement insert_end for VCE 3
David Rosca <[email protected]>
drm/amdgpu: Reject UVD message with dimensions above 4096
Candice Li <[email protected]>
drm/amdgpu: validate GEM_CREATE domain combinations
Yang Wang <[email protected]>
drm/amdgpu: check ASPM on the dGPU host link
Yang Wang <[email protected]>
drm/amdgpu: fix nbif 6.3.1 l1 low power not functional
David Rosca <[email protected]>
drm/amdgpu: Reject UVD message with invalid number of h265 refs
Nathan Lucas <[email protected]>
drm/amd/display: fix BT.2020 YCbCr output CSC matrices for DCE
Nathan Lucas <[email protected]>
drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix
Samuel Pitoiset <[email protected]>
drm/amd/display: Fix NULL pointer dereference in amdgpu_dm_crtc_set_vblank()
Harald Freudenberger <[email protected]>
s390/zcrypt: Fix CPRB memory allocation in zcrypt misc code
Eric Farman <[email protected]>
s390/vfio_ccw: Implement a crw lock
Eric Farman <[email protected]>
s390/vfio_ccw: Calculate idal length based on idaw type
Eric Farman <[email protected]>
s390/vfio_ccw: Selectively expand io_mutex
Eric Farman <[email protected]>
s390/vfio_ccw: Move cp cleanup out of not operational
Eric Farman <[email protected]>
s390/vfio_ccw: Fix out of bounds check on CCW array
Eric Farman <[email protected]>
s390/vfio_ccw: Ensure first IDAW remains constant
Eric Farman <[email protected]>
s390/vfio_ccw: Ensure index for read/write regions are within range
Eric Farman <[email protected]>
s390/vfio_ccw: Cancel existing workqueues
Eric Farman <[email protected]>
s390/vfio_ccw: Limit the number of channel program segments
Eric Farman <[email protected]>
s390/vfio_ccw: Free all memory if cp_init() fails
Jakub Kicinski <[email protected]>
eth: bnxt: make sure we populate the qcfg defaults on old FW/HW
Jakub Kicinski <[email protected]>
eth: bnxt: always set the queue mgmt ops
Guangshuo Li <[email protected]>
drm/radeon: fix autosuspend cleanup during teardown
Raag Jadav <[email protected]>
drm/xe: Fix xe_device_probe() failure
Matthew Brost <[email protected]>
drm/xe: Order ring writes before ring tail updates
Dmitry Osipenko <[email protected]>
pmdomain: mediatek: Fix mt8183 hang on boot
Binbin Zhou <[email protected]>
mmc: loongson2: Fix sg iteration in data reorder functions
John Harrison <[email protected]>
drm/connector/hdmi: Fix out of bounds memory read
Pei Xiao <[email protected]>
mmc: atmel-mci: Fix use-after-free in atmci_remove due to race condition
AngeloGioacchino Del Regno <[email protected]>
pmdomains: mediatek: Avoid setting RTFF's CLK_DIS before NRESTORE
Haibo Chen <[email protected]>
mmc: sdhci: make tuning_err a signed int
Guangshuo Li <[email protected]>
pmdomain: mediatek: fix remaining %pOF after of_node_put()
Myeonghun Pak <[email protected]>
mmc: sdhci: unmap the bounce buffer before device release
Zhan Xusheng <[email protected]>
mmc: omap_hsmmc: fix busy_timeout overflow in ns conversion on 32-bit
Kefu Chai <[email protected]>
libceph: tolerate addrvecs with multiple entries of the same type
Yiming Zhu <[email protected]>
ceph: fix MDS random selection readiness predicate
Raphael Zimmer <[email protected]>
libceph: Avoid using invalid osd indices from primary_temp
Dmitry Torokhov <[email protected]>
Input: sur40 - fix V4L error path cleanup
Dmitry Torokhov <[email protected]>
Input: sur40 - fix input device registration ordering
Ali Ahmet Memis <[email protected]>
openrisc: signal: do not restore privileged SR bits on sigreturn
Josh Poimboeuf <[email protected]>
ftrace: Fix off-by-one fentry site disable in ftrace_free_mem()
Leon Hwang <[email protected]>
ftrace: Protect direct_functions in ftrace_find_rec_direct
Pavitra Jha <[email protected]>
libceph: fix multiple unsafe decodes in decode_locker()
Praveen Talari <[email protected]>
pmdomain: arm: Fix -EINVAL from scmi_pd_set_perf_state() on state 0
Junjie Cao <[email protected]>
gpio: ml-ioh: use raw_spinlock_t for the register lock
Jordan Rhee <[email protected]>
gve: fix zero-length skb frag with header-split
Rui Qi <[email protected]>
selftests/ftrace: Convert ELF entry point to file offset in uprobe test
Cengiz Can <[email protected]>
gpio: sloppy-logic-analyzer: fix use-after-free via debugfs trigger on unbind
Jordan Rhee <[email protected]>
gve: fix NULL dereference due to missing ptp adjfine
Thorsten Blum <[email protected]>
crypto: qce - fix error path in devm_qce_register_algs
Thorsten Blum <[email protected]>
crypto: starfive - use scatterlist length before DMA mapping
Jianing Li <[email protected]>
Input: hynitron_cstxxx - validate touch count and finger IDs
Dmitry Torokhov <[email protected]>
Input: synaptics-rmi4 - propagate F54 worker errors to V4L2 queue
Dmitry Torokhov <[email protected]>
Input: synaptics-rmi4 - block s_input when F54 queue is busy
Bryam Vargas <[email protected]>
Input: synaptics-rmi4 - bound the F54 report size to the allocated buffer
Dmitry Torokhov <[email protected]>
Input: synaptics-rmi4 - zero report size on F54 work error
George Wilson <[email protected]>
powerpc/pseries: papr-phy-attest - validate cmd.length, plug mem leak
George Wilson <[email protected]>
powerpc/pseries: lparcfg - fix kbuf[] underflow
Linmao Li <[email protected]>
Input: byd - synchronize timer deletion before freeing private data
Pengpeng Hou <[email protected]>
Input: iforce - validate input packet lengths
Zhefu Zhang <[email protected]>
Input: atkbd - skip deactivate for Xiaomi Book Pro 14's internal keyboard
Linmao Li <[email protected]>
Input: psxpad-spi - set driver data before use
Richard Davies <[email protected]>
Input: focaltech - fix array out-of-bounds in focaltech_process_rel_packet
Dmitry Torokhov <[email protected]>
Input: synaptics-rmi4 - fix F55 transmitter electrode count typo
George Wilson <[email protected]>
powerpc/pseries: pci - logic bug
HyeongJun An <[email protected]>
Input: cs40l50-vibra - validate custom data from user space
Kyohei Kadota <[email protected]>
Input: xpad - add support for ZENAIM LEVERLESS
Bard Liao <[email protected]>
ASoC: SOF: topology: Use acpi mach from the machine driver
Asad Kamal <[email protected]>
drm/amdgpu: fix aperture iounmap skipped on device removal
Jesse Zhang <[email protected]>
drm/amdgpu: fix JPEG v4.0.5 queue reset failure in DPG mode
Jesse Zhang <[email protected]>
drm/amdgpu: fix JPEG v5.0.0 queue reset failure in DPG mode
Qiang Yu <[email protected]>
drm/amdgpu: read TRUNCATE_COORD_MODE on gfx12
Candice Li <[email protected]>
drm/amdgpu: reject oversized IBs with per-ring packet limits
Osama Abdelkader <[email protected]>
drm/panthor: skip zero-sized firmware sections
Mingyu Wang <[email protected]>
fbdev: core: Fix pointer desynchronization in fb_io_read()
Dawid Wróbel <[email protected]>
ASoC: codecs: lpass-wsa-macro: Fix enum kcontrol accesses
Peter Ujfalusi <[email protected]>
ASoC: cs35l41: sort the register default table
Peter Ujfalusi <[email protected]>
ASoC: cs35l45: sort the register default table
Peter Ujfalusi <[email protected]>
ASoC: cs4265: sort the register default table
Peter Ujfalusi <[email protected]>
ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout
Peter Ujfalusi <[email protected]>
ASoC: SOF: sof-audio: Fix error path in sof_widget_setup_unlocked()
Hidayath Khan <[email protected]>
s390/qeth: validate user buffer length in SNMP and ARP query ioctls
Wyatt Feng <[email protected]>
mptcp: fastopen: only mark MPTFO subflows with SYN data
Qing Luo <[email protected]>
mptcp: pm: fix data race in add_addr timer callback
Matthieu Baerts (NGI0) <[email protected]>
mptcp: options: reset DSS fields in case of unexpected size
Matthieu Baerts (NGI0) <[email protected]>
mptcp: avoid combining some incoming suboptions
Gang Yan <[email protected]>
selftests: mptcp: join: mark tests with data corruption as failed
Paolo Abeni <[email protected]>
mptcp: reclaim forward-allocated memory on RX path errors
Bryam Vargas <[email protected]>
selinux: reject a permission value exceeding the class permission count
Bryam Vargas <[email protected]>
selinux: reject an unclaimed class value in security_get_classes()
Bryam Vargas <[email protected]>
selinux: do not cancel a policy conversion that never started
Bryam Vargas <[email protected]>
selinux: reject a class permission count below its inherited common
Bryam Vargas <[email protected]>
selinux: require every boolean value to be defined
Yizhou Zhao <[email protected]>
ipvs: separate destination availability state
Liyuan Pang <[email protected]>
ubi: fastmap: fix ubi->fm memory leak
Cheng Ming Lin <[email protected]>
mtd: ubi: skip programming unused bits in ubi headers
Chao Shi <[email protected]>
block: stop the timeout timer when releasing a never added disk
Michael Diesen <[email protected]>
ALSA: hda/realtek: Add quirk for HP Dragonfly Folio G3 2-in-1 (103c:8a05)
-------------
Diffstat:
Makefile | 4 +- arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 + arch/m68k/Kconfig.cpu | 4 + arch/openrisc/include/asm/processor.h | 2 + arch/openrisc/kernel/signal.c | 5 +- arch/powerpc/platforms/pseries/lparcfg.c | 2 +- arch/powerpc/platforms/pseries/papr-phy-attest.c | 12 +- arch/powerpc/platforms/pseries/pci.c | 2 +- arch/riscv/kernel/ftrace.c | 5 +- arch/x86/kvm/x86.c | 6 + block/genhd.c | 12 +- crypto/ccm.c | 2 +- drivers/accel/amdxdna/aie2_ctx.c | 16 ++ drivers/ata/libata-eh.c | 29 +- drivers/ata/libata-scsi.c | 115 ++++++-- drivers/ata/libata.h | 3 +- drivers/base/regmap/regmap-sdw-mbq.c | 4 +- drivers/crypto/qce/core.c | 2 +- drivers/crypto/starfive/jh7110-aes.c | 2 +- drivers/crypto/tegra/tegra-se-aes.c | 22 +- drivers/firewire/ohci.c | 83 ++++-- drivers/gpio/gpio-ml-ioh.c | 71 ++--- drivers/gpio/gpio-sloppy-logic-analyzer.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 31 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 50 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 21 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 +- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 85 ++---- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 5 + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 21 +- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 21 +- drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c | 42 ++- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 26 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 2 +- .../gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 31 ++- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 7 +- .../drm/amd/display/dc/dce110/dce110_opp_csc_v.c | 7 +- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 24 +- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 18 +- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 3 +- drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 5 +- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 +- drivers/gpu/drm/clients/drm_log.c | 13 +- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 +- drivers/gpu/drm/drm_client.c | 181 ++++++------- drivers/gpu/drm/drm_fbdev_dma.c | 6 +- drivers/gpu/drm/drm_fbdev_shmem.c | 4 +- drivers/gpu/drm/drm_fbdev_ttm.c | 8 +- drivers/gpu/drm/panthor/panthor_fw.c | 3 + drivers/gpu/drm/radeon/radeon_kms.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 + drivers/gpu/drm/xe/xe_device.c | 6 +- drivers/gpu/drm/xe/xe_lrc.c | 7 + drivers/gpu/drm/xe/xe_oa.c | 4 + drivers/input/joystick/iforce/iforce-packets.c | 11 +- drivers/input/joystick/iforce/iforce-usb.c | 3 + drivers/input/joystick/psxpad-spi.c | 1 + drivers/input/joystick/xpad.c | 2 + drivers/input/keyboard/atkbd.c | 8 + drivers/input/misc/cs40l50-vibra.c | 10 +- drivers/input/mouse/byd.c | 2 +- drivers/input/mouse/focaltech.c | 2 +- drivers/input/rmi4/rmi_f54.c | 43 ++- drivers/input/rmi4/rmi_f55.c | 4 +- drivers/input/touchscreen/hynitron_cstxxx.c | 13 +- drivers/input/touchscreen/sur40.c | 23 +- drivers/mmc/host/atmel-mci.c | 2 + drivers/mmc/host/loongson2-mmc.c | 8 +- drivers/mmc/host/omap_hsmmc.c | 2 +- drivers/mmc/host/sdhci.c | 16 ++ drivers/mmc/host/sdhci.h | 2 +- drivers/mtd/ubi/attach.c | 4 +- drivers/mtd/ubi/fastmap-wl.c | 8 +- drivers/mtd/ubi/io.c | 10 + drivers/mtd/ubi/ubi.h | 12 + drivers/net/can/rcar/rcar_canfd.c | 181 ++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 30 ++- drivers/net/ethernet/google/gve/gve_ptp.c | 6 + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 5 + drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 + drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 4 +- drivers/net/ipvlan/ipvlan_main.c | 4 + drivers/net/macvlan.c | 4 + drivers/net/ntb_netdev.c | 294 ++++++++++++++------- drivers/net/ovpn/crypto.c | 16 +- drivers/net/ovpn/io.c | 10 +- drivers/net/phy/realtek/realtek_main.c | 2 +- drivers/net/tap.c | 3 +- drivers/net/veth.c | 2 +- drivers/pmdomain/arm/scmi_perf_domain.c | 2 +- drivers/pmdomain/mediatek/mt8183-pm-domains.h | 7 +- drivers/pmdomain/mediatek/mtk-pm-domains.c | 30 +-- drivers/s390/cio/vfio_ccw_async.c | 16 ++ drivers/s390/cio/vfio_ccw_chp.c | 31 ++- drivers/s390/cio/vfio_ccw_cp.c | 74 ++++-- drivers/s390/cio/vfio_ccw_cp.h | 10 + drivers/s390/cio/vfio_ccw_drv.c | 21 +- drivers/s390/cio/vfio_ccw_fsm.c | 8 +- drivers/s390/cio/vfio_ccw_ops.c | 39 ++- drivers/s390/cio/vfio_ccw_private.h | 10 +- drivers/s390/crypto/zcrypt_ccamisc.c | 20 +- drivers/s390/crypto/zcrypt_ep11misc.c | 16 +- drivers/s390/net/qeth_core_main.c | 3 + drivers/s390/net/qeth_l3_main.c | 5 + drivers/spi/spi-virtio.c | 2 + drivers/video/fbdev/core/fb_io_fops.c | 8 + fs/binfmt_misc.c | 32 ++- fs/btrfs/block-group.c | 36 +-- fs/btrfs/zoned.c | 5 +- fs/btrfs/zoned.h | 6 +- fs/ceph/caps.c | 17 +- fs/ceph/file.c | 9 +- fs/ceph/mds_client.c | 11 + fs/ceph/mds_client.h | 1 + fs/ceph/mdsmap.c | 2 +- fs/erofs/Kconfig | 3 +- fs/proc/task_mmu.c | 148 ++++++----- fs/smb/client/cifsglob.h | 6 - fs/smb/client/cifssmb.c | 6 +- fs/smb/client/connect.c | 2 +- fs/smb/client/smb1transport.c | 8 +- fs/smb/common/cifsglob.h | 5 + fs/smb/server/auth.c | 4 +- fs/smb/server/connection.c | 23 +- fs/smb/server/oplock.c | 8 +- fs/smb/server/server.c | 2 +- fs/smb/server/smb2pdu.c | 70 ++--- fs/smb/server/smb2pdu.h | 9 - fs/smb/server/smb_common.c | 26 +- fs/smb/server/smb_common.h | 14 +- fs/xfs/libxfs/xfs_exchmaps.c | 10 + fs/xfs/libxfs/xfs_rtrefcount_btree.c | 4 +- fs/xfs/libxfs/xfs_sb.c | 4 +- fs/xfs/scrub/agheader.c | 2 +- fs/xfs/scrub/agheader_repair.c | 152 +++++++++-- fs/xfs/scrub/alloc.c | 5 +- fs/xfs/scrub/attr_repair.c | 3 +- fs/xfs/scrub/bmap.c | 5 + fs/xfs/scrub/dirtree_repair.c | 22 +- fs/xfs/scrub/inode_repair.c | 2 +- fs/xfs/scrub/nlinks.c | 13 +- fs/xfs/scrub/nlinks_repair.c | 7 +- fs/xfs/scrub/parent.c | 2 +- fs/xfs/scrub/rtbitmap_repair.c | 46 ++-- fs/xfs/scrub/tempfile.c | 1 + fs/xfs/scrub/trace.h | 2 + fs/xfs/xfs_buf_item_recover.c | 57 ++-- fs/xfs/xfs_dquot.c | 3 +- fs/xfs/xfs_dquot_item_recover.c | 2 +- fs/xfs/xfs_rtalloc.c | 2 +- include/drm/drm_client.h | 16 +- include/linux/libata.h | 2 + include/linux/swapops.h | 4 +- include/net/ip_vs.h | 7 + include/uapi/linux/ip_vs.h | 6 - kernel/events/core.c | 8 +- kernel/futex/core.c | 4 +- kernel/sched/ext.c | 97 ++++--- kernel/trace/ftrace.c | 9 +- kernel/trace/ring_buffer.c | 118 +++++---- mm/hmm.c | 2 +- mm/huge_memory.c | 22 +- mm/khugepaged.c | 2 +- mm/madvise.c | 2 +- mm/memory.c | 4 +- mm/mempolicy.c | 2 +- mm/migrate.c | 2 +- mm/page_table_check.c | 20 +- mm/page_vma_mapped.c | 2 +- mm/pagewalk.c | 2 +- mm/pgtable-generic.c | 2 +- net/ceph/cls_lock_client.c | 21 +- net/ceph/decode.c | 18 +- net/ceph/osdmap.c | 9 +- net/ipv4/tcp_input.c | 6 +- net/ipv4/tcp_timer.c | 4 +- net/mptcp/fastopen.c | 7 +- net/mptcp/options.c | 67 ++++- net/mptcp/pm.c | 6 +- net/mptcp/protocol.c | 6 + net/mptcp/protocol.h | 1 + net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- net/netfilter/ipset/ip_set_core.c | 19 +- net/netfilter/ipset/ip_set_list_set.c | 10 +- net/netfilter/ipvs/ip_vs_conn.c | 4 +- net/netfilter/ipvs/ip_vs_core.c | 6 +- net/netfilter/ipvs/ip_vs_ctl.c | 4 +- net/netfilter/ipvs/ip_vs_dh.c | 4 +- net/netfilter/ipvs/ip_vs_lblc.c | 2 +- net/netfilter/ipvs/ip_vs_lblcr.c | 8 +- net/netfilter/nf_flow_table_core.c | 7 +- net/netfilter/nf_tables_offload.c | 2 +- net/packet/af_packet.c | 7 +- net/sched/act_api.c | 10 +- net/sched/cls_bpf.c | 18 +- net/sched/cls_u32.c | 3 + net/sched/sch_api.c | 24 +- net/tls/tls_sw.c | 5 + security/selinux/ss/policydb.c | 34 +++ security/selinux/ss/services.c | 28 +- sound/hda/codecs/realtek/alc269.c | 1 + sound/soc/codecs/cs35l41-lib.c | 2 +- sound/soc/codecs/cs35l45-tables.c | 32 +-- sound/soc/codecs/cs4265.c | 4 +- sound/soc/codecs/lpass-wsa-macro.c | 8 +- sound/soc/codecs/tas2562.c | 9 +- sound/soc/codecs/tas2781-i2c.c | 18 +- sound/soc/intel/common/sof-function-topology-lib.c | 7 +- sound/soc/sof/ipc4-pcm.c | 25 +- sound/soc/sof/ipc4-topology.c | 33 +++ sound/soc/sof/sof-audio.c | 9 +- sound/soc/xilinx/xlnx_formatter_pcm.c | 10 +- .../ftrace/test.d/dynevent/add_remove_uprobe.tc | 27 +- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 +- 214 files changed, 2504 insertions(+), 1265 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/217 ALSA: hda/realtek: Add quirk for HP Dragonfly Folio G3 2-in-1 (103c:8a05)
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Diesen <[email protected]>
[ Upstream commit bed0c8084044364f5ac3f3e89e1bbad423f6b0d4 ]
The HP Dragonfly Folio G3 2-in-1 also ships with PCI SSID 103c:8a05. On this unit the ALC245 codec reports subsystem id 103c:8a06 - the SSID that is already covered by commit 0a10faad5ca5 ("ALSA: hda/realtek: add quirk for HP Dragonfly Folio G3 2-in-1") - while the PCI SSID that SND_PCI_QUIRK matches against is 103c:8a05:
snd_hda_codec_alc269 ehdaudio0D0: ALC245: picked fixup for PCI SSID 103c:8a05 cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: CS35L41 Bound - SSID: 103C8A06
The existing entry therefore never applies here, the four CS35L41 amplifiers on SPI are not registered and the internal speakers stay silent.
Add the same fixup that the 8a06 entry uses: the four amplifiers bind and the speaker mute LED (codec GPIO 0x04) works.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -6839,6 +6839,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x103c ,0x89d3 ,"HP EliteBook 645 G9 (MB 89D2)" ,ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF ),SND_PCI_QUIRK (0x103c ,0x89da ,"HP Spectre x360 14t-ea100" ,ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX ),SND_PCI_QUIRK (0x103c ,0x89e7 ,"HP Elite x2 G9" ,ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED ), +SND_PCI_QUIRK (0x103c ,0x8a05 ,"HP Dragonfly Folio G3 2-in-1" ,ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED ),SND_PCI_QUIRK (0x103c ,0x8a06 ,"HP Dragonfly Folio G3 2-in-1" ,ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED ),SND_PCI_QUIRK (0x103c ,0x8a0f ,"HP Pavilion 14-ec1xxx" ,ALC287_FIXUP_HP_GPIO_LED ), SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 2/217 block: stop the timeout timer when releasing a never added disk
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Shi <[email protected]>
[ Upstream commit 26cb8ebbfaf713c82e142d08828d4d765057633b ]
disk_release() undoes blk_mq_init_allocated_queue() for a disk whose probe failed before add_disk(), but it only calls blk_mq_exit_queue(). Nothing there stops q->timeout, and that timer rolls forward: it stays pending until it next expires, not until the last request completes. So if the driver issued any I/O before adding the disk, the request_queue is freed while still linked into a timer wheel bucket.
Commit 6f8191fdf41d ("block: simplify disk shutdown") dropped the blk_cleanup_queue() call that used to stop it. __del_gendisk() and blk_mq_destroy_queue() still do; only the probe failure path lost it.
nvme gets there because nvme_update_ns_info() submits Report Zones or FDP io-mgmt-recv on ns->queue before the disk is added, so a later failure - a concurrent reset setting NVME_CTRL_FROZEN, or device_add_disk() failing - lands in put_disk() with the timer armed:
BUG: KASAN: slab-use-after-free in detach_if_pending+0x30c/0x340 Write of size 8 at addr ffff888004d71310 by task kworker/u8:2/37 __timer_delete_sync+0x156/0x240 kernel/time/timer.c:1621 blk_sync_queue+0x22/0x40 block/blk-core.c:222 nvme_sync_queues+0x100/0x150 drivers/nvme/host/core.c:5362 nvme_reset_work+0x138/0x930 drivers/nvme/host/pci.c:3264 Allocated by task 34: __blk_mq_alloc_disk+0x33/0x100 block/blk-mq.c:4462 nvme_alloc_ns+0x290/0x3870 drivers/nvme/host/core.c:4146 Freed by task 0: blk_free_queue_rcu+0x3a/0x50 block/blk-core.c:254 rcu_core+0xc10/0x1730 kernel/rcu/tree.c:2857
The queue being synced there is ctrl->admin_q, only a victim sharing a timer wheel bucket with the freed queue's dangling entry; other runs tripped in enqueue_timer(), __run_timers() or blk_mq_timeout_work(). Failing nvme_alloc_ns() with a debug patch makes it deterministic: one leaked timer trips KASAN within seconds, while 1987 patched releases produced no splat.
Stop the timer and the queue work items before blk_mq_exit_queue(), like blk_mq_destroy_queue() does.
Found by FuzzNvme.
--- block/genhd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
block/genhd.c +8 -4
@@ -1281,14 +1281,18 @@ static void disk_release(struct device *dev)/* * To undo the all initialization from blk_mq_init_allocated_queue in * case of a probe failure where add_disk is never called we have to -* call blk_mq_exit_queue here. We can't do this for the more common -* teardown case (yet) as the tagset can be gone by the time the disk -* is released once it was added. +* call blk_mq_exit_queue here, after stopping the timer and work items +* that I/O issued before add_disk may have left pending. We can't do +* this for the more common teardown case (yet) as the tagset can be +* gone by the time the disk is released once it was added. */ if (queue_is_mq (disk->queue) &&test_bit (GD_OWNS_QUEUE , &disk->state) && - !test_bit (GD_ADDED , &disk->state)) + !test_bit (GD_ADDED , &disk->state)) { +blk_sync_queue (disk->queue); +blk_mq_cancel_work_sync (disk->queue);blk_mq_exit_queue (disk->queue); + }blkcg_exit_disk (disk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 3/217 mtd: ubi: skip programming unused bits in ubi headers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Ming Lin <[email protected]>
[ Upstream commit 77530d1a78ca5c274e37d6494a965223672630b2 ]
This patch prevents unnecessary programming of bits in ec_hdr and vid_hdr that are not used or read during normal UBI operation. These unused bits are typcially already set to 1 in erased flash and do not need to be explicitly programmed to 0 if they are not used.
Programming such unused areas offers no functional benefit and may result in unnecessary flash wear, reducing the overall lifetime of the device. By skipping these writes, we preserve the flash state as much as possible and minimize wear caused by redundant operations.
This change ensures that only necessary fields are written when preparing UBI headers, improving flash efficiency without affecting functionality.
Additionally, the Kioxia TC58NVG1S3HTA00 datasheet (page 63) also notes that continuous program/erase cycling with a high percentage of '0' bits in the data pattern can accelerate block endurance degradation. This further supports avoiding large 0x00 patterns.
--- drivers/mtd/ubi/io.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/mtd/ubi/io.c +10 -0
@@ -868,6 +868,8 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,return -EROFS ; } +memset ((char *)ec_hdr +UBI_EC_HDR_SIZE ,0xFF , ubi->ec_hdr_alsize -UBI_EC_HDR_SIZE ); + err =ubi_io_write (ubi, ec_hdr, pnum,0 , ubi->ec_hdr_alsize);return err; }
@@ -1150,6 +1152,14 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,return -EROFS ; } +if (ubi->vid_hdr_shift) { +memset ((char *)p,0xFF , ubi->vid_hdr_shift); +memset ((char *)p + ubi->vid_hdr_shift +UBI_VID_HDR_SIZE ,0xFF , + ubi->vid_hdr_alsize - (ubi->vid_hdr_shift +UBI_VID_HDR_SIZE )); + }else { +memset ((char *)p +UBI_VID_HDR_SIZE ,0xFF , ubi->vid_hdr_alsize -UBI_VID_HDR_SIZE ); + } + err =ubi_io_write (ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 4/217 ubi: fastmap: fix ubi->fm memory leak
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liyuan Pang <[email protected]>
[ Upstream commit d133e30aabc7c8eb8206827f8fbe0f3679adb911 ]
The problem is that scan_fast() allocate memory for ubi->fm and ubi->fm->e[x], but if the following attach process fails in ubi_wl_init or ubi_read_volume_table, the whole attach process will fail without executing ubi_wl_close to free the memory under ubi->fm.
Fix this by add a new ubi_free_fastmap function in fastmap.c to free the memory allocated for fm.
If SLUB_DEBUG and KUNIT are enabled, the following warning messages will show:
ubi0: detaching mtd0
ubi0: mtd0 is detached
ubi0: default fastmap pool size: 200
ubi0: default fastmap WL pool size: 100
ubi0: attaching mtd0
ubi0: attached by fastmap
ubi0: fastmap pool size: 200
ubi0: fastmap WL pool size: 100
ubi0 error: ubi_wl_init [ubi]: no enough physical eraseblocks (4, need 203) ubi0 error: ubi_attach_mtd_dev [ubi]: failed to attach mtd0, error -28 UBI error: cannot attach mtd0
=================================================================
BUG ubi_wl_entry_slab (Tainted: G B O L ): Objects remaining in ubi_wl_entry_slab on __kmem_cache_shutdown()
-----------------------------------------------------------------------------
Slab 0xffff2fd23a40cd00 objects=22 used=1 fp=0xffff2fd1d0334fd8 flags=0x883fffc010200(slab|head|section=34|node=0|zone=1|lastcpupid=0x7fff)
CPU: 0 PID: 5884 Comm: insmod Tainted: G B O L 5.10.0 #1 Hardware name: LS1043A RDB Board (DT) Call trace: dump_backtrace+0x0/0x198 show_stack+0x18/0x28 dump_stack+0xe8/0x15c slab_err+0x94/0xc0 __kmem_cache_shutdown+0x1fc/0x39c kmem_cache_destroy+0x48/0x138 ubi_init+0x1d4/0xf34 [ubi] do_one_initcall+0xb4/0x24c do_init_module+0x4c/0x1dc load_module+0x212c/0x2260 __se_sys_finit_module+0xb4/0xd8 __arm64_sys_finit_module+0x18/0x28 el0_svc_common.constprop.0+0x78/0x1a0 do_el0_svc+0x78/0x90 el0_svc+0x20/0x38 el0_sync_handler+0xf0/0x140 normal+0x3d8/0x400 Object 0xffff2fd1d0334e68 @offset=3688 Allocated in ubi_scan_fastmap+0xf04/0xf40 [ubi] age=80 cpu=0 pid=5884 __slab_alloc.isra.21+0x6c/0xb4 kmem_cache_alloc+0x1e4/0x80c ubi_scan_fastmap+0xf04/0xf40 [ubi] ubi_attach+0x1f0/0x3a8 [ubi] ubi_attach_mtd_dev+0x810/0xbc8 [ubi] ubi_init+0x238/0xf34 [ubi] do_one_initcall+0xb4/0x24c do_init_module+0x4c/0x1dc load_module+0x212c/0x2260 __se_sys_finit_module+0xb4/0xd8 __arm64_sys_finit_module+0x18/0x28 el0_svc_common.constprop.0+0x78/0x1a0 do_el0_svc+0x78/0x90 el0_svc+0x20/0x38 el0_sync_handler+0xf0/0x140 normal+0x3d8/0x400
--- drivers/mtd/ubi/attach.c | 4 +++- drivers/mtd/ubi/fastmap-wl.c | 8 +------- drivers/mtd/ubi/ubi.h | 12 ++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-)
drivers/mtd/ubi/attach.c +3 -1
@@ -1600,7 +1600,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) err =ubi_read_volume_table (ubi, ai);if (err) - goto out_ai; + goto out_fm; err =ubi_wl_init (ubi, ai);if (err)
@@ -1642,6 +1642,8 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) out_vtbl:ubi_free_all_volumes (ubi);vfree (ubi->vtbl); +out_fm: +ubi_free_fastmap (ubi); out_ai:destroy_ai (ai);return err;
drivers/mtd/ubi/fastmap-wl.c +1 -7
@@ -530,8 +530,6 @@ int ubi_is_erase_work(struct ubi_work *wrk)static void ubi_fastmap_close (struct ubi_device *ubi) { -int i; -return_unused_pool_pebs (ubi, &ubi->fm_pool);return_unused_pool_pebs (ubi, &ubi->fm_wl_pool);
@@ -540,11 +538,7 @@ static void ubi_fastmap_close(struct ubi_device *ubi) ubi->fm_anchor =NULL ; } -if (ubi->fm) { -for (i =0 ; i < ubi->fm->used_blocks; i++) -kfree (ubi->fm->e[i]); - } -kfree (ubi->fm); +ubi_free_fastmap (ubi); }/**
drivers/mtd/ubi/ubi.h +12 -0
@@ -969,10 +969,22 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_attach_info *scan_ai);int ubi_fastmap_init_checkmap (struct ubi_volume *vol,int leb_count);void ubi_fastmap_destroy_checkmap (struct ubi_volume *vol); +static inline void ubi_free_fastmap (struct ubi_device *ubi) +{ +if (ubi->fm) { +int i; + +for (i =0 ; i < ubi->fm->used_blocks; i++) +kmem_cache_free (ubi_wl_entry_slab, ubi->fm->e[i]); +kfree (ubi->fm); + ubi->fm =NULL ; + } +}#else static inline int ubi_update_fastmap (struct ubi_device *ubi) {return 0 ; }static inline int ubi_fastmap_init_checkmap (struct ubi_volume *vol,int leb_count) {return 0 ; }static inline void ubi_fastmap_destroy_checkmap (struct ubi_volume *vol) {} +static inline void ubi_free_fastmap (struct ubi_device *ubi) { }#endif /* block.c */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 5/217 ipvs: separate destination availability state
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
commit cdcc4e46180df8161f4d2f3c6fd6beaf6990133d upstream.
IPVS configuration paths update destination availability while connection accounting updates destination overload state. The two independent states share dest->flags, so their read-modify-write updates can race and lose one another.
Keep OVERLOAD in flags, where the preceding patch serializes its updates with dst_lock, and move AVAILABLE to cflags. This keeps configuration- controlled availability out of the scheduler hot cacheline until a scheduler needs to check it. It also prevents availability updates from clobbering overload state.
The destination status bits are not exposed through the IPVS sockopt or netlink interfaces, so keep their definitions in the internal IPVS header.
Readers can still observe stale destination state; this does not provide a cross-field snapshot.
--- include/net/ip_vs.h | 7 +++++++ include/uapi/linux/ip_vs.h | 6 ------ net/netfilter/ipvs/ip_vs_conn.c | 4 ++-- net/netfilter/ipvs/ip_vs_core.c | 6 +++--- net/netfilter/ipvs/ip_vs_ctl.c | 4 ++-- net/netfilter/ipvs/ip_vs_dh.c | 4 ++-- net/netfilter/ipvs/ip_vs_lblc.c | 2 +- net/netfilter/ipvs/ip_vs_lblcr.c | 8 ++++---- 8 files changed, 21 insertions(+), 20 deletions(-)
include/net/ip_vs.h +7 -0
@@ -34,6 +34,12 @@#define IP_VS_HDR_INVERSE 1#define IP_VS_HDR_ICMP 2 +/* Destination Server Flags */ +#define IP_VS_DEST_F_OVERLOAD 0x0002/* server is overloaded */ + +/* Destination Server Config Flags */ +#define IP_VS_DEST_CF_AVAILABLE 0x0001/* server is available */ +/* Generic access of ipvs struct */ static inline struct netns_ipvs *net_ipvs (struct net * net) {
@@ -725,6 +731,7 @@ struct ip_vs_dest {volatile unsigned int flags;/* dest status flags */ atomic_t conn_flags;/* flags to copy to conn */ atomic_t weight;/* server weight */ +unsigned long cflags;/* config flags */ atomic_t last_weight;/* server latest weight */ __u16 tun_type;/* tunnel type */ __be16 tun_port;/* tunnel port */
include/uapi/linux/ip_vs.h +0 -6
@@ -28,12 +28,6 @@#define IP_VS_SVC_F_SCHED_SH_FALLBACK IP_VS_SVC_F_SCHED1/* SH fallback */ #define IP_VS_SVC_F_SCHED_SH_PORT IP_VS_SVC_F_SCHED2/* SH use port */ -/* -* Destination Server Flags -*/ -#define IP_VS_DEST_F_AVAILABLE 0x0001/* server is available */ -#define IP_VS_DEST_F_OVERLOAD 0x0002/* server is overloaded */ -/* * IPVS sync daemon states */
net/netfilter/ipvs/ip_vs_conn.c +2 -2
@@ -759,7 +759,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct, struct ip_vs_dest *cdest)* Checking the dest server status. */ if ((dest ==NULL ) || - !(dest->flags &IP_VS_DEST_F_AVAILABLE ) || + !(dest->cflags &IP_VS_DEST_CF_AVAILABLE ) ||expire_quiescent_template (ipvs, dest) || (cdest && (dest != cdest))) { IP_VS_DBG_BUF(9, "check_template: dest not available for "
@@ -1408,7 +1408,7 @@ void ip_vs_expire_nodest_conn_flush(struct netns_ipvs *ipvs)continue ; dest = cp->dest; -if (!dest || (dest->flags &IP_VS_DEST_F_AVAILABLE )) +if (!dest || (dest->cflags &IP_VS_DEST_CF_AVAILABLE ))continue ;if (atomic_read (&cp->n_control))
net/netfilter/ipvs/ip_vs_core.c +3 -3
@@ -124,7 +124,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)struct ip_vs_dest *dest = cp->dest;struct netns_ipvs *ipvs = cp->ipvs; -if (dest && (dest->flags &IP_VS_DEST_F_AVAILABLE )) { +if (dest && (dest->cflags &IP_VS_DEST_CF_AVAILABLE )) {struct ip_vs_cpu_stats *s;struct ip_vs_service *svc;
@@ -160,7 +160,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)struct ip_vs_dest *dest = cp->dest;struct netns_ipvs *ipvs = cp->ipvs; -if (dest && (dest->flags &IP_VS_DEST_F_AVAILABLE )) { +if (dest && (dest->cflags &IP_VS_DEST_CF_AVAILABLE )) {struct ip_vs_cpu_stats *s;struct ip_vs_service *svc;
@@ -2030,7 +2030,7 @@ ip_vs_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state }/* Check the server status */ -if (cp && cp->dest && !(cp->dest->flags &IP_VS_DEST_F_AVAILABLE )) { +if (cp && cp->dest && !(cp->dest->cflags &IP_VS_DEST_CF_AVAILABLE )) {/* the destination server is not available */ if (sysctl_expire_nodest_conn (ipvs)) {bool old_ct =ip_vs_conn_uses_old_conntrack (cp, skb);
net/netfilter/ipvs/ip_vs_ctl.c +2 -2
@@ -1058,7 +1058,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest, }/* set the dest status flags */ - dest->flags |=IP_VS_DEST_F_AVAILABLE ; + dest->cflags |=IP_VS_DEST_CF_AVAILABLE ;if (READ_ONCE (dest->u_threshold) != udest->u_threshold ||READ_ONCE (dest->l_threshold) != udest->l_threshold) {
@@ -1325,7 +1325,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest, int svcupd) { - dest->flags &= ~IP_VS_DEST_F_AVAILABLE ; + dest->cflags &= ~IP_VS_DEST_CF_AVAILABLE ;/* * Remove it from the d-linked destination list.
net/netfilter/ipvs/ip_vs_dh.c +2 -2
@@ -220,8 +220,8 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, s = (struct ip_vs_dh_state *) svc->sched_data; dest =ip_vs_dh_get (svc->af, s, &iph->daddr); -if (!dest - || !(dest->flags &IP_VS_DEST_F_AVAILABLE ) +if (!dest || + !(dest->cflags &IP_VS_DEST_CF_AVAILABLE ) ||atomic_read (&dest->weight) <=0 ||is_overloaded (dest)) {ip_vs_scheduler_err (svc,"no destination available" );
net/netfilter/ipvs/ip_vs_lblc.c +1 -1
@@ -503,7 +503,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,*/ dest = en->dest; -if ((dest->flags &IP_VS_DEST_F_AVAILABLE ) && +if ((dest->cflags &IP_VS_DEST_CF_AVAILABLE ) &&atomic_read (&dest->weight) >0 && !is_overloaded (dest, svc)) goto out; }
net/netfilter/ipvs/ip_vs_lblcr.c +4 -4
@@ -170,8 +170,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)if (least->flags &IP_VS_DEST_F_OVERLOAD )continue ; -if ((atomic_read (&least->weight) >0 ) - && (least->flags &IP_VS_DEST_F_AVAILABLE )) { +if ((atomic_read (&least->weight) >0 ) && + (least->cflags &IP_VS_DEST_CF_AVAILABLE )) { loh =ip_vs_dest_conn_overhead (least); goto nextstage; }
@@ -187,8 +187,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set) doh =ip_vs_dest_conn_overhead (dest);if (((__s64 )loh *atomic_read (&dest->weight) > - (__s64 )doh *atomic_read (&least->weight)) - && (dest->flags &IP_VS_DEST_F_AVAILABLE )) { + (__s64 )doh *atomic_read (&least->weight)) && + (dest->cflags &IP_VS_DEST_CF_AVAILABLE )) { least = dest; loh = doh; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 6/217 selinux: require every boolean value to be defined
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit a93d37a09b863810653f93d371fb197457d59deb upstream.
p_bools.nprim comes from the policy image independently of how many booleans follow it, and cond_index_bool() fills bool_val_to_struct[] at value - 1, so a count larger than the values present leaves NULL entries. Every user of that array then walks it by index and dereferences each
entry: cond_evaluate_expr() on the access-vector path, security_get_bools() and security_get_bool_value() behind selinuxfs, and security_set_bools(). A sparse class value is absorbed by policydb_class_isvalid() and its siblings; booleans have no such predicate, and no consumer that could use one.
Reject a boolean value that no boolean defines, once, where the array is built. Conforming policies define every boolean they declare and are unaffected.
--- security/selinux/ss/policydb.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
security/selinux/ss/policydb.c +19 -0
@@ -721,6 +721,7 @@ static inline void symtab_hash_eval(strustatic int policydb_index (struct policydb *p) {int i, rc; +u32 v;if (p->mls_enabled) pr_debug(
@@ -773,6 +774,24 @@ static int policydb_index(struct policydif (rc) goto out; } + +/* +* A sparse class value is absorbed by policydb_class_isvalid() and +* its siblings, but no such predicate exists for booleans: every +* user of bool_val_to_struct[] walks it by index and dereferences +* each entry -- cond_evaluate_expr(), the two getters and +* security_set_bools() -- so an unclaimed one has no consumer that +* can tolerate it. +*/ +for (v =0 ; v < p->p_bools.nprim; v++) { +if (!p->bool_val_to_struct[v]) { +pr_err ("SELinux: boolean %u is declared but not defined\n" , + v +1 ); + rc = -EINVAL ; + goto out; + } + } + rc =0 ; out:return rc;
Greg Kroah-Hartman
maintainerPATCH 7/217 selinux: reject a class permission count below its inherited common
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 9a82dcd98b6e6e11cfd162410967951f12152528 upstream.
security_get_permissions() maps an inherited common's permissions into an array sized by the class's own permissions.nprim, but class_read() takes that nprim verbatim from the policy image and never checks that it covers the common. A class that inherits a common of N permissions while declaring a smaller nprim is accepted, and on load the common's permissions are written past the class-sized array -- an out-of-bounds heap write.
Reject a class whose permission count is below its inherited common's. Well-formed policies, where the class count already includes the inherited permissions, are unaffected.
--- security/selinux/ss/policydb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
security/selinux/ss/policydb.c +12 -0
@@ -1385,6 +1385,18 @@ static int class_read(struct policydb *p cladatum->comkey); goto bad; } + +/* +* security_get_permissions() maps the common's permissions +* into an array sized by this class's nprim, so a class must +* declare at least as many as the common it inherits. +*/ +if (cladatum->permissions.nprim < + cladatum->comdatum->permissions.nprim) { +pr_err ("SELinux: class %s has fewer permissions than common %s\n" , + key, cladatum->comkey); + goto bad; + } }for (i =0 ; i < nel; i++) { rc =perm_read (p, &cladatum->permissions, fp);
Greg Kroah-Hartman
maintainerPATCH 8/217 selinux: do not cancel a policy conversion that never started
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit e5c0235a3c4e9eb047a16cd02323fe4ecf2f570e upstream.
sel_write_load() calls selinux_policy_cancel() when sel_make_policy_nodes() fails, and that helper dereferences the outgoing policy to cancel its sidtab conversion. On the first policy load there is no outgoing policy:security_load_policy() returns early for that case, before it converts anything, and state->policy is still NULL. A first load that fails while building the selinuxfs tree therefore takes a NULL dereference in selinux_policy_cancel(), reached from a write(2) to /sys/fs/selinux/load.
Skip the cancel when there is no old policy, mirroring the check security_load_policy() already makes before it converts.
--- security/selinux/ss/services.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
security/selinux/ss/services.c +3 -1
@@ -2220,7 +2220,9 @@ void selinux_policy_cancel(struct selinu oldpolicy =rcu_dereference_protected (state->policy,lockdep_is_held (&state->policy_mutex)); -sidtab_cancel_convert (oldpolicy->sidtab); +/* a first load has no outgoing policy and converted nothing */ +if (oldpolicy) +sidtab_cancel_convert (oldpolicy->sidtab);selinux_policy_free (load_state->policy);kfree (load_state->convert_data); }
Greg Kroah-Hartman
maintainerPATCH 9/217 selinux: reject an unclaimed class value in security_get_classes()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 22b05fec62c0fe9864cfceb52f7d0f3a34d9b1dd upstream.
security_get_classes() sizes an array by p_classes.nprim and fills it at value - 1, so a class value the policy never defines leaves a NULL. sel_make_classes() passes every entry to sel_make_dir(), reaching the same d_alloc_name() dereference as the permission array. The class symbol table is allowed to be sparse (policydb_class_isvalid() exists to absorb that), but this getter builds its own array straight from the hash table and has no such predicate.
Fail the lookup when a value went unclaimed instead of handing out the NULL. Conforming policies define every class they declare and are unaffected.
--- security/selinux/ss/services.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
security/selinux/ss/services.c +19 -5
@@ -3303,6 +3303,7 @@ int security_get_classes(struct selinux_ char ***classes, u32 *nclasses) { struct policydb *policydb; +u32 i;int rc; policydb = &policy->policydb;
@@ -3315,16 +3316,29 @@ int security_get_classes(struct selinux_ rc =hashtab_map (&policydb->p_classes.table, get_classes_callback, *classes); -if (rc) { -u32 i; +if (rc) + goto err; -for (i =0 ; i < *nclasses; i++) -kfree ((*classes)[i]); -kfree (*classes); +/* +* The class symtab may be sparse, which policydb_class_isvalid() exists +* to absorb; the callback fills this array by value, so an unclaimed +* one leaves a NULL that sel_make_classes() hands to sel_make_dir(). +*/ +for (i =0 ; i < *nclasses; i++) { +if (!(*classes)[i]) { + rc = -EINVAL ; + goto err; + } } out:return rc; + +err: +for (i =0 ; i < *nclasses; i++) +kfree ((*classes)[i]); +kfree (*classes); +return rc; }static int get_permissions_callback (void *k,void *d,void *args)
Greg Kroah-Hartman
maintainerPATCH 10/217 selinux: reject a permission value exceeding the class permission count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit d14b5d0e97fccd27974fedc03b903408872907fd upstream.
perm_read() bounds a permission value by SEL_VEC_MAX but never by the nprim of the owning class or common, which is taken verbatim from the policy image. security_get_permissions() then writes perms[value - 1] into an nprim-sized kcalloc() array, so a class declaring fewer permissions than its largest permission value drives an out-of-bounds heap write. The top-level symbol tables are validated this way; the nested per-class permission table is not.
Reject a permission whose value exceeds nprim, which is already set when perm_read() runs. Well-formed policies are unaffected.
--- security/selinux/ss/policydb.c | 3 +++ 1 file changed, 3 insertions(+)
security/selinux/ss/policydb.c +3 -0
@@ -1168,6 +1168,9 @@ static int perm_read(struct policydb *p, rc =symtab_insert (s, key, perdatum);if (rc) goto bad; +/* indexes an nprim-sized array in security_get_permissions() */ +if (perdatum->value > s->nprim) + goto bad;return 0 ; bad:
Greg Kroah-Hartman
maintainerPATCH 11/217 mptcp: reclaim forward-allocated memory on RX path errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
commit 41b49a8b914ec7dcb03eae93fb27f3c464078644 upstream.
After commit 9db5b3cec4ec ("mptcp: borrow forward memory from subflow"), errors in the receive path prior to queueing skbs into the receive queue do not trigger forward-allocated memory reclaiming.
Prevent forward memory from growing unboundedly in pathological drop scenarios by explicitly reclaiming memory when skbs are dropped.
--- net/mptcp/protocol.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/mptcp/protocol.c +6 -0
@@ -147,6 +147,12 @@ struct sock *__mptcp_nmpc_sk(struct mptcstatic void mptcp_drop (struct sock *sk,struct sk_buff *skb) { +/* The skb forward memory was already transferred to sk by +* mptcp_borrow_fwdmem(), even before setting the destructor. +*/ +if (!skb->destructor) +sk_mem_reclaim (sk); +sk_drops_skbadd (sk, skb);__kfree_skb (skb); }
Greg Kroah-Hartman
maintainerPATCH 12/217 selftests: mptcp: join: mark tests with data corruption as failed
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gang Yan <[email protected]>
commit ca318e7bbb7723f57bcd9e69a2873b5884435552 upstream.
check_transfer() compares the input and output files byte-by-byte using cmp -l "$in" "$out" | while read .... Because the while-loop body runs in a subshell (the script sets neither lastpipe nor pipefail), the fail_test call inside it -- which sets the global ret/last_test_failed -- and the return 1 both act on the subshell, not on check_transfer().
check_transfer() thus always falls through to return 0, and any data corruption affecting only the payload (leaving the subflow/PM counters untouched) is silently reported as PASS.
--- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/net/mptcp/mptcp_join.sh +2 -2
@@ -565,7 +565,7 @@ check_transfer() mv "$tmpfile" "$out" tmpfile="" fi - cmp -l "$in" "$out" | while read -r i a b; do + while read -r i a b; do local sum=$((0${a} + 0${b})) if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then fail_test "$what does not match (in, out):"
@@ -576,7 +576,7 @@ check_transfer() else print_info "$what has inverted byte at ${i}" fi - done + done < <(cmp -l "$in" "$out") return 0 }
Greg Kroah-Hartman
maintainerPATCH 13/217 mptcp: avoid combining some incoming suboptions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
commit b6ee361524641f57b2e2363f7737f20e17f67827 upstream.
Some MPTCP suboptions are mutually exclusive according to the RFC8684, but also because in different places, the code doesn't expect some combinations to be present. That's specially true for suboptions that would be present twice, but with different attributes.
The new restrictions are the same as the ones applied on the output side, with mptcp_write_options. The same rules can be reused with a small fix: an MP_FASTCLOSE can be used with a DSS when the sender picks this option [1], which is not the case on Linux. Here are the rules:
Which options can be used together?
X: mutually exclusive
O: often used together
C: can be used together in some cases
P: could be used together but we prefer not to (optimisations)
| Opt: | MPC | MPJ | DSS | ADD | RM | PRIO | FAIL | FC | |------|------|------|------|------|------|------|------|------| | MPC |------|------|------|------|------|------|------|------| | MPJ | X |------|------|------|------|------|------|------| | DSS | X | X |------|------|------|------|------|------| | ADD | X | X | P |------|------|------|------|------| | RM | C | C | C | P |------|------|------|------| | PRIO | X | C | C | C | C |------|------|------| | FAIL | X | X | C | X | X | X |------|------| | FC | X | X | P | X | X | X | X |------| | RST | X | X | X | X | X | X | O | O | |------|------|------|------|------|------|------|------|------|
The only difference is with the 'P': another stack could send and ADD_ADDR with other suboptions (DSS, RM_ADDR), and this should be allowed.
A few points of attention:
- In theory, an MP_CAPABLE could be used with a RM_ADDR, but there is no reason to add it with a SYN. Note that even with a 4th ACK, it doesn't seem to be useful, except when IDs are known in advance via another channel. Better not to break that.
- Now, combining both an MP_CAPABLE and an MP_JOIN will no longer result to a reject of the two options, but only the second suboption is ignored. That seems OK to do that for this unexpected error. At least now all inconsistent combinations are handled the same way. This could change later in next. This also means the explicit checks for having both MPC + MPJ in subflow.c will now be unreachable. That's fine, they will be removed in a follow-up patch.
- In case of conflicting combinations, the extra suboption(s) is/are
ignored: having such combinations either means the remote peer is buggy, or is evil. The simplest action is then taken in this case:
stop processing the current suboption.
- In mp_opt->suboptions, there is also a bit reserved to the checksum, which can be used in an MP_CAPABLE and a DSS. Each time a DSS option can be used in parallel with another option, the checksum can be set, so the verification is combined into a new OPTIONS_MPTCP_DSS macro.
- An MP_CAPABLE ACK can carry a Data-Level Length, and an optional
Checksum: they are the same as the ones found in a DSS, because a DSS cannot be used in parallel to an MP_CAPABLE. Similarly, even if there is room, a DSS cannot be used with an MP_JOIN.
--- net/mptcp/options.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++- net/mptcp/protocol.h | 1 2 files changed, 59 insertions(+), 1 deletion(-)
net/mptcp/options.c +58 -1
@@ -50,6 +50,14 @@ static void mptcp_parse_option(const str } } +/* Only the MPC + ACK can be used with a RM_ADDR */ +if (subopt ==OPTION_MPTCP_MPC_ACK ) { +if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR ) !=0 ) +break ; + }else if (mp_opt->suboptions !=0 ) { +break ; + } +/* Cfr RFC 8684 Section 3.3.0: * If a checksum is present but its use had * not been negotiated in the MP_CAPABLE handshake, the receiver MUST
@@ -122,6 +130,11 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_MP_JOIN : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; +if (opsize ==TCPOLEN_MPTCP_MPJ_SYN ) { mp_opt->suboptions |=OPTION_MPTCP_MPJ_SYN ; mp_opt->backup = *ptr++ &MPTCPOPT_BACKUP ;
@@ -153,6 +166,14 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_DSS : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO | +OPTION_MPTCP_FASTCLOSE | +OPTION_MPTCP_FAIL )) !=0 ) +break ; +pr_debug ("DSS\n" ); ptr++;
@@ -234,6 +255,12 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_ADD_ADDR : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; + mp_opt->echo = (*ptr++) &MPTCP_ADDR_ECHO ;if (!mp_opt->echo) { if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
@@ -293,6 +320,14 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_RM_ADDR : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_MPC_ACK | +OPTIONS_MPTCP_MPJ | +OPTIONS_MPTCP_DSS | +OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; +if (opsize <TCPOLEN_MPTCP_RM_ADDR_BASE +1 || opsize >TCPOLEN_MPTCP_RM_ADDR_BASE +MPTCP_RM_IDS_MAX )break ;
@@ -307,6 +342,13 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_MP_PRIO : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ | +OPTIONS_MPTCP_DSS | +OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_RM_ADDR )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_PRIO )break ;
@@ -316,6 +358,11 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_MP_FASTCLOSE : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RST )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_FASTCLOSE )break ;
@@ -327,6 +374,11 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_RST : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL | +OPTION_MPTCP_FASTCLOSE )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_RST )break ;
@@ -342,6 +394,11 @@ static void mptcp_parse_option(const strbreak ;case MPTCPOPT_MP_FAIL : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RST )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_FAIL )break ;
@@ -1416,7 +1473,7 @@ void mptcp_write_options(struct tcphdr ** RM | C | C | C | P |------|------|------|------| * PRIO | X | C | C | C | C |------|------|------| * FAIL | X | X | C | X | X | X |------|------| -* FC | X | X | X | X | X | X | X |------| +* FC | X | X | P | X | X | X | X |------| * RST | X | X | X | X | X | X | O | O | * ------|------|------|------|------|------|------|------|------| *
net/mptcp/protocol.h +1 -0
@@ -37,6 +37,7 @@ OPTION_MPTCP_MPC_ACK)#define OPTIONS_MPTCP_MPJ (OPTION_MPTCP_MPJ_SYN | OPTION_MPTCP_MPJ_SYNACK | \ OPTION_MPTCP_MPJ_ACK) +#define OPTIONS_MPTCP_DSS (OPTION_MPTCP_DSS | OPTION_MPTCP_CSUMREQD)/* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0
Greg Kroah-Hartman
maintainerPATCH 14/217 mptcp: options: reset DSS fields in case of unexpected size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
commit 35772b4981f38ba8059372cde8753e8e477e98ec upstream.
A remote peer could send a malformed DSS with a wrong size, followed by another DSS or MPC + Data. In this case, the first suboption will be ignored, but leaving some fields written, which could lead to inconsistency or access uninitialized data.
Explicitly reset the fields that could have been modified in case of unexpected size.
--- net/mptcp/options.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
net/mptcp/options.c +7 -1
@@ -209,8 +209,14 @@ static void mptcp_parse_option(const str* RFC 8684 Section 3.3.0 checks later in subflow_data_ready */ if (opsize != expected_opsize && - opsize != expected_opsize +TCPOLEN_MPTCP_DSS_CHECKSUM ) + opsize != expected_opsize +TCPOLEN_MPTCP_DSS_CHECKSUM ) { + mp_opt->dsn64 =0 ; + mp_opt->use_map =0 ; + mp_opt->ack64 =0 ; + mp_opt->use_ack =0 ; + mp_opt->data_fin =0 ;break ; + } mp_opt->suboptions |=OPTION_MPTCP_DSS ;if (mp_opt->use_ack) {
Greg Kroah-Hartman
maintainerPATCH 15/217 mptcp: pm: fix data race in add_addr timer callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Luo <[email protected]>
commit a7aad5b69d3bdaec20a3ed9284e184502450c0cd upstream.
The timer callback reads entry->retrans_times outside pm.lock to decide whether to call mptcp_pm_subflow_established(). Since mptcp_pm_announced_del_timer() can concurrently set retrans_times = ADD_ADDR_RETRANS_MAX under pm.lock, a race condition exists.
I discovered this issue while studying the code. AI tools helped me to verify the issue can potentially happen under race conditions.
Use a local 'retransmit' flag set inside pm.lock to capture whether retransmission is still possible when the lock is taken. This allows to call mptcp_pm_subflow_established() accordingly, and not depending on the situation that can be different when checked outside the pm.lock.
--- net/mptcp/pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/mptcp/pm.c +4 -2
@@ -345,6 +345,7 @@ static void mptcp_pm_add_timer(struct tistruct mptcp_sock *msk = entry->sock;struct sock *sk = (struct sock *)msk;unsigned int timeout =0 ; +bool retransmit;pr_debug ("msk=%p\n" , msk);
@@ -377,14 +378,15 @@ static void mptcp_pm_add_timer(struct ti entry->retrans_times++; } -if (entry->retrans_times <ADD_ADDR_RETRANS_MAX ) + retransmit = entry->retrans_times <ADD_ADDR_RETRANS_MAX ; +if (retransmit) timeout <<= entry->retrans_times;else timeout =0 ;spin_unlock_bh (&msk->pm.lock); -if (entry->retrans_times ==ADD_ADDR_RETRANS_MAX ) +if (!retransmit)mptcp_pm_subflow_established (msk); out:
Greg Kroah-Hartman
maintainerPATCH 16/217 mptcp: fastopen: only mark MPTFO subflows with SYN data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
commit e00b63056fb4f261455b3e5df5268a1f8ce47a87 upstream.
Passive TCP Fast Open accepts a valid-cookie SYN even when it carries no data. In that case the child socket's receive queue is intentionally left empty.
mptcp_fastopen_subflow_synack_set_params() set is_mptfo before checking for queued SYN data. That made data-less TFO SYNs hit a WARN and, if the warning was non-fatal, left stale MPTFO state behind. The stale flag could later trigger a state-confusion bug in check_fully_established().
Only mark the subflow as MPTFO after confirming that an SKB was queued. Return quietly when the receive queue is empty.
Note that mptcp_subflow_context's is_mptfo field is now not just about subflows where the TFO was present, but about MPTFO subflow that consumed SYN data. Only having a valid cookie but not carrying data is not really "doing TFO".
--- net/mptcp/fastopen.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
net/mptcp/fastopen.c +4 -3
@@ -24,12 +24,13 @@ void mptcp_fastopen_subflow_synack_set_p sk = subflow->conn; tp =tcp_sk (ssk); - subflow->is_mptfo =1 ; - +/* A valid TFO cookie does not guarantee SYN data. */ skb =skb_peek (&ssk->sk_receive_queue); -if (WARN_ON_ONCE (!skb)) +if (!skb)return ; + subflow->is_mptfo =1 ; +/* dequeue the skb from sk receive queue */ __skb_unlink (skb, &ssk->sk_receive_queue);skb_ext_reset (skb);
Greg Kroah-Hartman
maintainerPATCH 17/217 s390/qeth: validate user buffer length in SNMP and ARP query ioctls
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit d141f087b1af656f055d7c5793a3e87817ba0bbe upstream.
qeth_snmp_command() and qeth_l3_arp_query() allocate a buffer sized by a user-supplied length (udata_len) without checking a lower bound, then set udata_offset to a fixed non-zero value and pass both to a reply callback. The callback bounds-checks the copy with
if ((udata_len - udata_offset) < len)
Both fields are u32, so a udata_len smaller than udata_offset makes the subtraction wrap and the check pass, and the following memcpy() writes past the allocation. A udata_len of 0 also yields ZERO_SIZE_PTR from kzalloc(), which the existing NULL check does not catch.
Reject buffers smaller than udata_offset before allocating, so the callback subtraction can no longer underflow.
--- drivers/s390/net/qeth_core_main.c | 3 +++ drivers/s390/net/qeth_l3_main.c | 5 +++++ 2 files changed, 8 insertions(+)
drivers/s390/net/qeth_core_main.c +3 -0
@@ -4712,6 +4712,9 @@ static int qeth_snmp_command(struct qethif (req_len >QETH_BUFSIZE )return -EINVAL ; +if (qinfo.udata_len <sizeof (struct qeth_snmp_ureq_hdr )) +return -EINVAL ; + iob =qeth_get_adapter_cmd (card,IPA_SETADP_SET_SNMP_CONTROL , req_len);if (!iob)return -ENOMEM ;
drivers/s390/net/qeth_l3_main.c +5 -0
@@ -1416,6 +1416,11 @@ static int qeth_l3_arp_query(struct qeth rc = -EFAULT ; goto out; } + +if (qinfo.udata_len <QETH_QARP_ENTRIES_OFFSET ) { + rc = -EINVAL ; + goto out; + } qinfo.udata =kzalloc (qinfo.udata_len,GFP_KERNEL );if (!qinfo.udata) { rc = -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 18/217 ASoC: SOF: sof-audio: Fix error path in sof_widget_setup_unlocked()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit e780e4917d43683224812400fe3dc4816fceba75 upstream.
If either tplg_ops->dai_config or widget_kcontrol_setup fail during widget setup we would double decrement the use_count of the widget because the sof_widget_free_unlocked() would be called twice, similarly the core_put would be invoked twice as well.
Since the use_count and core_put() is handled within the widget_free function we need to return without falling through the pipe_widget_free label.
The fixes tag is picked to the last change around this part of the code which is adequately old enough for backporting purposes.
--- sound/soc/sof/sof-audio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
sound/soc/sof/sof-audio.c +4 -5
@@ -136,7 +136,6 @@ static int sof_widget_setup_unlocked(str {const struct sof_ipc_tplg_ops *tplg_ops =sof_ipc_get_ops (sdev, tplg);struct snd_sof_pipeline *spipe = swidget->spipe; -bool use_count_decremented = false;int ret;int i;
@@ -215,9 +214,10 @@ static int sof_widget_setup_unlocked(strreturn 0 ; widget_free: -/* widget use_count will be decremented by sof_widget_free() */ +/* widget use_count and core_put handled by sof_widget_free() */ sof_widget_free_unlocked (sdev, swidget); - use_count_decremented = true; +return ret; + pipe_widget_free:if (swidget->id != snd_soc_dapm_scheduler) {sof_widget_free_unlocked (sdev, swidget->spipe->pipe_widget);
@@ -232,8 +232,7 @@ pipe_widget_free: } } use_count_dec: -if (!use_count_decremented) - swidget->use_count--; + swidget->use_count--;return ret; }
Greg Kroah-Hartman
maintainerPATCH 19/217 ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit 17661c67b206612cb3ba65d5ae726cd2015d0a53 upstream.
Ignore IPC errors for pipeline state change if the firmware state is crashed or the IPC has timed out.
If the firmware has crashed the kernel still needs to go through the state changes to reset its internal to be able to correctly work the next time the DSP is booted up.
The case with IPC timeout is a bit more problematic, but it has been rootcaused to be the result of system scheduling blockage and the firmware did actually received and handled the message, but the reply handling got blocked by issues outside of the SOF stack.
So far the best way to handle this is to continue with setting the state.
--- sound/soc/sof/ipc4-pcm.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
sound/soc/sof/ipc4-pcm.c +19 -6
@@ -528,7 +528,19 @@ static int sof_ipc4_trigger_pipelines(st ret =sof_ipc4_set_multi_pipeline_state (sdev,SOF_IPC4_PIPE_PAUSED , trigger_list);if (ret <0 ) {spcm_err (spcm, substream->stream,"failed to pause all pipelines\n" ); - goto free; +/* +* workaround: if the firmware is crashed or the IPC timed out +* while setting the pipeline state we must ignore the error +* code and proceed to set adjust the local pipeline states. +* +* If the firmware is crashed we will not send IPC messages +* and we are going to see errors printed, but the state of the +* widgets will be correct for the next boot. +*/ +if (sdev->fw_state !=SOF_FW_CRASHED && ret != -ETIMEDOUT ) + goto free; + + ret =0 ; }/* update PAUSED state for all pipelines just triggered */
@@ -560,14 +572,15 @@ skip_pause_transition:"failed to set final state %d for all pipelines\n" , state);/* -* workaround: if the firmware is crashed while setting the -* pipelines to reset state we must ignore the error code and -* reset it to 0. -* Since the firmware is crashed we will not send IPC messages +* workaround: if the firmware is crashed or the IPC timed out +* while setting the pipeline state we must ignore the error +* code and proceed to set adjust the local pipeline states. +* +* If the firmware is crashed we will not send IPC messages * and we are going to see errors printed, but the state of the * widgets will be correct for the next boot. */ -if (sdev->fw_state !=SOF_FW_CRASHED || state !=SOF_IPC4_PIPE_RESET ) +if (sdev->fw_state !=SOF_FW_CRASHED && ret != -ETIMEDOUT ) goto free; ret =0 ;
Greg Kroah-Hartman
maintainerPATCH 20/217 ASoC: cs4265: sort the register default table
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit e4fe3e046524e5de3c04c6eef3743780cbdc231c upstream.
reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").
cs4265_reg_defaults[] lists CS4265_INT_MASK (0x0e), CS4265_STATUS_MODE_MSB (0x0f) and CS4265_STATUS_MODE_LSB (0x10) after CS4265_SPDIF_CTL1 (0x11) and CS4265_SPDIF_CTL2 (0x12), so the binary search does not find those three entries. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.
Sort the table by register address.
--- sound/soc/codecs/cs4265.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/cs4265.c +2 -2
@@ -46,11 +46,11 @@ static const struct reg_default cs4265_r { CS4265_DAC_CHA_VOL, 0x00 }, { CS4265_DAC_CHB_VOL, 0x00 }, { CS4265_DAC_CTL2, 0xC0 }, - { CS4265_SPDIF_CTL1, 0x00 }, - { CS4265_SPDIF_CTL2, 0x00 }, { CS4265_INT_MASK, 0x00 }, { CS4265_STATUS_MODE_MSB, 0x00 }, { CS4265_STATUS_MODE_LSB, 0x00 }, + { CS4265_SPDIF_CTL1, 0x00 }, + { CS4265_SPDIF_CTL2, 0x00 }, };static bool cs4265_readable_register (struct device *dev,unsigned int reg)
Greg Kroah-Hartman
maintainerPATCH 21/217 ASoC: cs35l45: sort the register default table
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit f39a68ed08bb6eef0ae711b41d645ee5e9448c09 upstream.
reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").
cs35l45_defaults[] lists the DSP1_RX*_RATE and DSP1_TX*_RATE registers (0x02b80080 - 0x02b802b8) in the middle of the table, ahead of entries with much lower addresses, so the binary search does not find 36 of its 73 entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.
Sort the table by register address.
--- sound/soc/codecs/cs35l45-tables.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
sound/soc/codecs/cs35l45-tables.c +16 -16
@@ -66,22 +66,6 @@ static const struct reg_default cs35l45_ { CS35L45_ASPTX3_INPUT, 0x00000020 }, { CS35L45_ASPTX4_INPUT, 0x00000028 }, { CS35L45_ASPTX5_INPUT, 0x00000048 }, - { CS35L45_DSP1_RX1_RATE, 0x00000001 }, - { CS35L45_DSP1_RX2_RATE, 0x00000001 }, - { CS35L45_DSP1_RX3_RATE, 0x00000001 }, - { CS35L45_DSP1_RX4_RATE, 0x00000001 }, - { CS35L45_DSP1_RX5_RATE, 0x00000001 }, - { CS35L45_DSP1_RX6_RATE, 0x00000001 }, - { CS35L45_DSP1_RX7_RATE, 0x00000001 }, - { CS35L45_DSP1_RX8_RATE, 0x00000001 }, - { CS35L45_DSP1_TX1_RATE, 0x00000001 }, - { CS35L45_DSP1_TX2_RATE, 0x00000001 }, - { CS35L45_DSP1_TX3_RATE, 0x00000001 }, - { CS35L45_DSP1_TX4_RATE, 0x00000001 }, - { CS35L45_DSP1_TX5_RATE, 0x00000001 }, - { CS35L45_DSP1_TX6_RATE, 0x00000001 }, - { CS35L45_DSP1_TX7_RATE, 0x00000001 }, - { CS35L45_DSP1_TX8_RATE, 0x00000001 }, { CS35L45_DSP1RX1_INPUT, 0x00000008 }, { CS35L45_DSP1RX2_INPUT, 0x00000009 }, { CS35L45_DSP1RX3_INPUT, 0x00000018 },
@@ -114,6 +98,22 @@ static const struct reg_default cs35l45_ { CS35L45_GPIO1_CTRL1, 0x81000001 }, { CS35L45_GPIO2_CTRL1, 0x81000001 }, { CS35L45_GPIO3_CTRL1, 0x81000001 }, + { CS35L45_DSP1_RX1_RATE, 0x00000001 }, + { CS35L45_DSP1_RX2_RATE, 0x00000001 }, + { CS35L45_DSP1_RX3_RATE, 0x00000001 }, + { CS35L45_DSP1_RX4_RATE, 0x00000001 }, + { CS35L45_DSP1_RX5_RATE, 0x00000001 }, + { CS35L45_DSP1_RX6_RATE, 0x00000001 }, + { CS35L45_DSP1_RX7_RATE, 0x00000001 }, + { CS35L45_DSP1_RX8_RATE, 0x00000001 }, + { CS35L45_DSP1_TX1_RATE, 0x00000001 }, + { CS35L45_DSP1_TX2_RATE, 0x00000001 }, + { CS35L45_DSP1_TX3_RATE, 0x00000001 }, + { CS35L45_DSP1_TX4_RATE, 0x00000001 }, + { CS35L45_DSP1_TX5_RATE, 0x00000001 }, + { CS35L45_DSP1_TX6_RATE, 0x00000001 }, + { CS35L45_DSP1_TX7_RATE, 0x00000001 }, + { CS35L45_DSP1_TX8_RATE, 0x00000001 }, };static bool cs35l45_readable_reg (struct device *dev,unsigned int reg)
Greg Kroah-Hartman
maintainerPATCH 22/217 ASoC: cs35l41: sort the register default table
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit d74aac116cfb2058b15df53996d23232b310f7ff upstream.
reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").
cs35l41_reg[] lists CS35L41_BSTCVRT_PEAK_CUR (0x3808) after CS35L41_BSTCVRT_COEFF (0x3810) and CS35L41_BSTCVRT_SLOPE_LBST (0x3814), so the binary search does not find those two entries. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.
Sort the table by register address.
--- sound/soc/codecs/cs35l41-lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/cs35l41-lib.c +1 -1
@@ -25,9 +25,9 @@ static const struct reg_default cs35l41_ { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, { CS35L41_TST_FS_MON0, 0x00020016 }, + { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A }, { CS35L41_BSTCVRT_COEFF, 0x00002424 }, { CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 }, - { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A }, { CS35L41_SP_ENABLES, 0x00000000 }, { CS35L41_SP_RATE_CTRL, 0x00000028 }, { CS35L41_SP_FORMAT, 0x18180200 },
Greg Kroah-Hartman
maintainerPATCH 23/217 ASoC: codecs: lpass-wsa-macro: Fix enum kcontrol accesses
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Wróbel <[email protected]>
commit 56f24311fd5607588a47e44675195a9efb200f29 upstream.
EAR SPKR PA Gain" and the four "WSA RX* Mux" controls are enumerated, but their get and put callbacks access the value through ucontrol->value.integer.value[0] (a long) instead of ucontrol->value.enumerated.item[0] (an unsigned int).
This same pattern was fixed in the sibling drivers by commit bcfe5f76cc40 ("ASoC: codecs: rx-macro: fix accessing array out of bounds for enum type") and
commit 0ea5eff7c606 ("ASoC: codecs: va-macro: fix accessing array out of bounds for enum type"), but wsa-macro was missed.
On 64-bit kernels with CONFIG_SND_CTL_DEBUG this trips the elem value sanity check and every read of these controls fails with -EINVAL.
--- sound/soc/codecs/lpass-wsa-macro.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
sound/soc/codecs/lpass-wsa-macro.c +4 -4
@@ -2167,7 +2167,7 @@ static int wsa_macro_ear_spkr_pa_gain_gestruct snd_soc_component *component =snd_soc_kcontrol_component (kcontrol);struct wsa_macro *wsa =snd_soc_component_get_drvdata (component); - ucontrol->value.integer.value[0 ] = wsa->ear_spkr_gain; + ucontrol->value.enumerated.item[0 ] = wsa->ear_spkr_gain;return 0 ; }
@@ -2178,7 +2178,7 @@ static int wsa_macro_ear_spkr_pa_gain_pustruct snd_soc_component *component =snd_soc_kcontrol_component (kcontrol);struct wsa_macro *wsa =snd_soc_component_get_drvdata (component); - wsa->ear_spkr_gain = ucontrol->value.integer.value[0 ]; + wsa->ear_spkr_gain = ucontrol->value.enumerated.item[0 ];return 0 ; }
@@ -2192,7 +2192,7 @@ static int wsa_macro_rx_mux_get(struct ssnd_soc_dapm_to_component (widget->dapm);struct wsa_macro *wsa =snd_soc_component_get_drvdata (component); - ucontrol->value.integer.value[0 ] = + ucontrol->value.enumerated.item[0 ] = wsa->rx_port_value[widget->shift];return 0 ; }
@@ -2206,7 +2206,7 @@ static int wsa_macro_rx_mux_put(struct ssnd_soc_dapm_to_component (widget->dapm);struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;struct snd_soc_dapm_update *update =NULL ; -u32 rx_port_value = ucontrol->value.integer.value[0 ]; +u32 rx_port_value = ucontrol->value.enumerated.item[0 ];u32 bit_input;u32 aif_rst;unsigned int dai_id;
Greg Kroah-Hartman
maintainerPATCH 24/217 fbdev: core: Fix pointer desynchronization in fb_io_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
commit 81cc73be40c6f028f1ee3f438ace46afe666dbae upstream.
In fb_io_read(), if copy_to_user() performs a partial copy (e.g., due to a faulty user buffer), the loop adjusts the chunk size 'c' and updates the remaining 'count'. However, the hardware 'src' pointer has already been eagerly advanced by the original chunk size.
If the loop is allowed to continue, the read will resume from an incorrect, over-advanced offset. Since the remaining 'count' was only decremented by the successful bytes, this desynchronization causes the next iterations to execute more hardware reads than originally bounded, eventually leading to out-of-bounds I/O reads.
Fix this by breaking out of the loop immediately upon a partial copy_to_user(). A partial copy indicates a faulty user buffer, making subsequent read attempts futile. Breaking out ensures we return the number of successfully read bytes without risking out-of-bounds hardware accesses in subsequent mismatched iterations.
--- drivers/video/fbdev/core/fb_io_fops.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/video/fbdev/core/fb_io_fops.c +8 -0
@@ -61,6 +61,14 @@ ssize_t fb_io_read(struct fb_info *info, buf += c; cnt += c; count -= c; + +/* +* If there was a partial copy, the user buffer is faulty. +* Break out to avoid over-advancing the src pointer and +* reading out of bounds in the next iteration. +*/ +if (trailing) +break ; }kfree (buffer);
Greg Kroah-Hartman
maintainerPATCH 25/217 drm/panthor: skip zero-sized firmware sections
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
commit 2b8f13d3c7e26c46c20d9e367904cf01729c88e6 upstream.
panthor_fw_load_section_entry() skips BO creation when the firmware section VA range is empty. If such a section is added to the firmware section list, section->mem is left as NULL.
Later reload and unplug paths iterate over all firmware sections and dereference section->mem, which can lead to a NULL pointer dereference.
Zero-sized firmware sections are valid, so accept them as no-op entries but skip adding them to the section list.
--- drivers/gpu/drm/panthor/panthor_fw.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/panthor/panthor_fw.c +3 -0
@@ -553,6 +553,9 @@ static int panthor_fw_load_section_entryreturn -EINVAL ; } +if (!section_size) +return 0 ; + name_len = iter->size - iter->offset; section =drmm_kzalloc (&ptdev->base,sizeof (*section),GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 26/217 drm/amdgpu: reject oversized IBs with per-ring packet limits
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
commit fd37f9dd5b5ab70a46fa7bc76623c0528d602b27 upstream.
On GFX rings, amdgpu_cs_p2_ib() passed user-supplied ib_bytes through to ib->length_dw without a limit, while ring_emit_ib() encodes length into packet fields. Oversized values can corrupt adjacent control bits and destabilize command submission.
Add a per-ring IB packet size limit helper and reject command submissions exceeding the corresponding dword limit before IB allocation. Use the documented 20-bit limit for GFX/compute/SDMA/VPE, and apply the MM fallback limit for other ring types.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +26 -1
@@ -42,6 +42,26 @@#include "amdgpu_gem.h" #include "amdgpu_ras.h" +/* +* Maximum IB length (dwords) for rings whose emit_ib packet format +* documents a 20-bit size field. +*/ +#define AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW 0xFFFFF +#define AMDGPU_MM_IB_PACKET_SIZE_MAX_DW 0x7FFFF0 + +static u32 amdgpu_cs_ib_packet_size_max_dw (enum amdgpu_ring_type type) +{ +switch (type) { +case AMDGPU_RING_TYPE_GFX : +case AMDGPU_RING_TYPE_COMPUTE : +case AMDGPU_RING_TYPE_SDMA : +case AMDGPU_RING_TYPE_VPE : +return AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW ; +default : +return AMDGPU_MM_IB_PACKET_SIZE_MAX_DW ; + } +} + static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, struct amdgpu_device *adev, struct drm_file *filp,
@@ -358,7 +378,6 @@ static int amdgpu_cs_p2_ib(struct amdgpu job = p->jobs[r]; ring =amdgpu_job_ring (job); - ib = &job->ibs[job->num_ibs++];/* submissions to kernel queues are disabled */ if (ring->no_user_submission)
@@ -387,6 +406,12 @@ static int amdgpu_cs_p2_ib(struct amdgpureturn -EINVAL ; } +if (chunk_ib->ib_bytes /4 > +amdgpu_cs_ib_packet_size_max_dw (ring->funcs->type)) +return -EINVAL ; + + ib = &job->ibs[job->num_ibs++]; +if (chunk_ib->flags &AMDGPU_IB_FLAG_PREAMBLE ) job->preamble_status |=AMDGPU_PREAMBLE_IB_PRESENT ;
Greg Kroah-Hartman
maintainerPATCH 27/217 drm/amdgpu: read TRUNCATE_COORD_MODE on gfx12
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiang Yu <[email protected]>
commit 2d69604b4d0b9c0c0ac71624b5fafb36cf249729 upstream.
TA_CNTL2.TRUNCATE_COORD_MODE selects whether texture coordinate truncation is D3D9/GL/Vulkan conformant. gfx11 reads it and reports it to userspace via AMDGPU_IDS_FLAGS_CONFORMANT_TRUNC_COORD, but gfx12 never read it, so the flag was always reported as 0 and userspace fell back to the non-conformant path.
Read it in gfx_v12_0_constants_init() like gfx11 does.
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +5 -0
@@ -1810,6 +1810,11 @@ static void gfx_v12_0_constants_init(strgfx_v12_0_get_tcc_info (adev); adev->gfx.config.pa_sc_tile_steering_override =0 ; +/* Set whether texture coordinate truncation is conformant. */ + tmp =RREG32_SOC15 (GC ,0 , regTA_CNTL2); + adev->gfx.config.ta_cntl2_truncate_coord_mode = +REG_GET_FIELD (tmp,TA_CNTL2 ,TRUNCATE_COORD_MODE ); +/* XXX SH_MEM regs */ /* where to put LDS, scratch, GPUVM in FSA64 space */ mutex_lock (&adev->srbm_mutex);
Greg Kroah-Hartman
maintainerPATCH 28/217 drm/amdgpu: fix JPEG v5.0.0 queue reset failure in DPG mode
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit c87801f545dac9fcbb84c96f280706572be00a85 upstream.
In DPG mode jpeg_v5_0_0_ring_reset() takes the DPG stop path, which only clears the JPEG_PG_MODE bit and never resets the JRBC. A hung ring is not
recovered: the post-reset ring test times out and the driver falls back to a full MODE1 reset.
Temporarily force the static power-gating path during the reset so the stop/start sequence power-cycles the JPEG block (JMI soft reset + power off/on), matching the jpeg_v4_0 reset which has no DPG path.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +17 -4
@@ -648,15 +648,28 @@ static int jpeg_v5_0_0_ring_reset(structunsigned int vmid, struct amdgpu_fence *timedout_fence) { + struct amdgpu_device *adev = ring->adev; +u32 pg_flags = adev->pg_flags;int r;amdgpu_ring_reset_helper_begin (ring, timedout_fence); - r =jpeg_v5_0_0_stop (ring->adev); -if (r) -return r; - r =jpeg_v5_0_0_start (ring->adev); + +/* +* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a +* hung JRBC, so the post-reset ring test times out and the driver falls +* back to a full MODE1 reset. Temporarily force the static power-gating +* path so the stop/start sequence actually power-cycles the JPEG block +* (JMI soft reset + ONO1 power off/on), matching the working jpeg_v4_0 +* reset. +*/ + adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG ; + r =jpeg_v5_0_0_stop (adev); +if (!r) + r =jpeg_v5_0_0_start (adev); + adev->pg_flags = pg_flags;if (r)return r; +return amdgpu_ring_reset_helper_end (ring, timedout_fence); }
Greg Kroah-Hartman
maintainerPATCH 29/217 drm/amdgpu: fix JPEG v4.0.5 queue reset failure in DPG mode
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit 4301e60e406c613aea06fdc0c36bf0675b0b8a2e upstream.
Like jpeg_v5_0_0, in DPG mode the ring reset path only clears the JPEG_PG_MODE bit and never resets a hung JRBC, so the post-reset ring test times out and the driver falls back to a full MODE1 reset.
Temporarily force the static power-gating path during the reset so the stop/start sequence power-cycles the JPEG block (JMI soft reset + power off/on), matching the jpeg_v4_0 reset.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +17 -4
@@ -772,15 +772,28 @@ static int jpeg_v4_0_5_ring_reset(structunsigned int vmid, struct amdgpu_fence *timedout_fence) { + struct amdgpu_device *adev = ring->adev; +u32 pg_flags = adev->pg_flags;int r;amdgpu_ring_reset_helper_begin (ring, timedout_fence); - r =jpeg_v4_0_5_stop (ring->adev); -if (r) -return r; - r =jpeg_v4_0_5_start (ring->adev); + +/* +* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a +* hung JRBC, so the post-reset ring test times out and the driver falls +* back to a full MODE1 reset. Temporarily force the static power-gating +* path so the stop/start sequence actually power-cycles the JPEG block +* (JMI soft reset + static power off/on), matching the working jpeg_v4_0 +* reset. +*/ + adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG ; + r =jpeg_v4_0_5_stop (adev); +if (!r) + r =jpeg_v4_0_5_start (adev); + adev->pg_flags = pg_flags;if (r)return r; +return amdgpu_ring_reset_helper_end (ring, timedout_fence); }
Greg Kroah-Hartman
maintainerPATCH 30/217 drm/amdgpu: fix aperture iounmap skipped on device removal
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
commit f9e5f51549000e2665e3b5e02ff876b9e09cfe95 upstream.
amdgpu_pci_remove() calls drm_dev_unplug() before invoking the fini routines. After drm_dev_unplug() the drm_dev_enter() guard in amdgpu_ttm_fini() always returns false, so iounmap() for aper_base_kaddr is silently skipped. On connected_to_cpu hardware ioremap_cache() maps the aperture as WB; when iounmap() is skipped the stale WB PAT entry persists. On reload IP discovery's memremap(MEMREMAP_WC) on the same aperture range hits a WB/WC conflict, producing an ioremap error and failing re-probe.
Remove the drm_dev_enter() guard and call iounmap() unconditionally. The aperture mapping is plain MMIO and does not require device-presence protection. Surprise-removal cleanup of aper_base_kaddr is already handled unconditionally by amdgpu_device_unmap_mmio().
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +2 -8
@@ -2163,8 +2163,6 @@ int amdgpu_ttm_init(struct amdgpu_device*/ void amdgpu_ttm_fini (struct amdgpu_device *adev) { -int idx; -if (!adev->mman.initialized)return ;
@@ -2191,13 +2189,9 @@ void amdgpu_ttm_fini(struct amdgpu_devicamdgpu_ttm_fw_reserve_vram_fini (adev);amdgpu_ttm_drv_reserve_vram_fini (adev); -if (drm_dev_enter (adev_to_drm (adev), &idx)) { - -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); +if (adev->mman.aper_base_kaddr) { +iounmap (adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr =NULL ; - -drm_dev_exit (idx); }if (!adev->gmc.is_app_apu)
Greg Kroah-Hartman
maintainerPATCH 31/217 ASoC: SOF: topology: Use acpi mach from the machine driver
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bard Liao <[email protected]>
commit ae63720dd7c3647d64f7a85e5e1870f90eb569d6 upstream.
The parameters may be changed by the sof_sdw machine driver is the SOC_SDW_PCH_DMIC quirk is set. Use the mach_params from the machine driver to ensure the sof_sdw_get_tplg_files() function select the right function topologies.
--- sound/soc/intel/common/sof-function-topology-lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
sound/soc/intel/common/sof-function-topology-lib.c +6 -1
@@ -30,7 +30,12 @@ enum tplg_device_id {int sof_sdw_get_tplg_files (struct snd_soc_card *card,const struct snd_soc_acpi_mach *mach,const char *prefix,const char ***tplg_files) { -struct snd_soc_acpi_mach_params mach_params = mach->mach_params; +struct snd_soc_acpi_mach *card_mach =dev_get_platdata (card->dev); +/* +* Use the acpi mach from the machine driver because the machine driver +* may change the dmic_num based on the machine driver quirk. +*/ +struct snd_soc_acpi_mach_params mach_params = card_mach->mach_params;struct snd_soc_dai_link *dai_link;const struct firmware *fw;char platform[SOF_INTEL_PLATFORM_NAME_MAX ];
Greg Kroah-Hartman
maintainerPATCH 32/217 Input: xpad - add support for ZENAIM LEVERLESS
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyohei Kadota <[email protected]>
commit 7d971337ebfad0b173cb46097c709db174ac3557 upstream.
Add the VID/PID for the ZENAIM LEVERLESS controller to xpad_device and the VID to xpad_table.
--- drivers/input/joystick/xpad.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/input/joystick/xpad.c +2 -0
@@ -428,6 +428,7 @@ static const struct xpad_device { { 0x3285, 0x0646, "Nacon Pro Compact", 0, XTYPE_XBOXONE }, { 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 }, { 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE }, + { 0x3507, 0x000b, "ZENAIM LEVERLESS", 0, XTYPE_XBOX360 }, { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, { 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 }, { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
@@ -591,6 +592,7 @@ static const struct usb_device_id xpad_tXPAD_XBOX360_VENDOR (0x31e3 ),/* Wooting Keyboards */ XPAD_XBOX360_VENDOR (0x3285 ),/* Nacon GC-100 */ XPAD_XBOXONE_VENDOR (0x3285 ),/* Nacon Evol-X */ +XPAD_XBOX360_VENDOR (0x3507 ),/* ZENAIM Controllers */ XPAD_XBOX360_VENDOR (0x3537 ),/* GameSir Controllers */ XPAD_XBOXONE_VENDOR (0x3537 ),/* GameSir Controllers */ XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */
Greg Kroah-Hartman
maintainerPATCH 33/217 Input: cs40l50-vibra - validate custom data from user space
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit 7d5c576cb1c86047b1fcb1aa9532e17fc5e46c1d upstream.
cs40l50_add() copies the custom data of an FF_PERIODIC/FF_CUSTOM effect straight from the ff_effect the user passed to EVIOCSFF, without requiring it to hold anything:
work_data.custom_data = memdup_array_user(periodic->custom_data,
periodic->custom_len,
sizeof(s16));
work_data.custom_len = periodic->custom_len;The driver then reads two words out of that buffer: custom_data[0] as the waveform bank in cs40l50_effect_bank_set(), and custom_data[1] as the index within the bank in cs40l50_effect_index_set(). Neither read is covered by a length check, and custom_len is fully user controlled:
- custom_len == 0 makes memdup_array_user() call memdup_user() with a length of zero, which returns ZERO_SIZE_PTR rather than an error, so custom_data[0] dereferences it.
- custom_len == 1 allocates two bytes. A bank of ROM or RAM keeps effect->type out of the OWT case, and custom_data[1] is then read one word past the allocation.
The bank value itself is also mishandled. It is masked with CS40L50_CUSTOM_DATA_MASK (0xffff) but stored in an s16, so a custom_data[0] of 0x8000 or above wraps to a negative value that passes the "bank_type >= CS40L50_WVFRM_BANK_NUM" test. cs40l50_effect_index_set() indexes vib->dsp.banks[] with it before the switch statement's default case gets a chance to reject it:
base_index = vib->dsp.banks[effect->type].base_index;
max_index = vib->dsp.banks[effect->type].max_index;Require the two words the driver reads to be present, and hold the masked bank in a u32 so the existing upper-bound test covers the whole range. The da7280 haptic driver already range checks custom_len this way.
--- drivers/input/misc/cs40l50-vibra.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/input/misc/cs40l50-vibra.c +8 -2
@@ -139,10 +139,10 @@ static struct cs40l50_effect *cs40l50_fistatic int cs40l50_effect_bank_set (struct cs40l50_work *work_data,struct cs40l50_effect *effect) { -s16 bank_type = work_data->custom_data[0 ] &CS40L50_CUSTOM_DATA_MASK ; +u32 bank_type = work_data->custom_data[0 ] &CS40L50_CUSTOM_DATA_MASK ;if (bank_type >=CS40L50_WVFRM_BANK_NUM ) { -dev_err (work_data->vib->dev,"Invalid bank (%d)\n" , bank_type); +dev_err (work_data->vib->dev,"Invalid bank (%u)\n" , bank_type);return -EINVAL ; }
@@ -327,6 +327,12 @@ static int cs40l50_add(struct input_devreturn -EINVAL ; } +if (periodic->custom_len <CS40L50_OWT_CUSTOM_DATA_SIZE ) { +dev_err (vib->dev,"Invalid custom data length (%u)\n" , + periodic->custom_len); +return -EINVAL ; + } + work_data.custom_data =memdup_array_user (effect->u.periodic.custom_data, effect->u.periodic.custom_len,sizeof (s16));
Greg Kroah-Hartman
maintainerPATCH 34/217 powerpc/pseries: pci - logic bug
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Wilson <[email protected]>
commit 649c10bff5cb7a514bf299094833ec8c9190aac3 upstream.
The checks on num_vfs in pseries_pci_sriov_enable() are ANDed where OR was apparently intended. Change it to OR.
--- arch/powerpc/platforms/pseries/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/platforms/pseries/pci.c +1 -1
@@ -132,7 +132,7 @@ static int pseries_pci_sriov_enable(stru/* First integer stores max config */ max_config_vfs =of_read_number (&max_vfs[0 ],1 ); -if (max_config_vfs < num_vfs && num_vfs >MAX_VFS_FOR_MAP_PE ) { +if (max_config_vfs < num_vfs || num_vfs >MAX_VFS_FOR_MAP_PE ) { dev_err(&pdev->dev, "Num VFs %x > %x Configurable VFs\n", num_vfs, (num_vfs > MAX_VFS_FOR_MAP_PE) ?
Greg Kroah-Hartman
maintainerPATCH 35/217 Input: synaptics-rmi4 - fix F55 transmitter electrode count typo
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 6058f0fea10f3caf63a435677358d1b8e9325114 upstream.
During F55 sensor detection, the transmitter (TX) electrode count was incorrectly assigned the value of the receiver (RX) electrode count due to copy-paste typos.
This incorrect value was then propagated to the driver data and used by F54 to determine the diagnostics report size. On devices with more RX than TX electrodes, this inflated the perceived TX count, leading to incorrect report size calculations and potential out-of-bounds buffer accesses.
Fix the typos by correctly assigning the TX electrode counts.
--- drivers/input/rmi4/rmi_f55.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/input/rmi4/rmi_f55.c +2 -2
@@ -54,10 +54,10 @@ static int rmi_f55_detect(struct rmi_fun f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET ]; f55->cfg_num_rx_electrodes = f55->num_rx_electrodes; - f55->cfg_num_tx_electrodes = f55->num_rx_electrodes; + f55->cfg_num_tx_electrodes = f55->num_tx_electrodes; drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes; - drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes; + drv_data->num_tx_electrodes = f55->cfg_num_tx_electrodes;if (f55->qry[F55_PHYS_CHAR_OFFSET ] &F55_CAP_SENSOR_ASSIGN ) {int i, total;
Greg Kroah-Hartman
maintainerPATCH 36/217 Input: focaltech - fix array out-of-bounds in focaltech_process_rel_packet
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Davies <[email protected]>
commit 296736076b3fd078742651c719555a488624023a upstream.
Make finger2 (and also finger1) unsigned, so that if the finger index in the packet is 0 then subtracting 1 creates an array index which overflows above the existing check for FOC_MAX_FINGERS, as the existing comment says it should, instead of writing to state->fingers[-1].
--- drivers/input/mouse/focaltech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/mouse/focaltech.c +1 -1
@@ -197,7 +197,7 @@ static void focaltech_process_rel_packet {struct focaltech_data *priv = psmouse->private;struct focaltech_hw_state *state = &priv->state; -int finger1, finger2; +unsigned int finger1, finger2; state->pressed = packet[0 ] >>7 ; finger1 = ((packet[0 ] >>4 ) &0x7 ) -1 ;
Greg Kroah-Hartman
maintainerPATCH 37/217 Input: psxpad-spi - set driver data before use
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 732f38c36059e68ba3b4b89c56911d777fd3185c upstream.
psxpad_spi_suspend() retrieves the controller state with spi_get_drvdata(), but probe never stores it, so suspend dereferences a NULL pointer. Store it during probe.
--- drivers/input/joystick/psxpad-spi.c | 1 + 1 file changed, 1 insertion(+)
drivers/input/joystick/psxpad-spi.c +1 -0
@@ -373,6 +373,7 @@ static int psxpad_spi_probe(struct spi_dreturn err; } +spi_set_drvdata (spi, pad);pm_runtime_enable (&spi->dev);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 38/217 Input: atkbd - skip deactivate for Xiaomi Book Pro 14s internal keyboard
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhefu Zhang <[email protected]>
commit 3a046db33bb9f28b43a951a7a090db771dc0f8b3 upstream.
The internal keyboard of the Xiaomi Book Pro 14 does not work unless atkbd skips deactivating it at the end of atkbd_probe().
Using 'i8042.dumbkbd=1' also makes the keyboard work, but then the driver never writes to the keyboard at all, so the Caps Lock LED is lost. The atkbd_deactivate_fixup quirk fixes both without a boot parameter.
DMI: XIAOMI Xiaomi Book Pro 14/TM2424, BIOS XMAPT4B0P0909 05/06/2026
--- drivers/input/keyboard/atkbd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/input/keyboard/atkbd.c +8 -0
@@ -1952,6 +1952,14 @@ static const struct dmi_system_id atkbd_ }, .callback = atkbd_deactivate_fixup, }, + { + /* Xiaomi Book Pro 14 (TM2424) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"), + DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14"), + }, + .callback = atkbd_deactivate_fixup, + }, { } };
Greg Kroah-Hartman
maintainerPATCH 39/217 Input: iforce - validate input packet lengths
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 5751c781d3c97ab6ce0e2a966156ed882152c415 upstream.
iforce_process_packet() reads fixed fields from joystick, wheel and status packets without first checking their lengths. In particular, the shared hats-and-buttons helper unconditionally reads data[6]. The status tail is a sequence of 16-bit effect addresses, but an incomplete final address is also consumed. A successful zero-length USB URB additionally reads the packet ID before the common parser is called.
Reject the zero-length USB transfer, require the seven-byte joystick and wheel prefixes and the two-byte status prefix, and consume only complete status-tail addresses.
--- drivers/input/joystick/iforce/iforce-packets.c | 11 ++++++++++- drivers/input/joystick/iforce/iforce-usb.c | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-)
drivers/input/joystick/iforce/iforce-packets.c +10 -1
@@ -155,6 +155,9 @@ void iforce_process_packet(struct iforceswitch (packet_id) {case 0x01 :/* joystick position data */ +if (len <7 ) +break ; +input_report_abs (dev,ABS_X , (__s16 )get_unaligned_le16 (data)); input_report_abs(dev, ABS_Y,
@@ -170,6 +173,9 @@ void iforce_process_packet(struct iforcebreak ;case 0x03 :/* wheel position data */ +if (len <7 ) +break ; +input_report_abs (dev,ABS_WHEEL , (__s16 )get_unaligned_le16 (data));input_report_abs (dev,ABS_GAS ,255 - data[2 ]);
@@ -181,6 +187,9 @@ void iforce_process_packet(struct iforcebreak ;case 0x02 :/* status report */ +if (len <2 ) +break ; +input_report_key (dev,BTN_DEAD , data[0 ] &0x02 );input_sync (dev);
@@ -200,7 +209,7 @@ void iforce_process_packet(struct iforce } } -for (j =3 ; j < len; j +=2 ) +for (j =3 ; j +sizeof (u16) <= len; j +=sizeof (u16))mark_core_as_ready (iforce,get_unaligned_le16 (data + j));break ;
drivers/input/joystick/iforce/iforce-usb.c +3 -0
@@ -158,6 +158,9 @@ static void iforce_usb_irq(struct urb *u goto exit; } +if (!urb->actual_length) + goto exit; +iforce_process_packet (iforce, iforce_usb->data_in[0 ], iforce_usb->data_in +1 , urb->actual_length -1 );
Greg Kroah-Hartman
maintainerPATCH 40/217 Input: byd - synchronize timer deletion before freeing private data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit c83e79c0842ed29860648bcce5022ef0ba5001c6 upstream.
byd_disconnect() uses timer_delete() before freeing the driver's private data. This does not wait for a running byd_clear_touch() callback, which dereferences the private data and its psmouse pointer. A callback racing with disconnect can therefore access the private data after it has been freed. The timer can also still be re-armed by byd_process_byte() while the disconnect is in progress.
Use timer_shutdown_sync() before freeing the private data: it waits for a running callback and turns any later re-arm attempt into a no-op.
--- drivers/input/mouse/byd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/mouse/byd.c +1 -1
@@ -425,7 +425,7 @@ static void byd_disconnect(struct psmousstruct byd_data *priv = psmouse->private;if (priv) { -timer_delete (&priv->timer); +timer_shutdown_sync (&priv->timer);kfree (psmouse->private); psmouse->private =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 41/217 powerpc/pseries: lparcfg - fix kbuf[] underflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Wilson <[email protected]>
commit fb442a6673ff1046bf67754957d95880fdb394b5 upstream.
In lparcfg_write(), a count of 0 results in kbuf[] being indexed at -1. Check for count == 0 in the existing check for count > sizeof(kbuf) and return -EINVAL if true.
--- arch/powerpc/platforms/pseries/lparcfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/platforms/pseries/lparcfg.c +1 -1
@@ -686,7 +686,7 @@ static ssize_t lparcfg_write(struct fileif (!firmware_has_feature (FW_FEATURE_SPLPAR ))return -EINVAL ; -if (count >sizeof (kbuf)) +if (count ==0 || count >sizeof (kbuf))return -EINVAL ;if (copy_from_user (kbuf, buf, count))
Greg Kroah-Hartman
maintainerPATCH 42/217 powerpc/pseries: papr-phy-attest - validate cmd.length, plug mem leak
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Wilson <[email protected]>
commit 5b17f3f34391372faf03e79d947e0c50ab6dd258 upstream.
In papr_phy_attest_create_handle(), the params->cmd.length is not validated before use, which can result in a buffer overlow. Check it and return -EINVAL if it is either 0 or exceeds sizeof(params->cmd).
Also, params is freed on the success path but not error. Free it on errors after memory allocation. And free it on negative fd.
--- arch/powerpc/platforms/pseries/papr-phy-attest.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
arch/powerpc/platforms/pseries/papr-phy-attest.c +11 -1
@@ -230,10 +230,17 @@ static long papr_phy_attest_create_handlreturn -ENOMEM ;if (copy_from_user (¶ms->cmd, ulc, -sizeof (struct papr_phy_attest_io_block ))) +sizeof (struct papr_phy_attest_io_block ))) { +kfree (params);return -EFAULT ; + } params->cmd_len =be32_to_cpu (params->cmd.length); +if (params->cmd_len ==0 || params->cmd_len >sizeof (params->cmd)) { +kfree (params); +return -EINVAL ; + } + seq = (struct papr_rtas_sequence ) { .begin = phy_attest_sequence_begin, .end = phy_attest_sequence_end,
@@ -246,6 +253,9 @@ static long papr_phy_attest_create_handl &papr_phy_attest_handle_ops, "[papr-physical-attestation]"); +if (fd <0 ) +kfree (params); +return fd; }
Greg Kroah-Hartman
maintainerPATCH 43/217 Input: synaptics-rmi4 - zero report size on F54 work error
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit dc76c3c8e8ad09362b8c1561f3928288c15cba2e upstream.
In rmi_f54_work(), if an error occurs during report request or command verification, the code jumped directly to the 'error' label, bypassing the 'abort' label where f54->report_size was normally zeroed out.
This left f54->report_size containing its previous successful payload size. If a user then altered the V4L2 format to a smaller size, and a subsequent run failed, rmi_f54_buffer_queue() would copy the stale, larger payload size into the shrunken V4L2 buffer, causing a heap buffer overflow.
Fix this by merging the 'abort' and 'error' labels into a single 'out' exit path, and ensuring that f54->report_size is always set to 0 on failure by checking for error and zeroing the local report_size first.
--- drivers/input/rmi4/rmi_f54.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/input/rmi4/rmi_f54.c +8 -8
@@ -545,7 +545,7 @@ static void rmi_f54_work(struct work_strdev_err (&fn->dev,"Bad report size, report type=%d\n" , f54->report_type); error = -EINVAL ; - goto error;/* retry won't help */ + goto out;/* retry won't help */ }/*
@@ -556,7 +556,7 @@ static void rmi_f54_work(struct work_str &command);if (error) {dev_err (&fn->dev,"Failed to read back command\n" ); - goto error; + goto out; }if (command &F54_GET_REPORT ) {if (time_after (jiffies, f54->timeout)) {
@@ -564,7 +564,7 @@ static void rmi_f54_work(struct work_str error = -ETIMEDOUT ; } report_size =0 ; - goto error; + goto out; }rmi_dbg (RMI_DEBUG_FN , &fn->dev,"Get report command completed, reading data\n" );
@@ -579,7 +579,7 @@ static void rmi_f54_work(struct work_str fifo, sizeof(fifo));if (error) {dev_err (&fn->dev,"Failed to set fifo start offset\n" ); - goto abort; + goto out; } error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr +
@@ -588,16 +588,16 @@ static void rmi_f54_work(struct work_strif (error) {dev_err (&fn->dev,"%s: read [%d bytes] returned %d\n" , __func__, size, error); - goto abort; + goto out; } } -abort: - f54->report_size = error ?0 : report_size; -error: +out:if (error) report_size =0 ; + f54->report_size = report_size; +if (report_size ==0 && !error) {queue_delayed_work (f54->workqueue, &f54->work,msecs_to_jiffies (1 ));
Greg Kroah-Hartman
maintainerPATCH 44/217 Input: synaptics-rmi4 - bound the F54 report size to the allocated buffer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 49c5adc2b7d6e43c5cf033e1c86fdb9c16ababb1 upstream.
rmi_f54_work() reads a diagnostics report from the device into f54->report_data, sizing the transfer with rmi_f54_get_report_size():
report_size = rmi_f54_get_report_size(f54);
...
for (i = 0; i < report_size; i += F54_REPORT_DATA_SIZE) {
int size = min(F54_REPORT_DATA_SIZE, report_size - i);
...
rmi_read_block(.., f54->report_data + i, size);
}report_data is allocated once at probe from F54's own electrode counts (array3_size(f54->num_tx_electrodes, f54->num_rx_electrodes, sizeof(u16))), but rmi_f54_get_report_size() computes the size from drv_data->num_*_electrodes when those are set, i.e. from the F55 function's electrode counts. Both counts come straight from device queries (F54 and F55 each report up to 255 electrodes) and nothing constrains the F55 counts to the F54 ones.
A malicious or malfunctioning RMI4 device that reports larger F55 electrode counts than its F54 counts makes report_size exceed the allocation, so the read loop writes past report_data (and the V4L2 dequeue memcpy() then reads past it). On conforming hardware the F55 configured electrodes are a subset of the F54 physical electrodes, so report_size never exceeds the buffer and well-behaved devices are unaffected.
Record the allocation size and reject a report that does not fit, mirroring the existing zero-size check.
--- drivers/input/rmi4/rmi_f54.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/input/rmi4/rmi_f54.c +10 -2
@@ -104,6 +104,7 @@ struct f54_data {enum rmi_f54_report_type report_type;u8 *report_data; +size_t max_report_size;int report_size;bool is_busy;
@@ -548,6 +549,13 @@ static void rmi_f54_work(struct work_str goto out;/* retry won't help */ } +if (report_size > f54->max_report_size) { +dev_err (&fn->dev,"Report size %d exceeds buffer size %zu\n" , + report_size, f54->max_report_size); + error = -EINVAL ; + goto out; + } +/* * Need to check if command has completed. * If not try again later.
@@ -678,8 +686,8 @@ static int rmi_f54_probe(struct rmi_func rx = f54->num_rx_electrodes; tx = f54->num_tx_electrodes; - f54->report_data =devm_kzalloc (&fn->dev, -array3_size (tx, rx,sizeof (u16)), + f54->max_report_size =array3_size (tx, rx,sizeof (u16)); + f54->report_data =devm_kzalloc (&fn->dev, f54->max_report_size,GFP_KERNEL );if (f54->report_data ==NULL )return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 45/217 Input: synaptics-rmi4 - block s_input when F54 queue is busy
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit fbfd76746adc16d64be29ff113f673b70bc3f5c2 upstream.
Changing the input (diagnostic report type) mid-stream changes the report size. Since V4L2 buffers are allocated based on the size at stream start, changing the input while streaming could lead to a heap buffer overflow if the new size is larger than the allocated buffers.
Prevent this by blocking VIDIOC_S_INPUT with -EBUSY if the V4L2 queue is busy (streaming).
--- drivers/input/rmi4/rmi_f54.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/input/rmi4/rmi_f54.c +6 -1
@@ -445,7 +445,12 @@ static int rmi_f54_set_input(struct f54_static int rmi_f54_vidioc_s_input (struct file *file,void *priv,unsigned int i) { -return rmi_f54_set_input (video_drvdata (file), i); +struct f54_data *f54 =video_drvdata (file); + +if (vb2_is_busy (&f54->queue)) +return -EBUSY ; + +return rmi_f54_set_input (f54, i); } static int rmi_f54_vidioc_g_input(struct file *file, void *priv,
Greg Kroah-Hartman
maintainerPATCH 46/217 Input: synaptics-rmi4 - propagate F54 worker errors to V4L2 queue
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 8786d74bf50e6797b6f655eb381ef6b25451161f upstream.
Previously, rmi_f54_buffer_queue() waited for the worker thread to finish but ignored whether it succeeded. If the worker failed (e.g., due to a timeout or register read failure), the queue thread would silently return success, delivering stale or uninitialized memory to userspace.
Add a 'report_error' field to struct f54_data to store the worker's exit status. Check this field in rmi_f54_buffer_queue() after the worker finishes, and mark the buffer as VB2_BUF_STATE_ERROR if an error occurred.
--- drivers/input/rmi4/rmi_f54.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/input/rmi4/rmi_f54.c +8 -0
@@ -106,6 +106,7 @@ struct f54_data {u8 *report_data;size_t max_report_size;int report_size; +int report_error;bool is_busy;struct mutex status_mutex;
@@ -340,6 +341,12 @@ static void rmi_f54_buffer_queue(structmutex_lock (&f54->data_mutex); } +if (f54->report_error) { +dev_err (&f54->fn->dev,"Error acquiring report: %d\n" , f54->report_error); + state =VB2_BUF_STATE_ERROR ; + goto data_done; + } + ptr =vb2_plane_vaddr (vb,0 );if (!ptr) {dev_err (&f54->fn->dev,"Error acquiring frame ptr\n" );
@@ -610,6 +617,7 @@ out: report_size =0 ; f54->report_size = report_size; + f54->report_error = error;if (report_size ==0 && !error) { queue_delayed_work(f54->workqueue, &f54->work,
Greg Kroah-Hartman
maintainerPATCH 47/217 Input: hynitron_cstxxx - validate touch count and finger IDs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianing Li <[email protected]>
commit 27f380ef0e1d3de3cde114e02d33f9320ce3a5a6 upstream.
The driver allocates max_touch_num input slots, which are indexed from zero through max_touch_num - 1. The current check allows a finger ID equal to max_touch_num to reach cst3xx_report_contact(). While the input core ignores out-of-range slot indices, reporting touch data without a valid slot change corrupts the touch state of the previously active slot.
The touch count is read from the controller's report and is used to index the fixed-size report buffer without first checking its range. Reject counts larger than the supported number of touch slots before checking the trailing byte or parsing touch data.
Reject finger IDs equal to or greater than max_touch_num, and return immediately when an invalid finger ID is encountered so that corrupt touch frames are discarded instead of reporting partial contact state.
The V821 Avaota F1 board configures the vendor driver with one touch slot, so finger ID 1 is already invalid on that device.
--- drivers/input/touchscreen/hynitron_cstxxx.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/input/touchscreen/hynitron_cstxxx.c +10 -3
@@ -313,6 +313,12 @@ static void cst3xx_touch_report(struct ireturn ; touch_cnt = buf[5 ] &CST3XX_TOUCH_COUNT_MASK ; +if (touch_cnt > ts_data->chip->max_touch_num) { +dev_err (&client->dev,"cst3xx invalid touch count (%d vs %d max)\n" , + touch_cnt, ts_data->chip->max_touch_num); +return ; + } +/* * Check the check bit of the last touch slot. The check bit is * always present after touch point 1 for valid data, and then
@@ -335,9 +341,10 @@ static void cst3xx_touch_report(struct i finger_id = (buf[idx] >>4 ) &0x0f ;/* Sanity check we don't have more fingers than we expect */ -if (ts_data->chip->max_touch_num < finger_id) { -dev_err (&client->dev,"cst3xx touch read failure\n" ); -break ; +if (finger_id >= ts_data->chip->max_touch_num) { +dev_err (&client->dev, +"cst3xx invalid finger id %d\n" , finger_id); +return ; }/* sw value of 0 means no touch, 0x03 means touch */
Greg Kroah-Hartman
maintainerPATCH 48/217 crypto: starfive - use scatterlist length before DMA mapping
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 6b36f13891ab4709b7d60023005176cdd5c368cf upstream.
Using sg_dma_len() is only valid after mapping a scatterlist with dma_map_sg(). However, starfive_aes_aead_do_one_req() uses it before mapping the scatterlist.
Use the original scatterlist length because the DMA length has not been populated yet when CONFIG_NEED_SG_DMA_LENGTH=y.
--- drivers/crypto/starfive/jh7110-aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/starfive/jh7110-aes.c +1 -1
@@ -677,7 +677,7 @@ static int starfive_aes_aead_do_one_req(if (cryp->total_in)sg_zero_buffer (rctx->in_sg,sg_nents (rctx->in_sg), -sg_dma_len (rctx->in_sg) - cryp->total_in, + rctx->in_sg->length - cryp->total_in, cryp->total_in); ctx->rctx = rctx;
Greg Kroah-Hartman
maintainerPATCH 49/217 crypto: qce - fix error path in devm_qce_register_algs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 9c75402286409f5e1a75e4a445555c84066f89db upstream.
If ops->register_algs() fails, the error path repeatedly calls the same ops->unregister_algs() from the failed registration. Use the loop index to unregister the previously registered algorithms instead.
--- drivers/crypto/qce/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/qce/core.c +1 -1
@@ -60,7 +60,7 @@ static int devm_qce_register_algs(struct ret = ops->register_algs (qce);if (ret) {for (j = i -1 ; j >=0 ; j--) - ops->unregister_algs (qce); + qce_ops[j]->unregister_algs (qce);return ret; } }
Greg Kroah-Hartman
maintainerPATCH 50/217 gve: fix NULL dereference due to missing ptp adjfine
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rhee <[email protected]>
commit 3992ced109c70b771efad9e51ae68e5c7a04dea3 upstream.
Fix NULL dereference due to missing implementation of adjfine, which can be triggered from usermode as follows:
sudo ./testptp -d /dev/ptp0 -f 0
[ 551.943697] BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] [ 552.061946] Call Trace: [ 552.064487] <TASK> [ 552.066681] ptp_clock_adjtime+0x1c0/0x2c0 [ 552.070874] ? get_clock_desc+0x6b/0xb0 [ 552.074825] pc_clock_adjtime+0x78/0xc0 [ 552.078755] __do_sys_clock_adjtime+0x85/0x110 [ 552.083293] do_syscall_64+0xea/0x610
--- drivers/net/ethernet/google/gve/gve_ptp.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/ethernet/google/gve/gve_ptp.c +6 -0
@@ -26,6 +26,11 @@ int gve_clock_nic_ts_read(struct gve_priv *priv)return 0 ; } +static int gve_ptp_adjfine (struct ptp_clock_info *ptp,long scaled_ppm) +{ +return -EOPNOTSUPP ; +} +static int gve_ptp_gettimex64 (struct ptp_clock_info *info,struct timespec64 *ts,struct ptp_system_timestamp *sts)
@@ -60,6 +65,7 @@ static long gve_ptp_do_aux_work(struct ptp_clock_info *info)static const struct ptp_clock_info gve_ptp_caps = { .owner =THIS_MODULE , .name ="gve clock" , + .adjfine = gve_ptp_adjfine, .gettimex64 = gve_ptp_gettimex64, .settime64 = gve_ptp_settime64, .do_aux_work = gve_ptp_do_aux_work,
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 51/217 gpio: sloppy-logic-analyzer: fix use-after-free via debugfs trigger on unbind
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cengiz Can <[email protected]>
commit 44f3468a0aef1aabdad551898ab7cfa2a9d20e99 upstream.
The "trigger" debugfs file has a hand-rolled ->write handler (trigger_write()) that dereferences the per-device gpio_la_poll_priv. The file is created with debugfs_create_file_unsafe(), and the handler never takes a debugfs reference. Nothing keeps the object alive while the handler runs.
priv is allocated with devm_kzalloc(). devres frees it when the platform device is unbound. debugfs_create_file_unsafe() installs no full_proxy wrapper, so debugfs_remove_recursive() in gpio_la_poll_remove() does not wait for an in-flight trigger_write(). The blob_lock taken there does not help, because trigger_write() never takes it. A write that races an unbind therefore writes into freed memory:
trigger_write() gpio_la_poll_remove()
priv = m->private
buf = memdup_user() [may sleep]
mutex_lock(&priv->blob_lock)
debugfs_remove_recursive() [no wait]
mutex_unlock(&priv->blob_lock)
(remove returns; devres frees priv)
priv->trig_data = buf <-- use-after-free write
priv->trig_len = countThe race is reachable by root via /sys/bus/platform/drivers/gpio-sloppy-logic-analyzer/unbind.
Create "trigger" with debugfs_create_file() instead. Its full_proxy wrapper makes debugfs_remove_recursive() drain any in-flight ->write before it returns.
The use-after-free is confirmed under KASAN with a minimal reproducer of the same debugfs_create_file_unsafe() plus devm_kzalloc() pattern (available on request); it produces a slab-use-after-free write in the handler.
--- drivers/gpio/gpio-sloppy-logic-analyzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-sloppy-logic-analyzer.c +1 -1
@@ -301,7 +301,7 @@ static int gpio_la_poll_probe(struct pladebugfs_create_ulong ("delay_ns_acquisition" ,0400 , priv->debug_dir, &priv->acq_delay);debugfs_create_file_unsafe ("buf_size" ,0600 , priv->debug_dir, priv, &fops_buf_size);debugfs_create_file_unsafe ("capture" ,0200 , priv->debug_dir, priv, &fops_capture); -debugfs_create_file_unsafe ("trigger" ,0200 , priv->debug_dir, priv, &fops_trigger); +debugfs_create_file ("trigger" ,0200 , priv->debug_dir, priv, &fops_trigger);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 52/217 selftests/ftrace: Convert ELF entry point to file offset in uprobe test
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rui Qi <[email protected]>
commit 24aa630f6259e6a2107936c06fed72063f712b64 upstream.
The add_remove_uprobe test uses readelf -h to obtain the ELF entry point (e_entry) and passes it directly as the offset to uprobe_events. However, uprobe_events expects a file offset, not a virtual address.
For PIE binaries, the virtual address happens to equal the file offset because the first LOAD segment has p_vaddr == p_offset, so the test works by coincidence. But for non-PIE executables, e_entry is an absolute virtual address that can far exceed the file size. When the probe is enabled, uprobe_register() checks offset > i_size_read(inode) and rejects it with -EINVAL.
Fix this by converting the virtual address to a file offset using the ELF program headers: scan readelf -lW output for the LOAD segment containing the entry point, then compute file_offset = e_entry - p_vaddr + p_offset. For PIE binaries the result is unchanged; for non-PIE binaries the offset is correctly translated.
The conversion uses only POSIX shell primitives, with no dependency on gawk or perl.
--- tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc | 27 +++++++++- 1 file changed, 25 insertions(+), 2 deletions(-)
tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc +25 -2
@@ -12,9 +12,32 @@ echo 0 > events/enable echo > dynamic_events REALBIN=`readlink -f /bin/sh` -ENTRYPOINT=`readelf -h ${REALBIN} | grep Entry | sed -e 's/[^0]*//'` -echo "p:myevent ${REALBIN}:${ENTRYPOINT}" >> uprobe_events +# Get the entry point virtual address from ELF header +ENTRY=`readelf -hW ${REALBIN} | grep "Entry point" | awk '{print $NF}'` + +# Convert virtual address to file offset: find the LOAD segment containing +# the entry point, then compute file_offset = e_entry - p_vaddr + p_offset. +# For PIE binaries this is a no-op (vaddr == file offset), but for non-PIE +# executables the virtual address is much larger than the file size and +# must be converted, otherwise uprobe_register() rejects it with -EINVAL. +ENTRY_DEC=$(printf '%d' "$ENTRY") +OFFSET=$ENTRY +while IFS= read -r line; do + set -- $line + [ "$1" = "LOAD" ] || continue + VA_DEC=$(printf '%d' "$3") + OFF_DEC=$(printf '%d' "$2") + FSZ_DEC=$(printf '%d' "$5") + if [ "$ENTRY_DEC" -ge "$VA_DEC" ] && [ "$ENTRY_DEC" -lt "$((VA_DEC + FSZ_DEC))" ]; then + OFFSET=$(printf '0x%x' "$((ENTRY_DEC - VA_DEC + OFF_DEC))") + break + fi +done << EOF +$(readelf -lW ${REALBIN} | grep LOAD) +EOF + +echo "p:myevent ${REALBIN}:${OFFSET}" >> uprobe_events grep -q myevent uprobe_events test -d events/uprobes/myevent
Greg Kroah-Hartman
maintainerPATCH 53/217 gve: fix zero-length skb frag with header-split
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rhee <[email protected]>
commit 6bf14575c65569dcded90ef78afb8a6d57323f04 upstream.
When header split is enabled and a header-only packet is received such as a pure TCP ACK, GVE will indicate an RX SKB with a zero-length fragment. If this SKB is then hairpinned and sent back out, the GVE TX path will emit a zero-length descriptor. Hardware considers this an illegal descriptor and stops the queue, causing a TX timeout and interface reset.
Fix it by not adding the zero-length skb frag.
--- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/google/gve/gve_rx_dqo.c +5 -0
@@ -859,6 +859,11 @@ static int gve_rx_dqo(struct napi_struct rx->rx_hsplit_unsplit_pkt += unsplit; rx->rx_hsplit_bytes += hdr_len;u64_stats_update_end (&rx->statss); + +if (!buf_len) { +gve_free_buffer (rx, buf_state); +return 0 ; + } }else if (!rx->ctx.skb_head && rx->dqo.page_pool &&netmem_is_net_iov (buf_state->page_info.netmem)) {/* when header split is disabled, the header went to the packet
Greg Kroah-Hartman
maintainerPATCH 54/217 gpio: ml-ioh: use raw_spinlock_t for the register lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junjie Cao <[email protected]>
commit 600411ea1f2443fdf5b1af9b6480f616d7aff9d0 upstream.
ioh_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid. ioh_irq_enable() and ioh_irq_disable() take the same lock from the .irq_enable/.irq_disable callbacks, which are likewise invoked with desc->lock held.
Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, and those critical sections only perform short sequences of MMIO register accesses (ioread32()/iowrite32()); the .irq_set_type callback additionally emits a dev_warn() on an unsupported type. None of these are sleepable operations, so keeping this register lock non-sleeping is appropriate for the irqchip callbacks and does not change the GPIO-side locking contract.
This is the same fix as commit a02b8950d619 ("gpio: pch: use raw_spinlock_t for the register lock"); this driver shares the same structure as gpio-pch.
--- drivers/gpio/gpio-ml-ioh.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
drivers/gpio/gpio-ml-ioh.c +18 -18
@@ -84,7 +84,7 @@ struct ioh_gpio {u32 gpio_use_sel;int ch;int irq_base; -spinlock_t spinlock; +raw_spinlock_t spinlock; };static const int num_ports[] = {6 ,12 ,16 ,16 ,15 ,16 ,16 ,12 };
@@ -95,7 +95,7 @@ static int ioh_gpio_set(struct gpio_chipstruct ioh_gpio *chip =gpiochip_get_data (gpio);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); reg_val =ioread32 (&chip->reg->regs[chip->ch].po);if (val) reg_val |=BIT (nr);
@@ -103,7 +103,7 @@ static int ioh_gpio_set(struct gpio_chip reg_val &= ~BIT (nr);iowrite32 (reg_val, &chip->reg->regs[chip->ch].po); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -123,7 +123,7 @@ static int ioh_gpio_direction_output(stru32 reg_val;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); pm =ioread32 (&chip->reg->regs[chip->ch].pm); pm &=BIT (num_ports[chip->ch]) -1 ; pm |=BIT (nr);
@@ -136,7 +136,7 @@ static int ioh_gpio_direction_output(str reg_val &= ~BIT (nr);iowrite32 (reg_val, &chip->reg->regs[chip->ch].po); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -147,12 +147,12 @@ static int ioh_gpio_direction_input(struu32 pm;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); pm =ioread32 (&chip->reg->regs[chip->ch].pm); pm &=BIT (num_ports[chip->ch]) -1 ; pm &= ~BIT (nr);iowrite32 (pm, &chip->reg->regs[chip->ch].pm); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -256,7 +256,7 @@ static int ioh_irq_type(struct irq_datadev_dbg (chip->dev,"%s:irq=%d type=%d ch=%d pos=%d type=%d\n" , __func__, irq, type, ch, im_pos, type); -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);switch (type) {case IRQ_TYPE_EDGE_RISING :
@@ -296,7 +296,7 @@ static int ioh_irq_type(struct irq_data ien =ioread32 (&chip->reg->regs[chip->ch].ien);iowrite32 (ien |BIT (ch), &chip->reg->regs[chip->ch].ien); end: -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -326,11 +326,11 @@ static void ioh_irq_disable(struct irq_dunsigned long flags;u32 ien; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); ien =ioread32 (&chip->reg->regs[chip->ch].ien); ien &= ~BIT (d->irq - chip->irq_base);iowrite32 (ien, &chip->reg->regs[chip->ch].ien); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags); }static void ioh_irq_enable (struct irq_data *d)
@@ -340,11 +340,11 @@ static void ioh_irq_enable(struct irq_daunsigned long flags;u32 ien; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); ien =ioread32 (&chip->reg->regs[chip->ch].ien); ien |=BIT (d->irq - chip->irq_base);iowrite32 (ien, &chip->reg->regs[chip->ch].ien); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags); }static irqreturn_t ioh_gpio_handler (int irq,void *dev_id)
@@ -440,7 +440,7 @@ static int ioh_gpio_probe(struct pci_dev chip->base = base; chip->reg = chip->base; chip->ch = i; -spin_lock_init (&chip->spinlock); +raw_spin_lock_init (&chip->spinlock);ioh_gpio_setup (chip, num_ports[i]); ret =devm_gpiochip_add_data (dev, &chip->gpio, chip);if (ret) {
@@ -484,9 +484,9 @@ static int __maybe_unused ioh_gpio_suspestruct ioh_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);ioh_gpio_save_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -496,11 +496,11 @@ static int __maybe_unused ioh_gpio_resumstruct ioh_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);iowrite32 (0x01 , &chip->reg->srst);iowrite32 (0x00 , &chip->reg->srst);ioh_gpio_restore_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 55/217 pmdomain: arm: Fix -EINVAL from scmi_pd_set_perf_state() on state 0
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Praveen Talari <[email protected]>
commit 3314c90a2eda3df7da4ab6f4388e667b2758de7f upstream.
Currently, scmi_pd_set_perf_state() treats a performance state of 0 as invalid and returns -EINVAL. As a result, devices attached to SCMI performance domains can report failures when relinquishing their performance vote.
The OPP framework use performance state 0 to indicate that no performance vote is required. For example, dev_pm_opp_set_rate(dev, 0) is commonly used (by firmware or linux) when a device is runtime suspended.
A zero performance state does not require any SCMI performance request to be sent. Treat it as a no-op and return success instead of reporting an error.
--- drivers/pmdomain/arm/scmi_perf_domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pmdomain/arm/scmi_perf_domain.c +1 -1
@@ -33,7 +33,7 @@ scmi_pd_set_perf_state(struct generic_pmreturn 0 ;if (!state) -return -EINVAL ; +return 0 ; ret = pd->perf_ops->level_set (pd->ph, pd->domain_id, state, false);if (ret)
Greg Kroah-Hartman
maintainerPATCH 56/217 libceph: fix multiple unsafe decodes in decode_locker()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <[email protected]>
commit 437b6551cfcc235eea1d735a874f9d421f555e17 upstream.
decode_locker() in cls_lock_client.c contains three unsafe decode operations that allow a malicious or compromised OSD to trigger slab-out-of-bounds reads:
1. ceph_decode_copy() at the locker_id_t name field has no preceding bounds check. With p == end after ceph_start_decoding() accepts struct_len=0, this reads sizeof(ceph_entity_name) = 9 bytes past the validated buffer boundary.
2. *p += sizeof(struct ceph_timespec) after the locker_info_t header is an unchecked pointer advance. A malicious OSD can position p past end, causing all subsequent _safe checks to pass against a bogus boundary.
3. len = ceph_decode_32(p) has no preceding bounds check, and the immediately following *p += len is uncapped. A malicious OSD can send len=0xffffffff, advancing p gigabytes past end and escaping the decode window entirely.
Fix all three by replacing bare operations with their safe variants:
ceph_decode_copy -> ceph_decode_copy_safe *p += sizeof(...) -> ceph_decode_skip_n ceph_decode_32(p) -> ceph_decode_32_safe *p += len -> ceph_decode_skip_n
A new label is added to return -EINVAL on any bounds violation. -EINVAL is appropriate here: the data received from the OSD is structurally malformed, which is an invalid argument to the decode contract regardless of whether the caller or the wire is at fault.
Attacker model: a malicious or compromised OSD in a multi-tenant Ceph deployment can trigger this against any kernel client that issues the lock.get_info class method (e.g. during RBD exclusive lock acquisition) without any further privileges beyond OSD session establishment.
[ idryomov: use ceph_decode_skip_string() to skip description, trim
changelog ]
--- net/ceph/cls_lock_client.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/ceph/cls_lock_client.c +9 -4
@@ -259,7 +259,8 @@ static int decode_locker(void **p, voidif (ret)return ret; -ceph_decode_copy (p, &locker->id.name,sizeof (locker->id.name)); +ceph_decode_copy_safe (p, end, &locker->id.name, +sizeof (locker->id.name), bad); s =ceph_extract_encoded_string (p, end,NULL ,GFP_NOIO );if (IS_ERR (s))return PTR_ERR (s);
@@ -270,19 +271,23 @@ static int decode_locker(void **p, voidif (ret)return ret; - *p +=sizeof (struct ceph_timespec );/* skip expiration */ +/* skip expiration */ +ceph_decode_skip_n (p, end,sizeof (struct ceph_timespec ), bad); ret =ceph_decode_entity_addr (p, end, &locker->info.addr);if (ret)return ret; - len =ceph_decode_32 (p); - *p += len;/* skip description */ +/* skip description */ +ceph_decode_skip_string (p, end, bad);dout ("%s %s%llu cookie %s addr %s\n" , __func__,ENTITY_NAME (locker->id.name), locker->id.cookie,ceph_pr_addr (&locker->info.addr));return 0 ; + +bad: +return -EINVAL ; } static int decode_lockers(void **p, void *end, u8 *type, char **tag,
Greg Kroah-Hartman
maintainerPATCH 57/217 ftrace: Protect direct_functions in ftrace_find_rec_direct
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
commit 63444b7617c09aeed36282e061c3f80818f2b600 upstream.
Fix accessing the __rcu pointer direct_functions with RCU protection.
--- kernel/trace/ftrace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +2 -1
@@ -2594,7 +2594,8 @@ unsigned long ftrace_find_rec_direct(uns {struct ftrace_func_entry *entry; - entry =__ftrace_lookup_ip (direct_functions, ip); +guard (preempt_notrace)(); + entry =__ftrace_lookup_ip (rcu_dereference_sched (direct_functions), ip);if (!entry)return 0 ;
Greg Kroah-Hartman
maintainerPATCH 58/217 ftrace: Fix off-by-one fentry site disable in ftrace_free_mem()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Poimboeuf <[email protected]>
commit 8b8292d6487c81bd57c2605a9b404b1cf8f1edfb upstream.
When a module's init text is freed, do_init_module() calls ftrace_free_mem() with a half-open [start, end) range. However the ftrace_cmp_recs() comparator treats the upper bound as inclusive, as all its other users do, passing 'ip + size - 1'. So ftrace_free_mem() can delete a record sitting exactly at 'end', which is outside the freed range.
For a kernel without CFI or IBT, the first record of a function is at the function start, which for the first function in a module is also the base of its text allocation. As the module allocator packs its regions, that address is often the 'end' passed by a neighboring module's do_init_module(), causing the first function's ftrace location to get disabled, preventing an attempt to livepatch it:
livepatch: failed to find location for function 'pcspkr_probe'
Convert the exclusive end to the inclusive 'end - 1' the comparator expects, and return early for an empty range to avoid the subtraction from underflowing when the init text size is zero.
--- kernel/trace/ftrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +5 -1
@@ -7864,7 +7864,8 @@ static void add_to_clear_hash_list(strucvoid ftrace_free_mem (struct module *mod,void *start_ptr,void *end_ptr) {unsigned long start = (unsigned long )(start_ptr); -unsigned long end = (unsigned long )(end_ptr); +/* end is inclusive and end_ptr is exclusive */ +unsigned long end = (unsigned long )(end_ptr) -1 ;struct ftrace_page **last_pg = &ftrace_pages_start;struct ftrace_page *tmp_page =NULL ;struct ftrace_page *pg;
@@ -7874,6 +7875,9 @@ void ftrace_free_mem(struct module *mod,struct ftrace_init_func *func, *func_next;LIST_HEAD (clear_hash); +if (start_ptr >= end_ptr) +return ; + key.ip = start; key.flags = end;/* overload flags, as it is unsigned long */
Greg Kroah-Hartman
maintainerPATCH 59/217 openrisc: signal: do not restore privileged SR bits on sigreturn
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit 32ef1b30ad736519f7a207bcc2986f3d4129d972 upstream.
restore_sigcontext() copies the whole supervision register (SR) from the signal frame and only clears SPR_SR_SM before the value is reloaded into the hardware SR (through ESR and l.rfe) on the return to user space. All other SR bits are left under user control.
An unprivileged task can thus return from a signal handler through a crafted sigframe that clears SPR_SR_DME. With the data MMU disabled the CPU performs no translation or protection on data accesses, so the task gains read and write access to arbitrary physical memory, a local privilege escalation. SPR_SR_IME, SPR_SR_SUMRA, SPR_SR_LEE, SPR_SR_EPH and the cache-enable bits are exposed the same way. The ptrace GPR regset already refuses any change to SR for exactly this reason.
Restore only the arithmetic flag bits (F, CY, OV) from the signal frame and take every privileged control bit from the SR the kernel saved on signal entry.
Verified with qemu-system-or1k -M or1k-sim: before this change an unprivileged PoC clears SPR_SR_DME in rt_sigreturn and writes a marker to physical address 0x03000000 (beyond the kernel's mem=32M); afterwards the same PoC receives SIGSEGV and physical memory is unchanged.
--- arch/openrisc/include/asm/processor.h | 2 ++ arch/openrisc/kernel/signal.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-)
arch/openrisc/include/asm/processor.h +2 -0
@@ -26,6 +26,8 @@ | SPR_SR_DCE | SPR_SR_SM)#define USER_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \ | SPR_SR_DCE | SPR_SR_IEE | SPR_SR_TEE) +/* SR bits user space may change via sigreturn, the rest stay kernel owned */ +#define SPR_SR_USER_MASK (SPR_SR_F | SPR_SR_CY | SPR_SR_OV)/* * User space process size. This is hardcoded into a few places,
arch/openrisc/kernel/signal.c +3 -2
@@ -74,6 +74,7 @@ static long save_fp_state(struct sigcontstatic int restore_sigcontext (struct pt_regs *regs,struct sigcontext __user *sc) { +unsigned long old_sr = regs->sr;int err =0 ;/* Always make any pending restarted system calls return -EINTR */
@@ -89,8 +90,8 @@ static int restore_sigcontext(struct pt_ err |=__copy_from_user (®s->sr, &sc->regs.sr,sizeof (unsigned long )); err |=restore_fp_state (sc); -/* make sure the SM-bit is cleared so user-mode cannot fool us */ - regs->sr &= ~SPR_SR_SM ; +/* keep the privileged SR bits kernel owned, restore only user flags */ + regs->sr = (old_sr & ~SPR_SR_USER_MASK ) | (regs->sr &SPR_SR_USER_MASK ); regs->orig_gpr11 =-1 ;/* Avoid syscall restart checks */
Greg Kroah-Hartman
maintainerPATCH 60/217 Input: sur40 - fix input device registration ordering
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 9da976eb649c9e2f588a4499410e4d8af687925f upstream.
In sur40_probe(), input_register_device() was previously called early before the V4L2 video device and vb2_queue components were fully initialized. If userspace opened the input device immediately upon registration, sur40_open() would trigger and start the sur40_poll() worker thread. This worker thread invokes sur40_process_video() and accesses the uninitialized vb2_queue structure, leading to a data race and potential system crash.
Furthermore, if V4L2 or video registration failed after input_register_device() succeeded, the error path fell through to calling input_free_device() on a successfully registered device instead of input_unregister_device(), corrupting input core state.
Move input_register_device() to the very end of sur40_probe(). This ensures the V4L2 and video queue structures are fully initialized before polling can start, and naturally resolves the error path bug since input_free_device() is now only called when input registration has not yet occurred.
To maintain strict LIFO (Last-In, First-Out) teardown ordering, also move input_unregister_device() to the very beginning of sur40_disconnect(). This guarantees that the input polling worker thread is stopped before V4L2 video components or control handlers are unregistered.
--- drivers/input/touchscreen/sur40.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
drivers/input/touchscreen/sur40.c +11 -10
@@ -725,21 +725,13 @@ static int sur40_probe(struct usb_interf goto err_free_input; } -/* register the polled input device */ - error =input_register_device (input); -if (error) { -dev_err (&interface->dev, -"Unable to register polled input device." ); - goto err_free_buffer; - } -/* register the video master device */ snprintf (sur40->v4l2.name,sizeof (sur40->v4l2.name),"%s" ,DRIVER_LONG ); error =v4l2_device_register (sur40->dev, &sur40->v4l2);if (error) {dev_err (&interface->dev,"Unable to register video master device." ); - goto err_unreg_v4l2; + goto err_free_buffer; }/* initialize the lock and subdevice */
@@ -798,6 +790,14 @@ static int sur40_probe(struct usb_interf goto err_unreg_video; } +/* register the polled input device */ + error =input_register_device (input); +if (error) { +dev_err (&interface->dev, +"Unable to register polled input device." ); + goto err_unreg_video; + } +/* we can register the device now, as it is ready */ usb_set_intfdata (interface, sur40);dev_dbg (&interface->dev,"%s is now attached\n" ,DRIVER_DESC );
@@ -823,11 +823,12 @@ static void sur40_disconnect(struct usb_ {struct sur40_state *sur40 =usb_get_intfdata (interface); +input_unregister_device (sur40->input); +v4l2_ctrl_handler_free (&sur40->hdl);video_unregister_device (&sur40->vdev);v4l2_device_unregister (&sur40->v4l2); -input_unregister_device (sur40->input);kfree (sur40->bulk_in_buffer);kfree (sur40);
Greg Kroah-Hartman
maintainerPATCH 61/217 Input: sur40 - fix V4L error path cleanup
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 062dc4693e2c10d77de06f61e6f3faf37c0a8383 upstream.
In sur40_probe(), if video_register_device() fails, the error path jumps to err_unreg_video. This incorrectly attempts to unregister a video device that was never successfully registered, and fails to free the V4L2 control handler (v4l2_ctrl_handler_free) that was initialized immediately prior.
Fix this by introducing an err_free_ctrl label to properly free the V4L2 control handler and bypass video_unregister_device() when video device registration fails.
--- drivers/input/touchscreen/sur40.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/input/touchscreen/sur40.c +3 -1
@@ -787,7 +787,7 @@ static int sur40_probe(struct usb_interfif (error) {dev_err (&interface->dev,"Unable to register video subdevice." ); - goto err_unreg_video; + goto err_free_ctrl; }/* register the polled input device */
@@ -806,6 +806,8 @@ static int sur40_probe(struct usb_interf err_unreg_video:video_unregister_device (&sur40->vdev); +err_free_ctrl: +v4l2_ctrl_handler_free (&sur40->hdl); err_unreg_v4l2:v4l2_device_unregister (&sur40->v4l2); err_free_buffer:
Greg Kroah-Hartman
maintainerPATCH 62/217 libceph: Avoid using invalid osd indices from primary_temp
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 3660b98d1204b419f6a77e9a295f148dcf38d042 upstream.
A corrupted osdmap received from a Ceph monitor or OSD may contain osd indices in its pg_temp, primary_temp, pg_upmap, and pg_upmap_items parts that don't exist, i.e., that are greater than max_osd or smaller than CEPH_HOMELESS_OSD (-1). These indices are used to create the up and acting set in ceph_pg_to_up_acting_osds(), called from calc_target(). While most of these osd indices are checked, the one from primary_temp is not. Subsequently, this may lead to calc_target() returning this (potentially invalid) index as target osd for a (linger) request. Because the osd_state, osd_weight, and osd_addr arrays only contain max_osd entries (with indices 0 to max_osd -1), this leads to out-of-bounds accesses when trying to read values from these arrays.
This patch fixes the issue by adding a check to get_temp_osds(), so that only valid osd indices from primary_temp are used, and it falls back to using the primary from pg_temp or the up set if it is invalid.
[ idryomov: changelog ]
--- net/ceph/osdmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/ceph/osdmap.c +3 -2
@@ -2811,9 +2811,10 @@ static void get_temp_osds(struct ceph_os } } -/* primary_temp? */ +/* primary_temp? (shouldn't ever be a nonexistent or down OSD) */ pg =lookup_pg_mapping (&osdmap->primary_temp, pgid); -if (pg) +if (pg && !WARN_ON_ONCE (ceph_osd_is_down (osdmap, + pg->primary_temp.osd))) temp->primary = pg->primary_temp.osd; }
Greg Kroah-Hartman
maintainerPATCH 63/217 ceph: fix MDS random selection readiness predicate
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiming Zhu <[email protected]>
commit 2c11c4bfdb7bd2808b3b3ac228e1f2d9bcf25457 upstream.
CEPH_MDS_IS_READY() is parsed so that the ternary expression can return true for an MDS entry with state 0 when it is not laggy. This allows the random selector to choose a down/DNE rank.
Group the ternary expression under the state check so zero-state ranks are not treated as ready.
--- fs/ceph/mdsmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ceph/mdsmap.c +1 -1
@@ -15,7 +15,7 @@#include "super.h" #define CEPH_MDS_IS_READY (i, ignore_laggy) \ - (m->m_info[i].state > 0 && ignore_laggy ? true : !m->m_info[i].laggy) + (m->m_info[i].state > 0 && (ignore_laggy ? true : !m->m_info[i].laggy))static int __mdsmap_get_random_mds (struct ceph_mdsmap *m,bool ignore_laggy) {
Greg Kroah-Hartman
maintainerPATCH 64/217 libceph: tolerate addrvecs with multiple entries of the same type
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kefu Chai <[email protected]>
commit 5a87925539acecfe88229bad76ab81bd75a7e3f5 upstream.
ceph_decode_entity_addrvec() rejects any addrvec containing more than one entry that matches the requested msgr type (LEGACY or MSGR2), logging "another match of type N in addrvec" and returning -EINVAL.
Some admin tooling (e.g. pveceph mon create from Proxmox VE) generates addrvecs with multiple same-type entries when public_network lists more than one CIDR: it picks one local IP per subnet and emits both a v2 and a v1 entry for each IP. Monmaps shaped this way cause:
libceph: mon0 (1)10.10.10.15:6789 session established
libceph: another match of type 1 in addrvec
libceph: problem decoding monmap, -22
No Ceph code uses the extra entries: since Nautilus, the userspace messenger (AsyncMessenger) unconditionally picks the first address of the requested type and ignores any subsequent matches.
Match that behavior: use the first matching entry and silently skip any subsequent ones. This is a compatibility fix for existing deployments and does not enable dual-stack or multi-subnet address selection.
[ idryomov: tweak ceph_decode_entity_addrvec() comment ]
--- net/ceph/decode.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
net/ceph/decode.c +9 -9
@@ -87,8 +87,9 @@ bad:EXPORT_SYMBOL (ceph_decode_entity_addr);/* -* Return addr of desired type (MSGR2 or LEGACY) or error. -* Make sure there is only one match. +* Return addr of desired type (MSGR2 or LEGACY) or error. In case of +* multiple matches, use the first one for compatibility with userspace +* messenger. * * Assume encoding with MSG_ADDR2. */
@@ -121,14 +122,13 @@ int ceph_decode_entity_addrvec(void **p,dout ("%s i %d addr %s\n" , __func__, i,ceph_pr_addr (&tmp_addr));if (tmp_addr.type == my_type) { -if (found) { -pr_err ("another match of type %d in addrvec\n" , -le32_to_cpu (my_type)); -return -EINVAL ; +if (!found) { +memcpy (addr, &tmp_addr,sizeof (*addr)); + found = true; + }else { +dout ("%s skipping extra match of type %d in addrvec\n" , + __func__,le32_to_cpu (my_type)); } - -memcpy (addr, &tmp_addr,sizeof (*addr)); - found = true; } }
Greg Kroah-Hartman
maintainerPATCH 65/217 mmc: omap_hsmmc: fix busy_timeout overflow in ns conversion on 32-bit
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit f64ea900e4bda3055ef24a2c906f8d049cf1c3bd upstream.
omap_hsmmc_prepare_data() converts the command busy timeout to nanoseconds with:
timeout = req->cmd->busy_timeout * NSEC_PER_MSEC;
busy_timeout is an unsigned int (milliseconds) and timeout is a u64, but NSEC_PER_MSEC is 1000000L. On 32-bit builds the multiplication is performed in 32-bit arithmetic and wraps for busy_timeout values above ~4294 ms, before the result is assigned to the u64.
The driver does not set mmc->max_busy_timeout, so the core does not cap the busy timeout, and commands such as erase or SANITIZE (MMC_SANITIZE_TIMEOUT_MS is 240000 ms) can pass a busy_timeout far larger than 4294 ms. The wrapped, much smaller ns value is then programmed via set_data_timeout(), so the data timeout is set too short and the operation can time out prematurely.
Cast busy_timeout to u64 before the multiplication so the conversion is done in 64-bit arithmetic.
--- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/host/omap_hsmmc.c +1 -1
@@ -1357,7 +1357,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmif (req->data ==NULL ) {OMAP_HSMMC_WRITE (host->base,BLK ,0 );if (req->cmd->flags &MMC_RSP_BUSY ) { - timeout = req->cmd->busy_timeout *NSEC_PER_MSEC ; + timeout = (u64 )req->cmd->busy_timeout *NSEC_PER_MSEC ;/* * Set an arbitrary 100ms data timeout for commands with
Greg Kroah-Hartman
maintainerPATCH 66/217 mmc: sdhci: unmap the bounce buffer before device release
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 9e9f561269dff35e6f84ed21776ec37fd6360b03 upstream.
sdhci_allocate_bounce_buffer() allocates its buffer with devm_kmalloc() but maps it with dma_map_single(). The buffer is therefore released by devres without the streaming DMA mapping being unmapped.
Register a managed action after dma_map_single() succeeds so the mapping is removed before devres releases the buffer. The action is registered only for buffers allocated and mapped by the SDHCI core, leaving buffers provided by host drivers under their existing ownership.
--- drivers/mmc/host/sdhci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/mmc/host/sdhci.c +16 -0
@@ -4187,6 +4187,14 @@ void __sdhci_read_caps(struct sdhci_host }EXPORT_SYMBOL_GPL (__sdhci_read_caps); +static void sdhci_unmap_bounce_buffer (void *data) +{ +struct sdhci_host *host = data; + +dma_unmap_single (mmc_dev (host->mmc), host->bounce_addr, + host->bounce_buffer_size,DMA_BIDIRECTIONAL ); +} +static void sdhci_allocate_bounce_buffer (struct sdhci_host *host) {struct mmc_host *mmc = host->mmc;
@@ -4241,6 +4249,14 @@ static void sdhci_allocate_bounce_buffer } host->bounce_buffer_size = bounce_size; + ret =devm_add_action_or_reset (mmc_dev (mmc), + sdhci_unmap_bounce_buffer, host); +if (ret) { +devm_kfree (mmc_dev (mmc), host->bounce_buffer); + host->bounce_buffer =NULL ; + host->bounce_buffer_size =0 ; +return ; + }/* Lie about this since we're bouncing */ mmc->max_segs = max_blocks;
Greg Kroah-Hartman
maintainerPATCH 67/217 pmdomain: mediatek: fix remaining %pOF after of_node_put()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 3e013bc8b941bd52c8e3a99798d0ae8792cb71ca upstream.
scpsys_get_bus_protection_legacy() looks up several legacy bus protection regmaps from device-tree nodes.
Two error paths put the device node before checking whether the regmap lookup failed, but still pass that node to dev_err_probe() with %pOF on failure. If of_node_put() drops the last reference, the later %pOF formatting can dereference a freed device node.
Keep the node reference until after the error message has been emitted in the infracfg and SMI lookup paths. Also drop the SMI node before returning when the SMI phandle is missing.
--- drivers/pmdomain/mediatek/mtk-pm-domains.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
drivers/pmdomain/mediatek/mtk-pm-domains.c +15 -7
@@ -774,12 +774,15 @@ static int scpsys_get_bus_protection_leg node =of_find_node_with_property (np,"mediatek,infracfg" );if (node) { regmap[0 ] =syscon_regmap_lookup_by_phandle (node,"mediatek,infracfg" ); -of_node_put (node); num_regmaps++; -if (IS_ERR (regmap[0 ])) -return dev_err_probe (dev,PTR_ERR (regmap[0 ]), +if (IS_ERR (regmap[0 ])) { + ret =dev_err_probe (dev,PTR_ERR (regmap[0 ]),"%pOF: failed to get infracfg regmap\n" , node); +of_node_put (node); +return ret; + } +of_node_put (node); }else { regmap[0 ] =NULL ; }
@@ -788,17 +791,22 @@ static int scpsys_get_bus_protection_leg node =of_find_node_with_property (np,"mediatek,smi" );if (node) { smi_np =of_parse_phandle (node,"mediatek,smi" ,0 ); -of_node_put (node); -if (!smi_np) +if (!smi_np) { +of_node_put (node);return -ENODEV ; + } regmap[1 ] =device_node_to_regmap (smi_np); num_regmaps++;of_node_put (smi_np); -if (IS_ERR (regmap[1 ])) -return dev_err_probe (dev,PTR_ERR (regmap[1 ]), +if (IS_ERR (regmap[1 ])) { + ret =dev_err_probe (dev,PTR_ERR (regmap[1 ]),"%pOF: failed to get SMI regmap\n" , node); +of_node_put (node); +return ret; + } +of_node_put (node); }else { regmap[1 ] =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 68/217 mmc: sdhci: make tuning_err a signed int
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haibo Chen <[email protected]>
commit ae31bcc92bb42502bb7c9029e6dc7a824cf6cd14 upstream.
Coverity report INTEGER_OVERFLOW for host->tuning_err.
The tuning_err field in struct sdhci_host is used to store an error code for re-tuning, but it was declared as unsigned int. Several call sites store negative error codes into it and later compare against negative values:
- sdhci.c, sdhci-of-dwcmshc.c and sdhci-pci-gli.c assign it the
return value of __sdhci_execute_tuning()/__sdhci_execute_tuning_9750(),
both of which return a signed int (possibly a negative errno);
- sdhci-of-esdhc.c assigns host->tuning_err = -EAGAIN and later does
"ret = host->tuning_err; if (ret == -EAGAIN ...)"; - sdhci-of-dwcmshc.c prints it with the %d (signed) conversion.
Storing a negative errno in an unsigned int and reading it back as a signed int only happens to work because of two's-complement, same-width integer conversions. It is misleading and triggers sign-conversion warnings. All users treat the value either as a signed error code or as a boolean (zero / non-zero), so changing the type to a signed int is safe and makes the intent explicit.
--- drivers/mmc/host/sdhci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/host/sdhci.h +1 -1
@@ -659,7 +659,7 @@ struct sdhci_host {unsigned int tuning_count;/* Timer count for re-tuning */ unsigned int tuning_mode;/* Re-tuning mode supported by host */ -unsigned int tuning_err;/* Error code for re-tuning */ +int tuning_err;/* Error code for re-tuning */ #define SDHCI_TUNING_MODE_1 0#define SDHCI_TUNING_MODE_2 1#define SDHCI_TUNING_MODE_3 2
Greg Kroah-Hartman
maintainerPATCH 69/217 pmdomains: mediatek: Avoid setting RTFFs CLK_DIS before NRESTORE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: AngeloGioacchino Del Regno <[email protected]>
commit cbb0140379de69fa46526672f3003f128f0b4e2e upstream.
For the PCIE_PHY (also called PEXTP_PHY) type of RTFF hardware, there is special handling setting CLK_DIS before performing the NRESTORE sequence for resetting the RTFF and start sequencing from a clean state.
That special handling, though, poses an issue in case the machine specific bootchain (bootloader in particular) ends up booting the kernel with both PCIe MAC and PHY enabled (not just power domains) as doing so will partially corrupt the PCIe MAC/PHY registers in an unpredictable manner, producing either an initialization fail in the PCI-Express drivers, or even a hard lockup!
Resolve this by simply removing the special handling: in this case the bootchain, or remote processors, setting is getting honored by the later check for PWR_RTFF_SAVE_FLAG presence in the RTFF ctl register.
--- drivers/pmdomain/mediatek/mtk-pm-domains.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/pmdomain/mediatek/mtk-pm-domains.c +0 -8
@@ -266,16 +266,8 @@ static int scpsys_ctl_pwrseq_on(struct sif (ret <0 )return ret; -if (pd->data->rtff_type ==SCPSYS_RTFF_TYPE_PCIE_PHY ) -regmap_set_bits (scpsys->base, pd->data->ctl_offs,PWR_RTFF_CLK_DIS ); -regmap_clear_bits (scpsys->base, pd->data->ctl_offs,PWR_CLK_DIS_BIT );regmap_clear_bits (scpsys->base, pd->data->ctl_offs,PWR_ISO_BIT ); - -/* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */ -if (pd->data->rtff_type ==SCPSYS_RTFF_TYPE_PCIE_PHY ) -udelay (5 ); -regmap_set_bits (scpsys->base, pd->data->ctl_offs,PWR_RST_B_BIT );/*
Greg Kroah-Hartman
maintainerPATCH 70/217 mmc: atmel-mci: Fix use-after-free in atmci_remove due to race condition
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pei Xiao <[email protected]>
commit c125ee35a49a0518521b52b27631eef061b8719a upstream.
In atmci_probe, &host->bh_work is bound with atmci_work_func, and atmci_interrupt, atmci_timeout_timer and atmci_dma_complete can all queue this work on system_bh_wq.
If we remove the module, atmci_remove makes cleanup and the memory allocated for host with devm_kzalloc() is released after the remove callback returns, while the work mentioned above may still be pending or running. The sequence of operations that may lead to a UAF bug is as follows:
CPU0 CPU1
| atmci_interrupt
| queue_work(system_bh_wq,
| &host->bh_work)
atmci_remove |
atmci_cleanup_slot(...) |
atmci_writel(host, ATMCI_IDR, ~0UL) |
timer_delete_sync(&host->timer) |
dma_release_channel(host->dma.chan) |
free_irq(platform_get_irq(pdev, 0), host) |
| atmci_work_func
| // use host
// devm resources released after |
// remove returns, host is freed |
| // use host (use-after-free)Fix it by canceling the work after all the sources that can schedule it (IRQ handler, timeout timer and DMA completion callback) have been stopped, and before proceeding with the remaining cleanup in atmci_remove.
--- drivers/mmc/host/atmel-mci.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/mmc/host/atmel-mci.c +2 -0
@@ -2616,6 +2616,8 @@ static void atmci_remove(struct platformfree_irq (platform_get_irq (pdev,0 ), host); +cancel_work_sync (&host->bh_work); +clk_disable_unprepare (host->mck);pm_runtime_disable (dev);
Greg Kroah-Hartman
maintainerPATCH 71/217 drm/connector/hdmi: Fix out of bounds memory read
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Harrison <[email protected]>
commit 9ecf8ba763d0ffe0673538eb4bf7806f20455d19 upstream.
A helper function was copying a given audio infoframe into the connector's copy but using the size of the destination (a generic target, sized to accept many different data blocks) not the source (a very specific type of data block). Thus, it was copying 60 bytes of data from a 28 byte allocation.
Fix that by using the source size instead, together with a build bug on the source size actually being smaller than the destination.
I hit this running KUnit tests under KASAN (while debugging something else entirely). In the real world, it seems unlikely to cause an actual problem. It is a read not a write so it can't corrupt any memory. However, it could potentially fall off the end of a page and cause an accvio bug.
--- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/display/drm_hdmi_state_helper.c +2 -1
@@ -1072,7 +1072,8 @@ drm_atomic_helper_connector_hdmi_update_mutex_lock (&connector->hdmi.infoframes.lock); -memcpy (&infoframe->data, frame,sizeof (infoframe->data)); +BUILD_BUG_ON (sizeof (*frame) >sizeof (infoframe->data)); +memcpy (&infoframe->data, frame,sizeof (*frame)); infoframe->set = true; ret =write_infoframe (connector, infoframe);
Greg Kroah-Hartman
maintainerPATCH 72/217 mmc: loongson2: Fix sg iteration in data reorder functions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Binbin Zhou <[email protected]>
commit 00179ed9fbe07799676e2cb63c4e7f0e7cd80a5c upstream.
In ls2k0500_mmc_reorder_cmd_data() and ls2k2000_mmc_reorder_cmd_data(), the for_each_sg() macro already iterates over the scatterlist entries, with 'sg' pointing to the current entry. However, the code incorrectly uses '&sg[i]' and 'sg_dma_len(&sg[i])' inside the loop, which treats 'sg' as an array base and indexes it again, leading to access of wrong sg entries (or out-of-bounds if the list is not an array).
--- drivers/mmc/host/loongson2-mmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mmc/host/loongson2-mmc.c +4 -4
@@ -628,8 +628,8 @@ static void ls2k0500_mmc_reorder_cmd_datreturn ;for_each_sg (cmd->data->sg, sg, cmd->data->sg_len, i) { - data =sg_virt (&sg[i]); -for (j =0 ; j < (sg_dma_len (&sg[i]) /4 ); j++) + data =sg_virt (sg); +for (j =0 ; j < (sg_dma_len (sg) /4 ); j++)if (cmd->opcode ==SD_SWITCH ) data[j] =bitrev8x4 (data[j]);else
@@ -761,8 +761,8 @@ static void ls2k2000_mmc_reorder_cmd_datreturn ;for_each_sg (cmd->data->sg, sg, cmd->data->sg_len, i) { - data =sg_virt (&sg[i]); -for (j =0 ; j < (sg_dma_len (&sg[i]) /4 ); j++) + data =sg_virt (sg); +for (j =0 ; j < (sg_dma_len (sg) /4 ); j++) data[j] =bitrev8x4 (data[j]); } }
Greg Kroah-Hartman
maintainerPATCH 73/217 pmdomain: mediatek: Fix mt8183 hang on boot
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Osipenko <[email protected]>
commit 818d56ac1d08b68a4c42d0326786f030cc640722 upstream.
Depending on firmware, part of the MFG domains may be partially left ON at boot time with kernel detecting PD as ON, while it's OFF.
Some of MFG cores may be left powered after bootloader, to let the ACP to prefetch the GPU region when the display controller is brought up for a continuous splash animation performed by downstream stack.
This doesn't play well with an eventual delay in probing upstream Panfrost driver when the display controller is fully set up, as that would make genpd's sync_state() to power off the domain while ACP tries to prefetch:
this is causing an AXI stall, effectively freezing the AP indefinitely.
In order to prevent trouble from happening, the sync_state() functionality must be obliterated on all of the MFG domains: while this guarantees a power leakage if the bootloader boots the kernel with MFG PDs partially powered on, this is the only way to ensure stable operation of the SoC during boot on devices with such firmware because, of course, those will never officially receive a firmware update.
Fixes Kappa Chromebook hanging during system boot.
--- drivers/pmdomain/mediatek/mt8183-pm-domains.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/pmdomain/mediatek/mt8183-pm-domains.h +5 -2
@@ -47,7 +47,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .pwr_sta2nd_offs = 0x0184, .sram_pdn_bits = 0, .sram_pdn_ack_bits = 0, - .caps = MTK_SCPD_DOMAIN_SUPPLY, + .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8183_POWER_DOMAIN_MFG] = { .name = "mfg",
@@ -57,7 +57,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .pwr_sta2nd_offs = 0x0184, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), - .caps = MTK_SCPD_DOMAIN_SUPPLY, + .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8183_POWER_DOMAIN_MFG_CORE0] = { .name = "mfg_core0",
@@ -67,6 +67,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .pwr_sta2nd_offs = 0x0184, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8183_POWER_DOMAIN_MFG_CORE1] = { .name = "mfg_core1",
@@ -76,6 +77,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .pwr_sta2nd_offs = 0x0184, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8183_POWER_DOMAIN_MFG_2D] = { .name = "mfg_2d",
@@ -85,6 +87,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .pwr_sta2nd_offs = 0x0184, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, .bp_cfg = { BUS_PROT_WR(INFRA, MT8183_TOP_AXI_PROT_EN_1_MFG,
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 74/217 drm/xe: Order ring writes before ring tail updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 9f83c94469ff0fa37274b873ba24922e02531fa7 upstream.
The ring buffer and the LRC context image are both mapped WC, so the ring tail update can become visible to the device before the ring contents it is meant to publish.
The GuC CT send does contain an xe_device_wmb(), so sending the H2G would flush the ring contents. The problem is that it comes too late:xe_lrc_set_ring_tail() publishes the tail before the H2G is sent, and the device samples the tail from the context image independently of it, either at context switch-in or while the context is already resident. A submitter which is interrupted between updating the tail and sending its H2G therefore leaves the device free to observe the new tail while the ring contents behind it are not yet visible:
1. Thread A emits a job into the ring, sets the tail to T_A and sends the H2G, which flushes A's ring contents. The GuC starts scheduling the context in, but it is not executing yet.
2. Thread B emits a job into ring[T_A..T_B]. Those writes are not yet visible to the device.
3. Thread B updates the ring tail to T_B. That write targets a different page and becomes visible first.
4. Thread B is interrupted before it sends its H2G, so the flush which would have published ring[T_A..T_B] has not happened yet.
5. The context is switched in and samples the ring tail from the context image, picking up T_B rather than T_A.
6. The GPU executes A's job, advances HEAD to T_A, and continues on to ring[T_A..T_B], which still holds the previous wrap's contents, so the CS parses stale commands.
The result is command stream corruption, which typically manifests as a hang or a spurious pagefault rather than anything that points back at the submission path.
Kernel jobs are by far the most likely to hit this. Kernel queues such as the migration queue are shared and can be driven by many threads concurrently, producing back-to-back submissions on an LRC which is already executing. User queues are typically tied to a single submitting thread, so the same interleaving is much harder to produce.
Add an xe_device_wmb() at the end of xe_lrc_write_ring() so that it covers every ring tail publication site, and so the invariant is local: once xe_lrc_write_ring() returns, the ring contents are visible to the device.
--- drivers/gpu/drm/xe/xe_lrc.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/xe/xe_lrc.c +7 -0
@@ -1692,6 +1692,13 @@ void xe_lrc_write_ring(struct xe_lrc *lr__xe_lrc_write_ring (lrc, ring, &noop,sizeof (noop)); } + +/* +* The ring and the LRC context image are both WC, so the ring tail +* update which publishes these writes can become visible to the device +* first. Ensure the ring contents are visible before returning. +*/ +xe_device_wmb (xe); }u64 xe_lrc_descriptor (struct xe_lrc *lrc)
Greg Kroah-Hartman
maintainerPATCH 75/217 drm/xe: Fix xe_device_probe() failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raag Jadav <[email protected]>
commit ef526d122b62af5afa437f095aa6661a953676c4 upstream.
Currently, xe_device_probe() jumps to err_unregister_display label in case of failure except for its last call, which directly returns the error without required cleanup handling. This results in stale drm device that isn't cleaned up on unwind. Fix it.
[ 810.194180] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0/drm/renderD128' [ 810.194183] CPU: 9 UID: 0 PID: 5616 Comm: modprobe Kdump: loaded Tainted: G S U E 7.2.0-rc2-xe #382 PREEMPT(full) [ 810.194185] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER, [E]=UNSIGNED_MODULE [ 810.194186] Hardware name: ASUS System Product Name/PRIME Z790-P WIFI, BIOS 1805 10/30/2024 [ 810.194186] Call Trace: [ 810.194187] <TASK> [ 810.194188] dump_stack_lvl+0xe0/0x100 [ 810.194195] dump_stack+0x14/0x20 [ 810.194197] sysfs_warn_dup+0x5f/0x80 [ 810.194204] sysfs_create_dir_ns+0xbe/0xd0 [ 810.194210] kobject_add_internal+0xbc/0x2b0 [ 810.194215] kobject_add+0x7c/0xe0 [ 810.194220] ? get_device_parent+0xcf/0x1e0 [ 810.194227] device_add+0xe3/0x870 [ 810.194231] ? __pfx_drm_gem_name_info+0x10/0x10 [drm] [ 810.194280] drm_minor_register+0x73/0x130 [drm] [ 810.194322] drm_dev_register+0x76/0x2a0 [drm]
--- drivers/gpu/drm/xe/xe_device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_device.c +5 -1
@@ -962,7 +962,11 @@ int xe_device_probe(struct xe_device *xeif (err) goto err_unregister_display; -return devm_add_action_or_reset (xe->drm.dev, xe_device_sanitize, xe); + err =devm_add_action_or_reset (xe->drm.dev, xe_device_sanitize, xe); +if (err) + goto err_unregister_display; + +return 0 ; err_unregister_display:xe_display_unregister (xe);
Greg Kroah-Hartman
maintainerPATCH 76/217 drm/radeon: fix autosuspend cleanup during teardown
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 587be7a17358ef8c0106775fcedae5a7bef50735 upstream.
radeon_driver_load_kms() calls pm_runtime_use_autosuspend() for PX devices, but radeon_driver_unload_kms() does not call the matching pm_runtime_dont_use_autosuspend() during teardown.
If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped.
The documentation for pm_runtime_use_autosuspend() also notes that it is important to undo it with pm_runtime_dont_use_autosuspend() at driver exit time, unless runtime PM was initially enabled with devm_pm_runtime_enable().
Add the missing pm_runtime_dont_use_autosuspend() call to the driver unload path.
This issue was found by manual code inspection.
--- drivers/gpu/drm/radeon/radeon_kms.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/radeon/radeon_kms.c +1 -0
@@ -71,6 +71,7 @@ void radeon_driver_unload_kms(struct drmif (radeon_is_px (dev)) {pm_runtime_get_sync (dev->dev);pm_runtime_forbid (dev->dev); +pm_runtime_dont_use_autosuspend (dev->dev); }radeon_acpi_fini (rdev);
Greg Kroah-Hartman
maintainerPATCH 77/217 eth: bnxt: always set the queue mgmt ops
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
commit 1410c7416dc343f15e9b7152eabddbdbe483002d upstream.
Core provides a centralized callback for validating per-queue settings but the callback is part of the queue management ops. Having the ops conditionally set complicates the parts of the driver which could otherwise lean on the core to feed it the correct settings.
Always set the queue ops, but provide no restart-related callbacks if queue ops are not supported by the device. This should maintain current behavior, the check in netdev_rx_queue_restart() looks both at op struct and individual ops.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +5 -1
@@ -16325,6 +16325,9 @@ static const struct netdev_queue_mgmt_op .supported_params = QCFG_RX_PAGE_SIZE, }; +static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops_unsupp = { +}; +static void bnxt_remove_one (struct pci_dev *pdev) {struct net_device *dev =pci_get_drvdata (pdev);
@@ -16977,9 +16980,10 @@ static int bnxt_init_one(struct pci_devif (BNXT_SUPPORTS_NTUPLE_VNIC (bp)) bp->rss_cap |=BNXT_RSS_CAP_MULTI_RSS_CTX ; + + dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops_unsupp;if (BNXT_SUPPORTS_QUEUE_API (bp)) dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops; - dev->request_ops_lock = true; dev->netmem_tx = true; rc =register_netdev (dev);
Greg Kroah-Hartman
maintainerPATCH 78/217 eth: bnxt: make sure we populate the qcfg defaults on old FW/HW
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
commit 3cf48c04966e1945de6c89bc9c0746ace2e7ddec upstream.
The driver now depends on the core to tell it what the rx page size should be for the agg ring. We must populate the ndo_default_qcfg callback even if we don't support any queue ops.
This fixes:
Oops: divide error: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN RIP: 0010:bnxt_alloc_rx_page_pool (drivers/net/ethernet/broadcom/bnxt/bnxt.c:3852)
with fw version 225.1.109.0.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +1 -0
@@ -16326,6 +16326,7 @@ static const struct netdev_queue_mgmt_op };static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops_unsupp = { + .ndo_default_qcfg = bnxt_queue_default_qcfg, };static void bnxt_remove_one (struct pci_dev *pdev)
Greg Kroah-Hartman
maintainerPATCH 79/217 s390/vfio_ccw: Free all memory if cp_init() fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 74186c2968f8f756ac3226b545b598457c910c75 upstream.
The routine cp_free() is called to unpin/free any memory once an I/O is completed successfully, or if cp_prefetch() fails. But if cp_init() fails, and cp->initialized is not enabled, the same routine cannot be used to free all the memory.
An attempt to address this exists in ccwchain_handle_ccw(), where a single call to ccwchain_free() is made for the currently-processed CCW segment. But this will leak other segments (created as a result of a Transfer in Channel) that had been allocated as part of the same channel program.
Address this by performing the cleanup outside of the recursive ccwchain_handle_ccw()/ccwchain_loop_tic() logic.
--- drivers/s390/cio/vfio_ccw_cp.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +18 -4
@@ -455,9 +455,6 @@ static int ccwchain_handle_ccw(dma32_t c/* Loop for tics on this new chain. */ ret =ccwchain_loop_tic (chain, cp); -if (ret) -ccwchain_free (chain); -return ret; }
@@ -486,6 +483,23 @@ static int ccwchain_loop_tic(struct ccwcreturn 0 ; } +static int ccwchain_build_ccws (dma32_t cda,struct channel_program *cp) +{ +struct ccwchain *chain, *temp; +int ret; + + ret =ccwchain_handle_ccw (cda, cp); + +if (ret) { +/* Cleanup if an error occurred */ +list_for_each_entry_safe (chain, temp, &cp->ccwchain_list, next) { +ccwchain_free (chain); + } + } + +return ret; +} +static int ccwchain_fetch_tic (struct ccw1 *ccw,struct channel_program *cp) {
@@ -735,7 +749,7 @@ int cp_init(struct channel_program *cp,memcpy (&cp->orb, orb,sizeof (*orb));/* Build a ccwchain for the first CCW segment */ - ret =ccwchain_handle_ccw (orb->cmd.cpa, cp); + ret =ccwchain_build_ccws (orb->cmd.cpa, cp);if (!ret) cp->initialized = true;
Greg Kroah-Hartman
maintainerPATCH 80/217 s390/vfio_ccw: Limit the number of channel program segments
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 5405c90d6a47b3014e74ee0618a162449abbbc93 upstream.
The processing of channel programs, and the CCWs within them, is done recursively. As such, there is an arbitrary (but not architectural) limit to the number of CCWs that can exist in a single channel program.
The vfio-ccw logic breaks these channel programs into segments whenever it encounters a Transfer-In-Channel (TIC) CCW, and the combined number of segments count towards the global limit. Impose an equivalent limit to the number of segments until such logic can be made non-recursive.
--- drivers/s390/cio/vfio_ccw_cp.c | 6 ++++++ drivers/s390/cio/vfio_ccw_cp.h | 8 ++++++++ 2 files changed, 14 insertions(+)
drivers/s390/cio/vfio_ccw_cp.c +6 -0
@@ -332,6 +332,7 @@ static struct ccwchain *ccwchain_alloc(s goto out_err;list_add_tail (&chain->next, &cp->ccwchain_list); + cp->ccwchain_count++;return chain;
@@ -441,6 +442,10 @@ static int ccwchain_handle_ccw(dma32_t cif (len <0 )return len; +/* Limit number of chains in a single channel program */ +if (cp->ccwchain_count >=CCWCHAIN_COUNT_MAX ) +return -EINVAL ; +/* Need alloc a new chain for this one. */ chain =ccwchain_alloc (cp, len);if (!chain)
@@ -745,6 +750,7 @@ int cp_init(struct channel_program *cp, vdev->dev, "Prefetching channel program even though prefetch not specified in ORB"); + cp->ccwchain_count =0 ;INIT_LIST_HEAD (&cp->ccwchain_list);memcpy (&cp->orb, orb,sizeof (*orb));
drivers/s390/cio/vfio_ccw_cp.h +8 -0
@@ -23,11 +23,18 @@*/ #define CCWCHAIN_LEN_MAX 256 +/* +* Maximum number of chains +*/ +#define CCWCHAIN_COUNT_MAX 16 +/** * struct channel_program - manage information for channel program * @ccwchain_list: list head of ccwchains * @orb: orb for the currently processed ssch request * @initialized: whether this instance is actually initialized +* @guest_cp: copy of guest channel program +* @ccwchain_count: number of channel program segments (linked by TIC) * * @ccwchain_list is the head of a ccwchain list, that contents the * translated result of the guest channel program that pointed out by
@@ -38,6 +45,7 @@ struct channel_program {union orb orb;bool initialized;struct ccw1 *guest_cp; +unsigned int ccwchain_count; };int cp_init (struct channel_program *cp,union orb *orb);
Greg Kroah-Hartman
maintainerPATCH 81/217 s390/vfio_ccw: Cancel existing workqueues
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 79c60b2c61105368dcc8444eb45847e21734f7c4 upstream.
The initialization of the io_work and crw_work workqueues begs the question of whether they should be un-initialized. Add the corresponding cleanup tags in _release_dev to ensure work isn't dispatched after the private struct is free'd.
--- drivers/s390/cio/vfio_ccw_ops.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/s390/cio/vfio_ccw_ops.c +15 -0
@@ -132,6 +132,13 @@ static void vfio_ccw_mdev_release_dev(st container_of(vdev, struct vfio_ccw_private, vdev);struct vfio_ccw_crw *crw, *temp; +/* +* Ensure these work items are fully drained, so none can +* fire after being released. +*/ +cancel_work_sync (&private->io_work); +cancel_work_sync (&private->crw_work); +list_for_each_entry_safe (crw, temp, &private->crw, next) {list_del (&crw->next);kfree (crw);
@@ -203,6 +210,14 @@ static void vfio_ccw_mdev_close_device(s container_of(vdev, struct vfio_ccw_private, vdev);vfio_ccw_fsm_event (private,VFIO_CCW_EVENT_CLOSE ); + +/* +* Ensure these work items are drained, in the event the +* device is re-opened instead of released. +*/ +cancel_work_sync (&private->io_work); +cancel_work_sync (&private->crw_work); +vfio_ccw_unregister_dev_regions (private); }
Greg Kroah-Hartman
maintainerPATCH 82/217 s390/vfio_ccw: Ensure index for read/write regions are within range
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 9f5f9a78fedc45bc29d6a0a64e3a3472361afae5 upstream.
The introduction of the capability chain rightly clamped the region indexes to the range of the capabilities itself, but neglected to do so for the existing read/write regions which should also be enforced.
--- drivers/s390/cio/vfio_ccw_async.c | 16 ++++++++++++++++ drivers/s390/cio/vfio_ccw_chp.c | 15 +++++++++++++++ drivers/s390/cio/vfio_ccw_ops.c | 7 +++---- 3 files changed, 34 insertions(+), 4 deletions(-)
drivers/s390/cio/vfio_ccw_async.c +16 -0
@@ -8,6 +8,7 @@*/ #include <linux/vfio.h> +#include <linux/nospec.h> #include "vfio_ccw_private.h"
@@ -24,11 +25,20 @@ static ssize_t vfio_ccw_async_region_reareturn -EINVAL ;mutex_lock (&private->io_mutex); + +if (i >= private->num_regions) { + ret = -EINVAL ; + goto out_unlock; + } + + i =array_index_nospec (i, private->num_regions); region = private->region[i].data;if (copy_to_user (buf, (void *)region + pos, count)) ret = -EFAULT ;else ret = count; + +out_unlock:mutex_unlock (&private->io_mutex);return ret; }
@@ -48,6 +58,12 @@ static ssize_t vfio_ccw_async_region_wriif (!mutex_trylock (&private->io_mutex))return -EAGAIN ; +if (i >= private->num_regions) { + ret = -EINVAL ; + goto out_unlock; + } + + i =array_index_nospec (i, private->num_regions); region = private->region[i].data;if (copy_from_user ((void *)region + pos, buf, count)) { ret = -EFAULT ;
drivers/s390/cio/vfio_ccw_chp.c +15 -0
@@ -9,6 +9,7 @@*/ #include <linux/slab.h> +#include <linux/nospec.h> #include <linux/vfio.h> #include "vfio_ccw_private.h"
@@ -26,6 +27,13 @@ static ssize_t vfio_ccw_schib_region_reareturn -EINVAL ;mutex_lock (&private->io_mutex); + +if (i >= private->num_regions) { + ret = -EINVAL ; + goto out; + } + + i =array_index_nospec (i, private->num_regions); region = private->region[i].data;if (cio_update_schib (sch)) {
@@ -97,6 +105,12 @@ static ssize_t vfio_ccw_crw_region_read(list_del (&crw->next);mutex_lock (&private->io_mutex); +if (i >= private->num_regions) { + ret = -EINVAL ; + goto out; + } + + i =array_index_nospec (i, private->num_regions); region = private->region[i].data;if (crw)
@@ -109,6 +123,7 @@ static ssize_t vfio_ccw_crw_region_read( region->crw =0 ; +out:mutex_unlock (&private->io_mutex);kfree (crw);
drivers/s390/cio/vfio_ccw_ops.c +3 -4
@@ -259,6 +259,7 @@ static ssize_t vfio_ccw_mdev_read(structreturn vfio_ccw_mdev_read_io_region (private, buf, count, ppos);default : index -=VFIO_CCW_NUM_REGIONS ; + index =array_index_nospec (index, private->num_regions);return private->region[index].ops->read (private, buf, count, ppos); }
@@ -311,6 +312,7 @@ static ssize_t vfio_ccw_mdev_write(strucreturn vfio_ccw_mdev_write_io_region (private, buf, count, ppos);default : index -=VFIO_CCW_NUM_REGIONS ; + index =array_index_nospec (index, private->num_regions);return private->region[index].ops->write (private, buf, count, ppos); }
@@ -353,11 +355,8 @@ static int vfio_ccw_mdev_get_region_info VFIO_CCW_NUM_REGIONS + private->num_regions)return -EINVAL ; - info->index =array_index_nospec (info->index, -VFIO_CCW_NUM_REGIONS + - private->num_regions); - i = info->index -VFIO_CCW_NUM_REGIONS ; + i =array_index_nospec (i, private->num_regions); info->offset =VFIO_CCW_INDEX_TO_OFFSET (info->index); info->size = private->region[i].size;
Greg Kroah-Hartman
maintainerPATCH 83/217 s390/vfio_ccw: Ensure first IDAW remains constant
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 565bef268d75bf7df665bce6923a88cd0eb74592 upstream.
The first IDAW in a list does not need to be on a 2K/4K boundary like all others, and so is read separately to accurately calculate the size of the buffer needed to read the full IDAL.
Verify that the address found in the first IDAW is unchanged between reads, to ensure a consistent set of IDAWs being worked with.
--- drivers/s390/cio/vfio_ccw_cp.c | 16 ++++++++++++++++ drivers/s390/cio/vfio_ccw_cp.h | 2 ++ 2 files changed, 18 insertions(+)
drivers/s390/cio/vfio_ccw_cp.c +16 -0
@@ -530,6 +530,7 @@ static dma64_t *get_guest_idal(struct cc &container_of(cp, struct vfio_ccw_private, cp)->vdev;dma64_t *idaws;dma32_t *idaws_f1; +u64 first_idaw;int idal_len = idaw_nr *sizeof (*idaws);int idaw_size =idal_is_2k (cp) ?PAGE_SIZE /2 :PAGE_SIZE ;int idaw_mask = ~(idaw_size -1 );
@@ -546,6 +547,18 @@ static dma64_t *get_guest_idal(struct cckfree (idaws);return ERR_PTR (ret); } + + idaws_f1 = (dma32_t *)idaws; +if (cp->orb.cmd.c64) + first_idaw =dma64_to_u64 (idaws[0 ]); +else + first_idaw =dma32_to_u32 (idaws_f1[0 ]); + +/* Unexpected mismatch from earlier read */ +if (first_idaw != cp->guest_iova) { +kfree (idaws); +return ERR_PTR (-EINVAL ); + } }else {/* Fabricate an IDAL based off CCW data address */ if (cp->orb.cmd.c64) {
@@ -611,6 +624,9 @@ static int ccw_count_idaws(struct ccw1 * iova =dma32_to_u32 (ccw->cda); } +/* Save the read address for later */ + cp->guest_iova = iova; +/* Format-1 IDAWs operate on 2K each */ if (!cp->orb.cmd.c64)return idal_2k_nr_words ((void *)iova, bytes);
drivers/s390/cio/vfio_ccw_cp.h +2 -0
@@ -35,6 +35,7 @@* @initialized: whether this instance is actually initialized * @guest_cp: copy of guest channel program * @ccwchain_count: number of channel program segments (linked by TIC) +* @guest_iova: first data address of a guest channel program * * @ccwchain_list is the head of a ccwchain list, that contents the * translated result of the guest channel program that pointed out by
@@ -46,6 +47,7 @@ struct channel_program {bool initialized;struct ccw1 *guest_cp;unsigned int ccwchain_count; +u64 guest_iova; };int cp_init (struct channel_program *cp,union orb *orb);
Greg Kroah-Hartman
maintainerPATCH 84/217 s390/vfio_ccw: Fix out of bounds check on CCW array
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit a005b7f1a491ffda61bff0fd0f6548f8986fb977 upstream.
The routine ccwchain_calc_length() counts the number of channel command words (CCWs) that are chained together in a single channel program, and rejects anything larger than CCWCHAIN_LEN_MAX (256) CCWs.
The loop itself is "do..while (count < 257)", and while the logic in is_cpa_within_range() correctly adjusts between the 0-index array of CCWs and the count of CCWs starting at 1, this means it would look at a possible 257th CCW before ending the loop and (correctly) returning an error.
Fix this by restructuring the loop to break as soon as 256 CCWs (thus indexes 0-255) are examined, without looking at memory outside the range.
--- drivers/s390/cio/vfio_ccw_cp.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +5 -12
@@ -377,11 +377,9 @@ static void ccwchain_cda_free(struct ccwstatic int ccwchain_calc_length (u64 iova,struct channel_program *cp) {struct ccw1 *ccw = cp->guest_cp; -int cnt =0 ; - - do { - cnt++; +int cnt; +for (cnt =1 ; cnt <=CCWCHAIN_LEN_MAX ; cnt++, ccw++) {/* * We want to keep counting if the current CCW has the * command-chaining flag enabled, or if it is a TIC CCW
@@ -391,15 +389,10 @@ static int ccwchain_calc_length(u64 iova* after the TIC, depending on the results of its operation. */ if (!ccw_is_chain (ccw) && !is_tic_within_range (ccw, iova, cnt)) -break ; - - ccw++; - }while (cnt <CCWCHAIN_LEN_MAX +1 ); - -if (cnt ==CCWCHAIN_LEN_MAX +1 ) - cnt = -EINVAL ; +return cnt; + } -return cnt; +return -EINVAL ; }static int tic_target_chain_exists (struct ccw1 *tic,struct channel_program *cp)
Greg Kroah-Hartman
maintainerPATCH 85/217 s390/vfio_ccw: Move cp cleanup out of not operational
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 0c11f61a876ed6fcca53d442ed3f33ea8362a0f9 upstream.
The fsm_notoper() routine is called when the device has been lost, and is (by definition) no longer operational. Since this can happen asynchronously from the normal behavior of the driver, the cleanup may happen when holding other locks in the calling sequence (notably, the cio subchannel lock).
Push the cleanup of the private->cp resources to a workqueue, where it can be done out from under that lock sequence and a future patch can safely manage the locking requirements.
--- drivers/s390/cio/vfio_ccw_drv.c | 9 +++++++++ drivers/s390/cio/vfio_ccw_fsm.c | 3 +-- drivers/s390/cio/vfio_ccw_ops.c | 13 +++++++++++++ drivers/s390/cio/vfio_ccw_private.h | 3 +++ 4 files changed, 26 insertions(+), 2 deletions(-)
drivers/s390/cio/vfio_ccw_drv.c +9 -0
@@ -125,6 +125,15 @@ void vfio_ccw_crw_todo(struct work_struceventfd_signal (private->crw_trigger); } +void vfio_ccw_notoper_todo (struct work_struct *work) +{ +struct vfio_ccw_private *private; + + private = container_of(work, struct vfio_ccw_private, notoper_work); + +cp_free (&private->cp); +} +/* * Css driver callbacks */
drivers/s390/cio/vfio_ccw_fsm.c +1 -2
@@ -170,8 +170,7 @@ static void fsm_notoper(struct vfio_ccw_css_sched_sch_todo (sch,SCH_TODO_UNREG ); private->state =VFIO_CCW_STATE_NOT_OPER ; -/* This is usually handled during CLOSE event */ -cp_free (&private->cp); +queue_work (vfio_ccw_work_q, &private->notoper_work); }/*
drivers/s390/cio/vfio_ccw_ops.c +13 -0
@@ -54,6 +54,7 @@ static int vfio_ccw_mdev_init_dev(structINIT_LIST_HEAD (&private->crw);INIT_WORK (&private->io_work, vfio_ccw_sch_io_todo);INIT_WORK (&private->crw_work, vfio_ccw_crw_todo); +INIT_WORK (&private->notoper_work, vfio_ccw_notoper_todo); private->cp.guest_cp =kcalloc (CCWCHAIN_LEN_MAX ,sizeof (struct ccw1 ),GFP_KERNEL );
@@ -135,9 +136,16 @@ static void vfio_ccw_mdev_release_dev(st/* * Ensure these work items are fully drained, so none can * fire after being released. +* +* notoper_work should have nothing to do here, because only +* open devices could have channel_program resources in use +* and those would be released during close. Nevertheless, +* call flush here as well to be certain anything that was +* allocated is freed. */ cancel_work_sync (&private->io_work);cancel_work_sync (&private->crw_work); +flush_work (&private->notoper_work);list_for_each_entry_safe (crw, temp, &private->crw, next) {list_del (&crw->next);
@@ -214,9 +222,14 @@ static void vfio_ccw_mdev_close_device(s/* * Ensure these work items are drained, in the event the * device is re-opened instead of released. +* +* notoper_work needs to be given a chance to run if it +* is queued, so any memory associated with the channel +* program can be returned. */ cancel_work_sync (&private->io_work);cancel_work_sync (&private->crw_work); +flush_work (&private->notoper_work);vfio_ccw_unregister_dev_regions (private); }
drivers/s390/cio/vfio_ccw_private.h +3 -0
@@ -102,6 +102,7 @@ struct vfio_ccw_parent {* @req_trigger: eventfd ctx for signaling userspace to return device * @io_work: work for deferral process of I/O handling * @crw_work: work for deferral process of CRW handling +* @notoper_work: work for deferred processing in not-operational state */ struct vfio_ccw_private {struct vfio_device vdev;
@@ -125,11 +126,13 @@ struct vfio_ccw_private {struct eventfd_ctx *req_trigger;struct work_struct io_work;struct work_struct crw_work; +struct work_struct notoper_work; }__aligned(8) ;int vfio_ccw_sch_quiesce (struct subchannel *sch);void vfio_ccw_sch_io_todo (struct work_struct *work);void vfio_ccw_crw_todo (struct work_struct *work); +void vfio_ccw_notoper_todo (struct work_struct *work);extern struct mdev_driver vfio_ccw_mdev_driver;
Greg Kroah-Hartman
maintainerPATCH 86/217 s390/vfio_ccw: Selectively expand io_mutex
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 34f4feff3e90bd09308fad0974e97113b23b812a upstream.
The io_mutex was defined to serialize the io_regions, but then has also sort of been associated with the I/O themselves because of the close relationship they share.
With the handful of races that are possible, the choices are either to:
A) expand the scope of io_mutex to close these remaining windows, or
B) reduce the scope of io_mutex to just io_region, and introduce a new lock mechanism for the remaining I/O resources
This patch implements A, since B brings with it a lot more interactions that would need to be tracked and kept in a correct hierarchy. It also takes advantage of the workqueue element for cp_free() that now gets called out of fsm_notoper(), which could be invoked out of an interrupt context and thus cannot acquire a mutex itself.
--- drivers/s390/cio/vfio_ccw_chp.c | 2 +- drivers/s390/cio/vfio_ccw_cp.c | 8 +++++++- drivers/s390/cio/vfio_ccw_drv.c | 6 ++++-- drivers/s390/cio/vfio_ccw_fsm.c | 5 +++++ drivers/s390/cio/vfio_ccw_private.h | 3 ++- 5 files changed, 19 insertions(+), 5 deletions(-)
drivers/s390/cio/vfio_ccw_chp.c +1 -1
@@ -98,13 +98,13 @@ static ssize_t vfio_ccw_crw_region_read(if (pos + count >sizeof (*region))return -EINVAL ; +mutex_lock (&private->io_mutex); crw =list_first_entry_or_null (&private->crw, struct vfio_ccw_crw, next);if (crw)list_del (&crw->next); -mutex_lock (&private->io_mutex);if (i >= private->num_regions) { ret = -EINVAL ; goto out;
drivers/s390/cio/vfio_ccw_cp.c +7 -1
@@ -976,17 +976,23 @@ void cp_update_scsw(struct channel_progr*/ bool cp_iova_pinned (struct channel_program *cp,u64 iova,u64 length) { +struct vfio_ccw_private *private = + container_of(cp, struct vfio_ccw_private, cp);struct ccwchain *chain;int i;if (!cp->initialized)return false; +mutex_lock (&private->io_mutex);list_for_each_entry (chain, &cp->ccwchain_list, next) {for (i =0 ; i < chain->ch_len; i++) -if (page_array_iova_pinned (&chain->ch_pa[i], iova, length)) +if (page_array_iova_pinned (&chain->ch_pa[i], iova, length)) { +mutex_unlock (&private->io_mutex);return true; + } } +mutex_unlock (&private->io_mutex);return false; }
drivers/s390/cio/vfio_ccw_drv.c +4 -2
@@ -91,6 +91,7 @@ void vfio_ccw_sch_io_todo(struct work_st is_final = !(scsw_actl (&irb->scsw) & (SCSW_ACTL_DEVACT |SCSW_ACTL_SCHACT )); +mutex_lock (&private->io_mutex);if (scsw_is_solicited (&irb->scsw)) {cp_update_scsw (&private->cp, &irb->scsw);if (is_final && private->state ==VFIO_CCW_STATE_CP_PENDING ) {
@@ -98,9 +99,7 @@ void vfio_ccw_sch_io_todo(struct work_st cp_is_finished = true; } } -mutex_lock (&private->io_mutex);memcpy (private->io_region->irb_area, irb,sizeof (*irb)); -mutex_unlock (&private->io_mutex);/* * Reset to IDLE only if processing of a channel program
@@ -110,6 +109,7 @@ void vfio_ccw_sch_io_todo(struct work_st*/ if (cp_is_finished) private->state =VFIO_CCW_STATE_IDLE ; +mutex_unlock (&private->io_mutex);if (private->io_trigger)eventfd_signal (private->io_trigger);
@@ -131,7 +131,9 @@ void vfio_ccw_notoper_todo(struct work_s private = container_of(work, struct vfio_ccw_private, notoper_work); +mutex_lock (&private->io_mutex);cp_free (&private->cp); +mutex_unlock (&private->io_mutex); }/*
drivers/s390/cio/vfio_ccw_fsm.c +5 -0
@@ -170,6 +170,7 @@ static void fsm_notoper(struct vfio_ccw_css_sched_sch_todo (sch,SCH_TODO_UNREG ); private->state =VFIO_CCW_STATE_NOT_OPER ; +/* This routine could be called from IRQ context, so defer */ queue_work (vfio_ccw_work_q, &private->notoper_work); }
@@ -409,7 +410,11 @@ static void fsm_close(struct vfio_ccw_pr private->state =VFIO_CCW_STATE_STANDBY ;spin_unlock_irq (&sch->lock); + +mutex_lock (&private->io_mutex);cp_free (&private->cp); +mutex_unlock (&private->io_mutex); +return ; err_unlock:
drivers/s390/cio/vfio_ccw_private.h +2 -1
@@ -88,7 +88,8 @@ struct vfio_ccw_parent {* @state: internal state of the device * @completion: synchronization helper of the I/O completion * @io_region: MMIO region to input/output I/O arguments/results -* @io_mutex: protect against concurrent update of I/O regions +* @io_mutex: protect against concurrent update of I/O resources +* and @cp lifecycle * @region: additional regions for other subchannel operations * @cmd_region: MMIO region for asynchronous I/O commands other than START * @schib_region: MMIO region for SCHIB information
Greg Kroah-Hartman
maintainerPATCH 87/217 s390/vfio_ccw: Calculate idal length based on idaw type
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 4f6fdc6e1a7fbfa36b945af33c65a417948feac0 upstream.
Sashiko pointed out that get_guest_idal() unconditionally calculates the length of the IDAL presuming everything is a Format-2 IDAW.
The output of vfio-ccw is always Format-2, but the input can be either Format-1 (31-bit addresses) or Format-2 (64-bit addresses). As a result, the size of the guest IDAL may be incorrect and should be trimmed down.
--- drivers/s390/cio/vfio_ccw_cp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +3 -2
@@ -233,6 +233,7 @@ static void convert_ccw0_to_ccw1(struct }#define idal_is_2k (_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k) +#define get_idaw_size (_cp) ((_cp)->orb.cmd.c64 ? sizeof(u64) : sizeof(u32))/* * Helpers to operate ccwchain.
@@ -524,7 +525,7 @@ static dma64_t *get_guest_idal(struct ccdma64_t *idaws;dma32_t *idaws_f1;u64 first_idaw; -int idal_len = idaw_nr *sizeof (*idaws); +int idal_len = idaw_nr *get_idaw_size (cp);int idaw_size =idal_is_2k (cp) ?PAGE_SIZE /2 :PAGE_SIZE ;int idaw_mask = ~(idaw_size -1 );int i, ret;
@@ -593,7 +594,7 @@ static int ccw_count_idaws(struct ccw1 *struct vfio_device *vdev = &container_of(cp, struct vfio_ccw_private, cp)->vdev;u64 iova; -int size = cp->orb.cmd.c64 ?sizeof (u64) :sizeof (u32); +int size =get_idaw_size (cp);int ret;int bytes =1 ;
Greg Kroah-Hartman
maintainerPATCH 88/217 s390/vfio_ccw: Implement a crw lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
commit 16b0798024c0e9117e395829ddbbe70981c79d9c upstream.
Unlike the channel_program struct, which covers synchronous I/O submissions and asynchronous interrupts, the CRW region relies exclusively on asynchronous events coming from hardware.
Implement a lock to manage the list of those payloads, to ensure they are read cohesively.
--- drivers/s390/cio/vfio_ccw_chp.c | 26 ++++++++++++++++---------- drivers/s390/cio/vfio_ccw_drv.c | 6 ++++++ drivers/s390/cio/vfio_ccw_ops.c | 4 ++++ drivers/s390/cio/vfio_ccw_private.h | 4 ++++ 4 files changed, 30 insertions(+), 10 deletions(-)
drivers/s390/cio/vfio_ccw_chp.c +16 -10
@@ -93,18 +93,13 @@ static ssize_t vfio_ccw_crw_region_read(loff_t pos = *ppos &VFIO_CCW_OFFSET_MASK ;struct ccw_crw_region *region;struct vfio_ccw_crw *crw; +unsigned long flags;int ret;if (pos + count >sizeof (*region))return -EINVAL ;mutex_lock (&private->io_mutex); - crw =list_first_entry_or_null (&private->crw, - struct vfio_ccw_crw, next); - -if (crw) -list_del (&crw->next); -if (i >= private->num_regions) { ret = -EINVAL ; goto out;
@@ -113,6 +108,16 @@ static ssize_t vfio_ccw_crw_region_read( i =array_index_nospec (i, private->num_regions); region = private->region[i].data; +spin_lock_irqsave (&private->crw_lock, flags); + crw =list_first_entry_or_null (&private->crw, + struct vfio_ccw_crw, next); + +if (crw) +list_del (&crw->next); + +/* Drop CRW lock while copying to userspace */ +spin_unlock_irqrestore (&private->crw_lock, flags); +if (crw)memcpy (®ion->crw, &crw->crw,sizeof (region->crw));
@@ -122,15 +127,16 @@ static ssize_t vfio_ccw_crw_region_read( ret = count; region->crw =0 ; - -out: -mutex_unlock (&private->io_mutex); -kfree (crw);/* Notify the guest if more CRWs are on our queue */ +spin_lock_irqsave (&private->crw_lock, flags);if (!list_empty (&private->crw) && private->crw_trigger)eventfd_signal (private->crw_trigger); +spin_unlock_irqrestore (&private->crw_lock, flags); + +out: +mutex_unlock (&private->io_mutex);return ret; }
drivers/s390/cio/vfio_ccw_drv.c +6 -0
@@ -118,11 +118,14 @@ void vfio_ccw_sch_io_todo(struct work_stvoid vfio_ccw_crw_todo (struct work_struct *work) {struct vfio_ccw_private *private; +unsigned long flags; private = container_of(work, struct vfio_ccw_private, crw_work); +spin_lock_irqsave (&private->crw_lock, flags);if (!list_empty (&private->crw) && private->crw_trigger)eventfd_signal (private->crw_trigger); +spin_unlock_irqrestore (&private->crw_lock, flags); }void vfio_ccw_notoper_todo (struct work_struct *work)
@@ -286,6 +289,7 @@ static void vfio_ccw_queue_crw(struct vf unsigned int rsid) {struct vfio_ccw_crw *crw; +unsigned long flags;/* * If unable to allocate a CRW, just drop the event and
@@ -303,7 +307,9 @@ static void vfio_ccw_queue_crw(struct vf crw->crw.erc = erc; crw->crw.rsid = rsid; +spin_lock_irqsave (&private->crw_lock, flags);list_add_tail (&crw->next, &private->crw); +spin_unlock_irqrestore (&private->crw_lock, flags);queue_work (vfio_ccw_work_q, &private->crw_work); }
drivers/s390/cio/vfio_ccw_ops.c +4 -0
@@ -55,6 +55,7 @@ static int vfio_ccw_mdev_init_dev(structINIT_WORK (&private->io_work, vfio_ccw_sch_io_todo);INIT_WORK (&private->crw_work, vfio_ccw_crw_todo);INIT_WORK (&private->notoper_work, vfio_ccw_notoper_todo); +spin_lock_init (&private->crw_lock); private->cp.guest_cp =kcalloc (CCWCHAIN_LEN_MAX ,sizeof (struct ccw1 ),GFP_KERNEL );
@@ -132,6 +133,7 @@ static void vfio_ccw_mdev_release_dev(ststruct vfio_ccw_private *private = container_of(vdev, struct vfio_ccw_private, vdev);struct vfio_ccw_crw *crw, *temp; +unsigned long flags;/* * Ensure these work items are fully drained, so none can
@@ -147,10 +149,12 @@ static void vfio_ccw_mdev_release_dev(stcancel_work_sync (&private->crw_work);flush_work (&private->notoper_work); +spin_lock_irqsave (&private->crw_lock, flags);list_for_each_entry_safe (crw, temp, &private->crw, next) {list_del (&crw->next);kfree (crw); } +spin_unlock_irqrestore (&private->crw_lock, flags);kmem_cache_free (vfio_ccw_crw_region, private->crw_region);kmem_cache_free (vfio_ccw_schib_region, private->schib_region);
drivers/s390/cio/vfio_ccw_private.h +4 -0
@@ -98,6 +98,8 @@ struct vfio_ccw_parent {* @cp: channel program for the current I/O operation * @irb: irb info received from interrupt * @scsw: scsw info +* @crw_lock: serialization of CRW list information +* @crw: list of Channel Report Word elements * @io_trigger: eventfd ctx for signaling userspace I/O results * @crw_trigger: eventfd ctx for signaling userspace CRW information * @req_trigger: eventfd ctx for signaling userspace to return device
@@ -120,6 +122,8 @@ struct vfio_ccw_private {struct channel_program cp;struct irb irb;union scsw scsw; + +spinlock_t crw_lock;struct list_head crw;struct eventfd_ctx *io_trigger;
Greg Kroah-Hartman
maintainerPATCH 89/217 s390/zcrypt: Fix CPRB memory allocation in zcrypt misc code
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
commit 5004889551dfaf7f4b2cda8ed213d234bb8ebf82 upstream.
Both CPRB alloc functions in zcrypt_ccamisc.c and zcrypt_ep11misc.c did not round up the memory allocation to a multiple of 4 bytes as it is needed by the zcrypt layer to process the CPRBs.
Now the alloc_and_prep_cprbmem() and alloc_cprbmem() functions guarantee that the base CPRB struct and a possible parameter block are aligned to a 4-byte boundary and the backing memory allocation is rounded up to the next multiple of 4 byte. Also the free_cprbmem() is updated and scrubs the rounded up amount of memory.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 20 ++++++++++++++------ drivers/s390/crypto/zcrypt_ep11misc.c | 16 +++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-)
drivers/s390/crypto/zcrypt_ccamisc.c +14 -6
@@ -16,6 +16,7 @@#include <linux/module.h> #include <linux/slab.h> #include <linux/random.h> +#include <linux/align.h> #include <asm/zcrypt.h> #include <asm/pkey.h>
@@ -268,6 +269,10 @@ EXPORT_SYMBOL(cca_check_sececckeytoken);* block, reply CPRB and reply param block and fill in values * for the common fields. Returns 0 on success or errno value * on failure. +* It is guaranteed that request and a possible param block +* are aligned to a 4 byte boundary. Furthermore if a param +* block is used, the memory allocated for this is rounded up to +* the next multiple of 4 bytes. */ static int alloc_and_prep_cprbmem(size_t paramblen, u8 **p_cprb_mem,
@@ -276,7 +281,8 @@ static int alloc_and_prep_cprbmem(size_t u32 xflags) {u8 *cprbmem =NULL ; -size_t cprbplusparamblen =sizeof (struct CPRBX ) + paramblen; +size_t cprbplusparamblen = +ALIGN (sizeof (struct CPRBX ),4 ) +ALIGN (paramblen,4 );size_t len =2 * cprbplusparamblen;struct CPRBX *preqcblk, *prepcblk;
@@ -303,10 +309,10 @@ static int alloc_and_prep_cprbmem(size_tmemcpy (preqcblk->func_id,"T2" ,2 ); preqcblk->rpl_msgbl = cprbplusparamblen;if (paramblen) { - preqcblk->req_parmb = - ((u8 __user *)preqcblk) +sizeof (struct CPRBX ); - preqcblk->rpl_parmb = - ((u8 __user *)prepcblk) +sizeof (struct CPRBX ); + preqcblk->req_parmb = ((u8 __user *)preqcblk) + +ALIGN (sizeof (struct CPRBX ),4 ); + preqcblk->rpl_parmb = ((u8 __user *)prepcblk) + +ALIGN (sizeof (struct CPRBX ),4 ); } *p_cprb_mem = cprbmem;
@@ -324,8 +330,10 @@ static int alloc_and_prep_cprbmem(size_t*/ static void free_cprbmem (void *mem,size_t paramblen,bool scrub,u32 xflags) { +size_t cprblen =ALIGN (sizeof (struct CPRBX ),4 ) +ALIGN (paramblen,4 ); +if (mem && scrub) -memzero_explicit (mem,2 * (sizeof (struct CPRBX ) + paramblen)); +memzero_explicit (mem,2 * cprblen);if (xflags &ZCRYPT_XFLAG_NOMEMALLOC )mempool_free (mem, cprb_mempool);
drivers/s390/crypto/zcrypt_ep11misc.c +11 -5
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/random.h> #include <linux/slab.h> +#include <linux/align.h> #include <asm/zcrypt.h> #include <asm/pkey.h> #include <crypto/aes.h>
@@ -356,21 +357,24 @@ EXPORT_SYMBOL(ep11_check_aes_key);/* * Allocate and prepare ep11 cprb plus additional payload. +* It is guaranteed that the memory is aligned to a 4 byte boundary. +* Furthermore the memory allocation is rounded up to the next +* multiple of 4 bytes (with taking the payload_len into account). */ static void *alloc_cprbmem (size_t payload_len,u32 xflags) { -size_t len =sizeof (struct ep11_cprb ) + payload_len; +size_t memlen =ALIGN (sizeof (struct ep11_cprb ) + payload_len,4 );struct ep11_cprb *cprb =NULL ;if (xflags &ZCRYPT_XFLAG_NOMEMALLOC ) { -if (len <=CPRB_MEMPOOL_ITEM_SIZE ) +if (memlen <=CPRB_MEMPOOL_ITEM_SIZE ) cprb =mempool_alloc_preallocated (cprb_mempool); }else { - cprb =kmalloc (len,GFP_KERNEL ); + cprb =kmalloc (memlen,GFP_KERNEL ); }if (!cprb)return NULL ; -memset (cprb,0 , len); +memset (cprb,0 , memlen); cprb->cprb_len =sizeof (struct ep11_cprb ); cprb->cprb_ver_id =0x04 ;
@@ -386,8 +390,10 @@ static void *alloc_cprbmem(size_t payloa*/ static void free_cprbmem (void *mem,size_t payload_len,bool scrub,u32 xflags) { +size_t memlen =ALIGN (sizeof (struct ep11_cprb ) + payload_len,4 ); +if (mem && scrub) -memzero_explicit (mem,sizeof (struct ep11_cprb ) + payload_len); +memzero_explicit (mem, memlen);if (xflags &ZCRYPT_XFLAG_NOMEMALLOC )mempool_free (mem, cprb_mempool);
Greg Kroah-Hartman
maintainerPATCH 90/217 drm/amd/display: Fix NULL pointer dereference in amdgpu_dm_crtc_set_vblank()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Pitoiset <[email protected]>
commit f2a1c4c6fe0a6fcde02e59dde546dba28d283635 upstream.
amdgpu_dm_crtc_set_vblank() dereferences acrtc_state->stream when vblank is enabled/queried from DRM_IOCTL_MODE_CRTC_GET_SEQUENCE before a stream is attached to it.
BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: amdgpu_dm_crtc_set_vblank+0x6b/0x4d0 [amdgpu] Call Trace: drm_vblank_enable drm_vblank_get drm_crtc_get_sequence_ioctl drm_ioctl_kernel drm_ioctl
Reproduced by running VKCTS with WSI tests enabled on RADV.
Guard the enable path on acrtc_state->stream being non-NULL, matching the existing checks in this function.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +1 -1
@@ -306,7 +306,7 @@ static inline int amdgpu_dm_crtc_set_vbl irq_type =amdgpu_display_crtc_idx_to_irq_type (adev, acrtc->crtc_id); -if (enable) { +if (enable && acrtc_state->stream) {struct dc *dc = adev->dm.dc;struct drm_vblank_crtc *vblank =drm_crtc_vblank_crtc (crtc);struct psr_settings *psr = &acrtc_state->stream->link->psr_settings;
Greg Kroah-Hartman
maintainerPATCH 91/217 drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Lucas <[email protected]>
commit 2f9a5c0f018d4a1586ee892f81f1383219676415 upstream.
COLOR_SPACE_YCBCR2020_TYPE, which is selected for COLOR_SPACE_2020_YCBCR_LIMITED color_space, has coefficients that are incorrect for limited-range output. Its luma and chroma scaling is full-range so output is too bright and colors are incorrect.
COLOR_SPACE_YCBCR2020_TYPE is closer to a full-range conversion matrix with incorrect luma offset, so correct the luma offset for full-range and rename it to COLOR_SPACE_YCBCR2020_FULL_TYPE.
Add COLOR_SPACE_YCBCR2020_LIMITED_TYPE with correct scaling and range for limited-range output.
Fix related functions so COLOR_SPACE_YCBCR2020_LIMITED_TYPE and COLOR_SPACE_YCBCR2020_FULL_TYPE are correctly selected based on dc_color_space.
Derivation of both matrices follows ITU-T H.273:
Table 4, MatrixCoefficients 9, BT.2020-NCL weights:
KR = 0.2627, KB = 0.0593, KG = 1 - KR - KB = 0.6780.
Equations 45-47 in matrix form:
[ KR KG KB 0 ]
M2020_NCL = [ -KR/(2(1-KB)) -KG/(2(1-KB)) 1/2 0 ]
[ 1/2 -KG/(2(1-KR)) -KB/(2(1-KR)) 0 ]
[ 0 0 0 1 ]Limited and Full transforms based on equations 30-32 and 36-38 with bit depth 10, normalized by 1023:
[ 876/1023 0 0 64/1023 ]
MLimited = [ 0 896/1023 0 512/1023 ]
[ 0 0 896/1023 512/1023 ]
[ 0 0 0 1 ] [ 1023/1023 0 0 0 ]
MFull = [ 0 1023/1023 0 512/1023 ]
[ 0 0 1023/1023 512/1023 ]
[ 0 0 0 1 ]M2020_NCL_Limited = MLimited x M2020_NCLM2020_NCL_Full = MFull x M2020_NCL
The upper three rows of M2020_NCL_* are stored in CR, Y, CB order. Each M2020_NCL_* value is stored as Round(value * 8192) in its 16-bit two's-complement representation.
--- drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 31 +++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +20 -11
@@ -51,7 +51,8 @@ enum dc_color_space_type {COLOR_SPACE_RGB_LIMITED_TYPE ,COLOR_SPACE_YCBCR601_TYPE ,COLOR_SPACE_YCBCR709_TYPE , -COLOR_SPACE_YCBCR2020_TYPE , +COLOR_SPACE_YCBCR2020_LIMITED_TYPE , +COLOR_SPACE_YCBCR2020_FULL_TYPE ,COLOR_SPACE_YCBCR601_LIMITED_TYPE ,COLOR_SPACE_YCBCR709_LIMITED_TYPE , COLOR_SPACE_YCBCR709_BLACK_TYPE,
@@ -103,9 +104,15 @@ static const struct out_csc_color_matrix {0xE00 ,0xF349 ,0xFEB7 ,0x1000 ,0x6CE ,0x16E3 ,0x24F ,0x200 , 0xFCCB, 0xF535, 0xE00, 0x1000} }, - { COLOR_SPACE_YCBCR2020_TYPE, +/* Corrected. Not included in the TODO above. */ + { COLOR_SPACE_YCBCR2020_LIMITED_TYPE, + { 0x0E04, 0xF31D, 0xFEDF, 0x1004, +0x0733 ,0x1294 ,0x01A0 ,0x0201 , + 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, +/* Corrected. Not included in the TODO above. */ + { COLOR_SPACE_YCBCR2020_FULL_TYPE, { 0x1000, 0xF149, 0xFEB7, 0x1004, -0x0868 ,0x15B2 ,0x01E6 ,0x201 , +0x0868 ,0x15B2 ,0x01E6 ,0 , 0xFB88, 0xF478, 0x1000, 0x1004} }, { COLOR_SPACE_YCBCR709_BLACK_TYPE, { 0x0000, 0x0000, 0x0000, 0x1000,
@@ -172,14 +179,14 @@ static bool is_ycbcr709_type(return ret; } -static bool is_ycbcr2020_type ( -enum dc_color_space color_space) +static bool is_ycbcr2020_limited_type (enum dc_color_space color_space) { -bool ret = false; +return color_space ==COLOR_SPACE_2020_YCBCR_LIMITED ; +} -if (color_space ==COLOR_SPACE_2020_YCBCR_LIMITED || color_space ==COLOR_SPACE_2020_YCBCR_FULL ) - ret = true; -return ret; +static bool is_ycbcr2020_full_type (enum dc_color_space color_space) +{ +return color_space ==COLOR_SPACE_2020_YCBCR_FULL ; } static bool is_ycbcr709_limited_type(
@@ -208,8 +215,10 @@ static enum dc_color_space_type get_colo type =COLOR_SPACE_YCBCR601_LIMITED_TYPE ; else if (is_ycbcr709_limited_type(color_space)) type =COLOR_SPACE_YCBCR709_LIMITED_TYPE ; - else if (is_ycbcr2020_type(color_space)) - type =COLOR_SPACE_YCBCR2020_TYPE ; + else if (is_ycbcr2020_limited_type(color_space)) + type =COLOR_SPACE_YCBCR2020_LIMITED_TYPE ; + else if (is_ycbcr2020_full_type(color_space)) + type =COLOR_SPACE_YCBCR2020_FULL_TYPE ; else if (color_space == COLOR_SPACE_YCBCR709) type =COLOR_SPACE_YCBCR709_BLACK_TYPE ; else if (color_space == COLOR_SPACE_YCBCR709_BLACK)
Greg Kroah-Hartman
maintainerPATCH 92/217 drm/amd/display: fix BT.2020 YCbCr output CSC matrices for DCE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Lucas <[email protected]>
commit cd22349e86faf6e15e6c622d70c0efc57d43201e upstream.
The commit cited by the Fixes tag added separate limited and full-range BT.2020 YCbCr entries to the DCE output CSC tables, but populated both entries with the same matrix copied from the common DC table. That matrix combined full-range scaling with limited-range luma offset and was incorrect for both limited and full-range output.
Replace the coefficients in both entries in the DCE paths with those from the new COLOR_SPACE_YCBCR2020_LIMITED_TYPE
and COLOR_SPACE_YCBCR2020_FULL_TYPE entries in the preceding commit ("drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix").
--- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 7 ++++--- drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +4 -3
@@ -115,10 +115,11 @@ static const struct out_csc_color_matrix { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, { COLOR_SPACE_2020_RGB_LIMITEDRANGE, { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} }, -{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, - 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, +/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */ +{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733, + 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, { COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, - 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} } + 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} } }; static bool setup_scaling_configuration(
drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c +4 -3
@@ -93,10 +93,11 @@ static const struct out_csc_color_matrix { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, { COLOR_SPACE_2020_RGB_LIMITEDRANGE, { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} }, -{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, - 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, +/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */ +{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733, + 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, { COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, - 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} } + 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} } }; enum csc_color_mode {
Greg Kroah-Hartman
maintainerPATCH 93/217 drm/amdgpu: Reject UVD message with invalid number of h265 refs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit 9fca434208f1f9ab977feac62df8ebb1cc7ce893 upstream.
Same change as for h264, avoids overflow later when calculating min dpb size.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +3 -0
@@ -802,6 +802,9 @@ static int amdgpu_uvd_cs_msg_decode(stru image_size =ALIGN (image_size,256 ); num_dpb_buffer = (le32_to_cpu (msg[59 ]) &0xff ) +2 ; +if (num_dpb_buffer >17 ) +return -EINVAL ; + min_dpb_size = image_size * num_dpb_buffer; min_ctx_size = ((width +255 ) /16 ) * ((height +255 ) /16 ) *16 * num_dpb_buffer +52 *1024 ;
Greg Kroah-Hartman
maintainerPATCH 94/217 drm/amdgpu: fix nbif 6.3.1 l1 low power not functional
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit cd688a3cb342b9f56399aa076157f1c324c15c5a upstream.
The PCIe L1 low‑power settings for NBIF 6.3.1 were never applied due to unresolved register mapping, which caused the relevant code to be compiled out. As a result, the PCIe link could not enter L1/L23 power‑down states or transition to L0s.
Properly configure the link control register to enable L1 and L23 power‑down, and permit L0s link transitions. Keep LTR disabled and let the PCI core enable it only after verifying end‑to‑end root complex support across switches.
--- drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c | 42 ++++++++++++------------------- 1 file changed, 17 insertions(+), 25 deletions(-)
drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c +17 -25
@@ -315,7 +315,6 @@ static u32 nbif_v6_3_1_get_rom_offset(ststatic void nbif_v6_3_1_program_ltr (struct amdgpu_device *adev) {uint32_t def, data; -u16 devctl2; def =RREG32_SOC15 (NBIO ,0 , regRCC_EP_DEV0_0_EP_PCIE_TX_LTR_CNTL); data =0x35EB ;
@@ -329,15 +328,8 @@ static void nbif_v6_3_1_program_ltr(struif (def != data)WREG32_SOC15 (NBIO ,0 , regRCC_STRAP0_RCC_BIF_STRAP2, data); -pcie_capability_read_word (adev->pdev,PCI_EXP_DEVCTL2 , &devctl2); - -if (adev->pdev->ltr_path == (devctl2 &PCI_EXP_DEVCTL2_LTR_EN )) -return ; - -if (adev->pdev->ltr_path) -pcie_capability_set_word (adev->pdev,PCI_EXP_DEVCTL2 ,PCI_EXP_DEVCTL2_LTR_EN ); -else - pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN); +pcie_capability_set_word (adev->pdev,PCI_EXP_DEVCTL2 , + PCI_EXP_DEVCTL2_LTR_EN); }#endif
@@ -345,7 +337,7 @@ static void nbif_v6_3_1_program_aspm(str {#ifdef CONFIG_PCIEASPM uint32_t def, data; -u16 devctl2, ltr; +u16 ltr; def = data =RREG32_SOC15 (PCIE ,0 , regPCIE_LC_CNTL); data &= ~PCIE_LC_CNTL__LC_L1_INACTIVITY_MASK ;
@@ -375,11 +367,8 @@ static void nbif_v6_3_1_program_aspm(strif (def != data)WREG32_SOC15 (NBIO ,0 , regRCC_STRAP0_RCC_BIF_STRAP5, data); -pcie_capability_read_word (adev->pdev,PCI_EXP_DEVCTL2 , &devctl2); - data = def = devctl2; - data &= ~PCI_EXP_DEVCTL2_LTR_EN ; -if (def != data) -pcie_capability_set_word (adev->pdev,PCI_EXP_DEVCTL2 , (u16 )data); +pcie_capability_clear_word (adev->pdev,PCI_EXP_DEVCTL2 , +PCI_EXP_DEVCTL2_LTR_EN ); ltr =pci_find_ext_capability (adev->pdev,PCI_EXT_CAP_ID_LTR );
@@ -387,15 +376,13 @@ static void nbif_v6_3_1_program_aspm(strpci_write_config_dword (adev->pdev, ltr +PCI_LTR_MAX_SNOOP_LAT ,0x10011001 ); } -#if 0 -/* regPSWUSP0_PCIE_LC_CNTL2 should be replace by PCIE_LC_CNTL2 or someone else ? */ - def = data =RREG32_SOC15 (NBIO ,0 , regPSWUSP0_PCIE_LC_CNTL2); - data |=PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK | -PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK ; - data &= ~PSWUSP0_PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK ; + def = data =RREG32_SOC15 (PCIE ,0 , regPCIE_LC_CNTL2); + data |=PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK | +PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK ; + data &= ~PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK ;if (def != data) -WREG32_SOC15 (NBIO ,0 , regPSWUSP0_PCIE_LC_CNTL2, data); -#endif +WREG32_SOC15 (PCIE ,0 , regPCIE_LC_CNTL2, data); + def = data =RREG32_SOC15 (PCIE ,0 , regPCIE_LC_CNTL4); data |=PCIE_LC_CNTL4__LC_L1_POWERDOWN_MASK ;if (def != data)
@@ -406,7 +393,12 @@ static void nbif_v6_3_1_program_aspm(strif (def != data)WREG32_SOC15 (PCIE ,0 , regPCIE_LC_RXRECOVER_RXSTANDBY_CNTL, data); -nbif_v6_3_1_program_ltr (adev); +/* +* Do not enable endpoint LTR unless the Root Complex and every +* upstream switch support it. +*/ +if (adev->pdev->ltr_path) +nbif_v6_3_1_program_ltr (adev); def = data =RREG32_SOC15 (NBIO ,0 , regRCC_STRAP0_RCC_BIF_STRAP3); data |=0x5DE0 <<RCC_STRAP0_RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT ;
Greg Kroah-Hartman
maintainerPATCH 95/217 drm/amdgpu: check ASPM on the dGPU host link
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 2a9c5154a5650c09ad44ff5e1dff74754e15a3c6 upstream.
dGPUs with an internal PCIe switch expose graphics functions below the switch downstream port. The automatic ASPM check uses the display endpoint and evaluates the internal link instead of the host link.
Use the switch upstream port for the check and report the selected link.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 50 ++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +49 -1
@@ -1928,6 +1928,31 @@ static bool amdgpu_device_aspm_support_q#endif } +/* +* Some dGPUs expose their display endpoint below an internal PCIe switch. +* Use the switch upstream port to query the host-facing link. +*/ +static struct pci_dev *amdgpu_device_get_aspm_pdev (struct amdgpu_device *adev) +{ +struct pci_dev *swds, *swus; + + swds =pci_upstream_bridge (adev->pdev); +if (!swds || + (swds->vendor !=PCI_VENDOR_ID_ATI && + swds->vendor !=PCI_VENDOR_ID_AMD ) || +pci_pcie_type (swds) !=PCI_EXP_TYPE_DOWNSTREAM ) +return adev->pdev; + + swus =pci_upstream_bridge (swds); +if (!swus || + (swus->vendor !=PCI_VENDOR_ID_ATI && + swus->vendor !=PCI_VENDOR_ID_AMD ) || +pci_pcie_type (swus) !=PCI_EXP_TYPE_UPSTREAM ) +return adev->pdev; + +return swus; +} +/** * amdgpu_device_should_use_aspm - check if the device should program ASPM *
@@ -1940,6 +1965,9 @@ static bool amdgpu_device_aspm_support_q*/ bool amdgpu_device_should_use_aspm (struct amdgpu_device *adev) { +struct pci_dev *aspm_pdev, *parent; +bool enabled; +switch (amdgpu_aspm) {case -1 :break ;
@@ -1954,7 +1982,27 @@ bool amdgpu_device_should_use_aspm(strucreturn false;if (amdgpu_device_aspm_support_quirk (adev))return false; -return pcie_aspm_enabled (adev->pdev); + +/* +* pcie_aspm_enabled() checks the link between its argument and +* the immediate upstream bridge. Use SWUS for dGPUs with an +* internal switch so that this is the host-facing link. +*/ + aspm_pdev =amdgpu_device_get_aspm_pdev (adev); + parent =pci_upstream_bridge (aspm_pdev); +if (!parent) { +dev_dbg (adev->dev,"ASPM: no upstream PCIe link for %s\n" , +pci_name (aspm_pdev)); +return false; + } + + enabled =pcie_aspm_enabled (aspm_pdev); +/* Report the exact link used for the automatic ASPM decision. */ +dev_dbg (adev->dev,"ASPM: link %s <-> %s is %s\n" , +pci_name (parent),pci_name (aspm_pdev), + enabled ?"enabled" :"disabled" ); + +return enabled; }/* if we get transitioned to only one device, take VGA back */
Greg Kroah-Hartman
maintainerPATCH 96/217 drm/amdgpu: validate GEM_CREATE domain combinations
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
commit 5e9d136ad74df4edec67e502ce267597064d8f86 upstream.
AMDGPU_GEM_CREATE checked domain bits against AMDGPU_GEM_DOMAIN_MASK, but did not validate domain combinations. Userspace could combine CPU|GTT|VRAM with DOORBELL, GDS, GWS, or OA, making amdgpu_bo_placement_from_domain() exceed AMDGPU_BO_MAX_PLACEMENTS and hit BUG_ON().
Allow combinations only within CPU/GTT/VRAM, and require non-CPU/GTT/ VRAM domains to be specified one at a time. Return -EINVAL for invalid combinations in amdgpu_gem_create_ioctl().
v2: Rename helper from amdgpu_gem_domain_valid() to
amdgpu_gem_are_domains_valid() (Christian)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +21 -0
@@ -385,6 +385,25 @@ const struct drm_gem_object_funcs amdgpu .vm_ops = &amdgpu_gem_vm_ops, }; +static bool amdgpu_gem_are_domains_valid (u32 domains) +{ +u32 normal =AMDGPU_GEM_DOMAIN_CPU | +AMDGPU_GEM_DOMAIN_GTT | +AMDGPU_GEM_DOMAIN_VRAM ; +/* Treat all non CPU/GTT/VRAM domains as special domains. */ +u32 special =AMDGPU_GEM_DOMAIN_MASK & ~normal; +u32 normal_mask = domains & normal; +u32 special_mask = domains & special; + +if (!special_mask) +return true; + +if (normal_mask) +return false; + +return !(special_mask & (special_mask -1 )); +} +/* * GEM ioctls. */
@@ -409,6 +428,8 @@ int amdgpu_gem_create_ioctl(struct drm_d/* reject invalid gem domains */ if (args->in.domains & ~AMDGPU_GEM_DOMAIN_MASK )return -EINVAL ; +if (!amdgpu_gem_are_domains_valid (args->in.domains)) +return -EINVAL ;if (!amdgpu_is_tmz (adev) && (flags &AMDGPU_GEM_CREATE_ENCRYPTED )) {DRM_NOTE_ONCE ("Cannot allocate secure buffer since TMZ is disabled\n" );
Greg Kroah-Hartman
maintainerPATCH 97/217 drm/amdgpu: Reject UVD message with dimensions above 4096
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit 8c9aebcdd9f46f7a14b98d6ab18574b7a48fbb08 upstream.
Fixes potential overflow in DPB size calculations.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +2 -2
@@ -654,8 +654,8 @@ static int amdgpu_uvd_cs_msg_decode(struunsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned int min_ctx_size = ~0 ; -/* Reject invalid dimensions to prevent division by zero */ -if (width <16 || height <16 ) { +/* Reject invalid dimensions */ +if (width <16 || height <16 || width >4096 || height >4096 ) {dev_WARN_ONCE (adev->dev,1 ,"Invalid UVD decoding dimensions (%dx%d)!\n" , width, height);
Greg Kroah-Hartman
maintainerPATCH 98/217 drm/amdgpu: Implement insert_end for VCE 3
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit d5ab4c6a64efef2d143a96df5357f59703cd703d upstream.
After a recent change VCE now hangs when VCE_CMD_END is emitted after a pipeline sync without VM flush.
Implement insert_end to correctly insert only one VCE_CMD_END per job.
--- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +22 -4
@@ -870,6 +870,23 @@ static void vce_v3_0_ring_emit_ib(structamdgpu_ring_write (ring, ib->length_dw); } +static void vce_v3_0_ring_emit_fence (struct amdgpu_ring *ring,u64 addr, +u64 seq,unsigned flags) +{ +WARN_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); + +amdgpu_ring_write (ring,VCE_CMD_FENCE ); +amdgpu_ring_write (ring, addr); +amdgpu_ring_write (ring,upper_32_bits (addr)); +amdgpu_ring_write (ring, seq); +amdgpu_ring_write (ring,VCE_CMD_TRAP ); +} + +static void vce_v3_0_ring_insert_end (struct amdgpu_ring *ring) +{ +amdgpu_ring_write (ring,VCE_CMD_END ); +} +static void vce_v3_0_emit_vm_flush (struct amdgpu_ring *ring,unsigned int vmid,uint64_t pd_addr) {
@@ -879,7 +896,6 @@ static void vce_v3_0_emit_vm_flush(strucamdgpu_ring_write (ring,VCE_CMD_FLUSH_TLB );amdgpu_ring_write (ring, vmid); -amdgpu_ring_write (ring,VCE_CMD_END ); }static void vce_v3_0_emit_pipeline_sync (struct amdgpu_ring *ring)
@@ -948,17 +964,19 @@ static const struct amdgpu_ring_funcs vc .set_wptr = vce_v3_0_ring_set_wptr, .patch_cs_in_place = amdgpu_vce_ring_parse_cs_vm, .emit_frame_size = -6 +/* vce_v3_0_emit_vm_flush */ +5 +/* vce_v3_0_emit_vm_flush */ 4 +/* vce_v3_0_emit_pipeline_sync */ - 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ +5 +5 +/* vce_v3_0_ring_emit_fence x2 vm fence */ + 1, /* vce_v3_0_ring_insert_end */ .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ .emit_ib = vce_v3_0_ring_emit_ib, .emit_vm_flush = vce_v3_0_emit_vm_flush, .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, - .emit_fence = amdgpu_vce_ring_emit_fence, + .emit_fence = vce_v3_0_ring_emit_fence, .test_ring = amdgpu_vce_ring_test_ring, .test_ib = amdgpu_vce_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .insert_end = vce_v3_0_ring_insert_end, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_vce_ring_begin_use, .end_use = amdgpu_vce_ring_end_use,
Greg Kroah-Hartman
maintainerPATCH 99/217 drm/amdgpu: Fix UVD min buffer sizes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit 18727670b44753865b81c56a9338c0d7bd102c54 upstream.
Use correct size for message buffer = sizeof(struct ruvd_msg). Add ITSCALING_TABLE_BUFFER size.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +7 -5
@@ -974,15 +974,16 @@ static int amdgpu_uvd_cs_pass2(struct am ctx->buf_sizes[cmd]);return -EINVAL ; } + }else if (cmd ==0x204 || cmd ==0x206 ) { +unsigned int min_size = ctx->buf_sizes[cmd ==0x204 ?5 :4 ]; - }else if (cmd ==0x206 ) { -if ((end - start) < ctx->buf_sizes[4 ]) { +if ((end - start) < min_size) {DRM_ERROR ("buffer (%d) to small (%d / %d)!\n" , cmd, (unsigned int )(end - start), - ctx->buf_sizes[4 ]); + min_size);return -EINVAL ; } - }else if ((cmd !=0x100 ) && (cmd !=0x204 )) { + }else if ((cmd !=0x100 )) {DRM_ERROR ("invalid UVD command %X!\n" , cmd);return -EINVAL ; }
@@ -1112,11 +1113,12 @@ int amdgpu_uvd_ring_parse_cs(struct amdg {struct amdgpu_uvd_cs_ctx ctx = {};unsigned int buf_sizes[] = { - [0x00000000 ] =2048 , + [0x00000000 ] =3556 , [0x00000001 ] =0xFFFFFFFF , [0x00000002 ] =0xFFFFFFFF , [0x00000003 ] =2048 , [0x00000004 ] =0xFFFFFFFF , + [0x00000005 ] =992 , };int r;
Greg Kroah-Hartman
maintainerPATCH 100/217 drm/amdgpu: Fix UVD dpb min size calculation for H264
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit 21a8084cd76223a13493237e04d45f5226d7cee6 upstream.
This should use actual number of references from the decode message, instead of maximum derived from level.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 62 ++------------------------------ 1 file changed, 4 insertions(+), 58 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +4 -58
@@ -645,11 +645,9 @@ static int amdgpu_uvd_cs_msg_decode(struunsigned int height = msg[7 ];unsigned int dpb_size = msg[9 ];unsigned int pitch = msg[28 ]; -unsigned int level = msg[57 ];unsigned int width_in_mb = width /16 ;unsigned int height_in_mb =ALIGN (height /16 ,2 ); -unsigned int fs_in_mb = width_in_mb * height_in_mb;unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned int min_ctx_size = ~0 ;
@@ -668,35 +666,9 @@ static int amdgpu_uvd_cs_msg_decode(struswitch (stream_type) {case 0 :/* H264 */ -switch (level) { -case 30 : - num_dpb_buffer =8100 / fs_in_mb; -break ; -case 31 : - num_dpb_buffer =18000 / fs_in_mb; -break ; -case 32 : - num_dpb_buffer =20480 / fs_in_mb; -break ; -case 41 : - num_dpb_buffer =32768 / fs_in_mb; -break ; -case 42 : - num_dpb_buffer =34816 / fs_in_mb; -break ; -case 50 : - num_dpb_buffer =110400 / fs_in_mb; -break ; -case 51 : - num_dpb_buffer =184320 / fs_in_mb; -break ; -default : - num_dpb_buffer =184320 / fs_in_mb; -break ; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61 ] >>16 ) &0xff ) +1 ;if (num_dpb_buffer >17 ) - num_dpb_buffer =17 ; +return -EINVAL ;/* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer;
@@ -746,35 +718,9 @@ static int amdgpu_uvd_cs_msg_decode(strubreak ;case 7 :/* H264 Perf */ -switch (level) { -case 30 : - num_dpb_buffer =8100 / fs_in_mb; -break ; -case 31 : - num_dpb_buffer =18000 / fs_in_mb; -break ; -case 32 : - num_dpb_buffer =20480 / fs_in_mb; -break ; -case 41 : - num_dpb_buffer =32768 / fs_in_mb; -break ; -case 42 : - num_dpb_buffer =34816 / fs_in_mb; -break ; -case 50 : - num_dpb_buffer =110400 / fs_in_mb; -break ; -case 51 : - num_dpb_buffer =184320 / fs_in_mb; -break ; -default : - num_dpb_buffer =184320 / fs_in_mb; -break ; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61 ] >>16 ) &0xff ) +1 ;if (num_dpb_buffer >17 ) - num_dpb_buffer =17 ; +return -EINVAL ;/* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer;
Greg Kroah-Hartman
maintainerPATCH 101/217 drm/amdgpu: Fix UVD decode image min size calculation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
commit b8bb9ba3f101a1b0011f785a577a4a0a38371174 upstream.
This needs to use pitch instead of width. Also reject pitch over 4096 to avoid overflow.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +2 -2
@@ -761,7 +761,7 @@ static int amdgpu_uvd_cs_msg_decode(strureturn -EINVAL ; } -if (width > pitch) { +if (width > pitch || pitch >4096 ) {DRM_ERROR ("Invalid UVD decoding target pitch!\n" );return -EINVAL ; }
@@ -773,7 +773,7 @@ static int amdgpu_uvd_cs_msg_decode(stru } buf_sizes[0x1 ] = dpb_size; - buf_sizes[0x2 ] = image_size; + buf_sizes[0x2 ] = (pitch * height) *3 /2 ; buf_sizes[0x4 ] = min_ctx_size;/* store image width to adjust nb memory pstate */ adev->uvd.decode_image_width = width;
Greg Kroah-Hartman
maintainerPATCH 102/217 drm/amdgpu: disallow multiple FENCE chunks in one submit
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit 931cd1d1baeae68e8eb2c23bc1f3d8934dca6241 upstream.
amdgpu_cs_pass1() dispatches on chunk_id once per chunk without rejecting repeated ids. p->uf_bo is a single-slot field, so a submission carrying two AMDGPU_CHUNK_ID_FENCE chunks runs amdgpu_cs_p1_user_fence() twice, and the second run overwrites p->uf_bo with a freshly referenced BO without dropping the reference taken by the first.
amdgpu_cs_parser_fini() only unrefs the final p->uf_bo, so every FENCE chunk but the last leaks a BO reference. The leaked BO outlives handle close and process exit.
Reject duplicate FENCE chunks the same way commit fec5f8e8c6bc ("drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit") did for p->bo_list.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +4 -0
@@ -261,6 +261,10 @@ static int amdgpu_cs_pass1(struct amdgpuif (size <sizeof (struct drm_amdgpu_cs_chunk_fence )) goto free_partial_kdata; +/* Only a single user fence is allowed to simplify handling. */ +if (p->uf_bo) + goto free_partial_kdata; + ret =amdgpu_cs_p1_user_fence (p, p->chunks[i].kdata, &uf_offset);if (ret)
Greg Kroah-Hartman
maintainerPATCH 103/217 xfs: propagate errors from xfs_rtginode_load
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
commit b7e53968cb8882c2d276429ea8550848a4940874 upstream.
xfs_rtginode_ensure() treats every xfs_rtginode_load() error other than -ENOENT as success. This can leave the realtime group inode unset after an I/O, allocation, or corruption error. Growfs then continues as though the inode had been loaded.
Only -ENOENT means that the inode needs to be created. Return all other errors to the growfs caller.
--- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_rtalloc.c +1 -1
@@ -734,7 +734,7 @@ xfs_rtginode_ensure(xfs_trans_cancel (tp);if (error != -ENOENT ) -return 0 ; +return error;return xfs_rtginode_create (rtg, type, true); }
Greg Kroah-Hartman
maintainerPATCH 104/217 xfs: fix off-by-one in rtrefcount btree root level validation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
commit cc3144da377de5fb422d44a2311f978623f7c900 upstream.
xfs_rtrefcountbt_compute_maxlevels() sets
mp->m_rtrefc_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
where the trailing "+ 1" already accounts for the inode-root level, so the deepest valid on-disk root level is m_rtrefc_maxlevels - 1 and a cursor must satisfy bc_nlevels <= bc_maxlevels (= m_rtrefc_maxlevels).
The two on-disk validation paths, xfs_rtrefcountbt_verify() and xfs_iformat_rtrefcount(), check the root level with ">" instead of ">=", so a crafted rtreflink (metadir + realtime + reflink) image whose /rtgroups/N.refcount inode has bb_level == m_rtrefc_maxlevels is accepted on mount. xfs_rtrefcountbt_init_cursor() then sets bc_nlevels = bb_level + 1, exceeding bc_maxlevels by one. Since the xfs_rtrefcountbt_cur slab object is sized for exactly bc_maxlevels entries, the first btree op on such a cursor indexes bc_levels[m_rtrefc_maxlevels] past the end of the object. This is reached by the first rtrefcount cursor built after mount, via log/CoW recovery (xfs_reflink_recover_cow() during xfs_mountfs()) or an FS_IOC_GETFSMAP over the realtime device.
Reject a root level equal to m_rtrefc_maxlevels, matching the ">=" form already used by the sibling data-device refcount/rmap verifiers and the in-memory rtrmap verifier.
BUG: KASAN: slab-out-of-bounds in xfs_btree_lookup (fs/xfs/libxfs/xfs_btree.c:2101) Write of size 2 at addr ffff888018391658 by task exploit/144 xfs_btree_lookup (fs/xfs/libxfs/xfs_btree.c:2101) xfs_btree_query_range (fs/xfs/libxfs/xfs_btree.c:5308) xfs_refcount_recover_cow_leftovers (fs/xfs/libxfs/xfs_refcount.c:2113) xfs_reflink_recover_cow (fs/xfs/xfs_reflink.c:1085) xlog_recover_finish (fs/xfs/xfs_log_recover.c:3551) xfs_mountfs (fs/xfs/xfs_mount.c:1158) xfs_fs_fill_super (fs/xfs/xfs_super.c:1940) get_tree_bdev_flags (fs/super.c:1634) vfs_get_tree (fs/super.c:1694) path_mount (fs/namespace.c:4161) __x64_sys_mount (fs/namespace.c:4367) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) The buggy address belongs to the cache xfs_rtrefcountbt_cur of size 216 The buggy address is located 8 bytes to the right of allocated 216-byte region [ffff888018391578, ffff888018391650) Kernel panic - not syncing: Fatal exception
--- fs/xfs/libxfs/xfs_rtrefcount_btree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_rtrefcount_btree.c +2 -2
@@ -201,7 +201,7 @@ xfs_rtrefcountbt_verify(if (fa)return fa; level =be16_to_cpu (block->bb_level); -if (level > mp->m_rtrefc_maxlevels) +if (level >= mp->m_rtrefc_maxlevels)return __this_address;return xfs_btree_fsblock_verify (bp, mp->m_rtrefc_mxr[level !=0 ]);
@@ -651,7 +651,7 @@ xfs_iformat_rtrefcount( numrecs =be16_to_cpu (dfp->bb_numrecs); level =be16_to_cpu (dfp->bb_level); -if (level > mp->m_rtrefc_maxlevels || +if (level >= mp->m_rtrefc_maxlevels ||xfs_rtrefcount_droot_space_calc (level, numrecs) > dsize) {xfs_inode_mark_sick (ip,XFS_SICK_INO_CORE );return -EFSCORRUPTED ;
Greg Kroah-Hartman
maintainerPATCH 105/217 xfs: bounds-check buffer log items dirty bitmap
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit 813f8136a2ce1fee266d02a7df73db6e8a541604 upstream.
xlog_recover_do_reg_buffer() replays each dirty region described by a buffer log item's bitmap into the buffer read for that item:
memcpy(xfs_buf_offset(bp, (uint)bit << XFS_BLF_SHIFT), item->ri_buf[i].iov_base, nbits << XFS_BLF_SHIFT);
The destination offset (bit/nbits, from the logged dirty bitmap) and the buffer size (from the logged blf_len) are both attacker-controlled and otherwise unrelated, yet the only thing bounding the copy is an ASSERT(), which compiles away on production kernels. A crafted image logging a small blf_len together with a bitmap bit past the end of that buffer drives the memcpy() past the buffer's allocation, corrupting adjacent kernel heap during mount-time log recovery. This is reachable by anyone who can get a crafted image mounted -- the malicious-filesystem threat model XFS already guards against elsewhere.
Turn the ASSERT() into a real XFS_IS_CORRUPT() check that aborts recovery of the buffer with -EFSCORRUPTED, consistent with the validate-and-fail idiom already used in xlog_recover_do_inode_buffer() and xfs_dquot_item_recover.c. xlog_recover_do_reg_buffer() therefore becomes STATIC int and its three callers propagate the error.
Found and confirmed with KASAN on a CONFIG_XFS_DEBUG=n build: the crafted image trips a slab-out-of-bounds write before this change and fails recovery cleanly with -EFSCORRUPTED after it.
--- fs/xfs/xfs_buf_item_recover.c | 57 ++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-)
fs/xfs/xfs_buf_item_recover.c +41 -16
@@ -461,7 +461,7 @@ xlog_recover_validate_buf_type(* given buffer. The bitmap in the buf log format structure indicates * where to place the logged data. */ -STATIC void +STATIC int xlog_recover_do_reg_buffer( struct xfs_mount *mp, struct xlog_recover_item *item,
@@ -489,8 +489,24 @@ xlog_recover_do_reg_buffer(ASSERT (nbits >0 );ASSERT (item->ri_buf[i].iov_base !=NULL );ASSERT (item->ri_buf[i].iov_len %XFS_BLF_CHUNK ==0 ); -ASSERT (BBTOB (bp->b_length) >= - ((uint )bit <<XFS_BLF_SHIFT ) + (nbits <<XFS_BLF_SHIFT )); +/* +* The bitmap is only trustworthy to the extent that it +* describes a region that actually fits inside the buffer we +* read in based on the (attacker-controlled) blf_len. Do not +* rely on an ASSERT() for this -- it compiles away entirely on +* non-DEBUG kernels, which is exactly where this matters, so +* validate it for real and abort recovery of this buffer rather +* than copying past the end of it. +*/ +if (XFS_IS_CORRUPT (mp,BBTOB (bp->b_length) < + ((uint )bit <<XFS_BLF_SHIFT ) + + (nbits <<XFS_BLF_SHIFT ))) { +xfs_alert (mp, +"Bad buffer log item dirty bitmap (bit %d, nbits %d) for %d-byte buffer at daddr 0x%llx." , + bit, nbits,BBTOB (bp->b_length), +xfs_buf_daddr (bp)); +return -EFSCORRUPTED ; + }/* * The dirty regions logged in the buffer, even though
@@ -544,6 +560,7 @@ xlog_recover_do_reg_buffer(ASSERT (i == item->ri_total);xlog_recover_validate_buf_type (mp, bp, buf_f, current_lsn); +return 0 ; }/*
@@ -552,10 +569,10 @@ xlog_recover_do_reg_buffer(* (ie. USR or GRP), then just toss this buffer away; don't recover it. * Else, treat it as a regular buffer and do recovery. * -* Return false if the buffer was tossed and true if we recovered the buffer to -* indicate to the caller if the buffer needs writing. +* Return 0 if the buffer was not recovered (tossed), 1 if it was recovered and +* needs writing, or a negative errno if recovery of the buffer failed. */ -STATIC bool +STATIC int xlog_recover_do_dquot_buffer( struct xfs_mount *mp, struct xlog *log,
@@ -564,6 +581,7 @@ xlog_recover_do_dquot_buffer( struct xfs_buf_log_format *buf_f) {uint type; +int error;trace_xfs_log_recover_buf_dquot_buf (log, buf_f);
@@ -571,7 +589,7 @@ xlog_recover_do_dquot_buffer(* Filesystems are required to send in quota flags at mount time. */ if (!mp->m_qflags) -return false; +return 0 ; type =0 ;if (buf_f->blf_flags &XFS_BLF_UDQUOT_BUF )
@@ -584,10 +602,12 @@ xlog_recover_do_dquot_buffer(* This type of quotas was turned off, so ignore this buffer */ if (log->l_quotaoffs_flag & type) -return false; +return 0 ; -xlog_recover_do_reg_buffer (mp, item, bp, buf_f,NULLCOMMITLSN ); -return true; + error =xlog_recover_do_reg_buffer (mp, item, bp, buf_f,NULLCOMMITLSN ); +if (error) +return error; +return 1 ; }/*
@@ -724,7 +744,9 @@ xlog_recover_do_primary_sb_buffer(xfs_rgnumber_t orig_rgcount = mp->m_sb.sb_rgcount;int error; -xlog_recover_do_reg_buffer (mp, item, bp, buf_f, current_lsn); + error =xlog_recover_do_reg_buffer (mp, item, bp, buf_f, current_lsn); +if (error) +return error;if (orig_agcount ==0 ) {xfs_alert (mp,"Trying to grow file system without AGs" );
@@ -1081,11 +1103,11 @@ xlog_recover_buf_commit_pass2( goto out_release; }else if (buf_f->blf_flags & (XFS_BLF_UDQUOT_BUF |XFS_BLF_PDQUOT_BUF |XFS_BLF_GDQUOT_BUF )) { -bool dirty; - - dirty =xlog_recover_do_dquot_buffer (mp, log, item, bp, buf_f); -if (!dirty) + error =xlog_recover_do_dquot_buffer (mp, log, item, bp, buf_f); +if (error <=0 ) goto out_release; +/* write dirty buffer */ + error =0 ; }else if ((xfs_blft_from_flags (buf_f) &XFS_BLFT_SB_BUF ) &&xfs_buf_daddr (bp) ==0 ) { error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
@@ -1105,7 +1127,10 @@ xlog_recover_buf_commit_pass2(xfs_buf_relse (rtsb_bp); } }else { -xlog_recover_do_reg_buffer (mp, item, bp, buf_f, current_lsn); + error =xlog_recover_do_reg_buffer (mp, item, bp, buf_f, + current_lsn); +if (error) + goto out_release; }/*
Greg Kroah-Hartman
maintainerPATCH 106/217 xfs: mark nonzero sb_gquotino as corrupt on metadir filesystems
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit b28d23c51635b646784a2a62c71ba99458c07d5e upstream.
On a metadir filesystem, the superblock gquotino field is always zero because we find the quota inodes through the metadata directory tree. A nonzero value is therefore a corruption (as pointed out by LOLLM) so mark the failure as such.
--- fs/xfs/scrub/agheader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/agheader.c +1 -1
@@ -266,7 +266,7 @@ xchk_superblock(xchk_block_set_corrupt (sc, bp);if (sb->sb_gquotino !=cpu_to_be64 (0 )) -xchk_block_set_preen (sc, bp); +xchk_block_set_corrupt (sc, bp); }else {if (sb->sb_uquotino !=cpu_to_be64 (mp->m_sb.sb_uquotino))xchk_block_set_preen (sc, bp);
Greg Kroah-Hartman
maintainerPATCH 107/217 xfs: clear zapped attr fork state when bmap repair finds no attr fork
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiang Ma <[email protected]>
commit 87b2a82e135ba81e49d82b59e3d72468cb66ea98 upstream.
xfstests xfs/377 can make xfs_scrub repeatedly check and repair the attr block map after inode repair zaps an attr fork.
When inode repair zaps an attr fork, it records XFS_SICK_INO_BMBTA_ZAPPED so that scrub/repair can revisit the attr fork block map. If the fork has been reset to an empty state and removed, BMBTA repair has no attr fork mappings to rebuild and can return success.
The post-repair scrub then runs with XREP_ALREADY_FIXED set, which means xchk_file_looks_zapped() deliberately ignores the stale zapped health bit and asks xchk_bmap() to check the current attr fork. For an absent attr fork, xchk_bmap() returns -ENOENT. Returning that error prevents xchk_bmap_attr() from marking XFS_SICK_INO_BMBTA_ZAPPED healthy, leaving the zapped health state behind even though there are no attr fork mappings left to check.
Treat -ENOENT during post-repair BMBTA revalidation as a clean result for the zapped attr fork: clear XFS_SICK_INO_BMBTA_ZAPPED and return success. Keep the existing -ENOENT behavior for ordinary scrubs of absent attr forks.
--- fs/xfs/scrub/bmap.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/xfs/scrub/bmap.c +5 -0
@@ -1170,6 +1170,11 @@ xchk_bmap_attr( } error =xchk_bmap (sc,XFS_ATTR_FORK ); +/* A repaired, empty attr fork no longer has mappings to check. */ +if (error == -ENOENT && (sc->flags &XREP_ALREADY_FIXED )) { +xchk_mark_healthy_if_clean (sc,XFS_SICK_INO_BMBTA_ZAPPED ); +return 0 ; + }if (error)return error;
Greg Kroah-Hartman
maintainerPATCH 108/217 xfs: check cowextsize in xrep_inode_cowextsize
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 270ffcd9b0a46254fbf3079d0e3341db7d7ec0e6 upstream.
LOLLM points out that the function that corrects cowextsize should check i_cowextsize, not i_extsize.
--- fs/xfs/scrub/inode_repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/inode_repair.c +1 -1
@@ -1956,7 +1956,7 @@ xrep_inode_cowextsize(/* Fix misaligned CoW extent size hints on a directory. */ if ((sc->ip->i_diflags &XFS_DIFLAG_RTINHERIT ) && (sc->ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) && - sc->ip->i_extsize % sc->mp->m_sb.sb_rextsize >0 ) { +xfs_extlen_to_rtxmod (sc->mp, sc->ip->i_cowextsize) >0 ) { sc->ip->i_cowextsize =0 ; sc->ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE ; }
Greg Kroah-Hartman
maintainerPATCH 109/217 xfs: fix transaction block reservation in xrep_rtbitmap
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 61606f8846a9da8ab7d2d36ff4617134c9d6df1b upstream.
LOLLM pointed out an inconsistency in the block reservation code in xrep_rtbitmap. The first is that the reservation computation is not consistent between the code that sets up the repair and the code that tries to avoid exceeding the transaction reservation once we know how big the rtbitmap really must be. As a result, the logic doesn't work.
In fixing that, a second problem emerges: if we do readjust, we ask for the entire reservation all over again. We really only need the delta, so ask only for that.
Fix all these problems by hoisting the computation to a trivial helper so that it gets used in both places.
--- fs/xfs/scrub/rtbitmap_repair.c | 46 ++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-)
fs/xfs/scrub/rtbitmap_repair.c +28 -18
@@ -36,6 +36,24 @@/* rt bitmap content repairs */ +/* +* Reserve enough blocks to write out a completely new bitmap file, plus twice +* as many blocks as we would need if we can only allocate one block per data +* fork mapping. This should cover the preallocation of the temporary file and +* exchanging the extent mappings. +* +* We cannot use xfs_exchmaps_estimate because we have not yet constructed the +* replacement bitmap and therefore do not know how many extents it will use. +* By the time we do, we will have a dirty transaction (which we cannot drop +* because we cannot drop the rtbitmap ILOCK) and cannot ask for more +* reservation. +*/ +static inline unsigned long long +xrep_rtbitmap_calc_blocks (struct xfs_mount *mp,unsigned long long blocks) +{ +return blocks + (xfs_bmbt_calc_size (mp, blocks) *2 ); +} +/* Set up to repair the realtime bitmap for this group. */ int xrep_setup_rtbitmap(
@@ -56,20 +74,7 @@ xrep_setup_rtbitmap(if (error)return error; -/* -* Reserve enough blocks to write out a completely new bitmap file, -* plus twice as many blocks as we would need if we can only allocate -* one block per data fork mapping. This should cover the -* preallocation of the temporary file and exchanging the extent -* mappings. -* -* We cannot use xfs_exchmaps_estimate because we have not yet -* constructed the replacement bitmap and therefore do not know how -* many extents it will use. By the time we do, we will have a dirty -* transaction (which we cannot drop because we cannot drop the -* rtbitmap ILOCK) and cannot ask for more reservation. -*/ - blocks +=xfs_bmbt_calc_size (mp, blocks) *2 ; + blocks =xrep_rtbitmap_calc_blocks (mp, mp->m_sb.sb_rbmblocks);if (blocks >UINT_MAX )return -EOPNOTSUPP ;
@@ -512,7 +517,7 @@ xrep_rtbitmap(struct xchk_rtbitmap *rtb = sc->buf;struct xfs_mount *mp = sc->mp;struct xfs_group *xg =rtg_group (sc->sr.rtg); -unsigned long long blocks =0 ; +unsigned long long blocks;unsigned int busy_gen;int error;
@@ -532,15 +537,20 @@ xrep_rtbitmap(* figure out if we need to adjust the block reservation in the * transaction. */ - blocks =xfs_bmbt_calc_size (mp, rtb->rbmblocks); + blocks =xrep_rtbitmap_calc_blocks (mp, rtb->rbmblocks);if (blocks >UINT_MAX )return -EOPNOTSUPP ;if (blocks > rtb->resblks) { - error =xfs_trans_reserve_more (sc->tp, blocks,0 ); +uint64_t delta = blocks - rtb->resblks; + +if (delta >UINT_MAX ) +return -EOPNOTSUPP ; + + error =xfs_trans_reserve_more (sc->tp, delta,0 );if (error)return error; - rtb->resblks += blocks; + rtb->resblks += delta; }/* Fix inode core and forks. */
Greg Kroah-Hartman
maintainerPATCH 110/217 xfs: zero i_nlink before repair puts inode on unlinked list
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 49933254ba8d421ed706cbe6ed0fbc264e572cab upstream.
LOLLM observes that we don't reset i_nlink if we encounter a file with no parent that isn't on the unlinked list. This causes unnecessary assertion trips on debugging kernels and an inconsistent file, so let's fix that.
--- fs/xfs/scrub/nlinks_repair.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/xfs/scrub/nlinks_repair.c +6 -1
@@ -232,9 +232,14 @@ xrep_nlinks_repair_inode(* unlinked list, put it on the unlinked list. */ if (total_links ==0 && !xfs_inode_on_unlinked_list (ip)) { +if (actual_nlink) +clear_nlink (VFS_I (ip)); error =xfs_iunlink (sc->tp, ip); -if (error) +if (error) { +if (actual_nlink) +set_nlink (VFS_I (ip), actual_nlink); goto out_trans; + } dirty = true; }
Greg Kroah-Hartman
maintainerPATCH 111/217 xfs: only check mergeability of bnobt records
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 97efed1091a50e4dbf31307015138b43a972d2e4 upstream.
In the cntbt (free space by block count) btree, records are not supposed to be in startblock order. Hence the mergeability check is pointless. Remove it, since it does nothing, as LOLLM points out.
--- fs/xfs/scrub/alloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/xfs/scrub/alloc.c +3 -2
@@ -136,7 +136,7 @@ xchk_allocbt_rec( const union xfs_btree_rec *rec) {struct xfs_alloc_rec_incore irec; -struct xchk_alloc *ca = bs->private; +struct xchk_alloc *ca = bs->private;xfs_alloc_btrec_to_irec (rec, &irec);if (xfs_alloc_check_irec (to_perag (bs->cur->bc_group), &irec) !=NULL ) {
@@ -144,7 +144,8 @@ xchk_allocbt_rec(return 0 ; } -xchk_allocbt_mergeable (bs, ca, &irec); +if (bs->sc->sm->sm_type ==XFS_SCRUB_TYPE_BNOBT ) +xchk_allocbt_mergeable (bs, ca, &irec);xchk_allocbt_xref (bs->sc, &irec);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 112/217 xfs: dont double-lock when deleting a self-referential directory
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 5fc643fb86599e29b38e7b2c2680b4b15bf8f772 upstream.
LOLLM notices that the dirtree scrubber can detect a directory that refers to itself. In this case, it's not correct for the directory tree repair code to try to iolock/ilock both sc->ip and dp, because they're the same inode. Fix this by detecting that corner case and handling it appropriately.
--- fs/xfs/scrub/dirtree_repair.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
fs/xfs/scrub/dirtree_repair.c +18 -4
@@ -349,6 +349,8 @@ xrep_dirtree_unlink_iolock(ASSERT (sc->ilock_flags &XFS_IOLOCK_EXCL ); +if (sc->ip == dp) +return 0 ;if (xfs_ilock_nowait (dp,XFS_IOLOCK_EXCL ))return 0 ;
@@ -400,8 +402,18 @@ xrep_dirtree_unlink(* directory code can handle a reservationless update. */ resblks =xfs_remove_space_res (mp, step->name_len); - error =xfs_trans_alloc_dir (dp, &M_RES (mp)->tr_remove, sc->ip, - &resblks, &sc->tp, &dontcare); +if (sc->ip == dp) { +again: + error =xfs_trans_alloc_inode (dp, &M_RES (mp)->tr_remove, + resblks,0 , false, &sc->tp); +if ((error == -ENOSPC || error == -EDQUOT ) && resblks >0 ) { + resblks =0 ; + goto again; + } + }else { + error =xfs_trans_alloc_dir (dp, &M_RES (mp)->tr_remove, sc->ip, + &resblks, &sc->tp, &dontcare); + }if (error) goto out_iolock;
@@ -489,9 +501,11 @@ out_trans_cancel:xchk_trans_cancel (sc); out_ilock:xfs_iunlock (sc->ip,XFS_ILOCK_EXCL ); -xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (dp != sc->ip) +xfs_iunlock (dp,XFS_ILOCK_EXCL ); out_iolock: -xfs_iunlock (dp,XFS_IOLOCK_EXCL ); +if (dp != sc->ip) +xfs_iunlock (dp,XFS_IOLOCK_EXCL );return error; }
Greg Kroah-Hartman
maintainerPATCH 113/217 xfs: set the prev pointer when reinserting an inode on the unlinked list
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit af146cb7ff8ff5c54162f35c238f3ff1d5ad110f upstream.
If we find a rogue free inode and decide to reinsert it into the unlinked list, we need to set the prev pointer to NULLAGINO so that the incore list gets updated.
--- fs/xfs/scrub/agheader_repair.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/xfs/scrub/agheader_repair.c +4 -0
@@ -1434,6 +1434,10 @@ xrep_iunlink_add_to_bucket(if (error)return error; + error =xrep_iunlink_store_prev (ragi, agino,NULLAGINO ); +if (error) +return error; +/* Remember the head inode's previous pointer. */ if (current_head !=NULLAGINO ) { error =xrep_iunlink_store_prev (ragi, current_head, agino);
Greg Kroah-Hartman
maintainerPATCH 114/217 xfs: pass runtime errors from xrep_iunlink_mark_ondisk_rec up to callers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 5644fab990fc72406dddc91cbb8304659d77f3f1 upstream.
LOLLM points out that the only error that xrep_iunlink_mark_ondisk_rec returns is ENOMEM, but we ignore that, and can end up writing a garbage AGI based on incomplete information. We shouldn't do that, though here we must be screen out EFSCORRUPTED/EFSBASDCRC because we haven't checked the inobt yet.
--- fs/xfs/scrub/agheader_repair.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/xfs/scrub/agheader_repair.c +12 -2
@@ -1302,7 +1302,7 @@ xrep_iunlink_mark_ondisk_rec(* iunlink_bmp. We haven't checked the inobt yet, so we don't error out if * the btree is corrupt. */ -STATIC void +STATIC intxrep_iunlink_mark_ondisk (struct xrep_agi *ragi) {
@@ -1314,6 +1314,14 @@ xrep_iunlink_mark_ondisk( cur =xfs_inobt_init_cursor (sc->sa.pag, sc->tp, agi_bp); error =xfs_btree_query_all (cur, xrep_iunlink_mark_ondisk_rec, ragi);xfs_btree_del_cursor (cur, error); + +/* +* Don't proceed if we couldn't set a bit in the bitmap. All other +* errors we ignore because we haven't actually checked the inobt yet. +*/ +if (error == -ENOMEM ) +return -ENOMEM ; +return 0 ; }/*
@@ -1505,7 +1513,9 @@ xrep_iunlink_rebuild_buckets(* If there are ondisk inodes that are unlinked and are not been loaded * into cache, record them in iunlink_bmp. */ -xrep_iunlink_mark_ondisk (ragi); + error =xrep_iunlink_mark_ondisk (ragi); +if (error) +return error;/* * Walk each iunlink bucket to (re)construct as much of the incore list
Greg Kroah-Hartman
maintainerPATCH 115/217 xfs: nlink scrub must take IOLOCK before determining ILOCK state
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit b1a296fc2241f724ef8f14da6a4efa800d444dac upstream.
In xchk_nlinks_ilock_dir, take the IOLOCK before accessing internal inode state to figure out if we need to take ILOCK shared or exclusive. That way we can't race with directory updates. LOLLM pointed out that the code was initially correct w.r.t. the IOLOCK, but then I broke it.
--- fs/xfs/scrub/nlinks.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/xfs/scrub/nlinks.c +7 -6
@@ -383,6 +383,12 @@ xchk_nlinks_ilock_dir(uint lock_mode =XFS_ILOCK_SHARED ;/* +* Take the IOLOCK so that other threads cannot start a directory +* update while we're scanning. +*/ +xfs_ilock (ip,XFS_IOLOCK_SHARED ); + +/* * We're going to scan the directory entries, so we must be ready to * pull the data fork mappings into memory if they aren't already. */
@@ -397,13 +403,8 @@ xchk_nlinks_ilock_dir( xfs_need_iread_extents(&ip->i_af)) lock_mode =XFS_ILOCK_EXCL ; -/* -* Take the IOLOCK so that other threads cannot start a directory -* update while we're scanning. -*/ - lock_mode |=XFS_IOLOCK_SHARED ;xfs_ilock (ip, lock_mode); -return lock_mode; +return lock_mode |XFS_IOLOCK_SHARED ; }/* Walk a directory to bump the observed link counts of the children. */
Greg Kroah-Hartman
maintainerPATCH 116/217 xfs: load next_agino from the correct xfarray in xrep_iunlink_relink_prev
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 6b9cd540138a06660a843a519facc147060acbef upstream.
LOLLM notices that xrep_iunlink_relink_prev has the comment "set the forward pointer..." but then loads the value from the xfarray that stores pointers to the previous inode in the unlinked list. That's wrong, so fix the variable access.
--- fs/xfs/scrub/agheader_repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/agheader_repair.c +1 -1
@@ -1626,7 +1626,7 @@ xrep_iunlink_relink_prev( want_rele = true;/* Set the forward pointer since this just came off disk. */ - error =xfarray_load (ragi->iunlink_prev, agino, &next_agino); + error =xfarray_load (ragi->iunlink_next, agino, &next_agino);if (error) goto out_rele;
Greg Kroah-Hartman
maintainerPATCH 117/217 xfs: fix ilock leak on error in xfs_dq_get_next_id
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
commit 63320a0f70f66f311f4bccff3af0719c2119f46c upstream.
xfs_dq_get_next_id() takes the quota inode ILOCK before calling xfs_iread_extents(). If xfs_iread_extents() fails, the function returns immediately without releasing the lock, leaking the quota inode ILOCK. This can leave the quota inode locked and cause subsequent quota operations to hang.
Fix this by jumping to a common unlock path on error instead of returning directly.
--- fs/xfs/xfs_dquot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/xfs/xfs_dquot.c +2 -1
@@ -778,7 +778,7 @@ xfs_dq_get_next_id( lock_flags =xfs_ilock_data_map_shared (quotip); error =xfs_iread_extents (NULL , quotip,XFS_DATA_FORK );if (error) -return error; + goto out_unlock;if (xfs_iext_lookup_extent (quotip, "ip->i_df, start, &cur, &got)) {/* contiguous chunk, bump startoff for the id calculation */
@@ -789,6 +789,7 @@ xfs_dq_get_next_id( error = -ENOENT ; } +out_unlock:xfs_iunlock (quotip, lock_flags);return error;
Greg Kroah-Hartman
maintainerPATCH 118/217 xfs: dont zap the attr fork on repair when there are queued pptr updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 5ee37132ea81abd36213b31a72140660c2aac54b upstream.
LOLLM noticed that xrep_xattr_rebuild_tree doesn't check for queued parent pointer updates when it decides that it's going to zap the attr fork. This is obviously incorrect, so fix that. We hold the IOLOCK and the ILOCK of sc->ip at that point in time, so we can't race with any /new/ operations.
--- fs/xfs/scrub/attr_repair.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/xfs/scrub/attr_repair.c +2 -1
@@ -1427,7 +1427,8 @@ xrep_xattr_rebuild_tree(* If we didn't find any attributes to salvage, repair the file by * zapping its attr fork. */ -if (rx->attrs_found ==0 ) { +if (rx->attrs_found ==0 && + (!xfs_has_parent (sc->mp) ||xfarray_length (rx->pptr_recs) ==0 )) {xfs_trans_ijoin (sc->tp, sc->ip,0 ); error =xrep_xattr_reset_fork (sc);if (error)
Greg Kroah-Hartman
maintainerPATCH 119/217 xfs: dont walk off the end of a null sc->sa.agi_bp in AGI repair
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 1e96a00e0d3a00be6e4f368b2f18e2d345f813ce upstream.
LOLLM noticed a longstanding bug where xrep_iunlink_walk_ondisk_bucket tries to walk ragi->sc->sa.agi_bp to rebuild the unlinked inode lists. Unfortunately, it's possible for agi_bp to be null if the buffer verifier fails, so we have to use ragi->agi_bp (which skips verifier checks) instead.
--- fs/xfs/scrub/agheader_repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/agheader_repair.c +1 -1
@@ -1081,7 +1081,7 @@ xrep_iunlink_walk_ondisk_bucket( unsigned int bucket) {struct xfs_scrub *sc = ragi->sc; -struct xfs_agi *agi = sc->sa.agi_bp->b_addr; +struct xfs_agi *agi = ragi->agi_bp->b_addr;xfs_agino_t prev_agino =NULLAGINO ;xfs_agino_t next_agino;int error =0 ;
Greg Kroah-Hartman
maintainerPATCH 120/217 xfs: fix allocated inodes that show up in the unlinked list
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 68ab37650ce5195b4f4f8466444a36a78207840c upstream.
If an allocated inode shows up in the unlinked list, we need to get it completely off the list. Set the corrected next/prev pointers such that the inode will not look like it should be on an unlinked list at all.
--- fs/xfs/scrub/agheader_repair.c | 63 ++++++++++++++++++++++++++++++++++++----- fs/xfs/scrub/trace.h | 1 2 files changed, 57 insertions(+), 7 deletions(-)
fs/xfs/scrub/agheader_repair.c +56 -7
@@ -980,6 +980,13 @@ err: }/* +* Magic value that means "not unlinked" because xfarrays don't support storing +* totally zeroed elements. There can't be a cluster that starts in daddr 0 so +* there can't be an inode #1 either. +*/ +#define LINKED_AGINO (0x1) + +/* * Record a forwards unlinked chain pointer from agino -> next_agino in our * staging information. */
@@ -1355,6 +1362,35 @@ xrep_iunlink_resolve_bucket(break ; } +if (VFS_I (ip)->i_nlink !=0 ) { +/* +* Inode is linked somewhere! Blow out both unlinked +* list pointers, advance the list, and pretend we +* didn't see this inode. Clear it from iunlink_bmp +* because it's linked. +*/ +trace_xrep_iunlink_resolve_allocated (sc->sa.pag, + bucket, prev_agino, next_agino); + + error =xrep_iunlink_store_next (ragi, next_agino, +NULLAGINO ); +if (error) +return error; + + error =xrep_iunlink_store_prev (ragi, next_agino, +LINKED_AGINO ); +if (error) +return error; + + error =xagino_bitmap_clear (&ragi->iunlink_bmp, + next_agino,1 ); +if (error) +return error; + + next_agino = ip->i_next_unlinked; +continue ; + } +if (next_agino %XFS_AGI_UNLINKED_BUCKETS != bucket) {/* * Inode is in the wrong bucket. Advance the list,
@@ -1537,6 +1573,24 @@ xrep_iunlink_rebuild_buckets( xrep_iunlink_add_lost_inodes, ragi); } +static inline void +set_inode_prev_unlinked ( +struct xfs_inode *ip, +xfs_agino_t prev_agino) +{ +/* +* Magic value that means "not unlinked" because xfarrays don't support +* storing totally zeroed elements. +*/ +if (prev_agino ==LINKED_AGINO ) + prev_agino =0 ; + +if (ip->i_prev_unlinked != prev_agino) { +trace_xrep_iunlink_relink_prev (ip, prev_agino); + ip->i_prev_unlinked = prev_agino; + } +} +/* Update i_next_iunlinked for the inode @agino. */ STATIC int xrep_iunlink_relink_next(
@@ -1570,8 +1624,7 @@ xrep_iunlink_relink_next(if (error) goto out_rele; -trace_xrep_iunlink_relink_prev (ip, prev_agino); - ip->i_prev_unlinked = prev_agino; +set_inode_prev_unlinked (ip, prev_agino); }/* Update the forward pointer. */
@@ -1638,11 +1691,7 @@ xrep_iunlink_relink_prev( ip->i_next_unlinked = next_agino; } -/* Update the backward pointer. */ -if (ip->i_prev_unlinked != prev_agino) { -trace_xrep_iunlink_relink_prev (ip, prev_agino); - ip->i_prev_unlinked = prev_agino; - } +set_inode_prev_unlinked (ip, prev_agino); out_rele:/*
fs/xfs/scrub/trace.h +1 -0
@@ -3583,6 +3583,7 @@ DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrepDEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_wronglist);DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_nolist);DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_ok); +DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_allocated); TRACE_EVENT(xrep_iunlink_relink_next, TP_PROTO(struct xfs_inode *ip, xfs_agino_t next_agino),
Greg Kroah-Hartman
maintainerPATCH 121/217 xfs: fix another iunlink infinite loop bug in online fsck
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 6d67c6b99f1fc07c64b97fcbc974c6f1ada7f622 upstream.
xrep_iunlink_resolve_bucket is supposed to reconstruct as much of the incore prev and next unlinked list pointers based on what it finds on disk and in memory before we move on to relinking the truly lost inodes back into the unlinked list. However, it's still vulnerable to infinite loops that come in via the next_unlinked pointers.
Fix this problem by remembering which inodes we've already seen and checking new agino pointers against that. If a bit is already set, either this is a loop or the inode has nonzero link count. We'll deal with the second case in a subsequent patch.
--- fs/xfs/scrub/agheader_repair.c | 37 ++++++++++++++++++++++++++++--------- fs/xfs/scrub/trace.h | 1 + 2 files changed, 29 insertions(+), 9 deletions(-)
fs/xfs/scrub/agheader_repair.c +28 -9
@@ -1341,15 +1341,32 @@ xrep_iunlink_resolve_bucket( struct xrep_agi *ragi, unsigned int bucket) { +struct xagino_bitmap seen;struct xfs_scrub *sc = ragi->sc;struct xfs_inode *ip;xfs_agino_t prev_agino =NULLAGINO ;xfs_agino_t next_agino = ragi->iunlink_heads[bucket];int error =0 ; +xagino_bitmap_init (&seen); +while (next_agino !=NULLAGINO ) { +unsigned int len =1 ; +if (xchk_should_terminate (ragi->sc, &error)) -return error; + goto out_bitmap; + +/* Inode already seen? We're stuck in a loop */ +if (xagino_bitmap_test (&seen, next_agino, &len)) { +trace_xrep_iunlink_resolve_infinite_loop (sc->sa.pag, + bucket, prev_agino, next_agino); + next_agino =NULLAGINO ; +break ; + } + + error =xagino_bitmap_set (&seen, next_agino,1 ); +if (error) + goto out_bitmap;/* Find the next inode in the chain. */ ip =xfs_iunlink_lookup (sc->sa.pag, next_agino);
@@ -1375,17 +1392,17 @@ xrep_iunlink_resolve_bucket( error =xrep_iunlink_store_next (ragi, next_agino,NULLAGINO );if (error) -return error; + goto out_bitmap; error =xrep_iunlink_store_prev (ragi, next_agino,LINKED_AGINO );if (error) -return error; + goto out_bitmap; error =xagino_bitmap_clear (&ragi->iunlink_bmp, next_agino,1 );if (error) -return error; + goto out_bitmap; next_agino = ip->i_next_unlinked;continue ;
@@ -1426,20 +1443,20 @@ xrep_iunlink_resolve_bucket(*/ error =xagino_bitmap_clear (&ragi->iunlink_bmp, next_agino,1 );if (error) -return error; + goto out_bitmap;/* Remember the previous inode's next pointer. */ if (prev_agino !=NULLAGINO ) { error =xrep_iunlink_store_next (ragi, prev_agino, next_agino);if (error) -return error; + goto out_bitmap; }/* Remember this inode's previous pointer. */ error =xrep_iunlink_store_prev (ragi, next_agino, prev_agino);if (error) -return error; + goto out_bitmap;/* Advance the list and remember this inode. */ prev_agino = next_agino;
@@ -1450,10 +1467,12 @@ xrep_iunlink_resolve_bucket(if (prev_agino !=NULLAGINO ) { error =xrep_iunlink_store_next (ragi, prev_agino, next_agino);if (error) -return error; + goto out_bitmap; } -return 0 ; +out_bitmap: +xagino_bitmap_destroy (&seen); +return error; }/* Reinsert this unlinked inode into the head of the staged bucket list. */
fs/xfs/scrub/trace.h +1 -0
@@ -3579,6 +3579,7 @@ DEFINE_EVENT(xrep_iunlink_resolve_class, TP_PROTO(const struct xfs_perag *pag, unsigned int bucket, \ xfs_agino_t prev_agino, xfs_agino_t next_agino), \ TP_ARGS(pag, bucket, prev_agino, next_agino)) +DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_infinite_loop);DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_uncached);DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_wronglist);DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT (xrep_iunlink_resolve_nolist);
Greg Kroah-Hartman
maintainerPATCH 122/217 xfs: dont return EFSCORRUPTED when scrubbing corrupt parent pointers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 8af9cd79cdf6ee96ec610d707db22244fa21eb40 upstream.
LOLLM noticed that scrub sets the CORRUPT flag when xfs_parent_from_attr thinks it's been given a corrupt parent pointer. This eliminates the potential to repair the filesystem because that error code is bubbled up the call stack. Fix this by collapsing them all to ECANCELED in xchk_parent_pptr, which doesn't have that trait.
--- fs/xfs/scrub/parent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/parent.c +1 -1
@@ -486,7 +486,7 @@ xchk_parent_scan_attr( valuelen, &parent_ino, NULL);if (error) {xchk_fblock_set_corrupt (sc,XFS_ATTR_FORK ,0 ); -return error; +return -ECANCELED ; }/* No self-referential parent pointers. */
Greg Kroah-Hartman
maintainerPATCH 123/217 xfs: avoid UAF on sc->tempip in xrep_tempfile_create
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 0c88e10d12de9ca7cbed1467bb1b52310101bff8 upstream.
LOLLM noticed a potential UAF if the tempfile creation code fails after it set sc->tempip. Fix that.
--- fs/xfs/scrub/tempfile.c | 1 + 1 file changed, 1 insertion(+)
fs/xfs/scrub/tempfile.c +1 -0
@@ -174,6 +174,7 @@ out_release_inode:xfs_iunlock (sc->tempip,XFS_ILOCK_EXCL );xfs_finish_inode_setup (sc->tempip);xchk_irele (sc, sc->tempip); + sc->tempip =NULL ; } out_release_dquots:xfs_qm_dqrele (udqp);
Greg Kroah-Hartman
maintainerPATCH 124/217 xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lin Jiapeng <[email protected]>
commit b2d5a81dae385333f9734910277fbf94c78bd17f upstream.
When exchanging two full-file ranges, xmi_can_exchange_reflink_flags() can move the reflink inode flag from the file that currently has it to the other file, as long as exactly one side is marked. This assumes that the file contents, and therefore all shared extents, are exchanged.
That assumption is not true when XFS_EXCHMAPS_INO1_WRITTEN is set. xfs_exchmaps_can_skip_mapping() can skip hole and unwritten mappings from file1, so an exchange can complete without moving every mapping that the earlier flag-swap decision accounted for. In that case the post-operation cleanup can clear the reflink flag from an inode that still owns shared written extents. Later writes then take the non-reflink write path and may update blocks that should still have been protected by CoW, which shows up as data corruption between reflink-related files.
Fix this by disabling the reflink flag exchange whenever XFS_EXCHMAPS_INO1_WRITTEN is requested. The contents exchange can still proceed; the conservative outcome is that both inodes keep the reflink flag. The regular reflink flag cleanup path can drop the extra flag later once the inode no longer has shared extents.
--- fs/xfs/libxfs/xfs_exchmaps.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/xfs/libxfs/xfs_exchmaps.c +10 -0
@@ -959,6 +959,16 @@ xmi_can_exchange_reflink_flags( {struct xfs_mount *mp = req->ip1->i_mount; +/* +* The INO1_WRITTEN optimization can skip exchanging hole and +* unwritten mappings, which means we cannot guarantee that all +* shared extents actually moved to the other file. Clearing the +* reflink flag of an inode that still holds shared extents breaks +* the CoW write path, so refuse to exchange the flags in that case. +*/ +if (req->flags &XFS_EXCHMAPS_INO1_WRITTEN ) +return false; +if (hweight32 (reflink_state) !=1 )return false;if (req->startoff1 !=0 || req->startoff2 !=0 )
Greg Kroah-Hartman
maintainerPATCH 125/217 xfs: dont swallow dquot recovery verification errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
commit e2b4a856085e9bd939bde2dee0d08b1d41babde9 upstream.
xlog_recover_dquot_commit_pass2() validates the recovered dquot with xfs_dqblk_verify() and, on failure, sets error = -EFSCORRUPTED and jumps to out_release. But out_release unconditionally returns 0, so the corruption error is discarded: the caller xlog_recover_items_pass2() sees success, log recovery proceeds as if the dquot were valid, and the corrupt quota buffer can be written back to disk.
--- fs/xfs/xfs_dquot_item_recover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_dquot_item_recover.c +1 -1
@@ -173,7 +173,7 @@ xlog_recover_dquot_commit_pass2( out_release:xfs_buf_relse (bp); -return 0 ; +return error; }const struct xlog_recover_item_ops xlog_dquot_item_ops = {
Greg Kroah-Hartman
maintainerPATCH 126/217 xfs: dont ignore runtime errors in xrep_iunlink_reload_next
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 0052633527158b49762ab427e73924e4f8d25e6c upstream.
LOLLM complained that this function ignores runtime errors being returned by xrep_iunlink_store_*. Rework the function signature so that we can return runtime errors to abort the repair.
--- fs/xfs/scrub/agheader_repair.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-)
fs/xfs/scrub/agheader_repair.c +22 -10
@@ -1041,31 +1041,40 @@ xrep_iunlink_next(* the chain or if we should stop walking the chain due to corruption; or a * per-AG inode number. */ -STATIC xfs_agino_t +STATIC intxrep_iunlink_reload_next (struct xrep_agi *ragi,xfs_agino_t prev_agino, -xfs_agino_t agino) +xfs_agino_t agino, +xfs_agino_t *next_agino) {struct xfs_scrub *sc = ragi->sc;struct xfs_inode *ip; -xfs_agino_t ret =NULLAGINO ;int error; + *next_agino =NULLAGINO ; + error =xchk_iget (ragi->sc,xfs_agino_to_ino (sc->sa.pag, agino), &ip);if (error) -return ret; +return 0 ;trace_xrep_iunlink_reload_next (ip, prev_agino);/* If this is a linked inode, stop processing the chain. */ if (VFS_I (ip)->i_nlink !=0 ) { -xrep_iunlink_store_next (ragi, agino,NULLAGINO ); + error =xrep_iunlink_store_next (ragi, agino,NULLAGINO ); +if (error) +return error; + + error =xrep_iunlink_store_prev (ragi, agino,LINKED_AGINO ); +if (error) +return error; + goto rele; } ip->i_prev_unlinked = prev_agino; - ret = ip->i_next_unlinked; + *next_agino = ip->i_next_unlinked;/* * Drop the inode reference that we just took. We hold the AGI, so
@@ -1074,7 +1083,7 @@ xrep_iunlink_reload_next(*/ rele:xchk_irele (sc, ip); -return ret; +return 0 ; }/*
@@ -1107,9 +1116,12 @@ xrep_iunlink_walk_ondisk_bucket(break ; next_agino =xrep_iunlink_next (sc, agino); -if (!next_agino) - next_agino =xrep_iunlink_reload_next (ragi, prev_agino, - agino); +if (!next_agino) { + error =xrep_iunlink_reload_next (ragi, prev_agino, + agino, &next_agino); +if (error) +break ; + } prev_agino = agino; }
Greg Kroah-Hartman
maintainerPATCH 127/217 xfs: check xfarray iteration errors when committing unlinked inode lists
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 2daf3ed5d059dec79c123aec42eb8d28e0c016d4 upstream.
LOLLM noticed that we neglect to check for xfarray_iter itself returning errors when writing a new AGI. Fix that.
--- fs/xfs/scrub/agheader_repair.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/xfs/scrub/agheader_repair.c +4 -0
@@ -1752,6 +1752,8 @@ xrep_iunlink_commit(if (error)return error; } +if (error <0 ) +return error;/* Fix all the back links */ idx =XFARRAY_CURSOR_INIT ;
@@ -1760,6 +1762,8 @@ xrep_iunlink_commit(if (error)return error; } +if (error <0 ) +return error;/* Copy the staged iunlink buckets to the new AGI. */ for (i =0 ; i <XFS_AGI_UNLINKED_BUCKETS ; i++) {
Greg Kroah-Hartman
maintainerPATCH 128/217 xfs: check v5 superblock features early
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
commit eb6b2cc1fc8ad566d746d128a559989ff0bba5cc upstream.
When working on a new features that reuses the existing pad in the superblock, I noticed that mounting such a file system on an old kernel logs a rather confusing warning:
XFS (vdc): Metadir superblock padding fields must be zero.
This is because we only validate the various feature fields in v5 superblocks after the common superblock validation helper is called.
Fix this by calling the feature validation first.
--- fs/xfs/libxfs/xfs_sb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_sb.c +2 -2
@@ -1118,10 +1118,10 @@ xfs_sb_read_verify(* because _verify_common checks the on-disk values. */ __xfs_sb_from_disk (&sb, dsb, false); - error =xfs_validate_sb_common (mp, bp, &sb); + error =xfs_validate_sb_read (mp, &sb);if (error) goto out_error; - error =xfs_validate_sb_read (mp, &sb); + error =xfs_validate_sb_common (mp, bp, &sb); out_error:if (error == -EFSCORRUPTED || error == -EFSBADCRC )
Greg Kroah-Hartman
maintainerPATCH 129/217 ceph: avoid fs reclaim while using current->journal_info
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
[ Upstream commit 5b602344a49e039e792ce5a8923bcc61412ee134 ]
handle_reply() stores a ceph_mds_request pointer in current->journal_info while filling the inode and dentry cache from an MDS reply.
An allocation in this section can enter direct reclaim and prune dentries from another filesystem. If this dirties an ext4 inode, ext4 starts a JBD2 transaction. JBD2 interprets the Ceph request in current->journal_info as a journal handle and dereferences the request's r_tid as h_transaction, causing a kernel crash, e.g.:
Unable to handle kernel paging request at virtual address 00000000077b4818 [...] Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: CPU: 6 UID: 0 PID: 2699135 Comm: kworker/6:3 Tainted: G W 6.18.38-i3 #1113 NONE [...] Workqueue: ceph-msgr ceph_con_workfn pstate: 80400009 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : jbd2__journal_start+0x2c/0x208 lr : __ext4_journal_start_sb+0x100/0x178 [...] Call trace: jbd2__journal_start+0x2c/0x208 (P) __ext4_journal_start_sb+0x100/0x178 ext4_dirty_inode+0x3c/0x90 __mark_inode_dirty+0x58/0x400 iput.part.0+0x2b0/0x370 iput+0x18/0x30 dentry_unlink_inode+0xc0/0x158 __dentry_kill+0x80/0x250 shrink_dentry_list+0x90/0x130 prune_dcache_sb+0x60/0x98 super_cache_scan+0xe8/0x190 do_shrink_slab+0x174/0x388 shrink_slab+0xd8/0x4c0 shrink_node+0x31c/0x908 do_try_to_free_pages+0xd0/0x508 try_to_free_pages+0x11c/0x238 __alloc_frozen_pages_noprof+0x4d0/0xdd0 __folio_alloc_noprof+0x18/0x70 __filemap_get_folio+0x248/0x440 ceph_readdir_prepopulate+0x570/0x9e8 mds_dispatch+0x1424/0x1ba0 ceph_con_process_message+0x74/0xa0 ceph_con_v1_try_read+0x3a0/0x1510 ceph_con_workfn+0x260/0x460
Enter a scoped NOFS allocation context and leave it after clearing journal_info. This prevents filesystem reclaim from recursing into another filesystem while the field contains Ceph-private data.
--- fs/ceph/mds_client.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/ceph/mds_client.c +11 -0
@@ -6,6 +6,7 @@#include <linux/slab.h> #include <linux/gfp.h> #include <linux/sched.h> +#include <linux/sched/mm.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/ratelimit.h>
@@ -3843,6 +3844,7 @@ static void handle_reply(struct ceph_mdsstruct ceph_mds_reply_head *head = msg->front.iov_base;struct ceph_mds_reply_info_parsed *rinfo;/* parsed reply info */ struct ceph_snap_realm *realm; +unsigned int nofs_flags;u64 tid;int err, result;int mds = session->s_mds;
@@ -3985,6 +3987,14 @@ static void handle_reply(struct ceph_mds/* insert trace into our cache */ mutex_lock (&req->r_fill_mutex); + +/* disable fs reclaim while we are using current->journal_info +* for our own purposes, or else shrinkers of other +* filesystems might dereference this pointer as a different +* type +*/ + nofs_flags =memalloc_nofs_save (); + current->journal_info = req; err =ceph_fill_trace (mdsc->fsc->sb, req);if (err ==0 ) {
@@ -3993,6 +4003,7 @@ static void handle_reply(struct ceph_mds err =ceph_readdir_prepopulate (req, req->r_session); } current->journal_info =NULL ; +memalloc_nofs_restore (nofs_flags);mutex_unlock (&req->r_fill_mutex);up_read (&mdsc->snap_rwsem);
Greg Kroah-Hartman
maintainerPATCH 130/217 ceph: fix hanging __ceph_get_caps() with stale mds_wanted
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
[ Upstream commit 50958bb928bad3bdba9e5d1b7ff4bbadcf6951e6 ]
A reader can hang forever in __ceph_get_caps() when the client no longer holds FILE_RD, but local cap state still says that the capability is already wanted (via mds_wanted).
One way to trigger this is through MDS cap revocation. If another client performs a conflicting operation, the MDS can revoke FILE_RD from the reader; the next read then has to reacquire FILE_RD. If the cap update that should request FILE_RD never reaches the MDS after cap->mds_wanted was raised, the reader is left holding only non-file caps while local mds_wanted still includes the file read caps.
In that state, try_get_cap_refs() sees need <= mds_wanted and returns 0, so __ceph_get_caps() just waits on i_cap_wq. If the cap update that was supposed to request FILE_RD never reaches the MDS after cap->mds_wanted was` raised, no further request is sent and the waiter can sleep indefinitely until unrelated cap traffic happens to wake it up.
The ordering issue is that cap->mds_wanted is updated in __prep_cap() before the CEPH_MSG_CLIENT_CAPS message is actually queued for send. That makes one field serve two different meanings at
once: what this client wants, and what the client believes the MDS already knows it wants.
A proper fix would be to split those states and track whether a cap update is actually in flight or has been observed by the MDS. However, simply moving the cap->mds_wanted assignment later would not be sufficient: queueing the message in the messenger does not guarantee that the MDS processed that specific wanted set, and reconnect or message loss can still invalidate that assumption. Fixing that properly would require a larger rework of the cap state machine.
To allow simpler backports to stable kernels, this patch implements a simpler workaround:
- stop waiting forever in __ceph_get_caps(); after a bounded wait, fall back to the renew path
- make ceph_renew_caps() issue a synchronous OPEN request whenever the inode still does not actually hold the wanted caps, instead of only calling ceph_check_caps()
The extra issued-vs-wanted check in ceph_renew_caps() is necessary because the previous test only checked whether the inode still had any real caps at all. That is not enough after revocation: the client can still hold something like pLs and yet be missing FILE_RD completely. In that case, falling back to ceph_check_caps() is not sufficient, because it still trusts cap->mds_wanted and may resend nothing. By requiring (issued & wanted) == wanted before taking the asynchronous path, the code only uses ceph_check_caps() when the wanted caps are already actually issued. Otherwise, it sends the synchronous OPEN renew.
This preserves the existing asynchronous fast path when the wanted caps are already issued, avoids changing cap-state semantics, and fixes the hang by guaranteeing that a stalled waiter eventually retries through a path that does not rely on the stale mds_wanted state.
[ idryomov: move CEPH_GET_CAPS_WAIT_TIMEOUT from libceph.h to
mds_client.h, formatting ]
--- fs/ceph/caps.c | 17 +++++++++++++++-- fs/ceph/file.c | 9 +++++---- fs/ceph/mds_client.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-)
fs/ceph/caps.c +15 -2
@@ -3090,7 +3090,19 @@ int __ceph_get_caps(struct inode *inode, ret = -ERESTARTSYS ;break ; } -wait_woken (&wait,TASK_INTERRUPTIBLE ,MAX_SCHEDULE_TIMEOUT ); + +/* +* If a cap update is lost after +* mds_wanted was raised, waiting +* forever will never make progress. +* Retry the renew path periodically +* so we can resend synchronously. +*/ +if (!wait_woken (&wait,TASK_INTERRUPTIBLE , +CEPH_GET_CAPS_WAIT_TIMEOUT )) { + ret = -EUCLEAN ; +break ; + } }remove_wait_queue (&ci->i_cap_wq, &wait);
@@ -3124,7 +3136,8 @@ int __ceph_get_caps(struct inode *inode,continue ; }if (ret == -EUCLEAN ) { -/* session was killed, try renew caps */ +/* session was killed or a waited cap +* request needs a retry */ ret =ceph_renew_caps (inode, flags);if (ret ==0 )continue ;
fs/ceph/file.c +5 -4
@@ -295,7 +295,7 @@ static int ceph_init_file(struct inode * }/* -* try renew caps after session gets killed. +* Retry cap acquisition after a stale session or a lost cap update. */ int ceph_renew_caps (struct inode *inode,int fmode) {
@@ -303,14 +303,15 @@ int ceph_renew_caps(struct inode *inode,struct ceph_client *cl = mdsc->fsc->client;struct ceph_inode_info *ci =ceph_inode (inode);struct ceph_mds_request *req; -int err, flags, wanted; +int err, flags, wanted, issued;spin_lock (&ci->i_ceph_lock);__ceph_touch_fmode (ci, mdsc, fmode); wanted =__ceph_caps_file_wanted (ci); + issued =__ceph_caps_issued (ci,NULL );if (__ceph_is_any_real_caps (ci) && - (!(wanted &CEPH_CAP_ANY_WR ) || ci->i_auth_cap)) { -int issued =__ceph_caps_issued (ci,NULL ); + (!(wanted &CEPH_CAP_ANY_WR ) || ci->i_auth_cap) && + (issued & wanted) == wanted) {spin_unlock (&ci->i_ceph_lock); doutc(cl, "%p %llx.%llx want %s issued %s updating mds_wanted\n", inode, ceph_vinop(inode), ceph_cap_string(wanted),
fs/ceph/mds_client.h +1 -0
@@ -74,6 +74,7 @@ struct ceph_fs_client;struct ceph_cap ;#define MDS_AUTH_UID_ANY -1 +#define CEPH_GET_CAPS_WAIT_TIMEOUT (5 * HZ)struct ceph_mds_cap_match {s64 uid;/* default to MDS_AUTH_UID_ANY */
Greg Kroah-Hartman
maintainerPATCH 131/217 libceph: Amend checking to fix `make W=1` build breakage
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 04d8712b079327409b09dee628378f9583e2e035 ]
In a few cases the code compares 32-bit value to a SIZE_MAX derived constant which is much higher than that value on 64-bit platforms, Clang, in particular, is not happy about this
net/ceph/osdmap.c:1441:10: error: result of comparison of constant 4611686018427387891 with expression of type 'u32' (aka 'unsigned int') is always false [-Werror,-Wtautological-constant-out-of-range-compare]
1441 | if (len > (SIZE_MAX - sizeof(*pg)) / sizeof(u32))
| ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
net/ceph/osdmap.c:1624:10: error: result of comparison of constant 2305843009213693945 with expression of type 'u32' (aka 'unsigned int') is always false [-Werror,-Wtautological-constant-out-of-range-compare]
1624 | if (len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
| ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Fix this by casting to size_t. Note, that possible replacement of SIZE_MAX by U32_MAX may lead to the behaviour changes on the corner cases.
Stable-dep-of: 9f00f9cf2be2 ("libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE")
--- net/ceph/osdmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ceph/osdmap.c +2 -2
@@ -1440,7 +1440,7 @@ static struct ceph_pg_mapping *__decode_ceph_decode_32_safe (p, end, len, e_inval);if (len ==0 && incremental)return NULL ;/* new_pg_temp: [] to remove */ -if (len > (SIZE_MAX -sizeof (*pg)) /sizeof (u32)) +if ((size_t )len > (SIZE_MAX -sizeof (*pg)) /sizeof (u32))return ERR_PTR (-EINVAL );ceph_decode_need (p, end, len *sizeof (u32), e_inval);
@@ -1621,7 +1621,7 @@ static struct ceph_pg_mapping *__decode_u32 len, i;ceph_decode_32_safe (p, end, len, e_inval); -if (len > (SIZE_MAX -sizeof (*pg)) / (2 *sizeof (u32))) +if ((size_t )len > (SIZE_MAX -sizeof (*pg)) / (2 *sizeof (u32)))return ERR_PTR (-EINVAL );ceph_decode_need (p, end,2 * len *sizeof (u32), e_inval);
Greg Kroah-Hartman
maintainerPATCH 132/217 libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 9f00f9cf2be293efe899db67dc5272e3a9c62717 ]
__decode_pg_temp() decodes an user-controlled length but only rejects values large enough to overflow the allocation; it does not bound it to CEPH_PG_MAX_SIZE. The helper backs both pg_temp and pg_upmap decoding, and apply_upmap()/get_temp_osds() later copy the decoded list into the fixed-size on-stack array struct ceph_osds.osds[CEPH_PG_MAX_SIZE]. A monitor that sends an OSDMap with a pg_temp/pg_upmap entry longer than 32 thus causes a stack out-of-bounds write.
An OSD set for a single PG can never exceed CEPH_PG_MAX_SIZE, so reject longer entries at decode time. The bound is well below the old overflow threshold, so it also covers the allocation-size overflow the previous check guarded against.
BUG: KASAN: stack-out-of-bounds in ceph_pg_to_up_acting_osds Write of size 4 ... by task exploit kasan_report (mm/kasan/report.c:595) ceph_pg_to_up_acting_osds (net/ceph/osdmap.c:2617 net/ceph/osdmap.c:2833) calc_target (net/ceph/osd_client.c:1638) __submit_request (net/ceph/osd_client.c:2394) ceph_osdc_start_request (net/ceph/osd_client.c:2490) ceph_osdc_call (net/ceph/osd_client.c:5164) rbd_dev_image_probe (drivers/block/rbd.c:6899) do_rbd_add (drivers/block/rbd.c:7138) ... kernel BUG at net/ceph/osdmap.c:2670!
[ idryomov: do the same in __decode_pg_upmap_items() ]
--- net/ceph/osdmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ceph/osdmap.c +2 -2
@@ -1440,7 +1440,7 @@ static struct ceph_pg_mapping *__decode_ceph_decode_32_safe (p, end, len, e_inval);if (len ==0 && incremental)return NULL ;/* new_pg_temp: [] to remove */ -if ((size_t )len > (SIZE_MAX -sizeof (*pg)) /sizeof (u32)) +if (len >CEPH_PG_MAX_SIZE )return ERR_PTR (-EINVAL );ceph_decode_need (p, end, len *sizeof (u32), e_inval);
@@ -1621,7 +1621,7 @@ static struct ceph_pg_mapping *__decode_u32 len, i;ceph_decode_32_safe (p, end, len, e_inval); -if ((size_t )len > (SIZE_MAX -sizeof (*pg)) / (2 *sizeof (u32))) +if (len >CEPH_PG_MAX_SIZE )return ERR_PTR (-EINVAL );ceph_decode_need (p, end,2 * len *sizeof (u32), e_inval);
Greg Kroah-Hartman
maintainerPATCH 133/217 libceph: fix two unsafe bare decodes in decode_lockers()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <[email protected]>
[ Upstream commit a109a556115271ca7896dcda7b4b7e45e156c227 ]
decode_lockers() in cls_lock_client.c contains two bare decode operations that allow a malicious or compromised OSD to trigger slab-out-of-bounds reads:
1. ceph_decode_32(p) at the num_lockers field has no preceding bounds check. ceph_start_decoding() accepts struct_len=0 as valid -- the internal ceph_decode_need(p, end, 0, bad) always passes -- so when an OSD sends struct_len=0, ceph_start_decoding() returns success with p == end. The immediately following bare ceph_decode_32(p) then reads 4 bytes past the validated buffer boundary. The garbage value is passed directly to kzalloc_objs() as the locker count.
The sibling function decode_watchers() in osd_client.c already uses ceph_decode_32_safe() after its own ceph_start_decoding() call. decode_lockers() was the only site using the bare variant.
2. ceph_decode_8(p) after the decode_locker() loop has no preceding bounds check. If an OSD crafts num_lockers such that the loop advances p exactly to end, the subsequent bare ceph_decode_8(p) reads one byte past the validated buffer boundary. The result is passed directly into *type, which is used as a lock type discriminator by callers, giving an OSD-controlled one-byte OOB read with direct influence over the lock type field.
Fix both by replacing bare operations with their safe variants:
ceph_decode_32(p) -> ceph_decode_32_safe(p, end, *num_lockers,
err_inval)
ceph_decode_8(p) -> ceph_decode_8_safe(p, end, *type,
err_free_lockers)
The goto targets differ intentionally:
err_inval: is a new label returning -EINVAL directly. It is used for the pre-allocation failure path where *lockers is not yet allocated and must not be passed to ceph_free_lockers().
err_free_lockers: is the existing label. It is used for the post-allocation failure path where *lockers is allocated and must be freed.
ret is set to -EINVAL before ceph_decode_8_safe() so that err_free_lockers returns the correct error code on bounds violation. Without this, err_free_lockers would return a stale ret value (0 from the successful decode_locker() loop), silently swallowing the error.
-EINVAL is correct for both failure paths. The data received from the OSD is structurally malformed. -ENOMEM would misrepresent the failure class to callers and to stable@ backporters triaging error paths.
Attacker model: a malicious or compromised OSD in a multi-tenant Ceph deployment can trigger this against any kernel client that issues the lock.get_info class method (e.g. during RBD exclusive lock acquisition).
[ idryomov: trim changelog, formatting ]
--- net/ceph/cls_lock_client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/ceph/cls_lock_client.c +6 -2
@@ -304,7 +304,7 @@ static int decode_lockers(void **p, voidif (ret)return ret; - *num_lockers =ceph_decode_32 (p); +ceph_decode_32_safe (p, end, *num_lockers, err_inval); *lockers =kcalloc (*num_lockers,sizeof (**lockers),GFP_NOIO );if (!*lockers)return -ENOMEM ;
@@ -315,7 +315,8 @@ static int decode_lockers(void **p, void goto err_free_lockers; } - *type =ceph_decode_8 (p); + ret = -EINVAL ; +ceph_decode_8_safe (p, end, *type, err_free_lockers); s =ceph_extract_encoded_string (p, end,NULL ,GFP_NOIO );if (IS_ERR (s)) { ret =PTR_ERR (s);
@@ -325,6 +326,9 @@ static int decode_lockers(void **p, void *tag = s;return 0 ; +err_inval: +return -EINVAL ; + err_free_lockers:ceph_free_lockers (*lockers, *num_lockers);return ret;
Greg Kroah-Hartman
maintainerPATCH 134/217 net/sched: serialize qdisc_rtab_list against concurrent get/put
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Ariel Panzardo <[email protected]>
[ Upstream commit f43ee0c0730d6191629b5ee1ceae27b1ebfdc047 ]
qdisc_get_rtab() and qdisc_put_rtab() mutate the process-global singly linked list qdisc_rtab_list and a plain non-atomic 'int refcnt' with no lock. This was only safe because every caller historically held the RTNL mutex, which serialized all rate-table lookups, inserts and frees.
That invariant no longer holds. cls_flower sets TCF_PROTO_OPS_DOIT_UNLOCKED, so tc_new_tfilter() keeps rtnl_held == false for it and sets TCA_ACT_FLAGS_NO_RTNL. That flag propagates through tcf_exts_validate_ex() -> tcf_action_init() -> tcf_action_init_1() -> tcf_police_init(), which calls qdisc_get_rtab()/qdisc_put_rtab() with the RTNL mutex NOT held. Two RTM_NEWTFILTER requests on different CPUs, each adding a flower filter with a police action carrying the same rate, then race on qdisc_rtab_list and on the non-atomic refcnt, leading to a use-after-free / double-free of the kmalloc-2k struct qdisc_rate_table. qdisc_rtab_list is a single global (not per-netns), so the corrupted object is shared system-wide.
BUG: KASAN: slab-use-after-free in qdisc_put_rtab+0x12f/0x160 qdisc_put_rtab+0x12f/0x160 tcf_police_init+0xda9/0x1590 tcf_action_init_1+0x460/0x6b0 tcf_action_init+0x439/0xa40 tcf_exts_validate_ex+0x42d/0x550 fl_change+0xddd/0x7da0 tc_new_tfilter+0xaa7/0x2420 rtnetlink_rcv_msg+0x95e/0xe90 which belongs to the cache kmalloc-2k of size 2048
Protect qdisc_rtab_list and the refcount with a dedicated spinlock. The (sleeping, GFP_KERNEL) allocation in qdisc_get_rtab() is performed before taking the lock; if a concurrent inserter added an identical table in the meantime the freshly allocated one is freed under the lock, so no duplicate is leaked. qdisc_put_rtab() now decrements the refcount and unlinks under the same lock.
--- net/sched/sch_api.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
net/sched/sch_api.c +19 -5
@@ -415,12 +415,13 @@ static __u8 __detect_linklayer(struct tc }static struct qdisc_rate_table *qdisc_rtab_list; +static DEFINE_SPINLOCK (qdisc_rtab_lock);struct qdisc_rate_table *qdisc_get_rtab (struct tc_ratespec *r,struct nlattr *tab,struct netlink_ext_ack *extack) { -struct qdisc_rate_table *rtab; +struct qdisc_rate_table *rtab, *new_rtab; if (tab == NULL || r->rate == 0 || r->cell_log == 0 || r->cell_log >= 32 ||
@@ -429,15 +430,20 @@ struct qdisc_rate_table *qdisc_get_rtab(return NULL ; } + new_rtab =kmalloc_obj (*new_rtab); + +spin_lock (&qdisc_rtab_lock);for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {if (!memcmp (&rtab->rate, r,sizeof (struct tc_ratespec )) && !memcmp (&rtab->data,nla_data (tab),TC_RTAB_SIZE )) { rtab->refcnt++; +spin_unlock (&qdisc_rtab_lock); +kfree (new_rtab);return rtab; } } - rtab =kmalloc (sizeof (*rtab),GFP_KERNEL ); + rtab = new_rtab;if (rtab) { rtab->rate = *r; rtab->refcnt =1 ;
@@ -449,6 +455,7 @@ struct qdisc_rate_table *qdisc_get_rtab( }else {NL_SET_ERR_MSG (extack,"Failed to allocate new qdisc rate table" ); } +spin_unlock (&qdisc_rtab_lock);return rtab; }EXPORT_SYMBOL (qdisc_get_rtab);
@@ -457,18 +464,25 @@ void qdisc_put_rtab(struct qdisc_rate_ta {struct qdisc_rate_table *rtab, **rtabp; -if (!tab || --tab->refcnt) +if (!tab) +return ; + +spin_lock (&qdisc_rtab_lock); +if (--tab->refcnt) { +spin_unlock (&qdisc_rtab_lock);return ; + }for (rtabp = &qdisc_rtab_list; (rtab = *rtabp) !=NULL ; rtabp = &rtab->next) {if (rtab == tab) { *rtabp = rtab->next; -kfree (rtab); -return ; +break ; } } +spin_unlock (&qdisc_rtab_lock); +kfree (tab); }EXPORT_SYMBOL (qdisc_put_rtab);
Greg Kroah-Hartman
maintainerPATCH 135/217 smb: move get_rfc1002_len() to common/smbglob.h
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit 36c31540cf5279262bfd148d8537cd04866499f2 ]
Rename get_rfc1002_length() to get_rfc1002_len(), then move duplicate definitions to common header file.
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/client/cifsglob.h | 6 ------ fs/smb/client/cifssmb.c | 6 +++--- fs/smb/client/connect.c | 2 +- fs/smb/client/smb1transport.c | 8 ++++---- fs/smb/common/cifsglob.h | 5 +++++ fs/smb/server/smb_common.h | 5 ----- 6 files changed, 13 insertions(+), 19 deletions(-)
fs/smb/client/cifsglob.h +0 -6
@@ -671,12 +671,6 @@ struct cifs_mnt_data {int flags; }; -static inline unsigned int -get_rfc1002_length (void *buf) -{ -return be32_to_cpu (*((__be32 *)buf)) &0xffffff ; -} -struct TCP_Server_Info {struct list_head tcp_ses_list;struct list_head smb_ses_list;
fs/smb/client/cifssmb.c +3 -3
@@ -615,7 +615,7 @@ CIFSSMBEcho(struct TCP_Server_Info *serv iov[0 ].iov_len =4 ; iov[0 ].iov_base = smb; - iov[1 ].iov_len =get_rfc1002_length (smb); + iov[1 ].iov_len =get_rfc1002_len (smb); iov[1 ].iov_base = (char *)smb +4 ; rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
@@ -1459,7 +1459,7 @@ cifs_async_readv(struct cifs_io_subreque rdata->iov[0 ].iov_base = smb; rdata->iov[0 ].iov_len =4 ; rdata->iov[1 ].iov_base = (char *)smb +4 ; - rdata->iov[1 ].iov_len =get_rfc1002_length (smb); + rdata->iov[1 ].iov_len =get_rfc1002_len (smb); trace_smb3_read_enter(rdata->rreq->debug_id, rdata->subreq.debug_index,
@@ -1835,7 +1835,7 @@ cifs_async_writev(struct cifs_io_subrequ/* 4 for RFC1001 length + 1 for BCC */ iov[0 ].iov_len =4 ; iov[0 ].iov_base = smb; - iov[1 ].iov_len =get_rfc1002_length (smb) +1 ; + iov[1 ].iov_len =get_rfc1002_len (smb) +1 ; iov[1 ].iov_base = (char *)smb +4 ; rqst.rq_iov = iov;
fs/smb/client/connect.c +1 -1
@@ -1295,7 +1295,7 @@ cifs_demultiplex_thread(void *p)* The right amount was read from socket - 4 bytes, * so we can now interpret the length field. */ - pdu_length =get_rfc1002_length (buf); + pdu_length =get_rfc1002_len (buf);cifs_dbg (FYI ,"RFC1002 header 0x%x\n" , pdu_length);if (!is_smb_response (server, buf[0 ]))
fs/smb/client/smb1transport.c +4 -4
@@ -165,7 +165,7 @@ SendReceiveNoRsp(const unsigned int xid,int resp_buf_type; iov[0 ].iov_base = in_buf; - iov[0 ].iov_len =get_rfc1002_length (in_buf) +4 ; + iov[0 ].iov_len =get_rfc1002_len (in_buf) +4 ; flags |=CIFS_NO_RSP_BUF ; rc =SendReceive2 (xid, ses, iov,1 , &resp_buf_type, flags, &rsp_iov);cifs_dbg (NOISY ,"SendRcvNoRsp flags %d rc %d\n" , flags, rc);
@@ -177,7 +177,7 @@ int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error) { - unsigned int len = get_rfc1002_length(mid->resp_buf) + 4; + unsigned int len = get_rfc1002_len(mid->resp_buf) + 4;dump_smb (mid->resp_buf,min_t (u32,92 , len));
@@ -370,7 +370,7 @@ SendReceive(const unsigned int xid, stru goto out; } - *pbytes_returned =get_rfc1002_length (midQ->resp_buf); + *pbytes_returned =get_rfc1002_len (midQ->resp_buf);memcpy (out_buf, midQ->resp_buf, *pbytes_returned +4 ); rc =cifs_check_receive (midQ, server,0 ); out:
@@ -554,7 +554,7 @@ SendReceiveBlockingLock(const unsigned i goto out; } - *pbytes_returned =get_rfc1002_length (midQ->resp_buf); + *pbytes_returned =get_rfc1002_len (midQ->resp_buf);memcpy (out_buf, midQ->resp_buf, *pbytes_returned +4 ); rc =cifs_check_receive (midQ, server,0 ); out:
fs/smb/common/cifsglob.h +5 -0
@@ -40,6 +40,11 @@ struct smb_version_values {size_t create_posix_size; }; +static inline unsigned int get_rfc1002_len (void *buf) +{ +return be32_to_cpu (*((__be32 *)buf)) &0xffffff ; +} +static inline void inc_rfc1001_len (void *buf,int count) {be32_add_cpu ((__be32 *)buf, count);
fs/smb/server/smb_common.h +0 -5
@@ -423,9 +423,4 @@ unsigned int ksmbd_server_side_copy_max_unsigned int ksmbd_server_side_copy_max_total_size (void );bool is_asterisk (char *p);__le32 smb_map_generic_desired_access (__le32 daccess); - -static inline unsigned int get_rfc1002_len (void *buf) -{ -return be32_to_cpu (*((__be32 *)buf)) &0xffffff ; -}#endif /* __SMB_COMMON_H__ */
Greg Kroah-Hartman
maintainerPATCH 136/217 smb/server: rename include guard in smb_common.h
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: ChenXiaoSong <[email protected]>
[ Upstream commit 01ab0d1640e379f0a0d6602250b33ff2b45e9560 ]
Make the include guard more descriptive to avoid conflicts with include guards that may be used in the future.
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/server/smb_common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/smb/server/smb_common.h +3 -3
@@ -3,8 +3,8 @@* Copyright (C) 2018 Samsung Electronics Co., Ltd. */ -#ifndef __SMB_COMMON_H__ -#define __SMB_COMMON_H__ +#ifndef __SMB_SERVER_COMMON_H__ +#define __SMB_SERVER_COMMON_H__#include <linux/kernel.h>
@@ -423,4 +423,4 @@ unsigned int ksmbd_server_side_copy_max_unsigned int ksmbd_server_side_copy_max_total_size (void );bool is_asterisk (char *p);__le32 smb_map_generic_desired_access (__le32 daccess); -#endif /* __SMB_COMMON_H__ */ +#endif /* __SMB_SERVER_COMMON_H__ */
Greg Kroah-Hartman
maintainerPATCH 137/217 ksmbd: Fix to handle removal of rfc1002 header from smb_hdr
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 0a70cac7896712a08e3cd22c16f44be976d40dbf ]
The commit that removed the RFC1002 header from struct smb_hdr didn't also fix the places in ksmbd that use it in order to provide graceful rejection of SMB1 protocol requests.
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/server/server.c | 2 +- fs/smb/server/smb_common.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-)
fs/smb/server/server.c +1 -1
@@ -95,7 +95,7 @@ static inline int check_conn_state(strucif (ksmbd_conn_exiting (work->conn) ||ksmbd_conn_need_reconnect (work->conn)) { - rsp_hdr = work->response_buf; + rsp_hdr =smb2_get_msg (work->response_buf); rsp_hdr->Status.CifsError =STATUS_CONNECTION_DISCONNECTED ;return 1 ; }
fs/smb/server/smb_common.c +10 -10
@@ -140,7 +140,7 @@ int ksmbd_verify_smb_message(struct ksmbif (smb2_hdr->ProtocolId ==SMB2_PROTO_NUMBER )return ksmbd_smb2_check_message (work); - hdr = work->request_buf; + hdr =smb2_get_msg (work->request_buf);if (*(__le32 *)hdr->Protocol ==SMB1_PROTO_NUMBER && hdr->Command ==SMB_COM_NEGOTIATE ) { work->conn->outstanding_credits++;
@@ -278,15 +278,14 @@ static int ksmbd_negotiate_smb_dialect(v req->DialectCount); } - proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol;if (proto ==SMB1_PROTO_NUMBER ) {struct smb_negotiate_req *req; - req = (struct smb_negotiate_req *)buf; + req = (struct smb_negotiate_req *)smb2_get_msg (buf);if (le16_to_cpu (req->ByteCount) <2 ) goto err_out; -if (offsetof(struct smb_negotiate_req , DialectsArray) -4 + +if (offsetof(struct smb_negotiate_req , DialectsArray) +le16_to_cpu (req->ByteCount) > smb_buf_length) { goto err_out; }
@@ -320,8 +319,8 @@ static u16 get_smb1_cmd_val(struct ksmbd*/ static int init_smb1_rsp_hdr (struct ksmbd_work *work) { -struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; -struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; +struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb2_get_msg (work->response_buf); +struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb2_get_msg (work->request_buf); rsp_hdr->Command =SMB_COM_NEGOTIATE ; *(__le32 *)rsp_hdr->Protocol =SMB1_PROTO_NUMBER ;
@@ -412,9 +411,10 @@ static int init_smb1_server(struct ksmbdint ksmbd_init_smb_server (struct ksmbd_conn *conn) { +struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb2_get_msg (conn->request_buf);__le32 proto; - proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol; + proto = *(__le32 *)rcv_hdr->Protocol;if (conn->need_neg == false) {if (proto ==SMB1_PROTO_NUMBER )return -EINVAL ;
@@ -572,12 +572,12 @@ static int __smb2_negotiate(struct ksmbdstatic int smb_handle_negotiate (struct ksmbd_work *work) { -struct smb_negotiate_rsp *neg_rsp = work->response_buf; +struct smb_negotiate_rsp *neg_rsp =smb2_get_msg (work->response_buf);ksmbd_debug (SMB ,"Unsupported SMB1 protocol\n" ); -if (ksmbd_iov_pin_rsp (work, (void *)neg_rsp +4 , -sizeof (struct smb_negotiate_rsp ) -4 )) +if (ksmbd_iov_pin_rsp (work, (void *)neg_rsp, +sizeof (struct smb_negotiate_rsp )))return -ENOMEM ; neg_rsp->hdr.Status.CifsError =STATUS_SUCCESS ;
Greg Kroah-Hartman
maintainerPATCH 138/217 ksmbd: rename smb2_get_msg to smb_get_msg
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 0b444cfd8b74ebce421ccd96eac9c495e536c92e ]
With the removal of the RFC1002 length field from the SMB header, smb2_get_msg is now used to get the smb1 request from the request buffer. Since this function is no longer exclusive to smb2 and now supports smb1 as well, This patch rename it to smb_get_msg to better reflect its usage.
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/server/auth.c | 4 +- fs/smb/server/connection.c | 2 - fs/smb/server/oplock.c | 8 ++--- fs/smb/server/server.c | 2 - fs/smb/server/smb2pdu.c | 70 ++++++++++++++++++++++----------------------- fs/smb/server/smb2pdu.h | 9 ----- fs/smb/server/smb_common.c | 18 +++++------ fs/smb/server/smb_common.h | 9 +++++ 8 files changed, 61 insertions(+), 61 deletions(-)
fs/smb/server/auth.c +2 -2
@@ -710,7 +710,7 @@ void ksmbd_gen_smb311_encryptionkey(struint ksmbd_gen_preauth_integrity_hash (struct ksmbd_conn *conn,char *buf,__u8 *pi_hash) { -struct smb2_hdr *rcv_hdr =smb2_get_msg (buf); +struct smb2_hdr *rcv_hdr =smb_get_msg (buf);char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;int msg_size =get_rfc1002_len (buf);struct sha512_ctx sha_ctx;
@@ -837,7 +837,7 @@ int ksmbd_crypt_message(struct ksmbd_wor unsigned int nvec, int enc) {struct ksmbd_conn *conn = work->conn; -struct smb2_transform_hdr *tr_hdr =smb2_get_msg (iov[0 ].iov_base); +struct smb2_transform_hdr *tr_hdr =smb_get_msg (iov[0 ].iov_base);unsigned int assoc_data_len =sizeof (struct smb2_transform_hdr ) -20 ;int rc;DECLARE_CRYPTO_WAIT (wait);
fs/smb/server/connection.c +1 -1
@@ -475,7 +475,7 @@ recheck:if (!ksmbd_smb_request (conn))break ; -if (((struct smb2_hdr *)smb2_get_msg (conn->request_buf))->ProtocolId == +if (((struct smb2_hdr *)smb_get_msg (conn->request_buf))->ProtocolId ==SMB2_PROTO_NUMBER ) {if (pdu_size <SMB2_MIN_SUPPORTED_HEADER_SIZE )break ;
fs/smb/server/oplock.c +4 -4
@@ -663,7 +663,7 @@ static void __smb2_oplock_break_noti(str goto out; } - rsp_hdr =smb2_get_msg (work->response_buf); + rsp_hdr =smb_get_msg (work->response_buf);memset (rsp_hdr,0 ,sizeof (struct smb2_hdr ) +2 ); rsp_hdr->ProtocolId =SMB2_PROTO_NUMBER ; rsp_hdr->StructureSize =SMB2_HEADER_STRUCTURE_SIZE ;
@@ -677,7 +677,7 @@ static void __smb2_oplock_break_noti(str rsp_hdr->SessionId =0 ;memset (rsp_hdr->Signature,0 ,16 ); - rsp =smb2_get_msg (work->response_buf); + rsp =smb_get_msg (work->response_buf); rsp->StructureSize =cpu_to_le16 (24 ); if (!br_info->open_trunc &&
@@ -776,7 +776,7 @@ static void __smb2_lease_break_noti(stru goto out; } - rsp_hdr =smb2_get_msg (work->response_buf); + rsp_hdr =smb_get_msg (work->response_buf);memset (rsp_hdr,0 ,sizeof (struct smb2_hdr ) +2 ); rsp_hdr->ProtocolId =SMB2_PROTO_NUMBER ; rsp_hdr->StructureSize =SMB2_HEADER_STRUCTURE_SIZE ;
@@ -790,7 +790,7 @@ static void __smb2_lease_break_noti(stru rsp_hdr->SessionId =0 ;memset (rsp_hdr->Signature,0 ,16 ); - rsp =smb2_get_msg (work->response_buf); + rsp =smb_get_msg (work->response_buf); rsp->StructureSize =cpu_to_le16 (44 ); rsp->Epoch = br_info->epoch; rsp->Flags =0 ;
fs/smb/server/server.c +1 -1
@@ -95,7 +95,7 @@ static inline int check_conn_state(strucif (ksmbd_conn_exiting (work->conn) ||ksmbd_conn_need_reconnect (work->conn)) { - rsp_hdr =smb2_get_msg (work->response_buf); + rsp_hdr =smb_get_msg (work->response_buf); rsp_hdr->Status.CifsError =STATUS_CONNECTION_DISCONNECTED ;return 1 ; }
fs/smb/server/smb2pdu.c +35 -35
240 lines not on this page · raw message
fs/smb/server/smb2pdu.h +0 -9
@@ -490,15 +490,6 @@ int smb2_ioctl(struct ksmbd_work *work);int smb2_oplock_break (struct ksmbd_work *work);int smb2_notify (struct ksmbd_work *ksmbd_work); -/* -* Get the body of the smb2 message excluding the 4 byte rfc1002 headers -* from request/response buffer. -*/ -static inline void *smb2_get_msg (void *buf) -{ -return buf +4 ; -} -#define POSIX_TYPE_FILE 0#define POSIX_TYPE_DIR 1#define POSIX_TYPE_SYMLINK 2
fs/smb/server/smb_common.c +9 -9
@@ -140,7 +140,7 @@ int ksmbd_verify_smb_message(struct ksmbif (smb2_hdr->ProtocolId ==SMB2_PROTO_NUMBER )return ksmbd_smb2_check_message (work); - hdr =smb2_get_msg (work->request_buf); + hdr =smb_get_msg (work->request_buf);if (*(__le32 *)hdr->Protocol ==SMB1_PROTO_NUMBER && hdr->Command ==SMB_COM_NEGOTIATE ) { work->conn->outstanding_credits++;
@@ -163,7 +163,7 @@ bool ksmbd_smb_request(struct ksmbd_connif (conn->request_buf[0 ] !=0 )return false; - proto = (__le32 *)smb2_get_msg (conn->request_buf); + proto = (__le32 *)smb_get_msg (conn->request_buf);if (*proto ==SMB2_COMPRESSION_TRANSFORM_ID ) {pr_err_ratelimited ("smb2 compression not support yet" );return false;
@@ -259,14 +259,14 @@ int ksmbd_lookup_dialect_by_id(__le16 *cstatic int ksmbd_negotiate_smb_dialect (void *buf) {int smb_buf_length =get_rfc1002_len (buf); -__le32 proto = ((struct smb2_hdr *)smb2_get_msg (buf))->ProtocolId; +__le32 proto = ((struct smb2_hdr *)smb_get_msg (buf))->ProtocolId;if (proto ==SMB2_PROTO_NUMBER ) {struct smb2_negotiate_req *req;int smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects); - req = (struct smb2_negotiate_req *)smb2_get_msg (buf); + req = (struct smb2_negotiate_req *)smb_get_msg (buf);if (smb2_neg_size > smb_buf_length) goto err_out;
@@ -281,7 +281,7 @@ static int ksmbd_negotiate_smb_dialect(vif (proto ==SMB1_PROTO_NUMBER ) {struct smb_negotiate_req *req; - req = (struct smb_negotiate_req *)smb2_get_msg (buf); + req = (struct smb_negotiate_req *)smb_get_msg (buf);if (le16_to_cpu (req->ByteCount) <2 ) goto err_out;
@@ -319,8 +319,8 @@ static u16 get_smb1_cmd_val(struct ksmbd*/ static int init_smb1_rsp_hdr (struct ksmbd_work *work) { -struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb2_get_msg (work->response_buf); -struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb2_get_msg (work->request_buf); +struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb_get_msg (work->response_buf); +struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg (work->request_buf); rsp_hdr->Command =SMB_COM_NEGOTIATE ; *(__le32 *)rsp_hdr->Protocol =SMB1_PROTO_NUMBER ;
@@ -411,7 +411,7 @@ static int init_smb1_server(struct ksmbdint ksmbd_init_smb_server (struct ksmbd_conn *conn) { -struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb2_get_msg (conn->request_buf); +struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg (conn->request_buf);__le32 proto; proto = *(__le32 *)rcv_hdr->Protocol;
@@ -572,7 +572,7 @@ static int __smb2_negotiate(struct ksmbdstatic int smb_handle_negotiate (struct ksmbd_work *work) { -struct smb_negotiate_rsp *neg_rsp =smb2_get_msg (work->response_buf); +struct smb_negotiate_rsp *neg_rsp =smb_get_msg (work->response_buf);ksmbd_debug (SMB ,"Unsupported SMB1 protocol\n" );
fs/smb/server/smb_common.h +9 -0
@@ -423,4 +423,13 @@ unsigned int ksmbd_server_side_copy_max_unsigned int ksmbd_server_side_copy_max_total_size (void );bool is_asterisk (char *p);__le32 smb_map_generic_desired_access (__le32 daccess); + +/* +* Get the body of the smb message excluding the 4 byte rfc1002 headers +* from request/response buffer. +*/ +static inline void *smb_get_msg (void *buf) +{ +return buf +4 ; +}#endif /* __SMB_SERVER_COMMON_H__ */
Greg Kroah-Hartman
maintainerPATCH 139/217 smb/server: fix minimum SMB1 PDU size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: ChenXiaoSong <[email protected]>
[ Upstream commit 3b9c30eb8f5aaad4a54cdfa470b74c0467cc71e8 ]
Since the RFC1002 header has been removed from struct smb_hdr, the minimum SMB1 PDU size should be updated as well.
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/server/connection.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/smb/server/connection.c +3 -2
@@ -376,7 +376,8 @@ bool ksmbd_conn_alive(struct ksmbd_connreturn true; } -#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr)) +/* "+2" for BCC field (ByteCount, 2 bytes) */ +#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)/**
@@ -444,7 +445,7 @@ recheck:if (pdu_size >MAX_STREAM_PROT_LEN )break ; -if (pdu_size <SMB1_MIN_SUPPORTED_HEADER_SIZE ) +if (pdu_size <SMB1_MIN_SUPPORTED_PDU_SIZE )break ;/* 4 for rfc1002 length field */
Greg Kroah-Hartman
maintainerPATCH 140/217 smb/server: fix minimum SMB2 PDU size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: ChenXiaoSong <[email protected]>
[ Upstream commit 4c7d8eb9a79ae5400eac19c4f6f0815bff674452 ]
The minimum SMB2 PDU size should be updated to the size of struct smb2_pdu (that is, the size of struct smb2_hdr + 2).
Stable-dep-of: cfc0b8e5080a ("ksmbd: validate minimum PDU size for transform requests")
--- fs/smb/server/connection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/connection.c +2 -2
@@ -378,7 +378,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn/* "+2" for BCC field (ByteCount, 2 bytes) */ #define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2) -#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4) +#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))/** * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
@@ -478,7 +478,7 @@ recheck:if (((struct smb2_hdr *)smb_get_msg (conn->request_buf))->ProtocolId ==SMB2_PROTO_NUMBER ) { -if (pdu_size <SMB2_MIN_SUPPORTED_HEADER_SIZE ) +if (pdu_size <SMB2_MIN_SUPPORTED_PDU_SIZE )break ; }
Greg Kroah-Hartman
maintainerPATCH 141/217 ksmbd: validate minimum PDU size for transform requests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit cfc0b8e5080aec87700774e8568765eaa4b7b92b ]
The receive path applies the minimum SMB2 PDU size check only when ProtocolId is SMB2_PROTO_NUMBER. A packet carrying SMB2_TRANSFORM_PROTO_NUM bypasses the check even when the negotiated dialect does not provide transform handling.
On an SMB 2.1 connection, a short transform packet therefore reaches init_smb2_rsp_hdr(), which interprets the request as a full SMB2 header and reads beyond the request allocation. The copied fields can then be returned to the unauthenticated client.
Compression transforms are converted to ordinary SMB2 messages before protocol validation. After that conversion, validate ordinary SMB2 requests against SMB2_MIN_SUPPORTED_PDU_SIZE and require encryption transform requests to contain both a transform header and an SMB2 header. This rejects truncated requests before work allocation.
--- fs/smb/server/connection.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
fs/smb/server/connection.c +11 -5
@@ -379,6 +379,8 @@ bool ksmbd_conn_alive(struct ksmbd_conn/* "+2" for BCC field (ByteCount, 2 bytes) */ #define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu)) +#define SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE \ + (sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr))/** * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
@@ -393,6 +395,7 @@ int ksmbd_conn_handler_loop(void *p)struct ksmbd_conn *conn = (struct ksmbd_conn *)p;struct ksmbd_transport *t = conn->transport;unsigned int pdu_size, max_allowed_pdu_size, max_req; +__le32 proto;char hdr_buf[4 ] = {0 ,};int size;
@@ -476,11 +479,14 @@ recheck:if (!ksmbd_smb_request (conn))break ; -if (((struct smb2_hdr *)smb_get_msg (conn->request_buf))->ProtocolId == -SMB2_PROTO_NUMBER ) { -if (pdu_size <SMB2_MIN_SUPPORTED_PDU_SIZE ) -break ; - } + proto = *(__le32 *)smb_get_msg (conn->request_buf); +if (proto ==SMB2_PROTO_NUMBER && + pdu_size <SMB2_MIN_SUPPORTED_PDU_SIZE ) +break ; + +if (proto ==SMB2_TRANSFORM_PROTO_NUM && + pdu_size <SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE ) +break ;if (!default_conn_ops.process_fn) {pr_err ("No connection request callback\n" );
Greg Kroah-Hartman
maintainerPATCH 142/217 btrfs: remove fs_info argument from btrfs_zoned_activate_one_bg()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <[email protected]>
[ Upstream commit a232ff90d14657c8637c6e94b606bb5d700a2ecb ]
We don't need it since we can grab fs_info from the given space_info. So remove the fs_info argument.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/block-group.c | 4 ++-- fs/btrfs/zoned.c | 5 ++--- fs/btrfs/zoned.h | 6 ++---- 3 files changed, 6 insertions(+), 9 deletions(-)
fs/btrfs/block-group.c +2 -2
@@ -3073,7 +3073,7 @@ int btrfs_inc_block_group_ro(struct btrf* We have allocated a new chunk. We also need to activate that chunk to * grant metadata tickets for zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (fs_info, space_info, true); + ret =btrfs_zoned_activate_one_bg (space_info, true);if (ret <0 ) goto out;
@@ -4354,7 +4354,7 @@ static void reserve_chunk_space(struct b* We have a new chunk. We also need to activate it for * zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (fs_info, info, true); + ret =btrfs_zoned_activate_one_bg (info, true);if (ret <0 )return ;
fs/btrfs/zoned.c +2 -3
@@ -2963,10 +2963,9 @@ int btrfs_zone_finish_one_bg(struct btrfreturn ret <0 ? ret :1 ; } -int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info, -bool do_finish) +int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish) { +struct btrfs_fs_info *fs_info = space_info->fs_info;struct btrfs_block_group *bg;int index;
fs/btrfs/zoned.h +2 -4
@@ -93,8 +93,7 @@ bool btrfs_zoned_should_reclaim(const stvoid btrfs_zoned_release_data_reloc_bg (struct btrfs_fs_info *fs_info,u64 logical,u64 length);int btrfs_zone_finish_one_bg (struct btrfs_fs_info *fs_info); -int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info,bool do_finish); +int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish);void btrfs_check_active_zone_reservation (struct btrfs_fs_info *fs_info);int btrfs_reset_unused_block_groups (struct btrfs_space_info *space_info,u64 num_bytes);#else /* CONFIG_BLK_DEV_ZONED */
@@ -261,8 +260,7 @@ static inline int btrfs_zone_finish_one_return 1 ; } -static inline int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info, +static inline int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish) {/* Consider all the block groups are active */
Greg Kroah-Hartman
maintainerPATCH 143/217 btrfs: zoned: fix missing chunk metadata reservation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
[ Upstream commit 8bc4d7209611e8aa9d5409b6a4a86a9eb91b69a3 ]
reserve_chunk_space() stores the return value of btrfs_zoned_activate_one_bg() in ret. The helper can return 1 after successfully activating a block group, but ret is later used to decide whether to reserve metadata for chunk tree updates.
As a result, successful activation skips btrfs_block_rsv_add() and leaves trans->chunk_bytes_reserved unchanged. Use a separate variable for the activation result so positive success does not affect the later reservation. Keep activation failures in ret instead of returning early so the function uses the common tail path.
--- fs/btrfs/block-group.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
fs/btrfs/block-group.c +19 -15
@@ -4350,25 +4350,29 @@ static void reserve_chunk_space(struct bif (IS_ERR (bg)) { ret =PTR_ERR (bg); }else { +int activate_ret; +/* * We have a new chunk. We also need to activate it for * zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (info, true); -if (ret <0 ) -return ; - -/* -* If we fail to add the chunk item here, we end up -* trying again at phase 2 of chunk allocation, at -* btrfs_create_pending_block_groups(). So ignore -* any error here. An ENOSPC here could happen, due to -* the cases described at do_chunk_alloc() - the system -* block group we just created was just turned into RO -* mode by a scrub for example, or a running discard -* temporarily removed its free space entries, etc. -*/ -btrfs_chunk_alloc_add_chunk_item (trans, bg); + activate_ret =btrfs_zoned_activate_one_bg (info, true); +if (activate_ret <0 ) { + ret = activate_ret; + }else { +/* +* If we fail to add the chunk item here, we end +* up trying again at phase 2 of chunk allocation, +* at btrfs_create_pending_block_groups(). So +* ignore any error here. An ENOSPC here could +* happen, due to the cases described at +* do_chunk_alloc() - the system block group we +* just created was just turned into RO mode by a +* scrub for example, or a running discard +* temporarily removed its free space entries, etc. +*/ +btrfs_chunk_alloc_add_chunk_item (trans, bg); + } } }
Greg Kroah-Hartman
maintainerPATCH 144/217 fs/proc/task_mmu: refactor pagemap_pmd_range()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes <[email protected]>
[ Upstream commit de4d6c94914f3659f0b51725e23e637d4e9f78cc ]
Separate out THP logic so we can drop an indentation level and reduce the amount of noise in this function.
We add pagemap_pmd_range_thp() for this purpose.
While we're here, convert the VM_BUG_ON() to a VM_WARN_ON_ONCE() at the same time.
No functional change intended.
Stable-dep-of: 4165b7d1c45c ("userfaultfd: wait on source PMD during UFFDIO_MOVE")
--- fs/proc/task_mmu.c | 148 +++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 70 deletions(-)
fs/proc/task_mmu.c +78 -70
@@ -1989,6 +1989,81 @@ static pagemap_entry_t pte_to_pagemap_enreturn make_pme (frame, flags); } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static int pagemap_pmd_range_thp (pmd_t *pmdp,unsigned long addr, +unsigned long end,struct vm_area_struct *vma, +struct pagemapread *pm) +{ +unsigned int idx = (addr & ~PMD_MASK ) >>PAGE_SHIFT ; +u64 flags =0 , frame =0 ; +pmd_t pmd = *pmdp; +struct page *page =NULL ; +struct folio *folio =NULL ; +int err =0 ; + +if (vma->vm_flags &VM_SOFTDIRTY ) + flags |=PM_SOFT_DIRTY ; + +if (pmd_present (pmd)) { + page =pmd_page (pmd); + + flags |=PM_PRESENT ; +if (pmd_soft_dirty (pmd)) + flags |=PM_SOFT_DIRTY ; +if (pmd_uffd_wp (pmd)) + flags |=PM_UFFD_WP ; +if (pm->show_pfn) + frame =pmd_pfn (pmd) + idx; + }else if (thp_migration_supported () &&is_swap_pmd (pmd)) { +swp_entry_t entry =pmd_to_swp_entry (pmd); +unsigned long offset; + +if (pm->show_pfn) { +if (is_pfn_swap_entry (entry)) + offset =swp_offset_pfn (entry) + idx; +else + offset =swp_offset (entry) + idx; + frame =swp_type (entry) | + (offset <<MAX_SWAPFILES_SHIFT ); + } + flags |=PM_SWAP ; +if (pmd_swp_soft_dirty (pmd)) + flags |=PM_SOFT_DIRTY ; +if (pmd_swp_uffd_wp (pmd)) + flags |=PM_UFFD_WP ; +VM_WARN_ON_ONCE (!is_pmd_migration_entry (pmd)); + page =pfn_swap_entry_to_page (entry); + } + +if (page) { + folio =page_folio (page); +if (!folio_test_anon (folio)) + flags |=PM_FILE ; + } + +for (; addr != end; addr +=PAGE_SIZE , idx++) { +u64 cur_flags = flags; +pagemap_entry_t pme; + +if (folio && (flags &PM_PRESENT ) && +__folio_page_mapped_exclusively (folio, page)) + cur_flags |=PM_MMAP_EXCLUSIVE ; + + pme =make_pme (frame, cur_flags); + err =add_to_pagemap (&pme, pm); +if (err) +break ; +if (pm->show_pfn) { +if (flags &PM_PRESENT ) + frame++; +else if (flags &PM_SWAP ) + frame += (1 <<MAX_SWAPFILES_SHIFT ); + } + } +return err; +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +static int pagemap_pmd_range (pmd_t *pmdp,unsigned long addr,unsigned long end,struct mm_walk *walk) {
@@ -1997,82 +2072,15 @@ static int pagemap_pmd_range(pmd_t *pmdpspinlock_t *ptl;pte_t *pte, *orig_pte;int err =0 ; -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#ifdef CONFIG_TRANSPARENT_HUGEPAGE ptl =pmd_trans_huge_lock (pmdp, vma);if (ptl) { -unsigned int idx = (addr & ~PMD_MASK ) >>PAGE_SHIFT ; -u64 flags =0 , frame =0 ; -pmd_t pmd = *pmdp; -struct page *page =NULL ; -struct folio *folio =NULL ; - -if (vma->vm_flags &VM_SOFTDIRTY ) - flags |=PM_SOFT_DIRTY ; - -if (pmd_present (pmd)) { - page =pmd_page (pmd); - - flags |=PM_PRESENT ; -if (pmd_soft_dirty (pmd)) - flags |=PM_SOFT_DIRTY ; -if (pmd_uffd_wp (pmd)) - flags |=PM_UFFD_WP ; -if (pm->show_pfn) - frame =pmd_pfn (pmd) + idx; - } -#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION - else if (is_swap_pmd(pmd)) { -swp_entry_t entry =pmd_to_swp_entry (pmd); -unsigned long offset; - -if (pm->show_pfn) { -if (is_pfn_swap_entry (entry)) - offset =swp_offset_pfn (entry) + idx; -else - offset =swp_offset (entry) + idx; - frame =swp_type (entry) | - (offset <<MAX_SWAPFILES_SHIFT ); - } - flags |=PM_SWAP ; -if (pmd_swp_soft_dirty (pmd)) - flags |=PM_SOFT_DIRTY ; -if (pmd_swp_uffd_wp (pmd)) - flags |=PM_UFFD_WP ; -VM_BUG_ON (!is_pmd_migration_entry (pmd)); - page =pfn_swap_entry_to_page (entry); - } -#endif - -if (page) { - folio =page_folio (page); -if (!folio_test_anon (folio)) - flags |=PM_FILE ; - } - -for (; addr != end; addr +=PAGE_SIZE , idx++) { -u64 cur_flags = flags; -pagemap_entry_t pme; - -if (folio && (flags &PM_PRESENT ) && -__folio_page_mapped_exclusively (folio, page)) - cur_flags |=PM_MMAP_EXCLUSIVE ; - - pme =make_pme (frame, cur_flags); - err =add_to_pagemap (&pme, pm); -if (err) -break ; -if (pm->show_pfn) { -if (flags &PM_PRESENT ) - frame++; -else if (flags &PM_SWAP ) - frame += (1 <<MAX_SWAPFILES_SHIFT ); - } - } + err =pagemap_pmd_range_thp (pmdp, addr, end, vma, pm);spin_unlock (ptl);return err; } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* * We can assume that @vma always points to a valid one and @end never