| Age | Commit message (Collapse) | Author |
|
The Lenovo ThinkBook X G2 IAH (MTM 21TU) has an ALC287 codec with four
CS35L41 amplifiers on I2C (CSC3551). It reports codec SSID 17aa:3929,
which it shares with the ThinkBook 13x Gen 5, and PCI SSID 17aa:3842.
Since PCI SSID 17aa:3842 has no quirk entry, the codec SSID matches
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD. That fixup binds only
two amps (cs35l41-hda.0 and .1), while the CS35L41 configuration table
describes four for 17AA3929. Amps .2 and .3 probe and load firmware,
but they are never bound to the codec, so half of the speakers stay
silent.
Add a ThinkPad-style fixup chain that binds four I2C amps, and match the
laptop by its PCI SSID so the ThinkBook 13x Gen 5 is not affected.
Tested with hda_model=1028:0c4d (alias to ALC287_FIXUP_CS35L41_I2C_4):
all four amps bind, apply their calibration and are runtime-active
during playback.
Cc: stable@vger.kernel.org
Signed-off-by: Evgeny Akhtimirov <evgeny@devduty.com>
Link: https://patch.msgid.link/20261009-thinkbook-x-g2-iah-v1-1-56012188aee0@devduty.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
snd_hdac_bus_process_unsol_events() assumes that the codec driver is
always set when it's accessible from the codec table. It's true in
general, but in a sheer timing, it might have been already NULLified
at the driver unbinding.
Although the codec removal should have been done properly by the
previous fixes, just for more safety, let's add a NULL check before
dereferencing and calling the driver's unsol_event callback.
Fixes: e7255c00b10e ("ALSA: hda: Skip event processing for unregistered codecs")
Link: https://patch.msgid.link/20261009133341.440917-6-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
In the recent commit f3607b6952ca ("ALSA: hda: Stop unsol events and
jack polling before codec unbind"), we applied the workaround to stop
pending works at the hda codec driver removal, but it was applied
after the bypass for hda-ext ops hdev_detach. Basically the same
issue is seen for hda-ext stuff, so it's safer to apply the workaround
at the beginning of hda_codec_driver_remove().
Along with it, the clearance of unsol_disabled flag is moved to the
beginning of hda_codec_driver_probe(), too; otherwise hda-ext
hdev_attach() might miss the unsol event handling when the code gets
re-bound.
Fixes: f3607b6952ca ("ALSA: hda: Stop unsol events and jack polling before codec unbind")
Link: https://patch.msgid.link/20261009133341.440917-5-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
Currently the places setting or clearing codec->registered flag have
no locking, while its reference in the unsol handling work
snd_hdac_bus_process_unsol_events() takes the bus->reg_lock lock.
Let's add the same bus->reg_lock at the places where codec->registered
is set and cleared for avoiding the races.
Link: https://patch.msgid.link/20261009133341.440917-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
When the HD-audio controller driver probe fails, it still leaves the
unsolicited event handling and jackpoll work active, hence if they are
pending, they might fire up later after the resource gets released,
which may lead to a UAF. A similar problem may be seen at shutdown,
too.
Add the recently added helper to disable unsol events and the cancel
of jackpoll_work at the appropriate places. We need the workaround in
the error path before driver->ops->remove, too. As unsol events and
jack polling may have been already enabled during the probe callback,
the driver->ops->remove call is done (more) conditionally now.
Fixes: c3ec8ac82105 ("ASoC: hdac_hda: fix memleak on module unload")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://patch.msgid.link/20261009133341.440917-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
https://github.com/MorseMicroLabs/linux-wireless
Lachlan Hodges says:
====================
mm81x 7.4 PR #2
- monitor mode support
- rx improvements
- fix persistent NO_IR flag bug
- misc minor LLM fixes
====================
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
In mms114_suspend, the driver synthesizes touch release events for all
slots and calls input_sync before disabling the hardware interrupt via
mms114_stop. Because the threaded interrupt handler runs independently
and does not share a lock with this early part of the suspend path, an
incoming hardware interrupt can fire after input_sync completes but
before disable_irq is invoked.
If a touch event arrives during this window, the interrupt handler
reports the touch slot as active again, overwriting the synthetic
release event right before the system goes to sleep. Upon resume,
lifting the finger does not generate a release interrupt, potentially
leaving userspace with a stuck active touch slot.
Fix this race by calling mms114_stop, which disables the IRQ and
synchronizes with any executing interrupt handler, before synthesizing
the touch release events. Also ensure that we only synthesize touch
release events if the input device is enabled, keeping the entire
suspend sequence protected by input_dev->mutex.
Reported-by: sashiko-bot@kernel.org
Assisted-by: Antigravity:gemini-3.6-flash
Link: https://patch.msgid.link/anKxGkyRRu5A92Q_@google.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
|
resctrl can be mounted on a system that supports monitoring but not allocation.
On such a system reading the "tasks" file in the default group reports no
tasks, even when there are tasks assigned to the default group. This problem
occurs because the check for whether a task belongs to a CTRL_MON group is
gated by a check for whether the system supports allocation.
The resctrl_arch_alloc_capable() check in is_closid_match() breaks task
reporting for the default group on monitor-only systems so remove this check.
On systems that support allocation the check is redundant.
Fixes: e6b2fac36fcc ("x86/resctrl: Use is_closid_match() in more places")
Closes: https://sashiko.dev/#/patchset/20260831174421.13921-1-tony.luck%40intel.com?part=9
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Link: https://patch.msgid.link/20261009193923.15498-1-tony.luck@intel.com
|
|
nouveau_abi16_ioctl_getparam() fetches the graphics engine with
gr = nvxx_gr(drm) (i.e. drm->nvkm->gr) and, for the
NOUVEAU_GETPARAM_GRAPH_UNITS parameter, passes it straight to
nvkm_gr_units(), which dereferences gr->func with no NULL check.
When graphics-engine construction returns -ENODEV, NVKM treats it as an
optional absent engine: the NVKM_LAYOUT_ONCE device constructor deletes
the subdevice, leaves device->gr == NULL and continues probing, and
Nouveau still registers a render node. An unprivileged client holding a
/dev/dri/renderD* fd can then issue DRM_IOCTL_NOUVEAU_GETPARAM with
NOUVEAU_GETPARAM_GRAPH_UNITS and oops the kernel on the NULL gr.
Report 0 units when gr is absent. This matches nvkm_gr_units() itself,
which already returns 0 when the engine exposes no units callback.
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Assisted-by: LLM
Signed-off-by: Zhenhao Wan <whi4ed0g@gmail.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patch.msgid.link/20260812-nouveau-nvkm-absent-subdev-null-deref-v1-2-7e057f6aeba0@gmail.com
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
Pull PCI fix from Bjorn Helgaas:
"This fixes some GPU initialization regressions caused by eddba19b8b5f
("PCI/AER: Support Advisory Non-Fatal Errors"), which appeared in
v7.3-rc1.
That commit also caused a MacBookPro16,1 spontaneous power-off
regression; I expect a fix for that next week"
* tag 'pci-v7.3-fixes-4' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci:
PCI/AER: Skip error recovery on false alarms
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC/MEMSTICK fixes from Ulf Hansson:
"MMC host:
- cavium-octeon|thunderx: Destroy slot platform devices on remove
- mtk-sd: Cancel request timeout work on remove
- sdhci-sprd: Disable runtime PM on remove
MEMSTICK:
- Wait for request completion before freeing card
- rtsx_usb_ms: Complete requests after eject instead of dropping
them"
* tag 'mmc-v7.3-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
memstick: rtsx_usb_ms: complete requests after eject instead of dropping them
memstick: core: wait for request completion before freeing card
mmc: cavium-thunderx: destroy slot platform devices on remove
mmc: cavium-octeon: destroy slot platform devices on remove
mmc: sdhci-sprd: disable runtime PM on remove
mmc: mtk-sd: Cancel request timeout work on remove
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media fix from Mauro Carvalho Chehab:
"A fix for em28xx unregister code affecting devices with FM radio
support"
* tag 'media/v7.3-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
media: em28xx: use video_unregister_device for radio_dev
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"A dozen of small fixes. All device-specific quirks or fixes, and
nothing exciting is expected.
- USB-audio and HD-audio quirks
- HD-audio TAS2781 codec fix
- ctxfi driver memory leak fix
- ASoC AMD quirks
- ASoC cs35l56 and adau1372 codec fixes"
* tag 'sound-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
ASoC: amd: acp: Add more ACP7.0 match entries for Cirrus Logic parts
ASoC: amd: acp: Add DMI override for ASUS EXPERTBOOK AM7406CKA
ASoC: sdw_utils: Switch CS35L56/57/62/63 to use OT25 DAI
ASoC: cs35l56: Add DAI for SDCA OT25 stream
ASoC: samsung: i2s: enable op_clk in probe to balance runtime PM
ASoC: adau1372: fix invalid default state of output ASRC and DAC muxes
ASoC: adau1372: allow sleepy powerdown GPIOs
ASoC: amd: yc: Add DMI quirk for Acer Aspire Go 15 (AG15-21P)
ALSA: hda/realtek: Add mute LED quirk for HP Pavilion 15-eg3xxx (103c:8bfd)
ALSA: hda/tas2781: Accept V1 calibration data without CRC
ALSA: ctxfi: Fix memory leakage when clearing DAO input mappers
ALSA: hda/realtek: Add quirk for ASRock NUC BOX-358H
ALSA: usb-audio: Add native DSD support for Cambridge Audio streamers
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm
Pull pmdomain provider fixes from Ulf Hansson:
- imx: Serialize power on/off across sibling domains for imx8m-blk-ctrl
- rockchip: Fix a couple of errors during probe
* tag 'pmdomain-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm:
pmdomain: rockchip: don't ignore clock lookup errors on attach
pmdomain: rockchip: fix clock leak on domain probe failure
pmdomain: rockchip: propagate subdomain add errors
pmdomain: imx8m-blk-ctrl: Serialize power on/off across sibling domains
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux
Pull dma-mapping fixes from Marek Szyprowski:
"Two more fixes for the corner cases in the DMA-mapping SWIOTLB code
(Peng Fan and Marek Szyprowski)"
* tag 'dma-mapping-7.3-2026-10-09' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux:
swiotlb: fix default_swiotlb_limit() for non-growable default pool
iommu/dma: skip swiotlb bounce for DMA_ATTR_MMIO in iommu_dma_map_phys
|
|
Pull fsverity fix from Eric Biggers:
"Fix a regression from commit f77f281b6118 ("fsverity: use a hashtable
to find the fsverity_info")"
* tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsverity/linux:
fsverity: RCU-delay the freeing of struct fsverity_info
|
|
takes effect
A child that ran a cid at a low cpuperf target leaves the target there when
PERF is revoked, since the kernel resets targets only at root enable. Reset
the target from ops.sub_child_ecaps_updated() once the revoke is in effect.
A detach reports nothing, so ops.sub_detach() resets the child's cids, and
the pool unless another child holds it. Count the deliveries in the hier
stats.
v2: Reset from ops.sub_detach() for a detaching child's cids.
v3: Skip the pool at detach while another child holds it (Andrea Righi).
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner:
"This contains fixes for the current development cycle.
All of them came out of a review of the mount code that started with a
bug report. The review modeled the corner cases of mount propagation,
unmounting and mount reference counting and turned up a lot of bugs.
Most of them years old. Most fixes come with a selftest.
- Rework connected mounts.
A mount that is unmounted together with its parent can stay
attached to the parent to keep its mountpoint covered. That happens
when the mountpoint is removed with rmdir(), unlink() or rename(),
when a detached tree is dissolved, and for locked mounts in any
umount that isn't synchronous, including the teardown of their
mount namespace. The parent then owns the child and drops it on its
own final mntput(). So any reference from the child's superblock
back to one of its ancestors becomes a cycle that is never freed.
A loop device backed by an image on a tmpfs and mounted on that
same tmpfs is enough. Remove the directory the tmpfs is mounted on
from the host, let the container's mount namespace exit, and the
loop device, the tmpfs and the filesystem on the loop device are
leaked for good. The same works with autofs, zram, ecryptfs,
binfmt_misc, fuse passthrough, zloop, a mass storage gadget and md,
and the selftests have reproducers for them. This has been possible
since v4.1. It is also why "put_mnt_ns(): leave mounts connected"
was reverted in -rc5. Keeping every mount of a dying mount
namespace connected made these cycles trivial to create.
Every unmounted mount is now detached from its parent. Where the
mountpoint has to stay covered the mount leaves a cover on the
parent instead, allocated together with the mount. A lookup on the
unmounted parent that hits a cover finds an empty immutable
directory or file on the private nullfs instance. Nothing leads
from a cover to another mount, so no unmounted mount owns another
one and no cycle can form.
This is visible to userspace. A formerly connected mount can no
longer be reached through its unmounted parent and ".." inside it
leads nowhere, as for every other lazily unmounted mount.
With that the private nullfs instance becomes reachable from
userspace, so it now refuses mounts on top, is mounted read-only,
and refuses fsnotify marks and file locks. Its inodes are shared by
every holder and a watch or a lock would otherwise reach across
users. may_decode_fh() now also decides its subtree check under a
single mount_lock hold, as a racing umount could otherwise let it
decode into what a locked child covered.
- umount:
* Don't silently unmount busy mounts.
Since v4.13 propagate_umount() takes down propagated copies of
the victim with children as long as each child is an overmount or
another copy of the victim, but propagate_mount_busy() only ever
checked copies without children or with just an overmount. A
container that moved a tree beneath its copy of a host mount lost
that tree from under its open file descriptor to a plain umount()
on the host. propagate_mount_busy() now applies the same rules,
walking each chain of copies once.
* Don't let a migrating task hide its reference from umount().
mnt_get_count() sums the per-cpu counters under mount_lock but
the mntget() and mntput() fast paths don't take it. A task that
takes a reference on a cpu the sum has already passed and drops
it after migrating to one the sum hasn't reached yet hides the
reference it held to begin with, and umount() succeeds with the
file still open. Gets and puts now live in separate per-cpu
counters and all puts are summed before all gets with a full
barrier in between, the way srcu_readers_active_idx_check() does
it. mntget() is unchanged and mntput() gains an smp_wmb().
* Check each submount for references right before unmounting it.
shrink_submounts() and mark_mounts_for_expiry() checked all their
victims up front. Unmounting the first could move a busy
overmount to where the next victim's propagated copy is looked up
and it was then unmounted without a check.
* Never expire a locked mount.
A shrinkable mount moved beneath a locked mount with
MOVE_MOUNT_BENEATH takes over the lock, and umount() of an
unlocked ancestor expired it and revealed what it covered. That
umount() now fails with EBUSY as it does for any other locked
child. A lazy umount still takes the whole tree.
- Overmounts and locked mounts:
* Unhash a dentry before detaching the mounts on it.
unlink(), rmdir() and rename() detach the mounts on the victim
but only d_delete() it once its inode is unlocked, a window that
includes an expedited RCU grace period. In between, a lookup from
a mount namespace in which the dentry is a mountpoint found it
hashed, positive and uncovered. Drop the dentry first, as
d_invalidate() already does.
* Don't reveal overmounted entries in refwalk.
A refwalk that had grabbed the dentry before the unlink never
rechecked it the way rcuwalk does with d_seq and mount_lock.
Without any artificial widening three walkers read the covered
file 27 times in a minute. step_into() now fails an unhashed
dentry marked DCACHE_CANT_MOUNT with -ESTALE and the walk is
retried.
* Keep covered mounts covered in OPEN_TREE_NAMESPACE.
Creating such a mount namespace only takes a user namespace and
the copy followed bind mount rules: no children without
AT_RECURSIVE and no unbindable mounts with it. An unprivileged
user could see what mounts covered in the source, such as the
parts of /proc and /sys that container runtimes mask. If the
caller doesn't own the source mount namespace a non-recursive
copy of a mount with something mounted below the requested
directory is now refused and a recursive copy includes unbindable
mounts, the way unshare() copies.
* Keep the lock on a mount that a propagated copy is moved beneath.
MNT_LOCKED moved to any mount that ended up beneath a locked
mount, propagated copies included. A host mount and umount on a
directory covered by a locked mount in a less privileged mount
namespace left that cover unlocked for the namespace's owner to
remove. Only mounts the caller places beneath take over the lock
now.
* Handle mount locking for automounts correctly. Which copies to
lock was decided by the mount namespace of the task that
triggered the automount. A task in a user namespace that
triggered one on a host mount through a file descriptor got the
host's own automount locked while its own copy stayed unlocked
and could have nosuid, nodev and noexec cleared. Use the owner of
the mount namespace the mount lands in.
- Use-after-free and crashes:
* Refuse an automount below a mount that is in no namespace.
The private clones overlayfs uses for its layers have the
MNT_NS_INTERNAL error pointer as their namespace, which
finish_automount() let through and count_mounts() dereferenced. A
fanotify filesystem mark on an overlayfs lower layer hands out
file descriptors on such a clone. With debugfs as the lower layer
opening "tracing" oopses with namespace_sem held for writing and
every mount operation on the system blocks from then on.
* Reset the old parent's ->overmount in mnt_change_mountpoint().
When propagate_umount() moved an overmount off a mount that a
file descriptor kept alive, MOVE_MOUNT_BENEATH through that
descriptor later followed the stale pointer into the freed
overmount.
* statmount() with STATMOUNT_BY_FD and pivot_root() read the parent
of a mount that may be unmounted and only held by a file
descriptor, while the parent's final mntput() can free it.
statmount() now reads it under mount_lock and pivot_root() first
checks that both mounts are in the caller's mount namespace.
* Queue a mount only once for mount notifications. A mount
reparented by one umount_tree() and taken down by the next under
the same namespace_sem hold, as in shrink_submounts(), was queued
twice. That cut the mounts queued in between out of notify_list
while it still pointed at them, and once they were freed every
later mount operation walked freed memory.
* Don't let a pseudo dentry become the root of a mount. A bind
mount of a bpf token file did that with a DCACHE_NORCU dentry,
which is freed without an RCU grace period while lockless path
walks may still look at it. Refuse to clone such a mount.
* Don't inherit MNT_UMOUNT in clone_mnt(). A bind mount of a lazily
unmounted nsfs or pidfs mount through its file descriptor started
out flagged as unmounted. Among other things __detach_mounts()
then dropped the namespace's reference on it, the mount outlived
its namespace and mount_setattr() through the descriptor read the
freed namespace. A recursive bind mount of such a mount also
copied the unmounted stack still attached to it. That now fails
with EINVAL, copying the mount itself still works.
* Remove the fsnotify marks of a mount namespace in free_mnt_ns()
instead of the RCU callback that frees the namespace, where
taking the group mutexes meant sleeping in softirq context.
- Propagation and copies:
* Keep a copied mount unbindable. Since v6.17 clone_mnt() didn't
copy the unbindable flag, so every mount namespace created with
CLONE_NEWNS had bindable copies of all unbindable mounts. This
had been fixed once before.
* Refuse MOVE_MOUNT_SET_GROUP on an unbindable mount. It made the
mount an unbindable slave, a state nothing else can produce, or
silently dropped the unbindable flag. CRIU applies MS_UNBINDABLE
after restoring sharing and isn't affected.
* Check a recursive bind mount for mount namespace loops.
Recursively bind mounting a tree from another mount namespace
could put a mount of a namespace's file inside that same
namespace, which then pins itself and all its mounts. Repeating
it leaks without limit, the reproducer took Shmem from 380 kB to
65916 kB. The copy is now checked with check_for_nsfs_mounts()
before it is grafted, as move_mount() does.
* Look at the topmost mount for a mount namespace file.
attach_recursive_mnt() never looked at the topmost mount of the
source's chain of overmounts. If that was the chain's only mount
namespace file an existing mount at a propagated destination got
buried below the root of the nsfs file where no path walk reaches
it.
* Don't put a mountpoint on a dentry that's being removed.
attach_recursive_mnt() makes a mountpoint of the source's root
without its inode lock, so a racing rmdir() of that directory
could leave a mount on it that nothing ever detaches.
d_set_mounted() now checks cant_mount() as well.
- nullfs:
* Take no inode lock for readdir of an immutable directory.
The root of every empty mount namespace is the same nullfs
directory and iterate_dir() held its i_rwsem across
->iterate_shared(). A reader whose buffer faults on a FUSE mount
of its own holds it for as long as its server wants, and with an
exclusive locker queued behind it every lookup that misses the
dcache, every create and every mount in that directory waits. One
user of an empty mount namespace stalls all others. Directories
with the new FOP_IMMUTABLE flag skip the lock.
* Refuse to reconfigure internal superblocks through fspick(),
MS_REMOUNT or the read-only remount that a synchronous umount()
of the root does. For nullfs only root in the initial user
namespace could do it, but the superblock is shared by every
mount namespace and the flags showed up in statfs() for all of
them.
* Don't update the access time on nullfs and refuse F_SET_RW_HINT
on an immutable inode.
- unshare: Free an nsproxy that was never installed with
nsproxy_free() when set_cred_ucounts() fails. put_nsproxy() dropped
active references that were never taken, which triggered a warning
and hid the caller's own namespaces from listns().
- Smaller changes: mount_setattr() checks the target before it walks
the tree to allocate peer group ids, unshare() puts the old
fs_struct before the old namespaces, dissolve_on_fput() drops the
file's reference to the tree itself, disconnect_mount() is
simplified and the documentation of the propagated unmount rule is
brought up to date"
* tag 'vfs-7.3-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (58 commits)
namespace: simplify disconnect_mount()
selftests/filesystems: test covered mounts
namespace: rework connected mounts
nullfs: add an empty immutable regular file
selftests/filesystems: check that reading the root of an empty mount namespace stalls nobody
selftests/filesystems: add a helper that holds a readdir in a page fault
readdir: take no inode lock on an immutable directory
nullfs: refuse file locks
fsnotify: let a filesystem refuse marks on its objects
namespace: nothing is mounted on or written through knullfs
namespace: keep the private nullfs instance in knullfs
fhandle: decide the subtree check under mount_lock
selftests/filesystems: check that an automount below an overlay layer is refused
selftests/filesystems: check the atime of the empty mount namespace root
selftests/filesystems: check that a lock lands on the right mount and stays
namespace: keep the lock on a mount that a propagated copy is moved beneath
namespace: never expire a locked mount
nullfs: don't update the access time
namespace: handle mount locking for automounts correctly
namespace: refuse an automount below a mount that is in no namespace
...
|
|
cap changes
A grant or revoke only records the target caps. They take effect on a cid at
its next dispatch, and nothing tells the parent when. Without that the
parent cannot act on a revoke: a child that ran a cid at a low cpuperf
target leaves the target there when PERF is revoked, as the kernel resets
targets only at root enable. Nor can the parent tell when it may schedule on
the cid again.
Add ops.sub_child_ecaps_updated(), delivered to the direct parent right
after the child's own ops.sub_ecaps_updated() with the child's cgroup id and
the same before and after caps, in the same dispatch context. Both
deliveries are suppressed while the child is bypassing and replayed together
afterwards. A disabled child reports nothing: ops.sub_detach() is where the
parent restores what it had delegated.
A sub is now bypassed before it is linked, so that the grants queued for it
from ops.sub_attach() are consumed while it is bypassed and replayed to it
and the parent once it is enabled. Otherwise a sync consumed before the
sub's ops are registered would reach the parent but never the sub.
v2: Drop the disable report with its sleep lock and nested-dispatch gate,
the parent restores from ops.sub_detach() instead.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Will Deacon:
"It finally seems to have calmed down on the arm64 fixes front, so
please pull these two straightforward fixes for -rc7. One fixes the
EL2 trap configuration for implementation-defined CPU PMU hardware
during boot and the other fixes a kcov selftest failure by excluding
our softirq early entry code:
- Fix PMU EL2 trap configuration for CPUs with an IMPDEF PMU
- Fix kcov boot selftest failure by excluding our early IRQ entry
code"
* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
arm64: irq: exclude the softirq stack switch from KCOV
arm64/boot: Don't set PMUv3p9 FGT2 bits without PMUv3
|
|
perf coordinates fixes:
cxl/acpi: Convert QTG _DSM latencies to picoseconds
cxl: Account for link width in latency calculation
cxl/port: Convert PCIe link latency to nanoseconds
GPF path fixes:
cxl/pci: Update only the Port GPF timeout fields
cxl/pci: Program the Port GPF timeouts before caching the DVSEC
cxl/pci: Use the Device GPF DVSEC for restricted endpoints
dport fixes:
cxl/port: Attach endpoints to a dport under the lock that pins it
cxl/core: Hold the dport host lock across dport lookup and use
cxl/port: Clear cached dport pointers when a dport is removed
|
|
The QTG _DSM expects read and write latencies in picoseconds, as
specified in CXL 3.0, Table 9-30.
The code base originally kept the latencies passed to the QTG _DSM in
picoseconds in effect. Commit 51293c565cf4 ("cxl: Fix incorrect region
perf data calculation") normalized CDAT and host bridge latencies to
nanoseconds, but did not add a conversion back to picoseconds when
constructing the _DSM input. Firmware can therefore select QTG IDs using
understated latencies.
Convert the latencies to picoseconds when constructing the _DSM input
package. Multiply in 64 bits and reject latencies that cannot fit in the
DWORD inputs defined by the specification.
Fixes: 51293c565cf4 ("cxl: Fix incorrect region perf data calculation")
Cc: stable@vger.kernel.org
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20261009045452.1107921-4-den@valinux.co.jp
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
cxl_pci_get_latency() derives bandwidth from the per-lane speed returned
by pcie_link_speed_mbps(), ignoring the negotiated link width. This
overestimates the FlitLatency contribution for multi-lane links.
Sections 2.11.3 and 2.11.4 of the Intel CXL Memory Device Software Guide
describe the link bandwidth as the product of the negotiated speed and
width.
Replace pcie_link_speed_mbps() with pcie_link_bandwidth_mbps() and
migrate both CXL callers (the only users of the API). The new helper
obtains speed and width from a single Link Status read. The CXL
bandwidth calculation no longer needs a separate width read and
multiplication.
While at it, make error handling more robust by converting PCI config
read errors to negative errno values and checking for zero bandwidth
before calculating latency.
Fixes: 4d07a05397c8 ("cxl: Calculate and store PCI link latency for the downstream ports")
Cc: stable@vger.kernel.org
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # pci/pci.c
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20261009045452.1107921-3-den@valinux.co.jp
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
Commit 51293c565cf4 ("cxl: Fix incorrect region perf data calculation")
converted CDAT latencies to nanoseconds and removed the conversion in
cxl_region_perf_data_calculate(), but left PCIe link latencies in
picoseconds.
This inflates the FlitLatency contribution to region and node latencies
by a factor of 1000, exposing incorrect values in sysfs. The resulting
abstract distances can incorrectly reverse the memory tier ordering of
nodes.
Convert the FlitLatency contribution to nanoseconds before adding it to
the access coordinates, rounding up as cdat_normalize() does.
Fixes: 51293c565cf4 ("cxl: Fix incorrect region perf data calculation")
Cc: stable@vger.kernel.org
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20261009045452.1107921-2-den@valinux.co.jp
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
update_gpf_port_dvsec() rebuilds the phase control register from just
the timeout base and scale, so the rest of the register is cleared by
the write. The other bits are reserved today and nothing is lost, but
the full-register rewrite would clobber any field the spec defines
there later.
Read-modify-write the register and change only the two timeout
fields.
Fixes: a52b6a2c1c99 ("cxl/pci: Support Global Persistent Flush (GPF)")
Assisted-by: LLM
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261008034619.28059-4-kanie@linux.alibaba.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
cxl_gpf_port_setup() caches the Port GPF DVSEC offset in the dport
before programming the phase timeouts, and ignores the return value
of both update_gpf_port_dvsec() calls: the function always reports
success.
A failing config write is therefore not only silent, it is also
permanent: the timeouts stay at the hardware defaults instead of the
maximum flush window the kernel is asking for, and the cached offset
keeps any later endpoint attach from retrying the update.
Propagate the errors and cache the offset only after both phases are
programmed, so the next endpoint attach retries the setup.
Fixes: 6af941db6a60 ("cxl/pci: Update Port GPF timeout only when the first EP attaching")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261008034619.28059-3-kanie@linux.alibaba.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
cxl_gpf_get_dvsec() picks between the Port and the Device GPF DVSEC
from the PCIe type of the given device, and only a plain endpoint
counts as a device. A restricted CXL device is an endpoint too, but
it falls into the port case and is probed for the Port GPF DVSEC
instead of the Device GPF DVSEC.
On an RCD, dirty shutdown tracking therefore never arms: the DVSEC
lookup in cxl_nvdimm_arm_dirty_shutdown_tracking() fails, the dirty
shutdown count stays invalid, and the warning complains about a
missing Port GPF DVSEC on a device.
Treat restricted endpoints as devices.
Fixes: 36aace15d9bd ("cxl/pci: Drop the parameter is_port of cxl_gpf_get_dvsec()")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261008034619.28059-2-kanie@linux.alibaba.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
devm_cxl_enumerate_ports() and add_port_attach_ep() look up or create a
dport under its port's device lock, drop the lock, then pass the dport
to cxl_add_ep(). add_ep() reads dport->port before taking the lock, and
cxl_gpf_port_setup() reads and writes the dport with no lock held.
A concurrent cxl_detach_ep() for another memdev below the same port can
free the dport in that window: it calls del_dports() under the port lock
when the last endpoint leaves. The enumerating memdev then dereferences
freed memory.
Attach the endpoint and set up GPF while the port lock from the lookup
is still held. Make add_ep() assert that lock instead of taking it.
Under the lock, a dport found in port->dports is still live, since
removal erases it from the xarray before freeing it.
[ dj: Added kdoc update from Alison. ]
Fixes: de516b40116e ("cxl/port: Record dport in endpoint references")
Reported-by: Li Ming <ming.li@zohomail.com>
Closes: https://lore.kernel.org/linux-cxl/0c68324c-cfc7-46b2-9344-24ae40e88923@zohomail.com/
Assisted-by: LLM
Reviewed-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261001154744.1095902-4-dave.jiang@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
Callers of cxl_pci_find_port() and cxl_mem_find_port() can be handed a
'struct cxl_dport' that is already freed, and all four dereference it
without the lock that would prevent that.
A dport is kzalloc()'d into a devres group on its host device, so it dies
when that host unbinds. The host is &port->dev for a switch port and
port->uport_dev for the root port.
Both helpers return the dport through an output parameter. The caller's
port reference pins struct cxl_port, not the dport allocation, and the
lookup itself is a bare xa_load() under no lock.
Add cxl_port_dport_host() to name the device that pins a dport, and
cxl_pci_find_dport() / cxl_mem_find_dport() to look one up with that
device's lock held and asserted. Convert the four callers to use them and
bail if the dport is gone. cxl_port_add_dport() already follows this rule.
cxl_mem_probe() chose its endpoint devm host from dport->rch, which meant
dereferencing the dport before taking any lock. Use cxl_port_dport_host():
rch dports only ever land on the root port, so it selects the same device
without needing the dport.
With every caller converted, the dport output parameter of
cxl_pci_find_port() and cxl_mem_find_port() is unused. Drop it.
Fixes: 733b57f262b0 ("cxl/pci: Early setup RCH dport component registers from RCRB")
Assisted-by: LLM
Reviewed-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261001154744.1095902-3-dave.jiang@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
Switch decoders cache dport pointers in cxlsd->target[], and nothing
clears them when a dport is freed. Readers then dereference freed memory.
KASAN caught it under a cxl_test load/unload loop with concurrent sysfs
reads (abbreviated).
Clear the matching slots from cxl_dport_remove(), walking the port's
decoders the way cxl_port_update_decoder_targets() does on the add side.
Scan all nr_targets slots, the target[] allocation size, and clear every
hit.
Fixes: 8330671c57c7 ("cxl: Add helper to delete dport")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20261001154744.1095902-2-dave.jiang@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
|
|
panthor_group_destroy() checks the GROUP_REGISTERED mark and then calls
xa_erase() without holding the xarray lock across both. If the handle is
destroyed by another thread in between, and a concurrent GROUP_CREATE
reuses the freed ID, the first destroy erases and releases the new,
still-initializing group, leading to a use-after-free in
panthor_group_create().
Do the mark check and erase atomically under xa_lock().
Fixes: eec7e23d848d ("drm/panthor: Prevent potential UAF in group creation")
Assisted-by: Claude:claude-opus-5.5
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Link: https://patch.msgid.link/20261008100935.3059587-1-osama.abdelkader@gmail.com
|
|
With CHECK_DTBS enabled, Kbuild appends a schema validation command to
the fdtoverlay command saved in a composite DTB's .cmd file. When DTB
decomposition is requested, process_dtb() treats every word after -i as
an input file, including the semicolon and the validator arguments.
FIT generation then fails with FileNotFoundError while opening or
checking the size of those words as files.
Limit the input list to the fdtoverlay command before extracting its
arguments. This preserves the base DTB and overlay order and ignores
the subsequent schema validation command.
Fixes: 17c31aded9a1 ("scripts/make_fit: Support decomposing DTBs")
Assisted-by: LLM
Signed-off-by: Ting-Han Hou <ue081723@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Link: https://patch.msgid.link/CA+NtrhQBK8uW32qO3dXxVxO1GSN-0EJfyJ16tnyx0o52T17WtQ@mail.gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
|
The BrokenPipeError handler in run-clang-tools.py calls os.open() and
os.dup2() without importing os. If this handler is reached, it raises
NameError instead of redirecting stdout and exiting with status 1.
Import os so the handler can work as intended.
Fixes: 87c7ee67deb7 ("scripts: handle BrokenPipeError for python scripts")
Assisted-by: LLM
Signed-off-by: Ting-Han Hou <ue081723@gmail.com>
Link: https://patch.msgid.link/20261009175836.2277-1-ue081723@gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
|
sym_get_near_range_bound() is meant to check whether the given value is
outside of the active range of an int/hex symbol, and is called with the
symbol's current value from sym_calc_value() and with the default value
from sym_get_string_default().
Since commit 9b8719973ee2 ("kconfig: use unsigned integers for hex range
checks") it ignores its value argument and uses the current value of the
symbol (via sym_get_range_val()) instead. As a result, an out-of-range
default is no longer clamped in sym_get_string_default(), and
savedefconfig writes out values that are equal to the effective default
again, for example CONFIG_A=4 for:
config A
int "a"
range 1 4
default 8
The existing savedefconfig_range test did not catch this because it only
covers symbols without a prompt.
Parse the value argument again, and add a test case for a symbol with a
prompt.
Found while fuzzing Kconfig input with ASan/UBSan.
Fixes: 9b8719973ee2 ("kconfig: use unsigned integers for hex range checks")
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Leizhen Zhang <lzsx618@gmail.com>
Tested-by: Julian Braha <julianbraha@gmail.com>
Reviewed-by: Julian Braha <julianbraha@gmail.com>
Link: https://patch.msgid.link/20261008164540.3686383-1-lzsx618@gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
|
If a choice is visible but none of its choice values is, conf_choice()
counts cnt == 0 visible values and finds no default. When the choice has
to be asked, e.g. because a new symbol was added to the same menu
(oldconfig, syncconfig) or because stdin is at EOF (oldaskconfig), the
loop that maps the answer to a menu entry never finds one and the
while (1) loop repeats forever, printing "choice[1-0?]: 0" each time.
This happens in the tree for s390 when the compiler supports none of the
-march=z* options (e.g. a non-s390 host compiler), so that all values of
the "Processor type" choice are invisible:
$ make ARCH=s390 defconfig
$ sed -i '/^CONFIG_NR_CPUS=/d' .config
$ make ARCH=s390 oldconfig # hangs
Before the removal of tristate choice support, conf_choice() returned
early in this case. Do the same when there is no visible choice value.
Found by fuzzing Kconfig input with ASan/UBSan.
Fixes: fde192511bdb ("kconfig: remove tristate choice support")
Assisted-by: Claude:claude-opus-5-5 libFuzzer
Signed-off-by: Leizhen Zhang <lzsx618@gmail.com>
Reviewed-by: Julian Braha <julianbraha@gmail.com>
Tested-by: Julian Braha <julianbraha@gmail.com>
Link: https://patch.msgid.link/20261008164521.3684735-1-lzsx618@gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
|
'keys' was removed from 'dialog_textbox' in:
commit e14f1242a8be ("kconfig: menuconfig: simplify global jump key assignment")
but the comment referencing it was never removed.
Let's cleanup this stale comment.
Signed-off-by: Julian Braha <julianbraha@gmail.com>
Reviewed-by: Nicolas Schier <n.schier@fritz.com>
Link: https://patch.msgid.link/20261009094617.17322-1-julianbraha@gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
|
Eduard Zingerman says:
====================
bpf: use scalar evolution to widen bounded loops
This series implements the scalar evolution (SCEV) technique for
verification of loops.
Scalar evolution is a static analysis technique that infers algebraic
expressions describing how variables change within a loop body.
These expressions can then be used to estimate the number of loop body
executions. This estimate can be used to represent induction variables
as ranges instead of enumerating each possible value.
For example, the following loop:
for (r0 = 0; r0 < 10; r0++) {
...
}
would now be verified with the assumption that r0 is a scalar value
in the range [0..9] within its body.
See the following patches for a more technical overview:
- "bpf: compute scalar evolution expressions for loops"
- "bpf: use SCEV to widen bounded loops"
The series can be viewed as consisting of the following parts:
- Preparatory patches fixing and extending liveness analysis and
adding utility functions. The liveness changes collect stack access
effects and register dependencies, including:
- "bpf: fix arg_track_xfer() for atomic stack spills and fills"
- "bpf: derive global subprog stack liveness from BTF signatures"
- "bpf: compute parameters liveness in bpf_compute_live_registers()"
- Patches relaxing the verifier's current restrictions on accessing
memory via varying offset pointers, specifically:
- "bpf: allow subrange relations for PTR_TO_STACK in regsafe()"
- "bpf: representation for intervals with steps"
- "bpf: varying offset access support for PTR_TO_BTF_ID pointers"
- Patches to compute the immediate dominator tree and loop hierarchy.
- Patches implementing scalar evolution and integrating it with
the main verification pass:
- "bpf: allow precision backtracking between overlapping checkpoints"
- "bpf: compute scalar evolution expressions for loops"
- "bpf: use SCEV to widen bounded loops"
- "bpf: avoid widening registers that hinder exact stack-slot tracking"
- Tests and test harness updates.
Literature
==========
- "Symbolic Evaluation of Chains of Recurrences for Loop Optimization"
Robert A. van Engelen, 2000
- "The CR# Algebra and its Application in Loop Analysis and Optimization"
Robert A. van Engelen, 2004
Supported patterns
==================
As scalar evolution analysis attempts to infer recurring relationships
from algebraic expressions describing loop variables, there are some
limitations on what can be expressed.
Below is a list of patterns that are expected to work with the current
implementation. The examples are pseudo-code for the indicated BPF
instruction shapes.
Loop widening currently requires allow_uninit_stack, the verifier mode
that permits reading uninitialized stack bytes. This requirement applies
even to loops that use only registers. Without it, the verifier uses
its existing iteration-by-iteration checking.
1. Counted loops, including decreasing counters:
u64 i = 0;
do { i += 1; } while (i < 10);
u64 j = 3;
do { j += -1; } while (j != 0);
Header ranges are i in [0,9] and j in [1,3].
Pre-condition loops, such as while (i < 10) { i += 1; },
are also supported. The counter can reside in a register or a fixed
8-byte frame-pointer spill.
2. Strided accesses into a map value:
/* bytes is a map-value array with at least 16 bytes. */
u64 i = 0, off = 0;
do {
bytes[off] = 1;
i += 1;
off += 2;
} while (i < 8);
At the header, off is in [0,14] with step 2. The byte store stays
within the map value even though i and off are tracked separately.
3. A nonconstant entry value with a separate counted induction variable:
u64 x = bpf_get_prandom_u32() & 6; // {0,2,4,6}
u64 i = 0;
do { x += 6; i += 1; } while (i < 3);
The counter i supplies the bound. At the header, x widens to [0,18]
with step 2, retaining the alignment common to its entry values and
its slope; x itself need not start at a constant.
4. Conditional assignment from an invariant value:
u64 x = 5;
for (u64 i = 0; i < 3; i += 1)
if (i == 1) x = 10;
return x;
Widening joins the pre-loop value 5 with the assigned value 10,
giving x in [5,10] both inside and after the loop.
5. Early exits in addition to the counted backedge:
u64 i = 0;
do {
if (bpf_get_prandom_u32() == 0) break;
i += 1;
} while (i != 3);
The counter still bounds the loop. An additional exit reduces the
available lower-bound information; it does not by itself prevent
widening.
6. Array accesses through different memory types:
Bounded varying offsets are supported for arrays in BTF-typed
objects, stack memory, map values and keys, packet data and
metadata, and memory buffers. The usual bounds, alignment and
access restrictions still apply.
For stack arrays indexed by a widened loop counter, only byte and
half-word accesses are supported; see limitation 5 below.
For an array in a BTF-typed object:
struct inner { int a, b; };
struct object { struct inner arr[8]; };
/* o points to a live, non-NULL BTF-typed struct object. */
u64 i = bpf_get_prandom_u32() & 7;
value = o->arr[i].b;
The 4-byte load has offsets 4 + 8*i, i in [0,7]. Bounds keep
accesses within arr; base and step 8 ensure that each possible
offset selects member b. Such accesses also work without a loop.
7. Nested loops with separate counters:
u64 i = 0;
do {
u64 j = 0;
do {
/* body */
j += 1;
} while (j < 3);
i += 1;
} while (i < 4);
Both loops can be widened: i is in [0,3] at the outer header,
and j is in [0,2] at the inner header. The inner counter is reset
on each outer iteration; i is unchanged by the inner loop.
8. Incrementing and comparing a pointer directly:
/* bytes is a map-value array with at least 8 bytes. */
u8 *p = bytes, *end = bytes + 8;
do {
*p = 1;
p++;
} while (p != end);
The initial pointer and fixed end pointer give eight iterations,
without a separate integer counter. At the loop header, p ranges
from bytes to bytes + 7, so each byte store stays within the array.
Deriving the iteration count requires the compared pointers to have
a provable common memory origin.
9. A loop bounded by an exit other than the latch:
u64 i = 0, len = 14;
do {
if (i == len)
break;
use(i);
i += 1;
} while (i != 64);
Every exit condition dominating the latch bounds the iteration
count; the smallest bound wins. Here i is in [0,14] at the header,
not [0,63], so use(i) sees the range established by the break.
Limitations
===========
Patterns that lose precision after widening
-------------------------------------------
Widening can lose information that the verifier gets by checking
each iteration separately. For example:
r7 = 5;
for (r6 = 0; r6 < 3; r6++)
if (r6 == 1)
r7 = 10;
if (r7 != 10)
invalid_stack_read();
R7 is always 10 at the real exit, but is represented as [5, 10] at
loop entry and after the loop. The verifier therefore cannot exclude
the invalid read and rejects this otherwise safe program.
It would be hard to avoid this limitation.
The same issue affects correlated linear counters at loop exit:
u64 i = 0, off = 0;
while (i < 8) {
i++;
off += 2;
}
if (off != 16)
invalid_stack_read();
Enumeration establishes off == 16. Widening tracks i and off
independently, and the exit check on i does not reconstruct off's exact
final value. This can be lifted after analysis adjustments.
Patterns not widened yet
------------------------
If one of the variables modified in the loop cannot be widened, the
verifier checks each iteration instead. Examples include:
1. 32-bit recurrences and comparisons:
for (u32 i = 0; i < 8; i++) // ALU32 / JMP32
use(i);
Only 64-bit arithmetic and comparisons are supported.
This limitation will be lifted.
2. Non-linear updates:
for (u64 i = 1; i < 16; i *= 2) // non-linear recurrence
use(i);
Recognition is currently limited to simple additive recurrences.
Literature describes a way to represent this, but it is not
considered a priority at the moment.
3. A controlling counter or bound that is not constant at loop entry:
u64 limit = unknown_in_range(1, 8);
for (u64 i = 0; i < limit; i++)
use(i);
u64 i = unknown_in_range(0, 7);
while (i < 8)
i++;
Both loops have finite bounds, but iteration-count evaluation
currently requires concrete entry values. Other induction variables
may have nonconstant entry ranges once a separate counter establishes
the iteration bound. This limitation can be lifted eventually.
4. Alternative values referring to another evolving register:
r7 = 0;
for (r6 = 0; r6 < 4; r6++)
if (condition)
r7 = r6;
use(r7);
R6 changes on each iteration. Widening currently supports
conditional assignments only from constants or values that do not
change in the loop. This limitation can be lifted.
5. Stack addresses whose widening would lose precise slot tracking:
u64 slots[4];
for (u64 i = 0; i < 4; i++)
slots[i] = i;
struct bpf_dynptr dptrs[4];
for (u64 i = 0; i < 4; i++)
bpf_dynptr_from_xdp(ctx, 0, &dptrs[i]);
Keep such indices concrete for 4- and 8-byte stack loads/stores and
calls requiring fixed-offset stack objects. Dependencies inside
nested loops also constrain the outer loop.
It would be hard to lift this limitation.
6. Values modified by a nested loop do not get a closed-form summary
for the enclosing loop:
u64 sum = 0;
for (u64 i = 0; i < 4; i++)
for (u64 j = 0; j < 4; j++)
sum++;
use(sum);
The inner loop may widen, but the outer analysis forgets values
modified by it rather than deriving the combined recurrence.
This limitation can be lifted.
7. Multiple backedges and irreducible control flow:
i = 0;
H: if (i >= 8) goto done;
if (condition) { i++; goto H; } // first backedge
i++; goto H; // second backedge
done:
i = 0;
if (condition) goto body; // second entry into the loop
H: i++;
body:
if (i < 8) goto H;
Widening requires a reducible loop with one backedge and a supported
dominating exit condition. Multiple exits are supported, but their
early-exit paths reduce what can be inferred about iteration counts.
It is unclear whether this can be lifted at the moment.
8. Large slopes and unsupported iteration bounds:
for (u64 i = 0, x = 0; i < 4; i++) {
use(x);
x += 65536; // slope outside signed 16 bits
}
Slopes used for linear widening must be nonzero signed-16-bit
constants. The inferred number of header executions must be finite
and less than U32_MAX. Counter wraparound must be ruled out while
deriving the bound.
9. Incompatible pointer alternatives or comparison operands:
p = &map_a[0];
q = &map_b[0];
for (u64 i = 0; i < 10; i++) {
if (i == 5)
p = q;
use(*p);
}
At the loop header, p has SCEV ANY(p_entry, q). The alternatives
point into different maps, so their offsets cannot be joined while
retaining one map's metadata. Joining invariant pointer
alternatives requires compatible pointer metadata, including type,
origin IDs, frame number.
10. Some hard-coded constant limits:
- Programs with more than 16 nested loops in one function are rejected.
- Loops with more than 256 exits exceed the metadata limits and are
not analyzed for widening.
- At most 4 exit conditions dominating the latch are consulted for
the iteration count of a loop.
- Expression traversal is limited to depth 8. Only a small fixed number
of alternative values can be joined.
Veristat changes
================
The main impact of the series is a 23% reduction in number of
processed instructions on a subset of Meta BPF programs.
Verdict changes
---------------
Two programs flip succes->failure, both selftests whose expectations
are updated by the series:
- verifier_gotox/gotox_edges_at_limit: test's CFG is a nest of ~1000
irreducible loops, deeper than the per-function loop stack (16),
the program is rejected with "Too many nested loops".
- verifier_scev/conditional_assignment_on_second_iteration:
a value assigned on the second iteration is checked after the loop
with its widened range, so a stack read guarded by that check
is rejected.
No program from the production corpora changes verdict.
Regressions
-----------
20 programs regress by 30-33% and 6 more by 10-21%, all from an
appliction objects sharing one unwinder library.
All programs share a common reason for regression:
- a big outer loop contains several smaller nested loops;
- nested loops are now widened and coverge, their convergence
adds backedges to the outer loop's SCC, thus flipping
checkpoint comparisons with the outer loop to RANGE_WITHIN mode.
Support for 32-bit recurrences and comparisons widens these loops too
and removes the regression. This would be handled in a followup.
Statistics
----------
A: master; B: scev-minimal-v3. Corpora: cilium, meta, scx, selftests.
Insns counts verifier-processed instructions, not program size.
Object exclusions: verifier_scev.bpf.o.
Histogram: selected programs, without the table filters.
Total progs: 7952
Old success: 5637
New success: 5646
total_insns diff min: -99.84%
total_insns diff max: 61.90%
0 -> value: 0
value -> 0: 0
total_insns abs max old: 837,487
total_insns abs max new: 837,487
-100 .. -95 %: 15
-95 .. -90 %: 12
-90 .. -85 %: 10
-85 .. -75 %: 8
-75 .. -70 %: 6
-70 .. -65 %: 14
-65 .. -60 %: 38
-60 .. -55 %: 10
-55 .. -50 %: 17
-50 .. -45 %: 36
-45 .. -40 %: 9
-40 .. -35 %: 25
-35 .. -25 %: 10
-25 .. -15 %: 11
-15 .. -10 %: 48
-10 .. -5 %: 47
-5 .. 0 %: 111
0 .. 5 %: 7488
5 .. 15 %: 3
15 .. 25 %: 5
30 .. 35 %: 20
35 .. 40 %: 7
40 .. 50 %: 1
60 .. 65 %: 1
Tables: success in both runs; baseline Insns >= 5,000.
Ranked by percentage change, then instruction-count change, file, program.
Meta names are anonymized; numbered objects are distinct files.
Top wins (50)
-------------
File Program Insns (A) Insns (B) Insns (DIFF)
---------------------------------- --------------------------------- --------- --------- -----------------
verifier_bounds.bpf.o crossing_64_bit_signed_boundary_2 12330 20 -12310 (-99.84%)
verifier_iterating_callbacks.bpf.o test1 7004 12 -6992 (-99.83%)
bpf_iter_tasks.bpf.o dump_task_sleepable 85522 556 -84966 (-99.35%)
bpf_iter_task_stack.bpf.o dump_task_stack 7209 65 -7144 (-99.10%)
profiler-10.bpf.o hhvm_stack 23828 347 -23481 (-98.54%)
bpf_iter_unix.bpf.o dump_unix 9026 226 -8800 (-97.50%)
meta-app-22.bpf.o program-03 8705 319 -8386 (-96.34%)
meta-app-22.bpf.o program-06 8948 328 -8620 (-96.33%)
security-sandbox-10.bpf.o fork 30760 1249 -29511 (-95.94%)
profiler-02.bpf.o on_py_event 79064 3864 -75200 (-95.11%)
profiler-03.bpf.o on_py_event 79064 3864 -75200 (-95.11%)
profiler-05.bpf.o on_py_event 79064 3864 -75200 (-95.11%)
security-monitor-66.bpf.o mac_sysctl_write 7333 448 -6885 (-93.89%)
profiler-04.bpf.o get_task_stacks 73176 6050 -67126 (-91.73%)
security-monitor-65.bpf.o lsm_bprm_creds_for_exec 17538 1701 -15837 (-90.30%)
security-monitor-65.bpf.o lsm_task_alloc 5674 565 -5109 (-90.04%)
security-monitor-65.bpf.o lsm_fo_task_update 11399 1181 -10218 (-89.64%)
security-sandbox-29.bpf.o test_glob_match 47257 5477 -41780 (-88.41%)
load-balancer-17.bpf.o edgeloom_tc 24854 2984 -21870 (-87.99%)
profiler-13.bpf.o handle_aten_op_call_start 7183 976 -6207 (-86.41%)
security-monitor-65.bpf.o lsm_file_open 154412 21168 -133244 (-86.29%)
security-monitor-17.bpf.o test_execve 293300 46071 -247229 (-84.29%)
security-sandbox-13.bpf.o kvm_die 36514 5807 -30707 (-84.10%)
security-monitor-97.bpf.o child_iter 41266 8182 -33084 (-80.17%)
scheduler-30.bpf.o lavd_dispatch 290915 66359 -224556 (-77.19%)
security-monitor-25.bpf.o syscalls_kill 98038 27912 -70126 (-71.53%)
security-sandbox-14.bpf.o kernel_module_request 7880 2357 -5523 (-70.09%)
security-sandbox-14.bpf.o kernel_load_data 7881 2358 -5523 (-70.08%)
security-sandbox-14.bpf.o kernel_read_file 7882 2359 -5523 (-70.07%)
xdp_lb_bench.bpf.o xdp_lb_bench 27126 9208 -17918 (-66.05%)
firewall-05.bpf.o ingress 54034 18584 -35450 (-65.61%)
firewall-05.bpf.o tc_in 54034 18584 -35450 (-65.61%)
firewall-07.bpf.o ingress 54034 18584 -35450 (-65.61%)
firewall-07.bpf.o tc_in 54034 18584 -35450 (-65.61%)
security-sandbox-01.bpf.o bpf 30692 10586 -20106 (-65.51%)
security-monitor-34.bpf.o syscall_setresuid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setfsgid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setfsuid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setgid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setregid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setreuid 122200 43305 -78895 (-64.56%)
security-monitor-34.bpf.o syscalls_setuid 122200 43305 -78895 (-64.56%)
security-monitor-15.bpf.o cve_2021_4034 122481 43629 -78852 (-64.38%)
security-monitor-16.bpf.o test 122517 43665 -78852 (-64.36%)
security-sandbox-10.bpf.o exec 12908 4626 -8282 (-64.16%)
security-monitor-12.bpf.o connect_security_socket_connect 216252 78013 -138239 (-63.92%)
security-monitor-19.bpf.o kernel_modules_do_init 92980 33776 -59204 (-63.67%)
security-monitor-23.bpf.o enter_pivot_root 93518 34311 -59207 (-63.31%)
security-monitor-08.bpf.o bpf_prog_detect 93384 34494 -58890 (-63.06%)
firewall-05.bpf.o egress 58436 21951 -36485 (-62.44%)
Top losses (38)
---------------
File Program Insns (A) Insns (B) Insns (DIFF)
-------------------------------- ----------------------------- --------- --------- ----------------
profiler-26.bpf.o handle_cu_mem_address_reserve 34326 45724 +11398 (+33.21%)
profiler-26.bpf.o handle_cu_mem_create 34326 45724 +11398 (+33.21%)
profiler-26.bpf.o handle_malloc 34326 45724 +11398 (+33.21%)
profiler-26.bpf.o handle_cu_mem_map 34524 45922 +11398 (+33.01%)
profiler-19.bpf.o sched_waking 17454 23153 +5699 (+32.65%)
profiler-27.bpf.o handle_cuda_launch_exc 17477 23176 +5699 (+32.61%)
profiler-27.bpf.o handle_cuda_launch 17490 23189 +5699 (+32.58%)
profiler-12.bpf.o on_custom_event_begin 17697 23396 +5699 (+32.20%)
profiler-12.bpf.o on_custom_event_end 17701 23400 +5699 (+32.20%)
profiler-26.bpf.o handle_mtia_cached_alloc 35494 46892 +11398 (+32.11%)
profiler-26.bpf.o handle_mtia_allocate_enter 35555 46953 +11398 (+32.06%)
profiler-26.bpf.o handle_pytorch_malloc 35847 47245 +11398 (+31.80%)
profiler-19.bpf.o oncpu 17990 23689 +5699 (+31.68%)
profiler-12.bpf.o on_task_enqueued 18035 23734 +5699 (+31.60%)
profiler-12.bpf.o sched_waking 18070 23769 +5699 (+31.54%)
profiler-12.bpf.o on_task_dequeued 18210 23909 +5699 (+31.30%)
profiler-12.bpf.o on_request_context_event 18301 24000 +5699 (+31.14%)
profiler-12.bpf.o on_pytorch_event 18302 24001 +5699 (+31.14%)
profiler-12.bpf.o on_task_stats 18384 24083 +5699 (+31.00%)
profiler-12.bpf.o oncpu 18488 24187 +5699 (+30.83%)
profiler-19.bpf.o sched_switch_offcpu 64726 78210 +13484 (+20.83%)
profiler-12.bpf.o sched_switch 33515 40257 +6742 (+20.12%)
profiler-09.bpf.o on_custom_event_start 38281 45973 +7692 (+20.09%)
profiler-09.bpf.o trace_func_entry 38281 45973 +7692 (+20.09%)
profiler-12.bpf.o get_crochet_walltime_stacks 43473 50215 +6742 (+15.51%)
profiler-24.bpf.o get_task_stacks 94740 103742 +9002 (+9.50%)
test_cls_redirect_subprogs.bpf.o cls_redirect 72052 73682 +1630 (+2.26%)
security-sandbox-20.bpf.o redirect_socket_connect 72423 73913 +1490 (+2.06%)
scheduler-28.bpf.o arena_alloc_mask 27159 27175 +16 (+0.06%)
scheduler-30.bpf.o arena_alloc_mask 27159 27175 +16 (+0.06%)
scx_cake.bpf.o arena_alloc_mask 28721 28737 +16 (+0.06%)
scx_arena.bpf.o arena_alloc_mask 28734 28750 +16 (+0.06%)
scx_arena_selftests.bpf.o arena_alloc_mask 28734 28750 +16 (+0.06%)
scx_chaos.bpf.o arena_alloc_mask 28734 28750 +16 (+0.06%)
scx_p2dq.bpf.o arena_alloc_mask 28734 28750 +16 (+0.06%)
scx_cake.bpf.o cake_init_task 28758 28774 +16 (+0.06%)
scheduler-01.bpf.o arena_alloc_mask 29197 29208 +11 (+0.04%)
scheduler-03.bpf.o arena_alloc_mask 29197 29208 +11 (+0.04%)
Changelog
=========
v2 -> v3:
TLDR: another bunch of major correctness fixes, plus several improvements
to avoid veristat-meta failure identified for v2.
- Widen only when allow_uninit_stack is set.
- Mark scalar registers and stack spills used by the selected bounding
condition's base, step and bound expressions precise before widening.
- Join alternative values only for registers with compatible pointer
metadata. Include the loop-entry value when a register is assigned an
invariant in the body, including unconditional assignments.
- Consider up to four exit conditions dominating the backedge and use
the tightest available iteration bound. Match the induction variable
in either operand of the comparison.
- Require full spills for linear stack recurrences. Treat partially
spilled and unallocated stack slots as unknown scalars and all-zero
slots as zero. Materialize writable stack values safely, growing the
stack when needed.
- Keep base/step in sync with the bounds as the last step of
reg_bounds_sync(). Preserve the register state when sign extension
leaves all possible values unchanged. Check that step is nonzero and
base is smaller than step.
- Handle latch comparison polarity correctly when the continuing branch
enters a nested loop. Compute SCEVs only for exits owned by the loop,
fixing a verifier bug for irreducible inner loops.
- Exclude BPF_F_INNER_MAP single-element arrays from the separate-lookup
shortcut in bpf_same_memory_origin().
- Fix stack-pointer tracking through load-acquire/store-release and
atomic exchange/fetch/cmpxchg operations, so accesses through recovered
stack pointers are included in liveness analysis.
- Derive global subprogram stack effects from BTF argument types, so
freplace cannot invalidate a loop termination proof based on the
original callee body.
- Compute argument liveness from callee reads for static subprograms
and from BTF-declared arguments for globals. Prepare argument metadata
before liveness analysis, avoiding unnecessarily live registers that
prevented widening.
- Treat already-unbounded scalars as already widened, allowing unknown
SCEVs such as stack outputs of probe-read helpers called through a
subprogram.
- Widen to an unbounded range when computing an induction variable's
range overflows signed 64-bit arithmetic, retaining the power-of-two
alignment common to the entry value and slope.
- Fix dominator computation for subprograms whose entry is a loop header:
initialize the entry as its own dominator during the fixed-point
computation and skip updates to it. Use overflow-checked predecessor
allocations.
- Replace the private worklist heap with the kernel min-heap and limit
expression rewriting to 32 passes before falling back to unknown.
- Add regression coverage for the liveness, stack, pointer, iteration
bound and widening changes. Fix __msg_next validation when an expected
message is missing.
v1 -> v2:
TLDR: a bunch of major correctness fixes.
- Introduce arg_access_info to distinguish read, may-write and
must-write effects of helper/kfunc stack accesses. Handle map-specific
argument semantics and writes through unknown callbacks.
- Fix base/step tracking across signed overflow, truncation,
sign/zero extension and linked-register updates.
- Rework iteration-count calculation for signed/unsigned increasing
and decreasing counters, including counter overflow checks.
Evaluate the full latch base expression and consistently count
header executions.
- Substitute all registers in instantiate_header_scevs().
- Track pointer origins when evaluating latch expressions.
Require compatible operands before deriving iteration bounds.
- Preserve the correct congruence base when widening nonconstant
entry values, assign fresh IDs to widened packet pointers,
and exclude nullable pointers from widening.
- Account for values modified on nested-loop exit paths when computing
invariants. Do not use an inner loop's latch to bound an outer loop.
- Restrict pruning against in-progress SCEV states to terminating
innermost loops sharing the same entry checkpoint, preventing
inner-loop pruning from hiding a nonterminating outer loop.
- Rework loop entry/exit handling on the main verification pass.
- Extend fixed-stack-offset widening suppression to ANY expressions
and all dynptr arguments described by helper/kfunc prototypes.
- Fix BTF array handling: retain bounds checks for fixed arrays inside
flexible-array elements and preserve array type IDs when element
types contain typedefs.
- Fix SCEV handling of endian conversions and narrow fills on
big-endian systems.
- Grow expression storage geometrically and scale the expression hash
table with program size. Add cancellation/rescheduling checks to
dominator computation and fix the postorder-number allocation leak.
- Pack bpf_reg_state/bpf_func_state for latter to fit back into
the 1 KiB allocation bucket, measured SCEV memory consumption
overhead is 3% now.
- Major additions in the selftests.
v1: https://lore.kernel.org/bpf/20260926-scev-minimal-rebase-v1-0-c8e5ab5ba79f@gmail.com/
v2: https://lore.kernel.org/bpf/20261004-scev-minimal-rebase-v2-0-f6254e29fdf2@gmail.com/
---
====================
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-0-bcba9bc53ac9@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
|
- Computed expression shapes: register and spilled-counter recurrences,
substitution at latches, agreeing and conflicting backedge updates,
and ALU, extension, byte-swap, load/store and atomic expressions.
- Iteration bounds and header-visit counts for:
- pre-condition loops using JEQ, JLT, JLE, JGE and JGT;
- post-condition loops using JLT, JLE, JGE, JGT and JNE;
- signed pre- and post-conditions using JSLT, JSLE, JSGT and JSGE;
- increasing and decreasing counters, nonzero initial values,
immediate and invariant-register bounds, and immediate exits;
- additional exits that reduce the minimum iteration count or
tighten the upper bound;
- rounded bounds, counter wraparound, count overflow, extreme
steps and JNE divisibility.
- Widening, backedge clamping and state-pruning convergence,
including multiple induction variables used for map-value accesses
and nonconstant entry values requiring a common alignment.
Check precision propagation to initial values and bounds.
- Nested and sibling loops, shared headers, exits to another loop
header, exits across multiple nesting levels, and side entries
into loop nests.
Check conservative summaries for irreducible children while still
widening supported reducible descendants, value preservation on
inner-loop exits, and detection of nonterminating outer loops.
- Invalidation of stack-slot expressions after indirect stack writes
and global calls. Widening across bpf_probe_read_kernel() calls
in static subprograms.
- Stack spill widths and slot states, including narrow spills, zero,
unallocated and STACK_MISC slots, and counters spilled and filled
using store-release/load-acquire.
- Avoid widening registers used to address stack spills, fills and
dynptr constructor arguments, including dependencies through nested
loops. Conversely, allow widening addresses of byte-sized stores.
- Conditional assignments joining scalar values and stack pointers,
including preservation of a common base and gcd-derived step.
- Pointer widening and comparisons with compatible memory origins,
fallback for incompatible origins and nullable pointers, and
invalidation of stale packet pointer relationships.
- Conservative fallback for unsupported recurrences, unavailable
counter spills and zero computed header counts.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-51-bcba9bc53ac9@gmail.com
|
|
Coverage:
- straight-line code with an ldimm64 in the middle;
- an asymmetric if-then-else diamond (unequal-depth idoms_intersect());
- a simple loop, a loop with an if-else body, and nested loops;
- a loop header with two back edges (three predecessors);
- an irreducible CFG (fixpoint convergence);
- immediate dominators across subprogram boundaries, including a callee
whose entry instruction is itself a loop header;
- a self-loop;
- an indirect jump (gotox) with a two-entry jump table.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-50-bcba9bc53ac9@gmail.com
|
|
Test cases covering the following branches in bpf_compute_loops():
- Case B: simple backedge creating a loop (loop_single)
- Case B: two independent loops (loop_two_independent)
- Case B + D: nested loops where the inner header's loop_header points
to the outer header (loop_nested)
- Case C: diamond CFG with no loops (fwd_edges_no_loop)
- Case D: sibling inner loops within one outer loop
(loop_nested_siblings)
- Three levels of loop nesting (loop_three_levels)
- Loop with an if-else body containing forward branches
(loop_with_if_else)
- Case E: An irreducible loop (loop_irreducible)
- A self-loop (loop_self)
- A test with sibling loops nested in outer loops
(loop_nested_siblings_common_ancestors)
- A test case with outer loop's backedge originating
from an inner loop (loop_outer_backedge_from_inner).
Cases B, C, D and E are described in loops.c:compute_loops_in_subprog().
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-49-bcba9bc53ac9@gmail.com
|
|
Verifier tests for accessing arrays at a varying offset through a
PTR_TO_BTF_ID pointer, e.g. a[i].b where 'i' is a register with a
varying value:
- bpf_obj_new() is used to obtain a PTR_TO_BTF_ID to a program-defined
struct
- bpf_get_current_task_btf() is used to obtain a PTR_TO_BTF_ID from
the kernel BTF.
The cases cover:
- in-bounds access to a field of an array of structs;
- out-of-bounds access where the maximal offset runs past the array;
- a scalar (long) array with a matching stride;
- a byte array (step 1);
- a 4-byte read whose maximal offset spills past the array end;
- an unaligned step that is not a whole number of elements;
- both dimensions of a 2D array;
- an array of pointers within a program-allocated object, where reading a
pointer member yields a SCALAR_VALUE but the varying offset is still
validated against the array bounds (in-bounds and out-of-bounds);
- a varying access into an array embedded in a kernel BTF type
(task_struct's comm[]), covering the non-allocated, trusted-pointer path
(in-bounds and out-of-bounds);
- an array nested below a struct member at a non-zero offset, exercising
the offset telescoping done while walking across a struct boundary
(in-bounds and out-of-bounds);
- a trailing flexible array member, whose unbounded tail makes a varying
access have no upper bound to exceed. A program-defined struct cannot be
used here because bpf_obj_new() forbids flexible array members, so a
kernel type (struct vring_used, with its 'ring[]' tail) is used
(in-bounds, and an unaligned step that is not a whole number of
elements).
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-48-bcba9bc53ac9@gmail.com
|
|
Tests for the base/step reasoning in states.c:range_within():
- step_prune_hit_multiple: prune a step-4 range contained in a cached
step-2 range when the scalar is used to address the stack.
- step_prune_miss_non_multiple: do not let a cached step-2 range hide a
step-3 path reaching division by zero.
- step_prune_hit_const_on_line: prune constant 6 against a cached
base-0, step-3 range.
- step_prune_miss_const_off_line: do not prune constant 7 against that
range even though its bounds and tnum admit the value.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-47-bcba9bc53ac9@gmail.com
|
|
- step_arith{32,64}_no_overflow: non-overflowing +, *, <<
operations maintain step and base.
- step_neg_value_range: Preserve the signed range of {-3, 0, 3, 6}
when intersecting with a non-power-of-two step across zero.
- step_arith{32,64}_overflow: Reset the stride and preserve valid
bounds when a {32,64}-bit operation wraps.
- step_mov32_truncate: Reset the stride when MOV32 discards nonzero
upper bits from positive values.
- step_mov32_negative: Reset the stride when MOV32 zero-extends
the low 32 bits of negative signed values.
- step_movsx: Reset the stride when sign extension changes the
register value.
- step_movsx_bounds_on_line: Keep bounds and stride when sign
extension does not change the register value.
- step_bounds_resync_after_arith: Snap bounds refined from var_off
back onto the line.
- step_linked_regs_add64: Translate both bounds and base when
propagating a comparison's refinement through a scalar-ID delta.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-46-bcba9bc53ac9@gmail.com
|
|
A static callee contributes the registers its code reads at the entry,
a global callee its declared arguments.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-45-bcba9bc53ac9@gmail.com
|
|
Check that passing a stack pointer to a no-op global callee produces:
- use, def and may_def marks for a fixed-size memory argument.
- No stack effects for an untrusted BTF pointer argument.
This verifies that call effects follow the declared argument types
rather than the callee's body.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-44-bcba9bc53ac9@gmail.com
|
|
Tests for helper arguments whose access size or read/write effects
depend on the map:
- helper_map_output_known_size checks that for a known map access
MEM_WRITE | MEM_UNINIT produces a must_write mark.
- helper_map_output_merged_sizes checks that when maps with different
value sizes merge, MEM_WRITE | MEM_UNINIT produces use and may_def
marks over the maximum value size, without a def mark.
- helper_bloom_peek_input checks that for bpf_map_peek_elem()
on a bloom filter the buffer is treated as an input.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-43-bcba9bc53ac9@gmail.com
|
|
Check stack write tracking for atomic operations:
- Restored by 64-bit load-acquire, xchg, fetch_add and cmpxchg.
- Spilled by store-release and restored by a plain load.
- Restored from a caller's stack slot by xchg in a callee.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-42-bcba9bc53ac9@gmail.com
|
|
Liveness analysis should produce may_def marks for read-modify-write
atomic operations:
- lock *(u64 *)(r10 -8) += r1
- r1 = atomic64_fetch_add((u64 *)(r10 -8), r1)
- r1 = atomic64_xchg((u64 *)(r10 -8), r1)
- r0 = atomic64_cmpxchg((u64 *)(r10 -8), r0, r1)
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-41-bcba9bc53ac9@gmail.com
|
|
Branches to cover:
- per-insn writes (record_stack_access_off):
* off_cnt==1, fully covered slots -> def + may_def (equal)
* partial coverage -> may_def only (no def)
* off_cnt 2-4, precise offsets -> may_def only, per offset
- whole-frame writes:
* off_cnt==0 (offset lost) -> may_def SPIS_ALL
* ARG_IMPRECISE (frame lost) -> may_def SPIS_ALL per frame
- merge_instances():
* both passes touch a frame -> may_def union
* one pass leaves a frame untouched -> may_def preserved
- merge_may_write(): a callee's writes into ancestor frames are
summarized as may_def at the caller's call instruction
- analyze_subprog() -> may_def stack slot range
when callback is unknown.
Tests exercising them:
- may_write_two_precise_offsets - off_cnt 2-4 precise multi-offset
- imprecise_frame_write - cross-frame ARG_IMPRECISE write,
plus its caller-side summarization
- merge_preserves_may_write - map-value vs stack pointer at two
callsites: union is preserved when
one pass does not touch the frame
- must_write_not_same_slot - off_cnt==0 whole-frame may_def
- two_byte_write_no_kill - partial write, may_def without def
- kfunc_iter_stack_liveness - full-slot def == may_def
- helper_output_unknown_size - output size unknown to liveness,
may_def without use or def
- caller_stack_write,
conditional_stx_in_subprog,
shared_instance_must_write_overwrite
- callee writes summarized as may_def
at the call site
- bpf_loop_two_callbacks - call to unknown callback marks full
stack range as may_def.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-40-bcba9bc53ac9@gmail.com
|
|
Validate changes from:
"bpf: allow subrange relations for PTR_TO_STACK in regsafe()".
Add a test case that checks that a widened stack pointer with range
[-72, -16] is considered a superset of a stack pointer with range
[-64, -16].
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-39-bcba9bc53ac9@gmail.com
|