Compare commits

...

590 Commits

Author SHA1 Message Date
Linus Torvalds
a91337fb5e configfs: Fixes for v7.4-rc2
- Fix the build of the configfs selftest on 32-bit architectures,
   broken since the test was added in the v7.4 merge window. The
   harness casts the ASSERT_NE() operands to intmax_t, so handing it
   the pointer returned by mkdtemp() triggers gcc's pointer-to-int-cast
   warning on 32-bit, and the test builds with -Werror. KernelCI's
   32-bit arm kselftest builds hit this.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEErIU5puj0ZwLKSkObNaOTn/x4d20FAmrt/jgACgkQNaOTn/x4
 d21yQw//cPeD23ovXeLJQph2ajMY+TN8AOUROEUUy5W+QHTFmlb4tcq6/yxQ9yc5
 UdvS5apZHoXzpAwlC1jko5OusE6iq9M2appewJsW/YF2Dl6to2rD16hFQguW6ove
 ftUb0k/xCl+HJ6Ac1qbGl2EUwHzCi5kp/swObI4hmZK3aN6bSYJtl2tfa11O56El
 c+bUW/06+uiv5TfkpH0MLTZuJsqfuPqx++P7VpRfSgXp3pZkI8V92Te0IAv17rQT
 PElqBKOJLLXxn8EN6XX/WrUXqg+yTVt6kkx4EivD8bqwzQBT6npvpvaE8Tjjh8EG
 Jn/MnuJgoo8lFHLf7P6+kK48Aa+cfvPU9sPdvdvAmlJHTmNJsqO4NCeIddmgAXP1
 kVWlu+usM6ef+ZMH0imZi8iA589NuIaM5HfhWtHZ8K0M6PfRwXKf/f7p4HhytW1F
 gZEhkOIvFvNIDB24Log5Ge+EFeyX6K6GLLe231lSj8BBqh4Jdti6l6vgFP7dyANP
 j/z1kS80qXudRC1P75WAB9nARLsO6e+YbeWPTdzqZf0h1nPwEpCrApGoZqSwSCmK
 +HavPFHD6B5Et/DHy2HKsdh1dDUXj6mzTfSfLPflo5ptPfxvI6GXID70REft8Zd1
 9dfoX7yEbsrkyYuFbPwCtTRRJE69FGgHqVZ6JQX3YxTFt+Tl+j0=
 =nOJZ
 -----END PGP SIGNATURE-----

Merge tag 'configfs-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/leitao/linux

Pull configfs fix from Breno Leitao:

 - Fix the build of the configfs selftest on 32-bit architectures,
   broken since the test was added in the v7.4 merge window.

   The harness casts the ASSERT_NE() operands to intmax_t, so handing it
   the pointer returned by mkdtemp() triggers gcc's pointer-to-int-cast
   warning on 32-bit, and the test builds with -Werror.

   KernelCI's 32-bit arm kselftest builds hit this.

* tag 'configfs-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/leitao/linux:
  selftests/configfs: fix the build on 32-bit architectures
2026-11-06 09:38:11 -08:00
Linus Torvalds
b556f1c4dc \n
-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmrt7bwACgkQnJ2qBz9k
 QNlW2AgA7AZxlZRg+7irymdWH89Oncn0axt9jMH0eL2SArC004f5g+Sgw38824VK
 iNiAlzng/oXvquUfS58HHLLr2TByKJe7S8Jeyz8lohZISRyY/uHfChm1NgDbezvZ
 tYZ4djrM7hc9S1XVbDDaT4yhewvW/KNGsNXdLvpkD4XMjCT1ij9LtELH7H27Ngop
 XGVkAfjlTlSKvg5b+VTRFjgjbjbLLZMo2RafcVXCWhrkYXTtZHmU5h1kPI+2ENYb
 Azew+HkqGINDRsbxsE9BbCEhiFexCOALrIcWMd9OGIeK9xgLe84exCKVknCwkDGO
 nXNf90PbVtg/IxK486cXndCf6usnFA==
 =I9am
 -----END PGP SIGNATURE-----

Merge tag 'fs_for_v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull udf, ext2, isofs and quota fixes from Jan Kara:
 - Some disk format validation improvements for udf
 - Fix isofs handling of dates before 1900
 - Fix ext2 inadvertedly syncing buffer on every directory modification
 - Fix ext2 O_DSYNC handling for direct IO
 - A couple of smaller ext2 fixes
 - Fix tmpfs quotas for root filesystem
 - Unify my email addresses in MAINTAINERS file

* tag 'fs_for_v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  udf: Fix incorrect error code in udf_current_aext()
  udf: Simplify udf_table_prealloc_blocks()
  udf: don't use eloc after the end of the unallocated space table
  udf: fix preallocation discarding before an empty allocation extent
  udf: check the unallocated space table when it is loaded
  udf: don't let the extent type hide an exhausted free-space table extent
  ext2: preserve IOMAP_F_DIRTY for extending direct writes
  udf, ext2, quota, jbd2: Unify email addresses in MAINTAINERS
  isofs: handle Rock Ridge long-form dates before 1900
  ext2: only flush DIRSYNC directories on every change
  ext2: preserve completed DIO bytes when buffered fallback fails
  ext2: take invalidate_lock in ext2_write_failed()
  ext2: Make sbi an proper alias for EXT2_SB(sb) in ext2_fill_super()
  udf: Validate extended attribute space is large enough
  quota: initialize dquot cache before mounting rootfs
  udf: validate vat20->lengthHeader and VAT inode size in udf_load_vat()
2026-11-06 09:00:12 -08:00
Linus Torvalds
fb382e8efd \n
-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmrt7VQACgkQnJ2qBz9k
 QNlCTgf/aCAAU+KgZF9QqWHe3OlftDc4bfImAVum+Z4iRTsxksgTAqFom+x2SgqH
 dulu87lSF/qqD7bZWCOqcnphJ0s+/647bZ7Lp7uRLcEL0km3fvE5H4fhI7loK56E
 gW0+WlTyZUwKKN4lvY2BT4CXaRIeouTyQC8k1OC2kYilkadBJ7da5Pe9+AUxpFrU
 wLiDDVWJLZFK6GfT5kkjkRJevecgUqj/7aff1K3Q8VbgmiRIMShtwjP03Wh1e6dP
 SnVyrqU6OnnSE6HSrLQcTBx37PWhjuzRGYwAskL9c/XEyazKPOJCmmYZZvkYLEsd
 KfXWAiKEjZm8zbtip+TOzK/XlzZqcQ==
 =LFSf
 -----END PGP SIGNATURE-----

Merge tag 'fsnotify_for_v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify fixes from Jan Kara:
 "Two small fixes for fsnotify"

* tag 'fsnotify_for_v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  inotify: do not coalesce rename events
  fsnotify: preserve 64-bit pre-content ranges
2026-11-06 08:55:48 -08:00
Linus Torvalds
0ccc72d4b3 xfs: fixes for v7.4-rc2
Signed-off-by: Carlos Maiolino <cem@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCau3PzQAKCRBcsMJ8RxYu
 Y5SKAYDYuEW5XCOtL9N7Vzm7wCRvhrVbmwXvGJ7X/niZ4zfGDU3OuIRGGuBO3Tlj
 TRbDdW0Bf2DhO9Szo8HZoapi7AkhUQcPc01HpMuaqcD785JrEwXnkBGHd/IhMyU7
 7XlKb1BrNw==
 =Yx7V
 -----END PGP SIGNATURE-----

Merge tag 'xfs-fixes-7.4-rc2' of git://git.kernel.org:/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Carlos Maiolino:
 "The most notable fix here IMO is for xfs's pNFS support (mostly
  related to LAYOUTCOMMIT) and for that it contains several patches.

  Besides that, this contains bug fixes for different subsystems in xfs.
  The last patch is mostly a refactor than a bug fix, but the refactor
  is done to prevent a nasty journal transaction state corruption to
  happen"

* tag 'xfs-fixes-7.4-rc2' of git://git.kernel.org:/pub/scm/fs/xfs/xfs-linux:
  xfs: kill xfs_trans_set/clear_context() helpers
  xfs: fix recovery of partial attr removals
  xfs: make pNFS LAYOUTCOMMIT stable the way fdatasync does
  xfs: add datasync and log_flushed arguments to xfs_log_force_inode()
  xfs: take the invalidate lock while mapping a pNFS layout
  xfs: clamp the pNFS layout range to the maximum file size
  xfs: cap the block count of xfs_iomap_write_direct() at one extent
  xfs: clamp a pNFS LAYOUTCOMMIT extent before computing its end
  xfs: refuse a pNFS LAYOUTCOMMIT of a range without blocks
  xfs: add a flag to convert unwritten extents without allocating blocks
  xfs: mark the inode preallocated for pNFS write layouts past EOF
  xfs: fix wrong compat fields in xfs_ioctl32_bstat_copyin()
  xfs: fix temporary cursor leak in btree shift corruption paths
  xfs: skip iunlock with empty iolock flags in xfs_file_dio_write_aligned
  xfs: don't skip free extents of the longest length in a whole-AG FITRIM
  xfs: don't skip free extents in later batches of a whole-AG FITRIM
  xfs: fix unwind handling during xfs_mount_sysfs_init()
  xfs: mark i_mode=0 and shut down on attr fork inactivation failure
  xfs: set healthmon mount cookie before publishing it
2026-11-06 08:50:27 -08:00
Linus Torvalds
ce8f728086 overlayfs fixes for 7.4-rc2
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE9zuTYTs0RXF+Ke33EVvVyTe/1WoFAmrsdYYACgkQEVvVyTe/
 1Wpjzg/+Lr21Tf5jrjrRE9Pgim8LMSqKwR0GV9WnYmHGMrQ6bk5vG0O5QnwFMZnf
 M4lxDvzyoYmaW2U7EILRz9YKAjoUT/5XRf40NN9OMFy/1mvKJCCk5zm7uxOGixf5
 nQW86p/ihzsIMxPGmKEAhFONAme92dLbyK355eCcOCFVryaFryrEkemicncMZMPt
 TO/+/Xm/f8ydxSzx0MjBHcM93Po/GwRYdvsRtG7H/Ov+4PoqtS0PTnMr1/lip6lA
 M+kX2ocG+GRjokQ1Jm8fIO437ZCZLDjNgi5lpUa+tmuQDsIfCTYdCk7a1hjgDlsb
 vENrQH0vf72ZM6IzayKnmJO3MKLvGRVj16WdS+3JTrnPu9BicjpRSfk/Koy1b7eS
 T/ahZPxoGBKPTKBdeLLddDGsSNfVtrRIys35oNjPC9Po83Su3FHrO7qp8iYf9caN
 2G5YFzvowC7pOsRMVpwuQzJYC56H+ID2mcyORUmJaQqIW+g/zXCaMcjZeGDDHb4i
 ipvXtcbRD73DOAS1cb4SOYMMK3XtAWSpB/dOttV9mw4rpDhuS3HwCDGVqbyozfGT
 ePOE7UQJZZ15AH3FtdUeuXT0DI/fkB4Z4U0kyfoQIPGdDuakbLWNl6GpQm8b0B8K
 JgIHY35lx/j4rM/NrB325jb1zknDjl381wHzHT2/b9eaFzorvIE=
 =XTA5
 -----END PGP SIGNATURE-----

Merge tag 'ovl-fixes-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs

Pull overlayfs fixes from Amir Goldstein:

 - Fix a self deadlock of a fanotify permission event listener that also
   watches the layers, when it reads an overlay directory

 - Three casefold fixes, found by Chris Mason's AI review

 - Fix a decode of a modified file handle with nfs_export=on, which
   could read the stale lower data of a copied up file, also found by
   Chris Mason's AI review

 - Fix an overlay selftest after an errno change

* tag 'ovl-fixes-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs:
  selftests/fscontext_ns: expect EINVAL for overlay descendant userns create
  ovl: look up the index by the decoded origin
  ovl: inherit FMODE_NONOTIFY when reading directory layers
  ovl: inherit FMODE_NONOTIFY when opening directory realfiles
  ovl: fix whiteout creation in casefolded directories
  ovl: do not let chattr change the casefold flag
  ovl: fail the mount if the casefold flag has changed
2026-11-06 08:28:14 -08:00
Linus Torvalds
41b77d5dcc xsa526 - xsa528 for 7.4
-----BEGIN PGP SIGNATURE-----
 
 iJEEABYKADkWIQRTLbB6QfY48x44uB6AXGG7T9hjvgUCau38KhsUgAAAAAAEAA5t
 YW51MiwyLjUrMS4xMiwyLDIACgkQgFxhu0/YY77p8gD/fzG/sN1gYAX12ANL3IiV
 +oJDtr/jYwdo7Cb93QVXV2UBAOsoraPsjHsWTixiPDIDyAc4L1EZgXmwtByZm1I8
 xHoB
 =H3M7
 -----END PGP SIGNATURE-----

Merge tag 'xsa526-xsa528-7.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen fixes from Juergen Gross:
 "Fix three UAF issues that can be hit in the Xen netback and blkback
  drivers when a guest is forcing a teardown of a PV device"

* tag 'xsa526-xsa528-7.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen-blkback: Avoid UAF when reading I/O statistics
  xen-netback: defer xenvif_mcast_addr_list_free()
  xen-netback: Fix UAF when reading statistics data
2026-11-06 08:16:23 -08:00
Juergen Gross
a02926f7c8 xen-blkback: Avoid UAF when reading I/O statistics
Reading I/O statistics via sysfs concurrently with tearing down a
frontend device might result in UAF or a NULL dereference, as the
reading of the statistics data is not synchronized with freeing the
data.

Use a rwlock for synchronizing.

This is XSA-528 / CVE-2026-100082

Fixes: db6fbc1067 ("xen/blkback: make st_ statistics per ring")
Reported-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
2026-11-06 17:09:08 +01:00
Jan Beulich
bfddc420af xen-netback: defer xenvif_mcast_addr_list_free()
In order for the function to legitimately avoid locking/RCU, it needs to
run after all TX/RX processing has finished/stopped: Lookups happen from
xenvif_start_xmit(), while adds/removes happen from xenvif_tx_action()
(called out of xenvif_poll()).

Move the call out of xenvif_disconnect_data() (the call to the function
from connect()'s error path doesn't require any cleaning up there), and
put it past the synchronization point in backend_disconnect().

This is XSA-527 / CVE-2026-100081.

Fixes: b17075d5c1 ("xen-netback: fix race condition on XenBus disconnect")
Reported-by: kerhunt <kerhunt@proton.me>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
2026-11-06 17:09:08 +01:00
Juergen Gross
5fb756f1bb xen-netback: Fix UAF when reading statistics data
The network statistic data in the driver is protected by RCU.
Unfortunately when tearing down the queues after an error during
connecting to the frontend (e.g. due to illegal Xenstore data filled
in by the guest), the statistic data is being freed without
synchronizing the RCU state.  In case the data is being read via sysfs
in this phase, access to already freed memory or memory being in new
use is possible.

Fix that by calling synchronize_net() before freeing the queue data.

This is XSA-526 / CVE-2026-100080

Reported-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Juergen Gross <jgross@suse.com>
2026-11-06 17:08:55 +01:00
Linus Torvalds
f66469d990 Including fixes from Bluetooth, IPsec, WiFi and CAN.
Current release - regressions:
 
   - eth: wwan: mhi_wwan_ctrl: send a DTR drop before it can be coalesced
 
 Previous releases - regressions:
 
   - core:
     - use a dedicated flag to track disabled napi instances
     - frags: limit the truesize of a reassembly queue
     - reject a negative TCP header offset in qdisc_pkt_len_segs_init()y
 
   - tcp:
     - reject unhashed sockets during established lookups
     - free ireq->ipv6_opt after an RCU grace period
 
   - ipv6:
     - fix fib6 walker UAF on NLM_F_REPLACE
     - raw: fix use-after-free in rawv6_send_hdrinc()
 
   - wifi:
     - mac80211: reinstate IEEE80211_TX_CTL_AMPDU, fix ath9k stall
     - brcmfmac: map msgbuf RX packet IDs bidirectional, fix firmware
       crash loop
 
   - vsock: size receive SKBs from declared payload
 
   - xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()
 
   - bluetooth: hci_sync: copy the LE accept list under hdev->lock
 
   - ptp: fix use-after-free in extts_fifo_show() reading tsevqs unlocked
 
   - can: protect the receive lists with a per-device lock
 
   - eth: bnxt: don't keep MSI-X vectors added before FW reserves them
 
   - eth: vxlan: stop rejecting dynamic FDB entries with a nexthop ID
 
 Previous releases - always broken:
 
   - sched: sch_qfq: prevent aggregate self-replacement
 
   - bridge: disable MRP ports before the FDB flush in del_nbp()
 
   - mptcp: do not use fast open on MP_JOIN subflows
 
   - ipv6: serialize multicast router socket ownership
 
   - bluetooth: hci_core: keep link-key filtering inside RCU
 
   - eth: atl1c: drop oversized RX frames instead of panicking
 
   - eth: stmmac: a bunch of XDP path fixes
 
   - eth: b53: enable IGMP and MLD control packet CPU copies
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmrsoSgWHHBhb2xvLmFi
 ZW5pQGdtYWlsLmNvbQAKCRApJHmNzI8TpIKzEACKtniC4wXVre3NhuKc2L0DXVau
 RxlHkwWfSATOXFl382UPRtCMTd1NDzeUGyMEHc1EPYpH6T7svr83MUPnYth0vGZd
 pSKe23Rdpoeppadnj9ErHtOZpcF3/4BcVvAV3AbmW33yUzfOWrT1735UspzQbVvz
 eXrxL1kK/PRyt3uKk/H3gpow/CfRjvPQ8x+mL564Ee/p8c7wXk1r+e/QPSXPZodl
 MZs5oDcLJHjb96aHwU6PuXwtQqfUwaALxtLWk7Bldo7nqMTl4ZWEE0C8X93kOtDS
 zGgTu7ykLhJ+Mlsp4gjWgydUWCPxKKqqFnDg2CG6yOLSdlFwNct0m0o9kV6qjBdD
 JZBpnYVUW3RH4RMcWpMo3szL/EwPc9gNMRK9ug6I7fMfnsB5D9PBljFNy6JRW0K+
 OxQcCMzHW6OVulMzg3hWI7bfG1pgQ5Np8CcjbSaYwT6z/dhP7VWWghdHKa0/w+qR
 PmTaLaBHOIcOsOSKD01ZaCX9QpC+zOSJo+3C0Q7JU9G1nL9z+U8sJlOWjP7MlzU5
 FZd8IiFhgHGe+C6GUigfHnHG30CoRQkcN7Pd53vSe63jtkzavG9VNBj5LLuL61nr
 4avuUKwk2PK4/FgNYGgi7+QwVOJO/txEsJiJlB0f2CEhJKK2IuwDLrT/+wWR2H6G
 Ag9KW4jNwHwFXDyfZw==
 =1UcP
 -----END PGP SIGNATURE-----

Merge tag 'net-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Paolo Abeni:
 "Including fixes from Bluetooth, IPsec, WiFi and CAN.

  Current release - regressions:

    - eth: wwan: mhi_wwan_ctrl: send a DTR drop before it can be coalesced

  Previous releases - regressions:

    - core:
       - use a dedicated flag to track disabled napi instances
       - frags: limit the truesize of a reassembly queue
       - reject a negative TCP header offset in qdisc_pkt_len_segs_init()y

    - tcp:
       - reject unhashed sockets during established lookups
       - free ireq->ipv6_opt after an RCU grace period

    - ipv6:
       - fix fib6 walker UAF on NLM_F_REPLACE
       - raw: fix use-after-free in rawv6_send_hdrinc()

    - wifi:
       - mac80211: reinstate IEEE80211_TX_CTL_AMPDU, fix ath9k stall
       - brcmfmac: map msgbuf RX packet IDs bidirectional, fix firmware
         crash loop

    - vsock: size receive SKBs from declared payload

    - xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()

    - bluetooth: hci_sync: copy the LE accept list under hdev->lock

    - ptp: fix use-after-free in extts_fifo_show() reading tsevqs unlocked

    - can: protect the receive lists with a per-device lock

    - eth:
       - bnxt: don't keep MSI-X vectors added before FW reserves them
       - vxlan: stop rejecting dynamic FDB entries with a nexthop ID

  Previous releases - always broken:

    - sched: sch_qfq: prevent aggregate self-replacement

    - bridge: disable MRP ports before the FDB flush in del_nbp()

    - mptcp: do not use fast open on MP_JOIN subflows

    - ipv6: serialize multicast router socket ownership

    - bluetooth: hci_core: keep link-key filtering inside RCU

    - eth:
       - atl1c: drop oversized RX frames instead of panicking
       - stmmac: a bunch of XDP path fixes
       - b53: enable IGMP and MLD control packet CPU copies"

* tag 'net-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (170 commits)
  tcp: ipv6: free ireq->ipv6_opt after an RCU grace period
  mptcp: pm: kernel: use RCU to free endpoint listeners
  tcp: initialize send sequence numbers before deferring TFO
  net: bridge: disable MRP ports before the FDB flush in del_nbp()
  net: stmmac: set XDP metadata length on the page_pool RX path
  bonding: fix missing down path on speed/duplex failure after FAIL->UP
  ip6mr: Serialize multicast router socket ownership
  bonding: 3ad: don't set BOND_LINK_FAIL on a slave that is not up
  net: ethernet: ti: am65-cpsw-nuss: Enable timestamping of unicast PTP packets
  net: count last skb of each sk_backlog pass in __release_sock()
  net: 8139cp: keep Rx masked while NAPI is scheduled
  net/smc: don't spin in smc_rx_recvmsg() while a pipe holds spliced data
  net: dsa: b53: restore the NSP IMP port 2 Gbps mode
  net: ethernet: bgmac: preserve forced 2.5 Gbps link speed
  l2tp: only return sessions of the given tunnel in l2tp_session_get()
  tipc: raise the minimum bearer MTU to fit tunnel and crypto overhead
  mptcp: do not use Fast Open on MP_JOIN subflows
  tcp: ipv6: do not read ireq->pktopts from tcp_v6_send_synack()
  ipv4: Call rt_add_uncached_list() if !do_cache in ip_route_input_slow().
  ipv6: Flush rt->from in rt6_uncached_list_flush_dev().
  ...
2026-11-05 18:00:16 -08:00
Linus Torvalds
2d2200551c platform-drivers-x86 for v7.4-2
Fixes
 
 - arm64: asus-glymur-ec: Resolve config loop due to THERMAL symbol
 
 - uniwill-laptop: Add .hw_offloaded() to avoid leds subsystem warning
                   about missing callback
 
 The following is an automated shortlog grouped by driver:
 
 arm64:
  -  drop the vacuous THERMAL dependency from EC_ASUS_GLYMUR
 
 uniwill-laptop:
  -  Implement .hw_offloaded trigger callback
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCauxNyQAKCRBZrE9hU+XO
 MQTuAQCHb0Jc4plu6Yfd2/mKDRYjzHCnJieOUQEBRzRpgUwfjgD/Wyo3XQQA8bGC
 MkBsCH8kNu7MupgnFGROskiMW5lffAU=
 =3ohE
 -----END PGP SIGNATURE-----

Merge tag 'platform-drivers-x86-v7.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull platform driver fixes from Ilpo Järvinen:

 - arm64: asus-glymur-ec: Resolve config loop due to THERMAL symbol

 - uniwill-laptop: Add .hw_offloaded() to avoid leds subsystem warning
   about missing callback

* tag 'platform-drivers-x86-v7.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86:
  platform/x86: uniwill-laptop: Implement .hw_offloaded trigger callback
  platform: arm64: drop the vacuous THERMAL dependency from EC_ASUS_GLYMUR
2026-11-05 17:32:20 -08:00
Linus Torvalds
eedaa7d61f chrome-platform-firmware: Fixes for v7.4-rc2
- Don't skip CBMEM entries outside of known memory resources.
 - Fix a Coccinelle warning for error-pointer handling in coreboot-cfr.
 -----BEGIN PGP SIGNATURE-----
 
 iIkEABYKADEWIQS0yQeDP3cjLyifNRUrxTEGBto89AUCaurtEhMcdHp1bmdiaUBr
 ZXJuZWwub3JnAAoJECvFMQYG2jz0H+gBAIevUDxLdZBx6xJv2F7JhZalkE+epvPr
 wRg7CVhO0FTCAP9B+pV+ZVvck1D36fiwchpYMGxw8qYxOPXB1gBZz1GKCg==
 =g5i+
 -----END PGP SIGNATURE-----

Merge tag 'chrome-platform-firmware-fixes-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux

Pull chrome platform firmware fixes from Tzung-Bi Shih:

 - Don't skip CBMEM entries outside of known memory resources

 - Fix a Coccinelle warning for error-pointer handling in coreboot-cfr

* tag 'chrome-platform-firmware-fixes-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux:
  firmware: coreboot: Fix CFR error-pointer handling warning
  firmware: coreboot: Don't skip CBMEM entries outside of known memory
2026-11-05 16:51:29 -08:00
Linus Torvalds
3e516eae69 hwmon fixes for v7.4-rc2
* acpi_power_meter: Check for 32-bit and 64-bit unknown ACPI values,
   Fix missing locking in sysfs show callbacks and resume, and Prevent
   spurious power alarm when power is unknown
 
 * aquacomputer_d5next: Avoid truncating scaled sensor readings, Check
   maxcollection when probing AQUAERO devices, and reject short status
   reports
 
 * asus_rog_ryujin: Fix pump control source on the Ryujin III, and Fix
   timeout when reading 0% duty cycle
 
 * asus_wmi_sensors: Avoid global struct mutation
 
 * chipcap2: Series of fixes addressing various bugs in the driver
 
 * coretemp: Check for NULL platform device in hotplug callbacks,
   Fix 32-bit jiffies wraparound in show_temp() hnd Set nr_cores only
   after core_data allocation succeeds
 
 * corsair-cpro: Cache fan target only after a successful command
 
 * gpd-fan: Reset both fans to automatic on duo boards, and
   Update the speed cache before dropping the PM reference
 
 * hp-wmi-sensors: Avoid global struct mutation, Fix unbounded loops in
   scale_numeric_sensor(), and Serialize alarm flag read-and-clear with
   state->lock
 
 * lm75: Fix setting polarity mask for chips with 16-bit config register
 
 * lm87: Fix drvdata type confusion in vrm_show() and vrm_store()
 
 * nct6683: Fix incorrect struct cast in show_pwm() and store_pwm()
 
 * peci/dimmtemp: Fix devres leak and UAF on concurrent unbind
 
 * pmbus core: Check return value from pmbus_thermal_add_sensor(),
   Register the thermal sensors with a 0-based index, and Fix return value
   check from thermal zone registration, and release devres allocated memory
   after devm_thermal_of_zone_register error
 
 * pmbus/q54sj108a2: Add missing NULL pointer check
 
 * sht15: Stop deferred work before releasing its resources
 
 * sht4x: Convert update_interval to jiffies in pending data check
 
 * tmp108: Fix initial conversion delay and wait until ready
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmrrtEsACgkQyx8mb86f
 mYFOtw/7Bzpn9T0daAQtJ/oM5wWeMQFDGyAQCyHlgRavcGhKwhNbU1CF6ESQ14ud
 7tIubFVDRuO4wqYrRkiGcf6e65npD2WNaacEbIjNXaFtT5XmNM8xFwF6wQfS8SHz
 jWUfb79zDo1zw0bFFkCpxyh0xmH3nhRJdVKBpB6Akqcd+0M5c8lX+vF3Vwu1sFby
 kCxclMun8n40MQ2ypaHKjP1nFhFSU5IlD5ojQsDwGyfJEUV32K074+Davq/MqOC7
 0Ev6IupMTq9gp/vZTsxj0bLIeTxz2ee6eIftTCav/1Ifp1RoWRz4hlw6WxxK/nx8
 n6v6+v1+fEXCvg0Dubf607r6+PeT4AX46YQsLV/UVz1UmFvziavm7KZvEtypCwTC
 +fB+W70gXNUTcohnY3gm2SPlmRgnN+32N+Oo6T9CuCLmPZ0eKUnVAjrJpQidHfGc
 HfbSyx7Cmf5gpRtKpmqZ0Z7ya/FZFY9jq4WmzoBuh2qDMEf2afUHqBrYVO/ZA4Ho
 cz2UeV47BM0HOQomqVRcWTRe4aehO28QxnKguQnD3bqvABn219mw6Jp5oxhDFHVF
 iv2MNMVFN2WKfjjDNJmFfJJzw98nzHy+Ip7Z3SE3Gl3sovkBm7vFBJ3/FC1jKxMk
 eTUlsiZDewox7gQUzm4iChtKtu2eaUYomfsqk9xySq8zC9OcXkw=
 =ALE6
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - acpi_power_meter: Check for 32-bit and 64-bit unknown ACPI values,
   Fix missing locking in sysfs show callbacks and resume, and Prevent
   spurious power alarm when power is unknown

 - aquacomputer_d5next: Avoid truncating scaled sensor readings, Check
   maxcollection when probing AQUAERO devices, and reject short status
   reports

 - asus_rog_ryujin: Fix pump control source on the Ryujin III, and Fix
   timeout when reading 0% duty cycle

 - asus_wmi_sensors: Avoid global struct mutation

 - chipcap2: Series of fixes addressing various bugs in the driver

 - coretemp: Check for NULL platform device in hotplug callbacks, Fix
   32-bit jiffies wraparound in show_temp() hnd Set nr_cores only after
   core_data allocation succeeds

 - corsair-cpro: Cache fan target only after a successful command

 - gpd-fan: Reset both fans to automatic on duo boards, and Update the
   speed cache before dropping the PM reference

 - hp-wmi-sensors: Avoid global struct mutation, Fix unbounded loops in
   scale_numeric_sensor(), and Serialize alarm flag read-and-clear with
   state->lock

 - lm75: Fix setting polarity mask for chips with 16-bit config register

 - lm87: Fix drvdata type confusion in vrm_show() and vrm_store()

 - nct6683: Fix incorrect struct cast in show_pwm() and store_pwm()

 - peci/dimmtemp: Fix devres leak and UAF on concurrent unbind

 - pmbus core: Check return value from pmbus_thermal_add_sensor(),
   Register the thermal sensors with a 0-based index, and Fix return
   value check from thermal zone registration, and release devres
   allocated memory after devm_thermal_of_zone_register error

 - pmbus/q54sj108a2: Add missing NULL pointer check

 - sht15: Stop deferred work before releasing its resources

 - sht4x: Convert update_interval to jiffies in pending data check

 - tmp108: Fix initial conversion delay and wait until ready

* tag 'hwmon-for-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (41 commits)
  hwmon: (asus_rog_ryujin) Fix timeout when reading 0% duty cycle
  hwmon: (hp-wmi-sensors) Serialize alarm flag read-and-clear with state->lock
  hwmon: (acpi_power_meter) Check for 32-bit and 64-bit unknown ACPI values
  hwmon: (acpi_power_meter) Prevent spurious power alarm when power is unknown
  hwmon: (acpi_power_meter) Fix missing locking in sysfs show callbacks and resume
  hwmon: (aquacomputer_d5next) Avoid truncating scaled sensor readings
  hwmon: (sht4x) Convert update_interval to jiffies in pending data check
  hwmon: (coretemp) Fix 32-bit jiffies wraparound in show_temp()
  hwmon: (coretemp) Set nr_cores only after core_data allocation succeeds
  hwmon: (coretemp) Check for NULL platform device in hotplug callbacks
  hwmon: (gpio-fan) Update the speed cache before dropping the PM reference
  hwmon: (tmp108) Fix initial conversion delay and wait until ready
  hwmon: (lm75) Fix setting polarity mask for chips with 16-bit config register
  hwmon: (pmbus) Fix return value check from thermal zone registration
  hwmon: (pmbus) Release devres allocated memory after devm_thermal_of_zone_register error
  hwmon: (pmbus) Check return value from pmbus_thermal_add_sensor()
  hwmon: (pmbus/q54sj108a2) Add missing NULL pointer check
  hwmon: (peci/dimmtemp) Fix devres leak and UAF on concurrent unbind
  hwmon: (nct6683) Fix incorrect struct cast in show_pwm() and store_pwm()
  hwmon: (lm87) Fix drvdata type confusion in vrm_show() and vrm_store()
  ...
2026-11-05 16:37:21 -08:00
Linus Torvalds
69e2b55fc3 vhost,virtio,vdpa: bugfixes
Just a bunch of fixes all over the place.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCgAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmrrL5QPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRphdEIAMnblbwjUhNUZ3u3MLkXGNlcNrDiuPdhoFvY
 RfRcmCWKDBWSu25uwOqqMhmTAqKlegeaeuemKMbaz7CYZFfatRj1B5EeCbrrqRJd
 5igTf9lE7hl6eZnLMY3z6x40cgP95zfkCcFOCN8CTv31sOdHj42uNI9B1faFnowT
 aRF6PCpYQ0qkUcVZha7BxpteqfbbD+hyQp/QydhaXV+owrTdnWryWL4mxmHRhnNs
 yHSzTZL4eoVK1voWup6PusvSa2K8mrhsj0e/e8MnRI3tvFlfka/mMcYAg2DFgrsw
 1Q/Y24qvywa8REcbVhFmVrsktYt5xCJsWhCOsl90/uQj9dQEKis=
 =XA2M
 -----END PGP SIGNATURE-----

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull virtio fixes from Michael Tsirkin:
 "vhost, virtio, and vdpa bugfixes.

  Just a bunch of fixes all over the place"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (38 commits)
  virtio_pci: don't take the MSI mutex under cpu_hotplug_lock
  virtio_ring: Initialize id field in packed indirect descriptors
  vhost-scsi: fix page reference leak in misaligned I/O fallback
  vduse: fix VA/PA confusion in the coherent page fault path
  hwrng: virtio - prevent use-after-free after a failed restore
  virtio: use consistent virtqueue terminology
  virtio_balloon: initialize wakeup_lock before virtqueues are set up
  MAINTAINERS: add missing virtio/vdpa/vduse/vhost headers
  vhost-vdpa: initialize state before publishing cdev
  vhost: reject backend enable without a kick file
  vhost-scsi: reject delayed virtqueue setup
  virtio_ring: use shadow flags when detaching split descriptors
  vhost-scsi: validate event queue descriptor direction
  vhost-scsi: do not count PI bytes in the data length
  vdpa/snet: Don't discard the DPU error in snet_send_ctrl_msg()
  iommu/virtio: Reset device before deleting virtqueues on probe failure
  vhost: fix used ring index wrap in vhost_add_used_n_in_order
  vhost-scsi: zero misaligned I/O bounce pages
  vringh: reject empty / undersized indirect descriptor tables
  virtio_blk: Reset device on probe error paths after DRIVER_OK
  ...
2026-11-05 15:10:52 -08:00
Linus Torvalds
d68ce4e712 Core memory management fixes for 7.4-rc2
This includes fixes to:
 
  - THP (Transparent Huge Pages)
  - GUP (Get User Pages)
  - KSM (Kernel Samepage Merging)
  - USERFAULTFD
  - SHARED MEMORY (shmem/tmpfs/memfd)
  - HUGETLB
  - Core MM, PAGE CACHE and MEMORY RECLAIM
 
 The main changes are:
 
  - Prevent information leaks through memfd pinning, and out-of
    bounds writes in GUP.
 
  - Fix data loss in shmem, THP collapse, KSM and memfd pinning.
 
  - Fix corruption and reference-counting errors with huge PMD/PUD
    mappings, and incorrect TLB flushing and unmapping.
 
  - Fix various use-after-free bugs, deadlocks and unkillable loops,
    witha a focus on shmem swap handling.
 
  - Fix execution-seal enforcement for memfd (incl. hugetlb).
 
 Other changes fix accounting, quota and userfaultfd (un)registration
 handling.
 
 Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRSU98w6emufXtGDgPH6csYRVW7eQUCauw3uAAKCRDH6csYRVW7
 eWVOAP9Z6aWCsj7SVZ76tC3pBnBl/HDoxTRCBdQLAnBVE9IqowD/e9KHgbg0N8ES
 hs6/IKHmZWN12pyxuhC0gzq5M+4wdAE=
 =HYHR
 -----END PGP SIGNATURE-----

Merge tag 'mm-core-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/mm/core

Pull core memory management fixes from David Hildenbrand:
 "Here's a bigger set of MM fixes that we didn't manage to have ready
  for -rc1. All fixes are stable-worthy; the majority fixes nasty
  long-standing bugs instead of being purely hotfixes.

  We have some more of these kinds of stable-worthy fixes in the
  pipeline, but we'll focus on the really urgent fixes as we get closer
  to the release.

  (Leaving urgent MM fixes lurking for various weeks is not good, but
  having too many changes close to the release is also not good, it's
  tricky ...)

  Most issues were reported by Anthropic. Others were found while
  reworking proposed fixes, and of course some of the fixes were just
  reported and fixed on the mailing list.

  All fixes were in linux-next for several days without changes. Some
  commit IDs changed recently when I had to drop some non-stable fixes,
  rebased to -rc1 and picked up more trailers.

  This includes fixes to:
   - THP (Transparent Huge Pages)
   - GUP (Get User Pages)
   - KSM (Kernel Samepage Merging)
   - USERFAULTFD
   - SHARED MEMORY (shmem/tmpfs/memfd)
   - HUGETLB
   - Core MM, PAGE CACHE and MEMORY RECLAIM

  The main changes are:

   - Prevent information leaks through memfd pinning, and out-of bounds
     writes in GUP.

   - Fix data loss in shmem, THP collapse, KSM and memfd pinning.

   - Fix corruption and reference-counting errors with huge PMD/PUD
     mappings, and incorrect TLB flushing and unmapping.

   - Fix various use-after-free bugs, deadlocks and unkillable loops,
     witha a focus on shmem swap handling.

   - Fix execution-seal enforcement for memfd (incl. hugetlb).

  Other changes fix accounting, quota and userfaultfd (un)registration
  handling"

* tag 'mm-core-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/mm/core: (61 commits)
  mm/gup: check folio->mapping under folio lock in memfd_pin_folios()
  khugepaged: fix readahead lock inversion in collapse_file()
  mm/huge_memory: set the mmu_gather page size in zap_huge_pud()
  mm/memory-tiers: unregister empty tiers outside memory_tier_lock
  mm/cma: don't release CMA pages still in use
  mm/vma: don't leak the charge for stack growth
  mm/huge_memory: split huge PUDs when adjusting VMA boundaries
  mm/vma: call ->may_split() before a partial merge
  mm/ksm: check large swap-cache folios before mapping them
  mm/ksm: fix use of a freed anon_vma at swap-in
  mm/ksm: reset the unstable trees of all nodes
  mm: fix deadlock of mremap() against UFFDIO_MOVE
  mm: fix unkillable fault loop on MAP_DROPPABLE memory
  mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit
  mm/memory: reject remote COW faults on PFN mappings
  mm/madvise: fix data loss from MADV_FREE on a KSM page
  mm/mremap: fix moving PUD leaves
  mm/mremap: recheck PUDs under the page table lock
  mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs
  mm/mmu_notifier: set ->mm only after mmgrab()
  ...
2026-11-05 13:13:35 -08:00
Linus Torvalds
46a062865b mm.git review status for linus..mm-nonmm-hotfixes-stable
Everything:
 
 Total patches:       22
 Fixes: tags:         19
 cc:stable patches:   17
 Reviews/patch:       0.77
 Reviewed rate:       68%
 
 22 patches. 17 are cc:stable.
 
 Most are OCFS2 fixes. These address extended-attribute corruption,
 missing attributes and kernel BUGs, along with crashes during cluster
 configuration, lock migration, recovery and unmount. Extent movement
 is also fixed to validate its range against a stable file size.
 
 Three FAT changes prevent a failed-write/FIBMAP race from spuriously
 making the filesystem read-only, correct directory link counts after
 rename, and speed up file expansion. The reported QEMU benchmarks show
 particularly large improvements on synchronous mounts.
 
 A taint-string fix prevents an out-of-bounds read which can expose slab
 contents in the kernel log. There are also build fixes for OpenRISC
 modules on CPUs without hardware multiply and for Clang 24.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCauwFhgAKCRDdBJ7gKXxA
 jukUAP4xNDGCuRNda8im/hJ7TzKmZg4j+raQASTj4SMaTmWR8AD8DrGZ1jLMM05q
 Ftj9PQ99DpBw74qIthIMH1nCzJdsSwI=
 =5/Ef
 -----END PGP SIGNATURE-----

Merge tag 'mm-nonmm-hotfixes-stable-2026-11-04-20-26' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM fixes from Andrew Morton:
 "22 patches. 17 are cc:stable.

  Most are OCFS2 fixes. These address extended-attribute corruption,
  missing attributes and kernel BUGs, along with crashes during cluster
  configuration, lock migration, recovery and unmount. Extent movement
  is also fixed to validate its range against a stable file size.

  Three FAT changes prevent a failed-write/FIBMAP race from spuriously
  making the filesystem read-only, correct directory link counts after
  rename, and speed up file expansion. The reported QEMU benchmarks show
  particularly large improvements on synchronous mounts.

  A taint-string fix prevents an out-of-bounds read which can expose
  slab contents in the kernel log. There are also build fixes for
  OpenRISC modules on CPUs without hardware multiply and for Clang 24"

* tag 'mm-nonmm-hotfixes-stable-2026-11-04-20-26' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (22 commits)
  ocfs2: cache the mount context for dentry lock callbacks
  ocfs2: wait for filecheck kobject release after a failed add
  fat: fix parent link count when replacing a sibling directory
  ocfs2/cluster: unlink socket containers before releasing resources
  ocfs2: stop recovery before shutting down local allocators
  ocfs2/dlm: serialize migration MLE cleanup on failure
  panic: zero the dynamically allocated taint buffer
  ocfs2: keep locking_state within the cluster connection lifetime
  MAINTAINERS: mailmap: use Clément Léger's linux.dev mail address
  MAINTAINERS: add an IPC entry
  ocfs2: validate move extents against a stable EOF
  fat: hold truncate_lock in fat_write_failed()
  fat: preallocate space before expanding in fat_cont_expand()
  ocfs2: do not read the entry array of an empty xattr block
  ocfs2: do not index before the entry array when dividing an empty bucket
  ocfs2: do not read the entry array of an empty xattr bucket
  ocfs2: find the xattr entry again after converting a block to a bucket
  ocfs2: find the xattr entry again after defragmenting a bucket
  ocfs2: read the xattr entry hash before defragmenting the bucket
  ocfs2/heartbeat: serialize concurrent writes to a region's dev attribute
  ...
2026-11-05 13:05:13 -08:00
Linus Torvalds
afd661f6a2 mm.git review status for linus..mm-hotfixes-stable
Everything:
 
 Total patches:       43
 Fixes: tags:         42
 cc:stable patches:   30
 Reviews/patch:       3.67
 Reviewed rate:       88%
 
 Excluding DAMON:
 
 Total patches:       40
 Fixes: tags:         39
 cc:stable patches:   27
 Reviews/patch:       3.95
 Reviewed rate:       95%
 
 Summary of patch series in this merge:
 
 - "mm: avoid losing atomic VMA flags" (Lorenzo Stoakes):
 
   Preserve guard-page and soft-dirty state across VMA changes. Prevent
   fork and THP collapse from losing guard markers, and keep changes
   visible to applications which track modified memory.
 
 - "MAINTAINERS: MM updates" (David Hildenbrand):
 
   Start routing more MM components through mm/core.git and add Zi Yan
   as a THP co-maintainer. Update component coverage and integration
   branches as part of the transition to separate MM component trees.
 
 - "mm/hugetlb: fix mremap bugs" (Li Zhe):
 
   Fix hugetlb mremap deadlocks and truncated move lengths. Prevent
   userfaultfd poison markers from affecting other processes through
   shared hugetlb page tables.
 
 - "MAINTAINERS updates for page and slab allocators" (Vlastimil Babka):
 
   Add Johannes Weiner as a page allocator co-maintainer and update
   page and slab allocator entries for their component trees and
   integration through mm/linux.
 
 - "mm/damon: fix three race bugs in sysfs and core" (SJ Park):
 
   Serialize DAMOS tuning updates and stop monitoring contexts from
   sharing mutable state. Avoid interference between concurrent DAMON
   instances and incorrect auto-tuning.
 
 - "mm: page_alloc: fix reserve access for non-blocking requests"
   (Johannes Weiner):
 
   Stop ordinary non-blocking allocations from consuming reserves or
   bypassing watermarks. Avoid severe allocation stalls under memory
   pressure and preserve reserves for requests entitled to use them.
 
 - "mm/cma: accept memory of CMA areas reserved with memblock_reserve()"
   (Mike Rapoport):
 
   Accept memory in fixed-address and multi-range CMA reservations.
   Prevent fatal accesses to these pages in TDX and SEV-SNP guests.
 
 Summary of the 20 singletons in this merge:
 
 Several fixes address crashes and unsafe memory access. Failed THP
 collapse now flushes stale translations before releasing pages which
 another collapse can free. A truncation race with MADV_DONTNEED could
 remove still-mapped shmem pages and hit a kernel BUG. Large-folio
 page-table scans no longer wrap addresses and crash near address-space
 boundaries. Hugetlb vmemmap optimization no longer causes write faults
 from racing reference-count operations. Memory-cgroup teardown is
 also protected against reclaim work accessing released state.
 
 KSM now preserves userfaultfd protection during merging and unmerging,
 and retains soft-dirty information needed by incremental memory
 dumpers. Reads of /proc/PID/maps and related files no longer omit
 continuously mapped ranges during concurrent VMA changes. There are
 also fixes for expanding mixed mappings with mremap() and querying
 NUMA placement with tagged addresses. Swapoff checks for signals while
 processing large address spaces and shmem files, so it can be
 interrupted without holding up suspend until the whole object is read.
 
 Costly allocations with cheap smaller-order fallbacks avoid direct
 reclaim and compaction. Reported arm64 PostgreSQL tests improved from
 58,602 to 157,246 transactions per second with defrag_mode disabled;
 this addresses a buffered-write regression under fragmentation.
 Background reclaim can recover on the highest-numbered memory node
 after it has given up, and 32-bit writeback threshold calculations
 no longer overflow and assign incorrect dirty-memory limits.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCauv/+AAKCRDdBJ7gKXxA
 juSZAQDqKyOAo0aRzvsJZf3MivTV2ByjTNV19RhdBhfwEzVNOAD8DQs6DdJbi4p/
 h+c2CpCNlgBRF1hMyHvLG7aNUE80aQQ=
 =f9Ds
 -----END PGP SIGNATURE-----

Merge tag 'mm-hotfixes-stable-2026-11-04-20-02' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull MM fixes from Andrew Morton:

 - "mm: avoid losing atomic VMA flags" (Lorenzo Stoakes):

   Preserve guard-page and soft-dirty state across VMA changes. Prevent
   fork and THP collapse from losing guard markers, and keep changes
   visible to applications which track modified memory.

 - "MAINTAINERS: MM updates" (David Hildenbrand):

   Start routing more MM components through mm/core.git and add Zi Yan
   as a THP co-maintainer. Update component coverage and integration
   branches as part of the transition to separate MM component trees.

 - "mm/hugetlb: fix mremap bugs" (Li Zhe):

   Fix hugetlb mremap deadlocks and truncated move lengths. Prevent
   userfaultfd poison markers from affecting other processes through
   shared hugetlb page tables.

 - "MAINTAINERS updates for page and slab allocators" (Vlastimil Babka):

   Add Johannes Weiner as a page allocator co-maintainer and update page
   and slab allocator entries for their component trees and integration
   through mm/linux.

 - "mm/damon: fix three race bugs in sysfs and core" (SJ Park):

   Serialize DAMOS tuning updates and stop monitoring contexts from
   sharing mutable state. Avoid interference between concurrent DAMON
   instances and incorrect auto-tuning.

 - "mm: page_alloc: fix reserve access for non-blocking requests"
   (Johannes Weiner):

   Stop ordinary non-blocking allocations from consuming reserves or
   bypassing watermarks. Avoid severe allocation stalls under memory
   pressure and preserve reserves for requests entitled to use them.

 - "mm/cma: accept memory of CMA areas reserved with memblock_reserve()"
   (Mike Rapoport):

   Accept memory in fixed-address and multi-range CMA reservations.
   Prevent fatal accesses to these pages in TDX and SEV-SNP guests.

 - Summary of singletons in this merge:

   Several fixes address crashes and unsafe memory access. Failed THP
   collapse now flushes stale translations before releasing pages which
   another collapse can free. A truncation race with MADV_DONTNEED could
   remove still-mapped shmem pages and hit a kernel BUG. Large-folio
   page-table scans no longer wrap addresses and crash near
   address-space boundaries. Hugetlb vmemmap optimization no longer
   causes write faults from racing reference-count operations.
   Memory-cgroup teardown is also protected against reclaim work
   accessing released state.

   KSM now preserves userfaultfd protection during merging and
   unmerging, and retains soft-dirty information needed by incremental
   memory dumpers. Reads of /proc/PID/maps and related files no longer
   omit continuously mapped ranges during concurrent VMA changes. There
   are also fixes for expanding mixed mappings with mremap() and
   querying NUMA placement with tagged addresses. Swapoff checks for
   signals while processing large address spaces and shmem files, so it
   can be interrupted without holding up suspend until the whole object
   is read.

   Costly allocations with cheap smaller-order fallbacks avoid direct
   reclaim and compaction. Reported arm64 PostgreSQL tests improved from
   58,602 to 157,246 transactions per second with defrag_mode disabled;
   this addresses a buffered-write regression under fragmentation.
   Background reclaim can recover on the highest-numbered memory node
   after it has given up, and 32-bit writeback threshold calculations no
   longer overflow and assign incorrect dirty-memory limits.

* tag 'mm-hotfixes-stable-2026-11-04-20-02' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (43 commits)
  MAINTAINERS: move SLAB ALLOCATOR under MEMORY MANAGEMENT
  MAINTAINERS: add Johannes as the page allocator co-maintainer
  MAINTAINERS: route more MM changes through mm/core.git
  MAINTAINERS: rename and move MEMORY HOT(UN)PLUG
  MAINTAINERS: add missing files to MM component sections
  MAINTAINERS: sort entries in MM sections
  MAINTAINERS: add Zi Yan as co-maintainer for MEMORY MANAGEMENT - THP
  MAINTAINERS: TMPFS (SHMEM FILESYSTEM) updates
  MAINTAINERS: mention for-next branch in MEMORY MANAGEMENT - MEMORY MAP
  mm: memcontrol: fix NULL pointer deref and UAF from high_work_func() on dying memcg
  mm/cma: accept memory of CMA areas reserved at a fixed address
  mm/cma: accept memory of multi-range CMA areas
  mm/page_alloc: avoid direct reclaim and compaction for costly __GFP_NORETRY allocations
  mm: page_alloc: remove ALLOC_NON_BLOCK from ALLOC_RESERVES
  mm: page_alloc: do not give all non-blocking requests reserve access
  mm/hugetlb_vmemmap: map the shared tail page writable
  fs/proc/task_mmu: fix missed VMAs when reading /proc/PID/maps and friends
  selftests/mm: fix khugepaged_race build with older glibc
  mm/vma: update VMA iterator state on error in new VMA merge
  mm/migrate: snapshot the source nid before the misplaced migration
  ...
2026-11-05 12:32:29 -08:00
Jan Kara
e5801273f9 udf: Fix incorrect error code in udf_current_aext()
There are two places in udf_current_aext() that return -1 instead of
proper error code. Fix them.

Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:11:44 +01:00
Jan Kara
a3b98efdb3 udf: Simplify udf_table_prealloc_blocks()
Simplify handling when the specified extent is not found in the table
of free blocks.

Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:09:19 +01:00
Matthias Goergens
94401199df udf: don't use eloc after the end of the unallocated space table
When udf_next_aext() returns 0, its eloc, elen and etype outputs hold
no defined value.  Two walks of the unallocated space table still use
eloc after the walk has reached the end of the table.

udf_table_prealloc_blocks() looks for a free extent starting at
first_block and decides whether it found one by comparing eloc with
first_block after the walk.  If the table's list ends in a continuation
descriptor that leads to an empty allocation extent, eloc is then the
block of that allocation extent, which is in use, and if that is
first_block, the block is handed out as preallocation.  Once
udf_discard_prealloc() no longer frees the wrong block, this is what
still makes fsx in generic/091 and generic/263 read back bad data on a
table, in about one run in four.  Only take the extent if the walk
stopped at it.

When udf_table_free_blocks() cannot merge the freed blocks into an
existing extent, it appends a new one and sets only its block number,
so the partition reference comes from whatever eloc held after the
walk, and with long allocation descriptors it is written to disk.  For
a table without extents, eloc was never set.  Take the partition
reference from the freed blocks instead.  Short allocation descriptors
do not store the partition reference, which is why this half remains a
latent long-descriptor fix rather than a reproduced failure.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Link: https://patch.msgid.link/fd9ca4c4ba98c00c012ec861f6c0bc08a3b1d07b.1793349907.git.matthias.goergens@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:07:35 +01:00
Matthias Goergens
0c52750caa udf: fix preallocation discarding before an empty allocation extent
udf_discard_prealloc() finds the last extent of a file by peeking at
the next one with udf_next_aext() and stopping when that returns 0.
The peek reads into eloc and elen, and the code then uses them as the
last extent.  But when udf_next_aext() returns 0 they hold no defined
value: if the extent list ends in a continuation descriptor that leads
to an empty allocation extent, they describe that continuation, i.e.
the block of the empty allocation extent, one block long.

The kernel creates such lists itself: when udf_delete_aext() removes
the only descriptor of the last allocation extent in a list, it leaves
that allocation extent empty and the continuation to it in place.

If the last extent is a preallocation, udf_discard_prealloc() deletes
it with udf_delete_aext(), which finds the following allocation extent
empty, so it also removes the continuation and frees that allocation
extent's block.  udf_discard_prealloc() then frees eloc and elen: that
block a second time, instead of the preallocated blocks.  On a space
bitmap the preallocated blocks leak and the free block count drifts.
On an unallocated space table the second free adds a second free
extent for the same block, which is later handed out twice: fsx as run
by generic/091 and generic/263 ends up with two parts of its test file
in one block and reads back bad data.

Peek into separate variables, so that eloc and elen keep the last
extent that udf_next_aext() returned with 1.

Fixes: cfe4c1b25d ("udf: Fix preallocation discarding at indirect extent boundary")
Cc: stable@vger.kernel.org
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Link: https://patch.msgid.link/480eccd1264a4cea5226fc36ed108931b2c403fb.1793349907.git.matthias.goergens@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:07:35 +01:00
Matthias Goergens
e614c3e35a udf: check the unallocated space table when it is loaded
udf_table_new_block() hands out the first block of the extent closest
to its goal and trusts that the extent covers at least one whole block
inside the partition.  Nothing checks that.  A zero-length extent makes
it return the block the extent points at, which need not be free, and
the subtraction of one block then underflows the length into the type
bits, turning the entry into a bogus continuation.  An extent running
past the end of the partition makes it return blocks behind the
partition.

Such tables are not only found on crafted images: until the previous
commit, udf_table_new_block() itself left zero-length extents behind
in tables written by mkudffs, and then converted them into extents
running past the partition.

Check every extent once when the table is loaded, and refuse
read-write access if one is empty, is not a whole number of blocks, or
does not lie inside the partition, in the same way as for other
allocation information the kernel cannot use.  Check first that the
table is an Unallocated Space Entry at all: the walk starts at the
offset of the allocation descriptors in one, and for a file entry that
offset lies before the inode's in-memory copy of the descriptors.
Treat a chain of allocation extent descriptors that leads back to
itself the same way: the walk would otherwise return the same extents
forever, and the mount would never finish.  Let a fatal signal
interrupt the walk and fail the mount.

Refusing read-write access to an empty extent is deliberate.  It shows
that an old kernel took the last block but left the entry behind.  If
consumed again, the entry returns an in-use block and turns into a huge
bogus extent.  Refusing the table before that
happens avoids this second allocation; the filesystem can still be
mounted read-only.  The check cannot detect every overlap that may
already exist in a damaged table.

This patch should be backported together with the previous one: that
patch stops creating new empty extents, and this one rejects existing
ones before they are consumed again.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Link: https://patch.msgid.link/81233decd91f4a48bf4d74e3d15b547c7711e39f.1793349907.git.matthias.goergens@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:07:35 +01:00
Matthias Goergens
da582d84fc udf: don't let the extent type hide an exhausted free-space table extent
udf_table_new_block() takes the first block of the free-space table
extent closest to the goal.  It keeps that extent's type and length
together in goal_elen, subtracts one block, and deletes the extent only
if goal_elen then reaches zero.  UDF 2.60 section 2.3.7.1 requires the
free-space extents of an Unallocated Space Entry to be of type 1
(allocated but not recorded), and mkudffs writes them that way.  For
such an extent the type bits keep goal_elen non-zero, so taking its last
block leaves a type-1 extent of length zero behind, starting at the
block after the extent, which is in use.

The next allocation that picks this empty extent returns that in-use
block.  Subtracting a block from 0x40000000 then borrows from the type
bits, and the extent becomes type 0 with a length of 2^30 - blocksize:
about a gigabyte of "free" space overlapping live metadata, the other
table extents and whatever lies behind the partition.  From then on
blocks are handed out twice, or past the end of the partition.

Extents that udf_table_free_blocks() adds are type 0, where the check
works, so only tables written by mkudffs or by another implementation
are affected.  Nothing more than filling such a filesystem is needed:
on a fresh 1 MiB "mkudffs --space=unalloctable" image, creating empty
files until the partition is full writes file entries over the reserve
volume descriptor sequence and the backup anchor, and df then reports a
negative amount of used space.

On syzbot's images the same double allocation is what the two reports
below trip over.  In the first, ftruncate() extends a new file with
enough hole extents to need a chain of allocation extent descriptors;
one AED is placed on another inode's file entry, and a later one is
placed on the block of the AED currently being filled, which
udf_setup_indirect_aext() zeroes, so __udf_add_aext() finds
lengthAllocDescs out of step with its cursor.  In the second, an AED
is placed past the end of the device, sb_getblk() fails, and the error
path of udf_do_extend_file() calls udf_truncate_extents() on an extent
list that no longer covers i_size.

Keep the type separately from the length, as udf_table_prealloc_blocks()
already does.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: syzbot+799a0e744ac47f928024@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=799a0e744ac47f928024
Reported-by: syzbot+43fc5ba6dcb33e3261ca@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=43fc5ba6dcb33e3261ca
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Link: https://patch.msgid.link/6b51c38d2d069544053c542470950e2a448b0b8d.1793349907.git.matthias.goergens@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 15:07:35 +01:00
Eric Dumazet
fafbc40511 tcp: ipv6: free ireq->ipv6_opt after an RCU grace period
ireq->ipv6_opt is only set by calipso_req_setattr(), when a CALIPSO
NetLabel mapping is configured.

Request socket migration (net.ipv4.tcp_migrate_req=1, or a
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE program) clones the request
socket with inet_reqsk_clone(), so that the old request socket and
its clone share the same ipv6_opt, then reqsk_migrate_reset() clears
the pointer in the old one.

Another cpu holding a reference on the old request socket can still
be using these options, sending a SYNACK from tcp_v6_send_synack()
or creating a child in tcp_v6_syn_recv_sock(), when the clone
is freed. tcp_v6_reqsk_destructor() frees ipv6_opt with a plain
kfree(), leading to a use-after-free.

Both readers already run under RCU, like their IPv4 counterparts.
Use kfree_rcu() in tcp_v6_reqsk_destructor(), as commit e3f33b0a1d
("ipv4: free inet_opt and ireq_opt after an RCU grace period") did
for ireq_opt.

Fixes: c905dee622 ("tcp: Migrate TCP_NEW_SYN_RECV requests at retransmitting SYN+ACKs.")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/netdev/179369559062.488856.15441115725436277776@kernel.org/
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Tested-by: Linkui Xiao <xiaolinkui@kylinos.cn>
Link: https://patch.msgid.link/20261103090011.4128420-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 15:07:23 +01:00
Kyle Zeng
49b09ae0bf mptcp: pm: kernel: use RCU to free endpoint listeners
mptcp_pm_nl_create_listen_socket() starts the TCP listener directly
instead of going through mptcp_listen(). It consequently misses setting
SOCK_RCU_FREE on the parent MPTCP socket.

tcp_child_process() can invoke the listener's subflow_data_ready()
callback without holding the MPTCP parent lock or a reference to the
parent. An authenticated MP_JOIN racing with endpoint teardown can
therefore access the parent after its last reference has been dropped.
The ADD_ADDR error path can also close an already published listener.

Set SOCK_RCU_FREE before __inet_listen_sk() publishes the TCP listener,
matching mptcp_listen(). This protects the parent on every subsequent
close path, including a failed endpoint addition.

Fixes: 1729cf186d ("mptcp: create the listening socket for new port")
Cc: stable@vger.kernel.org
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20261030042255.74216-1-kylebot@openai.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 15:01:42 +01:00
Qingfang Deng
57889a8f6d tcp: initialize send sequence numbers before deferring TFO
TCP_FASTOPEN_CONNECT can return from connect() before tcp_connect_init()
when a cached cookie or cookieless Fast Open allows deferring the SYN.
At this point write_seq contains the initial sequence number, while
snd_una and snd_nxt have not been initialized to that sequence number.

Consequently, inet_diag and /proc/net/tcp{,6} report the initial
sequence number as the send queue length despite no SYN or payload being
queued.

Initialize snd_una and snd_nxt to write_seq before marking the
connection as deferred. Both sequence-based queue lengths then remain
zero until the first write starts the connection and runs
tcp_connect_init().

Fixes: 19f6d3f3c8 ("net/tcp-fastopen: Add new API support")
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Link: https://patch.msgid.link/20261102035943.9700-1-qingfang.deng@linux.dev
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 12:36:46 +01:00
Cheng Yongkang
37dfd0efbf net: bridge: disable MRP ports before the FDB flush in del_nbp()
del_nbp() flushes the port's FDB entries before it unregisters the RX
handler. For a normal port, br_stp_disable_port() moves the port to
BR_STATE_DISABLED before this cleanup.

That does not hold for an MRP ring port. br_set_state() ignores state
changes while BR_MRP_AWARE_BIT is set, so br_stp_disable_port() leaves
the port state alone. br_mrp_port_del() then restores forwarding when
the bridge is up before clearing the bit. A frame received between
br_fdb_cleanup_by_dst() and netdev_rx_handler_unregister() can therefore
create a new FDB entry referencing the dying port. Nothing removes that
entry before destroy_nbp_rcu() frees the port, so a later frame to the
learned MAC can be forwarded through the freed port.

Remove the MRP and CFM instances before disabling the port, so that
br_stp_disable_port() actually transitions it to BR_STATE_DISABLED.
With CONFIG_BRIDGE_VLAN_FILTERING=y, synchronize_net() in
nbp_vlan_group_unpublish() also drains receive paths that could still
learn with the old state before the final FDB cleanup.

Found through an LLM-assisted source code analysis workflow and
reproduced on net with KASAN and CONFIG_BRIDGE_VLAN_FILTERING=y in QEMU.
A diagnostic switchdev module accepts MRP objects and delays the
NETDEV_CHANGEUPPER callback for 1.5 s, holding del_nbp() after the FDB
cleanup and before RX handler removal. The reproducer floods the MRP
port with rotating source MACs, waits for the port's RCU callback
through the module's rcu_barrier(), then sends frames to those MACs
from another port. The unpatched kernel reports:

  BUG: KASAN: slab-use-after-free in br_forward+0xb1/0x820
  Call Trace:
   <IRQ>
   br_forward+0xb1/0x820
   br_handle_frame_finish+0x148b/0x1e50
   br_handle_frame+0x90a/0x15c0

With this patch, three runs of six cycles each reach the delay without
a KASAN report.

Fixes: 6536993371 ("bridge: mrp: Integrate MRP into the bridge")
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Link: https://lore.kernel.org/netdev/20261012123051.GA714215@shredder/
Closes: https://lore.kernel.org/netdev/20261022090431.3641707-1-teel4res@gmail.com/
Signed-off-by: Cheng Yongkang <teel4res@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261101044840.1595584-1-1020691186@qq.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 12:14:28 +01:00
Lorenzo Bianconi
6d9b7c85af net: stmmac: set XDP metadata length on the page_pool RX path
stmmac_rx() initializes the XDP buffer with the metadata area valid, so
an XDP program can reserve metadata with bpf_xdp_adjust_meta() and write
it in [xdp->data_meta, xdp->data), for example to export the RX hardware
timestamp obtained from the metadata kfunc. When such a frame is passed
to the stack, the skb is built in place around the same page with
napi_build_skb(), but skb_metadata_set() is never called.

napi_build_skb() clears skb_shared_info up to dataref, which includes
meta_len, so skb_metadata_len() stays zero. The stack and TC BPF then see
an empty metadata range even though the bytes are present in the skb
headroom. The AF_XDP zero-copy path already records the length in
stmmac_construct_skb_zc().

Record the metadata length after reserving the headroom and adding the
frame data. No copy is needed because the skb is built over the buffer the
XDP program wrote to. With the length recorded, the software VLAN
stripping path can move the metadata together with the MAC header, as it
already does for zero-copy frames.

Fixes: e3f9c3e348 ("net: stmmac: add Rx HWTS metadata to XDP receive pkt")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20261102-stmmac_meatada_pp_path-v1-1-d93cc4f9a864@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 12:08:32 +01:00
Timur Stukan
a76ab5e733 bonding: fix missing down path on speed/duplex failure after FAIL->UP
In bond_miimon_commit(), when a slave is proposed as BOND_LINK_UP but
bond_update_speed_duplex() fails in bonding mode that needs speed/duplex
(802.3ad, tlb, alb), the slave is set to BOND_LINK_DOWN directly. This
bypasses bond_set_slave_link_state(), bond_miimon_link_change() and
failover.

This is fine for slave that coming from BOND_LINK_BACK, which was never
brought up and is not in use. But since commit 1899bb3251 ("bonding:
fix state transition issue in link monitoring") the commit phase also
handles BOND_LINK_FAIL -> BOND_LINK_UP which means a slave that is still
in use and may be curr_active_slave.

If the link recovers within downdelay and goes down again before the
commit phase reads speed/duplex, the slave is silently marked down while
remaining the active slave in worst cases. In alb/tlb the bond MAC stays
on the dead port, no failover happens and TLB/RLB state is not cleaned,
so the bond stops passing traffic until that link comes back even though
other slaves are up. A non-active slave is affected too, in alb, RLB
clients assigned to it are not reassigned and become unreachable.

Reproduced in tlb and alb mode with miimon=100 and downdelay=10000 by
flapping a slave within downdelay and dropping it again before commit
(a longer delay was added between inspect and commit to make window
wider and easier to test):
  bond0: (slave enp0s3): link status down for interface, disabling it in 10000 ms
  bond0: (slave enp0s3): link status up again after 3400 ms
  bond0: (slave enp0s3): failed to get link speed/duplex

procfs then shows the active slave with "MII Status: down" and "Link
Failure Count: 0", and all traffic is lost.

Fix this by dropping the loop in bond_mii_monitor() that applied all
proposed link states before bond_miimon_commit(). bond_miimon_commit()
now applies each state itself: UP after the speed/duplex check, as it
already did, DOWN in the down path, and FAIL/BACK directly. So when the
speed/duplex check runs, slave->link still holds the previous state. If
the check fails for a slave that is FAIL or UP, take it through the
regular down path, including failover. DOWN and BACK slaves were
never brought up and are still just reverted to DOWN. The down path is
moved into bond_miimon_slave_down() so both callers share it.

After the fix:
  bond0: (slave enp0s3): failed to get link speed/duplex
  bond0: (slave enp0s3): link status definitely down, disabling slave
  bond0: (slave enp0s4): making interface the new active one

Fixes: 1899bb3251 ("bonding: fix state transition issue in link monitoring")
Signed-off-by: Timur Stukan <timur.stukan.linux@gmail.com>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Link: https://patch.msgid.link/20261101150240.66292-1-timur.stukan.linux@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:53:05 +01:00
Kyle Zeng
c6b41de4dd ip6mr: Serialize multicast router socket ownership
MRT6_TABLE checks whether the socket owns its current table before
acquiring RTNL. MRT6_INIT also looks up its table before taking RTNL.
Consequently, concurrent TABLE and INIT calls can initialize the old
table and then change the socket's selected table. Another INIT can
register the same socket in the new table.

rawv6_close() calls ip6mr_sk_done(), which clears only the first table
owned by the socket. After the socket's RCU-delayed free, the other
table retains a dangling mroute_sk pointer. A subsequent multicast cache
report passes that pointer to sock_queue_rcv_skb_reason(). This produces
a KASAN slab-use-after-free in sk_filter_trim_cap().

Look up the selected table in ip6mr_sk_init() after acquiring RTNL.
Likewise, re-read the current table and check its owner under RTNL in
MRT6_TABLE before updating the selection. This preserves the single-table
ownership invariant shared with ip6mr_sk_done(), without changing the
locking of the other multicast socket options.

Fixes: d1db275dd3 ("ipv6: ip6mr: support multiple tables")
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261030042221.73996-1-kylebot@openai.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:33:48 +01:00
Timur Stukan
9a65b9c2a9 bonding: 3ad: don't set BOND_LINK_FAIL on a slave that is not up
In 802.3ad mode, when bond_update_speed_duplex() fails on NETDEV_UP or
NETDEV_CHANGE, bond_slave_netdev_event() sets the slave link to FAIL if
the slave has ever been up (last_link_up != 0), and to DOWN otherwise,
so that miimon can set it right once speed/duplex are valid.

last_link_up is never cleared, so a slave that is currently DOWN but
was up before is set to FAIL as well. miimon then treats it as a slave
that is still in use and takes it through the full down path again:
the link failure count is incremented, "link status definitely down"
is logged and the 802.3ad port is disabled a second time, although the
slave has not been up since it went down.

Reproduced in 802.3ad mode with miimon=100 by setting a slave down and
up again. On NETDEV_UP the speed is still unknown, so the notifier sets
FAIL, and the next miimon pass sees no carrier and proposes DOWN:

	ip link add bond0 type bond mode 802.3ad miimon 100 lacp_rate 1
	ip link set enp0s3 down
	ip link set enp0s4 down
	ip link set enp0s3 master bond0
	ip link set enp0s4 master bond0
	ip link set enp0s3 up
	ip link set enp0s4 up
	ip link set bond0 up
	# wait for LACP to settle
	ip link set enp0s3 down
	ip link set enp0s3 up

procfs then shows "Link Failure Count: 2" in enp0s3 slave part. Also in
dmesg wrote twice: "link status definitely down, disabling slave".

Fix this by setting FAIL only for a slave that is currently UP and
leaving other states alone. An up slave that loses speed/duplex still
goes through FAIL as before, and DOWN/BACK slaves are left to miimon,
as in the other modes.

Fixes: ea53abfab9 ("bonding/802.3ad: fix link_failure_count tracking")
Signed-off-by: Timur Stukan <timur.stukan.linux@gmail.com>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Link: https://patch.msgid.link/20261101145653.63648-1-timur.stukan.linux@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:26:32 +01:00
James Clark
6887a8f982 net: ethernet: ti: am65-cpsw-nuss: Enable timestamping of unicast PTP packets
On a BeagleY-AI (J722S), ptp4l as a unicast master (unicast_listen) logs
"received DELAY_REQ without timestamp" for each unicast Delay_Req, and
its port goes to FAULTY after "timed out while polling for tx timestamp"
for the first unicast Sync.

am65_cpsw_nuss_hwtstamp_set() does not set the TS_UNI_EN bit (bit 24) of
the port's TS_CTL_LTYPE2 register. According to the TRM (J722S TRM
SPRUJB3D, 12.2.1.4.7.13.5.1 Ethernet Port Receive Event and
12.2.1.4.7.13.5.2 Ethernet Port Transmit Event), this bit must be set
for the port to timestamp PTP event messages over UDP sent to a unicast
address; without it, only messages sent to the PTP multicast addresses
selected by the TS_107 and TS_129 to TS_132 bits are timestamped. TI's
netcp_ethss driver for the Keystone 2 Ethernet switch, which has the
same timestamping registers, always sets TS_UNI_EN.

Set TS_UNI_EN along with the other bits. With this change, ptp4l in the
same setup gets timestamps for the unicast Delay_Req and Sync messages.

Fixes: b1f66a5bee ("net: ethernet: ti: am65-cpsw-nuss: enable packet timestamping support")
Cc: stable@vger.kernel.org
Signed-off-by: James Clark <jjc@jclark.com>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/20261102135117.419539-1-jjc@jclark.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:20:32 +01:00
Ray Zhang
c4e4056b21 net: count last skb of each sk_backlog pass in __release_sock()
Running 500 concurrent TCPv6 streams (neper "tcp_stream -6 -T 1 -F 500")
on a 2-core Cortex-A53 (CONFIG_PREEMPT_NONE=y, HZ=1000, LATENCY_WARN)
triggers resched_latency_warn() in __release_sock():

  [ 3655.311821] sched: CPU 0 need_resched set for > 100006892 ns (100 ticks) without schedule
  [ 3655.311889] Call trace:
  ...
  [ 3655.311944]  resched_latency_warn+0x7c/0x88
  [ 3655.311958]  sched_tick+0x1c0/0x418
  ...
  [ 3655.312578]  net_rx_action+0x238/0x438
  ...
  [ 3655.312641]  do_softirq+0x4c/0x90
  [ 3655.312651]  __local_bh_enable_ip+0x84/0x90
  [ 3655.312663]  local_bh_enable+0x1c/0x28
  [ 3655.312674]  __dev_queue_xmit+0x4a8/0xb00
  ...
  [ 3655.312782]  tcp_v6_do_rcv+0x240/0x5f8
  [ 3655.312793]  __release_sock+0x9c/0x188
  [ 3655.312806]  release_sock+0x150/0x168
  [ 3655.312817]  tcp_sendmsg+0x4c/0x70

__release_sock() can loop past 100 ms without calling cond_resched():

- Each outer-loop pass drains sk_backlog, but "if (!skb) break;" runs
  before "++nb", so a pass of B skbs only adds B - 1 to nb (0 for 1 skb).
- With 500 TCPv6 streams and NAPI sharing two Cortex-A53 cores, runnable
  tasks keep TIF_NEED_RESCHED set on CPU 0.
- During spin_unlock_bh() and TX softirqs (__dev_queue_xmit() ->
  local_bh_enable()), tcp_add_backlog() coalesces arriving pure ACKs into
  a single tail skb.
- Repeated 1-skb passes never advance nb or call cond_resched(),
  triggering resched_latency_warn() after 100 ticks.

Restore the do-while loop and drop "if (!skb) break;" so every skb
increments nb across passes and calls cond_resched() every 16 skbs.

Reproduced the issue and verified the fix on two 2-core Cortex-A53 hosts
(CONFIG_PREEMPT_NONE=y, HZ=1000, LATENCY_WARN, latency_warn_once=0) with
a userspace reproducer over /dev/net/tun:

- CPU 0 runs a TCPv6 sender and a second runnable task while CPU 1 writes
  pure ACKs to /dev/net/tun (~30k TCPBacklogCoalesce/run), sustaining
  1-skb sk_backlog refills in __release_sock() for ~400 ms (ftrace).
- Before: CPU 0 stayed unscheduled in __release_sock(), hitting
  resched_latency_warn() 293 and 275 times on the two hosts (> 100.9 ms).
- After: cond_resched() yielded CPU 0 inside __release_sock(), with
  0 resched_latency_warn() hits on both hosts.
- Also observed no regression with the workload from
  commit 16c610162d ("net: call cond_resched() less often in
  __release_sock()"), "super_netperf 4 -H srv -T,10 -l 3000 &".

Fixes: 16c610162d ("net: call cond_resched() less often in __release_sock()")
Cc: stable@vger.kernel.org
Signed-off-by: Ray Zhang <sgzhang@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Link: https://patch.msgid.link/20261101075145.698399-1-sgzhang@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:16:38 +01:00
Colton Pawielski
547b1ae5ec net: 8139cp: keep Rx masked while NAPI is scheduled
cp_rx_poll() calls napi_complete_done() and only then takes cp->lock
with interrupts disabled to unmask the Rx interrupts. An interrupt
that is not masked while polling (TxOK, TxErr, ...) can arrive in
between. cp_interrupt() then sees the Rx status bits, which are still
set, finds NAPI no longer scheduled, masks Rx and schedules NAPI again.
cp_rx_poll() then carries on and unmasks Rx anyway.

From that point Rx interrupts are enabled while NAPI is scheduled:
cp_interrupt() leaves the Rx bits for the poll routine, does not mask
them because napi_schedule_prep() fails, and the level-triggered
interrupt fires again as soon as it returns. On an SH7751 LANDISK
under combined Tx/Rx load this interrupt storm was captured with a RAM
trace right before the board locked up hard.

Mask Rx in cp_interrupt() whenever Rx status is pending, not only when
NAPI gets scheduled. If the race leaves Rx unmasked, the next interrupt
masks it again, and the pending poll unmasks it when it completes.

Fixes: ab1e7e1d26 ("8139cp: use napi_complete_done()")
Signed-off-by: Colton Pawielski <colton.pawielski@gmail.com>
Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Link: https://patch.msgid.link/20261031-b4-8139cp-napi-v2-1-5824797c0fe6@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:09:42 +01:00
Bryam Vargas
8288ba942c net/smc: don't spin in smc_rx_recvmsg() while a pipe holds spliced data
While bytes spliced off the RMB are still in a pipe, recvmsg() waits
for the pipe to release them before it copies the data behind them.
The path to that wait skips the timeout and signal checks, and
smc_rx_wait() returns at once on RCV_SHUTDOWN. With a signal pending,
after SHUT_RD, or once the peer closes or shuts down writing,
recvmsg() spins on a CPU until the pipe is drained, and SIGKILL cannot
stop it. MSG_DONTWAIT and an expired SO_RCVTIMEO wait there too
instead of returning -EAGAIN.

Check the timeout and signals before that wait, and end it when the
pipe releases the data or the connection is killed, not on RCV_SHUTDOWN.
A zero-length read returns 0 without waiting for the pipe; a
non-blocking one returns -EAGAIN while poll() still reports the socket
readable (splice() can still take those bytes). The wait sets
SOCKWQ_ASYNC_WAITDATA like smc_rx_wait(), so a byte arriving behind
the pipe raises no SIGIO on a reader already asleep for it, and a full
barrier orders its wait queue entry before its read of splice_pending,
so no wake is lost.

Fixes: 9014db202c ("smc: add support for splice()")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
Link: https://patch.msgid.link/20261029-b4-disp-da7f8e6a-v2-1-9052904adf72@proton.me
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 11:06:27 +01:00
Hungyu Lin
4f91b042af ext2: preserve IOMAP_F_DIRTY for extending direct writes
ext2_iomap_begin() sets IOMAP_F_DIRTY for writes that may extend i_size,
but clears the flag after ext2_get_blocks(). When the write uses an
existing mapped block, iomap can then use FUA and skip
generic_write_sync(), even though ext2_dio_write_end_io() updates the
inode size. An O_DSYNC write can therefore return without persisting
the new size.

For example, on a FUA-capable device, a 512-byte O_DIRECT|O_DSYNC write
at offset 512 into a fsynced one-byte file returns successfully and
extends the in-memory size to 1024, while an immediate read of the
on-disk inode still shows size 1. An explicit fsync persists the new
size.

Move setting of IOMAP_F_DIRTY after the initialization.

Fixes: fb5de4358e ("ext2: Move direct-io to use iomap")
Cc: stable@vger.kernel.org
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Link: https://patch.msgid.link/20261029013616.97194-1-dennylin0707@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 09:36:19 +01:00
Jan Kara
d4a6efef3e udf, ext2, quota, jbd2: Unify email addresses in MAINTAINERS
In MAINTAINERS file I was using two different email address. With the
advent of various tools which use address in MAINTAINERS as an
identifier (like Sashiko's pre-existing issues list) it is a bit
annoying to remember which entry has what. Make all entries use the same
address.

Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-05 09:30:43 +01:00
Paolo Abeni
6c1c41effa linux-can-fixes-for-7.4-20261103
-----BEGIN PGP SIGNATURE-----
 
 iIkEABYKADEWIQSl+MghEFFAdY3pYJLMOmT6rpmt0gUCauoyOBMcbWtsQHBlbmd1
 dHJvbml4LmRlAAoJEMw6ZPquma3S/rUA+gJbmNTbkXcPgH93DbqwG8MnTrYgrJLC
 C+BPXzjWmKflAQCyrg/ogBJlF4vbzOhxqQiVdZ3J3kcSjhchvDx3BZv0AA==
 =PMgj
 -----END PGP SIGNATURE-----

Merge tag 'linux-can-fixes-for-7.4-20261103' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2026-11-03

this is a pull request of 15 patches for net/main.

The first patch is by Vincent Mailhol and drops CAN-XL frames on non
CAN-XL devices.

A patch by Kaixuan Li for the CAN ISOTP protocol improves the check
for the correct CAN CC/FD frames.

The next 3 patches are by Cunhao Lu and make CAN skb freeing safe in
any context in several CAN helper functions.

A series by Oliver Hartkopp et al fixes several problems in the CAN
net-layer:

Oliver Hartkopp contributes a patch to convert the unreliable
ARPHRD_CAN type check to the robust can_get_ml_priv(). Further a patch
that adds missing error checking to the bind callback of the CAN
ISO-TP protocol. Followed by converting the CAN RAW, BCM and ISO-TP
protocol to protect the receive lists with a per-device lock. Then the
RAW and ISO-TP protocols are converted to copy the socket options
outside of lock_sock().

3 patches target the CAN procfs: A patch by Runyu Xiao resets the CAN
pkg_stats using atomics, a patch by Oliver Hartkopp fixes the stats
calculation after a statistics reset. Followed by a patch to remove
kernel pointers from the output.

ChunYuZhiQiang contributes 2 patches for the CAN netlink interfaces,
to prevent waking up the CAN device, if the interface is down.

The last patch is by Liu Changjie and fixes the decoding of bulk USB
URBs in the Peak USB CAN driver.

linux-can-fixes-for-7.4-20261103

* tag 'linux-can-fixes-for-7.4-20261103' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: peak_usb: pcan_usb_fd_decode_buf(): accept short uCAN end-of-list records
  can: dev: can_tdc_fill_info(): don't read automatic TDCV if interface is down
  can: dev: can_fill_info(): don't wake up controller if interface is down
  can: proc: remove pointers from CAN specific proc output
  can: proc: skip stats calculation after reset in can_stat_update()
  can: proc: reset pkg_stats atomics individually
  can: raw, isotp: copy socket options outside of lock_sock()
  can: protect the receive lists with a per-device lock
  can: isotp: check the return values of can_rx_register() in isotp_bind()
  can: replace ARPHRD_CAN type checks with can_get_ml_priv()
  can: dev: can_put_echo_skb(): free skb on invalid echo index
  can: skb: make CAN skb allocation failure paths IRQ-safe
  can: skb: make echo skb freeing safe in any IRQ context
  can: isotp: check the frame type, not just the length
  can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
====================

Link: https://patch.msgid.link/20261103204305.3211144-1-mkl@pengutronix.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-05 09:21:43 +01:00
Paolo Abeni
6baae996ec Merge branch 'fix-tcp-retransmissions-on-ns-nsp-socs'
Florian Fainelli says:

====================
Fix TCP retransmissions on NS/NSP SoCs

On Northstar and Northstar Plus SoCs we would see about 1000 TCP
retransmissions per second due to a rate mismatch between bgmac and b53,
make sure that we run at the same speed on both side to avoid dropping
packets on the floor.

This issue was found during testing on a Northstar Plus reference board
(BCM958625HR) while running iperf3 to a test machine and noticing
retranmsisions:

Connecting to host 192.168.3.1, port 5201
[  4] local 192.168.3.204 port 49856 connected to 192.168.3.1 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  4]   0.00-1.00   sec   111 MBytes   933 Mbits/sec  915   99.0 KBytes
[  4]   1.00-2.00   sec   111 MBytes   928 Mbits/sec  909    109 KBytes
[  4]   2.00-3.00   sec   110 MBytes   925 Mbits/sec  1097   99.0 KBytes
[  4]   3.00-4.00   sec   111 MBytes   928 Mbits/sec  814   58.0 KBytes
[  4]   4.00-5.00   sec   111 MBytes   930 Mbits/sec  1187    109 KBytes
[  4]   5.00-6.00   sec   110 MBytes   923 Mbits/sec  893   72.1 KBytes
[  4]   6.00-7.00   sec   111 MBytes   929 Mbits/sec  843   67.9 KBytes
[  4]   7.00-8.00   sec   111 MBytes   928 Mbits/sec  920   79.2 KBytes
[  4]   8.00-9.00   sec   111 MBytes   929 Mbits/sec  1109   66.5 KBytes
[  4]   9.00-10.00  sec   111 MBytes   930 Mbits/sec  1055   63.6 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  4]   0.00-10.00  sec  1.09 GBytes   933 Mbits/sec  9742
sender
[  4]   0.00-10.01  sec  1.09 GBytes   933 Mbits/sec
receiver
====================

Link: https://patch.msgid.link/20261029211540.4123250-1-florian.fainelli@broadcom.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 22:18:47 +01:00
Florian Fainelli
41af383243 net: dsa: b53: restore the NSP IMP port 2 Gbps mode
The Northstar Plus IMP port uses the switch's proprietary 2 Gbps mode for
its internal link to the AMAC.  Its fixed-link description reports 1 Gbps,
so applying that speed clears PORT_OVERRIDE_SPEED_2000M and leaves the two
ends of the internal link configured at different speeds.

Force the 2 Gbps mode and flow control for BCM5301x and NSP CPU ports.  The
mismatch caused switch output queue discards on both copper and SerDes
ports, with one discard for every TCP retransmission.  With both ends
restored to their high-speed modes, iperf3 reports no retransmissions.

Fixes: b6a8a5477f ("net: dsa: b53: fix resetting speed and pause on forced link")
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261029211540.4123250-3-florian.fainelli@broadcom.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 22:18:44 +01:00
Florian Fainelli
d4f3d2c046 net: ethernet: bgmac: preserve forced 2.5 Gbps link speed
Northstar and Northstar Plus use a 2.5 Gbps internal link between the
AMAC and the switch.  BGMAC_FEAT_FORCE_SPEED_2500 makes bgmac_miiconfig()
configure that speed, but bgmac_adjust_link() subsequently replaces it
with the synthetic fixed PHY's 1 Gbps speed.

Use the forced speed when processing link changes so the MAC remains at
2.5 Gbps.  Together with configuring the switch IMP port for its 2 Gbps
mode, this eliminates the output queue discards that caused approximately
1000 TCP retransmissions per second during an iperf3 transmit test.

Restrict the platform forced-speed flag to Northstar Plus using the SoC
compatible, since Hurricane2 shares the AMAC compatible. Other platform
AMACs without a phy-handle must continue following the fixed PHY speed.
The BCMA path already selects the flag only for the Northstar family.

Fixes: f6a95a2495 ("net: ethernet: bgmac: Add platform device support")
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261029211540.4123250-2-florian.fainelli@broadcom.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 22:18:44 +01:00
Hengyu Liang
a75facf4bb l2tp: only return sessions of the given tunnel in l2tp_session_get()
Commit 5f77c18ea5 ("l2tp: use IDR for all session lookups") made
pppol2tp_connect() and the netlink session commands find sessions with
l2tp_session_get(), passing the socket of the tunnel they name.

L2TPv3 session IDs are unique per network namespace, except that
sessions carried over UDP are only unique per UDP socket, the socket of
their tunnel. However, l2tp_v3_session_get() only checks the socket when
another session has the same session ID. Otherwise it returns the
session, whichever tunnel it belongs to. As of now, a session command
that names the wrong tunnel acts on a session of another tunnel, and a
PPPoL2TP socket for a second L2TPv3 tunnel fails with EEXIST, because it
finds session 0 of the first tunnel.

The issue can be reproduced with:

    ip l2tp add tunnel tunnel_id 3 peer_tunnel_id 3 encap udp \
        local 127.0.0.1 remote 127.0.0.1 udp_sport 5003 udp_dport 6003
    ip l2tp add tunnel tunnel_id 4 peer_tunnel_id 4 encap udp \
        local 127.0.0.1 remote 127.0.0.1 udp_sport 5004 udp_dport 6004
    ip l2tp add session tunnel_id 3 session_id 7 peer_session_id 7
    ip l2tp del session tunnel_id 4 session_id 7
    ip l2tp show session

Before that commit, the delete fails with "No such device", and session
7 of tunnel 3 is still listed. After that commit, the delete succeeds,
and session 7 of tunnel 3 is gone.

This patch will make l2tp_session_get() return NULL when the L2TPv3
session it finds does not belong to the given socket. The receive path
calls l2tp_v3_session_get() directly and is not changed.

Fixes: 5f77c18ea5 ("l2tp: use IDR for all session lookups")
Cc: stable@vger.kernel.org
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
Acked-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20261030032617.4065353-1-hengyul@cs.unc.edu
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 22:11:09 +01:00
Amir Goldstein
db1c5da238 selftests/fscontext_ns: expect EINVAL for overlay descendant userns create
Commit a518e63c37 ("ovl: return EINVAL instead of EIO in case of
mismatched user_ns") changed the errno for completing an overlay
fscontext from another user namespace. Update the overlay test variant
to match binfmt_misc.

Reported-by: kernel test robot <yi1.lai@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202611020115.2281e158-lkp@intel.com
Fixes: a518e63c37 ("ovl: return EINVAL instead of EIO in case of mismatched user_ns")
Cc: stable@vger.kernel.org
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-04 21:47:48 +01:00
Chris Mason
520ef67f47 ovl: look up the index by the decoded origin
A file opened by file handle on an overlay with nfs_export=on can show
the stale lower data of a file that was copied up to the upper layer.
While the file opened this way stays in the inode cache, a lookup of the
copied up file by path fails with ESTALE for all users. The open can
also succeed for a file that was removed, where it has to fail with
ESTALE. This happens with a handle that has one byte changed. The handle
comes from an NFS client, or from a process that calls
open_by_handle_at() with CAP_DAC_READ_SEARCH in the initial user
namespace.

When a file in a lower layer is about to be modified, overlayfs first
copies it to the upper layer (copy up). With nfs_export=on, each copy up
also creates an entry in the index directory, a directory that overlayfs
keeps for itself on the upper filesystem.

The handle of an overlay file that comes from a lower layer wraps the
handle of its lower inode. Overlayfs calls this lower inode the origin.
The overlay handle stays valid after a copy up.

To decode such a handle, ovl_lower_fh_to_d() first decodes the wrapped
handle to the origin. If no overlay inode is cached for the origin, it
looks in the index directory:

- An index entry there leads to the upper file.
- A whiteout, the marker that overlayfs uses for a removed file, means
  that the overlay file was removed.

The name of an index entry is the handle that copy up encoded for the
origin, as a hex string.

ovl_lower_fh_to_d() builds the name for this lookup from the bytes that
the caller passed in. But handles with different bytes can decode to the
same inode:

- Overlayfs ignores some flag bits of the handle.
- A lower filesystem can accept a different fid type, extra bytes, or
  generation 0 for any generation.

Such a handle decodes to the origin but misses the index entry or the
whiteout. So the decode returns an overlay inode that has only the lower
file.

While that inode is cached, a path lookup of a copied up file fails with
ESTALE, since the upper file that the lookup finds does not match the
cached inode, which has none.

Reproduced on tmpfs and on ext4 with open_by_handle_at(), after a copy
up and a mount cycle. A handle in which one flag bit, the fid type, the
length or the generation was changed read the old lower data, and path
lookups returned ESTALE.

Fix this by re-encoding the decoded origin and building the index name
from that handle.

Fixes: f71bd9cfb6 ("ovl: decode indexed non-dir file handles")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-04 21:34:20 +01:00
Joas Antonio dos Santos
0389706606 tipc: raise the minimum bearer MTU to fit tunnel and crypto overhead
A peer can lower the link MTU to TIPC_MIN_BEARER_MTU (100 bytes, plus
the UDP encapsulation header) with the max_pkt field of a RESET or
ACTIVATE message; tipc_link_proto_rcv() only checks the lower bound
returned by tipc_bearer_min_mtu().  The same bound is applied to the
device MTU when a bearer is enabled.

That bound predates two later reductions of the link MSS:

  tipc_link_mss() = mtu - INT_H_SIZE                    (tunnel header)
                         - EMSG_OVERHEAD               (CONFIG_TIPC_CRYPTO)

With CONFIG_TIPC_CRYPTO=y, which is the default, an MTU of 100 gives an
MSS of 28.  Once the link comes up, tipc_named_node_up() calls
named_distribute(), which computes

  msg_dsz = ((tipc_node_get_mtu() - INT_H_SIZE) / ITEM_SIZE) * ITEM_SIZE;

For an MSS of 28 the subtraction is negative and the result truncates to
0xfffffff0; for an MSS between 40 and 59 it is 0.  named_prepare_buf()
then allocates a buffer with no room for any item (the u32 size wraps),
and msg_rem never reaches zero, so every cluster-scope publication on
the node is written with publ_to_item() past the end of that one skb,
over skb_shared_info and into adjacent memory.

Without crypto the MSS is at least 60, which still does not hold the
first fragment built by tipc_msg_build(): INT_H_SIZE fragment header
plus a message header of up to MAX_H_SIZE.  With pktmax below that, the
header copies run past the pktmax bytes allocated for the fragment.

Raise TIPC_MIN_BEARER_MTU to MAX_H_SIZE + 2 * INT_H_SIZE so the MSS can
always hold INT_H_SIZE + MAX_H_SIZE, which also leaves room for name
table items, and add tipc_bearer_mtu_floor(), which adds EMSG_OVERHEAD
on top for CONFIG_TIPC_CRYPTO=y.  Use it for the device MTU check
(tipc_mtu_bad()), the UDP MTU check, the netlink MTU setting and
tipc_bearer_min_mtu(), which also bounds the max_pkt negotiation.

Found by manual code review and reproduced with KASAN using two network
namespaces joined by a veth pair (see below).

Fixes: fc1b6d6de2 ("tipc: introduce TIPC encryption & authentication")
Fixes: 2320bcdae6 ("tipc: fix changeover issues due to large packet")
Suggested-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com>
Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Link: https://patch.msgid.link/179340438471.4412.6707287163192409104@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:55:53 +01:00
Yilin Zhang
6d2cf411ab mptcp: do not use Fast Open on MP_JOIN subflows
tcp_fastopen_create_child() hands the SYN packet itself to
subflow_syn_recv_sock(). For an MP_JOIN request this takes the
fatal fallback: the cloned child is destroyed and handed back with
drop_req flagged, but tcp_fastopen_create_child() does not check
the flag and queues it, so accept() can expose the freed child.

MP_JOIN cannot use Fast Open: data on a subflow requires the
completed HMAC exchange (RFC 8684, sec. 3.2). Refuse it (only the
TFO path passes a SYN skb here) and let tcp_conn_request() fall
back to the regular MP_JOIN handshake; also strip the Fast Open
cookie from MP_JOIN SYN/ACKs.

Fixes: 90bf45134d ("mptcp: add new sock flag to deal with join subflows")
Cc: stable@vger.kernel.org
Reported-by: Kimi Security Team <bug-report@moonshot.ai>
Suggested-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Yilin Zhang <yilinzhang@moonshot.ai>
[ Moving code to avoid clearing TS and consolidating checks. ]
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20261030-mptcp-tfo-mpj-v4-1-e6eff2027342@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:49:14 +01:00
Guenter Roeck
e395bbf3dd hwmon: (asus_rog_ryujin) Fix timeout when reading 0% duty cycle
The device uses the same zero-duty report format for both legitimate 0%
duty GET responses and SET confirmation ACKs on cooler and controller
duty channels. To distinguish them, rog_ryujin_raw_event() checks
!completion_done() on cooler_duty_set and controller_duty_set, assuming
this is only true while a SET command is awaiting confirmation.

However, init_completion() initializes the completion count to zero, so
!completion_done() evaluates to true from probe until the first SET
command completes. Likewise, if rog_ryujin_execute_cmd() fails to send a
command, times out, or is interrupted after reinit_completion(), the
completion remains uncompleted. When a valid 0% duty GET response then
arrives, rog_ryujin_raw_event() consumes it as a SET confirmation and
leaves the pending *_duty_received completion uncompleted, causing
rog_ryujin_execute_cmd() to wait 1.5 seconds and fail with -ETIMEDOUT.

Mark all completions as done with complete_all() after initialization in
rog_ryujin_probe(), and complete status_completion on error in
rog_ryujin_execute_cmd(), so !completion_done() is only true while a
command is actively awaiting a response.

Fixes: ed3e03790c ("hwmon: Add driver for ASUS ROG RYUJIN II 360 AIO cooler")
Cc: Aleksa Savic <savicaleksa83@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-04 06:43:35 -08:00
Eric Dumazet
8e069fd3fd tcp: ipv6: do not read ireq->pktopts from tcp_v6_send_synack()
When IPV6_FL_F_REFLECT is set on a listener, or the
net.ipv6.flowlabel_reflect sysctl has FLOWLABEL_REFLECT_ESTABLISHED,
tcp_v6_send_synack() reflects the flowlabel of the SYN packet,
reading it from the skb stored in ireq->pktopts.

Since commit 079096f103 ("tcp/dccp: install syn_recv requests
into ehash table"), request sockets are processed without holding
the listener lock. A cpu can then process a retransmitted SYN for a
request socket, and send a SYNACK from tcp_check_req(), while another
cpu receives the ACK completing the 3WHS. tcp_v6_syn_recv_sock()
consumes ireq->pktopts when it wins the hashdance, and the first cpu
reads a freed skb:

  BUG: KASAN: slab-use-after-free in tcp_v6_send_synack (include/linux/skbuff.h:3152 include/linux/ipv6.h:110 net/ipv6/tcp_ipv6.c:582)
  Read of size 8 at addr ffff88802b08b608 by task poc-ipv6-pktopt/5076

  Call Trace:
   <IRQ>
   tcp_v6_send_synack (include/linux/skbuff.h:3152 include/linux/ipv6.h:110 net/ipv6/tcp_ipv6.c:582)
   tcp_rtx_synack (net/ipv4/tcp_output.c:4719)
   tcp_check_req (net/ipv4/tcp_minisocks.c:762)
   tcp_v6_rcv (net/ipv6/tcp_ipv6.c:1826)
   ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
   ip6_input_finish (net/ipv6/ip6_input.c:534)
   ip6_input (include/linux/netfilter.h:325 include/linux/netfilter.h:319 net/ipv6/ip6_input.c:545)
   ipv6_rcv (include/net/dst.h:481 net/ipv6/ip6_input.c:119 include/linux/netfilter.h:325 include/linux/netfilter.h:319 net/ipv6/ip6_input.c:351)

  Freed by task 5074 on cpu 0 at 15.412249s:
   kmem_cache_free (include/linux/kasan.h:235 mm/slub.c:2780 mm/slub.c:6630 mm/slub.c:6757)
   tcp_v6_syn_recv_sock (net/ipv6/tcp_ipv6.c:1528)
   tcp_check_req (net/ipv4/tcp_minisocks.c:934)
   tcp_v6_rcv (net/ipv6/tcp_ipv6.c:1826)
   ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
   ip6_input_finish (net/ipv6/ip6_input.c:534)

Request socket migration has the same issue: reqsk_migrate_reset()
transfers ireq->pktopts to the clone, which can be freed while
another cpu holding a reference on the old request socket is still
sending a SYNACK.

The SYNACK timer itself is not an issue, because
inet_csk_reqsk_queue_drop() calls timer_delete_sync().

Save the flowlabel of the SYN in the request socket instead, so that
tcp_v6_send_synack() no longer needs ireq->pktopts.

As a side effect, the flowlabel is also reflected for SYN packets
reusing a TIME_WAIT socket, as ireq->pktopts is not set in this case.

Fixes: e994b2f0fb ("tcp: do not lock listener to process SYN packets")
Fixes: 079096f103 ("tcp/dccp: install syn_recv requests into ehash table")
Fixes: c905dee622 ("tcp: Migrate TCP_NEW_SYN_RECV requests at retransmitting SYN+ACKs.")
Reported-by: Anvik Loitongbam <permissiontogallop@gmail.com>
Reported-by: Yingjie Wang <x-professor@outlook.com>
Closes: https://lore.kernel.org/netdev/82c31e4d5043f3dbd11b44177cfba779d335aae3.1793599929.git.x-professor@outlook.com/
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261102075441.3771550-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:42:05 +01:00
Paolo Abeni
58fa96691c Merge branch 'ip-fix-route-leak-and-unregister_netdevice-stuck'
Kuniyuki Iwashima says:

====================
ip: Fix route leak and unregister_netdevice() stuck.

Jason Zhang fed commit 0346ec2f08 ("ipv6: Prevent
rt6_insert_exception() for dying fib6_info.") to LLM to
find tricks to cause the same symptom:

  unregister_netdevice: waiting for gre6 to become free. Usage count = 4
  ref_tracker: netdev@000000009652f190 has 1/3 users at
       dst_alloc+0x14b/0x490
       ip6_rt_cache_alloc+0x27b/0x670
       __ip6_rt_update_pmtu+0x572/0x850

This series treats them.
====================

Link: https://patch.msgid.link/20261101064418.2055158-1-kuniyu@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:34:53 +01:00
Kuniyuki Iwashima
4019af3afd ipv4: Call rt_add_uncached_list() if !do_cache in ip_route_input_slow().
Since the cited commit, ip_route_input_slow() could call
rt_dst_alloc() with vrf in the local_input: path.

If res->fi != NULL and one of the following is true,

  - a non-zero itag from fib_validate_source_reason()
    (realms/classid)
  - RTN_BROADCAST with BC_FORWARDING enabled

do_cache is set to false.

Then, the route is not added to rt_uncached_list, so the
route cannot be removed from rt_flush_dev().

If the route is cached in sk->sk_rx_dst, removing the
vrf device gets stuck. [0]

Let's call rt_add_uncached_list() if !do_cache in
ip_route_input_slow().

[0]:
unregister_netdevice: waiting for vrf0 to become free. Usage count = 2
ref_tracker: netdev@000000008b304ac4 has 1/1 users at
     dst_alloc+0x14b/0x490
     ip_route_input_rcu+0x1540/0x2530
     ip_route_input_noref+0x5a/0x90
     ip_rcv_finish_core+0x4b0/0x1140
     ip_rcv_finish+0xe6/0x190
     ip_rcv+0x6c/0x130
     __netif_receive_skb+0x121/0x300
     process_backlog+0x2df/0x5e0
     __napi_poll+0x8c/0x380
     net_rx_action+0x43c/0xab0
     handle_softirqs+0x19f/0x520
     do_softirq+0x46/0x60
     __local_bh_enable_ip+0x79/0x80
     __dev_queue_xmit+0x1b0e/0x24c0
     ip_finish_output2+0x8b2/0xcd0
     ip_output+0xf2/0x1e0

Fixes: f5a0aab84b ("net: ipv4: dst for local input routes should use l3mdev if relevant")
Reported-by: Jason Zhang <jdz@google.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261101064418.2055158-4-kuniyu@google.com
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:34:50 +01:00
Kuniyuki Iwashima
a0fe1a3f39 ipv6: Flush rt->from in rt6_uncached_list_flush_dev().
When a device is unregistered, rt6_uncached_list_flush_dev()
iterates over uncached routes and switches the dying dev
with blackhole_netdev.

However, rt->from could be cached via sk->sk_rx_dst and
hold the device reference.

Then, unregister_netdevice() gets stuck with the splat
below. [0]

Let's release rt->from in rt6_uncached_list_flush_dev().

Note that ip6_rt_copy_init() could set rt->from even if
in6_dev_get() returns NULL (e.g. mtu < IPV6_MIN_MTU is
set concurrently).

Also, rt->from->nh could be replaced with another device
than rt_dev and rt_idev->dev, and in such a case,
nexthop_flush_dev() sets fib6_destroying before
rt6_uncached_list_flush_dev().

[0]:
unregister_netdevice: waiting for dummy2 to become free. Usage count = 2
ref_tracker: netdev@000000006fb9da8c has 1/1 users at
     netdev_get_by_index+0x14c/0x170
     fib6_nh_init+0x1ae/0x1950
     ip6_route_info_create_nh+0x15d/0x780
     ip6_route_add+0x55/0x150
     inet6_rtm_newroute+0x15d/0x1360
     rtnetlink_rcv_msg+0x606/0x710
     netlink_rcv_skb+0x14f/0x2f0
     netlink_unicast+0x71b/0x940
     netlink_sendmsg+0x595/0x840
     __sock_sendmsg+0x119/0x150
     ____sys_sendmsg+0x3e9/0x5c0
     ___sys_sendmsg+0x157/0x1a0
     __x64_sys_sendmsg+0x119/0x170
     do_syscall_64+0x109/0x330
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

Fixes: 93531c6743 ("net/ipv6: separate handling of FIB entries from dst based routes")
Reported-by: Jason Zhang <jdz@google.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261101064418.2055158-3-kuniyu@google.com
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:34:50 +01:00
Kuniyuki Iwashima
9401b428b5 ipv6: Flush exception route while replacing nexthop.
The following creates a cyclic reference between IPv6 route
and nexthop:

  1. create a nexthop A
  2. create a nexthop group w/ A
  3. create an IPv6 route with the nexthop group
  4. create an exception route w/ A
  5. replace A with a new nexthop B in the nexthop group
  6. remove the IPv6 route
  7. replace B with A in the nexthop group
  8. remove the nexthop group

Then, removing a device tied to the route gets stuck and
triggers the splat below. [0]

At 5., fib6_nh_release_dsts() is called, but it does not
flush exception routes, so the nexthop A continues to grab
the IPv6 route reference.

  nh_A->rt6i_exception_bucket[] -> rt6_ex->rt6i->from

At 6., fib6_purge_rt() calls rt6_flush_exceptions(), but it
only purges exceptions tied to nexthop B.  Also, the route is
unlinked from the nexthop group by list_del_init(&rt->nh_list).

  -> f6i->nh -> nhg->nh_entries[]

At 8., __remove_nexthop_fib() cannot find the IPv6 route, and
remove_nexthop_group() calls list_del_init(&nhge->nh_list) to
unlink the group from the nexthop A's nhe->grp_list.

  nhg->nh_entries[] -> nh_A -> ... -> f6i

Here, the nexthop A is reachable from net->nexthop.devhash[],
but remove_nexthop_from_groups() cannot find the nexthop group,
leaking the whole chain.

Let's call fib6_nh_flush_exceptions() in fib6_nh_release_dsts().

[0]:
unregister_netdevice: waiting for gre6 to become free. Usage count = 4
ref_tracker: netdev@000000009652f190 has 1/3 users at
     dst_alloc+0x14b/0x490
     ip6_rt_cache_alloc+0x27b/0x670
     __ip6_rt_update_pmtu+0x572/0x850
     ip6_tnl_xmit+0x8c5/0x1b70
     __gre6_xmit+0x7af/0xaa0
     ip6gre_tunnel_xmit+0x685/0xdc0
     dev_hard_start_xmit+0x204/0x5a0
     __dev_queue_xmit+0xe8a/0x2550
     ip6_finish_output+0x232/0x570
     ip6_output+0x226/0x3b0
     ip6_send_skb+0x133/0x250
     rawv6_push_pending_frames+0x503/0x6f0
     rawv6_sendmsg+0xdf0/0x1310
     sock_sendmsg_nosec+0xde/0x130
     __sys_sendto+0x27f/0x320
     __x64_sys_sendto+0xd9/0xf0

Fixes: 7bf4796dd0 ("nexthops: add support for replace")
Reported-by: Jason Zhang <jdz@google.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261101064418.2055158-2-kuniyu@google.com
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:34:50 +01:00
Daehyeon Ko
d5e912448c vhost/vsock: size receive SKBs from declared payload
vhost_vsock_alloc_skb() sizes the skb from iov_length(), the total guest
descriptor length.  virtio_transport_inc_rx_pkt() instead adds hdr->len to
rx_bytes and buf_used, and budgets each queued skb as SKB_TRUESIZE(0).  The
guest controls the descriptor length and hdr->len independently.

A guest can therefore provide a 64 KiB descriptor while declaring a zero
payload.  The descriptor-sized skb remains queued, rx_bytes and buf_used
remain unchanged, and only the fixed queue-entry budget limits retention.
This is not a lifetime leak: the skb is freed when dequeued or at socket
teardown.  Repeating this across connections can nevertheless exhaust host
memory.  On Linux v7.2, 455 such descriptors retained 30,255,680 bytes for
a 262,144-byte receive buffer; a full-payload control retained 265,984
bytes.

Vhost previously read hdr->len and allocated pkt->buf from that value.  The
conversion from virtio_vsock_pkt to sk_buff instead allocated receive skbs
from the descriptor length, introducing the allocation-accounting mismatch.

Copy the header into a stack object and validate hdr->len before allocating
the skb.  Size the allocation as sizeof(hdr) + payload_len so descriptor
capacity no longer determines queued memory.  Check payload_len against
len - sizeof(hdr) to avoid addition overflow on 32-bit hosts.

Fixes: 71dc9ec9ac ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
Cc: stable@vger.kernel.org
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/20261004235101.1464007-1-4ncienth@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:23:27 +01:00
Avi Weiss
24614e72df net: skbuff: reject zero MPLS TTL before decrementing
skb_mpls_dec_ttl() decrements the u8 TTL before checking whether it
expired. An incoming TTL of zero wraps to 255, causing the TC MPLS
dec_ttl action to pass an expired packet instead of dropping it.

Reject a zero TTL before the decrement while preserving the existing
behavior for TTL one and valid TTL values.

Fixes: 2a2ea50870 ("net: sched: add mpls manipulation actions to TC")
Signed-off-by: Avi Weiss <thnkslprpt@gmail.com>
Reviewed-by: Xia Yan <yanxia@cmss.chinamobile.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261031114135.3784868-2-thnkslprpt@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:21:07 +01:00
Paolo Abeni
c4328134f3 A few fixes to start with:
- wext: fix notifier netns interaction
  - rsi: avoid TID OOB access
  - mac80211: reload pointer, fix A-MPDU flags
  - brcmfmac: fix DMA regression
  - cfg80211: fix regdb validation
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmroaaMACgkQ10qiO8sP
 aACgfg/8D6WdzZKyj+piglNv7ZfuNthkKTzQmEY85MD4e4JwZG6q0AMW9/diR+XT
 7E6dgXI0LWvMYbeHWBeF22Fkf1YKqtm+gNRzffkzRqRKMooSqNGeBNbbmiEhHe2A
 ti7I4CvkHCjAv8ko+wVm7YW/POtWFICAb0llOI6/vjaYRvUm0RiIHjGhAM4vZC9c
 NM0rDFZIWxamXf2QjUEDKTzsouo00UzxEDc6KCsJG252g7HksTnd0TFXKj2HpA8N
 SzK5g6seVLx8On4ybjhz+pBa814DKc8JYHMiGkuf9KjHVgKR+7x9fi+nynnsZOJ4
 LLZjkXMkZLaPiEq/TV9z8eAtZ4+jkC5z2N/hNbhrZf9T/qqOUv/uJ8blURqhywol
 ZRbXKZXtWjsn+OvpJhpZ0TjyQKHWSk+AaDWHjDs1kK07et4GQ0z67rEyYSNX42G8
 VgHVf8XYX4vaQQOg1+XMiEVxVb4k1UwF51dYhk/qIn9JS55FI3ObVdFVf3p++jKZ
 q6HDUmWuBIE0DyA0RGlSnkcxuzxUW+AJkD4dfZHWXYA+BgElx7Wq72KoFNDw/s6k
 xWXdbBsFOjMuaGP8e6SmKrQXAptQylZ5VEBDY4KSIxScH7UBtBUvY2TudiKIfNSm
 X/GYBvfhEpsX8fHXA41Nm++hap1oXZujsPR0dm2iCqTkfzYUWBM=
 =pZ1u
 -----END PGP SIGNATURE-----

Merge tag 'wireless-2026-11-02' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless

Johannes Berg says:

====================
A few fixes to start with:
 - wext: fix notifier netns interaction
 - rsi: avoid TID OOB access
 - mac80211: reload pointer, fix A-MPDU flags
 - brcmfmac: fix DMA regression
 - cfg80211: fix regdb validation

* tag 'wireless-2026-11-02' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless:
  wifi: mac80211: reinstate IEEE80211_TX_CTL_AMPDU flag in ieee80211_tx_prep_agg()
  wifi: cfg80211: fix out-of-bounds read in valid_rule()
  wifi: rsi: Skip TX aggregation setup for non-QoS frames
  wifi: wext: Limit notifier event flushes to the device's netns
  wifi: brcmfmac: map msgbuf RX packet IDs bidirectional
  wifi: mac80211: reload TDLS header pointer after skb_linearize()
====================

Link: https://patch.msgid.link/20261102104649.727621-3-johannes@sipsolutions.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 15:00:50 +01:00
Guillaume Nault
11140c51df tcp: Fix dup-ack detection on non-SACK bidirectional data transfer.
When receiving a pure ack from a peer that also sends data, we can
have SEG.SEQ > SND.WL1, even though the segment contains no data. This
makes tcp_may_update_window() return true (because of the
"after(ack_seq, tp->snd_wl1)" condition), and tcp_ack_update_window()
then adds FLAG_WIN_UPDATE to the segment set of flags, even when
there's no window update.

Since FLAG_WIN_UPDATE prevents the segment from being considered as
dup-ack (as it's part of FLAG_NOT_DUP), this can inhibit fast
retransmit on non-SACK connections, making recovery very slow as it
now entirely relies on RTO.

The "DUPLICATE ACKNOWLEDGMENT" definition of RFC 5681, section 2,
says that lack of window update is a necessary condition for a dup ack:
"(e) the advertised window in the incoming acknowledgment equals the
advertised window in the last incoming acknowledgment.". Spurious
window updates can thus prevent dup ack detection and, in the end, fast
retransmit.

Avoid this scenario by setting FLAG_WIN_UPDATE only when a window
update actually occurs. Pure acks with SEG.SEQ > SND.WL1 can now
be detected as dup-ack and trigger fast retransmission.

Also, stop setting FLAG_WIN_UPDATE in tcp_ack()'s header prediction
path. One of the conditions for header prediction to happen is that
received segments don't trigger a window update. This flag update was
thus wrong to begin with. Now that tcp_ack_update_window() sets
FLAG_WIN_UPDATE only if a window update actually occurred, we need the
header prediction path to stop reporting spurious window updates too.
Otherwise BPF programs would get inconsistent window update information
(CA_ACK_WIN_UPDATE) between fast an slow paths.

Finally, add FLAG_SND_UNA_ADVANCED to the definition of FLAG_NOT_DUP.
This is necessary for the case where an incoming segment acknowledges
less than a full segment of the retransmit queue. Such segments were
not considered dubious by tcp_ack_is_dubious() because of the spurious
FLAG_WIN_UPDATE flag, which prevented the segment from being seen as a
duplicate ack. Now that FLAG_WIN_UPDATE doesn't cover this scenario
anymore, we need another way to mark these acks as non-duplicate.
Adding FLAG_SND_UNA_ADVANCED to FLAG_NOT_DUP is the natural way of
doing this, since, by definition, a segment advancing SND.UNA, even by
a small amount, cannot be a duplicate ack.

A side effect of this patch is that repeated zero window acks received
from peer can now be considered duplicate acks (because of the the
"|| !win" condition in tcp_may_update_window()). Therefore, they can
now trigger fast retransmission and fast recovery, including congestion
window reduction, when the peer is stalled. This is RFC compliant and
shouldn't have any negative effect.

Add packetdrill selftest. Before this patch, the 1001:2001 segment was
retransmitted upon RTO, now it's sent right after reception of the
third duplicate ack.

Thanks to Tom Williams for the investigation help and initial
reproducer.

Reported-by: Tom Williams <Tom.D.Williams@MorganStanley.com>
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Link: https://patch.msgid.link/6426d558e45fc6ab724c40af62e4a8793215dd8a.1793219189.git.gnault@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 14:46:35 +01:00
Alexei Starovoitov
35d2d6e5ac net: reject a negative TCP header offset in qdisc_pkt_len_segs_init()
qdisc_pkt_len_segs_init() stores skb_transport_offset(), or the inner
offset, in the unsigned hdr_len. A header in front of skb->data gives a
negative offset. For an offset a little below zero, pskb_may_pull() gets a
small length and succeeds. Then a 64-bit kernel reads the TCP header far
after the skb and can crash. Further below zero pskb_may_pull() fails.

Commit 28a57fb2c5 ("net: iptunnel: fix stale transport header during
tunnel decapsulation") fixed one source of such offsets. Other code that
removes bytes from the front of a packet can leave the same stale header.

Return SKB_DROP_REASON_SKB_BAD_GSO for a negative offset in the TCP branch.
SKB_GSO_UDP_L4 and the other GSO types read no header and still get a wrong
qdisc_pkt_len(). On a 64-bit kernel only packets that cause the read after
the skb today get a new result. Then __dev_queue_xmit() drops them and
returns -EINVAL, but sch_handle_ingress() ignores the result. Their content
can be valid. Thus the code that leaves the header stale needs its own fix.

Fixes: 7fb4c19670 ("net: pull headers in qdisc_pkt_len_segs_init()")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
CC: stable@vger.kernel.org
Link: https://patch.msgid.link/20261101194433.2637113-1-alexei.starovoitov@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-04 13:25:05 +01:00
Hungyu Lin
0cbfc16fe4 isofs: handle Rock Ridge long-form dates before 1900
iso_date() stores the year relative to 1900 and rejects negative values.
Rock Ridge LONG_FORM timestamps encode calendar years from 1 to 9999,
so valid years before 1900 are returned as seconds since the Unix epoch
equal to zero instead of their recorded dates. For example, an 1899
timestamp on an image produced by xorriso is reported as 1970 by stat,
and cp -p preserves that incorrect time.

Use the calendar year for both timestamp formats and pass it directly
to mktime64(). Keep the epoch fallback for year zero, while allowing
valid long-form years before 1900. Short-form dates are unchanged.

Fixes: 5ea45f54c8 ("isofs: fix Y2038 and Y2156 issues in Rock Ridge TF entry")
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Link: https://patch.msgid.link/20261029004902.76944-1-dennylin0707@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-04 13:23:30 +01:00
Sasha Levin
57d94d26ed selftests/configfs: fix the build on 32-bit architectures
The fixture setup checks the result of mkdtemp() with ASSERT_NE(), which
hands the pointer to the harness. The harness casts both operands to
intmax_t to print them, and on 32-bit architectures gcc warns about the
cast from a pointer to an integer of a different size. The configfs
test builds with -Werror, so it fails to build there:

  kselftest_harness.h:797:49: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]

Compare the result against NULL inside ASSERT_TRUE(), so that the
harness only sees an int.

Fixes: a7fdcb2edd ("selftests/configfs: add tests for the userspace interface")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Reviewed-by: Breno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20261103141627.30838-1-sashal@kernel.org
Signed-off-by: Breno Leitao <leitao@debian.org>
2026-11-04 03:09:57 -08:00
Joseph Kain
241dec6f9a net: stop defer_count outliving the deferred-free list
After the llist conversion, rejected frees retain their counter
increments. A producer racing the counter reset and list detach can
also leave a count for an skb already drained. Deferred freeing can
then remain disabled while the list is empty.

Undo rejected reservations and subtract only the number of skbs
drained. Allow admission up to the configured limit. Retain the
halfway notification and also notify when the reserved count reaches
the limit, covering reservations published after an earlier purge.

Fixes: 844c9db7f7 ("net: use llist for sd->defer_list")
Signed-off-by: Joseph Kain <jkain@nuro.ai>
Assisted-by: LLM
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-04 08:43:21 +00:00
James Clark
3f1054a0cb net: ethernet: ti: am65-cpts: adjust perout genf following ptp changes
A periodic output requested by PTP_PEROUT_REQUEST2 drifts away from
the PHC as soon as the PHC frequency is adjusted, for example by ptp4l
or ts2phc: at +10 ppm each edge is 10 us later than the one before.

The GenF that generates the output counts its period in ref_clk
cycles, which the PPM correction of the CPTS clock does not reach;
each GenF has its own PPM registers. am65_cpts_ptp_adjfine() programs
them only for the GenF used for PPS, and am65_cpts_perout_enable_hw()
starts every GenF with them cleared, so a GenF used for a periodic
output is never corrected.

Commit eb9233ce67 ("net: ethernet: ti: am65-cpts: adjust pps following
ptp changes") added the correction for the PPS GenF, and
commit 7849c42da2 ("net: ethernet: ti: am65-cpts: adjust estf following
ptp changes") passed the same values to the ESTFs.

In am65_cpts_ptp_adjfine(), update every enabled GenF the way the PPS
GenF was updated: read its control register, set or clear the PPM
direction bit and write it back with the PPM value. The PPS GenF and the
ESTFs get exactly the values they got before. In
am65_cpts_perout_enable_hw(), start a GenF with the current correction
instead of none; this applies to the PPS GenF too.

Tested on a BeagleY-AI (J722S) with the GENF0 output looped back to
the HW1_TS_PUSH input (EXTTS 0). With the PHC frequency adjusted by
+10 ppm before the periodic output is started, the edges drift 10 us
per second against the PHC without this patch (290 us after 29 s);
with it, they stay 20 to 23 ns after the PHC second. This also works
if the frequency is adjusted after the periodic output has started.

Fixes: f6bd59526c ("net: ethernet: ti: introduce am654 common platform time sync driver")
Signed-off-by: James Clark <jjc@jclark.com>
Reviewed-by: Jacob Keller <Jacob.e.keller@intel.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-04 07:57:26 +00:00
Amir Goldstein
9ff338af0e ovl: inherit FMODE_NONOTIFY when reading directory layers
Listing a merged or impure overlay directory opens the real layer
directories from ovl_dir_read(), when the readdir cache is filled.
Those opens use plain ovl_path_open(), so when the directory fd is
one that fanotify created for a permission event, they can still raise
FS_OPEN_PERM.  A listener that also marks the backing filesystem and
calls getdents() on the event fd before answering then deadlocks the
same way as with the directory open fixed by the previous commit.

Store the overlay user file in struct ovl_readdir_data and pass it to
ovl_path_open_realfile() from ovl_dir_read(), for both the merged and
the impure cache.  Internal readers such as ovl_check_empty_dir() and
the mount-time workdir cleanup still pass no user file.

A note about severity and real world impact: The FAN_OPEN_PERM event is
traditionally used by anti-malware protection agents and security/audit
agents. The scope that is often used in those use cases is FAN_MARK_MOUNT
and agents typically monitor multiple mounts in a mount namespace.
FAN_OPEN_PERM from directory open requires user opt-in with FAN_ONDIR.
It is often not the case that anti-malware agents monitor open of
directories. Security/audit engines are more likely to opt-into
FAN_OPEN_PERM on directories, but are less likely to list the content
of a directory within the scope of FAN_OPEN_PERM event, so the real
world impact of this bug is likely not significant.

Reported-by: Edvard Conrad <edvard@tuta.io>
Closes: https://lore.kernel.org/all/P5Qu3co--N-9@tuta.io/
Cc: stable@vger.kernel.org
Tested-by: Edvard Conrad <edvard@tuta.io>
Link: https://lore.kernel.org/ltp/P5WKBbq--F-9@tuta.io/
Co-developed-by: Edvard Conrad <edvard@tuta.io>
Signed-off-by: Edvard Conrad <edvard@tuta.io>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-04 08:05:13 +01:00
Amir Goldstein
323899b4ed ovl: inherit FMODE_NONOTIFY when opening directory realfiles
When fanotify hands a listener an fd for a permission event on an
overlay directory, ovl_dir_open_realfile() opens the real directory via
dentry_open(), not backing_file_open(), so the lower open could still
raise FS_OPEN_PERM and deadlock a listener that also marks the backing
filesystem.

Export dentry_open_nonotify() and call it from ovl_path_open_realfile()
when the overlay user file must not generate events.  Ordinary
ovl_path_open() callers are unchanged.

Reported-by: Christian Brauner (Amutable) <brauner@kernel.org>
Closes: https://lore.kernel.org/all/20261030-welpen-anbinden-nullen-b2432cee1d10@brauner/
Fixes: 130fdbc3d1 ("ovl: pass correct flags for opening real directory")
Cc: stable@vger.kernel.org
Tested-by: Edvard Conrad <edvard@tuta.io>
Link: https://lore.kernel.org/ltp/P5Iny41--F-9@tuta.io/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-04 07:52:46 +01:00
Eric Dumazet
787268686c ipmr, ip6mr: queue netlink route queries out of band
ipmr_get_route() and ip6mr_get_route() queue synthetic skbs on the
unresolved MFC entry to answer RTM_GETROUTE requests once the route
is resolved. These skbs carry a fake IP header with version 0, and
ipmr_cache_resolve(), ipmr_destroy_unres(), ip6mr_cache_resolve()
and ip6mr_destroy_unres() rely on this in-band tag to tell them
apart from regular packets queued by the input and output paths.

The IP version is only validated once, in ip_rcv_core() and
ip6_rcv_core(). A netfilter hook running later, for instance an
nftables payload statement in a PREROUTING chain owned by an
unprivileged user namespace, can rewrite the first header byte to
zero. The SRv6 End.DX6 action also passes the decapsulated packet
to ip6_mr_input() without checking that the inner header version
is 6. If no MFC entry exists, the packet is queued and later handled
as a netlink request: its payload is treated as an nlmsghdr and
written to, mr_fill_mroute() may call skb_put() on a nonlinear skb
(hitting SKB_LINEAR_ASSERT()), and the skb is unicast to a netlink
portid taken from stale IPCB/IP6CB bytes in skb->cb[].

ipmr_cache_report() also relies on the same tag since
commit 94a6736bb5 ("ipmr: only copy pktinfo to cache reports").

Stop trusting packet contents: queue route queries on a dedicated
nl_queries list in the unresolved MFC entry, and pass an explicit
nl_query flag from the callers.

The per-entry limit of four queued skbs now applies to both lists
combined, as before. The synthetic header keeps version 0, since it
is copied into the NOCACHE report delivered to the mroute socket.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Fixes: 7bc570c8b4 ("[IPV6] MROUTE: Support multicast forwarding.")
Reported-by: Katherine Leaver <kleaver@janestreet.com>
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261030092303.2749386-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 22:30:55 +01:00
Jamal Hadi Salim
f19f2b308b net/sched: clamp skb->queue_mapping before indexing the tx queue
This issue was caught by Sashiko (nipa). A producer-side path cap is
already merged (ea4d4b5ddd); this patch adds the matching consumer-side
caps.

The issue:
The tx queue is picked and capped in netdev_core_pick_tx() before the
__dev_xmit_skb() qdisc enqueue path. A tc BPF program running inside an
egress qdisc (not clsact) can then change __sk_buff->queue_mapping; that
store is never re-checked. bpf_convert_ctx_access() bounds it only by
NO_QUEUE_MAPPING, not by the device's queue count.

Two consumers read the stale value:

  - On dequeue, qdisc_restart() calls netdev_get_tx_queue(), which
    indexes dev->_tx[]. netdev_get_tx_queue() guards it with just a
    DEBUG_NET_WARN_ON_ONCE, so sch_direct_xmit() takes the out-of-bounds
    txq->_xmit_lock and writes txq->xmit_lock_owner past the end of the
    allocation on non-lltx devices such as ifb. Drivers that index their
    rings from skb_get_queue_mapping() (ex: ifb) go out of range the same
    way.

  - On enqueue, taprio_enqueue() indexes q->qdiscs[] with the same value;
    the array is sized dev->num_tx_queues. A duplicating netem on a child
    qdisc clones the skb and re-enqueues the clone at the taprio root
    (qdisc_root_bh()) through a direct rootq->enqueue() call, so the value
    reaches taprio_enqueue() before any dequeue cap runs.

The Fix:
Cap the mapping at the consumers and write the capped value back, so the
qdisc's _tx[] lookup, the taprio q->qdiscs[] lookup and any later driver
read stay in range.

On the dequeue side the cap folds into the dequeue path instead of a
separate walk over the returned list: dequeue_skb() caps the head, and
each bulk helper caps the element it appends. For a qdisc that is not
TCQ_F_ONETXQUEUE, netdev_cap_txqueue() logs a ratelimited notice and
selects queue 0.

A TCQ_F_ONETXQUEUE qdisc is bound to a single tx queue: dequeue_skb() uses
q->dev_queue for the frozen check, the BQL limit and the trace point, while
qdisc_restart() transmits on the skb's queue. Capping an out-of-range
mapping to queue 0 would therefore send a per-queue child's skb through a
different queue than the one it was dequeued for. On mq, mqprio, taprio and
htb offload children, a stopped queue 0 could then park the list in
q->gso_skb, and the later wake would schedule queue 0's own child instead
of this qdisc. Pin a TCQ_F_ONETXQUEUE mapping to the qdisc's own queue to
keep the documented invariant.

The pin covers every mapping, not only an out-of-range one: an in-range
mapping that a filter sets on one of those per-queue children is rewritten
to the child's own queue, and this path does not call netdev_cap_txqueue(),
so it logs no notice. On a single-queue device qdisc_create() sets
TCQ_F_ONETXQUEUE, so the one-queue trigger described below also takes this
branch and is corrected without a notice.

That also keeps a bulk list on one queue by construction: every element of
a TCQ_F_ONETXQUEUE qdisc, including a follower changed by a filter, is
pinned to q->dev_queue before it is appended. The fast bulk helper
therefore needs no head comparison and no skb_bad_txq requeue; the slow
helper, used only by non-ONETXQUEUE qdiscs, still compares and requeues a
mismatched follower, where a wake on any queue reschedules q.

On the enqueue side taprio_enqueue() caps the mapping against
real_num_tx_queues and writes it back before selecting q->qdiscs[queue], so
a duplicating child cannot steer the clone out of the array.

Conditions to recreate the bug:
The dequeue path: load a SCHED_CLS or SCHED_ACT program that stores
__sk_buff->queue_mapping (a tc BPF action is enough), attach it to a
transmit qdisc (for example a matchall filter on a prio root), and send a
packet. With a 1-queue device a store of 1 indexes one past dev->_tx[].
Under KASAN with panic_on_warn=1 the unfixed kernel faults with "BUG:
KASAN: slab-out-of-bounds in sch_direct_xmit". Loading the program needs
CAP_BPF/CAP_SYS_ADMIN, so the trigger is root.

The enqueue path: on a multi-queue device, install a software taprio root,
graft a prio child with a duplicating netem on every class, and store an
out-of-range queue_mapping from a matchall+bpf filter on the prio. The
duplicate is re-enqueued at the taprio root and indexes q->qdiscs[] past
dev->num_tx_queues; the unfixed kernel faults in taprio_enqueue_one().
Same CAP_BPF/CAP_SYS_ADMIN requirement.

Fixes: 74e31ca850 ("bpf: add skb->queue_mapping write access from tc clsact")
Reported-by: Sashiko (nipa) <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/netdev/179033713973.2160803.4914570693994398206@kernel.org/
Link: https://lore.kernel.org/netdev/179329777513.3134.12135506558709584471@kernel.org/
Link: https://lore.kernel.org/netdev/179293123940.3134.1149128679923234677@kernel.org/
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-MD1X.v4.r0.20261021042722-1%40mojatatu.com
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-MD1X.v3.r0.20261015165943-1%40mojatatu.com
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-MD1X.v1.20261005193231%40mojatatu.com
Link: https://lore.kernel.org/netdev/20261015125822.GH83879@horms.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/QDISC-MD1X.v6.r0.20261029162633-1@mojatatu.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 22:29:23 +01:00
Chris Mason
e803c82dcd ovl: fix whiteout creation in casefolded directories
unlink and rmdir fail with EINVAL on an overlay with casefolded
(case-insensitive) layers, if the name exists in a lower layer.
Casefolded layers need CONFIG_UNICODE. Root can mount such an overlay,
and so can an unprivileged user in a user namespace, with tmpfs layers.

Overlayfs does not change a lower layer. To remove a name that exists
there, it hides the name with a marker file, a whiteout. It creates the
whiteout in the work directory, a scratch directory on the upper
filesystem, and renames it over the name in the upper directory:

- ovl_whiteout() creates the whiteout with mknod, or as a hard link to
  an earlier whiteout.
- ovl_cleanup_and_whiteout() then prepares the rename with
  start_renaming_two_dentries(), which returns -EINVAL if the source or
  the target dentry is unhashed, that is, not in the dentry hash table.

With casefolded directories, both dentries can be unhashed:

- The target. Lookup in a casefolded directory leaves a negative dentry
  unhashed, so the rename target is unhashed if the name does not exist
  in the upper directory.
- The source, which is the new whiteout. tmpfs hashes a dentry when
  mknod or link makes it positive, but ext4 does not, so on ext4 the
  source is unhashed as well.

The cleanup after the failure also refuses an unhashed dentry, so on
ext4 the whiteout is left behind in the work directory.

Reproduced with rm and rmdir on casefolded tmpfs and ext4 layers, also
as uid 1000 in a user namespace.

Fix this by creating the whiteout with ovl_create_temp(), which repeats
the lookup if the new dentry is unhashed. Prepare the rename with
start_renaming_dentry(), which looks up the target name with the
directories locked. The caller looked the name up without a lock, so
return -ESTALE if the name now refers to a different inode.

Fixes: 833d2b3a07 ("Add start_renaming_two_dentries()")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[amir: pass the name used for lookup instead of taking a name snapshot]
Tested-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-03 22:17:23 +01:00
Chris Mason
83b351c3ad ovl: do not let chattr change the casefold flag
chattr +F or -F on an overlay directory can make the directory, or the
whole mount, unusable. Lookups of the directory, and lookups in it, then
fail. From code inspection, the caller only needs to own the directory.
The upper filesystem must support casefolding: ext4 or f2fs with the
casefold feature, or tmpfs with the casefold option.

chattr +F and -F set and clear FS_CASEFOLD_FL, the casefold flag of a
directory. The flag enables casefolding (case-insensitive name lookup)
for the directory. All directories of an overlay must match the casefold
state that was recorded at mount time, and ovl_lookup_single() enforces
this:

- A lookup in a directory that does not match fails with -ESTALE.
- A lookup of the directory itself fails with -EREMOTE.

ovl_fileattr_set() copies the directory up, which creates it in the
upper layer if it only existed in a lower layer. It then passes
FS_CASEFOLD_FL on to the upper filesystem. The upper filesystem accepts
the change if the upper directory is empty, regardless of what the
merged directory contains. The merged directory is the one that the user
sees, with the names from the upper and the lower directories.

After the change the upper directory no longer matches the mount. If the
directory is the root of the overlay, the whole mount is affected.

The flag can also change without chattr +F or -F. chattr reads all flags
of a directory, changes one and writes all of them back. For a directory
that only exists in a lower layer, overlayfs reads the flags from the
lower filesystem. xfs with the ascii-ci feature reports FS_CASEFOLD_FL
on every inode, but never sets S_CASEFOLD, the inode flag that overlayfs
compares with the mount. So its directories count as not casefolded.
With a lower layer on such an xfs and an upper layer on ext4 with the
casefold feature, chattr +A on a lower-only directory therefore sets
FS_CASEFOLD_FL on the new, empty upper directory.

Reproduced as root on tmpfs and on ext4 with chattr +F or -F on an
overlay directory whose upper directory was empty. Afterwards lookups
below it failed with ESTALE, and lookups of the directory itself failed
with EREMOTE. The chattr +A case was seen once, on a kernel with an
earlier form of this patch that still passed the caller's flag on:
lookups of the directory failed with EREMOTE.

Fix this by returning -EOPNOTSUPP if FS_IOC_SETFLAGS, the only call that
can change the flag, asks for a casefold flag on a directory that does
not agree with the casefold state of the mount. This also refuses the
chattr +A case above.

Fixes: 083957f961 ("ovl: support layers on case-folding capable filesystems")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[amir: check the flag against the casefold state of the mount instead of
 reading back the flags]
Tested-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-03 22:17:23 +01:00
Chris Mason
c782fc8ada ovl: fail the mount if the casefold flag has changed
An unprivileged user in a user namespace can repeatedly trigger a kernel
warning with their own overlay mounts. They do so by changing the
casefold flag of the topmost layer's empty root, the top directory of
that layer, after the layers are set and before the mount is created.

The casefold flag of a directory makes name lookups in that directory
case-insensitive. All layers of an overlay must agree on casefolding.

ovl_mount_dir_check() reads the casefold flag of a layer root when
fsconfig() sets that layer, and saves the result in ofs->casefold. The
mount is created later, by another fsconfig() call with
FSCONFIG_CMD_CREATE.

The casefold flag of an empty directory can be changed.

The casefold flag of the overlay root must match ofs->casefold.
ovl_get_root() copies the flag from the topmost layer root, as it is
when the mount is created. On a mismatch, ovl_get_root() only does a
WARN_ON(), and the mount continues. The check is not a WARN_ON_ONCE(),
so each such mount warns again.

An unprivileged user needs CONFIG_UNICODE, and a tmpfs mounted with the
casefold option in their namespace.

Reproduced by changing the casefold flag of the empty upper directory
after the layers were set and before FSCONFIG_CMD_CREATE, with tmpfs and
ext4 layers, and as uid 1000 in a user namespace.

Fix this by replacing the WARN_ON() with a check that fails the mount
with -EINVAL.

Fixes: f9377faaea ("ovl: Add S_CASEFOLD as part of the inode flag to be copied")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Tested-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
2026-11-03 22:17:23 +01:00
Xia Yan
bc53aab488 ipv6: fix device binding after failed datagram connect
__ip6_datagram_connect() can change sk_bound_dev_if when connecting to
an address that needs a scope ID. If ip6_datagram_dst_update() fails,
the old peer address and port are restored, but the new device binding
is left behind.

A UDP socket can then keep reporting its original peer while sends and
attempts to reconnect to that peer fail with ENETUNREACH. Replies to the
socket are also dropped by the device match. The same problem occurs
when a scoped multicast destination picks up np->mcast_oif.

Save the original binding before processing the scope and restore it
along with the peer information on failure. This completes the rollback
in commit 2f987a76a9 ("net: ipv6: keep sk status consistent after
datagram connect failure") and preserves the new binding on success.

Found while reviewing scope-ID handling in __ip6_datagram_connect().

Confirmed by exchanging UDP traffic over ::1, then attempting a link-local
connect with a nonexistent scope ifindex or a down interface. After that
connect fails, the original peer is still reported but communication and
reconnecting to it fail.

Tested before and after the fix in UML for three rounds, covering explicit
scopes, multicast interface fallback, initially unconnected sockets and
existing bindings. With the fix, the old binding and peer are retained,
and traffic and reconnection to the original peer work. Also built on
x86_64 with W=1 using adjusted allmodconfig and allyesconfig
configurations, with no new warnings.

Fixes: 2f987a76a9 ("net: ipv6: keep sk status consistent after datagram connect failure")
Cc: stable@vger.kernel.org
Signed-off-by: Xia Yan <yanxia@cmss.chinamobile.com>
Link: https://patch.msgid.link/20261029135822.448299-1-yanxia@cmss.chinamobile.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 22:14:43 +01:00
Alexander Goodkind
34cc22a9ce net: ethernet: mediatek: preserve sibling PPE bindings
__mtk_ppe_check_skb() clears entry->hash for flows bound to other
hardware slots in the same software hash bucket. mtk_flow_offload_stats()
then skips their hardware counter updates. L2 cleanup also frees sibling
subflows without invalidating their hardware rules.

Restrict both cleanup paths to entries assigned to the inspected slot.

Two UDP trials reproduced the counter failure on a GL-MT3000/MT7981
running unmodified OpenWrt 25.12.5 with Linux 6.12.94:

1. Start a UDP connection.
2. Add a control connection in a different hash bucket.
3. Add a connection in the first connection's hash bucket.

AI code review of the original patch identified the cleanup problem
in L2 subflows.

Full ARM64 builds with allmodconfig and allyesconfig passed before
and after the patch using GCC 14.2.0 and W=1, without new warnings.
The builds used CONFIG_WERROR=n because the unmodified ARM64 kernel
already emits warnings. Hardware testing has not run for this revision.

Fixes: c4f033d9e0 ("net: ethernet: mtk_eth_soc: rework hardware flow table management")
Fixes: 33fc42de33 ("net: ethernet: mtk_eth_soc: support creating mac address based offload entries")
Link: https://github.com/openwrt/openwrt/pull/26107
Signed-off-by: Alexander Goodkind <alex@goodkind.io>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261030010517.45639-1-alex@goodkind.io
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 22:06:53 +01:00
Florian Fainelli
3362cb822e net: dsa: b53: Enable IGMP and MLD control packet CPU copies
IGMPv2 reports and MLDv1 reports are addressed to the multicast group
itself. Once the first listener is installed in the ARL table, subsequent
reports can follow that entry without reaching the CPU. The bridge then
fails to learn additional listeners, although static MDB forwarding works.

Enable the high-level protocol classifiers so that IGMP and MLD control
packets are copied to the CPU independently of the multicast ARL lookup.
Retain normal L2 forwarding by clearing the CPU-only forwarding modes,
and preserve unrelated protocol-control fields.

Handle the BCM5395's 16-bit register and different classifier fields
separately from the 32-bit layout on the BCM531xx, BCM5301x and newer
integrated RoboSwitch families, including BCM7445, BCM7278 and BCM4908.
Export the helper and call it from bcm_sf2_sw_setup() as well, since SF2
uses its own setup operation instead of b53_setup(). This also restores
the classifiers after the switch reset on resume. Leave older devices
with different IGMP controls untouched, and propagate register access
failures during setup.

The SF2 setup integration and BCM4908 chip gate were updated with
assistance from OpenAI Codex in response to review feedback.

Fixes: 5d65b64a3d ("net: dsa: b53: Add support for MDB")
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://patch.msgid.link/20261028235100.3892374-2-florian.fainelli@broadcom.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 21:49:02 +01:00
Guenter Roeck
e6b96b76d7 hwmon: (hp-wmi-sensors) Serialize alarm flag read-and-clear with state->lock
In hp_wmi_hwmon_read(), temperature and fan alarm flags (info->alarm)
are evaluated and cleared without acquiring state->lock, while only the
hwmon subsystem lock is held by the hwmon core. Meanwhile, the
asynchronous WMI event handler hp_wmi_notify() sets info->alarm under
state->lock. If hp_wmi_notify() sets info->alarm between the read and
the subsequent clear in hp_wmi_hwmon_read(), the newly reported fan
stall or critical temperature alarm is overwritten with false and
permanently lost.

The driver-local state->lock cannot be replaced with the hwmon
subsystem lock (hwmon_lock()):
- When no connected hwmon-supported sensors are present (!count), the
  driver operates in debugfs-only mode without registering a hwmon
  device, while debugfs attributes (fungible_show()) still require
  state->lock to serialize WMI queries and sensor state updates.
- Even when sensors are connected, add_event_handler() must subscribe
  to WMI events before make_chip_info() and
  devm_hwmon_device_register_with_info() because visibility of alarm
  and intrusion attributes depends on whether event registration
  succeeded. As a result, hp_wmi_notify() can run before the hwmon
  device exists during probe and after devm unregisters and frees the
  hwmon device during removal.

Acquire state->lock in hp_wmi_hwmon_read() around reading and clearing
info->alarm to prevent losing WMI alarm events.

Fixes: 23902f98f8 ("hwmon: add HP WMI Sensors driver")
Cc: James Seo <james@equiv.tech>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-03 11:32:45 -08:00
Samiullah Khawaja
71555ae8c7 mm/gup: check folio->mapping under folio lock in memfd_pin_folios()
memfd_pin_folios() pins folios from the page cache without taking the
folio lock. khugepaged or MADV_COLLAPSE can therefore replace a folio
after checking its refcount while memfd_pin_folios() still pins the old
folio. The caller then receives a folio which is no longer part of the
memfd.

For udmabuf and iommufd, this can cause data corruption: DMA accesses
the detached folio rather than the live memfd contents. DMA reads can
return stale data, while DMA writes update the detached copy and are
lost from the live memfd. The detached folio remains pinned, so these
accesses do not constitute a use-after-free or target another
application's memory. For memfd live update, the stale contents can
reappear in the memfd after handover.

Lock the folio and recheck folio->mapping before pinning it, like other
page cache users do. If the folio was removed, retry the folio lookup
from the index that was removed.

Fixes: 89c1905d9c ("mm/gup: introduce memfd_pin_folios() for pinning memfd folios")
Reported-by: Andy Lutomirski <luto@amacapital.net>
Closes: https://lore.kernel.org/all/CALCETrV5eqg6d9=+BQhCpRwBNe3aCQiut8vxPBs8b7PToqjaHg@mail.gmail.com/
Cc: stable@vger.kernel.org
Signed-off-by: Samiullah Khawaja <skhawaja@google.com>
Reviewed-by: Andy Lutomirski <luto@amacapital.net>
Link: https://patch.msgid.link/20261031203540.2282507-1-skhawaja@google.com
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Lance Yang
eadce52a9e khugepaged: fix readahead lock inversion in collapse_file()
collapse_file() can call page_cache_sync_readahead() while still holding
source folios locked. If truncate holds mapping->invalidate_lock
exclusively and waits for one of those folios, readahead waits for
invalidate_lock and neither side can make progress.

We need to release those folio locks before starting readahead. On a page
cache miss, roll back first, populate the collapse range, and retry once.
Doing readahead after rollback avoids an extra pass when all folios are
already present. If another miss occurs on retry, give up rather than keep
retrying while truncate or reclaim removes folios.

Keep page_cache_sync_readahead() and wait for read I/O with
filemap_lock_folio(), releasing each folio before moving to the next. The
existing uptodate check during collapse still handles read errors.

Shmem uses shmem_get_folio() for swapin and fallocated folios without
taking mapping->invalidate_lock, so it is unaffected.

Reported-by: syzbot+16bf7cd0ebeb1de93aa5@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=16bf7cd0ebeb1de93aa5
Fixes: 730633f0b7 ("mm: Protect operations adding pages to page cache with invalidate_lock")
Cc: stable@vger.kernel.org
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Link: https://patch.msgid.link/20261026152013.10511-1-lance.yang@linux.dev
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Ritesh Harjani (IBM)
466d6844c8 mm/huge_memory: set the mmu_gather page size in zap_huge_pud()
Unmapping a device-dax mapping with 1G alignment on powerpc radix kernel
built with CONFIG_DEBUG_VM triggers this warning on every munmap:

    WARNING: mm/mmu_gather.c:176 at __tlb_remove_folio_pages_size+0x38/0x230
    NIP [c00000000063d508] __tlb_remove_folio_pages_size+0x38/0x230
    LR [c0000000006fb688] zap_huge_pud+0x1b8/0x2d0
    Call Trace:
     zap_huge_pud+0x170/0x2d0 (unreliable)
     __zap_vma_range+0x1604/0x1e20
     unmap_vmas+0xa0/0x1f0
     unmap_region+0xb0/0x130
     vms_complete_munmap_vmas+0x120/0x310
     do_vmi_align_munmap+0x1ec/0x240
     __vm_munmap+0x148/0x220
     sys_munmap+0x28/0x40

To trigger this - it is enough to mmap() /dev/dax0.0, touch the first
byte so that the whole 1G is mapped by a single PUD and then munmap()
it.

PowerPC needs MMU_GATHER_PAGE_SIZE in which mmu_gather needs to record
the page size for which tlb flush is needed. zap_huge_pmd(),
zap_pte_range(), change_huge_pud() etc all do this already. However,
since commit:
  dbe5415329 ("mm/huge_memory: add vmf_insert_folio_pud()")

a device-dax PUD maps a real folio and zap_huge_pud() now hands it to
tlb_remove_page_size(tlb, page, HPAGE_PUD_SIZE). At that point
tlb->page_size is still whatever the previous user left behind, which is
0 for the fresh gather set up by munmap() and so the check fires.

Fix this in the same way like how other similar paths do.

Fixes: dbe5415329 ("mm/huge_memory: add vmf_insert_folio_pud()")
Cc: stable@vger.kernel.org
Reported-by: Pavithra <pavrampu@linux.ibm.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: Muchun Song <muchun.song@linux.dev>
Tested-by: Pavithra Prakash <pavrampu@linux.ibm.com>
Link: https://patch.msgid.link/8b853e5f9f16145859407b28af654b0f79e12642.1793318297.git.ritesh.list@gmail.com
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
500624f28e mm/memory-tiers: unregister empty tiers outside memory_tier_lock
When offlining a node's last memory empties its tier,
clear_node_memory_tier() calls device_unregister() while holding
memory_tier_lock. A concurrent sysfs read can hold a kernfs active
reference and block in nodelist_show() on that mutex. device_unregister()
then waits in kernfs_drain() for the read to finish and release its active
reference, while the reader waits for the offlining task to release the
mutex.

Return the node's former tier from clear_node_memory_tier(), making the
helper more similar to set_node_memory_tier(), which also returns a
memory_tier pointer. Let the caller unlink an empty tier under
memory_tier_lock before rebuilding demotion targets, then unregister its
device after dropping the lock.

Fixes: 9832fb8783 ("mm/demotion: expose memory tier details via sysfs")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-46-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Rik van Riel
e8abc61d8a mm/cma: don't release CMA pages still in use
When a driver calls dma_free_contiguous() before quiescing DMA, the
page might still have a reference from the device.
put_page_testzero() there returns false, WARN fires, but the code proceeds
to free_contig_frozen_range() putting a live page onto buddy and clearing
the bitmap. A subsequent allocation can hand the same PFN to a new
owner while the original holder still references it.

A concurrent put_page() that drops the last reference between the
testzero loop and free_contig_frozen_range() can double-queue the page
via page->lru, corrupting buddy lists.

Avoid the corruption by not freeing a CMA region if any of the
pages inside are still in use.

Make it explicit in the warning that the driver allowed a leak.

While at it, use page_ref_freeze() to make the semantics clearer and
switch to pr_warn_ratelimited().

Fixes: 9bda131c60 ("mm: cma: add cma_alloc_frozen{_compound}()")
Cc: stable@vger.kernel.org
Signed-off-by: Rik van Riel <riel@surriel.com>
Link: https://patch.msgid.link/20260811132045.5f114772@fangorn
[ david: use page_ref_freeze() + pr_warn_ratelimited() ]
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-45-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
b1ee878021 mm/vma: don't leak the charge for stack growth
acct_stack_growth() charges stack expansion even without VM_ACCOUNT.
This can happen for read-only or MAP_NORESERVE mappings created with
MAP_GROWSDOWN. Unmapping these VMAs does not release the charge, leaking
Committed_AS.

Only check and charge growth for VM_ACCOUNT VMAs, matching mremap().
Unaccounted growth skips the overcommit check while remaining subject
to the other stack-growth limits.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-44-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
23e5709274 mm/huge_memory: split huge PUDs when adjusting VMA boundaries
PFN mappings such as VFIO PCI BAR mappings can use PUD leaves while
allowing VMA splits at page granularity. However, vma_adjust_trans_huge()
only handles PMDs.

After faulting a writable PUD-sized VFIO BAR mapping, changing its first
page to read-only with mprotect() makes the PMD walk treat the PUD leaf
as a PMD table. Applying MADV_DONTFORK to the first PMD-sized chunk leaves
the PUD spanning two VMAs: the PMD-aligned boundary skips splitting.

Walk the page tables once at each adjusted boundary and split a huge
PUD or PMD leaf as needed. Handle PUD leaves even when the boundary is
PMD-aligned.

Fixes: f9e54c3a2f ("vfio/pci: implement huge_fault support")
Cc: stable@vger.kernel.org
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Link: https://patch.msgid.link/20261031-fixes_core-v3-43-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Chris Mason
0193e83368 mm/vma: call ->may_split() before a partial merge
A driver can use the ->may_split() hook to forbid a VMA boundary at
certain addresses.

A device-dax device is a character device that gives raw access to a
range of memory through mmap(). device-dax refuses any address that is not
a multiple of the device's alignment through vm_ops->may_split.

vma_merge_existing_range() can move boundaries, but does not call
vm_ops->may_split.

If a range at the edge of a VMA gets the attributes of the adjacent VMA,
the function moves only that range over to the neighbour: one VMA shrinks
and the other grows. This is a partial merge, and vma_modify() tries it
before any split.

Take a device-dax VMA that lies next to another VMA of the same file.
The user calls mprotect() on the one page of the first VMA that touches
the second VMA, and asks for the protection that the second VMA already
has. The result is a partial merge. It puts the boundary inside a 1 GiB
mapping, which is a single leaf entry at the PUD level.

As part of the merge, the kernel looks for a huge PMD to split at the
new boundary. That code does not expect a PUD leaf:

    vma_merge_existing_range()
      commit_merge()
        vma_adjust_trans_huge()
          split_huge_pmd_address()
            mm_find_pmd()
              treats the PUD leaf as a pointer to a PMD table,
              so the "table" is the device memory that the leaf maps
            __split_huge_pmd()
              reads a PMD that the user wrote to the device memory
              folio_put() on the folio that this PMD names

Bad. While the code must at some point be taught to split PUD entries as
well, the issue here is that we move VMA boundaries such that they are
incompatible with the driver.

Fix this by calling ->may_split() on the address that a partial merge
would move the boundary to, and by abandoning the merge if the driver
refuses. vma_modify() then tries the split, which fails with -EINVAL.

Factor out existing split handling into check_split() and reuse it.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 38607c62b3 ("fs/dax: properly refcount fs dax pages")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: improve description; cleanup the code ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-42-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Chris Mason
7f2c000ffb mm/ksm: check large swap-cache folios before mapping them
KSM folios are always small, but their shared swap slots can be read
back as part of a large folio in the swap cache. ksm_might_need_to_copy()
skips large folios, so another process can map a page with an incompatible
anon_vma or page index. Reverse mapping then cannot find the new
mapping, preventing migration or reclaim.

Apply the same compatibility checks to large folios as to small ones.
Pass the page corresponding to the swap entry and copy only that page
when necessary. In do_swap_page()'s copy path, decrement only that slot's
swap count, because the source swap-cache folio can now be large.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: f1879e8a0c ("mm, swap: never bypass the swap cache even for SWP_SYNCHRONOUS_IO")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-41-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
4c2dec1dce mm/ksm: fix use of a freed anon_vma at swap-in
A folio read from a swap slot previously shared by KSM can remain in the
swap cache after the process that first mapped it exits. Its anon_vma
can then be freed, so ksm_might_need_to_copy() must not dereference it
to compare roots.

Doing so can result in some false-positives, resulting in the reverse
mapping missing the new folio mapping, preventing migration and reclaim.

SLAB_TYPESAFE_BY_RCU allows individual anon_vma objects to be reused
immediately after freeing. A stale pointer can then refer to another
anon_vma whose root matches, even though the target VMA is not linked
to that anon_vma.

Move the anonymous rmap compatibility checks into
folio_anon_rmap_compatible(). Keep the page-index check and compare the
folio's anon_vma pointer against the VMA's own anon_vma and root first.

If neither matches, bite the bullet and walk the VMA's anon_vma_chain.
The VMA keeps these anon_vmas alive, and finding a match guarantees that
reverse mapping can find the new mapping.

Lorenzo Stoakes says in a private discussion:

  "This isn't quite equivalent to the existing check.

  Every anon_vma in an anon_vma_chain shares the same root, but if you
  split a VMA then fork both of them like this:

                  VMA A
               /        \         <split>
            VMA B      VMA C
               \        /
        root <- anon_vma 1
               ----^ ^----        <fork>
              /   parent  \
        anon_vma 2   anon_vma 3
             |            |
           VMA D        VMA E

  VMA's D and E both get their own new
  anon_vma's such that:

  VMA D: anon_vma 2 -> anon_vma 1 -> root
  VMA E: anon_vma 3 -> anon_vma 1 -> root

  And if you found a folio referencing anon_vma 2, the existing check:

	anon_vma->root == vma->anon-vma->root

  Would be true for VMA's B, C, D & E.

  However after your change it'd be true for VMA D only, as it's the only
  one with anon_vma 2 in its anon_vma_chain.

  Whether or not that could actually happen in practice... 🙂 I don't
  know.

  [...] after your change it'd be true for VMA D only, as it's the only
  one with anon_vma 2 in its anon_vma_chain. [...] I would [...] say that
  you are making the test stricter but more correct.
"

If this affects performance when KSM was never even involved, we could
just track whether KSM ever merged anything and just skip these checks.

There isn't really a lot we can do otherwise: for mapped folios we might
be able to use folio_get_anon_vma(), but for unmapped folios there really
is no easy way to see if the anon_vma is still valid.

Document the (confusing) lifetime requirements of folio_anon_vma().

Fixes: ba6f0ff398 ("ksm: fix ksm swapin time optimization")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Xu Xin <xu.xin@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-40-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
890e118e95 mm/ksm: reset the unstable trees of all nodes
Each full scan resets ksm_nr_node_ids unstable tree roots. Enabling
merge_across_nodes resets this count to 1, even if per-node roots were
previously allocated.

So when toggling "merge_across_nodes" 0 -> 1 -> 0, a scan that starts
while the setting is 1 and continues after switching back to 0 can
encounter stale unstable tree roots, resulting in UAF.

Only root is allowed to change "merge_across_nodes", and the documented
sequence is: "merge_across_nodes setting can be changed only when there
are no ksm shared pages in the system: set run 2 to unmerge pages first,
then to 1 after changing merge_across_nodes, to remerge according to the
new setting."

Let's fix it by tracking in ksm_nr_node_ids the actual number of
allocated tree roots.

remove_all_stable_nodes() and ksm_check_stable_tree() will now scan
more tree roots (skipping the empty ones), which is harmless.

Fixes: ef53d16cde ("ksm: allocate roots when needed")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-39-d6437171ecc3@kernel.org
Reviewed-by: Xu Xin <xu.xin@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Chris Mason
d03df42dda mm: fix deadlock of mremap() against UFFDIO_MOVE
With per-VMA locks, UFFDIO_MOVE can run concurrently with mremap()
on different VMAs in the same mm. Those VMAs can share page tables, so
both operations can acquire the same pair of page-table locks.

UFFDIO_MOVE orders the locks by address, while mremap() takes the source
lock first. These conflicting orders can deadlock; mremap() holding
mmap_lock for writing no longer helps.

Move double_pt_lock() and double_pt_unlock() to mm/internal.h and use
them for all page-table moves in mremap(). Preserve the source entry
checks after acquiring both locks. Remove the comments claiming that
exclusive mmap_lock makes lock ordering irrelevant.

In move_ptes(), make sure to just recheck source and destination PMD
after taking the locks and drop the overly-long comment.

Fix generated by an LLM and sent by Chris Mason in private.

[ david: use new helpers consistently; simplify description and comments;
         move_ptes() fixup ]

Fixes: 867a43a34f ("userfaultfd: use per-vma locks in userfaultfd operations")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-38-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Chris Mason
9f02ca8c15 mm: fix unkillable fault loop on MAP_DROPPABLE memory
handle_mm_fault() suppresses VM_FAULT_OOM for VM_DROPPABLE mappings.

For user-mode faults, pending signals are processed before retrying the
access. Kernel-mode faults on user buffers instead return directly to
the faulting instruction.

With persistent allocation failures (esp. memcg limits), a syscall,
such as write(), can therefore loop while not dropping locks.

Only suppress VM_FAULT_OOM when FAULT_FLAG_USER is set, allowing
kernel-mode faults and GUP to fail and signal allocation errors.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 9651fcedf7 ("mm: add MAP_DROPPABLE for designating always lazily freeable mappings")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: simplify description ]
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-37-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Josef Bacik
7a81bc23da mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit
Commit 9eab0421fa ("mm: fix unmap_mapping_range high bits shift bug")
made holebegin and holelen unsigned before they are shifted, by casting
them to pgoff_t. That is an unsigned long: on a 32-bit kernel the cast
cuts off the upper half of the two loff_t values, so a hole which begins
at 4 GiB or beyond is taken for one in the first 4 GiB of the file.

truncate_pagecache() passes the new size of the file and asks for private
COWed pages to be unmapped as well. If a file of 6 GiB is truncated to
5 GiB, everything from 1 GiB on is unmapped, and what a process has
written to a private mapping of the range between 1 GiB and 5 GiB is
lost: it reads the contents of the file again.

Where the range has an end, the wrong range is unmapped instead of the
right one. The page cache copes with that, as it unmaps every folio that
it removes. The callers which only have unmap_mapping_range() to get
rid of user mappings do not, for example drm_vma_node_unmap(), whose fake
offsets reach beyond 4 GiB on 32-bit, and revoke_iomem() with physical
addresses of more than 32 bits.

Cast to u64 instead. Nothing changes for 64-bit kernels.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 9eab0421fa ("mm: fix unmap_mapping_range high bits shift bug")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-36-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Chris Mason
8db6921cc0 mm/memory: reject remote COW faults on PFN mappings
When handling a COW fault without a normal source page (PFN mappings),
__wp_page_copy_user() copies from the faulting user address. For remote
faults, this accesses the wrong address space, resulting in wrong data
getting copied.

For example, user_events updates an enable bit in the registering
process's memory. If that memory needs to be faulted in,
user_event_enabler_fault_fixup() calls fixup_user_fault() from a work
item. Placing the enable bit in a private PFN mapping can trigger this
remote COW path.

Reject these faults with VM_FAULT_SIGBUS when the target mm differs from
current->mm: remote faults. Ordinary (non-PFN) mappings are not affected.

The user-address copy dates back to commit 6aab341e0a ("mm: re-architect
the VM_UNPAGED logic"); likely, actual ways to get remote faults in
there on COW PFN mappings appeared afterwards. But the fix is simple and
straight forward.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 6aab341e0a ("mm: re-architect the VM_UNPAGED logic")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: simplify comment and description ]
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-35-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
22d043c1da mm/madvise: fix data loss from MADV_FREE on a KSM page
MADV_FREE can clear the dirty flag of a singly mapped KSM folio. The
folio remains in the stable tree and can gain new mappings without being
dirtied again. Once marked lazyfree, reclaim can discard data that those
mappings still need.

KSM always marks a folio dirty when converting it to a KSM folio in
try_to_merge_one_page(). Marking a folio lazyfree clears PG_swapbacked
but leaves PG_dirty unchanged. Preserving PG_dirty makes reclaim restore
PG_swapbacked instead of discarding the folio. This also protects folios
that were already lazyfree when KSM converted them.

Skip KSM folios before clearing their dirty flag, checking under the
folio lock to serialize with KSM conversion.

Fixes: 854e9ed09d ("mm: support madvise(MADV_FREE)")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Xu Xin <xu.xin@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-34-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
Josef Bacik
440c877975 mm/mremap: fix moving PUD leaves
pud_none_or_clear_bad() only really works on page tables. PUD leaves
confuse the check and make us clear the page table entry and print a
warning.

Since commit aed877c2b4 ("device/dax: properly refcount device dax pages
when mapping"), this also leaks device-DAX folio references, mapcounts
and RSS accounting, resulting in "Bad rss-counter state" warnings on exit.

Allow PUD leaves in get_old_pud(). If a PUD leaf cannot be moved as a
whole or the move fails, split it. This unmaps it with proper accounting
instead of treating the leaf entry as a PMD table.

Keep using pud_trans_huge() for now, in the future this code should be
cleaned up to just check for PUD leaves.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: a00cc7d9dd ("mm, x86: add support for PUD-sized transparent hugepages")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: fallthrough after splitting ]
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-32-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:53 +01:00
David Hildenbrand (Arm)
402882943d mm/mremap: recheck PUDs under the page table lock
Once get_old_pud() is fixed to accept PUD leaves, unmap_mapping_range() can
clear a leaf between the lookup and the move. Holding mmap_lock in write
mode does not prevent this.

If the zap happens before move_page_tables() tests the entry, an empty
PUD can reach move_normal_pud(), where pud_populate() turns it into a
present page table entry. If it happens after the test, move_huge_pud()
can instead try to move an empty entry, triggering CONFIG_DEBUG_VM
warnings on powerpc.

Recheck the source under the page table lock in both helpers. Treat an
empty source in move_normal_pud() as a completed move, and use
__pud_trans_huge_lock() in move_huge_pud().

In the future we should likely have the code lookup a PUD/PMD lockless
once, instead of multiple times, because one of the problematic bits
here is the:

	pud_trans_huge(*old_pud)

Fixes: 0881ace292 ("mm/mremap: use pmd/pud_poplulate to update page table entries")
Cc: stable@vger.kernel.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-31-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
David Hildenbrand (Arm)
b4417d0803 mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs
move_huge_pud() reads the old PUD and clears it in separate operations.
Hardware accessed or dirty updates between those operations can be lost
when the saved entry is installed at the new address.

The raw pud_clear() also bypasses page_table_check_pud_clear(), while
set_pud_at() accounts for the destination mapping. This leaves the
checker counts unbalanced for mappings tracked by page table checking.

To fix it, simply use pudp_huge_get_and_clear().

Fixes: 7d846db7d0 ("mm/mremap: convert huge PUD move to separate helper")
Cc: stable@vger.kernel.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-30-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Chris Mason
5ad9e4b0f1 mm/mmu_notifier: set ->mm only after mmgrab()
Radeon uses a non-NULL notifier->mm to decide whether to call
mmu_interval_notifier_remove() when freeing a buffer object.
__mmu_interval_notifier_insert() sets ->mm before validating the range,
so a wrapping userptr range can leave ->mm set after insertion fails.
Cleanup then tries to remove an unregistered notifier for which no mm
reference was acquired.

Set ->mm only after mmgrab(), once insertion can no longer fail. While
we could fix radeon's code instead, setting ->mm on success only makes
the code more robust.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 3506ff69c3 ("drm/radeon: use mmu_interval_notifier_insert")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-29-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Josef Bacik
6d65925777 mm/mmu_notifier: finish non-blocking interval invalidation on error
When an ordinary MMU notifier rejects a non-blocking invalidation, the
interval invalidation started beforehand is left unfinished: the caller
skips mmu_notifier_invalidate_range_end(). Subsequent interval notifier
operations can then wait forever.

The only in-tree trigger is nouveau SVM, which uses both notifier types
and rejects non-blocking invalidations. Reaping via the OOM reaper or
process_mrelease() can therefore leave the GPU fault worker stuck,
holding a reference that prevents the dying process's address space
and memory from being freed.

End the interval invalidation when an ordinary notifier fails a
non-blocking invalidation, like mn_itree_invalidate() already does when
an interval notifier fails. Make that handling clearer in the
documentation of mmu_notifier_invalidate_range_start_nonblock().

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 99cb252f5e ("mm/mmu_notifier: add an interval tree notifier")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: simplify description, update function doc ]
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-28-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Josef Bacik
64ae7959a1 mm/mmu_gather: fix flushing ranges with 4 GiB or larger
__tlb_adjust_range() takes the size of the range which has to be flushed
as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
and pass an unsigned long. Consequently, a range that is 4 GiB or larger
gets truncated, possibly to 0.

On arm64 with hugetlb, a 64k kernel can have 16 GiB hugetlb folios
mapped contiguously at the PMD level and flush them when unmapping, and a
16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
at least these two scenarios are affected.

Fix it by flushing the proper range instead of the truncated one by
properly using "unsigned long" for range_size.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: b528e4b640 ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
Fixes: 8ce720d5bd ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: use two-tab indent, simplify description ]
Reviewed-by: Qi Zheng <qi.zheng@linux.dev>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: SJ Park <sj@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-27-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Gregory Price
05f64f211a mm/userfaultfd: compare exact registration modes before skipping
Changing registration from MISSING|WP to WP returns success but leaves
MISSING enabled. The no-op check sees that WP is already set and skips
the update, so later accesses to missing pages still wait for userspace.

Skip the update only when the current and requested UFFD modes match
exactly.

Fixes: 63b2d4174c ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: apply fixup from Lorenzo ]
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-26-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
David Hildenbrand (Arm)
4eee9c389b mm/userfaultfd: wake waiters when registration modes are removed
UFFDIO_REGISTER can replace MISSING or MINOR tracking without waking
faults that are already queued. For example, switching an anonymous
range from MISSING to WP leaves a missing-fault waiter asleep until
userspace explicitly wakes it.

When a registration change removes a UFFD mode, wake waiters in the
affected interval after updating the VMA. The VMA is write-locked at
this point, so no new faults can queue under the old modes and woken
threads cannot retry until mmap_write_unlock(). Waiters for retained
modes in the same interval may also wake and refault.

The hang reproduces for MISSING-to-WP and MINOR-to-MISSING transitions,
with both read and unread fault events.

Fixes: 63b2d4174c ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-25-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Josef Bacik
3afb19d68c mm/userfaultfd: wake all waiters on unregister
UFFDIO_UNREGISTER only wakes pending faults if VM_UFFD_MISSING is set.
Threads waiting on write-protect, minor or RWP faults can therefore remain
asleep after unregistering a range that does not track missing faults.

Wake pending faults regardless of the registration mode so they can retry
without an explicit UFFDIO_WAKE or closing the userfaultfd. This matches
the existing behavior for missing faults, including removing unread fault
messages for the woken waiters.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 63b2d4174c ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: rebase; simplify description ]
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-24-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
David Hildenbrand (Arm)
35f7ecd55c mm/userfaultfd: write-lock the VMA before waking waiters when unregistering
userfaultfd_unregister() wakes pending missing faults before clearing the
VMA's userfaultfd registration. With per-VMA fault locking, holding
mmap_lock for write does not prevent another fault from queuing after
the wakeup but before userfaultfd_clear_vma() write-locks the VMA. That
waiter can then remain asleep indefinitely.

Call vma_start_write() before waking waiters. Existing fault handlers
queue themselves before dropping the VMA read lock, and new readers are
excluded until mmap_write_unlock().

Fixes: 29a22b9e08 ("mm: handle userfaults under VMA lock")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-23-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
David Hildenbrand (Arm)
21a3888d3d mm/gup: check for overflow when converting nr_pages to bytes in GUP-fast
The overflow check in gup_fast_fallback() only covers the addition to
start. The preceding nr_pages << PAGE_SHIFT can already have truncated
the length on 32bit.

Users such as RapidIO's rio_dma_transfer() can derive such page counts
from a 64-bit userspace length.

Let's just check_shl_overflow() to reject any such overflow with
-EOVERFLOW early.

Fixes: c28b1fc703 ("mm/gup: reorganize internal_get_user_pages_fast()")
Cc: stable@vger.kernel.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Reviewed-by: Barry Song <baohua@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-22-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Chris Mason
1dfe4b276c mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast
With nr_pages == 0, GUP-fast still enters its page table walk and can
write past the caller's page array. The old end <= start check caught
empty ranges, but was replaced with an overflow check.

Users such as OrangeFS can pass a zero page count derived from a
userspace-supplied length. So let's return zero for nr_pages == 0 before
starting the walk, just like GUP-slow.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: c28b1fc703 ("mm/gup: reorganize internal_get_user_pages_fast()")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-21-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Chris Mason
c83ee2fa5a mm/gup: fix clearing folios in memfd_pin_folios()
memfd_pin_folios() pins folios obtained directly from the page cache
without checking whether they are uptodate. However, shmem fallocate()
can leave newly allocated folios uncleared and not uptodate. Callers
such as udmabuf can then expose uninitialized memory to userspace.

Clear non-uptodate folios and mark them uptodate under the folio lock
before returning them to the caller.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 89c1905d9c ("mm/gup: introduce memfd_pin_folios() for pinning memfd folios")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description and comment ]
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Tested-by: Samiullah Khawaja <skhawaja@google.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-20-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
David Hildenbrand (Arm)
79cb51d538 mm/gup: recheck the PUD under PTL in follow_pud_mask()
follow_pud_mask() reads the PUD without a lock. If it is a leaf, it takes
the lock and calls follow_huge_pud(), which reads the entry again, but
only tests whether it is present.

A leaf can be zapped concurrently and a page fault can fill the empty
entry with a page table.

This currently only applies when device-dax makes use of PUD entries,
and the fault after e.g., MADV_DONTNEED would find THPs to be disabled.

That requires a sequence like

1) Fault in the PUD
2) Disable THP
3) Have GUP race against concurrent MADV_DONTNEED + refault

Which is rather unlikely to happen in practice, which is why we never
received a report about such a problem.

Before commit 1b16761802 ("mm/gup: handle huge pud for
follow_pud_mask()"), we performed that check in follow_devmap_pud() by
testing for pud_devmap().

Let's fix it by just structuring follow_pud_mask() similar to
follow_pmd_mask(), minus protnone stuff that does not apply and minus
FOLL_SPLIT_PMD handling. That makes it much easier to spot any such
inconsistencies.

Perform the pud_bad() check early in follow_pmd_mask() and just forward
the PUD value. We can drop the pud_present() check in follow_huge_pud(),
just like we have in follow_huge_pmd().

Even though we are performing more changes than strictly necessary, the
fix should be easy to backport.

Fixes: 1b16761802 ("mm/gup: handle huge pud for follow_pud_mask()")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-19-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Chris Mason
fe2817e3d5 mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs
try_collapse_pte_mapped_thp() clears PTEs without transferring their dirty
bits to the folio. A shmem read fault can map a clean folio writable, so
a later store only dirties the PTE. Losing that dirty bit allows reclaim
to discard modified data.

The assumption that regular files are read-only is also obsolete since
commit 1b6444331b ("mm/khugepaged: enable clean pagecache folio collapse
for writable files"). In any case, transferring PTE dirty bits to the folio
when removing mappings (and while the folio is still mapped) is the right
thing to do.

Use get_and_clear_ptes() to collect the dirty bits and mark the folio
dirty before unmapping it. Update the comment.

This was reproduced with shmem using MADV_COLLAPSE followed by
MADV_PAGEOUT.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 27e1f82731 ("khugepaged: enable collapse pmd for pte-mapped THP")
Fixes: 1b6444331b ("mm/khugepaged: enable clean pagecache folio collapse for writable files")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: adjust comment; simplify description; cover file-thp as well ]
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-17-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Josef Bacik
db38b90230 mm/khugepaged: fix PMD table lock leak in try_collapse_pte_mapped_thp()
For a private mapping with userfaultfd, try_collapse_pte_mapped_thp()
takes the PMD table lock before it maps the page table for the second time.
If that (pte_offset_map_rw_nolock) fails, because the page table vanished
in the meantime due to concurrent page table reclaim, it leaves through
the abort label, where the PMD table lock is unlocked if it differs from
PTE table lock.

In case the PMD table lock and the PTE table lock match, which is the
case without CONFIG_SPLIT_PTE_PTLOCKS after pte_offset_map_rw_nolock()
failed, we miss to unlock the PMD table.

To fix it, forget the PTE table lock when we unmap+unlock the PTE table.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 6375e95f38 ("mm: pgtable: reclaim empty PTE page in madvise(MADV_DONTNEED)")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: move the ptl = NULL handling; rewrite description, drop wrong comments ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-16-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Josef Bacik
aa72cf34d9 mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp()
try_collapse_pte_mapped_thp() drops the PTE lock after it has cleared the
page table, and takes the PMD lock and the PTE lock to remove it.

In between, MADV_DONTNEED with CONFIG_PT_RECLAIM can reclaim the
page table. The pmd_same() check is supposed to handle this, but it is
only done with CONFIG_SPLIT_PTE_PTLOCKS.

Fix it by performing the check unconditionally.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 6375e95f38 ("mm: pgtable: reclaim empty PTE page in madvise(MADV_DONTNEED)")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: adjust description ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-15-d6437171ecc3@kernel.org
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:52 +01:00
Chris Mason
63a9405413 mm/huge_memory: fix zapping migration entries for device-private THPs
A PMD migration entry can refer to a device-private folio.
zap_huge_pmd_folio() checks the folio type instead of the entry type,
so it treats such a migration entry as a device-private entry.

Installing the migration entry already removed the reverse mapping and
dropped the mapping reference. Zapping it must not repeat those
operations. Concurrent MADV_DONTNEED during migration back to system
memory can trigger this.

Check the PMD entry type using pmd_is_device_private_entry().

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 368076f52e ("mm/huge_memory: add device-private THP support to PMD operations")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Link: https://patch.msgid.link/20261031-fixes_core-v3-14-d6437171ecc3@kernel.org
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:51 +01:00
Chris Mason
e6a07d29b0 mm/huge_memory: fix truncate racing with PMD zapping
zap_huge_pmd_folio() removes the rmap before calling folio_mark_dirty().
If this was the last mapping, truncation can skip unmapping the folio
and proceed without waiting for the PMD lock, racing with dirtying.

ifs_set_range_dirty() can oops if MADV_DONTNEED races with
ftruncate() on XFS, when we get the folio set dirty after it was found
to not be mapped anymore.

Move folio_mark_dirty() and folio_mark_accessed() before rmap removal,
matching the PTE zap path. This keeps the folio mapped while updating
its state, so truncation must wait for the page table lock.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: fe6cf98493 ("mm/huge_memory: transfer the pmd dirty bit to the folio on zap")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify comment and description ]
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-13-d6437171ecc3@kernel.org
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-03 20:20:51 +01:00
Liu Changjie
2d4c272e81 can: peak_usb: pcan_usb_fd_decode_buf(): accept short uCAN end-of-list records
A PCAN-USB FD v2 running firmware 3.2.0 sends a 16-byte status record
followed by a four-byte zero-size end marker.

Since commit 93fcab2c69 ("can: peak_usb: validate uCAN receive record
lengths") these transfers cause repeated receive-buffer dumps while the
interface is up.

This has been observed on Linux 7.2.11-arch1-1 with matching kernel
headers:
- Classic CAN, 500 kbit/s: 25 decoder errors in 5 s before the fix; none in
  15 s after.
- CAN FD, 500 kbit/s nominal and 2 Mbit/s data: 26 decoder errors in 5 s
  before the fix; none in 60 s after.
- Three additional down/up cycles: no decoder errors.

pcan_usb_fd_decode_buf() requires a complete 12-byte struct pucan_msg
before checking the size field, so it rejects the end marker with -EBADMSG.

Check that the size field is present before testing for an end marker.
Require the full header for nonzero-size records and keep the remaining
record and payload length checks.

This patch was created with LLM assistance.

Fixes: 93fcab2c69 ("can: peak_usb: validate uCAN receive record lengths")
Signed-off-by: Liu Changjie <liucj1228@outlook.com>
Reviewed-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
Link: https://patch.msgid.link/CH5PR19MB997156AB3BE253C3BE445223B0AC992@CH5PR19MB997156.namprd19.prod.outlook.com
Cc: stable@vger.kernel.org
[mkl: copy additional info to commit message]
[mkl: convert Assisted-by: tag to prose]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Built and tested the original and patched peak_usb modules on Arch
Linux 7.2.11-arch1-1 with matching kernel headers.

  - Classic CAN, 500 kbit/s: 25 decoder errors in 5 s before the fix;
    none in 15 s after.
  - CAN FD, 500 kbit/s nominal and 2 Mbit/s data: 26 decoder errors
    in 5 s before the fix; none in 60 s after.
  - Three additional down/up cycles: no decoder errors.

USB captures during the patched tests contained 406 packets with
short end markers. Neither receive-buffer dump recurred.

The CAN bus was disconnected; external TX/RX was not tested.
One startup "can_change_state: oops, state did not change" message and
an RX dropped count reaching 2 were observed during the patched tests.
Their causes remain undetermined.
2026-11-03 19:54:30 +01:00
Marc Kleine-Budde
54195bf371 Merge patch series "can: dev: can_fill_info(): don't wake up controller if interface is down"
This series prevents the CAN controller from being activated by netlink
queries as long as the interface is down.

Link: https://patch.msgid.link/20261027065012.191348-1-chunyuzhiqiang@yinhe.ht
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:30 +01:00
ChunYuZhiQiang
f5128a7672 can: dev: can_tdc_fill_info(): don't read automatic TDCV if interface is down
The automatic TDCV readback calls into the driver via do_get_auto_tdcv().
Some drivers, such as xcan_get_auto_tdcv(), read controller registers
without taking a runtime PM reference, so calling this while the
interface is down can touch registers whose clocks are gated.

Gate do_get_auto_tdcv() on netif_running() in can_tdc_fill_info() and
adjust can_tdc_get_size() and can_data_bittiming_get_size() so that only
the automatic TDCV size is skipped when the interface is down. The other
TDC parameters are still reported, as they are meaningful while the
interface is down.

This is a defensive hardening based on code inspection; the automatic
TDCV path has not been triggered on hardware.

Signed-off-by: ChunYuZhiQiang <chunyuzhiqiang@yinhe.ht>
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Fixes: e8060f08cd ("can: netlink: add can_priv::do_get_auto_tdcv() to retrieve tdcv from device")
Link: https://patch.msgid.link/20261027065012.191348-2-chunyuzhiqiang@yinhe.ht
[mkl: fix open parenthesis alignment]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:30 +01:00
ChunYuZhiQiang
75332c410c can: dev: can_fill_info(): don't wake up controller if interface is down
If the interface is down, the CAN controller might be powered down and
its clocks gated. Don't call do_get_berr_counter() to read the bus error
counters if the interface is down, and adjust can_get_size() to match.

This removes one trigger for a synchronous external abort seen on
i.MX8QXP when "ip link show" is run on a flexcan interface that was
never brought up. The underlying cause is platform-specific: on i.MX8QXP
the CAN clocks are gated through the SCU LPCG and the subsystem shares
the IMX_SC_R_CAN_0 power domain, and there is a window after
pm_runtime_resume_and_get() returns where the clock has not reached the
module yet. This patch avoids the netlink query path while the interface
is down, but does not root-cause the LPCG window itself.

As a result, IFLA_CAN_BERR_COUNTER is no longer reported for down
interfaces. Userspace must treat the attribute as optional.

The issue was triggered on an i.MX8QXP board by running "ip link show"
without ever bringing the interface up:

    Internal error: synchronous external abort: 0000000096000210

    pc : flexcan_read_le+0x0/0x18
    lr : flexcan_get_berr_counter+0x4c/0x8c
    Call trace:
     flexcan_read_le+0x0/0x18
     flexcan_get_berr_counter+0x4c/0x8c
     can_fill_info+0x1f8/0x434
     rtnl_fill_ifinfo+0x8fc/0xbb4
     rtnl_dump_ifinfo+0x364/0x448

This is the same class of problem fixed for m_can in
commit 91a55c72a8 ("can: m_can: m_can_get_berr_counter(): don't
wake up controller if interface is down").

Fixes: ec56acfef2 ("can: flexcan: flexcan_get_berr_counter(): switch on clocks before accessing ecr register")
Cc: stable@vger.kernel.org
Signed-off-by: ChunYuZhiQiang <chunyuzhiqiang@yinhe.ht>
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/20261027065012.191348-1-chunyuzhiqiang@yinhe.ht
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:30 +01:00
Marc Kleine-Budde
4937195745 Merge patch series "can: protect the receive lists with a per-device lock"
Oliver Hartkopp <socketcan@hartkopp.net> says:

This series fixes a use-after-free in CAN_ISOTP and CAN_BCM that can be
triggered when a CAN device is moved to another network namespace while
a socket bound to this device is released [1].

Patch 2 makes isotp_bind() check the return values of can_rx_register(),
so that bind() does not succeed with missing receivers.

Patch 4 copies the CAN_RAW and CAN_ISOTP specific socket options from
and to user space outside of lock_sock(), so that a stalled copy can not
block raw_notify() waiting for lock_sock() under RTNL.

Patches 5 and 6 fix the reset and the calculation of the CAN statistics.

Patch 7 removes the pointers from the CAN specific proc output. As it
changes the proc output ABI it is not intended for stable and has been
moved to the end of the series, so that patches 1-6 can be backported
without it.

The code of patches 1 and 5-7 is unchanged since v4, apart from the
rebase of patch 7 in v12. Only the commit message of patch 1 has been
updated after the Sashiko review of v4 to describe the actual NULL
pointer dereference in can_rx_unregister() and the CAN_ISOTP path that
reaches it.

The series is based on net/main.

The idea behind patch 3:

The receive lists of a CAN device are located in the device's
can_ml_priv and travel with the device when it is moved to another
network namespace. But they are protected by the per-netns
rcvlists_lock, so the lock that protects a device's lists depends on
the namespace the caller passes to can_rx_register() and
can_rx_unregister(). can_rx_unregister() silently returns when this
namespace does not match dev_net(dev) anymore.

isotp_release() and bcm_release() leave the netdev notifier list before
they can serialize against the notifier. When the device changes its
namespace in this window, their filters are not removed and the
remaining receivers point to the freed socket or bcm op.

Taking RTNL in these release paths is no option, as CAN_RAW already
holds RTNL while adding and removing up to CAN_RAW_FILTER_MAX filters
per socket, which unprivileged users can trigger repeatedly.

Instead, patch 3 protects the receive lists where they are located: A
spinlock in struct can_dev_rcv_lists protects the lists of a CAN device
(initialized in can_set_ml_priv()) or the 'any' CAN device lists of a
namespace (initialized in can_pernet_init()). can_rx_unregister() then
finds the subscription independently of the current namespace of the
device, which is kept accessible by the tracked device references the
protocols already hold. The per-netns rcvlists_lock only protects the
receive list statistics, for which CAN_RAW, CAN_BCM and CAN_ISOTP pass
the namespace that has been used for can_rx_register().

As a consequence, CAN_RAW and CAN_ISOTP do not need RTNL in bind(),
setsockopt() and release() anymore. bind() is serialized against
NETDEV_UNREGISTER by publishing the device inside the RCU section of
its lookup, as unlist_netdevice() and synchronize_net() precede
NETDEV_UNREGISTER both on unregistration and on a namespace change.
The notifiers recheck the binding under lock_sock(). As RTNL does not
keep NETDEV_DOWN out of bind() anymore, bind() checks IFF_UP after
publishing the bound device, with an smp_mb() pair against the
notifiers, so a down transition during bind() is still reported with
ENETDOWN.

Link: https://patch.msgid.link/20261027-can-rx-lock-v12-0-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Marc Kleine-Budde
d3592ab8a1 Merge patch series "can: skb: make echo skb freeing safe in any IRQ context"
Cunhao Lu <1579567540@qq.com> says:

can_put_echo_skb() and the CAN skb allocation helpers may release skbs in
hardware interrupt context or while hardware interrupts are disabled. This
series makes the affected public helper paths safe in either context and
fixes the invalid echo-index skb leak.

Link: https://patch.msgid.link/tencent_CD05F020BAFB2537F5D1F4CBB425588EA80A@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
b98179a6e1 can: proc: remove pointers from CAN specific proc output
The proc content in /proc/net/can/ and /proc/net/can-bcm/ is intended to
check the internal filter lists (af_can, can_raw) and the efficiency and
functionality of can_bcm jobs. While exposing kernel addresses was
acceptable when this code was written the times have changed and multiple
attempts have been made to hash or remove such now sensitive data.

This patch removes the disclosure of pointers and instead provides the
function names and sock inode numbers when available. When the function
name can not be resolved (e.g. KALLSYMS=n or stripped module symbols)
%ps would fall back to the raw text address. Therefore (unknown) is
printed instead in this case. As there's no known tooling around the CAN
specific proc output breaking the ABI with this rework creates no issue.

Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-7-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
01b19ed9fa can: proc: skip stats calculation after reset in can_stat_update()
Commit 80b5f90158 ("can: statistics: use atomic access in hot path")
introduced local snapshots of the statistics counters at the beginning
of can_stat_update(). When can_init_stats() resets the statistics, these
stale pre-reset snapshots are still used for the following total/current
/max calculations and overwrite the freshly reset values. Additionally a
jiffies tick between the snapshot and the reset could trigger a second
can_init_stats() call.

Merge the reset conditions into a single check and skip the calculation
for the current interval when the statistics have been reset.

Fixes: 80b5f90158 ("can: statistics: use atomic access in hot path")
Cc: stable@vger.kernel.org
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-6-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Runyu Xiao
12297f855b can: proc: reset pkg_stats atomics individually
Commit 80b5f90158 ("can: statistics: use atomic access in hot path")
converted several members of struct can_pkg_stats to atomic_long_t and
updated the hot TX/RX and procfs read paths to use atomic_long_*()
helpers. However, can_init_stats() still clears the whole struct with
memset().

can_init_stats() is reached from can_stat_update() in timer context and
also from the procfs reset path. Those paths can run while the TX/RX hot
paths are concurrently updating rx_frames, tx_frames, matches and their
*_delta counters. Hitting the whole-struct memset() in that window
performs plain writes to fields that otherwise follow an atomic_long_t
access contract, which can lose or mix live statistics updates.

This issue was found by source-level API-misuse analysis looking for
whole-object resets left behind after atomic_long_t conversions, then
manually audited on Linux v6.18.21.

Replace the whole-struct memset() with a helper that resets the
atomic_long_t counters via atomic_long_set() and clears the derived
scalar statistics explicitly. This preserves the existing reset
semantics for scalar fields while restoring atomic access discipline for
the live counters.

Build-tested by compiling net/can/proc.o on x86_64 netdev/main.
Runtime-tested with a QEMU + vcan setup on Linux v6.18.21 by driving
concurrent traffic and reset_stats reads, which reproduced inconsistent
exported statistics before the fix.

[Hartkopp] can_stat_update() also read the *_delta counters at the
beginning and cleared them with atomic_long_set() at the end. Increments
from the hot path in between were lost for both the current and the next
interval. Use atomic_long_xchg() to fetch and clear the *_delta counters
in one atomic step instead.

On x86_64 atomic_long_set() is a plain store like memset(), so the
memset() is an actual problem only on architectures with lock-based
atomics (e.g. parisc). The inconsistencies seen on x86_64 come from the
*_delta handling and from the stale snapshots, which are fixed in "can:
proc: skip stats calculation after reset in can_stat_update()". As
before, the counters are reset one at a time and the derived scalar
statistics use plain stores.

Fixes: 80b5f90158 ("can: statistics: use atomic access in hot path")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-5-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
43c973a088 can: raw, isotp: copy socket options outside of lock_sock()
The CAN_RAW and CAN_ISOTP specific socket options are copied from and
to user space while holding lock_sock(). A copy that faults or stalls,
e.g. on a userfaultfd or FUSE backed mapping, holds lock_sock() for its
whole duration.

raw_notify() and isotp_notify() take lock_sock() of a socket that is
bound to the vanishing device while holding RTNL. As the CAN_RAW
options can also be changed on a bound socket, a stalled copy can block
RTNL on an unregistration or namespace change of the bound device.
Before "can: protect the receive lists with a per-device lock",
raw_setsockopt() even held RTNL itself during the copy. CAN_ISOTP only
copies its options for unbound sockets, which isotp_notify() skips
without taking lock_sock().

Keep the user space copies out of the locked sections: Check the option
name and length and copy the option values, including the CAN_RAW_FILTER
filters, to kernel memory before lock_sock(). raw_setsockopt_locked()
and isotp_setsockopt_locked() get the copied values directly and drop
their now redundant length checks and copies. As a side effect, a
failing copy can not leave partially overwritten options behind
anymore. In raw_getsockopt() duplicate the filters under lock_sock() and
copy them to user space after release_sock().

As the option name and length are now checked before lock_sock(), the
order of the checks in isotp_setsockopt() and accordingly the order of
the returned error values changes. This is in line with POSIX, which
does not define an order in which multiple error conditions are
detected and reported.

The generic SOL_SOCKET options in sk_setsockopt() are not affected by
this patch.

Fixes: c18ce101f2 ("[CAN]: Add raw protocol")
Fixes: 1e5185c090 ("can: raw: add locking for raw flags bitfield")
Cc: stable@vger.kernel.org # depends on "can: protect the receive lists with a per-device lock"
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-4-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
0f3ad9ab40 can: protect the receive lists with a per-device lock
The receive lists of a CAN device are located in the device's
can_ml_priv and travel with the device when it is moved to another
network namespace. But they are protected by the per-netns
rcvlists_lock. So can_rx_unregister() needs dev_net(dev) to pick the
right lock and silently returns when the passed namespace does not
match dev_net(dev) anymore.

isotp_release() and bcm_release() leave their notifier list before they
take any lock that serializes against the netdev notifier, which runs
under RTNL. When the bound device is moved to another namespace in this
window, the notifier skips the socket and the release path has to remove
the filters itself. isotp_release() passes the socket's namespace, which
does not match dev_net(dev) anymore. bcm_rx_unreg() passes dev_net(dev),
which can_rx_unregister() reads again for its check, so a namespace
change between both reads makes the check fail as well. In both cases
can_rx_unregister() silently returns. As can_rx_register() stores
rcv->sk without a reference, the remaining receivers point to the freed
socket (isotp) or the freed op (bcm):

  BUG: KASAN: use-after-free in isotp_rcv+0x1570/0x24d0
  Read of size 1 at addr ffff888118130552 by task isotp_ns_uaf/578
   can_rcv_filter+0x4af/0x8c0
   can_receive+0x28d/0x3c0
   can_rcv+0x2a9/0x310
   __netif_receive_skb_one_core+0x21a/0x260
   process_backlog+0x210/0x760

Besides this, the lists of a device are protected by the rcvlists_lock
of the namespace that is passed in. Callers which pass dev_net(dev) read
it at different times, so the same lists may be modified under the locks
of different namespaces while the device is moved.

Taking RTNL in these release paths is no option: raw_bind(),
raw_setsockopt() and raw_release() already hold RTNL while adding and
removing up to CAN_RAW_FILTER_MAX filters per socket, which unprivileged
users can trigger repeatedly and which makes RTNL a global bottleneck.

Instead fix the root cause and add a spinlock to struct
can_dev_rcv_lists, which protects the receive lists of a CAN device or
the 'any' CAN device lists of a namespace. It is initialized in
can_set_ml_priv(), which is used by all CAN network devices. With this,
can_rx_unregister() finds the subscription independently of the
current namespace of the device. The protocols keep the device valid
with their tracked references. The per-netns rcvlists_lock only protects
the receive list statistics anymore, and CAN_RAW, CAN_BCM and CAN_ISOTP
pass the namespace that has been used for can_rx_register().

So isotp_release() and bcm_release() now remove their filters correctly
without RTNL, and raw_release(), raw_setsockopt(), raw_bind() and
isotp_bind() do not need RTNL anymore and add and remove their filters
under lock_sock(). To serialize bind() with NETDEV_UNREGISTER, bind()
publishes the device inside the RCU section of its lookup, and
raw_notify() and isotp_notify() recheck the bound device under lock_sock().
As RTNL does not keep NETDEV_DOWN out of bind() anymore, bind() checks
IFF_UP after publishing the bound device, with a barrier pair against
raw_notify() and isotp_notify(), so a down transition during bind() is
still reported with ENETDOWN.

Fixes: 20bab8b88b ("can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER")
Fixes: 8e8cda6d73 ("can: initial support for network namespaces")
Reported-by: Norbert Szetei <norbert@doyensec.com>
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Cc: stable@vger.kernel.org
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-3-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
874f5f14cf can: isotp: check the return values of can_rx_register() in isotp_bind()
isotp_bind() ignores the return values of can_rx_register() for the RX
and the echo receiver and binds the socket anyway. When a receiver can
not be allocated, bind() succeeds without this receiver, so the socket
does not receive frames or its transmissions time out. isotp_release()
and isotp_notify() later try to remove the missing receiver, which
triggers the "receive list entry not found" warning in
can_rx_unregister().

As the device has been checked before and RTNL prevents a namespace
change during bind(), only -ENOMEM can be returned here.

Check the return values and register the RX receiver as the last step.
The echo receiver is registered first, as it only handles the socket's
own echo frames and does nothing while no transmission is in progress.
So a failed RX registration only needs to remove the echo receiver, and
isotp_rcv() has never processed a frame for this socket.

Set so->ifindex before the registrations, so that a First Frame received
before so->bound is set can be answered with a Flow Control frame and
the RX timeout is started as usual. As the RX receiver is registered
last, this can only happen for a bind() that succeeds. Reset so->ifindex
when bind() fails.

Check IFF_UP only after the receivers have been registered, so that a
bind() that fails on a down device does not report ENETDOWN. As bind()
holds RTNL, the device state can not change in between.

Fixes: e057dd3fc2 ("can: add ISO 15765-2:2016 transport protocol")
Cc: stable@vger.kernel.org
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-2-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Oliver Hartkopp
962947b695 can: replace ARPHRD_CAN type checks with can_get_ml_priv()
Commit 4e096a1886 ("net: introduce CAN specific pointer in the struct
net_device") introduced an explicit way to assign the midlayer private
pointer (dev->ml_priv) to named users like ML_PRIV_CAN. A valid pointer
returned by can_get_ml_priv() therefore identifies a real CAN device.

The referenced commit only converted the j1939 and proc code to this
check, while the other parts of the CAN subsystem still rely on
dev->type == ARPHRD_CAN.

The TUNSETLINK ioctl allows a down TUN/TAP device to set its hardware
type to ARPHRD_CAN while dev->ml_priv remains NULL. Such a repurposed
netdevice passes the ARPHRD_CAN checks.

Commit 8aa59e3559 ("can: af_can: fix NULL pointer dereference in
can_rx_register()") already made can_rx_register() reject such devices.
But can_rx_unregister() still only checks dev->type and dereferences
the NULL ml_priv when it walks the receive lists of the device.

CAN_ISOTP reaches this path: isotp_bind() ignores the return values of
can_rx_register() and binds the socket anyway. When the socket is
released or the device is unregistered, isotp_release() and
isotp_notify() remove the filters that have never been registered and
trigger the NULL pointer dereference in can_rx_unregister(). This only
requires owning a TUN/TAP device or CAP_NET_ADMIN in an unprivileged
user namespace.

Convert the remaining ARPHRD_CAN checks in af_can, bcm, gw, isotp and
raw to can_get_ml_priv().

Fixes: 4e096a1886 ("net: introduce CAN specific pointer in the struct net_device")
Cc: stable@vger.kernel.org
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261027-can-rx-lock-v12-1-eb5afc2d8b9b@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:29 +01:00
Cunhao Lu
b4ebcbbf66 can: dev: can_put_echo_skb(): free skb on invalid echo index
can_put_echo_skb() consumes the skb on all paths except when the echo
index is out of bounds. This leaves ownership with the caller on -EINVAL,
unlike the other error paths, and can leak the skb if the caller expects
consistent semantics.

Free the skb before returning -EINVAL so that all return paths consume it.

Fixes: 6411959c10 ("can: dev: can_put_echo_skb(): don't crash kernel if can_priv::echo_skb is accessed out of bounds")
Cc: stable@vger.kernel.org
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_683AA16E643DE00211CD2FB62991264DC605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

---

FAQ:

Q: `can_skb_init_valid()` directly modifies `skb->data` without checking if
   the SKB is cloned or shared. Is this violating SKB shared buffer rules and
   causing data corruption?

A: The finding about can_skb_init_valid() modifying skb->data on a
   potentially shared buffer is not relevant for this (correct) patch.

   The FDF-flag write in can_skb_init_valid() only matters for PF_PACKET
   use: PF_CAN allocators already set CANFD_FDF. The write exists to
   normalize frames for PF_PACKET observers (tcpdump/Wireshark) so they can
   distinguish classic CAN from CAN FD at the netdev level, and to
   compensate for PF_PACKET senders that omit the bit. That normalization
   is functionally required.

   The shared-buffer concern only becomes realistic through a specific
   chain: a PF_PACKET sender injects a CANFD-sized frame, the CAN driver's
   loopback puts an echo skb back into can_rcv(), and cgw (without
   modfuncs) clones it for forwarding to another interface. Only on that
   second can_skb_init_valid() call is the skb cloned. By then the bit was
   already set on the exclusive skb during the initial xmit path, so the
   flags |= CANFD_FDF write is strictly idempotent for any parallel
   consumer of the shared buffer - no memory-safety or
   information-disclosure consequence. It's a formal violation of the skb
   sharing rules without an observable effect, so the current code can stay
   as-is.

Link: https://lore.kernel.org/all/54a3cc01-abcf-4a33-b932-39bb1f68cdd5@hartkopp.net/
[mkl: convert Oliver's mail to FAQ section]
2026-11-03 19:54:28 +01:00
Cunhao Lu
d4b616a381 can: skb: make CAN skb allocation failure paths IRQ-safe
The CAN skb allocation helpers are used from hardware interrupt receive
handlers. If can_skb_ext_add() fails, they release the newly allocated skb
with kfree_skb(), which is not safe in hardware interrupt context.

Use dev_kfree_skb_any() for the allocation failure paths in
alloc_can_skb(), alloc_canfd_skb(), and alloc_canxl_skb().

Fixes: 96ea3a1e2d ("can: add CAN skb extension infrastructure")
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_C825C17D442F801351CE2FBC4984064B4605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:54:28 +01:00
Cunhao Lu
d743071964 can: skb: make echo skb freeing safe in any IRQ context
can_put_echo_skb() can be called with hardware interrupts disabled. Its
direct drop paths use kfree_skb(), while can_create_echo_skb() uses
kfree_skb() when cloning fails and consume_skb() after a successful clone.
None of these helpers is safe in every IRQ context.

Use dev_kfree_skb_any() for all drop paths and dev_consume_skb_any() when
consuming a successfully cloned skb. This preserves the respective skb drop
and consumed semantics regardless of the caller IRQ context.

Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_E84809CF236D0137885E7E4E4D58340B3208@qq.com
Cc: stable@kernel.org
Fixes: ae64438be1 ("can: dev: fix skb drop check")
Fixes: 0ae89beb28 ("can: add destructor for self generated skbs")
Fixes: 3ccd4c6167 ("can: Unify droping of invalid tx skbs and netdev stats")
Fixes: 39549eef35 ("can: CAN Network device driver and Netlink interface")
[mkl: also convert can_dropped_invalid_skb(), can_dev_dropped_skb()]
[mkl: add stable on Cc + add Fixes tags]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

---

FAQ:

Q: What about the comment in drivers/net/can/virtio_can.c
   virtio_can_start_xmit()? The error handling for virtqueue_add_sgs()
   mentions that can_put_echo_skb() consumes the skb via consume_skb().

A: The comment in virtio_can.c will be updated in a separate series, to
   ease backporting of this patch.

[mkl: add FAQ section]
2026-11-03 19:54:28 +01:00
Kaixuan Li
933bf0fcb3 can: isotp: check the frame type, not just the length
isotp_rcv() separates Classic CAN from CAN FD by skb->len alone:

	if (skb->len != so->ll.mtu)
		return;

	cf = (struct canfd_frame *)skb->data;

A CAN XL frame with cxl->len 4 is CAN_MTU bytes, so it passes, and is then
read as a canfd_frame whose len comes out of canxl_frame.flags: at least
0x80.

Of the paths that follow, only the flow control one uses that length
without bounding it first, so check_pad() walks to 255 over a 16-byte
frame and the caller reports EBADMSG on an unrelated socket.

bcm_rx_handler(), j1939_can_recv(), can_can_gw_rcv() and raw_rcv() check
the frame type here, and can_dropped_invalid_skb() switches on
skb->protocol on the transmit side. isotp_rcv() is the gap.

Fixes: fb08cba12b ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Kaixuan Li <kaixuanli0131@gmail.com>
Reviewed-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260920035626.2581040-1-kaixuanli0131@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:49:14 +01:00
Vincent Mailhol
0fce44e29f can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
Sending a PF_PACKET bypasses the CAN framework logic and can directly
reach a CAN driver's xmit() function. The PF_PACKET framework only
checks that skb->len does not exceed the net_device MTU.

For a CAN device that is not CAN XL capable, anything above CANFD_MTU
(72 bytes) is therefore dropped before it reaches the driver. However,
CAN XL frames are variable length. can_is_canxl_skb() accepts lengths in
the range CANXL_HDR_SIZE + CANXL_MIN_DLEN up to CANXL_MTU, i.e. 13 to
2060 bytes.

As a result, an ETH_P_CANXL skb with a length between 13 and 72 bytes
can pass both the MTU and the can_dropped_invalid_skb() checks.

A driver that does not support CAN XL will interpret canxl_frame->flags
as a length because of the overlap with can_frame->len. And because
CANXL_XLF is set, the resulting length is between 128 and 255. For
drivers that do not check can_frame->len before copying can_frame->data,
as most drivers do, this results in a buffer overflow of up to 247
bytes.

Drop ETH_P_CANXL skbs if the device does not have the CAN_CAP_XL
capability. Keep can_is_canxl_skb() for the validation of CAN XL skbs.

Closes: https://sashiko.dev/#/patchset/20260731-master-v5-0-5b27029dee20@qq.com?part=1
Fixes: fb08cba12b ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/20260731-drop_canxl_frames-v1-1-7387b70353b3@kernel.org
Cc: stable@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2026-11-03 19:48:36 +01:00
Guenter Roeck
fe23bad215 hwmon: (acpi_power_meter) Check for 32-bit and 64-bit unknown ACPI values
According to the ACPI specification (Section 10.4), ACPI Power Meter
objects (_PMC capability fields, _PMM, _GHL, _PAI) report unknown or
unavailable integer values using an integer with all bits set, which can
be either U32_MAX (0xffffffff) or U64_MAX (0xffffffffffffffff) depending
on the DSDT revision.

Currently, only hwmon_power_average checks both 32-bit and 64-bit
unknown sentinels:
- power1_cap_hyst_show() only compares res->caps.hysteresis against the
  32-bit UNKNOWN_HYSTERESIS (0xffffffff), so a 64-bit U64_MAX sentinel
  bypasses the check, overflows when multiplied by 1000, and emits a
  bogus number instead of "unknown".
- power1_accuracy_show() does not check for unknown sentinels at all,
  formatting 0xffffffff as "4294967.295%".
- power_meter_read() does not check min_avg_interval, max_avg_interval,
  avg_interval, min_cap, max_cap, or cap for unknown sentinels, exposing
  scaled or overflowed values (or negative values when cast to signed
  long) to userspace instead of returning -ENODATA.
- get_power_alarm_state() does not check whether resource->cap is
  unknown before comparing resource->power > resource->cap.
- update_meter() passes an unknown caps.sampling_time directly to
  msecs_to_jiffies(), caching sensor readings for weeks on 64-bit builds.

Introduce acpi_power_meter_is_unknown() to check for both U32_MAX and
U64_MAX, and use it across sysfs attribute handlers and meter updates:
- Return -ENODATA in power_meter_read() when numeric power, interval, or
  cap attributes report an unknown value.
- Emit "unknown" in power1_cap_hyst_show() and power1_accuracy_show()
  when hysteresis or accuracy is unknown.
- Avoid comparing against an unknown cap in get_power_alarm_state(),
  returning 0 (no alarm, no error) unless a hardware capping
  notification was latched.
- Skip the sampling_time cache window in update_meter() when
  sampling_time is unknown.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: de584afa5e ("hwmon driver for ACPI 4.0 power meters")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-03 09:40:35 -08:00
Guenter Roeck
847ec34ec2 hwmon: (acpi_power_meter) Prevent spurious power alarm when power is unknown
According to the ACPI specification (Section 10.4.3 _PMM), if an error
occurs while obtaining the power meter reading or if the value is not
available, _PMM returns an integer with all bits set (U32_MAX or
U64_MAX).

In get_power_alarm_state(), update_meter() stores this unknown sentinel
value in resource->power and returns 0. Unlike the hwmon_power_average
handler in power_meter_read(), get_power_alarm_state() does not check
resource->power against UNKNOWN_POWER_32 or UNKNOWN_POWER_64 before
comparing resource->power > resource->cap. Because the sentinel is a
large unsigned integer, the comparison evaluates to true for any valid
cap, falsely reporting an active power alarm to userspace.

Furthermore, get_power_alarm_state() writes resource->power > resource->cap
back into resource->power_alarm, re-latching polled software comparisons
as if a hardware METER_NOTIFY_CAPPING event had occurred and causing the
next power1_alarm read to falsely report an alarm even after power drops
below cap or becomes unknown.

In addition, alarm attributes should not return error codes when the
alarm status cannot be determined; an inconclusive alarm state should
report 0 (no alarm, no error).

Convert get_power_alarm_state() to return a boolean alarm state. Consume
and clear any latched hardware capping notification in
resource->power_alarm without re-latching software comparisons, and
return false (0, no alarm) when no notification was latched and
resource->power is unknown or updating the meter or cap reading fails.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: de584afa5e ("hwmon driver for ACPI 4.0 power meters")
Fixes: 7532e68f5d ("hwmon: (acpi_power_meter) Fix uninitialized variables")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-03 09:40:35 -08:00
Guenter Roeck
321dcb9ae9 hwmon: (acpi_power_meter) Fix missing locking in sysfs show callbacks and resume
During system resume, acpi_power_meter_resume() calls free_capabilities()
and read_capabilities() without acquiring resource->lock. Because ACPI
notifications run on the non-freezable kacpi_notify_wq workqueue, a
concurrent METER_NOTIFY_CONFIG notification during resume can race with
acpi_power_meter_resume() and trigger a double-free or use-after-free on
the model_number, serial_number, and oem_info strings as well as
concurrently overwrite resource->caps. When CONFIG_SUSPEND_FREEZER is
disabled, concurrent sysfs readers can also dereference the freed
capability strings mid-update.

In addition, none of the extra sysfs attribute show callbacks acquire
res->lock:
- power1_average_min_show() and power1_average_max_show() read the 64-bit
  res->trip[] entries twice without locking while set_trip() modifies
  them under res->lock (including temporarily storing a candidate value
  before evaluating _PTP and rolling it back on failure). On 32-bit
  architectures this exposes torn 64-bit reads, and on all architectures
  it exposes uncommitted trip values and a TOCTOU race between the < 0
  check and multiplication (emitting "-1000" instead of "unknown" if
  set_trip() rolls back to -1).
- power1_model_number_show(), power1_oem_info_show(),
  power1_serial_number_show(), power1_cap_hyst_show(),
  power1_accuracy_show(), and power1_is_battery_show() read capability
  strings and 64-bit capability fields without synchronization against
  resume updates.

Acquire resource->lock using guard(mutex) in acpi_power_meter_resume()
and in all extra sysfs show callbacks. Also return -ENODATA in the
capability string show callbacks if a string pointer is NULL after a
failed capability re-read.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: de584afa5e ("hwmon driver for ACPI 4.0 power meters")
Fixes: 16746ce8ad ("hwmon: (acpi_power_meter) Replace the deprecated hwmon_device_register")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-03 09:40:35 -08:00
Linus Torvalds
05441d697f Coccinelle patches for 7.4-rc1
This contains three new semantic patches
 * From Joe Perches for using the typed devm_kmalloc_obj-family of allocations
 * From Ella Ma for detecting invalid use of __cleanup
 * From Alejandro Colomar for adding uses of ARRAY_END
 
 Signed-off-by: Julia Lawall <julia.lawall@inria.fr>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEnGZC8gbRfLXdcpA0F+92B3f5RZ0FAmrnzJEACgkQF+92B3f5
 RZ1bUhAAgfljTSX4tonrNyH7bSPa3QeGQmx16G5pDsn2CdLiVWN6w9Qn8L+vT81i
 P3/67FUzl1/bRxB0JcY2GADr+0eSde4fYwGo3PswEmpa/B4QHc/I3fqnt+1oE+9y
 oipS7ZlO7ZRTrdEx55Q9X6EMG/Dvvie+C8It2IBaSmNvfAGkfyjztQ27L2p4jBM2
 k3s2itN2k7p45h5ucXbBQn2hLl4LfS1PvuOG1jPMmQ6+xHTmT6jUyKVbj6gaUqfZ
 hB/trnKA8GrSUcS27Be/lyGO+sFc+wASzOWaqJxJjGShdWQfwX43qcMT8REj2GOy
 nO9jnRixIQ/d9bfJbXzGlJYMEQzEyciKdVf6RRrYATWIuiujYlPRVjJ3SxcJnmWT
 sCwJxQT03C0nRd0jRkPY+Dn5QXlrdtkoOTlq20knqHBUEklFB6gX8kYSiP1O7S4W
 sa+0eqZmyduoN382wH3eDHSccku07F0Hcejp6CMJHIW/udjwj23lQ5NTh6RRDPl0
 wm6O/xms9dDLawbd9HnpF3AsywQ6eb10EVgstT/7YpaGCh6vHvoV0vnstTMy6PsE
 QKVq1ePLVmGMfVugjxBENkVmxteLjoqUgxNJE/S4EqlypNhQ637HxBKvnPIgFW7S
 id5KNRMKljcRsUaZgSJyCQNzljkh0e93K/5EHaysfgJ3d0Un/g8=
 =pRgC
 -----END PGP SIGNATURE-----

Merge tag 'cocci-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlawall/linux

Pull Coccinelle updates from Julia Lawall:
 "This contains three new semantic patches

   - use the typed devm_kmalloc_obj-family of allocations (Joe Perches)

   - detect invalid use of __cleanup (Ella Ma)

   - add uses of ARRAY_END (Alejandro Colomar)"

* tag 'cocci-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlawall/linux:
  coccinelle: free: add a checker for `__cleanup(kfree)` usage
  coccinelle: Add devm_kmalloc_objs conversion script
  scripts/coccinelle: improve efficiency of array_end.cocci
  scripts/coccinelle: Add script for using ARRAY_END()
2026-11-03 08:36:32 -08:00
Linus Torvalds
7d1471e509 This is mostly a huge wave of LLM-driven fixes
A few exceptions:
 - a new vsock transport was added, since it's a variant of the existing
 fd/tcp transport there is little harm in taking it in
 - there's an incomplete fix for when file actual size doesn't match
 the size attribute (e.g. exports of sysfs), the fix addresses when
 st_size > actual size with cache=none but just about everything else
 is still broken (st_size=0 with actual data regardless of cache, or
 with data cache st_size > actual is still wrong and so are symlinks
 with 0 size)... Maybe at some point I'll find time to understand how
 netfs works and address these :|
 - some fixes for the usbg transport by its author, thank you!
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAmrpzl8ACgkQq06b7GqY
 5nA7SxAAmThz0j/BVRmej5Ii8ZWE18tibAG5o4EgEqTX15HfaePc3BxaogayrZkh
 xueb3ZBqN0jdKqScIL+6SeQcFwskoSohfZeFv5c75zafw+2x9MrmxVLeJw0oU2N0
 vybsMzLJOjMX7gRP3FUangqKlIoeQVOuP8XzYsbqLziMknQp4N2cAsZ/seuZOo+H
 +JBDWry3qok39TLEhIcFEACW+X3RNW2asRBtDNvjGrASBWRZsJSNnLdSIZ00XYPe
 BYddasTbBjkX3cdyXfEdtcYRb3BNmcNhdBEVpEuhVyUc/qL+Aft0lBTbIt1CIbdO
 LOmX/vbCvj4kTee7SjkE59aFp84wcZ+tYx0+4RmZBQPJE8FbqxMrtQ0i7Z6XNee4
 mgugn5OnnH37Fw8z3EhRMVDZrNXjaS7tl5gJxfEWuyn6RdKWWICWlm8K5P58WGy3
 HOU21/uOLxACLoAZLqudjA6CfjGoJXuk9T9+cnh4lqu9ghPgfY39lWVjXKSNpjg7
 4A1DNRn6fwfJiC7JtTlfbV9xtHmdsGV5syClKWNVGaCLUp+KDCs3J3aigHiUVt+y
 biBeB+yvU+0NkvAmzKUv97X7wBCzW0HgruZQQJ1rSEBAtrlaC4ev5CyjBOhn3//P
 wZ7wvAmW2fr2INo0nE4usv46jF6emLWH/kbWAKHzAW/BzFGaiUw=
 =oC41
 -----END PGP SIGNATURE-----

Merge tag '9p-for-7.4-rc2' of https://github.com/martinetd/linux

Pull late 9p updates from Dominique Martinet:
 "This is mostly a huge wave of LLM-driven fixes. At least the LLM fixes
  sort of slowed down recently? Or maybe it's just the time of the cycle
  and/or I got used to it, time will tell...

  A few exceptions:

   - a new vsock transport was added, since it's a variant of the
     existing fd/tcp transport there is little harm in taking it in

   - there's an incomplete fix for when file actual size doesn't match
     the size attribute (e.g. exports of sysfs).

     The fix addresses when st_size > actual size with cache=none but
     just about everything else is still broken (st_size=0 with actual
     data regardless of cache, or with data cache st_size > actual is
     still wrong and so are symlinks with 0 size)...

     Maybe at some point I'll find time to understand how netfs works
     and address these :|

   - some fixes for the usbg transport by its author, thank you!"

* tag '9p-for-7.4-rc2' of https://github.com/martinetd/linux: (39 commits)
  9p: optimize p9_fcall struct
  9p: reject RERROR/RLERROR with zero errcode
  9p: do not store the create fid on special files
  9p: fall back to the normal open path for non-regular files
  9p: don't decrement a server-owned zero nlink
  9p: fix kernel-doc warning for enum p9_session_flags
  9p: treat read return values of 0 as EOF
  9p/xen: validate the response size from the backend
  9p: fix typo in file header comments
  9p: remove duplicated assignment in v9fs_fill_super()
  9p: fix typos and wrong parameter docs in vfs_inode.c
  9p: fix header guard comment in acl.h
  net/9p/usbg: clear stale client pointer on close
  net/9p/usbg: remove bogus context initialization in alloc_requests
  net/9p/usbg: fix out_req buffer leak in disable_usb9pfs
  net/9p/usbg: call disable_usb9pfs() from usb9pfs_disable()
  net/9p/usbg: always reset completion when disconnecting
  net/9p/usbg: set client to Disconnected on usb9pfs_disable
  net/9p/usbg: also disable endpoints on p9_usbg_close
  net/9p/usbg: Fix use-after-free in disable_usb9pfs()
  ...
2026-11-03 08:32:35 -08:00
Linus Torvalds
51628610f9 vfs: fix take_dentry_name_snapshot() semantics
The take_dentry_name_snapshot() function would keep trying to take a
reference on a dentry name forever, even if that dentry had been
released and the dentry name would never become valid.

All normal users held a reference to the dentry, but this "dentry name
is dead" could hit the overlayfs RCU walk case, and Amir fixed it by
adding a new try_take_dentry_name_snapshot() that returns on failure.
See commit 15c6bd5cf1 ("vfs: add try_take_dentry_name_snapshot()").

However, that fix was uncomfortably ugly, and the new "try" version was
subtly buggy in that it would also fail spuriously during a rename. The
only current user of that doesn't really care: a spurious failure would
result in the lookup just exiting RCU mode and being retried with the
dentry ref held (using the non-try version), but this all just rubbed me
the wrong way.

Instead of introducing a new and differently buggy helper, this just
makes take_dentry_name_snapshot() deal with all these situations
correctly.

It does that by instead of retrying when the external name reference
cannot be taken, it now retries purely based on the dentry sequence
counter. That means that if the external name reference failed due to a
rename, we will correctly retry it, but if it fails because the dentry
is dead and the name really is gone, it will now return that failure
rather than looping forever.

In this model, take_dentry_name_snapshot() will never return a failure
when a dentry ref is held, so the existing non-overlayfs users don't
need to care and they can safely ignore the return value.

And users that don't hold a reference (ie currently only that overlayfs
case) can use the improved take_dentry_name_snapshot() function safely
and it won't loop forever when racing with the dentry being free'd.

To make this all really robust and easy to use for any possible new use
cases, the failure case will not just return false, but also make sure
that the returned name will be empty, and that you can still call
release_dentry_name_snapshot() on the name.

But since there won't actually be anything to release on failure, you
can also do what overlayfs does: return an error and *not* call the
release function.

IOW, instead of two different functions that each had their own problem
cases, we're now back to just one single function that is robust and
easy to use in all situations. Knock wood.

Link: https://lore.kernel.org/all/CAHk-=wiPhTLn1p0ZHx-7SMdk4_zazqDK1k7MMEn9scRfqeDgtw@mail.gmail.com/
Fixes: 15c6bd5cf1 ("vfs: add try_take_dentry_name_snapshot()")
Cc: Amir Goldstein <amir73il@gmail.com>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-11-03 08:28:20 -08:00
Kyle Zeng
647b81ddef tcp: wait for TIME_WAIT teardown before freeing per-netns ehash
inet_twsk_kill() removes a TIME_WAIT socket from the established hash
before it finishes using the ehash lock, hashinfo and bind tables, and
before it drops the death-row reference. A running timer can therefore
unhash its socket before inet_twsk_purge() reaches it. The purge cannot
synchronize with that timer, and tcp_sk_exit_batch() can free the
private ehash and hashinfo while inet_twsk_kill() is still using them.

An unprivileged reproducer using user and network namespaces, a private
TCP ehash and a FIN_WAIT2 timer triggers a KASAN slab-use-after-free in
inet_twsk_kill(). The allocation and free stacks point to
inet_pernet_hashinfo_alloc() and inet_pernet_hashinfo_free().

Wait for an RCU grace period after purging the whole batch, if one
netns in the batch uses a private ehash. TIME_WAIT removal runs with
bottom halves disabled, so this also waits for removers that were
already invisible to the purge. Keep the wait under
tcp_exit_batch_mutex, before freeing any private hashinfo.

The same window exists with the shared tcp_hashinfo. There, the
hashinfo memory stays valid, but tcp_sk_exit_batch() can decrement
tcp_death_row.tw_refcount from 2 to 1 before inet_twsk_kill() drops its
own reference. This triggers the WARN_ON_ONCE() in tcp_sk_exit_batch(),
then a refcount_t "decrement hit 0" warning from inet_twsk_kill().

Adding a grace period for the shared case would be costly on busy
hosts. It is not needed: struct net is freed by a later cleanup_net(),
after the synchronize_rcu() in ops_undo_list(), so inet_twsk_kill()
can safely drop the last tw_refcount reference itself.
Use refcount_dec_if_one() and only warn if tw_refcount is not 1
after a grace period.

Fixes: d1e5e6408b ("tcp: Introduce optional per-netns ehash.")
Signed-off-by: Kyle Zeng <kylebot@openai.com>
[edumazet: only call synchronize_net() if one netns in the batch uses a private ehash,
 use refcount_dec_if_one() to avoid a false WARN with the shared ehash]
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261030075843.2567707-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 15:43:22 +01:00
Kefeng Wang
7ba9663607 xfs: kill xfs_trans_set/clear_context() helpers
Open code the helpers so that tp->t_pflags access is explicit, reducing
the risk of misusing them outside the transaction owner thread as seen
in xfs_btree_split_worker().

Suggested-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:39:53 +01:00
Christoph Hellwig
30bb61651d xfs: fix recovery of partial attr removals
When running xfs/753 on parent pointer-enabled file systems with DEBUG
enabled, log recovery will eventually crash after a few dozen iterations
due to an ASSERT that XFS_ATTR_INCOMPLETE is not already set when
xfs_attr3_leaf_setflag is called:

XFS: Assertion failed: (entry->flags & XFS_ATTR_INCOMPLETE) == 0, file: fs/xfs/libxfs/xfs_attr_leaf.c, line: 3045

This is because parent pointer use logged attributes, and the attribute
intents do not track the work that has been done as the transaction
rolls, and the recovery mechanism is to run the operation from scratch.
Because of this various places check for XFS_DA_OP_RECOVERY skip work
already done.  But while recovery tolerates an attribute already fully
removed, it currently trips the above assert for an attribute that
already has the INCOMPLETE bit set, but still exists.  Fix this by
handling the case like all the others.

Fixes: 1d08e11d04 ("xfs: Implement attr logging and replay")
Cc: stable@vger.kernel.org # v5.19
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:35:15 +01:00
Paolo Abeni
7b1fd97321 Merge branch 'inet-fix-lockless-ehash-walk-races'
Hyunwoo Kim says:

====================
inet: fix lockless ehash walk races

Fix two issues in lockless ehash walks. Reject unhashed sockets after
taking a reference in established lookups, and restore the acquire/release
ordering around refcount publication and acquisition.

v4: https://lore.kernel.org/r/20261026003804.61923-1-imv4bel@gmail.com
v3: https://lore.kernel.org/r/20261024053720.1147022-1-imv4bel@gmail.com
v2: https://lore.kernel.org/r/20261023052542.3505250-1-imv4bel@gmail.com
v1: https://lore.kernel.org/r/ath58Egc-oI6p3Jl@v4bel
====================

Link: https://patch.msgid.link/20261029214219.1035176-1-imv4bel@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 15:33:16 +01:00
Hyunwoo Kim
5b5d8f351d net: restore refcount ordering for lockless socket access
Before commit fb041bb7c0 ("locking/refcount: Consolidate implementations
of refcount_t"), default builds implemented refcount_inc_not_zero() using
atomic_add_unless(), which provided full memory ordering on success. The
commit removed that ordering on weakly ordered architectures, allowing
accesses after a successful reference acquisition to be reordered before
it.

Use refcount_inc_not_zero_acquire() in the IPv4 and IPv6 established
lookups and in inet_twsk_purge(), where the socket is validated again
after taking a reference.

bpf_sk_assign() can receive a socket pointer obtained through BTF
without a reference. Use acquire ordering when it takes its own reference
for a refcounted socket.

Use refcount_set_release() when setting refcounts in the SYN cookie,
TCP Fast Open, request migration, and TIME_WAIT paths. Keep the existing
TIME_WAIT smp_wmb(), which separately orders the refcount store before
ehash publication.

Fixes: fb041bb7c0 ("locking/refcount: Consolidate implementations of refcount_t")
Fixes: 27e5203bd9 ("bpf: Change bpf_sk_assign to accept ARG_PTR_TO_BTF_ID_SOCK_COMMON")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261029214219.1035176-3-imv4bel@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 15:33:13 +01:00
Hyunwoo Kim
4e2b3ef19e inet: reject unhashed sockets during established lookups
TCP established ehash lookups are lockless. The socket caches involved
use SLAB_TYPESAFE_BY_RCU, so memory can be reused before an RCU reader
that retained its old address has finished.

After a tuple match, __inet_lookup_established() and
__inet6_lookup_established() acquire a reference and repeat the tuple
check. They do not check whether the new object is hashed. If the
address is reused for a socket with the same tuple, the lookup can
acquire a reference to the new object and return it while its nulls node
is unhashed.

A PoC that drives reuse with a SYN cookie request socket reproduced the
crash. The new request socket is unhashed and has a NULL rsk_listener.
A lookup that had loaded the address of the old request socket acquired
the reference published by tcp_get_cookie_sock() and returned the new
object. tcp_v4_rcv() then read sk_state through the NULL listener.

The resulting crash was:

  BUG: kernel NULL pointer dereference, address: 0000000000000012
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  ...
  Oops: Oops: 0000 [#1] SMP NOPTI
  CPU: 4 UID: 0 PID: 0 Comm: swapper/4 Not tainted 7.3.0-00591-g0e135910deec #1 PREEMPT(lazy)
  ...
  RIP: 0010:tcp_v4_rcv+0x44e/0x1280
  ...
  R10: 0000000000000001 R11: 00000000024ca8c0 R12: 0000000000000000
  ...
  CR2: 0000000000000012 CR3: 0000000103d50004 CR4: 0000000000770ef0
  ...
  Call Trace:
   <IRQ>
   ? raw_local_deliver+0xae/0x240
   ip_protocol_deliver_rcu+0x2d/0x180
   ip_local_deliver_finish+0x84/0x100
   ip_sublist_rcv_finish+0x5f/0x70
   ip_sublist_rcv+0x12a/0x1d0
   ip_list_rcv+0xfd/0x130
   __netif_receive_skb_list_core+0x223/0x250
   netif_receive_skb_list_internal+0x1d2/0x2c0
   ? try_fill_recv+0x39/0x7b0
   napi_complete_done+0x74/0x170
   virtnet_poll+0x445/0x600
   __napi_poll+0x27/0x1e0
   net_rx_action+0x2fe/0x3b0
   handle_softirqs+0xc2/0x2c0
   __irq_exit_rcu+0x74/0xd0
   common_interrupt+0x7f/0x90
   </IRQ>
  ...
  Kernel panic - not syncing: Fatal exception in interrupt

After taking a reference, check whether the nulls node is unhashed in
both IPv4 and IPv6 established lookups. If it is unhashed or the tuple
no longer matches, drop the reference and restart the lookup.

Lookups racing with the TIME_WAIT hashdance, or with a request being
replaced by its child, now restart and find the new socket instead of
returning the old one.

Request sockets that were never inserted into ehash can have a nonzero
refcount, and a stale lookup can hold a transient reference. Therefore,
when SYN cookie, Fast Open, and request migration paths fail after
setting a nonzero refcount, release the references held by those paths
with reqsk_put() instead of freeing the request directly.

Fixes: 079096f103 ("tcp/dccp: install syn_recv requests into ehash table")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261029214219.1035176-2-imv4bel@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 15:33:13 +01:00
Daejun Park
9cc3b0eda9 xfs: make pNFS LAYOUTCOMMIT stable the way fdatasync does
Every LAYOUTCOMMIT commits a synchronous transaction and forces the
log. fdatasync after the same overwrite does not, because timestamps
alone do not set ili_datasync_seq.

Do what fdatasync does. Commit without XFS_TRANS_SYNC, force the log up
to ili_datasync_seq, and flush the data device cache if that wrote no
iclog. Conversions and size changes still force the log. As with
fdatasync, a crash before the next log write can lose the new
timestamps and the change attribute that nfsd derives from the ctime.

Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:15:36 +01:00
Daejun Park
199eee7c67 xfs: add datasync and log_flushed arguments to xfs_log_force_inode()
Add datasync and log_flushed arguments to xfs_log_force_inode() and
move the body of xfs_fsync_flush_log() into it. The next patch needs a
datasync log force in the pNFS LAYOUTCOMMIT path. xfs_file_fsync()
calls it instead, and the other callers pass false and NULL. No
functional change.

Suggested-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20261014130124.GA15407@lst.de
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:15:36 +01:00
Daejun Park
23ba20ef28 xfs: take the invalidate lock while mapping a pNFS layout
xfs_fs_map_blocks() flushes the page cache under the iolock, but a
write fault takes only the invalidate lock. A fault on a shared mapping
can then add a delalloc extent before the range is mapped. That trips
an ASSERT, or nfsd warns and refuses the layout.

Take the invalidate lock with the iolock, as __xfs_file_fallocate()
does. Not for stable: pNFS already leaves local writers to shared
mappings unsynchronized.

Suggested-by: Darrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/20260519145949.GH9555@frogsfrogsfrogs
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:15:36 +01:00
Daejun Park
29f3c1be4e xfs: clamp the pNFS layout range to the maximum file size
xfs_fs_map_blocks() lets two bad layout ranges through. An offset of
2^63 or more is negative and passes "offset > limit". A length above
the limit, such as NFS4_UINT64_MAX, wraps "offset > limit - length"
and stays unclamped. With NFS4_UINT64_MAX, a read layout is built from
an uninitialized mapping.

Reject a negative offset and one at the limit, and clamp the length.
This needs "xfs: cap the block count of xfs_iomap_write_direct() at one
extent".

Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Pankaj Raghav <p.raghav@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:15:36 +01:00
Daejun Park
66d1ce09eb xfs: cap the block count of xfs_iomap_write_direct() at one extent
xfs_iomap_write_direct() reserves blocks for the whole count in an
unsigned int. For a pNFS layout the client chooses that count, and an
RW LAYOUTGET for 16 TiB wraps the reservation and shuts XFS down.

xfs_bmapi_write() maps at most XFS_MAX_BMBT_EXTLEN blocks here, so cap
the count at that. nfsd asks again for the rest. The other callers get
the same mapping as before.

Suggested-by: Darrick J. Wong <djwong@kernel.org>
Suggested-by: Christoph Hellwig <hch@lst.de>
Suggested-by: Pankaj Raghav <p.raghav@samsung.com>
Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:15:30 +01:00
Daejun Park
d8c2bc8846 xfs: clamp a pNFS LAYOUTCOMMIT extent before computing its end
xfs_fs_commit_blocks() adds the client's length to the offset before it
clamps the end to the file size. A large length wraps the sum and
reaches xfs_iomap_write_unwritten() unclamped. With the previous two
patches the LAYOUTCOMMIT then fails with -EIO and converts nothing.

Clamp the length first.

Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Pankaj Raghav <p.raghav@samsung.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:14:20 +01:00
Daejun Park
bcf0b7f18a xfs: refuse a pNFS LAYOUTCOMMIT of a range without blocks
A client can commit a hole in a LAYOUTCOMMIT, because nfsd does not
check the extents against its layouts. xfs_iomap_write_unwritten() then
allocates written blocks there. A large hole overruns the block
reservation and shuts XFS down. A small one exposes stale data.

Refuse such a range with -EIO, using XFS_BMAPI_CONVERT_ONLY.

Link: https://lore.kernel.org/r/20261014130834.GB15773@lst.de
Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:14:20 +01:00
Daejun Park
f3ca3498df xfs: add a flag to convert unwritten extents without allocating blocks
xfs_bmapi_write() with XFS_BMAPI_CONVERT also allocates blocks for
holes and delalloc extents in the range. Add XFS_BMAPI_CONVERT_ONLY for
callers that may only convert already allocated blocks. It stops at a
hole or delalloc extent, and returns -ENOSR if it stops before mapping
anything.

Marked for stable because "xfs: refuse a pNFS LAYOUTCOMMIT of a range
without blocks" needs it.

Suggested-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20261013120359.GB2944@lst.de
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Pankaj Raghav <p.raghav@samsung.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:14:20 +01:00
Daejun Park
8b8e265991 xfs: mark the inode preallocated for pNFS write layouts past EOF
xfs_fs_map_blocks() marks the inode XFS_DIFLAG_PREALLOC only when it
allocates blocks for a write layout. A write layout past EOF can also
hand out allocated blocks, such as speculative preallocation. blockgc
then frees them under the layout, and another file may get them.

Mark the inode whenever a write mapping ends past EOF.

Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Reported-by: Chuck Lever <cel@kernel.org>
Link: https://lore.kernel.org/r/4de5356f-bc4d-4f1a-9c81-fce09b1b46fd@slotpi15m67
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Pankaj Raghav <p.raghav@samsung.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:14:20 +01:00
Nguyen Dinh Phi
c0ef6144b4 vsock: reject negative tv_usec in SO_VM_SOCKETS_CONNECT_TIMEOUT
The timeval validation checks tv_usec < USEC_PER_SEC but not
tv_usec >= 0, so a negative tv_usec makes the timeout computation
wrap into a bogus value, later tripping "schedule_timeout: wrong
timeout value" instead of being rejected.

Fixes: d021c34405 ("VSOCK: Introduce VM Sockets")
Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.com>
Link: https://patch.msgid.link/20261030064428.73930-1-phind.uet@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 15:10:57 +01:00
Reid Downing
b7eb276a39 xfs: fix wrong compat fields in xfs_ioctl32_bstat_copyin()
bs_blocks and bs_xflags were both read from bstat32->bs_size.
Read each one from its own field instead.

Fixes: e94fc4a43e ("[XFS] Add compat handlers for swapext ioctl")
Cc: stable@vger.kernel.org # v2.6.29
Signed-off-by: Reid Downing <skibletz@gmail.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 15:07:14 +01:00
Hungyu Lin
581230d2ec inotify: do not coalesce rename events
inotify compares the mask, watch descriptor and name when coalescing
adjacent unread events, but ignores their rename cookies. Distinct
IN_MOVED_FROM events can therefore be coalesced, losing the cookie needed
to match a later IN_MOVED_TO event.

For example, watch two directories with IN_MOVE. Move an entry from the
first directory into an unwatched directory, recreate it under the same
name, then move it from the first directory into the second watched
directory before reading the events. The second IN_MOVED_FROM is merged
with the first, while the IN_MOVED_TO retains the second rename's cookie.
Userspace can no longer pair the second rename's events.

The original inotify implementation compared cookies before coalescing.
The fsnotify conversion lost this comparison. Do not coalesce
IN_MOVED_FROM or IN_MOVED_TO events, which carry the identity of their
respective renames. Leave coalescing of other event types unchanged.

Fixes: 63c882a054 ("inotify: reimplement inotify using fsnotify")
Cc: stable@vger.kernel.org
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Link: https://patch.msgid.link/20261027192027.8617-1-dennylin0707@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-03 14:05:25 +01:00
Josef Bacik
3f57fc2c49 ext2: only flush DIRSYNC directories on every change
Every change of an ext2 directory is written to disk before the system call
returns, whether the directory is DIRSYNC or not: its pages with
filemap_write_and_wait() and its inode with sync_inode_metadata().

Writes which reach the device for 2000 files, and 200 directories, in a
directory without DIRSYNC, with the flusher turned off:

            create   rename   unlink   mkdir
    before    4000     8000     4000     800
    after        0        0        0       0

In a directory with chattr +D the numbers are those of "before", before and
after.

commit bc943f4872 ("ext2: Don't flush page immediately for DIRSYNC
directories") moved the flush from ext2_commit_chunk() to the new
ext2_handle_dirsync().  The IS_DIRSYNC() check which was around it didn't
move along.

Fix by putting the check into ext2_handle_dirsync().

Fixes: bc943f4872 ("ext2: Don't flush page immediately for DIRSYNC directories")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://patch.msgid.link/20261027-b4-ext2-dirsync-v1-1-3dcd012d518d@toxicpanda.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-03 14:04:11 +01:00
Zenghui Yu (Huawei)
1a577f9402 virtio_pci: don't take the MSI mutex under cpu_hotplug_lock
Lockdep reports the following circular locking dependency when a virtio-net
device is probed with lockdep enabled on a system whose devices sit behind
an IOMMU:

    ======================================================
    WARNING: possible circular locking dependency detected
    7.3.0-rc1+ #84 Not tainted
    ------------------------------------------------------
    kworker/u34:0/57 is trying to acquire lock:
    ffff800104f83ee8 (&md->mutex){+.+.}-{4:4}, at: msi_domain_get_virq+0xf0/0x118

    but task is already holding lock:
    ffffc00081edd930 (cpu_hotplug_lock){++++}-{0:0}, at: cpus_read_lock+0x10/0x1c

    which lock already depends on the new lock.

    Chain exists of:
      &md->mutex --> &group->mutex --> cpu_hotplug_lock

The cycle is composed of three dependencies:

* cpu_hotplug_lock -> &md->mutex (which triggers the splat). virtio_net's
  init_vqs() calls cpus_read_lock() around virtnet_set_affinity(), which
  reaches vp_set_vq_affinity(). That calls pci_irq_vector(), which takes
  the per-device MSI mutex (&dev->msi.data->mutex) via
  msi_domain_get_virq().

* &md->mutex -> &domain->mutex -> &group->mutex.  MSI-X allocation of any
  device behind the IOMMU holds the MSI mutex while allocating interrupts
  through the IRQ domain hierarchy. The MSI parent domain (GICv2m, or ITS
  likewise) calls iommu_dma_prepare_msi() from its .alloc() to map the MSI
  doorbell, which takes the IOMMU group mutex.

* &group->mutex -> cpu_hotplug_lock. bus_iommu_probe() calls
  iommu_setup_dma_ops() under the group mutex; initializing the IOVA
  rcaches registers a cpuhp instance, which takes cpu_hotplug_lock.

The cycle only became complete since commit 288683c92b ("iommu: Make
iommu_dma_prepare_msi() into a generic operation"), where
iommu_dma_prepare_msi() switched to use the group mutex.

pci_irq_vector() is a pure lookup of a vector that is bound to the
queue for the whole lifetime of the queue, so there is no reason to
take the MSI mutex for it from cpu hotplug locked contexts.

Cache the IRQ number in virtio_pci_vq_info {} at vector binding time and
make vp_set_vq_affinity() use the cached value.

This also covers the CPU hotplug callbacks
(virtnet_cpu_online/virtnet_cpu_dead), which call virtnet_set_affinity()
with cpu_hotplug_lock already held.

Signed-off-by: Zenghui Yu (Huawei) <zenghui.yu@linux.dev>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261029121648.22155-1-zenghui.yu@linux.dev>
2026-11-03 07:32:14 -05:00
zhang jiao
92368f4fb8 virtio_ring: Initialize id field in packed indirect descriptors
The virtqueue_add_indirect_packed() function fills an indirect
descriptor table with addr, len, and flags for each entry, but does
not initialize the id field of struct vring_packed_desc. The table is
allocated via kmalloc() (not kzalloc) and then DMA-mapped with
DMA_TO_DEVICE, making the uninitialized 2-byte id field of each
descriptor readable by the device.

This leaks kernel heap memory to the device for every packed indirect
descriptor entry. A malicious or compromised device could extract heap
contents by reading the id fields from the DMA-mapped indirect
descriptor tables. This affects all virtio devices that use packed
virtqueues with indirect descriptors, which is the common configuration
for modern virtio devices.

Fix this by explicitly initializing desc[i].id to zero in the
descriptor filling loop. The id field is unused in indirect descriptor
table entries per the virtio specification (only the head descriptor in
the main ring uses id for buffer identification), so setting it to zero
is semantically correct.

This matches the split ring path where all four fields of struct
vring_desc (addr, len, flags, next) are explicitly written in
virtqueue_add_desc_split().

Signed-off-by: zhang jiao <zhangjiao2@cmss.chinamobile.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261029072511.851-1-zhangjiao2@cmss.chinamobile.com>
2026-11-03 07:32:14 -05:00
Jia Jia
058fc59326 vhost-scsi: fix page reference leak in misaligned I/O fallback
iov_iter_get_pages2() returns a byte count that excludes the offset into
the first page, but also returns a reference to that page in pages[].

On the misaligned-I/O fallback, vhost_scsi_revert_map_iov_to_sgl() puts
pages already added to the SG list. The cleanup loop starts at
pages[npages], but accounts for its first page as PAGE_SIZE bytes
rather than PAGE_SIZE - offset. If the remaining data starts at a
non-zero offset, it can finish one page early and leave a page reference
behind.

Use PAGE_SIZE - offset for the first remaining page and clear offset for
later pages, as in the mapping loop. Without this, each affected request
leaks one page reference.

Fixes: bca939d5bc ("vhost-scsi: Dynamically allocate scatterlists")
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261023104035.6686-1-physicalmtea@gmail.com>
2026-11-03 07:32:14 -05:00
chenglong.ma
bb2e6f1665 vduse: fix VA/PA confusion in the coherent page fault path
vduse_domain_get_coherent_page() assumes that iotlb entries above
bounce_size were installed by vduse_domain_alloc_coherent(), so it
treats map->addr as a physical address. But vduse registers with
use_va = true, and when the device is bound to vhost_vdpa,
vhost_vdpa_va_map() stores a userspace virtual address in map->addr,
which vduse_domain_set_map() then copies into the same iotlb. A
process holding the domain file descriptor across a rebind can
therefore fault in an arbitrary physical page with read/write
access, ignoring the entry permissions.

Additionally, since the domain file mmap lacks VM_IO, the domain
file itself can be mapped and passed to vhost_vdpa_va_map(),
producing self-referential entries that bypass the coherent path
check.

To fix, only translate entries whose backing file is the domain
file itself in vduse_domain_get_coherent_page(), reject such
entries in vduse_domain_set_map() since only external mappings
should be imported, and set VM_IO on the domain file mmap so
vhost_vdpa_va_map() refuses to map it in the first place.

Fixes: 8c773d53fb ("vduse: Implement an MMU-based software IOTLB")
Cc: Xie Yongji <xieyongji@bytedance.com>
Cc: stable@vger.kernel.org
Reported-by: chenglong.ma <longpareto@gmail.com>
Signed-off-by: chenglong.ma <longpareto@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-03 07:32:14 -05:00
Thorsten Blum
0f7bf47f5a hwrng: virtio - prevent use-after-free after a failed restore
remove_common() frees the driver data during freeze, but does not clear
vdev->priv, which points to freed memory. If probe_common() then fails
during restore, a later remove or freeze can dereference the dangling
pointer.

Clear vdev->priv on the probe_common() error cleanup path and before
freeing the driver data in remove_common(). Also reset the device and
return early from remove_common() if vdev->priv is already NULL for a
safe teardown after a failed restore.

Fixes: 08e53fbdb8 ("virtio-rng: support multiple virtio-rng devices")
Cc: stable@vger.kernel.org
Signed-off-by: Thorsten Blum <blum@kernel.org>
Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261016103640.4989-2-blum@kernel.org>
2026-11-03 07:32:14 -05:00
Wei-Shuo Chen
57c1c0d172 virtio: use consistent virtqueue terminology
Use virtqueue consistently in the notify function comments
across the MMIO and PCI transports.

Assisted-by: LLM

Signed-off-by: Wei-Shuo Chen <tavhadia@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261016072318.24015-1-tavhadia@gmail.com>
2026-11-03 07:32:14 -05:00
Mingbing Zhai
161aa708b0 virtio_balloon: initialize wakeup_lock before virtqueues are set up
Since c578123e63 ("virtio_balloon: Treat stats requests as wakeup
events") the stats_request() virtqueue callback takes vb->wakeup_lock
via start_wakeup_event().  init_vqs() registers that callback and even
primes and kicks the stats queue, so the lock is reachable from irq
context as soon as init_vqs() returns, long before the driver sets
DRIVER_OK: vring_interrupt() dispatches to the callback without any
DRIVER_OK check unless CONFIG_VIRTIO_HARDEN_NOTIFICATION is set, and
that option depends on BROKEN.  syzbot hit it from a threaded irq:

  INFO: trying to register non-static key in stats_request
  ...
  assign_lock_key
  register_lock_class
  lock_acquire
  rt_spin_lock
  start_wakeup_event drivers/virtio/virtio_balloon.c:150 [inline]
  stats_request drivers/virtio/virtio_balloon.c:435

The lock is only initialized near the end of virtballoon_probe(),
after init_vqs() and several steps that can still fail and unwind
through del_vqs(), where a racing interrupt still finds the callback
registered.  Until then it is whatever kzalloc() left in vb: lockdep
complains about the unregistered lock class, and wakeup_signal_mask
and processing_wakeup_event get updated from irq context while probe
is still running.

The rt_spin_lock() in the report is just spin_lock() on PREEMPT_RT;
any PROVE_LOCKING build takes the same path.

stop_update_lock(), which the same callback also acquires, is already
initialized before init_vqs(); do the same for wakeup_lock.

Fixes: c578123e63 ("virtio_balloon: Treat stats requests as wakeup events")
Reported-by: syzbot+13df72e0dc4be5c62215@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=13df72e0dc4be5c62215
Signed-off-by: Mingbing Zhai <zhaimingbing@cmss.chinamobile.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261016025429.901-1-zhaimingbing@cmss.chinamobile.com>
2026-11-03 07:32:13 -05:00
Eugenio Pérez
7a2609bcb8 MAINTAINERS: add missing virtio/vdpa/vduse/vhost headers
Several headers related to virtio, vDPA, VDUSE and vhost were not
covered by any specific MAINTAINERS entry and fell through to the
catch-all THE REST section:

- include/linux/device-id/virtio.h: not matched by the existing
  "include/linux/virtio*.h" glob, which only matches files directly
  under include/linux/ and does not recurse into subdirectories.

- include/uapi/linux/vdpa.h: the in-kernel include/linux/vdpa.h was
  listed under VIRTIO CORE but its UAPI companion was missing; the
  "include/uapi/linux/virtio_*.h" pattern does not match it because
  the filename lacks the "virtio_" prefix.

- include/uapi/linux/vduse.h: there is no dedicated VDUSE section in
  MAINTAINERS; the driver lives under drivers/vdpa/ which is already
  covered by VIRTIO CORE, so the UAPI header belongs there too.

- include/uapi/linux/vhost_types.h: the VIRTIO HOST (VHOST) section
  explicitly lists include/uapi/linux/vhost.h but omits its companion
  types header.

Assisted-by: claude-sonnet 4.6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261015094049.107999-1-eperezma@redhat.com>
2026-11-03 07:32:13 -05:00
Linfeng Sun
4b03d1e7f1 vhost-vdpa: initialize state before publishing cdev
Initialize the completion and as hash buckets before cdev_device_add()
makes the device accessible.

Fixes: 4c8cf31885 ("vhost: introduce vDPA-based backend")
Assisted-by: OpenAI-Codex:GPT-5.6
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261011-fix-null-pointer-in-vhost_vdpa_release-v2-1-66ba929971ce@gmail.com>
2026-11-03 07:32:13 -05:00
Linfeng Sun
509f6bd229 vhost: reject backend enable without a kick file
Enabling a backend without VHOST_SET_VRING_KICK dereferences a NULL
vq->kick in vhost_poll_start(). Reject the request with -EINVAL.

Fixes: 264ee5aa81 ("tools/virtio: Add --reset")
Assisted-by: OpenAI-Codex:GPT-5.6
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261011-fix-null-pointer-in-vhost_test_set_backend-v1-1-60b2f12d64c6@gmail.com>
2026-11-03 07:32:13 -05:00
Linfeng Sun
a543346b96 vhost-scsi: reject delayed virtqueue setup
vhost_scsi_set_endpoint() allocates command pools only for I/O
virtqueues that are already set up, but publishes the backend for every
virtqueue. Userspace can complete a skipped queue after attaching the
endpoint, then kick it with scsi_tags uninitialized and trigger the
alloc_hint warning in sbitmap_get().

Delayed virtqueue setup is not supported. Leave skipped I/O virtqueues
inactive and reject changes to the vring size or addresses while an
endpoint is attached. Userspace must clear the endpoint before changing
the vring configuration.

I found this bug myself, though the patch was written with AI assistance.

Fixes: 25b98b64e2 ("vhost scsi: alloc cmds per vq instead of session")
Assisted-by: OpenAI-Codex:GPT-5.6
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261010-fix-warning-in-sbitmap_get-v3-1-33de562d1359@gmail.com>
2026-11-03 07:32:13 -05:00
sungbyeongchan
e498eb93f9 virtio_ring: use shadow flags when detaching split descriptors
Split virtqueues save descriptor flags and next indexes in desc_extra
before publishing descriptors to the device. The detach path uses the
shadow next index, but decides whether to continue by rereading the NEXT
flag from the shared descriptor.

Use the shadow flags for the continuation decision as well. This keeps
all detach metadata in the same driver-owned snapshot and avoids an
unnecessary shared-ring read.

Fixes: 72b5e89587 ("virtio-ring: store DMA metadata in desc_extra for split virtqueue")
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Assisted-by: LLM
Signed-off-by: sungbyeongchan <tjdqudcks0424@naver.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261008050423.32221-1-tjdqudcks0424@naver.com>
2026-11-03 07:32:13 -05:00
Linfeng Sun
3d8c5b714c vhost-scsi: validate event queue descriptor direction
vhost_get_vq_desc() returns the number of device readable (output) and
device writable (input) iovec segments. A guest can submit an eventq
descriptor chain that fills vq->iov with output segments, setting out
to ARRAY_SIZE(vq->iov) and in to zero.

When the host later queues a vhost-scsi event, vhost_scsi_do_evt_work()
uses out as the index of the first input segment. This accesses one element
beyond vq->iov and triggers an array-index-out-of-bounds report. With
panic_on_warn enabled, the report panics the host.

The event queue accepts device writable buffers only. Reject chains that
contain output segments or lack an input segment before using out as an
index. The input check prevents the out-of-bounds access, while the output
check validates the eventq descriptor direction.

I found the descriptor direction issue myself, though the patch was
written with AI assistance.  The out-of-bounds read with an
output-only chain was separately reported by Jia Jia.

Fixes: a6c9af8736 ("tcm_vhost: Add hotplug/hotunplug support")
Reported-by: Jia Jia <physicalmtea@gmail.com>
Assisted-by: OpenAI-Codex:GPT-5
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Message-ID: <20261009-fix-arrary-index-out-of-bounds-in-vhost_scsi_complete_events-v2-1-1f7689a54735@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-03 07:32:07 -05:00
Paolo Abeni
b3427f41f8 ipsec-2026-11-02
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH7ZpcWbFyOOp6OJbrB3Eaf9PW7cFAmroXn4ACgkQrB3Eaf9P
 W7ftBw//ZSbGu6d51upKqTdQNdGwuSBPMTRQvH/hHtCTqBKUSUUMS+ukpKsyn1n1
 sV+TKfEGv12ZUiW3yayH4Oi85CpH2kVUhOV+WgxldOv5YbNOjniWkHCw4FOz75Ax
 McKzBAKKFDmB69ZEE7qR7mYOu0NLMargZEVPm8yfJj07OBs634d/0rRw6+6dxFUh
 8Gj1ythdYisK/ZQ8RvTcLGfnF4sxbciSVLzNA/rmiEOddVgC9VQBlohEcZyxlctX
 6FiUWZZtEc8pu7FvbzwwFSZADhabRmIsYgipxEfyhcNl7/hGGqGjdpyGMhZXhlzV
 dRawAAu0+wlFKot0dYnNQxn0R2LtF8RJ0bfr4Tuw/DPJAOSkuxYcEP6IIt++O0Pf
 C09yNNk7ZGzAkYYI6uwg1vdZUMs1vNOab41hFHAF5dBa4/8htzrmp7LrGGL07wqh
 DG9gjKtHMg/amoeBCrdjXJyzvh3YsKhtoElj4Vwu8p47wici9GeLnXnJ49uVJnTa
 60ZdHv72MpyxGyNzumBtqY8wrUWTGyx2WCmqSqAnS3ihuaPwp9dzHxQSuKkIWk+H
 rAjPgKSfW4dYnqat/PiSmNzCIe6E5oRXwhFkprvHumn3Np0s46PjDtGIX1wS+F+n
 0sLdv1pWb7dXlApgazRsF6pX3lVjdiy2fqnt+w1R2LYvBG3CFxw=
 =PxA2
 -----END PGP SIGNATURE-----

Merge tag 'ipsec-2026-11-02' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

Steffen Klassert says:

====================
pull request (net): ipsec 2026-11-02

1) xfrm: retry inexact policy lookup after node reinsertion
   Detect a concurrent change of the inexact policy tree while it is
   searched and retry the lookup, so an insertion can't make it return
   the wrong policy.

2) xfrm: interface: validate the IP header on xmit
   Validate the IP header in xfrmi_xmit() like the IP receive path
   does, so packets injected into an xfrm interface can't reach the
   output path with a malformed header.

3) xfrm: zero-initialise km_event in the replay-notify path
   Zero-initialise the replay event so the netlink header of a
   kernel-originated replay notification no longer carries
   uninitialised stack values.

4) xfrm: espintcp: reorder operations within espintcp_init_sk
   Publish the ESP-in-TCP context before installing the socket
   callbacks, so an early callback can't dereference a context that
   isn't set up yet.

5) xfrm: state: reject mark with bits outside its mask on add
   Reject a mark with bits outside its mask on state insert instead
   of silently truncating it, so a lookup can't be given a mark that
   never matches.

6) xfrm: state: reject mark with bits outside its mask on ALLOCSPI
   Apply the same mark validation to ALLOCSPI, keeping the state and
   policy insert paths consistent.

7) xfrm: policy: reject mark with bits outside its mask on add
   Apply the same mark validation to policy insert, so a policy can't
   be stored with a mark that never matches.

8) xfrm: state: exact mark/mask match for SPI-keyed control-plane SA lookups
   Match mark and mask exactly in the SPI-keyed netlink SA lookups, so
   a catch-all SA can no longer shadow a more specific one.

9) xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()
   Hold the cloned state for the whole migration, so a concurrent
   delete can't free it while it is still in use.

10) xfrm: fix hw offload state leak on xfrm_do_migrate_state() error path
    Remove the hardware offload of the cloned state on the migration
    error path, so the offloaded SA entry isn't leaked.

11) xfrm: include mark in MIGRATE_STATE SA collision check
    Include the mark in the SA collision check, so a migration that
    only changes the mark can't install a duplicate SA tuple.

12) xfrm: pass extack through to xfrm_init_replay() from xfrm_init_state()
    Pass the extack to xfrm_init_replay(), so replay window errors can
    be reported to userspace.

13) docs: xfrm: include mark in XFRM_MSG_MIGRATE_STATE EEXIST tuple
    Document the mark as part of the EEXIST tuple of the SA migration
    request.

14) xfrm4: use a full socket for local errors
    Resolve the socket owner with skb_to_full_sk() in the IPv4 local
    error path, so a TCP request socket isn't used as a full socket.

Please pull or let me know if there are problems.

ipsec-2026-11-02

* tag 'ipsec-2026-11-02' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec:
  xfrm4: use a full socket for local errors
  docs: xfrm: include mark in XFRM_MSG_MIGRATE_STATE EEXIST tuple
  xfrm: pass extack through to xfrm_init_replay() from xfrm_init_state()
  xfrm: include mark in MIGRATE_STATE SA collision check
  xfrm: fix hw offload state leak on xfrm_do_migrate_state() error path
  xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()
  xfrm: state: exact mark/mask match for SPI-keyed control-plane SA lookups
  xfrm: policy: reject mark with bits outside its mask on add
  xfrm: state: reject mark with bits outside its mask on ALLOCSPI
  xfrm: state: reject mark with bits outside its mask on add
  xfrm: espintcp: reorder operations within espintcp_init_sk
  xfrm: zero-initialise km_event in the replay-notify path
  xfrm: interface: validate the IP header on xmit
  xfrm: retry inexact policy lookup after node reinsertion
====================

Link: https://patch.msgid.link/20261102100451.2505200-1-steffen.klassert@secunet.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 13:20:11 +01:00
Paolo Abeni
03d3676329 bluetooth pull request for net:
Core:
 
  - hci_core: Initialize IRK before publication
  - hci_core: Initialize link key before publication
  - hci_core: Initialize LTK before publication
  - hci_core: Fix queuing rx_work while workqueue is drained
  - hci_core: Keep link-key filtering inside RCU
  - hci_core: Initialize advertising RPA work only once
  - hci_sync: Fix invalid Supervision_Timeout in LE Set Default Rate
  - hci_sync: re-enable legacy advertising on resume
  - hci_sync: pause advertising for the scan address update
  - hci_sync: Update the CIS host feature when enabling LE
  - hci_sync: Copy the LE accept list under hdev->lock
  - hci_sync: Protect resolving-list lookups
  - hci_sync: Copy the resolving-list IRK under RCU
  - hci_event: Clear explicit connect state on LE connection
  - L2CAP: Hold incoming data until encryption key size is known
  - L2CAP: Ignore connection responses with wrong ident
  - SMP: Protect link keys during LTK derivation
  - SMP: Protect LTK encryption with RCU
  - MGMT: Return RFKILLED for Set Powered on a blocked controller
  - MGMT: Clear disabled connection parameters when loading none
  - MGMT: Fix discovery stuck after a failed Stop Discovery
  - validate retained LE Create CIS command length
  - validate retained LE Set CIG Parameters command length
 
 Drivers:
 
  - btintel: fix buffer over-read in fw payload
  - btmtk: drop zero-length ISO packets from endpoint padding
  - btmtk: bound the ISO payload length by the controller's MTU
  - btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
  - btmtk: fix error handling in btmtk_usb_isointf_init()
  - qca: Fix the WCN3950 NVM baud rate offset
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmrpClsZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKX8dD/44mBWlS5mLxxsDlraw3Ew4
 IxZjzmkv3Lgf/5oTDeemBfiUCGmOoZTxCfARMoi4iYGZSYsYKqxOxnuue3+ganm1
 iAe2ZPxhlggajzvT6pSGatk2U5cpdLtCe3Ivc0XCcjFsTALCAbUr4XGHfg2wxnoe
 Lv+20pj2Re8e0b1yo/4ABLczVzi8yy+UbXVq9LspqnuhNr76h5OidnB6FhHz8jqy
 SwiInk0hWRfkxZFNf+0W+AVWEqKGAdvQnGQAqMADOgNWIi2EKqOjLRCeHCwfaz03
 yPRXXXvsXF5cREN3U8FNp805E/fu+qKU0WQCiKJT4AeA9YC7mFeE45WxeTkgrKxK
 2ryMsuv0cV8Rr6Wvvy5N5c0pxfMp+ShkzCLktnSpNY02kq3m50ywOoynVijGDg/l
 ILAhmC0jbw9rRwLSRaGe4K5n2aFkK7Uwp7V1LzlWAIOB1HTu2ZfubWJVTWhXYb8n
 Gwf1AkhdRiL1n8/0pxV+syAwIZwfYEulFc6NzUXe0Bzj0vKXleuiyH9JvTIM7020
 WPdXZA2/NSa6bgf3lbqAJ8r1lrQMtZ11FQdBCoUFvGG1pHVgDcHbQDCyEwlVdhPk
 QsCPUqL4qiXcKqAa44p49nSSESa6jOipj59jdy7WFixQmd9TLk7dFA88T0iigyvq
 nZcqwFNS/1z7SDrAMOh7tw==
 =RKn1
 -----END PGP SIGNATURE-----

Merge tag 'for-net-2026-11-02' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

Core:

 - hci_core: Initialize IRK before publication
 - hci_core: Initialize link key before publication
 - hci_core: Initialize LTK before publication
 - hci_core: Fix queuing rx_work while workqueue is drained
 - hci_core: Keep link-key filtering inside RCU
 - hci_core: Initialize advertising RPA work only once
 - hci_sync: Fix invalid Supervision_Timeout in LE Set Default Rate
 - hci_sync: re-enable legacy advertising on resume
 - hci_sync: pause advertising for the scan address update
 - hci_sync: Update the CIS host feature when enabling LE
 - hci_sync: Copy the LE accept list under hdev->lock
 - hci_sync: Protect resolving-list lookups
 - hci_sync: Copy the resolving-list IRK under RCU
 - hci_event: Clear explicit connect state on LE connection
 - L2CAP: Hold incoming data until encryption key size is known
 - L2CAP: Ignore connection responses with wrong ident
 - SMP: Protect link keys during LTK derivation
 - SMP: Protect LTK encryption with RCU
 - MGMT: Return RFKILLED for Set Powered on a blocked controller
 - MGMT: Clear disabled connection parameters when loading none
 - MGMT: Fix discovery stuck after a failed Stop Discovery
 - validate retained LE Create CIS command length
 - validate retained LE Set CIG Parameters command length

Drivers:

 - btintel: fix buffer over-read in fw payload
 - btmtk: drop zero-length ISO packets from endpoint padding
 - btmtk: bound the ISO payload length by the controller's MTU
 - btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
 - btmtk: fix error handling in btmtk_usb_isointf_init()
 - qca: Fix the WCN3950 NVM baud rate offset

* tag 'for-net-2026-11-02' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: (30 commits)
  Bluetooth: MGMT: Fix discovery stuck after a failed Stop Discovery
  Bluetooth: validate retained LE Set CIG Parameters command length
  Bluetooth: validate retained LE Create CIS command length
  Bluetooth: hci_core: Initialize advertising RPA work only once
  Bluetooth: L2CAP: Ignore connection responses with wrong ident
  Bluetooth: MGMT: Clear disabled connection parameters when loading none
  Bluetooth: hci_sync: Copy the resolving-list IRK under RCU
  Bluetooth: SMP: Protect LTK encryption with RCU
  Bluetooth: SMP: Protect link keys during LTK derivation
  Bluetooth: hci_core: Keep link-key filtering inside RCU
  Bluetooth: btmtk: fix error handling in btmtk_usb_isointf_init()
  Bluetooth: qca: Fix the WCN3950 NVM baud rate offset
  Bluetooth: MGMT: Return RFKILLED for Set Powered on a blocked controller
  Bluetooth: hci_sync: Protect resolving-list lookups
  Bluetooth: hci_sync: Copy the LE accept list under hdev->lock
  Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
  Bluetooth: btmtk: bound the ISO payload length by the controller's MTU
  Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding
  Bluetooth: hci_sync: Update the CIS host feature when enabling LE
  Bluetooth: L2CAP: Hold incoming data until encryption key size is known
  ...
====================

Link: https://patch.msgid.link/20261102222018.2610820-1-luiz.dentz@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 13:01:25 +01:00
Jakub Kicinski
f56daaadfe docs: netdev: try to force agents to disclose info for fixes
"LLM-driven-developers" are not including the info about discovery
method we want to see in commit messages. Try to add more forceful
language to make agents ask for it. claude and codex seem to load
maintainer-netdev.rst already.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Link: https://patch.msgid.link/20261029153459.2257998-1-kuba@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 12:54:03 +01:00
Eric Dumazet
64e45ed926 xfrm: iptfs: fix skb leak on error in __input_process_payload()
syzbot reported a memory leak of the received skb (and its sec_path
extension) in the IP-TFS receive path.

__input_process_payload() parses the inner packets of an IP-TFS payload
and queues them on @sublist, which is only sent after the parsing loop.
Three error paths inside the loop (skb_copy_seq_read() failure, invalid
inner IPv4 header length, unknown IP version) jump to the "done" label,
which is placed after the code sending @sublist.

Any skb already queued on @sublist is then neither delivered nor freed.
This includes skbs added by iptfs_reassem_cont() before the call, newly
allocated inner packets, and, since the received skb can be reused for
the first inner packet, the received skb itself.

Move the "done" label before the trim/send code, so that inner packets
parsed before the error are delivered as on the normal exit path. The
received skb is then still freed (or consumed) as before when it was
not reused.

Fixes: 6c82d24336 ("xfrm: iptfs: add basic receive packet (tunnel egress) handling")
Reported-by: syzbot+a3f21220cbbb6e14ee2e@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6ae4102e.9c6421ad.36baac.0005.GAE@google.com/
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
Link: https://patch.msgid.link/20261030083358.2653599-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 12:29:21 +01:00
Jia Jia
1f5bc40e33 vhost-scsi: do not count PI bytes in the data length
vhost_scsi_handle_vq() moves pi_bytesout or pi_bytesin into the
protection sgl and subtracts those bytes from exp_data_len.  The length
passed to TCM is still exp_data_len + prot_bytes.

prot_bytes comes from virtio_scsi_cmd_req_pi.  With
VIRTIO_SCSI_F_T10_PI negotiated, vhost reads that header and does not
check that the CDB is a READ or WRITE.  sbc_check_prot() replaces
data_length from the CDB only when the protect field is non-zero.
target_cmd_size_check() leaves a write's data_length unchanged when the
CDB size is smaller, so a command that does not get that replacement
keeps a data_length larger than the data sgl.

The KASAN report is a MODE SELECT whose header had pi_bytesout set.
The data sgl held only the parameter list.  spc_emulate_modeselect()
walked data_length and read the next physical page.

Pass the data sgl length.  Protected READ and WRITE still take their
length from the CDB in sbc_check_prot().

KASAN reports:

  BUG: KASAN: use-after-free in spc_emulate_modeselect+0x145/0x380 [target_core_mod]
  Read of size 1

  spc_emulate_modeselect
  __target_execute_cmd
  target_execute_cmd
  vhost_scsi_write_pending
  transport_generic_new_cmd
  __target_submit
  target_queued_submit_work
  process_one_work
  worker_thread
  kthread
  ret_from_fork
  ret_from_fork_asm

Fixes: 9f977ef7b6 ("vhost-scsi: Include prot_bytes into expected data transfer length")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261012103954.136698-1-physicalmtea@gmail.com>
2026-11-03 05:52:09 -05:00
Yuho Choi
f41f153d49 vdpa/snet: Don't discard the DPU error in snet_send_ctrl_msg()
snet_send_ctrl_msg() reads the error code the DPU reports when it ACKs
a control message, but then overwrites it with the return value of
snet_wait_for_dpu_completion(). As a result, a DESTROY, SUSPEND or
RESUME that the DPU rejects is reported to the caller as a success as
long as the DPU clears the opcode register in time.

For SUSPEND this means vhost-vdpa marks the device as suspended and
lets userspace reprogram the vrings while the DPU is still running
them; for DESTROY, snet_reset_dev() never even sees that the device
failed to stop.

Return the error from the saved ACK value once the completion wait
itself has succeeded.

Fixes: 3f3a1675b7 ("vdpa/snet: support getting and setting VQ state")
Cc: stable@vger.kernel.org
Signed-off-by: Yuho Choi <oss.patchbox@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261005044915.264532-1-oss.patchbox@gmail.com>
2026-11-03 05:52:09 -05:00
Yuho Choi
1f8efac19a iommu/virtio: Reset device before deleting virtqueues on probe failure
viommu_probe() marks the device DRIVER_OK before populating the event
virtqueue and registering the IOMMU device in sysfs.  viommu_fill_evtq()
hands the device a set of device-writable buffers through
virtqueue_add_inbuf(), so from that point on the device may write into
them and into the rings.

If either step fails, the error path deletes the virtqueues without
resetting the device first.  The event buffers are allocated with
devm_kmalloc_array() and are released as probe unwinds, so the device can
go on writing to memory that has been freed.

Reset the device before deleting the virtqueues, the way viommu_remove()
already does.

Fixes: edcd69ab9a ("iommu: Add virtio-iommu driver")
Cc: stable@vger.kernel.org
Signed-off-by: Yuho Choi <oss.patchbox@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261004182218.177343-1-oss.patchbox@gmail.com>
2026-11-03 05:52:09 -05:00
Fang Xieyan
e244725e86 vhost: fix used ring index wrap in vhost_add_used_n_in_order
vhost_add_used_n_in_order() advances start by nheads[i] but wraps it
with a single subtraction.  If start + nheads[i] >= 2 * vq->num, start
can remain outside the ring.

With used-ring logging enabled, start > vq->num makes (vq->num - start)
underflow.  log_write() then sets bits beyond the dirty-log bitmap,
potentially corrupting adjacent userspace memory.  This is reachable on
the vhost-net TX path with VIRTIO_F_IN_ORDER: done_idx can reach
VHOST_NET_BATCH (64), triggering the issue with a 32-entry ring.

Wrap start with a mask to keep it within the ring.  VHOST_SET_VRING_NUM
enforces a nonzero power-of-two ring size, allowing start to be wrapped
using & (vq->num - 1).

Fixes: 67a873df0c ("vhost: basic in order support")
Cc: stable@vger.kernel.org
Reviewed-by: Weibin Liu <liuwb@xiaopeng.com>
Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
Acked-by: Eugenio Pérez <eperezma@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261020232956.99970-1-fangxy@xiaopeng.com>
2026-11-03 05:52:09 -05:00
Shubham Antil
01c3a5fa6d vhost-scsi: zero misaligned I/O bounce pages
The misaligned I/O fallback copies the full bounce scatterlist to the
request buffer during completion.  If a data-in command transfers less
than requested, part of a newly allocated bounce page can remain unwritten.

Allocate bounce pages with __GFP_ZERO so all bytes copied during completion
have a defined value.  This path is already the slow fallback for
misaligned I/O, so the added initialization cost is acceptable.

Found during an LLM-assisted source audit and validated with a QEMU/KVM
vhost-scsi target using misaligned data-in commands.

Fixes: 5ced58bfa1 ("vhost-scsi: Fix alignment handling with windows")
Cc: stable@vger.kernel.org
Assisted-by: LLM (OpenAI Codex, gpt-5.6-sol)
Signed-off-by: Shubham Antil <shubham@octane.security>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261020105503.75904-1-shubham@octane.security>
2026-11-03 05:52:09 -05:00
Kyle Zeng
2e54b3e187 net/sched: sch_qfq: prevent aggregate self-replacement
qfq_change_class() snapshots the current aggregate settings while
holding the qdisc tree lock, but drops the lock before selecting the
destination aggregate. During that gap, qfq_enqueue() can move the
class to an aggregate matching the requested settings.

When qfq_change_class() resumes, qfq_find_agg() then returns cl->agg.
If it is a singleton, qfq_deact_rm_from_agg() frees the aggregate
before qfq_add_to_agg() immediately accesses the same pointer, causing
a use-after-free.

While holding the tree lock, skip the replacement when the destination
is already the current aggregate. Any estimator replacement has already
completed, so the class change can finish normally.

Fixes: 462dbc9101 ("pkt_sched: QFQ Plus: fair-queueing service at DRR cost")
Link: https://lore.kernel.org/netdev/20260731140533.566493-1-david.lee@trailofbits.com/
Cc: stable@vger.kernel.org
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Co-developed-by: David Lee <david.lee@trailofbits.com>
Signed-off-by: David Lee <david.lee@trailofbits.com>
Link: https://patch.msgid.link/20261029180957.43015-1-david.lee@trailofbits.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 11:04:43 +01:00
Eric Dumazet
213d491308 soreuseport: annotate data-races around reuse->socks[] and num_socks
reuseport_select_sock() and reuseport_migrate_sock() read
reuse->num_socks and reuse->socks[] locklessly under RCU, while
writers holding reuseport_lock can change them.

Readers snapshot num_socks once, then index socks[] with it.
Meanwhile, writers can perform several operations, storing into
slots below the reader's stale count:

- __reuseport_detach_sock() moves the last socket into slot i.
- __reuseport_add_sock() then writes the new socket at the
  (now smaller) num_socks index.
- reuseport_stop_listen_sock() calls __reuseport_detach_sock()
  then __reuseport_add_closed_sock(), which writes slot
  max_socks - num_closed_socks - 1. This can be the slot a reader
  still considers part of the listener region when the array is full.
- __reuseport_detach_closed_sock() can then rewrite that slot.

All pointers stored in socks[] remain valid for the RCU grace period,
but without annotations the compiler is allowed to tear or reload
these accesses. For instance, reuseport_select_sock_by_hash() could
reload reuse->socks[i] between the sk_state/sk_incoming_cpu checks
and the return, returning a socket that did not pass them.

Use WRITE_ONCE() for all socks[] stores done while the array is
visible to readers, and for num_socks updates (readers already use
READ_ONCE()). Use READ_ONCE() in the two lockless readers.

Fixes: ef456144da ("soreuseport: define reuseport groups")
Link: https://lore.kernel.org/netdev/20260902071900.395567-1-ruanjinjie@huawei.com/
Cc: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://patch.msgid.link/20261030120956.3026324-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 10:43:06 +01:00
Björn Töpel
c8848b2ca6 eth: fbnic: Report the logical RX queue to XDP
fbnic reports queue 0 to XDP on all RX queues. The XDP RX queue is
registered with the header buffer queue index, which is always 0,
instead of the completion queue index, which is the netdev queue id.

Any XDP program that reads rx_queue_index gets 0 on every queue, so a
program that uses the queue id uses the wrong queue. AF_XDP has the
same problem: XSKMAP finds the wrong socket, and redirect to a socket
on another queue fails.

Triggered on fbnic hardware (50G, firmware 25.08.05-004) with AF_XDP
zero-copy: sockets on queues other than 0 got no packets. With this
fix, a socket on queue 43, and sockets on four queues at once, get
their packets. On the QEMU model with two queues, a kprobe shows 0 and
0 before the fix, and 0 and 1 after it.

Fixes: 894d4a4ea6 ("eth: fbnic: move xdp_rxq_info_reg() to resource alloc")
Signed-off-by: Björn Töpel <bjorn@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261030141452.1173282-1-bjorn@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 10:30:25 +01:00
Bart Van Assche
750eb5ab45 mctp i3c: Fix locking in an error path
If netdev_alloc_skb() fails, mctp_i3c_read() jumps to a label that
unlocks mi->lock although that mutex has not been locked yet. Fix this
by returning -ENOMEM directly. This bug has been detected by the Clang
thread-safety analyzer.

Cc: Leo Yang <Leo-Yang@quantatw.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Jeremy Kerr <jk@codeconstruct.com.au>
Cc: Matt Johnston <matt@codeconstruct.com.au>
Cc: netdev@vger.kernel.org
Fixes: 2d2d4f60ed ("mctp i3c: fix MCTP I3C driver multi-thread issue")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Matt Johnston <matt@codeconstruct.com.au>
Link: https://patch.msgid.link/71e0a880ffe7a83237e501b07884bf54343e76ca.1793296780.git.bvanassche@acm.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 09:57:58 +01:00
Jianyun Gao
2bbca049de xfs: fix temporary cursor leak in btree shift corruption paths
In xfs_btree_lshift and xfs_btree_rshift, when XFS_IS_CORRUPT detects
an invalid firstrec/lastrec result after xfs_btree_dup_cursor has
successfully allocated a temporary cursor, the error path jumps to
error0 which returns without freeing tcur.  This leaks the cursor
memory, the xfs_group reference, and the per-level buffer references
held by the duplicated cursor.  Jump to error1 instead, which calls
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR) to properly release all
resources.

Cc: stable@vger.kernel.org
Fixes: 9eaead51be ("[XFS] implement generic xfs_btree_rshift")
Signed-off-by: Jianyun Gao <jianyungao89@gmail.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-03 09:49:54 +01:00
Sahil Chandna
684603842b net: mana: Add support to process throttled EQEs
When an event queue nears full, the hardware coalesces the per-CQ
GDMA_EQE_COMPLETION notifications into a single throttle EQE (type 4)
that carries no cq_id. The driver does not handle this event type, so
it falls through to the default case and is dropped. Any CQ whose
completion notification was replaced by the throttle EQE can remain
unserviced, causing its queue to stall.

This was observed internally as a TX stall:

  ens1: NETDEV WATCHDOG: CPU: 45: transmit queue 1 timed out 15133 ms
  mana 7870:00:00.0: HWC: Request timed out: 60000 ms
  mana 7870:00:00.0: Gf stats wk handler: gf stats query timed out.
  ens1: NETDEV WATCHDOG: CPU: 20: transmit queue 0 timed out 15859 ms
  ens1: NETDEV WATCHDOG: CPU: 15: transmit queue 0 timed out 31731 ms
  ens1: NETDEV WATCHDOG: CPU: 21: transmit queue 0 timed out 47603 ms
  ens1: NETDEV WATCHDOG: CPU: 42: transmit queue 0 timed out 62451 ms

Handle the throttle EQE:

- Record up to two child CQs per EQ when a CQ is created with a parent
  EQ. A mana_en EQ serves one TX CQ and one RX CQ, and the HWC EQ
  serves the HWC CQ.
- On a throttle EQE, call the callback of each child CQ that is still
  in cq_table[].
- Before a child CQ is freed, unlink it from its parent EQ and from
  cq_table[] in mana_gd_detach_cq(), then wait for an RCU
  grace period, because mana_gd_intr() reads both under
  rcu_read_lock(). mana_destroy_txq() and mana_destroy_rxq() detach
  the CQ before deleting its NAPI, so the synchronize_net() that NAPI
  deletion already needs also covers the CQ. mana_hwc_destroy_channel()
  detaches the HWC CQ and waits for a grace period before freeing the
  HWC queues.
- Advertise the capability bit for throttled EQE.
- Add a throttle eqe counter per queue.

Fixes: ca9c54d2d6 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Cc: stable@vger.kernel.org
Signed-off-by: Sahil Chandna <sahilchandna@linux.microsoft.com>
Link: https://patch.msgid.link/20261028084020.2051254-1-sahilchandna@linux.microsoft.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-03 09:47:33 +01:00
Cen Zhang
5b4696e0bf ocfs2: cache the mount context for dentry lock callbacks
ocfs2_drop_dentry_lock() drops the inode reference before releasing the
DENTRY lock.  This lets inode eviction release the local inode and open
locks before a remote unlink can proceed past the DENTRY lock.

A DLM callback can still arrive before the DENTRY lock has been dropped.
ocfs2_get_dentry_osb() obtains the mount context through dl_inode->i_sb,
which can access a freed inode when the downconvert thread drops the
last inode reference in its post-unlock callback:

  Downconvert thread                     DLM callback thread
  ------------------                     -------------------
  ocfs2_process_blocked_lock()
    ocfs2_dentry_post_unlock()
      ocfs2_dentry_lock_put()
        ocfs2_drop_dentry_lock()
          iput(dl->dl_inode)
          [inode reclaimed after RCU]
                                         ocfs2_blocking_ast()
                                           ocfs2_get_dentry_osb()
                                             dl->dl_inode->i_sb
          ocfs2_simple_drop_lockres()

Store the mount context in the DENTRY lock resource's l_priv field and use
the default mount-context lookup.  Recover the containing dentry lock with
container_of(), as already done for refcount locks, and remove
ocfs2_get_dentry_osb().  ocfs2_dismount_volume() shuts down the DLM before
freeing the mount context, so callbacks can use it without accessing the
inode.  Preserve the existing iput-before-unlock order to avoid delaying
local inode and open lock release until after the DENTRY lock is released.

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0012-v9-eeb9084fb29577971229@gmail.com
Fixes: 8ed6b23709 ("ocfs2: revert iput deferring code in ocfs2_drop_dentry_lock")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:59 -08:00
Cen Zhang
a25c02af29 ocfs2: wait for filecheck kobject release after a failed add
The filecheck kobject and its release completion are embedded in
ocfs2_super, so the osb must outlive the kobject. On a failed
kobject_init_and_add(), creation clears fs_fcheck and calls
kobject_put(), but returns without waiting for the release callback.

With CONFIG_DEBUG_KOBJECT_RELEASE, the last put queues delayed cleanup.
Mount failure can then free the containing osb before the embedded
release timer expires:

  Mount failure                     Delayed cleanup
  -------------                     ---------------
  ocfs2_filecheck_create_sysfs()
    kobject_init_and_add() fails
    fs_fcheck = NULL
    kobject_put()
      queue delayed release
  return to mount error cleanup
  ocfs2_dismount_volume()
    remove_sysfs() skips the wait
    kfree(osb)
                                    expire embedded release timer
                                      access freed osb

The normal removal path waits for fs_kobj_unregister, but it returns
early when fs_fcheck is NULL. The failed-add path therefore leaves the
delayed work and its completion in freed storage.

Wait for the existing release completion after the failed-add
kobject_put(), before returning to mount error cleanup. This keeps the
enclosing osb alive until the kobject has finished releasing, matching
the normal teardown path.

KASAN report as below:

    BUG: KASAN: slab-use-after-free in __run_timers+0xa6d/0xa90
    Write of size 8 at addr ffff8881178a5658 by task swapper/0/0
    
    CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.3.0-rc4-next-20260921-pmb-ocfs2-functional-v1+ #1 PREEMPT(lazy) 
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Call Trace:
     <IRQ>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? __run_timers+0xa6d/0xa90
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20e/0x420
     ? __run_timers+0xa6d/0xa90
     kasan_report+0xe0/0x110
     ? __run_timers+0xa6d/0xa90
     __run_timers+0xa6d/0xa90
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx___run_timers+0x10/0x10
     ? __lock_acquire+0x5a3/0x2140
     ? __pfx_do_raw_spin_lock+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     timer_expire_remote+0xfa/0x160
     ? __pfx_timer_expire_remote+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? trace_hardirqs_on+0x18/0x160
     tmigr_handle_remote_up+0x4ba/0x9d0
     ? __pfx_tmigr_handle_remote_up+0x10/0x10
     ? tmigr_handle_remote+0x21a/0x340
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x290
     ? __pfx_tmigr_handle_remote_up+0x10/0x10
     __walk_groups_from+0x5a/0x160
     tmigr_handle_remote+0x24f/0x340
     ? __pfx_tmigr_handle_remote+0x10/0x10
     ? lock_acquire+0x190/0x300
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x290
     run_timer_softirq+0x222/0x270
     ? __pfx_run_timer_softirq+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lockdep_hardirqs_on_prepare+0xb8/0x1a0
     ? srso_alias_return_thunk+0x5/0xfbef5
     handle_softirqs+0x1fa/0x8d0
     ? __pfx_handle_softirqs+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? _raw_spin_unlock+0x23/0x40
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __hrtimer_rearm_deferred+0x1fb/0x5d0
     __irq_exit_rcu+0x113/0x1e0
     irq_exit_rcu+0xe/0x20
     sysvec_apic_timer_interrupt+0x6c/0x80
     </IRQ>
     <TASK>
     asm_sysvec_apic_timer_interrupt+0x1a/0x20
    RIP: 0010:pv_native_safe_halt+0xf/0x20
    Code: fa 18 01 e9 ee 37 ff fa 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa eb 07 0f 00 2d 23 c7 14 00 fb f4 <e9> c7 37 ff fa 66 2e 0f 1f 84 00 00 00 00 00 66 90 90 90 90 90 90
    RSP: 0018:ffffffff87c07cf8 EFLAGS: 00000206
    RAX: 0000000000045d0f RBX: ffffffff87c2d4c0 RCX: ffffffff86111e95
    RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff815b508e
    RBP: fffffbfff0f85a98 R08: 0000000000000001 R09: ffffed10310c68ba
    R10: ffff8881886345d3 R11: 0000000000000000 R12: 0000000000000001
    R13: 0000000000000000 R14: 1ffffffff0f80fa4 R15: dffffc0000000000
     ? ct_kernel_exit.constprop.0+0xc5/0xf0
     ? do_idle+0x3ae/0x650
     default_idle+0x9/0x10
     default_idle_call+0x6c/0xb0
     do_idle+0x3ae/0x650
     ? __pfx___schedule+0x10/0x10
     ? __pfx_do_idle+0x10/0x10
     ? rest_init+0x1cd/0x330
     ? srso_alias_return_thunk+0x5/0xfbef5
     cpu_startup_entry+0x54/0x60
     rest_init+0x1e1/0x330
     ? __pfx_acpi_read_bit_register+0x10/0x10
     ? __pfx_rest_init+0x10/0x10
     ? acpi_os_write_port+0x23/0xb0
     ? __pfx_kernel_init+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? acpi_ut_status_exit+0xd6/0x180
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? acpi_ut_status_exit+0xd6/0x180
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? acpi_enable_subsystem+0x2b0/0x4e0
     ? __pfx_x86_late_time_init+0x10/0x10
     start_kernel+0x417/0x4b0
     x86_64_start_reservations+0x18/0x30
     x86_64_start_kernel+0x111/0x120
     common_startup_64+0x13e/0x158
     </TASK>
    
    Allocated by task 494:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x28d/0x610
     ocfs2_initialize_super.isra.0+0xab/0x3070
     ocfs2_fill_super+0x801/0x3920
     get_tree_bdev_flags+0x35d/0x5f0
     vfs_get_tree+0x93/0x320
     fc_mount+0x1d/0x200
     path_mount+0x592/0x1e00
     __x64_sys_mount+0x24b/0x2d0
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    Freed by task 494:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x308/0x580
     ocfs2_dismount_volume+0x43c/0x9b0
     ocfs2_fill_super+0x258f/0x3920
     get_tree_bdev_flags+0x35d/0x5f0
     vfs_get_tree+0x93/0x320
     fc_mount+0x1d/0x200
     path_mount+0x592/0x1e00
     __x64_sys_mount+0x24b/0x2d0
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    The buggy address belongs to the object at ffff8881178a4000
     which belongs to the cache kmalloc-8k of size 8192
    The buggy address is located 5720 bytes inside of
     freed 8192-byte region [ffff8881178a4000, ffff8881178a6000)
    
    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1178a0
    head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
    flags: 0x200000000000040(head|node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000040 ffff888100043880 dead000000000122 0000000000000000
    raw: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
    head: 0200000000000040 ffff888100043880 dead000000000122 0000000000000000
    head: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
    head: 0200000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
    head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
    page dumped because: kasan: bad access detected
    
    Memory state around the buggy address:
     ffff8881178a5500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
     ffff8881178a5580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    >ffff8881178a5600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                                        ^
     ffff8881178a5680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
     ffff8881178a5700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    ==================================================================

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0087-v6-78f3c3d6d70887d6e0cc@gmail.com
Fixes: b9fba67b38 ("ocfs2: fix error path kobject memory leak")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:58 -08:00
Hungyu Lin
6cd4c2736c fat: fix parent link count when replacing a sibling directory
vfat_rename() and do_msdos_rename() adjust parent link counts only when
updating the dotdot entry for a move between different parents.  Replacing
an existing empty directory in the same parent also removes a
subdirectory, but leaves the parent's link count unchanged.

For example, renaming one of two sibling directories over the other leaves
the parent with four links instead of three.  stat and ls report the stale
count, and find -links 3 does not match the parent.

Drop the parent's link count for this case after the source entry has been
removed successfully.  Leave cross-parent renames, regular files and the
existing error paths unchanged.

Share the parent link count check with rmdir through fat_dir_drop_nlink().
Only decrement counts of at least three and report a filesystem error
otherwise, rather than reducing a corrupted directory's count below two. 
Export the helper for the VFAT and MSDOS modules.

Link: https://lore.kernel.org/20261030060011.70237-1-dennylin0707@gmail.com
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Christian Brauner <brauner@kernel.org>
2026-11-02 19:18:58 -08:00
Cen Zhang
0988f0c0c7 ocfs2/cluster: unlink socket containers before releasing resources
A socket container's node and socket must remain alive while the
container is on sock_containers. The debugfs formatter reads sc_node
and sc_sock under o2net_debug_lock without taking their references, but
sc_kref_release() releases both before taking that lock to unlink the
container.

With CONFIG_DEBUG_FS enabled, a synchronous sender can retain its last
socket-container reference after o2net_disconnect_node() has detached
the connection and flushed o2net_wq. The caller runs outside that
workqueue. After the sender removes its configfs dependency, node
removal can proceed without waiting for the sender's final sc_put():

  Sender (final sc_put)    Configfs rmdir        Debugfs reader
  --------------------    --------------        --------------
  o2nm_undepend_item()
                          Drop node item refs
  o2nm_node_put()
    [node can be freed]
                                               sc_seq_show()
                                                 Lock debug lock
                                                 Read sc_node->nd_name
                                                 Unlock debug lock
  sc_node = NULL
  o2net_debug_del_sc()

The earlier socket release has a similar window. The container is
still selectable while its socket has been released and sc_sock has
not yet been cleared:

  Sender (final sc_put)                       Debugfs reader
  --------------------                       --------------
  sock_release(sc->sc_sock)
    [socket can be freed]
                                             sc_seq_show()
                                               Lock debug lock
                                               Read sc_sock->sk fields
                                               Unlock debug lock
  sc_sock = NULL
  ...
  o2net_debug_del_sc()

Move o2net_debug_del_sc() before releasing either resource. Unlinking
under the existing debug lock waits for an active formatter to finish
and prevents later readers from selecting the container. This covers
both socket fields and node fields, including nd_num in the stats
formatter.

KASAN report as below:

    BUG: KASAN: slab-use-after-free in string+0x42b/0x470
    Read of size 1 at addr ffff88810f56fc90 by task python3/506

    CPU: 0 UID: 0 PID: 506 Comm: python3 Not tainted 7.3.0-rc4-next-20260921-pmb-ocfs2-functional-v1+ #1 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     kasan_report+0xe0/0x110
     string+0x42b/0x470
     vsnprintf+0x330/0x1110
     seq_printf+0x1a8/0x260
     sc_seq_show+0x604/0x9f0
     seq_read_iter+0x480/0x1110
     seq_read+0x362/0x5a0
     full_proxy_read+0x11f/0x180
     vfs_read+0x1a0/0xc20
     ksys_read+0x111/0x200
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

(User register dump omitted.)

     </TASK>

    Allocated by task 497:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x28d/0x610
     o2nm_node_group_make_item+0xea/0x1a0
     configfs_mkdir+0x762/0xca0
     vfs_mkdir+0x399/0x7e0
     filename_mkdirat+0x129/0x450
     __x64_sys_mkdir+0x70/0xa0
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    Freed by task 505:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x308/0x580
     config_item_cleanup+0x14b/0x230
     config_item_put+0x79/0x90
     sc_put+0x454/0x6e0
     o2net_send_message_vec+0x63d/0x1560
     o2net_send_message+0xa6/0xe0
     validation_send_write+0x17f/0x1d0
     full_proxy_write+0x11f/0x180
     vfs_write+0x25a/0x1010
     ksys_write+0x111/0x200
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    The buggy address belongs to the object at ffff88810f56fc00
     which belongs to the cache kmalloc-512 of size 512
    The buggy address is located 144 bytes inside of
     freed 512-byte region [ffff88810f56fc00, ffff88810f56fe00)

(Page and shadow-memory dumps omitted.)

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0065-v6-3090153fd7cacb810214@gmail.com
Fixes: 2309e9e040 ("ocfs2/net: Add debug interface to o2net")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Kees Cook <kees@kernel.org>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Sunil Mushran <sunil.mushran@oracle.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:58 -08:00
Cen Zhang
126429e2f5 ocfs2: stop recovery before shutting down local allocators
Recovery completion needs the local allocators until it has finished
reclaiming a failed node's allocation window and truncate log.  During
unmount, quota recovery is stopped first, but that leaves recovery_state
at OCFS2_REC_QUOTA_DISABLED.  New non-quota recovery can still start.

ocfs2_truncate_log_shutdown() drains existing completion work and releases
osb_tl_bh before ocfs2_recovery_exit() closes that publication path:

  Unmount                             Recovery
  -------                             --------
  stop quota recovery; disable quotas
  truncate_log_shutdown()
    flush existing completion work
                                      recover another failed node
                                        queue completion
    flush local log; release buffer
                                      complete_truncate_log_recovery()
                                        use released osb_tl_bh
  recovery_exit(): disable and drain

An extra buffer reference alone would still let completion append new
records after the final truncate-log flush.

Split stopping and draining recovery from freeing its state. Stop all
recovery producers and drain completion work before shutting down either
local allocator. Keep recovery-state release at its existing later point,
so its lifetime relative to other teardown users stays unchanged. The
second stop at recovery_exit() is harmless once recovery is disabled.

KASAN report as below:

    BUG: KASAN: slab-use-after-free in ocfs2_truncate_log_needs_flush+0x23d/0x360
    Read of size 8 at addr ffff8881093711e8 by task kworker/u16:3/53
    
    CPU: 0 UID: 0 PID: 53 Comm: kworker/u16:3 Not tainted 7.3.0-rc4-next-20260921-pmb-ocfs2-functional-v1+ #1 PREEMPT(lazy) 
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Workqueue: ocfs2_wq ocfs2_complete_recovery
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? ocfs2_truncate_log_needs_flush+0x23d/0x360
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20e/0x420
     ? ocfs2_truncate_log_needs_flush+0x23d/0x360
     kasan_report+0xe0/0x110
     ? ocfs2_truncate_log_needs_flush+0x23d/0x360
     ocfs2_truncate_log_needs_flush+0x23d/0x360
     ? __pfx_ocfs2_truncate_log_needs_flush+0x10/0x10
     ? __pfx_down_write+0x10/0x10
     ocfs2_complete_truncate_log_recovery+0x315/0x780
     ? trace_hardirqs_on+0x18/0x160
     ? __pfx_ocfs2_complete_truncate_log_recovery+0x10/0x10
     ? ocfs2_complete_recovery+0x666/0x11b0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? kfree+0x308/0x580
     ocfs2_complete_recovery+0x676/0x11b0
     ? __pfx_ocfs2_complete_recovery+0x10/0x10
     ? reacquire_held_locks+0xdd/0x200
     ? process_one_work+0x7c8/0x1b40
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_acquire+0x190/0x300
     ? __pfx_autoremove_wake_function+0x10/0x10
     ? process_one_work+0x834/0x1b40
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x290
     ? srso_alias_return_thunk+0x5/0xfbef5
     process_one_work+0x9a8/0x1b40
     ? __pfx_process_one_work+0x10/0x10
     ? lock_acquire+0x190/0x300
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __kthread_parkme+0x177/0x220
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x351/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf70
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>
    
    Allocated by task 538:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_slab_alloc+0x89/0x90
     kmem_cache_alloc_noprof+0x20b/0x5c0
     alloc_buffer_head+0x26/0x120
     folio_alloc_buffers+0x122/0x1d0
     bdev_getblk+0x299/0x4f0
     ocfs2_read_blocks_sync+0x513/0xbc0
     ocfs2_iget+0x9cd/0x1a00
     ocfs2_get_system_file_inode+0x25e/0x7a0
     ocfs2_fill_super+0x1b05/0x3930
     get_tree_bdev_flags+0x35d/0x5f0
     vfs_get_tree+0x93/0x320
     fc_mount+0x1d/0x200
     path_mount+0x592/0x1e00
     __x64_sys_mount+0x24b/0x2d0
     do_syscall_64+0x114/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    Freed by task 553:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kmem_cache_free+0x242/0x580
     free_buffer_head+0x4b/0xc0
     try_to_free_buffers+0x1dc/0x330
     ocfs2_truncate_log_shutdown+0x789/0x1290
     ocfs2_dismount_volume+0x1da/0x940
     generic_shutdown_super+0x15f/0x490
     kill_block_super+0x40/0xa0
     deactivate_locked_super+0xae/0x120
     deactivate_super+0xa2/0xc0
     cleanup_mnt+0x217/0x450
     task_work_run+0x144/0x230
     exit_to_user_mode_loop+0x17d/0x570
     do_syscall_64+0x4d1/0x620
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    The buggy address belongs to the object at ffff8881093711c0
     which belongs to the cache buffer_head of size 160
    The buggy address is located 40 bytes inside of
     freed 160-byte region [ffff8881093711c0, ffff888109371260)
    
    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x109371
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff8881008883c0 dead000000000100 dead000000000122
    raw: 0000000000000000 0000000000120012 00000000f5000000 0000000000000000
    page dumped because: kasan: bad access detected
    
    Memory state around the buggy address:
     ffff888109371080: 00 00 00 00 fc fc fc fc fc fc fc fc 00 00 00 00
     ffff888109371100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    >ffff888109371180: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
                                                              ^
     ffff888109371200: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
     ffff888109371280: fc fc fc fc 00 00 00 00 00 00 00 00 00 00 00 00
    ==================================================================

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0019-v8-574dd69fd3f47f56348b@gmail.com
Fixes: ccd979bdbc ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:58 -08:00
Cen Zhang
61469249aa ocfs2/dlm: serialize migration MLE cleanup on failure
A migration MLE has a base reference for the mastering answer and an
in-use reference held by dlm_migrate_lockres(). The finishing assertion
consumes the base reference, but migration failure drops it again
without checking whether the assertion already consumed it.

The target queues its migration worker before it acknowledges the
ALL_DONE packet, so its finishing assertion can be handled while the
sender still waits for the status. If the connection fails before the
status arrives, dlm_send_one_lockres() returns an error for a migration
that the target has already completed:

  Old-master sender                  Finishing assertion
  -----------------                  -------------------
  publish MLE; take in-use reference
  send ALL_DONE; wait for status
                                     take lookup reference
                                     unlink MLE
                                     put lookup and base references
  send returns a connection error
  put base reference again; free MLE
  put in-use reference; access freed MLE

dlm_assert_master_handler() holds dlm->spinlock from the MLE lookup to
the final puts, and it takes dlm->master_lock around the unlink and the
puts. Decide under the same locks: if the MLE is already unhashed, the
assertion consumed the base reference, so drop only the sender's in-use
reference. Otherwise unlink it before consuming the base reference so a
later assertion no longer finds it.

An assertion that got there first has also made the target the owner
and cleared DLM_LOCK_RES_MIGRATING. Treating the attempt as failed at
that point would leave the lockres owned by the target while this node
still holds the other nodes' locks and refmap bits, so it could neither
be purged nor migrated again. Finish our side as a completed migration
does instead: drop those locks under res->spinlock if the target still
owns the lockres, and recalculate its usage.

Use the same cleanup for the pre-send failure, the send failure and the
target-death failure paths. The sender's in-use reference keeps the MLE
alive until its final put outside the nested locks. Successful
migration retains its existing in-use-only put.

A target that has died cannot assert after the sender has seen its
death. The o2net node-down callback runs before the DLM one; it
disconnects the node and flushes the workqueue that runs the message
handlers, so an assertion already received has been handled by the time
the DLM removes the node from the domain map. A node that leaves the
domain cleanly sends its exit message only after its assertions have
been answered.

Two windows of the hand-over itself are left as they are: the handler
switches the owner and the sender drops the other nodes' locks moments
later, and an assertion from a live target that arrives after the
sender has given up still meets the owner check in the handler. Waiting
for the target before giving up would only stretch the first window
into the time in which recovery of the target can observe it.

KASAN report, only the relevant frames are kept:

BUG: KASAN: slab-use-after-free in dlm_put_mle_inuse+0xce/0xe0
Read of size 8 at addr ffff8881190e3c20 by task umount/593

Call Trace:
 <TASK>
 dlm_put_mle_inuse+0xce/0xe0
 dlm_migrate_lockres+0x16af/0x20d0
 dlm_empty_lockres+0x60a/0xbd0
 dlm_unregister_domain+0x53b/0x11d0
 o2cb_cluster_disconnect+0xa5/0x110
 ocfs2_cluster_disconnect+0x73/0xc0
 ocfs2_dlm_shutdown+0x311/0x440
 ocfs2_dismount_volume+0x696/0x940
 generic_shutdown_super+0x15f/0x490
 kill_block_super+0x40/0xa0
 deactivate_locked_super+0xae/0x120
 deactivate_super+0xa2/0xc0
 cleanup_mnt+0x217/0x450
 task_work_run+0x144/0x230
 </TASK>

Allocated by task 593:
 kmem_cache_alloc_noprof+0x20b/0x5c0
 dlm_migrate_lockres+0x20e/0x20d0
 dlm_empty_lockres+0x60a/0xbd0
 dlm_unregister_domain+0x53b/0x11d0
 o2cb_cluster_disconnect+0xa5/0x110
 ocfs2_cluster_disconnect+0x73/0xc0
 ocfs2_dlm_shutdown+0x311/0x440
 ocfs2_dismount_volume+0x696/0x940

Freed by task 593:
 kmem_cache_free+0x242/0x580
 __dlm_put_mle+0x4b2/0x660
 dlm_migrate_lockres+0x1690/0x20d0
 dlm_empty_lockres+0x60a/0xbd0
 dlm_unregister_domain+0x53b/0x11d0
 o2cb_cluster_disconnect+0xa5/0x110
 ocfs2_cluster_disconnect+0x73/0xc0
 ocfs2_dlm_shutdown+0x311/0x440

The buggy address belongs to the object at ffff8881190e3c00
 which belongs to the cache o2dlm_mle of size 480
The buggy address is located 32 bytes inside of
 freed 480-byte region [ffff8881190e3c00, ffff8881190e3de0)

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0038-v9-659f247ea980d5f3fbeb@gmail.com
Fixes: 6714d8e86b ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:57 -08:00
Nickolai Zeldovich
723982e705 panic: zero the dynamically allocated taint buffer
A %s read of print_tainted()'s string can run past the end of the taint
buffer while another CPU rebuilds a longer string in it, reading slab
memory out of bounds into the kernel log (a KASAN slab-out-of-bounds
report at taint_buf + size).  A warning or an unhandled-signal dump on
another CPU reaches print_tainted() through dump_stack_print_info().

alloc_taint_buf() sizes the buffer for the longest taint string and
allocates it with kmalloc(), so the bytes past that string are never
written and the object holds no permanent NUL terminator. 
_print_tainted() rebuilds the string in place without locking and writes
the terminator last, so a reader that overtakes a writer extending the
string past the previous high-water mark finds no terminator inside the
object and walks off its end.  print_tainted()'s kernel-doc promises the
string is "always NULL terminated", a guarantee the previous zero-filled
static buffer kept.

Allocate the buffer with kzalloc() so its trailing bytes stay NUL and
every reader stops inside the object.

Reproduced on QEMU riscv64 under KASAN by growing the taint set while
processes took unhandled-signal dumps on several CPUs: the unpatched
kernel reports a slab-out-of-bounds read at taint_buf + size, the patched
one is clean.

Link: https://lore.kernel.org/20261024020153.830459-1-nickolai@csail.mit.edu
Fixes: a9dff0d0d1 ("kernel/panic: allocate taint string buffer dynamically")
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Bradley Morgan <brads@mainlining.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Cc: Rio <rioo.tsukatsukii@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:57 -08:00
Cen Zhang
5bdef46685 ocfs2: keep locking_state within the cluster connection lifetime
The locking_state reader calls ocfs2_dlm_lvb() through the selected
cluster stack.  Its debug-object reference keeps the tracking list alive,
but does not keep that stack selected without a cluster connection.

DLM initialization publishes the file before establishing its connection,
and DLM shutdown drops the connection while the file still exists.  Both
the mount error unwind in ocfs2_mount_volume() and ocfs2_dismount_volume()
remove the debugfs subtree only after ocfs2_dlm_shutdown() has returned. 
Whenever the disconnect releases the last stack reference, which is the
case for a failed mount and for any unmount without a pending hangup, a
concurrent reader dereferences a NULL active_stack:

  Mount error unwind                  Debugfs reader
  ------------------                  --------------
  ocfs2_mount_volume(): out_dlm
    ocfs2_dlm_shutdown()
      disconnect last cluster
        clear active_stack
                                      read locking_state
                                        ocfs2_dlm_seq_show()
                                          ocfs2_dlm_lvb()
                                            dereference active_stack
  fill_super(): out_debugfs
    remove debugfs subtree

Publish the debug files only after the connection and the mount lock
resources are initialized, so a failed DLM initialization has no debug
reference to drop.  Remove them again in the common DLM shutdown helper
before the connection is dropped: debugfs removal waits for readers that
are inside the file operations, and the parent directory is still present
at that point in every caller.  This covers the mount error unwind, the
ocfs2_fill_super() failures after a successful mount that dismount with
mnt_err set, and unmounts whose disconnect releases the stack directly.

Only the relevant frames of the report are kept:

Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
RIP: 0010:ocfs2_dlm_lvb+0x38/0xf0
Call Trace:
 <TASK>
 ocfs2_dlm_seq_show+0x36a/0xb70
 seq_read_iter+0x480/0x1110
 seq_read+0x362/0x5a0
 full_proxy_read+0x11f/0x180
 vfs_read+0x1a0/0xc20
 ksys_read+0x111/0x200
 </TASK>

Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0011-v7-61e3ef8b1ad44ac2e817@gmail.com
Fixes: 286eaa95c5 ("ocfs2: Break out stackglue into modules.")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:57 -08:00
Clément Léger
7e7022849e MAINTAINERS: mailmap: use Clément Léger's linux.dev mail address
I recently requested a @linux.dev address so I can keep a consistent one
throughout my contributions and use it for the upcoming ones.  Map my
previously used email addresses to this new one.

Link: https://lore.kernel.org/20261029095107.24985-1-clement.leger@linux.dev
Signed-off-by: Clément Léger <clement.leger@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-11-02 19:18:56 -08:00
Andrew Morton
fe626e8c60 MAINTAINERS: add an IPC entry
Add an entry covering ipc/ and its IPC and POSIX message queue selftests,
with Andrew Morton as maintainer and Manfred Spraul and Davidlohr Bueso as
reviewers.

Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Acked-by: Manfred Spraul <manfred@colorfullife.com>
2026-11-02 19:18:56 -08:00
Cen Zhang
84db6619cb ocfs2: validate move extents against a stable EOF
The move-extents range must be bounded by the inode size used for extent
movement.  ocfs2_ioctl_move_extents() checks and clamps the request before
taking the local inode and cluster locks in ocfs2_move_extents().  It also
uses separate i_size_read() calls for the range check and subtraction.

A concurrent truncate can invalidate the first check and make the later
unsigned subtraction underflow:

  Move-extents ioctl                  Truncate
  ------------------                  --------
  check me_start <= i_size
                                      take inode and cluster locks
                                      shrink EOF below me_start
                                      release locks
  compare me_start + me_len with EOF
  set me_len = EOF - me_start
    [unsigned underflow]
  acquire inode and cluster locks
  select extents using the bad range

A truncate after clamping can also leave the range extending beyond EOF. 
Conversely, the cached size may be smaller than the size refreshed when
the cluster inode lock is acquired.  Early validation can then reject a
valid start or permanently shorten the requested length and threshold. 
The me_start + me_len comparison can also wrap for a large input length.

Validate and adjust the original request once, after inode_lock(), the
exclusive rw lock and ocfs2_inode_lock() have stabilized and refreshed the
size.  Read EOF once, reject a start beyond it, and bound the length by
EOF minus start.  Normalize the threshold using the same EOF snapshot. 
This keeps zero as the default-threshold sentinel until validation uses
the size that will govern extent movement.

Move goal validation after range adjustment as well.  Its allocation-group
capacity check uses me_len and must see the EOF-clamped length.  Both
validation failures use the existing inode-lock unwind path before any
extent movement or transaction starts.

Range errors now reach the ioctl's normal copyout path, as goal errors
already did.  Unlike the old early rejection, a failed copyout can
therefore override -EINVAL with -EFAULT.

Link: https://lore.kernel.org/pm-ocfs2-move-extents-isize-rrw-v6-395bdee84ea81149068e@gmail.com
Fixes: 53069d4e76 ("Ocfs2/move_extents: move/defrag extents within a certain range.")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:56 -08:00
Matheus Alves de Almeida
7b90009546 fat: hold truncate_lock in fat_write_failed()
The current fat_write_failed() implementation calls into
fat_truncate_blocks() without holding truncate_lock.

A failed or short extending write racing with FIBMAP can spuriously make a
FAT filesystem read-only.  FIBMAP bounds its lookup by i_blocks, so it can
walk allocated clusters beyond i_size while fat_write_failed() is removing
them.  If the chain is shortened during the walk, the mapper can report a
bogus "request beyond EOF" error, triggering the default read-only error
policy.  Hold truncate_lock for write around the block cleanup to
serialize it with _fat_bmap().

For comparison, fat_setattr() correctly holds truncate_lock during
truncation:

	down_write(&MSDOS_I(inode)->truncate_lock);
	truncate_setsize(inode, attr->ia_size);
	fat_truncate_blocks(inode, attr->ia_size);
	up_write(&MSDOS_I(inode)->truncate_lock);

Make it so ->truncate_lock is held exclusive while truncating.

Link: https://lore.kernel.org/20261021162105.62525-1-matheus.aalmeida@inf.ufrgs.br
Fixes: 16fab20150 ("fat: permit to return phy block number by fibmap in fallocated region")
Fixes: 459f6ed3b8 ("fat: convert to use the new truncate convention.")
Signed-off-by: Matheus Alves de Almeida <matheus.aalmeida@inf.ufrgs.br>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:56 -08:00
Matheus Alves de Almeida
4bdfe8dd23 fat: preallocate space before expanding in fat_cont_expand()
The fat_cont_expand() implementation leaves allocation of new clusters
to generic_cont_expand_simple(). This path does many small cluster
allocations, harming performance.

Preallocate cluster space in fat_cont_expand(). Move preallocation to
a new fat_preallocate() helper used by both fat_cont_expand() and
fat_fallocate(FALLOC_FL_KEEP_SIZE). Use a FAT-specific
fat_cont_expand_simple() instead of generic_cont_expand_simple() to
avoid rechecking the new size after clusters have been allocated.

Benchmarking was done under QEMU/KVM with a virtio-blk device using
cache=none. Each result is the arithmetic mean of the listed samples.

start = now_ns();
for (unsigned i = 0; i < count; i++) {
    if (truncate_mode)
        ftruncate(fds[i], bytes);
    else
        fallocate(fds[i], 0, 0, bytes);
}
elapsed = now_ns() - start;

16 files, 512-byte clusters:
length    mode      sync?    before    after    improvement    samples
256MiB    ftruncate no       9.576s    5.345s   1.79x          10
256MiB    fallocate no       9.634s    5.640s   1.71x          10
1MiB      ftruncate yes      58.66s    0.362s   162.15x        5
1MiB      fallocate yes      61.36s    0.390s   157.15x        5

128 files, 512-byte clusters:
length    mode      sync?    before    after    improvement    samples
512KiB    ftruncate no       0.433s    0.352s   1.23x          10
512KiB    fallocate no       0.446s    0.393s   1.13x          10
64KiB     ftruncate yes      31.32s    0.429s   73.00x         10
64KiB     fallocate yes      29.59s    0.410s   72.42x         10

16 files, 4096-byte clusters:
length    mode      sync?    before    after    improvement    samples
256MiB    ftruncate no       5.181s    4.417s   1.17x          10
256MiB    fallocate no       5.166s    4.442s   1.16x          10
1MiB      ftruncate yes      9.294s    0.111s   84.06x         10
1MiB      fallocate yes      8.710s    0.110s   79.36x         10

The biggest improvement is on filesystems with a small cluster size and
on synchronous mounts.

Link: https://lore.kernel.org/20261024013021.251898-1-matheus.aalmeida@inf.ufrgs.br
Signed-off-by: Matheus Alves de Almeida <matheus.aalmeida@inf.ufrgs.br>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
2026-11-02 19:18:55 -08:00
Joseph Qi
cd7c3563a9 ocfs2: do not read the entry array of an empty xattr block
ocfs2_cp_xattr_block_to_bucket() sizes the name and value area it has to
carry over from the block's last entry, so an empty block makes it read
xh_entries[-1].  That lands on the header, where xe_name_offset overlaps
xh_name_value_len, and block storage never maintains that field, so it
reads as 0 and the copy runs from the header to the end of the block.

The bucket that comes out has xh_count 0 but a name_value_len of
blocksize less the header, and a matching xh_free_start that claims
those bytes are in use -- nearly the whole bucket with the common 4K
block size -- while the last block of the bucket holds a copy of the old
block's bytes.  Nothing but a trace event reads xh_name_value_len, the
copied bytes came from the same inode and were wiped before the entry
was removed, and ocfs2_defrag_xattr_bucket() recomputes xh_free_start,
so this corrupts the header rather than leaking anything.

Leave the bucket empty instead, carrying over the hash the block was
keyed by, since ocfs2_add_new_xattr_bucket() and
ocfs2_xattr_bucket_find() both read xh_entries[0] of an empty bucket.
That read is the exception ocfs2_xa_remove_entry() documents rather than
a new out of bounds access.

A block reaches the conversion empty when truncating an external value
back fails partway through: the "reusing" and "overwriting" callers of
ocfs2_xa_cleanup_value_truncate() remove the entry without setting
ctxt->set_abort, so ocfs2_xattr_block_set() sees a plain -ENOSPC and
converts.  The "growing" caller does set it, and the block form makes a
single attempt with no defragment and retry in between, so that is the
only route here.

Link: https://lore.kernel.org/20261024151012.1059683-7-joseph.qi@linux.alibaba.com
Fixes: 012255961c ("ocfs2: Enable xattr set in index btree")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:55 -08:00
Joseph Qi
7133a0d095 ocfs2: do not index before the entry array when dividing an empty bucket
ocfs2_divide_xattr_bucket() appends an empty bucket carrying a sentinel
hash when the source bucket has no divide position, taking that hash
from xh_entries[start - 1].  ocfs2_xattr_find_divide_pos() returns count
when every entry shares one hash, and its loop does not run at all for
count < 2, so an empty bucket comes back with start == count == 0 and
the read is xh_entries[-1].

That is outside the __counted_by_le(xh_count) bounds of xh_entries[] and
lands on the header, so the value picked up is
xh_count | xh_free_start << 16.  One above it is written into the new
bucket's xh_entries[0] and committed, which leaves a bucket whose first
hash does not follow the bucket before it.  ocfs2_xattr_bucket_find()
binary searches on xh_entries[0], so the broken key hides the range the
sentinel was meant to cover: getxattr() answers -ENODATA for an
attribute that is stored, and an insert can go to the wrong bucket and
leave two copies of a name.  The cross cluster divide hands the same
value back as a tree record's e_cpos, which then claims a hash range it
does not cover.

Read xh_entries[0] instead.  The branch is only reached when every entry
shares one hash, so for a non-empty bucket it holds the same value, and
for an empty one it is the slot that carries the bucket key.

An empty bucket reaches the divide from
ocfs2_check_xattr_bucket_collision(), which reports no collision for
one, through ocfs2_add_new_xattr_bucket() and
ocfs2_extend_xattr_bucket().  It does not take a failed set to get
there: a divide that finds no position is itself what leaves an empty
sentinel bucket behind, and a later extend can pick it as the target.

Link: https://lore.kernel.org/20261024151012.1059683-6-joseph.qi@linux.alibaba.com
Fixes: 80bcaf3469 ("ocfs2/xattr: Proper hash collision handle in bucket division")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:55 -08:00
Joseph Qi
e8de099f29 ocfs2: do not read the entry array of an empty xattr bucket
ocfs2_check_xattr_bucket_collision() decides whether splitting a bucket
can make room by comparing the hash being inserted against the first and
the last entry.  xh_count comes off disk and is never checked, and a
bucket is allowed to hold no entries: ocfs2_xa_remove_entry() keeps the
last slot when it removes the only one, so that an empty bucket still
carries the hash it is keyed by.  xh_count then reads back as 0 while
xh_entries[0] is still meaningful, and the second comparison indexes
xh_entries[-1].

That is outside the __counted_by_le(xh_count) bounds of xh_entries[] and
lands on the header.  An entry is 16 bytes and xe_name_hash is its first
field, so the value read is xh_count | xh_free_start << 16.  It stays
inside the block, but the answer is arbitrary, and for an empty bucket
it says there is no collision, so a new bucket gets added on the
strength of it.

An empty bucket holds no entries to collide with.  Return before reading
the array.

One way to reach the test with an empty bucket is a set that removes the
bucket's only entry during cleanup and then fails for space again, since
it is that second -ENOSPC which calls this.  Growing a value past
OCFS2_XATTR_INLINE_SIZE is the easy route: the cluster allocation fails,
the "!orig_clusters" arm of ocfs2_xa_cleanup_value_truncate() removes
the entry, and although the "growing" caller does set ctxt->set_abort,
only ocfs2_xattr_block_set() and __ocfs2_xattr_set_handle() look at it,
so ocfs2_xattr_set_entry_index_block() goes straight on to the collision
check.

This sits on commit a9ea8b397864 ("ocfs2: use the stored hash when
checking xattr bucket collision"), which gave the collision check its two
argument form and is marked for 6.2 and later.  The read fixed here is
present in the three argument version too, but a tree without that
commit needs the hunk adapted by hand.

Link: https://lore.kernel.org/20261024151012.1059683-5-joseph.qi@linux.alibaba.com
Fixes: 012255961c ("ocfs2: Enable xattr set in index btree")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:55 -08:00
Joseph Qi
9c191a7a44 ocfs2: find the xattr entry again after converting a block to a bucket
ocfs2_xattr_create_index_block() turns a non-indexed xattr block into a
tree by copying it into a bucket, and the copy sorts the entries: a
block holds them in insertion order, a bucket by name hash.
ocfs2_xattr_update_xattr_search() nevertheless relocates the caller's
search by the index the entry had in the block, so unless the two orders
agreed it points at an unrelated entry, and nothing between there and
the write compares that entry's name with the one being set.

Setting an xattr whose new value no longer fits the block arrives here
with xs->not_found clear.  The block gave up because
ocfs2_xa_block_can_reuse() wants an exact namevalue size match, while
ocfs2_xa_bucket_can_reuse() only wants an entry at least as large as the
new one, so the bucket accepts a pair the block rejected and the update
lands on whichever entry the sort left at that index.  Equal padded name
lengths get that other attribute's value replaced in place and its name
left alone, so setxattr returns success while the attribute asked for
keeps its old value.  A longer one trips ocfs2_xa_reuse_entry()'s
BUG_ON, and a shorter one is refused by the bucket as well, so
ocfs2_xa_prepare_entry() wipes the entry and writes the new name over
it, leaving xe_name_hash describing a name that is no longer there.

Find the entry again by the name being set, matching the type as well.
The copy carries every entry and every name over unchanged, and (type,
name) pairs are unique within a block, so the match is exact.  The type
matters because the handlers strip their prefix before calling
ocfs2_xattr_set(), so user.foo and trusted.foo share a stored name, a
stored length and a hash, and both can sit in the same block.

The name has to come from xi rather than from xs->here: a failed set can
remove the entry xs->here names, and only the "growing" caller sets
ctxt->set_abort, which is what stops the conversion.  Scan every entry
rather than narrowing on the hash the way ocfs2_find_xe_in_bucket()
does, since an existing entry keeps the hash it was stored under, which
a kernel that sign-extended the name bytes made different from the one
computed now.  An empty result means the entry did not survive the
failed set and this has become an insert; leaving xs->here alone would
keep it pointing into the block, which is rewritten as a tree root
before the caller reads it again.

Link: https://lore.kernel.org/20261024151012.1059683-4-joseph.qi@linux.alibaba.com
Fixes: 012255961c ("ocfs2: Enable xattr set in index btree")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:54 -08:00
Joseph Qi
9a40c050f5 ocfs2: find the xattr entry again after defragmenting a bucket
ocfs2_xattr_set_entry_bucket() hands loc.xl_entry to ocfs2_xa_set() twice:
once for the bucket as it stands, and, if that reports -ENOSPC, once more
after ocfs2_defrag_xattr_bucket() has packed the name/value pairs down.

Defragmenting ends by sorting the entry array on xe_name_hash.  Buckets
are kept sorted, so the sort only permutes entries that share a hash, but
lib/sort.c is an unstable heapsort and it does permute them.  loc.xl_entry
is an address inside xh_entries[], so afterwards it denotes whichever
entry landed in that slot rather than the one the search found.

The second ocfs2_xa_set() then works on the wrong entry.  Nothing on that
path compares the entry's name with xi->xi_name, so what happens depends
on how the two entries compare in size: ocfs2_xa_reuse_entry() trips its
BUG_ON() when the padded name sizes differ, and otherwise the new value is
written into the neighbouring attribute's value slot while the attribute
being set is left untouched.  setxattr() reports success either way.

Remember the entry's hash before defragmenting and look the entry up
again afterwards, the way ocfs2_xattr_bucket_find() does.  An entry that
cannot be found again means the bucket no longer holds what the search
found, so fail with -EFSCORRUPTED rather than writing through the stale
pointer.

Link: https://lore.kernel.org/20261024151012.1059683-3-joseph.qi@linux.alibaba.com
Fixes: 012255961c ("ocfs2: Enable xattr set in index btree")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:54 -08:00
Joseph Qi
f48151da59 ocfs2: read the xattr entry hash before defragmenting the bucket
Patch series "ocfs2: fix stale xattr entry pointers and empty header
reads", v1.

Five defects in the ocfs2 extended attribute code, plus one robustness
measure that belongs with them, all on the paths that move entries
between a block, a bucket and an index tree.  They fall into two groups.

Stale entry pointers (patches 1 to 3)

ocfs2_xa_set() writes through a pointer into xh_entries[] that two of
its callers invalidate first.  Defragmenting a bucket ends in a sort()
on xe_name_hash, and lib/sort.c is an unstable heapsort, so entries that
share a hash can trade slots.  Copying a block into a bucket changes the
order outright, since a block holds its entries in insertion order while
a bucket holds them by hash, yet ocfs2_xattr_update_xattr_search()
relocates the search by the index the entry had in the block.  Neither
path compares the entry's name with the one being set, so setxattr() can
replace a neighbouring attribute's value and still report success, or
trip ocfs2_xa_reuse_entry()'s BUG_ON.  Patch 1 takes the hash before the
sort; patches 2 and 3 look the entry up again afterwards.

Reads of an empty entry array (patches 4 to 6)

A block and a bucket may both hold no entries: ocfs2_xa_remove_entry()
keeps the last slot when it removes the only one, so an empty bucket
still carries the hash it is keyed by.  Three sites index xh_entries[]
without checking xh_count and so read xh_entries[-1], which lands on the
header and comes back as xh_count | xh_free_start << 16.  Nothing
faults, but the value is acted on: the collision check reports no
collision for an empty bucket, the divide commits a sentinel hash that
hides part of the key space from ocfs2_xattr_bucket_find(), and the
block to bucket copy claims storage the bucket does not hold.  Patches 4
to 6 guard each site and keep the one read of xh_entries[0] that
ocfs2_xa_remove_entry() documents as intentional.


This patch (of 6):

ocfs2_xattr_set_entry_index_block() takes the hash a bucket split has to
work with out of xs->here, but only after ocfs2_xattr_set_entry_bucket()
has tried and failed to fit the entry.  That call defragments the bucket
when it runs out of room, and ocfs2_defrag_xattr_bucket() finishes by
sorting the entry array by name hash.  lib/sort.c is not stable, so two
entries sharing a hash may trade slots and xs->here is left naming an
entry other than the one the search found.

The hash value itself survives the permutation -- the array is already
sorted, so a slot can only exchange with an equal-hash neighbour -- but
there is no reason to depend on that.  Pick the hash up before the set,
where xs->here is unambiguously the entry the search landed on.

No functional change intended.

Link: https://lore.kernel.org/20261024151012.1059683-1-joseph.qi@linux.alibaba.com
Link: https://lore.kernel.org/20261024151012.1059683-2-joseph.qi@linux.alibaba.com
Fixes: e39baff18b ("ocfs2: use the stored hash when checking xattr bucket collision")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
2026-11-02 19:18:54 -08:00
Eklavya Singh
0a8f258c0f ocfs2/heartbeat: serialize concurrent writes to a region's dev attribute
o2hb_region_dev_store() checks reg->hr_bdev_file to see if the region
is already started, but nothing stops two writers from doing that at
the same time. configfs only serializes writes through the same open
file, so two processes that each open the dev attribute can both get
past the check:

  A: hr_bdev_file is NULL, opens file A, sets hr_bdev_file = A
  B: hr_bdev_file is NULL, opens file B, sets hr_bdev_file = B
  A: start fails, fput(hr_bdev_file) drops B, sets it to NULL
  B: start fails, fput(NULL)

Both calls also use the same hr_slots, hr_slot_data and hr_tmp_block,
so the error paths can free the slot data twice.

syzbot hit the fput(NULL) with an unbound loop device, where every
start fails with -EIO. With four threads doing the same thing on a
KASAN kernel I get both crashes within a second:

  BUG: KASAN: double-free in o2hb_unmap_slot_data+0x14d/0x2f0
  BUG: kernel NULL pointer dereference, address: 0000000000000158

Add a mutex to the region and hold it in dev_store(), in the
block_bytes, start_block and blocks stores, and in dev_show(), since
they all look at hr_bdev_file. dev_store() cleans up with goto, so it
takes the mutex in a small wrapper rather than with guard(). The mutex
is dropped while dev_store() waits for the heartbeat to become steady,
which takes seconds, so a read of dev doesn't stall behind a start.
hr_bdev_file is already set at that point, so other writers still get
-EINVAL, and the cleanup after the wait retakes the mutex.

With the patch the same test ran for 10 minutes with lockdep on and
nothing was reported. So did a second one, with a working loop device,
that interrupts starts during the wait while other threads read and
write the attributes.

Link: https://lore.kernel.org/20261020212339.46591-1-eklavyasingh2106@gmail.com
Fixes: a7f6a5fb4b ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
Signed-off-by: Eklavya Singh <eklavyasingh2106@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: <syzbot+5d4e96acd0febccb5e87@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=5d4e96acd0febccb5e87
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Deepanshu Kartikey <kartikey406@gmail.com>
Cc: Cen Zhang <zzzccc427@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:54 -08:00
Andrew Morton
8ff981aa28 openrisc: export __mulsi3 for modules
OpenRISC configurations without hardware multiplication fail to build
modules which contain compiler-generated calls to __mulsi3.  The failure
is widespread, affecting filesystems, drivers and KUnit tests at modpost.

When CONFIG_OPENRISC_HAVE_INST_MUL is disabled, the architecture Makefile
passes -msoft-mul to GCC.  The multiplication helper is supplied by the
libgcc archive linked into vmlinux, but or32_ksyms.c does not export it. 
Built-in callers can therefore link while module callers cannot resolve
the symbol.

Export __mulsi3 alongside the other compiler-generated helpers.

The omission predates 7c3f4d699f ("resource, kunit: stop selecting
GET_FREE_REGION"), which the robot identified when reporting an additional
failing module.  It was already present in the initial OpenRISC export
list.

Fixes: 616257669e ("OpenRISC: Miscellaneous")
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202610290106.o8Fs3NvO-lkp@intel.com/
Reviewed-by: Bradley Morgan <brads@mainlining.org>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Karl Mehltretter <kmehltretter@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:53 -08:00
Nathan Chancellor
3af83c11cf lib/base64: silence clang-24 -Wconstant-conversion with diag pragmas
After a recent change in clang to warn on signed char conversions within
array initializers [1], there are several instances of this warning from
base64_rev_maps in lib/base64.c, which can break the build with W=e or
CONFIG_WERROR=y:

  lib/base64.c:58:18: error: implicit conversion from 'int' to 's8' (aka 'signed char') changes value from 131 to -125 [-Werror,-Wconstant-conversion]
     58 |         [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
        |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
  lib/base64.c:52:2: note: expanded from macro 'BASE64_REV_INIT'
     48 | #define BASE64_REV_INIT(ch_62, ch_63) { \
        |                                       ~
     49 |         [0 ... 0x1f] = -1, \
     50 |         INIT_32(0x20, ch_62, ch_63), \
     51 |         INIT_32(0x40, ch_62, ch_63), \
     52 |         INIT_32(0x60, ch_62, ch_63), \
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  ...
  lib/base64.c:34:42: note: expanded from macro 'INIT_1'
     34 |                 : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
        |                                              ~~~~~~~~~~^~~~
  lib/base64.c:58:18: error: implicit conversion from 'int' to 's8' (aka 'signed char') changes value from 130 to -126 [-Werror,-Wconstant-conversion]
     58 |         [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
        |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
  lib/base64.c:52:2: note: expanded from macro 'BASE64_REV_INIT'
     48 | #define BASE64_REV_INIT(ch_62, ch_63) { \
        |                                       ~
     49 |         [0 ... 0x1f] = -1, \
     50 |         INIT_32(0x20, ch_62, ch_63), \
     51 |         INIT_32(0x40, ch_62, ch_63), \
     52 |         INIT_32(0x60, ch_62, ch_63), \
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  ...
  lib/base64.c:34:42: note: expanded from macro 'INIT_1'
     34 |                 : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
        |                                              ~~~~~~~~~~^~~~
  ...

These are false positives, as the branch where the wraparound could happen
is unreachable with the values that clang reports.  This is not considered
a bug by some clang folks [2][3], so silence the warnings using the __diag
macros the kernel has to workaround compiler warnings when necessary.

Link: https://lore.kernel.org/20261008-base64-silence-clang-24-constant-conversion-v1-1-0858b60b23c8@kernel.org
Link: a5ef934a8d [1]
Link: https://github.com/llvm/llvm-project/issues/223923#issuecomment-6056856245 [2]
Link: https://github.com/llvm/llvm-project/pull/226775#pullrequestreview-5454407389 [3]
Fixes: c4eb7ad32e ("lib/base64: optimize base64_decode() with reverse lookup tables")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Closes: https://github.com/ClangBuiltLinux/linux/issues/2181
Acked-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Bill Wendling <morbo@google.com>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Guan-Chun Wu <409411716@gms.tku.edu.tw>
Cc: <stable@vger.kernel.org>
2026-11-02 19:18:53 -08:00
Vlastimil Babka (SUSE)
19eab4cf78 MAINTAINERS: move SLAB ALLOCATOR under MEMORY MANAGEMENT
Following David's consolidation of several other MM subcomponents, do
the same for the slab allocator.

Rename the section to MEMORY MANAGEMENT - SLAB ALLOCATOR and move it to
remain in alphabetical order.

Remove Andrew as M: to signify he's not the primary person for picking
patches in this subcomponent. get_maintainers will continue CCing him on
most patches via the catch-all MM entry. David prefers not being added
for mail volume reasons.

Indicate the primary integration branch (slab/for-next) in the T: entry.
It will now be integrrated via the mm/linux integration tree.

Link: https://lore.kernel.org/20261101-maint-page_alloc-update-v1-2-27e8c246b13d@kernel.org
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Rientjes <rientjes@google.com>
Acked-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: SJ Park <sj@kernel.org>
Cc: Hao Li <hao.li@linux.dev>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Gregory Price <gourry@gourry.net>
2026-11-02 18:14:50 -08:00
Vlastimil Babka (SUSE)
a1836d0d6f MAINTAINERS: add Johannes as the page allocator co-maintainer
Patch series "MAINTAINERS updates for page and slab allocators".

Following David's updates [1], perform similar updates for page and slab
allocators to indicate the MM process transition for these
subcomponents. Importantly, add Johannes as a page allocator
co-maintainer.


This patch (of 2):

Johannes is a long-time expert and reviewer for the page allocator and
has agreed to step up to a co-maintainer role, so do that. Thanks!

Additionally, page allocator is joining the MM transition, following the
MM core updates from David [2].

Patches will be collected in the mm/page_alloc git tree and integrated
via the mm/linux integration tree. To signify the change from Andrew's
mm tree, remove Andrew as M: - get_maintainers will continue CCing him
on most patches via the catch-all MM entry. David prefers not being
added for mail volume reasons.

Link: https://lore.kernel.org/20261101-maint-page_alloc-update-v1-0-27e8c246b13d@kernel.org
Link: https://lore.kernel.org/20261101-maint-page_alloc-update-v1-1-27e8c246b13d@kernel.org
Link: https://lore.kernel.org/all/20261030-maintainers-v1-0-97278f8a5f54@kernel.org/ [1]
Link: https://lore.kernel.org/all/20261030-maintainers-v1-7-97278f8a5f54@kernel.org/ [2]
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: SJ Park <sj@kernel.org>
Cc: Hao Li <hao.li@linux.dev>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Gregory Price <gourry@gourry.net>
2026-11-02 18:14:50 -08:00
David Hildenbrand (Arm)
4e8a639c28 MAINTAINERS: route more MM changes through mm/core.git
Let's start routing more components I (co)maintain through mm/core.git.
Update the git trees by pointing them at the for-next branch:

 - MEMORY MANAGEMENT - BALLOON
 - MEMORY MANAGEMENT - CORE
 - MEMORY MANAGEMENT - GUP (GET USER PAGES)
 - MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
 - MEMORY MANAGEMENT - MEMORY HOT(UN)PLUG
 - MEMORY MANAGEMENT - MIGRATION
 - MEMORY MANAGEMENT - NUMA PLACEMENT
 - MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
 - MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)

Leave out MISC for now.

This change doesn't imply that all changes to these components will
immediately be routed through that tree; in particular changes that cover
other components, or severe conflicts will require coordination with
Andrew's tree.

So this marks merely the start of "mm/core.git will start picking
relevant material for these components".

Remove Andrew from these components to set the expectation that he won't be
the primary person picking stuff for these components; he is listed as
maintainer under the generic "MEMORY MANAGEMENT" and will get CCed on most
changes, and can keep an eye on stuff that falls through the cracks
(thanks!).

While at it, drop the link to http://www.linux-mm.org: it's not
particularly useful in 2026.

Link: https://lore.kernel.org/20261030-maintainers-v1-7-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Harry Yoo <harry@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:50 -08:00
David Hildenbrand (Arm)
d650358622 MAINTAINERS: rename and move MEMORY HOT(UN)PLUG
Prefix "MEMORY HOT(UN)PLUG" with "MEMORY MANAGEMENT" and put it into the
right spot in the MM component section list.

Link: https://lore.kernel.org/20261030-maintainers-v1-6-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Harry Yoo <harry@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:49 -08:00
David Hildenbrand (Arm)
a32c741897 MAINTAINERS: add missing files to MM component sections
We want to make sure that MM components cover all relevant MM files. The
generic "MEMORY MANAGEMENT" sections will probably go away at some
point.

We have a bunch of files that are not explicitly tracked under MM
components. Let's add these missing files.

Split up tools/mm to the appropriate components, but still add it also
under MISC, similar to what we did with selftests.

Don't split up selftests for now. They are covered by MISC and some
sections name them separately.

Some files like

 - include/linux/numa.h
 - include/trace/events/kmem.h
 - Documentation/admin-guide/numastat.rst

are a bit fuzzy. Add them to the best fit for now.

Link: https://lore.kernel.org/20261030-maintainers-v1-5-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Harry Yoo <harry@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:49 -08:00
David Hildenbrand (Arm)
3504810144 MAINTAINERS: sort entries in MM sections
We try to keep these entries sorted; let's sort the MM related ones.

Link: https://lore.kernel.org/20261030-maintainers-v1-4-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:49 -08:00
David Hildenbrand (Arm)
afa77645c9 MAINTAINERS: add Zi Yan as co-maintainer for MEMORY MANAGEMENT - THP
Zi has been contributing to THP consistently and reliably over many
years and is considered one of our most valuable THP experts. As THP is
an especially active area lately, having a single dedicated THP maintainer
is not sustainable.

Fortunately, Zi volunteered to take on more responsibility by stepping
up as a THP co-maintainer. So let's do exactly that.

His placement in the MAINTAINERS entry is very convenient to perform
this change :)

Link: https://lore.kernel.org/20261030-maintainers-v1-3-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Barry Song <baohua@kernel.org>
Acked-by: Lance Yang <lance.yang@linux.dev>
Acked-by: Dev Jain <dev.jain@arm.com>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:48 -08:00
David Hildenbrand (Arm)
bf2b6c47af MAINTAINERS: TMPFS (SHMEM FILESYSTEM) updates
I am not really the best shmem/tmpfs/memfd expert around, but it should
be good enough to judge when something is ready to be picked up, to then
pick it up. I'll have to heavily rely on Hugh and Baolin on judgment
for the more involved and more controversial bits.

Rename "TMPFS (SHMEM FILESYSTEM)" to "MEMORY MANAGEMENT - SHARED MEMORY
(SHMEM/TMPFS/MEMFD)" and move it accordingly. Add myself as a MAINTAINER
so people know whom to CC.

Add mm/core.git as the target git tree. Once shmem becomes a high volume
component we can dedicate it a separate tree and have dedicated people
pick it up.

While at it, add some more shmem/tmpfs/memfd related files+directories
we missed so far.

There is also "kernel/pid_sysctl.h", which includes some of the pid
namespaced sysctl vm.memfd_noexec. But that's really more of a proc/
namespace thingy, so it's not a good fit here.

Link: https://lore.kernel.org/20261030-maintainers-v1-2-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:48 -08:00
David Hildenbrand (Arm)
c4948eb28f MAINTAINERS: mention for-next branch in MEMORY MANAGEMENT - MEMORY MAP
Patch series "MAINTAINERS: MM updates".

Several MM updates:

Make Zi Yan a THP maintainer (thanks for all your hard work over
the years and thanks for taking on this responsibility), and perform some
MM MAINTAINERS cleanups.

Then, start the next step of the transition from Andrew's MM tree to
separate component trees that all get integrated into the mm-next
integration tree.

Start routing shmem through mm/core.git, adding me as a maintainer
primarily to pick patches.

Then, target the following components for the mm/core.git tree that I
(co)maintain:

     - MEMORY MANAGEMENT - BALLOON
     - MEMORY MANAGEMENT - CORE
     - MEMORY MANAGEMENT - GUP (GET USER PAGES)
     - MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
     - MEMORY MANAGEMENT - MEMORY HOT(UN)PLUG
     - MEMORY MANAGEMENT - MIGRATION
     - MEMORY MANAGEMENT - NUMA PLACEMENT
     - MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
     - MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)

More details in the last patch.

In the upcoming cycles we'll then route more of the other MM components
through different trees.

Let's see how this goes, in particular with the continuous stream of
fixes. But getting these in in a controlled way has highest priority
right now wither way.


This patch (of 7):

"memmap" will be used as a prefix for branches, but not as a branch
itself. "for-next" is the integration for all these things against which
people should ideally send patches.

Not mentioning a branch makes them assume "master", which is wrong.

So just mention the right thing, which is "for-next"

Link: https://lore.kernel.org/20261030-maintainers-v1-0-97278f8a5f54@kernel.org
Link: https://lore.kernel.org/20261030-maintainers-v1-1-97278f8a5f54@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Acked-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: Harry Yoo (Meta) <harry@kernel.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: SJ Park <sj@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Hao Li <hao.li@linux.dev>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Will Deacon <will@kernel.org>
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
2026-11-02 18:14:48 -08:00
T.J. Mercier
dd94d8c766 mm: memcontrol: fix NULL pointer deref and UAF from high_work_func() on dying memcg
When memory.high is exceeded in non-task context, try_charge_memcg()
schedules memcg->high_work without taking a reference on the memcg, and
high_work_func() invokes reclaim_high() without pinning the memcg.

With obj_cgroup reparenting, introduced in commit bf4f059954 ("mm:
memcg/slab: obj_cgroup API"), objects charged to a child memcg are
reparented to its parent in mem_cgroup_css_offline() instead of holding a
reference on the child until uncharged.  Subsequent uncharges of those
objects go to the parent, which can leave the child's memory use
permanently above its high limit, so any later charge on the offlined
memcg in non-task context schedules high_work.  This was later widened
from kernel memory to LRU folios when commit f1cf8d2f36 ("mm:
memcontrol: eliminate the problem of dying memory cgroup for LRU folios")
converted LRU folios to use obj_cgroup reparenting.

cancel_work_sync(&memcg->high_work) only runs at the end of teardown in
mem_cgroup_css_free(), so high_work_func() can start or still be running
reclaim_high() after mem_cgroup_css_released() or shrink_many() has called
lru_gen_release_memcg() and unhashed lruvec->lrugen.list.  If reclaim
tries to rotate the memcg, lru_gen_rotate_memcg() dereferences a NULL
pprev pointer.  This issue is specific to MGLRU and was introduced with
the memcg LRU in commit e4dde56cd2 ("mm: multi-gen LRU: per-node
lru_gen_folio lists").

With either traditional LRU or MGLRU, css_free_rwork_fn() calls
css_rstat_exit() which frees per-CPU rstat data before calling
mem_cgroup_css_free().  If reclaim_high() is still running, rstat updates
via mod_lruvec_state() -> __css_rstat_updated() cause a use-after-free on
the per-CPU rstat data.  This was introduced when commit 5da3bfa029
("cgroup: use separate rstat trees for each subsystem") moved
css_rstat_exit() ahead of ss->css_free().

Fix both problems by acquiring a reference with css_tryget_online() in
high_work_func() before calling reclaim_high(), and by resetting
memory.high and swap.high to PAGE_COUNTER_MAX in mem_cgroup_css_offline()
so that charges via references on an offlined memcg do not trigger
high_work on the dead child and skip checking live ancestors in
try_charge_memcg().

Acquiring the reference in high_work_func() rather than before scheduling
high_work is safe because mem_cgroup_css_free() calls irq_work_sync() and
cancel_work_sync() which cancels pending work and waits for an already
running high_work_func() to complete before mem_cgroup_free() frees the
memcg.  css_tryget_online() uses percpu_ref_tryget_live() and is safe to
call after percpu_ref_exit() before the cgroup is freed unlike
css_tryget().

Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
CPU: 1 UID: 0 PID: 27 Comm: kworker/1:0 Tainted: G    B   W           7.3.0-rc5-g2bba28e98578 #284 PREEMPT(full)
Tainted: [B]=BAD_PAGE, [W]=WARN  <-- Taint from lru_gen_rotate_memcg() VM_WARN_ON_ONCE
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
Workqueue: events high_work_func
RIP: 0010:lru_gen_rotate_memcg+0x1a3/0xe90
Call Trace:
 <TASK>
 ? read_ctrl_pos+0x22f/0x3f0
 shrink_lruvec+0x16cb/0x1b80
 ? ret_from_fork_asm+0x1a/0x30
 ? lapic_next_event+0x15/0x20
 ? clockevents_program_event+0x2bb/0x6f0
 ? lapic_next_event+0x15/0x20
 ? __pfx_shrink_lruvec+0x10/0x10
 ? __pfx_clockevents_program_event+0x10/0x10
 ? _raw_spin_lock+0x84/0xe0
 ? __pfx__raw_spin_lock+0x10/0x10
 ? kasan_save_stack+0x30/0x50
 ? psi_group_change+0x381/0x740
 ? __pfx_sched_clock_cpu+0x10/0x10
 ? save_fpregs_to_fpstate+0xc4/0x2c0
 ? finish_task_switch.isra.0+0x1de/0xac0
 ? __schedule+0xf62/0x42c0
 ? __pfx___schedule+0x10/0x10
 ? __pfx___irq_work_queue_local+0x10/0x10
 ? shrink_node+0x626/0x31e0
 shrink_node+0x626/0x31e0
 ? ring_buffer_unlock_commit+0x11d/0x5c0
 ? kswapd_clear_hopeless+0xa0/0x150
 ? __pfx_shrink_node+0x10/0x10
 ? 0xffffffffc0000095
 do_try_to_free_pages+0x255/0x13b0
 ? ring_buffer_unlock_commit+0x11d/0x5c0
 ? reclaim_high+0x10a/0x1b0
 try_to_free_mem_cgroup_pages+0x1f9/0x5a0
 ? __pfx_try_to_free_mem_cgroup_pages+0x10/0x10
 ? irqentry_exit+0xc6/0x670
 reclaim_high+0x10a/0x1b0
 ? __pfx_reclaim_high+0x10/0x10
 ? process_one_work+0x5ff/0x1030
 ? __pfx_high_work_func+0x10/0x10
 process_one_work+0x6e2/0x1030
 ? __pfx___schedule+0x10/0x10
 ? __pfx_process_one_work+0x10/0x10
 worker_thread+0x422/0xbb0
 ? __pfx_worker_thread+0x10/0x10
 kthread+0x2cd/0x3a0
 ? recalc_sigpending+0x15c/0x200
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x368/0x590
 ? __pfx_ret_from_fork+0x10/0x10
 ? __switch_to+0x588/0xf50
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>

Link: https://lore.kernel.org/20261029201858.2932905-1-tjmercier@google.com
Fixes: e4dde56cd2 ("mm: multi-gen LRU: per-node lru_gen_folio lists")
Fixes: 5da3bfa029 ("cgroup: use separate rstat trees for each subsystem")
Signed-off-by: T.J. Mercier <tjmercier@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Qi Zheng <qi.zheng@linux.dev>
Cc: JP Kobryn <jp.kobryn@linux.dev>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:48 -08:00
Mike Rapoport (Microsoft)
f8f9cbc34a mm/cma: accept memory of CMA areas reserved at a fixed address
CMA areas allocated from memblock have their memory accepted by
memblock_alloc_range_nid(), but areas reserved at a fixed address with
memblock_reserve() are not.

If a fixed CMA area is requested by the cma=<size>@<base> command line
parameter, it may be in regular RAM and on TDX and SEV-SNP guests it
must be accepted.

Accept the memory of fixed CMA areas as well, so that all CMA areas are
accepted regardless of how they were reserved.

Link: https://lore.kernel.org/20261029-cma-multi-v1-2-2cbced8b5cb7@kernel.org
Fixes: 75d090fd16 ("x86/tdx: Add unaccepted memory support")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com>
Tested-by: Pankaj Gupta <pankaj.gupta@amd.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:47 -08:00
Mike Rapoport (Microsoft)
5d00200160 mm/cma: accept memory of multi-range CMA areas
Patch series "mm/cma: accept memory of CMA areas reserved with
memblock_reserve()", v1.

Pages of allocated CMA areas are released to the buddy allocator with
__free_pages(), which does not check for unaccepted memory.

This usually works because memblock accepts the memory it allocates.

However, multi-range CMA areas, used by hugetlb_cma, and fixed CMA areas
requested with cma=<size>@<base> are reserved with memblock_reserve() and
their memory is never accepted.

On TDX and SEV-SNP guests the first access to such a page is fatal.

To ease the backporting, each case is addressed by a separate patch:
- patch 1 accepts the memory of multi-range CMA areas
- patch 2 does the same for the fixed CMA areas

The second patch won't apply cleanly to 6.6 and 6.12, but I believe the
stable team LLMs will take care of that :)


This patch (of 2):

On systems with unaccepted memory, memblock allocations accept the
allocated range, but when cma_declare_contiguous_multi() uses open coded
allocation of multiple ranges, it reserves them with memblock_reserve()
and they are never accepted.

These pages are released to the buddy allocator by cma_activate_area()
with __free_pages() that does not check for unaccepted memory, so the
first access to such a page in a TDX or SEV-SNP guest is fatal.

Accept the memory of each range when it is reserved.

Link: https://lore.kernel.org/20261029-cma-multi-v1-0-2cbced8b5cb7@kernel.org
Link: https://lore.kernel.org/20261029-cma-multi-v1-1-2cbced8b5cb7@kernel.org
Fixes: c009da4258 ("mm, cma: support multiple contiguous ranges, if requested")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com>
Tested-by: Pankaj Gupta <pankaj.gupta@amd.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:47 -08:00
Salvatore Dipietro
0e05a469c2 mm/page_alloc: avoid direct reclaim and compaction for costly __GFP_NORETRY allocations
Commit 5d8edfb900 ("iomap: Copy larger chunks from userspace")
introduced high-order folio allocations in the iomap buffered write path. 
When memory is fragmented, each failed costly-order allocation enters
__alloc_pages_slowpath() which runs direct reclaim, direct compaction and
drain_all_pages(), causing a 0.38x throughput drop on PostgreSQL pgbench
(simple-update) with 1024 clients on a 96-vCPU arm64 system.

The root issue is that direct reclaim and direct compaction are too
expensive for hot allocation paths that have fallbacks to smaller
allocations.  __filemap_get_folio_mpol() already marks higher-order
allocations with __GFP_NORETRY | __GFP_NOWARN, signalling that the caller
can handle failure.  However, the page allocator still enters the full
blocking slowpath for costly orders with __GFP_NORETRY, which is
unnecessarily aggressive when the caller will simply retry at a lower
order.

For costly-order allocations with __GFP_NORETRY, clear
__GFP_DIRECT_RECLAIM at the very start of the slowpath, before
can_direct_reclaim, can_compact and the nofail checks are evaluated.  This
makes the entire slowpath treat the request as non-blocking: no direct
reclaim, no direct compaction and no drain_all_pages() IPI across every
CPU.  Reclaim and compaction move to the background instead: kswapd is
still woken for reclaim, and it wakes kcompactd for defragmentation.  The
system keeps its long-term health while the latency-critical direct
allocation path no longer stalls.

Allocations that also request __GFP_THISNODE are exempted.  That flag
pairing identifies the local-node-first THP attempt issued by
alloc_pages_mpol() (mempolicy.c), which relies on direct compaction to
form transparent huge pages.

Clearing __GFP_DIRECT_RECLAIM makes these allocations reach the
!can_direct_reclaim bailout, which since commit 4c0ed883e0
("mm/page_alloc: fix defrag_mode for non-reclaimable allocations") drops
ALLOC_NOFRAGMENT and retries instead of failing when defrag_mode is on. 
With vm.defrag_mode=1 a __GFP_NORETRY allocation could therefore succeed
by fragmenting another migratetype's pageblock.  That is the wrong trade
for a caller that has already communicated it can handle failure and has a
cheap lower-order fallback, so exclude __GFP_NORETRY from the relaxation. 
The exclusion is not restricted to costly orders: any __GFP_NORETRY caller
has said it can cope with failure, so failing is preferable to fragmenting
for all of them.

Test environment:
  Hardware:  AWS EC2 m8g.24xlarge (96 vCPU, arm64)
             12x 1TB IO2 32000 IOPS RAID0 XFS
  OS:        AL2023
  Kernel:    v7.3-rc1
  Database:  PostgreSQL 18.4
  Workload:  pgbench simple-update, 1024 clients, 96 threads, 1200s

Results (average of 3 runs, TPS):

  Config                                       Avg TPS   % vs baseline
  v7.3-rc1 baseline (vm.defrag_mode=0)          58,602               -
  v7.3-rc1 + this patch (vm.defrag_mode=0)     157,246         +168.3%
  v7.3-rc1 baseline (vm.defrag_mode=1)         109,012               -
  v7.3-rc1 + this patch (vm.defrag_mode=1)     157,778          +44.7%

Link: https://lore.kernel.org/20261001082152.2879289-1-dipiets@amazon.it
Link: https://lore.kernel.org/all/20260403193535.9970-1-dipiets@amazon.it/T/#t [v1]
Link: https://lore.kernel.org/linux-mm/20260420161404.642-1-dipiets@amazon.it/T/#u [v2]
Link: https://lore.kernel.org/all/20260710143437.12379-1-dipiets@amazon.it/T/#u [v3]
Link: https://lore.kernel.org/all/20260904115629.3993331-1-dipiets@amazon.it/T/#u [v4]
Link: https://lore.kernel.org/all/20260911142102.2294202-1-dipiets@amazon.it/T/#u [v5]
Fixes: 5d8edfb900 ("iomap: Copy larger chunks from userspace")
Signed-off-by: Salvatore Dipietro <dipiets@amazon.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: David Hildenbrand <david@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Dave Chinner <dgc@kernel.org>
Cc: Ritesh Harjani <ritesh.list@gmail.com>
Cc: Dmitry Ilvokhin <d@ilvokhin.com>
Cc: Hazem Mohamed Abuelfotoh <abuehaze@amazon.com>
Cc: Ali Saidi <alisaidi@amazon.com>
Cc: Geoff Blake <blakgeof@amazon.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: <dipietro.salvatore@gmail.com>
Cc: Darrick J. Wong <djwong@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: <rvvandan@amazon.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: "Garg, Shivank" <shivankg@amd.com>
2026-11-02 18:14:47 -08:00
Johannes Weiner
fe21f930d1 mm: page_alloc: remove ALLOC_NON_BLOCK from ALLOC_RESERVES
1ebbb21811 ("mm/page_alloc: explicitly define how __GFP_HIGH
non-blocking allocations accesses reserves") stopped handing out reserve
access for ALLOC_NON_BLOCK on its own: the extra 25% below the min
watermark is now only granted on top of ALLOC_MIN_RESERVE.  But the flag
was left in ALLOC_RESERVES, which produces something odd:

With the ALLOC_RESERVES match, __zone_watermark_unusable_free() doesn't
subtract the free highatomic pages for them.  So in the slowpath, they get
to consume regular blocks below the min watermark by the number of free
highatomic pages.  The highatomic reserve is capped at 1% of the zone,
which on any decently sized machine is a multiple of the min watermark:
GFP_NOWAIT can drain regular memory to zero.

The user-visible result is brutal hiccups during bursts of GFP_NOWAIT
allocations under memory pressure.  This was found in review and
reproduced with a synthetic burst, not observed in production, but the
sequence of events is a realistic one: On a 32G box with an anonymous
working set, swap, and a filled 290M highatomic reserve, a GFP_NOWAIT
burst drove regular free memory in the 28G Normal zone (min=60M) to 28M,
0.8M and 0.6M in three runs.  Swapout failed to allocate its swap table,
reclaim scanned 13M pages to reclaim 200k, page faults stalled for tens to
hundreds of milliseconds.  The machine survives it, but not by design:
direct reclaimers eventually fail and start unreserving highatomic blocks,
until the allocation succeeds or the reserve is gone and the OOM killer
runs.  That reserve exists for high-order atomic allocations; here it is
destroyed to bail out a GFP_NOWAIT consumer that was never entitled to the
memory.

Remove ALLOC_NON_BLOCK from ALLOC_RESERVES.  With that, the GFP_NOWAIT
burst is stopped short at the min watermark.  No direct reclaim, no
stalls, no failed allocations, and the highatomic reserve stays intact for
the requests it exists for.

__zone_watermark_ok() is unaffected, since everything it keys on
ALLOC_NON_BLOCK is already nested under ALLOC_MIN_RESERVE.  Update the
flag comments accordingly: ALLOC_NON_BLOCK just means the caller can't
block; the reserve math belongs with ALLOC_MIN_RESERVE.

GFP_ATOMIC order-0 requests have a milder version of the same problem. 
Through ALLOC_MIN_RESERVE they also count the free highatomic pages in
their watermark check, but rmqueue_buddy() serves them regular pages first
and only falls back to the reserve once those are gone.  They can still
push regular free memory to 37.5% of min minus the free highatomic pages
before the reserve is touched.  Unlike GFP_NOWAIT they are entitled to the
reserve, so this needs the watermark check and the freelist order reworked
together, and is left to a separate patch.

Link: https://lore.kernel.org/20261028171719.2043421-3-hannes@cmpxchg.org
Fixes: 1ebbb21811 ("mm/page_alloc: explicitly define how __GFP_HIGH non-blocking allocations accesses reserves")
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Balbir Singh <balbirs@nvidia.com>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Salvatore Dipietro <dipiets@amazon.it>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <dgc@kernel.org>
Cc: Matt Fleming <matt@readmodwrite.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Zi Yan <ziy@nvidia.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:47 -08:00
Johannes Weiner
6ee3d87b94 mm: page_alloc: do not give all non-blocking requests reserve access
Patch series "mm: page_alloc: fix reserve access for non-blocking
requests", v2.

Two fixes for how non-blocking allocations interact with the highatomic
reserve.  There are prerequisites for Salvatore's "mm/page_alloc: avoid
direct reclaim and compaction for costly __GFP_NORETRY allocations" [0].

Patch 1 narrows which requests may physically take highatomic pages,
patch 2 narrows which requests may count them in their watermark check.

Both are prerequisites for Salvatore's patch: it clears
__GFP_DIRECT_RECLAIM for costly __GFP_NORETRY requests, which turns every
large page cache folio allocation that reaches the slowpath into a
non-blocking one.  Without patch 1, those requests may fall back to the
highatomic freelists reserved for atomic requests.  Without patch 2, they
count the free highatomic pages in their watermark check while being
served from regular memory, so they can consume regular high-order blocks
below the min watermark by the size of the reserve.  GFP_NOWAIT requests
hit both paths today, so these are existing problems worthy of their own
stable backports; but Salvatore's patch would widen them significantly.

Patch 2 reproduction: a GFP_NOWAIT burst under memory pressure can drain
regular free memory to zero while the highatomic reserve sits idle. 
Measured on a 32G box with an anonymous working set, swap, and a full 290M
reserve, three synthetic bursts drove the 28G Normal zone's regular free
memory to 28M, 0.8M and 0.6M against a 60M min watermark.  Swapout failed
its swap table allocation inside reclaim, reclaim scanned 13M pages to
free 200k, and page faults stalled for tens to hundreds of milliseconds. 
With the fix the burst stops at the min watermark and nothing else
happens.  This was found in review and reproduced synthetically; it has
not been observed in production.

GFP_ATOMIC order-0 requests have a milder version of the same problem:
They are entitled to the reserve but are served regular memory first, so
the fix there has to change the watermark check and the freelist order
together.  Salvatore's change doesn't interact with this, though; fixing
that is left for a separate patch.


This patch (of 2):

281dd25c1a ("mm/page_alloc: let GFP_ATOMIC order-0 allocs access
highatomic reserves") accidentally gave all non-blocking allocation
requests access to highatomic reserves, which includes GFP_NOWAIT and
other sites clearing __GFP_DIRECT_RECLAIM.

While this improved atomic request success rate, it's unintentionally
broad and can actually worsen highatomic requests by squandering the
reserves on requests that don't need it.

There are concurrent efforts to clear __GFP_DIRECT_RECLAIM altogether
for costly order __GFP_NORETRY requests, which would then also fall
into this exemption and deplete reserves even faster.

What GFP_ATOMIC has over the others is __GFP_HIGH, which
alloc_flags_slowpath() translates to ALLOC_MIN_RESERVE.

Narrow the exemption to contexts that have both ALLOC_NON_BLOCK |
ALLOC_MIN_RESERVE.

Link: https://lore.kernel.org/20261001082152.2879289-1-dipiets@amazon.it [0]
Link: https://lore.kernel.org/linux-mm/arFBWvzXPYrKuIYi@cmpxchg.org/ [1]
Link: https://lore.kernel.org/linux-mm/20261001082152.2879289-1-dipiets@amazon.it/ [2]
Link: https://lore.kernel.org/20261028171719.2043421-1-hannes@cmpxchg.org
Link: https://lore.kernel.org/20261028171719.2043421-2-hannes@cmpxchg.org
Fixes: 281dd25c1a ("mm/page_alloc: let GFP_ATOMIC order-0 allocs access highatomic reserves")
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260904115629.3993331-1-dipiets@amazon.it
Acked-by: Balbir Singh <balbirs@nvidia.com>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Salvatore Dipietro <dipiets@amazon.it>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <dgc@kernel.org>
Cc: Matt Fleming <matt@readmodwrite.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Zi Yan <ziy@nvidia.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:46 -08:00
Kiryl Shutsemau (Meta)
0120a603af mm/hugetlb_vmemmap: map the shared tail page writable
page_ref_add_unless_zero() reads the refcount and then updates it with a
cmpxchg.  A lockless get, such as a page cache lookup or a PFN scanner,
can read a non-zero refcount from a page that is then freed and reused as
a hugetlb tail page.  If HVO remaps its struct page to the shared tail
page in between, the cmpxchg writes to read-only vmemmap:

    CPU0 (lockless get)               CPU1
    c = atomic_read(&page->_refcount)
                                      page freed
                                      page allocated as a hugetlb tail
                                      HVO remaps the struct page RO
    try_cmpxchg(&page->_refcount, &c, c + 1)
      -> write fault on read-only vmemmap

The refcount is zero by then and the compare fails, but a compare-and-swap
instruction needs write access whether or not it succeeds.  The kernel
oopses when hugetlb pages are allocated at runtime with HVO enabled while
a lockless get races with it.

Commit bd225530a4 ("mm/hugetlb_vmemmap: fix race with speculative PFN
walkers") closed the window with RCU on both sides.  The RCU was removed
together with fake heads, on the wrong belief that it was only needed for
them.

Map the shared tail page writable instead of restoring the RCU.  Every
struct page on it is a tail with a zero refcount, so a late cmpxchg
fails and leaves the page unchanged.  RCU would put rcu_read_lock()
back around every get and synchronize_rcu() back into hugetlb
allocation and freeing.

The cost is the protection against stray writes to tail struct pages.  The
shared page is shared by all hugetlb folios of the same order in the zone,
so such a write now corrupts all of them instead of oopsing.

Bootmem folios optimized when the memmap is set up keep their tails
read-only.  Nothing does a lockless get on them before hugetlb takes them
over.

Link: https://lore.kernel.org/20261028132623.2560146-1-kirill@shutemov.name
Fixes: 32c440d67e ("mm: drop fake head checks")
Fixes: 01b1d0ffb6 ("hugetlb: remove VMEMMAP_SYNCHRONIZE_RCU")
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: David Hildenbrand (Arm) <david@kernel.org>
Closes: https://lore.kernel.org/r/ebc7bde1-f52e-4da8-b16f-822d6c0a4d74@kernel.org
Acked-by: Muchun Song <muchun.song@linux.dev>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:46 -08:00
Lorenzo Stoakes (ARM)
ee1afc5539 fs/proc/task_mmu: fix missed VMAs when reading /proc/PID/maps and friends
Reading /proc/PID/maps under per-VMA locks can skip continuously mapped
address ranges during concurrent VMA splits or merges. This violates the
guarantee in Documentation/filesystems/proc.rst:

"If there is something at a given vaddr during the entirety of the
life of the smaps/maps walk, there will be some output for it."

lock_next_vma() reuses a tree iterator across calls under RCU. The iterator
remembers the range of its last entry. When its node is replaced,
mas_next_slot() walks the tree again at the last index of that range, then
advances past the entry containing that index. If VMA boundaries changed,
this can skip a range that has not been reported:

- A lookup finds [A, C), then mprotect() splits it into [A, B) and [B, C)
  before vma_start_read() locks the first VMA. The reader reports [A, B),
  but the iterator still covers [A, C). The next call starts from B yet
  advances past C, omitting [B, C).

- The reader reports [A, B) and unlocks it. A concurrent mprotect() then
  merges it with [B, C). On the next call, the iterator resumes at B - 1,
  which now belongs to [A, C), and advances past C. Again, [B, C) is lost.

Checking the mmap_lock sequence only within the next call misses writers
that completed before that call began. Also, a NULL result is currently
accepted without validation, so a race can terminate the walk early.

Even a fresh lookup can skip a mapping. Suppose it finds a gap before
[B, C). A writer inserts an adjacent VMA at the end of that gap, then
merges it into [B, C), replacing the node. The lookup resumes at the old
gap's last index, now inside the merged VMA, and steps past it. The
original [B, C) remains mapped throughout. Repeating the forward lookup
is insufficient: another merge can make it skip the same mapping again,
returning the same later VMA or NULL.

The fresh-lookup race also affects /proc/PID/smaps, numa_maps and
smaps_rollup. Resetting the iterator after gathering each VMA's statistics
does not prevent a merge during the next lookup. Fixing lock_next_vma()
also prevents omitted entries and incomplete rollup statistics.

Tie VMA iterator state with the current mm and the write generation at the
point of last mm speculation in vma_rcu_iter, whose values we call 'rvmi'.

This allows us to neatly abstract the existing priv->iter logic alongside
query_vma_find_by_addr() which uses its own VMA iterator.

Then, provide helpers that act on the rvmi - vma_rcu_iter_[maybe_changed,
may_have_skipped]() to determine whether any VMAs may have
been altered since last mm speculation.

Additionally introduce vma_range_is_empty(), used by
vma_rcu_iter_may_have_skipped(), to determine conclusively whether VMAs
exist in a set range, needing to be traversed.

Original fix generated by an LLM and sent by Josef Bacik in private, then
amended by David Hildenbrand, and Lorenzo Stoakes added additional
abstraction.

Link: https://lore.kernel.org/20261027-fix-proc-pid-maps-missing-vmas-v2-1-2791cc9fc95f@kernel.org
Fixes: 5631da56c9 ("fs/proc/task_mmu: read proc/pid/maps under per-vma lock")
Fixes: ea3085dd7a ("fs/proc/task_mmu: read proc/pid/{smaps|numa_maps} under per-vma lock")
Fixes: 0e985559d7 ("proc/task_mmu: read proc/pid/smaps_rollup under per-vma lock")
Fixes: d9d1c2d817 ("fs/proc/task_mmu: execute PROCMAP_QUERY ioctl under per-vma locks")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Co-developed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Tested-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: SJ Park <sj@kernel.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:46 -08:00
Zenghui Yu (Huawei)
1b8fd9a235 selftests/mm: fix khugepaged_race build with older glibc
glibc versions before 2.37 do not define MADV_COLLAPSE in <sys/mman.h>, so
khugepaged_race fails to build against them (e.g. glibc 2.34):

[root@localhost mm]# make
  CC       khugepaged_race
khugepaged_race.c: In function 'main':
khugepaged_race.c:506:23: error: 'MADV_COLLAPSE' undeclared (first use in this function); did you mean 'MADV_COLD'?
  506 |       hpage_pmd_size, MADV_COLLAPSE);
      |                       ^~~~~~~~~~~~~
      |                       MADV_COLD
khugepaged_race.c:506:23: note: each undeclared identifier is reported only once for each function it appears in
make: *** [../lib.mk:225: /data/code/mm/tools/testing/selftests/mm/khugepaged_race] Error 1

Include <linux/mman.h> to get the UAPI definition of MADV_COLLAPSE.

Link: https://lore.kernel.org/20261027122013.4286-1-zenghui.yu@linux.dev
Fixes: 66c3744644 ("selftests/mm: add khugepaged race harness")
Signed-off-by: Zenghui Yu (Huawei) <zenghui.yu@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
2026-11-02 18:14:45 -08:00
Lorenzo Stoakes (ARM)
168ed9c5d5 mm/vma: update VMA iterator state on error in new VMA merge
Commit cacded5e42 ("mm: avoid using vma_merge() for new VMAs") shared
code between vma_merge_new_range() and vma_expand().

However in doing so, it failed to correctly restore the VMA iterator when
vma_expand() errors out.

This is a problem when the immediately preceding VMA is mergeable and
vmg->just_expand isn't specified, at which point the VMA iterator is moved
to the previous VMA.

(Note that vmg->just_expand is a special case for brk(), where the
iterator will already be positioned at the VMA to be expanded.)

Resolve things by restoring the VMA iterator on error. Use
vma_iter_next_range() to do this, so it will correctly stop on the gap
after the previous VMA, rather than skip to the next VMA after it (this is
a new VMA merge, so is being applied at a gap).

To isolate the error handling, return early when a merge isn't
possible (what the vmg->target check was doing before), then handle the
merge success/failure case explicitly.

While here, update vma_expand() to jump to the nomem case when
dup_anon_vma() fails, so vmg->state is correctly updated.

This doesn't impact anything in practice, but is the correct course and
since it's part of the error path that this patch addresses, it makes sense
to update it also.

Users are very unlikely to have observed the issue this patch addresses in
practice, as it is near-impossible to fail an allocation for an anon_vma,
but a process under memory pressure that receives a fatal signal could
trigger it.

This issue was originally reported by Li Jinyue for which I am grateful. He
indicated this was uncovered by a private syzkaller instance.

Link: https://lore.kernel.org/20261027-fix-new-merge-bug-v1-1-7023a787e6b9@kernel.org
Fixes: cacded5e42 ("mm: avoid using vma_merge() for new VMAs")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Li Jinyue <jinyue.li@linux.alibaba.com>
Closes: https://lore.kernel.org/all/20261025093921.1011927-1-jinyue.li@linux.alibaba.com/
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:45 -08:00
Yafang Shao
fe623a81ad mm/migrate: snapshot the source nid before the misplaced migration
A successful migration frees the source folio before the promotion
counter update, so the folio_nid() read there operates on a freed
folio — which may already have been reallocated. It happens to work
today, as Zi explained:

  : Strictly speaking, it can be seen as a benign UAF. It works, because
  : 1. folio->flags happens to be the same as page->flags,
  : 2. folio/page nid is stored in the ->flags and never changed.
  :
  : In memdesc world, after a folio is freed, I assume folio->flags would be
  : zeroed since struct folio is freed and calling folio_nid() on a freed
  : folio would give a bogus result (yeah, it can be mitigated by not
  : zeroing node field and each node has its own struct folio pool, but that
  : makes folio_nid() implementation dependent).

and Matthew explained further:

  : once struct folio is separately allocated, it's a UAF.  It could be
  : recycled to a different NID or maybe the slab containing the folio could
  : be freed (assuming we're not holding the RCU read lock at this point in
  : migration, and I don't see why we would be).

A separate concern is memory hot-removal.  With memory-tiering mode
enabled, successful migration can release the source before the
promotion-accounting folio_nid() read.  If the task is preempted there,
an otherwise-free source block can be offlined and removed first.  On
the x86 path, removal can unmap the source's vmemmap, so the later read
can fault.  The snapshot avoids that read.

Link: https://lore.kernel.org/20261027021721.95781-1-laoar.shao@gmail.com
Fixes: e39bb6be9f ("NUMA Balancing: add page promotion counter")
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Zi Yan <ziy@nvidia.com>
Suggested-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:45 -08:00
Lance Yang
990d6c2194 mm/ksm: fix userfaultfd protection during merge and unmerge
KSM loses userfaultfd protection when replace_page() builds a new PTE from
vma->vm_page_prot.  Dropping its uffd bit lets a subsequent write go
through ordinary COW instead of userfaultfd write protection handling. 
For RWP, a merged page also becomes readable without faulting.

Keeping the uffd bit and restoring PAGE_NONE fixes merging, but we also
have to handle unmerging.  An existing KSM page can be protected with RWP
before MADV_UNMERGEABLE, so unmerging already needs fixing independently
of preserving RWP during merging.

Unsharing replaces a shared page with a private one and should leave
userfaultfd protection in place, as do_wp_page() already does for write
protection.  Currently, an unshare fault reaches do_uffd_rwp() before it
can proceed to do_wp_page().

- With synchronous RWP, handle_userfault() returns VM_FAULT_SIGBUS.
  break_ksm() then reports success with a KSM page still merged.

- With asynchronous RWP, protection is cleared before unsharing.

Preserve the uffd bit when merging, and restore PAGE_NONE for RWP.  Let
FAULT_FLAG_UNSHARE skip RWP fault handling and keep PAGE_NONE on each
private copy as well.  Unsharing can then complete with RWP still armed
for a subsequent access.

Link: https://lore.kernel.org/20261026130054.91461-1-lance.yang@linux.dev
Link: https://lore.kernel.org/all/20261019010934.697895-1-samarth.colleges@gmail.com/
Link: https://lore.kernel.org/all/20261020055518.36087-1-lance.yang@linux.dev/
Fixes: 63b2d4174c ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Fixes: 2d427bb016 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP")
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Co-developed-by: Samarth Narang <samarth.colleges@gmail.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Xu Xin <xu.xin@linux.dev>"
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Bobby Powers <bobbypowers@gmail.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Denis Plotnikov <dplotnikov@virtuozzo.com>
Cc: Doug Gilbert <dgilbert@interlog.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Martin Cracauer <cracauer@cons.org>
Cc: Marty McFadden <mcfadden8@llnl.gov>
Cc: Maya Gokhale <gokhale2@llnl.gov>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Shaohua Li <shli@fb.com>
Cc: James Houghton <jthoughton@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: SJ Park <sj@kernel.org>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Mohammed EL Kadiri <med08elkadiri@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:45 -08:00
Hungyu Lin
7d8746d7dc mm/migrate: untag addresses when querying page nodes
When move_pages() is used with nodes == NULL, do_pages_stat_array() passes
each page address directly to vma_lookup().  A valid tagged address
therefore fails the VMA lookup and gets -EFAULT in its status entry,
instead of the node reported for the corresponding untagged address.

The tagged address ABI permits these pointers, and the migration path
already removes their tags.  Apply the target mm's untagging rules to the
query path as well, while holding its mmap read lock.

Link: https://lore.kernel.org/20261026195330.46757-1-dennylin0707@gmail.com
Fixes: 057d338910 ("mm: untag user pointers passed to memory syscalls")
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/r/20260721183257.706661F000E9@smtp.kernel.org
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: <odys.yuan@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:44 -08:00
Chris Down
740128dd1a mm: make swapoff interruptible when unusing mms/shmem
try_to_unuse() only checks for a pending signal between mms, and
shmem_unuse() doesn't check at all.  That means that once swapoff gets to
a process or a shmem file with a lot swapped out, nothing can interrupt it
until every last page of it has been read back in.

Just as one example of where this can concretely show up, freezing tasks
for suspend or hibernation has to wait for swapoff to notice the freezer's
fake signal, and gives up after freeze_timeout_msecs (20 seconds by
default).

Here's a facetious example where one swaps out 2GiB of one process to a
swap file on ext4, starts swapoff, and half a second later tries to freeze
with pm_test=freezer.  Writing to /sys/power/state then fails with EBUSY
and this in dmesg:

    Freezing user space processes failed after 20.003 seconds (1 tasks refusing to freeze, wq_busy=0):
    task:swapoff         state:D stack:0     pid:3175  tgid:3175  ppid:2955   task_flags:0x400100 flags:0x00000419
    Call trace:
     [...]
     io_schedule+0x44/0x70
     folio_wait_bit_common+0x1ec/0x3d0
     __folio_lock+0x24/0x40
     unuse_pte_range+0x2d0/0x348
     unuse_vma+0x158/0x248
     unuse_mm+0xfc/0x150
     try_to_unuse+0x104/0x3f8
     __do_sys_swapoff+0x220/0x5d8
     [...]

The same goes for anything else that wants swapoff to stop, like an admin
hitting ^C in a panic, of course.

Prior to commit b56a2d8af9 ("mm: rid swapoff of quadratic complexity")
try_to_unuse() was driven by find_next_to_unuse() which checks for a
signal before every entry, so let's restore that behaviour.

Just as an example of the improvements, here's how long freezing takes
in the same test while swapoff is happening on my computer:

                      before                  after
    400MiB anon       8.925s                  0.028s
    400MiB shmem      1.639s                  0.003s
    2GiB anon         failed after 20.003s    0.011s

Link: https://lore.kernel.org/at9kJwdGkHPsWwgG@chrisdown.name
Fixes: b56a2d8af9 ("mm: rid swapoff of quadratic complexity")
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Vineeth Pillai (Google) <vineeth@bitbyteword.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Kairui Song <kasong@tencent.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Chris Li <chrisl@kernel.org>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Youngjun Park <youngjun.park@lge.com>
Cc: Ying Huang <huang.ying.caritas@gmail.com>
Cc: Kelley Nielsen <kelleynnn@gmail.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:44 -08:00
SJ Park
c4ff3ea306 mm/damon/core: move static variable rotation to damon_ctx
damon_split_some_reigons() uses a static variable, rotation, to remember
how many times it was called.  It is again used to determine fair
selection of regions to split.  Since it is a static variable, it can be
indeterministic and therefore less fair.

The user impact is not critical.  No crash, no leak.  DAMON's
best-effort and indeterministic monitoring accuracy could be slightly
more indeterministic when multiple kdamonds are used in parallel.

Fix the problem by moving the static variable into the damon_ctx struct.

Link: https://lore.kernel.org/20261025164808.152048-4-sj@kernel.org
Fixes: 1a582e6e01 ("mm/damon/core: split a fraction of regions when nr_regions exceeds max/2")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Closes: https://sashiko.dev/#/bug/linux-eebfcdde-2881-48ef-8df1-e2019d2a47f2
Cc: Jiayuan Chen <jiayuan.chen@shopee.com>
Cc: <stable@vger.kernel.org> # 7.3.x
2026-11-02 18:14:44 -08:00
SJ Park
26ae50a090 mm/damon/core: move static variable last_nr_regions to damon_ctx
kdamond_split_regions() uses a static variable last_nr_regions, to infer
if the region boundaries are too stable.  If it looks too stable, it
does a more aggressive region split because it might be a fake stability
coming from non-aggressive split.  Because the variable is static, the
inference can be racy and wrong when multiple kdamonds are running in
parallel.

The user impact is not critical.  No crash, no leak.  DAMON's
best-effort monitoring accuracy can be degraded when multiple kdamonds
are used in parallel and the workload has certain access patterns. Still
it is a bug that is better to fix.

Move the variable into the damon_ctx struct to fix the problem.

Link: https://lore.kernel.org/20261025164808.152048-3-sj@kernel.org
Fixes: 75c1c2b53c ("mm/damon/dbgfs: support multiple contexts")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Closes: https://sashiko.dev/#/bug/linux-eebfcdde-2881-48ef-8df1-e2019d2a47f2
Cc: Fernand Sieber <sieberf@amazon.com>
Cc: SeongJae Park <sjpark@amazon.de>
Cc: <stable@vger.kernel.org> # 5.15.x
2026-11-02 18:14:44 -08:00
SJ Park
a76adcace3 mm/damon/sysfs-schemes: hold damon_sysfs_lock in target_metric_store()
Patch series "mm/damon: fix three race bugs in sysfs and core", v1.

There are three race condition bugs in DAMON sysfs interface and the
core layer.  User impacts are not critical but better to fix sooner than
later.

Patch 1 fixes a toctou bug in DAMON sysfs interface that can mess up
DAMOS auto-tuning.  Patches 2 and 3 move static variables that can be
wrongly shared with multiple kdamonds and therefore make DAMON
monitoring results be a little more indeterministic.


This patch (of 3):

damon_sysfs_add_quota_score() reads damos_sysfs_quota_goal->metric
twice, once to set damos_quota_goal->metric to the value, and once again
to set the metric-dependent damos_quota_goal unions based on the value.

target_metrics_score() can update damos_sysfs_quota_goal->metric between
the two reads.  This time-of-check to time-of-use (toctou) race can make
the union fields incorrectly set.  The incorrect damos_quota_goal will
be passed to the core layer and make DAMOS incorrectly behave.

Users could reproduce the race by writing a new value to the
target_metric sysfs file while DAMON is starting, or online parameters
update is ongoing.  The issue will only rarely happen in the real use
cases.  It requires sysfs write permission.  The race window is short.
Sane users wouldn't do such writes while DAMON enablement and/or online
parameters update is ongoing.

The user impact is not very critical.  The race is not easy to
unintentionally trigger.  No leak or crash happens.  Nonetheless, DAMOS
could be unexpectedly more or less aggressive and does not achieve the
auto-tune goal.  Because of the nature of races, investigating will be
difficult.  Users can control the impact from unexpected aggressiveness
using additional quotas and resolve the issue in runtime by
re-installing the quota goal, though.

Avoid the race by protecting damos_sysfs_quota_goal->metric write in
target_metric_store() with damon_sysfs_lock.  Because
damon_sysfs_add_quota_score() is called while holding the same lock, the
race is removed.

The issue was discovered as a part of a bug report [1] from Sashiko,
which is partially outdated.  In more detail, the Sashiko report [1] was
mainly for an outdated bug [2].  But it was also mentioning the issue of
this patch as a similar class bug.

Link: https://lore.kernel.org/20261025164808.152048-1-sj@kernel.org
Link: https://lore.kernel.org/20261025164808.152048-2-sj@kernel.org
Link: https://sashiko.dev/#/bug/linux-7f814c9a-986f-4103-a55a-ef9537dcf62b [1]
Link: https://lore.kernel.org/20261021005234.94107-1-sj@kernel.org [2]
Fixes: 85fcf0ffc4 ("mm/damon/sysfs-schemes: connect damos_quota_goal nid with core layer")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: <stable@vger.kernel.org> # 6.16.x
2026-11-02 18:14:43 -08:00
Hengyu Liang
bfc1d9724c fs/proc/task_mmu: return -ENOTTY for unknown pagemap ioctls
Commit 52526ca7fd ("fs/proc/task_mmu: implement IOCTL to get and
optionally clear info about PTEs") made do_pagemap_cmd() the ioctl
handler of /proc/<pid>/pagemap.

However, do_pagemap_cmd() returns -EINVAL for every command other than
PAGEMAP_SCAN. Before that commit, pagemap had no ioctl handler, and
the VFS returned -ENOTTY for these commands. As of now, they fail with
EINVAL, so tcgetattr() and isatty() on pagemap report EINVAL instead
of ENOTTY.

The issue can be reproduced with a simple C program:

    #include <fcntl.h>
    #include <stdio.h>
    #include <termios.h>

    int main(void)
    {
            struct termios t;
            int fd = open("/proc/self/pagemap", O_RDONLY);

            if (tcgetattr(fd, &t) < 0)
                    perror("tcgetattr");
            return 0;
    }

Before that commit, the result is:

    tcgetattr: Inappropriate ioctl for device

After that commit, the result is:

    tcgetattr: Invalid argument

This patch will return -ENOIOCTLCMD for unknown commands, as
procfs_procmap_ioctl() in the same file does, so that the VFS turns it
into -ENOTTY.

Link: https://lore.kernel.org/20261023181300.3366487-1-hengyul@cs.unc.edu
Fixes: 52526ca7fd ("fs/proc/task_mmu: implement IOCTL to get and optionally clear info about PTEs")
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Muhammad Usama Anjum <usama.anjum@arm.com>
Cc: Andrei Vagin <avagin@gmail.com>
Cc: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:43 -08:00
Samarth Narang
2efc6332f1 mm/ksm: keep soft-dirty when merging a page
replace_page() maps the KSM page with a PTE built from scratch, so the
soft-dirty bit of the PTE it replaces is lost.  A page written since
"clear_refs 4" then no longer shows as soft-dirty once it is merged, and a
soft-dirty based dumper treats it as unchanged.

Copy the soft-dirty bit from the original PTE to the new PTE.

Link: https://lore.kernel.org/20261021182157.1873726-1-samarth.colleges@gmail.com
Fixes: 0f8975ec4d ("mm: soft-dirty bits for user memory changes tracking")
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Assisted-by: LLM
Cc: Xu Xin <xu.xin@linux.dev>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Peter Xu <peterx@redhat.com>
Cc: Kiryl Shutsemau <kas@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:43 -08:00
Lorenzo Stoakes (ARM)
c386d799f4 mm/vma: avoid losing atomic VMA flags when setting sticky VMA flags
vma_merge_existing_range() merges an existing VMA (middle) when its
attributes have changed to match those of one or both adjacent VMAs.

Sticky flags are propagated if they are set in any of the merged VMAs. They
are initialised from vmg->vma_flags, which is assumed to contain middle's
sticky flags when the function is invoked.

However, the VMA write lock is not held for middle when they are first
populated, so concurrent updates to atomic VMA flags may occur, which will
be lost upon merge.

This can result in fork failing to propagate guard region markers and (if
file-backed) THP collapse discarding them.

Resolve this by propagating the sticky flags after middle is locked.

Make life easier by factoring this into propagate_sticky_flags(), which
treats vmg->vma_flags as its base (in case any sticky flags are set there),
updating it as sticky flags are accumulated from merged VMAs.

Also update vma_expand() to use propagate_sticky_flags() so all merge paths
utilise it.

propagate_sticky_flags() also asserts that the VMA write lock is held for
the VMA whose sticky flags are being read, with a comment explaining why.

Another means by which atomic VMA flags can fail to be observed is when the
merge is finalised in commit_merge().

rmap locks are dropped in vma_complete() before the sticky flags are
written, meaning an rmap walker can observe the VMA without sticky flags
set, which can also result in retract_page_tables() discarding guard
markers.

Resolve this by assigning the sticky flags before dropping rmap locks,
factored into commit_sticky_flags() with a write assert on the VMA being
written to.

Also remove the vma_set_flags_mask() invocation at the end of
vma_merge_existing_range() as this was introduced by commit
64212ba02e ("mm: implement sticky VMA flags") to propagate sticky flags,
which is now redundant with the introduction of commit_sticky_flags().

The vma_set_flags_mask() invocation at the end of vma_expand() setting
sticky flags only is also removed for the same reason.

Also update vma_merge_existing_range()'s comment to reflect the fact that
vmg->vma_flags gets updated.

Finally, update the userland VMA tests to reflect a previously missed
const-ification in vma_assert_write_locked() which would otherwise cause a
warning when building them.

Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-4-8ff4fae1fc85@kernel.org
Fixes: 2ab7f1bbaf ("mm/madvise: allow guard page install/remove under VMA lock")
Fixes: 49e14dabed ("mm: set the VM_MAYBE_GUARD flag on guard region install")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jann Horn <jannh@google.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: SJ Park <sj@kernel.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Colin Cross <ccross@google.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:42 -08:00
David Hildenbrand (Arm)
652f15be3c mm/madvise: preserve VMA_SOFTDIRTY_BIT when changing anonymous names
When changing the anonymous VMA name, madvise_update_vma() calls
vma_modify_name() to possibly merge with adjacent VMAs. We don't call
vma_modify_flags() and consequently don't obtain the new VMA flags.

Later in the function we update the VMA flags to the stale new_vma_flags
we obtained before. This can result in us losing the VMA_SOFTDIRTY_BIT
flag set on a VMA we just merged with.

There is no need to update the VMA flags at all, so just exit early. This
skips calling khugepaged_enter_vma(), but since the flags didn't change
this is fine.

[ljs@kernel.org: minor edit of commit message, rebased]
Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-3-8ff4fae1fc85@kernel.org
Fixes: 9a10064f56 ("mm: add a field to store names for private anonymous memory")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jann Horn <jannh@google.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: SJ Park <sj@kernel.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Colin Cross <ccross@google.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:42 -08:00
David Hildenbrand (Arm)
769417e410 mm/vma: write lock source VMA before duplicating it in __split_vma()
__split_vma() duplicates the source VMA before taking its VMA write lock,
and until the VMA is write-locked, a concurrent thread might set
VMA_MAYBE_GUARD_BIT, resulting in the duplication missing the flag.

If this happens, then fork may fail to duplicate guard markers and, if a
file-backed mapping, THP collapse may also discard the markers.

Resolve this by taking the VMA write lock before vm_area_dup() and, since
all callers of vm_area_dup() now hold the VMA write lock, assert that this
is the case there, and add a comment to explain why it's needed.

[ljs@kernel.org: add VMA write assert in vm_area_dup(), commit message touchup]
Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-2-8ff4fae1fc85@kernel.org
Fixes: 2ab7f1bbaf ("mm/madvise: allow guard page install/remove under VMA lock")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>
Reviewed-by: Pedro Falcato <pfalcato@suse.de> 
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jann Horn <jannh@google.com>
Cc: SJ Park <sj@kernel.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Colin Cross <ccross@google.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:42 -08:00
Lorenzo Stoakes (ARM)
13fc99f463 mm: do not unintentionally overwrite atomic VMA flags
Patch series "mm: avoid losing atomic VMA flags", v1.

Since commit 2ab7f1bbaf ("mm/madvise: allow guard page install/remove
under VMA lock"), VMA_MAYBE_GUARD_BIT can be set atomically under the VMA
read lock.

However, a number of places wrongly assume the flags are stable under the
read lock, which can cause stale atomic VMA flags to overwrite existing
valid ones.

Additionally, one case in which VMA_SOFTDIRTY_BIT was overwritten is also
addressed.

This series addresses each of these, while keeping the logic inline with
existing conventions.

Each patch in this series is a hotfix.


This patch (of 4):

madvise, mlock and mprotect take a copy of a VMA's flags holding only the
VMA read lock, later writing it back under the write lock (in
madvise_update_vma(), mlock_fixup(), mlock_vma_pages_range() and
mprotect_fixup()).

This was done on the assumption that VMA flags cannot change with a read
lock held.

However this changed in commit 2ab7f1bbaf ("mm/madvise: allow guard page
install/remove under VMA lock"), which allowed VM_ATOMIC_SET_ALLOWED
flags (currently only VMA_MAYBE_GUARD_BIT) to be written concurrently under
a VMA read lock.

The actual write itself is safe as this is done under the VMA write lock
at which point no further concurrent writes can occur, however at this
point the stale flags mean that these callers can unintentionally overwrite
atomic flags incorrectly.

The consequences of this are significant - a missing VMA_MAYBE_GUARD_BIT
could result in page tables not being copied on fork (the vma_needs_copy()
check can return false) or being overwritten on file-backed THP
collapse (the file_backed_vma_is_retractable() can return true).

Resolve the issue by always taking care to retain existing atomic flags
when overwriting VMA flags, replacing the inconsistently named
vma_flags_reset_once() with vma_overwrite_flags() to do so, and always
invoking it when flags are overwritten like this.

Reads are a problem too - madvise, mlock and mprotect all compare VMA flags
without a VMA write lock held via vma_flags_same_pair().

This has more serious impact, as concurrent changes to atomic VMA flags can
cause two sets of VMA flags to be wrongly considered different.

For mprotect and madvise this causes a useless split, but mlock is impacted
more seriously as it can result in mm->locked_vm underflow.

Fix this by updating vma_flags_same_pair() to disregard
VM_ATOMIC_SET_ALLOWED VMAs - VMA equality is the same as VMA mergeability,
and atomic VMA flags are disregarded when comparing VMA flags for merge -
so this is justified semantically.

Additionally, remove the redundant vma_flags_same_mask() and the unused
vma_flags_same() as part of the change, and replace VM_ATOMIC_SET_ALLOWED
with VMA_ATOMIC_SET_ALLOWED, using the new VMA flag API.

Finally, update userland VMA tests to reflect the changes.

Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-0-8ff4fae1fc85@kernel.org
Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-1-8ff4fae1fc85@kernel.org
Fixes: 2ab7f1bbaf ("mm/madvise: allow guard page install/remove under VMA lock")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jann Horn <jannh@google.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: SJ Park <sj@kernel.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Colin Cross <ccross@google.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:42 -08:00
Lorenzo Stoakes (ARM)
8146c64782 mm/vma: fix expansion of VMA_MIXEDMAP_BIT VMAs
Commit ca3d76b0aa ("mm: add merging after mremap resize") combined
merging with expansion of mremap()'d VMAs, however it also unintentionally
disallowed the expansion of unmergeable VMAs.

Previously it was possible to expand a mixed mapping which mremap() had
already ensured was a legal expansion.

This is clearly seen in the mremap() logic, as it checks
vma_is_fixed_mapping() to determine legality of an expansion rather than
vma_can_merge().

Additionally, copy_vma() allows for a failed merge to result in a new VMA
being instantiated if MREMAP_MAYMOVE is specified.

However, this is not attempted, as a failure in vma_merge_extend() is
assumed to be an -ENOMEM failure.

Since vma_merge_extend() is used exclusively by mremap() to perform a merge
and/or expansion, resolve the issue by invoking vma_expand() for
unmergeable VMAs there.

Explicitly assert that the VMA is both non-fixed and a mixed mapping.
This provides double insurance against broken changes in future.

Note that khugepaged_enter_vma() (which vma_merge_new_range() runs) is
redundant in this case, as a mixed mapping is not subject to khugepaged.

Also update the VMA userland tests to add a required predicate.

Link: https://lore.kernel.org/20261023-vma-expansion-fix-v1-1-6142baf1f46b@kernel.org
Fixes: ca3d76b0aa ("mm: add merging after mremap resize")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Luiz Capitulino <luizcap@redhat.com>
Closes: https://lore.kernel.org/all/20261023023106.515365-1-luizcap@redhat.com/
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Jann Horn <jannh@google.com>
Cc: Jakub Matěna <matenajakub@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:41 -08:00
Zenghui Yu (Huawei)
b6732c6d43 mm/page_alloc: mark pages freed by __free_pages_core() as not tagged
Onlining hotplugged memory (e.g., a dev_dax device bound to kmem) with
CONFIG_MEM_ALLOC_PROFILING_DEBUG triggers:

  alloc_tag was not set
  WARNING: ./include/linux/alloc_tag.h:166 at __pgalloc_tag_sub+0x1fc/0x254
  Call trace:
   __pgalloc_tag_sub+0x1fc/0x254 (P)
   __free_pages_ok+0x14c/0x6ac
   __free_pages_core+0xa8/0x188
   generic_online_page+0x14/0x20
   online_pages+0x220/0x3b0
   memory_subsys_online+0xfc/0x198
   device_online+0x58/0xe0
   state_store+0xf0/0xf8

Pages entering the buddy through __free_pages_core() have never been
allocated, so their allocation tag references are NULL.  The free path,
__free_pages_prepare() -> pgalloc_tag_sub(), expects a valid tag or a
CODETAG_EMPTY mark and warns otherwise.  Paths feeding never-allocated
pages into the buddy are therefore expected to mark them with
clear_page_tag_ref() first, like init_cma_reserved_pageblock() and
free_reserved_pages() do; of __free_pages_core()'s callers only
memblock_free_pages() clears the tag ref itself, and the hotplug
onlining path was missed.

Since all __free_pages_core() callers free never-allocated pages, mark the
head page as not tagged in __free_pages_core() itself instead of relying on
each caller, and drop the now-redundant clearing from
memblock_free_pages().

Link: https://lore.kernel.org/20261022122752.74774-1-zenghui.yu@linux.dev
Fixes: dcfe378c81 ("lib: introduce support for page allocation tagging")
Signed-off-by: Zenghui Yu (Huawei) <zenghui.yu@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Zi Yan <ziy@nvidia.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:41 -08:00
Li Zhe
92daa8652f mm/hugetlb: fix mremap deadlock when PMD sharing is possible
move_hugetlb_page_tables() holds the mapping's i_mmap_rwsem for
write while moving hugetlb PTEs. This prevents races with truncation
and protects huge_pmd_unshare(), but the move loop must not call
helpers that can acquire the same rwsem for read.

huge_pte_alloc() can do that when the destination can use PMD
sharing: it may call huge_pmd_share(), which takes i_mmap_rwsem for
read while searching for a shareable PMD table. Calling it while the
move path already holds i_mmap_rwsem for write can deadlock.

Avoid that path for PMD-sized hugetlb mappings that can use PMD
sharing. Instead of allocating or sharing the destination page table
while moving, zap the source range and let the destination fault path
populate or share the PMD lazily.

Reuse the hugetlb unmap logic for the source-side zap by splitting
the core loop out of __unmap_hugepage_range(). The wrapper keeps the
existing tlb_start_vma(), tlb_end_vma() and huge_pmd_unshare_flush()
behavior, while move_hugetlb_page_tables() can reuse the unmap loop
with its existing mmu_gather.

Link: https://lore.kernel.org/20261022034543.51226-4-lizhe.67@bytedance.com
Fixes: 550a7d60bd ("mm, hugepages: add mremap() support for hugepage backed vma")
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
Co-developed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:41 -08:00
David Hildenbrand (Arm)
809cbe72ac mm/hugetlb: disable PMD sharing for UFFD missing mode
For UFFDIO_POISON to install a poison marker in a hugetlb mapping, it is
sufficient to have the VMA registered for missing mode.

However, UFFD missing mode does currently not block PMD table sharing, so
installing the marker will be visible to everyone using the shared PMD
table, which is wrong as UFFDIO_POISON must stay local to the process.

To fix it, make uffd_disable_huge_pmd_share() cover VM_UFFD_MISSING as
well. With missing mode covered, hugetlb PMD sharing is disabled for all
userfaultfd registered VMAs, so the helper can simply return whether the
VMA has a userfaultfd context instead of testing individual UFFD mode
flags. Add a debug check on the marker installation path.

The existing registration path will then unshare PMD tables, and
subsequent faults will not share them while the mapping remains
registered.

The alternative would be to unshare PMD tables selectively when
installing poison markers, which results in way more complexity. Or
alternatively, simply failing the marker installation, which might break
some use cases.

This also disables PMD sharing for userfaultfd registrations that never
use UFFDIO_POISON.

Link: https://lore.kernel.org/20261022034543.51226-3-lizhe.67@bytedance.com
Fixes: 8a13897fb0 ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Li Zhe <lizhe.67@bytedance.com>
Suggested-by: Mike Rapoport <rppt@kernel.org>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Jose A. Perez de Azpillaga <azpijr@gmail.com>
2026-11-02 18:14:41 -08:00
Li Zhe
dfb190302d mm/hugetlb: fix mremap move length truncation
Patch series "mm/hugetlb: fix mremap bugs", v3.

This series fixes a few hugetlb mremap bugs.

Patch 1 fixes the return type of move_hugetlb_page_tables(), so large
hugetlb moves cannot be truncated when reported back to the generic
mremap code.

Patch 2 disables hugetlb PMD sharing for UFFD missing mode, so
UFFDIO_POISON markers cannot become visible through shared PMD page
tables.

Patch 3 fixes the recursive i_mmap_rwsem deadlock in the hugetlb mremap
path by avoiding the destination PMD sharing allocation path while the
mapping lock is already held for write.


This patch (of 3):

move_hugetlb_page_tables() returns the number of bytes moved, but
its return type is int while the generic move_page_tables() path uses
unsigned long lengths.

A hugetlb mremap() move length above INT_MAX can therefore be
misreported to copy_vma_and_data(). The out-of-range conversion to int
is implementation-defined; on common 64-bit builds, for example, a
4 GiB move can be reported as zero, making the caller treat the move as
a failure and use the wrong length for rollback.

Return unsigned long from move_hugetlb_page_tables(), matching
move_page_tables() and preserving the full byte count.

Link: https://lore.kernel.org/20261022034543.51226-1-lizhe.67@bytedance.com
Link: https://lore.kernel.org/20261022034543.51226-2-lizhe.67@bytedance.com
Fixes: 550a7d60bd ("mm, hugepages: add mremap() support for hugepage backed vma")
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:40 -08:00
Gregory Price (Meta)
83367658a0 mm/page_alloc: let the highest memory node recover from hopeless state
free_frozen_page_commit() clears a hopeless node's kswapd failures once
its zone recovers above the high watermark, but only if another memory
node exists for allocations to fall back to.

The test `next_memory_node(nid) < MAX_NUMNODES` finds only memory nodes
with a higher id.  The highest-numbered memory node therefore never
recovers on this path, and its kswapd stays disabled until reclaim on that
node makes progress and balances it, or demotion is re-enabled.

In many cases, direct reclaim many never fully run against a lower node
(CXL/kmem), and that means its kswapd can end up full disabled in rare
situations.

To reproduce, fill the highest memory node with bound, non-THP anonymous
memory and no swap until kswapd gives up, then free it: /proc/zoneinfo
keeps showing node_unreclaimable 1 for that node.  A lower node recovers.

Count the memory nodes instead.  Adding first_memory_node != nid to the
existing test would also work, but a count says directly what the check
means: some other memory node exists.

Link: https://lore.kernel.org/20261019184850.3427905-1-gourry@gourry.net
Fixes: e7a5f249e6 ("mm: re-enable kswapd when memory pressure subsides or demotion is toggled")
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Chanwon Park <flyinrm@gmail.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:40 -08:00
Danish Khateeb
332c1bd174 selftests/mm: merge: keep the far mremap() targets in the carveout
The merge tests map their areas at fixed addresses within a 30-page
PROT_NONE carveout. Several mremap() tests move an area 1000 or 2000
pages away to separate it from the others, but those targets are outside
the carveout, and MREMAP_FIXED unmaps whatever is mapped there.

Under virtme-ng, the shared libraries are packed right above the
carveout and the dynamic linker starts about 4 MiB above it. The moves
then replace part of its text with an anonymous mapping, and the test
crashes in its next lazily bound call:

  merge[6980]: segfault at 7f7ebb3c1e60 ip 00007f7ebb3c1e60 sp 00007ffd35fbaec8 error 14

Two to four of the mremap() tests then fail with "Test terminated
unexpectedly by signal 11", depending on the exact layout. On a host
where libc is mapped at a 2 MiB aligned address, the targets happen to
land above the dynamic linker and the tests pass.

Since the areas are all within the first 30 pages, moving one by 30
pages is enough to keep it apart from the others. Add FAR_PAGES for
that distance, move areas by FAR_PAGES or 2 * FAR_PAGES pages, and make
the carveout 3 * FAR_PAGES pages so that it covers every target.

Link: https://lore.kernel.org/20261022121837.28723-1-danishkhateeb03@gmail.com
Fixes: 4e25f85b9f ("tools/testing/selftests: add mremap() unfaulted/faulted test cases")
Signed-off-by: Danish Khateeb <danishkhateeb03@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: David Hildenbrand <david@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Shuah Khan <shuah@kernel.org>
2026-11-02 18:14:40 -08:00
Hungyu Lin
9597c2056e mm/page-writeback: avoid 32-bit overflow in dirty threshold shares
The ratios used by __wb_calc_thresh() are scaled to parts per million, but
the threshold and ratio operands are unsigned long.  On 32-bit kernels,
their multiplication can wrap before the result is assigned to u64.

For example, with a threshold of 25600 pages and the default maximum ratio
of 1000000, wb_max_thresh becomes 4125 pages instead of 25600.  The shared
threshold and minimum share calculations can overflow in the same way,
producing incorrect per-writeback dirty limits.

Use a u64 threshold for the three ratio multiplications and div_u64() to
retain the existing division order and rounding.

Link: https://lore.kernel.org/20261021060654.27855-1-dennylin0707@gmail.com
Fixes: ae82291e9c ("mm: use part per 1000000 for bdi ratios")
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Stefan Roesch <shr@devkernel.io>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:39 -08:00
Baolin Wang
243cf1f67b mm: memory: fix truncation removing mapped folios
Ayush reported an issue that shmem/tmpfs folios are still mapped when
truncating them on production:
"
BUG: Bad page cache in process ...  pfn:...
page dumped because: still mapped when deleted
"

I reproduced the issue with Ayush's reproducer [1] with the latest
mm-unstable branch, and I got the following crash info.  From the dump
message, we can see that truncate_inode_folio() is really trying to remove
mapped folios, which is incorrect.

"
[  189.171977] page: refcount:3 mapcount:1 mapping:00000000fe168ee1
index:0x3880 pfn:0x191647
[  189.171995] memcg:ffff0000cc073d40
[  189.171997] aops:shmem_aops ino:3c01 dentry name(?):"memfd:runsc-memory"
[  189.172006] flags: 0x17fffef0002022d(locked|referenced|uptodate|lru|
workingset|swapbacked|node=0|zone=2|lastcpupid=0x3ffff)
.......
[  189.172017] page dumped because: VM_BUG_ON_FOLIO(folio_mapped(folio))
[  189.172026] ------------[ cut here ]------------
[  189.172027] kernel BUG at mm/filemap.c:155!
[  189.172057] Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP
.......
[  189.177721] CPU: 3 UID: 0 PID: 5521 Comm: repro Kdump: loaded Tainted:
7.3.0-rc4+ #277 PREEMPT(lazy)
.......
[  189.183986] Call trace:
[  189.184124]  filemap_unaccount_folio+0xf0/0x1e8 (P)
[  189.184391]  __filemap_remove_folio+0x34/0x160
[  189.184633]  filemap_remove_folio+0x4c/0xb0
[  189.184859]  truncate_inode_folio+0x34/0x58
[  189.185087]  shmem_undo_range+0x220/0x658
[  189.185308]  shmem_fallocate+0x2f0/0x470
[  189.185527]  vfs_fallocate+0x128/0x328
......
[  189.187078]  el0t_64_sync+0x184/0x188
"

After analysis, I believe the race exists between truncation and
MADV_DONTNEED, and shmem's ->map_pages() merely makes the issue easier to
reproduce.  Since MADV_DONTNEED synchronously releases the pagetable page
before calling tlb_flush_rmaps(), this could cause another thread's
truncation to skip zap_pte_range() (due to pmd is none) but still observe
the folio's mapcount as non-zero.  A possible race scenario is as follows:

CPU 0                           CPU 1
shmem_fallocate                 madvise_dontneed_single_vma
  unmap_mapping_range            .......
  ......
  (filemap_map_pages() remap folios)
				  zap_pte_range
  truncate_inode_folio		    zap_empty_pte_table(pmd clear)
    unmap_mapping_folio
    ......
      zap_pmd_range (saw pmd none, skip)

  filemap_remove_folio
    BUG_ON(folio_mapped)
                                    tlb_flush_rmaps(remove rmaps)

To fix this issue, we should move the pmd clear operation (via
zap_empty_pte_table()) to after tlb_flush_rmaps() and use
sync_with_folio_pmd_zap() to sync with concurrent zapping, so that when we
find a pmd_none() while unmapping a folio without holding the PTL, the
folio's mappings are guaranteed to have been removed via
tlb_flush_rmaps().

Meanwhile move the second pmd_none() check to where it belongs: if
splitting zapped the PMD.

Link: https://lore.kernel.org/14ebbd556cc4941f0ebc43da59fa6a2fdca25dc8.1793148609.git.baolin.wang@linux.alibaba.com
Link: https://lore.kernel.org/all/20260925065013.3682431-1-ayushr@modal.com/ [1]
Fixes: 6375e95f38 ("mm: pgtable: reclaim empty PTE page in madvise(MADV_DONTNEED)")
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Ayush Ranjan <ayushr@modal.com>
Closes: https://lore.kernel.org/all/20260924061708.1645968-1-ayushr@modal.com/
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Jan Kara <jack@suse.cz>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:39 -08:00
David Hildenbrand (Arm)
f681d4580d mm: fix address wraparound when scanning large folio PTEs
numa_rebuild_large_mapping() and do_swap_page() can be tricked into
generating an address wraparound, crashing the kernel. All that's required
is to map a tail page of a large folio close enough to the start/end of
the address space to e.g., make

	unsigned long addr_start = addr - (nr << PAGE_SHIFT);

to wrap around.

Let's fix it by providing a better helper, folio_scan_range(), that
takes care of staying within VMA and page table boundaries while
handling possible wraparounds.

There are some nasty details, like not being able to use pmd_addr_end()
in this context. Add some helpful comments for these cases.

Link: https://lore.kernel.org/20261014-folio_pte_scan_range-v2-1-00cf9bbaa364@kernel.org
Fixes: d2136d749d ("mm: support multi-size THP numa balancing")
Fixes: 508758960b ("mm: swap: entirely map large folios found in swapcache")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Kyle Zeng <kylebot@openai.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Barry Song <baohua@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Ying Huang <huang.ying.caritas@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Chuanhua Han <hanchuanhua@oppo.com>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:39 -08:00
Kyle Zeng
854e5ff8b3 mm/khugepaged: flush deferred unmaps before dropping a failed folio
collapse_file() can fail its reference-count or dirty-folio check after
unmapping with TTU_BATCH_FLUSH.  Both paths put back the isolated folio,
then unlock it and drop the lookup reference before reaching the common
try_to_unmap_flush().

The page-cache reference does not keep the folio stable once the lock is
released.  Another collapse can replace and free it.  With its PTEs
already gone, that collapse cannot flush the first task's per-task TLB
batch, and retract_page_tables() skips short or unaligned VMAs.  A CPU can
therefore retain a user translation to the freed folio.  This has been
reproduced with unprivileged MADV_COLLAPSE on a memfd.

Flush at out_unlock while the lookup reference and folio lock are still
held.  The common flush continues to cover the accumulated pagelist on
both success and rollback, preserving batching on successful collapses.

Link: https://lore.kernel.org/20261007041001.43181-1-kylebot@openai.com
Fixes: 6d9df8a588 ("mm/thp: collapse_file() do try_to_unmap(TTU_BATCH_FLUSH)")
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Hugh Dickins <hughd@google.com>
Assisted-by: LLM
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Kiryl Shutsemau <kas@kernel.org>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: <stable@vger.kernel.org>
2026-11-02 18:14:39 -08:00
Linus Torvalds
a4da531b17 bpf-fixes
-----BEGIN PGP SIGNATURE-----
 
 iQJRBAABCgA7FiEE+soXsSLHKoYyzcli6rmadz2vbToFAmrpFg8dHGFsZXhlaS5z
 dGFyb3ZvaXRvdkBnbWFpbC5jb20ACgkQ6rmadz2vbTomMg/7BZOpai5HDHlhvJSS
 RxOUoiO/ZTZXNdskY7lno/Qc4EinXEOpai+WB8foWWm4l4LTqCTIzBzfGdLpXX3T
 MlrSZ2+EPahcS1qkF4ks9VCigeMQkk6/9J0VZGjDLeIVJdxWY7b4n5yte92ZHgT7
 /OmXijjcEBvFdzH1YcKSh63L3ay9XSNPx96KfLqIzoq+AXqujLQMurJJaj3qZ9zS
 CTGqEglWbjBtGxeUvekxboV3FASg/W8oyeikovhZNWdSKSWrL1DgKeLMx2NYTbhE
 Ij4w7PVR6XTxI4bN66bvF3caYztQV3diW3ODpEnrXLJft/s/9m9M7E3TBs772BHK
 HwOsdyH47egwE124NTlP6ehtjrhOTZnSc+264YfDxTk6vBg4I5WTfpb8WeQbM5us
 aq1yslQaOdP6glVDQz3wYzgb4MtoQeDN0LlNqPqASxNUezinjq2D5anixCVWMo7m
 8gPwp4mVsk4rYgZpUrccKWlAnpKb9tCKmrl2FEfBWagXJ6mEbnHB31nlNPhbDjCI
 jZOZXdM32/Z2RMvxBJp2+hrE/ebVljXjTQTsv8srdamf+jmnVq/ToMkCOgmpJvlt
 ORleXtGtbSuZKGoSk0F99TtjeaQGA/S8rbMNgqQSgNNWuoWz6y3ED0M9UQJOzryX
 XRQMqBnCsF91+R5D2DjqOVT67Gg=
 =40m5
 -----END PGP SIGNATURE-----

Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull bpf fixes from Alexei Starovoitov:
 "Fix various bugs in bpf core and bpf-lwt. Looks like the speed of us
  fixing bugs is higher than the number of new bugs found. Not out of
  the woods yet. sockmap fixes will come later.

   - Various fixes (Alexei Starovoitov):
       - Use one may_goto time slice per prog invocation instead of one
         per stack frame to fix a soft lockup in loops that nest across
         calls
       - Fix use-after-free in btf__add_type() in libbpf
       - Invalidate a dynptr slice when its stack buffer is written or
         when the frame of the buffer returns
       - Fix the tracking of pointers to the stack in SCEV
       - Keep the valid bytes of a packet pointer in SCEV
       - Fix bpf_throw() in a prog with a private stack in x86 JIT
       - Compare the arguments of an extension prog with those of its
         target
       - Don't accept memory of the prog for struct arguments of
         KF_ACQUIRE kfuncs and for arguments of an empty struct type
       - Fix mmap() of an arena: refuse address 0 and a length above
         max_entries pages, etc.
       - Don't let bpf_skb_adjust_room() raise gso_size to GSO_BY_FRAGS
       - Fix lwt progs: reset skb->cb and don't leave a stale MAC header
         after a prog pushes an IP header, require BPF_LWT_REROUTE when
         an lwt_in prog changes the protocol, don't call into IPv6 when
         it is disabled, don't look for the SRH again in the End.BPF
         helpers, and set a dst for test runs of lwt_in progs

   - Fix bpf_dynptr_copy() for overlapping ranges in one packet
     (Ayushman Rout)

   - Various fixes (Chris Mason):
       - Reject memory of the prog for kfunc projection type arguments
       - Require prog fd or capability for cgroup prog detach
       - Keep the skb network offset signed in cgroup skb progs
       - Reject non-IPv6 packets in BPF_LWT_ENCAP_SEG6
       - Limit the SRH length and move the MAC header in
         bpf_lwt_seg6_adjust_srh()
       - Move the transport header together with the headers that
         bpf_skb_adjust_room() and bpf_lwt_seg6_adjust_srh() move, and
         use the inner transport header after a decap
       - Check the offset in bpf_skb_generic_{push,pop}()

   - Mark jmp mode of ftrace direct trampolines on x86 by clearing bit
     63 of the address instead of setting bit 0, since an ftrace
     callback can start at an odd address (Daniel Borkmann)

   - Fix psock update-side data races on sk->sk_prot and progs in
     sockmap (Jakub Sitnicki)

   - Fix skb_pull() BUG in __bpf_redirect_neigh(): make sure that the
     MAC and IP headers are there and are linear (Jamal Hadi Salim)

   - Fix jited line info that is off by the CFI preamble on x86-64,
     arm64 and riscv64 (Jose Fernandez)

   - Clamp the trace length in __bpf_get_stack() to fix a write after
     the end of the buffer (Josef Bacik)

   - Drop percpu_counter from the htab element count, since its lock can
     deadlock with NMI and tracing progs that update the same map
     (Puranjay Mohan)

   - Propagate scalar precision through stack arguments (Xu Yunxiang)

   - Fix callback recursion selftest with llvm24 (Yonghong Song)

   - Free the skb when bpf_xmit() fails to expand the headroom (Yuqiang
     Sun)"

* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: (61 commits)
  libbpf: Fix use-after-free in btf__add_type
  selftests/bpf: Exercise stack argument precision on state reuse
  bpf: Propagate scalar precision through stack arguments
  selftests/bpf: Fix callback recursion test with noipa global func
  selftests/bpf: Test one may_goto time slice per prog invocation
  bpf: End bpf_loop() when the time of may_goto is up
  bpf: One may_goto time slice per prog invocation
  bpf: Pass a pointer to arch_bpf_timed_may_goto()
  s390/bpf: Support internal-only MOV instruction to resolve per-CPU addrs
  selftests/bpf: End the loop of parallel_test_bitmap after 50 ms
  selftests/bpf: Give the first loop of cond_break5 an end
  selftests/bpf: Don't cast a pointer to .bss in arena_htab_asm
  bpf: Emit timed may_goto for JITed progs only
  selftests/bpf: Test writes to the buffer of bpf_dynptr_slice_rdwr()
  bpf: Invalidate a dynptr slice when its stack buffer is written
  selftests/bpf: Test a callee that overwrites a spilled pointer of its caller
  bpf: Don't trust pointers spilled in slots that a callee can write
  selftests/bpf: Test the join of fp+0 with a value that is not a pointer to stack
  bpf: Fix the join of fp+0 with a value that is not a pointer to stack
  selftests/bpf: Run arena_mmap serially and test MAP_FIXED addresses
  ...
2026-11-02 16:16:26 -08:00
Linus Torvalds
508d578642 x86:
- Check validity of vmcb01 save area copied from SMRAM on RSM
 
 - Conditionally resched when retrying gPTE walk on A/D update failure
 
 - Conditionally resched when restarting REP string emulation
 
 - Process each host MSR entry at most once when unwinding failed VM-Entry
 
 - Cap number of parents of page table pages, to avoid quadratic teardown
 
 - Unconditionally reset MMU context when emulating INIT
 
 - Flush guest TLB when emulating a RESET to strictly honor the spec
 
 - Add array_index_nospec() to evmcs_field_offset()
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmrpFz4UHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroM8PQf8CUtTIZTsJMDj9fjyudqdGzacmvxp
 1ThdTxDFselGIrE+Kqm8b+LMOZJ3FK5GFOhnJtfUhuHk8nJyGau1uZi7hLaQwzmF
 ZXzcQdcErYcPRXw6aIH034Ys4+K+QgsJvu1l9Kg/VGJ+mElQWlZjEuzW/B5iGW6f
 r0gj06XqbN6ipj+5YezyClkUkfsclPDBKfF+tEW3m3wyCCnF1asmyrWzm71NuGBq
 CeKjiuX7sXWXAapbXZfhXD0MrQV1wZpEEVhvcnoOzwMTOaRL6IEwcluKYlVi5uC2
 Vv+5VbYUTQZaYiLFcJQh4OGL8lz/HuQgzFhFJ4XIABpFDb8uWRRqyE+KdA==
 =TjJZ
 -----END PGP SIGNATURE-----

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull KVM fixes from Paolo Bonzini:
 "x86:
   - Check validity of vmcb01 save area copied from SMRAM on RSM
   - Conditionally resched when retrying gPTE walk on A/D update failure
   - Conditionally resched when restarting REP string emulation
   - Process each host MSR entry at most once when unwinding failed VM-Entry
   - Cap number of parents of page table pages, to avoid quadratic teardown
   - Unconditionally reset MMU context when emulating INIT
   - Flush guest TLB when emulating a RESET to strictly honor the spec
   - Add array_index_nospec() to evmcs_field_offset()"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: VMX: Add array_index_nospec() to evmcs_field_offset()
  KVM: x86: Flush guest TLB when emulating a RESET to strictly honor the spec
  KVM: x86: Unconditionally reset MMU context when emulating INIT
  KVM: x86/mmu: Cap number of parent PTEs per SP at 1000 (the arbitrary rmap limit)
  KVM: nVMX: Process each host MSR entry at most once when unwinding failed VM-Entry
  KVM: x86: Conditionally resched when restarting REP string emulation
  KVM: x86/mmu: Conditionally resched when retrying gPTE walk on A/D update failure
  KVM: nSVM: Check validity of vmcs01 save area copied from SMRAM on RSM
2026-11-02 16:11:25 -08:00
Linus Torvalds
b2e7a7bbc1 Crypto library fixes for v7.4-rc2
- Disable the MIPS64 Octeon optimized SHA-1, SHA-256, and SHA-512 code
   on little-endian kernels, since it doesn't work correctly on them
 
 - Remove the PowerPC optimized Poly1305 code. It's already been marked
   as BROKEN for over a year due to not working in softirq context, but
   it turns out some of the Poly1305 math is incorrect too
 
 - A few robustness improvements for the ML-DSA code
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQSacvsUNc7UX4ntmEPzXCl4vpKOKwUCaujLJxQcZWJpZ2dlcnNA
 a2VybmVsLm9yZwAKCRDzXCl4vpKOKxd5AP9gCKliD6T4RAmnUtM0Jzys24ezmsl2
 NZuA7BDT3rvD9wEAjSyxFeMrWCxJmAx4yKzXVNJcZC9gRc2e/0OP39Mplwg=
 =tcgp
 -----END PGP SIGNATURE-----

Merge tag 'libcrypto-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux

Pull crypto library fixes from Eric Biggers:

 - Disable the MIPS64 Octeon optimized SHA-1, SHA-256, and SHA-512 code
   on little-endian kernels, since it doesn't work correctly on them

 - Remove the PowerPC optimized Poly1305 code. It's already been marked
   as BROKEN for over a year due to not working in softirq context, but
   it turns out some of the Poly1305 math is incorrect too

 - A few robustness improvements for the ML-DSA code

* tag 'libcrypto-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux:
  lib/crypto: mldsa: Add __must_check to mldsa_verify()
  lib/crypto: mldsa: Explicitly check that 'alg' is a valid value
  lib/crypto: mldsa: Check pk_len before doing pointer arithmetic
  lib/crypto: powerpc/poly1305: Remove BROKEN implementation
  lib/crypto: mips: Disable Octeon SHA code on little-endian kernels
2026-11-02 16:04:49 -08:00
Alexei Starovoitov
9abe2c42ec
libbpf: Fix use-after-free in btf__add_type
For every string btf_rewrite_str() does:

  off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off));

When the string belongs to the base, the pointer goes into the raw data
of the base. btf__add_str() looks the string up in the base first,
btf__find_str() calls btf_ensure_modifiable() on the base, and that
frees the raw data. Then strset__find_str() reads the freed string.

Make all the bases of dst modifiable before the pointer is taken.

This bug is triggered by the sharing of BTF bases between src
and dst, as introduced by the resolve_btfids changes to build
inline BTF.

Fixes: cf91a7db92 ("resolve_btfids: Build separate main and inline BTF objects")
Reported-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Alan Maguire <almagui@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <almagui@kernel.org>
Link: https://patch.msgid.link/20261102185839.1190122-1-almagui@kernel.org
2026-11-02 22:47:44 +00:00
Alexei Starovoitov
38bce81d47
Merge branch 'bpf-fix-stack-argument-precision-propagation'
Xu Yunxiang says:

====================
bpf: Fix stack argument precision propagation

Outgoing stack arguments retain scalar state separately from registers
and ordinary spills. Their precision dependencies must reach ancestor
states when verification reuses a state or falls back to marking all
scalars precise. Otherwise, an out-of-bounds map access can reuse a state
validated for an in-bounds argument.

Patch 1 covers outgoing scalar argument slots in both precision paths.
Patch 2 adds two load-only asm regressions in verifier_stack_arg.c, based
on Alexei's examples.

Changes in v2:
- Keep the patch 1 fix and explanation unchanged; rebase onto bpf/master
  at 03b0138974.
- Replace the standalone instruction/BTF test builder with two asm tests
  in the existing verifier_stack_arg.c, as requested by Alexei.
- Reuse that file's compiler capability and architecture guards, which
  already cover x86-64, arm64 and RV64. Drop the separate host-side guard.
- Rewrite patch 2's explanation for the two replacement tests.

v1:
https://lore.kernel.org/bpf/20261027061303.1754535-1-xyx2021@mail.ustc.edu.cn/
Review:
https://lore.kernel.org/bpf/DMJI3GWXQOC9.UA3K9X139AR@gmail.com/

Validation on x86-64 with Clang 23.1.4, JIT enabled and panic_on_warn=1:
- Built all four kernel variants and their BPF test modules, plus the
  complete test_progs runner with BPF_STRICT_BUILD=1.
- The two new tests distinguish the two precision paths:

                         State reuse       Fallback
  Unmodified baseline    wrongly accepts   wrongly accepts
  Propagation fix only   rejects           wrongly accepts
  Fallback fix only      wrongly accepts   rejects
  Complete fix           rejects           rejects

  Rejections report the intended map-value bounds violation. The two
  corresponding in-bounds controls load successfully on all four kernels.
  These programs are never attached or executed.
- All 274 subtests passed, with no skips, across verifier_precision,
  verifier_spill_fill, verifier_subprog_precision, verifier_scalar_ids,
  stack_arg_precision, verifier_stack_arg, verifier_stack_arg_order and
  iters on the complete candidate. No kernel WARN/Oops or panic occurred.
- Compiled the test object under x86-64, arm64 and RV64 guard definitions;
  Clang 20 correctly selects the existing unsupported-compiler dummy.
  Runtime testing was x86-64 only, and the unfiltered suite was not run.

Codex assisted with implementation, test integration, commit messages
and validation. The v2 test code was supplied by Alexei and is used
unchanged.
====================

Link: https://patch.msgid.link/20261102190350.788433-1-xyx2021@mail.ustc.edu.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 22:42:11 +00:00
Xu Yunxiang
68851f7d3e
selftests/bpf: Exercise stack argument precision on state reuse
Add two asm regressions for the precision of the sixth argument, which
is passed in a stack argument slot and used as a map value offset.

The first test reuses a safe state after storing arg6 from a register.
Precision must propagate from that slot to the register at an earlier
checkpoint, so a later out-of-bounds path cannot reuse that checkpoint.

The second test triggers conservative precision fallback by backtracking
across a store through a register that later becomes a scalar through
pointer subtraction. The caller's argument slot must become precise so
an out-of-bounds argument cannot reuse the safe state.

Both programs are load-only rejection tests and use the existing stack
argument compiler and architecture guards.

The two test programs were supplied by Alexei Starovoitov during review
and are included unchanged.

AI assistance was used in preparing this patch.

Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Signed-off-by: Xu Yunxiang <xyx2021@mail.ustc.edu.cn>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/DMJI3GWXQOC9.UA3K9X139AR@gmail.com/
Link: https://patch.msgid.link/20261102190350.788433-3-xyx2021@mail.ustc.edu.cn
2026-11-02 22:42:11 +00:00
Xu Yunxiang
d537252cc8
bpf: Propagate scalar precision through stack arguments
Outgoing stack arguments retain scalar verifier state separately from
registers and ordinary spills. State comparison uses their precision
marks, but propagate_precision() does not carry those dependencies from
a reused state to the current path's ancestors. A path can consequently
reuse a state without making earlier checkpoints distinguish scalar
values that will later be used as memory offsets.

Seed the existing backtracking batch with precise scalar argument slots
from every frame. Incoming arguments live in the caller's outgoing
slots, so include caller frames as well as the current frame.

Also cover scalar argument slots in bpf_mark_all_scalars_precise(), so
conservative fallback preserves the same invariant. Keep its existing
ancestor-only traversal and leave pointer and uninitialized slots alone.

AI assistance was used in preparing this patch.

Fixes: 0f6bd5e7a8 ("bpf: Support stack arguments for bpf functions")
Signed-off-by: Xu Yunxiang <xyx2021@mail.ustc.edu.cn>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102190350.788433-2-xyx2021@mail.ustc.edu.cn
2026-11-02 22:42:10 +00:00
Yonghong Song
fdda033f7f
selftests/bpf: Fix callback recursion test with noipa global func
With llvm24 after commit 28b4a2032f97 ("[BPF] Mark global functions
noipa"), the test recursion_via_global_func_and_callback fails:

  13: (85) call bpf_loop#181 4: frame1: R1=scalar() R10=fp0 cb
  ; return static_calls_global(i); @ verifier_global_subprogs.c:548
  4: (85) call pc+1
  ...
  ; return global_calls_loop(x); @ verifier_global_subprogs.c:543
  6: (85) call pc+1
  Func#3 ('global_calls_loop') is global and assumed valid.
  7: frame2: R0=scalar()
  7: (95) exit
  ...
  ; return static_calls_global(i); @ verifier_global_subprogs.c:548
  5: (95) exit
  At callback return the register R0 has unknown scalar value should have been in [0, 1]
  =============
  EXPECTED   SUBSTR: 'recursive call from global_calls_loop() to loop_cb_calls_static()'
   #669/9   verifier_global_subprogs/recursion_via_global_func_and_callback:FAIL

The callback loop_cb_calls_static() returns the result of
static_calls_global(), which in turn returns the result of the global
function global_calls_loop().

Before the above llvm24 commit, IPSCCP (interprocedural sparse
conditional constant propagation) could fold the return value of
global_calls_loop() into its callers. global_calls_loop() is not
static, but it has a non-weak definition in the same compilation unit,
so IPSCCP may assume that definition is the one called. It found that
global_calls_loop() always returns 0 and replaced the uses of the call
result with 0, which made static_calls_global() and then
loop_cb_calls_static() return a constant 0 as well. The calls stay, only
their return values are replaced. So the callback set R0 to 0 itself,
passed the bpf_loop callback return range check, and verification went
on to report the expected recursion.

The llvm24 commit marks global functions noipa, since the verifier
checks a global function only against its BTF prototype and freplace
can replace it. With noipa, IPSCCP no longer propagates the return
value of global_calls_loop() to callers. The verifier does not look
into a global function either, so R0 after the call is an unknown
scalar, and the callback return check fails before the recursion is
detected.

Make static_calls_global() return void and let loop_cb_calls_static()
return 0 explicitly. The call chain the test is about stays the same,
and the test passes with both llvm24 and earlier versions (e.g. llvm21
to llvm23).

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://github.com/llvm/llvm-project/pull/237690
Link: https://patch.msgid.link/20261102192727.762933-1-yonghong.song@linux.dev
2026-11-02 22:40:38 +00:00
Alexei Starovoitov
c5973f3067
Merge branch 'bpf-one-may_goto-time-slice-per-prog-invocation'
Alexei Starovoitov says:

====================
bpf: One may_goto time slice per prog invocation

From: Alexei Starovoitov <ast@kernel.org>

may_goto stops a loop that the verifier cannot bound: after 250 ms the loop
must exit. The count and the timestamp are in the stack frame of the
function that contains the loop. So the limit is for one call of a subprog,
not for one invocation of a prog. Loops that nest across calls multiply it,
and 9 insns lock up a cpu:

  main:                 sub:
  1: call sub           1: may_goto 2f
     may_goto 2f           goto 1b
     goto 1b            2: r0 = 0
  2: r0 = 1                exit
     exit

This series uses one count and one timestamp for all may_goto of a prog, in
per-cpu memory of the prog. The main prog sets them in its first insns.
When the time is up each loop ends at its next may_goto, in any function.

There is nothing in the stack frame any more, and nothing at the entry or
at an exit of a subprog. The C code of may_goto, helpers, kfuncs and
trampolines do not change. The callers of async callbacks save and restore
count and timestamp.

 - Patch 1: the interpreter can run a prog with the timed form of may_goto.
   Then the kernel crashes. This fix does not depend on the other patches.
 - Patches 2-4 change three selftests that rely on a time slice for each
   frame.
 - Patch 5 adds per-cpu insns to the JIT of s390. It is the only JIT with
   timed may_goto that doesn't have them.
 - Patch 6 passes a pointer to arch_bpf_timed_may_goto() in place of an
   offset in the stack frame. It removes code from six archs.
 - Patch 7 is the change.
 - Patch 8 ends bpf_loop() and bpf_for_each_map_elem() when the time is up.
 - Patch 9 has the tests.

What changes for a prog:
 - The 250 ms are for all loops of an invocation, not for each frame.
 - When the time is up, a function that is called after that makes no
   iteration. Today each call has a new time slice.

Count and timestamp are per-cpu, so a second invocation of the same prog on
the same cpu shares them with the first one. The error is on the long side:
the first one gets more time. None is stopped before it is 250 ms old.

All progs with may_goto get different code: 56 of 493 progs of scx, none of
Cilium. The series adds 1.8% to their JITed code, and they use 25% less
stack. On x86-64 (Zen 5) a call of a function with may_goto is cheaper than
before, and an iteration of an empty loop costs 0.09 nsec more.

Tested on x86-64: test_progs, test_progs-no_alu32, test_progs-cpuv4,
test_progs-bpf_gcc and test_verifier have no new failure. The same is true
for test_progs with KASAN, and for test_progs and test_verifier with
mitigations on. On arm64 the new tests pass in QEMU. On s390 test_progs did
not run: progs for the per-cpu insn and for may_goto pass in QEMU. riscv,
loongarch and powerpc are compile tested only.

v1 was patches 7 and 8 of [1]. I dropped them from v2 of that series [2].
v1 -> v2:
 - v1 also had a count in per-cpu memory. A subprog took it at its entry
   and gave it back at each exit. The insns at the exit changed R2, which
   is a part of a 16-byte return value (Ihor). Now each may_goto uses the
   per-cpu count, and there are no insns at the entry and at exits.
 - Each read of the clock walked the stack to find the prog. Now may_goto
   has the address.
 - Add patches 1-6 and 8.

[1] https://lore.kernel.org/bpf/20261026025943.404450-1-alexei.starovoitov@gmail.com/
[2] https://lore.kernel.org/bpf/20261027190314.1440199-1-alexei.starovoitov@gmail.com/

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261031215543.682284-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 22:20:02 +00:00
Alexei Starovoitov
9d8affd7b6
selftests/bpf: Test one may_goto time slice per prog invocation
Most tests call a function that spins until may_goto stops it, four times.
With one time slice for an invocation of the prog only the first call
spins. With a time slice for each frame all four calls spin, and the test
fails after 1 sec.

  group           tests
  --------------  ------------------------------------------------------
  the problem     9 insns, three levels of short loops, a subprog with
                  65534 iterations, bpf_loop() with a callback that spins
                  or makes 60000 iterations
  ways to a loop  call, call through a function without a loop, global
                  function, callx, bpf_loop() inlined and not,
                  bpf_for_each_map_elem(), bpf_user_ringbuf_drain(),
                  bpf_find_vma(), bpf_rbtree_add()
  bpf_loop()      ends when the time is up: inlined and not, in a callback
                  of bpf_loop(). Goes on when BPF code calls the callback
                  too
  count           a loop that is on the stack ends when the time is up,
                  65535 calls that make one iteration read the clock
  new time slice  timer, wq, task_work, call_rcu, call_rcu_tasks_trace,
                  each after a prog on the cpu that used up its time. Tail
                  call, extension prog
  same one        a timer callback that interrupts the prog doesn't give it
                  more time, the exception callback
  registers       may_goto takes a register that is dead: R0-RN are live,
                  for each N. A register that is live through the back
                  edge only, at the target only, behind the may_goto only.
                  All of that when it calls C and when the time is up.
                  16-byte return value
  other           tracing prog with frames in a private stack, may_goto in
                  dead code

Two tests lock up a cpu on a kernel with a time slice for each frame: the
9 insns and the three levels of short loops. All other tests give up and
fail there, or pass. The tests are for x86-64 and arm64 with the JIT only.

may_goto_far gets four subtests with the may_goto in a subprog.

The test is serial. Its progs spin for 250 ms in an RCU read-side critical
section, one after the other. Next to them in 'test_progs -j' the test
"mmap" gives up its wait for the end of a map. The test takes 10 sec.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-10-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
c16c6c4683
bpf: End bpf_loop() when the time of may_goto is up
When the time of a prog is up all loops with may_goto end, but bpf_loop()
goes on. It calls its callback up to 1 << 23 times. The loops in the
callback make no iteration, but the rest of the callback runs, and that can
be another bpf_loop(). Two test progs with bpf_loop(1 << 23, cb) and some
work in cb return after 4 sec and 10 sec. With this patch they return after
250 ms.

bpf_loop() and bpf_for_each_map_elem() end their loop when the callback
returns 1. So return 1 in the first insns of the callback when the time is
up:

  r0 = address of the count
  r0 = &(void __percpu *)(r0)
  r0 = *(u64 *)(r0 +0)
  if r0 != 0x0 goto pc+2
  r0 = 1
  exit

The verifier has seen what follows: the loop of the helper can end after
each call of the callback.

A function that BPF code calls too, or that is the callback of another
helper or kfunc, stays as it is: there the return value has another
meaning. The callback of bpf_user_ringbuf_drain() stays as it is too. The
helper takes a sample out of the buffer for each call, so a call that
does nothing loses the sample. Its loop ends after 128K samples.

This patch does not limit bpf_loop() itself. Only may_goto counts and reads
the clock. So nested bpf_loop() are not stopped when the prog has no
may_goto, or has none in the callbacks: bpf_loop(1 << 20, cb) with
bpf_loop(4096, cb2) in cb takes 5 sec. Nested open coded iterators have the
same problem. A follow up will fix these holes.

A call of such a callback executes 4 more insns. The cost on x86-64 (Zen 5)
in nsec:

                                                   before  after
  callback makes 1 iteration, inlined bpf_loop()    1.16    1.54
  callback makes 1 iteration, bpf_loop()            6.52    6.74
  callback without may_goto, inlined bpf_loop()     1.16    1.16
  callback without may_goto, bpf_loop()             4.95    4.95
  callback without may_goto, nested bpf_loop()      1.13    1.38

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-9-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
ec274bb466
bpf: One may_goto time slice per prog invocation
The count and the timestamp of may_goto are in the stack frame. So the
limit of 250 ms is for one call of a subprog, not for one invocation of the
prog, and loops that nest across calls multiply it. These 9 insns cause a
soft lockup:

  main:                 sub:
  1: call sub           1: may_goto 2f
     may_goto 2f           goto 1b
     goto 1b            2: r0 = 0
  2: r0 = 1                exit
     exit

Use one count and one timestamp for all may_goto of a prog, in per-cpu
memory of the prog. The main prog sets them in its first insns. When the
time is up each loop ends at its next may_goto, in any function.

  rX = address of the count
  rX = &(void __percpu *)(rX)
  r12 = *(u64 *)(rX +0)
  if r12 == 0x0 goto target
  r12 -= 1
  if r12 != 0x0 goto pc+2
  r12 = rX
  call arch_bpf_timed_may_goto
  *(u64 *)(rX +0) = r12

rX is a register that is dead at the may_goto. When all ten are live R0 is
saved in the stack.

An async callback can interrupt the prog on the same cpu. So its caller
sets count and timestamp, and puts the old values back at the end. A second
invocation of the prog on the same cpu gives more time to the first one.

  x86-64 (Zen 5), nsec                             before  after
  iteration, empty loop                             0.36    0.44
  iteration, the body takes 4 cycles                0.89    0.89
  call of a subprog and 1 iteration                 1.21    1.16

The 56 progs of scx with may_goto get 1.7% more JITed code and use 25% less
stack.

Fixes: e723608bf4 ("bpf: Add verifier support for timed may_goto")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-8-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
78821f4d8d
bpf: Pass a pointer to arch_bpf_timed_may_goto()
arch_bpf_timed_may_goto() gets the offset of count and timestamp in the
stack frame in BPF_REG_AX. Arch code adds the frame pointer to it, and
calls bpf_check_timed_may_goto() with the result. On arm64, riscv,
loongarch, powerpc and s390 the asm function does it. On x86-64 the JIT
does it, because the frame pointer is in another register when the prog has
a private stack.

The next patch moves count and timestamp out of the stack frame. So pass
the pointer in BPF_REG_AX, and let the verifier emit the addition:

  before                           after

  r12 = -16                        r12 = r10
  call arch_bpf_timed_may_goto     r12 += -16
                                   call arch_bpf_timed_may_goto

The JITs know which register r10 is. The asm functions have a move in place
of the addition, and the special case in the x86-64 JIT goes away.

These insns run when the count is used up: in each 65535th iteration. The
cost of an iteration does not change.

Three tests have the insns of may_goto in them. Update them.

Tested on x86-64, and on arm64 and s390 in QEMU. riscv, loongarch and
powerpc are compile tested only.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-7-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
85b6a11252
s390/bpf: Support internal-only MOV instruction to resolve per-CPU addrs
The verifier emits BPF_MOV64_PERCPU_REG to turn the address of a per-cpu
variable into the address of the copy of this cpu. s390 keeps the per-cpu
offset of the cpu in the lowcore. Add it to the register with one insn, the
way the JIT reads cpu_nr and current_task for the helpers that it inlines.

With bpf_jit_supports_percpu_insn() the verifier inlines the lookup in
per-cpu array and per-cpu hash maps, and resolves the address of a value in
a per-cpu array. Patch 7 needs the insn for may_goto.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-6-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
5eced83779
selftests/bpf: End the loop of parallel_test_bitmap after 50 ms
The two progs of parallel_test_bitmap change bits of the same words in a
loop of 10000000 iterations with can_loop. The loop goes on until may_goto
stops it. The functions that it calls retry a cmpxchg that fails:

  do {
          ...
          actual = cmpxchg(&bmp->bits[idx], old, new);
          if (actual == old)
                  return true;
  } while (can_loop);
  return false;

The retry is always possible only while each stack frame has a time slice
of its own. With one time slice for all may_goto of a prog, a function that
is called after the time is up makes no iteration. The bit does not change,
and the test fails with -EINVAL, in 53 of 900 runs.

Leave the loop after 50 ms.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-5-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
40a3a2e686
selftests/bpf: Give the first loop of cond_break5 an end
The main prog of cond_break5 spins until may_goto stops the loop. Then it
calls a subprog and expects that the loop of the subprog makes iterations.
This is true only while each stack frame has a time slice of its own.

Stop the first loop after 100 iterations. The test still makes sure that
may_goto works in the main prog and in a subprog of one prog.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-4-alexei.starovoitov@gmail.com
2026-11-02 22:20:01 +00:00
Alexei Starovoitov
fcda8096dc
selftests/bpf: Don't cast a pointer to .bss in arena_htab_asm
arena_htab_asm is arena_htab.c with BPF_ARENA_FORCE_ASM. In this variant
__arena has no address space, so arr1 is in .bss, and cast_kern() is a real
insn. cast_kern(arr) turns the pointer to .bss into an offset in the arena.
Each of the 100000 stores to arr[i] faults, and the fault handler of the
arena skips it.

Remove the cast. In the other variant it is a nop. The prog takes 67 ms in
place of 950 ms on a kernel with lockdep.

With one time slice for all may_goto of a prog, may_goto stops the loops of
the old prog after 250 ms. The test does not see that, because it looks at
the first keys only.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-3-alexei.starovoitov@gmail.com
2026-11-02 22:20:00 +00:00
Alexei Starovoitov
1ddffb57b3
bpf: Emit timed may_goto for JITed progs only
The timed form of may_goto calls arch_bpf_timed_may_goto(). This function
takes its argument and returns its result in BPF_REG_AX, in a register of
the cpu. Only JITed code can call it.

The verifier emits the timed form when the arch has a JIT that supports it.
It does not look at the prog. With CONFIG_BPF_JIT_ALWAYS_ON=n the
interpreter can run such a prog: the JIT is off, or it fails. The
interpreter calls the function like a helper. The function takes what the C
code left in that register for a pointer, and bpf_check_timed_may_goto()
reads and writes through it.

Emit the timed form only when the prog asks for a JIT, and make the JIT
mandatory for such a prog. All other progs get the form that counts down
from BPF_MAX_LOOPS.

One test of verifier_may_goto_1 shows the insns of the timed form. Load it
only when progs are JITed.

Fixes: e723608bf4 ("bpf: Add verifier support for timed may_goto")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031215543.682284-2-alexei.starovoitov@gmail.com
2026-11-02 22:20:00 +00:00
Kevin Dewald
60b10121db Bluetooth: MGMT: Fix discovery stuck after a failed Stop Discovery
Stop Discovery moves the discovery to DISCOVERY_STOPPING, and
stop_discovery_complete() only moves it on to DISCOVERY_STOPPED when
stopping succeeded. When it fails, for example because LE Set Scan
Enable times out, nothing moves the discovery out of
DISCOVERY_STOPPING: Stop Discovery is rejected, as the discovery is not
active anymore, and the LE scan timeout was cancelled before the scan
was disabled. Until the controller is powered off, every Start
Discovery then fails with Busy, and hci_update_passive_scan_sync()
skips background scanning, so devices set to auto-connect are not
connected anymore.

Move the discovery back to DISCOVERY_FINDING when stopping it failed
while its inquiry or active LE scan is still running, so that it can be
stopped again. Only change the state while the discovery is still
stopping, as Inquiry Cancel may already have stopped it, for example
when only the passive scan could not be disabled, and a new Start
Discovery may have followed. Do this under hci_dev_lock(), like the
command completions that change these flags, and before replying, so
that a client acting on the reply sees the new state. Only cancel the
LE scan timeout once the scan is disabled, so that the discovery still
ends on its own, except when suspending, where it is still cancelled
first.

A timed out LE Set Scan Enable can still complete afterwards, which
cancels the timeout as well, so also stop the discovery when its scan
is disabled while the timeout is pending, or while the timeout work
waits for the lock.

Fixes: 0e05bba6f6 ("Bluetooth: Update stop_discovery to use HCI request")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Kevin Dewald <kevin@simpleble.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Yifan Zhang
ed4d302af7 Bluetooth: validate retained LE Set CIG Parameters command length
hci_cc_le_set_cig_params() validates the controller response but not the
parameters of the previously sent command.  A short command can claim a
large num_cis without containing the corresponding cis[] array.  A
complete successful response then makes the handler read beyond the
command skb while looking up each CIS ID.

KASAN reports:

  BUG: KASAN: slab-out-of-bounds in hci_cc_le_set_cig_params
  Read of size 1
  hci_cc_le_set_cig_params
  hci_cmd_complete_evt
  hci_event_packet

Obtain the retained parameter length and require both the fixed header and
the complete CIS array before using the command data.

The reproducer no longer triggers a KASAN report with this change.

Fixes: 71e9588435 ("Bluetooth: ISO: use correct CIS order in Set CIG Parameters event")
Closes: https://lore.kernel.org/linux-bluetooth/179317463153.87610.8996555110609321376@stu.pku.edu.cn/
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Yifan Zhang
1eb52f35fc Bluetooth: validate retained LE Create CIS command length
hci_cs_le_create_cis() retrieves the parameters of the previously sent
command without their length.  It then trusts num_cis and walks the
flexible cis[] array when a controller reports a failed command.

A five-byte HCI command containing only num_cis can therefore make the
handler read beyond the command skb.  KASAN reports:

  BUG: KASAN: slab-out-of-bounds in hci_cs_le_create_cis
  Read of size 2
  hci_cs_le_create_cis
  hci_cmd_status_evt
  hci_event_packet

Add a length-returning saved-command helper and require the fixed header
and complete CIS array before walking it.

The reproducer no longer triggers a KASAN report with this change.

Fixes: 26afbd826e ("Bluetooth: Add initial implementation of CIS connections")
Closes: https://lore.kernel.org/linux-bluetooth/179317462624.87574.6271582002629080499@stu.pku.edu.cn/
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Cen Zhang
a7c5c18b7c Bluetooth: hci_core: Initialize advertising RPA work only once
hci_add_adv_instance() also updates existing instances and calls
INIT_DELAYED_WORK() on their rpa_expired_cb every time, even when the
work is pending or running. cancel_delayed_work_sync() then no longer
finds the work, so hci_remove_adv_instance() can free the instance
under it:

  hdev->workqueue                 MGMT_OP_ADD_EXT_ADV_PARAMS
  adv_instance_rpa_expired()
                                  hci_dev_lock(hdev)
                                  hci_add_adv_instance()
                                    INIT_DELAYED_WORK()
                                  mgmt_pending_new() fails
                                  hci_remove_adv_instance()
                                    cancel_delayed_work_sync()
                                      returns without waiting
                                    kfree(adv)
                                  hci_dev_unlock(hdev)
    adv->rpa_expired = true

The work has been initialized on every update since it was added.
Initialize it only when the instance is allocated.

KASAN report as below:

    BUG: KASAN: slab-use-after-free in adv_instance_rpa_expired+0x139/0x160
    Write of size 1 at addr ffff888108d84b2e by task kworker/u17:0/504

    Workqueue: hci0 adv_instance_rpa_expired
    Call Trace:
     adv_instance_rpa_expired+0x139/0x160

    Allocated by task 560:
     hci_add_adv_instance+0x68d/0x9d0
     add_ext_adv_params+0x4d4/0xb60
     hci_sock_sendmsg+0x128b/0x22e0

    Freed by task 594:
     kfree+0x307/0x580
     hci_remove_adv_instance+0x230/0x540
     add_ext_adv_params+0xa43/0xb60
     hci_sock_sendmsg+0x128b/0x22e0

    Last potentially related work creation:
     insert_work+0x37/0x210
     __queue_work+0xaba/0x1270
     call_timer_fn+0x171/0x500

    The buggy address belongs to the object at ffff888108d84800
     which belongs to the cache kmalloc-1k of size 1024
    The buggy address is located 814 bytes inside of
     freed 1024-byte region [ffff888108d84800, ffff888108d84c00)

Fixes: a73c046a28 ("Bluetooth: Implement Set ADV set random address")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Jinwang Li
a9f9eeb534 Bluetooth: L2CAP: Ignore connection responses with wrong ident
L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.

l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Kevin Dewald
d90f24dc38 Bluetooth: MGMT: Clear disabled connection parameters when loading none
Load Connection Parameters only clears the disabled connection
parameters when it loads more than one entry, so that loading a single
entry can update the parameters of one device without dropping the
others. Loading no entries does not clear them either, though, which is
what bluetoothd does when it starts without stored connection
parameters.

Pair Device adds disabled connection parameters for the device it pairs
with, so these now survive bluetoothd restarts, and new connections to
the device keep using the parameters they were created with instead of
the defaults set since, e.g. the connection interval from main.conf.

Clear the disabled connection parameters unless a single entry is
loaded, as was done for any number of entries before.

Fixes: 0ece498c27 ("Bluetooth: MGMT: Make MGMT_OP_LOAD_CONN_PARAM update existing connection")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Kevin Dewald <kevin@simpleble.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:03 -05:00
Cen Zhang
9ff7371191 Bluetooth: hci_sync: Copy the resolving-list IRK under RCU
hci_le_add_resolve_list_sync() copies the peer IRK into the LE Add
Device To Resolving List command after hci_find_irk_by_addr() has
returned. The finder ends its RCU read-side section before returning
the borrowed entry, and neither the request worker nor
interleave_scan_work() holds hdev->lock here. The resolving-list
membership check between the lookup and the copy takes hdev->lock and
may sleep on it, which widens the window.

When LL privacy programs a peer with address resolution enabled,
MGMT_OP_LOAD_IRKS can free its IRK before the copy:

  Request worker                   Management / RCU reclamation
  hci_le_add_resolve_list_sync()
    irk = hci_find_irk_by_addr()
                                   load_irks()
                                     hci_dev_lock(hdev)
                                     hci_smp_irks_clear(hdev)
                                       list_del_rcu(), kfree_rcu()
                                     hci_dev_unlock(hdev)
                                   grace period ends, irk is freed
    resolving-list membership check
    memcpy(cp.peer_irk, irk->val, 16)

Copy the IRK value in an RCU read-side section right after the lookup,
as hci_le_set_privacy_mode_sync() does for the identity address. The
section ends before hdev->lock is taken and before the synchronous HCI
command is sent.

KASAN reported this on a test kernel with scheduling hooks, whose
frames appear in the trace. The report predates the hdev->lock taken
by the membership check.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in hci_le_add_resolve_list_sync+0x8d9/0x910
    Read of size 16 at addr ffff88810d21452d by task kworker/u17:0/504

    CPU: 2 UID: 0 PID: 504 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #2 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Workqueue: hci0 interleave_scan_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? hci_le_add_resolve_list_sync+0x8d9/0x910
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? hci_le_add_resolve_list_sync+0x8d9/0x910
     kasan_report+0xe0/0x110
     ? hci_le_add_resolve_list_sync+0x8d9/0x910
     hci_le_add_resolve_list_sync+0x8d9/0x910
     ? __pfx_hci_le_add_resolve_list_sync+0x10/0x10
     ? pmbd_probe_hit_cookie+0xe7/0x1c0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? pmbd_probe_hit_cookie+0xee/0x1c0
     ? __pfx_pmbd_probe_hit_cookie+0x10/0x10
     hci_le_add_accept_list_sync+0x18e/0x820
     ? conn_params_copy+0x36e/0x650
     ? __pfx_hci_le_add_accept_list_sync+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? conn_params_copy+0x3a0/0x650
     hci_passive_scan_sync+0x95f/0x1f10
     ? __pfx_hci_passive_scan_sync+0x10/0x10
     ? debug_object_deactivate+0x2f8/0x3c0
     ? pwq_dec_nr_in_flight+0x880/0xdf0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_acquire+0x17b/0x2f0
     ? process_one_work+0x895/0x19c0
     interleave_scan_work+0x11b/0x470
     process_one_work+0x908/0x19c0
     ? __pfx_process_one_work+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x34f/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf80
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>

    Allocated by task 535:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_add_irk+0xb6/0x220
     load_irks+0x5f9/0x840
     hci_sock_sendmsg+0x128b/0x22e0
     __sys_sendto+0x425/0x470
     __x64_sys_sendto+0xe5/0x1c0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    Freed by task 0:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     __rcu_free_sheaf_prepare+0x65/0x2a0
     rcu_free_sheaf+0x1f/0xe0
     rcu_core+0x661/0x1d10
     handle_softirqs+0x201/0x930
     __irq_exit_rcu+0x110/0x1e0
     irq_exit_rcu+0xe/0x20
     sysvec_apic_timer_interrupt+0x6c/0x80
     asm_sysvec_apic_timer_interrupt+0x1a/0x20

    The buggy address belongs to the object at ffff88810d214500
     which belongs to the cache kmalloc-64 of size 64
    The buggy address is located 45 bytes inside of
     freed 64-byte region [ffff88810d214500, ffff88810d214540)

    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10d214
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff8881000428c0 dead000000000100 dead000000000122
    raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff88810d214400: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810d214480: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    >ffff88810d214500: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                                      ^
     ffff88810d214580: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810d214600: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    ==================================================================

Fixes: e8907f7654 ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Cen Zhang
add463a658 Bluetooth: SMP: Protect LTK encryption with RCU
smp_ltk_encrypt() checks the security level of the LTK returned by
hci_find_ltk() and then starts encryption with its EDIV, Rand, value
and key size. The finder ends its RCU read-side section before
returning the borrowed entry, and neither caller holds hdev->lock: the
SMP Security Request handler runs from the receive path, and
setsockopt(BT_SECURITY) reaches smp_conn_security() with only the
socket and channel locks held.

MGMT_OP_LOAD_LONG_TERM_KEYS can therefore free the LTK in between:

  Socket security request          Management / RCU reclamation
  smp_ltk_encrypt()
    key = hci_find_ltk()
                                   load_long_term_keys()
                                     hci_dev_lock(hdev)
                                     hci_smp_ltks_clear(hdev)
                                       list_del_rcu(), kfree_rcu()
                                     hci_dev_unlock(hdev)
                                   grace period ends, key is freed
    smp_ltk_sec_level(key)
    hci_le_start_enc(hcon, key->ediv, key->rand, key->val, ...)

Keep an RCU read-side section across the lookup and every use of the
key. hci_le_start_enc() copies the key into the command and queues it
with a GFP_ATOMIC allocation, so the whole sequence can stay inside the
section.

KFENCE reported this on a test kernel where the socket thread was
paused after the lookup until the RCU callback had freed the key.

KFENCE report as below:

    ==================================================================
    BUG: KFENCE: use-after-free read in smp_ltk_encrypt.isra.0+0xf3/0x370

    Use-after-free read at 0x00000000c45332eb (in kfence-#128):
     smp_ltk_encrypt.isra.0+0xf3/0x370
     smp_conn_security+0x489/0x9d0
     l2cap_sock_setsockopt+0x1bbe/0x2300
     do_sock_setsockopt+0x1fb/0x430
     __sys_setsockopt+0x106/0x180
     __x64_sys_setsockopt+0xc2/0x160
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    kfence-#128: 0x00000000d45af9b0-0x0000000053c1365e, size=72, cache=kmalloc-96

    allocated by task 533 on cpu 0 at 50.484258s (0.449177s ago):
     hci_add_ltk+0x1f5/0x3a0
     load_long_term_keys+0x6ea/0x930
     hci_sock_sendmsg+0x128b/0x22e0
     sock_write_iter+0x4c0/0x550
     vfs_write+0x637/0x1010
     ksys_write+0x1b7/0x200
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    freed by task 0 on cpu 0 at 50.846944s (0.093664s ago):
     __rcu_free_sheaf_prepare+0x261/0x2a0
     rcu_free_sheaf_nobarn+0x1d/0x50
     rcu_core+0x661/0x1d10
     handle_softirqs+0x201/0x930
     __irq_exit_rcu+0x110/0x1e0
     irq_exit_rcu+0xe/0x20
     sysvec_apic_timer_interrupt+0x6c/0x80
     asm_sysvec_apic_timer_interrupt+0x1a/0x20
     pv_native_safe_halt+0xf/0x20
     default_idle+0x9/0x10
     default_idle_call+0x6c/0xb0
     do_idle+0x3a7/0x650
     cpu_startup_entry+0x54/0x60
     rest_init+0x15e/0x2b0
     start_kernel+0x412/0x4b0
     x86_64_start_reservations+0x18/0x30
     x86_64_start_kernel+0x111/0x120
     common_startup_64+0x13e/0x158

    CPU: 2 UID: 0 PID: 534 Comm: l2cap-ltk-actor Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #5 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    ==================================================================

Fixes: 988c5997d3 ("Bluetooth: Use the LTK after receiving a LE Security Request")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Cen Zhang
ebc4f217c1 Bluetooth: SMP: Protect link keys during LTK derivation
sc_generate_ltk() reads the type and value of the peer link key after
hci_find_link_key() has returned. The finder ends its RCU read-side
section before returning the borrowed entry, and the SMP receive path
does not hold hdev->lock: l2cap_recv_acldata() releases it before the
PDU is dispatched. The L2CAP connection and channel locks held by SMP
do not serialize with management link-key removal.

When BR/EDR Secure Connections pairing derives an LTK from the stored
link key, MGMT_OP_LOAD_LINK_KEYS can free that key mid-derivation:

  HCI RX worker (SMP)              Management / RCU reclamation
  sc_generate_ltk()
    key = hci_find_link_key()
                                   load_link_keys()
                                     hci_dev_lock(hdev)
                                     hci_link_keys_clear(hdev)
                                       list_del_rcu(), kfree_rcu()
                                     hci_dev_unlock(hdev)
                                   grace period ends, key is freed
    read key->type
    smp_h6() or smp_h7() reads key->val

Hold an RCU read-side section from the lookup until the type and value
have been consumed. smp_h6() and smp_h7() only run the synchronous
AES-CMAC library code, which neither sleeps nor allocates. Release the
section before sc_add_ltk(), which allocates with GFP_KERNEL.

KASAN reported this on a test kernel whose scheduling hook paused the
receive worker after the lookup; the hook frames appear in the trace.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in smp_distribute_keys+0x2983/0x2b70
    Read of size 1 at addr ffff88810618e9a6 by task kworker/u17:0/500

    CPU: 0 UID: 0 PID: 500 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Workqueue: hci1 hci_rx_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? smp_distribute_keys+0x2983/0x2b70
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? smp_distribute_keys+0x2983/0x2b70
     kasan_report+0xe0/0x110
     ? smp_distribute_keys+0x2983/0x2b70
     smp_distribute_keys+0x2983/0x2b70
     ? __pfx_smp_distribute_keys+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? pmbd_gate_maybe+0x47/0x60
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? pmbd_probe_hit_cookie+0xe7/0x1c0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? pmbd_probe_hit_cookie+0xee/0x1c0
     ? __pfx_pmbd_probe_hit_cookie+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __asan_memset+0x23/0x50
     ? smp_recv_cb+0x12e2/0x8f30
     ? srso_alias_return_thunk+0x5/0xfbef5
     smp_recv_cb+0x12e2/0x8f30
     ? __pfx_smp_recv_cb+0x10/0x10
     ? __pfx___might_resched+0x10/0x10
     ? __pfx_sched_balance_find_src_group+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_lock+0x182c/0x2590
     ? l2cap_recv_frame+0x9ef/0x8830
     ? __pfx___mutex_lock+0x10/0x10
     ? __lock_acquire+0x466/0x2260
     ? __pfx_l2cap_chan_hold_unless_zero+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? l2cap_recv_frame+0x13cc/0x8830
     ? __pfx_smp_recv_cb+0x10/0x10
     l2cap_recv_frame+0x13cc/0x8830
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_lock+0x182c/0x2590
     ? __pfx_l2cap_recv_frame+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? find_held_lock+0x2b/0x80
     ? l2cap_recv_acldata+0x1eb/0x10e0
     ? __pfx___mutex_lock+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_unlock_slowpath+0x147/0x920
     ? __pfx_l2cap_conn_hold_unless_zero+0x10/0x10
     ? __pfx_hci_conn_enter_active_mode+0x10/0x10
     ? l2cap_recv_acldata+0x13d/0x10e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     l2cap_recv_acldata+0xe9f/0x10e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     hci_rx_work+0x5a6/0xf00
     ? srso_alias_return_thunk+0x5/0xfbef5
     process_one_work+0x908/0x19c0
     ? __pfx_process_one_work+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x34f/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf80
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>

    Allocated by task 500:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_add_link_key+0x474/0x840
     hci_link_key_notify_evt+0x492/0xce0
     hci_event_packet+0x894/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    Freed by task 0:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     __rcu_free_sheaf_prepare+0x65/0x2a0
     rcu_free_sheaf+0x1f/0xe0
     rcu_core+0x661/0x1d10
     handle_softirqs+0x201/0x930
     __irq_exit_rcu+0x110/0x1e0
     irq_exit_rcu+0xe/0x20
     sysvec_apic_timer_interrupt+0x6c/0x80
     asm_sysvec_apic_timer_interrupt+0x1a/0x20

    The buggy address belongs to the object at ffff88810618e980
     which belongs to the cache kmalloc-64 of size 64
    The buggy address is located 38 bytes inside of
     freed 64-byte region [ffff88810618e980, ffff88810618e9c0)

    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10618e
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff8881000428c0 dead000000000122 0000000000000000
    raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff88810618e880: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810618e900: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    >ffff88810618e980: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                                   ^
     ffff88810618ea00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810618ea80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    ==================================================================

Fixes: b5ae344d4c ("Bluetooth: Add full SMP BR/EDR support")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Cen Zhang
281ddc4e01 Bluetooth: hci_core: Keep link-key filtering inside RCU
hci_find_link_key() must keep the matching link key allocated while it
checks the key against the blocked-key list. It currently leaves the
key-list RCU read-side section before passing k->val to
hci_is_blocked_key(). That helper's own RCU section protects the
blocked-key list, but it cannot keep an unlinked link key from being
reclaimed.

The SMP receive path calls the finder without hdev->lock: Secure
Connections key distribution over BR/EDR reaches it through
smp_distribute_keys() and sc_generate_ltk(). With a stored peer link
key and a link-key entry in the blocked-key list,
MGMT_OP_LOAD_LINK_KEYS can free the selected key before the comparison:

  HCI RX worker (SMP)              Management / RCU reclamation
  hci_find_link_key()
    rcu_read_lock()
    select k
    rcu_read_unlock()
                                   load_link_keys()
                                     hci_dev_lock(hdev)
                                     hci_link_keys_clear(hdev)
                                       list_del_rcu(), kfree_rcu()
                                     hci_dev_unlock(hdev)
                                   grace period ends, k is freed
    hci_is_blocked_key(hdev, ..., k->val)
      memcmp() reads the freed key

Keep the RCU read-side section active through the blocked-key
comparison and the warning that prints k->bdaddr, and release it before
returning on both matched-key paths. hci_find_ltk() already handles its
blocked-key check this way.

KASAN reported this on a test kernel whose scheduling hook paused the
receive worker after the lookup until the key had been freed.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in hci_is_blocked_key+0x2db/0x300
    Read of size 1 at addr ffff88810b5f89a7 by task kworker/u17:0/502

    CPU: 1 UID: 0 PID: 502 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #5 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Workqueue: hci1 hci_rx_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? hci_is_blocked_key+0x2db/0x300
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? hci_is_blocked_key+0x2db/0x300
     kasan_report+0xe0/0x110
     ? hci_is_blocked_key+0x2db/0x300
     hci_is_blocked_key+0x2db/0x300
     hci_find_link_key+0x12e/0x400
     smp_distribute_keys+0x1830/0x2950
     ? trace_hardirqs_on+0x18/0x160
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? queue_delayed_work_on+0xb3/0xf0
     ? __pfx_smp_distribute_keys+0x10/0x10
     ? __pfx_smp_send_cmd.isra.0+0x10/0x10
     ? __cancel_work+0x1b0/0x290
     ? __entry_text_end+0x1020f7/0x1020f9
     ? lockdep_hardirqs_on_prepare+0xea/0x1a0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __asan_memset+0x23/0x50
     ? smp_recv_cb+0x12c7/0x8d80
     ? srso_alias_return_thunk+0x5/0xfbef5
     smp_recv_cb+0x12c7/0x8d80
     ? __pfx_smp_recv_cb+0x10/0x10
     ? __pfx___might_resched+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? stack_depot_save_flags+0x29/0x9a0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_lock+0x182c/0x2590
     ? kasan_save_stack+0x42/0x60
     ? l2cap_recv_frame+0x9ef/0x8830
     ? __kasan_slab_free+0x5f/0x80
     ? kmem_cache_free+0x242/0x580
     ? kfree_skbmem+0x15e/0x1d0
     ? sk_skb_reason_drop+0x12f/0x490
     ? hci_event_packet+0x556/0xc70
     ? hci_rx_work+0x367/0xf00
     ? process_one_work+0x908/0x19c0
     ? worker_thread+0x65c/0xe40
     ? __pfx___mutex_lock+0x10/0x10
     ? __lock_acquire+0x466/0x2260
     ? __pfx_l2cap_chan_hold_unless_zero+0x10/0x10
     ? l2cap_recv_frame+0x13cc/0x8830
     ? __pfx_smp_recv_cb+0x10/0x10
     l2cap_recv_frame+0x13cc/0x8830
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_lock+0x182c/0x2590
     ? __pfx_l2cap_recv_frame+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? find_held_lock+0x2b/0x80
     ? l2cap_recv_acldata+0x1eb/0x10e0
     ? __pfx___mutex_lock+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_unlock_slowpath+0x147/0x920
     ? __pfx_l2cap_conn_hold_unless_zero+0x10/0x10
     ? __pfx_hci_conn_enter_active_mode+0x10/0x10
     ? l2cap_recv_acldata+0x13d/0x10e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     l2cap_recv_acldata+0xe9f/0x10e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     hci_rx_work+0x5a6/0xf00
     ? srso_alias_return_thunk+0x5/0xfbef5
     process_one_work+0x908/0x19c0
     ? __pfx_process_one_work+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x34f/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf80
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>

    Allocated by task 504:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_add_link_key+0x474/0x840
     hci_link_key_notify_evt+0x492/0xce0
     hci_event_packet+0x894/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    Freed by task 29:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     __rcu_free_sheaf_prepare+0x65/0x2a0
     rcu_free_sheaf_nobarn+0x1d/0x50
     rcu_core+0x661/0x1d10
     handle_softirqs+0x201/0x930
     run_ksoftirqd+0x33/0x60
     smpboot_thread_fn+0x3bd/0x9a0
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    The buggy address belongs to the object at ffff88810b5f8980
     which belongs to the cache kmalloc-64 of size 64
    The buggy address is located 39 bytes inside of
     freed 64-byte region [ffff88810b5f8980, ffff88810b5f89c0)

    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10b5f8
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff8881000428c0 dead000000000100 dead000000000122
    raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff88810b5f8880: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810b5f8900: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
    >ffff88810b5f8980: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                                   ^
     ffff88810b5f8a00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810b5f8a80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    ==================================================================

Fixes: 600a87490f ("Bluetooth: Implementation of MGMT_OP_SET_BLOCKED_KEYS.")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Ismail Tarim
3b70dd827b Bluetooth: btmtk: fix error handling in btmtk_usb_isointf_init()
btmtk_usb_isointf_init() submits the ISO interrupt IN URB and then
sends the vendor command 0xfd98. If that command fails, the function
returns an error without killing the URB it has just submitted. The
caller then leaves BTMTK_ISOPKT_RUNNING clear, so the driver treats the
ISO path as inactive while its RX URB is still in flight, and
btmtk_usb_suspend() skips killing it. Kill the anchored URBs on this
path, as the URB submission failure path already does.

The return value of __set_mtk_intr_interface() is also ignored: a
failure to select the ISO alternate setting or to find its endpoints
is logged, but the function goes on to submit the URB. Return the
error instead.

Fixes: ceac1cb025 ("Bluetooth: btusb: mediatek: add ISO data transmission functions")
Signed-off-by: Ismail Tarim <ismailtarim7@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Michael McAllister
5b7d0386a4 Bluetooth: qca: Fix the WCN3950 NVM baud rate offset
WCN3950 uses the HCI transport tag layout that stores the UART baud rate
at byte 1, like WCN3991. However, QCA_WCN3950 precedes QCA_WCN3991 in
qca_btsoc_type, so qca_tlv_check_data() writes the baud rate to byte 2
instead.

On a Motorola Moto G10 with WCN3950 and cmnv12.bin, configuring a 3 Mbps
UART therefore leaves the NVM baud rate at its default 3.2 Mbps and
overwrites the following byte. Firmware download completes, but the
subsequent HCI_RESET times out and Bluetooth initialization fails.

Include WCN3950 in the byte-1 case so the NVM baud rate matches the host
UART without altering the following transport parameter.

Fixes: d5712c511c ("Bluetooth: qca: add WCN3950 support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Michael McAllister <me@michaelmcallister.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Tobias Wilken
7eac806143 Bluetooth: MGMT: Return RFKILLED for Set Powered on a blocked controller
Since MGMT_OP_SET_POWERED runs through hci_cmd_sync, powering on a
controller that is blocked by rfkill fails with -ERFKILL from
hci_dev_open_sync(), and mgmt_set_powered_complete() reports it with
mgmt_status(err). mgmt_errno_status() has no case for -ERFKILL, so
userspace gets MGMT_STATUS_FAILED instead of MGMT_STATUS_RFKILLED.

Before that conversion, power on went through hci_power_on(), whose
error path mgmt_set_powered_failed() still maps -ERFKILL to
MGMT_STATUS_RFKILLED. bluetoothd relies on that status: for
RFKILLED it sets the adapter PowerState to "off-blocked" and returns
org.bluez.Error.Blocked for the Powered property, for any other status
it returns org.bluez.Error.Failed.

With the controller soft blocked, "bluetoothctl power on" printed
"Failed to set power on: org.bluez.Error.Failed" and btmon showed
"Set Powered (0x0005) Status: Failed (0x03)". With this change it
prints org.bluez.Error.Blocked and btmon shows "Status: RFKilled
(0x12)".

Map -ERFKILL to MGMT_STATUS_RFKILLED in mgmt_errno_status().

Fixes: cf75ad8b41 ("Bluetooth: hci_sync: Convert MGMT_SET_POWERED")
Assisted-by: LLM
Signed-off-by: Tobias Wilken <tooangel@tooangel.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Cen Zhang
f05bd61a32 Bluetooth: hci_sync: Protect resolving-list lookups
The host resolving list is updated under hdev->lock, and each
bdaddr_list_with_irk entry must remain alive throughout a lookup.
hci_le_del_resolve_list_sync() and hci_le_add_resolve_list_sync()
traverse that list without taking the lock.

On an LE privacy-capable controller with a programmed entry, passive
scan reconciliation can reach hci_le_del_resolve_list_sync() while a
privileged HCI_RAW client sends LE Clear Resolving List. The raw
command does not take req_lock, and its successful completion runs
on the controller workqueue independently of request work:

  Request work                     Raw HCI / event work
  hci_le_del_resolve_list_sync()
    lookup loads a list node
                                   hci_sock_sendmsg()
                                     queue LE Clear Resolving List
                                   hci_cc_le_clear_resolv_list()
                                     take hdev->lock
                                     unlink and free the node
                                     release hdev->lock
    read the node's address/type

The clear can free the node after the lookup loads it and before its
address/type read, causing a use-after-free. The report below shows
this access with the delete helper on the faulting stack. The add
helper uses the same unprotected lookup.

Take hdev->lock around each resolving-list membership lookup and
retain only a boolean result. This serializes traversal with clear
completion and keeps entry pointers inside the protected section.
Release the lock before issuing a synchronous HCI command, whose
completion also needs the lock.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in
    hci_bdaddr_list_lookup_with_irk+0x106/0x120
    Read of size 1 at addr ffff88810b036e16 by task kworker/u17:0/495

    CPU: 2 UID: 0 PID: 495 Comm: kworker/u17:0 Not tainted
    7.2.0-rc6-pmb-bt-functional-v1+ #3 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
    1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Workqueue: hci0 hci_cmd_sync_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     kasan_report+0xe0/0x110
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     hci_bdaddr_list_lookup_with_irk+0x106/0x120
     hci_le_del_resolve_list_sync.isra.0+0xd6/0x3f0
     ? __pfx_hci_le_del_resolve_list_sync.isra.0+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     hci_le_del_accept_list_sync.isra.0+0x11c/0x290
     ? __pfx_hci_le_del_accept_list_sync.isra.0+0x10/0x10
     ? hci_passive_scan_sync+0x551/0x1e80
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x280
     hci_passive_scan_sync+0x71c/0x1e80
     ? __pfx_hci_passive_scan_sync+0x10/0x10
     ? find_held_lock+0x2b/0x80
     ? hci_lookup_le_connect+0xe1/0x3c0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? find_held_lock+0x2b/0x80
     ? hci_update_passive_scan_sync+0x437/0x950
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x280
     hci_update_passive_scan_sync+0x461/0x950
     hci_cmd_sync_work+0x1b3/0x450
     ? srso_alias_return_thunk+0x5/0xfbef5
     process_one_work+0x908/0x19c0
     ? __pfx_process_one_work+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x34f/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf80
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>

    Allocated by task 495:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_bdaddr_list_add_with_irk+0x183/0x3e0
     hci_cc_le_add_to_resolv_list+0x18c/0x240
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    Freed by task 497:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x307/0x580
     hci_bdaddr_list_clear+0x134/0x230
     hci_cc_le_clear_resolv_list+0x13d/0x240
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    The buggy address belongs to the object at ffff88810b036e00
    which belongs to the cache kmalloc-64 of size 64
    The buggy address is located 22 bytes inside of
    freed 64-byte region [ffff88810b036e00, ffff88810b036e40)

    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
    pfn:0x10b036
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff8881000428c0 dead000000000100
    dead000000000122
    raw: 0000000000000000 0000000000200020 00000000f5000000
    0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff88810b036d00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
     ffff88810b036d80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    >ffff88810b036e00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                             ^
     ffff88810b036e80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810b036f00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    ==================================================================
    Disabling lock debugging due to kernel taint

Fixes: e8907f7654 ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Cen Zhang
6740069127 Bluetooth: hci_sync: Copy the LE accept list under hdev->lock
The LE accept-list mirror consists of bdaddr_list entries that are
added, removed and freed under hdev->lock. The ordinary branch of
hci_update_accept_list_sync() traverses this list without that lock.
The request worker's req_lock does not serialize raw HCI completions,
and the RCU sections protect connection and pending-action lookups,
not the accept-list nodes.

Changing connectability can reach this iterator through
set_connectable_sync(), hci_update_connectable_sync(),
hci_update_passive_scan_sync() and hci_passive_scan_sync(). With a
populated mirror, a privileged raw HCI sender can issue
HCI_OP_LE_CLEAR_ACCEPT_LIST while request work is reconciling it:

  Request work                    HCI event work
  select b and successor t
                                  hci_cc_le_clear_accept_list()
                                    hci_dev_lock(hdev)
                                    hci_bdaddr_list_clear()
                                      unlink nodes and kfree(b)
                                    hci_dev_unlock(hdev)
  read b->bdaddr_type

The clear completion can therefore free the selected node before its
field read, or the saved successor before the iterator advances.
KASAN reported a one-byte read of bdaddr_type from the freed node.

Copy each entry's address and type under hdev->lock and reconcile the
private array instead. Release the mutex before issuing synchronous
commands, since their completion handlers also acquire it. Free the
copy after iteration and use the existing error path to disable
accept-list filtering if allocation fails.

This change has not been runtime-tested.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in hci_passive_scan_sync+0x1cc4/0x1f80
    Read of size 1 at addr ffff888105ee6c56 by task kworker/u17:1/499

    Workqueue: hci0 hci_cmd_sync_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? hci_passive_scan_sync+0x1cc4/0x1f80
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? hci_passive_scan_sync+0x1cc4/0x1f80
     kasan_report+0xe0/0x110
     ? hci_passive_scan_sync+0x1cc4/0x1f80
     hci_passive_scan_sync+0x1cc4/0x1f80
     ? pmbd_gate_site_armed+0x31/0x1c0
     ? __pfx_hci_passive_scan_sync+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? pmbd_probe_hit_cookie+0x10/0x1c0
     ? __pfx_pmbd_probe_hit_cookie+0x10/0x10
     ? hci_update_passive_scan_sync+0x43f/0x9e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x280
     hci_update_passive_scan_sync+0x473/0x9e0
     hci_update_connectable_sync+0x13c/0x250
     set_connectable_sync+0x39/0xb0
     hci_cmd_sync_work+0x1b3/0x450
     ? srso_alias_return_thunk+0x5/0xfbef5
     process_one_work+0x908/0x19c0
     ? __pfx_process_one_work+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_is_held_type+0x8f/0x100
     ? srso_alias_return_thunk+0x5/0xfbef5
     worker_thread+0x65c/0xe40
     ? __pfx_worker_thread+0x10/0x10
     kthread+0x34f/0x460
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __pfx_kthread+0x10/0x10
     ret_from_fork+0x659/0x940
     ? __pfx_ret_from_fork+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __switch_to+0x74f/0xf80
     ? __pfx_kthread+0x10/0x10
     ret_from_fork_asm+0x1a/0x30
     </TASK>

    Allocated by task 511:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_bdaddr_list_add+0x179/0x390
     hci_cc_le_add_to_accept_list+0x189/0x2d0
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    Freed by task 511:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x307/0x580
     hci_bdaddr_list_clear+0x134/0x230
     hci_cc_le_clear_accept_list+0x80/0x1f0
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/0xc70
     hci_rx_work+0x367/0xf00
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    The buggy address belongs to the object at ffff888105ee6c40
                                                                which
                                belongs to the cache kmalloc-32 of size 32
    The buggy address is located 22 bytes inside of
                                                                freed
                                32-byte region [ffff888105ee6c40,
                                ffff888105ee6c60)

    The buggy address belongs to the physical page:
        page: refcount:0 mapcount:0 mapping:0000000000000000
    index:0xffff888105ee69c0 pfn:0x105ee6
    flags: 0x200000000000200(workingset|node=0|zone=2)
    page_type: f5(slab)
        raw: 0200000000000200 ffff888100042780 ffffea0004187150
    ffffea00042534d0
        raw: ffff888105ee69c0 000000000040003f 00000000f5000000
    0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff888105ee6b00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
     ffff888105ee6b80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
    >ffff888105ee6c00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
                                                     ^
     ffff888105ee6c80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
     ffff888105ee6d00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
    ==================================================================

Fixes: e8907f7654 ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Chris Lu
855c9a5460 Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
The ISO data transfer size is spelled out twice: as a raw byte pair in the
vendor command sent by btmtk_usb_isointf_init(), and as MTK_ISO_THRESHOLD
for the padding in btmtk_isopkt_pad(). Build the command payload from the
macro so the size is stated once, and update the setting for current
MediaTek controllers.

Fixes: ceac1cb025 ("Bluetooth: btusb: mediatek: add ISO data transmission functions")
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:02 -05:00
Chris Lu
d015faf684 Bluetooth: btmtk: bound the ISO payload length by the controller's MTU
btmtk_recv_isopkt() bounds the Data_Total_Length reported by the
controller with skb_tailroom(skb) < hci_skb_expect(skb). That keeps the
reassembly inside the skb, but it enforces no protocol limit: the head
allocation is rounded up to the next kmalloc bucket and skb_tailroom()
reports what the bucket can hold rather than what was requested, which is
several hundred bytes more. An oversized length therefore passes, and the
parser keeps pulling bytes out of the following transfers to fill it,
swallowing the real ISO packets they carry until the frame is handed to
hci_recv_frame().

The controller reports the largest ISO_Data_Packet_Length it will send in
LE Read Buffer Size [v2], which hci_cc_le_read_buffer_size_v2() keeps in
hdev->iso_mtu. Once that is available, bound the length by it and size the
receive skb to hold that much plus the 4-byte header. HCI_MAX_ISO_SIZE is
kept only as a fallback for the window before the command completes.

Keep the skb_tailroom() test as well, because a fragment started before
hdev->iso_mtu was populated sits in an skb sized for the fallback.

Fixes: ceac1cb025 ("Bluetooth: btusb: mediatek: add ISO data transmission functions")
Co-developed-by: Hao Qin <hao.qin@mediatek.com>
Signed-off-by: Hao Qin <hao.qin@mediatek.com>
Co-developed-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Chris Lu
8524c3588f Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding
The ISO interrupt IN endpoint delivers a fixed-size transfer that holds
one HCI ISO packet and zero-fills the remainder. That padding belongs to
the transfer rather than to the stream, so it has to be dropped instead of
reported to the host.

btmtk_recv_isopkt() keeps parsing it: the zero bytes read as an ISO header
with handle 0 and a Data_Total_Length of zero, and each one is passed to
hci_recv_frame() as a complete frame. A single transfer yields a long run
of them, which is what fills the HCI log with malformed ISO packets, and
iso_recv() drops the SDU it is reassembling whenever handle 0 belongs to a
live CIS/BIS.

A zero Data_Total_Length carries no ISO Data Load, so such a packet is
never part of the stream. Check for the zero-filled remainder before
starting to parse the next frame, rather than after assembling a 4-byte
header: a remainder shorter than HCI_ISO_HDR_SIZE would otherwise be held
across calls as a partial header, corrupting the next transfer's framing.
This also means a fully zero-filled remainder no longer costs an skb
allocation that gets immediately freed. Reaching a zero Data_Total_Length
any other way is then a genuine error, not padding.

This was observed on MT7925, but btmtk_recv_isopkt() is shared by every
MediaTek USB controller that supports ISO data.

Fixes: ceac1cb025 ("Bluetooth: btusb: mediatek: add ISO data transmission functions")
Co-developed-by: Hao Qin <hao.qin@mediatek.com>
Signed-off-by: Hao Qin <hao.qin@mediatek.com>
Co-developed-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Luiz Augusto von Dentz
e24bfbc5e2 Bluetooth: hci_sync: Update the CIS host feature when enabling LE
The Connected Isochronous Stream (Host Support) feature bit is only set
during init, based on LE being enabled at that time. If LE is enabled
afterwards without the init being repeated, as happens when the
controller is still auto powered on after registration, the bit stays
cleared and controllers enforcing it reject LE Create CIS with Command
Disallowed.

Update the bit whenever LE Host Supported is written, so it follows the
LE state.

Fixes: 709788b154 ("Bluetooth: hci_core: Fix using {cis,bis}_capable for current settings")
Assisted-by: OpenCode:claude-opus-5.5
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Luiz Augusto von Dentz
5d005ded2c Bluetooth: L2CAP: Hold incoming data until encryption key size is known
Once encryption is enabled on an ACL link, the encryption key size is
read from the controller, using hdev->min_enc_key_size in the meantime.
Data received before the reply is processed with that key size, so a
peer starting SMP over BR/EDR right after encryption, which it may do,
gets its Pairing Request rejected with "Encryption Key Size" whenever
the pending security level is FIPS, as that requires a 16 octet key:

  > HCI Event: Encryption Change (0x08) plen 4
  > ACL Data RX: Handle 1 flags 0x02 dlen 11
        BR/EDR SMP: Pairing Request (0x01) len 6
  @ MGMT Event: Authentication Failed (0x0011) plen 8
        Status: Authentication Failed (0x05)
  < HCI Command: Read Encryption Key Size (0x05|0x0008) plen 2
  > HCI Event: Command Complete (0x0e) plen 7
        Key size: 16
  < ACL Data TX: Handle 1 flags 0x00 dlen 6
        BR/EDR SMP: Pairing Failed (0x05) len 1
        Reason: Encryption key size (0x06)

Mark the connection with HCI_CONN_ENC_KEY_SIZE_PEND while the key size
is read and hold incoming L2CAP data back in pending_rx meanwhile,
processing it once the reply is handled.

Found with mgmt-tester "Pairing Acceptor - SMP over BR/EDR 2" under User
Mode Linux time travel, where the emulated peer always replies before
the key size is read.

Fixes: e3f6a257a7 ("Bluetooth: Use actual encryption key size for SMP over BR/EDR")
Assisted-by: OpenCode:claude-opus-5.5
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Luiz Augusto von Dentz
1eebde8ece Bluetooth: hci_core: Convert hci_conn flags to a bitmap
struct hci_conn stores its flags in a single unsigned long, but the
HCI_CONN_* enum already has 33 entries (up to HCI_CONN_PA_SYNC_FAILED
= 32), so on 32-bit architectures set_bit()/test_bit() on the highest
flags access memory past the flags field, aliasing the adjacent
conn_reason field.

Fix this by declaring flags with DECLARE_BITMAP() sized by a new
__HCI_CONN_NUM_FLAGS terminator so it can accommodate any number of
flags.

Assisted-by: OpenCode:claude-opus-5.5
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Kevin Dewald
f5cd268af1 Bluetooth: hci_event: Clear explicit connect state on LE connection
Since commit 6cd29ec6ae ("Bluetooth: hci_sync: Wait for proper events
when connecting LE"), create_le_conn_complete() only runs once the LE
Connection Complete event has been handled, and le_conn_complete_evt()
has already removed the connection parameters from pend_le_conns by
then. hci_connect_le_scan_cleanup() looks the parameters up in
pend_le_conns, so after a successful connection it no longer clears
explicit_connect, nor deletes the parameters that were only created for
the explicit connect.

The parameters of every device connected through an explicit connect,
such as an L2CAP or ATT connect or MGMT Pair Device, are thus left with
explicit_connect set. MGMT Remove Device for all devices then keeps
them as HCI_AUTO_CONN_EXPLICIT instead of freeing them, and if the
device was set to auto-connect and is disconnected, they also stay on
pend_le_conns: the kernel keeps scanning for the device and connects to
it as soon as it advertises, although no one asked for it any more.

Do the cleanup in le_conn_complete_evt() instead, where the explicit
connect request is fulfilled: clear explicit_connect, delete the
parameters if they only existed for it, and put report parameters back
on pend_le_reports. Auto-connect parameters are added back to
pend_le_conns on disconnection, as before. Update the comment in
hci_explicit_conn_params_set() that names hci_connect_le_scan_cleanup()
as the only place deleting them.

Fixes: 6cd29ec6ae ("Bluetooth: hci_sync: Wait for proper events when connecting LE")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Kevin Dewald <kevin@simpleble.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Catherine L
f92b7bca98 Bluetooth: btintel: fix buffer over-read in fw payload
The firmware decoder cast fw_ptr + frag_len to struct
hci_command_hdr and read cmd->plen before confirming the
header and payload still fit in the remaining firmware
buffer.

Add explicit bounds checks before each dereference:
1. Reject if the command header is not fully contained
   in remain.
2. Reject if the full command including payload exceeds
   remain.
3. Log the offending fragment length and remaining size
   before returning -EINVAL.

Fixes: fbbe83c52b ("Bluetooth: btintel: Create common function for firmware download")
Signed-off-by: Catherine L <catherine.l@intel.com>
Tested-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Akhil Arul
19b4e57017 Bluetooth: hci_core: Fix queuing rx_work while workqueue is drained
hci_recv_frame() drops a frame unless HCI_UP or HCI_INIT is set, but the
check is not synchronized with hci_dev_close_sync().  A driver can pass
the check, then close clears HCI_UP, flushes rx_work and starts
drain_workqueue(), and the late queue_work() of rx_work hits the
draining workqueue:

  workqueue: cannot queue hci_rx_work on wq hci0
  WARNING: kernel/workqueue.c:2352 at __queue_work+0x2c0/0x780
  Call Trace:
   queue_work_on+0xb2/0xc0
   hci_recv_frame+0x18f/0x330
   vhci_write+0x174/0x240
   vfs_write+0x271/0x680
   ksys_write+0x7c/0x110

Skipping the queue_work() while HCI_CMD_DRAIN_WORKQUEUE is set, as done
for tx_work, does not work for rx_work: the flag covers the whole close,
and events still have to be received in that window, for the commands
sent by hdev->shutdown() and for the reset done with
HCI_QUIRK_RESET_ON_CLOSE.

Run hci_recv_frame() under rcu_read_lock() and wait with
synchronize_rcu() once HCI_UP has been cleared, so that every caller
which still saw HCI_UP has queued its work before the workqueue is
drained, and later callers drop the frame.

HCI_INIT does not reopen that window.  Apart from the
HCI_QUIRK_RESET_ON_CLOSE reset, which runs after drain_workqueue() has
returned, it is only set by hci_dev_init_sync() during open, and open
and close are serialized by hci_req_sync_lock.  So once the grace period
has ended, nothing can pass the check and queue rx_work until the drain
is over.

Tested in qemu with the syzbot C reproducer, one run per boot: the
warning showed up on 12 of 30 boots before and on none of 42 boots after.
Bringing a vhci controller up and down 50 times behaves the same with
and without this change.

Fixes: 76727c02c1 ("Bluetooth: Call drain_workqueue() before resetting state")
Reported-by: syzbot+2344fb8002f3ef5b1712@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2344fb8002f3ef5b1712
Signed-off-by: Akhil Arul <akhilarul324@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Valentin Kindschi
56ed6b127a Bluetooth: hci_sync: pause advertising for the scan address update
hci_active_scan_sync() programs a non-resolvable private address with LE
Set Random Address on every active scan start.

BLUETOOTH CORE SPECIFICATION Vol 4, Part E, 7.8.4 says the controller
shall return Command Disallowed (0x0C) for that command while legacy
advertising or scanning is enabled. hci_pause_addr_resolution(), called
just above, only stops advertising when LL privacy is in use, so on a
controller without it the command is issued while advertising is still
on:

  Bluetooth: hci0: Opcode 0x2005 failed: -16

It does not converge either. hdev->random_addr is only set on a
successful command complete, so it stays BDADDR_ANY, and the deferral
added by commit c2994b0084 ("Bluetooth: hci_sync: Fix not setting
Random Address when required") requires it to be set. Unlike the
resolvable address a few lines above, which is reused while rpa_valid(),
the non-resolvable one is regenerated and rewritten on every call, so a
controller that refuses the write is asked again at the scan restart
period of about 10 s, for as long as discovery keeps restarting.
Observed on a BCM43455, which has no LL privacy and no extended
advertising, 190 rejections in one capture, every one retrying the same
address:

  < LE Set Random Address  Address: 02:16:91:90:F1:D4 (Non-Resolvable)
  > Command Complete       LE Set Random Address, Command Disallowed
  < LE Set Random Address  Address: 26:90:57:96:9A:3E (Non-Resolvable)
  > Command Complete       LE Set Random Address, Command Disallowed

Pause advertising for the address update, and resume it once the update
is done and before the scan is started. The pause does not outlive the
function: it is taken only when nothing else holds it, and every exit
resumes advertising, which also releases the pause taken by
hci_pause_addr_resolution(). A failed pause returns before marking
anything paused, so the error path is a no-op.

The resume in the error path is no longer guarded by ll_privacy_capable().
That guard matched a pause taken only under LL privacy; the pause added
here is unconditional, and hci_resume_advertising_sync() returns early
when nothing was paused.

One caveat this widens, raised on the previous posting. When
HCI_ADVERTISING is set, hci_pause_advertising_sync() also clears
HCI_DISCOVERABLE and HCI_LIMITED_DISCOVERABLE and zeroes discov_timeout,
and hci_resume_advertising_sync() restores only HCI_ADVERTISING, so the
discoverable state is lost. It reproduces today on an LL privacy
controller through hci_pause_addr_resolution(); the unconditional pause
makes it reachable without LL privacy as well. hci_suspend_sync() also
pauses unconditionally, so a device that suspends loses the same state
on any controller today. That asymmetry is pre-existing and is left
alone here rather than folded into a scan path fix.

Legacy controllers have one random address register, shared by the
scanner and the advertiser. Restoring the advertiser here can reprogram
it when the advertiser is non-connectable, so the scan then uses that
address rather than the one generated for it. Both are non-resolvable
and neither is linkable to the identity address. With privacy enabled
both roles already share one resolvable address the same way.

With the patch, on the same hardware:

  < LE Set Advertising Enable    Enable: 0x00              Success
  < LE Set Random Address                                  Success
  < LE Set Advertising Parameters                          Success
  < LE Set Advertising Enable    Enable: 0x01              Success
  < LE Set Scan Parameters                                 Success
  < LE Set Scan Enable           Enable: 0x01              Success

The address write is accepted, and advertising is restored before the
scan is started.

Over 119369 btmon records and about 12 minutes of the normal workload of
that device, alternating active and passive scanning with ten outgoing
connection attempts, every LE Set Random Address succeeded and there were
no Command Disallowed responses of any opcode, against one per scan
restart before.

Patch 1 is required: without it the resume added here returns -EPERM on
the controllers this fixes and leaves advertising disabled.

Fixes: 3c44a431d6 ("Bluetooth: hci_sync: Resume adv with no RPA when active scan")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5.5 btmon
Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Valentin Kindschi
737139f415 Bluetooth: hci_sync: re-enable legacy advertising on resume
hci_resume_advertising_sync() never re-enables advertising on a
controller without extended advertising.

It restores HCI_ADVERTISING from advertising_old_state, then calls
hci_schedule_adv_instance_sync(), which starts with:

  if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev))
          return -EPERM;

The flag it tests was set a few lines earlier by the resume itself, so
the call returns -EPERM without sending anything. The return value is
discarded by every caller, so the failure is silent: advertising_paused
is cleared, HCI_ADVERTISING is set, and the controller is not
advertising.

Observed on a BCM43455 (no extended advertising) after an active scan:
btmon shows the pause disabling advertising and no re-enable in the ten
seconds that follow, the device does not appear in another controller's
scan, and btmgmt info still reports "advertising" in current settings.

Enable instance 0x00 directly in that case, the way reenable_adv_sync()
already does for the same situation. Instances continue to go through
hci_schedule_adv_instance_sync() so the software rotation loop is
rearmed.

This affects every caller of hci_resume_advertising_sync(), not only the
scan path: address resolution changes, accept list updates, discovery
stop, suspend/resume and the end of an LE connection attempt all leave
advertising disabled on such a controller today.

The resume does nothing when the controller is already advertising, as
it is after directed advertising was started for a peripheral
connection, so it does not replace that advertising.

err is initialised because the extended branch leaves it unset when
adv_instances is empty and HCI_LE_ADV_0 is clear.

Fixes: ad383c2c65 ("Bluetooth: hci_sync: Enable advertising when LL privacy is enabled")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5.5 btmon
Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:01 -05:00
Binbin Deng
4335849380 Bluetooth: hci_core: Initialize LTK before publication
hci_add_ltk() publishes a newly allocated LTK on hdev->long_term_keys
before initializing its address, type, value, authentication state,
encryption size, EDIV, and random value.  hci_find_ltk() and the debugfs
long_term_keys_show() traverse this list under RCU and can therefore see
a zero or partially initialized key before those stores complete.

The race is reachable by racing an LTK addition with another CPU looking
up or dumping long-term keys.  For example, userspace can issue
MGMT_OP_LOAD_LONG_TERM_KEYS while another process reads the corresponding
debugfs file.

Initialize all fields of a new LTK before list_add_rcu() makes it visible
to RCU readers.  Existing LTKs remain published and continue to be updated
in place.

Found during a static-analysis-assisted audit: candidate sites were
surfaced by a Coccinelle rule, and the reader/writer paths were
confirmed by LLM-assisted (GLM-5.3) code inspection.  The issue was
not observed at runtime; it is identified by code inspection only.

Fixes: 970d0f1b28 ("Bluetooth: Convert LTK list to RCU")
Assisted-by: GLM-5.3 coccinelle
Signed-off-by: Binbin Deng <18983559317@163.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:00 -05:00
Binbin Deng
ae9c8df1ff Bluetooth: hci_core: Initialize link key before publication
hci_add_link_key() allocates a new link key with kzalloc(), inserts it into
hdev->link_keys with list_add_rcu(), and only then initializes its address,
value, type, and PIN length.  RCU readers such as hci_find_link_key()
and the debugfs link_keys_show() do not take hci_dev_lock, so they can
traverse the new entry during that initialization window and observe
a zero or partially initialized key.

This can be triggered by racing a link-key update with another CPU looking
up or dumping keys.  In particular, userspace can issue
MGMT_OP_LOAD_LINK_KEYS while another process reads the corresponding
debugfs file.

Complete all fields of a newly allocated key before publishing it with
list_add_rcu().  Existing keys remain visible and keep their current
in-place update behavior.

Found during a static-analysis-assisted audit: candidate sites were
surfaced by a Coccinelle rule, and the reader/writer paths were
confirmed by LLM-assisted (GLM-5.3) code inspection.  The issue was
not observed at runtime; it is identified by code inspection only.

Fixes: 0378b59770 ("Bluetooth: Convert link keys list to use RCU")
Signed-off-by: Binbin Deng <18983559317@163.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:00 -05:00
Binbin Deng
f0cf5a24ce Bluetooth: hci_core: Initialize IRK before publication
hci_add_irk() initializes the identity address and address type of a newly
allocated IRK, publishes it on hdev->identity_resolving_keys, and only then
initializes its value and RPA.  RCU readers such as hci_find_irk_by_rpa()
and the debugfs identity_resolving_keys_show() can traverse the new entry
during that window and see a zero or partially initialized IRK.

The race is reachable by racing an IRK addition with another CPU resolving
or dumping IRKs.  In particular, userspace can issue MGMT_OP_LOAD_IRKS
while another process reads the corresponding debugfs file or triggers RPA
resolution.

Initialize the IRK value and RPA before publishing a newly allocated IRK.
Existing IRKs remain published and continue to be updated in place.

Found during a static-analysis-assisted audit: candidate sites were
surfaced by a Coccinelle rule, and the reader/writer paths were
confirmed by LLM-assisted (GLM-5.3) code inspection.  The issue was
not observed at runtime; it is identified by code inspection only.

Fixes: adae20cb2d ("Bluetooth: Convert IRK list to RCU")
Assisted-by: GLM-5.3 coccinelle
Signed-off-by: Binbin Deng <18983559317@163.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:00 -05:00
Luiz Augusto von Dentz
fb1baa000d Bluetooth: hci_sync: Fix invalid Supervision_Timeout in LE Set Default Rate
The LE Set Default Rate Parameters command is rejected with Invalid HCI
Command Parameters (0x12) because the Supervision_Timeout of 120 ms is
exactly the minimum recommended by HOGP v1.2:

  Greater than or equal to (1 + Peripheral Latency) x Subrate max x
  Connection Interval max x 2

But the Core spec treats the equality as invalid:

BLUETOOTH CORE SPECIFICATION Version 6.3 | Vol 4, Part E
7.8.158. LE Set Default Rate Parameters command

  If Connection_Interval_Max x Subrate_Max x (Max_Latency + 1) is
  greater than or equal to Supervision_Timeout x 40, the Controller
  shall return the error code Invalid HCI Command Parameters (0x12).

With the current values 0x78 x 4 x 1 = 480 >= 0x0c x 40 = 480.

Fix this by using 2 s as the default Supervision_Timeout, which is 10x
lower than the 20 s used for non-SCI connections while still well above
the minimum required, and make sure it remains above the minimum in
case interval_max is raised to match the controller's minimum supported
connection interval.

Fixes: 2f8784cfe8 ("Bluetooth: Add support for Shorter Connection Interval (SCI) feature")
Assisted-by: OpenCode:claude-opus-5.5
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-11-02 17:09:00 -05:00
Yingjie Wang
c3e67bd82b ipv6: reject wrapped temporary address preferred lifetimes
ipv6_create_tempaddr() raises a temporary address's preferred lifetime to
regen_advance + age + 1 when the configured lifetime is too short. The
result is stored in a u32, while regen_advance and age are unsigned long.
If the sum wraps or is truncated, the stored lifetime can still be less
than or equal to regen_advance + age.

addrconf_verify_rtnl() then sees the new address as due for regeneration
and creates another one. Temporary addresses are not limited by
max_addresses since commit 4b08a8f1bd ("ipv6: remove max_addresses
check from ipv6_create_tempaddr"), so this can cause unbounded address
growth. With dad_transmits set to -1, a baseline kernel reached 2859
loopback addresses in two seconds.

After storing the adjusted lifetime, verify that it is still greater than
regen_advance + age. Reject the new address if the check fails.

On an x86-64 KASAN kernel, the normal configuration created three IPv6
addresses. The negative dad_transmits, positive multiplication overflow,
and large retransmission-time cases each left only the loopback and public
addresses. An i386 defconfig and an x86-64 allmodconfig both built
addrconf.o with W=1.

Fixes: f4bcbf360a ("net: ipv6/addrconf: clamp preferred_lft to the minimum required")
Cc: stable@vger.kernel.org
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Link: https://lore.kernel.org/netdev/20261029175827.GA1411453@shredder/
Signed-off-by: Yingjie Wang <1075151112@qq.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Alex Henrie <alexhenrie24@gmail.com>
Link: https://patch.msgid.link/tencent_7A270291DDE5CD89DAFFE8A745D094D5BD06@qq.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 22:31:32 +01:00
Eric Dumazet
3ae20e4697 inet: frags: limit the truesize of a reassembly queue
The truesize of fragments in a reassembly queue is only bounded by
the per netns ipfrag_high_thresh sysctl, which has no upper limit.

inet_frag_reasm_finish() sums the truesize of all fragments in an int.
If this sum reaches 2^32, it wraps, and the final sk_wmem_alloc
adjustment of the socket owning the reassembled skb can cancel its own
reference, leading to a use-after-free of this socket.

This can be triggered from an unprivileged user/network namespace,
raising ipfrag_high_thresh and using padded TUN packets, which keep
a large truesize after being trimmed by ip_rcv_core().

Track the sum of the truesize of fragments in each queue, and refuse
a fragment that would make it bigger than INT_MAX / 2. Callers kill
the queue on this error. This bound is far above the needs of
legitimate traffic.

Fixes: 18685451fc ("inet: inet_defrag: prevent sk release while still in use")
Cc: stable@vger.kernel.org
Reported-by: Kyle Zeng <kylebot@openai.com>
Cc: Florian Westphal <fw@strlen.de>
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Tested-by: Wang Zhan <wang.zhan@smartx.com>
Link: https://patch.msgid.link/20261030081225.2575462-1-edumazet@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 22:00:27 +01:00
Alexei Starovoitov
29f85bba33
Merge branch 'bpf-fix-the-stack-buffer-that-bpf_dynptr_slice_rdwr-returns'
Alexei Starovoitov says:

====================
bpf: Fix the stack buffer that bpf_dynptr_slice_rdwr() returns

From: Alexei Starovoitov <ast@kernel.org>

bpf_dynptr_slice_rdwr() and bpf_dynptr_slice() can return the buffer. When
the buffer is on the stack, the prog has two pointers to the same stack
slot, and the verifier knows only one of them. A store through the slice
changes data that the verifier tracks in the slot: a known scalar, a
spilled pointer, a dynptr, an iterator. Such a prog loads today and can
crash the kernel. A load through the slice reads such data as a scalar.

Patch 1 invalidates the slice when the prog stores to the buffer, or when
the frame of the buffer returns. Patch 2 has the tests.

The selftests that pass a stack buffer to the kfuncs only read the buffer
after the call. They load as before, with the same number of processed
insns. Cilium and sched-ext/scx do not use the kfuncs. test_progs and
test_verifier have no new failure.

v1 -> v2:
 - Read-only slices of bpf_dynptr_slice() follow the same rule (Sashiko).
 - Tests for read-only slices, one of them with a file dynptr. The progs
   end with a load through the slice.
 - Shorter tests: a macro for the callees, less in the run-time test.

v1: https://lore.kernel.org/bpf/20261102055543.3584718-1-alexei.starovoitov@gmail.com/

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261102170958.3586893-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 20:26:02 +00:00
Alexei Starovoitov
c820e6f70d
selftests/bpf: Test writes to the buffer of bpf_dynptr_slice_rdwr()
bpf_dynptr_slice_rdwr() and bpf_dynptr_slice() can return the buffer. When
the buffer is on the stack, a store to the buffer invalidates the slice.
See "bpf: Invalidate a dynptr slice when its stack buffer is written".

dynptr_fail.c gets short progs with skb, xdp and file dynptrs. They cover
the events that invalidate a slice, the borders of the buffer, a copy of
the slice on the stack and in a caller, pruning, read-only slices, and
events that leave the slice valid. They end with a load through the slice
and are only loaded.

test_dynptr_skb_slice_rdwr_buffer in dynptr_success.c runs on a non-linear
skb. It shows that the slice is the buffer, and that the pattern of the
documentation continues to work. It passes without the fix too.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102170958.3586893-3-alexei.starovoitov@gmail.com
2026-11-02 20:26:01 +00:00
Alexei Starovoitov
51f6627d44
bpf: Invalidate a dynptr slice when its stack buffer is written
bpf_dynptr_slice(&ptr, off, buffer, size) and bpf_dynptr_slice_rdwr()
return a pointer to the data of a dynptr. When the data is not contiguous,
for example in a non-linear skb, they copy it to 'buffer' and return
'buffer'. Usually the buffer is on the stack. For the verifier the result
is plain memory (PTR_TO_MEM), and an access through it is not an access to
the stack:
 - A store makes wrong what the verifier tracks in the buffer: a known
   scalar, a spilled pointer, a dynptr, an iterator, irq flags.
 - A load gives the bytes of a spilled pointer or of a dynptr as a scalar.
 - Both are possible after the frame of the buffer returned.

The accesses are safe while the buffer contains only unknown bytes, as it
does after the call. Thus keep this rule: the buffer contains no tracked
data while a slice that can be the buffer exists. The slice remembers the
frame, the offset and the size of its buffer. The verifier invalidates the
slice, read-only or not, at each event that breaks the rule:

  event                                              slices of the buffer
  -------------------------------------------------  --------------------
  the prog stores to bytes of the buffer             invalid
  a dynptr, an iterator or irq flags are made there  invalid
  the frame of the buffer returns                    invalid
  a helper or a kfunc fills the buffer               no change
  a store next to the buffer, a read of the buffer   no change

Tracked data gets into a stack slot in check_stack_write(), also the bytes
of a new dynptr, iterator or irq flags. Thus one call there, and one call
in prepare_func_exit(), are sufficient. Each is one walk over the
registers, only in progs that have such a slice. Helpers and kfuncs leave
only unknown bytes: mark_raw_stack() goes around check_stack_write().

The range of the buffer is in the part of bpf_reg_state that the verifier
copies with the register and compares for pruning. A slice that is the
buffer of a second call passes its range on. Local, ringbuf and skb
metadata dynptrs never return the buffer: no range. A dynptr argument of a
global function counts as an skb dynptr.

The usual pattern only reads the buffer, and it continues to load:

  if (p == buffer)
          bpf_dynptr_write(&ptr, 0, buffer, sizeof(buffer), 0);

A prog that stores to the buffer and then uses the old slice is rejected:
"R7 invalid mem access 'scalar'". The diagnostics name the reason, and the
log shows the buffer of a slice: R7=mem(sz=8,buf=fp[0]-8+8).

Fixes: 66e3a13e7c ("bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102170958.3586893-2-alexei.starovoitov@gmail.com
2026-11-02 20:26:01 +00:00
Amirmohammad Eftekhar
d21eef2084 KVM: VMX: Add array_index_nospec() to evmcs_field_offset()
evmcs_field_offset() bounds-checks the guest-supplied field index against
nr_evmcs_1_fields and then indexes vmcs_field_to_evmcs_1[] without an
array_index_nospec() clamp, unlike its vmcs12 counterpart
get_vmcs12_field_offset().

A regular VMREAD instruction is allowed while an enlightened VMCS is active
since 6cbbaab60f ("KVM: nVMX: Allow VMREAD when Enlightened VMCS is in
use"), and it reaches evmcs_field_offset() with a guest-supplied field
encoding. But because the index is not clamped, the guest may be able to
speculatively access past the bound check and read out of bounds of
vmcs_field_to_evmcs_1[] (Spectre v1). The leaked value is only the u16
'offset', so the exposure is limited.

The other callers of evmcs_field_offset() are not under direct guest
control, but the array_index_nospec() clamp does not hurt them.

Clamp the index with array_index_nospec(), mirroring
get_vmcs12_field_offset().

Fixes: 6cbbaab60f ("KVM: nVMX: Allow VMREAD when Enlightened VMCS is in use")
Signed-off-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
Message-ID: <20261031090529.65240-1-amirmohammad.eftekhar@cispa.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 13:15:45 -05:00
Alexei Starovoitov
8ed2506a7c
Merge branch 'bpf-fix-two-holes-in-the-analysis-of-stack-arguments'
Alexei Starovoitov says:

====================
bpf: Fix two holes in the analysis of stack arguments

From: Alexei Starovoitov <ast@kernel.org>

Before the main pass, arg_track follows pointers to the stack through
registers and spills. For each insn it tells which slots the insn can read,
which slots it can write, and which slot it writes for certain. Scalar
evolution and the removal of dead slots rely on the answer.

In two cases a store to other memory counts as a certain write to a stack
slot. Then scalar evolution misses a real write to the counter of a loop,
and a prog that accesses a map value out of bounds loads.

  patch 1   "r10, or not a pointer to the stack" counts as "exactly r10".
  patch 3   A call does not change what is known about the pointers that
            are spilled in the frame of the caller. But a static subprog or
            a callback can replace such a pointer with a pointer to a map
            value. Valid progs are rejected too.

Patches 2 and 4 are the tests. Patch 3 needs patch 1 for a spilled copy of
r10.

v1 -> v2:
- One series. v1 was two series [1] [2], and CI applied [2] without [1]
- Rebase on the bpf tree: patch 2 did not apply
- Test a callee that overwrites a spilled copy of r10: the case in which
  patch 3 needs patch 1 (CI bot)
- Change the two tests that match the log in patch 3, not in patch 4: they
  failed in between
- Load the test with a callback only when progs are JITed
- Make the tests shorter. None of them is in verifier_scev.c now
- Patch 1: the example in the log stores a pointer to a map value, as the
  test does. With 0 the prog does not load

[1] https://lore.kernel.org/bpf/20261031220615.804426-1-alexei.starovoitov@gmail.com/
[2] https://lore.kernel.org/bpf/20261101004657.3406576-1-alexei.starovoitov@gmail.com/

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261102055913.3598414-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 17:53:15 +00:00
Alexei Starovoitov
c9a45b2ede
selftests/bpf: Test a callee that overwrites a spilled pointer of its caller
The caller spills &fp[-8] to fp-16 and passes a pointer to another slot of
its frame to a callee, which stores a pointer to a map value to fp-16. The
caller fills fp-16 and stores through it. That store is not a certain write
to fp-8.

Three valid progs read fp-8 after the store. The callee is a static subprog
or a callback of bpf_loop(). In callee_overwrites_spilled_r10 the slot
holds a copy of r10. That prog also needs "bpf: Fix the join of fp+0 with
a value that is not a pointer to stack". Without the fix they fail with:

  reading from stack off -8+0 size 8, slot poisoned by dead code elimination

In callee_overwrites_spilled_fp_hidden_store the store hides a write to the
counter of a loop. Without the fix the prog loads, and it accesses a map
value out of bounds.

The test for callx checks the spilled pointer in the log.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102055913.3598414-5-alexei.starovoitov@gmail.com
2026-11-02 17:53:14 +00:00
Alexei Starovoitov
cdefba74b5
bpf: Don't trust pointers spilled in slots that a callee can write
arg_track follows pointers to the stack through registers and spills.
Scalar evolution and the removal of dead slots rely on it to know which
slots an insn reads and writes.

arg_track assumes that a call does not change the pointers that are spilled
in the frame of the caller. But a static subprog or a callback can store
a pointer to other memory there, and the caller can use it:

  *(u64 *)(r10 - 16) = fp-8
  r1 = fp-16, r2 = map_value
  call sub                        ; *(u64 *)(r1 + 0) = r2
  r7 = *(u64 *)(r10 - 16)         ; verifier: map_value. arg_track: fp-8
  *(u64 *)(r10 - 8) = fp-24
  *(u64 *)(r7 + 0) = 0            ; arg_track: fp-8 is overwritten
  r8 = *(u64 *)(r10 - 8)          ; verifier: fp-24. arg_track: none
  loop:
    r1 = *(u64 *)(r10 - 24)       ; the counter of the loop
    ...
    *(u64 *)(r8 + 0) = 4096       ; arg_track: not a write to fp-24

Scalar evolution does not see the last store. It gives the counter the
range of a loop that only increments it. The prog loads, and it accesses
a map value out of bounds.

Valid progs are rejected as well. The store through r7 makes fp-8 dead, and
a later read of fp-8 fails with "slot poisoned by dead code elimination".

When a static subprog or a callback can get a pointer to the frame of its
caller, join every slot of that frame with "not a pointer to the stack".
Reads and possible writes through a filled pointer are still seen, but no
store through it is a certain write. It has to be every slot: the callee
reaches the whole frame from one pointer, and callees are analyzed after
the caller. The price is precision: an 8-byte load through a filled
pointer gives a value that can point to any frame.

For a spilled copy of r10 this needs "bpf: Fix the join of fp+0 with
a value that is not a pointer to stack".

In selftests, Cilium and sched_ext the stack marks change in 4 of 12522
progs. Verdicts, insns and states do not change in any prog.

one_fp_clear_stack_threshold and two_fp_clear_stack_threshold expect the
fake offset fp+0 in the log now.

Fixes: bf0c571f7f ("bpf: introduce forward arg-tracking dataflow analysis")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102055913.3598414-4-alexei.starovoitov@gmail.com
2026-11-02 17:53:14 +00:00
Alexei Starovoitov
27f0738d34
selftests/bpf: Test the join of fp+0 with a value that is not a pointer to stack
A register is r10 on one path and a pointer to a map value on the other
path. A store through it is not a certain write to the stack.

join_of_r10_and_map_value is a valid prog. It reads the slots after the
stores. The join has one branch for "pointer to stack joins other value"
and one branch for the reverse order. The prog has one register for each
order, and it checks in the log that it takes both branches. Without the
fix the slots are dead in front of the stores, and the verifier rejects
the read:

  reading from stack off -8+0 size 8, slot poisoned by dead code elimination

In join_of_r10_and_map_value_hidden_store the slot holds a pointer to the
counter of a loop. Without the fix the pointer is lost, and scalar
evolution does not see the store through it. The prog loads, and it
accesses a map value out of bounds.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102055913.3598414-3-alexei.starovoitov@gmail.com
2026-11-02 17:53:14 +00:00
Alexei Starovoitov
6185d4fc6e
bpf: Fix the join of fp+0 with a value that is not a pointer to stack
arg_track follows pointers to the stack through registers and spills.
Scalar evolution and the removal of dead slots rely on it to know which
slots an insn reads and writes.

Where two paths meet, a register can be fp-N on one path and not a pointer
to the stack on the other path. There is no value for that. The join adds
a fake second offset, fp+0: with two offsets no store through the register
is a certain write. But for fp+0 the fake offset is the offset itself:

  join(fp-8, none) = {fp-8, fp+0}    two offsets
  join(fp+0, none) = {fp+0}          one offset: "exactly fp+0"

Then a store counts as a certain write to the stack, but at run time it can
go to other memory:

  r7 = r10, or r7 = map_value + 8 ; arg_track: exactly fp+0
  *(u64 *)(r10 - 8) = fp-24
  *(u64 *)(r7 - 8) = map_value    ; arg_track: fp-8 is overwritten
  r8 = *(u64 *)(r10 - 8)          ; fp-24 or map_value. arg_track: none
  loop:
    r1 = *(u64 *)(r10 - 24)       ; the counter of the loop
    ...
    *(u64 *)(r8 + 0) = 4096       ; arg_track: not a write to fp-24

Scalar evolution does not see the last store. It gives the counter the
range of a loop that only increments it. The prog loads, and it accesses
a map value out of bounds.

Valid progs are rejected as well. The store through r7 makes fp-8 dead, and
a later read of fp-8 fails with "slot poisoned by dead code elimination".

When the single offset is 0, drop the offsets. The result is a pointer to
an unknown slot of the frame, and all updates through it are weak.

Veristat sees no difference in selftests, Cilium and sched_ext.

Fixes: bf0c571f7f ("bpf: introduce forward arg-tracking dataflow analysis")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102055913.3598414-2-alexei.starovoitov@gmail.com
2026-11-02 17:53:14 +00:00
Sean Christopherson
0cb8f16f88 KVM: x86: Flush guest TLB when emulating a RESET to strictly honor the spec
Flush the guest TLB when emulating a RESET even though such a flush should
be completely unnecessary since KVM only performs a RESET when creating a
vCPU, and so it should be impossible for the vCPU to have any accrued TLB
state.  Making the flush unconditional aligns KVM's behavior with both the
SDM and APM (ignoring that both specifications contradict themselves), and
avoids having to worry about hypotheticals like "what if KVM did provide a
way to emulate RESET after a vCPU is created?".

Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261022015407.279870-3-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:49:57 -05:00
Sean Christopherson
c7c288d178 KVM: x86: Unconditionally reset MMU context when emulating INIT
Force an MMU reset when emulating an INIT even if paging was already
disabled, as the MMU page role includes guest_mode (L2), i.e. an INIT while
L2 is running with CR0.PG=0 will result in KVM running L1 with a stale MMU
context.

Alternatively, the reset could be scoped strictly to paging being enabled
or L2 being active, but SMM is also encoded in the page role.  Even though
it _should_ be impossible for the vCPU to be INIT'd while SMM is active,
there's zero value in not handling SMM.  At that point, the only scenario
where KVM _doesn't_ need to reset the MMU context is on an INIT with the
vCPU running in Real Mode or Unpaged Protect Mode, and while INIT in those
modes is somewhat common, it's far from a hot path and re-initializing the
MMU is not expensive, especially when the role isn't changing (KVM elides
most of the re-configuration in that case).

Note, like the Fixes commit, this bug only affects nested SVM as INIT is an
unconditional intercept on VMX, i.e. it's impossible to emulate INIT while
L2 is active.

Temporarily keep the guest TLB flush when CR0.PG is being cleared even
though it is fully redundant with the flush that is emitted on all INIT
events (KVM itself only does RESET when a vCPU is being created, i.e. when
CR0.PG must be '0').

Fixes: ed129ec905 ("KVM: x86: forcibly leave nested mode on vCPU reset")
Reported-by: Stefan Teodorescu <fane@google.com>
Reported-by: Oren Yomtov <thenameisoren@gmail.com>
Reported-by: Chris Mason <mason@kernel.org>
Cc: stable@vger.kernel.org
Cc: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261022015407.279870-2-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:49:51 -05:00
Sean Christopherson
e4558c3d71 KVM: x86/mmu: Cap number of parent PTEs per SP at 1000 (the arbitrary rmap limit)
When potentially reusing a shadow page, zap the shadow page if its number
of parent PTEs exceeds KVM's (mostly) arbitrary rmap recycling threshold.
Letting the guest create a (mostly) unbounded number of parent PTEs allows
the guest to coerce KVM into creating lists containing millions of PTEs,
effectively bounded only by the maximum number of shadow pages.

Because PTE lists are simple singly linked lists, removal is O(n).  Even
worse, if a list is constructed just so, teardown can be O(n^2), e.g. if
SPTEs are built such that zapping child SPTEs always zaps the last entry
in the list.  To cap things off, all paths that walk PTE lists do so
while holding mmu_lock, without conditionally rescheduling.

Using a doubly linked list would not address the issue, as removal would
remain O(n) since KVM still wouldn't know where in the list to remove from.
Removal could be made O(1) by storing a per-SPTE pointer, but that would
largely defeat the purpose of reusing SPs, and would penalize well-behaved
guests, especially for nested TDP where aliasing page tables is uncommon.

So, cap the maximum number of parent PTEs at the rmap limit.  In practice,
well-behaved guests will likely never run afoul of the limit.  E.g. when
running Linux as L1 with TDP, the number of parent PTEs for a single SP
tops out at under 200 (though undoubtedly obscure workloads can push it
higher).  Deliberately use a "greater than or equal" as opposed to rmap's
strictly "greater than", as the rmap code checks the threshold immediately
*after* inserting into the list, i.e. the limit is 1000 for rmaps, KVM just
very briefly blows past it.

Apply the check to both indirect and direct SPs, because while a fully
direct MMU naturally limits the number of parent PTEs to '1', direct SPs in
indirect MMUs have no such constraint.  E.g. if the guest maps a huge PTE
into many locations in its page tables, and KVM is backing the hugepage
with a direct SP, i.e. with a series of smaller pages, then KVM could end
up with a direct SP with many parents.

Note, shadow_mmu_try_split_huge_pages() always restarts the rmap walk or
bails entirely if it gets to the point where it tries to grab a SP, i.e.
there is *no* pre-existing bug that would be tripped by zapping a SP and
thus rmaps when getting a SP.

Cc: Jim Mattson <jmattson@google.com>
Cc: James Houghton <jthoughton@google.com>
Cc: Yosry Ahmed <yosry@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: stable@vger.kernel.org
Reported-by: Stefan Teodorescu <fane@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261027171518.1432557-1-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:49:28 -05:00
Sean Christopherson
c33ef9d334 KVM: nVMX: Process each host MSR entry at most once when unwinding failed VM-Entry
Add a missing "break" in the inner for-loop of the open coded mess that
unwinds MSRs back to the pre-VM-Enter state when VMLAUNCH/VMRESUME VM-Fails
due to a consistency check that is caught by hardware but missed by KVM.
I.e. move on to the next MSR in the VM-Entry load list after performing a
write using a value found in the VM-Exit load list.  Processing *every*
matching entry in the VM-Exit load list makes the processing quadratic,
which is problematic if the load lists are full of MSRs that are expensive
to emulate.  E.g. writing APIC_BASE triggers kvm_recalculate_apic_map() and
a whole pile of unnecessary work.

Functionally, arbitrarily restoring the value of the first matching entry
is "fine", because none of this is architecturally correct: the load lists
are never supposed to have been used in the first place.  In practice, it's
likely a moot point as no well-behaved VMM will have multiple, diverging
entries in the load lists.

Fixes: bd18bffca3 ("KVM: nVMX: restore host state in nested_vmx_vmexit for VMFail")
Cc: stable@vger.kernel.org
Cc: David Woodhouse <dwmw2@infradead.org>
Reported-by: Stefan Teodorescu <fane@google.com>
Suggested-by: Stefan Teodorescu <fane@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261027185917.1478906-1-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:49:18 -05:00
Sean Christopherson
ae85ac25eb KVM: x86: Conditionally resched when restarting REP string emulation
When restarting emulation, e.g. of a REP-prefixed string instruction,
conditionally reschedule as emulating guest writes can be deceptively slow
and expensive, e.g. when shadow paging is in use and each write can trigger
write tracking.

In a perfect world, restarting emulation (or not) would be less arbitrary,
e.g. would honor not only host events (NEED_RESCHED, signals, etc.) but
also guest events (e.g. by checking kvm_vcpu_has_events()).  Unfortunately,
as pointed out by Sashiko, pio_in_emulated()'s read-ahead logic is baked
into the restart logic, as KVM relies on restarting emulation to drain the
cache and avoid duplicate reads from the I/O port.  I.e. re-entering the
guest on kvm_vcpu_has_events() or __xfer_to_guest_mode_work_pending() would
introduce architecturally-incorrect, guest-visible changes.

Fixes: 5cd21917da ("KVM: x86 emulator: restart string instruction without going back to a guest.")
Cc: stable@vger.kernel.org
Cc: David Woodhouse <dwmw2@infradead.org>
Reported-by: Stefan Teodorescu <fane@google.com>
Suggested-by: Stefan Teodorescu <fane@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261028173638.1765329-1-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:48:51 -05:00
Sean Christopherson
b2691b3a6c KVM: x86/mmu: Conditionally resched when retrying gPTE walk on A/D update failure
Conditionally reschedule when retrying a guest PTE walk because the CMPXCHG
to update A/D bits failed, e.g. because a different task/vCPU modified the
relevant gPTEs.  On kernels without involuntary preemption of some kind, a
misbehaving guest can "capture" a pCPU effectively indefinitely and trigger
soft lockups by continuously modifying its gPTEs such that the result of
the walk is remains valid.

Fixes: b3e4e63fd9 ("KVM: MMU: Use cmpxchg for pte updates on walk_addr()")
Cc: stable@vger.kernel.org
Reported-by: Stefan Teodorescu <fane@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261022015903.282261-1-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:48:39 -05:00
Sean Christopherson
053621535f KVM: nSVM: Check validity of vmcs01 save area copied from SMRAM on RSM
When doing RSM to L2, validate L1's state after copying it back into vmcb01
from SMRAM, as SMRAM is carved out of guest memory, i.e. is writable by the
guest.  Failure to validate L1's state is especially problematic for inputs
to MMU context, as KVM can end up with impossible CR4 vs. EFER state.  E.g.
without the recent hardening FNAME(walk_addr_generic), a guest can trigger:

  ------------[ cut here ]------------
  UBSAN: array-index-out-of-bounds in arch/x86/kvm/mmu/paging_tmpl.h:435:15
  index 3 is out of range for type 'u32 [2]'
  CPU: 3 UID: 0 PID: 92 Comm: CPU 1/KVM Not tainted 7.3.0-rc1 #2 PREEMPT(lazy)
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x5f/0x90
   dump_stack+0x10/0x18
   ubsan_epilogue+0x9/0x39
   __ubsan_handle_out_of_bounds.cold+0x50/0x55
   paging32_walk_addr_generic+0x889/0x970
   paging32_page_fault+0x79/0xa60
   kvm_mmu_do_page_fault+0x125/0x270
   kvm_mmu_page_fault+0x88/0x7b0
   npf_interception+0xc8/0x220 [kvm_amd]
   svm_invoke_exit_handler+0x16d/0x1d0 [kvm_amd]
   svm_handle_exit+0xb7/0x160 [kvm_amd]
   vcpu_enter_guest+0x428/0x16a0
   kvm_arch_vcpu_ioctl_run+0x479/0x920
   kvm_vcpu_ioctl+0x316/0xb00
   __x64_sys_ioctl+0xa3/0x100
   x64_sys_call+0x281/0x23d0
   do_syscall_64+0xba/0x550
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
  RIP: 0033:0x79bb30deb04b
   </TASK>
  ---[ end trace ]---

Fixes: 37be407b2c ("KVM: nSVM: Fix L1 state corruption upon return from SMM")
Cc: stable@vger.kernel.org
Reported-by: Bill Wendling <morbo@google.com>
Reported-by: Stefan Teodorescu <fane@google.com>
Tested-by: Stefan Teodorescu <fane@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20261022021046.295001-1-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-11-02 12:48:36 -05:00
Alexei Starovoitov
03b0138974
Merge branch 'bpf-follow-ups-for-the-arena-mmap-fixes'
Alexei Starovoitov says:

====================
bpf: Follow-ups for the arena mmap() fixes

From: Alexei Starovoitov <ast@kernel.org>

Two follow-ups for the arena patches of the series
"bpf: Fixes for the verifier, arena, skb and lwt helpers", merge
commit 714b711201. They answer review comments on that series.

Commit ca580b0343 ("bpf: Refuse to map an arena at address 0") tests for
address 0 in front of round_up(), and round_up() can wrap to 0. Patch 1
does not move a MAP_FIXED address at all. Patch 2 makes arena_mmap serial,
as the other arena tests are, and adds subtests for patch 1.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261102064231.2153879-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 16:22:44 +00:00
Alexei Starovoitov
c08b50dd17
selftests/bpf: Run arena_mmap serially and test MAP_FIXED addresses
Each arena reserves 4 GiB of vmalloc space. The KASAN shadow of arenas from
parallel tests can exhaust the memory of a CI VM. Thus commit a14f9ba080
("selftests/bpf: Run arena tests serially") made arena_* and libarena*
serial. Do the same for arena_mmap, which the commit below added later.

Add four subtests for "bpf: Don't move a MAP_FIXED address in
arena_get_unmapped_area()". Test that mmap() with MAP_FIXED or
MAP_FIXED_NOREPLACE fails with EINVAL if the range crosses a 4 GiB
boundary. Test that mmap() with MAP_FIXED also fails for a range that wraps
and for a map_extra range that ends above TASK_SIZE. Today
arena_map_alloc() accepts such a map_extra. map_extra_last_pages also
passes if the kernel refuses the map, because no task can map this range.

The arch code gets a range before the arena code tests it for a crossing.
For the last two ranges LoongArch returns -EINVAL, and powerpc with the
hash MMU returns -ENOMEM. There the two subtests do not reach that test. On
the other architectures with arenas, the arena code returns -EINVAL or
__get_unmapped_area() returns -ENOMEM. Thus the two subtests accept both
errnos. All these errors occur before mmap() changes a mapping.

Two other changes of that patch have no subtest. With MAP_FIXED the arch
code gets len and not 2 * len. A 64-bit task on x86, arm64 or riscv does
not see this. LoongArch, s390 and powerpc with the hash MMU compare the end
of the range with different limits. In arena_mmap the unsigned ret changes
only the errno of map_extra_last_pages, which accepts both.

Fixes: 14d3e5bf9f ("selftests/bpf: Test the length and the address of an arena mmap()")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102064231.2153879-3-alexei.starovoitov@gmail.com
2026-11-02 16:22:43 +00:00
Alexei Starovoitov
92b5ce3ca5
bpf: Don't move a MAP_FIXED address in arena_get_unmapped_area()
The user range of an arena must not cross a 4 GiB boundary. Thus
arena_get_unmapped_area() asks the mm for 2 * len bytes and rounds the
result up if necessary. This is correct only if the mm finds a free range.
With MAP_FIXED the mm does no search and returns addr. For
MAP_FIXED_NOREPLACE, do_mmap() also sets MAP_FIXED.

With MAP_FIXED the arena is not at addr after round_up(). Thus mmap()
removes mappings outside the range from addr to addr + len. It keeps a part
of those in this range. Also, round_up() can wrap to address 0, and the
test for address 0 is before it.

The arch code gets twice the length of the mapping. Thus it can refuse a
valid MAP_FIXED range. On s390 the arch code also grows the page table for
the range. With the double length it can omit this step for a valid range.

The test for a crossing is not exact. Because ret is a long, ret >> 32
extends the sign, but the other side is unsigned. The sides are never equal
for an address with bit 63 set, and round_up() always runs. Such user
addresses exist on s390. arena_map_alloc() does the same test with a u64.

With MAP_FIXED, pass len to the mm. Return -EINVAL if the range crosses a
boundary, as for address 0. Make ret unsigned, so that only these ranges
get the error. On x86-64, if round_up() gives address 0 today, mmap() now
fails with -EINVAL or with -ENOMEM from the mm. Today mmap() can also fail
for the address after round_up(), for example with -ENOMEM, -EEXIST, -EPERM
or -EBUSY.

Without MAP_FIXED the mm must still find a free range of 2 * len bytes
inside the address space of the task. The range after round_up() is inside
it, and round_up() cannot wrap. An address with bit 63 set now moves only
if its range crosses a boundary.

For an arena, libbpf uses MAP_FIXED only with map_extra, and
arena_map_alloc() refuses a map_extra range that crosses a boundary. A
subsequent mmap() must use the range of the first mmap(). For mmap() of the
map fd, this range comes from arena_get_unmapped_area(), thus it crosses no
boundary. arena_map_alloc() still accepts a map_extra above TASK_SIZE, and
mmap() of such an arena fails.

Fixes: 317460317a ("bpf: Introduce bpf_arena.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261102064231.2153879-2-alexei.starovoitov@gmail.com
2026-11-02 16:22:43 +00:00
Ido Schimmel
7308ef8b4a vxlan: Stop rejecting dynamic FDB entries with a nexthop ID
Commit 98fc57d167 ("vxlan: reject dynamic fdb entries that reference a
nexthop id") started rejecting FDB entries that point to FDB nexthops
unless they are configured as "permanent" or "static". The intent was to
prevent such entries from being aged out by vxlan_cleanup(), which runs
without RTNL and can therefore race with other VXLAN devices that modify
the same per-nexthop FDB list.

However, FRR installs remote MACs that are behind a multihomed Ethernet
Segment (EVPN-MH) as dynamic FDB entries that point to an FDB nexthop
group. Since the above commit, these entries are rejected and traffic
towards the corresponding MACs is flooded to all the remote VTEPs.

These entries are also marked as externally learned ("extern_learn")
and are therefore skipped by vxlan_cleanup(), but exempting externally
learned entries from the checks is not enough: vxlan_cleanup() reads
the state and flags of an entry without the hash lock, so an entry that
is concurrently changed from dynamic and externally learned to static
can still be aged out.

Instead, remove the checks added by the above commit and make
vxlan_cleanup() skip FDB entries that point to FDB nexthops. Such
entries can only be configured from user space, cannot be learned and
cannot roam, so there is no reason to age them out. The nexthop pointer
of an FDB entry is set before the entry is linked and is only cleared
after it was unlinked and an RCU grace period has passed, so it can be
checked without the hash lock.

Adjust the test cases added by the above commit and add a test case
that checks that dynamic FDB entries that point to FDB nexthops are not
aged out. Without the fix:

 # ./fib_nexthops.sh -t "ipv4_fdb_grp_fcnal ipv6_fdb_grp_fcnal"

 IPv4 fdb groups functional
 --------------------------
 [...]
 TEST: Fdb mac add with nexthop group and dynamic state              [FAIL]
 TEST: Fdb mac add with nexthop group and extern_learn               [FAIL]
 TEST: Fdb mac without nexthop group aged out                        [ OK ]
 TEST: Fdb mac with nexthop group not aged out                       [FAIL]
 [...]

 IPv6 fdb groups functional
 --------------------------
 [...]
 TEST: Fdb mac add with nexthop group and dynamic state              [FAIL]
 TEST: Fdb mac add with nexthop group and extern_learn               [FAIL]
 TEST: Fdb mac without nexthop group aged out                        [ OK ]
 TEST: Fdb mac with nexthop group not aged out                       [FAIL]
 [...]

 Tests passed:  44
 Tests failed:   6
 Tests skipped:  0

With the fix:

 # ./fib_nexthops.sh -t "ipv4_fdb_grp_fcnal ipv6_fdb_grp_fcnal"

 IPv4 fdb groups functional
 --------------------------
 [...]
 TEST: Fdb mac add with nexthop group and dynamic state              [ OK ]
 TEST: Fdb mac add with nexthop group and extern_learn               [ OK ]
 TEST: Fdb mac without nexthop group aged out                        [ OK ]
 TEST: Fdb mac with nexthop group not aged out                       [ OK ]
 [...]

 IPv6 fdb groups functional
 --------------------------
 [...]
 TEST: Fdb mac add with nexthop group and dynamic state              [ OK ]
 TEST: Fdb mac add with nexthop group and extern_learn               [ OK ]
 TEST: Fdb mac without nexthop group aged out                        [ OK ]
 TEST: Fdb mac with nexthop group not aged out                       [ OK ]
 [...]

 Tests passed:  50
 Tests failed:   0
 Tests skipped:  0

Fixes: 1274e1cc42 ("vxlan: ecmp support for mac fdb entries")
Fixes: 98fc57d167 ("vxlan: reject dynamic fdb entries that reference a nexthop id")
Cc: stable@vger.kernel.org
Reported-by: Sascha Frey <sf@techfak.net>
Closes: https://lore.kernel.org/netdev/20261028142928.GA8406@techfak.de/
Tested-by: Sascha Frey <sf@techfak.net>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20261030133750.28668-1-idosch@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 17:07:43 +01:00
Paolo Abeni
e55f9e70b8 Merge branch 'net-stmmac-re-apply-taprio-offload-in-__stmmac_open-and-stmmac_resume'
Lorenzo Bianconi says:

====================
net: stmmac: re-apply taprio offload in __stmmac_open() and stmmac_resume()

Reconfigure MTL_EST registers after sw reset in __stmmac_open().
Remove priv->est->enable dependency in est_configure().
Initialize est_lock at probe time.

v4: https://lore.kernel.org/r/20261026-stmmac-est-fixes-v4-0-999dac4de44f@oss.qualcomm.com
v2: https://lore.kernel.org/r/20260829-stmmac-est-reapply-after-open-v2-1-5e5ccb185e92@oss.qualcomm.com
v1: https://lore.kernel.org/r/20260825-stmmac-est-reapply-after-open-v1-1-dfa80735e0a1@oss.qualcomm.com
====================

Link: https://patch.msgid.link/20261029-stmmac-est-fixes-v5-0-85b830a795a9@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:59:45 +01:00
Lorenzo Bianconi
23d96de472 net: stmmac: re-apply taprio offload in __stmmac_open() and stmmac_resume()
The core soft reset issued by stmmac_init_dma_engine(), called from
stmmac_hw_setup(), clears the MTL_EST registers. Nothing re-applies the
taprio offload afterwards, so priv->est->enable stays true while the
hardware EST block is left disabled: taprio keeps being reported as
offloaded, the TX/XDP paths keep dropping frames larger than
priv->est->max_sdu[], and the programmed base time is stale.

Re-apply the offload from __stmmac_open() and stmmac_resume() after PTP
has been brought up. The base time is recomputed from the reserved base
time and the current PTP time, because the timestamp counter has been
re-initialised and the previously programmed base time cannot be reused.

Factor the recompute-and-program sequence into __stmmac_setup_est(),
which must be called with est_lock held, and into stmmac_setup_est(),
which takes the lock and re-applies the offload only when it is
currently enabled and PTP has been brought up. Use the same helper in
stmmac_adjust_time() so the PTP adjust path shares the base time
computation.

Only tc_taprio_configure() updates priv->est->enable: it is set when a
REPLACE succeeds and cleared on DESTROY or a programming failure. The
re-apply helpers leave it untouched, so the flag records that an offload
is installed rather than the current hardware programming state.
__stmmac_setup_est() only reprograms the EST block, and
stmmac_setup_est() replays the FPE mapping afterwards. On a failed
re-apply the open and resume callers abort, while stmmac_adjust_time()
keeps the offload configured.

The same reset also discards the FPE preemption programming, and on XGMAC
stmmac_dma_tx_mode() overwrites the queue-to-traffic-class map. Save the
preemptible traffic class mask in priv->est->pclass when a REPLACE
succeeds and replay the FPE mapping from stmmac_setup_est() as well.

Re-applying the offload is best-effort with respect to PTP:
stmmac_setup_est() does nothing when PTP was not enabled (for example
when clk_ptp_rate is 0), so a missing PTP reference clock does not by
itself fail ndo_open(). If re-applying the EST or FPE programming fails
while restoring the interface, the failure is fatal to the caller:
__stmmac_open() aborts the open, and stmmac_resume() takes the same error
path already used for a failed timestamp counter restore.

Since __stmmac_open() and stmmac_resume() now trust priv->est->enable,
also make tc_taprio_configure() consistent: hold est_lock across the
whole validate-and-program sequence, build the gate list in a temporary
buffer, and only commit it and enable EST after validation and hardware
programming succeed. A REPLACE rejected during validation then leaves the
currently installed schedule intact in both software and hardware, while
a hardware or FPE mapping failure disables EST instead of leaving a stale
enable flag behind. Reject cycle times whose seconds field would not fit
in priv->est->ctr[1].

Fixes: b60189e039 ("net: stmmac: Integrate EST with TAPRIO scheduler API")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20261029-stmmac-est-fixes-v5-3-85b830a795a9@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:59:43 +01:00
Lorenzo Bianconi
e4f5b46dfb net: stmmac: pass the desired EST enable state to est_configure()
Pass the desired EST enable state explicitly to est_configure() instead
of having it derive from cfg->enable. This decouples the hardware
programming state from the priv->est->enable flag, which records whether
the taprio offload is attached.

No functional change intended: the callers keep toggling
priv->est->enable around the EST programming, as before.

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261029-stmmac-est-fixes-v5-2-85b830a795a9@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:59:43 +01:00
Lorenzo Bianconi
98caed39c1 net: stmmac: initialize est_lock at probe time
priv->est is allocated with devm_kzalloc() on the first TAPRIO REPLACE
and priv->est_lock is initialized in the same place, which ties the
validity of the lock to whether TAPRIO has ever been configured. The
lock is also never destroyed.

Initialize priv->est_lock in __stmmac_dvr_probe() next to priv->lock
and destroy it in stmmac_dvr_remove(). This keeps the lock valid for
the entire lifetime of the device, independent of the TAPRIO state,
and removes the lazy initialization from the TAPRIO configuration
path.

No functional change intended.

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261029-stmmac-est-fixes-v5-1-85b830a795a9@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:59:43 +01:00
Joonhoe Kim
743b5c8627 net: qrtr: announce local services again once our HELLO is sent
Since commit 544d85de4d ("net: qrtr: Send HELLO message on endpoint
register"), qrtr_node_enqueue() drops every packet but HELLO with
-EAGAIN until our HELLO has gone out to the node. When the remote's
HELLO arrives first, the NEW_SERVER replies from the name service are
dropped, and so are the broadcasts for services registered before our
HELLO goes out. Nothing announces these services again, so the remote
never learns about them.

On Kaanapali the modem sends its HELLO before it accepts ours. With
rmtfs started first, the modem never learns about rmtfs and its
watchdog resets the SoC about 40 s later.

Remember that the remote has sent a HELLO. Once our HELLO has been
sent to such a node, pass a HELLO from it to the local name service
again, so that it announces the services it has at that point. Retry
the replay if it cannot be queued, and queue it under ep_lock only
while the endpoint is registered, so that it cannot follow the BYE
from qrtr_endpoint_unregister().

The flag is not cleared when qrtr_endpoint_hello() restarts the
handshake on resume, so a HELLO that the remote sent before then is
not lost. The cost is that the remote gets the same NEW_SERVER
announcements twice when its HELLO arrives before ours goes out but
the name service handles it after, and on every resume.

Fixes: 544d85de4d ("net: qrtr: Send HELLO message on endpoint register")
Cc: stable@vger.kernel.org
Tested-by: Filippo Falezza <effeffe99@gmail.com> # Motorola Moto G 5G Plus nairo (SM7250)
Signed-off-by: Joonhoe Kim <26rote@gmail.com>
Link: https://patch.msgid.link/20261029105142.2503-1-26rote@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:39:52 +01:00
Nguyen Ngoc Thang
d1cf56164d net: phy: don't require RTNL to detach a PHY from an unregistered netdev
phy_detach_internal() reads dev->hwprov with rtnl_dereference(), but
MAC drivers commonly attach and detach PHYs while their net_device is
not registered, without holding RTNL. Before register_netdev(), a failed
phylink_connect_phy() or phy_attach_direct() unwinds through
phy_detach_internal(). After unregister_netdev(), a driver's remove path
may call phy_disconnect(). Both trip lockdep:

  WARNING: suspicious RCU usage
  drivers/net/phy/phy_device.c:1831 suspicious rcu_dereference_protected() usage!
   phy_detach_internal+0x6a5/0x830 drivers/net/phy/phy_device.c:1831
   phylink_connect_phy+0x22e/0x2b0 drivers/net/phy/phylink.c:2452
   ax88772_bind+0xbb1/0x1520 drivers/net/usb/asix_devices.c:925
   usbnet_probe+0xbb3/0x27e0 drivers/net/usb/usbnet.c:1812

syzbot hits this with an emulated asix device. phy_eee_rx_clock_stop()
fails on a USB MDIO error, so phylink_bringup_phy() fails and the PHY is
detached from inside usbnet_probe(), before the netdev is registered.

hwprov is only set through ethtool, under RTNL, on a registered device.
reg_state also changes only under RTNL. So if the device is not
registered, no one else can reach hwprov, and RTNL is not needed. Tell
lockdep that. A detach from a registered device without RTNL still
warns.

Fixes: 35f7cad174 ("net: Add the possibility to support a selected hwtstamp in netdevice")
Reported-by: syzbot+583f42a41879bb60de32@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=583f42a41879bb60de32
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Link: https://patch.msgid.link/20261029142423.93573-1-ngocthang2710.1999@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 16:09:39 +01:00
Vas Zayarskiy
c221091f7e hwmon: (aquacomputer_d5next) Avoid truncating scaled sensor readings
High Flow Next power is reported in watts. Multiplying the 16-bit value
by one million can overflow both the signed intermediate and the u32
cache. Store power in long, perform the conversion in u64, and clamp to
LONG_MAX. The other existing power conversions fit in a signed 32-bit
value. Return -ENODATA for unavailable power instead of exposing the
stored error as a reading.

The power cache is updated by HID reports without the hwmon read mutex.
Read it once with READ_ONCE() and use that snapshot for both the
availability check and the returned value. Mark the corresponding
updates with WRITE_ONCE() so that the shared accesses are explicit.

Widen the shared current cache to u32. The Aquastream XT conversion to
milliamperes can exceed 65535 mA; clamp its negative conversion results
to zero before assigning to the unsigned cache. This also permits devices
with scaled aggregate currents to store milliamperes directly.

Fixes: aed80bb91d ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer High Flow Next")
Cc: stable@vger.kernel.org
Signed-off-by: Vas Zayarskiy <contact@vasily.cc>
Link: https://patch.msgid.link/20260927191316.4137752-2-contact@vasily.cc
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
1a30ea0be6 hwmon: (sht4x) Convert update_interval to jiffies in pending data check
In sht4x_read_values(), the check for whether a pending post-heater
measurement is still fresh compares get_jiffies_64() against
data->heating_complete + data->update_interval. However,
data->heating_complete is stored in jiffies whereas data->update_interval
is stored in milliseconds.

Whenever HZ != 1000, adding data->update_interval directly without
msecs_to_jiffies() mixes incompatible time units. For example, with the
default 2000 ms update_interval, the validity window is inflated to 8
seconds at HZ=250 and 20 seconds at HZ=100 instead of 2 seconds. A read
within that extended window skips triggering a fresh measurement and
instead returns and caches the stale post-heating measurement left in the
sensor's output buffer.

Convert data->update_interval to jiffies using msecs_to_jiffies() when
computing the pending measurement expiration deadline, matching the
next_update calculation right below it.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 0eed6fc3d2 ("hwmon: (sht4x): add heater support")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
9a6aa085c9 hwmon: (coretemp) Fix 32-bit jiffies wraparound in show_temp()
show_temp() rate-limits MSR reads by storing tdata->last_updated as an
unsigned long and comparing it against jiffies using
time_after(jiffies, tdata->last_updated + HZ).

time_after() relies on signed long subtraction, which only produces the
expected result while the two timestamps are within LONG_MAX jiffies of
each other. On 32-bit kernels, if tempX_input is not read for more than
LONG_MAX jiffies (~24.85 days at HZ=1000), the signed difference flips
sign and time_after() evaluates to false. Because tdata->last_updated is
only refreshed when time_after() succeeds, subsequent reads remain
blocked from refreshing for another ~24.85 days until jiffies wraps
past tdata->last_updated + HZ again, returning either a stale cached
temperature or -ENODATA if the sensor had never been read since
initialization.

Store tdata->last_updated as a u64 and use get_jiffies_64() with
time_after64(), which does not wrap in any practical uptime.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: bebe467823 ("hwmon: New coretemp driver")
Cc: stable@vger.kernel.org
Tested-by: Asaf Nuri Bertizlioğlu <ycistak@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
95638f1f05 hwmon: (coretemp) Set nr_cores only after core_data allocation succeeds
In init_temp_data(), pdata->nr_cores is populated from
topology_num_cores_per_package() before allocating pdata->core_data. If
that allocation fails, init_temp_data() returns NULL with
pdata->core_data still NULL and pdata->nr_cores set to a positive value.

coretemp_add_core() logs the error without failing coretemp_cpu_online(),
so the CPU still comes online with pdata->hwmon_dev registered. When the
CPU is later taken offline (or the module is unloaded),
coretemp_cpu_offline() calls get_temp_data(pd, cpu), which loops up to
pdata->nr_cores and dereferences the NULL pdata->core_data pointer.

Store the core count in a local variable and assign pdata->nr_cores only
after pdata->core_data is allocated, preserving the invariant that
pdata->nr_cores is zero whenever pdata->core_data is NULL.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 1a793caf6f ("hwmon: (coretemp) Use dynamic allocated memory for core temp_data")
Cc: stable@vger.kernel.org
Tested-by: Asaf Nuri Bertizlioğlu <ycistak@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
0f9c7ed3b5 hwmon: (coretemp) Check for NULL platform device in hotplug callbacks
coretemp_get_pdev() returns NULL when topology_logical_die_id(cpu) is
negative (such as -ENODEV or -ERANGE from topology_get_logical_id() on a
firmware/hardware APIC ID mismatch) or exceeds max_zones (for example,
under asymmetric or anomalous ACPI die topologies where
topology_max_packages() * topology_max_dies_per_package() is smaller
than the logical die count).

Commit 6d03bbff45 ("hwmon: (coretemp) Simplify platform device
handling") pre-allocated zone_devices[0 .. max_zones - 1] during module
init and dropped the NULL checks on pdev in coretemp_cpu_online() and
coretemp_cpu_offline(), passing pdev unconditionally to
platform_get_drvdata(). When coretemp_get_pdev() returns NULL,
platform_get_drvdata(pdev) dereferences &pdev->dev and triggers a kernel
NULL pointer dereference.

Check for a NULL pdev and return 0 in both coretemp_cpu_online() and
coretemp_cpu_offline() before calling platform_get_drvdata(). Returning
0 in coretemp_cpu_online() ignores the unmapped CPU without blocking CPU
bringup or tearing down valid thermal zones on other dies.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 6d03bbff45 ("hwmon: (coretemp) Simplify platform device handling")
Cc: stable@vger.kernel.org
Tested-by: Asaf Nuri Bertizlioğlu <ycistak@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Baek Kyu, Kim
f324179e6c hwmon: (gpio-fan) Update the speed cache before dropping the PM reference
set_fan_speed() writes the GPIO control value before dropping the runtime
PM reference when stopping the fan. pm_runtime_put_sync() decrements the
usage count even when suspending the device fails, but the error return
currently leaves speed_index at the previous running speed.

A request for that same running speed then returns success without
changing the GPIOs or taking a runtime PM reference. Retrying the stop
instead drops a reference the driver no longer owns and can trigger a
runtime PM usage count underflow warning.

Update speed_index after writing the GPIOs and before dropping the PM
reference. The initial same-speed check already excludes a stopped fan,
so a zero target is sufficient to identify the transition that needs a
PM put. Preserve the PM error return and the CONFIG_PM=n exception.

This keeps the cached control state and PM reference ownership consistent
without restoring running GPIOs after a possibly partial supply failure.
It does not clear persistent runtime PM errors or claim that a failing
regulator has successfully powered off.

Fixes: 0d01110e63 ("hwmon: (gpio-fan) Add regulator support")
Cc: stable@vger.kernel.org
Signed-off-by: Baek Kyu, Kim <pocj8ur4in@gmail.com>
Link: https://patch.msgid.link/20261031095039.11683-1-pocj8ur4in@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
7cd6053807 hwmon: (tmp108) Fix initial conversion delay and wait until ready
In tmp108_common_probe(), the driver only adds the 30 ms conversion delay
(TMP108_CONVERSION_TIME_MS) to ready_time if the sensor was previously in
TMP108_MODE_SHUTDOWN. However, the TMP108 hardware defaults to continuous
conversion mode (TMP108_MODE_CONTINUOUS) upon power-on reset, including
immediately after enabling the vcc supply regulator during probe, while
the temperature register retains its power-on reset value of 0x0000 (0°C)
until the first conversion completes. Because the initial mode is not
shutdown, the delay is bypassed and early reads via thermal zone
registration or sysfs before the first conversion finishes return an
uninitialized 0°C reading.

In addition, returning -EAGAIN from tmp108_read() while waiting for a
conversion to complete after probe or resume can trigger an unnecessary
tight retry loop in callers or fail initial reads.

Unconditionally set ready_time to TMP108_CONVERSION_TIME_MS ahead in
tmp108_common_probe(), track ready_time as ktime_t, and wait for the
remaining conversion time in tmp108_read() using usleep_range() instead
of returning -EAGAIN.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 66e1c91713 ("hwmon: Add Texas Instruments TMP108 temperature sensor driver.")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
3897309ede hwmon: (lm75) Fix setting polarity mask for chips with 16-bit config register
When probing a 16-bit compatible temperature sensor configured with the
"ti,alert-polarity-active-high" device property, lm75_generic_probe()
writes to a reserved bit instead of the alert polarity bit due to an
incorrect bit shift in the 16-bit polarity mask.
On 16-bit sensors, the polarity bit is physically located at bit 2 of the
MSByte. When accessed via i2c_smbus_read_word_data() or
i2c_smbus_write_word_data(), the SMBus protocol maps the first received
byte (the physical MSByte) to the lower 8 bits of the integer
representation. Consequently, the polarity bit is consistently mapped to
bit 2, identically to 8-bit sensors. However, the
LM75_ALERT_POLARITY_HIGH_16_BIT macro applies an 8-bit left shift,
erroneously targeting bit 10. This causes the driver to silently corrupt a
reserved bit in the configuration register while leaving the active-high
alert polarity unconfigured, breaking the polarity feature.

Use BIT(2) as polarity mask in the configuration register for all chips
to fix the problem.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 1be4001d9b ("hwmon: (lm75) Support active-high alert polarity")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
4fc79634af hwmon: (pmbus) Fix return value check from thermal zone registration
The PMBus core used to call devm_thermal_zone_of_sensor_register()
to register thermal zones. Commit 613ed3f676 ("hwmon: pm_bus: core:
Switch to new of thermal API") changed this to call
devm_thermal_of_zone_register() instead. The code subsequently checks if
the call failed because the thermal subsystem is not configured.
devm_thermal_zone_of_sensor_register() used to return -ENODEV in this
case. devm_thermal_of_zone_register() returns -ENOTSUPP. The code currently
still checks for -ENOVEV. This results in driver instantiation failures if
the thermal subsystem is disabled.

Check for -ENOTSUPP to fix the problem. Keep checking for -ENODEV because
this indicates that no thermal zone is configured for the sensor, which is
acceptable for the driver and must not cause a registration failure.

Fixes: 613ed3f676 ("hwmon: pm_bus: core: Switch to new of thermal API")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
9aa6cc563e hwmon: (pmbus) Release devres allocated memory after devm_thermal_of_zone_register error
In pmbus_thermal_add_sensor(), a devres memory leak occurs when a PMBus
temperature sensor is initialized but no thermal zone is configured for
it.
The function allocates a pmbus_thermal_data structure using
devm_kzalloc(). It then attempts to register the sensor with the thermal
subsystem via devm_thermal_of_zone_register(). If this registration
returns -ENODEV (e.g., when no thermal zone is mapped in the Device Tree
or CONFIG_THERMAL_OF is disabled), the function intentionally catches the
error and returns 0 to allow device probing to continue.

Because devm_kfree() is not called on the -ENODEV path, the unused tdata
structure remains allocated on the device's managed resource list. Since
most PMBus temperature sensors are not attached to thermal zones, this
results in an accumulation of unused objects that needlessly consume kernel
memory for the lifetime of the PMBus device.

Add the missing call to devm_kfree() to fix the problem.

Fixes: 3aa74796cf ("hwmon: (pmbus) Register with thermal for PSC_TEMPERATURE")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
11dfbd835b hwmon: (pmbus) Check return value from pmbus_thermal_add_sensor()
During PMBus device probe, if registering a temperature sensor with the
thermal subsystem fails, pmbus_add_sensor() silently ignores the error and
returns success.
When a valid temperature sensor is detected (class PSC_TEMPERATURE and type
"input"), pmbus_add_sensor() invokes pmbus_thermal_add_sensor() to hook it
into the kernel's thermal framework. However, the return value of this call
is completely discarded. If thermal registration fails, such as from an
-ENOMEM allocation failure or an invalid device tree configuration like a
malformed #thermal-sensor-cells property, no error is propagated.

Because the hardware monitor probe falsely succeeds despite the failure to
register the thermal zone, the system is left without thermal mitigation
for the affected PMBus device. This silently blinds the system to actual
PMIC temperatures, preventing the execution of necessary cooling mechanisms
or emergency shutdowns and risking localized overheating.

Pass the return value from pmbus_thermal_add_sensor() to the calling code
to fix the problem. To enable passing the actual error, change the error
return from pmbus_add_sensor() from NULL to ERR_PTR() and extract the error
from in the calling code.

Fixes: 3aa74796cf ("hwmon: (pmbus) Register with thermal for PSC_TEMPERATURE")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:05 -08:00
Guenter Roeck
a5802c587d hwmon: (pmbus/q54sj108a2) Add missing NULL pointer check
When CONFIG_DEBUG_FS is enabled and per-client PMBus debugfs directory
creation fails during pmbus_do_probe(), q54sj108a2_probe() passes the NULL
pointer returned by pmbus_get_debugfs_dir() to debugfs_create_dir()
without validation, creating its debugfs directory at the debugfs root
instead of under the client directory.

If pmbus_init_debugfs() fails to create the client directory, data->debugfs
is left as NULL or an ERR_PTR, which pmbus_get_debugfs_dir() converts to
NULL. Passing a NULL parent to debugfs_create_dir() places q54sj108a2_dir
in the root of the debugfs filesystem and populates it with attribute files
whose private data pointers reference psu->debugfs_entries. Because this
root-level directory is outside the client debugfs hierarchy, PMBus core
cleanup does not remove it on device unbind, leaking the debugfs entries
and causing a use-after-free of the devm-allocated struct q54sj108a2_data
if the orphaned files are accessed via q54sj108a2_debugfs_read() or
q54sj108a2_debugfs_write() after device removal.

Fix the problem by adding the missing NULL pointer check.

Fixes: d014538aa3 ("hwmon: (pmbus) Driver for Delta power supplies Q54SJ108A2")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
61bc4514b8 hwmon: (peci/dimmtemp) Fix devres leak and UAF on concurrent unbind
When a peci_dimmtemp device is unbound concurrently with its delayed
initialization work (detect_work), newly allocated devm resources and
the hwmon device are leaked, leading to a use-after-free when reading
the lingering hwmon sysfs attributes.

In peci_dimmtemp_probe(), detect_work is registered for cancellation via
devm_delayed_work_autocancel(). During driver detach, devres_release_all()
first moves all existing entries from dev->devres_head onto a local todo
list before invoking their release callbacks in reverse order. If
create_dimm_temp_info_delayed() is already running when
devm_delayed_work_drop() calls cancel_delayed_work_sync(),
create_dimm_temp_info() can allocate dimmtemp_label strings via
devm_kzalloc()/devm_kasprintf() and register the hwmon device via
devm_hwmon_device_register_with_info(), appending new devres entries to
the now-empty dev->devres_head. Once the work finishes,
devres_release_all() frees priv and priv->name from the local todo list
without re-evaluating dev->devres_head, leaving the late devres
allocations and registered hwmon device behind with a dangling priv
pointer.

Cancel detect_work synchronously in a driver .remove() callback instead
of relying on devm_delayed_work_autocancel() so that the work is fully
drained before devres_release_all() detaches dev->devres_head, allowing
any devm resources registered by the delayed work to be released in
proper reverse order. Also only schedule detect_work when
check_populated_dimms() returns -EAGAIN so that probe failure paths do
not leave delayed work pending.

Fixes: 73bc1b885d ("hwmon: peci: Add dimmtemp driver")
Cc: stable@vger.kernel.org
Cc: Iwona Winiarska <iwona.winiarska@intel.com>
Reviewed-by: Iwona Winiarska <iwona.winiarska@intel.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
c4a01c2a80 hwmon: (nct6683) Fix incorrect struct cast in show_pwm() and store_pwm()
On big-endian architectures, reading or writing the pwm[1-8] sysfs
attributes in the nct6683 hardware monitoring driver always redirects to
channel 0 due to an incorrect struct downcast in show_pwm() and
store_pwm().
The driver defines the PWM sysfs attributes using SENSOR_TEMPLATE(),
which initializes them as struct sensor_device_attribute (where the index
is a 32-bit int). However, the sysfs callbacks show_pwm() and store_pwm()
incorrectly downcast the attribute to a struct sensor_device_attribute_2
(where the index is an 8-bit u8). Because both structs start with struct
device_attribute, container_of() resolves to the same base address. On
big-endian architectures, reading the 8-bit index field from the memory
layout of a 32-bit int fetches the most significant byte (which is 0),
rather than the intended channel number.
This type mismatch causes all PWM reads to return data for channel 0, and
any writes intended to configure other channels will silently overwrite the
duty cycle of PWM channel 0 instead.

Fix the type casts in show_pwm() and store_pwm() to solve the problem.

Fixes: 41082d66bf ("hwmon: Driver for NCT6683D")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
5b51ff0887 hwmon: (lm87) Fix drvdata type confusion in vrm_show() and vrm_store()
When an LM87 or ADM1024 device is probed with VID support enabled, reading
from or writing to the vrm sysfs attribute triggers a driver data type
confusion in vrm_show() and vrm_store() in drivers/hwmon/lm87.c.

In lm87_probe(), the driver stores the struct lm87_data pointer on the I2C
client via i2c_set_clientdata() and passes the struct i2c_client pointer as
the drvdata argument to devm_hwmon_device_register_with_groups(), which
attaches the attribute groups to the registered hwmon device with client as
its driver_data. Unlike the other sysfs callbacks that retrieve client via
dev_get_drvdata() and then obtain data via i2c_get_clientdata(), vrm_show()
and vrm_store() assign dev_get_drvdata(dev) directly to struct lm87_data *.
Dereferencing data->vrm therefore accesses the struct i2c_client instance
at offsetof(struct lm87_data, vrm), causing vrm_show() to leak an unrelated
byte from struct i2c_client to userspace and vrm_store() to corrupt a byte
within struct i2c_client while failing to update the actual VRM value.

Fix the problem by assigning the return value from dev_get_drvdata(dev) to
struct i2c_client *client and using i2c_get_clientdata() to get the actual
client data.

Fixes: 00a0c905ab ("hwmon: (lm87) Use hwmon to create the sysfs groups")
Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
185039b1c0 hwmon: (hp-wmi-sensors) Fix unbounded loops in scale_numeric_sensor()
In scale_numeric_sensor() in the hp-wmi-sensors hwmon driver, an unbounded
loop occurs if the ACPI WMI implementation provides a highly anomalous or
malformed UnitModifier value for a numeric sensor.
The UnitModifier property is extracted from a WMI ACPI object without
bounds checking and cast to a signed 32-bit integer. This value directly
controls the iteration count of two scaling loops. If the provided
unit_modifier is extremely negative (e.g., INT_MIN), the first loop
executes billions of times before reaching target_modifier. Conversely,
if unit_modifier is extremely large (e.g., INT_MAX) and the current
sensor reading (val) is exactly 0, the second loop's overflow safeguard
(val > LONG_MAX / 10) never evaluates to true, resulting in billions of
unnecessary iterations. This prolonged execution causes severe CPU stalls
and thread soft lockups during driver initialization or whenever a
user-space process reads the sensor attribute via sysfs, resulting in a
denial of service on the affected CPU core.

Fix the problem in the first loop by exiting it as soon as val is zero.
Fix the problem with the second loop by only entering it if val is not
zero. Also add a check for val < LONG_MIN / 10 and exit the loop if that
is the case.

Fixes: 23902f98f8 ("hwmon: add HP WMI Sensors driver")
Cc: stable@vger.kernel.org
Cc: James Seo <james@equiv.tech>
Acked-by: James Seo <james@equiv.tech>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
dc992efeac hwmon: (hp-wmi-sensors) Avoid global struct mutation
In the HP WMI sensors driver, make_chip_info() assigns a device-managed
memory allocation to a static global structure, resulting in a
use-after-free when the device unbinds.
During hp_wmi_sensors_probe(), make_chip_info() dynamically allocates a
hwmon_channel_info array using devm_kcalloc() and assigns it to the
static global hp_wmi_chip_info.info pointer.

If multiple instances probe sequentially or concurrently, the shared
global pointer is overwritten by each new device. When any device unbinds,
its devm-managed memory is automatically freed, leaving the global
hp_wmi_chip_info struct and any other active device instances with a
dangling pointer. Subsequent accesses by the hwmon core (such as thermal
zone reads) will dereference this freed memory, causing a use-after-free.

While this is not supposed to happen in the real world (there should only
be one instance of the driver in any system), modifying global structures
is undesirable and should be avoided whenever possible. Allocate struct
hwmon_chip_info as part of struct hp_wmi_sensors instead and initialize it
in make_chip_info() to avoid mutating the global structure.

Fixes: 23902f98f8 ("hwmon: add HP WMI Sensors driver")
Cc: stable@vger.kernel.org
Cc: James Seo <james@equiv.tech>
Acked-by: James Seo <james@equiv.tech
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
59d586c9e4 hwmon: (asus_wmi_sensors) Avoid global struct mutation
In the asus_wmi_sensors driver, device-managed memory allocated in
asus_wmi_configure_sensor_setup() is assigned to a global static structure,
leading to a potential use-after-free when the device is unbound.
The driver defines a single global asus_wmi_chip_info structure to register
with the hwmon core. During probe, it dynamically allocates the .info
channel array using devm_kcalloc() and assigns it directly to this global
structure. When a device is unbound, its device-managed memory is
automatically freed, leaving asus_wmi_chip_info.info as a dangling pointer.
Furthermore, if multiple WMI devices are probed sequentially, each probe
overwrites the same global pointer, forcing all registered hwmon instances
to reference the channel information of the most recently probed device.

While it is unlikely if not impossible that multiple WMI devices of the same
kind exist, modifying a global static data structure is undesirable. Remove
the static data structure and allocate it as part of struct asus_wmi_sensors
to avoid the potential problem.

Fixes: 548820e21c ("hwmon: (asus_wmi_sensors) Support X370 Asus WMI.")
Cc: stable@vger.kernel.org
Cc: Ed Brindley <kernel@maidavale.org>
Cc: Denis Pauk <pauk.denis@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Guenter Roeck
b7743c6dbe hwmon: (aquacomputer_d5next) Check maxcollection when probing AQUAERO devices
When a USB HID device matching USB_PRODUCT_ID_AQUAERO presents a
malformed report descriptor, an out-of-bounds array access occurs in
aqc_probe() due to an unchecked index into the parsed collections array.
During device initialization, the driver distinguishes between the
multiple logical interfaces exposed by the Aquaero device by evaluating
the type of the second element in the collection array. The driver
unconditionally accesses hdev->collection[1] without verifying that
hdev->maxcollection is greater than 1. Because the collection array is
dynamically allocated by the HID core based on the number of collections
found in the report descriptor, a crafted device exposing fewer than two
collections causes an immediate heap out-of-bounds read or NULL pointer
dereference. This leads to a kernel panic during the device probe phase.

Add the missing check to fix the problem.

Fixes: 2c55211104 ("hwmon: (aquacomputer_d5next) Support sensors for Aquacomputer Aquaero")
Cc: stable@vger.kernel.org
Cc: Aleksa Savic <savicaleksa83@gmail.com>
Cc: Jack Doan <me@jackdoan.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
8c02722be2 hwmon: chipcap2: synchronize ready IRQ state
The ready IRQ handler can race with reinit_completion() in the enable
path. In particular, a handler from an earlier operation can complete
the completion after it is reset for a new operation.

Use irq_lock to serialize access to the completion and process_irqs.
Disable IRQ processing and synchronize any running handler before resetting
the completion for a new operation.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-11-27ebfc2c5b9e@gmail.com
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
bed5f0c075 hwmon: chipcap2: serialize access to the alarm indicators
low_alarm and high_alarm are accessed from the threaded interrupt
handlers and from sysfs without any locking, which can lead to lost
alarms.

Add a mutex to serialize the access to the alarm indicators and to
process_irqs, which the handlers use to decide whether an interrupt
belongs to an ongoing operation.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-10-27ebfc2c5b9e@gmail.com
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
22aecf164e hwmon: chipcap2: do not discard pending alarms on disable
cc2_disable() stops processing interrupts before the device is powered
down to ignore the alarms caused by voltage toggling. The handler of an
alarm raised by the last measurement might not have run at that point,
and the alarm is discarded when it finally does.

The sysfs read that triggered the measurement can then report no alarm
although the device raised one.

Wait for the alarm handlers that have already been raised before the
interrupt processing is stopped. This covers the case where the handler
thread has not been scheduled yet; an alarm that has not reached the
interrupt core at that point is discarded.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-9-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
378add65fd hwmon: chipcap2: balance regulator state
The current implementation does not guarantee that the calls to
regulator_enable() and regulator_disable() are balanced.
regulator_is_enabled() might return a negative value, and an always-on
attribute in the DT might break the symmetry anyway.

Add a regulator_enabled flag to keep balance within this regulator
consumer.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-8-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
d1ce827a9c hwmon: chipcap2: enable IRQ processing when regulator is already enabled
cc2_enable() returns early when the regulator is already enabled.
This can happen if a previous regulator_disable() failed or if the
regulator was configured as always-on.

In this case, process_irqs remains false, causing the ready interrupt
to be ignored. Subsequent operations waiting for the ready completion
then time out.

Set process_irqs before returning when the regulator is already
enabled, so that the driver continues to process ready interrupts.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-7-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
4724ac5556 hwmon: chipcap2: disable device after hwmon teardown
cc2_remove() disables the device while the device-managed hwmon device is
still registered. A concurrent sysfs callback can then enable the device
after it has been disabled during removal.

Register a device-managed disable action before registering the hwmon
device, so devres unregisters the hwmon device before disabling the
physical device.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-6-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
d2a66c515d hwmon: chipcap2: fix IRQ teardown ordering
The threaded IRQs are currently requested before the hwmon device
is registered. Since devres releases resources in reverse order,
the hwmon device is unregistered before the IRQs are freed during
driver teardown. An IRQ may therefore still run after the hwmon
device has been released and access the stale data->hwmon pointer.

Separate IRQ discovery from IRQ registration so that the IRQ numbers
and alarm visibility flags are initialized before registering the
hwmon device while the IRQs are released before the hwmon device
during devres cleanup.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-5-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
b5a1412618 hwmon: chipcap2: defer probe when IRQs are unavailable
This device can work with or without interrupts, but if they
are provided and still not available, but if -EPROBE_DEFER is read,
its value must be propagated to enable probe retries.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-4-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
36b07ddfe2 hwmon: chipcap2: fix be16 handling
The driver currently only works correctly on little-endian
architectures when writing 16-bit register values.

Use i2c_smbus_write_word_swapped() for writes and get_unaligned_be16()
for reads to correctly handle the ChipCap 2's big-endian data format
on all architectures.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-3-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
4c0e65a4ed hwmon: chipcap2: fix off-by-one in command mode retry loop
i == CC2_CM_RETRIES can never be true inside the loop, since it
only runs while i < CC2_CM_RETRIES. Use CC2_CM_RETRIES - 1 so the
last failed retry breaks out immediately instead of doing a useless
disable + 80 ms power-cycle delay before the loop condition ends it
anyway.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-2-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Javier Carrasco
d0a03e1a2d hwmon: chipcap2: fix command error diagnostics
The command response field only contains bits 1:0, while the
error flags are stored in bits 2:5. The existing diagnostic
checks test the extracted response field, so they can never report
an error flag.

Test the full status byte for the error flags, and check the
configuration-load flag instead of RAM parity for the last diagnostic.

Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-1-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Alexei Solcanu
d1f60971fb hwmon: (gpd-fan) Reset both fans to automatic on duo boards
On boards using gpd_duo_drvdata (GPD Duo, GPD Win 5), writing
pwm1_enable=2 only returns the first fan to EC control. The second fan
keeps its last manual duty cycle, e.g. full speed after pwm1=255, so a
fan control tool that exits leaves it running at that speed.

gpd_duo_write_pwm() writes both fan registers (pwm_write and
pwm_write + 1), but switching to automatic only clears pwm_write.
Also clear pwm_write + 1, so both fans return to EC control.

Tested on a GPD Win 5 (G1618-05). Not tested on the GPD Duo.

Fixes: 0ab88e2394 ("hwmon: add GPD devices sensor driver")
Cc: stable@vger.kernel.org
Signed-off-by: Alexei Solcanu <alexei.solcanu@pm.me>
Reviewed-by: Antheas Kapenekakis <lkml@antheas.dev>
Link: https://patch.msgid.link/20260926-gpd-fan-duo-auto-v2-1-0a2ea41ee3b5@pm.me
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Zac Lanzon
743b4481b6 hwmon: (asus_rog_ryujin) Fix pump control source on the Ryujin III
The RYUJIN III pump has a 4-pin cable for a motherboard fan header in
addition to USB. Byte 2 of the set cooler duty command selects the pump
control source: 0 hands the pump to its internal controller, which
follows the PWM of the header its 4-pin cable is plugged into, and 1
makes it follow the pump duty in byte 3. Byte 3 of the cooler duty
report returns the current source.

The driver fills byte 2 with duty_channel, which is 1 for the RYUJIN
III, and a pwm2 write re-sends the reported pump duty with the new fan
duty. So writing only the internal fan duty takes the pump away from
its internal controller.

Measured on a RYUJIN III 360 (firmware AURJ2-S750-0108) with the pump
cable on AIO_PUMP and the header PWM set through nct6775, after loading
the driver with the pump on its internal controller (pump rpm):

                                   header 50%   header 80%   source
  no write yet                        2160         3090         0
  pwm2 = 40%, before this patch       1740         1740         1
  pwm2 = 40%, with this patch         2130         3090         0

Send the reported source with pwm2 writes. The fan duty applies with
either source (40%: 1545 to 1590 rpm, 30%: 870 rpm). A pwm2 write sent
right after a pwm1 write that took the pump over, before the report
could show the change, left the pump on USB and applied its fan duty
(2 of 2 trials, and 7 of 7 with raw commands up to 0.9 s after).

pwm1 writes keep selecting source 1. The cooler reports the pump duty of
the last write, whichever source it selected, and 40% after power-on.
Byte 9 of the status report follows the duty the pump runs at. Measured
from power-on (PSU switched off) once per driver, with the header at
100%:

                                  before this patch   with this patch
                                  source duty  rpm    source duty  rpm
  no write yet                       0    100  3570      0    100  3570
  pwm2 = 40%                         1    100  3570      0    100  3570
  pwm1 = 40%, the reported duty      1    100  3570      1     40  1710
  pwm1 = 60%                         1     60  2430
  pwm1 = 40%                         1     40  1725

So a pwm1 write of the reported duty did not reach the pump, while
other duties applied in one write, also when taking the pump from its
internal controller (60%: 2460 rpm). When a pwm1 write requests the
reported duty, write a duty 1% away first (below at 100%), then the
requested one. Sent back to back, the two writes left the pump at the
requested duty in all 19 trials, 9 with raw commands and 10 through
this driver.

Tested on the RYUJIN III 360 only. The EXTREME, EVA and WHITE EDITION
use the same rog_ryujin_iii_info and send the same command, and Edward
Blair's analysis of the WHITE EDITION firmware shows the same pump
control source. The RYUJIN II, whose duty_channel is 0, is unchanged.

Fixes: cd258aca0d ("hwmon: (asus_rog_ryujin) Add ROG Ryujin III support")
Closes: https://github.com/aleksamagicka/asus_rog_ryujin-hwmon/issues/12
Suggested-by: Edward Blair <edward.blair@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Zac Lanzon <lanzonza@gmail.com>
Link: https://patch.msgid.link/7ca8fe6cd6b4125813613bd4187ff6cdda72e4b6.1790512964.git.lanzonza@gmail.com
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Vincent Jardin
d4f272230f hwmon: (pmbus/core) Register the thermal sensors with a 0-based index
Since commit
  3aa74796cf ("hwmon: (pmbus) Register with thermal for PSC_TEMPERATURE")
pmbus_core registers each temperature input with the thermal core using
its hwmon index as the sensor id. That index starts at 1, so temp1 is
registered as sensor 1.

The thermal core expects a 0-based id, which is what the hwmon core
passes for the drivers that set HWMON_C_REGISTER_TZ:
thermal_of matches a thermal-sensors phandle without cells as id 0, so a
PMBus device with a single temperature input cannot
use #thermal-sensor-cells = <0>.

Cc: stable+noautosel@kernel.org # changes the DT-visible sensor id, no in-tree user
Fixes: 3aa74796cf ("hwmon: (pmbus) Register with thermal for PSC_TEMPERATURE")
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Link: https://patch.msgid.link/20261001-for-upstream-dt-mpq8785-thermal-sensor-cells-v3-1-bfafba9fcc95@free.fr
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Jiale Yao
cf8f81babd hwmon: (aquacomputer_d5next) reject short status reports
The HID raw_event callback runs before HID core validates the received
report length. aqc_raw_event() reads device-specific status fields at fixed
offsets, including multi-byte values, without first ensuring that the
received buffer contains every field. A truncated report can therefore
cause out-of-bounds reads and update hwmon state with unrelated data.

The required length differs between supported devices and cannot be
derived from the HID report descriptor. Define the minimum length needed
by each asynchronous status format, select it while configuring the
device, and reject reports that do not contain the last field accessed by
that format. Keep the published length zero until probe configuration is
complete, which also excludes legacy devices whose status is retrieved
through feature reports.

Suggested-by: Guenter Roeck <linux@roeck-us.net>
Fixes: 0e35f63f7f ("hwmon: add driver for Aquacomputer D5 Next")
Fixes: 19692f17cd ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream XT")
Cc: stable@vger.kernel.org
Signed-off-by: Jiale Yao <yaojiale02@163.com>
Link: https://patch.msgid.link/20261021120408.48495-1-yaojiale02@163.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Baek Kyu, Kim
e2c26431b4 hwmon: (corsair-cpro) Cache fan target only after a successful command
set_target() updates the cached fan target before sending the command.
If the command fails, subsequent fanN_target reads report the failed
request instead of the previous value. For example, after successfully
setting 1200 RPM, a rejected request for 1800 RPM returns an error but
leaves fanN_target reporting 1800. A failed request also replaces
-ENODATA when no target has been successfully set.

Update the target cache under the existing mutex only after
send_usb_cmd() succeeds, as set_pwm() already does when invalidating
the target. Preserve the previous cached value and return the original
error on failure.

Fixes: 40c3a44542 ("hwmon: add Corsair Commander Pro driver")
Cc: stable@vger.kernel.org
Signed-off-by: Baek Kyu, Kim <pocj8ur4in@gmail.com>
Link: https://patch.msgid.link/20261020160941.36787-1-pocj8ur4in@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Myeonghun Pak
5eab1e7f7e hwmon: (sht15) Stop deferred work before releasing its resources
The IRQ handler and regulator notifier can leave work pending after a
measurement or notification completes. Neither work item is drained before
its resources are released on removal or probe failure.

Disable read_work before freeing the IRQ, since the worker can re-enable
it. Use request_irq()/free_irq() for explicit teardown. Unregister the
regulator notifier before cancelling update_supply_work and disabling the
regulator. Apply the same ordering to probe failures.

Fixes: 251eb40f5c ("hwmon: sht15 humidity sensor driver")
Cc: stable@vger.kernel.org
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
Link: https://patch.msgid.link/20261024014044.27853-1-mhun512@gmail.com
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2026-11-02 07:00:04 -08:00
Bryam Vargas
f38bce9af9 net/iucv: take a private, writable frame before rewriting it in place
afiucv_hs_rcv() rewrites the frame in place -- EBCASC() on four name
fields, then afiucv_swap_src_dest() swaps them and pushes an Ethernet
header -- and can hand the same skb to dev_queue_xmit(), without making
it private first, so a packet socket that also gets the frame reads the
rewritten names. An ETH_P_ALL tap runs first and leaves af_iucv a
cloned skb; a socket opened for ETH_P_AF_IUCV sits on a ptype_specific
list, walked after ptype_base[], so deliver_skb() takes a reference and
af_iucv runs on an skb that is shared but not cloned.

Unshare, then cow, in that order: skb_cow() can reach
pskb_expand_head(), which has BUG_ON(skb_shared()). skb_cow() tests
skb_cloned(), which is what a rewrite of the data needs; skb_cow_head()
tests only the header. Asking for ETH_HLEN also covers the unchecked
push in afiucv_swap_src_dest(); on the ordinary path eth_type_trans()
has already pulled that much, so it only compares.

Fixes: 3881ac441f ("af_iucv: add HiperSockets transport")
Closes: https://sashiko.dev/#/patchset/20260813-b4-disp-60433a46-v1-1-509e1200533e@proton.me?part=1
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261028-b4-disp-1edbbc34-v3-1-13495411f5b9@proton.me
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:39:42 +01:00
Daniel Machon
873363ac59 net: sparx5/lan969x: release the in-flight slot of a stale TX skb
sparx5_ptp_txtstamp_request() counts every two step TX skb waiting for
its timestamp in sparx5->ptp_skbs, and refuses new ones once
SPARX5_MAX_PTP_ID are in flight. sparx5_ptp_txtstamp_old_release()
frees the skbs that have waited longer than SPARX5_PTP_TIMEOUT.

Before this patch, old_release() does not decrement ptp_skbs, so every
skb whose timestamp never arrives, for example because the switch
discarded the frame, keeps its slot forever. Once SPARX5_MAX_PTP_ID
slots are lost, two step frames fail to transmit on every port of the
switch.

Return the number of released skbs from old_release() and subtract it
from ptp_skbs in txtstamp_request(), under the ptp_ts_id_lock it already
takes.

This fixes the accounting only. A port's stale skbs are still aged out
only when that port sends a two step frame, so a port that stops sending
them keeps its stale skbs, and their slots, until it sends one again.
That behaviour is unchanged by this patch.

Found by an AI code review agent. Reproduced on a lan9696 board with a
modified kernel that drops the TX timestamps of two step frames, after
which two step timestamping stopped working on the port. With the fix,
timestamping keeps working on that board and on a sparx5 PCB135 board.

Fixes: 70dfe25cd8 ("net: sparx5: Update extraction/injection for timestamping")
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261029-sparx5-ptp-stale-tx-slot-v1-1-ec15f391bbb7@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:31:20 +01:00
Xia Yan
c1f04ea0aa selftests: net: check veth carrier after changing channel counts
Extend veth.sh to check that changing channel counts preserves carrier
state. When only one end is up, the running end must not report LOWER_UP.

Cover up/up and both mixed up/down combinations. Resize RX and TX queues
in both directions on each endpoint, and check carrier after a rejected
out-of-range request as well. Create the pair with two queues explicitly
so the carrier cases also run on single-CPU systems.

Reuse the existing namespace setup and cleanup. Run each carrier case
in a subshell to keep its variables separate from the other tests, and
accumulate failures in the caller. Only check LOWER_UP on running
interfaces, where the flag exposes carrier state.

Tested-by: Hangbin Liu <liuhangbin@kylinos.cn>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Signed-off-by: Xia Yan <yana06070@163.com>
Link: https://patch.msgid.link/20261029024259.3700-2-yana06070@163.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:24:58 +01:00
Xia Yan
2d02191779 veth: keep carrier off when resizing channels with a down peer
veth_set_channels() temporarily turns carrier off while reconfiguring a
running interface. It then turns carrier on for both ends without
checking whether the peer is administratively up. If only one end is up,
changing its channel counts therefore reports LOWER_UP even though the
peer remains down.

For example, after creating a pair with two RX and TX queues per end:

  ip link set vca up
  ethtool -L vca rx 1 tx 1

vca incorrectly reports LOWER_UP while vcb is still down.

Only restore carrier when the peer has IFF_UP, matching veth_open().
The local interface is already known to be running at this point.

Found during LLM-assisted source review and reproduced with a veth pair
in network namespaces, without kernel instrumentation or error injection.
The companion veth.sh test reproduces the two mixed up/down failures
before the fix and passes after it.

Fixes: 4752eeb3d8 ("veth: implement support for set_channel ethtool op")
Cc: stable@vger.kernel.org
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Signed-off-by: Xia Yan <yana06070@163.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://patch.msgid.link/20261029024259.3700-1-yana06070@163.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:24:53 +01:00
Fang Xieyan
60a792b979 vringh: reject empty / undersized indirect descriptor tables
move_to_indirect() validates an indirect descriptor table only with
"len % sizeof(struct vring_desc)".  A descriptor flagged
VRING_DESC_F_INDIRECT with len == 0 passes that test, so *desc_max is
set to 0 while *descs points at the empty table.  __vringh_iov() then
copies one struct vring_desc from descs[0] -- 16 bytes past the end of
the table -- before the "indirect_count > desc_max" loop detection
aborts the walk.  The over-read value is discarded when the walk aborts
and is never used to map anything, but the access itself is out of
bounds.

Reject any len smaller than one descriptor, alongside the existing
stride check, so an empty table is refused with -EINVAL and no
descriptor is ever fetched from it.

Fixes: f87d0fbb57 ("vringh: host-side implementation of virtio rings.")
Cc: stable@vger.kernel.org
Assisted-by: Hawkeye:GLM-5.3-flash
Assisted-by: Qoder:Qwen3.8-Max
Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
Message-ID: <20260926160755.21485-1-fangxy@xiaopeng.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-02 09:07:01 -05:00
Yuho Choi
f4f6e9a9cb virtio_blk: Reset device on probe error paths after DRIVER_OK
virtblk_probe() marks the device ready before revalidating zones and
adding the disk, and either of those can fail.  The out_cleanup_disk path
they take goes on to delete the virtqueues, but nothing tells the device
to stop first, so it is still live when the rings are freed.

Reset the device at out_cleanup_disk, which is only reachable after
virtio_device_ready().  virtblk_remove() and virtblk_freeze_priv() both
reset before deleting the virtqueues for the same reason.

Fixes: dbb301f91f ("virtio_blk: add error handling support for add_disk()")
Signed-off-by: Yuho Choi <oss.patchbox@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260922211207.523999-1-oss.patchbox@gmail.com>
2026-11-02 09:07:01 -05:00
Fang Xieyan
8689ee3842 vringh: add regression test for cyclic indirect descriptor
Add a case to tools/virtio/vringh_test.c that builds a top-level
indirect descriptor whose NEXT points back at itself and checks that
vringh_getdesc_user() rejects it with -ELOOP.

Without the preceding fix, the walk re-enters the same top-level
descriptor without making forward progress: count stays flat, so the
traversal limit is never reached and -ELOOP is never returned. With the
fix, the top-level count advances on each re-entry and
vringh_getdesc_user() returns -ELOOP once the traversal limit is reached.

Use index 1 rather than 0 for the self-cycle, since returning from an
indirect table is only performed for a positive up_next value. A
self-cycle at index 0 would instead terminate the walk and would not
reproduce the bug.

Assisted-by: Hawkeye:GLM-5.3-flash
Assisted-by: Qoder:Qwen3.8-Max
Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
Acked-by: Jason Wang <jasowangio@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260922122955.69433-3-fangxy@xiaopeng.com>
2026-11-02 09:07:01 -05:00
Fang Xieyan
f898439ace vringh: bound top-level re-entry into indirect tables
In __vringh_iov(), the F_INDIRECT branch descends into the indirect
table and continues before the descriptor accounting runs. A top-level
indirect descriptor is therefore never charged to count. If such a
descriptor sets NEXT to point back at itself, returning from the
indirect table resumes at the same top-level descriptor, which is again
not counted, so the walk never makes forward progress.

Because count stays flat and indirect_count is reset to 0 on every
return to the top-level table, neither bound in the loop check trips.
A guest can spin the vringh worker at 100% CPU inside __vringh_iov(),
an uninterruptible host DoS.

Move the descriptor accounting above the indirect switch so that a
top-level indirect descriptor is charged one top-level traversal step
before the walk descends into its table, bringing this re-entry under
the existing vrh->vring.num bound. Each top-level descriptor is still
charged at most one step and indirect_count still bounds a single
table, so legitimate chains (including the multiple-indirect case in
tools/virtio/vringh_test.c) stay within vring.num, while a cyclic
indirect descriptor is now rejected with -ELOOP.

Fixes: dbd29e0752 ("vringh: Fix loop descriptors check in the indirect cases")
Cc: Xie Yongji <xieyongji@bytedance.com>
Cc: stable@vger.kernel.org
Assisted-by: Hawkeye:GLM-5.3-flash
Assisted-by: Qoder:Qwen3.8-Max
Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260922122955.69433-2-fangxy@xiaopeng.com>
2026-11-02 09:07:01 -05:00
Jia Jia
cf0a5805d4 vduse: avoid infinite loop when no affinity CPU is online
If all CPUs in vq->irq_affinity are offline, cpumask_next() walks to the
end of the mask, and the loop then resets the cursor to IRQ_UNBOUND and
restarts the scan. When VDUSE_VQ_INJECT_IRQ is issued, the intersection of
vq->irq_affinity and cpu_online_mask is empty, so the caller busy-loops in
kernel context on its current CPU (e.g. CPU2).

Replace the while loop in vduse_vq_update_effective_cpu() with
cpumask_next_and_wrap() to find the intersection of vq->irq_affinity and
cpu_online_mask in a single wrapped scan. If the intersection is empty, set
curr_cpu to IRQ_UNBOUND and let the existing unbound workqueue handle
injection, avoiding repeated rescans when all CPUs in the affinity are
offline. Use cpus_read_lock()/cpus_read_unlock() to keep the selected CPU
online.

Fixes: 28f6288eb6 ("vduse: Support set_vq_affinity callback")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260919083933.104437-1-physicalmtea@gmail.com>
2026-11-02 09:07:01 -05:00
Sergii Ushakov
434d2bc41b virtio-blk: clamp max_segments to virtqueue ring size
In virtblk_add_req(), each request consumes 2 extra descriptors (out_hdr
and in_hdr) in addition to the data scatter-gather segments.

When a hypervisor (e.g. QNX Hypervisor) advertises VIRTIO_BLK_F_SEG_MAX
with seg_max = 1024 alongside a 1024-entry split ring (vring.num = 1024)
and VIRTIO_RING_F_INDIRECT_DESC disabled, lim->max_segments is set to
1024. When the block layer submits requests with 1023 or 1024 data
segments, total_sg reaches 1025 or 1026. This exceeds vring.num (1024),
causing virtqueue_add_split() to return -ENOSPC and permanently wedge
the blk-mq queue.

Furthermore, the Virtio specification (2.7.5.3.1) requires that a
descriptor chain never exceed the Queue Size, and virtqueue_add_split()
falls back to direct descriptors if indirect table allocation fails.

Fix this by:
1. Rejecting queues with ring_size < 3 at probe, or
   ring_size < (queue_max_segments + 2) during resume/reset recovery in
   init_vq().
2. Unconditionally clamping sg_elems to (ring_size - 2) across all
   virtqueues in virtblk_read_limits().

Reported-by: Stjepan Poljak <stjepan.poljak@gmail.com>
Fixes: 0864b79a15 ("virtio: block: dynamic maximum segments")
Signed-off-by: Sergii Ushakov <sergiiushakov@google.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260918135120.1261150-1-sergiiushakov@google.com>
2026-11-02 09:07:01 -05:00
Yu Zhang
c9c1c1b7b3 vhost-vdpa: drop the parent's vq callback before the call fd is released
VHOST_SET_VRING_CALL releases the previous call eventfd inside
vhost_vring_ioctl() -- it swaps the new context into vq->call_ctx.ctx
and then eventfd_ctx_put()s the old one, which is a synchronous
kfree(). The parent vdpa device is only told about the change
afterwards, when vhost_vdpa_vring_ioctl() reaches ops->set_vq_cb().

Parent drivers cache the pointer handed to them in
vdpa_callback::trigger and do not take a reference on it, so
throughout that window the parent holds a dangling eventfd_ctx and may
signal it. The documentation added with the field describes what
signalling it means but says nothing about how long it stays valid.

This is the same hazard that "vhost_vdpa: assign irq bypass producer
token correctly" addressed for the irq bypass producer token, by
moving vhost_vdpa_unsetup_vq_irq() ahead of the vhost_vring_ioctl()
call. The producer token was only one of the two consumers of that
pointer; the one the parent keeps via ->set_vq_cb() was left behind
the free.

With VDUSE the window is directly reachable from userspace, because
the device emulation daemon can inject an interrupt at any time from a
different fd, and neither side shares a lock with the other: VDUSE
takes vq->irq_lock, vhost takes vhost_dev.mutex + vq->mutex.

  BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x76/0xe0
  Write of size 4 at addr ffff8881084e8788 by task vduse_uaf/2987

  _raw_spin_lock_irqsave+0x76/0xe0
  eventfd_signal_mask+0x69/0x120
  vduse_dev_ioctl+0x337/0x1a60     <- vduse_vq_signal_irqfd(), inlined
  __x64_sys_ioctl+0x120/0x170      <- VDUSE_VQ_INJECT_IRQ

  Allocated by task 2986:
   do_eventfd+0x50/0x200
   __x64_sys_eventfd2+0x2e/0x40

  kmalloc-64, freed 64-byte region [ffff8881084e8780, ffff8881084e87c0)

One thread loops VHOST_SET_VRING_CALL on /dev/vhost-vdpa-N with a
fresh eventfd and then unbinds it, while another loops
VDUSE_VQ_INJECT_IRQ on /dev/vduse/<name>. This reproduces in 5 out of
5 ten-second runs on v7.1.6 and 3 out of 3 on v7.2-rc6. With the patch
there are no reports in 3 out of 3 runs on either, while the same
workload still gets ~30000 interrupts per run delivered into live
eventfds, so the path is still being exercised.

Tell the parent to drop the callback before vhost_vring_ioctl() can
free the eventfd, mirroring what is already done for the bypass
producer, and restore it if the ioctl fails -- on failure the swap
never happened, the old context is still installed, and leaving the
parent without a callback would silently drop that vq's interrupts.

Clearing the callback only stops a parent from starting to use the
context; a handler that already loaded it can still be running. For
parents with a real interrupt, wait for it with synchronize_irq() on
the vq's irq. VDUSE does not implement get_vq_irq, so that case stays
covered by the teardown above.

Fixes: 5e68470f4e ("vdpa: Add eventfd for the vdpa callback")
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260918040436.47982-1-yuz08559@gmail.com>
2026-11-02 09:07:00 -05:00
Tal Zussman
73d135601d vhost-vdpa: unpin mappings by range
vhost_vdpa_pa_unmap() unpins each mapping a page at a time, dirtying
each page first if the mapping is writable. Each mapping is physically
contiguous, so use unpin_user_page_range_dirty_lock() instead, which
marks every folio dirty once and drops its pins in one go. Do the same
for the pages left pinned in the vhost_vdpa_pa_map() error path.

This removes the last use of set_page_dirty_lock() in vhost.

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Message-ID: <20261031-vhost-vdpa-unpin-v1-2-94ffc9683256@columbia.edu>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-02 09:07:00 -05:00
Tal Zussman
fd1462c96b vhost-vdpa: fix pinned page leak in vhost_vdpa_pa_map() error path
When pin_user_pages() or vhost_vdpa_map() fails, vhost_vdpa_pa_map()
is supposed to unpin the pages pinned after the last successfully
mapped chunk, i.e. the range [map_pfn, last_pfn]. The unpin is guarded
by nchunks, but nchunks is reset to 0 every time a chunk is mapped from
inside the current page list, so a failure after any such boundary
leaves that pending range pinned forever. With physically scattered
memory nearly every page list contains a boundary, so the leak happens
on practically every failed IOTLB update.

The pending range is non-empty exactly when a page has been pinned,
which last_pfn already tells us, so drop nchunks and test last_pfn.

Fixes: ad89653f79 ("vhost-vdpa: fix page pinning leakage in error path (rework)")
Cc: stable@vger.kernel.org
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reported-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261031-vhost-vdpa-unpin-v1-1-94ffc9683256@columbia.edu>
2026-11-02 09:07:00 -05:00
Linfeng Sun
b179f21d2d vhost: reject invalid IOTLB update permissions
vhost_chr_write_iter() validates the type and size of an IOTLB update, but
does not validate its permission field. An invalid permission can therefore
reach perm_to_iommu_flags() and trigger its warning in vhost_vdpa_map().

Reject IOTLB UPDATE messages whose permission field is empty or contains
bits outside VHOST_ACCESS_RW before dispatching them to a backend.

Fixes: 4c8cf31885 ("vhost: introduce vDPA-based backend")
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260913-fix-vhost_chr_write_iter-v1-1-76bf1f436cfe@gmail.com>
2026-11-02 09:07:00 -05:00
Xiang Mei
1f8824fe7f vdpa: fix double free of the reply skb in vdpa_nl_cmd_dev_config_get_doit()
genlmsg_reply() consumes the reply skb on every outcome: netlink_unicast()
frees it whether it queues it, drops it, or bails out early.
vdpa_nl_cmd_dev_config_get_doit() lets its return value fall through to the
shared error label, which calls nlmsg_free(msg) again and double-frees the
sk_buff on any reply failure. The failure is reachable unprivileged:
VDPA_CMD_DEV_CONFIG_GET carries no GENL_ADMIN_PERM, so batching several
requests into one sendto() on a socket with a shrunken SO_RCVBUF fills the
receive queue, and netlink_attachskb() then takes its MSG_DONTWAIT path,
freeing the skb and returning -EAGAIN.

Set msg to NULL once genlmsg_reply() has consumed it so the shared exit
path frees the skb only on the early error gotos that still own it;
nlmsg_free(NULL) is a no-op.

  BUG: KASAN: slab-use-after-free in sk_skb_reason_drop (net/core/skbuff.c:1220)
  Read of size 4 at addr ffff88800d99d49c by task exploit/147
  Call Trace:
   sk_skb_reason_drop (net/core/skbuff.c:1220)
   vdpa_nl_cmd_dev_config_get_doit (drivers/vdpa/vdpa.c:1324)
   genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114)
   genl_rcv_msg (net/netlink/genetlink.c:1194)
   netlink_rcv_skb (net/netlink/af_netlink.c:2556)
   genl_rcv (net/netlink/genetlink.c:1218)
   netlink_unicast (net/netlink/af_netlink.c:1345)
   netlink_sendmsg (net/netlink/af_netlink.c:1900)
   __sys_sendto (net/socket.c:2281)
   __x64_sys_sendto (net/socket.c:2284)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

  The buggy address belongs to the object at ffff88800d99d3c0
   which belongs to the cache skbuff_head_cache of size 232
  The buggy address is located 220 bytes inside of
   freed 232-byte region [ffff88800d99d3c0, ffff88800d99d4a8)

Fixes: ad69dd0bf2 ("vdpa: Introduce query of device config layout")
Reported-by: co+6dcbccedc9ec6452@bugs.sh
Closes: https://lore.kernel.org/all/ILTHcT8oe1HP47sY25JVxssvKmkCTjYlX9Hs%40bugs.sh/
Assisted-by: Claude:claude-opus-5
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reported-by: Paul Moses <p@1g4.org>
Message-ID: <20260912215401.126194-1-xmei5@asu.edu>
2026-11-02 09:07:00 -05:00
Maoxia
104d58a6d2 virtio_pci: add missing newline to the pmcsr error message
The error message emitted when the PCI power management control
register cannot be read is not newline-terminated, so the next kernel
message is appended to it on the same line.

Add the missing '\n'.

Fixes: dff4fa0e57 ("virtio: Add support for no-reset virtio PCI PM")
Signed-off-by: Maoxia <2312891301@qq.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <tencent_031B923A83E0DEE884BD05D49030890C0406@qq.com>
2026-11-02 09:07:00 -05:00
Linfeng Sun
bfcde6b647 vhost: fix dirty logging for in-order used ring entries
With VIRTIO_F_IN_ORDER, one used ring element can represent multiple
buffers, so vhost_add_used_n_in_order() can write consecutive elements to
nonadjacent slots. Dirty logging combines the initial slot with a length
based on the final position, which can miss written elements or log past
the end of the ring.

Replay nheads[] after the write barrier and log the written slots,
coalescing adjacent elements and splitting at gaps and wraps.

Fixes: 67a873df0c ("vhost: basic in order support")
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Message-ID: <20260912-fix-log_write-v1-1-72c23db01268@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-02 09:07:00 -05:00
Dudu Lu
fe812fd896 vhost/vringh: Fix IOTLB permission in putu16_iotlb()
putu16_iotlb() performs a write operation (__put_user / WRITE_ONCE)
but requests IOTLB translation with VHOST_MAP_RO (read-only
permission).  This means the IOTLB lookup succeeds only if the page
has read permission, ignoring write permission entirely.  A page
mapped read-only in the IOTLB would incorrectly allow the write,
while a page mapped write-only would incorrectly deny it.

The neighbouring getu16_iotlb() correctly uses VHOST_MAP_RO for its
read operation, and the copydesc write path (putdesc_iotlb) correctly
uses VHOST_MAP_WO, confirming this is a copy-paste error.

Fix by changing VHOST_MAP_RO to VHOST_MAP_WO to match the write
semantics of putu16_iotlb().

Fixes: 0ea9ee430111 ("vhost/vringh: add IOTLB support")
Signed-off-by: Dudu Lu <phx0fer@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260413090526.80563-1-phx0fer@gmail.com>
2026-11-02 09:06:59 -05:00
Jia Jia
a016d03a9c vhost-scsi: do not relock event vq mutex on send_evt fallback
vhost_scsi_send_evt() is called with the event virtqueue mutex held.
If the worker is gone, the fallback currently calls
vhost_scsi_complete_events(), which tries to acquire the same mutex again
and deadlocks the caller.

Split event completion into a helper for callers that already hold the
mutex and a locking wrapper for the event worker. Use the helper on the
fallback path.

Link: https://lore.kernel.org/all/20260905005352.1E5B01F00A3D@smtp.kernel.org/
Fixes: b1b2ce58ed ("vhost-scsi: Handle vhost_vq_work_queue failures for events")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260915094244.7900-3-physicalmtea@gmail.com>
2026-11-02 09:06:59 -05:00
Jia Jia
a9a428115b vhost-scsi: preserve event ordering
vhost_scsi_send_evt() uses llist_add(), so pending events are LIFO.
vhost_scsi_complete_events() walks the detached list directly.
This can deliver a later hotplug or hotunplug event before an earlier
one.

Reverse the detached list before processing it.
This keeps delivery in enqueue order.

Fixes: a6c9af8736 ("tcm_vhost: Add hotplug/hotunplug support")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260915094244.7900-2-physicalmtea@gmail.com>
2026-11-02 09:06:59 -05:00
Linfeng Sun
acbf36deb5 vdpa: invalidate DMA mappings before releasing memory
vdpa can release pinned pages and file references before the device stops
using the corresponding mappings, allowing stale DMA to corrupt memory.

Invalidate mappings before dropping their backing references. For set_map
backends, publish an IOTLB without the invalidated range and keep the old
references if that fails. Do this immediately even within a batch.

Serialize vdpa_sim set_map updates with its worker so publishing a new map
cannot race an active transfer. Abort mlx5 map replacement when resumable
virtqueues cannot be suspended, since changing the memory region while
those queues remain active would preserve the same stale DMA window. Reject
zero-sized and wrapping invalidations before calculating their inclusive
range end.

I found this bug myself, though the patch was written with AI assistance.

Fixes: 4c8cf31885 ("vhost: introduce vDPA-based backend")
Assisted-by: OpenAI-Codex:GPT-5
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Message-ID: <20260911-fix-vdpa-iotlb-lifetime-v3-2-8766d371748e@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-02 09:06:59 -05:00
Linfeng Sun
8517ed4429 vdpa_sim: serialize IOTLB updates with dataplane access
The simulator translates IOTLB entries into iovecs or bvecs under
iommu_lock, then drops the lock before copying data. A concurrent DMA
unmap can delete the mapping and release its pinned backing pages while
the copy is still in progress, leading to a UAF in _copy_from_iter().

Use the existing simulator mutex to serialize DMA map changes with the
full backend work function. Also make vhost-vdpa stop device access before
unpinning the backing pages. Otherwise, waiting in the simulator DMA unmap
callback happens after the pages have already been released and cannot
protect their lifetime.

Keep iommu_lock for the IOTLB table itself and avoid adding a second
long-lived lock to the simulator.

I found this bug myself, though the patch was written with AI assistance.

Fixes: 2c53d0f64c ("vdpasim: vDPA device simulator")
Assisted-by: OpenAI-Codex:GPT-5
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Message-ID: <20260911-fix-vdpa-iotlb-lifetime-v3-1-8766d371748e@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2026-11-02 09:06:59 -05:00
Li RongQing
d7825623a9 virtio_ring: reset IN_ORDER state in virtqueue_init()
The IN_ORDER feature uses additional software state to track the next
available descriptor and in-flight descriptor batches.

virtqueue_init() resets the common virtqueue state, but free_head and
batch_last.id are initialized only when the virtqueue is created. When
an IN_ORDER virtqueue is reset, these fields can retain state from the
previous queue instance.

Reset free_head and invalidate batch_last when initializing an IN_ORDER
virtqueue. Keep this in virtqueue_init() so the state is initialized
consistently for both newly created and reset virtqueues.

Fixes: f6a15d8549 ("virtio_ring: add in order support")
Signed-off-by: Li RongQing <lirongqing@baidu.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260910123903.1717-1-lirongqing@baidu.com>
2026-11-02 09:06:59 -05:00
Karl Mehltretter
62b0a9b11e virtio-spi: Fix virtio_spi_config kernel-doc
struct virtio_spi_config contains max_cs_inactive_ns, but its
kernel-doc describes max_cs_incative_ns. This leaves the real member
undescribed and adds a nonexistent member to the generated
documentation.

Correct the spelling.

Fixes: 6a1f3390fa ("virtio-spi: Add virtio-spi.h")
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260909064938.90995-1-kmehltretter@gmail.com>
2026-11-02 09:06:58 -05:00
Paolo Abeni
631c3b1859 Merge branch 'sfc-fix-ptp-synchronization-races'
Alex Austin says:

====================
sfc: fix PTP synchronization races

This series fixes PTP synchronization races found by code inspection, and
a related frequency-adjustment bug found while reviewing the locking.

efx_ptp_start() resets the driver's cached current_adjfreq as though
MC_CMD_PTP_OP_ENABLE also resets the NIC's frequency adjustment on the
MC. It does not, so the next time-only adjustment reprograms the clock
from a stale cache. Patch 1 removes this reset.

efx_ptp_pps_worker() and the SIOCSHWTSTAMP path through
efx_ptp_change_mode() both call efx_ptp_synchronize(). Concurrent calls
can interfere with the shared DMA handshake and the shared timeset
results, because the MCDI interface is released inside
efx_mcdi_rpc_finish() and acquired after the handshake flag is cleared.
Patch 2 serializes a function's synchronization transactions and clock
operations under a new mutex. Patch 3 returns the PPS timestamp in
caller-owned storage to prevent concurrent synchronization from
overwriting it while the PPS worker reads it.

Tested on two hosts with X2522-25G NICs cabled back to back at 25G.
Both PCI functions share one clock.

Clock operations on the function that registers the clock were run
against repeated efx_ptp_change_mode() -> efx_ptp_synchronize() on the
other function:

  hwstamp_ctl -i ens41f0np0 -r 1 -t 1
  hwstamp_ctl -i ens41f1np1 -r 1 -t 1

  for i in $(seq 150); do
          phc_ctl /dev/ptp1 freq 1000
          phc_ctl /dev/ptp1 adj 0.0001
          phc_ctl /dev/ptp1 get
  done &
  for i in $(seq 40); do
          hwstamp_ctl -i ens41f1np1 -r 0 -t 0
          hwstamp_ctl -i ens41f1np1 -r 1 -t 1
  done &
  wait

  ethtool -S ens41f1np1 | grep ptp_

                                without    with
  ptp_good_syncs                     400     400
  ptp_bad_syncs                        0       0
  ptp_sync_timeouts                    0       0
  ptp_no_time_syncs                    0       0
  ptp_invalid_sync_windows             0       0
  ptp_undersize_sync_windows           0       8
  ptp_oversize_sync_windows            0       0

The undersize counter rejects readings as implausibly fast rather than
inaccurate. FW reports a 40ns minimum sync window; without the series
the fastest readings sit exactly on that limit, and with it they sit a
few nanoseconds below. The shift tracks the barrier in the mutex
acquisition rather than the serialization it provides: an smp_mb() alone
where the mutex is taken reproduces the counter on an otherwise
unmodified driver, while a plain memory access there does not. No
synchronization failed: each takes eight readings and needs one to
succeed.

End-to-end PTP sync quality is unchanged (tested with ptp4l and
phc2sys).
====================

Link: https://patch.msgid.link/20261026123023.3566549-1-alex.austin@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:02:49 +01:00
Alex Austin
23d23e6c65 sfc: ptp: avoid racing PPS timestamp updates
efx_ptp_pps_worker() can race with SIOCHWTSTAMP via
efx_ptp_change_mode(). After the worker completes synchronization, the
ioctl can start another synchronization and update host_time_pps while
the worker copies it into the PPS event. This can report a partially
updated timestamp. Serializing synchronization transactions alone does
not protect this copy, which happens after phc_lock is released.

Return the timestamp through the caller's own pps_event_time rather
than the shared field in efx_ptp_data, so the worker reads storage no
one else can write.

Fixes: 7c236c43b8 ("sfc: Add support for IEEE-1588 PTP")
Signed-off-by: Alex Austin <alex.austin@amd.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Link: https://patch.msgid.link/20261026123023.3566549-4-alex.austin@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:02:48 +01:00
Alex Austin
f707347b33 sfc: ptp: serialize host and MC synchronization transactions
efx_ptp_synchronize() clears the MC-ready DMA flag before
efx_mcdi_rpc_start() acquires the MCDI interface, and processes results
into ptp->timeset[] after efx_mcdi_rpc_finish() has released it. The PPS
worker and the hwtstamp enable path can therefore clobber each other's
handshake flag and timesets.

Hold a PHC mutex across the whole transaction and over the clock
operations, so efx_phc_settime() reads and adjusts atomically and
current_adjfreq is consistently read and written under one lock. Also
bail out when efx_mcdi_rpc_start() fails rather than finishing an RPC
that was never acquired.

Fixes: 7c236c43b8 ("sfc: Add support for IEEE-1588 PTP")
Signed-off-by: Alex Austin <alex.austin@amd.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20261026123023.3566549-3-alex.austin@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:02:48 +01:00
Alex Austin
21d4917cfc sfc: ptp: drop the stale frequency reset in efx_ptp_start()
FW does not touch the clock frequency state on MC_CMD_PTP_OP_DISABLE or
MC_CMD_PTP_OP_ENABLE, so the driver doesn't need to either. Doing so
just desyncs the driver's cached current_adjfreq from what FW still has
programmed.

Resetting current_adjfreq to 0 here means the first efx_phc_adjtime()
call after efx_ptp_start() reprograms the NIC's clock frequency to 0,
since efx_phc_adjtime() always sends current_adjfreq to FW alongside
the time step. efx_ptp_start() runs on every SIOCSHWTSTAMP mode change,
on ifup, and on the reset_required path in efx_ptp_worker(), so each of
those silently drops any frequency correction the PTP servo had already
applied.

efx_ptp_start() is also reached from reset recovery, but that is fine:
on an FLR or PCIe reset FW does not touch the NIC clock, and on a full
MC reboot the clock is reset to 1970, so a stale current_adjfreq from
before the reset is hardly consequential - especially as it is bound to
MAX_PPB, 1000000 ppb.

Fixes: 7c236c43b8 ("sfc: Add support for IEEE-1588 PTP")
Signed-off-by: Alex Austin <alex.austin@amd.com>
Link: https://patch.msgid.link/20261026123023.3566549-2-alex.austin@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 15:02:44 +01:00
Anthony Iliopoulos
1e253beed5 xfs: skip iunlock with empty iolock flags in xfs_file_dio_write_aligned
When using RWF_NOWAIT, xfs_file_write_checks may fail to acquire an
exclusive lock upgrade and return -EAGAIN for aligned DIO, setting
iolock to 0.

In XFS_DEBUG kernels, passing no lock flags to xfs_iunlock triggers an
assertion failure. Fix this by unlocking the iolock only when there are
any flags set.

Fixes: 2e23834058 ("xfs: implement direct writes to zoned RT devices")
Signed-off-by: Anthony Iliopoulos <ailiop@suse.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 14:35:16 +01:00
Qihang
1f1f8e8c51 cipso: fix optlen corruption in cipso_v4_delopt()
cipso_v4_delopt() recomputes the option length by walking the option
buffer after the CIPSO option has been moved out.  The walk then reads
the stale bytes at the tail of the buffer as option data, and a crafted
setsockopt(IP_OPTIONS) buffer can make it treat one of them as an option
length, increasing opt->opt.optlen beyond the valid option data.

The corrupted length stays on the socket and is later used as the copy
length by getsockopt(IP_OPTIONS) and by the udp/raw/ping sendmsg paths,
where it exceeds the size of the buffers they copy into.

Compute the new length from the intact options before the move and
subtract the CIPSO length, and fill the padding with IPOPT_END.

Assisted-by: LLM
Fixes: 014ab19a69 ("selinux: Set socket NetLabel based on connection endpoint")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 12:53:31 +00:00
Daniel Machon
263a5514cb net: lan966x: don't free XDP buffers in fdma tx clear with budget 0
lan966x_fdma_tx_clear_buf() runs from the NAPI poll and frees the
buffers of completed tx DCBs with napi_consume_skb(),
page_pool_recycle_direct() and xdp_return_frame_bulk().

netpoll calls the NAPI poll with a budget of 0 and hardirqs disabled.
With a budget of 0, a driver cannot call any XDP or page pool API.

Before this patch, the XDP_TX pages and ndo_xdp_xmit frames are freed
regardless of the budget. With netconsole on the port that owns the
FDMA NAPI, such a buffer is freed with hardirqs disabled, and
__page_pool_put_page() warns via lockdep_assert_no_hardirq().

Leave the XDP buffers of completed DCBs in place when the budget is 0,
and free them in the next NAPI poll. napi_consume_skb() already handles
a budget of 0, so skbs are still freed.

Found by an AI code review agent. Reproduced on a lan9668 board with a
modified kernel that runs the NAPI poll with a budget of 0 and hardirqs
disabled. With the fix the warning is gone.

Fixes: 19c6f534f6 ("net: lan966x: Add support for XDP_TX")
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261029-lan966x-fdma-tx-clear-budget-v1-1-38c52d7aab8c@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 12:59:38 +01:00
Daejun Park
5745f4f10a xfs: don't skip free extents of the longest length in a whole-AG FITRIM
Since commit a66d636385 ("xfs: fix fstrim offset calculations"), the
by-length walk of an AG in FITRIM starts with
xfs_alloc_lookup_ge(cur, 0, pagf_longest) and walks down. The lookup
lands on the longest free extent with the lowest block number. The
other free extents of that length sort after it and are never
discarded.

Start every by-length batch with xfs_alloc_lookup_le() at restart_bno.

Suggested-by: Dave Chinner <dgc@kernel.org>
Link: https://lore.kernel.org/r/ZgiJWxVcVwag0fIP@dread.disaster.area
Cc: stable@vger.kernel.org
Fixes: a66d636385 ("xfs: fix fstrim offset calculations")
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 12:55:09 +01:00
Daejun Park
595e67d726 xfs: don't skip free extents in later batches of a whole-AG FITRIM
A whole-device FITRIM walks every AG but the last by length, in
batches. xfs_trim_gather_extents() saves the record to restart from in
tcur->start. But tcur->start is also the start of the range to trim.
Later batches therefore never discard the free extents below that
block.

Save the restart record in a new restart_bno field.

Cc: stable@vger.kernel.org # v6.10
Fixes: b0ffe661fa ("xfs: fix performance problems when fstrimming a subset of a fragmented AG")
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 12:55:09 +01:00
Armin Wolf
086aeca907
platform/x86: uniwill-laptop: Implement .hw_offloaded trigger callback
Since commit 8e04e5382a ("leds: trigger: Add hw_offloaded() callback
and provide trigger_may_offload_to_hw attribute") the LED subsystem
allows triggers to report if they are being offloaded to the underlying
hardware. Implement the necessary callback so that the LED subsystem
knows that the lightbar trigger is always offloaded to hardware.

Fixes: d1c0c89969 ("platform/x86: uniwill-laptop: Implement rainbow animation as trigger")
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://patch.msgid.link/20261030194704.424388-1-W_Armin@gmx.de
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
2026-11-02 13:32:40 +02:00
Wilfred Mallawa
7e31d6dd34 xfs: fix unwind handling during xfs_mount_sysfs_init()
The goto for failing to setup /error/metadata jumps to the wrong place
in xfs_mount_sysfs_init(). Fix it.

Fixes: a9a7b9e868 ("xfs: add support for lazy direct read bounce buffering")
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 12:10:00 +01:00
Ravi Singh
bde0010631 xfs: mark i_mode=0 and shut down on attr fork inactivation failure
xfs_attr_inactive() can fail on an I/O error reading the attribute
fork's btree blocks, for example from fault injection such as the
dm-flakey errors used by xfstests generic/475. On failure,
xfs_ifork_zap_attr() zeros af_nextents without freeing the attribute
blocks or decrementing i_nblocks, leaving the inode in an
inconsistent in-memory state.

The inode is marked XFS_IRECLAIMABLE and remains in the cache. If a
concurrent operation (e.g., XFS_IOC_FSBULKSTAT) calls xfs_iget() on
this inode, xfs_iget_check_free_state() will allow recycling if
i_mode != 0. The recycled inode reuses the stale in-memory state
(af_nextents=0, i_nblocks=1).

When the recycled inode is queued for inactivation again,
xfs_attr_inactive() sees af_nextents=0 and skips truncation, leaving
i_nblocks non-zero. This triggers the assertion in xfs_ifree():

  XFS: Assertion failed: ip->i_nblocks == 0

Clear i_mode so the stale inode cannot be recycled, and force a
shutdown so log recovery frees the still-unlinked inode on the next
mount.

Suggested-by: Dave Chinner <dgc@kernel.org>
Signed-off-by: Ravi Singh <ravising@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 12:04:34 +01:00
Binbin Deng
0344a9492e xfs: set healthmon mount cookie before publishing it
xfs_ioc_health_monitor() allocates the healthmon object with kzalloc(), so
mount_cookie starts as zero.  zero is also DETACHED_MOUNT_COOKIE, but
xfs_healthmon_attach() publishes hm through mp->m_healthmon before storing
the mount cookie.  A concurrent reporter can therefore acquire hm from
xfs_healthmon_get(), see the detached cookie in xfs_healthmon_push(), and
drop the event even though the monitor is being attached.

This is reachable by racing XFS_IOC_HEALTH_MONITOR with an operation
that reports a health event, such as a filesystem shutdown.  Initialize
the mount cookie before making hm visible through the RCU pointer so
reporters always observe an attached monitor.

Found during a static-analysis-assisted audit: candidate sites were
surfaced by a Coccinelle rule, and the reader/writer paths were
confirmed by LLM-assisted (GLM-5.3) code inspection.  The issue was
not observed at runtime; it is identified by code inspection only.

Fixes: a48373e7d3 ("xfs: start creating infrastructure for health monitoring")
Cc: stable@vger.kernel.org
Signed-off-by: Binbin Deng <18983559317@163.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2026-11-02 12:02:12 +01:00
Hungyu Lin
cbf04dde8b ext2: preserve completed DIO bytes when buffered fallback fails
ext2_dio_write_iter() can complete part of a direct write before
falling back to buffered I/O for a hole inside i_size. If
generic_perform_write() then fails, its error overwrites the completed
direct-I/O byte count.

For example, on a full filesystem, an 8 KiB write to a file with an
allocated 4 KiB prefix and a 4 KiB hole overwrites the prefix but returns
ENOSPC and leaves the file position unchanged. GNU dd with oflag=direct
consequently reports zero bytes written.

Preserve a positive direct-I/O result and return the buffered error
when no bytes were direct-written. This restores the fallback policy of
generic_file_write_iter(), which ext2 used before its iomap conversion.

Fixes: fb5de4358e ("ext2: Move direct-io to use iomap")
Cc: stable@vger.kernel.org
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
Link: https://patch.msgid.link/20261102061555.55183-1-dennylin0707@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-11-02 11:45:08 +01:00
Paolo Abeni
21f57ec673 Merge branch 'net-stmmac-xdp-path-fixes'
Lorenzo Bianconi says:

====================
net: stmmac: XDP path fixes

This series adds some stmmac XDP preliminary fixes needed to introduce XDP
RX multi-buff support.

v1: https://lore.kernel.org/r/20261023-stmmac-xdp-fixes-v1-0-efb37e19f5bd@oss.qualcomm.com
====================

Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-0-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:15 +01:00
Lorenzo Bianconi
363ff81627 net: stmmac: fix XDP RX buffer DMA sync length
stmmac_rx() bounded the DMA sync length by the largest data_end seen
before and after the XDP program and passed it to page_pool_put_page()
on the XDP_CONSUMED path. bpf_xdp_adjust_tail() zeroes the grown area,
which dirties the CPU cache, but a later negative adjust only moves
data_end back. If the program grows and then shrinks the tail, both
endpoints miss the zeroed range, so those dirty cache lines are not
written back before the page is reused.

The length was also wrong since commit 8809572851 ("net: stmmac: fix
rx Scatter-Gather support") moved the page_pool DMA window to offset 0
and set max_len to dma_buf_sz + page_offset: the driver still
subtracted buf->page_offset, so it synced [base, data_end - page_offset)
instead of [base, data_end).

On a non-coherent platform those dirty lines can be evicted after the
device has DMA'd the next frame into the recycled page and corrupt it.

Sync the whole page_pool DMA window on the XDP_CONSUMED path with
page_pool_recycle_direct(), as the PASS path and page_pool allocation
already do. The device only writes [page_offset, page_offset +
dma_buf_sz), so syncing [base, base + max_len) covers every cache line
it can touch, regardless of how the program adjusted the packet.

Fixes: be8b38a722 ("net: stmmac: Add support for XDP_TX action")
Fixes: 8809572851 ("net: stmmac: fix rx Scatter-Gather support")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-6-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
Lorenzo Bianconi
68bdbffcae net: stmmac: fix VLAN tag stripping on short and non-linear RX frames
stmmac_rx_vlan() reads the VLAN header straight from skb->data and
removes it with skb_pull(), assuming the header is fully present in the
linear part of the skb. XDP can change the frame length and head layout
before the tag is stripped.

An XDP program can use bpf_xdp_adjust_tail() to shrink a frame to as
little as ETH_HLEN while bytes 12-13 still contain a VLAN ethertype. The
driver then reads h_vlan_TCI past skb->len and pops the tag, leaving less
than ETH_HLEN in the skb. eth_type_trans() cannot pull the MAC header, so
a malformed skb is passed up. The TCI is also read from the wrong place
when the tag is not fully in the linear head, e.g. when it spans into a
frag.

Read h_vlan_proto after pulling ETH_HLEN into the linear part, and check
it together with the device features. Only if the tag is actually going
to be popped, pull VLAN_ETH_HLEN and re-derive the header pointer
afterwards, as pskb_may_pull() may reallocate the skb head. Return an
error so the callers can drop a frame that claims a VLAN tag but cannot
provide the full header. This also drops and counts frames shorter than
ETH_HLEN in rx_dropped, even when VLAN RX offload is disabled;
bpf_xdp_adjust_head() and bpf_xdp_adjust_tail() cannot produce such a
frame, so it only affects a runt that reaches the driver, and dropping it
is safer than handing it to eth_type_trans().

Also move the XDP metadata written with bpf_xdp_adjust_meta() together
with the MAC header when the tag is popped, so data_meta still points at
the metadata after eth_type_trans() anchors mac_header, instead of at the
first bytes of the destination MAC.

Fixes: 5fabb01207 ("net: stmmac: Add initial XDP support")
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-5-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
Lorenzo Bianconi
41d78e9ac0 net: stmmac: copy XDP metadata in AF_XDP zero-copy RX
stmmac_construct_skb_zc() reserves headroom for the XDP metadata and
records the length reported by the XDP program, but only copies the
packet data starting at xdp->data. The bytes in
[xdp->data_meta, xdp->data) are never copied into the new skb, so the
skb advertises metadata that is not there: after eth_type_trans()
anchors mac_header, data_meta points at uninitialized headroom instead
of what the program wrote.

Copy the metadata together with the packet data starting at
xdp->data_meta, leaving skb->data at the start of the frame and the
metadata immediately before it, and record its length. This keeps
data_meta valid for the stack and TC BPF after eth_type_trans() anchors
mac_header.

Fixes: bba2556efa ("net: stmmac: Enable RX via AF_XDP zero-copy")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-4-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
Lorenzo Bianconi
52ffd771e0 net: stmmac: drop multi-buffer frames in XDP mode
stmmac_rx() runs the XDP program once per descriptor buffer and uses
skb == NULL as the only marker for the start of a frame. A frame larger
than one buffer is split by the hardware across several descriptors;
GMAC4 enables jumbo frames unconditionally (GMAC_CONFIG_JE in
GMAC_CORE_INIT), so an on-link peer can deliver such a frame even when
the interface MTU is left at 1500.

When an XDP verdict ends a non-last descriptor, skb is cleared and the
next descriptor of the same hardware frame is parsed as a new frame.
For XDP_CONSUMED this happens via read_again with len preserved, so
stmmac_rx_buf1_len() then returns min(dma_buf_sz, plen - len) for the
last descriptor, which can be as small as 0-3 bytes. buf1_len -=
ETH_FCS_LEN underflows and xdp_prepare_buff() puts data_end far past
data; on XDP_PASS this produces an skb whose length is close to 4G that
reaches the network stack (skb->tail and skb->len are 32-bit and wrap
below skb->end, so skb_over_panic() does not fire). A 4+ byte tail is
instead offered to the XDP program and delivered as a standalone
mid-payload Ethernet frame on XDP_PASS. XDP_TX/XDP_REDIRECT instead
falls through to the next iteration, resetting the running length, so
the tail is re-parsed as a full-size new frame.

The same fault exists when a single descriptor uses its second buffer:
buffer2 is now handed to the hardware for non-SPH frames on GMAC4/XGMAC,
so a frame up to 2 * dma_buf_sz can land on a single descriptor while the
XDP program still only sees the first buffer. XDP_TX then transmits a
truncated frame, and XDP_PASS appends the second buffer only after the
program has already run over the first one.

XDP does not support scatter-gather frames until the multi-buffer
rework, so drop the whole frame instead. When a non-last descriptor is
seen while an XDP program is attached, mark the frame as errored and
drain the remaining descriptors, including the last. A descriptor that
uses its second buffer is dropped directly before the program runs as
well; in XDP mode it is necessarily the last descriptor of the frame,
so it does not need the error marker. Removing the re-parse lets both
XDP verdict branches simply complete the packet via next.

The buffers consumed by the discard path are no longer returned to the
page pool, and the new SG and second-buffer drops do not return them
either. They stay in rx_q->buf_pool[] and stmmac_rx_refill() reuses them
in place, allocating only when a slot is empty. This is safe because the
drop checks run before the buffer is synced for CPU access or
prefetched. The discard-path change and the in-place reuse apply with or
without an XDP program attached.

The !error guard on the discard check also changes the accounting for
errored multi-descriptor frames on dwmac100/dwmac1000: rx_errors is
incremented once per frame instead of once per descriptor. This too is
independent of XDP mode.

Note: the subsequent "net: stmmac: rework stmmac_rx to support XDP rx
multi-buff" accumulates the whole frame into a single xdp_buff and
supersedes this patch; the fix is kept so the net portion of the series
stands on its own.

Fixes: 5fabb01207 ("net: stmmac: Add initial XDP support")
Fixes: 8809572851 ("net: stmmac: fix rx Scatter-Gather support")
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-3-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
Lorenzo Bianconi
834ec95308 net: stmmac: drop split frames on AF_XDP zero-copy RX
stmmac_rx_zc() assumes a 1:1 mapping between a received frame and an
XSK pool buffer and drops any frame that spans more than one RX
descriptor:

        /* XSK pool expects RX frame 1:1 mapped to XSK buffer */
        if (likely(status & rx_not_ls)) {
                xsk_buff_free(buf->xdp);
                buf->xdp = NULL;
                dirty++;
                count++;
                goto read_again;
        }

The non-last descriptors are freed and dropped, but the frame is not
marked as errored. When the poll reaches the last descriptor of the
same frame, error is still 0, so the fragment is handled as a complete
frame: it is passed to the XDP program, copied into an skb on XDP_PASS,
or converted for XDP_TX. The tail starts in the middle of the original
payload at a predictable offset and, parsed as a fresh frame (len == 0),
stmmac_rx_buf1_len() reports the full dma_buf_sz length for it even
though the DMA engine only wrote the tail remainder into that buffer, so
the reads extend past the received bytes and can reach beyond the end of
the XSK pool buffer. GMAC4 always enables jumbo frames (GMAC_CONFIG_JE
in GMAC_CORE_INIT), so an on-link peer can trigger such a split even
when the interface MTU is left at 1500.

Set error when the 1:1 mapping check drops a descriptor, so the
remaining descriptors of the frame - including the last one - are
drained and released with xsk_buff_free() instead of being processed as
a new frame. Account every freed buffer with dirty and count the
dropped frame once in the poll budget / rx_pkt_n. The direct 1:1
mapping drop also increments rx_dropped.

Use a bit test instead of an equality test for discard_frame.
Commit 644b8437cc ("net: stmmac: dwmac4: report Rx checksum errors
in status") made dwmac4_wrback_get_rx_status() set discard_frame on
RDES3_ERROR_SUMMARY and OR in csum_none on RDES1_IP_HDR_ERROR or
RDES1_IP_PAYLOAD_ERROR, so it can return discard_frame | csum_none.
The old "status == discard_frame" test missed that value and delivered
frames with CRC, overflow, watchdog or giant errors to the stack in
stmmac_rx() - or to XDP/XSK in stmmac_rx_zc() - when they also failed
the IP checksum. The change therefore affects the regular RX path, not
only zero-copy. The bit test is also required for the
discard_frame | rx_not_ls value returned for non-last legacy
descriptors below.

Normalize the legacy normal and enhanced descriptor callbacks to report
rx_not_ls together with discard_frame for non-last descriptors. This
allows both stmmac_rx_zc() and stmmac_rx() to drain split frames on
dwmac100 and dwmac1000 instead of reparsing the final fragment as a new
packet.

Fixes: bba2556efa ("net: stmmac: Enable RX via AF_XDP zero-copy")
Fixes: 644b8437cc ("net: stmmac: dwmac4: report Rx checksum errors in status")
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-2-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
James Hilliard
26219e9402 net: stmmac: take ownership of saved RX state at poll entry
When a saved partial packet completes with a poll budget of one, the
old loop can leave state_saved and state.skb pointing at an skb that
has already been delivered or freed. The next poll then reuses that
pointer, causing a use-after-free or double free.

Take the saved state at poll entry and clear the stored ownership
immediately. Save it again only if the packet remains incomplete,
including when the next descriptor is still DMA-owned.

Track the frame-in-progress flag independently of the status read from
the next descriptor. The old code keyed the save on the status of the
last descriptor looked at, so a loop stopped at a DMA-owned descriptor
(rx status not yet valid) could drop the saved error/length bookkeeping
in stmmac_rx_zc().

Drop the saved state both when the queue parameters are reset and when
the ring is destroyed. stmmac_reset_rx_queue() is reached from
__stmmac_open(), stmmac_xdp_open(), stmmac_resume() and
stmmac_enable_rx_queue(); without draining it there, a partial frame
saved before suspend (or before a queue is disabled and re-enabled)
survives while cur_rx and dirty_rx are rewound to zero. On the resume
path the ring is only re-armed in place: stmmac_clear_descriptors()
sets the ownership bits and stmmac_init_dma_engine() restores the tail
pointer, but the RX buffer addresses are not reprogrammed. The first
poll would then resume the stale skb against a ring position that no
longer matches the descriptors it was built from.
__free_dma_rx_desc_resources() releases it on teardown.

Apply the same state handling to stmmac_rx_zc(), which also leaves
state_saved set when a saved frame finishes at the budget boundary.
That path saves only error and length bookkeeping, not an skb pointer.

Fixes: ec222003bd ("net: stmmac: Prepare to add Split Header support")
Fixes: bba2556efa ("net: stmmac: Enable RX via AF_XDP zero-copy")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Co-developed-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20261027-stmmac-xdp-fixes-v2-1-10eae8a093a8@oss.qualcomm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-11-02 11:43:11 +01:00
David Hildenbrand (Arm)
d90bdc02e3 mm/huge_memory: properly handle refcounted PUD mappings on fork
copy_huge_pud() copies device-DAX entries without taking a folio reference
or updating mapcounts and the child's RSS.

For example, MADV_GUARD_INSTALL sets VM_MAYBE_GUARD on a device-DAX VMA,
forcing copy_page_range() to traverse the whole VMA on fork. Any remaining
huge PUDs are then copied without accounting for the new mappings.
Unmapping them in the child decrements accounting that was never added.

Use vm_normal_page_pud() to identify refcounted mappings. Take a folio
reference and add the child's PUD rmap and RSS accounting before installing
the copied entry. Pass src and dst VMAs consistently instead of src and
dst MM. Move the TODO.

Fixes: aed877c2b4 ("device/dax: properly refcount device dax pages when mapping")
Cc: stable@vger.kernel.org
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-11-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
David Hildenbrand (Arm)
f09171b67e mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio()
Since the deferred split queue became a list_lru, the isolate callback
moves the folios it took a reference on to an on-stack list, linked
through folio->_deferred_list, and deferred_split_scan() takes them off
that list with list_del_init() without holding the list_lru lock.

deferred_split_folio() does not know about the on-stack list. It only
holds the list_lru lock when it looks at the same list_head, and it can
run for such a folio: a THP is queued when it is mapped, as a candidate
for the underused check, and is queued "again" when a part of it gets
unmapped:

  CPU0 deferred_split_scan()          CPU1 deferred_split_folio()
  list_del_init(&folio->_deferred_list)
    next->prev = prev
    prev->next = next
    entry->next = entry
                                      list_lru_lock_irqsave()
                                      folio_set_partially_mapped()
                                      __list_lru_add()
                                        list_empty(item)  -> true
                                        list_add_tail(item, &l->list)
                                          item->next = &l->list
                                          item->prev = tail
    entry->prev = entry

The folio now sits on the list_lru with ->prev pointing to itself. The
next removal leaves the neighbours pointing to it, and they still do so
after the folio has been freed. With CONFIG_DEBUG_LIST:

  list_del corruption. prev->next should be ffd4000000270090, but was
  ffd4000000278090. (prev=ffd4000000270090)

Fix it by grabbing the lock around list_del_init() so
deferred_split_folio() cannot race with it.

Fixes: fafaeceb89 ("mm: switch deferred split shrinker to list_lru")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Mani Tofigh <mt4022@columbia.edu>
Tested-by: Mani Tofigh <mt4022@columbia.edu>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-10-d6437171ecc3@kernel.org
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
David Hildenbrand (Arm)
f3c493d2f4 mm/rmap: handle device-exclusive entries in folio_referenced_one()
page_vma_mapped_walk() can return non-present device-exclusive entries,
but folio_referenced_one() passes them to PTE young-bit accessors that
require present PTEs.

We must neither call clear_flush_young_ptes_notify() nor
folio_pte_batch() with non-present entries. For example, clearing the
young bit on non-present PTEs can corrupt the entry: on arm64
PTE_AF overlaps the swap type, so clearing it turns a device-exclusive
entry into an ordinary swap entry.

folio_pte_batch() will VM_WARN_ON_FOLIO.

Apply the same approach as the previous fixes to e.g., damon_ptep_mkold():
treat these entries as old from the CPU's perspective and obtain their
young state through the MMU notifier.

Skip PTE batching and MGLRU look-around for non-present entries, and
don't modify non-present PTEs.

Fixes: b756a3b5e7 ("mm: device exclusive memory access")
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-9-d6437171ecc3@kernel.org
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
David Hildenbrand (Arm)
97156a6c35 mm/filemap: finish fault cleanup before dropping the fault lock
On a retried fault, a fatal signal interrupting the folio lock wait
makes lock_folio_maybe_drop_mmap() drop the fault lock without pinning
the file. However, filemap_fault() may still need to release
mapping->invalidate_lock. A concurrent munmap() can release the last
file reference and free the mapping before that unlock.

Defer dropping the fault lock to filemap_fault()'s retry cleanup, after
releasing invalidate_lock. If the fault lock was already dropped for
I/O, release the existing file reference instead. Keep the fault lock
held for FAULT_FLAG_RETRY_NOWAIT as before.

Fixes: 730633f0b7 ("mm: Protect operations adding pages to page cache with invalidate_lock")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Reviewed-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-8-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
Josef Bacik
8ccb6ded6a mm/filemap: don't lose a folio lock wakeup to a signal
An exclusive waiter in folio_wait_bit_common() can leave the wait loop
because of a fatal signal, then be woken by folio_unlock() before
finish_wait(). If the waker did not hand over the lock, the waiter returns
-EINTR without trying to acquire it.

folio_wake_bit() stops after waking the first exclusive waiter, so this
loses the wakeup and can leave other waiters asleep indefinitely on an
unlocked folio.

After finish_wait(), let a waiter woken without a lock handoff try once
more to acquire the lock. If successful, return success so the caller's
eventual unlock wakes the next waiter. Otherwise, the current lock owner
will do so.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 5ef64cc898 ("mm: allow a controlled amount of unfairness in the page lock")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: clarify and simplify comment + description ]
Reviewed-by: Rik van Riel <riel@surriel.com>
Acked-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-7-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
Josef Bacik
dc24e27324 mm/filemap: read mapping->a_ops->free_folio under i_lock
memory_failure() -> ... -> filemap_remove_folio() can read mapping->a_ops
after the inode has been freed. Once the folio is deleted from the
pagecache it no longer pins the mapping, so after i_lock is dropped
e.g., a concurrent final iput() can evict and free the inode before
filemap_free_folio() looks up mapping->a_ops->free_folio.

Most callers hold a reference on the inode, but not all.

Documentation/filesystems/vfs.rst explicitly states that ->free_folio()
must not assume the original address_space mapping still exists.

Fix it by loading ->free_folio while i_lock is still held, similar to
what folio_unmap_invalidate() does.

Inline filemap_free_folio() into its remaining caller such that
delete_from_page_cache_batch() also just loads the callback before
dropping the i_lock.

The bug was found by code inspection and has not been reproduced.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 59c66c5f8c ("mm: factor out page cache page freeing into a separate function")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: get rid of filemap_free_folio() entirely; improve patch description ]
Reviewed-by: Rik van Riel <riel@surriel.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-6-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
David Hildenbrand (Arm)
9cf632e139 mm/truncate: look again if a folio left the mapping
invalidate_inode_pages2_range() skips a folio which no longer belongs to
the mapping by the time it has got the folio lock, on the assumption
that somebody else has removed it from the page cache. But the folio may
have been replaced, and then there is a new folio with the same data at
that index.

For most cases, like folio migration, that is impossible. However,
collapse_file() only checks the refcount of the old folios, under the
i_pages lock, and relies on their folio locks from there on. That works for
users which repeat the lookup when they find folio->mapping changed.
The following scenario is, however, possible:

  CPU0 pwrite(O_DIRECT)               CPU1 collapse_file()
  kiocb_invalidate_pages()
                                      read the folio (old data), lock it
                                      refcount check
  the write completes                 copy to new_folio
  kiocb_invalidate_post_direct_write()
    find_get_entries() -> old folio
                                      xas_store(new_folio)
                                      folio->mapping = NULL
                                      folio_unlock(folio)
    folio_lock()
    folio->mapping != mapping
      -> continue

In that scenario, the collapsed folio with the data from before the write
stays in the page cache after the write has returned.

This used to be impossible, as khugepaged only collapsed files that nobody
had open for writing.

Restart the lookup at that index, like shmem_undo_range() does. The same
problem seems to exist in truncate_inode_pages_range() as well when
truncate_inode_folio() fails, so handle it there as well, but slightly
differently: simply check once more through find_get_entries().

Fixes: 1b6444331b ("mm/khugepaged: enable clean pagecache folio collapse for writable files")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Rik van Riel <riel@surriel.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-5-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:29 +01:00
Josef Bacik
5426cd43a4 mm/memfd: make f_pos accesses atomic
Commit 9c225f2655 ("vfs: atomic f_pos accesses as per POSIX") made
read(), write() and lseek() on a shared open file description of a regular
file serialize on ->f_pos_lock.  The flag that asks for it,
FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
too, but its struct file comes from alloc_file_pseudo() and never passes
through do_dentry_open(), so it does not get the flag:

  CPU0                                CPU1
  write(memfd, "a", 1)                write(memfd, "b", 1)
    pos = file->f_pos  (= 0)
                                        pos = file->f_pos  (= 0)
    vfs_write(..., &pos)
                                        vfs_write(..., &pos)
    file->f_pos = pos  (= 1)
                                        file->f_pos = pos  (= 1)

One of the two bytes is overwritten.  Two threads writing 100000 bytes
each, one at a time, to a memfd end up with a file that is far shorter than
200000 bytes, while the same program on a tmpfs file never loses a byte.

Set the flag when the memfd is created.  As for any other regular file the
lock is only taken if the file is reachable in more than one way, and
nothing a memfd does in read or write waits for another operation on the
same file.  This cannot be done for all alloc_file_pseudo() files: anon
inode files such as eventfd are S_IFREG as well, and a blocked read holding
->f_pos_lock would lock out the write that is supposed to wake it.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 9183df25fe ("shm: add memfd_create() syscall")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: minor description tweaks ]
Reviewed-by: Rik van Riel <riel@surriel.com>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-4-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
d371011183 mm/shmem: make shmem_file() check the file's inode
shmem_file() only checks if file->f_mapping is a shmem mapping. This
mapping can belong to another file, however, as with a Coda file backed
by a tmpfs container after mmap().

So it does not guarantee that the file inode is an actual shmem inode.

Seal handling and memfd preservation use this check before accessing
shmem inode state, so they can access an inode of the wrong type.

Let's make shmem_file() check the inode's file operations instead, to
identify shmem inodes reliably. This will identify regular shmem inodes,
including memfds and ordinary tmpfs files, independently of wrapper file
operations.

Use shmem_mapping() in collapse_file() instead to not change the behavior
of collapse_file(): it operates on the page cache and uses mapping->host
for shmem inode operations. Focusing on the file does not seem relevant.

Fixes: c49fcfcda8 ("mm/shmem: update file sealing comments and file checking")
Fixes: b3749f174d ("mm: memfd_luo: allow preserving memfd")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Suggested-by: Pratyush Yadav <pratyush@kernel.org>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Link: https://patch.msgid.link/20261031-fixes_core-v3-3-d6437171ecc3@kernel.org
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
ef694e2d21 fork: take mmap_lock before copying mm_struct
dup_mm() copies the parent's mm_struct before dup_mmap() takes the
mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
and newer heap mappings, causing later brk() requests to fail.

Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
cause inconsistencies.

As a simple and robust fix, grab the parent's mmap_lock earlier. This
way we don't need to update individual mm fields in dup_mmap() and
keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
exec_vm, stack_vm), as that is now no longer required.

Keep releasing the parent's mmap_lock in dup_mmap(), before
userfaultfd completion, to avoid moving the userfaultfd handling into the
caller. This should get cleaned up later.

Move uprobe_start_dup_mmap() to preserve the lock ordering.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Rik van Riel <riel@surriel.com>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: SJ Park <sj@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-2-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Josef Bacik
65a9bf08a3 mm/mglru: don't use stack pointers when walking PUD and PMD tables
MGLRU passes stack copies of page-table entries in walk_pud_range() and
walk_pmd_range() when walking to the next level. These copies can become
stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
table concurrently.

This pattern dates back to commit bd74fdaea1 ("mm: multi-gen LRU:
support page table walks"). Likely, earlier locking masked the latent
bug. Later changes exposed it: commit 1d65b771bc ("mm/khugepaged:
retract_page_tables() without mmap or vma lock") allowed concurrent
retraction, and commit cf4a65539c ("memcg-v1: no need for memcg locking
for MGLRU") dropped the walker's outer RCU protection.

The fix is simple, so just fix the original commit so we don't have to
speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
RCU-protected lookup and validation against the live PMD. Note that the PUD
handling is required as well to handle folded page tables correctly in all
cases.

Fix generated by an LLM and sent by Josef Bacik in private.

[ david: handle walk_pud_range() as well, clarify+simplify description,
         adjust Fixes: ]

Fixes: bd74fdaea1 ("mm: multi-gen LRU: support page table walks")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Rik van Riel <riel@surriel.com>
Reviewed-by: Qi Zheng <qi.zheng@linux.dev>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Kairui Song <kasong@tencent.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: SJ Park <sj@kernel.org>
Link: https://patch.msgid.link/20261031-fixes_core-v3-1-d6437171ecc3@kernel.org
Reviewed-by: Baoquan He <baoquan.he@linux.dev>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
59511d630a mm/shmem: fix truncation of files containing only swapin-error markers
It might not be very common, but we can end up with shmem files that are
composed only of swapin-error/poison markers.

Such markers are not counted in info->alloced. Consequently,
shmem_setattr() can skip shmem_truncate_range(), leaving the markers
behind.

Truncating the file to zero and growing it again will result in reads
failing with -EIO instead of returning zeroes.

Check whether the mapping contains entries, in addition to
info->alloced, before skipping the truncation. Keep the info->alloced
check so that shmem_recalc_inode(), called at the end of
shmem_undo_range(), can fix up accounting after reclaim has emptied the
mapping.

Fixes: 6cec2b95da ("mm/shmem: fix infinite loop when swap in shmem error at swapoff time")
Cc: stable@vger.kernel.org
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-15-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
66ce68a249 mm/shmem: fix accounting of swapin-error markers
A failed swap read replaces the swap entry with a swapin-error marker in
the page-cache and subtracts its pages from "alloced" and "swapped";
however, it leaves their block charge in place.

Removing the marker during truncate then subtracts from "swapped" again.
This can underflow the counters or make swapped reach zero while other
pages remain swapped out, causing swapoff to loop without finding them.

When installing the marker, subtract only from "swapped" and let
shmem_recalc_inode() reduce "alloced" and release the block charge.

Make shmem_free_swap() report successful removal separately from the
number of swap pages freed, so removing a swapin-error marker does not
subtract from "swapped" again.

It's a bit confusing, but replacing a swapped out page by a swapin-error
marker in shmem_set_folio_swapin_error() behaves as follows:

Initially:
	alloced=1, swapped=1, nrpages=0
Calling shmem_recalc_inode(inode, 0, -1)
	-> swapped = 0
	-> freed =  1 - 0 - 0 = 1
	-> alloced -= freed
	-> alloced=0, swapped=0, block charge released

Fixes: 6cec2b95da ("mm/shmem: fix infinite loop when swap in shmem error at swapoff time")
Cc: stable@vger.kernel.org
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-14-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
5f1ec2cf92 mm/shmem: fix truncate loop after boundary swapin failure
If swapping in a large entry at the new EOF fails, shmem_undo_range()
leaves the entry in place. Its final scan skips the entry, then restarts
from the same start index and finds it again. Truncation can loop forever
while holding i_rwsem.

Advance start past the skipped entry so that a restarted scan can finish,
as we already do for folios that cannot be split.

Note that this does not fix the missing zeroing when boundary swapin fails,
it merely prevents the endless loop.

Fixes: 8a1968bd99 ("mm/shmem, swap: fix race of truncate and swap entry split")
Cc: stable@vger.kernel.org
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-13-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
f4ce23b1fe mm/shmem: preserve allocation errors when swapping in large entries
shmem_swapin_folio() adjusts swap to the requested slot within a large
swap entry before allocating a folio. If allocation or charging fails,
the error path compares this adjusted value with the original entry
still stored in the XArray in shmem_confirm_swap().

Unless the index is at the start of the entry, this turns -ENOMEM into
-EEXIST even though nothing changed.

The caller retries -EEXIST, so persistent allocation failures can leave
the task spinning instead of returning the error.

Restore swap to index_entry on allocation failure so the existing error
path checks the original entry. This preserves the allocation error if
the entry is unchanged and still retries if it changed concurrently.

Fixes: 91ab656ece ("mm/shmem, swap: tidy up swap entry splitting")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-12-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
fa213b08f3 mm/shmem: fix truncate hang in large swap entry
Truncating a tmpfs file or memfd to a page-aligned size inside a large
swap entry can loop indefinitely in shmem_undo_range(). The task holds
the inode lock and cannot be killed.

A large swap entry represents a whole swapped-out folio. For example,
truncate a file whose pages 0-7 share one swap entry to four pages:

    [ 0  1  2  3 | 4  5  6  7 ]
         keep    |   discard
                 ^
            new EOF, start = 4

i_size has already been updated when boundary handling asks
shmem_get_partial_folio() for page 4. Since it is swapped out, the helper
calls shmem_get_folio() with SGP_READ. That rejects page 4 with -EINVAL
because its starting offset equals i_size. Nothing is read back.

The final scan cannot free the entry without losing pages 0-3. It skips
it, restarts from start = 4, and finds it again indefinitely. An unaligned
truncate avoids this particular failure because the requested page starts
below i_size. Folios already in the page-cache cannot trigger it as the
direct lookup will return them beyond EOF.

Fix it by letting shmem_get_partial_folio() call shmem_swapin_folio()
directly for swap entries. This bypasses the read path's i_size check,
allowing the existing boundary handling to zero and split the folio. If
swap-in returns a smaller folio, it also splits the swap entry so the
final scan can free the entries beyond EOF. Retry the lookup if the entry
changes during swap-in.

Handling swap-in allocation failures remains broken and is unchanged by
this commit. Even when shmem_swapin_folio() correctly returns -ENOMEM
instead of -EEXIST, shmem_get_partial_folio() returns NULL and
shmem_undo_range() skips boundary handling. If the large swap entry
remains intact, truncation can still loop in the final scan, while hole
punching can return without zeroing the boundary.

This may read an entire large folio back from swap while holding
i_rwsem, only to discard part of it. Avoiding that I/O would require
splitting both the swap entry and any large folio still in the swap
cache. That, however, is much bigger work.

Fixes: 8a1968bd99 ("mm/shmem, swap: fix race of truncate and swap entry split")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-11-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
f0d67b3d0a mm/shmem: rescan after nonuniform folio splitting
The final scan in shmem_undo_range() restarts after a successful split
only if the original folio is no longer large. A nonuniform split can
leave that folio large, so the scan skips the newly created folios.
Hole punching then leaves pages within the hole allocated even though
they could be discarded.

For example, a fault below the hole can allocate a 2 MiB folio after
boundary handling. Punching a 1 MiB hole at offset 64 KiB splits the
folio successfully but leaves the original folio at order 4. The scan
continues past all 512 pages, leaving 2 MiB allocated instead of 1 MiB.
The hole reads as zero, but the pages and their block charges remain.

Fixes: 7460b470a1 ("mm/truncate: use folio_split() in truncate operation")
Cc: stable@vger.kernel.org
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-10-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
David Hildenbrand (Arm)
23f2a880c0 mm/shmem: discard whole new large folios on fallocate rollback
When undoing a failed fallocate(), shmem_undo_range() must discard each
newly allocated folio. Its second scan instead passes large
folios to truncate_inode_partial_folio(), which does not necessarily
discard the entire large folio, but instead tries splitting it to
discard only the requested range.

For example, with huge=always, a failed allocation starting at offset
4 KiB can leave page 0 allocated in an otherwise empty file.

Discard the whole folio when unfalloc is set. Note that we enter this
path only for folios that are not uptodate, and can consequently be
dropped without losing any data.

Fixes: 55ac8bbe35 ("mm/shmem: fix race in shmem_undo_range w/THP")
Cc: stable@vger.kernel.org
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-9-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Chris Mason
0c80043539 mm/shmem: preserve data in clean folios when splitting fails
A shared writable mapping can have dirty PTEs while its shmem folio is
still clean. A read fault can install a writable PTE, and a later store
sets the PTE's dirty bit without marking the folio dirty.

After shmem_undo_range() has handled the boundary folios, a concurrent
read fault into a hole below the new EOF can allocate a large folio.
For example, on a tmpfs mount with huge=always, the fault's offset must
be within the file, but the allocated folio can extend beyond i_size.
The final scan then finds this folio and calls
truncate_inode_partial_folio() without marking it dirty.

Splitting normally collects the PTE dirty bits when unmapping the
folio. An extra reference, for example from vmsplice(), can make it
fail before that step. The fallback unmapping on split failure excludes
shmem, so the helper still sees a clean folio and drops it, losing data
outside the range.

CPU0: ftruncate(fd, 3M)                CPU1: MAP_SHARED, tmpfs huge=always
─────────────────────────────────────  ──────────────────────────────────
i_size = 3M
shmem_undo_range(3M, -1)
  first pass: hole, nothing to do
  boundary folio at 3M: hole, none
                                       read fault at 2M+x (below EOF)
                                         PMD folio [2M,4M), crosses EOF
                                         writable PTE, folio clean
                                       store to 2M+x
                                         PTE dirty, folio still clean
                                       vmsplice(2M+x)
                                         extra folio reference
  whole_folios: finds [2M,4M) folio
  truncate_inode_partial_folio()
    zero [3M,4M)
    folio_split()
      unmap_folio(): extra ref
        → -EAGAIN, PTE dirty bit
          never reaches the folio
    folio clean
      → truncate_inode_folio(whole)
        [2M,3M) dropped
                                       read 2M+x → refault → zeroes

Mark large folios dirty before partial truncation in the final scan,
as the boundary handling already does. Exclude failed-fallocate
rollback, which must discard the folios it added.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: b9a8a4195c ("truncate,shmem: Handle truncates that split large folios")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: simplify descriptions, adjust comments ]
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-8-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Chris Mason
a842a1f947 mm/shmem: stop retrying folios that cannot be split
A fault or collapse can insert a large folio crossing EOF after
shmem_undo_range() has handled the boundary folios. If splitting that
folio fails, truncate_inode_partial_folio() retains it when it is dirty.
The final scan then repeatedly finds it because it restarts from an
unchanged start.

Truncation keeps the inode lock and ignores fatal signals while looping.
A concurrent unlink() can then block other directory operations while
holding the directory lock and waiting for the file's lock.

Advance start past the retained folio, whose truncated part has already
been zeroed. Do not move start backwards if the failed split has shrunk
the folio.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 55ac8bbe35 ("mm/shmem: fix race in shmem_undo_range w/THP")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: split fixes, simplify descriptions, adjust comments ]
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Balbir Singh <balbirs@nvidia.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-7-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Josef Bacik
8f59173b5c mm/shmem: hold off eviction in shmem_writeout()
Once shmem_writeout() has moved the folio from the page cache to the
swap cache, the folio lock no longer keeps the inode alive: truncation
and eviction find a swap entry, free it and do not wait for anybody.
That did not matter as long as swap_writeout() was the last thing the
function did.  But since it puts the folio back when swap_writeout()
returns AOP_WRITEPAGE_ACTIVATE, it uses the mapping and the inode
afterwards:

  reclaim                               last close of an unlinked file
  shmem_writeout()
    shmem_delete_from_page_cache()
    swap_writeout()
      zswap_store() fails               shmem_evict_inode()
      writeback is disabled               shmem_truncate_range()
      return AOP_WRITEPAGE_ACTIVATE         shmem_free_swap()
                                        destroy_inode()
                                        ... RCU grace period, freed
    shmem_add_to_page_cache(mapping)
      xas_lock_irq()            <- use after free

swap_writeout() behaves that way if zswap is enabled, cannot take the
folio and the memcg or one of its ancestors has memory.zswap.writeback
set to 0.

shmem_unuse() already added infrastructure to deal with that.
Reuse info->stop_eviction to protect the inode during writeout. Increment
it before removing the folio from the page cache, and decrement it after
swap_writeout() and any attempted reinsertion and inode accounting.
In shmem_evict_inode(), wait for the counter to reach zero even if
swapoff has already removed the inode from the swap list. Add some helpers
to make the code easier to digest.

There is a known remaining issue with two swapoffs racing, and the empty
list check not being able to detect that race. That will be addressed
separately later.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 6344a6d9ce ("mm/shmem: writeout free swap if swap_writeout() reactivates")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Baolin Wang <baolin.wang@linux.alibaba.com>
[ david: code cleanups; improve description ]
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-6-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Eva Kurchatova
b7f570e7ce hugetlbfs: enforce F_SEAL_EXEC in setattr
F_SEAL_EXEC is enforced by shmem_setattr(), but hugetlbfs_setattr() does
not check it. As a result, fchmod() can change the execute bits of a
sealed hugetlbfs memfd.

Use memfd_check_seals_mode() in hugetlbfs_setattr() to reject changes
to execute bits when F_SEAL_EXEC is set.

This also fixes the memfd_test hugetlbfs SEAL-EXEC subtest, where
fchmod() incorrectly succeeded after applying F_SEAL_EXEC.

Fixes: 6fd7353829 ("mm/memfd: add F_SEAL_EXEC")
Cc: stable@vger.kernel.org
Signed-off-by: Eva Kurchatova <eva.kurchatova@virtuozzo.com>
Link: https://patch.msgid.link/20260629180247.2343229-1-eva.kurchatova@virtuozzo.com
Acked-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
[ david: use common helper; fixup Fixes:; check only regular files ]
Acked-by: Oscar Salvador <osalvador@suse.de>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-5-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Chris Mason
0237c47ca1 mm/shmem: honour F_SEAL_EXEC when an ACL is set
The owner of a memfd sealed with F_SEAL_EXEC can still change its
execute bits by setting a POSIX access ACL. With CONFIG_TMPFS_POSIX_ACL,
this lets an unprivileged owner make a non-executable memfd executable,
bypassing vm.memfd_noexec=2.

simple_set_acl() updates i_mode directly, bypassing the seal check in
shmem_setattr(). Add shmem_set_acl() to check the resulting mode. Share
the F_SEAL_EXEC check with shmem_setattr() using memfd_check_seals_mode()
in include/linux/memfd.h.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 6fd7353829 ("mm/memfd: add F_SEAL_EXEC")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Acked-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: use common helper; simplify description ]
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-4-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Josef Bacik
d5d861ee30 tmpfs: preserve explicitly disabled quota limits
An administrator’s decision to disable a user’s or group’s quota
limits can be silently lost when tmpfs restores the mount defaults
after releasing and reacquiring the quota record. This can cause
later file creation or writes to fail with EDQUOT, even though the
administrator has explicitly disabled quota limits for the user or
group.

do_set_dqblk() sets DQ_FAKE_B when all block and inode limits are zero.
This means quota enforcement is disabled for that user or group.
shmem_is_empty_dquot() treats the flag as a reason to discard the entry
from the mount's quota tree. The next shmem_acquire_dquot() finds no
saved entry and recreates it with the mount's default hard limits.

If the cached dquot is reused, DQ_FAKE_B remains set: Q_GETQUOTA reports
the restored defaults, but enforcement is still disabled. Once that
dquot has been reclaimed, a new dquot enforces the restored defaults.

Remove the DQ_FAKE_B test. Only discard entries with zero usage, zero
soft limits and hard limits equal to the mount defaults. Explicitly
disabled limits are then preserved whenever the mount defaults are
nonzero.

Explicitly disabled limits now retain a quota-tree entry, just like other
limits that differ from the mount defaults.

Rename shmem_is_empty_dquot() to shmem_is_default_dquot() to describe
the check for default values.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: de4c0e7ca8 ("shmem: Add default quota limit mount options")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: code cleanups; rewrite description ]
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-3-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Josef Bacik
968d734630 tmpfs: keep the quota soft limits of an unused id
When the last reference to a dquot goes away, shmem_release_dquot()
stores its limits in the rb tree of the mount, unless
shmem_is_empty_dquot() says that there is nothing worth storing. That
function looks at the usage and at the two hard limits only.

So if the administrator sets nothing but soft limits for an id that owns
no file yet, the entry is thrown away as soon as the dquot that
Q_SETQUOTA used is released, and the id never gets to see a limit.

To fix it, compare the soft limits as well: an entry can be empty only if
both soft limits are zero as well, which is exactly what
shmem_acquire_dquot() sets for a new entry.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: de4c0e7ca8 ("shmem: Add default quota limit mount options")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: slightly adjusted description ]
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-2-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Chris Mason
68b2aa37af mm/mempolicy: charge shared policy nodes
Any local user can bypass memory.max with mbind() on a tmpfs file, and
allocate unbounded kernel memory.

mbind() sets a NUMA memory policy for a range of a mapping. If the
mapping is of a shmem and friends, the kernel also stores the policy on
the inode, in a tree with one entry per range of the file.

Each mbind() on a single page of a mapping can add one shared policy node
(struct sp_node) and one struct mempolicy to that tree. They outlive the
mapping and stay around until the inode is destroyed. The tree is not
bounded by the file size, so the file can be empty.

Memory that user space can allocate must be charged to a memory cgroup. A
slab cache does that for all of its objects if it is created with
SLAB_ACCOUNT. numa_policy_init() creates the slab caches for both
structs without SLAB_ACCOUNT, so they are not charged to any cgroup.

Reproduced with mbind() on single pages of an empty tmpfs file, from a
cgroup with memory.max=8M: the global OOM killer killed tasks owned by
root, and the machine panicked.

Fix this by creating both caches with SLAB_ACCOUNT. This change implies
that mbind() can now fail when running into memcg limits. Further,
the policy_cache also serves task and VMA policies, so they are
similarly accounted now.

Note that per-file limits are not really helpful, as the user could
simply use many files; having limits per user is tricky as well.

Fix generated by an LLM and submitted by Chris Mason in private.

Fixes: 5d097056c9 ("kmemcg: account certain kmem allocations to memcg")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Acked-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>
[ david: smaller description tweaks ]
Reviewed-by: Balbir Singh <balbirs@nvidia.com>
Link: https://patch.msgid.link/20261029-fixes_shmem-v4-1-392fc715d8f6@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
2026-11-02 11:21:28 +01:00
Eric Dumazet
031c403d13 tcp: do not let tcp_collapse() drive sk_forward_alloc negative
tcp_collapse() charges each newly allocated skb with skb_set_owner_r()
before the skbs it replaces are freed, without scheduling memory first.

Since sk_mem_uncharge() reclaims eagerly, sk->sk_forward_alloc has no
cushion and can become negative. This can be durable when the collapsed
skbs had a high payload/truesize ratio or were partially read, because
the new skbs can have a bigger total truesize than the old ones.

A negative sk_forward_alloc then confuses tcp_wmem_schedule(), which
can return a negative length to tcp_sendmsg_locked(), triggering
a WARN_ON_ONCE(bytes > INT_MAX) in check_copy_size().

Call sk_forced_mem_schedule() before charging nskb.

Fixes: 4890b686f4 ("net: keep sk->sk_forward_alloc as small as possible")
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Octavian Purdila <tavip@google.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 10:21:23 +00:00
Cen Zhang (Microsoft)
23fec4bd76 ipv6: fix fib6 walker UAF on NLM_F_REPLACE
fib6_walker uses w->leaf to remember the next fib6_info to dump, so an
RTM_GETROUTE dump can continue there on the next recvmsg().  This
assumes that whoever removes a route from the tree also updates the
walkers pointing at it.  fib6_del_route() does: it moves w->leaf to
the next route.  The NLM_F_REPLACE branch of fib6_add_rt2node() does
not: it removes the old route, fib6_add() frees it, and w->leaf keeps
pointing at the freed object.

The fn_sernum version check in fib6_dump_table() normally protects
against resuming on a stale w->leaf, but it can be bypassed:
ip6_link_failure() resets fn_sernum to -1 when the default route
fails, which an unprivileged user in a user+net namespace can cause:

  1) link failure            fn_sernum = -1
  2) dump pauses on route R
  3) replace R               fn_sernum changed, R freed
  4) link failure            fn_sernum = -1
  5) dump resumes            -1 == -1, reads freed R  <- UAF

  BUG: KASAN: slab-use-after-free in rt6_fill_node+0x1c22/0x2cd0
  Read of size 4 at addr ff11000011fa0064 by task poc/101
   rt6_fill_node <- rt6_dump_route

Fix by adjusting walkers separately for replacement and deletion.
For replacement, add fib6_walkers_replace_leaf() points w->leaf
at the new route. For deletion and ECMP sibling removal,
fib6_walkers_skip_rt() calls fib6_walkers_replace_leaf() with the
next route. Reset w->skip_in_node when updating w->leaf, and set
w->state to FWS_U when no next route remains.

Fixes: 4a287eba2d ("IPv6 routing, NLM_F_* flag support: REPLACE and EXCL flags support, warn about missing CREATE flag")
Cc: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Cen Zhang (Microsoft) <cenzhang@linux.microsoft.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 09:56:02 +00:00
Vlad Poenaru
af449230bd bnxt_en: Don't keep MSI-X vectors added before FW reserves them
When dynamic MSI-X is supported, bnxt_check_rings() grows the MSI-X
vectors with bnxt_change_msix() once FW says the new rings would fit,
and keeps them.  FW only reserves the extra IRQs later, when
bnxt_reserve_rings() calls __bnxt_reserve_rings().  The MSI-X table
entries beyond the function's reserved IRQs are not backed until then:
the MSI message written when the new vectors are activated is lost, and
the entries read back as zero.  After FW reserves them they are live but
still zero, so the NQ rings bound to them signal address 0 and every
completion on those rings is lost.  The next ring change (for example
ethtool -G) then times out freeing each of those rings and the TX
watchdog fires:

  bnxt_en 0002:01:00.0 eth0: Resp cmpl intr err msg: 0x51
  bnxt_en 0002:01:00.0 eth0: hwrm_ring_free type 1 failed. rc:fffffff0 err:0
  ...
  bnxt_en 0002:01:00.0 eth0: NETDEV WATCHDOG: CPU: 17: transmit queue 18 timed out 5716 ms

On x86 this is hidden: GENERIC_IRQ_RESERVATION_MODE makes the PCI MSI
domains MSI_FLAG_MUST_REACTIVATE, so the message is composed and written
again when the IRQ is requested, after FW has reserved the vector.
Since commit 0d6a7c4179 ("irqchip/gic-v3-its: Enable dynamic MSI-X
allocation"), arm64 GICv3 systems take the dynamic path as well, but
write the message only once, at allocation.  On an NVIDIA Grace system
with a BCM57508, raising the channel count from 18 to 32 left MSI-X
entries 18-31 all zero, and the 14 rings using them lost their
interrupts.

Keep the allocation in bnxt_check_rings() as a check that enough vectors
are available, but free the new vectors again right away when FW manages
IRQ reservations (BNXT_NEW_RM).  bnxt_reserve_rings() then allocates
them after __bnxt_reserve_rings() has reserved them.  Without
BNXT_NEW_RM there is no IRQ reservation and bnxt_reserve_rings() does
not grow the vectors, so keep the current behaviour there.

In bnxt_reserve_rings(), size that allocation from the rings FW actually
reserved (bnxt_get_num_msix()) instead of the count computed before the
reservation, so that a partial grant does not activate unreserved
entries either, at least while no RoCE driver is registered.

The allocation can now fail after FW has committed the reservation.  A
later open would then find nothing to reserve and return before growing
the vectors, and bnxt_request_irq() would use irq_tbl[] entries past
bp->total_irqs, which still hold the freed virqs.  Grow the vectors in
that case as well, and clear irq_tbl[].vector when trimming.

Fixes: 2d51eb0bd8 ("bnxt_en: Add MSIX check in bnxt_check_rings()")
Reported-by: Andrew Preece <apreece@meta.com>
Closes: https://lore.kernel.org/all/20261022193620.2152038-1-vlad.wing@gmail.com/
Signed-off-by: Vlad Poenaru <vlad.wing@gmail.com>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 09:34:18 +00:00
Joas Antonio dos Santos
902407bc58 net/mlx5: macsec: free struct mlx5_fs_id after an RCU grace period
macsec_fs_id_del() removes a struct mlx5_fs_id from its rhashtable with
rhashtable_remove_fast() and then frees it with kfree() right away.

The TX (SCI) table is read locklessly from the transmit path:
mlx5e_macsec_handle_tx_skb() and mlx5e_macsec_tx_build_eseg() call
mlx5_macsec_fs_get_fs_id_from_hashtable(), which does
rhashtable_lookup() under rcu_read_lock() and then reads
mlx5_fs_id->id. A transmit that looked the entry up just before it was
removed reads freed memory.

Before commit d4ece08f4b ("net/mlx5: Maintain fs_id xarray per MACsec
device inside macsec steering") the SCI table held struct
mlx5e_macsec_sa directly, and mlx5e_macsec_del_txsa() freed it with
kfree_rcu_mightsleep(). That commit moved the table into macsec_fs.c
with the new struct mlx5_fs_id, but frees it with a plain kfree().

Add an rcu_head to struct mlx5_fs_id and free it with kfree_rcu().

The same issue was flagged by the Sashiko AI review as a pre-existing
problem while reviewing the HW-GRO for PSP series.

Fixes: d4ece08f4b ("net/mlx5: Maintain fs_id xarray per MACsec device inside macsec steering")
Link: https://lore.kernel.org/all/20260909065542.4B80D1F00ACA@smtp.kernel.org/
Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com>
Assisted-by: Yaga Agent HackerSec Claude:claude-opus-5-5
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 09:20:26 +00:00
Peter Hunt
10f51f4fb9 net: wwan: mhi_wwan_ctrl: send a DTR drop before it can be coalesced
DTR/RTS changes are sent from a work item that only sends the latest
state, so a drop followed quickly by a raise, for example TIOCMBIC then
TIOCMBIS or a quick close and reopen, can reach the modem as just the
raise. A drop matters on its own, a modem set to AT&D2 hangs up on it.

Flush the work when DTR goes low so the drop is sent before ->dtr_rts()
returns, and flush it in stop() so any pending state is sent before the
channel is stopped. A drop that hits a full UL ring is still retried
with whatever state is latest by then.

Fixes: d509edf90b ("net: wwan: mhi_wwan_ctrl: drive DTR/RTS via the IP_CTRL channel")
Suggested-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Peter Hunt <peter.hunt@opengear.com>
Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 09:15:34 +00:00
Federico Musto
c4ba171685 net: atl1c: drop oversized RX frames instead of panicking
atl1c sizes its receive buffers from the netdev MTU plus a fixed set of L2
overheads, which comes to 1522 bytes at the default MTU.  A link partner
that sends a longer frame - in practice a MikroTik CCR2004-1G-2XS-PCIe,
whose RouterOS side defaults to l2mtu 1600 while the host stays at MTU 1500
- makes the length reported by the RX return descriptor exceed what the
hardware wrote, and skb_put() then either includes bytes that were never
received or trips skb_over_panic and takes the host down.

Compare the descriptor length against buffer_info->length, the length the
hardware was given, rather than against skb_tailroom(): the skb carries 64
bytes of slack for the DMA erratum, so tailroom is larger than the DMA
buffer and a frame in between would pass the check and still be delivered
with a tail the device never wrote.  The same test rejects frames shorter
than ETH_HLEN + ETH_FCS_LEN; before this change a reported length below
ETH_FCS_LEN underflowed in skb_put().

The frame is dropped with kfree_skb_reason(SKB_DROP_REASON_PKT_TOO_BIG) so
drop_monitor and the kfree_skb tracepoint see it, and counted through
dev_core_stats_rx_dropped_inc(), which survives atl1c_get_stats()
overwriting the hardware counters on every read.  It also counts as work:
atl1c_clean_rfd() has already recycled the RFD, and the refill at the end
of the poll only runs when work_done is non-zero, so sustained oversized
traffic would otherwise drain the ring and stop RX.

Tested on a MikroTik CCR2004-1G-2XS-PCIe (4x AR8151) in a Proxmox VE host,
with atl1c built from a DKMS tree carrying this change: the l2mtu-1600
traffic that panics the stock driver is dropped and counted with the patch
applied, and received normally once the host MTU is raised to match.

This complements commit 36c2009d90 ("net: atl1c: fix soft lockup on
out-of-range tpd_cons read"), which fixed the TX side of the same
"host dies while the card resets" problem.

Fixes: 43250ddd75 ("atl1c: Atheros L1C Gigabit Ethernet driver")
Cc: stable@vger.kernel.org
Signed-off-by: Federico Musto <federico@rimpianto.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-11-02 08:27:03 +00:00
Yuqiang Sun
5e96760b25
bpf: lwt: Free the skb when bpf_xmit() fails to expand the headroom
When an LWT xmit program returns BPF_OK, bpf_xmit() makes sure that
the skb still has room for the link layer header. If
pskb_expand_head() fails there, bpf_xmit() returns -ENOMEM without
freeing the skb. Its callers, lwtunnel_xmit() and then
ip_finish_output2() or ip6_finish_output2(), take any return value
other than LWTUNNEL_XMIT_CONTINUE to mean that the skb has been
consumed, so nothing frees it.

Each such failure leaks the skb, together with what it holds: its dst
and its charge to the sending socket, so the socket is never freed
either. The other error paths of bpf_xmit() (BPF_DROP, an illegal
return code, a changed protocol, a failed reroute) all free the skb.

Free it here too.

The leak was found with kbound, a static analysis prototype for
ownership mismatches at kernel interfaces, on v7.2.12; it is present in
mainline.

Build-tested with x86_64 and arm64 allmodconfig (W=1, sparse): no new
warnings. Run-tested on QEMU (x86_64, KVM) with KASAN: a route through a
dummy device with an LWT xmit program that pushes one byte with
bpf_skb_change_head(), so the headroom check has to expand the head, and
failslab limited to allocations under bpf_xmit(). Each of 10 pings then
fails with ENOMEM. Without this patch each leaves a raw socket behind
(RAW slab objects 6 -> 16); with it none does (6 -> 6), and nothing else
is reported. Without injection both kernels go from 6 to 6.

Fixes: 3a0af8fd61 ("bpf: BPF for lightweight tunnel infrastructure")
Signed-off-by: Yuqiang Sun <izaiahsun@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101182343.17991-1-izaiahsun@gmail.com
2026-11-02 06:17:37 +00:00
Sean Rhodes
2433db2af8 firmware: coreboot: Fix CFR error-pointer handling warning
The scoped kfree cleanup already ignores error pointers, so passing the
pointer through no_free_ptr() before PTR_ERR() is unnecessary. It also
makes the IS_ERR/PTR_ERR expressions appear inconsistent to Coccinelle.

Return PTR_ERR() directly. The scoped cleanup still leaves error pointers
untouched while freeing successful allocations on later returns.

Fixes: f2e05ce976 ("firmware: coreboot: Add CFR firmware attributes driver")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202610210637.LiJ3U0ob-lkp@intel.com/
Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Link: https://lore.kernel.org/r/CABtds-16eUH6ah3Rr9R=N2605TPdFgDekM5oXVeWqGcmYfWqag@mail.gmail.com
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
2026-11-02 03:11:53 +00:00
Michał Kopeć
e094fd05de firmware: coreboot: Don't skip CBMEM entries outside of known memory
coreboot leaves CBMEM out of the /memory node of the device tree that it
passes to FIT payloads, e.g. LinuxBoot on arm64 Chromebooks, and only
lists it in the memory reservation block. The kernel has no resource for
that memory, so region_intersects() reports it as neither System RAM nor
Reserved memory, and since commit e31ecda9e3 ("firmware: coreboot:
Skip no-map CBMEM entries") all CBMEM entries are skipped on such boards.
That loses the coreboot log, the TPM event log and everything else that
CBMEM devices expose.

Also accept entries that don't intersect any memory resource. No-map
regions are still skipped, as they are IORESOURCE_MEM resources, as are
device regions.

Fixes: e31ecda9e3 ("firmware: coreboot: Skip no-map CBMEM entries")
Signed-off-by: Michał Kopeć <michal@nozomi.space>
Link: https://lore.kernel.org/r/20261017090351.1266064-1-michal@nozomi.space
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
2026-11-02 02:48:43 +00:00
Alexei Starovoitov
714b711201
Merge branch 'bpf-fixes-for-the-verifier-arena-skb-and-lwt-helpers'
Alexei Starovoitov says:

====================
bpf: Fixes for the verifier, arena, skb and lwt helpers

From: Alexei Starovoitov <ast@kernel.org>

These patches fix bugs in BPF:

  patches  area
  -------  ----------------------------------------------------------------
  01-02    stack traces: the limit of the trace length
  03-07    arena: the range of mmap() and of bpf_arena_free_pages()
  08-12    arguments of kfuncs and of extension progs
  13       cgroup detach: the permission check
  14       cgroup skb progs: the network offset
  15       bpf_skb_adjust_room(): the limit of gso_size
  16-24    lwt and seg6local End.BPF progs: pushed headers, skb->cb, dst
  25-27    skb offsets when a helper adds or removes room

10 of the patches are from Chris Mason and Josef Bacik. Patches 07 and 12
are selftests.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261101190535.1454146-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 00:10:41 +00:00
Chris Mason
ee36c9aa44
bpf: Check the offset in bpf_skb_generic_{push,pop}()
To make room for len bytes at offset off, bpf_skb_generic_push() moves the
first off bytes and clears len bytes after them. It assumes that the first
off bytes are in the linear part. But in bpf_skb_adjust_room() off can be
the end of the IP header, and this header can be in a frag. Then the
function reads and writes after skb->tail, and can damage skb_shared_info.

bpf_skb_generic_pop() checks off + len, but this u32 sum can wrap to a
small value. bpf_skb_adjust_room() and bpf_skb_change_proto() calculate off
from skb_mac_header_len(). This length is a very large u32 when
network_header < mac_header. Then the check can pass, and memmove() reads
and writes far outside the skb.

Return -ENOMEM from both functions, like the present check, when
off > skb->len. Thus the sum cannot wrap. In bpf_skb_generic_push() also
pull the first off bytes into the linear part. Now bpf_skb_adjust_room()
fails when a prog grows an skb that ends before off. network_header stays
wrong.

Fixes: 6578171a7f ("bpf: add bpf_skb_change_proto helper")
Fixes: 2be7e212d5 ("bpf: add bpf_skb_adjust_room helper")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-28-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Chris Mason
33be492c2e
bpf: Use the inner transport header after a decap
If skb->encapsulation is set, qdisc_pkt_len_segs_init() reads the TCP
header of a GSO packet at skb->inner_transport_header. Otherwise it uses
skb->transport_header. A decap with BPF_F_ADJ_ROOM_DECAP_L4_{GRE,UDP}
removes the outer transport header. It clears skb->encapsulation if no
tunnel flag remains in gso_type. The result in BPF_ADJ_ROOM_MAC mode is:

  before  | MAC | outer IP | GRE | inner IP | TCP | payload
          transport_header ^                ^ inner_transport_header
  after                    | MAC | inner IP | TCP | payload
                transport_header ^          ^ inner_transport_header

Then qdisc_pkt_len_segs_init() reads the inner IP header as a TCP header.
Thus the kernel can drop a valid packet with SKB_DROP_REASON_SKB_BAD_GSO.

Copy skb->inner_transport_header to skb->transport_header when a decap
clears skb->encapsulation. Keep skb->transport_header if it is larger. This
occurs if nothing sets the inner field. At tc ingress nothing changes for
IPIP or GRO packets. Both fields are at the TCP header there.

Fixes: ec20dee2f2 ("bpf: Clear decap state on skb_adjust_room shrink path")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-27-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Chris Mason
a9d08fe60f
bpf: Move the transport header with the moved headers
bpf_skb_net_hdr_pop() removes len bytes at offset off.
bpf_skb_net_hdr_push() does the opposite.

           skb->data       off
  before   | A             | removed | B            |
  after              | A             | B            |
                     skb->data       off

mac_header and network_header move with A. transport_header moves only when
it is equal to network_header. inner_transport_header never moves. This is
correct only for a header in B. In bpf_lwt_seg6_adjust_srh()
transport_header is in A. bpf_skb_adjust_room() can remove both transport
headers. With an incorrect header offset, the stack can drop the skb or
read outside of it.

Also move transport_header with A when it is in A. Set it to offset off
when it is in the removed bytes. In BPF_ADJ_ROOM_MAC mode it is then equal
to network_header. Do not unset it, because skb_gso_validate_mac_len() uses
it without a check. After a removal, set inner_transport_header to off when
it is not in B and skb->encapsulation is set. A has only outer headers.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Fixes: 868d523535 ("bpf: add bpf_skb_adjust_room encap flags")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-26-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
95f1d5e4ab
bpf: Don't let lwt_in progs call into IPv6 when it is disabled
With ipv6.disable=1, inet6_init() returns before it registers any pernet
subsystem. Thus net->ipv6.devconf_all and net->ipv6.seg6_data stay NULL.
IS_ENABLED(CONFIG_IPV6) only says that the code is built in.
bpf_lwt_input_reroute() and bpf_push_seg6_encap() call into IPv6, but do
not test ipv6_mod_enabled(). An lwt_in prog also runs with ipv6.disable=1,
and skb->protocol == htons(ETH_P_IPV6) does not prove that IPv6 is enabled.
Thus the kernel dereferences NULL and crashes.

Return -EAFNOSUPPORT before these calls if ipv6_mod_enabled() is false.
BPF_LWT_REROUTE then drops an IPv6 skb. With IPv6 enabled nothing changes.

The first Fixes tag is for bpf_push_seg6_encap(), which never had this
test. The second tag is for bpf_lwt_input_reroute(). Until that commit it
used ipv6_stub, which returned -EAFNOSUPPORT with ipv6.disable=1.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Fixes: ad84b1eefe ("bpf: remove ipv6_bpf_stub completely and use direct function calls")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-25-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
d9618a6196
bpf: Require BPF_LWT_REROUTE when an lwt_in prog changes the protocol
When an lwt_in prog returns BPF_OK, bpf_input() calls orig_input(), the
input handler of the route. This handler is for one IP version and needs a
dst of the same family. But BPF_LWT_ENCAP_IP lets the prog push a header of
the other IP version and thus change skb->protocol. Then the handler reads
and changes a header of the other IP version. The push of an SRH also
replaces the dst, because seg6_lookup_nexthop() puts an rt6_info into the
skb. Then ip_forward() uses the rt6_info as a struct rtable.

Drop the skb with -EINVAL when skb->protocol changes, as bpf_xmit() does.
Drop it also when the family of the dst changes, because skb->protocol does
not always show this change. Today no such skb leaves as the prog made it.
A prog works as before if it returns BPF_LWT_REROUTE, or if it pushes an
SRH on an IPv6 route.

The commit in the first Fixes tag lets a prog change skb->protocol. The
commit in the second tag adds the check to bpf_xmit() only.

Fixes: 52f278774e ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
Fixes: 3bd0b15281 ("bpf: add handling of BPF_LWT_REROUTE to lwt_bpf.c")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-24-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
b3ad42f618
bpf: Reset skb->cb after an lwt prog pushes an IP header
IPCB(skb)->opt holds the offsets from the network header to the IPv4
options. But bpf_lwt_push_ip_encap() moves the network header and does not
change IPCB(skb). Then ip_forward_options() and __ip_options_echo() use the
old offsets on the pushed header. Thus the kernel corrupts the skb and the
stack. If the family changes, the kernel also reads IP6CB(skb) as
IPCB(skb), or the reverse. With CONFIG_IPV6_MIP6, it reads IPSKB_FORWARDED
as frag_max_size and adds a needless fragment header.

Reset skb->cb after the prog. bpf_lwt_push_ip_encap() cannot do it, because
bpf_prog_run_save_cb() can restore skb->cb. For IPv4 in IPv4, clear
IPCB(skb)->opt as ip_tunnel_xmit() does. If the family changes, clear the
cb of the new family but keep iif, because ip6_forward() gets the input
device from it. Behind a VRF, skb->skb_iif is the VRF device and cannot
replace iif. Do nothing for IPv6 in IPv6, as in seg6_do_srh_encap().

Do the reset in bpf_input() only after a push. Without a push,
ip_forward_options() needs the offsets. Do it in bpf_xmit() before each
reroute, because an lwt_xmit prog can also change the options. Thus after a
reroute without a push, ip_options_fragment() leaves the options in all
fragments, and ICMP errors echo none. After BPF_OK or BPF_REDIRECT the skb
goes to a device, thus bpf_xmit() does no reset. The inner IPv4 checksum
can still be wrong after ip_rcv_options() changes an option.

Fixes: 52f278774e ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
Reported-by: Xiang Mei <xmei5@asu.edu>
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-23-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
701ffd202b
bpf: Don't leave a stale MAC header in bpf_lwt_push_ip_encap()
With BPF_LWT_ENCAP_IP, bpf_lwt_push_encap() pushes a new IP header. The new
header overwrites the MAC header of a received skb. But skb->mac_header
continues to point to the same bytes. Code that reads the MAC header after
the push, for example netfilter, gets bytes of the new header.

  before the push                        | MAC header  | old IP | payload
                                         ^ mac_header  ^ network_header
  today                            | new header        | old IP | payload
                    network_header ^     ^ mac_header
  this patch, lwt_in | MAC header  | new header        | old IP | payload
                     ^ mac_header  ^ network_header
  this patch, lwt_xmit             | new header        | old IP | payload
                    network_header ^     mac_header is not set

For lwt_in, move the MAC header in front of the new header before the
memcpy(), as __seg6_do_srh_encap() does. skb_cow_head() already reserves
len + skb->mac_len bytes.

For lwt_xmit, the output path makes a new MAC header. Thus mark
skb->mac_header as not set. This is the state of a locally generated skb.

Fixes: 52f278774e ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-22-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Chris Mason
0fcb3f11a9
bpf: Move the MAC header in bpf_lwt_seg6_adjust_srh()
bpf_skb_net_hdr_push() and bpf_skb_net_hdr_pop() change skb->data and
skb->mac_header by len. That is correct in a tc prog, where skb->data is
the MAC header. But bpf_lwt_seg6_adjust_srh() calls them in an End.BPF
prog, where skb->data is the network header. The MAC header does not move:

  before push  |       free       | MAC header   | IPv6 | SRH | payload
               ^ head             ^ mac_header   ^ data
  today        |       free       | MAC h| IPv6 | SRH   + len | payload
               ^ head     ^ mac_header   ^ data
  this patch   |   free   | MAC header   | IPv6 | SRH   + len | payload
               ^ head     ^ mac_header   ^ data

Users of skb_mac_header() get incorrect bytes until __dev_queue_xmit() sets
skb->mac_header again. skb_cow_head() reserves only len bytes. Thus the
16-bit offset skb->mac_header can wrap. A push also changes the "not set"
value. In both cases skb_mac_header() points after the skb.

Move the MAC header too. Pass len + skb->mac_len to skb_cow_head(). Keep
the "not set" value. The second Fixes tag is for this case. Since that
commit an End.BPF prog can get an skb with skb->mac_header not set.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Fixes: 20a081b798 ("seg6: add VRF support for SRv6 End.DT6 behavior")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-21-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
45bcc58d57
bpf: Don't look for the SRH again in the End.BPF helpers
A packet can have two SRHs. Thus input_action_end_bpf() uses
IP6_FH_F_SKIP_RH to skip routing headers with segments_left 0. The helpers
bpf_lwt_seg6_store_bytes() and bpf_lwt_seg6_adjust_srh() can reallocate the
head of the skb. Thus they look for the SRH again, but without this flag.

  +------------------------+ <- the helpers: srh_state->srh
  | SRH 1, segments_left 0 |
  +------------------------+ <- input_action_end_bpf(): srh_state->srh
  | SRH 2                  |    and srh_state->hdrlen
  +------------------------+

Then the helpers check offset against the wrong limits. If a helper changes
TLVs, seg6_bpf_has_valid_srh() writes the length of SRH 2 to SRH 1.

Neither helper changes the offset of the SRH from skb->data. Calculate the
new address from this offset. To add IP6_FH_F_SKIP_RH is not sufficient,
because advance_nextseg() can set segments_left of SRH 2 to 0. The helper
bpf_lwt_seg6_action() can change the headers and still looks for the SRH.

Fixes: fbbc5bc2ab ("seg6: ignore routing header with segments left equal to 0")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-20-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Chris Mason
ac159f39b2
bpf: Limit the SRH length in bpf_lwt_seg6_adjust_srh()
bpf_lwt_seg6_adjust_srh() lets an End.BPF prog change the size of the TLVs
in the SRH. The helper keeps the SRH length in srh_state->hdrlen, in bytes
and without the first 8 bytes. Later seg6_bpf_has_valid_srh() writes it to
srh->hdrlen, an 8-bit field in units of 8 bytes. But srh_state->hdrlen has
no upper limit, and the cast to u8 can truncate it. After that,
seg6_validate_srh() gets the SRH length from srh->hdrlen, and thus it can
accept the SRH. Then srh->hdrlen is too small, and a parser reads TLVs as
the subsequent header.

Return -EFAULT when the new srh_state->hdrlen is larger than 2040, the
largest length that srh->hdrlen can hold. To replace a TLV in the largest
SRH, a prog can no longer add bytes first. It must remove bytes first.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-19-alexei.starovoitov@gmail.com
2026-11-02 00:10:40 +00:00
Alexei Starovoitov
c1ca06e48e
bpf: Set a dst for test runs of lwt_in progs
When an lwt prog runs on a route, the skb always has a dst. To push an SRH,
bpf_lwt_push_encap() reads the device from this dst. But
bpf_prog_test_run_skb() sets a dst for lwt_xmit progs only. Thus the helper
dereferences a NULL dst in a test run of an lwt_in prog.

Set the same dst, ip6_null_entry, for lwt_in progs. When IPv6 is disabled
or not built, their test run now fails with -EOPNOTSUPP too. An lwt_out
prog cannot call this helper.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-18-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Chris Mason
58e39f8d58
bpf: Reject non-IPv6 packets in BPF_LWT_ENCAP_SEG6
The mode BPF_LWT_ENCAP_SEG6 of bpf_lwt_push_encap() pushes an IPv6 header
and an SRH, and it replaces the dst. The SRH says that IPv6 follows, and
skb->protocol does not change. Thus the mode assumes an IPv6 packet, but an
lwt_in prog also runs for IPv4 packets. After the prog, bpf_input() calls
orig_input() of the old dst. This IPv4 handler reads the pushed headers as
IPv4. It can write after the packet data, and the kernel crashes.

                 after the push         orig_input() expects
                 ---------------------  --------------------
  skb->protocol  ETH_P_IP               ETH_P_IP
  dst            rt6_info               rtable
  packet         | IPv6 | SRH | IPv4 |  | IPv4 |

The mode BPF_LWT_ENCAP_SEG6_INLINE returns -EBADMSG for non-IPv6 packets.
Apply this check to both modes. End.BPF does not change, because
seg6_local_input() drops non-IPv6 packets.

Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-17-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
6d8118937b
bpf: Don't let bpf_skb_adjust_room() raise gso_size to GSO_BY_FRAGS
When bpf_skb_adjust_room() shrinks a TCP GSO skb, it adds the number of
removed bytes to gso_size. gso_size has 16 bits, and nothing checks the
sum. Thus gso_size can wrap to 0 or to a small size, or it can be
GSO_BY_FRAGS. GSO_BY_FRAGS is not a size. It tells skb_segment() to read
the length of each segment from the frag_list. If the TCP GSO skb has no
frag_list, skb_segment() dereferences a NULL pointer.

Return -ENOTSUPP and do not change the skb if the sum is GSO_BY_FRAGS or
larger. With BPF_F_ADJ_ROOM_FIXED_GSO the helper does not change gso_size,
so it shrinks the skb as before.

Fixes: 2be7e212d5 ("bpf: add bpf_skb_adjust_room helper")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-16-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Chris Mason
3f9780d62d
bpf, cgroup: Keep the skb network offset signed
cgroup_skb progs see a packet from its network header. While they run,
__cgroup_bpf_run_filter_skb() moves skb->data there. It assumes that the
network header is not after skb->data. It negates skb_network_offset(skb)
and pushes skb->data by this offset. The offset is an unsigned int.

But ip6mr_cache_report() and bpf_lwt_xmit_reroute() can pass an skb that
has data before the network header. Then the offset wraps. On a 64-bit
kernel skb->data is then far below skb->head.

skb->len has 32 bits and wraps to the correct value, thus only skb->data is
wrong. A read of packet data faults or gets other memory.

Keep the offset in an int. Pull skb->data when the network header is after
it. Otherwise push it, as today.

Fixes: 3007098494 ("cgroup: add support for eBPF programs")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-15-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Chris Mason
2962329f7c
bpf: Require prog fd or capability for cgroup detach
Since the commit below a cgroup prog detach does not require CAP_NET_ADMIN.
The fd of the attached prog gives the permission instead. But the detach
requires this fd only with BPF_F_ALLOW_MULTI. Without this flag a cgroup
has only one prog per attach type. Then find_detach_entry() returns this
prog and does not compare it with the prog of the caller. Thus the kernel
detaches this prog for a caller with neither the fd nor a capability.

Compare the two progs. If they are different, require CAP_NET_ADMIN or
CAP_SYS_ADMIN in the initial user namespace. The error is -EPERM. A detach
from tcx or netkit without a prog fd already requires these capabilities.
With BPF_F_ALLOW_MULTI nothing changes.

Without these capabilities, a caller of bpf_prog_detach() of libbpf must
now use bpf_prog_detach2() with the fd of the attached prog.

Fixes: 2c78ee898d ("bpf: Implement CAP_BPF")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-14-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
9abda4d8fc
selftests/bpf: Test the arguments of an extension prog
An extension must not expect more of its arguments than the callers of the
replaced function provide. It must fail if it expects more memory, a
non-NULL pointer or another kind of argument. The same argument, less
memory or a pointer that can be NULL must pass. Test check_ext_args() at
load and at attach to another function of the same target prog. The load
must fail with the message of the check, and the attach with -EINVAL.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-13-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
faea3cda41
bpf: Compare the arguments of an extension with those of its target
An extension replaces its target, a global function of another prog. From
BTF, btf_prepare_func_args() derives the kind of each argument, such as the
context, memory of a given size or a kernel object. The verifier checks the
callers with the BTF of the target and the extension with its own BTF.

Only btf_check_func_type_match() compares the two prototypes. For a pointer
to a struct, it compares only the struct names and assumes that the pointer
is the context. That was true until the commit below added pointers to
memory. Later the __arg_* tags added more kinds. Thus an extension can rely
on more than the callers guarantee (size, not NULL, kind). Then what the
verifier proved for it is false at run time.

Keep the result of btf_prepare_func_args() in bpf_func_info_aux and compare
the two results at load and on attach to another target. Return -EINVAL
unless the kind and the BTF id are the same and the memory is not larger.
The extension can also accept NULL where the callers never pass it. An
extension with the prototype and the tags of its target loads as before. An
argument that is the context only because of __arg_ctx needs the tag in the
extension too. The tag __arg_untrusted or __arg_arena on the extension only
is safe, but it is rejected because the kind differs.

Fixes: e5069b9c23 ("bpf: Support pointers in global func args")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-12-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
ed02b9cc1d
bpf: Don't turn kfunc arguments of an empty struct type into memory
A kfunc can take a pointer to a struct that has only scalar members. Then
the verifier also accepts memory of the prog: resolve_func_arg_type()
changes ARG_PTR_TO_BTF_ID to memory of the size of the struct. An empty
struct meets this condition too. But it is a handle for an object of
another type. The io_uring kfuncs cast the empty struct iou_ctx to struct
io_ring_ctx. Thus they use memory of the prog as a struct io_ring_ctx.

Keep ARG_PTR_TO_BTF_ID for a pointer to an empty struct. Then the verifier
accepts only a PTR_TO_BTF_ID of that struct, such as the ctx argument of
loop_step(). Only one other kfunc takes an empty struct, struct
bpf_ws_lock. It releases this argument, and the verifier does not change an
argument that the kfunc releases. Add the rule to kfuncs.rst.

Fixes: ec02fe217f ("io_uring/bpf-ops: restrict ctx access to BPF")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-11-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
07684726d3
bpf: Don't turn struct arguments of KF_ACQUIRE kfuncs into memory
When a kfunc takes a pointer to a struct that has only scalar members, the
verifier also accepts memory of the prog. Then resolve_func_arg_type()
changes ARG_PTR_TO_BTF_ID to ARG_PTR_TO_MEM. This is correct for a struct
of parameters. But struct bpf_cpumask also has only scalar members, and the
kernel allocates and frees it. Thus bpf_cpumask_acquire() returns memory of
the prog as a referenced object, and bpf_cpumask_release() can free it.

The verifier does not change the argument that a kfunc releases. KF_ACQUIRE
does not say which argument is the object. Thus do not change any argument
of a KF_ACQUIRE kfunc. Then the verifier rejects memory there. No other
KF_ACQUIRE kfunc takes memory in an ARG_PTR_TO_BTF_ID argument. Add to
kfuncs.rst that a KF_ACQUIRE kfunc must pair a struct of parameters with a
__sz argument.

The first commit below added the bug. Later the struct had pointers in an
rcu_head, so the verifier rejected memory. The second commit removed them.

Fixes: 516f4d3397 ("bpf: Enable cpumasks to be queried and used as kptrs")
Fixes: 8e07bb9ebc ("bpf: Convert bpf_cpumask to bpf_mem_cache_free_rcu.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-10-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Chris Mason
f89ebf0749
bpf: Reject memory for kfunc projection type args
struct __sk_buff and struct xdp_md are projection types of struct sk_buff
and struct xdp_buff. A kfunc that takes a projection type casts the
argument to the underlying type. When the projection type is the ctx type
of the prog, the verifier accepts only the ctx. In other progs,
process_arg_ptr_to_btf_id() accepts a pointer to the underlying type.

But this function identifies the underlying type only by its name. A struct
of the same name in prog BTF also matches. Its objects are memory of the
prog. This test also ignores the offset of the register. Thus the kfunc
uses memory of the prog, or the middle of an skb, as an skb.

Accept the underlying type only from kernel BTF, and only at offset 0. A
prog that passes an skb of the kernel sees no change.

struct xdp_md has only scalar members. Thus in a prog with another ctx
type, resolve_func_arg_type() changes ARG_PTR_TO_BTF_ID to memory, and the
verifier accepts memory of the prog. Keep ARG_PTR_TO_BTF_ID for projection
types. The first Fixes tag is for this change. That commit merged the
conntrack kfunc sets of two prog types with different ctx types. Thus
bpf_xdp_ct_{alloc,lookup}() can use memory of the prog as an xdp_buff.

Fixes: a4703e3184 ("bpf: Switch to new kfunc flags infrastructure")
Fixes: ec209ad863 ("bpf: verifier: Relax caller requirements for kfunc projection type args")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-9-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
14d3e5bf9f
selftests/bpf: Test the length and the address of an arena mmap()
libbpf maps all max_entries pages of an arena and never maps it at
address 0. No test maps an arena differently. Thus the checks from
"bpf: Refuse an arena mmap() longer than max_entries pages" and
"bpf: Refuse to map an arena at address 0" have no test. Test that a longer
mmap() fails with E2BIG, and that an mmap() at address 0 fails with EINVAL.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-8-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
15dedd4b25
bpf: Remove the WARN from arena_get_unmapped_area()
The user range of an arena must not cross a 4 GiB boundary. Thus
arena_get_unmapped_area() asks the mm for 2 * len bytes and rounds the
result up if necessary. If user_vm_start is not 0, addr must be equal to
it. A WARN_ON_ONCE() assumes that the mm returns addr. But addr is only a
hint without MAP_FIXED, and the mm can return a different range that
crosses a boundary. This is not a kernel bug.

Remove the WARN_ON_ONCE() and its -EFAULT. arena_map_mmap() already
compares vm_start with user_vm_start under arena->lock. If the rounded
result is user_vm_start, mmap() succeeds. If not, it returns -EBUSY.

Fixes: 317460317a ("bpf: Introduce bpf_arena.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-7-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
1e01345b87
bpf: Refuse an arena mmap() longer than max_entries pages
arena_map_alloc() puts max_entries free pages in the range tree of an
arena. But the arena kfuncs check their arguments against user_vm_start and
user_vm_end. Without map_extra, arena_map_mmap() takes both from the first
vma. This vma can be up to 4 GiB long. Then arena_free_pages() also marks
pages as free that were never in the range tree. Thus max_entries does not
limit the memory of the arena, but these pages are inside kern_vm.

Refuse an mmap() longer than max_entries pages with -E2BIG. With map_extra
this limit exists already. libbpf always maps max_entries pages. Replace
both SZ_4G checks with this limit, because it is at most 4 GiB.

Fixes: 317460317a ("bpf: Introduce bpf_arena.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-6-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
52498f14c2
bpf: Don't let bpf_arena_free_pages() see a half-set user range
If map_extra is 0, the first arena_map_mmap() sets user_vm_start and
user_vm_end. It holds arena->lock, but bpf_arena_free_pages() reads both
fields without this mutex. The kfunc relies on the verifier, which rejects
a prog if user_vm_start of its arena is 0. But this check covers only the
maps in used_maps. The kfunc accepts any trusted pointer to struct bpf_map.

Thus the kfunc can run during arena_map_mmap() and read user_vm_start as 0
and user_vm_end as vma->vm_end. Then min() does not limit page_cnt to the
arena. arena_free_range() unmaps and frees pages of other vmalloc areas.

Read user_vm_start one time and return if it is 0. This value means that no
range is set, because arena_get_unmapped_area() rejects address 0. If only
user_vm_end is still 0, uaddr_end is 0 and the kfunc returns, as today.

Fixes: 317460317a ("bpf: Introduce bpf_arena.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-5-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
ca580b0343
bpf: Refuse to map an arena at address 0
The first mmap() of an arena sets user_vm_start and user_vm_end. Each
subsequent mmap() must use the same range. The value 0 in user_vm_start
means that the range is not set, but a mapping can start at address 0. Then
arena_map_mmap() does not check vm_start and sets user_vm_start again. The
range tree counts pages from user_vm_start. With a new user_vm_start it
reports allocated pages as free, and apply_range_set_cb() fails with
-EBUSY.

An arena at address 0 is not useful, because the verifier rejects all progs
that refer to it. Return -EINVAL from arena_get_unmapped_area(). It runs
before mmap() removes the old mappings in the range.

Fixes: 317460317a ("bpf: Introduce bpf_arena.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-4-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
a08ba2ab79
bpf: Clamp the trace length before the skip test in stackid_init()
stackid_init() gives a bucket of the stack map
min(trace_nr - skip, max_depth - skip) trace entries. Here max_depth is the
size of a bucket plus skip, but at most perf_event_max_stack. Context
markers can make trace_nr larger than that, so the skip test can pass when
max_depth < skip. Then 'max_depth - skip' wraps, and the kernel can write
after the bucket.

Clamp trace_nr to max_depth before the skip test, as __bpf_get_stack_pe()
does. The result changes only when skip >= max_depth. Then it is -EFAULT.
Until now skip == max_depth could give the id of an empty trace.

get_perf_callchain() releases the trace, so an NMI can change trace->nr.
Use READ_ONCE() in bpf_get_stackid(), so the compiler reads it one time.

Fixes: 23f852daa4 ("bpf: Fix stackmap overflow check in __bpf_get_stackid()")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-3-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Josef Bacik
007fd46079
bpf: Clamp the trace length in __bpf_get_stack() again
get_perf_callchain() and get_callchain_entry_for_task() store a trace in a
per-CPU entry, one per context. They release the entry before they return
it. Thus a second user in the same context can write to the entry while the
first user reads it. preempt_disable() stops only other tasks.

__bpf_get_stack() requests at most max_depth frames. This is skip plus the
frames that fit in the buffer, but not more than perf_event_max_stack.
Since the commit below, it copies 'trace->nr - skip' frames with no limit.
But a second user can store a longer trace. The unwinders of PowerPC add
context markers that max_depth does not limit. In both cases the copy
writes after the end of the buffer.

Read trace->nr one time. Clamp the value to max_depth before the skip test,
as __bpf_get_stack_pe() does. Thus when max_depth is less than skip, the
helper returns -EFAULT, and 'trace_nr - skip' does not underflow. The
copied frames can still be those of the second user.

Fixes: e17d62fedd ("bpf: Refactor stack map trace depth calculation into helper function")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-2-alexei.starovoitov@gmail.com
2026-11-02 00:10:39 +00:00
Alexei Starovoitov
1d55411e8b
Merge branch 'bpf-x86-fix-bpf_throw-in-a-prog-with-a-private-stack'
Alexei Starovoitov says:

====================
bpf, x86: Fix bpf_throw() in a prog with a private stack

From: Alexei Starovoitov <ast@kernel.org>

On x86-64 a prog whose main prog has a private stack and that calls
bpf_throw() returns to the kernel with wrong callee saved registers. The
kernel crashes. A tracepoint prog or an fentry prog with more than 48 bytes
of stack is sufficient.

Patch 1 is the fix. Patch 2 has the tests. The existing tests of this
combination are loaded, but they never run.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261031050558.2410721-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 00:04:29 +00:00
Alexei Starovoitov
6cc0cf0a6f
selftests/bpf: Test bpf_throw() in a prog with a private stack
'Private stack, exception in main prog' and 'Private stack, exception in
subprog' are fentry progs. The test loader does not attach them, and
BPF_PROG_TEST_RUN of a fentry prog does not call the prog. They are
loaded, but they never run.

Add three raw_tp progs. BPF_PROG_TEST_RUN runs them, and the default
exception callback returns the cookie of bpf_throw():
 - the main prog has a private stack and throws
 - the main prog has a private stack, its subprog throws
 - the main prog has no private stack, its subprog has one and throws

Without the fix of the x86-64 JIT the first two crash the kernel. The
third one passes with and without it: it makes sure that only the frame
of the main prog is taken into account.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031050558.2410721-3-alexei.starovoitov@gmail.com
2026-11-02 00:04:28 +00:00
Alexei Starovoitov
91068ed2d3
bpf, x86: Fix bpf_throw() in a prog with a private stack
When the main prog has a private stack and the prog calls bpf_throw(), it
returns to the kernel with wrong values in r12, rbx, r13, r14 and r15. The
kernel crashes soon after that, for example:

  BUG: kernel NULL pointer dereference, address: 0000000000000010
  RIP: 0010:__bpf_prog_test_run_raw_tp+0x125/0x380

The main prog of a prog that can throw saves these five registers at its
entry. bpf_throw() walks the stack to the frame of the main prog and
gives the stack pointer of that frame to the exception callback, which
pops the registers from there. In a function with a private stack r9 is
the frame pointer, and the JIT emits 'push r9' in front of every call
and 'pop r9' after it. So the stack pointer that bpf_throw() finds is
8 bytes too low:

  r12
  rbx
  r13
  r14
  r15  <- the callback has to pop from here
  r9   <- rsp of the main prog at the call

r15 gets the address of the private stack and every other register gets
the value of its neighbour.

This happens in tracepoint, raw_tp, perf_event and tracing progs, except
iterators, and in struct_ops progs that ask for a private stack, when
the main prog has more than 48 bytes of stack. The throw can be in the
main prog or in a subprog.

aux->stack_arg_sp_adjust already moves the stack pointer from the
outgoing stack arguments up to the saved registers. Add the 8 bytes of
r9 to it when the main prog has a private stack.

A constant is enough. Calls of helpers, kfuncs and subprogs and callx
all have the push. A prog with tail calls has no private stack, and a
callback cannot throw. Only the frame of the main prog matters: the
frames of subprogs are dropped, with or without a private stack. On
x86-64 a function with stack arguments has no private stack, hence only
one of the two parts is not zero.

The JITed code does not change.

Fixes: 7d1cd70d4b ("bpf, x86: Support private stack in jit")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031050558.2410721-2-alexei.starovoitov@gmail.com
2026-11-02 00:04:28 +00:00
Alexei Starovoitov
a620922325
Merge branch 'bpf-keep-the-valid-bytes-of-a-packet-pointer-in-scalar-evolution'
Alexei Starovoitov says:

====================
bpf: Keep the valid bytes of a packet pointer in scalar evolution

From: Alexei Starovoitov <ast@kernel.org>

Sashiko found a bug in the review of [1]. It is in the tree since scalar
evolution widens packet pointers.

'range - umax' bytes from a packet pointer are in the packet. At the head
of a counted loop scalar evolution sets new bounds, and reg_bounds_sync()
makes umax smaller: 58 becomes 56 when the step is 8. The range does not
change. Then the verifier accepts 2 bytes that are not in the packet.

  prog                                    bpf tree  this fix
  --------------------------------------  --------  --------
  r6 += 8, access in the loop             loads     rejected
  r6 += -8, access in the loop            loads     rejected
  r6 += -8, the offset can be negative    loads     rejected
  access in the second iteration          loads     rejected
  r5 is r6 + 8 or r6                      loads     rejected

veristat shows the same verdicts and the same number of insns for all progs
of 36 weekly builds of Cilium (5032 progs), of sched-ext/scx (563 progs)
and of the selftests. test_progs, test_progs-no_alu32, test_progs-cpuv4,
test_progs-bpf_gcc and test_verifier have no new failure on x86-64.

v1 -> v2:
 - Use smax in place of umax. umax is U64_MAX when the offset can be
   negative. Then v1 did not change the range, or made it larger (Sashiko).
 - Change the range one time, after the last register of a union. v1
   changed it after each register. Then the subsequent register had a
   different range, and a correct prog got "verifier bug: union of
   incompatible registers" (bpf-ci, Sashiko).
 - Add widen_pkt_pointer_negative_offset. Change the prog in
   union_pkt_pointer_var_off_lowers_umax: it loads without the fix now.
 - Patch 1: correct the log. The removal of the mark can change a verdict.
 - v1 was on top of [1], which is in the bpf tree now. BPF CI and the two
   bots applied v1 without [1]. The two tests that failed in CI and the
   comments about bpf_clamp_scev_regs() have this cause.

v1: https://lore.kernel.org/bpf/20261027201436.3192716-1-alexei.starovoitov@gmail.com/
[1] https://lore.kernel.org/bpf/20261027190314.1440199-15-alexei.starovoitov@gmail.com/

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
====================

Link: https://patch.msgid.link/20261030210950.1904640-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-02 00:04:07 +00:00
Alexei Starovoitov
61f833f968
selftests/bpf: Test the valid bytes of a packet pointer in a counted loop
Each test adds r4 to a packet pointer. r4 is 0, 8 .. 48, but its umax is
50.

  test                                      umax gets smaller    result
  ----------------------------------------  -------------------  ------
  widen_pkt_pointer_step_lowers_umax        at the loop entry    reject
  widen_pkt_pointer_step_lowers_umax_down   the same, r6 += -8   reject
  widen_pkt_pointer_negative_offset         no, only smax        reject
  clamp_pkt_pointer_step_lowers_umax        at the back edge     reject
  union_pkt_pointer_var_off_lowers_umax     r5 is r6 + 8 or r6   reject
  widen_pkt_pointer_keeps_valid_bytes       at the loop entry    loads

The first five progs load without the fix. The last prog reads only bytes
that the compare with pkt_end covers.

widen_pkt_pointer_beyond_pkt_end makes sure that the mark "beyond pkt_end"
is not in the state at the head of the loop.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261030210950.1904640-3-alexei.starovoitov@gmail.com
2026-11-02 00:04:07 +00:00
Alexei Starovoitov
88e2c896d8
bpf: Keep the valid bytes of a packet pointer in scalar evolution
check_packet_access() accepts an access when umax + off + size <= range.
Thus 'range - umax' bytes from a packet pointer are in the packet, and
nothing can make umax smaller without a change of the range. For this
reason commit b88822d258 ("bpf: Fix packet range of pointers sharing an
id") removed reg_bounds_sync() from the arithmetic on packet pointers.

At the head of a counted loop scalar evolution gives new bounds to a packet
pointer, in bpf_set_reg_range() and in bpf_reg_union(). The two functions
call reg_bounds_sync(). Then the step or var_off makes umax smaller.

     r4 &= 0x38
     if r4 > 50 goto 2f         ; r4 is 0, 8 .. 48, but umax is 50
     r6 = pkt
     r6 += r4
     r5 = r6
     r5 += 8
     if r5 > pkt_end goto 2f    ; 8 bytes from r6 are in the packet
  1: r0 = *(u16 *)(r6 + 0)
     r6 += 8
     r9 += 1
     if r9 < 2 goto 1b

  r6                       umax  range  valid bytes
  -----------------------  ----  -----  ------------
  in front of the loop       50     58  8
  in all iterations          58     58  0
  after the step of 8        56     58  2, incorrect

In the second iteration r6 can be pkt_end. The verifier accepts the prog,
and the prog reads 2 bytes after the packet. A kernel without scalar
evolution rejects it.

Make the range smaller by the same number as the largest offset.

The largest offset is smax, not umax. With 'r6 += -8' in the loop the
offset can be negative. Then umax is U64_MAX before and after
reg_bounds_sync(). The verifier rejects an access through such r6. It
accepts an access through 'r5 = r6; r5 += 8', and r5 has the range of r6.

All registers of a union have the same range, and bpf_reg_union() makes
sure of that for each register. Thus change the range one time, after the
last register. The range goes with the largest offset of all registers.

The range can also be a mark: the pointer is at pkt_end or beyond pkt_end.
The mark is for the pointer at the entry of the loop, not for all
iterations. Remove it when the pointer is widened. The arithmetic in the
loop removes the mark too. Thus the state that returns to the head was not
pruned, and the verifier made one more pass with the two branches of each
compare. Now the first pass examines the two branches. The verdict can
change only when no state returned to the head: the mark sent each path out
of the loop, and the other insns of the loop were dead code.

Fixes: 6ccf49f793 ("bpf: Use SCEV to widen bounded loops")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261030210950.1904640-2-alexei.starovoitov@gmail.com
Closes: https://lore.kernel.org/bpf/sashiko-outbox-187068@kernel.org/
2026-11-02 00:04:07 +00:00
Ella Ma
7af2a51f19 coccinelle: free: add a checker for __cleanup(kfree) usage
Using __cleanup(kfree) will pass the stack address of the annotated
local variable to kfree functions. This will lead to invalid
deallocation issues. Inspired by CVE-2026-45959 and similar bugs
recently detected.

Signed-off-by: Ella Ma <alansnape3058@gmail.com>
Signed-off-by: Julia Lawall <julia.lawall@inria.fr>
2026-11-02 00:28:04 +01:00
Joe Perches
afb17ae1db coccinelle: Add devm_kmalloc_objs conversion script
Like commit bdc5071d7f ("coccinelle: Add kmalloc_objs conversion script")
with commit 1c7bbaeed1 ("coccinelle: kmalloc_obj: Remove default GFP_KERNEL arg")

Finds and converts sized devm_kmalloc-family of allocations into the typed
devm_kmalloc_obj-family of allocations.

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Julia Lawall <julia.lawall@inria.fr>
2026-11-02 00:27:25 +01:00
Julia Lawall
14be5faa8b scripts/coccinelle: improve efficiency of array_end.cocci
* Add disable zero_multiple_format to each rule to avoid considering
the possibility that an array index is expressed using '\0'
* Omit outer parentheses on context and org/report rules that
only match ubt don't transform, since matching a subterm gives
the same result whether or not the parentheses are present.

Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
2026-11-01 23:43:36 +01:00
Alejandro Colomar
6b828a87a6 scripts/coccinelle: Add script for using ARRAY_END()
Recently, we added an ARRAY_END() macro to simplify finding a pointer
one past the last element in an array.  Such a pointer is often called
the 'end', and thus the macro name.

Make it easy to find more places where that macro should be used.

See also:
436debc9ca ("array_size.h: add ARRAY_END()")
8118f197b7 ("mm: fix benign off-by-one bugs")
a9e5620c9a ("kernel: fix off-by-one benign bugs")
61e9210e23 ("mm: use ARRAY_END() instead of open-coding it")

Cc: Kees Cook <kees@kernel.org>
Cc: Markus Elfring <Markus.Elfring@web.de>
Cc: Julia Lawall <Julia.Lawall@inria.fr>
Cc: Nicolas Palix <nicolas.palix@imag.fr>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
2026-11-01 23:43:35 +01:00
Alexei Starovoitov
5b96632457
Merge branch 'bpf-fix-overlapping-copies-in-bpf_dynptr_copy'
Ayushman Rout says:

====================
bpf: Fix overlapping copies in bpf_dynptr_copy()

bpf_dynptr_copy() can corrupt data when both ranges are in the same xdp
packet and overlap: a slice of one range is used as the buffer for
__bpf_dynptr_read() or __bpf_dynptr_write(), and the chunk loop always
copies forward.

Patch 1 does not use a slice as the buffer for a copy within one packet
and copies from the end when the destination is above the source.
Patch 2 adds selftests. They pass with the fix.

Changes in v2:
- Dropped the bpf_xdp_copy_buf() change and fixed everything in
  bpf_dynptr_copy(), as suggested by Alexei
- Reworked the tests into bpf_dynptr_copy() tests where only one of the
  ranges crosses into frag0

v1: https://lore.kernel.org/bpf/20261024092659.76422-1-ayushmanrout27@gmail.com/
====================

Link: https://patch.msgid.link/20261026162810.12862-1-ayushmanrout27@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-11-01 01:10:23 +00:00
Ayushman Rout
8f92b56d22
selftests/bpf: Test overlapping dynptr copies on xdp frags
Add dynptr tests for copies within one xdp packet with frags, where the
source and the destination overlap and the destination is above the
source:

- test_dynptr_copy_xdp_overlap: both ranges cross from the linear part
  into frag0. bpf_dynptr_copy() of 1200 bytes with the destination 100
  bytes above the source.
- test_dynptr_copy_xdp_overlap_src_linear: the source is in the linear
  part and the destination crosses into frag0.
- test_dynptr_copy_xdp_overlap_dst_frag: the source crosses into frag0
  and the destination is in frag0.

The new tests set err when the data is wrong. The existing
test_dynptr_copy_xdp does not, so it can pass on corrupted data.

Without the fix to bpf_dynptr_copy(), test_dynptr_copy_xdp_overlap
fails. With it, all the new tests pass.

Signed-off-by: Ayushman Rout <ayushmanrout27@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261026162810.12862-3-ayushmanrout27@gmail.com
2026-11-01 01:10:23 +00:00
Ayushman Rout
696f0954e3
bpf: Fix bpf_dynptr_copy() for overlapping ranges in one packet
When both dynptrs point into the same packet and the ranges overlap,
bpf_dynptr_copy() can copy wrong data in two ways.

If one range fits into a segment and the other one does not, the slice
of the first range is used as the buffer for __bpf_dynptr_read() or
__bpf_dynptr_write(). The range that crosses into a frag is copied piece
by piece, and an earlier piece can overwrite bytes that a later piece
has yet to read.

If neither range fits into a segment, the chunks are copied from the
start to the end through a 256 byte stack buffer. When the destination
is above the source, a chunk written to the destination overwrites
source bytes that later chunks have yet to read. For a copy of 1200
bytes with the destination 100 bytes above the source, the first chunk
writes source bytes 100..355 and the second chunk then reads bytes
256..355 after they were overwritten.

Do not use a slice as the buffer when both dynptrs share the same data,
and copy the chunks from the end to the start when the destination is
above the source, like memmove() does.

The selftests added later in this series pass with this change.

Fixes: daec295a70 ("bpf/helpers: Introduce bpf_dynptr_copy kfunc")
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Ayushman Rout <ayushmanrout27@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261026162810.12862-2-ayushmanrout27@gmail.com
2026-11-01 01:10:23 +00:00
Jakub Sitnicki
bcd07fd167
bpf, sockmap: Fix psock update-side data races on sk->sk_prot and progs
The update side of the sockmap psock lifecycle has several unsynchronized
accesses to sk->sk_prot and psock prog state that KCSAN flags when the
new update-vs-delete race selftest runs. The fix comes from Alexei [1]:

* sock_map_link() installed psock programs and called sock_map_init_proto()
  before taking sk->sk_callback_lock, racing a concurrent teardown's
  tcp_bpf_update_proto() write of sk->sk_prot. Take the write_lock early,
  before psock_set_prog() and sock_map_init_proto(), and drop the
  psock->saved_data_ready gating from prog detection (it is re-checked
  under the lock before stopping progs).

* sock_map_del_link() read psock->saved_data_ready outside the lock. Move
  the saved_data_ready check under write_lock_bh(&sk->sk_callback_lock)
  so prog teardown is serialized against the proto restore.

* sock_map_psock_get_checked() and sock_map_sk_is_suitable() did plain
  sk->sk_prot reads. Convert to READ_ONCE() to mark the intentional racy
  read against the WRITE_ONCE() swap in sock_replace_proto().

With these changes the sock_map_link/psock_set_prog side of the reported
KCSAN splats is silenced; the remaining teardown-vs-core-TCP pairings
are the separate read-side annotation problem.

[1] https://lore.kernel.org/bpf/DMBHB0TQOV1L.38MECMYFGUS5B@gmail.com

Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261030-bpf-next-v1-2-035eabf8eae7@cloudflare.com
2026-10-31 20:50:56 +00:00
Jamal Hadi Salim
23503acb21
bpf: Fix skb_pull() BUG in __bpf_redirect_neigh()
The issue:
This is a follow-up to the short link-layer header fixes from Eric.
After vlan pop_eth, a privileged SCHED_ACT BPF program can call
bpf_skb_change_head(skb, 1, 0) and then bpf_redirect_neigh().

__bpf_redirect_neigh() calls skb_pull(skb, sizeof(*ethh)) after checking
only that mac_header < network_header.  Nothing verifies that the MAC
header is long enough, that it is linear, or that the IP header the
redirect goes on to read is linear either.

A SCHED_ACT BPF program can do:

    bpf_skb_change_head(skb, 1, 0);
    bpf_redirect_neigh(lo, NULL, 0, 0);

after vlan pop_eth.  The skb then has mac_len == 1 and only one byte of
linear data; skb_pull(ETH_HLEN) trips the skb->len < skb->data_len BUG in
__skb_pull():

    kernel BUG at ./include/linux/skbuff.h:2839!
    RIP: skb_pull+0x40/0x50
    Call Trace: skb_do_redirect -> packet_xmit -> packet_sendmsg
    Kernel panic - not syncing: Fatal exception in interrupt

The v4 and v6 paths read ip_hdr() and ipv6_hdr() as soon as the MAC
header is gone.  On the AF_PACKET frame below that leaves headlen == 0
after the pull, so the network header sits at skb->tail and the route
lookup reads ip4h->protocol, ip4h->saddr and ip4h->daddr past the linear
area.

The Fix:
Use skb_network_offset(), which is the MAC header span, instead of
skb->mac_len.  mac_len is zero for locally generated tc egress and netkit
packets, while the span still rejects the one-byte header produced by
pop_eth + bpf_skb_change_head(skb, 1, 0).  The single check also covers
the mac_header >= network_header test it replaces.

Use pskb_may_pull() to make the Ethernet header linear before it is read
or pulled, and to make the IP header linear in both the v4 and the v6
path before ip_hdr()/ipv6_hdr() is read.  The header pointers are taken
after the pull, since pskb_may_pull() may reallocate skb->head.

Conditions to recreate the bug:
On x86-64 with 4 KiB pages, enable CONFIG_PACKET, CONFIG_BPF_SYSCALL,
CONFIG_NET_SCH_INGRESS, CONFIG_NET_CLS_MATCHALL, CONFIG_NET_ACT_VLAN and
CONFIG_NET_ACT_BPF.  Run as root with BPF loading, network administration
and raw-packet privileges.  Bring lo up and attach a SCHED_ACT program
that calls bpf_skb_change_head(skb, 1, 0), then returns
bpf_redirect_neigh(skb->ifindex, NULL, 0, 0):

  ip link set lo up
  tc qdisc add dev lo clsact
  tc filter add dev lo egress matchall action vlan pop_eth pipe \
      action bpf object-file neigh_chghead.o section action

Send an untagged ETH_P_IP frame of ETH_HLEN + 8192 bytes through an
AF_PACKET/SOCK_RAW socket bound to lo, without PACKET_VNET_HDR or
PACKET_QDISC_BYPASS.  Use a unicast destination MAC.  The sender's skb
has a 14-byte linear Ethernet prefix and a fragmented payload; pop_eth
removes that prefix and change_head restores only one linear byte.
The unfixed neighbor redirect then tries to pull 14 bytes and BUGs.

Sending the same frame without pop_eth and change_head leaves the IP
header in the frags, which is the route lookup reading past skb->tail.

Fixes: b4ab314149 ("bpf: Add redirect_neigh helper as redirect drop-in")
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Victor Nogueira <victor@mojatatu.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/netdev/20261027082604.1485903-1-edumazet@kernel.org/
Link: https://lore.kernel.org/all/2a0f5ff1d8db81b07fc4b344b8e68e3505fcbf36f72a471d1678b2f1cecd881b@mail.kernel.org/
Link: https://lore.kernel.org/netdev/DMII4JGTEUEG.2WRJPT6ODT6J0@gmail.com/
Link: https://patch.msgid.link/bpf_redirect_neigh_short_linear.v3.r0.20261031153053-1@mojatatu.com
2026-10-31 20:50:16 +00:00
Thomas Fourier
cb284914e7 net: ipa: Fix double free of the interrupt structure on config error
Since ipa_interrupt_init() allocates struct ipa_interrupt in ipa_probe(),
the structure is owned by ipa_probe() and released with
ipa_interrupt_exit() on its error paths and in ipa_remove().  The error
path of ipa_interrupt_config() still frees it with kfree().  If
ipa_interrupt_config() fails (called from ipa_config() via ipa_setup()),
ipa_probe() unwinds through err_interrupt_exit, which frees the same
structure again.

Drop the kfree() from ipa_interrupt_config(); it should only undo what it
set up itself. Drop the leftover initialization and cleanup of
ipa->interrupt now managed in ipa_proble() and ipa_remove() of ipa_main.c.

Fixes: ad1be80d75 ("net: ipa: introduce ipa_interrupt_init()")
Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
Reviewed-by: Alex Elder <elder@riscstar.com>
Link: https://patch.msgid.link/20261029082100.17722-2-fourier.thomas@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 19:04:37 -07:00
Tung Nguyen
0a0257228b tipc: reject attaching bearer of different media to the same occupied device
Currently, two bearers of different media types can be added to the
same device (e.g., "eth:eth0" and "ib:eth0") via tipc command:

tipc bearer enable media eth dev eth0
tipc bearer enable media ib dev eth0

For each command execution, tipc_enable_l2_media() is called:

tipc_enable_l2_media()
 dev_get_by_name()
  dev_hold()

As a result, device->dev_refcnt is incremented twice, but the second
bearer replaces the first one. This causes a leak in device->dev_refcnt.

Fix this by rejecting a bearer with a different media type when the
device is already occupied.

Fixes: cb30a63384 ("tipc: refactor function tipc_enable_bearer()")
Reported-by: Jiakai Xu <xujiakai24@mails.ucas.ac.cn>
Closes: http://lore.kernel.org/netdev/20260918013509.1853952-1-xujiakai24@mails.ucas.ac.cn/
Signed-off-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Link: https://patch.msgid.link/20261029030522.8306-1-tung.quang.nguyen@est.tech
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 19:03:37 -07:00
Fernando Fernandez Mancera
162cf592b5 net/smc: fix limit_smc_hs sysctl on big-endian architecture
net->smc.limit_smc_hs is a bool, but its sysctl entry uses
proc_dointvec_minmax() with .maxlen = sizeof(int), so the handler
accesses four bytes at the address of a one-byte field.

On little-endian this works with the extra bytes being written in struct
padding. On big-endian (tested on s390x) the bool sits at the most
significant byte of the int therefore the bool stays false and the "1"
goes into padding. The sysctl reads back 1 but SMC sockets created
afterwards see limit_smc_hs as disabled.

Fix this by using proc_dobool() handler and adjust the maxlen to the
right value.

Fixes: f8406a2fd2 ("net/smc: add sysctl for smc_limit_hs")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Link: https://patch.msgid.link/20261028225350.3753-1-fmancera@suse.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:25:14 -07:00
Jakub Kicinski
7b29287b18 Merge branch 'ptp-make-virtual-clock-sampling-and-teardown-failure-safe'
James Hilliard says:

====================
ptp: make virtual clock sampling and teardown failure-safe

Fix virtual-clock sampling errors, registration rollback and parent
teardown in separate patches. Keep failed PHC reads out of the timecounter
and serialize extended samples with virtual-clock adjustments. Also
preserve the zero sentinel for packets without hardware timestamps.

Retain the existing cyclecounter mask, scaling and conversion windows.
Retry the first failed refresh promptly, then back off consecutive failures
while preserving regular two-second refresh attempts. Queue the first
refresh immediately after registration. Prolonged sampling gaps remain
subject to the existing half-wrap conversion window and full-wrap sampling
limit.
====================

Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-0-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:16:00 -07:00
James Hilliard
63787dfd1b ptp: vclock: preserve missing hardware timestamps
Socket timestamp delivery converts hardware timestamps to a bound
virtual clock before checking whether a hardware timestamp is present.
A zero timestamp means that the packet has no hardware timestamp, but
timecounter_cyc2time() can turn that zero into a nonzero virtual time.
The socket then reports a hardware timestamp which was never supplied.

Return zero without conversion when the input timestamp is absent.
This also covers skb_get_tx_timestamp(), which checks for an absent
timestamp after the same conversion.

This was identified during review of virtual clock sampling changes.

Fixes: d7c0882655 ("net: socket: support hardware timestamp conversion to PHC bound")
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-5-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:15:58 -07:00
James Hilliard
d3fcce5afe ptp: vclock: serialize extended samples with counter updates
The extended and cross-timestamp callbacks sample the physical clock
before taking the virtual clock mutex. A concurrent frequency adjustment
can advance the timecounter and change its multiplier in between, so the
older sample is converted using a different frequency than the one in
effect when it was taken.

Take the mutex before sampling and keep it held through the conversion.
Retain timecounter_cyc2time() and its existing conversion window. A PHC
sample need not advance the counter: for example, e1000e explicitly
allows non-monotonic SYSTIM readings. Treating a slightly older sample
as a forward delta would instead advance virtual time by nearly a full
counter wrap.

This race was found by code inspection of the virtual clock sampling
paths.

Fixes: f0067ebfc4 ("ptp: add gettimex64() to virtual clocks.")
Fixes: 21fad63084 ("ptp: add getcrosststamp() to virtual clocks.")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-4-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:15:58 -07:00
James Hilliard
d1bdfdafd6 ptp: vclock: propagate physical clock sampling errors
The cyclecounter read callback cannot report errors. ptp_vclock_read()
ignores the return from the physical clock and consumes its output even
if the read failed. A zero sample followed by the real counter can add
an extra 32-bit wrap to virtual time. This was found by code inspection
of reset-time PHC access and the virtual clock callers.

Sample the parent before calling timecounter_read() or timecounter_init()
and have the cyclecounter callback return the cached successful sample.
On failure, leave the counter and frequency adjustment unchanged and
return the PHC error to the caller.

Retry the first failed refresh after 10 ms instead of waiting another two
seconds. With the existing 32-bit nanosecond mask, timecounter_cyc2time()
can interpret a fresh timestamp as being in the past once the last
successful refresh is about 2.147 seconds old. An isolated read failure
should not deliberately defer the next attempt until that sample is four
seconds old.

Double the retry delay after consecutive failures, up to the normal
two-second refresh interval, and reset it after a successful refresh.
Each virtual clock has its own worker, and a failed parent read can involve
bus traffic and error logging. Backoff limits that repeated work during a
persistent failure while retaining a prompt first retry.

Limit each retry delay to the next regular refresh deadline. Otherwise,
backoff can skip the next two-second refresh opportunity and lose a full
counter wrap even when the parent has recovered before that refresh was
due. Advance the deadline when an attempt reaches it without resetting the
backoff, so sustained failures still settle at the normal refresh interval.
Keep the retry state private to each clock's auxiliary worker.

Take the initial sample and initialize the counter before publishing the
clock. Return an error pointer from registration and propagate its errno
through n_vclocks, including when the initial sample fails. Queue the first
refresh immediately after registration so registration latency is not
followed by another full refresh interval.

Keep the existing cyclecounter mask and scaling. These scheduling changes
do not guarantee timely samples: prolonged read failures or worker delays
can still exceed the half-wrap conversion window, and a gap of about
4.295 seconds between successful samples can lose a full counter wrap.
Do not assume that getcycles64() exposes a full-width nanosecond counter.

Fixes: 5d43f951b1 ("ptp: add ptp virtual clock driver framework")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-3-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:15:58 -07:00
James Hilliard
3dea778260 ptp: unwind partially completed virtual clock creation
n_vclocks_store() publishes the new clock count only after every child
has been registered. If a later registration fails, it returns without
unregistering the children already created by that request. Those clocks
are left out of n_vclocks, and a subsequent request can overwrite their
index entries without removing them.

Unregister the newly created children in reverse order and clear their
index entries on failure. Leave the previously installed clocks and
their count unchanged. The n_vclocks mutex serializes this rollback with
other sysfs changes, and parent removal drains the store before walking
the children.

This was found by code inspection while adding initial PHC sample error
handling to virtual clock registration.

Fixes: 73f37068d5 ("ptp: support ptp physical/virtual clocks conversion")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-2-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:15:58 -07:00
James Hilliard
0e4a135aeb ptp: drain virtual clock sysfs operations before unregistering children
Parent clock removal walks its virtual clocks before removing the
n_vclocks sysfs attribute. The mutex taken by ptp_vclock_in_use() is
released before that walk, so a concurrent sysfs deletion can pick the
same child and unregister and free its ptp_vclock a second time. A
reference held by the device iterator does not protect that separately
allocated virtual clock.

Remove n_vclocks before walking the children. Removing the attribute
prevents new stores and drains stores already running, without holding
n_vclocks_mux across a callback that needs that mutex. Skip virtual
clocks, which do not have this attribute.

This race was found by code inspection of virtual-clock registration
failure cleanup and parent removal.

Fixes: bfcbb76b0f ("ptp: unregister virtual clocks when unregistering physical clock.")
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-1-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:15:57 -07:00
Yu Zhang
603a0c40d4 ptp: fix use-after-free in extts_fifo_show() reading tsevqs unlocked
extts_fifo_show() walks ptp->tsevqs with list_count_nodes() and then
list_first_entry() without holding ptp->tsevqs_lock, the spinlock that
"protects tsevqs from concurrent access". Every other accessor of the
list honours it: ptp_open() (list_add_tail), ptp_release() (list_del
followed by kfree of the per-fd queue), ptp_clock_release() and
ptp_clock_event() all take tsevqs_lock. extts_fifo_show() is the only
one that does not.

A per-fd timestamp queue is appended to tsevqs on open("/dev/ptpN") and
removed and freed on close(), both under tsevqs_lock:

	scoped_guard(spinlock_irq, &ptp->tsevqs_lock)
		list_del(&queue->qlist);
	bitmap_free(queue->mask);
	kfree(queue);

So a read of /sys/class/ptp/ptpN/fifo running concurrently with a
close() of a /dev/ptpN fd can have list_count_nodes() walk into the
queue that close() is removing and freeing, dereferencing freed memory
(use-after-free) or a poisoned list pointer.

Take tsevqs_lock around the list walk. The fifo only ever draws from the
first queue, which is the registration-time queue created in
ptp_clock_register() and freed only in ptp_clock_release(); that cannot
run while the sysfs attribute is being read, so the dequeue from
queue->buf under queue->lock may stay outside tsevqs_lock and the lock
order is unchanged.

Fixes: d26ab5a35a ("ptp: Replace timestamp event queue with linked list")
Cc: stable@vger.kernel.org
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
Link: https://patch.msgid.link/20261026100535.68114-1-yuz08559@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:04:08 -07:00
Jakub Kicinski
cd74322d83 Merge branch 'net-ethernet-mtk_wed-misc-fixes'
Zhi-Jun You says:

====================
net: ethernet: mtk_wed: misc fixes

Ths patch series includes some fixes for issues that were discovered
by Sashiko and one original patch fixing issue I encountered.

Patch 1,2,3 fix issues that were found by Sashiko.
Patch 1 was compiled test only.
Patch 2,3,4 were tested on a mt7986.

Patch 1 fixes tx wdma ring reset for WED v3.
Patch 2 fixes the reset condition for rx wdma.
Patch 3 fixes rx ring and tx wdma ring not being freed up
Patch 4 fixes WED on non-DBDC mt7986.
====================

Link: https://patch.msgid.link/20261026-wedfix-v6-0-a52f6b15d2fc@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:03:41 -07:00
Zhi-Jun You
dd6efae552 net: ethernet: mtk_wed: setup WDMA_RING_TX(0) for non-DBDC MT7986
WDMA_RING_TX(0) is required to set MTK_WED_WDMA_RING_TX for WED RX
but on a non-DBDC MT7986 it is never setup because idx is 1.

Setting MTK_WED_WDMA_RING_TX with WDMA_RING_TX(1) is not feasible because
WED still tries to send through WDMA_RING_TX(0). This is verified with
register dump.

Fix this by calling mtk_wed_wdma_tx_ring_setup if wed is v2 and
rx_ring[0] is not allocated and reset tx_wdma[0] if it's already
allocated also add error messages and bail when mtk_wed_start fails.

Fixes: 4c5de09eb0 ("net: ethernet: mtk_wed: add configure wed wo support")
Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
Link: https://patch.msgid.link/20261026-wedfix-v6-4-a52f6b15d2fc@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:03:39 -07:00
Zhi-Jun You
5b8d12512c net: ethernet: mtk_wed: free up rings during detach
During __mtk_wed_detach, rx_ring and tx_wdma aren't freed up.

Fix this by add them to mtk_wed_free_rx_rings.

This patch is pulled from mtk-openwrt-feeds to address Sashiko's review
and edit to rely on ring->desc instead of an extra flag.

Link: https://github.com/mediatek/mtk-openwrt-feeds/blob/main/25.12/files/target/linux/mediatek/patches-6.12/999-wed-04-Fix-reinsert-wifi-module-cause-memory-leak-issue.patch
Fixes: 4c5de09eb0 ("net: ethernet: mtk_wed: add configure wed wo support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/message/179000700034.2160803.10594281691384015089%40kernel.org
Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
Link: https://patch.msgid.link/20261026-wedfix-v6-3-a52f6b15d2fc@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:03:39 -07:00
Zhi-Jun You
7180a42d8e net: ethernet: mtk_wed: fix reset condition for rx wdma
In mtk_wdma_rx_reset, currently only resets the CPU index of the rings
that doesn't have a descriptor. This is wrong because no descriptor
means the ring is not configured.

Also mtk_wed_start makes sure that all rx_wdma rings are set up this
would lead to no ring getting their CPU index reset.

Fix this by inverting the reset condition so allocated rings will be
reset.

Fixes: 4c5de09eb0 ("net: ethernet: mtk_wed: add configure wed wo support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260724172040.1653-1-hujy652%40gmail.com
Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
Link: https://patch.msgid.link/20261026-wedfix-v6-2-a52f6b15d2fc@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:03:39 -07:00
Zhi-Jun You
cb50f16f37 net: ethernet: mtk_wed: skip ring reset in wdma_tx_ring_setup for WED v3
Currently WED v3 tx wdma ring, ring reset happens in a separate code
block unconditionally.

Moreover, v3 has double the size of wdma_desc and has different init
values. mtk_wed_ring_reset doens't deal with that and would corrupt the
wdma_desc.

Fix this by skipping mtk_wed_ring_reset in mtk_wdma_tx_ring_setup for
WED v3.

Fixes: e2f64db13a ("net: ethernet: mtk_wed: introduce WED support for MT7988")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260711112128.971-1-hujy652@gmail.com?part=1
Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
Link: https://patch.msgid.link/20261026-wedfix-v6-1-a52f6b15d2fc@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 16:03:39 -07:00
Maxime Chevallier
8dc87fc5d6 net: Use a dedicated flag to track disabled napi instances
Trying to disable the napi threaded state while the napi instance is
disabled will hang forever in napi_stop_kthread(), as it waits for
NAPIF_STATE_SCHED_THREADED to clear.

This won't happen until the next ____napi_schedule() call, which won't
happen as it's disabled.

This happens in 2 instances :

 - Drivers that create but don't use napi instances (stmmac's rxtx napi
   for AF_XDP for example), here it's a driver bug

 - Drivers that create their napi instances in .probe(). Here, setting
   threaded off while the interface is down will hang :

   ip link set eth0 down
   echo 1 > /sys/class/net/eth0/threaded
   echo 0 > /sys/class/net/eth0/threaded
   -> hang

Checking on netif_running() isn't enough, as napi instances may be
transiently disabled when changing the MTU for example, let's use a
dedicated flag to track if the instance is disabled.

This allows immediately disabling the kthread when the instance is
disabled.

This was tested on mvpp2 (probe-time napi_add) and stmmac.

Fixes: 689883de94 ("net: stop napi kthreads when THREADED napi is disabled")
Tested-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20261029153130.121204-1-maxime.chevallier@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 15:47:58 -07:00
Puranjay Mohan
1cd28b5354
bpf: Drop percpu_counter from the htab element count
The element count of a large non-preallocated hash map is a
percpu_counter, whose slow path takes fbc->lock with
raw_spin_lock_irqsave(). That is not safe against BPF programs that run
while the lock is held or contended: NMI programs and, as
queued_spin_lock_slowpath() calls trace_contention_end() with the lock
already held, programs attached to the contention_end tracepoint. If such
a program updates the same map it spins on the lock its own CPU holds:

  WARNING: possible recursive locking detected
  cend/250 is trying to acquire lock:
  (key#5){....}-{2:2}, at: _raw_spin_lock_irqsave+0x18/0x30
  but task is already holding lock:
  (key#5){....}-{2:2}, at: _raw_spin_lock_irqsave+0x18/0x30
    percpu_counter_add_batch+0xd8/0x160
    alloc_htab_elem+0x408/0x480
    htab_map_update_elem+0x1e8/0x6a0
    bpf_prog_7a29a1ae68aedf07_cend+0x14c/0x1f8
    __bpf_trace_contention_end+0x14/0x20
    queued_spin_lock_slowpath+0x2e8/0x468
    percpu_counter_add_batch+0xd8/0x160
    alloc_htab_elem+0x408/0x480
    htab_map_update_elem+0x1e8/0x6a0

is_map_full() is affected too, as __percpu_counter_compare() falls back
to percpu_counter_sum(), which takes the same lock.

map.elem_count already is a lockless per-cpu count of the same elements.
Make htab->count follow it in steps of PERCPU_COUNTER_BATCH and let
is_map_full() sum elem_count once count is within nr_cpu_ids * batch of
max_entries. Each cpu's elem_count is ahead of count by less than the
batch, so that is exact, in NMI as well.

Fixes: 86fe28f769 ("bpf: Optimize element count in non-preallocated hash map.")
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261021185117.650403-1-puranjay@kernel.org
2026-10-30 22:18:50 +00:00
Masafumi Suzuki
ed6c53b27b sctp: account for chunk padding in sctp_init_cause()
sctp_init_cause() accepts a chunk when skb_tailroom() can hold the
cause header and the payload. sctp_addto_chunk() then writes 0-3
bytes of padding before that header so the chunk stays 4-byte
aligned. The check does not include the padding, and the following
skb_put() calls skb_over_panic() from softirq.

Count the padding sctp_addto_chunk() is about to write. The cause
length on the wire stays the header plus the payload.

Found by LLM inspection, triggered and tested the fix.

Fixes: 8914f4bace ("sctp: add sctp_make_op_error_limited and reuse inner functions")
Cc: stable@vger.kernel.org
Signed-off-by: Masafumi Suzuki <shengshilingmu97@gmail.com>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20261027082405.1297-1-shengshilingmu97@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 15:08:42 -07:00
Jakub Kicinski
84574c7e46 Here are a few batman-adv bugfixes:
- avoid WARN_ON for orig_ifinfo allocation failure, by Deepanshu Kartikey
 
 - close OGM aggregation before transmission, by Chengfeng Ye
 
 - mcast: validate tracker padding before forwarding, by Kyle Zeng
 
 The remaining bugfixes are authored by Sven Eckelmann:
 
 - tpmeter: fix u32 truncation of reported bytes
 
 - dat: initialize orig_node of unfilled candidate slots
 
 - fix skb leak when hard_iface is being released
 
 - stop originator purge worker before freeing tt
 
 - tt: fix flag and event handling (6 patches)
 
 - tt: limit local table to single TVLV response size
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEE1ilQI7G+y+fdhnrfoSvjmEKSnqEFAmrknyAWHHN3QHNpbW9u
 d3VuZGVybGljaC5kZQAKCRChK+OYQpKeoaNWEACKp6LrH/AcPfvHZdsAc6qCud1a
 p/U2axzCDiabpabhdT/5vB4APk9WtKq0emDoPyzoscYDqkSGUza4Vlr6E4zf+zRP
 M4l+HcF3KMfhFY+yEMwFA/wt7eTzmVZzd7fu28Xha2nc1a8zwiSOLIKmh3QPxXFj
 zQfPZyR8a+fpakdJBWGk8IU1F5dJSWKZkUcV5PPYRN0kyI/hNY/y7xjjV5SNua4K
 IpRKv0ADXNdn4VHdW0KhYBFPWrMyJJkEJC2snjfJYKtwAVOj38AkC3xuX0tGkQQX
 id9SYExWwIISOiZcuCE7bynp95LM/F+CsdS7D7I92AB/FHqrLun2lrmdLhHQLyPn
 +zmOFVoTWpDrSttwHIPkv15cdsdPovH1ctCfVEkH13GD6k3Z4T0XGD+lUkeHDsAc
 O+irSMqdNIqSS6niDmBGmYicuZnIGuo+IQFzy3/GfP91ryn7e3XelRGn+CTJ4upe
 LnLx+UN3Y+EqBJ5LeJeZdo+C64Va/GezI36KygdDUtgBal2ietFhPm9lb90mhlg9
 ETi7oBU7VDGVvHeYm90XYP0vOLtVd/C1qfwi3NvqFanbAzwEWKAQW2ZYzkDHQx4K
 TXC+q9xRnYMwOscrAiZRbnGiJgXjBX1cDvdTDrdMt9vn0NDy8vdU69fqxObmu60O
 6VW1pFog501NQeSkmg==
 =LkDM
 -----END PGP SIGNATURE-----

Merge tag 'batadv-net-pullrequest-20261030' of https://git.open-mesh.org/batadv

Simon Wunderlich says:

====================
Here are a few batman-adv bugfixes:

- avoid WARN_ON for orig_ifinfo allocation failure, by Deepanshu Kartikey

- close OGM aggregation before transmission, by Chengfeng Ye

- mcast: validate tracker padding before forwarding, by Kyle Zeng

The remaining bugfixes are authored by Sven Eckelmann:

- tpmeter: fix u32 truncation of reported bytes

- dat: initialize orig_node of unfilled candidate slots

- fix skb leak when hard_iface is being released

- stop originator purge worker before freeing tt

- tt: fix flag and event handling (6 patches)

- tt: limit local table to single TVLV response size

* tag 'batadv-net-pullrequest-20261030' of https://git.open-mesh.org/batadv:
  batman-adv: tt: limit local table to single TVLV response size
  batman-adv: tt: don't drop local events queued during TVLV update
  batman-adv: tt: only update flags for TT events
  batman-adv: tt: ignore ROAM flag of received ADD changes
  batman-adv: tt: send ROAM_ADV on each roamed back client
  batman-adv: tt: clear ROAM flag when re-adding a pending local client
  batman-adv: tt: only transmit local ROAM flag together with DEL
  batman-adv: stop originator purge worker before freeing TT
  batman-adv: fix skb leak when hard_iface is being released
  batman-adv: dat: initialize orig_node of unfilled candidate slots
  batman-adv: tpmeter: fix u32 truncation of reported bytes
  batman-adv: mcast: validate tracker padding before forwarding
  batman-adv: Close OGM aggregation before transmission
  batman-adv: avoid WARN_ON for orig_ifinfo allocation failure
====================

Link: https://patch.msgid.link/20261030135105.2555887-1-sw@simonwunderlich.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-30 14:54:01 -07:00
Jose Fernandez (Anthropic)
3e4279dc51
bpf: Fix jited line info off by the CFI preamble
With CONFIG_CFI=y, every jited line info entry after a function's
first is cfi_get_offset() bytes too high on x86-64, riscv64 and arm64,
so tools that use it show the wrong source line.

The JITs count the insn_to_jit_off[] offsets from the start of the
image. Since the CFI commits below, prog->bpf_func starts
cfi_get_offset() bytes into the image, and bpf_prog_fill_jited_linfo()
adds the offsets to prog->bpf_func. s390 corrects its offsets before
the call, the other three JITs do not.

Subtract cfi_get_offset() once in bpf_prog_fill_jited_linfo() and drop
the s390 correction. jited_linfo[0] stays prog->bpf_func, the
function's ksym address. Without CONFIG_CFI, cfi_get_offset() is 0 and
nothing changes.

Fixes: 4f9087f166 ("x86/cfi,bpf: Fix BPF JIT call")
Fixes: e63985ecd2 ("bpf, riscv64/cfi: Support kCFI + BPF on riscv64")
Fixes: 710618c760 ("arm64/cfi,bpf: Support kCFI + BPF on arm64")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Reported-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261030-b4-arm64-bpf-linfo-cfi-v2-1-4eac83435d4b@linux.dev
Closes: https://lore.kernel.org/all/20260904014748.C04AA1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/DLNXZ2WK7TPD.2RZBUNRS4FA4L@gmail.com/
2026-10-30 21:33:15 +00:00
Daniel Borkmann
99681d9a38
selftests/bpf: Test kprobe and fentry/fexit programs on one function
A kprobe next to a BPF trampoline makes the ftrace site of the function
call ftrace_regs_caller and from there the list of ftrace callbacks,
the path that crashed while ftrace_ops_list_func() started at an odd
address. No test covers a function traced by both. Thus, attach an
fentry program and a kprobe to bpf_fentry_test1(), then a second fentry
program, which modifies the trampoline of the shared site, then an fexit
program, after which ftrace_regs_caller enters the trampoline by a jmp,
then detach the kprobe, after which the site jumps to it directly. After
each step, check that every attached program ran once for the call and
saw its argument, and the fexit program its return value.

Without the previous fix the test crashes the kernel, but only where
ftrace_ops_list_func() is at an odd address (in my test with gcc +
CONFIG_CC_OPTIMIZE_FOR_SIZE=y). With the fix it passes:

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t fentry_kprobe_shared
  [...]
  #147     fentry_kprobe_shared:OK
  Summary: 1/0 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: https://patch.msgid.link/20261028202345.1215859-2-daniel@iogearbox.net
2026-10-30 21:21:46 +00:00
Daniel Borkmann
31ac959c91
x86/ftrace: Mark jmp mode by clearing bit 63 of trampoline address
Since commit 0c3772a8db ("x86/ftrace: Implement DYNAMIC_FTRACE_WITH_JMP")
ftrace_call_replace() emits a jmp instead of a call when bit 0 of the
target is set, the mark of a direct trampoline that is entered by a jmp.
ftrace_update_ftrace_func() and arch_ftrace_update_trampoline() use it
too, for the call of the ftrace callback in ftrace_caller, ftrace_regs_caller
and the ftrace trampolines, but a callback is a C function and can start
at an odd address. It does with gcc13 and CONFIG_CC_OPTIMIZE_FOR_SIZE=y:
gcc13 has no -fmin-function-alignment, so CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT
is not set, and the -falign-functions=16 used in its place does not apply
to functions optimized for size. Here ftrace_ops_list_func() starts at:

  ffffffff810e0147 T ftrace_ops_list_func

ftrace_regs_call then becomes a jmp to the byte before it:

  ftrace_regs_call ffffffff810374f3: e9 4e 8c 0a 00

That byte is the last one of the preceding function's tail jump, and with
the first two of ftrace_ops_list_func() it decodes as an inc DWORD PTR
[rcx+0x57], which swallows the push %r15 of the prologue. Entered without
a return address and one push short, the list function returns through
the pt_regs that ftrace_regs_caller saved, here to the saved R14:

  BUG: unable to handle page fault for address: ffff888116c29f40
  #PF: supervisor instruction fetch in kernel mode
  RIP: 0010:0xffff888116c29f40
  R13: 0000000000000000 R14: ffff888116c29f40 R15: 0000000000000000
  Call Trace:
   ? bpf_trampoline_6442499918+0x1/0x149
   ? bpf_lsm_file_open+0x5/0x8
   ? bpf_lsm_file_open+0x5/0x8
   ? security_file_open+0x19/0x46
   ? do_dentry_open+0x16c/0x32a

The list function is installed whenever two ftrace_ops are registered,
and a function that two of them trace calls it. A kprobe next to a BPF
trampoline is one such case, and with the single ftrace_ops of the BPF
trampolines every update_ftrace_direct_mod() is another, as it registers
a stub ops for the sites it modifies. Here, detaching one of several BPF
LSM programs from a busy hook crashed the tasks that ran the hook during
the update.

Bit 0 is free only in the direct trampolines that a dyn_ftrace record can
point to, but bit 63 is set in every kernel text address on x86_64. Thus,
mark jmp mode by clearing bit 63 instead, so that ftrace_is_jmp() is false
for any callback, whatever its alignment, and ftrace_regs_caller sets the
bit again where it cleared bit 0 before. A marked address is not canonical,
so a return or indirect branch to one that missed ftrace_jmp_get() faults
instead of running from a byte before its target.

Fixes: 0c3772a8db ("x86/ftrace: Implement DYNAMIC_FTRACE_WITH_JMP")
Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Link: https://patch.msgid.link/20261028202345.1215859-1-daniel@iogearbox.net
2026-10-30 21:21:46 +00:00
Prasad Koya
d8a4f4c59d macvlan: fix allmulti reference counting in passthru mode
Enabling allmulticast on a down passthru macvlan, bringing it up,
then toggling allmulticast off and on can underflow the lower device's
allmulti reference count.

macvlan_change_rx_flags() only propagates IFF_ALLMULTI changes while
the macvlan is up. However, the passthru path in macvlan_open() skips
taking an allmulti reference when IFF_ALLMULTI is already set.
Clearing allmulticast after opening the device therefore decrements
a reference that was never taken. With no other allmulti users, the
unsigned counter wraps from zero to UINT_MAX. The next increment
fails with -EOVERFLOW and reports "allmulti touches roof".

The issue was observed during development testing with 5.10 and 6.12
kernels. It was reproduced on Linux 6.12.68 by enabling allmulticast
on a down passthru macvlan, bringing it up, and toggling allmulticast
off and on. This triggered the “allmulti touches roof” warning.

Signed-off-by: Prasad Koya <prasad@arista.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-10-30 10:06:40 +00:00
Zhou Qiuyue
66dfb2cacd ipv6: raw: fix use-after-free in rawv6_send_hdrinc()
rawv6_send_hdrinc() caches the route before handing the skb to
l3mdev_ip6_out(). The VRF output path may replace skb->dst and release
the original route, leaving the cached pointer stale.

The function later dereferences that pointer for statistics accounting
and as the output device passed to NF_HOOK(). Its RCU read-side critical
section starts after l3mdev_ip6_out(), so it cannot prevent the old route
from being reclaimed in between.

Reload the route from the current skb destination after
l3mdev_ip6_out() returns.

KASAN reports a slab-use-after-free in rawv6_sendmsg(), with the route
allocated by ip6_dst_alloc(), freed by dst_destroy() from rcu_core(), and
the related RCU callback queued from vrf_l3_out().

Fixes: 4c1feac58e ("net: vrf: Flip IPv6 output path from FIB lookup hook to out hook")
Cc: stable@vger.kernel.org
Signed-off-by: Zhou Qiuyue <n0ps1edzz@gmail.com>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-10-30 09:32:15 +00:00
Franck Baur
ed9179fc72 net: jme: keep RX MAC clock enabled for WoL
On the JMicron JMC250 revision 03, the MAC reset performed during
suspend leaves GPREG1_RXCLKOFF set. Although the driver enables Magic
Packet detection, the gated RX MAC clock prevents wake-up from ACPI S3.

Keep the RX MAC clock enabled while WoL is armed. Restore the gated
clock state immediately after disabling WoL during resume, preserving
the RX engine initialization ordering.

Prevent concurrent link-change work from gating the clock again after
WoL has been armed. Quiesce interrupt-driven link-change scheduling,
synchronize pending interrupts, and cancel outstanding link-change
work before programming WoL in suspend and shutdown paths.

Restore the deferred processing state before requesting link
reinitialization on resume.

Tested on an ASUS K42JE with JMC250 [197b:0250] rev 03 using a
Debian 6.12.111 kernel and an externally built module. ACPI S3 wake
with a Magic Packet completed in 19 seconds, while a control without
a Magic Packet resumed through the RTC alarm after 123 seconds.
Ethernet and SSH recovered after resume.

S4 and S5 wake behaviour has not been validated with this revision.

Fixes: 854a2e7c33 ("jme: Safer MAC processor reset sequence")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Franck Baur <franck.baur.67@gmail.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
2026-10-30 09:18:33 +00:00
Sven Eckelmann
a137095419
batman-adv: tt: limit local table to single TVLV response size
The reservation of local TT entries and VLANs only limits the local table
by (int) packet_size_max. But the full table response is sent as a single
unicast TVLV packet whose tvlv_len (covering the TVLV header and the TT
TVLV) is only 16 bit wide. The reservation must therefore be capped at the
minimum of both the packet_size_max and the maximum theoretic table
response.

The size limit was already missing the 16 bit tvlv_len cap since the
original packet_size_max check was introduced. But this check was only
reachable with fragmentation disabled and a hard interface MTU larger than
the maximum unicast TVLV packet. In this case,
batadv_tt_prepare_tvlv_local_data() refuses to build the full table
response and no oversized packet is created. It is therefore mostly
affecting the commit 85fb027f61 ("batman-adv: tt: reject VLAN/TT entries
before reaching size limit"), which should prevent this kind of
overallocation.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260930094558.3723766-2-sw%40simonwunderlich.de?part=8
Fixes: a19d3d85e1 ("batman-adv: limit local translation table max size")
Cc: <stable+noautosel@kernel.org> # requires 85fb027f61, old behavior only affects MTU > 64KiB without fragmentation
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:27 +01:00
Sven Eckelmann
ed7a0dfdd3
batman-adv: tt: don't drop local events queued during TVLV update
batadv_tt_tvlv_container_update() read the number of local changes without
holding changes_list_lock. batadv_tt_local_event() is not serialized by
the commit_lock and can queue new events before the changes_list is
flushed:

  CPU0                          CPU1
  batadv_tt_tvlv_container_update()
    num = ...local_changes;
                                batadv_tt_local_event()
                                  list_add_tail(...);
                                  ...local_changes++;
    spin_lock_bh(&...changes_list_lock);
    /* only num events copied but all freed */

The additional events were freed without ever being sent. Other nodes will
only notice this via a CRC mismatch and must request the full table.

The number of changes and the changes_list must therefore be taken
atomically. Events queued afterwards then stay in the tt.changes_list for
the next TT round.

The changes can no longer be kept for the next round when the TVLV buffer
allocation fails. But they would be sent with a skipped TTVN anyway, so the
other nodes have to request the full table in this case either way. The
last changeset is only dropped in this case when the TTVN was incremented.
Without new changes, it still describes the current TTVN.

Previously, the unconsumed changes caused a retry of the TVLV container
update in the next commit round. Since the changes are now consumed, the
next round would only take the path without changes and wait for
BATADV_TT_OGM_APPEND_MAX rounds before updating the container again. Until
then, the outdated container with the previous TTVN would still be
announced. The ogm_append_cnt is therefore reset on failure to retry the
update in the next OGM interval.

This doesn't make the CRC consistent with the announced changeset. The
local table modifications are still not serialized with the commit and
batadv_tt_local_transition_new() can still make a client part of the CRC
for which the event is only part of the next TT round. Such an
inconsistency is detected by the CRC check of the other nodes and solved
via a full table request.

Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/bug/linux-fc286ddd-5bed-4683-b842-ee7a307eeb19
Fixes: a73105b8d4 ("batman-adv: improved client announcement mechanism")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:27 +01:00
Sven Eckelmann
ad1fd828aa
batman-adv: tt: only update flags for TT events
In the first implementation of the translation table events, it was only
possible to announce:

* ADD: new locally detected client
* DEL: disappeared local client

If an ADD event was queued and then a DEL event was queued in the same
timeslot, it is valid to destroy both events because nothing actually
changed for remode nodes

But with commit 3c4f7ab60c ("batman-adv: improve the TT component to
support runtime flag changes") and subsequent changes, it could also happen
that there are extra ADD events:

* ADD: _NEW_ locally detected client
* ADD: already existing client with new flags
* DEL: disappeared local client

The first and the last type of event could in theory still be removed
together from the (to be announced) events queue. But if the "update flags"
ADD is dropped together with the DEL, it would still leave global
translation table of a remote node in the incorrect state - believing that
the client didn't disappear.

If a detected client was previously announced, a DEL event must only
overwrite the "update flags" ADD but the DEL itself must still continue to
exist in the (to be anounced) events queue. For now, adjustment of the
announced flags is used for everything instead of dropping already queued
up events completely.

Similarly, a DEL followed by an ADD caused both entries to be deleted. But
the new ADD could announce flags changes which were not yet present for the
client before it was marked for DELetion. The new ADD must therefore only
overwrite the DEL - but still be kept.

Cc: stable@vger.kernel.org
Fixes: 3c4f7ab60c ("batman-adv: improve the TT component to support runtime flag changes")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:27 +01:00
Sven Eckelmann
c5d68abe6e
batman-adv: tt: ignore ROAM flag of received ADD changes
A received TT change (OGM diff or full table response) with the ROAM flag
but without DEL is handled by batadv_tt_global_add() like a ROAMING_ADV:

* a newly created global entry gets BATADV_TT_CLIENT_ROAM and is
  therefore excluded from the global CRC. The sender has it in its local
  CRC and the receiver has to request the full table again
* batadv_tt_global_purge_local() removes the local entry of the
  receiver. The receiver's own client is considered as roamed to the sender
  and frames for it are rerouted

The ROAM flag only has a meaning together with DEL. Drop it on reception to
keep it from populating the global table with a temporary ROAMING entry
which is not part of the CRC - and therefore causing a CRC mismatch.

Cc: stable@vger.kernel.org
Fixes: 068ee6e204 ("batman-adv: roaming handling mechanism redesign")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:26 +01:00
Sven Eckelmann
aff4d5d10f
batman-adv: tt: send ROAM_ADV on each roamed back client
When a ROAMING_ADV is received for an announced local client,
batadv_roam_tvlv_unicast_handler_v1() creates a global entry with the
BATADV_TT_CLIENT_ROAM flag set.

If the client sends a frame again before the next TTVN commit,
batadv_tt_local_add_roam() is expected to announce this return via a
ROAM_ADV frame. But this doesn't happen because the global entry (created
by the first ROAMING_ADV) carries BATADV_TT_CLIENT_ROAM until the new
originator announces the client.

Let batadv_tt_local_add_roam() always handle a roamed back client -
independent of the ROAM flag of the global entry:

* trigger sending of the ROAM_ADV frame(s)
* remove the (with the roaming) associated global entry

Cc: stable@vger.kernel.org
Fixes: 068ee6e204 ("batman-adv: roaming handling mechanism redesign")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:26 +01:00
Sven Eckelmann
cc2186d785
batman-adv: tt: clear ROAM flag when re-adding a pending local client
When a ROAMING_ADV is received for an announced local client,
batadv_tt_local_mark_removed() sets BATADV_TT_CLIENT_ROAM, queues a
DEL|ROAM change and marks the entry as BATADV_TT_CLIENT_PENDING. If the
client sends a frame again before the next TTVN commit,
batadv_tt_local_add_existing() only clears the PENDING flag and returns
early. The ADD cancels the queued DEL, but the entry keeps the ROAM flag:

* batadv_is_my_client() reports the client as not served by this node
* batadv_tt_local_client_is_roaming() reroutes unicast frames for it to
  the node which sent the ROAMING_ADV

The ROAM flag is only removed with the next frame of the client.

Since BATADV_TT_CLIENT_ROAM is set together with BATADV_TT_CLIENT_PENDING,
it has to be cleared also at the same time with BATADV_TT_CLIENT_PENDING
when the client roamed back.

Cc: stable@vger.kernel.org
Fixes: 068ee6e204 ("batman-adv: roaming handling mechanism redesign")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:26 +01:00
Sven Eckelmann
10f24f0584
batman-adv: tt: only transmit local ROAM flag together with DEL
BATADV_TT_CLIENT_ROAM is part of BATADV_TT_REMOTE_MASK but on the wire it
only has a defined meaning together with BATADV_TT_CLIENT_DEL: the
originator no longer serves the client because it roamed to another node.
Such a DEL is only relevant for events (non-full table requests).

An ADD carrying ROAM is processed (by accident) by the receiver like a
ROAMING_ADV: a newly created global entry is marked as roaming and is
excluded from the global CRC. But the sender includes it in its local CRC.

But such a behavior doesn't make sense for non-ROAM_ADV because a new TTVN
is meant as announced commit of the local TT table of a node and should
therefore not be used to create a temporary (roam) global entry in a node.

At the moment, such an ADD with the BATADV_TT_CLIENT_ROAM flag set can
happen due to two mechanisms:

batadv_tt_local_valid() copies all flags of the local entry into a full
table response. It is not synchronized with batadv_tt_local_mark_removed().
An entry which was marked as ROAM|PENDING by a ROAMING_ADV is still part of
the current TTVN and is sent with the ROAM flag set. The receivers then
create a roaming global entry for it and detect a CRC mismatch, which
causes them to request the full table again.

The same can happen for an ADD change which is queued for an entry which
(still) has the ROAM flag set. For example when only the dynamic WIFI or
ISOLA flags were updated.

It is not triggered by batadv_send_other_tt_response() because
batadv_tt_global_valid() is already taking care of filtering out
BATADV_TT_CLIENT_ROAM entries.

For the two problematic announcement mechanism, only send the ROAM flag of
local entries together with a DEL.

This only fixes the ROAM marking of the global entry and the resulting CRC
mismatch. When the requester of the full table is the node which sent the
ROAMING_ADV, the still announced entry will (independent of the ROAM flag)
cause batadv_tt_global_purge_local() to remove the requester's own (new)
local entry for the client. This is not addressed here.

Cc: stable@vger.kernel.org
Fixes: 27b37ebfa2 ("batman-adv: correctly pass the client flag on tt_response")
Fixes: 068ee6e204 ("batman-adv: roaming handling mechanism redesign")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:26 +01:00
Sven Eckelmann
f89eda5a9c
batman-adv: stop originator purge worker before freeing TT
batadv_mesh_free() releases the translation tables via batadv_tt_free()
before batadv_originator_free() stops orig_work. The purge worker can
therefore still run while the TT is torn down. When an originator times
out, batadv_purge_orig_ref() calls batadv_tt_global_del_orig(), which
loads tt.global_hash and walks all buckets while taking their locks:

  CPU0                          CPU1
  batadv_tt_free()              batadv_purge_orig()
                                  batadv_tt_global_del_orig()
                                    hash = ...tt.global_hash;
    batadv_tt_global_table_free()
      batadv_hash_destroy(hash);
                                    spin_lock_bh(&hash->list_locks[i]);

Disable orig_work at the beginning of batadv_mesh_free(), directly after
the mesh was marked as deactivating. The second
disable_delayed_work_sync() in batadv_originator_free() is harmless because
it is free'd anyway.

Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260708091821.314516-1-sw%40simonwunderlich.de?part=3
Fixes: 9d31b3ce81 ("batman-adv: fix potential TT client + orig-node memory leak")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:25 +01:00
Sven Eckelmann
522e4aece2
batman-adv: fix skb leak when hard_iface is being released
batadv_batman_skb_recv() owns the skb it is given. When the hard_iface
refcount already dropped to zero, the function jumped to err_out, which
only returned NET_RX_DROP and skipped the kfree_skb() under err_free.

To avoid a leak, free the skb before returning in this case.

Cc: stable@vger.kernel.org
Fixes: 4fe56e60ac ("batman-adv: Check hard_iface refcnt when receiving skb")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:25 +01:00
Sven Eckelmann
4eb19a389d
batman-adv: dat: initialize orig_node of unfilled candidate slots
batadv_dat_select_candidates() allocates the candidate array without
zeroing it. batadv_choose_next_candidate() marks each slot as
BATADV_DAT_CANDIDATE_NOT_FOUND but only sets orig_node when an eligible
originator was found. In the following rounds,
batadv_is_orig_node_eligible() compares res[j].orig_node of all previous
slots against the evaluated originator. For slots without candidates, it
reads uninitialized memory.

The orig_node has to be cleared together with the
BATADV_DAT_CANDIDATE_NOT_FOUND type.

Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/bug/linux-b25d9aa4-10bb-427c-a145-ccaadc2a1bb9
Fixes: 785ea11441 ("batman-adv: Distributed ARP Table - create DHT helper functions")
Acked-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:25 +01:00
Sven Eckelmann
1025b76d13
batman-adv: tpmeter: fix u32 truncation of reported bytes
When more than 4 GB are transferred by the throughput meter,
batadv_tp_batctl_notify() will cut of the upper 32 bit of the u64 counter
and thus under-report the actual transferred bytes.

The data type of the temporary storage variable must therefore still
continue to use u64.

Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/bug/linux-08bb3be4-6c6a-452d-b4e4-606940c6cfa5
Fixes: 33a3bb4a33 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:24 +01:00
Kyle Zeng
ea01fff30f
batman-adv: mcast: validate tracker padding before forwarding
A multicast tracker with an even number of destinations needs two
padding bytes after its destination list. batadv_mcast_forw_packet()
currently only checks that the count field and the addresses fit in
the tracker TVLV.

If an unpadded even tracker is compacted to an odd number of
destinations, batadv_mcast_forw_shrink_update_headers() includes those
missing padding bytes in the amount to remove. The subsequent memmove
can then write two bytes past the old packet tail. With no tailroom,
this corrupts skb_shared_info.

Include the required padding in the existing tracker length check.
This rejects the malformed tracker before either received or locally
generated packets can reach the compactor.

Fixes: 2dfe644a1c ("batman-adv: mcast: shrink tracker packet after scrubbing")
Cc: stable@vger.kernel.org
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-30 10:11:07 +01:00
Andrea Mayer
5838f10563 seg6: fix transport header for inner IPv4 with IP options
The End.DT4, End.DT46 (its IPv4 path only) and End.DX4 behaviors set the
transport header of the decapsulated IPv4 packet at a fixed 20 bytes, the
size of an IPv4 header without options. They do not validate the header
length either. With options, the transport header points at the first
option byte. The effects include:
- ping -R sends an echo request with a 60-byte IPv4 header to a local
  address through an End.DT4 or an End.DX4 SID. Since icmp_rcv()
  computes the ICMP checksum from the first option byte, the request
  fails the check and is counted in IcmpInCsumErrors.
- A UDP datagram can reach a port that an iptables rule drops. The rule
  checks the UDP header after the full IPv4 header, while the socket
  lookup reads it at the fixed 20-byte offset.
- With an inbound AH state, ah_input() reads the AH header at the fixed
  20-byte offset, but copies the IPv4 header over it with the length in
  the IHL field. A packet shorter than that length can make ah_input()
  write past the end of the data, into skb_shared_info when the skb has
  no tailroom.

Validate the inner IPv4 header length with the new helper
seg6_validate_iphdr_len() and set the transport header at that length. A
packet that is not IPv4, whose header length field is below 5, or whose
header is truncated, is dropped with a drop reason. The fix is limited to
the header length, which the transport header relies on. Other checks done
on IPv4 input, such as the header checksum, the total length and the IP
options, are not addressed here.

Found by code inspection while reviewing commit 44930446dd ("ipv6: seg6:
clear IPv4 control block on IPIP decapsulation"), as a pre-existing issue
that Sashiko also reported on v2 of that patch. Without this patch, a
bpftrace probe on ah_input() shows the reporter's reproducer packet
written into skb_shared_info. With it, that packet is dropped before
ah_input(), ping -R no longer fails the ICMP checksum, the UDP datagram
reaches its real port, and the SRv6 selftests still pass. These effects
reproduce on an unmodified kernel, without error injection.

Fixes: 891ef8dd2a ("ipv6: sr: implement additional seg6local actions")
Fixes: 664d6f8686 ("seg6: add support for the SRv6 End.DT4 behavior")
Reported-by: Hazley Samsudin <hazleycryilis@gmail.com>
Closes: https://lore.kernel.org/netdev/20260809221915.2ffc1ecd0f445fcb70270e31@uniroma2.it/
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20261028171511.35-1-andrea.mayer@uniroma2.it
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-29 16:56:36 -07:00
Eric Biggers
01ad209f12 lib/crypto: mldsa: Add __must_check to mldsa_verify()
Signature verification status always must be checked.  Add __must_check,
for consistency with e.g. the AES-GCM and ChaCha20Poly1305 functions.

No effect on current callers, who always check the return value.

Fixes: 64edccea59 ("lib/crypto: Add ML-DSA verification support")
Cc: stable@vger.kernel.org
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20261029054534.68481-4-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-10-29 10:12:11 -07:00
Eric Biggers
efb621a57d lib/crypto: mldsa: Explicitly check that 'alg' is a valid value
C doesn't guarantee at the language level that an enum actually has one
of the declared values.

For robustness, make mldsa_verify() handle invalid values of 'alg'.

No effect on current callers, who always pass a valid value for 'alg'.
(Except for the KUnit test case that this commit adds.)

Fixes: 64edccea59 ("lib/crypto: Add ML-DSA verification support")
Cc: stable@vger.kernel.org
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20261029054534.68481-3-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-10-29 10:12:08 -07:00
Eric Biggers
5c140c8700 lib/crypto: mldsa: Check pk_len before doing pointer arithmetic
Though common in the kernel and benign in practice (not even triggering
UBSAN warnings), taking an address past the end of an array is undefined
behavior according to the C specification.

Therefore, compute &pk[RHO_LEN] only after pk_len has been validated,
since pk_len could be less than RHO_LEN if an incorrectly sized public
key is provided.

(Also fix a typo that isn't worth its own commit.)

Fixes: 64edccea59 ("lib/crypto: Add ML-DSA verification support")
Cc: stable@vger.kernel.org
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20261029054534.68481-2-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-10-29 10:12:05 -07:00
Eric Biggers
539436435f lib/crypto: powerpc/poly1305: Remove BROKEN implementation
The PowerPC implementation of Poly1305 has been marked as BROKEN for
well over a year, since commit bc8169003b ("crypto: powerpc/poly1305 -
add depends on BROKEN for now").  So, it's not being built or used.

The justification for marking it BROKEN was that it didn't work in
softirq context.  That still fully applies.

However, it turns out the assembly file actually also contains logic
bugs that make it compute incorrect Poly1305 values in some cases.  This
is shown by it failing the test case test_poly1305_split_update_carry
(if "depends on BROKEN" is removed).  The cause of that appears to be a
lost carry bit in Carry_reduction.  However, there also appears to be a
bug in do_final_update where it incorrectly assumes v6 is fully reduced.

In addition, poly1305_emit_64 contains a secret-dependent branch.

Let's just drop this code.  A fixed version can be reconsidered later.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20261029063522.124421-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-10-29 10:09:21 -07:00
Haiyue Wang
6cea839b2d
platform: arm64: drop the vacuous THERMAL dependency from EC_ASUS_GLYMUR
'depends on THERMAL || THERMAL=n' is always true and is semantically a
no-op, but it couples NEW_LEDS, which is selected here, to THERMAL and
closes a Kconfig dependency loop. The C tools stay silent because they
fold the always-true expression to 'y' before running dependency loop
detection; kconfiglib, used by the Yocto kernel config audit, does not
fold and rejects the config at parse time.

The loop is easy to expose with the in-tree tools, using the technique
from commit b33a654a5b ("drm/tiny: Kconfig: Remove always-y THERMAL
dep. from TINYDRM_REPAPER"),
https://git.kernel.org/linus/b33a654a5bd6: temporarily make THERMAL
tristate so the folding stops, then any config target reports it:

  $ sed -i 's/bool "Thermal drivers"/tristate "Thermal drivers"/' \
      drivers/thermal/Kconfig
  $ make allnoconfig
  error: recursive dependency detected!
	symbol POWER_SUPPLY is selected by HID_ASUS
	symbol HID_ASUS depends on LEDS_CLASS
	symbol LEDS_CLASS depends on NEW_LEDS
	symbol NEW_LEDS is selected by EC_ASUS_GLYMUR
	symbol EC_ASUS_GLYMUR depends on THERMAL
	symbol THERMAL is selected by AB8500_BM
	symbol AB8500_BM depends on POWER_SUPPLY

Drop the vacuous line to break the loop; the driver still builds both
with and without THERMAL.

Fixes: db3a9dddab ("platform: arm64: Add a driver for the EC found on ASUS Glymur machines")
Signed-off-by: Haiyue Wang <haiyuewa@163.com>
Assisted-by: LLM
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://patch.msgid.link/20261029021330.460192-1-haiyuewa@163.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
2026-10-29 15:04:56 +02:00
Chengfeng Ye
f91f64a916
batman-adv: Close OGM aggregation before transmission
The OGM send worker leaves its forwarding packet on forw_bat_list until
after batadv_iv_ogm_emit() returns. Aggregation holds forw_bat_list_lock,
but emission reads and clones the packet without that lock.

CPU 0 can therefore start emitting a queued packet while CPU 1 takes the
list lock, finds the same packet and appends another OGM. The sender can
observe the new packet length before the corresponding direct-link flag
is set, or clone the skb while its length and payload are being updated.
This can transmit an OGM with incorrect flags or inconsistent data.

KCSAN reported:

  BUG: KCSAN: data-race in batadv_iv_ogm_queue_add / batadv_iv_send_outstanding_bat_ogm_packet
  write to 0xffff888100fedcf8 of 2 bytes by interrupt on cpu 1:
  read to 0xffff888100fedcf8 of 2 bytes by task 70 on cpu 2:
  value changed: 0x00c0 -> 0x00d8

Mark the aggregate as full under forw_bat_list_lock before emission. This
waits for any ongoing append and prevents further aggregation. Emission
uses packet_len to walk the OGMs, so all queued packets are still sent.
Keep the packet on the list so interface purging can find the worker,
wait for it to finish and free the packet.

Fixes: 9b4aec647a ("batman-adv: fix rare race conditions on interface removal")
Cc: stable@vger.kernel.org # 4.10.x: 434becf57b ("batman-adv: Limit number of aggregated packets directly")
Cc: stable@vger.kernel.org # 4.10.x
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
[ sven: drop assisted tag, document new meaning of num_packets ]
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-29 08:12:44 +01:00
Dominique Martinet
35ecd40c0d 9p: optimize p9_fcall struct
p9_fcall has a 1 byte hole followed by more data and then a single byte
element:

struct p9_fcall {
	u32                        size;                 /*     0     4 */
	u8                         id;                   /*     4     1 */

	/* XXX 1 byte hole, try to pack */

	u16                        tag;                  /*     6     2 */
	size_t                     offset;               /*     8     8 */
	size_t                     capacity;             /*    16     8 */
	struct kmem_cache *        cache;                /*    24     8 */
	u8 *                       sdata;                /*    32     8 */
	bool                       zc;                   /*    40     1 */

	/* size: 48, cachelines: 1, members: 8 */
	/* sum members: 40, holes: 1, sum holes: 1 */
	/* padding: 7 */
	/* last cacheline: 48 bytes */
};

move `zc` up to optimize it:

struct p9_fcall {
	u32                        size;                 /*     0     4 */
	u8                         id;                   /*     4     1 */
	bool                       zc;                   /*     5     1 */
	u16                        tag;                  /*     6     2 */
	size_t                     offset;               /*     8     8 */
	size_t                     capacity;             /*    16     8 */
	struct kmem_cache *        cache;                /*    24     8 */
	u8 *                       sdata;                /*    32     8 */

	/* size: 40, cachelines: 1, members: 8 */
	/* last cacheline: 40 bytes */
};

This in turn also makes p9_req_t 16 bytes smaller (152 -> 136) as it
contains two of these.

Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
Message-ID: <20261029060014.3-1-asmadeus@codewreck.org>
2026-10-29 06:05:56 +00:00
Hui Peng
241d469012 9p: reject RERROR/RLERROR with zero errcode
In p9_check_errors() (net/9p/client.c), a malicious or buggy 9p server
returning P9_RERROR or P9_RLERROR with ecode == 0 causes
p9_check_errors() to return 0 (success) while leaving the unparsed
response payload as if the expected reply message type succeeded.

Map ecode == 0 on RERROR / RLERROR to -EPROTO.

Link: https://lore.kernel.org/all/20260919221734.3708000-1-benquike@gmail.com/
Signed-off-by: Hui Peng <benquike@gmail.com>
Message-ID: <20261029055801.3-1-asmadeus@codewreck.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:05:55 +00:00
Yuanfu Xie
56894cadf2 9p: do not store the create fid on special files
v9fs_vfs_atomic_open_dotl() always stores the create fid in
file->private_data after finish_open().  FIFO and device inodes
already have type-specific file_operations that own that field.
Overwriting it with the fid makes later read/write/close treat the
p9_fid as a pipe_inode_info, which corrupts the fid and can use it
after it has been clunked.  The non-dotl atomic_open path does not
assign the fid this way.

Only attach the fid for regular files and directories.  Special
files do not need the create fid; leave it for the existing
p9_fid_put() on the out path so it is clunked before return.

KASAN report, linux-stable 4982d3552a3b:

BUG: KASAN: slab-use-after-free in anon_pipe_prefill_and_lock+0x376/0x3f0
Read of size 4 at addr ffff88800ab30538 by task repro/1

Call Trace:
 <TASK>
 anon_pipe_prefill_and_lock+0x376/0x3f0
 anon_pipe_write+0x127/0x1600
 fifo_pipe_write+0x24/0x300
 vfs_write+0x659/0xd00
 ksys_write+0x10f/0x200
 do_syscall_64+0xdd/0x4a0
 </TASK>

Fixes: 30d9049474 ("kill struct opendata")
Signed-off-by: Yuanfu Xie <yuanfuxie@stu.pku.edu.cn>
Message-ID: <92377346-29E9-46D3-96F5-AABA8A64CD57@stu.pku.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:11 +00:00
Yuanfu Xie
ff1baa01a6 9p: fall back to the normal open path for non-regular files
v9fs_vfs_atomic_open() and v9fs_vfs_atomic_open_dotl() call
finish_open(file, dentry, generic_file_open) regardless of the file
type the server reported for the created dentry.  The supplied
callback replaces f_op->open in do_dentry_open(), so blkdev_open()
never runs for a server-reported device node: an open() with O_CREAT
succeeds with f_op = def_blk_fops while f_mapping still points at the
9p inode, because the bdev mapping swap only happens inside
blkdev_open().  The block file methods then derive their block_device
from that inode with I_BDEV(); the loads land at the tail of a
656-byte v9fs_inode_cache object (offsets +624 and +632), which KASAN
reports as slab-out-of-bounds, and the garbage they read is then
dereferenced, so the first read(), write(), ioctl() or close() ends
in a NULL pointer write and a panic.  In the ioctl(BLKGETSIZE64)
variant the value read this way is returned to userspace.

The server controls the file type reported for the create, so a
malicious server can crash the client this way.  KASAN report of the
read() variant, on a build of linux-stable 2709dd5ae32f:

BUG: KASAN: slab-out-of-bounds in blkdev_read_iter+0x3cd/0x440
Read of size 8 at addr ffff88800828ceb0 by task repro/1

Call Trace:
 <TASK>
 dump_stack_lvl+0x7b/0xa0
 print_report+0xd0/0x630
 kasan_report+0xe5/0x120
 blkdev_read_iter+0x3cd/0x440
 vfs_read+0x718/0xa50
 ksys_read+0x10f/0x200
 do_syscall_64+0xdd/0x4a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
 </TASK>

The buggy address belongs to the object at ffff88800828cc40
 which belongs to the cache v9fs_inode_cache of size 656
The buggy address is located 624 bytes inside of
 allocated 656-byte region [ffff88800828cc40, ffff88800828ced0)

A plain open() without O_CREAT is not affected: it runs blkdev_open()
and either maps the device correctly or fails with -ENXIO for an rdev
with no registered device.  When the created inode is not a regular
file, clunk the fid the create opened.  The unopened fid is already
on the dentry.  Set FMODE_CREATED and return finish_no_open(file, NULL)
so the VFS keeps its dentry reference and calls the inode's ->open.
Regular files still use finish_open() with generic_file_open.

Fixes: be12af3ef5 ("getting rid of 'opened' argument of ->atomic_open() - part 1")
Signed-off-by: Yuanfu Xie <yuanfuxie@stu.pku.edu.cn>
Message-ID: <908FC420-EC1F-46FC-8526-698F646961A8@stu.pku.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:11 +00:00
Yuanfu Xie
4e915aa856 9p: don't decrement a server-owned zero nlink
A 9P2000.L server can report nlink=0 for a regular file that still
exists.  On a cache=loose or cache=fscache mount, lookup stores that
value with set_nlink().  A later successful unlink calls
v9fs_dec_count(), which still calls drop_nlink() for a non-directory.
drop_nlink() warns, and the unsigned link count wraps to 4294967295.
fstat() on a descriptor opened before the unlink shows 0 before and
4294967295 after.

The warning on the unpatched kernel, trimmed:

WARNING: fs/inode.c:408 at drop_nlink+0xac/0xd0, CPU#1: trigger/188
CPU: 1 UID: 0 PID: 188 Comm: trigger Tainted: G                 N  7.3.0-rc4-00537-ga3ff15db6820 #1 PREEMPT(lazy)
RIP: 0010:drop_nlink+0xac/0xd0
Call Trace:
 <TASK>
 v9fs_remove+0x529/0x750
 vfs_unlink+0x2f0/0xbd0
 filename_unlinkat+0x340/0x6c0
 __x64_sys_unlink+0x46/0x70
 do_syscall_64+0xe8/0x4f0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
 </TASK>
---[ end trace 0000000000000000 ]---

Directories whose cached nlink is at most 2 already skip this
decrement, because the exported filesystem may not maintain nlink
(commit ac89b2ef9b).  cache=none skips it as well (commit
574aa0b479).  cache=mmap does not take this path: it sets neither
CACHE_META nor CACHE_LOOSE.  A regular file on cache=loose or
cache=fscache still does.  Its count came from GETATTR and may
already be zero, so skip the decrement when i_nlink is already 0.

Verified on 7.3-rc4-00537-ga3ff15db6820 with only this change.  A
server that advertises nlink=0 and accepts the unlink no longer
warns, and the open descriptor stays at nlink 0.  An honest server
on the same mount still goes from 1 to 0.  A rejected unlink leaves
the count unchanged.  cache=none is unchanged.  With panic_on_warn
the unpatched kernel panics on the warning; the patched kernel does
not.

Fixes: ac89b2ef9b ("9p: don't maintain dir i_nlink if the exported fs doesn't either")
Cc: stable@vger.kernel.org
Signed-off-by: Yuanfu Xie <yuanfuxie@stu.pku.edu.cn>
Message-ID: <8B490036-EBB0-4A36-AE39-F294F7C79649@stu.pku.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:11 +00:00
Omokefe Emmanuel Onanaroghene
d037e9c1b4 9p: fix kernel-doc warning for enum p9_session_flags
kernel-doc cannot parse enum p9_session_flags, since its documentation
comment is followed by #define lines instead of the enum declaration:

  fs/9p/v9fs.h:31 : error: Cannot parse enum!

Move the three #define lines below the enum whose values they are
derived from, and give V9FS_ACCESS_ANY and V9FS_ACCESS_MASK their own
kernel-doc comments with the descriptions they had in the enum comment.

Also document the four enum members that had no description, using the
corresponding mount option wording from
Documentation/filesystems/9p.rst.

Fixes: 76381a42e4 ("fs/9p: Add access = client option to opt in acl evaluation.")
Assisted-by: LLM
Signed-off-by: Omokefe Emmanuel Onanaroghene <emmaonana18@gmail.com>
Message-ID: <20261002035837.39703-1-emmaonana18@gmail.com>
[Dominique: slight reword, also fixed typo in Doc/ for access=client]
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:10 +00:00
Barret Rhoden
a3a6212c7d 9p: treat read return values of 0 as EOF
If your 9p server shares a synthetic file system such as sysfs, the file
size from stat often disagrees with the actual file size.

Treat non-error reads of 0 as EOF, except in the case where the request
was for 0 bytes.

Tested:
	git@github.com:hugelgupf/p9.git, served "/" on 10.0.2.2

	bash-5.3# mount -t 9p -o trans=tcp,port=12345,cache=none 10.0.2.2 /tmp/foo
	bash-5.3# cat /tmp/foo/sys/devices/system/cpu/online
	0-47

Fixes: eb497943fa ("9p: Convert to using the netfs helper lib to do reads and caching")
Signed-off-by: Barret Rhoden <brho@google.com>
Message-ID: <20260702090941.1298188-1-brho@google.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:10 +00:00
Yehyeong Lee
9b4cf60c6b 9p/xen: validate the response size from the backend
p9_xen_response() takes the length of an incoming response from the ring
-- the first field of the 9p header, which the Xen transport reuses as
its framing header -- and uses it to advance the consumer index, but
never checks that it is at least the header size or no larger than the
number of bytes the backend has actually produced.

A malicious or buggy backend can post a response whose size is smaller
than the header (for example 0). The consumer index then never advances,
so the response work re-reads the same ring contents instead of making
progress. In testing this raced with the teardown that the malformed
reply triggers and dereferenced a freed p9_client:

  9pfs 9pfs-0: Wrong req tag=ffff
  BUG: kernel NULL pointer dereference, address: 0000000000000060
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  PGD 0 P4D 0
  Oops: Oops: 0000 [#1] SMP NOPTI
  CPU: 0 UID: 0 PID: 11 Comm: kworker/0:1 Not tainted 7.2.0-rc5 #6 PREEMPT(lazy)
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
  Workqueue: events p9_xen_response
  RIP: 0010:idr_find+0x4/0x10
  RSP: 0018:ffffbf5d80063de8 EFLAGS: 00010202
  RAX: 0000000000000001 RBX: ffffa229c21195a0 RCX: ffffa229c2400000
  RDX: ffffa229c11c2200 RSI: 000000000000ffff RDI: 0000000000000050
  RBP: 000000000000ffff R08: 3fffffffffffdfff R09: ffffffffffffffff
  R10: 3fffffffffffdfff R11: ffffffff87a60e80 R12: 0000000000000050
  R13: 0000000000000000 R14: 000000000000ffff R15: 0000000000100000
  FS:  0000000000000000(0000) GS:ffffa22a7661c000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 0000000000000060 CR3: 000000003ac34002 CR4: 0000000000770ef0
  PKRU: 55555554
  Call Trace:
   <TASK>
   p9_tag_lookup+0x2b/0x90
   p9_xen_response+0x17c/0x2e0
   process_one_work+0x16a/0x3a0
   worker_thread+0x172/0x2e0
   kthread+0xdd/0x110
   ret_from_fork+0x18b/0x240
   ret_from_fork_asm+0x1a/0x30
   </TASK>
  Modules linked in:
  CR2: 0000000000000060
  ---[ end trace 0000000000000000 ]---

Reject a response whose size is outside [sizeof(header), queued] before
using it, matching the validation the backend already applies to
incoming requests.

Fixes: f66c72bea1 ("xen/9pfs: receive responses")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Reviewed-by: Juergen Gross <jgross@suse.com>
Message-ID: <20261005125640.274054-1-yhlee@isslab.korea.ac.kr>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:09 +00:00
Ankit Thakur
8a152d6a38 9p: fix typo in file header comments
Fix the spelling mistake contians -> contains in the header comments
of vfs_addr.c, vfs_dentry.c and vfs_file.c.

Signed-off-by: Ankit Thakur <codeankit.thakur@gmail.com>
Message-ID: <20261024092154.1844-4-codeankit.thakur@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:09 +00:00
Ankit Thakur
9eb9b583ea 9p: remove duplicated assignment in v9fs_fill_super()
The declaration of v9ses assigns it twice (v9ses = v9ses =
sb->s_fs_info). Drop the redundant assignment. No functional change.

Signed-off-by: Ankit Thakur <codeankit.thakur@gmail.com>
Message-ID: <20261024092154.1844-3-codeankit.thakur@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:09 +00:00
Ankit Thakur
6b18056882 9p: fix typos and wrong parameter docs in vfs_inode.c
Fix spelling mistakes in comments (functon -> function, Hadlink ->
Hardlink).

Also fix the kernel-doc of v9fs_vfs_mkdir(), which described @dir and
@dentry as being unlinked instead of being the parent directory and the
directory being created.

Signed-off-by: Ankit Thakur <codeankit.thakur@gmail.com>
Message-ID: <20261024092154.1844-2-codeankit.thakur@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:09 +00:00
Ankit Thakur
ec8cd74fcf 9p: fix header guard comment in acl.h
The closing comment of the include guard says FS_9P_XATTR_H, but the
guard macro is FS_9P_ACL_H. Fix the comment to match.

Signed-off-by: Ankit Thakur <codeankit.thakur@gmail.com>
Message-ID: <20261024092154.1844-1-codeankit.thakur@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-10-29 06:01:08 +00:00
Fourie Zhang
5def91015b xfrm4: use a full socket for local errors
xfrm4_local_error() passes skb->sk to inet_sk() and ip_local_error()
without ensuring it points to a full socket. TCP SYN-ACK skbs can be owned
by TCP_NEW_SYN_RECV request sockets.

xfrm4_tunnel_check_size() already checks sk_fullsock() since commit
1620c88887 ("xfrm: Fix the usage of skb->sk"), so iptfs_is_too_big() is
the only remaining IPv4 caller passing a request socket here: the sk it
tests is the listener, while skb->sk is the request socket.

When IP-TFS rejects such an skb because it exceeds its payload MTU, the
local error path treats the request socket as a struct inet_sock. KASAN
reports a slab-out-of-bounds read in ip_local_error() beyond the
request_sock_TCP allocation.

Resolve the skb owner with skb_to_full_sk() before accessing inet_sock
state or reporting the error. This maps a request socket to its listener
and rejects sockets that cannot be used as full sockets, matching what
commit 6973a21ee7 ("ipv6: xfrm: use full sockets in local error paths")
did for xfrm6_local_error().

Fixes: 0e4fbf013f ("xfrm: iptfs: add user packet (tunnel ingress) handling")
Cc: stable@vger.kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Link: https://lore.kernel.org/netdev/20260908224856.1591189-1-kuba@kernel.org/
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Assisted-by: tencentos-corvus-ai:hy4-preview
Signed-off-by: Fourie Zhang <fouriezhang@tencent.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-27 09:09:36 +00:00
Avi Weiss
1dcf2be94b fsnotify: preserve 64-bit pre-content ranges
vfs_fallocate() and remap_verify_area() pass 64-bit lengths to
fsnotify_file_area_perm(), which truncates them to size_t on
32-bit systems.

Use 64 bit (unsigned) types throughout the entire pre-content
notification chain to keep the full range. The userspace range
field is already 64-bits.

Fixes: 9740d17162 ("fsnotify: pass optional file access range in pre-content event")
Signed-off-by: Avi Weiss <thnkslprpt@gmail.com>
Link: https://patch.msgid.link/20261015175701.3674449-1-thnkslprpt@gmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:21:01 +01:00
Pedro Falcato
5406ffab82 ext2: take invalidate_lock in ext2_write_failed()
Currently, ext2_write_failed() takes care of removing extra data
(folios & blocks) from the page cache by first truncating the page cache,
then truncating the actual inode's blocks.

Understanding that this is correct - namely, that a concurrent page cache
lookup can't create stale pages and stale block mappings between
truncate_pagecache() and ext2_truncate_blocks() - is non trivial. This is
correct for two non-obvious reasons:

1) every caller of ext2_write_failed() holds some sort of exclusion
against truncation. In most cases, callers hold (in some way) the inode
lock. ext2_write_failed() is only reachable from buffered/direct IO write
paths, which hold it. page_symlink() can also call write_begin _without
the inode lock_, but at that point the inode is I_NEW, so there are no other
users.

2) the page cache is generally extremely careful at never instantiating
pages beyond EOF.

This is all quite confusing. Holding the invalidate lock across both
operations is largely simpler, and mirrors other bits of other filesystems
(like ext4_truncate_failed_write). Do that.

This has the side effect of making it so ext2_evict_inode() doesn't take
the invalidate_lock when truncating blocks on inode deletion. This is safe
as the inode should not have any users at that point.

Signed-off-by: Pedro Falcato <pfalcato@suse.de>
Link: https://patch.msgid.link/20261024222726.889520-1-pfalcato@suse.de
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:19:22 +01:00
Nathan Chancellor
afb28ca1f1 ext2: Make sbi an proper alias for EXT2_SB(sb) in ext2_fill_super()
A recent LLVM change to fix parsing and validating __guarded_by on
structure members [1] reveals a couple of warnings in ext2_fill_super()
from the annotations added by commit 023051c2d0 ("ext2: mark
s_mount_state as guarded by s_lock") and commit c23746524f ("ext2:
annotate s_rsv_window_root as requiring s_rsv_window_lock"):

  fs/ext2/super.c:1040:7: error: writing variable 's_mount_state' requires holding spinlock '_res->s_lock' exclusively [-Werror,-Wthread-safety-precise]
   1040 |         sbi->s_mount_state = le16_to_cpu(es->s_state);
        |              ^
  fs/ext2/super.c:1040:7: note: found near match 'EXT2_SB(sb).s_lock'
  fs/ext2/super.c:1138:8: error: writing variable 's_rsv_window_root' requires holding spinlock '_res->s_rsv_window_lock' exclusively [-Werror,-Wthread-safety-precise]
   1138 |                 sbi->s_rsv_window_root = RB_ROOT;
        |                      ^
  fs/ext2/super.c:1138:8: note: found near match 'EXT2_SB(sb).s_rsv_window_lock'

Context analysis does very minimal alias detection [2], so it is not
able to figure out that sbi == sb->s_fs_info == EXT2_SB(sb). The only
reason there were no warnings before the above LLVM change is because
the annotation was not parsed and verified correctly.

Rework the allocation and assignment of sbi to have a direct assignment
of EXT2_SB(sb) to sbi so that the analysis knows that sbi and
EXT2_SB(sb) refer to the same object, clearing up the warnings.

Fixes: 9708538ba2 ("ext2: enable context analysis support for ext2 filesystem")
Link: 217e229a1f [1]
Link: https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis [2]
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Reviewed-by: Marco Elver <elver@google.com>
Link: https://patch.msgid.link/20261023-ext2-fix-context-analysis-clang-24-v2-1-a33961453899@kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:19:22 +01:00
Jan Kara
0415c2624f udf: Validate extended attribute space is large enough
When there is extended attributes space in ICB, there must be at least
enough space for the header of this space. Otherwise the fs is corrupted
and other offset validity checks could underflow.

Reported-by: Lennart Finke <lfinke@student.ethz.ch>
Fixes: 127b0d8764 ("udf: Avoid confusion of missing and corrupted extended attributes")
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:19:22 +01:00
YouYou Yu
e21a6f39aa quota: initialize dquot cache before mounting rootfs
On some systems, a tmpfs backed rootfs is extensively used throughout
system's lifecycle. tmpfs quotas are needed to limit per user rootfs
usage. However, booting with CONFIG_TMPFS_QUOTA=y, an initramfs, no root=
and "initramfs_options=usrquota" panics at boot:

  BUG: kernel NULL pointer dereference, address: 0000000000000000
  RIP: 0010:dqget+0x1ac/0x490
  Call Trace:
   __dquot_initialize
   dquot_initialize
   shmem_get_inode
   shmem_fill_super
   ...
   mnt_init
   vfs_caches_init
   start_kernel

The rootfs is mounted from mnt_init(), but the dquot hash table and
cache are only set up later by dquot_init(), an fs_initcall. Creating
the root inode of a quota enabled rootfs thus dereferences the NULL
dquot_hash in dqget().

Rename dquot_init() to dquot_cache_init() and call it from
vfs_caches_init() before mnt_init(). The slab, percpu and early
workqueue code it relies on is available there, and the workqueue
rescuer and shrinker debugfs entries are set up later by their own
subsystems. Keep the sysctl registration in an fs_initcall, as done
for the dcache, inode and mount sysctls. This only moves existing
allocations earlier in boot.

Fixes: 278033a225 ("fs: Add 'initramfs_options' to set initramfs mount options")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Co-developed-by: Dylan Johnson <dgj@amazon.com>
Signed-off-by: Dylan Johnson <dgj@amazon.com>
Signed-off-by: YouYou Yu <youyouyu@amazon.com>
Reviewed-by: Gunnar Kudrjavets <gunnarku@amazon.com>
Link: https://patch.msgid.link/20261021181217.20171-1-youyouyu@amazon.com
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:19:20 +01:00
Hui Peng
49f771d145 udf: validate vat20->lengthHeader and VAT inode size in udf_load_vat()
In udf_load_vat() (fs/udf/super.c), validate that vat20->lengthHeader is
at least sizeof(struct virtualAllocationTable20) and does not exceed the
mapped buffer or VAT inode size so computing the VAT table pointer and
entry count cannot underflow or read out of bounds.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Link: https://patch.msgid.link/20260919222600.3793513-1-benquike@gmail.com
Signed-off-by: Hui Peng <benquike@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
2026-10-26 14:18:57 +01:00
Toke Høiland-Jørgensen
25e73f1d68 wifi: mac80211: reinstate IEEE80211_TX_CTL_AMPDU flag in ieee80211_tx_prep_agg()
The commit 592234e941 ("wifi: mac80211: Fix iTXQ AMPDU fragmentation
handling") changed the way handling of the IEEE80211_TX_CTL_AMPDU flag
is done in mac80211, so the only place it is set is in
ieee80211_tx_dequeue().

This means that any frames that are sent to the driver via drv_tx() will
no longer have the flag set. In particular, this affects packets going
through ieee80211_tx_pending(). Evan reported that this can result in
the ath9k driver failing to account such packets in its block ack
window, eventually overrunning the window and stalling TX.

Fix this by reinstating the flag in ieee80211_tx_prep_agg() when inside
a valid block ack window. This should be harmless for the TXQ path, and
will reinstate the previous behaviour for drivers that use the flag as a
signal to track the packet in the window.

Fixes: 592234e941 ("wifi: mac80211: Fix iTXQ AMPDU fragmentation handling")
Cc: stable@vger.kernel.org
Reported-by: Evan Severson <eseverson@gmail.com>
Link: https://lore.kernel.org/all/20261014025734.2288693-1-eseverson@gmail.com/
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Tested-by: Evan Severson <eseverson@gmail.com>
Link: https://patch.msgid.link/20261023110052.650519-1-toke@toke.dk
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-26 12:20:45 +01:00
Eric Biggers
dd2a4edb26 lib/crypto: mips: Disable Octeon SHA code on little-endian kernels
Kernels built for the MIPS64-based Cavium Octeon SoCs are normally
big-endian, but little-endian builds are also supported.  Currently, the
SHA-1, SHA-256, and SHA-512 code using the Octeon crypto co-processor is
enabled in both builds.

This code is untestable without the hardware.  However, based on the
code itself, it is implausible that it computes hash values correctly in
little-endian builds.  Such builds write many incorrect values to COP2:

  - SHA-1 and SHA-256: The 64-bit integer that contains the last two
    32-bit message words of each block is written to COP2 entirely
    byte-reflected, due to missing endianness conversion in
    octeon_sha1_start() and octeon_sha256_start() to compensate for
    using native 64-bit loads from the message bytes.  This differs from
    all the earlier message words which are written correctly.

    Furthermore, the state is written to COP2 with each 32-bit word
    byte-reflected within each 64-bit integer, due to incorrect use of
    64-bit endianness conversion in write_octeon_64bit_hash_dword() when
    the state is kept in memory in native-endian 32-bit words.

  - SHA-512: All the 64-bit message words are written to COP2
    byte-reflected, due to missing endianness conversion in
    write_octeon_64bit_block_sha512() and octeon_sha512_start().  The
    SHA-512 state words seem to be written correctly.

Big-endian kernels aren't affected by these bugs.  These bugs also
aren't new; this code has been broken on little-endian ever since it and
Octeon little-endian support were first added in v4.1.

Commit d2a948d2db ("MIPS: Octeon: Make octeon-md5 driver
endian-agnostic") made the MD5 code work on little-endian kernels by
adding 64-bit endianness conversions to the COP2 macros used by MD5
(some of which are shared by SHA-1 and SHA-256, despite those algorithms
keeping the state words in native-endian instead of MD5's little-endian,
causing some of the strange behavior described above).  However, SHA-1,
SHA-256, and SHA-512 were never fixed to work on little-endian kernels.

Therefore, disable the Octeon SHA-1, SHA-256, and SHA-512 code in
little-endian kernels.  This causes the generic code that actually
computes hash values correctly to be used instead.

Fixes: 82be2dcfa6 ("crypto: octeon - add SHA1 module")
Fixes: c3d0def620 ("crypto: octeon - add SHA256 module")
Fixes: fbaa4dfd51 ("crypto: octeon - add SHA512 module")
Cc: stable@vger.kernel.org
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20261022054450.20746-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-10-24 13:19:57 -07:00
Zijing Yin
9d8ec0b5b5 wifi: cfg80211: fix out-of-bounds read in valid_rule()
valid_rule() validates a struct fwdb_rule from the regulatory database
firmware file, but bounds checks only the first byte of the structure,
the length field itself.

It then uses that length, which comes straight out of the file, to
decide whether the optional fields are present, and reads rule->wmm_ptr
at offset 18 of the 20-byte structure once the length claims 20 bytes or
more.

A rule placed in the last bytes of the file therefore makes the parser
read up to 19 bytes past the end of the firmware image. The image comes
from vmalloc() in kernel_read_file(), so with the rule at the end of a
page the read falls into the guard page and oopses, with no memory
debugging enabled.

A length of at least offsetofend(max_bw) but below offsetofend(wmm_ptr)
takes the other branch, so valid_rule() returns true having read nothing
out of bounds, and the database is accepted. regdb_query_country() does
not re-check the rule, and reads rule->start, rule->end, rule->max_bw
and rule->cac_timeout off the end of the kmemdup()ed copy.

A malformed regulatory.db is parsed by cfg80211's own
request_firmware_nowait() at init time, and on demand from user space
through NL80211_CMD_RELOAD_REGDB, which needs CAP_NET_ADMIN but no
wireless hardware. Both paths require write access to the firmware
search path and CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=n.

Bound the whole declared rule, not just its length field. The existing
check on sizeof(rule->len) is still needed, since rule->len has to be
shown to be inside the file before it can be read, so the new test goes
after it. A rule reaching past the end of the file is now rejected,
which fails the database rather than reading out of bounds. That also
gives regdb_query_country() the bound it already assumes.

Fixes: 230ebaa189 ("cfg80211: read wmm rules from regulatory database")
Cc: stable@vger.kernel.org
Signed-off-by: Zijing Yin <yzjaurora@gmail.com>
Link: https://patch.msgid.link/20261015133159.1499728-1-yzjaurora@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-22 12:04:31 +02:00
Alex Kazinsky
71f756a4c0 wifi: rsi: Skip TX aggregation setup for non-QoS frames
When transmitting a non-QoS unicast frame to a station in AP mode,
rsi_core_xmit() assigns IEEE80211_NONQOS_TID (16) to tid. The station
lookup succeeds, allowing tid to index start_tx_aggr[], which has only
IEEE80211_NUM_TIDS (16) elements. This causes an out-of-bounds read and,
if the value read is zero, an out-of-bounds write.

Only access the aggregation state for tids below IEEE80211_NUM_TIDS,
excluding the non-QoS sentinel from TX aggregation setup.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 19844c0a9a ("rsi: data and managemet path changes for AP mode")
Cc: stable@vger.kernel.org
Signed-off-by: Alex Kazinsky <a.kazinsky@ideco.ru>
Link: https://patch.msgid.link/20261015072010.742369-1-a.kazinsky@ideco.ru
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-22 12:04:02 +02:00
Cosmin Ratiu
48c0045366 wifi: wext: Limit notifier event flushes to the device's netns
With mlx5 netdev instance locking enabled, registering an IPoIB netdev
calls the WEXT notifier while holding the instance mutex. Its call to
wireless_nlevent_flush() takes net_rwsem to walk every namespace,
completing the following lockdep dependency cycle:

  netdev instance mutex -> net_rwsem (read) -> GID table mutex
    -> event_handler_rwsem (read) -> netdev instance mutex

RoCE GID enumeration takes the GID table mutex under net_rwsem. GID
updates dispatch events under the table mutex, taking event_handler_rwsem.
The IPoIB event handler takes the netdev instance mutex in
ipoib_queue_work() to traverse child interfaces.

The all-namespace walk originated in the single global worker servicing
per-namespace WEXT queues. The ordering fixes later reused that routine
in netdevice notifiers to prevent delayed WEXT RTM_NEWLINK messages from
following RTM_DELLINK or reporting stale interface flags. A notifier only
needs to drain the affected device's namespace; there is no reason for it
to walk and flush all namespaces.

Pass dev_net(dev) from both notifier callers and make the flush helper
operate on that namespace. Keep the all-namespace walk and net_rwsem in
the existing worker. This removes the instance-mutex -> net_rwsem
dependency while retaining synchronous flushing from the notifiers.

It may seem strange that the fix for a lock cycle across multiple
subsystems lies in a completely unrelated part of the code, but this
seemed the most justified lock cycle edge to break.

Fixes: 8f7b00307b ("net/mlx5e: Convert mlx5 netdevs to instance locking")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Link: https://patch.msgid.link/20261021144111.611840-1-cratiu@nvidia.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-22 12:00:05 +02:00
Jason Perlow
7ed5dce55f wifi: brcmfmac: map msgbuf RX packet IDs bidirectional
Commit f0ba5fd51f ("wifi: brcmfmac: Set DMA direction for msgbuf
packet IDs") maps the RX packet ID buffers DMA_FROM_DEVICE. The
BCM4364 firmware also reads posted RX buffers, so with VT-d
translation enabled every such read faults ("PTE Read access is not
set") and the firmware crashes and resets in a loop.

Map the RX pool DMA_BIDIRECTIONAL again, as before that commit. TX
keeps DMA_TO_DEVICE.

Fixes: f0ba5fd51f ("wifi: brcmfmac: Set DMA direction for msgbuf packet IDs")
Cc: stable@vger.kernel.org
Signed-off-by: Jason Perlow <jperlow@gmail.com>
Signed-off-by: Aditya Garg <aditya.garg@linux.dev>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Link: https://patch.msgid.link/20261021172238.10004-1-aditya.garg@linux.dev
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-22 11:59:42 +02:00
Weigang He
35c5a5ea44 wifi: mac80211: reload TDLS header pointer after skb_linearize()
ieee80211_process_tdls_channel_switch() sets tf = skb->data before it
calls skb_linearize(), and reads tf->action_code afterwards.

ieee80211_rx_h_data() queues TDLS channel switch requests and
responses to the interface after pulling only
offsetof(struct ieee80211_tdls_data, u) bytes, so the skb can still be
non-linear when the interface work handles it. Drivers that build
paged RX skbs do this for every frame that does not fit into the skb
head, e.g. iwlwifi (mvm), which is also the only mac80211 driver
that sets NL80211_FEATURE_TDLS_CHANNEL_SWITCH. If the remaining data
does not fit into the tailroom, skb_linearize() moves the data to a
new head and frees the old one, and the action code is then read from
freed memory. Depending on what that memory holds by then, the frame
is handled as before or ends in the WARN_ON_ONCE() of the default
case.

The frame only has to be a data frame with the TDLS ethertype from an
authorized peer, e.g. relayed by the AP from another station in the
BSS; the read happens before the sender is checked to be a TDLS peer.

Load tf after skb_linearize(), as the request and response handlers
already do.

Found by static analysis tool CodeQL.

Fixes: 8a4d32f30d ("mac80211: add TDLS channel-switch Rx flow")
Cc: stable@vger.kernel.org
Assisted-by: LLM codeql
Signed-off-by: Weigang He <geoffreyhe2@gmail.com>
Link: https://patch.msgid.link/20261021145807.3018338-1-geoffreyhe2@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2026-10-22 11:59:31 +02:00
Steffen Klassert
835912998c Merge branch 'xfrm: state: exact mark/mask match for control-plane SA lookups'
Antony Antony says:

====================
While looking into a XFRM_MSG_MIGRATE_STATE issue reported by Sashiko,
we found the underlying problem generalizes: xfrm allows multiple SAs
to coexist for the same (SPI, daddr, proto) differing only in mark,
and every netlink method that resolves "which SA" - xfrm get_sa(),
del_sa(), update, get_ae, new_ae, expire, migrate - uses the same
wildcard mark match the data path needs. A broader-mask SA can
silently shadow a more specific one:

  # ip xfrm state add ... spi 0x1000 mark 1 mask 1 (SA_target)
  # ip xfrm state add ... spi 0x1000 mark 0 mask 0
    (SA_decoy, catch-all, added after -> bucket head)
  # ip xfrm state delete dst ... proto esp spi 0x1000 mark 1 mask 1
    -> deletes SA_decoy; SA_target survives, untouched

xfrm policy had the same bug, fixed in commit 4f47e8ab6a
("xfrm: policy: match with both mark and mask on user interfaces").

Netlink state lookups using spi use an exact mark/mask match except
for UPDSA; the wildcard match stays for the data path and state_add only.
This series applies that fix across every affected method,
not just XFRM_MSG_MIGRATE_STATE.

Also reject marks with value bits outside the mask (state ADD,
ALLOCSPI, policy ADD, MIGRATE_STATE new mark). These are
misconfigurations anyway, since the extra bits can never match, and
break exact match added here.

This series does not touch PF_KEY, which no longer receives
non-critical fixes.

state_lookup_byaddr is out of scope. This is only fixing spi based
lookups.
====================

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-20 07:41:14 +02:00
Antony Antony
dcf413245c docs: xfrm: include mark in XFRM_MSG_MIGRATE_STATE EEXIST tuple
Document mark as part of the EEXIST tuple and update the SA lookup
description to match.

Fixes: c13c0cc6f5 ("xfrm: add documentation for XFRM_MSG_MIGRATE_STATE")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:09 +02:00
Antony Antony
24bc5e5499 xfrm: pass extack through to xfrm_init_replay() from xfrm_init_state()
xfrm_init_state() takes an extack parameter but doesn't pass it to
xfrm_init_replay(), so replay-window errors can't be reported via
extack.

Fixes: 231a1744dc ("xfrm: add extack to xfrm_init_state")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:08 +02:00
Antony Antony
a46232c697 xfrm: include mark in MIGRATE_STATE SA collision check
The SA lookup tuple is (daddr, spi, proto, family, mark), but the
EEXIST pre-check and the xfrm_state_insert() vs xfrm_state_add()
decision only considered daddr and family, ignoring mark.
A migration that only changes the mark inserts a duplicate SA tuple
into the hash tables.

The collision check is implemented as xfrm_state_mark_collides(),
which walks the SPI hash bucket for the target tuple and excludes the
state being migrated by pointer, rather than doing a separate
exact-match lookup followed by a wildcard lookup and comparing the
result against self.

Before:
root@west:~# ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \
        spi 0x1000  reqid 100 mode tunnel aead "rfc4106(gcm(aes))" \
        0x1111111111111111111111111111111111111111 96 \
        mark 0x1 mask 0xff

root@west:~# ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \
        spi 0x1000  reqid 100 mode tunnel aead "rfc4106(gcm(aes))" \
        0x1111111111111111111111111111111111111111 96 \
        mark 0x2 mask 0xff
root@west:~# ip xfrm state migrate dst 10.1.1.2 proto esp spi 0x1000 \
        mark 0x1 mask 0xff \
        new-dst 10.1.1.2 new-src 10.1.1.1 new-reqid 100 \
        new-mark 0x2 mask 0xff
ip x s
src 10.1.1.1 dst 10.1.1.2
    proto esp spi 0x00001000 reqid 100 mode tunnel
    replay-window 0
    mark 0x2/0xff
    aead rfc4106(gcm(aes)) 0x1111111111111111111111111111111111111111 96
    anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
src 10.1.1.1 dst 10.1.1.2
    proto esp spi 0x00001000 reqid 100 mode tunnel
    replay-window 0
    mark 0x2/0xff
    aead rfc4106(gcm(aes)) 0x1111111111111111111111111111111111111111 96
    anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
    sel src 0.0.0.0/0 dst 0.0.0.0/0

Notice two states with same mark 0x2/0xff.
After:

Error: New SA tuple already occupied.

Fixes: a9d155ea9b ("xfrm: add XFRM_MSG_MIGRATE_STATE for single SA migration")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:07 +02:00
Antony Antony
da94223774 xfrm: fix hw offload state leak on xfrm_do_migrate_state() error path
In the error path, the cloned state is dropped without removing its
hardware offload, leaking the offloaded SA entry.

Fixes: a9d155ea9b ("xfrm: add XFRM_MSG_MIGRATE_STATE for single SA migration")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:06 +02:00
Antony Antony
3eb841b771 xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()
A concurrent delete can free the migrated state before
xfrm_do_migrate_state() finishes using it.

Fixes: a9d155ea9b ("xfrm: add XFRM_MSG_MIGRATE_STATE for single SA migration")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:05 +02:00
Antony Antony
6362f459bf xfrm: state: exact mark/mask match for SPI-keyed control-plane SA lookups
Add __xfrm_state_lookup_exact(); wire it into DELSA/GETSA, GETAE/NEWAE,
EXPIRE, MIGRATE_STATE.  xfrm_state_update() (UPDSA) keeps wildcard match
because ALLOCSPI's larval state may be unmarked (mark 0/0), so an
exact-match UPDSA would not find it and the ADD fallback would then
fail with -EEXIST via xfrm_state_add().

Fixes: 3d6acfa764 ("xfrm: SA lookups with mark")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:05 +02:00
Antony Antony
b3056e57b0 xfrm: policy: reject mark with bits outside its mask on add
Same issue as states: an invalid mark/mask is silently truncated on
insert, so GETPOLICY and DELPOLICY can no longer find the policy by
id. Reject it instead.

The mark is no longer sanitized on policy insert.

Fixes: 0b91fda3a1 ("xfrm: Sanitize marks before insert")
Cc: <stable+noautosel@kernel.org> # avoid breaking existing userspace ABI
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:03 +02:00
Antony Antony
07d7b25224 xfrm: state: reject mark with bits outside its mask on ALLOCSPI
Like state add and policy add in this series, ALLOCSPI rejects a mark
whose value has bits outside its mask.

Fixes: bd55775c8d ("xfrm: SA lookups signature with mark")
Cc: <stable+noautosel@kernel.org> # avoid breaking existing userspace ABI
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:02 +02:00
Antony Antony
c8c2c8a2bb xfrm: state: reject mark with bits outside its mask on add
A mark/mask like 0x101/0xff is silently truncated to 0x01/0xff on
insert, so the exact-match lookups added later in this series (DELSA,
GETSA, GETAE, NEWAE, EXPIRE, MIGRATE_STATE) could not find the SA.
Reject it instead.

The mark is no longer sanitized on state add.

Also reject an invalid XFRMA_MARK (the new mark) in
XFRM_MSG_MIGRATE_STATE.

Fixes: 0b91fda3a1 ("xfrm: Sanitize marks before insert")
Cc: <stable+noautosel@kernel.org> # needs exact-match SA lookups from this series
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-19 08:02:02 +02:00
Deepanshu Kartikey
dfa953ba53
batman-adv: avoid WARN_ON for orig_ifinfo allocation failure
batadv_orig_ifinfo_new() returns NULL only when its GFP_ATOMIC
allocation fails, which is a normal runtime condition and not a bug.
batadv_v_ogm_forward() already handles this the same way, simply
checking for NULL without a WARN_ON.

Do the same in batadv_iv_ogm_update_seqnos() to avoid a spurious
WARN_ON splat when the allocation fails (e.g. under fault injection).

Fixes: 7351a4822d ("batman-adv: split out router from orig_node")
Reported-by: syzbot+a079f084653164a652d1@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a079f084653164a652d1
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-10-13 15:52:44 +02:00
Sabrina Dubroca
f9a11716c8 xfrm: espintcp: reorder operations within espintcp_init_sk
When enabled on a socket, espintcp sets the socket callbacks to its
own before it has finished setting up its context and published it as
icsk_ulp_data. Any one of those callbacks that gets called before will
dereference a NULL icsk_ulp_data.

Fix this by reording the operations, and add memory barriers to ensure
callers will have a struct espintcp_ctx available. Add a few
WRITE_ONCE/READ_ONCE too while we're there.

Fixes: e27cca96cd ("xfrm: add espintcp (RFC 8229)")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Reported-by: Peihan Liu <ronbogo@outlook.com>
Reported-by: Yilin Zhu <zylzyl2333@gmail.com>
Reported-by: Ren Wei <n05ec@lzu.edu.cn>
Reported-by: Eulgyu Kim <eulgyukim@snu.ac.kr>
Reported-by: Jaeyoung Chung <jjy600901@snu.ac.kr>
Link: https://lore.kernel.org/all/c30b645074a1b379e0f7fe297f917c66137d9964.1778464688.git.zylzyl2333@gmail.com/
Link: https://lore.kernel.org/all/20260819155349.3555804-1-jjy600901@snu.ac.kr
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-12 10:40:32 +02:00
Shubham Antil
e35a12dffd xfrm: zero-initialise km_event in the replay-notify path
xfrm_replay_notify(), xfrm_replay_notify_bmp() and
xfrm_replay_notify_esn() declare a struct km_event on the stack and
initialise only its .event and .data.aevent fields, leaving .seq and
.portid uninitialised. build_aevent() then builds the XFRM_MSG_NEWAE
message with those fields:

  nlmsg_put(skb, c->portid, c->seq, ...)

so the netlink header of a replay event carries uninitialised stack
values rather than defined ones. This was confirmed at runtime rather
than by inspection alone: the .seq and .portid carried in that header
hold values that nothing in the replay path assigns.

The request-driven paths set these header fields from the requester
(xfrm_get_ae() / xfrm_new_ae()); only the kernel-originated replay path
leaves them unset. Zero-initialise the event so the header fields are 0,
the correct value for a kernel-originated notification.

Fixes: f8cd54884e ("[IPSEC]: Sync series - core changes")
Reported-by: Giovanni Vignone <gio@octane.security>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Shubham Antil <shubham@octane.security>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-10-12 10:40:31 +02:00
Qihang
86de3a1118 xfrm: interface: validate the IP header on xmit
Packets injected into an xfrm interface (e.g. AF_PACKET on an xfrmi
device) reach the xfrm output path without IP header validation, but
xfrm4_transport_output() uses iph->ihl for __skb_pull() and memmove()
and expects the header to be valid.

vti_tunnel_xmit() already calls pskb_inet_may_pull() before handing
packets to the xfrm output path.  Do the same in xfrmi_xmit() and
perform the header checks ip_rcv_core()/ip6_rcv_core() do on entry
to the IP stack: reject wrong IP versions and malformed IPv4 header
lengths.

Fixes: f203b76d78 ("xfrm: Add virtual xfrm interfaces")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-09-30 07:54:33 +02:00
Hyungjung Joo
a478958f4c net/9p/usbg: clear stale client pointer on close
p9_usbg_close() tears down the client transport, but usb9pfs keeps
using usb9pfs->client from asynchronous TX and RX completion handlers.
A late completion can therefore dereference a client that has already
been freed during mount teardown.

Clear usb9pfs->client under usb9pfs->lock when closing the transport,
detach any pending TX request from in_req->context, and make the TX/RX
completion handlers bail out once the transport has been detached. This
keeps late completions from touching a freed or rebound p9_client.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Signed-off-by: Hyungjung Joo <jhj140711@gmail.com>
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-7-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:45 +00:00
Michael Grzeschik
bbdb38b2e5 net/9p/usbg: remove bogus context initialization in alloc_requests
alloc_requests() initializes usb9pfs->in_req->context to point at the
struct f_usb9pfs instance itself. usb9pfs_queue_tx() later overwrites
this with the real struct p9_req_t pointer before every transmit, and
usb9pfs_tx_complete() clears it back to NULL after each completion, so
in_req->context only ever holds a valid p9_req_t once a request has
actually been queued.

usb9pfs_clear_tx(), however, can run at any time (mount close, gadget
disable) independent of whether a request was ever queued. If it runs
before the first usb9pfs_transmit(), it reads the leftover sentinel
value, type-confuses the struct f_usb9pfs pointer as a struct
p9_req_t, and both writes through it (req->t_err = -ECONNRESET) and
hands it to p9_client_cb(), which manipulates req->wq and req->refcount
at bogus offsets inside f_usb9pfs. This reliably corrupts memory or
panics whenever the transport is torn down before any 9p request has
been transmitted, e.g. mounting and immediately unmounting, or a cable
disconnect racing the very first request.

usb9pfs->out_req->context is set the same way but is never read by
this transport (usb9pfs_rx_complete() identifies the instance via
ep->driver_data instead), so it serves no purpose either.

Both endpoints' ->driver_data are already set to usb9pfs in
enable_endpoint(), which is what the completion handlers actually use
to recover the f_usb9pfs instance. Just drop the leftover
->context assignments; usb_ep_alloc_request()/alloc_ep_req() already
return zeroed requests, so in_req->context correctly starts out NULL.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-6-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:44 +00:00
Michael Grzeschik
5f9807270c net/9p/usbg: fix out_req buffer leak in disable_usb9pfs
usb9pfs->out_req is allocated with alloc_ep_req(), which also
allocates the request's data buffer (req->buf). disable_usb9pfs()
frees it with plain usb_ep_free_request(), which only frees the
usb_request structure itself and leaks req->buf on every close.

Use free_ep_req() instead, matching the allocator, as documented by
its own comment ("Requests allocated via alloc_ep_req() *must* be
freed by free_ep_req()").

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-5-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:44 +00:00
Michael Grzeschik
cd1988cf72 net/9p/usbg: call disable_usb9pfs() from usb9pfs_disable()
usb9pfs_disable() is the usb_function ->disable callback, invoked by
the composite gadget core whenever the host resets or unconfigures
the gadget. The gadget function API requires this callback to disable
its endpoints; every other in-tree function driver does so from its
->disable hook.

usb9pfs_disable() never called disable_usb9pfs(), so the IN/OUT
endpoints and their usb_request objects were left active and
allocated across a host-driven disable. When the host later
reconfigures the device, enable_usb9pfs() calls alloc_requests() again
and unconditionally overwrites usb9pfs->in_req/out_req, permanently
leaking the previous allocations, while the endpoints themselves are
left enabled underneath the function's own idea of being disabled.

Call disable_usb9pfs() before reinit_completion(&usb9pfs->send),
mirroring the same sequence already used in p9_usbg_close(). Placing
it before the reinit_completion() also ensures usb_ep_disable() has
synchronously flushed any requests still queued in hardware before the
completion is reset, closing the same race that motivated resetting
the completion here in the first place.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Assisted-by: Claude:claude-opus-4.8
Cc: stable@vger.kernel.org
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-4-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:44 +00:00
Michael Grzeschik
08c6b9f484 net/9p/usbg: always reset completion when disconnecting
When some tx or rx transfers were pending while closing the connection,
the completion handler could catch one pending completion call. To
ensure a normal start when mounting again, we have to reset the
completion and flush any pending completions.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-3-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:43 +00:00
Michael Grzeschik
795f8eeca0 net/9p/usbg: set client to Disconnected on usb9pfs_disable
This patch is setting the client status to Disconnected, when the
client is still in use. Otherwise a disconnected usb cable would run
any use of the mount to faults.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-2-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:11:39 +00:00
Michael Grzeschik
f81cdb9164 net/9p/usbg: also disable endpoints on p9_usbg_close
The close function has to fully reverse the state change of 9p_create
(mount) and the potential call of set_alt(1). This includes to ensure
that the usage of the endpoints is not active any more.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260922-usb9pfsfixes-v1-1-9d8dcc52904c@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:40 +00:00
Yizhou Zhao
6f401e3509 net/9p/usbg: Fix use-after-free in disable_usb9pfs()
disable_usb9pfs() frees the IN and OUT usb_request objects before it
disables the corresponding endpoints. If either request is still queued,
the later usb_ep_disable() call cancels the endpoint queue and the UDC
driver can still access the already freed request.

With dummy_hcd and KASAN, this is reproducible by queueing the OUT
request and then disconnecting the configfs gadget:

  BUG: KASAN: slab-use-after-free in dummy_disable+0x2b4/0x300
  Read of size 8 at addr ffff888009702400 by task sh/1
  usb_ep_disable+0x8e/0x1f0
  usb9pfs_func_unbind+0x193/0x350
  gadget_dev_desc_UDC_store+0x135/0x280

dummy_free_request() also warns because the request is freed while its
queue entry is still linked.

Disable both endpoints before freeing the request objects. This lets
usb_ep_disable() cancel any queued transfers and invoke the completion
callback while the request storage is still valid. The request objects
are then freed only after they have been removed from the endpoint
queues.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Acked-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260607130118.16579-1-zhaoyz24@mails.tsinghua.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:39 +00:00
Haobin Wu
55d6732b80 9p: skip over-long directory entry names for legacy 9p2000 too
The legacy 9p2000 and 9p2000.u readdir path, v9fs_dir_readdir(), parses
each entry with p9stat_read() and, unlike the 9p2000.L path, never had
a 256-byte name limit: a name of any length up to the wire maximum was
handed to dir_emit(). getdents64() therefore returned names longer than
NAME_MAX that no later syscall can use, and failed with -EIO for names
of PATH_MAX bytes or more.

Apply the same NAME_MAX check as the previous patch does for
v9fs_dir_readdir_dotl(), so both protocol variants behave the same.

Note that this is a behaviour change for 9p2000 and 9p2000.u,
Name length 256..4095:
  - before: listed, but unusable (ENAMETOOLONG)
  - now: entry skipped, fetch continues
Name length >=4096:
  - before: aborts the entire fetch (similar to 9p2000.L side)
  - now: entry skipped, fetch continues

Suggested-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Link: https://lore.kernel.org/all/3910569.MHq7AAxBmi@weasel/
Signed-off-by: Haobin Wu <853555@gmail.com>
Message-ID: <20260918024851.51229-4-853555@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:39 +00:00
Haobin Wu
edd807dc20 9p: skip directory entries with names longer than NAME_MAX
The 9p wire format carries directory entry names of up to 65535 bytes
and nothing on the client checks them against NAME_MAX. Since the
previous patch, v9fs_dir_readdir_dotl() passes such names straight to
dir_emit(), and the VFS only rejects names of PATH_MAX bytes or more in
verify_dirent_name(), as -EIO, which again fails the whole getdents64()
call.

A name between NAME_MAX and PATH_MAX is therefore returned to userspace
even though every later operation on it fails with -ENAMETOOLONG, and
POSIX requires readdir() to only return components of at most NAME_MAX
bytes. Nothing can use such an entry, so skip it instead of returning it
or failing the listing, reusing the strlen() result that was already
computed for dir_emit(). Log the skipped entry at P9_DEBUG_ERROR, the
same level as the strscpy() failure message this replaces.

Suggested-by: Dominique Martinet <asmadeus@codewreck.org>
Link: https://lore.kernel.org/all/vz5bum547fqyxf5z4m3x7tuqkuq52jlopm65t7hvynqeulh7i3@2t4wnhfxs7qv/
Signed-off-by: Haobin Wu <853555@gmail.com>
Reviewed-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Message-ID: <20260918024851.51229-3-853555@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:39 +00:00
Haobin Wu
8bb0279930 9p: skip intermediate directory entry name copy in p9dirent_read()
v9fs_dir_readdir_dotl() decodes each entry of a Rreaddir reply with
p9dirent_read(), which parses it through p9pdu_readf("Qqbs"). The 's'
conversion in p9pdu_vreadf() already allocates a NUL-terminated copy
of the name from the wire buffer; p9dirent_read() then strscpy()s that
copy into the fixed 256-byte p9_dirent::d_name and frees the original.

The wire format carries the name length in 16 bits, so a name longer
than 255 bytes is valid on the wire and may well be valid on the
server's filesystem, but it makes strscpy() return -E2BIG.
v9fs_dir_readdir_dotl() turns that into -EIO and aborts getdents64(),
so every entry after the long one disappears from the listing.

Drop the second copy: keep the string allocated by p9pdu_vreadf() in
p9_dirent and let v9fs_dir_readdir_dotl(), its only user, free it once
dir_emit() has consumed it. p9_dirent is a short-lived stack object, so
the string's lifetime does not change.

Note that the VFS only rejects names of PATH_MAX bytes or more in
verify_dirent_name(), so after this change a name between NAME_MAX and
PATH_MAX is returned by getdents64() even though any later lookup on it
fails with -ENAMETOOLONG. The next patch skips such entries.

Fixes: 7751bdb3a0 ("9p: readdir implementation for 9p2000.L")
Closes: https://github.com/microsoft/WSL/issues/41192
Signed-off-by: Haobin Wu <853555@gmail.com>
Reviewed-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Message-ID: <20260918024851.51229-2-853555@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:39 +00:00
Kees Cook
a869fe526c 9p: Add const and unsigned to wnames allocation type
In preparation for converting the kmalloc family of allocators to the
type-aware kmalloc_obj family, we need to make sure that the returned
type from the allocation matches the type of the variable being
assigned. (The kmalloc family returns "void *", which can be implicitly
cast to any pointer type.)

The assigned type is "const unsigned char **", but the converted
allocation type would be "char **", which differs in both the const
qualifier and the signedness of the character type. Take the size from
the assignment target instead. No change in allocation size results.

Build tested ARCH=x86_64 allmodconfig with GCC 16.2.0:
fs/9p/fid.o

Assisted-by: LLM coccinelle
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Message-ID: <20260917211158.i.129-kees@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:38 +00:00
Yizhou Zhao
7b6f2e3c29 9p/xen: drain response work after unbinding IRQ
commit ea4f100940 ("9p/xen : Fix use after free bug in
xen_9pfs_front_remove due to race condition") added cancel_work_sync()
to keep xen_9pfs_front_free() from freeing a ring while
p9_xen_response() is still running.

The work is currently drained before the event channel IRQ is unbound.
That leaves a race window where xen_9pfs_front_event_handler() can run
after cancel_work_sync() returns and queue p9_xen_response() again.  The
following unbind_from_irqhandler() synchronizes with the IRQ handler, but
it does not cancel work that the handler already queued.  The teardown
can then free the ring and private data while the response work remains
pending, and the worker later dereferences ring->priv and priv->client.

Unbind the event channel IRQ before draining the work.  Once the IRQ is
unbound, no new response work can be queued by the backend event channel,
and cancel_work_sync() waits for any work that was queued before or
during the unbind.  It is then safe to release the ring resources.

Fixes: ea4f100940 ("9p/xen : Fix use after free bug in xen_9pfs_front_remove due to race condition")
Cc: stable@vger.kernel.org
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Message-ID: <20260609155202.1706-1-zhaoyz24@mails.tsinghua.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:10:32 +00:00
Rosen Penev
b3d07d6483 9p/xen: Use array for data rings
Store the fixed set of Xen 9p data rings in the frontend private
allocation instead of allocating a separate rings array.

This keeps the data ring storage tied to the frontend lifetime and
simplifies the allocation and cleanup paths.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Message-ID: <20260913192740.29668-1-rosenp@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:07:34 +00:00
Matus Skvarla
33625427a3 net/9p: add vsock transport
Add vsock as a transport option for 9P client connections. This
allows mounting 9P filesystems over VM sockets without requiring TCP/IP
networking or additional userspace tools, which can be useful with
hypervisors other than Qemu/KVM, for example Hyper-V/WSL which is used
by podman machine on Windows[1][2].

The implementation extends trans_fd.c with vsock support, reusing the
existing socket infrastructure. A new p9_fd_create_vsock() function
handles vsock connection setup by parsing the CID from the mount source,
creating an AF_VSOCK socket, and connecting to the specified endpoint.
All other transport operations (close, request, cancel) use the shared
fd transport implementation.

The privport mount option is not currently implemented for vsock and
returns -EOPNOTSUPP if specified.

Add CONFIG_NET_9P_VSOCK option that conditionally compiles vsock support
into 9pnet_fd.ko. This follows the pattern where socket-based transports
(TCP, Unix, vsock) share trans_fd.c, while specialized hardware transports
(virtio, xen, rdma) have dedicated files.

Usage:
  mount -t 9p -o trans=vsock[,port=<port>] <CID> /mnt/point

Link: https://github.com/podman-container-tools/podman/blob/main/cmd/podman/machine/server9p.go [1]
Link: https://github.com/podman-container-tools/podman/blob/main/cmd/podman/machine/client9p.go [2]
Signed-off-by: Matus Skvarla <skvarlamatus@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
Message-ID: <20260709161741.15138-1-skvarlamatus@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:07:34 +00:00
Dmitry Antipov
74795e00cf 9p: simplify v9fs_cache_session_get_cookie()
Use the convenient 'strreplace()' to simplify
'v9fs_cache_session_get_cookie()'.

Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Message-ID: <20260814040826.1213127-1-dmantipov@yandex.ru>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:07:34 +00:00
Deepanshu Kartikey
64f350a594 9p: don't WARN_ONCE on racy symlink fid lookup failure
v9fs_init_request() WARN_ONCE()s when v9fs_fid_lookup() fails for a
symlink read via the page cache. This is a benign TOCTOU race: a
concurrent unlink()/rename() can remove the target between the walk
finding the dentry and p9_client_walk() completing, so the lookup
legitimately fails with -ENOENT (observed: dentry=/file0, err=-2).

With panic_on_warn=1, this WARN escalates to a full kernel panic --
an unprivileged local DoS reachable by racing mount() against a
concurrent unlink/rename.

Return the error directly instead of WARN_ONCE().

Reported-by: syzbot+344c09c64fcd8d3d2782@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=344c09c64fcd8d3d2782
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Message-ID: <20260725014448.18711-1-kartikey406@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:07:33 +00:00
Zhao Zhang
2acd800de8 9p: fix caches_show() out-of-bounds write
The sysfs show handler for /sys/fs/9p/caches appends cache tags with
snprintf(buf + count, limit, ...) and then advances count and limit by
the return value. This is incorrect for truncation because snprintf()
returns the full would-have-been length, not the number of bytes stored.

Once the accumulated output exceeds PAGE_SIZE, count can advance past
the sysfs buffer and limit can become negative. A later iteration then
passes an out-of-bounds destination pointer and an oversized size_t
into snprintf(), leading to an out-of-bounds write.

Use sysfs_emit_at() for the append instead. It follows the sysfs buffer
contract and returns the number of bytes actually stored, so the offset
remains bounded even when the output is truncated.

Fixes: 86db0c32f1 ("9p: fix /sys/fs/9p/caches overwriting itself")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Assisted-by: Codex:GPT-5.4
Signed-off-by: Zhao Zhang <zzhan461@ucr.edu>
Co-authored-by: Ren Wei <n05ec@lzu.edu.cn>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Message-ID: <abfb65f4800634dafb08238bba20cb48797e796f.1781908090.git.zzhan461@ucr.edu>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 08:07:33 +00:00
Yifei Gao
4d183e6f15 9p/xen: fix refcount leak in p9_xen_response() on wrong tag
p9_xen_response() looks up the request for an incoming reply with
p9_tag_lookup(), which takes a reference on the returned p9_req_t. When
the tag does not resolve to a request in REQ_STATUS_SENT, the function
warns and continues the loop without dropping that reference, permanently
leaking the p9_req_t and its msize buffers. The reply header, including
the tag, is supplied by the backend, so a malicious or buggy 9P backend
can leak kernel memory on every crafted response.

Drop the reference before continuing.

Fixes: 728356dede ("9p: Add refcount to p9_req_t")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yifei Gao <gyf161023@gmail.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Message-ID: <20260806144255.4167019-1-gyf161023@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 07:55:03 +00:00
Michael Bommarito
5bfef2b6da 9p/trans_virtio: reject mount tags longer than NAME_MAX at probe
p9_virtio_probe() reads a 16-bit mount tag length (tag_len) from the
device config and kzalloc()s tag_len + 1 bytes for chan->tag with no
upper bound. A malicious or compromised host can present a tag of up to
65535 bytes; that tag is later copied into the single-page sysfs buffer
by p9_mount_tag_show() (memcpy(buf, chan->tag, tag_len + 1)), a
host-controlled out-of-bounds write of up to ~64 KiB past the PAGE_SIZE
attribute buffer.

Reject an overlong tag at probe time. A 9p mount tag is a name-like
identifier, so bound it by NAME_MAX (255): that limit is independent of
the sysfs/seq_file page size and is far above any legitimate mount tag,
which keeps p9_mount_tag_show() safe at the root without hard-coding a
seq_file implementation detail.

Fixes: 179a5bc4b8 ("net/9p: use memcpy() instead of snprintf() in p9_mount_tag_show()")
Cc: stable@vger.kernel.org
Suggested-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Message-ID: <20260627211012.4042372-1-michael.bommarito@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 07:55:03 +00:00
Chengfeng Ye
b58943dd69 net/9p/usbg: clear stale request context after abort
usb9pfs_clear_tx() serializes access to the active TX request with
usb9pfs->lock, but leaves in_req->context pointing at the request after
p9_client_cb() drops the transport reference.  A later teardown path can
therefore retrieve the same request after it has been freed:

  CPU 0 (p9_usbg_close)        CPU 1 (usb9pfs_disable)
  lock(usb9pfs->lock)
  req = in_req->context
  p9_client_cb(client, req)
    p9_req_put(client, req)
  unlock(usb9pfs->lock)
  request reaches zero refs
    kmem_cache_free(req)
                                lock(usb9pfs->lock)
                                req = in_req->context
                                read req->t_err

The lock orders the two callbacks, but cannot protect a pointer that
remains published after its reference has been released.  KASAN reported:

  BUG: KASAN: slab-use-after-free in usb9pfs_clear_tx+0x166/0x1b0
  Read of size 4 at addr ffff88810e7420f4 by task poc/94
  Call Trace:
   usb9pfs_clear_tx+0x166/0x1b0
   usb9pfs_disable+0x1d/0x30
   reset_config+0x9d/0x200
   __composite_disconnect+0xa7/0x140
  Allocated by task 93:
   kmem_cache_alloc_noprof+0x141/0x370
   p9_tag_alloc+0x8f/0x5b0
   p9_client_prepare_req+0xff/0x350
   p9_client_rpc+0x1a5/0xac0
  Freed by task 0:
   slab_free_after_rcu_debug+0xa6/0x1e0
   rcu_core+0x50a/0x1850
  Last potentially related work creation:
   kmem_cache_free+0x1db/0x3d0
   p9_req_put+0x164/0x1f0
   usb9pfs_clear_tx+0x120/0x1b0
   p9_usbg_close+0x7e/0x150

Clear in_req->context after the callback while still holding the lock.
This matches the consume-and-clear pattern in usb9pfs_tx_complete(), so
subsequent teardown calls return without touching the released request.
The existing callback and error ordering remain unchanged.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Signed-off-by: Qi Zhang <marsy12010123@gmail.com>
Message-ID: <20260802152148.810390-1-marsy12010123@gmail.com>
Acked-by: Michael Grzeschik <mgr@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 07:54:44 +00:00
Yizhou Zhao
5c69297356 net/9p/usbg: Fix use-after-free on usb9pfs_clear_tx
When p9_usbg_close() is called, it invokes usb9pfs_clear_tx() but does
not clear usb9pfs->client nor usb9pfs->in_req->context afterwards.
The 9p client core (p9_client_destroy) calls close() and then
kfree(clnt), so after p9_usbg_close returns the client struct is freed.

If the USB gadget is later disabled (e.g., host disconnect),
usb9pfs_disable calls usb9pfs_clear_tx again, which passes the dangling
usb9pfs->client pointer to p9_client_cb. Inside p9_client_cb,
p9_req_put(c, req) dereferences the freed client to access its reqs IDR,
causing a use-after-free.

Additionally, usb9pfs_clear_tx does not clear usb9pfs->in_req->context
after calling p9_client_cb, so a second invocation finds a stale request
pointer and attempts double-completion, further compounding the UAF risk.

Fix by:
1. Clearing usb9pfs->in_req->context to NULL in usb9pfs_clear_tx()
   before checking usb9pfs->client, so that even if the client is gone
   the stale request pointer is consumed and cannot cause
   double-completion.
2. Adding a NULL check on usb9pfs->client in usb9pfs_clear_tx() to skip
   p9_client_cb() when the client has already been destroyed.
3. Setting usb9pfs->client = NULL in p9_usbg_close() after calling
   usb9pfs_clear_tx(), to prevent any subsequent call from dereferencing
   the freed client pointer.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Message-ID: <20260529081026.77732-1-zhaoyz24@mails.tsinghua.edu.cn>
Acked-by: Michael Grzeschik <mgr@kernel.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-22 07:54:33 +00:00
Chengfeng Ye
868f63c8bf xfrm: retry inexact policy lookup after node reinsertion
An inexact policy lookup first records pointers to candidate hlist heads
and then traverses the lists.  A concurrent policy insertion can merge
inexact tree nodes between those operations:

  lookup                         policy insertion
  ------                         ----------------
  find inexact candidates
    save obsolete hlist head
                                 write_seqcount_begin(&bin->count)
                                 merge inexact tree nodes
                                   hlist_del_rcu(&policy->bydst)
                                   reinsert policy->bydst in survivor
                                 write_seqcount_end(&bin->count)
  evaluate saved candidate list
    miss the moved policy

The merge immediately reinserts the same hlist node into the surviving
tree node.  RCU keeps the policy alive, but it does not provide a
consistent view while its list node is moved.  A lookup that selected the
obsolete list can observe it empty.  A lookup already traversing a moved
policy can instead follow the next pointer rewritten by the reinsertion.
Either case can return an incorrect IPsec policy result.

The per-bin sequence counter already brackets calls to
xfrm_policy_inexact_insert_node(), including node merges.  The read side,
however, currently validates the counter only while searching an
individual rb-tree.  A successful search returns without validation, and
the later candidate-list traversal is outside that read-side section.

Snapshot the per-bin sequence before discovering candidate heads and
validate it after evaluating all candidate lists.   Retry the lookup if
the inexact policy tree changes while it is being searched.

Fixes: 9cf545ebd5 ("xfrm: policy: store inexact policies in a tree ordered by destination address")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-09-17 08:09:05 +02:00
Yizhou Zhao
9ee83ef8d2 net/9p/usbg: fix prefix matching in device lookup
p9_usbg_create() matches the mount source against registered usb9pfs
instance tags with strncmp() and the length of the caller supplied source.
That accepts any prefix of the registered tag.

For example, a gadget instance tagged "secret_channel" can be selected with
"s", "sec", or any other non-empty prefix.  Once selected, the instance is
marked in use and the client is attached to that transport.  This differs
from the configfs tag lookup path, which uses strcmp() and therefore
requires an exact tag match.

Require an exact tag match in p9_usbg_create() as well.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Cc: stable@vger.kernel.org
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Co-developed-by: Jackie Liu <liuyun01@kylinos.cn>
Signed-off-by: Jackie Liu <liuyun01@kylinos.cn>
Message-ID: <20260607121907.12588-1-zhaoyz24@mails.tsinghua.edu.cn>
Message-ID: <20260719040346.88295-1-liu.yun@linux.dev>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-13 08:26:00 +00:00
Yizhou Zhao
0955472fff net/9p/usbg: fix descriptor cleanup use-after-free
usb9pfs_free_func() frees the f_usb9pfs object before calling
usb_free_all_descriptors().  The usb_function passed to the latter is
embedded in the freed object, so removing the function from a gadget
dereferences freed memory.

The failing teardown sequence is:

  configfs unlink
    usb9pfs_free_func()
      kfree(usb9pfs)
      usb_free_all_descriptors(f)
        dereference the embedded usb_function

KASAN reported:

  BUG: KASAN: slab-use-after-free in usb_free_all_descriptors+0x138/0x190
  Read of size 8 at addr ffff888106a73088 by task poc/95
  Call Trace:
   usb_free_all_descriptors+0x138/0x190
   config_usb_cfg_unlink+0x1f0/0x2f0
   configfs_unlink+0x321/0x6f0

Free the descriptors before freeing their containing object.

Fixes: a3be076dc1 ("net/9p/usbg: Add new usb gadget function transport")
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Co-developed-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Acked-by: Michael Grzeschik <mgr@kernel.org>
Message-ID: <20260529081817.77898-1-zhaoyz24@mails.tsinghua.edu.cn>
Message-ID: <20260731150414.3135662-1-nicoyip.dev@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-13 08:25:26 +00:00
Stefano Garzarella
7fb9bd3659 9p: fix privport option setting wrong RDMA field
While reviewing a patch adding vsock transport to 9p, I noticed that
since commit 1f3e4142c0 ("9p: convert to the new mount API"), the
Opt_privport case incorrectly sets rdma_opts->port instead of
rdma_opts->privport, so mounting with the privport option overwrites
the RDMA port number instead of enabling privileged port usage.

Fixes: 1f3e4142c0 ("9p: convert to the new mount API")
Cc: stable@vger.kernel.org
Cc: sandeen@redhat.com
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Acked-by: Eric Sandeen <sandeen@redhat.com>
Message-ID: <20260703102254.114446-1-sgarzare@redhat.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-13 08:21:27 +00:00
Yizhou Zhao
37dce65a0b 9p: use fc->net_ns for network namespace in RDMA and socket transports
The 9p RDMA transport currently passes &init_net to rdma_create_id().
As a result, RDMA address resolution and connection setup are performed
in the initial network namespace, even when the mount is initiated from
a non-initial network namespace.

This differs from the socket-based 9p transports, which create sockets
in current->nsproxy->net_ns.  Use fc->net_ns for both the RDMA and
socket transports instead, so that transport setup follows the VFS
mount namespace context rather than depending on the calling process's
current namespace.

This avoids surprising behaviour where a 9p RDMA mount from a container
or other non-initial network namespace may use the host namespace for
RDMA CM operations.

Fixes: fa20105e09 ("IB/cma: Add support for network namespaces")
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Suggested-by: Dominique Martinet <asmadeus@codewreck.org>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Message-ID: <20260529090625.78761-1-zhaoyz24@mails.tsinghua.edu.cn>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-13 08:21:27 +00:00
Hemanth Selam
5852cdf000 net/9p: fix typos in comments
Fix typos in comments, reported by scripts/checkpatch.pl using the
misspelling list in scripts/spelling.txt.
Only touches comments, no code changes.

Assisted-by: Cursor:claude-opus-5
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
Reviewed-by: Christian Schoenebeck <linux_oss@crudebyte.com>
Message-ID: <20260904112100.34541-1-hemanth.selam@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
2026-09-13 08:13:24 +00:00
434 changed files with 10969 additions and 4668 deletions

View File

@ -233,6 +233,10 @@ Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
Chuck Lever <cel@kernel.org> <cel@netapp.com>
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
Clément Léger <clement.leger@linux.dev> <cleger@kalray.eu>
Clément Léger <clement.leger@linux.dev> <clement.leger@bootlin.com>
Clément Léger <clement.leger@linux.dev> <cleger@rivosinc.com>
Clément Léger <clement.leger@linux.dev> <cleger@meta.com>
Coiby Xu <coiby.xu@gmail.com> <coxu@redhat.com>
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
Corey Minyard <minyard@acm.org>

View File

@ -407,6 +407,13 @@ referenced kptr (by invoking bpf_kptr_xchg). If not, the verifier fails the
loading of the BPF program until no lingering references remain in all possible
explored states of the program.
A pointer to a struct in the arguments of a KF_ACQUIRE kfunc accepts only an
object of that type. The same applies to the argument that a KF_RELEASE kfunc
releases. For other arguments a kfunc also accepts memory of the program, if the
struct has only scalar members. A struct without members, struct __sk_buff and
struct xdp_md never accept memory. A KF_ACQUIRE kfunc which wants such memory
has to pair the pointer with a __sz argument.
2.5.2 KF_RET_NULL flag
----------------------

View File

@ -50,6 +50,14 @@ mount points. Each 9P export is seen by the client as a virtio device with an
associated "mount_tag" property. Available mount tags can be
seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
For server accessible over vsock (VM sockets)::
mount -t 9p -o trans=vsock[,port=<port>] <CID> /mnt/9
where CID is the vsock Context ID of the remote endpoint (2 for host from
a guest VM, 3+ for guest VMs from the host). The port to connect to can be
specified with the port option (default: 564).
USBG Usage
==========
@ -117,6 +125,8 @@ Options
tcp specifying a normal TCP/IP connection
fd used passed file descriptors for connection
(see rfdno and wfdno)
vsock connect over VM sockets (vsock) using
CID as the mount source
virtio connect to the next virtio channel available
(from QEMU with trans_virtio module)
rdma connect to a specified RDMA channel
@ -228,7 +238,7 @@ Options
any
v9fs does single attach and performs all
operations as one user
clien
client
ACL based access check on the 9p client
side for access validation

View File

@ -731,7 +731,8 @@ When decoding an overlay file handle, the following steps are followed:
1. Find underlying layer by UUID and path type information.
2. Decode the underlying filesystem file handle to underlying dentry.
3. For a lower file handle, lookup the handle in index directory by name.
3. For a lower file handle, encode the decoded underlying inode again and
lookup that handle in index directory by name.
4. If a whiteout is found in index, return ESTALE. This represents an
overlay object that was deleted after its file handle was encoded.
5. For a non-directory, instantiate a disconnected overlay dentry from the

View File

@ -34,6 +34,12 @@ Usage notes
As these are USB HIDs, the driver can be loaded automatically by the kernel and
supports hot swapping.
The pump of the RYUJIN III also has a 4-pin cable for a motherboard fan header.
The cooler either hands the pump to its internal controller, which follows the
PWM of the header its 4-pin cable is plugged into, or runs it at the pump duty
set over USB. Writing pwm1 selects the duty set over USB. Writing pwm2 sets
only the internal fan duty and leaves the pump control as it is.
Sysfs entries
-------------

View File

@ -130,8 +130,19 @@ pages of ``struct page`` (page 1 to page 7) are tail pages.
The optimization is only applied when the size of the struct page is a power
of 2. In this case, all tail pages of the same order are identical. See
compound_head(). This allows us to remap the tail pages of the vmemmap to a
shared, read-only page. The head page is also remapped to a new page. This
allows the original vmemmap pages to be freed.
shared page. The head page is also remapped to a new page. This allows the
original vmemmap pages to be freed.
The shared page is mapped writable. A lockless get of a page reference can
read a non-zero refcount before the remap and attempt its atomic update
after it. The refcount of a tail page is zero, so the update fails without
changing the page. Nothing else may write to the shared page: it is shared
by all HugeTLB pages of the same size in the zone, and a stray write would
corrupt all of them.
HugeTLB pages whose vmemmap is optimized when the memmap is first set up at
boot keep a read-only mapping of the shared page. Nothing can do a lockless
get on them before they are handed to HugeTLB.
Here is how things look after remapping::

View File

@ -1040,17 +1040,21 @@ As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several f
lists to deliver received CAN frames to CAN protocol modules. These
receive lists, their filters and the count of filter matches can be
checked in the appropriate receive list. All entries contain the
device and a protocol module identifier::
CAN network device, the filter (can_id/can_mask), the number of filter
matches, the inode number of the subscribing socket and the name of the
receive function. A sock_inode of 0 denotes a kernel internal subscriber
without a socket (e.g. CAN gateway or J1939). When the function name can
not be resolved (e.g. with CONFIG_KALLSYMS=n) "(unknown)" is printed::
foo@bar:~$ cat /proc/net/can/rcvlist_all
receive list 'rx_all':
(vcan3: no entry)
(vcan2: no entry)
(vcan1: no entry)
device can_id can_mask function userdata matches ident
vcan0 000 00000000 f88e6370 f6c6f400 0 raw
(any: no entry)
device can_id can_mask matches sock_inode function
vcan0 000 00000000 0 63586 raw_rcv [can_raw]
(vcan1: no entry)
(vcan2: no entry)
(vcan3: no entry)
In this example an application requests any CAN traffic from vcan0::

View File

@ -27,15 +27,20 @@ SA Identification
=================
The struct is defined in ``include/uapi/linux/xfrm.h``. The SA is looked
up using ``xfrm_state_lookup()`` with ``id.spi``,
``id.daddr``, ``id.proto``, ``id.family``, and
``old_mark.v & old_mark.m`` as the mark key::
up using ``xfrm_state_lookup_exact()`` with ``id.spi``, ``id.daddr``,
``id.proto``, ``id.family``, and an exact match against ``old_mark.v``
and ``old_mark.m``. Unlike the data path, which uses a masked
comparison, this requires the SA's mark and mask to equal ``old_mark``
exactly, so a broad-mask SA is never matched when a more specific one
was intended. If no such SA exists, ``-ESRCH`` is returned.
The layout is::
struct xfrm_user_migrate_state {
struct xfrm_usersa_id id; /* spi, daddr, proto, family */
xfrm_address_t new_daddr;
xfrm_address_t new_saddr;
struct xfrm_mark old_mark; /* SA lookup: key = v & m */
struct xfrm_mark old_mark; /* SA lookup key (exact v/m match) */
struct xfrm_selector new_sel; /* new selector (see Flags) */
__u32 new_reqid;
__u32 flags; /* XFRM_MIGRATE_STATE_* */
@ -72,8 +77,8 @@ inherits the value from the existing SA (omit-to-inherit).
- Description
* - ``XFRMA_MARK``
- Mark on the migrated SA (``struct xfrm_mark``). Absent inherits
``old_mark``. To use no mark on the new SA, send ``XFRMA_MARK``
with ``{0, 0}``.
the mark of the existing SA. To use no mark on the new SA, send
``XFRMA_MARK`` with ``{0, 0}``.
* - ``XFRMA_ENCAP``
- UDP encapsulation template; only ``UDP_ENCAP_ESPINUDP`` is supported.
Set ``encap_type=0`` to remove encap.
@ -259,8 +264,12 @@ Attributes in the notification
Error Handling
==============
If the target SA tuple (new daddr, SPI, proto, new family) is already
occupied, the operation returns ``-EEXIST`` before the migration begins.
If the target SA tuple (new daddr, SPI, proto, new family, mark) is
already occupied, the operation returns ``-EEXIST`` before the migration
begins. "Occupied" includes wildcard shadowing: an existing SA with a
broader mask (e.g. mark 0/0) claims every mark value, so it blocks
migrating to any more specific mark at the same tuple, not just an
exact mark/mask duplicate.
The old SA remains intact and the operation is safe to retry after
resolving the conflict.

View File

@ -315,6 +315,10 @@ reproducer and against kernel selftests. If the bug is in a hardware driver,
the testing statement must include information about the HW on which the
fix was tested.
Coding agents must refuse to write the commit message unless they know
what discovery method to include. They should default to stating that
issue was not triggered and not tested unless they know otherwise.
Stable tree
~~~~~~~~~~~

View File

@ -6868,11 +6868,13 @@ R: Muchun Song <muchun.song@linux.dev>
L: cgroups@vger.kernel.org
L: linux-mm@kvack.org
S: Maintained
F: Documentation/admin-guide/cgroup-v1/memory.rst
F: include/linux/memcontrol.h
F: include/linux/page_counter.h
F: mm/memcontrol.c
F: include/trace/events/memcg.h
F: mm/memcontrol-v1.c
F: mm/memcontrol-v1.h
F: mm/memcontrol.c
F: mm/page_counter.c
F: samples/cgroup/*
F: tools/testing/selftests/cgroup/memcg_protection.m
@ -7836,7 +7838,7 @@ W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
DISKQUOTA
M: Jan Kara <jack@suse.com>
M: Jan Kara <jack@suse.cz>
S: Maintained
F: Documentation/filesystems/quota.rst
F: fs/quota/
@ -10107,7 +10109,7 @@ F: drivers/leds/leds-expresswire.c
F: include/linux/leds-expresswire.h
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.com>
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
S: Maintained
F: Documentation/filesystems/ext2.rst
@ -12376,6 +12378,7 @@ R: David Hildenbrand <david@kernel.org>
L: linux-mm@kvack.org
S: Maintained
F: Documentation/ABI/testing/sysfs-kernel-mm-hugepages
F: Documentation/admin-guide/cgroup-v1/hugetlb.rst
F: Documentation/admin-guide/mm/hugetlbpage.rst
F: Documentation/mm/hugetlbfs_reserv.rst
F: Documentation/mm/vmemmap_dedup.rst
@ -12387,6 +12390,7 @@ F: mm/hugetlb.c
F: mm/hugetlb_cgroup.c
F: mm/hugetlb_cma.c
F: mm/hugetlb_cma.h
F: mm/hugetlb_internal.h
F: mm/hugetlb_sysctl.c
F: mm/hugetlb_sysfs.c
F: mm/hugetlb_vmemmap.c
@ -12406,6 +12410,7 @@ M: Miaohe Lin <linmiaohe@huawei.com>
R: Naoya Horiguchi <nao.horiguchi@gmail.com>
L: linux-mm@kvack.org
S: Maintained
F: Documentation/ABI/testing/sysfs-memory-page-offline
F: include/linux/memory-failure.h
F: include/trace/events/memory-failure.h
F: mm/hwpoison-inject.c
@ -14070,6 +14075,16 @@ S: Maintained
F: io_uring/bpf-ops.*
F: io_uring/loop.*
IPC
M: Andrew Morton <akpm@linux-foundation.org>
R: Manfred Spraul <manfred@colorfullife.com>
R: Davidlohr Bueso <dave@stgolabs.net>
L: linux-kernel@vger.kernel.org
S: Maintained
F: ipc/
F: tools/testing/selftests/ipc/
F: tools/testing/selftests/mqueue/
IPMI SUBSYSTEM
M: Corey Minyard <corey@minyard.net>
L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
@ -14309,7 +14324,7 @@ F: include/uapi/linux/jffs2.h
JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
M: "Theodore Ts'o" <tytso@mit.edu>
M: Jan Kara <jack@suse.com>
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
S: Maintained
F: fs/jbd2/
@ -17456,21 +17471,6 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
F: drivers/devfreq/tegra30-devfreq.c
MEMORY HOT(UN)PLUG
M: David Hildenbrand <david@kernel.org>
M: Oscar Salvador <osalvador@suse.de>
L: linux-mm@kvack.org
L: linux-cxl@vger.kernel.org
S: Maintained
F: Documentation/admin-guide/mm/memory-hotplug.rst
F: Documentation/core-api/memory-hotplug.rst
F: drivers/base/memory.c
F: include/linux/memory_hotplug.h
F: include/linux/memremap.h
F: mm/memremap.c
F: mm/memory_hotplug.c
F: tools/testing/selftests/memory-hotplug/
MEMORY MANAGEMENT
M: Andrew Morton <akpm@linux-foundation.org>
L: linux-mm@kvack.org
@ -17494,18 +17494,15 @@ F: mm/alloc_tag.c
F: tools/testing/selftests/alloc_tag/
MEMORY MANAGEMENT - BALLOON
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
L: linux-mm@kvack.org
L: virtualization@lists.linux.dev
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: include/linux/balloon.h
F: mm/balloon.c
MEMORY MANAGEMENT - CORE
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <liam@infradead.org>
@ -17515,27 +17512,34 @@ R: Suren Baghdasaryan <surenb@google.com>
R: Michal Hocko <mhocko@suse.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/admin-guide/sysctl/vm.rst
F: Documentation/core-api/gfp_mask-from-fs-io.rst
F: fs/proc/meminfo.c
F: include/linux/cacheflush.h
F: include/linux/folio_batch.h
F: include/linux/gfp.h
F: include/linux/gfp_types.h
F: include/linux/highmem-internal.h
F: include/linux/highmem.h
F: include/linux/leafops.h
F: include/linux/memory.h
F: include/linux/mm.h
F: include/linux/mm_*.h
F: include/linux/mmzone.h
F: include/linux/mmdebug.h
F: include/linux/mmu_notifier.h
F: include/linux/mmzone.h
F: include/linux/pagewalk.h
F: include/linux/pfn.h
F: include/linux/pgalloc.h
F: include/linux/pgtable.h
F: include/linux/ptdump.h
F: include/linux/sched/mm.h
F: include/linux/vm_event_item.h
F: include/linux/vmpressure.h
F: include/linux/vmstat.h
F: fs/proc/meminfo.c
F: include/trace/events/mmflags.h
F: include/trace/events/pagemap.h
F: kernel/fork.c
F: mm/Kconfig
F: mm/debug.c
@ -17554,6 +17558,7 @@ F: mm/ptdump.c
F: mm/util.c
F: mm/vmpressure.c
F: mm/vmstat.c
F: scripts/gdb/linux/mm.py
N: include\/linux\/page[-_][a-zA-Z]*
MEMORY MANAGEMENT - EXECMEM
@ -17565,15 +17570,14 @@ F: include/linux/execmem.h
F: mm/execmem.c
MEMORY MANAGEMENT - GUP (GET USER PAGES)
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Jason Gunthorpe <jgg@nvidia.com>
R: John Hubbard <jhubbard@nvidia.com>
R: Peter Xu <peterx@redhat.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/core-api/pin_user_pages.rst
F: mm/gup.c
F: mm/gup_test.c
F: mm/gup_test.h
@ -17582,14 +17586,12 @@ F: tools/testing/selftests/mm/gup.c
F: tools/testing/selftests/mm/gup_longterm.c
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Xu Xin <xu.xin@linux.dev>
R: Chengming Zhou <chengming.zhou@linux.dev>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/ABI/testing/sysfs-kernel-mm-ksm
F: Documentation/admin-guide/mm/ksm.rst
F: Documentation/mm/ksm.rst
@ -17598,13 +17600,30 @@ F: include/trace/events/ksm.h
F: mm/ksm.c
F: mm/mm_slot.h
MEMORY MANAGEMENT - MEMORY HOT(UN)PLUG
M: David Hildenbrand <david@kernel.org>
M: Oscar Salvador <osalvador@suse.de>
L: linux-mm@kvack.org
L: linux-cxl@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/ABI/testing/sysfs-devices-memory
F: Documentation/admin-guide/mm/memory-hotplug.rst
F: Documentation/core-api/memory-hotplug.rst
F: drivers/base/memory.c
F: include/linux/memory_hotplug.h
F: include/linux/memremap.h
F: mm/memory_hotplug.c
F: mm/memremap.c
F: tools/testing/selftests/memory-hotplug/
MEMORY MANAGEMENT - MEMORY MAP
M: Muchun Song <muchun.song@linux.dev>
M: Mike Rapoport <rppt@kernel.org>
M: David Hildenbrand <david@kernel.org>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git memmap
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/mm/memory-model.rst
F: arch/*/include/asm/sparsemem.h
F: include/asm-generic/memory_model.h
@ -17636,7 +17655,6 @@ F: mm/vmscan.c
F: mm/workingset.c
MEMORY MANAGEMENT - MIGRATION
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Matthew Brost <matthew.brost@intel.com>
@ -17647,10 +17665,10 @@ R: Ying Huang <ying.huang@linux.alibaba.com>
R: Alistair Popple <apopple@nvidia.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: include/linux/migrate.h
F: include/linux/migrate_mode.h
F: include/trace/events/migrate.h
F: mm/migrate.c
F: mm/migrate_device.c
@ -17674,15 +17692,20 @@ F: Documentation/admin-guide/mm/
F: Documentation/core-api/memory-allocation.rst
F: Documentation/core-api/mm-api.rst
F: Documentation/mm/
X: Documentation/admin-guide/mm/damon/
X: Documentation/mm/damon/
F: mm/char-mem.c
F: fs/proc/page.c
F: include/linux/backing-dev-defs.h
F: include/linux/backing-dev.h
F: include/linux/cma.h
F: include/linux/dmapool.h
F: include/linux/ioremap.h
F: include/linux/kernel-page-flags.h
F: include/linux/page_idle.h
F: include/trace/events/cma.h
F: include/uapi/linux/kernel-page-flags.h
F: mm/backing-dev.c
F: mm/char-mem.c
F: mm/cma.c
F: mm/cma.h
F: mm/cma_debug.c
F: mm/cma_sysfs.c
F: mm/dmapool.c
@ -17695,7 +17718,11 @@ F: mm/page_idle.c
F: mm/pgalloc-track.h
F: mm/process_vm_access.c
F: tools/lib/mm/
F: tools/mm/
F: tools/testing/selftests/mm/
X: Documentation/ABI/testing/sysfs-kernel-mm-damon
X: Documentation/admin-guide/mm/damon/
X: Documentation/mm/damon/
MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION
M: Andrew Morton <akpm@linux-foundation.org>
@ -17703,13 +17730,13 @@ M: Mike Rapoport <rppt@kernel.org>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git
F: include/linux/numa.h
F: include/linux/numa_memblks.h
F: mm/numa.c
F: mm/numa_emulation.c
F: mm/numa_memblks.c
MEMORY MANAGEMENT - NUMA PLACEMENT
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Gregory Price <gourry@gourry.net>
R: Zi Yan <ziy@nvidia.com>
@ -17718,11 +17745,11 @@ R: Rakie Kim <rakie.kim@sk.com>
R: Ying Huang <ying.huang@linux.alibaba.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
F: Documentation/admin-guide/numastat.rst
F: include/linux/memory-tiers.h
F: include/linux/mempolicy.h
F: include/uapi/linux/mempolicy.h
@ -17741,19 +17768,22 @@ F: include/uapi/linux/oom.h
F: mm/oom_kill.c
MEMORY MANAGEMENT - PAGE ALLOCATOR
M: Andrew Morton <akpm@linux-foundation.org>
M: Vlastimil Babka <vbabka@kernel.org>
M: Johannes Weiner <hannes@cmpxchg.org>
R: Suren Baghdasaryan <surenb@google.com>
R: Michal Hocko <mhocko@suse.com>
R: Brendan Jackman <brendan.jackman@linux.dev>
R: Johannes Weiner <hannes@cmpxchg.org>
R: Zi Yan <ziy@nvidia.com>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/page_alloc.git page_alloc/for-next
F: include/linux/compaction.h
F: include/linux/gfp.h
F: include/linux/page-isolation.h
F: include/linux/pageblock-flags.h
F: include/trace/events/compaction.h
F: include/trace/events/page_isolation.h
F: include/trace/events/page_ref.h
F: mm/compaction.c
F: mm/debug_page_alloc.c
F: mm/debug_page_ref.c
@ -17770,6 +17800,9 @@ F: mm/page_reporting.h
F: mm/show_mem.c
F: mm/shuffle.c
F: mm/shuffle.h
F: scripts/gdb/linux/page_owner.py
F: tools/mm/page_owner_filter.c
F: tools/mm/page_owner_sort.c
MEMORY MANAGEMENT - RECLAIM
M: Andrew Morton <akpm@linux-foundation.org>
@ -17781,11 +17814,11 @@ R: Shakeel Butt <shakeel.butt@linux.dev>
R: Lorenzo Stoakes <ljs@kernel.org>
L: linux-mm@kvack.org
S: Maintained
F: include/trace/events/vmscan.h
F: mm/vmscan.c
F: mm/workingset.c
MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Rik van Riel <riel@surriel.com>
@ -17796,6 +17829,7 @@ R: Jann Horn <jannh@google.com>
R: Lance Yang <lance.yang@linux.dev>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: include/linux/rmap.h
F: mm/interval_tree.c
F: mm/page_vma_mapped.c
@ -17810,6 +17844,54 @@ S: Maintained
F: include/linux/secretmem.h
F: mm/secretmem.c
MEMORY MANAGEMENT - SHARED MEMORY (SHMEM/TMPFS/MEMFD)
M: Hugh Dickins <hughd@google.com>
M: David Hildenbrand <david@kernel.org>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/filesystems/tmpfs.rst
F: Documentation/mm/shmfs.rst
F: Documentation/userspace-api/mfd_noexec.rst
F: include/linux/memfd.h
F: include/linux/shmem_fs.h
F: include/uapi/linux/memfd.h
F: mm/memfd.c
F: mm/shmem.c
F: mm/shmem_quota.c
F: tools/testing/selftests/memfd/
F: tools/testing/selftests/tmpfs/
MEMORY MANAGEMENT - SLAB ALLOCATOR
M: Vlastimil Babka <vbabka@kernel.org>
M: Harry Yoo <harry@kernel.org>
R: Hao Li <hao.li@linux.dev>
R: Christoph Lameter <cl@gentwo.org>
R: David Rientjes <rientjes@google.com>
R: Roman Gushchin <roman.gushchin@linux.dev>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/slab.git slab/for-next
F: Documentation/ABI/testing/sysfs-kernel-slab
F: Documentation/admin-guide/mm/slab.rst
F: Documentation/mm/slab.rst
F: include/linux/mempool.h
F: include/linux/slab.h
F: include/trace/events/kmem.h
F: lib/tests/slub_kunit.c
F: mm/failslab.c
F: mm/mempool.c
F: mm/slab.h
F: mm/slab_common.c
F: mm/slub.c
F: scripts/gdb/linux/slab.py
F: tools/cgroup/memcg_slabinfo.py
F: tools/include/linux/slab.h
F: tools/lib/slab.c
F: tools/mm/slabinfo-gnuplot.sh
F: tools/mm/slabinfo.c
MEMORY MANAGEMENT - SWAP
M: Andrew Morton <akpm@linux-foundation.org>
M: Chris Li <chrisl@kernel.org>
@ -17829,14 +17911,13 @@ F: include/linux/swapfile.h
F: include/linux/swapops.h
F: mm/page_io.c
F: mm/swap.h
F: mm/swap_table.h
F: mm/swap_state.c
F: mm/swap_table.h
F: mm/swapfile.c
MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Zi Yan <ziy@nvidia.com>
M: Zi Yan <ziy@nvidia.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
R: Liam R. Howlett <liam@infradead.org>
R: Nico Pache <nico.pache@linux.dev>
@ -17848,17 +17929,18 @@ R: Usama Arif <usama.arif@linux.dev>
R: Kiryl Shutsemau <kas@kernel.org>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
F: Documentation/ABI/testing/sysfs-kernel-mm-transparent-hugepage
F: Documentation/admin-guide/mm/transhuge.rst
F: include/linux/huge_mm.h
F: include/linux/khugepaged.h
F: include/trace/events/huge_memory.h
F: include/trace/events/thp.h
F: mm/collapse.h
F: mm/huge_memory.c
F: mm/khugepaged.c
F: mm/mm_slot.h
F: tools/mm/thpmaps
F: tools/testing/selftests/mm/khugepaged.c
F: tools/testing/selftests/mm/split_huge_page_test.c
F: tools/testing/selftests/mm/transhuge-stress.c
@ -17902,10 +17984,16 @@ L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: mm/char-mem.c
F: include/trace/events/mmap.h
F: Documentation/core-api/protection-keys.rst
F: Documentation/filesystems/mmap_prepare.rst
F: Documentation/userspace-api/mseal.rst
F: fs/proc/task_mmu.c
F: fs/proc/task_nommu.c
F: include/linux/mman.h
F: include/linux/pkeys.h
F: include/trace/events/mmap.h
F: include/uapi/linux/mman.h
F: mm/char-mem.c
F: mm/mincore.c
F: mm/mlock.c
F: mm/mmap.c
@ -18743,6 +18831,7 @@ M: Peter Zijlstra <peterz@infradead.org>
L: linux-arch@vger.kernel.org
L: linux-mm@kvack.org
S: Maintained
F: Documentation/core-api/cachetlb.rst
F: arch/*/include/asm/tlb.h
F: include/asm-generic/tlb.h
F: include/trace/events/tlb.h
@ -20924,7 +21013,7 @@ S: Maintained
F: drivers/char/hw_random/optee-rng.c
OP-TEE RTC DRIVER
M: Clément Léger <clement.leger@bootlin.com>
M: Clément Léger <clement.leger@linux.dev>
L: linux-rtc@vger.kernel.org
S: Maintained
F: drivers/rtc/rtc-optee.c
@ -21853,6 +21942,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
F: arch/*/include/asm/percpu.h
F: include/linux/percpu*.h
F: include/trace/events/percpu.h
F: lib/percpu*.c
F: mm/percpu*.c
F: mm/percpu-internal.h
@ -23823,7 +23913,7 @@ F: Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
F: drivers/rtc/rtc-renesas-rtca3.c
RENESAS RZ/N1 A5PSW SWITCH DRIVER
M: Clément Léger <clement.leger@bootlin.com>
M: Clément Léger <clement.leger@linux.dev>
L: linux-renesas-soc@vger.kernel.org
L: netdev@vger.kernel.org
S: Maintained
@ -25579,6 +25669,7 @@ F: include/linux/shrinker.h
F: mm/list_lru.c
F: mm/shrinker.c
F: mm/shrinker_debug.c
F: tools/cgroup/memcg_shrinker.py
SH_VOU V4L2 OUTPUT DRIVER
L: linux-media@vger.kernel.org
@ -25800,34 +25891,6 @@ S: Maintained
F: Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml
F: drivers/nvmem/layouts/sl28vpd.c
SLAB ALLOCATOR
M: Vlastimil Babka <vbabka@kernel.org>
M: Harry Yoo <harry@kernel.org>
M: Andrew Morton <akpm@linux-foundation.org>
R: Hao Li <hao.li@linux.dev>
R: Christoph Lameter <cl@gentwo.org>
R: David Rientjes <rientjes@google.com>
R: Roman Gushchin <roman.gushchin@linux.dev>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/slab.git
F: Documentation/admin-guide/mm/slab.rst
F: Documentation/mm/slab.rst
F: include/linux/mempool.h
F: include/linux/slab.h
F: lib/tests/slub_kunit.c
F: mm/failslab.c
F: mm/mempool.c
F: mm/slab.h
F: mm/slab_common.c
F: mm/slub.c
F: scripts/gdb/linux/slab.py
F: tools/cgroup/memcg_slabinfo.py
F: tools/include/linux/slab.h
F: tools/lib/slab.c
F: tools/mm/slabinfo-gnuplot.sh
F: tools/mm/slabinfo.c
SLCAN CAN NETWORK DRIVER
M: Dario Binacchi <dario.binacchi@amarulasolutions.com>
L: linux-can@vger.kernel.org
@ -28245,17 +28308,6 @@ S: Maintained
F: Documentation/hwmon/tmp513.rst
F: drivers/hwmon/tmp513.c
TMPFS (SHMEM FILESYSTEM)
M: Hugh Dickins <hughd@google.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
L: linux-mm@kvack.org
S: Maintained
F: include/linux/memfd.h
F: include/linux/shmem_fs.h
F: mm/memfd.c
F: mm/shmem.c
F: mm/shmem_quota.c
TOMOYO SECURITY MODULE
M: Kentaro Takeda <takedakn@nttdata.co.jp>
M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
@ -28662,7 +28714,7 @@ F: arch/m68k/coldfire/
F: arch/m68k/include/asm/*_no.*
UDF FILESYSTEM
M: Jan Kara <jack@suse.com>
M: Jan Kara <jack@suse.cz>
S: Maintained
F: Documentation/filesystems/udf.rst
F: fs/udf/
@ -29610,9 +29662,12 @@ F: drivers/block/virtio_blk.c
F: drivers/crypto/virtio/
F: drivers/vdpa/
F: drivers/virtio/
F: include/linux/device-id/virtio.h
F: include/linux/vdpa.h
F: include/linux/virtio*.h
F: include/linux/vringh.h
F: include/uapi/linux/vdpa.h
F: include/uapi/linux/vduse.h
F: include/uapi/linux/virtio_*.h
F: net/vmw_vsock/virtio*
F: tools/virtio/
@ -29686,6 +29741,7 @@ F: drivers/vhost/
F: include/linux/sched/vhost_task.h
F: include/linux/vhost_iotlb.h
F: include/uapi/linux/vhost.h
F: include/uapi/linux/vhost_types.h
F: kernel/vhost_task.c
VIRTIO HOST (VHOST-SCSI)
@ -29879,9 +29935,11 @@ S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: include/linux/vmalloc.h
F: include/trace/events/vmalloc.h
F: lib/test_vmalloc.c
F: mm/vmalloc.c
F: mm/vmalloc.h
F: lib/test_vmalloc.c
F: scripts/gdb/linux/vmalloc.py
VME SUBSYSTEM
L: linux-kernel@vger.kernel.org

View File

@ -17,16 +17,10 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
str x7, [sp, #80]
/*
* Stack depth was passed in BPF_REG_AX (x9), add it to the BPF_FP
* (x25) to get the pointer to count and timestamp and pass it as the
* first argument in x0.
*
* Before generating the call to arch_bpf_timed_may_goto, the verifier
* generates a load instruction using FP, i.e. REG_AX = *(u64 *)(FP -
* stack_off_cnt), so BPF_REG_FP (x25) is always set up by the arm64
* jit in this case.
* The pointer to count and timestamp was passed in BPF_REG_AX (x9),
* pass it as the first argument in x0.
*/
add x0, x9, x25
mov x0, x9
bl bpf_check_timed_may_goto
/* BPF_REG_AX(x9) will be stored into count, so move return value to it. */
mov x9, x0

View File

@ -22,14 +22,10 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
st.d a4, sp, 48
/*
* BPF_REG_AX (t0) holds the offset passed in by the verifier;
* add it to BPF_REG_FP (s4) to get the pointer to the count and
* timestamp, then pass it as the first argument in a0.
*
* The verifier emits a load using FP right before this call,
* so BPF_REG_FP (s4) is always set up by the JIT in this case.
* BPF_REG_AX (t0) holds the pointer to the count and timestamp;
* pass it as the first argument in a0.
*/
add.d a0, t0, s4
move a0, t0
bl bpf_check_timed_may_goto
/* BPF_REG_AX (t0) will be stored into count, so move the return value to it. */
move t0, a0

View File

@ -35,6 +35,7 @@ DECLARE_EXPORT(__divsi3);
DECLARE_EXPORT(__umodsi3);
DECLARE_EXPORT(__modsi3);
DECLARE_EXPORT(__muldi3);
DECLARE_EXPORT(__mulsi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
DECLARE_EXPORT(__lshrdi3);

View File

@ -8,7 +8,7 @@
* arch_bpf_timed_may_goto() trampoline for powerpc64
*
* Custom BPF convention (verifier/JIT):
* - input: stack offset in BPF_REG_AX (r12)
* - input: pointer to count and timestamp in BPF_REG_AX (r12)
* - output: updated count in BPF_REG_AX (r12)
*
* Call bpf_check_timed_may_goto(ptr) with normal powerpc64 ABI:
@ -31,11 +31,8 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
std r7, 64(r1)
std r8, 72(r1)
/*
* r3 = BPF_REG_FP + BPF_REG_AX
* BPF_REG_FP is r31; BPF_REG_AX is r12 (stack offset in bytes).
*/
add r3, r31, r12
/* r3 = BPF_REG_AX (r12) */
mr r3, r12
bl CFUNC(bpf_check_timed_may_goto)
/* Put return value back into AX */

View File

@ -6,13 +6,11 @@
/*
* Trampoline for the BPF timed may_goto loop bound. Custom calling convention:
* - input: stack offset in BPF_REG_AX (t0)
* - input: pointer to count and timestamp in BPF_REG_AX (t0)
* - output: updated count in BPF_REG_AX (t0)
*
* Calls bpf_check_timed_may_goto(ptr) with the standard RISC-V ABI, where
* ptr = BPF_REG_FP (s5) + BPF_REG_AX (t0). BPF R0-R5 (t6, a0-a4) and stack
* arguments 6-8 (a5-a7) are saved across the call; BPF_REG_FP (s5) is
* callee-saved and needs no saving.
* Calls bpf_check_timed_may_goto(ptr) with the standard RISC-V ABI. BPF R0-R5
* (t6, a0-a4) and stack arguments 6-8 (a5-a7) are saved across the call.
*/
SYM_FUNC_START(arch_bpf_timed_may_goto)
@ -33,7 +31,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
REG_S a6, 7*SZREG(sp)
REG_S a7, 8*SZREG(sp)
add a0, t0, s5
mv a0, t0
call bpf_check_timed_may_goto
mv t0, a0

View File

@ -1005,6 +1005,17 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
(jit->prg - patch_brc) >> 1;
break;
}
if (insn_is_mov_percpu_addr(insn)) {
const u64 *percpu_offset = &get_lowcore()->percpu_offset;
if (dst_reg != src_reg)
/* lgr %dst,%src */
EMIT4(0xb9040000, dst_reg, src_reg);
/* ag %dst,percpu_offset */
EMIT6_DISP_LH(0xe3000000, 0x0008, dst_reg, REG_0, REG_0,
(unsigned long)percpu_offset);
break;
}
switch (insn->off) {
case 0: /* DST = SRC */
/* lgr %dst,%src */
@ -1866,9 +1877,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
if ((void *)func == arch_bpf_timed_may_goto) {
/*
* arch_bpf_timed_may_goto() has a special ABI: the
* parameters are in BPF_REG_AX and BPF_REG_10; the
* return value is in BPF_REG_AX; and all GPRs except
* REG_W0, REG_W1, and BPF_REG_AX are callee-saved.
* parameter is in BPF_REG_AX; the return value is in
* BPF_REG_AX; and all GPRs except REG_W0, REG_W1, and
* BPF_REG_AX are callee-saved.
*/
/* brasl %r0,func */
@ -2428,8 +2439,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
fp->jited_len = jit.size - cfi_get_offset();
if (!fp->is_func || extra_pass) {
for (int i = 0; i < fp->len; i++)
jit.addrs[i] -= cfi_get_offset();
bpf_prog_fill_jited_linfo(fp, jit.addrs + 1);
free_addrs:
kvfree(jit.addrs);
@ -3116,6 +3125,11 @@ bool bpf_jit_supports_timed_may_goto(void)
return true;
}
bool bpf_jit_supports_percpu_insn(void)
{
return true;
}
bool bpf_jit_inlines_helper_call(s32 imm)
{
switch (imm) {

View File

@ -21,9 +21,9 @@
SYM_FUNC_START(arch_bpf_timed_may_goto)
/*
* This function has a special ABI: the parameters are in %r12 and
* %r13; the return value is in %r12; all GPRs except %r0, %r1, and
* %r12 are callee-saved; and the return address is in %r0.
* This function has a special ABI: the parameter is in %r12; the
* return value is in %r12; all GPRs except %r0, %r1, and %r12 are
* callee-saved; and the return address is in %r0.
*/
stmg %r2,%r5,FRAME_OFF+R2_OFF(%r15)
stg %r14,FRAME_OFF+R14_OFF(%r15)
@ -33,7 +33,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
lay %r15,-FRAME_SIZE(%r15)
stg %r1,__SF_BACKCHAIN(%r15)
lay %r2,0(%r12,%r13)
lgr %r2,%r12
brasl %r14,bpf_check_timed_may_goto
lgr %r12,%r2

View File

@ -286,9 +286,9 @@ SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL)
RET
1:
testb $1, %al
jz 2f
andq $0xfffffffffffffffe, %rax
/* See ftrace_jmp_set(), jmp to the trampoline */
btsq $63, %rax
jc 2f
movq %rax, MCOUNT_REG_SIZE+8(%rsp)
restore_mcount_regs
/* Restore flags */

View File

@ -2359,6 +2359,16 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm *kvm,
continue;
}
/*
* Note! Unlike fully direct MMUs, direct SPs in indirect MMUs
* can have an arbitrary number of parents, e.g if the guest is
* mapping a huge PTE at many points in its page tables.
*/
if (pte_list_count(&sp->parent_ptes) >= RMAP_RECYCLE_THRESHOLD) {
kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
break;
}
/* unsync and write-flooding only apply to indirect SPs. */
if (sp->role.direct)
goto out;

View File

@ -339,6 +339,13 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
gpa_t real_gpa;
gfn_t gfn;
/*
* KVM might sleep/resched when retrying the walk if the updating A/D
* fails because the gPTE changed between reading the gPTE and trying
* the CMPXHG to set A/D bits.
*/
might_sleep();
trace_kvm_mmu_pagetable_walk(addr, access);
retry_walk:
walker->level = w->cpu_role.base.level;
@ -481,8 +488,10 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
addr, write_fault);
if (unlikely(ret < 0))
goto error;
else if (ret)
else if (ret) {
cond_resched();
goto retry_walk;
}
}
return 1;

View File

@ -1889,6 +1889,21 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
/* 'clean' and 'hv_enlightenments' are not changed by KVM */
}
bool nested_svm_check_vmcb01_save(struct kvm_vcpu *vcpu,
struct vmcb_save_area *save)
{
struct vmcb_save_area_cached save_cached;
if (!(save->cr0 & X86_CR0_PG) ||
!(save->cr0 & X86_CR0_PE) ||
(save->rflags & X86_EFLAGS_VM) ||
((save->efer & EFER_LMA) && !(save->efer & EFER_LME)))
return false;
__nested_copy_vmcb_save_to_cache(&save_cached, save);
return nested_vmcb_check_save(vcpu, &save_cached, false);
}
static int svm_get_nested_state(struct kvm_vcpu *vcpu,
struct kvm_nested_state __user *user_kvm_nested_state,
u32 user_data_size)
@ -1968,7 +1983,6 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
&user_kvm_nested_state->data.svm[0];
struct vmcb_control_area *ctl;
struct vmcb_save_area *save;
struct vmcb_save_area_cached save_cached;
struct vmcb_ctrl_area_cached ctl_cached;
bool use_separate_l2_pat;
unsigned long cr0;
@ -2040,12 +2054,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
* KVM_GET_NESTED_STATE, and (b) it is not loaded at emulated
* #VMEXIT.
*/
__nested_copy_vmcb_save_to_cache(&save_cached, save);
if (!(save->cr0 & X86_CR0_PG) ||
!(save->cr0 & X86_CR0_PE) ||
(save->rflags & X86_EFLAGS_VM) ||
((save->efer & EFER_LMA) && !(save->efer & EFER_LME)) ||
!nested_vmcb_check_save(vcpu, &save_cached, false))
if (!nested_svm_check_vmcb01_save(vcpu, save))
goto out_free;
/*

View File

@ -5223,6 +5223,8 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
*/
svm_copy_vmrun_state(vcpu, &svm->vmcb01.ptr->save, m_save.map.hva + 0x400);
if (!nested_svm_check_vmcb01_save(vcpu, &svm->vmcb01.ptr->save))
return 1;
/*
* Enter the nested guest now

View File

@ -911,6 +911,8 @@ void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm,
struct vmcb_save_area *save);
void nested_sync_control_from_vmcb02(struct vcpu_svm *svm);
bool nested_svm_check_vmcb01_save(struct kvm_vcpu *vcpu,
struct vmcb_save_area *save);
void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb);

View File

@ -136,6 +136,8 @@ static __always_inline int evmcs_field_offset(unsigned long field,
if (unlikely(index >= nr_evmcs_1_fields))
return -ENOENT;
index = array_index_nospec(index, nr_evmcs_1_fields);
evmcs_field = &vmcs_field_to_evmcs_1[index];
/*

View File

@ -5059,6 +5059,7 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu)
__func__, j, h.index, h.value);
goto vmabort;
}
break;
}
}

View File

@ -6558,10 +6558,12 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
} else if (vcpu->arch.complete_userspace_io) {
writeback = false;
r = 0;
} else if (r == EMULATION_RESTART)
} else if (r == EMULATION_RESTART) {
cond_resched();
goto restart;
else
} else {
r = 1;
}
writeback:
if (writeback) {
@ -9730,29 +9732,31 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
kvm_x86_call(update_exception_bitmap)(vcpu);
/*
* On the standard CR0/CR4/EFER modification paths, there are several
* complex conditions determining whether the MMU has to be reset and/or
* which PCIDs have to be flushed. However, CR0.WP and the paging-related
* bits in CR4 and EFER are irrelevant if CR0.PG was '0'; and a reset+flush
* is needed anyway if CR0.PG was '1' (which can only happen for INIT, as
* CR0 will be '0' prior to RESET). So we only need to check CR0.PG here.
* Unconditionally reset the MMU, even though super strictly speaking,
* a MMU reset is only necessary if and only one of the page role bits
* is changing. All of the CR0/CR4/EFER bits effectively get covered
* by checking CR0.PG=1, as CR0.WP and the paging-related bits in CR4
* and EFER are irrelevant if CR0.PG was '0'. Subtly, if the vCPU was
* in guest mode (L2) or SMM (although emulating INIT in SMM _should_
* be impossible), an MMU reset is also necessary as "guest mode" and
* "smm" are both encoded in the shadow page role. As a result, the
* only scenarios where an MMU reset is *not* needed is if the vCPU is
* in Real Mode or Unpaged Protected Mode, and micro-optimizing those
* paths are not worth the risk of running with a stale MMU context.
*/
if (old_cr0 & X86_CR0_PG) {
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
kvm_mmu_reset_context(vcpu);
}
kvm_mmu_reset_context(vcpu);
/*
* Intel's SDM states that all TLB entries are flushed on INIT. AMD's
* APM states the TLBs are untouched by INIT, but it also states that
* the TLBs are flushed on "External initialization of the processor."
* Flush the guest TLB regardless of vendor, there is no meaningful
* benefit in relying on the guest to flush the TLB immediately after
* INIT. A spurious TLB flush is benign and likely negligible from a
* performance perspective.
* Intel's SDM states that all TLB entries are flushed on INIT "as with
* a hardware reset", and AMD's APM states the TLBs are flushed on
* "External initialization of the processor". Flush the guest TLB for
* both RESET and INIT, regardless of vendor, even though both the SDM
* and APM contradict the above statements in other tables. There is
* no meaningful benefit in relying on the guest to flush the TLB, and
* a spurious TLB flush is benign and likely negligible from a
* performance perspective (especially for RESET).
*/
if (init_event)
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_reset);

View File

@ -2626,8 +2626,13 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
* Arg 6 goes into r9 register, not on stack.
*/
outgoing_rsp = out_stack_arg_cnt > 1 ? (out_stack_arg_cnt - 1) * 8 : 0;
/*
* bpf_throw() sees rsp of this frame as it is at a call. The callee-saved
* regs are above the outgoing args, or above r9, which is pushed around
* every call when the stack is private.
*/
if (bpf_prog->aux->exception_boundary)
bpf_prog->aux->stack_arg_sp_adjust = outgoing_rsp;
bpf_prog->aux->stack_arg_sp_adjust = outgoing_rsp + (priv_frame_ptr ? 8 : 0);
emit_sub_rsp(&prog, outgoing_rsp);
if (arena_vm_start)
@ -3436,18 +3441,6 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
ip += emit_kfunc_arg_moves(fm, outgoing_arg_base -
outgoing_rsp, &prog);
}
if (func == (u8 *)arch_bpf_timed_may_goto) {
u32 fp = priv_frame_ptr ? X86_REG_R9 : BPF_REG_FP;
/*
* AX has the offset of count and timestamp
* in the stack. Turn it into a pointer.
* add r10, rbp or add r10, r9
*/
maybe_emit_mod(&prog, BPF_REG_AX, fp, true);
EMIT2(0x01, add_2reg(0xC0, BPF_REG_AX, fp));
ip += 3;
}
if (priv_frame_ptr) {
push_r9(&prog);
ip += 2;

View File

@ -25,10 +25,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
/* Save stack argument 6. */
pushq %r9
/*
* r10 has the pointer to count and timestamp. JIT added the frame
* pointer to the offset. Pass it as first argument.
*/
/* r10 has the pointer to count and timestamp. Pass it as first argument. */
movq %r10, %rdi
/* Emit call depth accounting for call below. */

View File

@ -1022,6 +1022,30 @@ static int init_vq(struct virtio_blk *vblk)
goto out;
for (i = 0; i < num_vqs; i++) {
unsigned int ring_size = virtqueue_get_vring_size(vqs[i]);
/*
* Each request consumes 2 extra descriptors (out_hdr and
* in_hdr) in addition to the data segments.
*
* At initial probe (!vblk->disk), each virtqueue must fit at
* least 1 data segment + 2 header descriptors (3).
* On resume/recovery (vblk->disk), each virtqueue must fit the
* existing queue_max_segments() + 2 header descriptors.
*/
unsigned int min_ring_size = 3;
if (vblk->disk)
min_ring_size = queue_max_segments(vblk->disk->queue) + 2;
if (ring_size < min_ring_size) {
dev_err(&vdev->dev,
"virtqueue %u ring size %u is smaller than minimum %u\n",
i, ring_size, min_ring_size);
vdev->config->del_vqs(vdev);
err = -EINVAL;
goto out;
}
spin_lock_init(&vblk->vqs[i].lock);
vblk->vqs[i].vq = vqs[i];
}
@ -1254,7 +1278,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk,
u16 min_io_size;
u8 physical_block_exp, alignment_offset;
size_t max_dma_size;
int err;
int err, i;
/* We need to know how many segments before we allocate. */
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
@ -1268,6 +1292,23 @@ static int virtblk_read_limits(struct virtio_blk *vblk,
/* Prevent integer overflows and honor max vq size */
sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
/*
* virtblk_add_req() uses separate outgoing and incoming header
* descriptors (out_hdr and in_hdr), consuming 2 extra descriptors
* per request in addition to the data segments.
*
* Per virtio specification (2.7.5.3.1), a driver MUST NOT create a
* descriptor chain longer than the Queue Size of the device.
*
* Clamp max_segments to (ring_size - 2) across all virtqueues so
* that a request never exceeds the ring size of any queue.
*/
for (i = 0; i < vblk->num_vqs; i++) {
u32 ring_size = virtqueue_get_vring_size(vblk->vqs[i].vq);
sg_elems = min_t(u32, sg_elems, ring_size - 2);
}
/* We can handle whatever the host told us to handle. */
lim->max_segments = sg_elems;
@ -1467,6 +1508,7 @@ static int virtblk_probe(struct virtio_device *vdev)
mutex_init(&vblk->vdev_mutex);
vblk->vdev = vdev;
vblk->disk = NULL;
INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
@ -1548,6 +1590,7 @@ static int virtblk_probe(struct virtio_device *vdev)
return 0;
out_cleanup_disk:
virtio_reset_device(vdev);
put_disk(vblk->disk);
out_free_tags:
blk_mq_free_tag_set(&vblk->tag_set);

View File

@ -318,8 +318,10 @@ struct xen_blkif {
unsigned int nr_ring_pages;
bool multi_ref;
/* All rings for this device. */
rwlock_t rings_lock;
struct xen_blkif_ring *rings;
unsigned int nr_rings;
unsigned long buffer_squeeze_end;
};

View File

@ -127,14 +127,23 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
return;
}
static int xen_blkif_alloc_rings(struct xen_blkif *blkif)
static int xen_blkif_alloc_rings(struct xen_blkif *blkif,
unsigned int nr_rings)
{
unsigned int r;
struct xen_blkif_ring *rings;
blkif->rings = kzalloc_objs(struct xen_blkif_ring, blkif->nr_rings);
if (!blkif->rings)
rings = kzalloc_objs(struct xen_blkif_ring, nr_rings);
if (!rings)
return -ENOMEM;
write_lock(&blkif->rings_lock);
blkif->rings = rings;
blkif->nr_rings = nr_rings;
write_unlock(&blkif->rings_lock);
for (r = 0; r < blkif->nr_rings; r++) {
struct xen_blkif_ring *ring = &blkif->rings[r];
@ -174,6 +183,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
blkif->domid = domid;
atomic_set(&blkif->refcnt, 1);
init_completion(&blkif->drain_complete);
rwlock_init(&blkif->rings_lock);
/*
* Because freeing back to the cache may be deferred, it is not
@ -268,6 +278,7 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
struct pending_req *req, *n;
unsigned int j, r;
bool busy = false;
struct xen_blkif_ring *rings;
for (r = 0; r < blkif->nr_rings; r++) {
struct xen_blkif_ring *ring = &blkif->rings[r];
@ -334,10 +345,16 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
* blkif->rings was allocated in connect_ring, so we should free it in
* here.
*/
kfree(blkif->rings);
write_lock(&blkif->rings_lock);
rings = blkif->rings;
blkif->rings = NULL;
blkif->nr_rings = 0;
write_unlock(&blkif->rings_lock);
kfree(rings);
return 0;
}
@ -385,6 +402,7 @@ void xen_blkif_interface_fini(void)
unsigned int i; \
unsigned long long result = 0; \
\
read_lock(&blkif->rings_lock); \
if (!blkif->rings) \
goto out; \
\
@ -395,6 +413,7 @@ void xen_blkif_interface_fini(void)
} \
\
out: \
read_unlock(&blkif->rings_lock); \
return sprintf(buf, format, result); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
@ -1102,8 +1121,7 @@ static int connect_ring(struct backend_info *be)
requested_num_queues, xenblk_max_queues);
return -ENOSYS;
}
blkif->nr_rings = requested_num_queues;
if (xen_blkif_alloc_rings(blkif))
if (xen_blkif_alloc_rings(blkif, requested_num_queues))
return -ENOMEM;
pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename,

View File

@ -1201,7 +1201,29 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
err = -EINVAL;
while (fw_ptr - fw->data < fw->size) {
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
struct hci_command_hdr *cmd;
size_t remain = fw->size - (fw_ptr - fw->data);
/* Ensure the header fits before dereferencing */
if (frag_len + sizeof(*cmd) > remain) {
bt_dev_err(hdev,
"Firmware buffer overrun at header (frag_len %u, need %zu, remain %zu)",
frag_len, frag_len + sizeof(*cmd), remain);
err = -EINVAL;
goto done;
}
cmd = (void *)(fw_ptr + frag_len);
/* Ensure the full command (header + payload) fits before use */
if (frag_len + sizeof(*cmd) + cmd->plen > remain) {
bt_dev_err(hdev,
"Firmware buffer overrun at payload (frag_len %u, plen %u, need %zu, remain %zu)",
frag_len, cmd->plen,
frag_len + sizeof(*cmd) + cmd->plen, remain);
err = -EINVAL;
goto done;
}
frag_len += sizeof(*cmd) + cmd->plen;

View File

@ -7,6 +7,7 @@
#include <linux/usb.h>
#include <linux/iopoll.h>
#include <linux/overflow.h>
#include <linux/string.h>
#include <linux/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@ -30,7 +31,7 @@
#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
/* It is for mt79xx iso data transmission setting */
#define MTK_ISO_THRESHOLD 264
#define MTK_ISO_THRESHOLD 342
struct btmtk_patch_header {
u8 datetime[16];
@ -1556,8 +1557,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
struct sk_buff *skb;
unsigned long flags;
unsigned int iso_mtu;
int err = 0;
/* The controller reports the largest Data_Total_Length it will send in
* LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that
* command has not completed yet.
*/
iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE;
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
skb = btmtk_data->isopkt_skb;
@ -1565,7 +1573,16 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
int len;
if (!skb) {
skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
/* Drop the endpoint's zero-filled padding before
* allocating an skb for it; a zero Data_Total_Length
* check below would miss a padding remainder
* shorter than an ISO header.
*/
if (mem_is_zero(buffer, count))
break;
skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu,
GFP_ATOMIC);
if (!skb) {
err = -ENOMEM;
break;
@ -1588,7 +1605,24 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
/* Complete ISO header */
hci_skb_expect(skb) = __le16_to_cpu(dlen);
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
if (!hci_skb_expect(skb)) {
/* Zero padding was ruled out above, so a
* zero Data_Total_Length here is invalid.
*/
kfree_skb(skb);
skb = NULL;
err = -EILSEQ;
break;
}
/* Reject a length the controller said it would never
* send. The skb_tailroom() test is kept because a
* fragment started before hdev->iso_mtu was populated
* sits in a smaller skb than iso_mtu now allows.
*/
if (hci_skb_expect(skb) > iso_mtu ||
skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
skb = NULL;
@ -1707,13 +1741,15 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
static int btmtk_usb_isointf_init(struct hci_dev *hdev)
{
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
u8 iso_param[2] = { 0x08, 0x01 };
__le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD);
struct sk_buff *skb;
int err;
spin_lock_init(&btmtk_data->isorxlock);
__set_mtk_intr_interface(hdev);
err = __set_mtk_intr_interface(hdev);
if (err < 0)
return err;
err = btmtk_submit_intr_urb(hdev, GFP_KERNEL);
if (err < 0) {
@ -1722,9 +1758,10 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev)
return err;
}
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param,
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
return PTR_ERR(skb);
}

View File

@ -426,7 +426,8 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
tlv_nvm->data[0] |= 0x80;
/* UART Baud Rate */
if (soc_type >= QCA_WCN3991)
if (soc_type == QCA_WCN3950 ||
soc_type >= QCA_WCN3991)
tlv_nvm->data[1] = nvm_baud_rate;
else
tlv_nvm->data[2] = nvm_baud_rate;

View File

@ -190,6 +190,7 @@ static int probe_common(struct virtio_device *vdev)
err_find:
ida_free(&rng_index_ida, index);
err_ida:
vdev->priv = NULL;
kfree(vi);
return err;
}
@ -198,6 +199,11 @@ static void remove_common(struct virtio_device *vdev)
{
struct virtrng_info *vi = vdev->priv;
if (!vi) {
virtio_reset_device(vdev);
return;
}
vi->hwrng_removed = true;
vi->data_avail = 0;
vi->data_idx = 0;
@ -207,6 +213,7 @@ static void remove_common(struct virtio_device *vdev)
virtio_reset_device(vdev);
vdev->config->del_vqs(vdev);
ida_free(&rng_index_ida, vi->index);
vdev->priv = NULL;
kfree(vi);
}

View File

@ -341,7 +341,7 @@ static int coreboot_cfr_read_value(const struct coreboot_cfr_setting *setting,
int ret;
if (IS_ERR(efi_name))
return PTR_ERR(no_free_ptr(efi_name));
return PTR_ERR(efi_name);
ret = efivar_lock();
if (ret)

View File

@ -114,6 +114,30 @@ void coreboot_driver_unregister(struct coreboot_driver *driver)
}
EXPORT_SYMBOL(coreboot_driver_unregister);
/*
* Whether the memory of a CBMEM entry may be mapped: it must be exclusively
* System RAM, or exclusively Reserved memory, as CBMEM often is on x86, or
* memory that the kernel doesn't know about at all. coreboot leaves CBMEM out
* of the /memory node of the device tree that it passes to FIT payloads, e.g.
* on arm64, and only lists it in the memory reservation block.
*
* Anything else, such as no-map regions on arm64, which are IORESOURCE_MEM
* (see request_standard_resources() in arch/arm64/kernel/setup.c), must not
* be mapped.
*/
static bool cbmem_entry_is_mappable(const struct lb_cbmem_entry *entry)
{
resource_size_t start = entry->address;
size_t size = entry->entry_size;
return region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
IORES_DESC_NONE) == REGION_INTERSECTS ||
region_intersects(start, size, IORESOURCE_MEM,
IORES_DESC_RESERVED) == REGION_INTERSECTS ||
region_intersects(start, size, IORESOURCE_MEM,
IORES_DESC_NONE) == REGION_DISJOINT;
}
static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_t len)
{
int i, ret;
@ -149,23 +173,7 @@ static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_
switch (device->entry.tag) {
case LB_TAG_CBMEM_ENTRY:
/*
* Skip entries that are not exclusively System RAM or
* Reserved memory.
* On ARM64, no-map regions are filtered out as they are
* IORESOURCE_MEM (see request_standard_resources() in
* arch/arm64/kernel/setup.c).
* On x86, CBMEM often resides in standard reserved regions
* (IORES_DESC_RESERVED).
*/
if (region_intersects(device->cbmem_entry.address,
device->cbmem_entry.entry_size,
IORESOURCE_SYSTEM_RAM,
IORES_DESC_NONE) != REGION_INTERSECTS &&
region_intersects(device->cbmem_entry.address,
device->cbmem_entry.entry_size,
IORESOURCE_MEM,
IORES_DESC_RESERVED) != REGION_INTERSECTS) {
if (!cbmem_entry_is_mappable(&device->cbmem_entry)) {
kfree(device);
continue;
}

View File

@ -30,13 +30,6 @@
#define POWER_METER_CAN_CAP (1 << 2)
#define POWER_METER_CAN_NOTIFY (1 << 3)
#define POWER_METER_IS_BATTERY (1 << 8)
#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
/*
* ACPI integers can either be 32-bit or 64-bit wide, so
* we have to check for both values.
*/
#define UNKNOWN_POWER_32 U32_MAX
#define UNKNOWN_POWER_64 U64_MAX
#define METER_NOTIFY_CONFIG 0x80
#define METER_NOTIFY_TRIP 0x81
@ -54,6 +47,15 @@ static bool force_cap_on;
static DEFINE_MUTEX(acpi_notify_lock);
/*
* ACPI integers can either be 32-bit or 64-bit wide, so
* we have to check for both values.
*/
static bool acpi_power_meter_is_unknown(u64 val)
{
return val == U32_MAX || val == U64_MAX;
}
static int can_cap_in_hardware(void)
{
return force_cap_on || cap_in_hardware;
@ -179,9 +181,10 @@ static int update_meter(struct acpi_power_meter_resource *resource)
acpi_status status;
unsigned long local_jiffies = jiffies;
if (time_before(local_jiffies, resource->sensors_last_updated +
if (!acpi_power_meter_is_unknown(resource->caps.sampling_time) &&
time_before(local_jiffies, resource->sensors_last_updated +
msecs_to_jiffies(resource->caps.sampling_time)) &&
resource->sensors_valid)
resource->sensors_valid)
return 0;
status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
@ -377,28 +380,30 @@ static int set_avg_interval(struct acpi_power_meter_resource *resource,
return 0;
}
static int get_power_alarm_state(struct acpi_power_meter_resource *resource,
long *val)
static bool get_power_alarm_state(struct acpi_power_meter_resource *resource)
{
bool alarm = false;
int ret;
if (resource->caps.flags & POWER_METER_CAN_NOTIFY)
alarm = resource->power_alarm;
resource->power_alarm = false;
ret = update_meter(resource);
if (ret)
return ret;
if (ret || acpi_power_meter_is_unknown(resource->power))
return alarm;
/* need to update cap if not to support the notification. */
if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) {
ret = update_cap(resource);
if (ret)
return ret;
resource->power_alarm = resource->power > resource->cap;
*val = resource->power_alarm;
} else {
*val = resource->power_alarm || resource->power > resource->cap;
resource->power_alarm = resource->power > resource->cap;
return false;
}
return 0;
if (acpi_power_meter_is_unknown(resource->cap))
return alarm;
return alarm || resource->power > resource->cap;
}
static umode_t power_meter_is_visible(const void *data,
@ -458,37 +463,47 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type,
ret = update_meter(res);
if (ret)
return ret;
if (res->power == UNKNOWN_POWER_32 || res->power == UNKNOWN_POWER_64)
if (acpi_power_meter_is_unknown(res->power))
return -ENODATA;
*val = res->power * 1000;
break;
case hwmon_power_average_interval_min:
if (acpi_power_meter_is_unknown(res->caps.min_avg_interval))
return -ENODATA;
*val = res->caps.min_avg_interval;
break;
case hwmon_power_average_interval_max:
if (acpi_power_meter_is_unknown(res->caps.max_avg_interval))
return -ENODATA;
*val = res->caps.max_avg_interval;
break;
case hwmon_power_average_interval:
ret = update_avg_interval(res);
if (ret)
return ret;
*val = (res)->avg_interval;
if (acpi_power_meter_is_unknown(res->avg_interval))
return -ENODATA;
*val = res->avg_interval;
break;
case hwmon_power_cap_min:
if (acpi_power_meter_is_unknown(res->caps.min_cap))
return -ENODATA;
*val = res->caps.min_cap * 1000;
break;
case hwmon_power_cap_max:
if (acpi_power_meter_is_unknown(res->caps.max_cap))
return -ENODATA;
*val = res->caps.max_cap * 1000;
break;
case hwmon_power_alarm:
ret = get_power_alarm_state(res, val);
if (ret)
return ret;
*val = get_power_alarm_state(res);
break;
case hwmon_power_cap:
ret = update_cap(res);
if (ret)
return ret;
if (acpi_power_meter_is_unknown(res->cap))
return -ENODATA;
*val = res->cap * 1000;
break;
default:
@ -584,6 +599,8 @@ static ssize_t power1_average_min_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (res->trip[POWER_METER_TRIP_AVERAGE_MIN_IDX] < 0)
return sysfs_emit(buf, "unknown\n");
@ -596,6 +613,8 @@ static ssize_t power1_average_max_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (res->trip[POWER_METER_TRIP_AVERAGE_MAX_IDX] < 0)
return sysfs_emit(buf, "unknown\n");
@ -608,7 +627,9 @@ static ssize_t power1_cap_hyst_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
if (res->caps.hysteresis == UNKNOWN_HYSTERESIS)
guard(mutex)(&res->lock);
if (acpi_power_meter_is_unknown(res->caps.hysteresis))
return sysfs_emit(buf, "unknown\n");
return sysfs_emit(buf, "%llu\n", res->caps.hysteresis * 1000);
@ -619,8 +640,14 @@ static ssize_t power1_accuracy_show(struct device *dev,
char *buf)
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
unsigned int acc = res->caps.accuracy;
unsigned int acc;
guard(mutex)(&res->lock);
if (acpi_power_meter_is_unknown(res->caps.accuracy))
return sysfs_emit(buf, "unknown\n");
acc = res->caps.accuracy;
return sysfs_emit(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
}
@ -630,6 +657,8 @@ static ssize_t power1_is_battery_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
return sysfs_emit(buf, "%u\n",
res->caps.flags & POWER_METER_IS_BATTERY ? 1 : 0);
}
@ -640,6 +669,11 @@ static ssize_t power1_model_number_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->model_number)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->model_number);
}
@ -649,6 +683,11 @@ static ssize_t power1_oem_info_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->oem_info)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->oem_info);
}
@ -658,6 +697,11 @@ static ssize_t power1_serial_number_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->serial_number)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->serial_number);
}
@ -984,6 +1028,8 @@ static int acpi_power_meter_resume(struct device *dev)
{
struct acpi_power_meter_resource *resource = dev_get_drvdata(dev);
guard(mutex)(&resource->lock);
free_capabilities(resource);
read_capabilities(resource);

View File

@ -19,6 +19,7 @@
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/unaligned.h>
@ -132,6 +133,7 @@ static u8 aquaero_secondary_ctrl_report[] = {
#define AQUAERO_FAN_CURRENT_OFFSET 0x06
#define AQUAERO_FAN_POWER_OFFSET 0x08
#define AQUAERO_FAN_SPEED_OFFSET 0x00
#define AQUAERO_MIN_STATUS_REPORT_SIZE (0x18B + AQUAERO_FAN_POWER_OFFSET + sizeof(u16))
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
/* Control report offsets for the Aquaero fan controllers */
@ -155,6 +157,8 @@ static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 };
#define D5NEXT_5V_VOLTAGE 0x39
#define D5NEXT_12V_VOLTAGE 0x37
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
#define D5NEXT_MIN_STATUS_REPORT_SIZE (D5NEXT_PUMP_OFFSET + AQC_FAN_SPEED_OFFSET + \
sizeof(u16))
static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
/* Control report offsets for the D5 Next pump */
@ -179,11 +183,14 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
#define AQUASTREAMULT_MIN_STATUS_REPORT_SIZE (AQUASTREAMULT_PRESSURE_OFFSET + sizeof(u16))
static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
/* Spec and sensor report offset for the Farbwerk RGB controller */
#define FARBWERK_NUM_SENSORS 4
#define FARBWERK_SENSOR_START 0x2f
#define FARBWERK_MIN_STATUS_REPORT_SIZE (FARBWERK_SENSOR_START + \
FARBWERK_NUM_SENSORS * AQC_SENSOR_SIZE)
/* Specs of the Farbwerk 360 RGB controller */
#define FARBWERK360_NUM_SENSORS 4
@ -193,6 +200,8 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
/* Sensor report offsets for the Farbwerk 360 */
#define FARBWERK360_SENSOR_START 0x32
#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a
#define FARBWERK360_MIN_STATUS_REPORT_SIZE (FARBWERK360_VIRTUAL_SENSORS_START + \
FARBWERK360_NUM_VIRTUAL_SENSORS * AQC_SENSOR_SIZE)
/* Control report offsets for the Farbwerk 360 */
#define FARBWERK360_TEMP_CTRL_OFFSET 0x8
@ -209,6 +218,7 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
#define OCTO_SENSOR_START 0x3D
#define OCTO_VIRTUAL_SENSORS_START 0x45
#define OCTO_FLOW_SENSOR_OFFSET 0x7B
#define OCTO_MIN_STATUS_REPORT_SIZE (0xD8 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
/* Control report offsets for the Octo */
@ -229,6 +239,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_SENSOR_START 0x34
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
#define QUADRO_MIN_STATUS_REPORT_SIZE (0x97 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
/* Control report offsets for the Quadro */
@ -248,6 +259,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
#define HIGHFLOWNEXT_CONDUCTIVITY 95
#define HIGHFLOWNEXT_5V_VOLTAGE 97
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
#define HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE (HIGHFLOWNEXT_5V_VOLTAGE_USB + sizeof(u16))
/* Specs of the Leakshield */
#define LEAKSHIELD_NUM_SENSORS 2
@ -263,6 +275,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
#define LEAKSHIELD_FLOW_IN 111
#define LEAKSHIELD_RESERVOIR_VOLUME 313
#define LEAKSHIELD_RESERVOIR_FILLED 311
#define LEAKSHIELD_MIN_STATUS_REPORT_SIZE (LEAKSHIELD_RESERVOIR_VOLUME + sizeof(u16))
/* Specs of the Aquastream XT pump */
#define AQUASTREAMXT_SERIAL_START 0x3a
@ -554,6 +567,7 @@ struct aqc_data {
const char *name;
int status_report_id; /* Used for legacy devices, report is stored in buffer */
u16 min_report_size;
int ctrl_report_id;
int secondary_ctrl_report_id;
int secondary_ctrl_report_size;
@ -599,9 +613,9 @@ struct aqc_data {
u32 speed_input_min[1];
u32 speed_input_target[1];
u32 speed_input_max[1];
u32 power_input[8];
long power_input[8];
u16 voltage_input[8];
u16 current_input[8];
u32 current_input[8];
/* Label values */
const char *const *temp_label;
@ -976,7 +990,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
/* Calculation derived from linear regression */
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
priv->current_input[0] = DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52;
priv->current_input[0] = max(DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52, 0);
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
@ -1006,6 +1020,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
long power;
int ret;
struct aqc_data *priv = dev_get_drvdata(dev);
@ -1070,7 +1085,10 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
}
break;
case hwmon_power:
*val = priv->power_input[channel];
power = READ_ONCE(priv->power_input[channel]);
if (power == -ENODATA)
return -ENODATA;
*val = power;
break;
case hwmon_pwm:
switch (priv->kind) {
@ -1333,6 +1351,8 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
return 0;
priv = hid_get_drvdata(hdev);
if (!priv->min_report_size || size < priv->min_report_size)
return 0;
/* Info provided with every report */
priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
@ -1368,9 +1388,9 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->speed_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->speed);
priv->power_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->power) * 10000;
WRITE_ONCE(priv->power_input[i],
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->power) * 10000);
priv->voltage_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->voltage) * 10;
@ -1410,7 +1430,8 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
WRITE_ONCE(priv->power_input[1],
get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000);
priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
@ -1423,10 +1444,11 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
case highflownext:
/* If external temp sensor is not connected, its power reading is also N/A */
if (priv->temp_input[1] == -ENODATA)
priv->power_input[0] = -ENODATA;
WRITE_ONCE(priv->power_input[0], -ENODATA);
else
priv->power_input[0] =
get_unaligned_be16(data + HIGHFLOWNEXT_POWER) * 1000000;
WRITE_ONCE(priv->power_input[0],
min_t(u64, get_unaligned_be16(data + HIGHFLOWNEXT_POWER) *
1000000ULL, LONG_MAX));
priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10;
priv->voltage_input[1] =
@ -1518,6 +1540,7 @@ static void aqc_debugfs_init(struct aqc_data *priv)
static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct aqc_data *priv;
u16 min_report_size = 0;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
@ -1554,7 +1577,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
* they present. The two other devices have the type of the second element in
* their respective collections set to 1, while the real device has it set to 0.
*/
if (hdev->collection[1].type != 0) {
if (hdev->maxcollection < 2 || hdev->collection[1].type != 0) {
ret = -ENODEV;
goto fail_and_close;
}
@ -1585,6 +1608,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = AQUAERO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_D5NEXT:
priv->kind = d5next;
@ -1610,6 +1634,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_d5next_power;
priv->voltage_label = label_d5next_voltages;
priv->current_label = label_d5next_current;
min_report_size = D5NEXT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_FARBWERK:
priv->kind = farbwerk;
@ -1620,6 +1645,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
priv->temp_label = label_temp_sensors;
min_report_size = FARBWERK_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_FARBWERK360:
priv->kind = farbwerk360;
@ -1636,6 +1662,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_label = label_temp_sensors;
priv->virtual_temp_label = label_virtual_temp_sensors;
min_report_size = FARBWERK360_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_OCTO:
priv->kind = octo;
@ -1665,6 +1692,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = OCTO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_QUADRO:
priv->kind = quadro;
@ -1694,6 +1722,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = QUADRO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_HIGHFLOWNEXT:
priv->kind = highflownext;
@ -1711,6 +1740,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->speed_label = label_highflownext_fan_speed;
priv->power_label = label_highflownext_power;
priv->voltage_label = label_highflownext_voltage;
min_report_size = HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_LEAKSHIELD:
/*
@ -1730,6 +1760,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_label = label_leakshield_temp_sensors;
priv->speed_label = label_leakshield_fan_speed;
min_report_size = LEAKSHIELD_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_AQUASTREAMXT:
priv->kind = aquastreamxt;
@ -1760,6 +1791,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_aquastreamult_power;
priv->voltage_label = label_aquastreamult_voltages;
priv->current_label = label_aquastreamult_current;
min_report_size = AQUASTREAMULT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_POWERADJUST3:
priv->kind = poweradjust3;
@ -1833,6 +1865,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
break;
}
priv->min_report_size = min_report_size;
if (priv->buffer_size != 0) {
priv->checksum_start = 0x01;
priv->checksum_length = priv->buffer_size - 3;

View File

@ -50,6 +50,7 @@ static const struct rog_ryujin_device_info rog_ryujin_iii_info = {
#define MAX_REPORT_LENGTH 65
/* Cooler duty report offsets */
#define RYUJIN_PUMP_SOURCE 3
#define RYUJIN_PUMP_DUTY 4
#define RYUJIN_INTERNAL_FAN_DUTY 5
@ -70,10 +71,15 @@ static const u8 get_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x9A };
static const u8 get_controller_speed_cmd[] = { RYUJIN_CMD_PREFIX, 0xA0 };
static const u8 get_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0xA1 };
#define RYUJIN_SET_COOLER_CHANNEL_OFFSET 2
#define RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET 3
#define RYUJIN_SET_COOLER_FAN_DUTY_OFFSET 4
static const u8 set_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x1A, 0x00, 0x00, 0x00 };
/* Pump control sources in the set cooler duty command and the cooler duty report */
#define RYUJIN_SOURCE_HEADER 0
#define RYUJIN_SOURCE_USB 1
#define RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET 4
static const u8 set_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x21, 0x00, 0x00, 0x00 };
@ -117,6 +123,7 @@ struct rog_ryujin_data {
s32 temp_input[1];
u16 speed_input[6]; /* Pump, internal fan and four controller fan speeds in RPM */
u8 duty_input[3]; /* Pump, internal fan and controller fan duty in PWM */
u8 pump_source; /* Pump control source from the cooler duty report */
u8 *buffer;
unsigned long updated; /* jiffies */
@ -200,16 +207,23 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
/* Send command for getting data */
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
if (ret < 0)
return ret;
goto out_complete;
ret = wait_for_completion_interruptible_timeout(status_completion,
msecs_to_jiffies(STATUS_VALIDITY));
if (ret == 0)
return -ETIMEDOUT;
else if (ret < 0)
return ret;
ret = -ETIMEDOUT;
if (ret < 0)
goto out_complete;
return 0;
out_complete:
spin_lock_irqsave(&priv->status_report_request_lock, flags);
if (!completion_done(status_completion))
complete_all(status_completion);
spin_unlock_irqrestore(&priv->status_report_request_lock, flags);
return ret;
}
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
@ -306,6 +320,44 @@ static int rog_ryujin_read_string(struct device *dev, enum hwmon_sensor_types ty
return 0;
}
/*
* On devices with a non-zero duty_channel (the RYUJIN III), the channel byte of
* the set cooler duty command selects the pump control source.
* RYUJIN_SOURCE_HEADER hands the pump to its internal controller, which follows
* the PWM of the header its 4-pin cable is plugged into. RYUJIN_SOURCE_USB
* makes the pump follow the pump duty in the command. The cooler duty report
* returns the current source.
*
* A fan duty write sends the reported source back, so that it leaves the pump
* control source as it is. A pump duty write selects USB. The cooler does not
* pass on a pump duty equal to the one it reports, and after power-on it
* reports 40% while a pump handed over at that duty runs at full speed. So
* when a pump duty write asks for the reported duty, write a duty 1% away
* first.
*/
static int rog_ryujin_select_pump_source(struct rog_ryujin_data *priv, u8 *set_cmd,
int channel)
{
u8 duty = set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET];
int ret;
if (channel == 1) {
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->pump_source;
return 0;
}
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = RYUJIN_SOURCE_USB;
if (duty != rog_ryujin_pwm_to_percent(priv->duty_input[0]))
return 0;
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty < 100 ? duty + 1 : duty - 1;
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty;
return ret;
}
static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
{
u8 set_cmd[SET_CMD_LENGTH];
@ -323,7 +375,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
set_cmd[2] = priv->info->duty_channel;
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->info->duty_channel;
/* Cooler duties are set as 0-100% */
val = rog_ryujin_pwm_to_percent(val);
@ -340,6 +392,12 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
}
if (priv->info->duty_channel) {
ret = rog_ryujin_select_pump_source(priv, set_cmd, channel);
if (ret < 0)
return ret;
}
return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
} else {
/*
@ -482,6 +540,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
goto unlock;
}
read_cooler_duty:
priv->pump_source = data[RYUJIN_PUMP_SOURCE];
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
@ -578,6 +637,18 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
init_completion(&priv->cooler_duty_set);
init_completion(&priv->controller_duty_set);
/*
* Start completions in the completed state so rog_ryujin_raw_event()
* only sees !completion_done() while rog_ryujin_execute_cmd() is
* awaiting a response.
*/
complete_all(&priv->cooler_status_received);
complete_all(&priv->controller_status_received);
complete_all(&priv->cooler_duty_received);
complete_all(&priv->controller_duty_received);
complete_all(&priv->cooler_duty_set);
complete_all(&priv->controller_duty_set);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin",
priv, &rog_ryujin_chip_info, NULL);
if (IS_ERR(priv->hwmon_dev)) {

View File

@ -164,6 +164,7 @@ struct asus_wmi_wmi_info {
struct asus_wmi_sensors {
struct asus_wmi_wmi_info wmi;
struct hwmon_chip_info chip_info;
/* lock access to internal cache */
struct mutex lock;
};
@ -496,11 +497,6 @@ static const struct hwmon_ops asus_wmi_hwmon_ops = {
.read_string = asus_wmi_hwmon_read_string,
};
static struct hwmon_chip_info asus_wmi_chip_info = {
.ops = &asus_wmi_hwmon_ops,
.info = NULL,
};
static int asus_wmi_configure_sensor_setup(struct device *dev,
struct asus_wmi_sensors *sensor_data)
{
@ -508,7 +504,7 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
struct hwmon_channel_info *asus_wmi_hwmon_chan;
int nr_count[hwmon_max] = {}, nr_types = 0;
struct asus_wmi_sensor_info *temp_sensor;
const struct hwmon_chip_info *chip_info;
struct hwmon_chip_info *chip_info;
enum hwmon_sensor_types type;
struct device *hwdev;
int i, idx;
@ -549,8 +545,9 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
if (!ptr_asus_wmi_ci)
return -ENOMEM;
asus_wmi_chip_info.info = ptr_asus_wmi_ci;
chip_info = &asus_wmi_chip_info;
chip_info = &sensor_data->chip_info;
chip_info->ops = &asus_wmi_hwmon_ops;
chip_info->info = ptr_asus_wmi_ci;
sensor_data->wmi.info_by_id = devm_kcalloc(dev, sensor_data->wmi.sensor_count,
sizeof(*sensor_data->wmi.info_by_id),

View File

@ -20,7 +20,9 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/unaligned.h>
#include <linux/regulator/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
@ -90,6 +92,9 @@ struct cc2_data {
int irq_low;
int irq_high;
bool process_irqs;
/* protects process_irqs and the alarm indicators */
struct mutex irq_lock;
bool regulator_enabled;
};
/* %RH as a per cent mille from a register value */
@ -118,20 +123,33 @@ static int cc2_enable(struct cc2_data *data)
{
int ret;
/* exclusive regulator, check in case a disable failed */
if (regulator_is_enabled(data->regulator))
return 0;
if (data->irq_ready > 0) {
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = false;
/* clear any pending completion */
try_wait_for_completion(&data->complete);
synchronize_irq(data->irq_ready);
scoped_guard(mutex, &data->irq_lock)
reinit_completion(&data->complete);
}
/* exclusive regulator, check in case a disable failed */
if (data->regulator_enabled) {
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = true;
return 0;
}
ret = regulator_enable(data->regulator);
if (ret < 0)
return ret;
data->regulator_enabled = true;
usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
data->process_irqs = true;
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = true;
return 0;
}
@ -140,15 +158,36 @@ static void cc2_disable(struct cc2_data *data)
{
int err;
/* let the alarms already raised by the last measurement be processed */
if (data->irq_low > 0)
synchronize_irq(data->irq_low);
if (data->irq_high > 0)
synchronize_irq(data->irq_high);
/* ignore alarms triggered by voltage toggling when powering up */
data->process_irqs = false;
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = false;
if (data->irq_ready > 0)
synchronize_irq(data->irq_ready);
/* exclusive regulator, check in case an enable failed */
if (regulator_is_enabled(data->regulator)) {
err = regulator_disable(data->regulator);
if (err)
dev_dbg(&data->client->dev, "Failed to disable device");
if (!data->regulator_enabled)
return;
err = regulator_disable(data->regulator);
if (err) {
dev_dbg(&data->client->dev, "Failed to disable device");
return;
}
data->regulator_enabled = false;
}
static void cc2_disable_action(void *data)
{
cc2_disable(data);
}
static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
@ -167,13 +206,13 @@ static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
case CC2_RESPONSE_BUSY:
return -EBUSY;
case CC2_RESPONSE_NACK:
if (resp & CC2_ERR_CORR_EEPROM)
if (status & CC2_ERR_CORR_EEPROM)
dev_dbg(dev, "Command failed: corrected EEPROM\n");
if (resp & CC2_ERR_UNCORR_EEPROM)
if (status & CC2_ERR_UNCORR_EEPROM)
dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
if (resp & CC2_ERR_RAM_PARITY)
if (status & CC2_ERR_RAM_PARITY)
dev_dbg(dev, "Command failed: RAM parity\n");
if (resp & CC2_ERR_RAM_PARITY)
if (status & CC2_ERR_CONFIG_LOAD)
dev_dbg(dev, "Command failed: configuration error\n");
return -ENODATA;
default:
@ -226,7 +265,7 @@ static int cc2_command_mode_start(struct cc2_data *data)
2 * CC2_RESP_START_CM_US);
}
ret = cc2_read_command_status(data->client);
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES)
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES - 1)
break;
/* command window missed, prepare for a retry */
@ -260,8 +299,7 @@ static int cc2_write_reg(struct cc2_data *data, u8 reg, u16 val)
if (ret < 0)
goto disable;
cpu_to_be16s(&val);
ret = i2c_smbus_write_word_data(data->client, reg, val);
ret = i2c_smbus_write_word_swapped(data->client, reg, val);
if (ret < 0)
goto disable;
@ -311,7 +349,7 @@ static int cc2_read_reg(struct cc2_data *data, u8 reg, u16 *val)
if (ret != CC2_EEPROM_DATA_LEN)
return ret < 0 ? ret : -EIO;
*val = be16_to_cpup((__be16 *)&buf[1]);
*val = get_unaligned_be16(&buf[1]);
return cc2_read_command_status(data->client);
}
@ -351,10 +389,10 @@ static int cc2_data_fetch(struct i2c_client *client,
switch (type) {
case hwmon_humidity:
*val = cc2_rh_convert(be16_to_cpup((__be16 *)&data[0]));
*val = cc2_rh_convert(get_unaligned_be16(&data[0]));
break;
case hwmon_temp:
*val = cc2_temp_convert(be16_to_cpup((__be16 *)&data[2]));
*val = cc2_temp_convert(get_unaligned_be16(&data[2]));
break;
default:
return -EINVAL;
@ -482,8 +520,10 @@ static irqreturn_t cc2_ready_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs)
complete(&cc2->complete);
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs)
complete(&cc2->complete);
}
return IRQ_HANDLED;
}
@ -492,10 +532,12 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_min_alarm, 0);
cc2->rh_alarm.low_alarm = true;
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_min_alarm, 0);
cc2->rh_alarm.low_alarm = true;
}
}
return IRQ_HANDLED;
@ -505,10 +547,12 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_max_alarm, 0);
cc2->rh_alarm.high_alarm = true;
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_max_alarm, 0);
cc2->rh_alarm.high_alarm = true;
}
}
return IRQ_HANDLED;
@ -524,11 +568,13 @@ static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
if (ret < 0)
return ret;
if (data->rh_alarm.low_alarm) {
*val = (measurement < min_hyst) ? 1 : 0;
data->rh_alarm.low_alarm = *val;
} else {
*val = 0;
scoped_guard(mutex, &data->irq_lock) {
if (data->rh_alarm.low_alarm) {
*val = (measurement < min_hyst) ? 1 : 0;
data->rh_alarm.low_alarm = *val;
} else {
*val = 0;
}
}
return 0;
@ -544,11 +590,13 @@ static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
if (ret < 0)
return ret;
if (data->rh_alarm.high_alarm) {
*val = (measurement > max_hyst) ? 1 : 0;
data->rh_alarm.high_alarm = *val;
} else {
*val = 0;
scoped_guard(mutex, &data->irq_lock) {
if (data->rh_alarm.high_alarm) {
*val = (measurement > max_hyst) ? 1 : 0;
data->rh_alarm.high_alarm = *val;
} else {
*val = 0;
}
}
return 0;
@ -631,28 +679,47 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
}
}
static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
static int cc2_get_irqs(struct cc2_data *data, struct device *dev)
{
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
if (data->irq_ready == -EPROBE_DEFER)
return data->irq_ready;
if (data->irq_ready > 0)
init_completion(&data->complete);
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
if (data->irq_low == -EPROBE_DEFER)
return data->irq_low;
if (data->irq_low > 0)
data->rh_alarm.low_alarm_visible = true;
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
if (data->irq_high == -EPROBE_DEFER)
return data->irq_high;
if (data->irq_high > 0)
data->rh_alarm.high_alarm_visible = true;
return 0;
}
static int cc2_request_data_ready(struct cc2_data *data, struct device *dev)
{
int ret = 0;
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
if (data->irq_ready > 0) {
init_completion(&data->complete);
if (data->irq_ready > 0)
ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
cc2_ready_interrupt,
IRQF_ONESHOT |
IRQF_TRIGGER_RISING,
dev_name(dev), data);
}
return ret;
}
static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
{
int ret = 0;
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
if (data->irq_low > 0) {
ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
cc2_low_interrupt,
@ -661,11 +728,8 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
dev_name(dev), data);
if (ret)
return ret;
data->rh_alarm.low_alarm_visible = true;
}
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
if (data->irq_high > 0) {
ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
cc2_high_interrupt,
@ -674,8 +738,6 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
dev_name(dev), data);
if (ret)
return ret;
data->rh_alarm.high_alarm_visible = true;
}
return ret;
@ -717,6 +779,8 @@ static int cc2_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
mutex_init(&data->irq_lock);
data->client = client;
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
@ -726,14 +790,18 @@ static int cc2_probe(struct i2c_client *client)
device_property_read_string(dev, "label", &data->label);
ret = cc2_request_ready_irq(data, dev);
ret = cc2_get_irqs(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to get IRQs\n");
ret = devm_add_action_or_reset(dev, cc2_disable_action, data);
if (ret)
return ret;
ret = cc2_request_data_ready(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request ready irq\n");
ret = cc2_request_alarm_irqs(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
data, &cc2_chip_info,
NULL);
@ -741,16 +809,13 @@ static int cc2_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(data->hwmon),
"Failed to register hwmon device\n");
ret = cc2_request_alarms(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
return 0;
}
static void cc2_remove(struct i2c_client *client)
{
struct cc2_data *data = i2c_get_clientdata(client);
cc2_disable(data);
}
static const struct i2c_device_id cc2_id[] = {
{ .name = "cc2d23" },
{ .name = "cc2d23s" },
@ -783,7 +848,6 @@ static struct i2c_driver cc2_driver = {
.of_match_table = cc2_of_match,
},
.probe = cc2_probe,
.remove = cc2_remove,
.id_table = cc2_id,
};
module_i2c_driver(cc2_driver);

View File

@ -76,7 +76,7 @@ struct temp_data {
int temp;
bool temp_valid;
int tjmax;
unsigned long last_updated;
u64 last_updated;
unsigned int cpu;
int index;
u32 cpu_core_id;
@ -407,7 +407,7 @@ static ssize_t show_temp(struct device *dev,
mutex_lock(&tdata->update_lock);
/* Check whether the time interval has elapsed */
if (time_after(jiffies, tdata->last_updated + HZ)) {
if (time_after64(get_jiffies_64(), tdata->last_updated + HZ)) {
tjmax = get_tjmax(tdata, dev);
rdmsrq_on_cpu(tdata->cpu, tdata->status_reg, &val.q);
/*
@ -417,7 +417,7 @@ static ssize_t show_temp(struct device *dev,
*/
tdata->temp_valid = (val.l >> 31) & 1;
tdata->temp = tjmax - ((val.l >> 16) & 0xff) * 1000;
tdata->last_updated = jiffies;
tdata->last_updated = get_jiffies_64();
}
valid = tdata->temp_valid;
@ -491,11 +491,12 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
struct temp_data *tdata;
if (!pdata->core_data) {
pdata->nr_cores = topology_num_cores_per_package();
pdata->core_data = kzalloc_objs(struct temp_data *,
pdata->nr_cores);
int nr_cores = topology_num_cores_per_package();
pdata->core_data = kzalloc_objs(struct temp_data *, nr_cores);
if (!pdata->core_data)
return NULL;
pdata->nr_cores = nr_cores;
}
tdata = kzalloc_obj(struct temp_data);
@ -520,11 +521,8 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
tdata->cpu = cpu;
tdata->cpu_core_id = topology_core_id(cpu);
tdata->attr_size = MAX_CORE_ATTRS;
/*
* A zero timestamp does not look stale on 32-bit, where jiffies
* starts just short of wrapping. Backdate it instead.
*/
tdata->last_updated = jiffies - HZ - 1;
/* Backdate to force a refresh on the first read */
tdata->last_updated = get_jiffies_64() - HZ - 1;
mutex_init(&tdata->update_lock);
return tdata;
}
@ -695,6 +693,9 @@ static int coretemp_cpu_online(unsigned int cpu)
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
return 0;
if (!pdev)
return 0;
pdata = platform_get_drvdata(pdev);
if (!pdata->hwmon_dev) {
struct device *hwmon;
@ -746,6 +747,9 @@ static int coretemp_cpu_offline(unsigned int cpu)
return 0;
/* If the physical CPU device does not exist, just return */
if (!pdev)
return 0;
pd = platform_get_drvdata(pdev);
if (!pd->hwmon_dev)
return 0;

View File

@ -215,10 +215,11 @@ static int set_target(struct ccp_device *ccp, int channel, long val)
int ret;
val = clamp_val(val, 0, 0xFFFF);
ccp->target[channel] = val;
mutex_lock(&ccp->mutex);
ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
if (!ret)
ccp->target[channel] = val;
mutex_unlock(&ccp->mutex);
return ret;

View File

@ -444,6 +444,7 @@ static void gpd_duo_set_pwm_enable(struct gpd_fan_data *data, enum FAN_PWM_ENABL
break;
case AUTOMATIC:
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write, 0);
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write + 1, 0);
break;
}
}

View File

@ -150,7 +150,10 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
if (fan_data->speed_index > 0 && speed_index == 0) {
/* The GPIOs have changed, and a PM put drops the reference on error. */
fan_data->speed_index = speed_index;
if (speed_index == 0) {
int ret;
ret = pm_runtime_put_sync(fan_data->dev);
@ -158,8 +161,6 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
return ret;
}
fan_data->speed_index = speed_index;
return 0;
}

View File

@ -390,6 +390,7 @@ struct hp_wmi_info {
*/
struct hp_wmi_sensors {
struct wmi_device *wdev;
struct hwmon_chip_info chip_info;
struct hp_wmi_info **info_map[hwmon_max];
u8 channel_count[hwmon_max];
bool has_intrusion;
@ -738,15 +739,21 @@ static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
val = current_reading;
for (; unit_modifier < target_modifier; unit_modifier++)
for (; val && unit_modifier < target_modifier; unit_modifier++)
val = DIV_ROUND_CLOSEST(val, 10);
for (; unit_modifier > target_modifier; unit_modifier--) {
if (val > LONG_MAX / 10) {
val = LONG_MAX;
break;
if (val) {
for (; unit_modifier > target_modifier; unit_modifier--) {
if (val > LONG_MAX / 10) {
val = LONG_MAX;
break;
}
if (val < LONG_MIN / 10) {
val = LONG_MIN;
break;
}
val *= 10;
}
val *= 10;
}
if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
@ -1473,8 +1480,10 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
(type == hwmon_fan && attr == hwmon_fan_alarm)) {
mutex_lock(&state->lock);
*out_val = info->alarm ? 1 : 0;
info->alarm = false;
mutex_unlock(&state->lock);
return 0;
}
@ -1531,11 +1540,6 @@ static const struct hwmon_ops hp_wmi_hwmon_ops = {
.write = hp_wmi_hwmon_write,
};
static struct hwmon_chip_info hp_wmi_chip_info = {
.ops = &hp_wmi_hwmon_ops,
.info = NULL,
};
static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
const char *event_description)
{
@ -1962,7 +1966,8 @@ static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
if (!ptr_channel_info)
return -ENOMEM;
hp_wmi_chip_info.info = ptr_channel_info;
state->chip_info.ops = &hp_wmi_hwmon_ops;
state->chip_info.info = ptr_channel_info;
for (type = hwmon_chip; type < hwmon_max; type++) {
count = channel_count[type];
@ -2053,7 +2058,7 @@ static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
return err;
hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
state, &hp_wmi_chip_info,
state, &state->chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwdev);
}

View File

@ -123,8 +123,7 @@ struct lm75_data {
static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
#define LM75_ALERT_POLARITY_HIGH_8_BIT (BIT(2))
#define LM75_ALERT_POLARITY_HIGH_16_BIT (BIT(2) << 8)
#define LM75_ALERT_POLARITY_HIGH_BIT BIT(2)
#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
/* The structure below stores the configuration values of the supported devices.
@ -770,11 +769,7 @@ static int lm75_generic_probe(struct device *dev, const char *name,
data->orig_conf = status;
/* Enforce polarity active-low (default) or active-high (devicetree) */
if (!data->params->config_reg_16bits)
pol_mask = LM75_ALERT_POLARITY_HIGH_8_BIT;
else
pol_mask = LM75_ALERT_POLARITY_HIGH_16_BIT;
pol_mask = LM75_ALERT_POLARITY_HIGH_BIT;
clr_mask = data->params->clr_mask | pol_mask;
set_mask = data->params->set_mask & ~pol_mask;
if (device_property_read_bool(dev, "ti,alert-polarity-active-high"))

View File

@ -606,13 +606,16 @@ static DEVICE_ATTR_RO(cpu0_vid);
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm87_data *data = dev_get_drvdata(dev);
struct i2c_client *client = dev_get_drvdata(dev);
struct lm87_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lm87_data *data = dev_get_drvdata(dev);
struct i2c_client *client = dev_get_drvdata(dev);
struct lm87_data *data = i2c_get_clientdata(client);
unsigned long val;
int err;

View File

@ -920,7 +920,7 @@ static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6683_data *data = nct6683_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int index = sattr->index;
return sprintf(buf, "%d\n", data->pwm[index]);
@ -930,7 +930,7 @@ static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct nct6683_data *data = dev_get_drvdata(dev);
int index = sattr->index;
unsigned long val;

View File

@ -4,7 +4,6 @@
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/devm-helpers.h>
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/module.h>
@ -326,11 +325,13 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
if (ret == -ENODEV) {
dev_dbg(priv->dev, "No DIMMs found\n");
return 0;
} else if (ret) {
}
if (ret == -EAGAIN) {
schedule_delayed_work(&priv->detect_work, DIMM_MASK_CHECK_DELAY_JIFFIES);
dev_dbg(priv->dev, "Deferred populating DIMM temp info\n");
return ret;
}
if (ret)
return ret;
channels = priv->gen_info->chan_rank_max * priv->gen_info->dimm_idx_max;
@ -398,10 +399,8 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
"Unexpected PECI revision %#x, some features may be unavailable\n",
peci_dev->info.peci_revision);
ret = devm_delayed_work_autocancel(priv->dev, &priv->detect_work,
create_dimm_temp_info_delayed);
if (ret)
return ret;
auxiliary_set_drvdata(adev, priv);
INIT_DELAYED_WORK(&priv->detect_work, create_dimm_temp_info_delayed);
ret = create_dimm_temp_info(priv);
if (ret && ret != -EAGAIN) {
@ -412,6 +411,13 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
return 0;
}
static void peci_dimmtemp_remove(struct auxiliary_device *adev)
{
struct peci_dimmtemp *priv = auxiliary_get_drvdata(adev);
cancel_delayed_work_sync(&priv->detect_work);
}
static int
read_thresholds_hsx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
{
@ -665,6 +671,7 @@ MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids);
static struct auxiliary_driver peci_dimmtemp_driver = {
.probe = peci_dimmtemp_probe,
.remove = peci_dimmtemp_remove,
.id_table = peci_dimmtemp_ids,
};

View File

@ -1524,14 +1524,22 @@ static int pmbus_thermal_add_sensor(struct pmbus_data *pmbus_data,
tdata->sensor = sensor;
tdata->pmbus_data = pmbus_data;
tzd = devm_thermal_of_zone_register(dev, index, tdata,
/*
* The PMBus core numbers its temperature sensors from 1, as the
* hwmon tempN attributes, while the thermal core expects a 0-based
* sensor index.
*/
tzd = devm_thermal_of_zone_register(dev, index - 1, tdata,
&pmbus_thermal_ops);
/*
* If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
* so ignore that error but forward any other error.
* If CONFIG_THERMAL_OF is disabled, devm_thermal_of_zone_register()
* returns -ENOTSUPP. If no thermal zone is configured for the sensor,
* it returns -ENODEV. Ignore those errors but forward any other error.
*/
if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV))
if (IS_ERR(tzd) && PTR_ERR(tzd) != -ENODEV && PTR_ERR(tzd) != -ENOTSUPP) {
devm_kfree(dev, tdata);
return PTR_ERR(tzd);
}
return 0;
}
@ -1546,10 +1554,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
{
struct sensor_device_attribute *a;
struct pmbus_sensor *sensor;
int err;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return NULL;
return ERR_PTR(-ENOMEM);
a = &sensor->attribute;
if (type)
@ -1574,14 +1583,17 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
pmbus_set_sensor, -1);
if (pmbus_add_attribute(data, &a->dev_attr.attr))
return NULL;
return ERR_PTR(-ENOMEM);
sensor->next = data->sensors;
data->sensors = sensor;
/* temperature sensors with _input values are registered with thermal */
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0)
pmbus_thermal_add_sensor(data, sensor, seq);
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0) {
err = pmbus_thermal_add_sensor(data, sensor, seq);
if (err)
return ERR_PTR(err);
}
return sensor;
}
@ -1682,8 +1694,8 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
page, 0xff, l->reg, attr->class,
attr->update || l->update,
l->readonly, l->writeonly, true);
if (!curr)
return -ENOMEM;
if (IS_ERR(curr))
return PTR_ERR(curr);
if (l->sbit && (info->func[page] & attr->sfunc)) {
ret = pmbus_add_boolean(data, name,
l->alarm, index,
@ -1722,8 +1734,8 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
}
base = pmbus_add_sensor(data, name, "input", index, page, phase,
attr->reg, attr->class, true, true, false, true);
if (!base)
return -ENOMEM;
if (IS_ERR(base))
return PTR_ERR(base);
/* No limit and alarm attributes for phase specific sensors */
if (attr->sfunc && phase == 0xff) {
ret = pmbus_add_limit_attrs(client, data, info, name,
@ -2396,8 +2408,8 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
false, false, false, true);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
if (!((data->info->func[page] & PMBUS_HAVE_PWM12) ||
(data->info->func[page] & PMBUS_HAVE_PWM34)))
@ -2407,15 +2419,15 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
false, false, false, true);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
true, false, false, false);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
return 0;
}
@ -2432,6 +2444,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
int f;
for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
struct pmbus_sensor *sensor;
int regval;
if (!(info->func[page] & pmbus_fan_flags[f]))
@ -2452,10 +2465,11 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
continue;
if (pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
PSC_FAN, true, true, false, true) == NULL)
return -ENOMEM;
sensor = pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
PSC_FAN, true, true, false, true);
if (IS_ERR(sensor))
return PTR_ERR(sensor);
/* Fan control */
if (pmbus_check_word_register(client, page,

View File

@ -351,6 +351,8 @@ static int q54sj108a2_probe(struct i2c_client *client)
psu->client = client;
debugfs = pmbus_get_debugfs_dir(client);
if (!debugfs)
return 0;
q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);

View File

@ -31,6 +31,7 @@
#include <linux/bitrev.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/workqueue.h>
/* Commands */
#define SHT15_MEASURE_TEMP 0x03
@ -976,25 +977,22 @@ static int sht15_probe(struct platform_device *pdev)
goto err_release_reg;
}
ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
sht15_interrupt_fired,
IRQF_TRIGGER_FALLING,
"sht15 data",
data);
ret = request_irq(gpiod_to_irq(data->data), sht15_interrupt_fired,
IRQF_TRIGGER_FALLING, "sht15 data", data);
if (ret)
goto err_release_reg;
disable_irq_nosync(gpiod_to_irq(data->data));
ret = sht15_connection_reset(data);
if (ret)
goto err_release_reg;
goto err_free_irq;
ret = sht15_soft_reset(data);
if (ret)
goto err_release_reg;
goto err_free_irq;
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");
goto err_release_reg;
goto err_free_irq;
}
data->hwmon_dev = hwmon_device_register(data->dev);
@ -1007,9 +1005,13 @@ static int sht15_probe(struct platform_device *pdev)
err_release_sysfs_group:
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
err_free_irq:
disable_work_sync(&data->read_work);
free_irq(gpiod_to_irq(data->data), data);
err_release_reg:
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
return ret;
@ -1023,12 +1025,16 @@ static void sht15_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
disable_work_sync(&data->read_work);
free_irq(gpiod_to_irq(data->data), data);
ret = sht15_soft_reset(data);
if (ret)
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
}

View File

@ -111,7 +111,9 @@ static int sht4x_read_values(struct sht4x_data *data)
}
if (data->data_pending &&
time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) {
time_before64(get_jiffies_64(),
data->heating_complete +
msecs_to_jiffies(data->update_interval))) {
data->data_pending = false;
} else {
next_update = data->last_updated +

View File

@ -13,7 +13,7 @@
#include <linux/i2c.h>
#include <linux/i3c/device.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -78,7 +78,7 @@
struct tmp108 {
struct regmap *regmap;
u16 orig_config;
u64 ready_time;
ktime_t ready_time;
const struct tmp108_params *params;
};
@ -121,6 +121,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
struct tmp108 *tmp108 = dev_get_drvdata(dev);
unsigned int regval;
int err, hyst;
s64 delay;
if (type == hwmon_chip) {
if (attr == hwmon_chip_update_interval) {
@ -137,12 +138,10 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
switch (attr) {
case hwmon_temp_input:
/* Is it too early to return a conversion ? */
if (time_before64(get_jiffies_64(), tmp108->ready_time)) {
dev_dbg(dev, "%s: Conversion not ready yet..\n",
__func__);
return -EAGAIN;
}
/* Wait if it is too early to return a conversion */
delay = ktime_us_delta(tmp108->ready_time, ktime_get());
if (delay > 0)
usleep_range(delay, delay + 1000);
err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, &regval);
if (err < 0)
return err;
@ -477,11 +476,8 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
return err;
}
tmp108->ready_time = get_jiffies_64();
if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) ==
TMP108_MODE_SHUTDOWN)
tmp108->ready_time +=
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
tmp108->ready_time = ktime_add_ms(ktime_get(),
TMP108_CONVERSION_TIME_MS);
err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108);
if (err) {
@ -528,8 +524,8 @@ static int tmp108_resume(struct device *dev)
err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS);
tmp108->ready_time = get_jiffies_64() +
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
tmp108->ready_time = ktime_add_ms(ktime_get(),
TMP108_CONVERSION_TIME_MS);
return err;
}

View File

@ -1227,12 +1227,12 @@ static int viommu_probe(struct virtio_device *vdev)
/* Populate the event queue with buffers */
ret = viommu_fill_evtq(viommu);
if (ret)
goto err_free_vqs;
goto err_reset_vdev;
ret = iommu_device_sysfs_add(&viommu->iommu, dev, NULL, "%s",
virtio_bus_name(vdev));
if (ret)
goto err_free_vqs;
goto err_reset_vdev;
vdev->priv = viommu;
@ -1244,6 +1244,8 @@ static int viommu_probe(struct virtio_device *vdev)
return 0;
err_reset_vdev:
virtio_reset_device(vdev);
err_free_vqs:
vdev->config->del_vqs(vdev);

View File

@ -2779,6 +2779,27 @@ static void bond_miimon_link_change(struct bonding *bond,
}
}
static bool bond_miimon_slave_down(struct bonding *bond,
struct slave *slave)
{
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
BOND_SLAVE_NOTIFY_NOW);
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
return slave == rcu_access_pointer(bond->curr_active_slave);
}
static void bond_miimon_commit(struct bonding *bond)
{
struct slave *slave, *primary, *active;
@ -2807,10 +2828,22 @@ static void bond_miimon_commit(struct bonding *bond)
err = bond_update_speed_duplex(slave);
netdev_unlock_ops(slave->dev);
if (err && bond_needs_speed_duplex(bond)) {
slave->link = BOND_LINK_DOWN;
if (net_ratelimit())
slave_warn(bond->dev, slave->dev,
"failed to get link speed/duplex\n");
/* Coming from FAIL/UP, the slave may still be
* in use and may be curr_active_slave, so take
* it through the full down path. Coming from
* DOWN/BACK, it was never brought up, so just
* revert it to DOWN.
*/
if (slave->link == BOND_LINK_FAIL ||
slave->link == BOND_LINK_UP) {
if (bond_miimon_slave_down(bond, slave))
do_failover = true;
continue;
}
slave->link = BOND_LINK_DOWN;
continue;
}
bond_set_slave_link_state(slave, BOND_LINK_UP,
@ -2839,28 +2872,13 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
case BOND_LINK_DOWN:
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
BOND_SLAVE_NOTIFY_NOW);
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
if (slave == rcu_access_pointer(bond->curr_active_slave))
if (bond_miimon_slave_down(bond, slave))
do_failover = true;
continue;
case BOND_LINK_FAIL:
case BOND_LINK_BACK:
bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
slave->link_new_state);
continue;
@ -2894,8 +2912,6 @@ static void bond_mii_monitor(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mii_work.work);
struct list_head *iter;
struct slave *slave;
unsigned long delay;
bool commit;
@ -2917,13 +2933,8 @@ static void bond_mii_monitor(struct work_struct *work)
goto re_arm;
}
if (commit) {
bond_for_each_slave(bond, slave, iter) {
bond_commit_link_state(slave,
BOND_SLAVE_NOTIFY_LATER);
}
if (commit)
bond_miimon_commit(bond);
}
if (bond->send_peer_notif)
bond_peer_notify_may_events(bond, true);
@ -3973,18 +3984,13 @@ static int bond_slave_netdev_event(unsigned long event,
case NETDEV_CHANGE:
/* For 802.3ad mode only:
* Getting invalid Speed/Duplex values here will put slave
* in weird state. Mark it as link-fail if the link was
* previously up or link-down if it hasn't yet come up, and
* let link-monitoring (miimon) set it right when correct
* speeds/duplex are available.
* in weird state. Mark an up slave as link-fail and let
* miimon set it right when correct speed/duplex are available.
*/
if (bond_update_speed_duplex(slave) &&
BOND_MODE(bond) == BOND_MODE_8023AD) {
if (slave->last_link_up)
slave->link = BOND_LINK_FAIL;
else
slave->link = BOND_LINK_DOWN;
}
BOND_MODE(bond) == BOND_MODE_8023AD &&
slave->link == BOND_LINK_UP)
slave->link = BOND_LINK_FAIL;
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_adapter_speed_duplex_changed(slave);

View File

@ -720,7 +720,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
return 0;
}
static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
static size_t can_tdc_get_size(const struct net_device *dev,
struct data_bittiming_params *dbt_params,
u32 tdc_flags)
{
bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK;
@ -742,7 +743,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
}
if (tdc_flags) {
if (tdc_manual || dbt_params->do_get_auto_tdcv)
if (tdc_manual ||
(dbt_params->do_get_auto_tdcv && netif_running(dev)))
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
if (dbt_params->tdc_const->tdcf_max)
@ -752,7 +754,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
return size;
}
static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params,
static size_t can_data_bittiming_get_size(const struct net_device *dev,
struct data_bittiming_params *dbt_params,
u32 tdc_flags)
{
size_t size = 0;
@ -764,7 +767,7 @@ static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_para
if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST */
size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) *
dbt_params->data_bitrate_const_cnt);
size += can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
size += can_tdc_get_size(dev, dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
return size;
}
@ -812,7 +815,7 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
if (priv->do_get_berr_counter && netif_running(dev)) /* IFLA_CAN_BERR_COUNTER */
size += nla_total_size(sizeof(struct can_berr_counter));
if (priv->termination_const) {
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
@ -825,10 +828,10 @@ static size_t can_get_size(const struct net_device *dev)
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */
size += can_data_bittiming_get_size(&priv->fd,
size += can_data_bittiming_get_size(dev, &priv->fd,
priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK);
size += can_data_bittiming_get_size(&priv->xl,
size += can_data_bittiming_get_size(dev, &priv->xl,
priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK);
size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */
priv->ctrlmode & CAN_CTRLMODE_XL_TMS);
@ -910,7 +913,7 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev,
if (tdc_manual) {
tdcv = tdc->tdcv;
err = 0;
} else if (dbt_params->do_get_auto_tdcv) {
} else if (dbt_params->do_get_auto_tdcv && netif_running(dev)) {
err = dbt_params->do_get_auto_tdcv(dev, &tdcv);
}
if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
@ -1006,7 +1009,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
(priv->do_get_berr_counter &&
(priv->do_get_berr_counter && netif_running(dev) &&
!priv->do_get_berr_counter(dev, &bec) &&
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||

View File

@ -4,6 +4,7 @@
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
*/
#include <linux/can/can-ml.h>
#include <linux/can/dev.h>
#include <linux/module.h>
#include <net/can.h>
@ -54,6 +55,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
dev_kfree_skb_any(skb);
return -EINVAL;
}
@ -62,7 +64,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD) &&
skb->protocol != htons(ETH_P_CANXL))) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
return 0;
}
@ -90,7 +92,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
} else {
/* locking problem with netif_stop_queue() ?? */
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
kfree_skb(skb);
dev_kfree_skb_any(skb);
return -EBUSY;
}
@ -227,7 +229,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_cc;
}
@ -258,7 +260,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_fd;
}
@ -296,7 +298,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_xl;
}
@ -388,7 +390,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
break;
case ETH_P_CANXL:
if (!can_is_canxl_skb(skb))
if (!can_cap_enabled(dev, CAN_CAP_XL) || !can_is_canxl_skb(skb))
goto inval_skb;
break;
@ -402,7 +404,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
return false;
inval_skb:
kfree_skb(skb);
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return true;
}

View File

@ -755,7 +755,7 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
u16 rx_msg_type, rx_msg_size;
size_t rx_msg_min_size;
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
if (msg_end - msg_ptr < sizeof(rx_msg->size)) {
err = -EBADMSG;
break;
}
@ -766,6 +766,11 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
break;
}
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
err = -EBADMSG;
break;
}
rx_msg_size = le16_to_cpu(rx_msg->size);
rx_msg_type = le16_to_cpu(rx_msg->type);

View File

@ -836,6 +836,59 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
}
EXPORT_SYMBOL(b53_brcm_hdr_setup);
int b53_enable_mcast_snooping(struct b53_device *dev)
{
u16 val16;
u32 val;
int ret;
/* Older switches use different IGMP controls, not HL_PRTC_CTRL. */
if (is5325(dev) || is5365(dev) || dev->chip_id == BCM5389_DEVICE_ID ||
is5397_98(dev) || is63xx(dev))
return 0;
/* IGMPv2 and MLDv1 reports use the group's destination MAC. Once
* the first listener is offloaded, ordinary multicast forwarding
* can keep subsequent reports from reaching the bridge CPU.
*/
/* BCM5395 has a narrower register and a single IGMP classifier.
* Its ICMPv6 classifier also covers MLD.
*/
if (dev->chip_id == BCM5395_DEVICE_ID) {
ret = b53_read16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val16);
if (ret)
return ret;
val16 |= HL_PRTC_IGMP_IP_EN_5395 | HL_PRTC_ICMPV6_EN;
/* Zero forwarding modes copy control traffic to the CPU
* independently of the ARL lookup, retaining L2 forwarding.
*/
val16 &= ~(HL_PRTC_IGMP_FWD_MODE_5395 |
HL_PRTC_ICMPV6_FWD_MODE);
return b53_write16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL,
val16);
}
ret = b53_read32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val);
if (ret)
return ret;
val |= HL_PRTC_IGMP_RPTLVE_EN | HL_PRTC_IGMP_QRY_EN |
HL_PRTC_IGMP_UKN_EN | HL_PRTC_MLD_RPTDONE_EN |
HL_PRTC_MLD_QRY_EN;
/* Zero forwarding modes copy control traffic to the CPU
* independently of the ARL lookup, retaining L2 forwarding.
*/
val &= ~(HL_PRTC_IGMP_RPTLVE_FWD_MODE | HL_PRTC_IGMP_QRY_FWD_MODE |
HL_PRTC_IGMP_UKN_FWD_MODE | HL_PRTC_MLD_RPTDONE_FWD_MODE |
HL_PRTC_MLD_QRY_FWD_MODE);
return b53_write32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, val);
}
EXPORT_SYMBOL(b53_enable_mcast_snooping);
static void b53_enable_cpu_port(struct b53_device *dev, int port)
{
u8 port_ctrl;
@ -1334,6 +1387,10 @@ static int b53_setup(struct dsa_switch *ds)
b53_disable_port(ds, port);
}
ret = b53_enable_mcast_snooping(dev);
if (ret)
return ret;
return b53_setup_devlink_resources(ds);
}
@ -1663,9 +1720,15 @@ static void b53_phylink_mac_link_up(struct phylink_config *config,
}
if (mode == MLO_AN_FIXED) {
/* Force flow control on BCM5301x's CPU port */
if (is5301x(dev) && dsa_is_cpu_port(ds, port))
tx_pause = rx_pause = true;
/* Force flow control and 2Gbits/sec on BCM5301x and NSP CPU
* ports
*/
if ((is5301x(dev) || dev->chip_id == BCM58XX_DEVICE_ID) &&
dsa_is_cpu_port(ds, port)) {
tx_pause = true;
rx_pause = true;
speed = 2000;
}
b53_force_port_config(dev, port, speed, duplex,
tx_pause, rx_pause);

View File

@ -504,6 +504,7 @@ static inline struct gpio_desc *b53_switch_get_reset_gpio(struct b53_device *dev
/* Exported functions towards other drivers */
void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port);
int b53_configure_vlan(struct dsa_switch *ds);
int b53_enable_mcast_snooping(struct b53_device *dev);
void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data);
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);

View File

@ -274,6 +274,23 @@
/* Revision ID register (8 bit) */
#define B53_REV_ID 0x40
/* High-level protocol control (16 bit on BCM5395, otherwise 32 bit) */
#define B53_HL_PRTC_CTRL 0x50
#define HL_PRTC_ICMPV6_EN BIT(4)
#define HL_PRTC_ICMPV6_FWD_MODE BIT(5)
#define HL_PRTC_IGMP_IP_EN_5395 BIT(6)
#define HL_PRTC_IGMP_FWD_MODE_5395 BIT(8)
#define HL_PRTC_IGMP_RPTLVE_EN BIT(9)
#define HL_PRTC_IGMP_RPTLVE_FWD_MODE BIT(10)
#define HL_PRTC_IGMP_QRY_EN BIT(11)
#define HL_PRTC_IGMP_QRY_FWD_MODE BIT(12)
#define HL_PRTC_IGMP_UKN_EN BIT(13)
#define HL_PRTC_IGMP_UKN_FWD_MODE BIT(14)
#define HL_PRTC_MLD_RPTDONE_EN BIT(15)
#define HL_PRTC_MLD_RPTDONE_FWD_MODE BIT(16)
#define HL_PRTC_MLD_QRY_EN BIT(17)
#define HL_PRTC_MLD_QRY_FWD_MODE BIT(18)
/* Broadcom header RX control (16 bit) */
#define B53_BRCM_HDR_RX_DIS 0x60

View File

@ -1059,6 +1059,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
unsigned int port;
int ret;
/* Enable all valid ports and disable those unused */
for (port = 0; port < priv->hw_params.num_ports; port++) {
@ -1074,6 +1075,10 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
b53_configure_vlan(ds);
bcm_sf2_enable_acb(ds);
ret = b53_enable_mcast_snooping(priv->dev);
if (ret)
return ret;
return b53_setup_devlink_resources(ds);
}

View File

@ -1934,6 +1934,39 @@ static int atl1c_clean_rx(struct napi_struct *napi, int budget)
break;
}
atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
/* A link partner whose l2mtu is larger than ours can hand us a
* frame that does not fit the buffer the hardware was given:
* the descriptor reports the untruncated length while at most
* buffer_info->length bytes were written. skb_put() of such a
* length would pull in whatever the tail of the buffer holds
* and, past the end of the skb, trips skb_over_panic and takes
* the host down. Bound it by what the device actually wrote
* rather than by skb_tailroom(): the skb carries 64 bytes of
* slack for the DMA erratum, so the two are not the same.
*
* Frames shorter than an Ethernet header plus its FCS are
* rejected by the same test; before this, a length below
* ETH_FCS_LEN underflowed in skb_put().
*/
if (unlikely(length < ETH_HLEN + ETH_FCS_LEN ||
length > buffer_info->length)) {
dev_core_stats_rx_dropped_inc(netdev);
if (netif_msg_rx_err(adapter))
dev_warn_ratelimited(&pdev->dev,
"dropped rx frame: %u bytes, buffer %u\n",
length, buffer_info->length);
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
/* atl1c_clean_rfd() has already recycled the RFD, so
* count the drop as work: the refill at the end of the
* poll only runs when work_done is non-zero, and
* sustained oversized traffic would otherwise drain the
* ring and stop RX for good.
*/
work_done++;
continue;
}
skb_put(skb, length - ETH_FCS_LEN);
skb->protocol = eth_type_trans(skb, netdev);
atl1c_rx_checksum(adapter, skb, rrs);

View File

@ -243,7 +243,8 @@ static int bgmac_probe(struct platform_device *pdev)
bgmac->phy_connect = platform_phy_connect;
} else {
bgmac->phy_connect = bgmac_phy_connect_direct;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
if (of_machine_is_compatible("brcm,nsp"))
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
}
return bgmac_enet_probe(bgmac);

View File

@ -1430,11 +1430,15 @@ void bgmac_adjust_link(struct net_device *net_dev)
{
struct bgmac *bgmac = netdev_priv(net_dev);
struct phy_device *phy_dev = net_dev->phydev;
int speed = phy_dev->speed;
bool update = false;
if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500)
speed = SPEED_2500;
if (phy_dev->link) {
if (phy_dev->speed != bgmac->mac_speed) {
bgmac->mac_speed = phy_dev->speed;
if (speed != bgmac->mac_speed) {
bgmac->mac_speed = speed;
update = true;
}

View File

@ -11544,6 +11544,7 @@ static int bnxt_change_msix(struct bnxt *bp, int total)
map.index = i - 1;
map.virq = bp->irq_tbl[i - 1].vector;
pci_msix_free_irq(bp->pdev, map);
bp->irq_tbl[i - 1].vector = 0;
bp->total_irqs--;
}
return bp->total_irqs;
@ -11721,8 +11722,23 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
int irqs_required;
int rc;
if (!bnxt_need_reserve_rings(bp))
if (!bnxt_need_reserve_rings(bp)) {
/* FW may already hold the reservation from an earlier
* reservation that was not followed by growing the dynamic
* MSI-X vectors, e.g. because the allocation failed.
*/
if (irq_re_init && BNXT_NEW_RM(bp) && bp->irq_tbl &&
pci_msix_can_alloc_dyn(bp->pdev)) {
irqs_required = bnxt_get_num_msix(bp);
if (irqs_required > bp->total_irqs &&
bnxt_change_msix(bp, irqs_required) != irqs_required) {
netdev_err(bp->dev, "Unable to allocate %d MSIX vectors, maximum available %d\n",
irqs_required, bp->total_irqs);
return -ENOSPC;
}
}
return 0;
}
if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
@ -11748,6 +11764,10 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
rc = bnxt_init_int_mode(bp);
bnxt_ulp_irq_restart(bp, rc);
} else if (irq_change && !rc) {
/* Size the vectors from what FW actually reserved, which
* can be less than what was requested.
*/
irqs_required = bnxt_get_num_msix(bp);
if (bnxt_change_msix(bp, irqs_required) != irqs_required)
rc = -ENOSPC;
}
@ -15113,6 +15133,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
}
if (hwr.cp > bp->total_irqs) {
int old_total = bp->total_irqs;
int total_msix = bnxt_change_msix(bp, hwr.cp);
if (total_msix < hwr.cp) {
@ -15120,6 +15141,17 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp, total_msix);
rc = -ENOSPC;
}
/* FW has not reserved the new vectors yet, and writes to
* MSI-X table entries beyond the reserved IRQs don't
* stick (seen on BCM57508). Free them again;
* bnxt_reserve_rings() allocates them after
* __bnxt_reserve_rings(). Without the new resource
* manager there is no IRQ reservation and
* bnxt_reserve_rings() does not grow the vectors, so
* keep them.
*/
if (BNXT_NEW_RM(bp))
bnxt_change_msix(bp, old_total);
}
}
return rc;

View File

@ -1502,7 +1502,8 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
* all other events are ignored
*/
jwrite32(jme, JME_IEVE, intrstat);
schedule_work(&jme->linkch_task);
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
schedule_work(&jme->linkch_task);
goto out_reenable;
}
@ -1546,7 +1547,8 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
/*
* Re-enable interrupt
*/
jwrite32f(jme, JME_IENS, INTR_ENABLE);
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
jwrite32f(jme, JME_IENS, INTR_ENABLE);
}
static irqreturn_t
@ -1892,6 +1894,7 @@ jme_powersave_phy(struct jme_adapter *jme)
jme_set_100m_half(jme);
if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
jme_wait_link(jme);
jme_mac_rxclk_on(jme);
jme_clear_pm_enable_wol(jme);
} else {
jme_phy_off(jme);
@ -3158,6 +3161,21 @@ jme_shutdown(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct jme_adapter *jme = netdev_priv(netdev);
if (netif_running(netdev)) {
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
netif_device_detach(netdev);
netif_stop_queue(netdev);
jme_stop_irq(jme);
synchronize_irq(pdev->irq);
jme_stop_irq(jme);
cancel_work_sync(&jme->linkch_task);
tasklet_disable(&jme->pcc_task);
napi_disable(&jme->napi);
tasklet_disable(&jme->txclean_task);
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
}
jme_powersave_phy(jme);
pci_pme_active(pdev, true);
}
@ -3172,11 +3190,16 @@ jme_suspend(struct device *dev)
if (!netif_running(netdev))
return 0;
atomic_dec(&jme->link_changing);
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
netif_device_detach(netdev);
netif_stop_queue(netdev);
jme_stop_irq(jme);
synchronize_irq(jme->pdev->irq);
jme_stop_irq(jme);
cancel_work_sync(&jme->linkch_task);
tasklet_disable(&jme->pcc_task);
napi_disable(&jme->napi);
atomic_dec(&jme->link_changing);
tasklet_disable(&jme->txclean_task);
tasklet_disable(&jme->rxclean_task);
@ -3215,6 +3238,7 @@ jme_resume(struct device *dev)
return 0;
jme_clear_pm_disable_wol(jme);
jme_mac_rxclk_off(jme);
jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
jme_set_link_ksettings(netdev, &jme->old_cmd);
@ -3226,8 +3250,11 @@ jme_resume(struct device *dev)
atomic_inc(&jme->link_changing);
jme_reset_link(jme);
napi_enable(&jme->napi);
tasklet_enable(&jme->pcc_task);
clear_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
jme_reset_link(jme);
jme_start_irq(jme);
return 0;

View File

@ -450,6 +450,7 @@ enum jme_flags_bits {
JME_FLAG_SSET = 2,
JME_FLAG_POLL = 5,
JME_FLAG_SHUTDOWN = 6,
JME_FLAG_WOL_QUIESCE = 7,
};
#define TX_TIMEOUT (5 * HZ)

View File

@ -754,8 +754,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
hlist_for_each_entry_safe(entry, n, head, list) {
if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
MTK_FOE_STATE_BIND))
if (entry->hash != hash)
continue;
entry->hash = 0xffff;
@ -764,7 +763,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
}
if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) {
if (entry->hash != 0xffff)
if (entry->hash == hash)
entry->hash = 0xffff;
continue;
}

View File

@ -257,7 +257,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
if (dev->rx_wdma[i].desc)
if (!dev->rx_wdma[i].desc)
continue;
wdma_w32(dev,
@ -949,6 +949,14 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
static void
mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++)
mtk_wed_free_ring(dev, &dev->rx_ring[i]);
for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
mtk_wed_free_rx_buffer(dev);
mtk_wed_free_ring(dev, &dev->rro.ring);
}
@ -1938,7 +1946,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
if (reset)
if (!mtk_wed_is_v3_or_greater(dev->hw) && reset)
mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
if (!idx) {
@ -2337,7 +2345,20 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
if (!dev->rx_wdma[i].desc)
mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
if (mtk_wed_wdma_rx_ring_setup(dev, i, 16, false)) {
dev_err(dev->hw->dev, "wdma rx ring %d setup failed\n", i);
return;
}
/*
* non-DBDC MT7986 allocates only rx_ring[1] and tx_wdma[1] during setup
* but tx_wdma[0] is also needed for WED to function.
*/
if (mtk_wed_is_v2(dev->hw) && !dev->rx_ring[0].desc)
if (mtk_wed_wdma_tx_ring_setup(dev, 0, MTK_WED_WDMA_RING_SIZE, !!dev->tx_wdma[0].desc)) {
dev_err(dev->hw->dev, "wdma tx ring 0 setup failed\n");
return;
}
if (dev->wlan.hw_rro) {
for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {

View File

@ -94,6 +94,7 @@ struct mlx5_fs_id {
refcount_t refcnt;
sci_t sci;
struct rhash_head hash;
struct rcu_head rcu;
};
struct mlx5_macsec_device {
@ -684,7 +685,7 @@ static void macsec_fs_id_del(struct list_head *macsec_devices_list, u32 fs_id,
xa_erase(fs_id_xa, fs_id);
kfree(fs_id_found);
kfree_rcu(fs_id_found, rcu);
if (macsec_fs_is_macsec_device_empty(macsec_device)) {
list_del(&macsec_device->macsec_devices_list_entry);

View File

@ -2072,7 +2072,7 @@ static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn,
fbnic_bdq_set_page_size(&qt->sub1, rx_page_size);
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->sub0.q_idx,
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->cmpl.q_idx,
nv->napi.napi_id);
if (err)
goto free_page_pools;

View File

@ -353,6 +353,12 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
if (!fdma_db_is_done(db))
continue;
/* XDP and page pool APIs can't be used with a budget of 0.
* Leave these buffers for the next NAPI poll.
*/
if (!weight && !dcb_buf->use_skb)
continue;
dcb_buf->dev->stats.tx_packets++;
dcb_buf->dev->stats.tx_bytes += dcb_buf->len;

View File

@ -204,9 +204,10 @@ static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
*rew_op = IFH_REW_OP_TWO_STEP_PTP;
}
static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
static unsigned int sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
{
struct sk_buff *skb, *skb_tmp;
unsigned int purged = 0;
unsigned long flags;
spin_lock_irqsave(&port->tx_skbs.lock, flags);
@ -217,8 +218,11 @@ static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
__skb_unlink(skb, &port->tx_skbs);
dev_kfree_skb_any(skb);
purged++;
}
spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
return purged;
}
int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
@ -226,6 +230,7 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
{
struct sparx5 *sparx5 = port->sparx5;
u8 rew_op, pdu_type, pdu_w16_offset;
unsigned int purged;
unsigned long flags;
sparx5_ptp_classify(port, skb, &rew_op, &pdu_type, &pdu_w16_offset);
@ -236,9 +241,10 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
if (rew_op != IFH_REW_OP_TWO_STEP_PTP)
return 0;
sparx5_ptp_txtstamp_old_release(port);
purged = sparx5_ptp_txtstamp_old_release(port);
spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
sparx5->ptp_skbs -= purged;
if (sparx5->ptp_skbs == SPARX5_MAX_PTP_ID) {
spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
return -EBUSY;

View File

@ -757,6 +757,27 @@ void mana_gd_free_service_wq(struct gdma_context *gc)
gc->service_wq = NULL;
}
static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
{
struct gdma_context *gc = eq->gdma_dev->gdma_context;
struct gdma_queue *cq;
u8 i;
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
cq = rcu_dereference(eq->eq.child_cq[i]);
if (!cq)
continue;
if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
!gc->cq_table || gc->cq_table[cq->id] != cq)
continue;
if (cq->cq.callback)
cq->cq.callback(cq->cq.context, cq);
}
}
static void mana_gd_process_eqe(struct gdma_queue *eq)
{
u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE);
@ -787,6 +808,14 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
break;
case GDMA_EQE_THROTTLE:
u64_stats_update_begin(&eq->eq.stats.syncp);
u64_stats_inc(&eq->eq.stats.throttle_count);
u64_stats_update_end(&eq->eq.stats.syncp);
mana_gd_schedule_eq_cqs(eq);
break;
case GDMA_EQE_TEST_EVENT:
gc->test_event_eq_id = eq->id;
complete(&gc->eq_test_event);
@ -1032,6 +1061,8 @@ static int mana_gd_create_eq(struct gdma_dev *gd,
queue->eq.msix_index = INVALID_PCI_MSIX_INDEX;
queue->id = INVALID_QUEUE_ID;
u64_stats_init(&queue->eq.stats.syncp);
log2_num_entries = ilog2(queue->queue_size / GDMA_EQE_SIZE);
if (spec->eq.log2_throttle_limit > log2_num_entries) {
@ -1073,25 +1104,66 @@ static void mana_gd_create_cq(const struct gdma_queue_spec *spec,
struct gdma_queue *queue)
{
u32 log2_num_entries = ilog2(spec->queue_size / GDMA_CQE_SIZE);
struct gdma_queue *parent;
u8 i;
queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries);
queue->cq.parent = spec->cq.parent_eq;
parent = spec->cq.parent_eq;
queue->cq.parent = parent;
queue->cq.context = spec->cq.context;
queue->cq.callback = spec->cq.callback;
if (!parent)
return;
/* For throttled EQE store the child CQ */
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
if (!rcu_access_pointer(parent->eq.child_cq[i])) {
rcu_assign_pointer(parent->eq.child_cq[i], queue);
return;
}
}
WARN_ONCE(1, "mana: EQ %u has no free child CQ slot\n", parent->id);
}
/* Unlink queue from its parent EQ's child_cq[] and from gc->cq_table[].
*
* Return: true if queue was in the parent EQ's child_cq[]. In that case the
* caller must wait for an RCU grace period before freeing queue, because
* mana_gd_intr() may still be handling a throttle EQE for it.
*/
bool mana_gd_detach_cq(struct gdma_context *gc, struct gdma_queue *queue)
{
struct gdma_queue *eq = queue->cq.parent;
bool attached = false;
u32 id = queue->id;
u8 i;
if (eq) {
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
if (rcu_access_pointer(eq->eq.child_cq[i]) == queue) {
RCU_INIT_POINTER(eq->eq.child_cq[i], NULL);
attached = true;
}
}
}
/* Check if CQ might have been detached already, only clear if
* it still points to same queue .
*/
if (id < gc->max_num_cqs && READ_ONCE(gc->cq_table[id]) == queue)
WRITE_ONCE(gc->cq_table[id], NULL);
return attached;
}
static void mana_gd_destroy_cq(struct gdma_context *gc,
struct gdma_queue *queue)
{
u32 id = queue->id;
if (id >= gc->max_num_cqs)
return;
if (!gc->cq_table[id])
return;
gc->cq_table[id] = NULL;
/* Wait for irq reader holding the cq */
if (mana_gd_detach_cq(gc, queue))
synchronize_net();
}
int mana_gd_create_hwc_queue(struct gdma_dev *gd,

View File

@ -364,7 +364,7 @@ static void mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self)
completions = hwc_cq->comp_buf;
comp_read = mana_gd_poll_cq(q_self, completions, hwc_cq->queue_depth);
WARN_ON_ONCE(comp_read <= 0 || comp_read > hwc_cq->queue_depth);
WARN_ON_ONCE(comp_read < 0 || comp_read > hwc_cq->queue_depth);
for (i = 0; i < comp_read; ++i) {
comp_data = *(struct hwc_rx_oob *)completions[i].cqe_data;
@ -820,9 +820,14 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
*/
if (gc->max_num_cqs > 0) {
mana_smc_teardown_hwc(&gc->shm_channel, false);
gc->max_num_cqs = 0;
WRITE_ONCE(gc->max_num_cqs, 0);
}
if (hwc->cq)
mana_gd_detach_cq(gc, hwc->cq->gdma_cq);
synchronize_rcu();
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);

View File

@ -2703,6 +2703,7 @@ static void mana_deinit_txq(struct mana_port_context *apc, struct mana_txq *txq)
static void mana_destroy_txq(struct mana_port_context *apc)
{
struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
struct napi_struct *napi;
int i;
@ -2721,8 +2722,6 @@ static void mana_destroy_txq(struct mana_port_context *apc)
napi_synchronize(napi);
napi_disable_locked(napi);
cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
/* Forget the SKBs freed without being completed after a drain
@ -2735,6 +2734,18 @@ static void mana_destroy_txq(struct mana_port_context *apc)
if (apc->tx_qp[i]->tx_object != INVALID_MANA_HANDLE)
mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i]->tx_object);
if (apc->tx_qp[i]->txq.napi_initialized) {
/* Detach the CQ only after the WQ object is destroyed,
* so a completion EQE that arrives before then still
* finds the CQ in cq_table[] rather than hitting the
* WARN in mana_gd_process_eqe(). One grace period then
* covers both mana_gd_intr() and NAPI users.
*/
mana_gd_detach_cq(gc, apc->tx_qp[i]->tx_cq.gdma_cq);
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
mana_deinit_cq(apc, &apc->tx_qp[i]->tx_cq);
mana_deinit_txq(apc, &apc->tx_qp[i]->txq);
@ -2941,7 +2952,6 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
napi_disable_locked(napi);
cancel_work_sync(&rxq->rx_cq.dim.work);
netif_napi_del_locked(napi);
}
if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
@ -2950,6 +2960,12 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
if (rxq->rxobj != INVALID_MANA_HANDLE)
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
if (napi_initialized) {
/* See the comment in mana_destroy_txq() */
mana_gd_detach_cq(gc, rxq->rx_cq.gdma_cq);
netif_napi_del_locked(napi);
}
mana_deinit_cq(apc, &rxq->rx_cq);
if (rxq->xdp_save_va)

View File

@ -147,7 +147,8 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
return ARRAY_SIZE(mana_eth_stats) +
ARRAY_SIZE(mana_phy_stats) +
ARRAY_SIZE(mana_hc_stats) +
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT +
MANA_STATS_EQ_COUNT);
case ETH_SS_PRIV_FLAGS:
return MANA_PRIV_FLAG_MAX;
@ -198,6 +199,9 @@ static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
ethtool_sprintf(data, "tx_%d_csum_partial", i);
ethtool_sprintf(data, "tx_%d_mana_map_err", i);
}
for (i = 0; i < num_queues; i++)
ethtool_sprintf(data, "eq_%d_throttle_events", i);
}
static void mana_get_strings_priv_flags(u8 **data)
@ -234,6 +238,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
void *phy_stats = &apc->phy_stats;
struct mana_stats_rx *rx_stats;
struct mana_stats_tx *tx_stats;
struct gdma_eq_stats *eq_stats;
unsigned int start;
u64 packets, bytes;
u64 xdp_redirect;
@ -251,6 +256,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
u64 csum_partial;
u64 mana_map_err;
int q, i = 0, j;
u64 throttled;
if (!apc->port_is_up)
return;
@ -325,6 +331,17 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
data[i++] = csum_partial;
data[i++] = mana_map_err;
}
for (q = 0; q < num_queues; q++) {
eq_stats = &apc->eqs[q].eq->eq.stats;
do {
start = u64_stats_fetch_begin(&eq_stats->syncp);
throttled = u64_stats_read(&eq_stats->throttle_count);
} while (u64_stats_fetch_retry(&eq_stats->syncp, start));
data[i++] = throttled;
}
}
static u32 mana_get_rx_ring_count(struct net_device *ndev)

View File

@ -600,11 +600,11 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
goto out_unlock;
}
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
if (napi_schedule_prep(&cp->napi)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
if (napi_schedule_prep(&cp->napi))
__napi_schedule(&cp->napi);
}
}
if (status & (TxOK | TxErr | TxEmpty | SWInt))
cp_tx(cp);

View File

@ -36,6 +36,7 @@
#include <linux/errno.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pps_kernel.h>
#include <linux/ptp_clock_kernel.h>
#include "net_driver.h"
@ -266,11 +267,12 @@ struct efx_ptp_rxfilter {
* @evt_frag_idx: Current fragment number
* @evt_code: Last event code
* @start: Address at which MC indicates ready for synchronisation
* @host_time_pps: Host time at last PPS
* @adjfreq_ppb_shift: Shift required to convert scaled parts-per-billion
* frequency adjustment into a fixed point fractional nanosecond format.
* @current_adjfreq: Current ppb adjustment.
* @phc_clock: Pointer to registered phc device (if primary function)
* @phc_lock: Serializes PHC commands and synchronization, and protects
* @current_adjfreq
* @phc_clock_info: Registration structure for phc device
* @pps_work: pps work task for handling pps events
* @pps_workwq: pps work queue
@ -326,10 +328,10 @@ struct efx_ptp_data {
int evt_frag_idx;
int evt_code;
struct efx_buffer start;
struct pps_event_time host_time_pps;
unsigned int adjfreq_ppb_shift;
s64 current_adjfreq;
struct ptp_clock *phc_clock;
struct mutex phc_lock;
struct ptp_clock_info phc_clock_info;
struct work_struct pps_work;
struct workqueue_struct *pps_workwq;
@ -907,7 +909,8 @@ static void efx_ptp_read_timeset(MCDI_DECLARE_STRUCT_PTR(data),
static int
efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
size_t response_length,
const struct pps_event_time *last_time)
const struct pps_event_time *last_time,
struct pps_event_time *host_time_pps)
{
unsigned number_readings =
MCDI_VAR_ARRAY_LEN(response_length,
@ -985,6 +988,10 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
"PTP bad synchronisation seconds\n");
return -EAGAIN;
}
if (!host_time_pps)
return 0;
delta.tv_sec = (last_sec - start_sec) & 1;
delta.tv_nsec =
last_time->ts_real.tv_nsec -
@ -1001,14 +1008,22 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
delta.tv_nsec += ktime_to_timespec64(mc_time).tv_nsec;
/* Set PPS timestamp to match NIC top of second */
ptp->host_time_pps = *last_time;
pps_sub_ts(&ptp->host_time_pps, delta);
*host_time_pps = *last_time;
pps_sub_ts(host_time_pps, delta);
return 0;
}
/* Synchronize times between the host and the MC */
static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
/* Synchronize times between the host and the MC.
*
* The MC serializes PTP requests, so MC_CMD_PTP_OP_ADJUST cannot be applied
* while MC_CMD_PTP_OP_SYNCHRONIZE is collecting timesets. This holds across
* functions of a controller, which share the clock but adjust it only through
* the function that registered it, so a secondary function can capture here
* without serializing against the primary.
*/
static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings,
struct pps_event_time *host_time_pps)
{
struct efx_ptp_data *ptp = efx->ptp_data;
MCDI_DECLARE_BUF(synch_buf, MC_CMD_PTP_OUT_SYNCHRONIZE_LENMAX);
@ -1026,11 +1041,14 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
MCDI_SET_QWORD(synch_buf, PTP_IN_SYNCHRONIZE_START_ADDR,
ptp->start.dma_addr);
mutex_lock(&ptp->phc_lock);
/* Clear flag that signals MC ready */
WRITE_ONCE(*start, 0);
rc = efx_mcdi_rpc_start(efx, MC_CMD_PTP, synch_buf,
MC_CMD_PTP_IN_SYNCHRONIZE_LEN);
EFX_WARN_ON_ONCE_PARANOID(rc);
if (rc)
goto out;
/* Wait for start from MCDI (or timeout) */
timeout = jiffies + msecs_to_jiffies(MAX_SYNCHRONISE_WAIT_MS);
@ -1054,18 +1072,20 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
&response_length);
if (rc == 0) {
rc = efx_ptp_process_times(efx, synch_buf, response_length,
&last_time);
&last_time, host_time_pps);
if (rc == 0)
++ptp->good_syncs;
else
++ptp->no_time_syncs;
}
out:
/* Increment the bad syncs counter if the synchronize fails, whatever
* the reason.
*/
if (rc != 0)
++ptp->bad_syncs;
mutex_unlock(&ptp->phc_lock);
return rc;
}
@ -1445,7 +1465,6 @@ static int efx_ptp_start(struct efx_nic *efx)
goto fail;
ptp->evt_frag_idx = 0;
ptp->current_adjfreq = 0;
return 0;
@ -1485,14 +1504,15 @@ static void efx_ptp_pps_worker(struct work_struct *work)
{
struct efx_ptp_data *ptp =
container_of(work, struct efx_ptp_data, pps_work);
struct pps_event_time host_time_pps = {};
struct efx_nic *efx = ptp->efx;
struct ptp_clock_event ptp_evt;
if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS))
if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS, &host_time_pps))
return;
ptp_evt.type = PTP_CLOCK_PPSUSR;
ptp_evt.pps_times = ptp->host_time_pps;
ptp_evt.pps_times = host_time_pps;
ptp_clock_event(ptp->phc_clock, &ptp_evt);
}
@ -1569,6 +1589,7 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
if (!efx->ptp_data)
return -ENOMEM;
mutex_init(&ptp->phc_lock);
ptp->efx = efx;
ptp->channel = channel;
@ -1640,6 +1661,7 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
efx_nic_free_buffer(efx, &ptp->start);
fail1:
mutex_destroy(&ptp->phc_lock);
kfree(efx->ptp_data);
efx->ptp_data = NULL;
@ -1694,6 +1716,7 @@ void efx_ptp_remove(struct efx_nic *efx)
destroy_workqueue(efx->ptp_data->workwq);
efx_nic_free_buffer(efx, &efx->ptp_data->start);
mutex_destroy(&efx->ptp_data->phc_lock);
kfree(efx->ptp_data);
efx->ptp_data = NULL;
}
@ -1825,7 +1848,8 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
rc = efx_ptp_start(efx);
if (rc == 0) {
rc = efx_ptp_synchronize(efx,
PTP_SYNC_ATTEMPTS * 2);
PTP_SYNC_ATTEMPTS * 2,
NULL);
if (rc != 0)
efx_ptp_stop(efx);
}
@ -2105,23 +2129,23 @@ static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
MCDI_SET_QWORD(inadj, PTP_IN_ADJUST_FREQ, adjustment_ns);
MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_SECONDS, 0);
MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_NANOSECONDS, 0);
mutex_lock(&ptp_data->phc_lock);
rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inadj, sizeof(inadj),
NULL, 0, NULL);
if (rc != 0)
return rc;
ptp_data->current_adjfreq = adjustment_ns;
return 0;
if (!rc)
ptp_data->current_adjfreq = adjustment_ns;
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
static int _efx_phc_adjtime(struct efx_ptp_data *ptp_data, s64 delta)
__must_hold(&ptp_data->phc_lock)
{
u32 nic_major, nic_minor;
struct efx_ptp_data *ptp_data = container_of(ptp,
struct efx_ptp_data,
phc_clock_info);
struct efx_nic *efx = ptp_data->efx;
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ADJUST_LEN);
struct efx_nic *efx = ptp_data->efx;
u32 nic_major, nic_minor;
lockdep_assert_held(&ptp_data->phc_lock);
efx->ptp_data->ns_to_nic_time(delta, &nic_major, &nic_minor);
@ -2134,6 +2158,18 @@ static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
NULL, 0, NULL);
}
static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data,
phc_clock_info);
int rc;
mutex_lock(&ptp_data->phc_lock);
rc = _efx_phc_adjtime(ptp_data, delta);
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct efx_ptp_data *ptp_data = container_of(ptp,
@ -2165,23 +2201,21 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
{
/* Get the current NIC time, efx_phc_gettime.
* Subtract from the desired time to get the offset
* call efx_phc_adjtime with the offset
* call _efx_phc_adjtime with the offset
*/
struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data,
phc_clock_info);
struct timespec64 time_now, delta;
int rc;
struct timespec64 time_now;
struct timespec64 delta;
mutex_lock(&ptp_data->phc_lock);
rc = efx_phc_gettime(ptp, &time_now);
if (rc != 0)
return rc;
delta = timespec64_sub(*e_ts, time_now);
rc = efx_phc_adjtime(ptp, timespec64_to_ns(&delta));
if (rc != 0)
return rc;
return 0;
if (!rc) {
delta = timespec64_sub(*e_ts, time_now);
rc = _efx_phc_adjtime(ptp_data, timespec64_to_ns(&delta));
}
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_enable(struct ptp_clock_info *ptp,

View File

@ -205,7 +205,7 @@ static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
x->rx_length++;
return discard_frame;
return discard_frame | rx_not_ls;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {

View File

@ -620,7 +620,7 @@ struct stmmac_mmc_ops {
struct stmmac_est_ops {
int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
unsigned int ptp_rate);
unsigned int ptp_rate, bool enable);
void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
};

View File

@ -70,7 +70,7 @@ static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
x->rx_length++;
return discard_frame;
return discard_frame | rx_not_ls;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {

View File

@ -239,6 +239,7 @@ struct stmmac_est {
u32 gcl[EST_GCL];
u32 gcl_size;
u32 max_sdu[MTL_MAX_TX_QUEUES];
u32 pclass;
};
struct stmmac_msi {

View File

@ -26,7 +26,7 @@ static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
}
static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
unsigned int ptp_rate)
unsigned int ptp_rate, bool enable)
{
void __iomem *est_addr = priv->estaddr;
int i, ret = 0;
@ -62,7 +62,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
EST_GMAC5_PTOV_SHIFT;
}
if (cfg->enable)
if (enable)
ctrl |= EST_EEST | EST_SSWL | EST_DFBS;
else
ctrl &= ~EST_EEST;
@ -70,7 +70,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
writel(ctrl, est_addr + EST_CONTROL);
/* Configure EST interrupt */
if (cfg->enable)
if (enable)
ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
else
ctrl = 0;
@ -80,6 +80,61 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
return 0;
}
int __stmmac_setup_est(struct stmmac_priv *priv)
{
struct timespec64 current_time, time;
ktime_t current_time_ns, basetime;
u64 cycle_time;
int err;
lockdep_assert_held(&priv->est_lock);
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops, &current_time,
NULL);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->est->btr_reserve[0];
time.tv_sec = priv->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC + priv->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime, current_time_ns, cycle_time);
priv->est->btr[0] = (u32)time.tv_nsec;
priv->est->btr[1] = (u32)time.tv_sec;
err = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate, true);
if (err) {
netdev_err(priv->dev, "failed to re-configure EST\n");
return err;
}
return 0;
}
int stmmac_setup_est(struct stmmac_priv *priv)
{
int ret = 0;
if (!priv->ptp_enabled)
return 0;
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable) {
ret = __stmmac_setup_est(priv);
if (ret)
goto unlock;
ret = stmmac_fpe_map_preemption_class(priv, priv->dev, NULL,
priv->est->pclass);
}
unlock:
mutex_unlock(&priv->est_lock);
return ret;
}
static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt)
{

View File

@ -4,6 +4,9 @@
* stmmac EST(802.3 Qbv) handling
*/
#ifndef __STMMAC_EST_H__
#define __STMMAC_EST_H__
#define EST_GMAC4_OFFSET 0x00000c50
#define EST_XGMAC_OFFSET 0x00001050
@ -65,3 +68,8 @@
#define EST_GCL_DATA 0x00000034
extern const struct stmmac_est_ops dwmac510_est_ops;
int __stmmac_setup_est(struct stmmac_priv *priv);
int stmmac_setup_est(struct stmmac_priv *priv);
#endif /* __STMMAC_EST_H__ */

View File

@ -48,6 +48,7 @@
#include "stmmac_ptp.h"
#include "stmmac_fpe.h"
#include "stmmac.h"
#include "stmmac_est.h"
#include "stmmac_pcs.h"
#include "stmmac_xdp.h"
#include <linux/reset.h>
@ -2182,6 +2183,9 @@ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv,
else
dma_free_rx_skbufs(priv, dma_conf, queue);
dev_kfree_skb_any(rx_q->state.skb);
rx_q->state.skb = NULL;
rx_q->state_saved = false;
rx_q->buf_alloc_num = 0;
rx_q->xsk_pool = NULL;
@ -4201,6 +4205,10 @@ static int __stmmac_open(struct net_device *dev,
if (ret)
goto ptp_error;
ret = stmmac_setup_est(priv);
if (ret)
goto est_error;
stmmac_init_coalesce(priv);
phylink_start(priv->phylink);
@ -4224,7 +4232,7 @@ static int __stmmac_open(struct net_device *dev,
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
est_error:
stmmac_release_ptp(priv);
ptp_error:
stmmac_stop_all_dma(priv);
@ -5099,22 +5107,35 @@ static netdev_features_t stmmac_features_check(struct sk_buff *skb,
return vlan_features_check(skb, features);
}
static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
static int stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
{
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
__be16 vlan_proto = veth->h_vlan_proto;
u16 vlanid;
struct vlan_ethhdr *veth;
if ((vlan_proto == htons(ETH_P_8021Q) &&
if (!pskb_may_pull(skb, ETH_HLEN))
return -EINVAL;
veth = skb_vlan_eth_hdr(skb);
if ((veth->h_vlan_proto == htons(ETH_P_8021Q) &&
dev->features & NETIF_F_HW_VLAN_CTAG_RX) ||
(vlan_proto == htons(ETH_P_8021AD) &&
(veth->h_vlan_proto == htons(ETH_P_8021AD) &&
dev->features & NETIF_F_HW_VLAN_STAG_RX)) {
__be16 vlan_proto = veth->h_vlan_proto;
u8 meta_len = skb_metadata_len(skb);
u16 vlanid;
/* pop the vlan tag */
if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
return -EINVAL;
veth = skb_vlan_eth_hdr(skb);
vlanid = ntohs(veth->h_vlan_TCI);
memmove(skb->data + VLAN_HLEN, veth, ETH_ALEN * 2);
memmove(skb->data - meta_len + VLAN_HLEN,
skb->data - meta_len, meta_len + ETH_ALEN * 2);
skb_pull(skb, VLAN_HLEN);
__vlan_hwaccel_put_tag(skb, vlan_proto, vlanid);
}
return 0;
}
static bool stmmac_rx_need_ic(struct stmmac_priv *priv,
@ -5516,7 +5537,8 @@ static struct sk_buff *stmmac_construct_skb_zc(struct stmmac_channel *ch,
return NULL;
skb_reserve(skb, xdp->data - xdp->data_hard_start);
memcpy(__skb_put(skb, datasize), xdp->data, datasize);
__skb_put(skb, datasize);
memcpy(skb->data - metasize, xdp->data_meta, datasize + metasize);
if (metasize)
skb_metadata_set(skb, metasize);
@ -5542,12 +5564,15 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
if (priv->hw->hw_vlan_en)
if (priv->hw->hw_vlan_en) {
/* MAC level stripping. */
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
else
/* Driver level stripping. */
stmmac_rx_vlan(priv->dev, skb);
} else if (stmmac_rx_vlan(priv->dev, skb)) {
dev_kfree_skb_any(skb);
priv->xstats.rx_dropped++;
return;
}
skb->protocol = eth_type_trans(skb, priv->dev);
if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
@ -5629,12 +5654,12 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int count = 0, error = 0, len = 0;
int dirty = stmmac_rx_dirty(priv, queue);
unsigned int next_entry = rx_q->cur_rx;
bool in_progress = rx_q->state_saved;
u32 rx_errors = 0, rx_dropped = 0;
unsigned int desc_size;
struct bpf_prog *prog;
bool failure = false;
int xdp_status = 0;
int status = 0;
if (netif_msg_rx_status(priv)) {
void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0);
@ -5645,23 +5670,25 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true,
rx_q->dma_rx_phy, desc_size);
}
if (rx_q->state_saved) {
error = rx_q->state.error;
len = rx_q->state.len;
rx_q->state_saved = false;
}
while (count < limit) {
struct stmmac_rx_buffer *buf;
struct stmmac_xdp_buff *ctx;
unsigned int buf1_len = 0;
struct dma_desc *np, *p;
int entry;
int entry, status;
int res;
if (!count && rx_q->state_saved) {
error = rx_q->state.error;
len = rx_q->state.len;
} else {
rx_q->state_saved = false;
if (!in_progress) {
error = 0;
len = 0;
}
read_again:
if (count >= limit)
break;
@ -5700,6 +5727,8 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
if (!buf->xdp)
break;
in_progress = status & rx_not_ls;
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
@ -5707,18 +5736,21 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
dirty++;
if (unlikely(!error && (status & discard_frame))) {
error = 1;
if (!priv->hwts_rx_en)
rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
goto read_again;
if (unlikely(error)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
dirty++;
if (status & rx_not_ls)
goto read_again;
count++;
continue;
}
@ -5727,8 +5759,9 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
if (likely(status & rx_not_ls)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
rx_dropped++;
error = 1;
dirty++;
count++;
goto read_again;
}
@ -5776,7 +5809,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
count++;
}
if (status & rx_not_ls) {
if (in_progress) {
rx_q->state_saved = true;
rx_q->state.error = error;
rx_q->state.len = len;
@ -5818,9 +5851,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue];
unsigned int count = 0, error = 0, len = 0;
int status = 0, coe = priv->hw->rx_csum;
unsigned int next_entry = rx_q->cur_rx;
bool in_progress = rx_q->state_saved;
enum dma_data_direction dma_dir;
int coe = priv->hw->rx_csum;
unsigned int desc_size;
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
@ -5840,25 +5874,28 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true,
rx_q->dma_rx_phy, desc_size);
}
if (rx_q->state_saved) {
skb = rx_q->state.skb;
error = rx_q->state.error;
len = rx_q->state.len;
rx_q->state.skb = NULL;
rx_q->state_saved = false;
}
while (count < limit) {
unsigned int buf1_len = 0, buf2_len = 0;
enum pkt_hash_types hash_type;
struct stmmac_rx_buffer *buf;
struct dma_desc *np, *p;
int entry;
int entry, status;
u32 hash;
if (!count && rx_q->state_saved) {
skb = rx_q->state.skb;
error = rx_q->state.error;
len = rx_q->state.len;
} else {
rx_q->state_saved = false;
if (!in_progress) {
skb = NULL;
error = 0;
len = 0;
}
read_again:
if (count >= limit)
break;
@ -5887,6 +5924,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
prefetch(np);
in_progress = status & rx_not_ls;
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
@ -5894,21 +5933,26 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
page_pool_put_page(rx_q->page_pool, buf->page, 0, true);
buf->page = NULL;
if (unlikely(!error && (status & discard_frame))) {
error = 1;
if (!priv->hwts_rx_en)
rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
goto read_again;
/* We do not support SG in XDP mode */
if (unlikely(!error && (status & rx_not_ls) &&
stmmac_xdp_is_enabled(priv))) {
rx_dropped++;
error = 1;
}
if (unlikely(error)) {
if (status & rx_not_ls)
goto read_again;
dev_kfree_skb(skb);
skb = NULL;
count++;
continue;
goto next;
}
/* Buffer is good. Go on. */
@ -5918,13 +5962,19 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
buf2_len = stmmac_rx_buf2_len(priv, p, status, len);
len += buf2_len;
/* Drop the packet if it is split over buf1 and buf2 on a
* single descriptor if the interface is running in XDP mode.
*/
if (unlikely(stmmac_xdp_is_enabled(priv) && buf2_len)) {
rx_dropped++;
goto next;
}
/* ACS is disabled; strip manually. */
if (likely(!(status & rx_not_ls)))
len -= ETH_FCS_LEN;
if (!skb) {
unsigned int pre_len, sync_len;
/* Each frame starts here: reset the FCS handling */
fcs_stripped = false;
@ -5942,55 +5992,32 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
xdp_prepare_buff(&ctx.xdp, page_address(buf->page),
buf->page_offset, buf1_len, true);
pre_len = ctx.xdp.data_end - ctx.xdp.data_hard_start -
buf->page_offset;
ctx.priv = priv;
ctx.desc = p;
ctx.ndesc = np;
skb = stmmac_xdp_run_prog(priv, &ctx.xdp);
/* Due xdp_adjust_tail: DMA sync for_device
* cover max len CPU touch
*/
sync_len = ctx.xdp.data_end - ctx.xdp.data_hard_start -
buf->page_offset;
sync_len = max(sync_len, pre_len);
/* For Not XDP_PASS verdict */
if (IS_ERR(skb)) {
unsigned int xdp_res = -PTR_ERR(skb);
if (xdp_res & STMMAC_XDP_CONSUMED) {
page_pool_put_page(rx_q->page_pool,
virt_to_head_page(ctx.xdp.data),
sync_len, true);
page_pool_recycle_direct(rx_q->page_pool,
virt_to_head_page(ctx.xdp.data));
buf->page = NULL;
rx_dropped++;
/* Clear skb as it was set as
* status by XDP program.
*/
skb = NULL;
if (unlikely((status & rx_not_ls)))
goto read_again;
count++;
continue;
goto next;
} else if (xdp_res & (STMMAC_XDP_TX |
STMMAC_XDP_REDIRECT)) {
xdp_status |= xdp_res;
buf->page = NULL;
skb = NULL;
count++;
continue;
goto next;
}
}
}
if (!skb) {
unsigned int head_pad_len;
unsigned int metasize;
/* XDP program may expand or reduce tail */
buf1_len = ctx.xdp.data_end - ctx.xdp.data;
@ -6007,10 +6034,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
}
/* XDP program may adjust header */
head_pad_len = ctx.xdp.data - ctx.xdp.data_hard_start;
skb_reserve(skb, head_pad_len);
skb_reserve(skb,
ctx.xdp.data - ctx.xdp.data_hard_start);
skb_put(skb, buf1_len);
skb_mark_for_recycle(skb);
metasize = ctx.xdp.data - ctx.xdp.data_meta;
if (metasize)
skb_metadata_set(skb, metasize);
buf->page = NULL;
} else if (buf1_len) {
dma_sync_single_for_cpu(priv->device, buf->addr,
@ -6041,20 +6072,20 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
/* Remove FCS if needed */
if (!fcs_stripped && pskb_trim(skb, len)) {
dev_kfree_skb_any(skb);
skb = NULL;
rx_dropped++;
count++;
continue;
goto next;
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
if (priv->hw->hw_vlan_en)
if (priv->hw->hw_vlan_en) {
/* MAC level stripping. */
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
else
/* Driver level stripping. */
stmmac_rx_vlan(priv->dev, skb);
} else if (stmmac_rx_vlan(priv->dev, skb)) {
dev_kfree_skb_any(skb);
rx_dropped++;
goto next;
}
skb->protocol = eth_type_trans(skb, priv->dev);
@ -6069,14 +6100,15 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rx_napi, skb);
skb = NULL;
rx_packets++;
rx_bytes += len;
next:
in_progress = false;
skb = NULL;
count++;
}
if (status & rx_not_ls || skb) {
if (in_progress || skb) {
rx_q->state_saved = true;
rx_q->state.skb = skb;
rx_q->state.error = error;
@ -8213,6 +8245,7 @@ static int __stmmac_dvr_probe(struct device *device,
stmmac_napi_add(ndev);
mutex_init(&priv->lock);
mutex_init(&priv->est_lock);
rwlock_init(&priv->ptp_lock);
stmmac_fpe_init(priv);
@ -8346,6 +8379,7 @@ void stmmac_dvr_remove(struct device *dev)
destroy_workqueue(priv->wq);
mutex_destroy(&priv->lock);
mutex_destroy(&priv->est_lock);
bitmap_free(priv->af_xdp_zc_qps);
pm_runtime_disable(dev);
@ -8421,6 +8455,9 @@ static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue)
{
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
dev_kfree_skb_any(rx_q->state.skb);
rx_q->state.skb = NULL;
rx_q->state_saved = false;
rx_q->cur_rx = 0;
rx_q->dirty_rx = 0;
}
@ -8525,6 +8562,10 @@ int stmmac_resume(struct device *dev)
ret = stmmac_init_timestamping(priv);
if (ret)
goto error_stop_dma;
ret = stmmac_setup_est(priv);
if (ret)
goto error_stop_dma;
}
init_coalesce:

View File

@ -8,6 +8,7 @@
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
*******************************************************************************/
#include "stmmac.h"
#include "stmmac_est.h"
#include "stmmac_ptp.h"
#define PTP_SAFE_TIME_OFFSET_NS 500000
@ -54,8 +55,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
u32 sec, nsec;
u32 quotient, reminder;
int neg_adj = 0;
bool xmac, est_rst = false;
int ret;
bool xmac;
xmac = dwmac_is_xmac(priv->plat->core_type);
@ -69,47 +69,21 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
nsec = reminder;
/* If EST is enabled, disabled it before adjust ptp time. */
if (priv->est && priv->est->enable) {
est_rst = true;
mutex_lock(&priv->est_lock);
priv->est->enable = false;
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable)
stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
}
priv->plat->clk_ptp_rate, false);
mutex_unlock(&priv->est_lock);
write_lock_irqsave(&priv->ptp_lock, flags);
stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac);
write_unlock_irqrestore(&priv->ptp_lock, flags);
/* Calculate new basetime and re-configured EST after PTP time adjust. */
if (est_rst) {
struct timespec64 current_time, time;
ktime_t current_time_ns, basetime;
u64 cycle_time;
mutex_lock(&priv->est_lock);
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops,
&current_time, NULL);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->est->btr_reserve[0];
time.tv_sec = priv->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC +
priv->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime,
current_time_ns,
cycle_time);
priv->est->btr[0] = (u32)time.tv_nsec;
priv->est->btr[1] = (u32)time.tv_sec;
priv->est->enable = true;
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
if (ret)
netdev_err(priv->dev, "failed to configure EST\n");
}
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable)
__stmmac_setup_est(priv);
mutex_unlock(&priv->est_lock);
return 0;
}

View File

@ -966,11 +966,12 @@ static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv,
static int tc_taprio_configure(struct stmmac_priv *priv,
struct tc_taprio_qopt_offload *qopt)
{
u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
u32 wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
struct netlink_ext_ack *extack = qopt->mqprio.extack;
struct timespec64 time, current_time, qopt_time;
ktime_t current_time_ns;
int err, i, ret = 0;
u32 *gcl = NULL;
u64 ctr;
if (qopt->base_time < 0)
@ -1013,44 +1014,46 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
return -EOPNOTSUPP;
}
mutex_lock(&priv->est_lock);
if (qopt->cmd == TAPRIO_CMD_DESTROY)
goto disable;
if (qopt->num_entries > dep)
return -EINVAL;
if (!qopt->cycle_time)
return -ERANGE;
if (qopt->cycle_time_extension >= BIT(wid + 7))
return -ERANGE;
if (!priv->est) {
priv->est = devm_kzalloc(priv->device, sizeof(*priv->est),
GFP_KERNEL);
if (!priv->est)
return -ENOMEM;
mutex_init(&priv->est_lock);
} else {
mutex_lock(&priv->est_lock);
memset(priv->est, 0, sizeof(*priv->est));
mutex_unlock(&priv->est_lock);
if (qopt->num_entries > dep) {
ret = -EINVAL;
goto error_unlock;
}
size = qopt->num_entries;
if (!qopt->cycle_time ||
qopt->cycle_time > (u64)U32_MAX * NSEC_PER_SEC) {
ret = -ERANGE;
goto error_unlock;
}
mutex_lock(&priv->est_lock);
priv->est->gcl_size = size;
priv->est->enable = qopt->cmd == TAPRIO_CMD_REPLACE;
mutex_unlock(&priv->est_lock);
if (qopt->cycle_time_extension >= BIT(wid + 7)) {
ret = -ERANGE;
goto error_unlock;
}
for (i = 0; i < size; i++) {
gcl = kcalloc(qopt->num_entries, sizeof(*gcl), GFP_KERNEL);
if (!gcl) {
ret = -ENOMEM;
goto error_unlock;
}
for (i = 0; i < qopt->num_entries; i++) {
s64 delta_ns = qopt->entries[i].interval;
u32 gates = qopt->entries[i].gate_mask;
if (delta_ns > GENMASK(wid - 1, 0))
return -ERANGE;
if (gates > GENMASK(31 - wid, 0))
return -ERANGE;
if (delta_ns > GENMASK(wid - 1, 0)) {
ret = -ERANGE;
goto error_unlock;
}
if (gates > GENMASK(31 - wid, 0)) {
ret = -ERANGE;
goto error_unlock;
}
switch (qopt->entries[i].command) {
case TC_TAPRIO_CMD_SET_GATES:
@ -1062,13 +1065,26 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
gates &= ~BIT(0);
break;
default:
return -EOPNOTSUPP;
ret = -EOPNOTSUPP;
goto error_unlock;
}
priv->est->gcl[i] = delta_ns | (gates << wid);
gcl[i] = delta_ns | (gates << wid);
}
mutex_lock(&priv->est_lock);
if (!priv->est) {
priv->est = devm_kzalloc(priv->device, sizeof(*priv->est),
GFP_KERNEL);
if (!priv->est) {
ret = -ENOMEM;
goto error_unlock;
}
} else {
memset(priv->est, 0, sizeof(*priv->est));
}
memcpy(priv->est->gcl, gcl, sizeof(*gcl) * qopt->num_entries);
priv->est->gcl_size = qopt->num_entries;
/* Adjust for real system time */
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops, &current_time,
NULL);
@ -1092,8 +1108,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
tc_taprio_map_maxsdu_txq(priv, qopt);
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
priv->plat->clk_ptp_rate, true);
if (ret) {
netdev_err(priv->dev, "failed to configure EST\n");
goto disable;
@ -1104,24 +1119,31 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
if (ret)
goto disable;
priv->est->pclass = qopt->mqprio.preemptible_tcs;
priv->est->enable = true;
mutex_unlock(&priv->est_lock);
kfree(gcl);
return 0;
disable:
if (priv->est) {
mutex_lock(&priv->est_lock);
priv->est->enable = false;
stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
priv->plat->clk_ptp_rate, false);
/* Reset taprio status */
for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
priv->xstats.max_sdu_txq_drop[i] = 0;
priv->xstats.mtl_est_txq_hlbf[i] = 0;
priv->xstats.mtl_est_txq_hlbs[i] = 0;
}
mutex_unlock(&priv->est_lock);
}
err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
error_unlock:
mutex_unlock(&priv->est_lock);
kfree(gcl);
return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret;
}

View File

@ -128,6 +128,7 @@
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_319 BIT(21)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_320 BIT(22)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO BIT(23)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_UNI_EN BIT(24)
/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */
#define AM65_CPSW_TS_EVENT_MSG_TYPE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3))
@ -1857,7 +1858,8 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_132 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_319 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_320 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO;
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_UNI_EN;
ts_ctrl = AM65_CPSW_TS_EVENT_MSG_TYPE_BITS <<
AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT;

View File

@ -176,6 +176,9 @@ struct am65_cpts {
struct mutex ptp_clk_lock; /* PHC access sync */
u64 timestamp;
u32 genf_enable;
bool genf_neg_adj;
u32 genf_ppm_hi;
u32 genf_ppm_low;
u32 hw_ts_enable;
u32 estf_enable;
struct sk_buff_head txq;
@ -436,9 +439,11 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
u32 estf_ctrl_val = 0, estf_ppm_hi = 0, estf_ppm_low = 0;
u32 genf_ctrl_val[AM65_CPTS_GENF_MAX_NUM];
u32 genf_ppm_hi, genf_ppm_low;
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
int pps_index = cpts->pps_genf_idx;
u64 adj_period, pps_adj_period;
u64 adj_period, genf_adj_period;
u32 ctrl_val, ppm_hi, ppm_low;
unsigned long flags;
int neg_adj = 0, i;
@ -470,20 +475,33 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
ppm_hi = upper_32_bits(adj_period) & 0x3FF;
ppm_low = lower_32_bits(adj_period);
if (cpts->pps_enabled) {
estf_ctrl_val = am65_cpts_read32(cpts, genf[pps_index].control);
if (neg_adj)
estf_ctrl_val &= ~BIT(1);
else
estf_ctrl_val |= BIT(1);
/* GenF PPM will do correction using cpts refclk tick which is
* (cpts->ts_add_val + 1) ns, so GenF length PPM adj period
* need to be corrected.
*/
genf_adj_period = adj_period * (cpts->ts_add_val + 1);
genf_ppm_hi = upper_32_bits(genf_adj_period) & 0x3FF;
genf_ppm_low = lower_32_bits(genf_adj_period);
cpts->genf_neg_adj = neg_adj;
cpts->genf_ppm_hi = genf_ppm_hi;
cpts->genf_ppm_low = genf_ppm_low;
/* GenF PPM will do correction using cpts refclk tick which is
* (cpts->ts_add_val + 1) ns, so GenF length PPM adj period
* need to be corrected.
*/
pps_adj_period = adj_period * (cpts->ts_add_val + 1);
estf_ppm_hi = upper_32_bits(pps_adj_period) & 0x3FF;
estf_ppm_low = lower_32_bits(pps_adj_period);
for (i = 0; i < AM65_CPTS_GENF_MAX_NUM; i++) {
if (cpts->genf_enable & BIT(i)) {
genf_ctrl_val[i] = am65_cpts_read32(cpts,
genf[i].control);
if (neg_adj)
genf_ctrl_val[i] &= ~BIT(1);
else
genf_ctrl_val[i] |= BIT(1);
}
}
if (cpts->pps_enabled) {
/* am65_cpts_perout_enable_hw() sets pps_index in genf_enable */
estf_ctrl_val = genf_ctrl_val[pps_index];
estf_ppm_hi = genf_ppm_hi;
estf_ppm_low = genf_ppm_low;
}
spin_lock_irqsave(&cpts->lock, flags);
@ -500,10 +518,13 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
am65_cpts_write32(cpts, ppm_hi, ts_ppm_hi);
am65_cpts_write32(cpts, ppm_low, ts_ppm_low);
if (cpts->pps_enabled) {
am65_cpts_write32(cpts, estf_ctrl_val, genf[pps_index].control);
am65_cpts_write32(cpts, estf_ppm_hi, genf[pps_index].ppm_hi);
am65_cpts_write32(cpts, estf_ppm_low, genf[pps_index].ppm_low);
for (i = 0; i < AM65_CPTS_GENF_MAX_NUM; i++) {
if (cpts->genf_enable & BIT(i)) {
am65_cpts_write32(cpts, genf_ctrl_val[i],
genf[i].control);
am65_cpts_write32(cpts, genf_ppm_hi, genf[i].ppm_hi);
am65_cpts_write32(cpts, genf_ppm_low, genf[i].ppm_low);
}
}
for (i = 0; i < AM65_CPTS_ESTF_MAX_NUM; i++) {
@ -513,7 +534,6 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
am65_cpts_write32(cpts, estf_ppm_low, estf[i].ppm_low);
}
}
/* All GenF/EstF can be updated here the same way */
spin_unlock_irqrestore(&cpts->lock, flags);
mutex_unlock(&cpts->ptp_clk_lock);
@ -679,9 +699,12 @@ static void am65_cpts_perout_enable_hw(struct am65_cpts *cpts,
val = lower_32_bits(cycles);
am65_cpts_write32(cpts, val, genf[req->index].length);
am65_cpts_write32(cpts, 0, genf[req->index].control);
am65_cpts_write32(cpts, 0, genf[req->index].ppm_hi);
am65_cpts_write32(cpts, 0, genf[req->index].ppm_low);
am65_cpts_write32(cpts, cpts->genf_neg_adj ? 0 : BIT(1),
genf[req->index].control);
am65_cpts_write32(cpts, cpts->genf_ppm_hi,
genf[req->index].ppm_hi);
am65_cpts_write32(cpts, cpts->genf_ppm_low,
genf[req->index].ppm_low);
cpts->genf_enable |= BIT(req->index);
} else {

View File

@ -260,10 +260,8 @@ int ipa_interrupt_config(struct ipa *ipa)
interrupt->enabled = 0;
interrupt->suspend_enabled = bitmap_zalloc(ipa->endpoint_count,
GFP_KERNEL);
if (!interrupt->suspend_enabled) {
ret = -ENOMEM;
goto err_kfree;
}
if (!interrupt->suspend_enabled)
return -ENOMEM;
/* Disable IPA interrupt types */
reg = ipa_reg(ipa, IPA_IRQ_EN);
@ -289,8 +287,6 @@ int ipa_interrupt_config(struct ipa *ipa)
goto err_disable_wakeup;
}
ipa->interrupt = interrupt;
return 0;
err_disable_wakeup:
@ -299,8 +295,6 @@ int ipa_interrupt_config(struct ipa *ipa)
free_irq(interrupt->irq, interrupt);
err_free_bitmap:
bitmap_free(interrupt->suspend_enabled);
err_kfree:
kfree(interrupt);
return ret;
}
@ -311,8 +305,6 @@ void ipa_interrupt_deconfig(struct ipa *ipa)
struct ipa_interrupt *interrupt = ipa->interrupt;
struct device *dev = ipa->dev;
ipa->interrupt = NULL;
dev_pm_clear_wake_irq(dev);
(void)device_init_wakeup(dev, false);
free_irq(interrupt->irq, interrupt);

View File

@ -643,6 +643,14 @@ static int macvlan_open(struct net_device *dev)
if (err < 0)
goto out;
}
if (dev->flags & IFF_ALLMULTI) {
err = dev_set_allmulti(lowerdev, 1);
if (err < 0) {
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, -1);
goto out;
}
}
goto hash_add;
}
@ -713,6 +721,8 @@ static int macvlan_stop(struct net_device *dev)
dev_mc_unsync(lowerdev, dev);
if (macvlan_passthru(vlan->port)) {
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(lowerdev, -1);
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, -1);
goto hash_del;

View File

@ -111,8 +111,7 @@ static int mctp_i3c_read(struct mctp_i3c_device *mi)
mi->mrl + sizeof(struct mctp_i3c_internal_hdr));
if (!skb) {
stats->rx_dropped++;
rc = -ENOMEM;
goto err;
return -ENOMEM;
}
skb->protocol = htons(ETH_P_MCTP);

View File

@ -1826,9 +1826,13 @@ static void phy_detach_internal(struct phy_device *phydev, bool notify_bus)
struct hwtstamp_provider *hwprov;
/* hwprov may technically be protected by ops lock but
* not for devices with a phydev, see phy_link_topo_add_phy()
* not for devices with a phydev, see phy_link_topo_add_phy().
* Drivers may detach without RTNL while dev is unregistered,
* but then nothing else can reach hwprov.
*/
hwprov = rtnl_dereference(dev->hwprov);
hwprov = rcu_dereference_protected(dev->hwprov,
lockdep_rtnl_is_held() ||
dev->reg_state != NETREG_REGISTERED);
/* Disable timestamp if it is the one selected */
if (hwprov && hwprov->phydev == phydev) {
rcu_assign_pointer(dev->hwprov, NULL);

View File

@ -1377,9 +1377,10 @@ static int veth_set_channels(struct net_device *dev,
* to identify the range we have to disable
*/
veth_disable_range_safe(dev, new_rx_count, old_rx_count);
netif_carrier_on(dev);
if (peer)
if (peer && (peer->flags & IFF_UP)) {
netif_carrier_on(dev);
netif_carrier_on(peer);
}
}
/* update XDP supported features */

View File

@ -1005,12 +1005,6 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
return -EOPNOTSUPP;
}
if (rcu_access_pointer(f->nh) &&
!(state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "Cannot make a nexthop fdb dynamic");
return -EOPNOTSUPP;
}
/* Do not allow an externally learned entry to take over an entry added
* by the user.
*/
@ -1274,11 +1268,6 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (err)
return err;
if (nhid && !(ndm->ndm_state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "A nexthop fdb cannot be dynamic");
return -EINVAL;
}
cfg = rtnl_dereference(vxlan->cfg);
if (cfg->remote_ip.sa.sa_family != ip.sa.sa_family)
return -EAFNOSUPPORT;
@ -2947,6 +2936,9 @@ static void vxlan_cleanup(struct timer_list *t)
if (f->flags & NTF_EXT_LEARNED)
continue;
if (rcu_access_pointer(f->nh))
continue;
timeout = READ_ONCE(f->updated) + cfg->age_interval * HZ;
if (time_before_eq(timeout, jiffies)) {
spin_lock(&vxlan->hash_lock);

Some files were not shown because too many files have changed in this diff Show More