6.6.153-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainercover 6.6.153-rc1 review
This is the start of the stable review cycle for the 6.6.153 release. There are 166 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.6.153-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.6.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 6.6.153-rc1
Paolo Abeni <[email protected]>
net: harmonize tstats and dstats
Christian Brauner <[email protected]>
binfmt_misc: use exe_file_deny_write_access() for the interpreter clone
Baul Lee <[email protected]>
net/x25: fix use-after-free of the socket by its timers
Gao Xiang <[email protected]>
erofs: fix EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS on some UP platforms
Jamal Hadi Salim <[email protected]>
net/sched: cls_bpf: reject dev-bound programs bound to a different device
Siddharth Vadapalli <[email protected]>
net: ethernet: ti: am65-cpsw-nuss: Fix port_id extraction from SRC TAG
Uwe Kleine-König <[email protected]>
m68k: Define NR_CPUS to 1
Christoph Hellwig <[email protected]>
m68k: use the coherent DMA code for coldfire without data cache
Christoph Hellwig <[email protected]>
dma-direct: add a CONFIG_ARCH_HAS_DMA_ALLOC symbol
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
Victor Nogueira <[email protected]>
net: sched: Add initial TC error skb drop reasons
Victor Nogueira <[email protected]>
net: sched: Move drop_reason to struct tc_skb_cb
Yan Zhai <[email protected]>
packet: add a generic drop reason for receive
Jamal Hadi Salim <[email protected]>
net, sched: Fix SKB_NOT_DROPPED_YET splat under debug config
Daniel Borkmann <[email protected]>
net, sched: Add tcf_set_drop_reason for {__,}tcf_classify
Daniel Borkmann <[email protected]>
net, sched: Make tc-related drop reason more flexible
Eric Dumazet <[email protected]>
af_packet: Don't send zero-byte data in tpacket_snd().
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
Wei Fang <[email protected]>
net: packet: fix wrong transport_header when sending VLAN-tagged frame
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
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
Herbert Xu <[email protected]>
crypto: ccm - Set rfc4309 maxauthsize from child
Jon Hunter <[email protected]>
arm64: tegra: Add EL2 virtual timer interrupt for Tegra194
Lorenzo Stoakes (ARM) <[email protected]>
mm/huge_memory: fix huge_zero_pfn race
Jérémy Jean <[email protected]>
tls: rx: restore msg_iter before TLS 1.3 optimistic retry
Sabrina Dubroca <[email protected]>
selftests: tls: add rekey tests
Paolo Bonzini <[email protected]>
KVM: SVM: Serialize accesses to the owner and mirror list with separate lock
Lorenzo Stoakes (ARM) <[email protected]>
mm/ptdump: always stabilise against page table freeing using init_mm
Lorenzo Stoakes (ARM) <[email protected]>
mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF
Lorenzo Stoakes <[email protected]>
mm/pagewalk: split walk_page_range_novma() into kernel/user parts
Pierre-Eric Pelloux-Prayer <[email protected]>
drm/amdgpu: move debug_vm handling to amdgpu_cs_parser_fini
Yang Wang <[email protected]>
drm/amd/pm: fix pptable use-after-free
Yang Wang <[email protected]>
drm/amd/pm: fix torn gpu metrics reads
Tu Nguyen <[email protected]>
can: rcar_canfd: change the initializing flow for clocks and resets
Jonas Gorski <[email protected]>
i2c: iproc: reset bus after timeout if START_BUSY is stuck
Wolfram Sang <[email protected]>
i2c: bcm-iproc: remove printout on handled timeouts
Eric Dumazet <[email protected]>
vxlan: use pskb_network_may_pull() for transmit path header pulls
Guillaume Nault <[email protected]>
vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
Guillaume Nault <[email protected]>
vrf: Make pcpu_dstats update functions available to other modules.
Jeremy Kerr <[email protected]>
net: core,vrf: Change pcpu_dstat fields to u64_stats_t
Breno Leitao <[email protected]>
vxlan: Do not alloc tstats manually
Dawid Osuchowski <[email protected]>
ice: fix VF interrupts cleanup
Christian Brauner <[email protected]>
binfmt_misc: restore write access when removing an entry
Amir Goldstein <[email protected]>
fs: don't block write during exec on pre-content watched files
Matt Fleming <[email protected]>
veth: convert frag_list skbs before running XDP
Chengfeng Ye <[email protected]>
net: pktgen: fix proc entry use-after-free
Peter Seiderer <[email protected]>
net: pktgen: fix code style (WARNING: Block comments)
Namjae Jeon <[email protected]>
ksmbd: reject repeated SMB2 NEGOTIATE requests
Namjae Jeon <[email protected]>
ksmbd: conn lock to serialize smb2 negotiate
David Carlier <[email protected]>
igc: remove napi_synchronize() in igc_down()
Mark Brown <[email protected]>
ASoC: tas2562: Validate values for volume writes
Chengfeng Ye <[email protected]>
Bluetooth: hci_sync: Fix advertising data UAFs
Luiz Augusto von Dentz <[email protected]>
Bluetooth: eir: Fix possible crashes on eir_create_adv_data
Luiz Augusto von Dentz <[email protected]>
Bluetooth: hci_core: Fix not handling hdev->le_num_of_adv_sets=1
Gustavo A. R. Silva <[email protected]>
Bluetooth: hci_conn, hci_sync: Use __counted_by() to avoid -Wfamnae warnings
Kees Cook <[email protected]>
overflow: Change DEFINE_FLEX to take __counted_by member
Maciej Fijalkowski <[email protected]>
ice: make ice_vsi_cfg_rxq() static
Przemek Kitszel <[email protected]>
ice: make use of DEFINE_FLEX() in ice_switch.c
Kefeng Wang <[email protected]>
mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
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()
Naohiro Aota <[email protected]>
btrfs: add space_info argument to btrfs_chunk_alloc()
David Sterba <[email protected]>
btrfs: add debug build only WARN
Yuxiang Yang <[email protected]>
tcp: challenge ACK for non-exact RST in SYN-RECEIVED
Ilpo Järvinen <[email protected]>
tcp: fast path functions later
Ilpo Järvinen <[email protected]>
tcp: Pass flags to __tcp_send_ack
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
ChenXiaoSong <[email protected]>
smb/server: rename include guard in smb_common.h
ZhangGuoDong <[email protected]>
smb: move get_rfc1002_len() to common/smbglob.h
ZhangGuoDong <[email protected]>
smb: move smb_version_values to common/smbglob.h
Christian Brauner <[email protected]>
super: fix emergency thaw deadlock on frozen block devices
Aldo Ariel Panzardo <[email protected]>
net/sched: serialize qdisc_rtab_list against concurrent get/put
Shiming Cheng <[email protected]>
net: gro: fix double aggregation of flush-marked skbs
Felix Fietkau <[email protected]>
net: move skb_gro_receive_list from udp to core
Pavitra Jha <[email protected]>
libceph: fix two unsafe bare decodes in decode_lockers()
Mike Rapoport (Microsoft) <[email protected]>
userfaultfd: prevent registration of special VMAs
Mike Rapoport (Microsoft) <[email protected]>
userfaultfd: move vma_can_userfault out of line
Chunyan Zhang <[email protected]>
mm: userfaultfd: add pgtable_supports_uffd_wp()
Zhang Yi <[email protected]>
iomap: fix out-of-bounds bitmap_set() with zero-length range
Matthew Wilcox (Oracle) <[email protected]>
iomap: hold state_lock over call to ifs_set_range_uptodate()
Chancel Liu <[email protected]>
ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP
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
Matthew Wilcox (Oracle) <[email protected]>
ceph: Use a folio in ceph_page_mkwrite()
Max Kellermann <[email protected]>
ceph: fix hanging __ceph_get_caps() with stale mds_wanted
Matthew Wilcox (Oracle) <[email protected]>
ceph: Remove ceph_writepage()
Max Kellermann <[email protected]>
ceph: avoid fs reclaim while using current->journal_info
Sabrina Dubroca <[email protected]>
selftests: tls: add test with a partially invalid iov
Palmer Dabbelt <[email protected]>
RISC-V: Provide pgtable_l5_enabled on rv32
Christoph Hellwig <[email protected]>
xfs: check v5 superblock features early
Long Li <[email protected]>
xfs: don't swallow dquot recovery verification errors
Long Li <[email protected]>
xfs: fix ilock leak on error in xfs_dq_get_next_id
Darrick J. Wong <[email protected]>
xfs: only check mergeability of bnobt records
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
David Rosca <[email protected]>
drm/amdgpu: Reject UVD message with invalid number of h265 refs
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 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
Guangshuo Li <[email protected]>
drm/radeon: fix autosuspend cleanup during teardown
Pei Xiao <[email protected]>
mmc: atmel-mci: Fix use-after-free in atmci_remove due to race condition
Haibo Chen <[email protected]>
mmc: sdhci: make tuning_err a signed int
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()
Thorsten Blum <[email protected]>
crypto: qce - fix error path in devm_qce_register_algs
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: lparcfg - fix kbuf[] underflow
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
Kyohei Kadota <[email protected]>
Input: xpad - add support for ZENAIM LEVERLESS
Asad Kamal <[email protected]>
drm/amdgpu: fix aperture iounmap skipped on device removal
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: 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
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
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
Erni Sri Satya Vennela <[email protected]>
net: mana: Fix EQ leak in mana_remove on NULL port
Yizhou Zhao <[email protected]>
ipvs: separate destination availability state
Chao Yu <[email protected]>
f2fs: fix UAF issue in f2fs_merge_page_bio()
Chao Shi <[email protected]>
block: stop the timeout timer when releasing a never added disk
-------------
Diffstat:
Makefile | 4 +- arch/arm/Kconfig | 1 + arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 + arch/m68k/Kconfig | 7 +- arch/m68k/Kconfig.cpu | 16 + arch/m68k/kernel/Makefile | 2 +- arch/m68k/kernel/dma.c | 2 +- arch/openrisc/include/asm/processor.h | 2 + arch/openrisc/kernel/dma.c | 4 +- arch/openrisc/kernel/signal.c | 5 +- arch/parisc/Kconfig | 1 + arch/powerpc/platforms/pseries/lparcfg.c | 2 +- arch/powerpc/platforms/pseries/pci.c | 2 +- arch/riscv/include/asm/pgtable-32.h | 3 + arch/riscv/include/asm/pgtable.h | 1 - arch/riscv/mm/init.c | 2 + arch/riscv/mm/pageattr.c | 8 +- arch/x86/kvm/svm/sev.c | 34 +- arch/x86/kvm/svm/svm.h | 1 + block/genhd.c | 12 +- crypto/ccm.c | 2 +- drivers/crypto/qce/core.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 34 +- 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/vce_v3_0.c | 26 +- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 27 +- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 16 +- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 6 +- drivers/gpu/drm/radeon/radeon_kms.c | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 11 +- 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/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/omap_hsmmc.c | 2 +- drivers/mmc/host/sdhci.c | 16 + drivers/mmc/host/sdhci.h | 2 +- drivers/net/can/rcar/rcar_canfd.c | 28 +- drivers/net/ethernet/intel/ice/ice_base.c | 58 ++- drivers/net/ethernet/intel/ice/ice_base.h | 3 +- drivers/net/ethernet/intel/ice/ice_lib.c | 56 --- drivers/net/ethernet/intel/ice/ice_lib.h | 4 - drivers/net/ethernet/intel/ice/ice_switch.c | 63 +-- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 27 + .../net/ethernet/intel/ice/ice_vf_lib_private.h | 1 + drivers/net/ethernet/intel/ice/ice_virtchnl.c | 21 + drivers/net/ethernet/intel/ice/ice_xsk.c | 2 +- drivers/net/ethernet/intel/igc/igc_main.c | 1 - drivers/net/ethernet/microsoft/mana/mana_en.c | 4 +- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 + drivers/net/ipvlan/ipvlan_main.c | 4 + drivers/net/macvlan.c | 4 + drivers/net/veth.c | 4 +- drivers/net/vrf.c | 49 +- drivers/net/vxlan/vxlan_core.c | 45 +- drivers/net/vxlan/vxlan_mdb.c | 4 +- drivers/s390/cio/vfio_ccw_async.c | 16 + drivers/s390/cio/vfio_ccw_chp.c | 17 +- drivers/s390/cio/vfio_ccw_cp.c | 53 +- drivers/s390/cio/vfio_ccw_cp.h | 8 + drivers/s390/cio/vfio_ccw_drv.c | 15 +- drivers/s390/cio/vfio_ccw_fsm.c | 8 +- drivers/s390/cio/vfio_ccw_ops.c | 35 +- drivers/s390/cio/vfio_ccw_private.h | 6 +- drivers/s390/net/qeth_core_main.c | 3 + drivers/s390/net/qeth_l3_main.c | 5 + drivers/video/fbdev/core/fb_io_fops.c | 8 + fs/binfmt_elf.c | 4 +- fs/binfmt_elf_fdpic.c | 4 +- fs/binfmt_misc.c | 14 +- fs/btrfs/block-group.c | 61 ++- fs/btrfs/block-group.h | 3 +- fs/btrfs/extent-tree.c | 6 +- fs/btrfs/messages.h | 7 + fs/btrfs/space-info.c | 2 +- fs/btrfs/transaction.c | 5 +- fs/btrfs/zoned.c | 5 +- fs/btrfs/zoned.h | 6 +- fs/ceph/addr.c | 54 +- fs/ceph/caps.c | 17 +- fs/ceph/file.c | 9 +- fs/ceph/mds_client.c | 11 + fs/ceph/mds_client.h | 2 + fs/ceph/mdsmap.c | 2 +- fs/erofs/Kconfig | 3 +- fs/exec.c | 6 +- fs/f2fs/data.c | 2 +- fs/iomap/buffered-io.c | 42 +- fs/smb/client/cifsglob.h | 27 - fs/smb/client/cifssmb.c | 6 +- fs/smb/client/connect.c | 2 +- fs/smb/client/transport.c | 8 +- fs/smb/common/cifsglob.h | 36 ++ fs/smb/server/auth.c | 4 +- fs/smb/server/connection.c | 23 +- fs/smb/server/connection.h | 5 + fs/smb/server/oplock.c | 8 +- fs/smb/server/smb2misc.c | 2 +- fs/smb/server/smb2ops.c | 32 +- fs/smb/server/smb2pdu.c | 88 ++-- fs/smb/server/smb2pdu.h | 9 - fs/smb/server/smb_common.c | 43 +- fs/smb/server/smb_common.h | 43 +- fs/super.c | 22 +- fs/userfaultfd.c | 20 +- fs/xfs/libxfs/xfs_sb.c | 4 +- fs/xfs/scrub/alloc.c | 5 +- fs/xfs/xfs_dquot.c | 3 +- fs/xfs/xfs_dquot_item_recover.c | 2 +- include/asm-generic/pgtable_uffd.h | 17 + include/linux/fs.h | 12 + include/linux/mm_inline.h | 7 +- include/linux/mmap_lock.h | 4 + include/linux/netdevice.h | 52 +- include/linux/overflow.h | 52 ++ include/linux/pagewalk.h | 7 +- include/linux/userfaultfd_k.h | 19 +- include/net/bluetooth/hci.h | 8 +- include/net/bluetooth/hci_core.h | 1 + include/net/dropreason-core.h | 21 + include/net/gro.h | 1 + include/net/ip_vs.h | 7 + include/net/pkt_cls.h | 16 + include/net/pkt_sched.h | 3 +- include/net/sch_generic.h | 2 - include/net/tcp.h | 58 +-- include/uapi/linux/ip_vs.h | 6 - kernel/dma/Kconfig | 9 + kernel/dma/direct.c | 12 +- kernel/fork.c | 12 +- kernel/trace/ftrace.c | 9 +- lib/overflow_kunit.c | 19 + mm/huge_memory.c | 49 +- mm/internal.h | 7 + mm/migrate_device.c | 5 +- mm/pagewalk.c | 82 ++- mm/ptdump.c | 10 +- mm/userfaultfd.c | 26 + mm/vmalloc.c | 49 +- net/bluetooth/eir.c | 7 +- net/bluetooth/eir.h | 2 +- net/bluetooth/hci_core.c | 9 + net/bluetooth/hci_event.c | 3 +- net/bluetooth/hci_sync.c | 237 +++++---- net/ceph/cls_lock_client.c | 21 +- net/ceph/decode.c | 18 +- net/ceph/osdmap.c | 9 +- net/core/dev.c | 29 +- net/core/gro.c | 31 ++ net/core/pktgen.c | 43 +- net/ipv4/bpf_tcp_ca.c | 2 +- net/ipv4/tcp_dctcp.h | 2 +- net/ipv4/tcp_input.c | 56 ++- net/ipv4/tcp_minisocks.c | 12 +- net/ipv4/tcp_output.c | 6 +- net/ipv4/udp_offload.c | 29 -- net/mptcp/fastopen.c | 7 +- net/mptcp/options.c | 67 ++- 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 | 27 +- net/sched/act_api.c | 13 +- net/sched/cls_api.c | 32 +- net/sched/cls_bpf.c | 18 +- net/sched/cls_u32.c | 3 + net/sched/sch_api.c | 24 +- net/tls/tls_sw.c | 7 + net/x25/af_x25.c | 4 +- net/x25/x25_timer.c | 25 +- security/selinux/ss/policydb.c | 31 ++ security/selinux/ss/services.c | 28 +- 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/fsl/fsl_sai.c | 29 +- sound/soc/sof/sof-audio.c | 9 +- sound/soc/xilinx/xlnx_formatter_pcm.c | 10 +- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 +- tools/testing/selftests/net/tls.c | 549 +++++++++++++++++++++ 200 files changed, 2659 insertions(+), 1145 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/166 block: stop the timeout timer when releasing a never added disk
6.6-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
@@ -1174,14 +1174,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 2/166 f2fs: fix UAF issue in f2fs_merge_page_bio()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit edf7e9040fc52c922db947f9c6c36f07377c52ea upstream.
As JY reported in bugzilla [1],
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 pc : [0xffffffe51d249484] f2fs_is_cp_guaranteed+0x70/0x98 lr : [0xffffffe51d24adbc] f2fs_merge_page_bio+0x520/0x6d4 CPU: 3 UID: 0 PID: 6790 Comm: kworker/u16:3 Tainted: P B W OE 6.12.30-android16-5-maybe-dirty-4k #1 5f7701c9cbf727d1eebe77c89bbbeb3371e895e5 Tainted: [P]=PROPRIETARY_MODULE, [B]=BAD_PAGE, [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Workqueue: writeback wb_workfn (flush-254:49) Call trace: f2fs_is_cp_guaranteed+0x70/0x98 f2fs_inplace_write_data+0x174/0x2f4 f2fs_do_write_data_page+0x214/0x81c f2fs_write_single_data_page+0x28c/0x764 f2fs_write_data_pages+0x78c/0xce4 do_writepages+0xe8/0x2fc __writeback_single_inode+0x4c/0x4b4 writeback_sb_inodes+0x314/0x540 __writeback_inodes_wb+0xa4/0xf4 wb_writeback+0x160/0x448 wb_workfn+0x2f0/0x5dc process_scheduled_works+0x1c8/0x458 worker_thread+0x334/0x3f0 kthread+0x118/0x1ac ret_from_fork+0x10/0x20
[1] https://bugzilla.kernel.org/show_bug.cgi?id=220575
The panic was caused by UAF issue w/ below race condition:
kworker
- writepages
- f2fs_write_cache_pages
- f2fs_write_single_data_page
- f2fs_do_write_data_page
- f2fs_inplace_write_data
- f2fs_merge_page_bio
- add_inu_page
: cache page #1 into bio & cache bio in
io->bio_list
- f2fs_write_single_data_page
- f2fs_do_write_data_page
- f2fs_inplace_write_data
- f2fs_merge_page_bio
- add_inu_page
: cache page #2 into bio which is linked
in io->bio_list
write
- f2fs_write_begin
: write page #1
- f2fs_folio_wait_writeback
- f2fs_submit_merged_ipu_write
- f2fs_submit_write_bio
: submit bio which inclues page #1 and #2
software IRQ
- f2fs_write_end_io
- fscrypt_free_bounce_page
: freed bounced page which belongs to page #2
- inc_page_count( , WB_DATA_TYPE(data_folio), false)
: data_folio points to fio->encrypted_page
the bounced page can be freed before
accessing it in f2fs_is_cp_guarantee()
It can reproduce w/ below testcase:
Run below script in shell #1:
for ((i=1;i>0;i++)) do xfs_io -f /mnt/f2fs/enc/file \
-c "pwrite 0 32k" -c "fdatasync"
Run below script in shell #2:
for ((i=1;i>0;i++)) do xfs_io -f /mnt/f2fs/enc/file \
-c "pwrite 0 32k" -c "fdatasync"
So, in f2fs_merge_page_bio(), let's avoid using fio->encrypted_page after commit page into internal ipu cache.
--- fs/f2fs/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/f2fs/data.c +1 -1
@@ -948,7 +948,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)if (fio->io_wbc)wbc_account_cgroup_owner (fio->io_wbc, fio->page,PAGE_SIZE ); -inc_page_count (fio->sbi,WB_DATA_TYPE (page, false)); +inc_page_count (fio->sbi,WB_DATA_TYPE (fio->page, false)); *fio->last_block = fio->new_blkaddr; *fio->bio = bio;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 3/166 ipvs: separate destination availability state
In reply to Greg Kroah-Hartman6.6-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
@@ -758,7 +758,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 "
@@ -1401,7 +1401,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;
@@ -2026,7 +2026,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 4/166 net: mana: Fix EQ leak in mana_remove on NULL port
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit 65267c9c4f28199985505977bc2c628c82fc50ef ]
In mana_remove(), when a NULL port is encountered in the port iteration loop, 'goto out' skips the mana_destroy_eq(ac) call, leaking the event queues allocated earlier by mana_create_eq().
This can happen when mana_probe_port() fails for port 0, leaving ac->ports[0] as NULL. On driver unload or error cleanup, mana_remove() hits the NULL entry and jumps past mana_destroy_eq().
Change 'goto out' to 'break' so the for-loop exits normally and mana_destroy_eq() is always reached. Remove the now-unreferenced out:
label.
[ hmahfooz: resolve conflict in mana_remove() due to missing commit
3b194343c250 ("net: mana: Implement ndo_tx_timeout and serialize queue resets per port.") ]
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +2 -2
@@ -2931,7 +2931,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)if (!ndev) {if (i ==0 )dev_err (dev,"No net device to remove\n" ); - goto out; +break ; }/* All cleanup actions should stay after rtnl_lock(), otherwise
@@ -2958,7 +2958,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) }mana_destroy_eq (ac); -out: +mana_gd_deregister_device (gd);if (suspending)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 5/166 selinux: require every boolean value to be defined
In reply to Greg Kroah-Hartman6.6-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
@@ -715,6 +715,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("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
@@ -770,6 +771,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 6/166 selinux: reject a class permission count below its inherited common
In reply to Greg Kroah-Hartman6.6-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
@@ -1351,6 +1351,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 7/166 selinux: do not cancel a policy conversion that never started
In reply to Greg Kroah-Hartman6.6-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
@@ -2157,7 +2157,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 8/166 selinux: reject an unclaimed class value in security_get_classes()
In reply to Greg Kroah-Hartman6.6-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
@@ -3349,6 +3349,7 @@ int security_get_classes(struct selinux_ char ***classes, u32 *nclasses) { struct policydb *policydb; +u32 i;int rc; policydb = &policy->policydb;
@@ -3361,16 +3362,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 9/166 selftests: mptcp: join: mark tests with data corruption as failed
In reply to Greg Kroah-Hartman6.6-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
@@ -573,7 +573,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):"
@@ -584,7 +584,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 10/166 mptcp: avoid combining some incoming suboptions
In reply to Greg Kroah-Hartman6.6-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 ;
@@ -1415,7 +1472,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
@@ -36,6 +36,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 11/166 mptcp: options: reset DSS fields in case of unexpected size
In reply to Greg Kroah-Hartman6.6-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 12/166 mptcp: fastopen: only mark MPTFO subflows with SYN data
In reply to Greg Kroah-Hartman6.6-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 13/166 s390/qeth: validate user buffer length in SNMP and ARP query ioctls
In reply to Greg Kroah-Hartman6.6-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
@@ -4710,6 +4710,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
@@ -1415,6 +1415,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 14/166 ASoC: SOF: sof-audio: Fix error path in sof_widget_setup_unlocked()
In reply to Greg Kroah-Hartman6.6-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
@@ -139,7 +139,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;
@@ -218,9 +217,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);
@@ -235,8 +235,7 @@ pipe_widget_free: } } use_count_dec: -if (!use_count_decremented) - swidget->use_count--; + swidget->use_count--;return ret; }
Greg Kroah-Hartman
maintainerPATCH 15/166 ASoC: cs4265: sort the register default table
In reply to Greg Kroah-Hartman6.6-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 16/166 ASoC: cs35l45: sort the register default table
In reply to Greg Kroah-Hartman6.6-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 },
@@ -113,6 +97,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 17/166 ASoC: cs35l41: sort the register default table
In reply to Greg Kroah-Hartman6.6-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
@@ -23,9 +23,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 18/166 ASoC: codecs: lpass-wsa-macro: Fix enum kcontrol accesses
In reply to Greg Kroah-Hartman6.6-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
@@ -1859,7 +1859,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 ; }
@@ -1870,7 +1870,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 ; }
@@ -1884,7 +1884,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 ; }
@@ -1898,7 +1898,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;struct wsa_macro *wsa =snd_soc_component_get_drvdata (component);
Greg Kroah-Hartman
maintainerPATCH 19/166 fbdev: core: Fix pointer desynchronization in fb_io_read()
In reply to Greg Kroah-Hartman6.6-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
@@ -57,6 +57,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 20/166 drm/amdgpu: fix aperture iounmap skipped on device removal
In reply to Greg Kroah-Hartman6.6-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
@@ -2044,8 +2044,6 @@ int amdgpu_ttm_init(struct amdgpu_device*/ void amdgpu_ttm_fini (struct amdgpu_device *adev) { -int idx; -if (!adev->mman.initialized)return ;
@@ -2068,13 +2066,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); }amdgpu_vram_mgr_fini (adev);
Greg Kroah-Hartman
maintainerPATCH 21/166 Input: xpad - add support for ZENAIM LEVERLESS
In reply to Greg Kroah-Hartman6.6-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
@@ -417,6 +417,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 },
@@ -575,6 +576,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(0x413d), /* Black Shark Green Ghost Controller */
Greg Kroah-Hartman
maintainerPATCH 22/166 powerpc/pseries: pci - logic bug
In reply to Greg Kroah-Hartman6.6-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
@@ -159,7 +159,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 23/166 Input: synaptics-rmi4 - fix F55 transmitter electrode count typo
In reply to Greg Kroah-Hartman6.6-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 24/166 Input: focaltech - fix array out-of-bounds in focaltech_process_rel_packet
In reply to Greg Kroah-Hartman6.6-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 25/166 Input: psxpad-spi - set driver data before use
In reply to Greg Kroah-Hartman6.6-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
@@ -369,6 +369,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 26/166 Input: atkbd - skip deactivate for Xiaomi Book Pro 14s internal keyboard
In reply to Greg Kroah-Hartman6.6-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
@@ -1959,6 +1959,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 27/166 Input: iforce - validate input packet lengths
In reply to Greg Kroah-Hartman6.6-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
@@ -161,6 +161,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,
@@ -176,6 +179,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 ]);
@@ -187,6 +193,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);
@@ -206,7 +215,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
@@ -159,6 +159,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 28/166 powerpc/pseries: lparcfg - fix kbuf[] underflow
In reply to Greg Kroah-Hartman6.6-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
@@ -673,7 +673,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 29/166 Input: synaptics-rmi4 - zero report size on F54 work error
In reply to Greg Kroah-Hartman6.6-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
@@ -547,7 +547,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 */ }/*
@@ -558,7 +558,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)) {
@@ -566,7 +566,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" );
@@ -581,7 +581,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 +
@@ -590,16 +590,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 30/166 Input: synaptics-rmi4 - bound the F54 report size to the allocated buffer
In reply to Greg Kroah-Hartman6.6-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;
@@ -550,6 +551,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.
@@ -680,8 +688,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 31/166 Input: synaptics-rmi4 - block s_input when F54 queue is busy
In reply to Greg Kroah-Hartman6.6-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
@@ -447,7 +447,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 32/166 Input: synaptics-rmi4 - propagate F54 worker errors to V4L2 queue
In reply to Greg Kroah-Hartman6.6-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" );
@@ -612,6 +619,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 33/166 Input: hynitron_cstxxx - validate touch count and finger IDs
In reply to Greg Kroah-Hartman6.6-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 34/166 crypto: qce - fix error path in devm_qce_register_algs
In reply to Greg Kroah-Hartman6.6-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
@@ -58,7 +58,7 @@ static int qce_register_algs(struct qce_ 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 35/166 libceph: fix multiple unsafe decodes in decode_locker()
In reply to Greg Kroah-Hartman6.6-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 36/166 ftrace: Protect direct_functions in ftrace_find_rec_direct
In reply to Greg Kroah-Hartman6.6-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
@@ -2562,7 +2562,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 37/166 ftrace: Fix off-by-one fentry site disable in ftrace_free_mem()
In reply to Greg Kroah-Hartman6.6-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
@@ -7250,7 +7250,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;
@@ -7260,6 +7261,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 38/166 openrisc: signal: do not restore privileged SR bits on sigreturn
In reply to Greg Kroah-Hartman6.6-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
@@ -42,6 +42,7 @@ asmlinkage int do_work_pending(struct ptstatic 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 */
@@ -57,8 +58,8 @@ static int restore_sigcontext(struct pt_ err |=__copy_from_user (®s->sr, &sc->regs.sr,sizeof (unsigned long )); err |=__copy_from_user (®s->fpcsr, &sc->fpcsr,sizeof (unsigned long )); -/* 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 39/166 Input: sur40 - fix input device registration ordering
In reply to Greg Kroah-Hartman6.6-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 40/166 Input: sur40 - fix V4L error path cleanup
In reply to Greg Kroah-Hartman6.6-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 41/166 libceph: Avoid using invalid osd indices from primary_temp
In reply to Greg Kroah-Hartman6.6-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 42/166 ceph: fix MDS random selection readiness predicate
In reply to Greg Kroah-Hartman6.6-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 43/166 libceph: tolerate addrvecs with multiple entries of the same type
In reply to Greg Kroah-Hartman6.6-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 44/166 mmc: omap_hsmmc: fix busy_timeout overflow in ns conversion on 32-bit
In reply to Greg Kroah-Hartman6.6-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
@@ -1358,7 +1358,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 45/166 mmc: sdhci: unmap the bounce buffer before device release
In reply to Greg Kroah-Hartman6.6-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
@@ -4152,6 +4152,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;
@@ -4206,6 +4214,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 46/166 mmc: sdhci: make tuning_err a signed int
In reply to Greg Kroah-Hartman6.6-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
@@ -606,7 +606,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 47/166 mmc: atmel-mci: Fix use-after-free in atmci_remove due to race condition
In reply to Greg Kroah-Hartman6.6-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
@@ -2658,6 +2658,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 (&pdev->dev);
Greg Kroah-Hartman
maintainerPATCH 48/166 drm/radeon: fix autosuspend cleanup during teardown
In reply to Greg Kroah-Hartman6.6-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 49/166 s390/vfio_ccw: Free all memory if cp_init() fails
In reply to Greg Kroah-Hartman6.6-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
@@ -452,9 +452,6 @@ static int ccwchain_handle_ccw(u32 cda,/* Loop for tics on this new chain. */ ret =ccwchain_loop_tic (chain, cp); -if (ret) -ccwchain_free (chain); -return ret; }
@@ -483,6 +480,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) {
@@ -729,7 +743,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 50/166 s390/vfio_ccw: Limit the number of channel program segments
In reply to Greg Kroah-Hartman6.6-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
@@ -331,6 +331,7 @@ static struct ccwchain *ccwchain_alloc(s goto out_err;list_add_tail (&chain->next, &cp->ccwchain_list); + cp->ccwchain_count++;return chain;
@@ -438,6 +439,10 @@ static int ccwchain_handle_ccw(u32 cda,if (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)
@@ -739,6 +744,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 51/166 s390/vfio_ccw: Cancel existing workqueues
In reply to Greg Kroah-Hartman6.6-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 52/166 s390/vfio_ccw: Ensure index for read/write regions are within range
In reply to Greg Kroah-Hartman6.6-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 53/166 s390/vfio_ccw: Fix out of bounds check on CCW array
In reply to Greg Kroah-Hartman6.6-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
@@ -376,11 +376,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
@@ -390,15 +388,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 54/166 s390/vfio_ccw: Move cp cleanup out of not operational
In reply to Greg Kroah-Hartman6.6-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,1 ); } +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 55/166 s390/vfio_ccw: Selectively expand io_mutex
In reply to Greg Kroah-Hartman6.6-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
@@ -953,17 +953,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,1 );
@@ -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 56/166 drm/amdgpu: Reject UVD message with invalid number of h265 refs
In reply to Greg Kroah-Hartman6.6-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
@@ -795,6 +795,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 57/166 drm/amdgpu: validate GEM_CREATE domain combinations
In reply to Greg Kroah-Hartman6.6-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
@@ -273,6 +273,25 @@ static const struct drm_gem_object_funcs .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. */
@@ -308,6 +327,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 58/166 drm/amdgpu: Reject UVD message with dimensions above 4096
In reply to Greg Kroah-Hartman6.6-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
@@ -647,8 +647,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 59/166 drm/amdgpu: Implement insert_end for VCE 3
In reply to Greg Kroah-Hartman6.6-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
@@ -873,6 +873,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) {
@@ -882,7 +899,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)
@@ -952,17 +968,19 @@ static const struct amdgpu_ring_funcs vc .set_wptr = vce_v3_0_ring_set_wptr, .parse_cs = 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 60/166 drm/amdgpu: Fix UVD min buffer sizes
In reply to Greg Kroah-Hartman6.6-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
@@ -967,15 +967,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 ; }
@@ -1105,11 +1106,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 61/166 drm/amdgpu: Fix UVD dpb min size calculation for H264
In reply to Greg Kroah-Hartman6.6-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
@@ -638,11 +638,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 ;
@@ -661,35 +659,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;
@@ -739,35 +711,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 62/166 drm/amdgpu: Fix UVD decode image min size calculation
In reply to Greg Kroah-Hartman6.6-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
@@ -754,7 +754,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 ; }
@@ -766,7 +766,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 63/166 drm/amdgpu: disallow multiple FENCE chunks in one submit
In reply to Greg Kroah-Hartman6.6-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
@@ -253,6 +253,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 64/166 xfs: only check mergeability of bnobt records
In reply to Greg Kroah-Hartman6.6-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
@@ -124,7 +124,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 (bs->cur, &irec) !=NULL ) {
@@ -132,7 +132,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 65/166 xfs: fix ilock leak on error in xfs_dq_get_next_id
In reply to Greg Kroah-Hartman6.6-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
@@ -723,7 +723,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 */
@@ -734,6 +734,7 @@ xfs_dq_get_next_id( error = -ENOENT ; } +out_unlock:xfs_iunlock (quotip, lock_flags);return error;
Greg Kroah-Hartman
maintainerPATCH 66/166 xfs: dont swallow dquot recovery verification errors
In reply to Greg Kroah-Hartman6.6-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 67/166 xfs: check v5 superblock features early
In reply to Greg Kroah-Hartman6.6-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
@@ -865,10 +865,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 68/166 RISC-V: Provide pgtable_l5_enabled on rv32
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Palmer Dabbelt <[email protected]>
commit 10128f8b1663a8bce27df051c750d116bb8cd737 upstream.
A few of the other page table level helpers are defined on rv32, but not pgtable_l5_enabled. This adds the definition as a constant and converts pgtable_l4_enabled to a constant as well.
[ Ben: Applies unchanged; needed by both 6.1.y and 6.6.y. Both trees took
commit e59e5e2754bf ("riscv: correct pt_level name via pgtable_l5/4_enabled") -- 6.1.y as of v6.1.64 -- without this prerequisite from the same series, so arch/riscv/mm/ptdump.c fails to build on rv32 whenever CONFIG_PTDUMP_CORE is enabled:
arch/riscv/mm/ptdump.c: In function 'ptdump_init':
arch/riscv/mm/ptdump.c:387:28: error: 'pgtable_l5_enabled' undeclared (first use in this function); did you mean 'pgtable_l4_enabled'?
Only pgtable_l5_enabled fails because pgtable_l4_enabled still has an unconditional extern in asm/pgtable.h; this patch removes that and provides both as constants for rv32. The only assignments to them, in disable_pgtable_l4/l5(), are already inside
#if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL), so making them const on rv32 is safe. v6.12 and later are unaffected. ]
--- arch/riscv/include/asm/pgtable-32.h | 3 +++ arch/riscv/include/asm/pgtable.h | 1 - arch/riscv/mm/init.c | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-)
arch/riscv/include/asm/pgtable-32.h +3 -0
@@ -33,4 +33,7 @@ _PAGE_WRITE | _PAGE_EXEC | \ _PAGE_USER | _PAGE_GLOBAL)) +static const __maybe_unused int pgtable_l4_enabled; +static const __maybe_unused int pgtable_l5_enabled; +#endif /* _ASM_RISCV_PGTABLE_32_H */
arch/riscv/include/asm/pgtable.h +0 -1
@@ -905,7 +905,6 @@ extern uintptr_t _dtb_early_pa;#define dtb_early_pa _dtb_early_pa#endif /* CONFIG_XIP_KERNEL */ extern u64 satp_mode; -extern bool pgtable_l4_enabled;void paging_init (void );void misc_mem_init (void );
arch/riscv/mm/init.c +2 -0
@@ -50,10 +50,12 @@ u64 satp_mode __ro_after_init = SATP_MOD#endif EXPORT_SYMBOL (satp_mode); +#ifdef CONFIG_64BIT bool pgtable_l4_enabled =IS_ENABLED (CONFIG_64BIT ) && !IS_ENABLED (CONFIG_XIP_KERNEL );bool pgtable_l5_enabled =IS_ENABLED (CONFIG_64BIT ) && !IS_ENABLED (CONFIG_XIP_KERNEL );EXPORT_SYMBOL (pgtable_l4_enabled);EXPORT_SYMBOL (pgtable_l5_enabled); +#endif phys_addr_t phys_ram_base__ro_after_init ;EXPORT_SYMBOL (phys_ram_base);
Greg Kroah-Hartman
maintainerPATCH 69/166 selftests: tls: add test with a partially invalid iov
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
[ Upstream commit dc54b813df63020e946ccdef35b64d4fa99fd622 ]
Make sure that we don't return more bytes than we actually received if the userspace buffer was bogus. We expect to receive at least the rest of rec1, and possibly some of rec2 (currently, we don't, but that would be ok).
Stable-dep-of: 1c8629651cb5 ("tls: rx: restore msg_iter before TLS 1.3 optimistic retry")
--- tools/testing/selftests/net/tls.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
tools/testing/selftests/net/tls.c +34 -0
@@ -1570,6 +1570,40 @@ TEST_F(tls, getsockopt)EXPECT_EQ (errno,EINVAL ); } +TEST_F(tls, recv_efault) +{ +char *rec1 ="1111111111" ; +char *rec2 ="2222222222" ; +struct msghdr hdr = {}; +struct iovec iov[2 ]; +char recv_mem[12 ]; +int ret; + +if (self->notls) +SKIP (return,"no TLS support" ); + +EXPECT_EQ (send (self->fd, rec1,10 ,0 ),10 ); +EXPECT_EQ (send (self->fd, rec2,10 ,0 ),10 ); + + iov[0 ].iov_base = recv_mem; + iov[0 ].iov_len =sizeof (recv_mem); + iov[1 ].iov_base =NULL ;/* broken iov to make process_rx_list fail */ + iov[1 ].iov_len =1 ; + + hdr.msg_iovlen =2 ; + hdr.msg_iov = iov; + +EXPECT_EQ (recv (self->cfd, recv_mem,1 ,0 ),1 ); +EXPECT_EQ (recv_mem[0 ], rec1[0 ]); + + ret =recvmsg (self->cfd, &hdr,0 ); +EXPECT_LE (ret,sizeof (recv_mem)); +EXPECT_GE (ret,9 ); +EXPECT_EQ (memcmp (rec1, recv_mem,9 ),0 ); +if (ret >9 ) +EXPECT_EQ (memcmp (rec2, recv_mem +9 , ret -9 ),0 ); +} +FIXTURE (tls_err) {int fd, cfd;
Greg Kroah-Hartman
maintainerPATCH 70/166 ceph: avoid fs reclaim while using current->journal_info
In reply to Greg Kroah-Hartman6.6-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>
@@ -3675,6 +3676,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;
@@ -3817,6 +3819,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 ) {
@@ -3825,6 +3835,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 71/166 ceph: Remove ceph_writepage()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit 19a288110435408fcf2cb274823f2a17d03caf9b ]
Ceph already has a writepages operation which is preferred over writepage in all situations except for page migration. By adding a migrate_folio operation, there will be no situations in which ->writepage should be called. filemap_migrate_folio() is an appropriate operation to use because the ceph data stored in folio->private does not contain any reference to the memory address of the folio.
Stable-dep-of: cbf59617cd71 ("ceph: fix writeback_count leak in write_folio_nounlock()")
--- fs/ceph/addr.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-)
fs/ceph/addr.c +1 -27
@@ -810,32 +810,6 @@ static int writepage_nounlock(struct pagreturn err; } -static int ceph_writepage (struct page *page,struct writeback_control *wbc) -{ -int err; -struct inode *inode = page->mapping->host; -BUG_ON (!inode); -ihold (inode); - -if (wbc->sync_mode ==WB_SYNC_NONE && -ceph_inode_to_fs_client (inode)->write_congested) { -redirty_page_for_writepage (wbc, page); -return AOP_WRITEPAGE_ACTIVATE ; - } - -wait_on_page_fscache (page); - - err =writepage_nounlock (page, wbc); -if (err == -ERESTARTSYS ) { -/* direct memory reclaimer was killed by SIGKILL. return 0 -* to prevent caller from setting mapping/page error */ - err =0 ; - } -unlock_page (page); -iput (inode); -return err; -} -/* * async writeback completion handler. *
@@ -1586,7 +1560,6 @@ out:const struct address_space_operations ceph_aops = { .read_folio = netfs_read_folio, .readahead = netfs_readahead, - .writepage = ceph_writepage, .writepages = ceph_writepages_start, .write_begin = ceph_write_begin, .write_end = ceph_write_end,
@@ -1594,6 +1567,7 @@ const struct address_space_operations ce .invalidate_folio = ceph_invalidate_folio, .release_folio = ceph_release_folio, .direct_IO = noop_direct_IO, + .migrate_folio = filemap_migrate_folio, };static void ceph_block_sigs (sigset_t *oldset)
Greg Kroah-Hartman
maintainerPATCH 72/166 ceph: fix hanging __ceph_get_caps() with stale mds_wanted
In reply to Greg Kroah-Hartman6.6-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 | 2 ++ 3 files changed, 22 insertions(+), 6 deletions(-)
fs/ceph/caps.c +15 -2
@@ -3091,7 +3091,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);
@@ -3123,7 +3135,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
@@ -294,7 +294,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) {
@@ -302,14 +302,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 +2 -0
@@ -68,6 +68,8 @@ enum ceph_feature_type {struct ceph_fs_client ;struct ceph_cap ; +#define CEPH_GET_CAPS_WAIT_TIMEOUT (5 * HZ) +/* * parsed info about a single inode. pointers are into the encoded * on-wire structures within the mds reply message payload.
Greg Kroah-Hartman
maintainerPATCH 73/166 ceph: Use a folio in ceph_page_mkwrite()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit 88a59bda3f3786107694a3f5fd7f9df421752c21 ]
Convert the passed page to a folio and use it
throughout ceph_page_mkwrite(). Removes the last call to page_mkwrite_check_truncate(), the last call to offset_in_thp() and one of the last calls to thp_size(). Saves a few calls to compound_head().
Stable-dep-of: cbf59617cd71 ("ceph: fix writeback_count leak in write_folio_nounlock()")
--- fs/ceph/addr.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
fs/ceph/addr.c +13 -13
@@ -1684,8 +1684,8 @@ static vm_fault_t ceph_page_mkwrite(strustruct ceph_inode_info *ci =ceph_inode (inode);struct ceph_file_info *fi = vma->vm_file->private_data;struct ceph_cap_flush *prealloc_cf; -struct page *page = vmf->page; -loff_t off =page_offset (page); +struct folio *folio =page_folio (vmf->page); +loff_t off =folio_pos (folio);loff_t size =i_size_read (inode);size_t len;int want, got, err;
@@ -1702,10 +1702,10 @@ static vm_fault_t ceph_page_mkwrite(strusb_start_pagefault (inode->i_sb);ceph_block_sigs (&oldset); -if (off +thp_size (page) <= size) - len =thp_size (page); +if (off +folio_size (folio) <= size) + len =folio_size (folio);else - len =offset_in_thp (page, size); + len =offset_in_folio (folio, size);doutc (cl,"%llx.%llx %llu~%zd getting caps i_size %llu\n" ,ceph_vinop (inode), off, len, size);
@@ -1722,30 +1722,30 @@ static vm_fault_t ceph_page_mkwrite(strudoutc (cl,"%llx.%llx %llu~%zd got cap refs on %s\n" ,ceph_vinop (inode), off, len,ceph_cap_string (got)); -/* Update time before taking page lock */ +/* Update time before taking folio lock */ file_update_time (vma->vm_file);inode_inc_iversion_raw (inode); do { struct ceph_snap_context *snapc; - lock_page(page); + folio_lock(folio); - if (page_mkwrite_check_truncate(page, inode) < 0) { - unlock_page(page); + if (folio_mkwrite_check_truncate(folio, inode) < 0) { + folio_unlock(folio); ret = VM_FAULT_NOPAGE; break; } - snapc = ceph_find_incompatible(page); + snapc = ceph_find_incompatible(&folio->page); if (!snapc) { - /* success. we'll keep the page locked. */ - set_page_dirty(page); + /* success. we'll keep the folio locked. */ + folio_mark_dirty(folio); ret = VM_FAULT_LOCKED; break; } - unlock_page(page); + folio_unlock(folio); if (IS_ERR(snapc)) { ret = VM_FAULT_SIGBUS;
Greg Kroah-Hartman
maintainerPATCH 74/166 libceph: Amend checking to fix `make W=1` build breakage
In reply to Greg Kroah-Hartman6.6-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 75/166 libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE
In reply to Greg Kroah-Hartman6.6-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 76/166 ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chancel Liu <[email protected]>
[ Upstream commit d091132889c1378dd0944a72f86eae3e4da1e4fa ]
When the BCLK divider ratio is 1:1, fsl_sai_set_bclk() enables bypass mode by setting BYP, but never clears the bit. The BYP=1 value remains in the regcache, and is restored by regcache_sync() on the next runtime resume.
Since BYP=1 combined with BCD=1 immediately outputs the ungated MCLK as BCLK without waiting for BCE/TE/RE to be enabled, the clock is driven prematurely before the stream is fully configured, causing noise on some codecs.
Fix this by clearing BYP and BCI in fsl_sai_hw_free() taking into account sync mode and the opposite stream's state, so that the regcache holds BYP=0 before runtime suspend and regcache_sync() on resume will not restore bypass mode prematurely.
--- sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
sound/soc/fsl/fsl_sai.c +25 -4
@@ -716,6 +716,8 @@ static int fsl_sai_hw_free(struct snd_pcstruct fsl_sai *sai =snd_soc_dai_get_drvdata (cpu_dai);bool tx = substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ;unsigned int ofs = sai->soc_data->reg_offset; +int adir = tx ?RX :TX ; +int dir = tx ?TX :RX ;/* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ regmap_write (sai->regmap,FSL_SAI_xMR (tx),0 );
@@ -723,10 +725,29 @@ static int fsl_sai_hw_free(struct snd_pcregmap_update_bits (sai->regmap,FSL_SAI_xCR3 (tx, ofs),FSL_SAI_CR3_TRCE_MASK ,0 ); -if (!sai->is_consumer_mode && - sai->mclk_streams &BIT (substream->stream)) { -clk_disable_unprepare (sai->mclk_clk[sai->mclk_id[tx]]); - sai->mclk_streams &= ~BIT (substream->stream); +if (!sai->is_consumer_mode) { +bool adir_active = !!(sai->mclk_streams &BIT (!substream->stream)); +/* +* If opposite stream provides clocks for synchronous mode and +* it is inactive, Clear BYP and BCI +*/ +if (fsl_sai_dir_is_synced (sai, adir) && !adir_active) +regmap_update_bits (sai->regmap,FSL_SAI_xCR2 (!tx, ofs), +FSL_SAI_CR2_BCI |FSL_SAI_CR2_BYP ,0 ); +/* +* Clear BYP and BCI of current stream if either of: +* 1. current stream doesn't provide clocks for synchronous mode +* 2. current stream provides clocks for synchronous mode but no +* more stream is active. +*/ +if (!fsl_sai_dir_is_synced (sai, dir) || !adir_active) +regmap_update_bits (sai->regmap,FSL_SAI_xCR2 (tx, ofs), +FSL_SAI_CR2_BCI |FSL_SAI_CR2_BYP ,0 ); + +if (sai->mclk_streams &BIT (substream->stream)) { +clk_disable_unprepare (sai->mclk_clk[sai->mclk_id[tx]]); + sai->mclk_streams &= ~BIT (substream->stream); + } }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 77/166 iomap: hold state_lock over call to ifs_set_range_uptodate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit 279d5fc3227f04ef2c6125e5c440e7952173a89a ]
Patch series "Add folio_end_read", v2.
The core of this patchset is the new folio_end_read() call which filesystems can use when finishing a page cache read instead of separate calls to mark the folio uptodate and unlock it. As an illustration of its use, I converted ext4, iomap & mpage; more can be converted.
I think that's useful by itself, but the interesting optimisation is that we can implement that with a single XOR instruction that sets the uptodate bit, clears the lock bit, tests the waiter bit and provides a write memory barrier. That removes one memory barrier and one atomic instruction from each page read, which seems worth doing. That's in patch 15.
The last two patches could be a separate series, but basically we can do the same thing with the writeback flag that we do with the unlock flag; clear it and test the waiters bit at the same time.
This patch (of 17):
This is really preparation for the next patch, but it lets us call folio_mark_uptodate() in just one place instead of two.
Stable-dep-of: 9c7d8f7c8994 ("iomap: fix out-of-bounds bitmap_set() with zero-length range")
--- fs/iomap/buffered-io.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
fs/iomap/buffered-io.c +11 -9
@@ -57,30 +57,32 @@ static inline bool ifs_block_is_uptodatereturn test_bit (block, ifs->state); } -static void ifs_set_range_uptodate (struct folio *folio, +static bool ifs_set_range_uptodate (struct folio *folio,struct iomap_folio_state *ifs,size_t off,size_t len) {struct inode *inode = folio->mapping->host;unsigned int first_blk = off >> inode->i_blkbits;unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits;unsigned int nr_blks = last_blk - first_blk +1 ; -unsigned long flags; -spin_lock_irqsave (&ifs->state_lock, flags);bitmap_set (ifs->state, first_blk, nr_blks); -if (ifs_is_fully_uptodate (folio, ifs)) -folio_mark_uptodate (folio); -spin_unlock_irqrestore (&ifs->state_lock, flags); +return ifs_is_fully_uptodate (folio, ifs); }static void iomap_set_range_uptodate (struct folio *folio,size_t off,size_t len) {struct iomap_folio_state *ifs = folio->private; +unsigned long flags; +bool uptodate = true; + +if (ifs) { +spin_lock_irqsave (&ifs->state_lock, flags); + uptodate =ifs_set_range_uptodate (folio, ifs, off, len); +spin_unlock_irqrestore (&ifs->state_lock, flags); + } -if (ifs) -ifs_set_range_uptodate (folio, ifs, off, len); -else +if (uptodate)folio_mark_uptodate (folio); }
Greg Kroah-Hartman
maintainerPATCH 78/166 iomap: fix out-of-bounds bitmap_set() with zero-length range
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
[ Upstream commit 9c7d8f7c8994c790fca501dc45ce66e7356cbe05 ]
ifs_set_range_dirty() and ifs_set_range_uptodate() compute last_blk as (off + len - 1) >> i_blkbits. When off is 0 and len is 0, the unsigned subtraction underflows to SIZE_MAX, producing a huge last_blk and nr_blks value that causes bitmap_set() to write far beyond the ifs->state allocation.
Regarding ifs_set_range_uptodate(), it is temporarily safe because len cannot be passed in as 0. However, for ifs_set_range_dirty() this is reachable from __iomap_write_end(): when copy_folio_from_iter_atomic() returns 0 (e.g. user buffer fault) and the folio is already uptodate, the guard at the top of __iomap_write_end() does not trigger because !folio_test_uptodate() is false, and iomap_set_range_dirty() is called with copied == 0.
Add a !len guard to both functions before the computation, so that a zero-length range is a no-op.
--- fs/iomap/buffered-io.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
fs/iomap/buffered-io.c +14 -8
@@ -61,11 +61,13 @@ static bool ifs_set_range_uptodate(struc struct iomap_folio_state *ifs, size_t off, size_t len) { struct inode *inode = folio->mapping->host; -unsigned int first_blk = off >> inode->i_blkbits; -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk; -bitmap_set (ifs->state, first_blk, nr_blks); +if (len) { + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits; +bitmap_set (ifs->state, first_blk, last_blk - first_blk +1 ); + }return ifs_is_fully_uptodate (folio, ifs); }
@@ -127,13 +129,17 @@ static void ifs_set_range_dirty(struct f {struct inode *inode = folio->mapping->host;unsigned int blks_per_folio =i_blocks_per_folio (inode, folio); -unsigned int first_blk = (off >> inode->i_blkbits); -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk;unsigned long flags; +if (!len) +return ; + + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits;spin_lock_irqsave (&ifs->state_lock, flags); -bitmap_set (ifs->state, first_blk + blks_per_folio, nr_blks); +bitmap_set (ifs->state, first_blk + blks_per_folio, + last_blk - first_blk +1 );spin_unlock_irqrestore (&ifs->state_lock, flags); }
Greg Kroah-Hartman
maintainerPATCH 79/166 mm: userfaultfd: add pgtable_supports_uffd_wp()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chunyan Zhang <[email protected]>
[ Upstream commit f59c0924d61aa2a2bb85936a593140f327112787 ]
Some platforms can customize the PTE/PMD entry uffd-wp bit making it unavailable even if the architecture provides the resource. This patch adds a macro API pgtable_supports_uffd_wp() that allows architectures to define their specific implementations to check if the uffd-wp bit is available on which device the kernel is running.
Also this patch is removing "ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP" and "ifdef CONFIG_PTE_MARKER_UFFD_WP" in favor of pgtable_supports_uffd_wp() and uffd_supports_wp_marker() checks respectively that default to IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_WP) and "IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_WP) && IS_ENABLED(CONFIG_PTE_MARKER_UFFD_WP)" if not overridden by the architecture, no change in behavior is expected.
Stable-dep-of: 3c58f641e813 ("userfaultfd: prevent registration of special VMAs")
--- fs/userfaultfd.c | 20 ++++++++++---------- include/asm-generic/pgtable_uffd.h | 17 +++++++++++++++++ include/linux/mm_inline.h | 7 ++++--- include/linux/userfaultfd_k.h | 8 +++++--- 4 files changed, 36 insertions(+), 16 deletions(-)
fs/userfaultfd.c +10 -10
@@ -1354,9 +1354,9 @@ static int userfaultfd_register(struct uif (uffdio_register.mode &UFFDIO_REGISTER_MODE_MISSING ) vm_flags |=VM_UFFD_MISSING ;if (uffdio_register.mode &UFFDIO_REGISTER_MODE_WP ) { -#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_WP - goto out; -#endif +if (!pgtable_supports_uffd_wp ()) + goto out; + vm_flags |=VM_UFFD_WP ; }if (uffdio_register.mode &UFFDIO_REGISTER_MODE_MINOR ) {
@@ -2068,13 +2068,13 @@ static int userfaultfd_api(struct userfa uffdio_api.features &= ~(UFFD_FEATURE_MINOR_HUGETLBFS |UFFD_FEATURE_MINOR_SHMEM );#endif -#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_WP - uffdio_api.features &= ~UFFD_FEATURE_PAGEFAULT_FLAG_WP ; -#endif -#ifndef CONFIG_PTE_MARKER_UFFD_WP - uffdio_api.features &= ~UFFD_FEATURE_WP_HUGETLBFS_SHMEM ; - uffdio_api.features &= ~UFFD_FEATURE_WP_UNPOPULATED ; -#endif +if (!pgtable_supports_uffd_wp ()) + uffdio_api.features &= ~UFFD_FEATURE_PAGEFAULT_FLAG_WP ; + +if (!uffd_supports_wp_marker ()) { + uffdio_api.features &= ~UFFD_FEATURE_WP_HUGETLBFS_SHMEM ; + uffdio_api.features &= ~UFFD_FEATURE_WP_UNPOPULATED ; + } ret = -EINVAL ;if (features & ~uffdio_api.features)
include/asm-generic/pgtable_uffd.h +17 -0
@@ -1,6 +1,23 @@ #ifndef _ASM_GENERIC_PGTABLE_UFFD_H #define _ASM_GENERIC_PGTABLE_UFFD_H +/* + * Some platforms can customize the uffd-wp bit, making it unavailable + * even if the architecture provides the resource. + * Adding this API allows architectures to add their own checks for the + * devices on which the kernel is running. + * Note: When overriding it, please make sure the + * CONFIG_HAVE_ARCH_USERFAULTFD_WP is part of this macro. + */ +#ifndef pgtable_supports_uffd_wp +#define pgtable_supports_uffd_wp() IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_WP) +#endif + +static inline bool uffd_supports_wp_marker(void) +{ + return pgtable_supports_uffd_wp() && IS_ENABLED(CONFIG_PTE_MARKER_UFFD_WP); +} + #ifndef CONFIG_HAVE_ARCH_USERFAULTFD_WP static __always_inline int pte_uffd_wp(pte_t pte) {
include/linux/mm_inline.h +4 -3
@@ -547,7 +547,6 @@ static inline pte_marker copy_pte_markerreturn dstm; } -#endif /* * If this pte is wr-protected by uffd-wp in any form, arm the special pte to
@@ -565,9 +564,11 @@ static inline void pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, pte_t *pte, pte_t pteval) { -#ifdef CONFIG_PTE_MARKER_UFFD_WP bool arm_uffd_pte = false; +if (!uffd_supports_wp_marker ()) +return ; +/* The current status of the pte should be "cleared" before calling */ WARN_ON_ONCE (!pte_none (ptep_get (pte)));
@@ -594,7 +595,6 @@ pte_install_uffd_wp_if_needed(struct vm_if (unlikely (arm_uffd_pte))set_pte_at (vma->vm_mm, addr, pte,make_pte_marker (PTE_MARKER_UFFD_WP )); -#endif }static inline bool vma_has_recency (struct vm_area_struct *vma)
@@ -607,5 +607,6 @@ static inline bool vma_has_recency(strucreturn true; } +#endif #endif
include/linux/userfaultfd_k.h +5 -3
@@ -166,15 +166,17 @@ static inline bool vma_can_userfault(strif ((vm_flags &VM_UFFD_MINOR ) && (!is_vm_hugetlb_page (vma) && !vma_is_shmem (vma)))return false; -#ifndef CONFIG_PTE_MARKER_UFFD_WP +/* * If user requested uffd-wp but not enabled pte markers for * uffd-wp, then shmem & hugetlbfs are not supported but only * anonymous. */ -if ((vm_flags &VM_UFFD_WP ) && !vma_is_anonymous (vma)) +if (!uffd_supports_wp_marker () && (vm_flags &VM_UFFD_WP ) && + !vma_is_anonymous (vma))return false; -#endif + +/* By default, allow any of anon|shmem|hugetlb */ return vma_is_anonymous (vma) ||is_vm_hugetlb_page (vma) ||vma_is_shmem (vma); }
Greg Kroah-Hartman
maintainerPATCH 80/166 userfaultfd: move vma_can_userfault out of line
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Mike Rapoport (Microsoft)" <[email protected]>
[ Upstream commit a5bb8669872b6b8463b8777a7a259a8305060016 ]
vma_can_userfault() has grown pretty big and it's not called on performance critical path.
Move it out of line.
No functional changes.
Stable-dep-of: 3c58f641e813 ("userfaultfd: prevent registration of special VMAs")
--- include/linux/userfaultfd_k.h | 21 +-------------------- mm/userfaultfd.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-)
include/linux/userfaultfd_k.h +1 -20
@@ -160,26 +160,7 @@ static inline bool userfaultfd_armed(strreturn vma->vm_flags & __VM_UFFD_FLAGS; } -static inline bool vma_can_userfault (struct vm_area_struct *vma, -unsigned long vm_flags) -{ -if ((vm_flags &VM_UFFD_MINOR ) && - (!is_vm_hugetlb_page (vma) && !vma_is_shmem (vma))) -return false; - -/* -* If user requested uffd-wp but not enabled pte markers for -* uffd-wp, then shmem & hugetlbfs are not supported but only -* anonymous. -*/ -if (!uffd_supports_wp_marker () && (vm_flags &VM_UFFD_WP ) && - !vma_is_anonymous (vma)) -return false; - -/* By default, allow any of anon|shmem|hugetlb */ -return vma_is_anonymous (vma) ||is_vm_hugetlb_page (vma) || -vma_is_shmem (vma); -} +bool vma_can_userfault (struct vm_area_struct *vma,unsigned long vm_flags);extern int dup_userfaultfd (struct vm_area_struct *,struct list_head *);extern void dup_userfaultfd_complete (struct list_head *);
mm/userfaultfd.c +20 -0
@@ -891,3 +891,23 @@ out_unlock:mmap_read_unlock (dst_mm);return err; } + +bool vma_can_userfault (struct vm_area_struct *vma,unsigned long vm_flags) +{ +if ((vm_flags &VM_UFFD_MINOR ) && + (!is_vm_hugetlb_page (vma) && !vma_is_shmem (vma))) +return false; + +/* +* If user requested uffd-wp but not enabled pte markers for +* uffd-wp, then shmem & hugetlbfs are not supported but only +* anonymous. +*/ +if (!uffd_supports_wp_marker () && (vm_flags &VM_UFFD_WP ) && + !vma_is_anonymous (vma)) +return false; + +/* By default, allow any of anon|shmem|hugetlb */ +return vma_is_anonymous (vma) ||is_vm_hugetlb_page (vma) || +vma_is_shmem (vma); +}
Greg Kroah-Hartman
maintainerPATCH 81/166 userfaultfd: prevent registration of special VMAs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Mike Rapoport (Microsoft)" <[email protected]>
[ Upstream commit 3c58f641e813c3c71039f8fd4d4e2a3aab713288 ]
Vova Tokarev says:
userfaultfd allows registration on shadow stack VMAs. With userfaultfd access, you can register on the shadow stack, discard a page ... and inject a page with chosen return addresses via UFFDIO_COPY.
Update vma_can_userfault() to reject VM_SHADOW_STACK.
While on it, also reject VM_SPECIAL so that if a driver would implement vm_uffd_ops, it wouldn't be possible to register special VMAs with userfaultfd.
Since VM_SPECIAL includes VM_DONTEXPAND which is set but hugetlb, exclude hugetlb VMAs from the check for VM_SPECIAL.
--- mm/userfaultfd.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/userfaultfd.c +6 -0
@@ -894,6 +894,12 @@ out_unlock:bool vma_can_userfault (struct vm_area_struct *vma,unsigned long vm_flags) { +if (vma->vm_flags &VM_SHADOW_STACK ) +return false; + +if (!is_vm_hugetlb_page (vma) && (vma->vm_flags &VM_SPECIAL )) +return false; +if ((vm_flags &VM_UFFD_MINOR ) && (!is_vm_hugetlb_page (vma) && !vma_is_shmem (vma)))return false;
Greg Kroah-Hartman
maintainerPATCH 82/166 libceph: fix two unsafe bare decodes in decode_lockers()
In reply to Greg Kroah-Hartman6.6-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 83/166 net: move skb_gro_receive_list from udp to core
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 8928756d53d5b99dcd18073dc7738b8ebdbe7d96 ]
This helper function will be used for TCP fraglist GRO support
Stable-dep-of: e751256486d0 ("net: gro: fix double aggregation of flush-marked skbs")
--- include/net/gro.h | 1 + net/core/gro.c | 29 +++++++++++++++++++++++++++++ net/ipv4/udp_offload.c | 29 ----------------------------- 3 files changed, 30 insertions(+), 29 deletions(-)
include/net/gro.h +1 -0
@@ -442,6 +442,7 @@ static inline __wsum ip6_gro_compute_pse }int skb_gro_receive (struct sk_buff *p,struct sk_buff *skb); +int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb);/* Pass the currently batched GRO_NORMAL SKBs up to the stack. */ static inline void gro_normal_list (struct napi_struct *napi)
net/core/gro.c +29 -0
@@ -230,6 +230,35 @@ done:return 0 ; } +int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb) +{ +if (unlikely (p->len + skb->len >=65536 )) +return -E2BIG ; + +if (NAPI_GRO_CB (p)->last == p) +skb_shinfo (p)->frag_list = skb; +else +NAPI_GRO_CB (p)->last->next = skb; + +skb_pull (skb,skb_gro_offset (skb)); + +NAPI_GRO_CB (p)->last = skb; +NAPI_GRO_CB (p)->count++; + p->data_len += skb->len; + +/* sk ownership - if any - completely transferred to the aggregated packet */ + skb->destructor =NULL ; + skb->sk =NULL ; + p->truesize += skb->truesize; + p->len += skb->len; + +skb_shinfo (p)->flags |=skb_shinfo (skb)->flags &SKBFL_SHARED_FRAG ; + +NAPI_GRO_CB (skb)->same_flow =1 ; + +return 0 ; +} +static void napi_gro_complete (struct napi_struct *napi,struct sk_buff *skb) {
net/ipv4/udp_offload.c +0 -29
@@ -527,35 +527,6 @@ out:return segs; } -static int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb) -{ -if (unlikely (p->len + skb->len >=65536 )) -return -E2BIG ; - -if (NAPI_GRO_CB (p)->last == p) -skb_shinfo (p)->frag_list = skb; -else -NAPI_GRO_CB (p)->last->next = skb; - -skb_pull (skb,skb_gro_offset (skb)); - -NAPI_GRO_CB (p)->last = skb; -NAPI_GRO_CB (p)->count++; - p->data_len += skb->len; - -/* sk ownership - if any - completely transferred to the aggregated packet */ - skb->destructor =NULL ; - skb->sk =NULL ; - p->truesize += skb->truesize; - p->len += skb->len; - -skb_shinfo (p)->flags |=skb_shinfo (skb)->flags &SKBFL_SHARED_FRAG ; - -NAPI_GRO_CB (skb)->same_flow =1 ; - -return 0 ; -} -#define UDP_GRO_CNT_MAX 64 static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
Greg Kroah-Hartman
maintainerPATCH 84/166 net: gro: fix double aggregation of flush-marked skbs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shiming Cheng <[email protected]>
[ Upstream commit e751256486d0ded20f5a9f9863467f1dce65142f ]
Commit 0ab03f353d36 ("net-gro: Fix GRO flush when receiving a GSO packet.") added a flush check to skb_gro_receive(), but skb_gro_receive_list() lacks the same validation.
As a result, packets marked with NAPI_GRO_CB(skb)->flush may still be re-aggregated.
This allows already-GRO'd packets with existing frag_list to be re-aggregated into a new GRO session, corrupting the frag_list chain structure. When skb_segment() attempts to unpack these malformed packets, it encounters invalid state and triggers a kernel panic.
Scenario (Tethering/Device forwarding):
1. Driver: Generated aggregated packet P1 via LRO with frag_list
2. Dev A: Receives aggregated fraglist packet and flush flag set
3. Dev A: Re-enters GRO, skb_gro_receive_list() is called
4. Missing flush check allows re-aggregation despite flush flag
5. Frag_list chain becomes corrupted (loops or dangling refs)
6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list
Root cause in skb_segment():
The check at line ~4891:
if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) { When frag_list is corrupted by double aggregation, when list_skb is a NULL pointer from skb->next, skb_headlen(list_skb) dereference NULL/corrupted pointers occurs.
Call Trace: skb_headlen(NULL skb) skb_segment tcp_gso_segment tcp4_gso_segment inet_gso_segment skb_mac_gso_segment __skb_gso_segment skb_gso_segment validate_xmit_skb validate_xmit_skb_list sch_direct_xmit qdisc_restart __qdisc_run qdisc_run net_tx_action
Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in skb_gro_receive_list(), matching the defensive programming pattern of skb_gro_receive().
--- net/core/gro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/gro.c +3 -1
@@ -232,7 +232,9 @@ done:int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb) { -if (unlikely (p->len + skb->len >=65536 )) +/* make sure to check flush flag and to not merge */ +if (unlikely (p->len + skb->len >=65536 || +NAPI_GRO_CB (skb)->flush))return -E2BIG ;if (NAPI_GRO_CB (p)->last == p)
Greg Kroah-Hartman
maintainerPATCH 85/166 net/sched: serialize qdisc_rtab_list against concurrent get/put
In reply to Greg Kroah-Hartman6.6-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
@@ -413,12 +413,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 ||
@@ -427,15 +428,20 @@ struct qdisc_rate_table *qdisc_get_rtab(return NULL ; } + new_rtab =kmalloc (sizeof (*new_rtab),GFP_KERNEL ); + +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),1024 )) { 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 ;
@@ -447,6 +453,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);
@@ -455,18 +462,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 86/166 super: fix emergency thaw deadlock on frozen block devices
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 ]
do_thaw_all_callback() calls bdev_thaw() while holding sb->s_umount exclusively. If the block device was frozen via bdev_freeze() dropping the last block layer freeze reference calls fs_bdev_thaw() which reacquires s_umount:
do_thaw_all_callback(sb)
super_lock_excl(sb) # holds sb->s_umount
bdev_thaw(sb->s_bdev)
mutex_lock(&bdev->bd_fsfreeze_mutex)
# bd_fsfreeze_count drops 1 -> 0
bd_holder_ops->thaw == fs_bdev_thaw
get_bdev_super(bdev)
bdev_super_lock(bdev, true)
super_lock(sb, true)
down_write(&sb->s_umount) # same task: deadlockThe emergency thaw worker deadlocks against itself holding both s_umount and bd_fsfreeze_mutex. That fscks any subsequent unmount, freeze, or thaw of that filesystem and block device.
[ 81.878470] sysrq: Show Blocked State [ 81.880140] task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208060 flags:0x00080000 [ 81.884876] Workqueue: events do_thaw_all [ 81.886656] Call Trace: [ 81.887759] <TASK> [ 81.888763] __schedule+0x579/0x1420 [ 81.890372] schedule+0x3a/0x100 [ 81.891794] schedule_preempt_disabled+0x15/0x30 [ 81.893848] rwsem_down_write_slowpath+0x1ea/0x900 [ 81.895191] ? __pfx_do_thaw_all_callback+0x10/0x10 [ 81.896528] down_write+0xbd/0xc0 [ 81.897505] super_lock+0x91/0x180 [ 81.898457] ? __mutex_lock+0xa99/0x1140 [ 81.900748] ? __mutex_unlock_slowpath+0x1f/0x400 [ 81.902069] bdev_super_lock+0x5b/0x150 [ 81.903132] get_bdev_super+0x10/0x60 [ 81.904042] fs_bdev_thaw+0x23/0xf0 [ 81.904755] bdev_thaw+0x82/0x100 [ 81.905484] do_thaw_all_callback+0x2c/0x50 [ 81.906298] __iterate_supers+0x5d/0x130 [ 81.907067] do_thaw_all+0x20/0x40 [ 81.907739] process_one_work+0x206/0x5e0 [ 81.908545] worker_thread+0x1e2/0x3c0 [ 81.909339] ? __pfx_worker_thread+0x10/0x10 [ 81.910171] kthread+0xf4/0x130 [ 81.910799] ? __pfx_kthread+0x10/0x10 [ 81.911528] ret_from_fork+0x2e2/0x3b0 [ 81.912259] ? __pfx_kthread+0x10/0x10 [ 81.913010] ret_from_fork_asm+0x1a/0x30 [ 81.913806] </TASK>
bdev_super_lock() even documents the violated requirement with lockdep_assert_not_held(&sb->s_umount).
Acquiring bd_fsfreeze_mutex under s_umount also inverts the bd_fsfreeze_mutex vs. s_umount ordering established by bdev_{freeze,thaw}() and can thus ABBA against a concurrent block-layer freeze even when the recursive path isn't hit.
Fix this by not holding s_umount around the bdev_thaw() loop at all. Pin the superblock with an active reference instead as filesystems_freeze_callback() does. The active reference keeps the superblock from being shut down and so ->s_bdev stays valid without holding s_umount. The block-layer-held freeze is dropped by fs_bdev_thaw() with FREEZE_MAY_NEST | FREEZE_HOLDER_USERSPACE exactly as a regular unfreeze would and thaw_super_locked() handles filesystem-level freezes as before.
The emergency thaw path has deadlocked like this in one form or another for a long long time but the current exclusively-held shape dates back to commit [1] where thaw_bdev() already ended in thaw_super() with s_umount held by do_thaw_all_callback().
--- fs/super.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
fs/super.c +15 -7
@@ -1217,16 +1217,24 @@ void emergency_remount(void)static void do_thaw_all_callback (struct super_block *sb) { -bool born =super_lock_excl (sb); +bool active = false; -if (born && sb->s_root) { -if (IS_ENABLED (CONFIG_BLOCK )) -while (sb->s_bdev && !thaw_bdev (sb->s_bdev)) -pr_warn ("Emergency Thaw on %pg\n" , sb->s_bdev); +if (super_lock_excl (sb)) + active =atomic_inc_not_zero (&sb->s_active); +super_unlock_excl (sb); +if (!active) +return ; + +/* thaw_bdev() acquires s_umount so it must not be held here */ +if (IS_ENABLED (CONFIG_BLOCK )) +while (sb->s_bdev && !thaw_bdev (sb->s_bdev)) +pr_warn ("Emergency Thaw on %pg\n" , sb->s_bdev); + +if (super_lock_excl (sb))thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ); - }else { +else super_unlock_excl (sb); - } +deactivate_super (sb); }static void do_thaw_all (struct work_struct *work)
Greg Kroah-Hartman
maintainerPATCH 87/166 smb: move smb_version_values to common/smbglob.h
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit 34cf191bb6a349dc88ec2c4f6355fe006ac669e0 ]
Merge the struct members of the server and the client:
- req_capabilities: from client
- header_preamble_size: from client
- cap_unicode: from client
- capabilities: from server, rename to req_capabilities
- max_read_size: from server
- max_write_size: from server
- max_trans_size: from server
- max_credits: from server
- create_durable_size: from server
- create_durable_v2_size: from server
- create_mxac_size: from server
- create_disk_id_size: from server
- create_posix_size: from server
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 | 21 --------------------- fs/smb/common/cifsglob.h | 31 +++++++++++++++++++++++++++++++ fs/smb/server/smb2misc.c | 2 +- fs/smb/server/smb2ops.c | 32 ++++++++++++++++---------------- fs/smb/server/smb2pdu.c | 10 +++++----- fs/smb/server/smb_common.h | 29 ----------------------------- 6 files changed, 53 insertions(+), 72 deletions(-)
fs/smb/client/cifsglob.h +0 -21
@@ -606,27 +606,6 @@ struct smb_version_operations { const char *symname); }; -struct smb_version_values { -char *version_string; -__u16 protocol_id; -__u32 req_capabilities; -__u32 large_lock_type; -__u32 exclusive_lock_type; -__u32 shared_lock_type; -__u32 unlock_lock_type; -size_t header_preamble_size; -size_t header_size; -size_t max_header_size; -size_t read_rsp_size; -__le16 lock_cmd; -unsigned int cap_unix; -unsigned int cap_nt_find; -unsigned int cap_large_files; -__u16 signing_enabled; -__u16 signing_required; -size_t create_lease_size; -}; -#define HEADER_SIZE (server) (server->vals->header_size)#define MAX_HEADER_SIZE (server) (server->vals->max_header_size)#define HEADER_PREAMBLE_SIZE (server) (server->vals->header_preamble_size)
fs/smb/common/cifsglob.h +31 -0
@@ -9,6 +9,37 @@#ifndef _COMMON_CIFS_GLOB_H#define _COMMON_CIFS_GLOB_H +struct smb_version_values { +char *version_string; +__u16 protocol_id; +__le16 lock_cmd; +__u32 req_capabilities; +__u32 max_read_size; +__u32 max_write_size; +__u32 max_trans_size; +__u32 max_credits; +__u32 large_lock_type; +__u32 exclusive_lock_type; +__u32 shared_lock_type; +__u32 unlock_lock_type; +size_t header_preamble_size; +size_t header_size; +size_t max_header_size; +size_t read_rsp_size; +unsigned int cap_unix; +unsigned int cap_nt_find; +unsigned int cap_large_files; +unsigned int cap_unicode; +__u16 signing_enabled; +__u16 signing_required; +size_t create_lease_size; +size_t create_durable_size; +size_t create_durable_v2_size; +size_t create_mxac_size; +size_t create_disk_id_size; +size_t create_posix_size; +}; +static inline void inc_rfc1001_len (void *buf,int count) {be32_add_cpu ((__be32 *)buf, count);
fs/smb/server/smb2misc.c +1 -1
@@ -465,7 +465,7 @@ int ksmbd_smb2_check_message(struct ksmb } validate_credit: -if ((work->conn->vals->capabilities &SMB2_GLOBAL_CAP_LARGE_MTU ) && +if ((work->conn->vals->req_capabilities &SMB2_GLOBAL_CAP_LARGE_MTU ) &&smb2_validate_credit_charge (work->conn, hdr))return 1 ;
fs/smb/server/smb2ops.c +16 -16
@@ -15,7 +15,7 @@static struct smb_version_values smb21_server_values = { .version_string =SMB21_VERSION_STRING , .protocol_id =SMB21_PROT_ID , - .capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , .max_read_size =SMB21_DEFAULT_IOSIZE , .max_write_size =SMB21_DEFAULT_IOSIZE , .max_trans_size =SMB21_DEFAULT_IOSIZE ,
@@ -41,7 +41,7 @@ static struct smb_version_values smb21_sstatic struct smb_version_values smb30_server_values = { .version_string =SMB30_VERSION_STRING , .protocol_id =SMB30_PROT_ID , - .capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , .max_read_size =SMB3_DEFAULT_IOSIZE , .max_write_size =SMB3_DEFAULT_IOSIZE , .max_trans_size =SMB3_DEFAULT_TRANS_SIZE ,
@@ -68,7 +68,7 @@ static struct smb_version_values smb30_sstatic struct smb_version_values smb302_server_values = { .version_string =SMB302_VERSION_STRING , .protocol_id =SMB302_PROT_ID , - .capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , .max_read_size =SMB3_DEFAULT_IOSIZE , .max_write_size =SMB3_DEFAULT_IOSIZE , .max_trans_size =SMB3_DEFAULT_TRANS_SIZE ,
@@ -95,7 +95,7 @@ static struct smb_version_values smb302_static struct smb_version_values smb311_server_values = { .version_string =SMB311_VERSION_STRING , .protocol_id =SMB311_PROT_ID , - .capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_LARGE_MTU , .max_read_size =SMB3_DEFAULT_IOSIZE , .max_write_size =SMB3_DEFAULT_IOSIZE , .max_trans_size =SMB3_DEFAULT_TRANS_SIZE ,
@@ -204,7 +204,7 @@ void init_smb2_1_server(struct ksmbd_con conn->signing_algorithm =SIGNING_ALG_HMAC_SHA256_LE ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_LEASES ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_LEASING ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_LEASING ; }/**
@@ -221,20 +221,20 @@ void init_smb3_0_server(struct ksmbd_con conn->signing_algorithm =SIGNING_ALG_AES_CMAC_LE ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_LEASES ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_DIRECTORY_LEASING ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && conn->cli_cap &SMB2_GLOBAL_CAP_ENCRYPTION ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || (!(server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF ) && conn->cli_cap &SMB2_GLOBAL_CAP_ENCRYPTION )) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; }/**
@@ -251,19 +251,19 @@ void init_smb3_02_server(struct ksmbd_co conn->signing_algorithm =SIGNING_ALG_AES_CMAC_LE ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_LEASES ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_DIRECTORY_LEASING ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || (!(server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF ) && conn->cli_cap &SMB2_GLOBAL_CAP_ENCRYPTION )) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_ENCRYPTION ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; }/**
@@ -280,14 +280,14 @@ int init_smb3_11_server(struct ksmbd_con conn->signing_algorithm =SIGNING_ALG_AES_CMAC_LE ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB2_LEASES ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_DIRECTORY_LEASING ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ;if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; + conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ;INIT_LIST_HEAD (&conn->preauth_sess_table);return 0 ;
fs/smb/server/smb2pdu.c +5 -5
@@ -284,7 +284,7 @@ int init_smb2_neg_rsp(struct ksmbd_work/* Not setting conn guid rsp->ServerGUID, as it * not used by client for identifying connection */ - rsp->Capabilities =cpu_to_le32 (conn->vals->capabilities); + rsp->Capabilities =cpu_to_le32 (conn->vals->req_capabilities);/* Default Max Message Size till SMB2.0, 64K*/ rsp->MaxTransactSize =cpu_to_le32 (conn->vals->max_trans_size); rsp->MaxReadSize =cpu_to_le32 (conn->vals->max_read_size);
@@ -963,7 +963,7 @@ bool smb3_encryption_negotiated(struct k* SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag. * SMB 3.1.1 uses the cipher_type field. */ -return (conn->vals->capabilities &SMB2_GLOBAL_CAP_ENCRYPTION ) || +return (conn->vals->req_capabilities &SMB2_GLOBAL_CAP_ENCRYPTION ) || conn->cipher_type; }
@@ -1216,7 +1216,7 @@ int smb2_handle_negotiate(struct ksmbd_w rc = -EINVAL ; goto err_out; } - rsp->Capabilities =cpu_to_le32 (conn->vals->capabilities); + rsp->Capabilities =cpu_to_le32 (conn->vals->req_capabilities);/* For stats */ conn->connection_type = conn->dialect;
@@ -3480,7 +3480,7 @@ int smb2_open(struct ksmbd_work *work) share_ret =ksmbd_smb_check_shared_mode (fp->filp, fp);if (!test_share_config_flag (work->tcon->share_conf,KSMBD_SHARE_FLAG_OPLOCKS ) || (req_op_level ==SMB2_OPLOCK_LEVEL_LEASE && - !(conn->vals->capabilities &SMB2_GLOBAL_CAP_LEASING ))) { + !(conn->vals->req_capabilities &SMB2_GLOBAL_CAP_LEASING ))) {if (share_ret <0 && !S_ISDIR (file_inode (fp->filp)->i_mode)) { rc = share_ret; goto err_out1;
@@ -8081,7 +8081,7 @@ static int fsctl_validate_negotiate_info goto err_out; } - neg_rsp->Capabilities =cpu_to_le32 (conn->vals->capabilities); + neg_rsp->Capabilities =cpu_to_le32 (conn->vals->req_capabilities);memset (neg_rsp->Guid,0 ,SMB2_CLIENT_GUID_SIZE ); neg_rsp->SecurityMode =cpu_to_le16 (conn->srv_sec_mode); neg_rsp->Dialect =cpu_to_le16 (conn->dialect);
fs/smb/server/smb_common.h +0 -29
@@ -336,35 +336,6 @@ struct file_id_full_dir_info {char FileName[]; } __packed;/* level 0x105 FF rsp data */ -struct smb_version_values { -char *version_string; -__u16 protocol_id; -__le16 lock_cmd; -__u32 capabilities; -__u32 max_read_size; -__u32 max_write_size; -__u32 max_trans_size; -__u32 max_credits; -__u32 large_lock_type; -__u32 exclusive_lock_type; -__u32 shared_lock_type; -__u32 unlock_lock_type; -size_t header_size; -size_t max_header_size; -size_t read_rsp_size; -unsigned int cap_unix; -unsigned int cap_nt_find; -unsigned int cap_large_files; -__u16 signing_enabled; -__u16 signing_required; -size_t create_lease_size; -size_t create_durable_size; -size_t create_durable_v2_size; -size_t create_mxac_size; -size_t create_disk_id_size; -size_t create_posix_size; -}; -struct filesystem_posix_info {/* For undefined recommended transfer size return -1 in that field */ __le32 OptimalTransferSize;/* bsize on some os, iosize on other os */
Greg Kroah-Hartman
maintainerPATCH 88/166 smb: move get_rfc1002_len() to common/smbglob.h
In reply to Greg Kroah-Hartman6.6-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/transport.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
@@ -643,12 +643,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
@@ -595,7 +595,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,
@@ -1363,7 +1363,7 @@ cifs_async_readv(struct cifs_readdata *r 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);kref_get (&rdata->refcount); rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
@@ -1707,7 +1707,7 @@ cifs_async_writev(struct cifs_writedata/* 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
@@ -1230,7 +1230,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/transport.c +4 -4
@@ -882,7 +882,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);
@@ -942,7 +942,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));
@@ -1462,7 +1462,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:
@@ -1647,7 +1647,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
@@ -421,9 +421,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 89/166 smb/server: rename include guard in smb_common.h
In reply to Greg Kroah-Hartman6.6-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>
@@ -421,4 +421,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 90/166 ksmbd: rename smb2_get_msg to smb_get_msg
In reply to Greg Kroah-Hartman6.6-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/smb2pdu.c | 70 ++++++++++++++++++++++----------------------- fs/smb/server/smb2pdu.h | 9 ----- fs/smb/server/smb_common.c | 6 +-- fs/smb/server/smb_common.h | 9 +++++ 7 files changed, 54 insertions(+), 54 deletions(-)
fs/smb/server/auth.c +2 -2
@@ -920,7 +920,7 @@ int ksmbd_gen_preauth_integrity_hash(str __u8 *pi_hash) {int rc; -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 ksmbd_crypto_ctx *ctx =NULL ;
@@ -1107,7 +1107,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/smb2pdu.c +35 -35
240 lines not on this page · raw message
fs/smb/server/smb2pdu.h +0 -9
@@ -496,15 +496,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 +3 -3
@@ -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;
fs/smb/server/smb_common.h +9 -0
@@ -421,4 +421,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 91/166 smb/server: fix minimum SMB1 PDU size
In reply to Greg Kroah-Hartman6.6-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 92/166 smb/server: fix minimum SMB2 PDU size
In reply to Greg Kroah-Hartman6.6-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 93/166 ksmbd: validate minimum PDU size for transform requests
In reply to Greg Kroah-Hartman6.6-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 94/166 tcp: Pass flags to __tcp_send_ack
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit 9866884ce8ef25338c5b33cbb97c2b5d92088528 ]
Accurate ECN needs to send custom flags to handle IP-ECN field reflection during handshake.
Stable-dep-of: a28c4fcbf774 ("tcp: challenge ACK for non-exact RST in SYN-RECEIVED")
--- include/net/tcp.h | 2 +- net/ipv4/bpf_tcp_ca.c | 2 +- net/ipv4/tcp_dctcp.h | 2 +- net/ipv4/tcp_output.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-)
include/net/tcp.h +1 -1
@@ -615,7 +615,7 @@ void tcp_send_fin(struct sock *sk);void tcp_send_active_reset (struct sock *sk,gfp_t priority);int tcp_send_synack (struct sock *);void tcp_push_one (struct sock *,unsigned int mss_now); -void __tcp_send_ack (struct sock *sk,u32 rcv_nxt); +void __tcp_send_ack (struct sock *sk,u32 rcv_nxt,u16 flags);void tcp_send_ack (struct sock *sk);void tcp_send_delayed_ack (struct sock *sk);void tcp_send_loss_probe (struct sock *sk);
net/ipv4/bpf_tcp_ca.c +1 -1
@@ -128,7 +128,7 @@ static int bpf_tcp_ca_btf_struct_access( BPF_CALL_2(bpf_tcp_send_ack, struct tcp_sock *, tp, u32, rcv_nxt) {/* bpf_tcp_ca prog cannot have NULL tp */ -__tcp_send_ack ((struct sock *)tp, rcv_nxt); +__tcp_send_ack ((struct sock *)tp, rcv_nxt,0 );return 0 ; }
net/ipv4/tcp_dctcp.h +1 -1
@@ -28,7 +28,7 @@ static inline void dctcp_ece_ack_update(*/ if (inet_csk (sk)->icsk_ack.pending &ICSK_ACK_TIMER ) {dctcp_ece_ack_cwr (sk, *ce_state); -__tcp_send_ack (sk, *prior_rcv_nxt); +__tcp_send_ack (sk, *prior_rcv_nxt,0 ); }inet_csk (sk)->icsk_ack.pending |=ICSK_ACK_NOW ; }
net/ipv4/tcp_output.c +3 -3
@@ -4098,7 +4098,7 @@ void tcp_send_delayed_ack(struct sock *s }/* This routine sends an ack and also updates the window. */ -void __tcp_send_ack (struct sock *sk,u32 rcv_nxt) +void __tcp_send_ack (struct sock *sk,u32 rcv_nxt,u16 flags) {struct sk_buff *buff;
@@ -4127,7 +4127,7 @@ void __tcp_send_ack(struct sock *sk, u32/* Reserve space for headers and prepare control bits. */ skb_reserve (buff,MAX_TCP_HEADER ); -tcp_init_nondata_skb (buff,tcp_acceptable_seq (sk),TCPHDR_ACK ); +tcp_init_nondata_skb (buff,tcp_acceptable_seq (sk),TCPHDR_ACK | flags);/* We do not want pure acks influencing TCP Small Queues or fq/pacing * too much.
@@ -4142,7 +4142,7 @@ EXPORT_SYMBOL_GPL(__tcp_send_ack);void tcp_send_ack (struct sock *sk) { -__tcp_send_ack (sk,tcp_sk (sk)->rcv_nxt); +__tcp_send_ack (sk,tcp_sk (sk)->rcv_nxt,0 ); }/* This routine sends a packet with an out of date sequence
Greg Kroah-Hartman
maintainerPATCH 95/166 tcp: fast path functions later
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit 61b2f7baa9779b12a7bf1b9800a3f2a2549a1315 ]
The following patch will use tcp_ecn_mode_accecn(), TCP_ACCECN_CEP_INIT_OFFSET, TCP_ACCECN_CEP_ACE_MASK in __tcp_fast_path_on() to make new flag for AccECN.
No functional changes.
Stable-dep-of: a28c4fcbf774 ("tcp: challenge ACK for non-exact RST in SYN-RECEIVED")
--- include/net/tcp.h | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-)
include/net/tcp.h +27 -27
@@ -715,33 +715,6 @@ static inline u32 __tcp_set_rto(const streturn usecs_to_jiffies ((tp->srtt_us >>3 ) + tp->rttvar_us); } -static inline void __tcp_fast_path_on (struct tcp_sock *tp,u32 snd_wnd) -{ -/* mptcp hooks are only on the slow path */ -if (sk_is_mptcp ((struct sock *)tp)) -return ; - - tp->pred_flags =htonl ((tp->tcp_header_len <<26 ) | -ntohl (TCP_FLAG_ACK ) | - snd_wnd); -} - -static inline void tcp_fast_path_on (struct tcp_sock *tp) -{ -__tcp_fast_path_on (tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); -} - -static inline void tcp_fast_path_check (struct sock *sk) -{ -struct tcp_sock *tp =tcp_sk (sk); - -if (RB_EMPTY_ROOT (&tp->out_of_order_queue) && - tp->rcv_wnd && -atomic_read (&sk->sk_rmem_alloc) < sk->sk_rcvbuf && - !tp->urg_data) -tcp_fast_path_on (tp); -} -u32 tcp_delack_max (const struct sock *sk);/* Compute the actual rto_min value */
@@ -1658,6 +1631,33 @@ static inline bool tcp_paws_reject(constreturn true; } +static inline void __tcp_fast_path_on (struct tcp_sock *tp,u32 snd_wnd) +{ +/* mptcp hooks are only on the slow path */ +if (sk_is_mptcp ((struct sock *)tp)) +return ; + + tp->pred_flags =htonl ((tp->tcp_header_len <<26 ) | +ntohl (TCP_FLAG_ACK ) | + snd_wnd); +} + +static inline void tcp_fast_path_on (struct tcp_sock *tp) +{ +__tcp_fast_path_on (tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); +} + +static inline void tcp_fast_path_check (struct sock *sk) +{ +struct tcp_sock *tp =tcp_sk (sk); + +if (RB_EMPTY_ROOT (&tp->out_of_order_queue) && + tp->rcv_wnd && +atomic_read (&sk->sk_rmem_alloc) < sk->sk_rcvbuf && + !tp->urg_data) +tcp_fast_path_on (tp); +} +bool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time);
Greg Kroah-Hartman
maintainerPATCH 96/166 tcp: challenge ACK for non-exact RST in SYN-RECEIVED
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
[ Upstream commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 ]
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response.
--- include/net/tcp.h | 2 + net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++++++++----------- net/ipv4/tcp_minisocks.c | 12 +++++++++- 3 files changed, 56 insertions(+), 14 deletions(-)
include/net/tcp.h +2 -0
@@ -1660,6 +1660,8 @@ static inline void tcp_fast_path_check(sbool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack (struct sock *sk,struct sk_buff *skb, +struct request_sock *req);static inline void tcp_mib_init (struct net *net) {
net/ipv4/tcp_input.c +43 -13
79 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +11 -1
@@ -736,7 +736,7 @@ struct sock *tcp_check_req(struct sock ** elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ -if ((flg &TCP_FLAG_ACK ) && !fastopen && +if ((flg &TCP_FLAG_ACK ) && !(flg &TCP_FLAG_RST ) && !fastopen && (TCP_SKB_CB (skb)->ack_seq !=tcp_rsk (req)->snt_isn +1 ))return sk;
@@ -769,6 +769,16 @@ struct sock *tcp_check_req(struct sock * flg &= ~TCP_FLAG_SYN ; } +/* RFC 5961 section 3.2, as clarified by RFC 9293 section +* 3.10.7.4, requires a challenge ACK for a non-exact +* in-window RST in SYN-RECEIVED. +*/ +if ((flg &TCP_FLAG_RST ) && +TCP_SKB_CB (skb)->seq !=tcp_rsk (req)->rcv_nxt) { +tcp_reqsk_send_challenge_ack (sk, skb, req); +return NULL ; + } +/* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */
Greg Kroah-Hartman
maintainerPATCH 97/166 btrfs: add debug build only WARN
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba <[email protected]>
[ Upstream commit 3db15c6ca6feb2c5000a1cbb39c33866e0349abd ]
Add conditional WARN() wrapper that's enabled only in debug build. It should be used for unexpected conditions that should be noisy. Use it instead of ASSERT(0). As it will not lead to BUG() make sure that continuing is still possible, e.g. the error is handled anyway.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/messages.h | 7 +++++++ 1 file changed, 7 insertions(+)
fs/btrfs/messages.h +7 -0
@@ -181,6 +181,13 @@ do { \#define ASSERT (expr) (void)(expr)#endif +#ifdef CONFIG_BTRFS_DEBUG +/* Verbose warning only under debug build. */ +#define DEBUG_WARN(args...) WARN(1, KERN_ERR args) +#else +#define DEBUG_WARN (...) do {} while(0) +#endif + __printf(5, 6)__cold void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
Greg Kroah-Hartman
maintainerPATCH 98/166 btrfs: add space_info argument to btrfs_chunk_alloc()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naohiro Aota <[email protected]>
[ Upstream commit 098a442d5b6d440602604dc1a88706a2a91bce4e ]
Take a btrfs_space_info argument in btrfs_chunk_alloc(). New block group will belong to that space_info.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/block-group.c | 27 +++++++++++++++++---------- fs/btrfs/block-group.h | 3 ++- fs/btrfs/extent-tree.c | 6 ++++-- fs/btrfs/space-info.c | 2 +- fs/btrfs/transaction.c | 5 +++-- 5 files changed, 27 insertions(+), 16 deletions(-)
fs/btrfs/block-group.c +17 -10
@@ -2929,6 +2929,7 @@ int btrfs_inc_block_group_ro(struct btrf bool do_chunk_alloc) {struct btrfs_fs_info *fs_info = cache->fs_info; +struct btrfs_space_info *space_info = cache->space_info;struct btrfs_trans_handle *trans;struct btrfs_root *root =btrfs_block_group_root (fs_info);u64 alloc_flags;
@@ -2981,7 +2982,7 @@ int btrfs_inc_block_group_ro(struct btrf*/ alloc_flags =btrfs_get_alloc_profile (fs_info, cache->flags);if (alloc_flags != cache->flags) { - ret =btrfs_chunk_alloc (trans, alloc_flags, + ret =btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE );/* * ENOSPC is allowed here, we may have enough space
@@ -3009,15 +3010,15 @@ int btrfs_inc_block_group_ro(struct btrf (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM)) goto unlock_out; - alloc_flags =btrfs_get_alloc_profile (fs_info, cache->space_info->flags); - ret =btrfs_chunk_alloc (trans, alloc_flags,CHUNK_ALLOC_FORCE ); + alloc_flags =btrfs_get_alloc_profile (fs_info, space_info->flags); + ret =btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE );if (ret <0 ) goto out;/* * 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, cache->space_info, true); + ret =btrfs_zoned_activate_one_bg (fs_info, space_info, true);if (ret <0 ) goto out;
@@ -3875,8 +3876,15 @@ static int should_alloc_chunk(const struint btrfs_force_chunk_alloc (struct btrfs_trans_handle *trans,u64 type) {u64 alloc_flags =btrfs_get_alloc_profile (trans->fs_info, type); +struct btrfs_space_info *space_info; + + space_info =btrfs_find_space_info (trans->fs_info, type); +if (!space_info) { +DEBUG_WARN (); +return -EINVAL ; + } -return btrfs_chunk_alloc (trans, alloc_flags,CHUNK_ALLOC_FORCE ); +return btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE ); }static struct btrfs_block_group *do_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags)
@@ -4072,6 +4080,8 @@ out:* * This function, btrfs_chunk_alloc(), belongs to phase 1. * +* @space_info: specify which space_info the new chunk should belong to. +* * If @force is CHUNK_ALLOC_FORCE: * - return 1 if it successfully allocates a chunk, * - return errors including -ENOSPC otherwise.
@@ -4080,11 +4090,11 @@ out:* - return 1 if it successfully allocates a chunk, * - return errors including -ENOSPC otherwise. */ -int btrfs_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags, +int btrfs_chunk_alloc (struct btrfs_trans_handle *trans, +struct btrfs_space_info *space_info,u64 flags,enum btrfs_chunk_alloc_enum force) {struct btrfs_fs_info *fs_info = trans->fs_info; -struct btrfs_space_info *space_info;struct btrfs_block_group *ret_bg;bool wait_for_alloc = false;bool should_alloc = false;
@@ -4123,9 +4133,6 @@ int btrfs_chunk_alloc(struct btrfs_transif (flags &BTRFS_BLOCK_GROUP_SYSTEM )return -ENOSPC ; - space_info =btrfs_find_space_info (fs_info, flags); -ASSERT (space_info); - do { spin_lock(&space_info->lock); if (force < space_info->force_alloc)
fs/btrfs/block-group.h +2 -1
@@ -327,7 +327,8 @@ int btrfs_add_reserved_bytes(struct btrf bool force_wrong_size_class);void btrfs_free_reserved_bytes (struct btrfs_block_group *cache,u64 num_bytes,int delalloc); -int btrfs_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags, +int btrfs_chunk_alloc (struct btrfs_trans_handle *trans, +struct btrfs_space_info *space_info,u64 flags,enum btrfs_chunk_alloc_enum force);int btrfs_force_chunk_alloc (struct btrfs_trans_handle *trans,u64 type);void check_system_chunk (struct btrfs_trans_handle *trans,const u64 type);
fs/btrfs/extent-tree.c +4 -2
@@ -4034,6 +4034,7 @@ static int can_allocate_chunk(struct btrstatic int find_free_extent_update_loop (struct btrfs_fs_info *fs_info,struct btrfs_key *ins,struct find_free_extent_ctl *ffe_ctl, +struct btrfs_space_info *space_info,bool full_search) {struct btrfs_root *root = fs_info->chunk_root;
@@ -4088,7 +4089,7 @@ static int find_free_extent_update_loop(return ret; } - ret =btrfs_chunk_alloc (trans, ffe_ctl->flags, + ret =btrfs_chunk_alloc (trans, space_info, ffe_ctl->flags,CHUNK_ALLOC_FORCE_FOR_EXTENT );/* Do not bail out on ENOSPC since we can do more. */
@@ -4488,7 +4489,8 @@ loop: }up_read (&space_info->groups_sem); - ret =find_free_extent_update_loop (fs_info, ins, ffe_ctl, full_search); + ret =find_free_extent_update_loop (fs_info, ins, ffe_ctl, space_info, + full_search);if (ret >0 ) goto search;
fs/btrfs/space-info.c +1 -1
@@ -807,7 +807,7 @@ static void flush_space(struct btrfs_fs_ ret =PTR_ERR (trans);break ; } - ret =btrfs_chunk_alloc (trans, + ret =btrfs_chunk_alloc (trans, space_info,btrfs_get_alloc_profile (fs_info, space_info->flags), (state ==ALLOC_CHUNK ) ?CHUNK_ALLOC_NO_FORCE :CHUNK_ALLOC_FORCE );
fs/btrfs/transaction.c +3 -2
@@ -729,9 +729,10 @@ got_it:* value here. */ if (do_chunk_alloc && num_bytes) { -u64 flags = h->block_rsv->space_info->flags; +struct btrfs_space_info *space_info = h->block_rsv->space_info; +u64 flags = space_info->flags; -btrfs_chunk_alloc (h,btrfs_get_alloc_profile (fs_info, flags), +btrfs_chunk_alloc (h, space_info,btrfs_get_alloc_profile (fs_info, flags),CHUNK_ALLOC_NO_FORCE ); }
Greg Kroah-Hartman
maintainerPATCH 99/166 btrfs: remove fs_info argument from btrfs_zoned_activate_one_bg()
In reply to Greg Kroah-Hartman6.6-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
@@ -3018,7 +3018,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;
@@ -4284,7 +4284,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
@@ -2457,10 +2457,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
@@ -81,8 +81,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);#else /* CONFIG_BLK_DEV_ZONED */ static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
@@ -253,8 +252,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 100/166 btrfs: zoned: fix missing chunk metadata reservation
In reply to Greg Kroah-Hartman6.6-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
@@ -4280,25 +4280,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 101/166 mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kefeng Wang <[email protected]>
[ Upstream commit 63867c82d0c0c2d182016a32b1cc0103116b0ea5 ]
pte_pfn() and pte_dirty() have undefined behaviour when called on a non-present PTE. In migrate_vma_collect_pmd(), these functions may be invoked on non-present entries (e.g., device-private entries), leading to potential crashes from pte_pfn() or incorrect dirty folio accounting from pte_dirty(). Fix both by guarding with pte_present() checks.
--- mm/migrate_device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
mm/migrate_device.c +3 -2
@@ -194,7 +194,8 @@ again:bool anon_exclusive;pte_t swp_pte; -flush_cache_page (vma, addr,pte_pfn (pte)); +if (pte_present (pte)) +flush_cache_page (vma, addr,pte_pfn (pte)); anon_exclusive =PageAnon (page) &&PageAnonExclusive (page);if (anon_exclusive) { pte =ptep_clear_flush (vma, addr, ptep);
@@ -213,7 +214,7 @@ again: migrate->cpages++;/* Set the dirty flag on the folio now the pte is gone. */ -if (pte_dirty (pte)) +if (pte_present (pte) &&pte_dirty (pte))folio_mark_dirty (page_folio (page));/* Setup special migration page table entry */
Greg Kroah-Hartman
maintainerPATCH 102/166 ice: make use of DEFINE_FLEX() in ice_switch.c
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Przemek Kitszel <[email protected]>
[ Upstream commit e268b972270567e0414836919c5b9f8bc01651a4 ]
Use DEFINE_FLEX() macro for 1-elem flex array members of ice_switch.c
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- drivers/net/ethernet/intel/ice/ice_switch.c | 63 ++++++---------------------- 1 file changed, 14 insertions(+), 49 deletions(-)
drivers/net/ethernet/intel/ice/ice_switch.c +14 -49
@@ -1812,15 +1812,11 @@ ice_aq_alloc_free_vsi_list(struct ice_hwenum ice_sw_lkup_type lkup_type, enum ice_adminq_opc opc) { -struct ice_aqc_alloc_free_res_elem *sw_buf; + DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); +u16 buf_len =__struct_size (sw_buf);struct ice_aqc_res_elem *vsi_ele; -u16 buf_len;int status; - buf_len =struct_size (sw_buf, elem,1 ); - sw_buf =devm_kzalloc (ice_hw_to_dev (hw), buf_len,GFP_KERNEL ); -if (!sw_buf) -return -ENOMEM ; sw_buf->num_elems =cpu_to_le16 (1 ); if (lkup_type == ICE_SW_LKUP_MAC ||
@@ -1841,8 +1837,7 @@ ice_aq_alloc_free_vsi_list(struct ice_hw sw_buf->res_type =cpu_to_le16 (ICE_AQC_RES_TYPE_VSI_LIST_PRUNE ); }else { - status = -EINVAL ; - goto ice_aq_alloc_free_vsi_list_exit; +return -EINVAL ; }if (opc == ice_aqc_opc_free_res)
@@ -1850,16 +1845,14 @@ ice_aq_alloc_free_vsi_list(struct ice_hw status =ice_aq_alloc_free_res (hw, sw_buf, buf_len, opc);if (status) - goto ice_aq_alloc_free_vsi_list_exit; +return status;if (opc == ice_aqc_opc_alloc_res) { vsi_ele = &sw_buf->elem[0 ]; *vsi_list_id =le16_to_cpu (vsi_ele->e.sw_resp); } -ice_aq_alloc_free_vsi_list_exit: -devm_kfree (ice_hw_to_dev (hw), sw_buf); -return status; +return 0 ; }/**
@@ -2089,15 +2082,10 @@ ice_aq_get_recipe_to_profile(struct ice_*/ int ice_alloc_recipe (struct ice_hw *hw,u16 *rid) { -struct ice_aqc_alloc_free_res_elem *sw_buf; -u16 buf_len; + DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); +u16 buf_len =__struct_size (sw_buf);int status; - buf_len =struct_size (sw_buf, elem,1 ); - sw_buf =kzalloc (buf_len,GFP_KERNEL ); -if (!sw_buf) -return -ENOMEM ; - sw_buf->num_elems =cpu_to_le16 (1 ); sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE << ICE_AQC_RES_TYPE_S) |
@@ -2106,7 +2094,6 @@ int ice_alloc_recipe(struct ice_hw *hw, ice_aqc_opc_alloc_res);if (!status) *rid =le16_to_cpu (sw_buf->elem[0 ].e.sw_resp); -kfree (sw_buf);return status; }
@@ -4438,28 +4425,19 @@ int ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, u16 *counter_id) { - struct ice_aqc_alloc_free_res_elem *buf; -u16 buf_len; + DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); +u16 buf_len =__struct_size (buf);int status; -/* Allocate resource */ - buf_len =struct_size (buf, elem,1 ); - buf =kzalloc (buf_len,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; - buf->num_elems =cpu_to_le16 (num_items); buf->res_type =cpu_to_le16 (((type <<ICE_AQC_RES_TYPE_S ) &ICE_AQC_RES_TYPE_M ) | alloc_shared); status =ice_aq_alloc_free_res (hw, buf, buf_len, ice_aqc_opc_alloc_res);if (status) - goto exit; +return status; *counter_id =le16_to_cpu (buf->elem[0 ].e.sw_resp); - -exit: -kfree (buf);return status; }
@@ -4475,16 +4453,10 @@ int ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, u16 counter_id) { - struct ice_aqc_alloc_free_res_elem *buf; -u16 buf_len; + DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); +u16 buf_len =__struct_size (buf);int status; -/* Free resource */ - buf_len =struct_size (buf, elem,1 ); - buf =kzalloc (buf_len,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; - buf->num_elems =cpu_to_le16 (num_items); buf->res_type =cpu_to_le16 (((type <<ICE_AQC_RES_TYPE_S ) &ICE_AQC_RES_TYPE_M ) | alloc_shared);
@@ -4494,7 +4466,6 @@ ice_free_res_cntr(struct ice_hw *hw, u8if (status)ice_debug (hw,ICE_DBG_SW ,"counter resource could not be freed\n" ); -kfree (buf);return status; }
@@ -4512,15 +4483,10 @@ ice_free_res_cntr(struct ice_hw *hw, u8*/ int ice_share_res (struct ice_hw *hw,u16 type,u8 shared,u16 res_id) { -struct ice_aqc_alloc_free_res_elem *buf; -u16 buf_len; + DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); +u16 buf_len =__struct_size (buf);int status; - buf_len =struct_size (buf, elem,1 ); - buf =kzalloc (buf_len,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; - buf->num_elems =cpu_to_le16 (1 );if (shared) buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
@@ -4538,7 +4504,6 @@ int ice_share_res(struct ice_hw *hw, u16ice_debug (hw,ICE_DBG_SW ,"Could not set resource type %u id %u to %s\n" , type, res_id, shared ?"SHARED" :"DEDICATED" ); -kfree (buf);return status; }
Greg Kroah-Hartman
maintainerPATCH 103/166 ice: make ice_vsi_cfg_rxq() static
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 3e5fb691faee1d43ee13d4ce2666b0a05e1555b3 ]
Currently, XSK control path in ice driver calls directly ice_vsi_cfg_rxq() whereas we have ice_vsi_cfg_single_rxq() for that purpose. Use the latter from XSK side and make ice_vsi_cfg_rxq() static.
ice_vsi_cfg_rxq() resides in ice_base.c and is rather big, so to reduce the code churn let us move two callers of it from ice_lib.c to ice_base.c.
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- drivers/net/ethernet/intel/ice/ice_base.c | 58 +++++++++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_base.h | 3 + drivers/net/ethernet/intel/ice/ice_lib.c | 56 ---------------------------- drivers/net/ethernet/intel/ice/ice_lib.h | 4 -- drivers/net/ethernet/intel/ice/ice_xsk.c | 2 - 5 files changed, 60 insertions(+), 63 deletions(-)
drivers/net/ethernet/intel/ice/ice_base.c +57 -1
@@ -544,7 +544,7 @@ static unsigned int ice_get_frame_sz(str* * Return 0 on success and a negative value on error. */ -int ice_vsi_cfg_rxq (struct ice_rx_ring *ring) +static int ice_vsi_cfg_rxq (struct ice_rx_ring *ring) {struct device *dev =ice_pf_to_dev (ring->vsi->back);u32 num_bufs =ICE_RX_DESC_UNUSED (ring);
@@ -636,6 +636,62 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *return 0 ; } + +int ice_vsi_cfg_single_rxq (struct ice_vsi *vsi,u16 q_idx) +{ +if (q_idx >= vsi->num_rxq) +return -EINVAL ; + +return ice_vsi_cfg_rxq (vsi->rx_rings[q_idx]); +} + +/** +* ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length +* @vsi: VSI +*/ +static void ice_vsi_cfg_frame_size (struct ice_vsi *vsi) +{ +if (!vsi->netdev ||test_bit (ICE_FLAG_LEGACY_RX , vsi->back->flags)) { + vsi->max_frame =ICE_MAX_FRAME_LEGACY_RX ; + vsi->rx_buf_len =ICE_RXBUF_1664 ; +#if (PAGE_SIZE <8192 ) + } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && + (vsi->netdev->mtu <=ETH_DATA_LEN )) { + vsi->max_frame =ICE_RXBUF_1536 -NET_IP_ALIGN ; + vsi->rx_buf_len =ICE_RXBUF_1536 -NET_IP_ALIGN ; +#endif + }else { + vsi->max_frame =ICE_AQ_SET_MAC_FRAME_SIZE_MAX ; + vsi->rx_buf_len =ICE_RXBUF_3072 ; + } +} + +/** +* ice_vsi_cfg_rxqs - Configure the VSI for Rx +* @vsi: the VSI being configured +* +* Return 0 on success and a negative value on error +* Configure the Rx VSI for operation. +*/ +int ice_vsi_cfg_rxqs (struct ice_vsi *vsi) +{ +u16 i; + +if (vsi->type ==ICE_VSI_VF ) + goto setup_rings; + +ice_vsi_cfg_frame_size (vsi); +setup_rings: +/* set up individual rings */ +ice_for_each_rxq (vsi, i) { +int err =ice_vsi_cfg_rxq (vsi->rx_rings[i]); + +if (err) +return err; + } + +return 0 ; +}/** * __ice_vsi_get_qs - helper function for assigning queues from PF to VSI
drivers/net/ethernet/intel/ice/ice_base.h +2 -1
@@ -6,7 +6,8 @@#include "ice.h" -int ice_vsi_cfg_rxq (struct ice_rx_ring *ring); +int ice_vsi_cfg_single_rxq (struct ice_vsi *vsi,u16 q_idx); +int ice_vsi_cfg_rxqs (struct ice_vsi *vsi);int __ice_vsi_get_qs (struct ice_qs_cfg *qs_cfg);int ice_vsi_ctrl_one_rx_ring (struct ice_vsi *vsi,bool ena,u16 rxq_idx,bool wait);
drivers/net/ethernet/intel/ice/ice_lib.c +0 -56
74 lines not on this page · raw message
drivers/net/ethernet/intel/ice/ice_lib.h +0 -4
@@ -54,12 +54,8 @@ bool ice_pf_state_is_nominal(struct ice_void ice_update_eth_stats (struct ice_vsi *vsi); -int ice_vsi_cfg_single_rxq (struct ice_vsi *vsi,u16 q_idx); -int ice_vsi_cfg_single_txq (struct ice_vsi *vsi,struct ice_tx_ring **tx_rings,u16 q_idx); -int ice_vsi_cfg_rxqs (struct ice_vsi *vsi); -int ice_vsi_cfg_lan_txqs (struct ice_vsi *vsi);void ice_vsi_cfg_msix (struct ice_vsi *vsi);
drivers/net/ethernet/intel/ice/ice_xsk.c +1 -1
@@ -252,7 +252,7 @@ static int ice_qp_ena(struct ice_vsi *vsice_tx_xsk_pool (vsi, q_idx); } - err =ice_vsi_cfg_rxq (rx_ring); + err =ice_vsi_cfg_single_rxq (vsi, q_idx);if (err) goto free_buf;
Greg Kroah-Hartman
maintainerPATCH 104/166 overflow: Change DEFINE_FLEX to take __counted_by member
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
[ Upstream commit d8e45f2929b94099913eb66c3ebb18b5063e9421 ]
The norm should be flexible array structures with __counted_by annotations, so DEFINE_FLEX() is updated to expect that. Rename the non-annotated version to DEFINE_RAW_FLEX(), and update the few existing users. Additionally add selftests for the macros.
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- drivers/net/ethernet/intel/ice/ice_switch.c | 10 ++--- include/linux/overflow.h | 52 ++++++++++++++++++++++++++++ lib/overflow_kunit.c | 19 ++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/ice/ice_switch.c +5 -5
@@ -1812,7 +1812,7 @@ ice_aq_alloc_free_vsi_list(struct ice_hwenum ice_sw_lkup_type lkup_type, enum ice_adminq_opc opc) { - DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);u16 buf_len =__struct_size (sw_buf);struct ice_aqc_res_elem *vsi_ele;int status;
@@ -2082,7 +2082,7 @@ ice_aq_get_recipe_to_profile(struct ice_*/ int ice_alloc_recipe (struct ice_hw *hw,u16 *rid) { - DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);u16 buf_len =__struct_size (sw_buf);int status;
@@ -4425,7 +4425,7 @@ int ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, u16 *counter_id) { - DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);u16 buf_len =__struct_size (buf);int status;
@@ -4453,7 +4453,7 @@ int ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, u16 counter_id) { - DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);u16 buf_len =__struct_size (buf);int status;
@@ -4483,7 +4483,7 @@ ice_free_res_cntr(struct ice_hw *hw, u8*/ int ice_share_res (struct ice_hw *hw,u16 type,u8 shared,u16 res_id) { - DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);u16 buf_len =__struct_size (buf);int status;
include/linux/overflow.h +52 -0
56 lines not on this page · raw message
lib/overflow_kunit.c +19 -0
@@ -1113,6 +1113,24 @@ static void castable_to_type_test(struct#undef TEST_CASTABLE_TO_TYPE } +struct foo { +int a; +u32 counter; + s16 array[] __counted_by(counter); +}; + +static void DEFINE_FLEX_test (struct kunit *test) +{ + DEFINE_RAW_FLEX(struct foo, two, array, 2); + DEFINE_FLEX(struct foo, eight, array, counter, 8); + DEFINE_FLEX(struct foo, empty, array, counter, 0); + +KUNIT_EXPECT_EQ (test,__struct_size (two), +sizeof (struct foo ) +sizeof (s16) +sizeof (s16)); +KUNIT_EXPECT_EQ (test,__struct_size (eight),24 ); +KUNIT_EXPECT_EQ (test,__struct_size (empty),sizeof (struct foo )); +} +static struct kunit_case overflow_test_cases[] = {KUNIT_CASE (u8_u8__u8_overflow_test),KUNIT_CASE (s8_s8__s8_overflow_test),
@@ -1135,6 +1153,7 @@ static struct kunit_case overflow_test_cKUNIT_CASE (overflows_type_test),KUNIT_CASE (same_type_test),KUNIT_CASE (castable_to_type_test), + KUNIT_CASE(DEFINE_FLEX_test), {} };
Greg Kroah-Hartman
maintainerPATCH 105/166 Bluetooth: hci_conn, hci_sync: Use __counted_by() to avoid -Wfamnae warnings
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Gustavo A. R. Silva" <[email protected]>
[ Upstream commit c4585edf708edb5277a3cc4b8581ccb833f3307d ]
Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions).
Also, -Wflex-array-member-not-at-end is coming in GCC-14, and we are getting ready to enable it globally.
So, use the DEFINE_FLEX() helper for multiple on-stack definitions of a flexible structure where the size of the flexible-array member is known at compile-time, and refactor the rest of the code, accordingly.
Notice that, due to the use of __counted_by() in struct hci_cp_le_create_cis, the for loop in function hci_cs_le_create_cis() had to be modified. Once the index i, through which cp->cis[i] is accessed, falls in the interval [0, cp->num_cis), cp->num_cis cannot be decremented all the way down to zero while accessing cp->cis[]:
net/bluetooth/hci_event.c:4310:
4310 for (i = 0; cp->num_cis; cp->num_cis--, i++) {
...4314 handle = __le16_to_cpu(cp->cis[i].cis_handle);
otherwise, only half (one iteration before cp->num_cis == i) or half plus one (one iteration before cp->num_cis < i) of the items in the array will be accessed before running into an out-of-bounds issue. So, in order to avoid this, set cp->num_cis to zero just after the for loop.
Also, make use of aux_num_cis variable to update cmd->num_cis after a list_for_each_entry_rcu() loop.
With these changes, fix the following warnings:net/bluetooth/hci_sync.c:1239:56: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:1415:51: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:1731:51: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:6497:45: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- include/net/bluetooth/hci.h | 8 ++-- net/bluetooth/hci_event.c | 3 + net/bluetooth/hci_sync.c | 84 +++++++++++++++++--------------------------- 3 files changed, 40 insertions(+), 55 deletions(-)
include/net/bluetooth/hci.h +4 -4
@@ -1949,7 +1949,7 @@ struct hci_cp_le_set_ext_adv_data {__u8 operation;__u8 frag_pref;__u8 length; -__u8 data[]; + __u8 data[] __counted_by(length); } __packed;#define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038
@@ -1958,7 +1958,7 @@ struct hci_cp_le_set_ext_scan_rsp_data {__u8 operation;__u8 frag_pref;__u8 length; -__u8 data[]; + __u8 data[] __counted_by(length); } __packed;#define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039
@@ -1983,7 +1983,7 @@ struct hci_cp_le_set_per_adv_data {__u8 handle;__u8 operation;__u8 length; -__u8 data[]; + __u8 data[] __counted_by(length); } __packed;#define HCI_OP_LE_SET_PER_ADV_ENABLE 0x2040
@@ -2084,7 +2084,7 @@ struct hci_cis {struct hci_cp_le_create_cis {__u8 num_cis; -struct hci_cis cis[]; + struct hci_cis cis[] __counted_by(num_cis); } __packed;#define HCI_OP_LE_REMOVE_CIG 0x2065
net/bluetooth/hci_event.c +2 -1
@@ -4253,7 +4253,7 @@ static void hci_cs_le_create_cis(structhci_dev_lock (hdev);/* Remove connection if command failed */ -for (i =0 ; cp->num_cis; cp->num_cis--, i++) { +for (i =0 ; i < cp->num_cis; i++) {struct hci_conn *conn;u16 handle;
@@ -4269,6 +4269,7 @@ static void hci_cs_le_create_cis(structhci_conn_del (conn); } } + cp->num_cis =0 ;if (pending)hci_le_create_cis_pending (hdev);
net/bluetooth/hci_sync.c +34 -50
188 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 106/166 Bluetooth: hci_core: Fix not handling hdev->le_num_of_adv_sets=1
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit e77f43d531af41e9ce299eab10dcae8fa5dbc293 ]
If hdev->le_num_of_adv_sets is set to 1 it means that only handle 0x00 can be used, but since the MGMT interface instances start from 1 (instance 0 means all instances in case of MGMT_OP_REMOVE_ADVERTISING) the code needs to map the instance to handle otherwise users will not be able to advertise as instance 1 would attempt to use handle 0x01.
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 9 +++++++++ net/bluetooth/hci_sync.c | 19 +++++++++---------- 3 files changed, 19 insertions(+), 10 deletions(-)
include/net/bluetooth/hci_core.h +1 -0
@@ -245,6 +245,7 @@ struct adv_info {bool periodic_enabled;__u8 mesh;__u8 instance; +__u8 handle;__u32 flags;__u16 timeout;__u16 remaining_time;
net/bluetooth/hci_core.c +9 -0
@@ -1706,6 +1706,15 @@ struct adv_info *hci_add_adv_instance(st adv->pending = true; adv->instance = instance; + +/* If controller support only one set and the instance is set to +* 1 then there is no option other than using handle 0x00. +*/ +if (hdev->le_num_of_adv_sets ==1 && instance ==1 ) + adv->handle =0x00 ; +else + adv->handle = instance; +list_add (&adv->list, &hdev->adv_instances); hdev->adv_instance_cnt++; }
net/bluetooth/hci_sync.c +9 -10
@@ -1195,11 +1195,10 @@ static int hci_disable_ext_adv_instance_struct hci_cp_ext_adv_set *set;u8 data[sizeof (*cp) +sizeof (*set) *1 ];u8 size; +struct adv_info *adv =NULL ;/* If request specifies an instance that doesn't exist, fail */ if (instance >0 ) { -struct adv_info *adv; - adv =hci_find_adv_instance (hdev, instance);if (!adv)return -EINVAL ;
@@ -1218,7 +1217,7 @@ static int hci_disable_ext_adv_instance_ cp->num_of_sets = !!instance; cp->enable =0x00 ; - set->handle = instance; + set->handle = adv ? adv->handle : instance; size =sizeof (*cp) +sizeof (*set) * cp->num_of_sets;
@@ -1312,7 +1311,7 @@ static int hci_set_ext_adv_data_sync(str len =eir_create_adv_data (hdev, instance, pdu->data); pdu->length = len; - pdu->handle = instance; + pdu->handle = adv ? adv->handle : instance; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ;
@@ -1465,7 +1464,7 @@ int hci_setup_ext_adv_instance_sync(stru cp.own_addr_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; - cp.handle = instance; + cp.handle = adv ? adv->handle : instance;if (flags &MGMT_ADV_FLAG_SEC_2M ) { cp.primary_phy =HCI_ADV_PHY_1M ;
@@ -1523,7 +1522,7 @@ static int hci_set_ext_scan_rsp_data_syn len =eir_create_scan_rsp (hdev, instance, pdu->data); - pdu->handle = instance; + pdu->handle = adv ? adv->handle : instance; pdu->length = len; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ;
@@ -1605,7 +1604,7 @@ int hci_enable_ext_advertising_sync(strumemset (set,0 ,sizeof (*set)); - set->handle = instance; + set->handle = adv ? adv->handle : instance;/* Set duration per instance since controller is responsible for * scheduling it.
@@ -1684,10 +1683,10 @@ static int hci_set_per_adv_data_sync(str DEFINE_FLEX(struct hci_cp_le_set_per_adv_data, pdu, data, length, HCI_MAX_PER_AD_LENGTH);u8 len; +struct adv_info *adv =NULL ;if (instance) { -struct adv_info *adv =hci_find_adv_instance (hdev, instance); - + adv =hci_find_adv_instance (hdev, instance);if (!adv || !adv->periodic)return 0 ; }
@@ -1695,7 +1694,7 @@ static int hci_set_per_adv_data_sync(str len =eir_create_per_adv_data (hdev, instance, pdu->data); pdu->length = len; - pdu->handle = instance; + pdu->handle = adv ? adv->handle : instance; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA,
Greg Kroah-Hartman
maintainerPATCH 107/166 Bluetooth: eir: Fix possible crashes on eir_create_adv_data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 47c03902269aff377f959dc3fd94a9733aa31d6e ]
eir_create_adv_data may attempt to add EIR_FLAGS and EIR_TX_POWER without checking if that would fit.
Stable-dep-of: cdc36db204ff ("Bluetooth: hci_sync: Fix advertising data UAFs")
--- net/bluetooth/eir.c | 7 ++++--- net/bluetooth/eir.h | 2 +- net/bluetooth/hci_sync.c | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-)
net/bluetooth/eir.c +4 -3
@@ -242,7 +242,7 @@ u8 eir_create_per_adv_data(struct hci_dereturn ad_len; } -u8 eir_create_adv_data (struct hci_dev *hdev,u8 instance,u8 *ptr) +u8 eir_create_adv_data (struct hci_dev *hdev,u8 instance,u8 *ptr,u8 size) {struct adv_info *adv =NULL ;u8 ad_len =0 , flags =0 ;
@@ -286,7 +286,7 @@ u8 eir_create_adv_data(struct hci_dev *h/* If flags would still be empty, then there is no need to * include the "Flags" AD field". */ -if (flags) { +if (flags && (ad_len +eir_precalc_len (1 ) <= size)) { ptr[0 ] =0x02 ; ptr[1 ] =EIR_FLAGS ; ptr[2 ] = flags;
@@ -316,7 +316,8 @@ skip_flags: }/* Provide Tx Power only if we can provide a valid value for it */ -if (adv_tx_power !=HCI_TX_POWER_INVALID ) { +if (adv_tx_power !=HCI_TX_POWER_INVALID && + (ad_len +eir_precalc_len (1 ) <= size)) { ptr[0 ] =0x02 ; ptr[1 ] =EIR_TX_POWER ; ptr[2 ] = (u8 )adv_tx_power;
net/bluetooth/eir.h +1 -1
@@ -9,7 +9,7 @@void eir_create (struct hci_dev *hdev,u8 *data); -u8 eir_create_adv_data (struct hci_dev *hdev,u8 instance,u8 *ptr); +u8 eir_create_adv_data (struct hci_dev *hdev,u8 instance,u8 *ptr,u8 size);u8 eir_create_scan_rsp (struct hci_dev *hdev,u8 instance,u8 *ptr);u8 eir_create_per_adv_data (struct hci_dev *hdev,u8 instance,u8 *ptr);
net/bluetooth/hci_sync.c +3 -2
@@ -1308,7 +1308,8 @@ static int hci_set_ext_adv_data_sync(strreturn 0 ; } - len =eir_create_adv_data (hdev, instance, pdu->data); + len =eir_create_adv_data (hdev, instance, pdu->data, +HCI_MAX_EXT_AD_LENGTH ); pdu->length = len; pdu->handle = adv ? adv->handle : instance;
@@ -1339,7 +1340,7 @@ static int hci_set_adv_data_sync(structmemset (&cp,0 ,sizeof (cp)); - len =eir_create_adv_data (hdev, instance, cp.data); + len =eir_create_adv_data (hdev, instance, cp.data,sizeof (cp.data));/* There's nothing to do if the data hasn't changed */ if (hdev->adv_data_len == len &&
Greg Kroah-Hartman
maintainerPATCH 108/166 Bluetooth: hci_sync: Fix advertising data UAFs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit cdc36db204ffd97b947d64374cf23a210dc74777 ]
hci_find_adv_instance() returns an adv_info pointer that is valid only while hdev->lock is held. The advertising command-sync paths perform instance lookups without that lock and, in some cases, retain the pointer while waiting for a controller response.
An advertising termination event can therefore interleave as follows:
hci_cmd_sync_work hci_rx_work
hci_find_adv_instance()
__hci_cmd_sync_status()
wait for controller reply hci_dev_lock()
hci_remove_adv_instance()
kfree(adv)
adv->scan_rsp_changed = false
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 hci_schedule_adv_instance_sync+0x390/0x4c0 hci_cmd_sync_work+0x173/0x300 Allocated by task 87: hci_add_adv_instance+0x538/0xac0 add_advertising+0x885/0x1160 Freed by task 89: kfree+0x131/0x3c0 hci_remove_adv_instance+0x1d8/0x3b0 hci_le_ext_adv_term_evt+0x17b/0x730
Protect the instance lookup and payload construction in the extended advertising, scan response, and periodic advertising data paths. Snapshot the advertising parameters under hdev->lock, but release the lock before waiting for the controller.
Clear advertising-data dirty bits before issuing their commands and restore them after a failure using a fresh lookup. Likewise, update the reported transmit power through a fresh lookup after the parameter command completes. No adv_info pointer then survives an HCI command wait.
--- net/bluetooth/hci_sync.c | 131 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 34 deletions(-)
net/bluetooth/hci_sync.c +97 -34
@@ -1252,10 +1252,11 @@ static int hci_set_adv_set_random_addr_s }static int -hci_set_ext_adv_params_sync (struct hci_dev *hdev,struct adv_info *adv, +hci_set_ext_adv_params_sync (struct hci_dev *hdev,u8 instance,const struct hci_cp_le_set_ext_adv_params *cp,struct hci_rp_le_set_ext_adv_params *rp) { +struct adv_info *adv;struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
@@ -1283,11 +1284,15 @@ hci_set_ext_adv_params_sync(struct hci_dif (!rp->status) { hdev->adv_addr_type = cp->own_addr_type; -if (!cp->handle) { +if (!instance) {/* Store in hdev for instance 0 */ hdev->adv_tx_power = rp->tx_power; - }else if (adv) { - adv->tx_power = rp->tx_power; + }else { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->tx_power = rp->tx_power; +hci_dev_unlock (hdev); } }
@@ -1303,9 +1308,13 @@ static int hci_set_ext_adv_data_sync(strint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->adv_data_changed) +if (!adv || !adv->adv_data_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len = eir_create_adv_data(hdev, instance, pdu->data,
@@ -1316,16 +1325,27 @@ static int hci_set_ext_adv_data_sync(str pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->adv_data_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->adv_data_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -/* Update data if the command succeed */ -if (adv) { - adv->adv_data_changed = false; - }else { +if (!instance) {memcpy (hdev->adv_data, pdu->data, len); hdev->adv_data_len = len; }
@@ -1379,22 +1399,22 @@ int hci_setup_ext_adv_instance_sync(strustruct adv_info *adv;bool secondary_adv; -if (instance >0 ) { - adv =hci_find_adv_instance (hdev, instance); -if (!adv) -return -EINVAL ; - }else { - adv =NULL ; - } -/* Updating parameters of an active instance will return a -* Command Disallowed error, so we must first disable the -* instance if it is active. +* Command Disallowed error, so disable it before taking a snapshot. */ -if (adv) { +if (instance >0 ) { err =hci_disable_ext_adv_instance_sync (hdev, instance);if (err)return err; + +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv) { +hci_dev_unlock (hdev); +return -EINVAL ; + } + }else { + adv =NULL ; } flags =hci_adv_instance_flags (hdev, instance);
@@ -1405,8 +1425,11 @@ int hci_setup_ext_adv_instance_sync(stru connectable = (flags &MGMT_ADV_FLAG_CONNECTABLE ) ||mgmt_get_connectable (hdev); -if (!is_advertising_allowed (hdev, connectable)) +if (!is_advertising_allowed (hdev, connectable)) { +if (instance) +hci_dev_unlock (hdev);return -EPERM ; + }/* Set require_privacy to true only when non-connectable * advertising is used and it is not periodic.
@@ -1417,8 +1440,11 @@ int hci_setup_ext_adv_instance_sync(stru err =hci_get_random_address (hdev, require_privacy,adv_use_rpa (hdev, flags), adv, &own_addr_type, &random_addr); -if (err <0 ) +if (err <0 ) { +if (instance) +hci_dev_unlock (hdev);return err; + }memset (&cp,0 ,sizeof (cp));
@@ -1467,6 +1493,9 @@ int hci_setup_ext_adv_instance_sync(stru cp.channel_map = hdev->le_adv_channel_map; cp.handle = adv ? adv->handle : instance; +if (instance) +hci_dev_unlock (hdev); +if (flags &MGMT_ADV_FLAG_SEC_2M ) { cp.primary_phy =HCI_ADV_PHY_1M ; cp.secondary_phy =HCI_ADV_PHY_2M ;
@@ -1479,12 +1508,12 @@ int hci_setup_ext_adv_instance_sync(stru cp.secondary_phy =HCI_ADV_PHY_1M ; } - err =hci_set_ext_adv_params_sync (hdev, adv, &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev, instance, &cp, &rp);if (err)return err;/* Update adv data as tx power is known now */ - err =hci_set_ext_adv_data_sync (hdev, cp.handle); + err =hci_set_ext_adv_data_sync (hdev, instance);if (err)return err;
@@ -1492,9 +1521,14 @@ int hci_setup_ext_adv_instance_sync(stru own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) && bacmp(&random_addr, BDADDR_ANY)) {/* Check if random address need to be updated */ -if (adv) { -if (!bacmp (&random_addr, &adv->random_addr)) +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv || !bacmp (&random_addr, &adv->random_addr)) { +hci_dev_unlock (hdev);return 0 ; + } +hci_dev_unlock (hdev); }else {if (!bacmp (&random_addr, &hdev->random_addr))return 0 ;
@@ -1516,9 +1550,13 @@ static int hci_set_ext_scan_rsp_data_synint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->scan_rsp_changed) +if (!adv || !adv->scan_rsp_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_scan_rsp (hdev, instance, pdu->data);
@@ -1528,15 +1566,27 @@ static int hci_set_ext_scan_rsp_data_syn pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->scan_rsp_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_SCAN_RSP_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->scan_rsp_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -if (adv) { - adv->scan_rsp_changed = false; - }else { +if (!instance) {memcpy (hdev->scan_rsp_data, pdu->data, len); hdev->scan_rsp_data_len = len; }
@@ -1551,8 +1601,14 @@ static int __hci_set_scan_rsp_data_sync(memset (&cp,0 ,sizeof (cp)); +if (instance) +hci_dev_lock (hdev); + len =eir_create_scan_rsp (hdev, instance, cp.data); +if (instance) +hci_dev_unlock (hdev); +if (hdev->scan_rsp_data_len == len && !memcmp (cp.data, hdev->scan_rsp_data, len))return 0 ;
@@ -1687,9 +1743,13 @@ static int hci_set_per_adv_data_sync(strstruct adv_info *adv =NULL ;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->periodic) +if (!adv || !adv->periodic) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_per_adv_data (hdev, instance, pdu->data);
@@ -1698,6 +1758,9 @@ static int hci_set_per_adv_data_sync(str pdu->handle = adv ? adv->handle : instance; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; +if (adv) +hci_dev_unlock (hdev); +return __hci_cmd_sync_status (hdev,HCI_OP_LE_SET_PER_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT );
@@ -6402,7 +6465,7 @@ static int hci_le_ext_directed_advertisiif (err)return err; - err =hci_set_ext_adv_params_sync (hdev,NULL , &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev,0 , &cp, &rp);if (err)return err;
Greg Kroah-Hartman
maintainerPATCH 109/166 ASoC: tas2562: Validate values for volume writes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Brown <[email protected]>
[ Upstream commit 8fb41964f7e4e4207c8999af2056894caa7a252a ]
tas2562_volume_control_put() does not do any validation of the control value written by userspace, it uses it to look up a value in a fixed size array which can easily be overflowed and then writes whatever value it gets back to the device. Add validation that we are loading a value we have in the array.
--- sound/soc/codecs/tas2562.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
sound/soc/codecs/tas2562.c +7 -2
@@ -473,10 +473,15 @@ static int tas2562_volume_control_put(st {struct snd_soc_component *component =snd_soc_kcontrol_component (kcontrol);struct tas2562_data *tas2562 =snd_soc_component_get_drvdata (component); -int ret; +int ret, index;u32 reg_val; - reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; + index = ucontrol->value.integer.value[0 ] /2 ; +if (index <0 || index >=ARRAY_SIZE (float_vol_db_lookup)) +return -EINVAL ; + + reg_val = float_vol_db_lookup[index]; +/* * The device applies the 32-bit coefficient to the playback path on * the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the
Greg Kroah-Hartman
maintainerPATCH 110/166 igc: remove napi_synchronize() in igc_down()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit 5ffab5b9589c50e4cfc0cf36ffd76c89422d4019 ]
When an AF_XDP zero-copy application is killed abruptly, the XSK pool is torn down but NAPI keeps polling. igc_clean_rx_irq_zc() then returns the full budget on every poll, so napi_complete_done() never clears NAPI_STATE_SCHED.
igc_down() calls napi_synchronize() before napi_disable(), so it spins forever waiting for that bit and the interface never goes down. Drop the napi_synchronize() and let napi_disable() do the job -- it sets NAPI_STATE_DISABLE, which forces the stuck poll to complete. Reorder it ahead of igc_set_queue_napi() so the NAPI mapping is cleared only after polling has stopped, matching the recent igb fix b1e067240379.
--- drivers/net/ethernet/intel/igc/igc_main.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/ethernet/intel/igc/igc_main.c +0 -1
@@ -5085,7 +5085,6 @@ void igc_down(struct igc_adapter *adaptefor (i =0 ; i < adapter->num_q_vectors; i++) {if (adapter->q_vector[i]) { -napi_synchronize (&adapter->q_vector[i]->napi);napi_disable (&adapter->q_vector[i]->napi); } }
Greg Kroah-Hartman
maintainerPATCH 111/166 ksmbd: conn lock to serialize smb2 negotiate
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit fe4ed2f09b492e3507615a053814daa8fafdecb1 ]
If client send parallel smb2 negotiate request on same connection, ksmbd_conn can be racy. smb2 negotiate handling that are not performance-related can be serialized with conn lock.
Stable-dep-of: cb469993b3a6 ("ksmbd: reject repeated SMB2 NEGOTIATE requests")
--- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/smb2pdu.c +2 -0
@@ -1114,6 +1114,7 @@ int smb2_handle_negotiate(struct ksmbd_wreturn rc; } +ksmbd_conn_lock (conn); smb2_buf_len =get_rfc1002_len (work->request_buf); smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects);if (smb2_neg_size > smb2_buf_len) {
@@ -1264,6 +1265,7 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_conn_set_need_setup (conn); err_out: +ksmbd_conn_unlock (conn);if (rc) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;
Greg Kroah-Hartman
maintainerPATCH 112/166 ksmbd: reject repeated SMB2 NEGOTIATE requests
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit cb469993b3a61a72653770856d37af616d72d05f ]
Unauthenticated client can send multiple successful SMB2 NEGOTIATE requests on one connection before SESSION_SETUP. While the connection is in KSMBD_SESS_NEED_SETUP, smb2_handle_negotiate() accepts another SMB3.1.1 NEGOTIATE and overwrites conn->preauth_info with a new allocation. Only the final allocation is freed when the connection is released, leaking one object for every additional successful request.
A repeated SMB2 NEGOTIATE after a dialect has been selected is a protocol violation. MS-SMB2 section 3.3.5.4 requires the server to disconnect without replying in this case. Set the connection exiting when rejecting the request, in addition to suppressing the response.
Reject SMB2 NEGOTIATE unless the connection is new or is waiting for the SMB2 NEGOTIATE that follows an SMB1 multi-protocol negotiate. Serialize both SMB1 and SMB2 negotiation paths under conn->srv_mutex, since they update connection-wide dialect and negotiation state.
Move the locking contract to ksmbd_smb_negotiate_common(), where the state and dialect are selected, and add ksmbd_conn_new() for consistent state access.
--- fs/smb/server/connection.h | 5 +++++ fs/smb/server/smb2pdu.c | 10 ++-------- fs/smb/server/smb_common.c | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 15 deletions(-)
fs/smb/server/connection.h +5 -0
@@ -194,6 +194,11 @@ void ksmbd_conn_r_count_dec(struct ksmbd* This is a hack. We will move status to a proper place once we land * a multi-sessions support. */ +static inline bool ksmbd_conn_new (struct ksmbd_conn *conn) +{ +return READ_ONCE (conn->status) ==KSMBD_SESS_NEW ; +} +static inline bool ksmbd_conn_good (struct ksmbd_conn *conn) {return READ_ONCE (conn->status) ==KSMBD_SESS_GOOD ;
fs/smb/server/smb2pdu.c +2 -8
@@ -1095,6 +1095,8 @@ static __le32 deassemble_neg_contexts(st* smb2_handle_negotiate() - handler for smb2 negotiate command * @work: smb work containing smb request buffer * +* The caller holds conn->srv_mutex. +* * Return: 0 */ int smb2_handle_negotiate (struct ksmbd_work *work)
@@ -1108,13 +1110,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_debug (SMB ,"Received negotiate request\n" ); conn->need_neg = false; -if (ksmbd_conn_good (conn)) { -pr_err ("conn->tcp_status is already in CifsGood State\n" ); - work->send_no_response =1 ; -return rc; - } - -ksmbd_conn_lock (conn); smb2_buf_len =get_rfc1002_len (work->request_buf); smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects);if (smb2_neg_size > smb2_buf_len) {
@@ -1265,7 +1260,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_conn_set_need_setup (conn); err_out: -ksmbd_conn_unlock (conn);if (rc) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;
fs/smb/server/smb_common.c +30 -7
@@ -592,23 +592,46 @@ int ksmbd_smb_negotiate_common(struct ksstruct ksmbd_conn *conn = work->conn;int ret; - conn->dialect = -ksmbd_negotiate_smb_dialect (work->request_buf); -ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); -if (command ==SMB2_NEGOTIATE_HE ) { +/* +* An SMB2 NEGOTIATE is valid for a new connection, or after an +* SMB1 multi-protocol negotiate has selected SMB2. Do not allow +* a second SMB2 NEGOTIATE to replace connection-wide state +* while a session setup is pending. KSMBD_SESS_NEED_RECONNECT +* is a transient session state and does not restart transport +* negotiation. +*/ +ksmbd_conn_lock (conn); +if (!ksmbd_conn_new (conn) && + !ksmbd_conn_need_negotiate (conn)) { + work->send_no_response =1 ; +ksmbd_conn_set_exiting (conn); +ksmbd_conn_unlock (conn); +return 0 ; + } + + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); ret =smb2_handle_negotiate (work); +ksmbd_conn_unlock (conn);return ret; }if (command ==SMB_COM_NEGOTIATE ) { +ksmbd_conn_lock (conn); + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect);if (__smb2_negotiate (conn)) {init_smb3_11_server (conn); -init_smb2_neg_rsp (work); + ret =init_smb2_neg_rsp (work);ksmbd_debug (SMB ,"Upgrade to SMB2 negotiation\n" ); -return 0 ; + }else { + ret =smb_handle_negotiate (work); } -return smb_handle_negotiate (work); +ksmbd_conn_unlock (conn); +return ret; }pr_err ("Unknown SMB negotiation command: %u\n" , command);
Greg Kroah-Hartman
maintainerPATCH 113/166 net: pktgen: fix code style (WARNING: Block comments)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Seiderer <[email protected]>
[ Upstream commit 870b856cb478bc02fffe4d89897e62c692efb09a ]
Fix checkpatch code style warnings:
WARNING: Block comments use a trailing */ on a separate line
+ * removal by worker thread */
WARNING: Block comments use * on subsequent lines
+ __u8 tos; /* six MSB of (former) IPv4 TOS
+ are for dscp codepoint */
WARNING: Block comments use a trailing */ on a separate line
+ are for dscp codepoint */
WARNING: Block comments use * on subsequent lines
+ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6
+ (see RFC 3260, sec. 4) */
WARNING: Block comments use a trailing */ on a separate line
+ (see RFC 3260, sec. 4) */
WARNING: Block comments use * on subsequent lines
+ /* = {
+ 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
WARNING: Block comments use * on subsequent lines
+ /* Field for thread to receive "posted" events terminate,
+ stop ifs etc. */
WARNING: Block comments use a trailing */ on a separate line
+ stop ifs etc. */
WARNING: Block comments should align the * on each line
+ * we go look for it ...
+*/
WARNING: Block comments use a trailing */ on a separate line
+ * we resolve the dst issue */
WARNING: Block comments use a trailing */ on a separate line
+ * with proc_create_data() */
Stable-dep-of: 817ff6efdb7f ("net: pktgen: fix proc entry use-after-free")
--- net/core/pktgen.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-)
net/core/pktgen.c +23 -16
@@ -284,7 +284,8 @@ struct pktgen_dev {int pkt_overhead;/* overhead for MPLS, VLANs, IPSEC etc */ int nfrags;int removal_mark;/* non-zero => the device is marked for -* removal by worker thread */ +* removal by worker thread +*/ struct page *page;u64 delay;/* nano-seconds */
@@ -347,10 +348,12 @@ struct pktgen_dev {__u16 udp_dst_max;/* exclusive, dest UDP port */ /* DSCP + ECN */ -__u8 tos;/* six MSB of (former) IPv4 TOS -are for dscp codepoint */ -__u8 traffic_class;/* ditto for the (former) Traffic Class in IPv6 -(see RFC 3260, sec. 4) */ +__u8 tos;/* six MSB of (former) IPv4 TOS +* are for dscp codepoint +*/ +__u8 traffic_class;/* ditto for the (former) Traffic Class in IPv6 +* (see RFC 3260, sec. 4) +*/ /* IMIX */ unsigned int n_imix_entries;
@@ -390,12 +393,12 @@ struct pktgen_dev {__u8 hh[14 ];/* = { -0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, - -We fill in SRC address later -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x08, 0x00 -}; +* 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, +* +* We fill in SRC address later +* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +* 0x08, 0x00 +* }; */ __u16 pad;/* pad out the hh struct to an even 16 bytes */
@@ -459,7 +462,8 @@ struct pktgen_thread {char result[512 ];/* Field for thread to receive "posted" events terminate, -stop ifs etc. */ +* stop ifs etc. +*/ u32 control;int cpu;
@@ -2343,7 +2347,7 @@ static inline int f_pick(struct pktgen_d#ifdef CONFIG_XFRM /* If there was already an IPSEC SA, we keep it as is, else * we go look for it ... -*/ +*/ #define DUMMY_MARK 0static void get_ipsec_sa (struct pktgen_dev *pkt_dev,int flow) {
@@ -2642,7 +2646,8 @@ static int pktgen_output_ipsec(struct skif (!x)return 0 ;/* XXX: we dont support tunnel mode for now until -* we resolve the dst issue */ +* we resolve the dst issue +*/ if ((x->props.mode !=XFRM_MODE_TRANSPORT ) && (pkt_dev->spi ==0 ))return 0 ;
@@ -3710,7 +3715,8 @@ static int add_dev_to_thread(struct pktg* userspace on another CPU than the kthread. The if_lock() * is used here to sync with concurrent instances of * _rem_dev_from_if_list() invoked via kthread, which is also -* updating the if_list */ +* updating the if_list +*/ if_lock (t);if (pkt_dev->pg_thread) {
@@ -3907,7 +3913,8 @@ static int pktgen_remove_device(struct p/* Remove proc before if_list entry, because add_device uses * list to determine if interface already exist, avoid race -* with proc_create_data() */ +* with proc_create_data() +*/ proc_remove (pkt_dev->entry);/* And update the thread if_list */
Greg Kroah-Hartman
maintainerPATCH 114/166 net: pktgen: fix proc entry use-after-free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit 817ff6efdb7f484ea547218e11e17d8e43daa3b4 ]
pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock. pktgen_remove_device() removes the same entry before _rem_dev_from_if_list() takes that lock.
This allows the following interleaving:
CPU 0 (NETDEV_CHANGENAME) CPU 1 (kpktgend)
if_lock(t)
proc_remove(pkt_dev->entry)
proc_remove(pkt_dev->entry)
pkt_dev->entry = proc_create_data(...)
if_unlock(t)
The kthread can pass the stale proc_dir_entry to proc_remove() after the rename path has freed it. A reproducer with a widened race window reports:
BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80 Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67 Call Trace: proc_remove+0x78/0x80 pktgen_remove_device.isra.0+0x11c/0x4c0 pktgen_thread_worker+0x1214/0x6bc0 kthread+0x2c6/0x3b0 Allocated by task 95: __proc_create+0x204/0x790 proc_create_data+0x72/0xe0 pktgen_thread_write+0xd61/0x1510 Freed by task 28: kmem_cache_free+0xcb/0x3d0 proc_free_inode+0x5b/0x80 rcu_core+0x50a/0x1850 The buggy address belongs to the object at ffff8881478fea00 which belongs to the cache proc_dir_entry of size 192
Move proc_remove() into the if_lock-protected list removal helper. Keep it before list_del_rcu() to preserve the ordering required by add_device(). The rename path must then finish replacing the entry before removal, or it observes that the device is no longer on the list.
--- net/core/pktgen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/core/pktgen.c +1 -3
@@ -3886,6 +3886,7 @@ static void _rem_dev_from_if_list(structstruct pktgen_dev *p;if_lock (t); +proc_remove (pkt_dev->entry);list_for_each_safe (q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list);if (p == pkt_dev)
@@ -3915,9 +3916,6 @@ static int pktgen_remove_device(struct p* list to determine if interface already exist, avoid race * with proc_create_data() */ -proc_remove (pkt_dev->entry); - -/* And update the thread if_list */ _rem_dev_from_if_list (t, pkt_dev);#ifdef CONFIG_XFRM
Greg Kroah-Hartman
maintainerPATCH 115/166 veth: convert frag_list skbs before running XDP
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Fleming <[email protected]>
[ Upstream commit d0d6415963040c401e7a7e4e482a698ba52448cb ]
A frag_list skb can reach veth with data_len set but nr_frags zero. veth_convert_skb_to_xdp_buff() only converts skbs that are shared, locked, have frags[], or do not have enough headroom. It later uses skb_is_nonlinear() to decide whether to set XDP_FLAGS_HAS_FRAGS and xdp_frags_size.
That exposes frag_list data to XDP as if it were stored in frags[], but frags[] is empty. AF_XDP copy mode can then trust the bogus XDP fragment metadata, walk an empty fragment entry, and crash in memcpy() from __xsk_rcv().
Route non-linear skbs through skb_pp_cow_data() before exposing them to XDP, and only advertise XDP frags when the resulting skb has frags[]. skb_copy_bits() already handles frag_list input, and skb_pp_cow_data() builds frags[] output with skb_add_rx_frag(), which is the representation XDP multi-buffer expects.
--- drivers/net/veth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/veth.c +2 -2
@@ -731,7 +731,7 @@ static int veth_convert_skb_to_xdp_buff(u32 frame_sz;if (skb_shared (skb) ||skb_head_is_locked (skb) || -skb_shinfo (skb)->nr_frags || +skb_is_nonlinear (skb) ||skb_headroom (skb) <XDP_PACKET_HEADROOM ) {u32 size, len, max_head_size, off;struct sk_buff *nskb;
@@ -808,7 +808,7 @@ static int veth_convert_skb_to_xdp_buff(xdp_prepare_buff (xdp, skb->head,skb_headroom (skb),skb_headlen (skb), true); -if (skb_is_nonlinear (skb)) { +if (skb_shinfo (skb)->nr_frags) {skb_shinfo (skb)->xdp_frags_size = skb->data_len;xdp_buff_set_frags_flag (xdp); }else {
Greg Kroah-Hartman
maintainerPATCH 116/166 fs: dont block write during exec on pre-content watched files
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 0357ef03c94ef835bd44a0658b8edb672a9dbf51 ]
Commit 2a010c412853 ("fs: don't block i_writecount during exec") removed the legacy behavior of getting ETXTBSY on attempt to open and executable file for write while it is being executed.
This commit was reverted because an application that depends on this legacy behavior was broken by the change.
We need to allow HSM writing into executable files while executed to fill their content on-the-fly.
To that end, disable the ETXTBSY legacy behavior for files that are watched by pre-content events.
This change is not expected to cause regressions with existing systems which do not have any pre-content event listeners.
Stable-dep-of: db1856ea9196 ("binfmt_misc: restore write access when removing an entry")
--- fs/binfmt_elf.c | 4 ++-- fs/binfmt_elf_fdpic.c | 4 ++-- fs/exec.c | 6 +++--- include/linux/fs.h | 12 ++++++++++++ kernel/fork.c | 12 ++++++------ 5 files changed, 25 insertions(+), 13 deletions(-)
fs/binfmt_elf.c +2 -2
@@ -1287,7 +1287,7 @@ out_free_interp: } reloc_func_desc = interp_load_addr; -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter);kfree (interp_elf_ex);
@@ -1396,7 +1396,7 @@ out_free_dentry:kfree (interp_elf_ex);kfree (interp_elf_phdata); out_free_file: -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);if (interpreter)fput (interpreter); out_free_ph:
fs/binfmt_elf_fdpic.c +2 -2
@@ -398,7 +398,7 @@ static int load_elf_fdpic_binary(struct goto error; } -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter); interpreter =NULL ; }
@@ -471,7 +471,7 @@ static int load_elf_fdpic_binary(struct error:if (interpreter) { -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter); }kfree (interpreter_name);
fs/exec.c +3 -3
@@ -935,7 +935,7 @@ static struct file *do_open_execat(int f path_noexec(&file->f_path)) goto exit; - err =deny_write_access (file); + err =exe_file_deny_write_access (file);if (err) goto exit;
@@ -1521,7 +1521,7 @@ static void free_bprm(struct linux_binprabort_creds (bprm->cred); }if (bprm->file) { -allow_write_access (bprm->file); +exe_file_allow_write_access (bprm->file);fput (bprm->file); }if (bprm->executable)
@@ -1824,7 +1824,7 @@ static int exec_binprm(struct linux_binp bprm->file = bprm->interpreter; bprm->interpreter =NULL ; -allow_write_access (exec); +exe_file_allow_write_access (exec);if (unlikely (bprm->have_execfd)) {if (bprm->executable) {fput (exec);
include/linux/fs.h +12 -0
@@ -2824,6 +2824,18 @@ static inline void allow_write_access(stif (file)atomic_inc (&file_inode (file)->i_writecount); } + +static inline int exe_file_deny_write_access (struct file *exe_file) +{ +return deny_write_access (exe_file); +} +static inline void exe_file_allow_write_access (struct file *exe_file) +{ +if (unlikely (!exe_file)) +return ; +allow_write_access (exe_file); +} +static inline bool inode_is_open_for_write (const struct inode *inode) {return atomic_read (&inode->i_writecount) >0 ;
kernel/fork.c +6 -6
@@ -640,8 +640,8 @@ static void dup_mm_exe_file(struct mm_st* We depend on the oldmm having properly denied write access to the * exe_file already. */ -if (exe_file &&deny_write_access (exe_file)) -pr_warn_once ("deny_write_access() failed in %s\n" , __func__); +if (exe_file &&exe_file_deny_write_access (exe_file)) +pr_warn_once ("exe_file_deny_write_access() failed in %s\n" , __func__); }#ifdef CONFIG_MMU
@@ -1431,13 +1431,13 @@ int set_mm_exe_file(struct mm_struct *mm* We expect the caller (i.e., sys_execve) to already denied * write access, so this is unlikely to fail. */ -if (unlikely (deny_write_access (new_exe_file))) +if (unlikely (exe_file_deny_write_access (new_exe_file)))return -EACCES ;get_file (new_exe_file); }rcu_assign_pointer (mm->exe_file, new_exe_file);if (old_exe_file) { -allow_write_access (old_exe_file); +exe_file_allow_write_access (old_exe_file);fput (old_exe_file); }return 0 ;
@@ -1476,7 +1476,7 @@ int replace_mm_exe_file(struct mm_structreturn ret; } - ret =deny_write_access (new_exe_file); + ret =exe_file_deny_write_access (new_exe_file);if (ret)return -EACCES ;get_file (new_exe_file);
@@ -1488,7 +1488,7 @@ int replace_mm_exe_file(struct mm_structmmap_write_unlock (mm);if (old_exe_file) { -allow_write_access (old_exe_file); +exe_file_allow_write_access (old_exe_file);fput (old_exe_file); }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 117/166 binfmt_misc: restore write access when removing an entry
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit db1856ea9196cf6e015d12199a34c0b9313c7bfa ]
Registering an entry with the MISC_FMT_OPEN_FILE flag opens the interpreter via open_exec() which denies write access to it for as long as the entry exists. Removing the entry closes the interpreter file via filp_close() but never restores write access, leaving the inode's i_writecount permanently negative. Opening the interpreter for writing keeps failing with ETXTBSY long after the entry is gone until the inode is evicted from the inode cache.
Commit 90f601b497d7 ("binfmt_misc: restore write access before closing files opened by open_exec()") fixed the same imbalance in the error path of bm_register_write() but the actual removal path has been leaking the write denial since the introduction of the flag.
Restore write access in put_binfmt_handler() before closing the interpreter file.
--- fs/binfmt_misc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/binfmt_misc.c +3 -1
@@ -163,8 +163,10 @@ static Node *get_binfmt_handler(struct lstatic void put_binfmt_handler (Node *e) {if (refcount_dec_and_test (&e->users)) { -if (e->flags &MISC_FMT_OPEN_FILE ) +if (e->flags &MISC_FMT_OPEN_FILE ) { +exe_file_allow_write_access (e->interp_file);filp_close (e->interp_file,NULL ); + }kfree (e); } }
Greg Kroah-Hartman
maintainerPATCH 118/166 ice: fix VF interrupts cleanup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Osuchowski <[email protected]>
[ Upstream commit fb096882095e5a8d6b5159e43793d4a38a0c5b1f ]
When a virtual function sends an IRQ map command, the PF will set up interrupts according to that request. However, because these interrupts are never reset, the next time Virtual Function initializes, the interrupts are still enabled for a given VF, which leads to performance degradation in certain cases due to interrupts being unexpectedly enabled and thus causing interrupt floods.
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 27 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_vf_lib_private.h | 1 drivers/net/ethernet/intel/ice/ice_virtchnl.c | 21 +++++++++++++++ 3 files changed, 49 insertions(+)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +27 -0
@@ -833,6 +833,30 @@ static void ice_notify_vf_reset(struct i }/** +* ice_reset_interrupts - clear all queue interrupt configuration for a VSI +* @vsi: the VSI whose interrupt registers should be cleared +* +* Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues +* in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX, +* CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only +* clears the CAUSE_ENA bit. +*/ +void ice_reset_interrupts (struct ice_vsi *vsi) +{ +struct ice_pf *pf = vsi->back; +struct ice_hw *hw = &pf->hw; +int i; + +ice_for_each_alloc_rxq (vsi, i) +wr32 (hw,QINT_RQCTL (vsi->rxq_map[i]),0 ); + +ice_for_each_alloc_txq (vsi, i) +wr32 (hw,QINT_TQCTL (vsi->txq_map[i]),0 ); + +ice_flush (hw); +} + +/** * ice_reset_vf - Reset a particular VF * @vf: pointer to the VF structure * @flags: flags controlling behavior of the reset
@@ -914,6 +938,9 @@ int ice_reset_vf(struct ice_vf *vf, u32ice_dis_vf_qs (vf); +/* cleanup interrupt registers */ +ice_reset_interrupts (vsi); +/* Call Disable LAN Tx queue AQ whether or not queues are * enabled. This is needed for successful completion of VFR. */
drivers/net/ethernet/intel/ice/ice_vf_lib_private.h +1 -0
@@ -26,6 +26,7 @@void ice_initialize_vf_entry (struct ice_vf *vf);void ice_deinitialize_vf_entry (struct ice_vf *vf);void ice_dis_vf_qs (struct ice_vf *vf); +void ice_reset_interrupts (struct ice_vsi *vsi);int ice_check_vf_init (struct ice_vf *vf);enum virtchnl_status_code ice_err_to_virt_err (int err);struct ice_port_info *ice_vf_get_port_info (struct ice_vf *vf);
drivers/net/ethernet/intel/ice/ice_virtchnl.c +21 -0
@@ -1216,6 +1216,24 @@ static void ice_vf_ena_rxq_interrupt(str }/** +* ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL +* @vsi: VSI of the VF to configure +* @q_idx: VF queue index used to determine the queue in the PF's space +*/ +static void ice_vf_dis_rxq_interrupt (struct ice_vsi *vsi,u32 q_idx) +{ +struct ice_hw *hw = &vsi->back->hw; +u32 pfq = vsi->rxq_map[q_idx]; +u32 reg; + + reg =rd32 (hw,QINT_RQCTL (pfq)); + reg &= ~QINT_RQCTL_CAUSE_ENA_M ; +wr32 (hw,QINT_RQCTL (pfq), reg); + +ice_flush (hw); +} + +/** * ice_vc_ena_qs_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer
@@ -1408,6 +1426,8 @@ static int ice_vc_dis_qs_msg(struct ice_ goto error_param; } +for_each_set_bit (vf_q_id, &q_map,ICE_MAX_RSS_QS_PER_VF ) +ice_vf_dis_rxq_interrupt (vsi, vf_q_id);bitmap_zero (vf->rxq_ena,ICE_MAX_RSS_QS_PER_VF ); }else if (q_map) {for_each_set_bit (vf_q_id, &q_map,ICE_MAX_RSS_QS_PER_VF ) {
@@ -1428,6 +1448,7 @@ static int ice_vc_dis_qs_msg(struct ice_ goto error_param; } +ice_vf_dis_rxq_interrupt (vsi, vf_q_id);/* Clear enabled queues flag */ clear_bit (vf_q_id, vf->rxq_ena); }
Greg Kroah-Hartman
maintainerPATCH 119/166 vxlan: Do not alloc tstats manually
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit e28c5efc31397af17bc5a7d55b963f59bcde0166 ]
With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of in this driver.
With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now.
Remove the allocation in the vxlan driver and leverage the network core allocation instead.
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vxlan/vxlan_core.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
drivers/net/vxlan/vxlan_core.c +2 -11
@@ -2990,15 +2990,9 @@ static int vxlan_init(struct net_devicereturn err; } - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); -if (!dev->tstats) { - err = -ENOMEM ; - goto err_vnigroup_uninit; - } - err =gro_cells_init (&vxlan->gro_cells, dev);if (err) - goto err_free_percpu; + goto err_vnigroup_uninit; err =vxlan_mdb_init (vxlan);if (err)
@@ -3009,8 +3003,6 @@ static int vxlan_init(struct net_device err_gro_cells_destroy:gro_cells_destroy (&vxlan->gro_cells); -err_free_percpu: -free_percpu (dev->tstats); err_vnigroup_uninit:if (vxlan->cfg.flags &VXLAN_F_VNIFILTER )vxlan_vnigroup_uninit (vxlan);
@@ -3041,8 +3033,6 @@ static void vxlan_uninit(struct net_devigro_cells_destroy (&vxlan->gro_cells);vxlan_fdb_delete_default (vxlan, vxlan->cfg.vni); - -free_percpu (dev->tstats); }/* Start ageing timer and join group when device is brought up */
@@ -3269,6 +3259,7 @@ static void vxlan_setup(struct net_devic dev->min_mtu =ETH_MIN_MTU ; dev->max_mtu =ETH_MAX_MTU ; + dev->pcpu_stat_type =NETDEV_PCPU_STAT_TSTATS ;INIT_LIST_HEAD (&vxlan->next);timer_setup (&vxlan->age_timer, vxlan_cleanup,TIMER_DEFERRABLE );
Greg Kroah-Hartman
maintainerPATCH 120/166 net: core,vrf: Change pcpu_dstat fields to u64_stats_t
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeremy Kerr <[email protected]>
[ Upstream commit fa59dc2f6fc616fde3941f62ccd4adcaa21ccd47 ]
The pcpu_sw_netstats and pcpu_lstats structs both contain a set of u64_stats_t fields for individual stats, but pcpu_dstats uses u64s instead.
Make this consistent by using u64_stats_t across all stats types.
The per-cpu dstats are only used by the vrf driver at present, so update that driver as part of this change.
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vrf.c | 38 ++++++++++++++++++++++---------------- include/linux/netdevice.h | 12 ++++++------ 2 files changed, 28 insertions(+), 22 deletions(-)
drivers/net/vrf.c +22 -16
@@ -126,8 +126,8 @@ static void vrf_rx_stats(struct net_devistruct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats);u64_stats_update_begin (&dstats->syncp); - dstats->rx_packets++; - dstats->rx_bytes += len; +u64_stats_inc (&dstats->rx_packets); +u64_stats_add (&dstats->rx_bytes, len);u64_stats_update_end (&dstats->syncp); }
@@ -150,11 +150,11 @@ static void vrf_get_stats64(struct net_d dstats =per_cpu_ptr (dev->dstats, i);do { start =u64_stats_fetch_begin (&dstats->syncp); - tbytes = dstats->tx_bytes; - tpkts = dstats->tx_packets; - tdrops = dstats->tx_drops; - rbytes = dstats->rx_bytes; - rpkts = dstats->rx_packets; + tbytes =u64_stats_read (&dstats->tx_bytes); + tpkts =u64_stats_read (&dstats->tx_packets); + tdrops =u64_stats_read (&dstats->tx_drops); + rbytes =u64_stats_read (&dstats->rx_bytes); + rpkts =u64_stats_read (&dstats->rx_packets); }while (u64_stats_fetch_retry (&dstats->syncp, start)); stats->tx_bytes += tbytes; stats->tx_packets += tpkts;
@@ -408,10 +408,15 @@ static int vrf_local_xmit(struct sk_buff skb->protocol =eth_type_trans (skb, dev); -if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) +if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) {vrf_rx_stats (dev, len); -else -this_cpu_inc (dev->dstats->rx_drops); + }else { +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->rx_drops); +u64_stats_update_end (&dstats->syncp); + }return NETDEV_TX_OK ; }
@@ -599,19 +604,20 @@ static netdev_tx_t is_ip_tx_frame(structstatic netdev_tx_t vrf_xmit (struct sk_buff *skb,struct net_device *dev) { +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); +int len = skb->len;netdev_tx_t ret =is_ip_tx_frame (skb, dev); +u64_stats_update_begin (&dstats->syncp);if (likely (ret ==NET_XMIT_SUCCESS || ret ==NET_XMIT_CN )) { -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); -u64_stats_update_begin (&dstats->syncp); - dstats->tx_packets++; - dstats->tx_bytes += len; -u64_stats_update_end (&dstats->syncp); +u64_stats_inc (&dstats->tx_packets); +u64_stats_add (&dstats->tx_bytes, len); }else { -this_cpu_inc (dev->dstats->tx_drops); +u64_stats_inc (&dstats->tx_drops); } +u64_stats_update_end (&dstats->syncp);return ret; }
include/linux/netdevice.h +6 -6
@@ -2748,12 +2748,12 @@ struct pcpu_sw_netstats { }__aligned(4 * sizeof(u64)) ;struct pcpu_dstats { -u64 rx_packets; -u64 rx_bytes; -u64 rx_drops; -u64 tx_packets; -u64 tx_bytes; -u64 tx_drops; +u64_stats_t rx_packets; +u64_stats_t rx_bytes; +u64_stats_t rx_drops; +u64_stats_t tx_packets; +u64_stats_t tx_bytes; +u64_stats_t tx_drops;struct u64_stats_sync syncp; }__aligned(8 * sizeof(u64)) ;
Greg Kroah-Hartman
maintainerPATCH 121/166 vrf: Make pcpu_dstats update functions available to other modules.
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Nault <[email protected]>
[ Upstream commit 18eabadd73ae60023ab05e376246bd725fb0c113 ]
Currently vrf is the only module that uses NETDEV_PCPU_STAT_DSTATS. In order to make this kind of statistics available to other modules, we need to define the update functions in netdevice.h.
Therefore, let's define dev_dstats_*() functions for RX and TX packet updates (packets, bytes and drops). Use these new functions in vrf.c instead of vrf_rx_stats() and the other manual counter updates.
While there, update the type of the "len" variables to "unsigned int", so that there're aligned with both skb->len and the new dstats update functions.
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vrf.c | 49 +++++++++++++--------------------------------- include/linux/netdevice.h | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 35 deletions(-)
drivers/net/vrf.c +14 -35
@@ -121,16 +121,6 @@ struct net_vrf {int ifindex; }; -static void vrf_rx_stats (struct net_device *dev,int len) -{ -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -u64_stats_update_begin (&dstats->syncp); -u64_stats_inc (&dstats->rx_packets); -u64_stats_add (&dstats->rx_bytes, len); -u64_stats_update_end (&dstats->syncp); -} -static void vrf_tx_error (struct net_device *vrf_dev,struct sk_buff *skb) { vrf_dev->stats.tx_errors++;
@@ -395,7 +385,7 @@ static bool qdisc_tx_is_default(const ststatic int vrf_local_xmit (struct sk_buff *skb,struct net_device *dev,struct dst_entry *dst) { -int len = skb->len; +unsigned int len = skb->len;skb_orphan (skb);
@@ -408,15 +398,10 @@ static int vrf_local_xmit(struct sk_buff skb->protocol =eth_type_trans (skb, dev); -if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) { -vrf_rx_stats (dev, len); - }else { -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -u64_stats_update_begin (&dstats->syncp); -u64_stats_inc (&dstats->rx_drops); -u64_stats_update_end (&dstats->syncp); - } +if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) +dev_dstats_rx_add (dev, len); +else +dev_dstats_rx_dropped (dev);return NETDEV_TX_OK ; }
@@ -604,20 +589,14 @@ static netdev_tx_t is_ip_tx_frame(structstatic netdev_tx_t vrf_xmit (struct sk_buff *skb,struct net_device *dev) { -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -int len = skb->len; -netdev_tx_t ret =is_ip_tx_frame (skb, dev); - -u64_stats_update_begin (&dstats->syncp); -if (likely (ret ==NET_XMIT_SUCCESS || ret ==NET_XMIT_CN )) { +unsigned int len = skb->len; +netdev_tx_t ret; -u64_stats_inc (&dstats->tx_packets); -u64_stats_add (&dstats->tx_bytes, len); - }else { -u64_stats_inc (&dstats->tx_drops); - } -u64_stats_update_end (&dstats->syncp); + ret =is_ip_tx_frame (skb, dev); +if (likely (ret ==NET_XMIT_SUCCESS || ret ==NET_XMIT_CN )) +dev_dstats_tx_add (dev, len); +else +dev_dstats_tx_dropped (dev);return ret; }
@@ -1400,7 +1379,7 @@ static struct sk_buff *vrf_ip6_rcv(strucif (!is_ndisc) {struct net_device *orig_dev = skb->dev; -vrf_rx_stats (vrf_dev, skb->len); +dev_dstats_rx_add (vrf_dev, skb->len); skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex;
@@ -1456,7 +1435,7 @@ static struct sk_buff *vrf_ip_rcv(struct goto out; } -vrf_rx_stats (vrf_dev, skb->len); +dev_dstats_rx_add (vrf_dev, skb->len);if (!list_empty (&vrf_dev->ptype_all)) {int err;
include/linux/netdevice.h +40 -0
@@ -2797,6 +2797,46 @@ static inline void dev_lstats_add(structu64_stats_update_end (&lstats->syncp); } +static inline void dev_dstats_rx_add (struct net_device *dev, +unsigned int len) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->rx_packets); +u64_stats_add (&dstats->rx_bytes, len); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_rx_dropped (struct net_device *dev) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->rx_drops); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_tx_add (struct net_device *dev, +unsigned int len) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->tx_packets); +u64_stats_add (&dstats->tx_bytes, len); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_tx_dropped (struct net_device *dev) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->tx_drops); +u64_stats_update_end (&dstats->syncp); +} +#define __netdev_alloc_pcpu_stats (type, gfp) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\
Greg Kroah-Hartman
maintainerPATCH 122/166 vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Nault <[email protected]>
[ Upstream commit be226352e8dc77d3313c096b2d8e7f69bf6980fc ]
VXLAN uses the TSTATS infrastructure (dev_sw_netstats_*()) for RX and TX packet counters. It also uses the device core stats (dev_core_stats_*()) for RX and TX drops.
Let's consolidate that using the DSTATS infrastructure, which can handle both packet counters and packet drops. Statistics that don't fit DSTATS are still updated atomically with DEV_STATS_INC().
While there, convert the "len" variable of vxlan_encap_bypass() to unsigned int, to respect the types of skb->len and dev_dstats_[rt]x_add().
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vxlan/vxlan_core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/net/vxlan/vxlan_core.c +14 -14
@@ -1798,13 +1798,13 @@ static int vxlan_rcv(struct sock *sk, stif (unlikely (!(vxlan->dev->flags &IFF_UP ))) {rcu_read_unlock (); -dev_core_stats_rx_dropped_inc (vxlan->dev); +dev_dstats_rx_dropped (vxlan->dev);vxlan_vnifilter_count (vxlan, vni, vninode,VXLAN_VNI_STATS_RX_DROPS ,0 ); goto drop; } -dev_sw_netstats_rx_add (vxlan->dev, skb->len); +dev_dstats_rx_add (vxlan->dev, skb->len);vxlan_vnifilter_count (vxlan, vni, vninode,VXLAN_VNI_STATS_RX , skb->len);gro_cells_receive (&vxlan->gro_cells, skb);
@@ -1858,7 +1858,7 @@ static int arp_reduce(struct net_device goto out;if (!pskb_may_pull (skb,arp_hdr_len (dev))) { -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 ); goto out;
@@ -1916,7 +1916,7 @@ static int arp_reduce(struct net_device reply->pkt_type =PACKET_HOST ;if (netif_rx (reply) ==NET_RX_DROP ) { -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2077,7 +2077,7 @@ static int neigh_reduce(struct net_devic goto out;if (netif_rx (reply) ==NET_RX_DROP ) { -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2370,8 +2370,8 @@ static void vxlan_encap_bypass(struct sk {union vxlan_addr loopback;union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip; +unsigned int len = skb->len;struct net_device *dev; -int len = skb->len; skb->pkt_type =PACKET_HOST ; skb->encapsulation =0 ;
@@ -2398,16 +2398,16 @@ static void vxlan_encap_bypass(struct skif ((dst_vxlan->cfg.flags &VXLAN_F_LEARN ) && snoop)vxlan_snoop (dev, &loopback,eth_hdr (skb)->h_source,0 , vni); -dev_sw_netstats_tx_add (src_vxlan->dev,1 , len); +dev_dstats_tx_add (src_vxlan->dev, len);vxlan_vnifilter_count (src_vxlan, vni,NULL ,VXLAN_VNI_STATS_TX , len);if (__netif_rx (skb) ==NET_RX_SUCCESS ) { -dev_sw_netstats_rx_add (dst_vxlan->dev, len); +dev_dstats_rx_add (dst_vxlan->dev, len);vxlan_vnifilter_count (dst_vxlan, vni,NULL ,VXLAN_VNI_STATS_RX , len); }else { drop: -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (dst_vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2700,7 +2700,7 @@ out_unlock:return ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);return ;
@@ -2745,7 +2745,7 @@ static void vxlan_xmit_nh(struct sk_buffreturn ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (netdev_priv (dev), vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);
@@ -2783,7 +2783,7 @@ static netdev_tx_t vxlan_xmit_nhid(strucreturn NETDEV_TX_OK ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (netdev_priv (dev), vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);
@@ -2881,7 +2881,7 @@ static netdev_tx_t vxlan_xmit(struct sk_ !is_multicast_ether_addr(eth->h_dest))vxlan_fdb_miss (vxlan, eth->h_dest); -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );kfree_skb (skb);
@@ -3259,7 +3259,7 @@ static void vxlan_setup(struct net_devic dev->min_mtu =ETH_MIN_MTU ; dev->max_mtu =ETH_MAX_MTU ; - dev->pcpu_stat_type =NETDEV_PCPU_STAT_TSTATS ; + dev->pcpu_stat_type =NETDEV_PCPU_STAT_DSTATS ;INIT_LIST_HEAD (&vxlan->next);timer_setup (&vxlan->age_timer, vxlan_cleanup,TIMER_DEFERRABLE );
Greg Kroah-Hartman
maintainerPATCH 123/166 vxlan: use pskb_network_may_pull() for transmit path header pulls
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit b9553558b48db54ac9273e6b98d7263ef5c1a329 ]
In vxlan_xmit(), arp_reduce(), and vxlan_mdb_entry_skb_get(), pskb_may_pull() was being called to verify the availability of network layer headers (ARP, IPv6/ND, IP/IPv6 MDB keys).
However, during transmit skb->data points to the MAC header, so skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, len) only checks len bytes from skb->data rather than skb_network_offset(skb) + len, which can leave part of the network header in non-linear frags.
Replace these remaining pskb_may_pull() calls with pskb_network_may_pull() to properly account for the MAC header offset.
--- drivers/net/vxlan/vxlan_core.c | 6 +++--- drivers/net/vxlan/vxlan_mdb.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/vxlan/vxlan_core.c +3 -3
@@ -1857,7 +1857,7 @@ static int arp_reduce(struct net_deviceif (dev->flags &IFF_NOARP ) goto out; -if (!pskb_may_pull (skb,arp_hdr_len (dev))) { +if (!pskb_network_may_pull (skb,arp_hdr_len (dev))) {dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );
@@ -2831,8 +2831,8 @@ static netdev_tx_t vxlan_xmit(struct sk_return arp_reduce (dev, skb, vni); #if IS_ENABLED(CONFIG_IPV6) else if (ntohs(eth->h_proto) == ETH_P_IPV6 && - pskb_may_pull(skb, sizeof(struct ipv6hdr) + - sizeof(struct nd_msg)) && + pskb_network_may_pull(skb, sizeof(struct ipv6hdr) + + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {struct nd_msg *m = (struct nd_msg *)(ipv6_hdr (skb) +1 );
drivers/net/vxlan/vxlan_mdb.c +2 -2
@@ -1326,7 +1326,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_switch (skb->protocol) {case htons (ETH_P_IP ): -if (!pskb_may_pull (skb,sizeof (struct iphdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct iphdr )))return NULL ; group.dst.sa.sa_family =AF_INET ; group.dst.sin.sin_addr.s_addr =ip_hdr (skb)->daddr;
@@ -1335,7 +1335,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_break ;#if IS_ENABLED (CONFIG_IPV6 )case htons (ETH_P_IPV6 ): -if (!pskb_may_pull (skb,sizeof (struct ipv6hdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct ipv6hdr )))return NULL ; group.dst.sa.sa_family =AF_INET6 ; group.dst.sin6.sin6_addr =ipv6_hdr (skb)->daddr;
Greg Kroah-Hartman
maintainerPATCH 124/166 i2c: bcm-iproc: remove printout on handled timeouts
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit 796e2c260187e32530cf343546ba1cdf2e2f5491 ]
I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout.
Stable-dep-of: 98f2e9e6d6f9 ("i2c: iproc: reset bus after timeout if START_BUSY is stuck")
--- drivers/i2c/busses/i2c-bcm-iproc.c | 2 -- 1 file changed, 2 deletions(-)
drivers/i2c/busses/i2c-bcm-iproc.c +0 -2
@@ -811,8 +811,6 @@ static int bcm_iproc_i2c_xfer_wait(struc }if (!time_left && !iproc_i2c->xfer_is_done) { -dev_err (iproc_i2c->device,"transaction timed out\n" ); -/* flush both TX/RX FIFOs */ val =BIT (M_FIFO_RX_FLUSH_SHIFT ) |BIT (M_FIFO_TX_FLUSH_SHIFT );iproc_i2c_wr_reg (iproc_i2c,M_FIFO_CTRL_OFFSET , val);
Greg Kroah-Hartman
maintainerPATCH 125/166 i2c: iproc: reset bus after timeout if START_BUSY is stuck
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonas Gorski <[email protected]>
[ Upstream commit 98f2e9e6d6f91a6abb43f166b244b428ba85fa2b ]
If a transaction times out, the START_BUSY signal can stay up, and subsequent transactaction attempts will fail as the bus is still considered busy.
I can easily trigger this by attempting to read from an address with no device, e.g. when running i2cdetect. After the first read times out, all subsequent read attempts return busy.
To get to a working state again, the controller needs to be reset to clear the START_BUSY signal. So check for START_BUSY still asserted on a timeout, and do reset in case it is,
This is also done by the original non-upstream iproc-smbus driver implementation [1].
Works around situations like:
bcm-iproc-2c 1803b000.i2c: transaction timed out
bcm-iproc-2c 1803b000.i2c: bus is busy
bcm-iproc-2c 1803b000.i2c: bus is busy
bcm-iproc-2c 1803b000.i2c: bus is busy
bcm-iproc-2c 1803b000.i2c: bus is busy
bcm-iproc-2c 1803b000.i2c: bus is busy
...where the bus never recovers after a timeout.
--- drivers/i2c/busses/i2c-bcm-iproc.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/i2c/busses/i2c-bcm-iproc.c +11 -0
@@ -811,6 +811,17 @@ static int bcm_iproc_i2c_xfer_wait(struc }if (!time_left && !iproc_i2c->xfer_is_done) { +/* +* The controller may fail to clear START_BUSY after a timeout, +* reset the controller to recover in that case. +*/ +if (!!(iproc_i2c_rd_reg (iproc_i2c,M_CMD_OFFSET ) & +BIT (M_CMD_START_BUSY_SHIFT ))) { +bcm_iproc_i2c_enable_disable (iproc_i2c, false); +bcm_iproc_i2c_init (iproc_i2c); +bcm_iproc_i2c_enable_disable (iproc_i2c, true); + } +/* flush both TX/RX FIFOs */ val =BIT (M_FIFO_RX_FLUSH_SHIFT ) |BIT (M_FIFO_TX_FLUSH_SHIFT );iproc_i2c_wr_reg (iproc_i2c,M_FIFO_CTRL_OFFSET , val);
Greg Kroah-Hartman
maintainerPATCH 126/166 can: rcar_canfd: change the initializing flow for clocks and resets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tu Nguyen <[email protected]>
[ Upstream commit bef9004c5b91debfceaea2841855a4ebe81ff2b3 ]
Testing CANFD on RZ/G3E shows that many registers do not reset to their initial values with the current flow of deasserting resets first and then enabling clocks.
Based on the HW manual, clocks should be supplied first and the resets deasserted afterward.
section 7.4.3 Procedure for Activating Modules: RZ/G2L section 4.4.9.3 Procedure for Starting up Units: RZ/G3E
So, update the order of the initializing flow for resets and clocks to match the hardware manual, resetting all CANFD registers to their initial values. Also update rcar_canfd_global_deinit() to assert resets before disabling clocks, so the teardown path mirrors the new init ordering.
--- drivers/net/can/rcar/rcar_canfd.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/net/can/rcar/rcar_canfd.c +14 -14
@@ -1999,27 +1999,27 @@ static int rcar_canfd_probe(struct platf } } - err =reset_control_reset (gpriv->rstc1); -if (err) - goto fail_dev; - err =reset_control_reset (gpriv->rstc2); -if (err) { -reset_control_assert (gpriv->rstc1); - goto fail_dev; - } -/* Enable peripheral clock for register access */ err =clk_prepare_enable (gpriv->clkp);if (err) {dev_err (dev,"failed to enable peripheral clock: %pe\n" ,ERR_PTR (err)); - goto fail_reset; + goto fail_dev; + } + + err =reset_control_reset (gpriv->rstc1); +if (err) + goto fail_clk; + err =reset_control_reset (gpriv->rstc2); +if (err) { +reset_control_assert (gpriv->rstc1); + goto fail_clk; } err =rcar_canfd_reset_controller (gpriv);if (err) {dev_err (dev,"reset controller failed: %pe\n" ,ERR_PTR (err)); - goto fail_clk; + goto fail_reset; }/* Controller in Global reset & Channel reset mode */
@@ -2070,11 +2070,11 @@ fail_channel:rcar_canfd_channel_remove (gpriv, ch); fail_mode:rcar_canfd_disable_global_interrupts (gpriv); -fail_clk: -clk_disable_unprepare (gpriv->clkp); fail_reset:reset_control_assert (gpriv->rstc1);reset_control_assert (gpriv->rstc2); +fail_clk: +clk_disable_unprepare (gpriv->clkp); fail_dev:return err; }
@@ -2094,9 +2094,9 @@ static void rcar_canfd_remove(struct pla/* Enter global sleep mode */ rcar_canfd_set_bit (gpriv->base,RCANFD_GCTR ,RCANFD_GCTR_GSLPR ); -clk_disable_unprepare (gpriv->clkp);reset_control_assert (gpriv->rstc1);reset_control_assert (gpriv->rstc2); +clk_disable_unprepare (gpriv->clkp); }static int __maybe_unused rcar_canfd_suspend (struct device *dev)
Greg Kroah-Hartman
maintainerPATCH 127/166 drm/amd/pm: fix torn gpu metrics reads
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit 048f4541b71fb19645fb79d6e62e6e4da23a4035 ]
amdgpu_dpm_get_gpu_metrics() returns a pointer to the shared metrics cache after dropping adev->pm.mutex. The sysfs path then copies from that pointer. Another reader can refresh the cache in place during the copy and return a snapshot containing data from two generations.
Pass caller-provided storage through the DPM interface and copy the metrics while the mutex is held. This keeps the cache pointer private and makes each sysfs read observe one complete sample.
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 12 +++++++++--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 8 +------- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +9 -3
@@ -1255,17 +1255,23 @@ int amdgpu_dpm_set_power_profile_mode(streturn ret; } -int amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void **table) +ssize_t amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void *buf, +size_t size) {const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; -int ret =0 ; +void *table; +ssize_t ret;if (!pp_funcs->get_gpu_metrics)return 0 ;mutex_lock (&adev->pm.mutex); ret = pp_funcs->get_gpu_metrics (adev->powerplay.pp_handle, - table); + &table); +if (ret >0 ) { + ret =min_t (ssize_t, ret, size); +memcpy (buf, table, ret); + }mutex_unlock (&adev->pm.mutex);return ret;
drivers/gpu/drm/amd/pm/amdgpu_pm.c +1 -7
@@ -1781,7 +1781,6 @@ static ssize_t amdgpu_get_gpu_metrics(st {struct drm_device *ddev =dev_get_drvdata (dev);struct amdgpu_device *adev =drm_to_adev (ddev); -void *gpu_metrics;ssize_t size =0 ;int ret;
@@ -1796,15 +1795,10 @@ static ssize_t amdgpu_get_gpu_metrics(streturn ret; } - size =amdgpu_dpm_get_gpu_metrics (adev, &gpu_metrics); + size =amdgpu_dpm_get_gpu_metrics (adev, buf,PAGE_SIZE -1 );if (size <=0 ) goto out; -if (size >=PAGE_SIZE ) - size =PAGE_SIZE -1 ; - -memcpy (buf, gpu_metrics, size); - out:pm_runtime_mark_last_busy (ddev->dev);pm_runtime_put_autosuspend (ddev->dev);
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +2 -1
@@ -493,7 +493,8 @@ int amdgpu_dpm_get_power_profile_mode(st char *buf);int amdgpu_dpm_set_power_profile_mode (struct amdgpu_device *adev,long *input,uint32_t size); -int amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void **table); +ssize_t amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void *buf, +size_t size);int amdgpu_dpm_get_fan_control_mode (struct amdgpu_device *adev,uint32_t *fan_mode); int amdgpu_dpm_set_fan_speed_pwm(struct amdgpu_device *adev,
Greg Kroah-Hartman
maintainerPATCH 128/166 drm/amd/pm: fix pptable use-after-free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit bb493058c35c8676e48269ab6732688ea733d23c ]
amdgpu_dpm_get_pp_table() returns a pointer to a driver-owned power table after dropping adev->pm.mutex. The sysfs path then copies from that pointer. A concurrent pp_table write can replace and free the allocation during the copy, causing a use-after-free.
Change the DPM interface to copy into caller-provided storage while the mutex is held. Keep the size-only query for attribute discovery without exposing the driver-owned pointer.
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 15 +++++++++++++-- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 8 +------- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +13 -2
@@ -996,17 +996,28 @@ int amdgpu_dpm_dispatch_task(struct amdgreturn ret; } -int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char **table) +int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char *table, +size_t size) {const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; +char *pptable =NULL ;int ret =0 ; +if ((!table && size) || (table && !size)) +return -EINVAL ; +if (!pp_funcs->get_pp_table)return 0 ;mutex_lock (&adev->pm.mutex); ret = pp_funcs->get_pp_table (adev->powerplay.pp_handle, - table); + &pptable); +if (ret >0 && !pptable) { + ret = -EINVAL ; + }else if (ret >0 && table) { + ret =min_t (size_t, ret, size); +memcpy (table, pptable, ret); + }mutex_unlock (&adev->pm.mutex);return ret;
drivers/gpu/drm/amd/pm/amdgpu_pm.c +1 -7
@@ -496,7 +496,6 @@ static ssize_t amdgpu_get_pp_table(struc {struct drm_device *ddev =dev_get_drvdata (dev);struct amdgpu_device *adev =drm_to_adev (ddev); -char *table =NULL ;int size, ret;if (amdgpu_in_reset (adev))
@@ -510,7 +509,7 @@ static ssize_t amdgpu_get_pp_table(strucreturn ret; } - size =amdgpu_dpm_get_pp_table (adev, &table); + size =amdgpu_dpm_get_pp_table (adev, buf,PAGE_SIZE -1 );pm_runtime_mark_last_busy (ddev->dev);pm_runtime_put_autosuspend (ddev->dev);
@@ -518,11 +517,6 @@ static ssize_t amdgpu_get_pp_table(strucif (size <=0 )return size; -if (size >=PAGE_SIZE ) - size =PAGE_SIZE -1 ; - -memcpy (buf, table, size); -return size; }
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +2 -1
@@ -463,7 +463,8 @@ int amdgpu_dpm_get_pp_num_states(structint amdgpu_dpm_dispatch_task (struct amdgpu_device *adev,enum amd_pp_task task_id,enum amd_pm_state_type *user_state); -int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char **table); +int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char *table, +size_t size); int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev, uint32_t type, long *input,
Greg Kroah-Hartman
maintainerPATCH 129/166 drm/amdgpu: move debug_vm handling to amdgpu_cs_parser_fini
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pierre-Eric Pelloux-Prayer <[email protected]>
[ Upstream commit d8726ef11512754a68c0ab53c57634a569b8feff ]
The commit referenced below restarts the CS if the validation is still in progress. When debug_vm is enabled, all BOs from the CS are invalidated so we will hit an infinite loop.
To avoid that, defer BO invalidation to amdgpu_cs_parser_fini.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +16 -14
@@ -1182,19 +1182,6 @@ static int amdgpu_cs_vm_handling(struct job->vm_pd_addr =amdgpu_gmc_pd_addr (vm->root.bo); } -if (amdgpu_vm_debug) { -/* Invalidate all BOs to test for userspace bugs */ -amdgpu_bo_list_for_each_entry (e, p->bo_list) { -struct amdgpu_bo *bo = e->bo; - -/* ignore duplicates */ -if (!bo) -continue ; - -amdgpu_vm_bo_invalidate (adev, bo, false); - } - } -return 0 ; }
@@ -1383,6 +1370,8 @@ static int amdgpu_cs_submit(struct amdgp/* Cleanup the parser structure */ static void amdgpu_cs_parser_fini (struct amdgpu_cs_parser *parser) { +struct amdgpu_device *adev = parser->adev; +struct amdgpu_bo_list_entry *e;unsigned int i;amdgpu_sync_free (&parser->sync);
@@ -1398,8 +1387,21 @@ static void amdgpu_cs_parser_fini(structif (parser->ctx)amdgpu_ctx_put (parser->ctx); -if (parser->bo_list) +if (parser->bo_list) { +if (amdgpu_vm_debug) { +/* Invalidate all BOs to test for userspace bugs */ +amdgpu_bo_list_for_each_entry (e, parser->bo_list) { +struct amdgpu_bo *bo = e->bo; + +/* ignore duplicates */ +if (!bo) +continue ; + +amdgpu_vm_bo_invalidate (adev, bo, false); + } + }amdgpu_bo_list_put (parser->bo_list); + }for (i =0 ; i < parser->nchunks; i++)kvfree (parser->chunks[i].kdata);