https://www.vusec.net/projects/btr/ was announced today: We present Branch Target Reuse (BTR), a new Spectre-v2 attack targeting just-in-time (JIT) compilers. BTR affects the JIT engines found in web browsers, language runtimes, and the operating system kernel, across multiple CPU vendors. We analyzed the attack surface of Linux cBPF, Oracle GraalVM and SpiderMonkey (the JIT engine of the Firefox browser), and built two end-to-end exploits against the Linux kernel.
The key insight behind the attack is that, while modern CPUs restore architectural code coherence after self-modification, they do not necessarily invalidate stale indirect branch prediction entries (i.e., branch targets). In JIT engines, these stale targets can outlive the original code and later be reused when the code cache is repopulated, yielding a speculative execute-after-free primitive. This allows attackers to hijack speculative control flow to newly generated code at obsolete offsets, bypassing software hardening or reaching misaligned gadgets. The paper is at: https://download.vusec.net/papers/btrccs26.pdf
And their PoC code: https://github.com/vusec/btr
As for mitigations: Linux kernel. The kernel developers upstreamed a new mitigation for x86 that issues an IBPB on all cores when a cBPF program reuses a previously executed cBPF/eBPF region, and discourages such reuse as an optimization. The mitigation applies whether or not IBT is enabled. Two CVEs were assigned:
CVE-2026-64507 – x86/bugs: Enable IBPB flush on BPF JIT allocation CVE-2026-64508 – bpf: Support for hardening against JIT spraying
Oracle. GraalVM instead hinders region reuse by randomizing JIT code-cache locations.
Mozilla. Mozilla considered IBPB-based mitigations, but is currently prioritizing the completion and deployment of site isolation. -- -Alan Coopersmith- alan.coopersmith () oracle com Oracle Solaris Engineering - https://blogs.oracle.com/solaris
In the Linux kernel, the following vulnerability has been resolved:
KVM: x86/mmu: Check write tracking in all address spaces
kvmgfniswritetracked() checks only the supplied memslot, but page tracking is per-address-space and shadow pages are shared across all address spaces. With SMM, a GFN can therefore be write-tracked in one address space and appear untracked through the other.
Check the supplied slot first, then the slot for the other address space. This ensures all callers honor write tracking regardless of the active address space. In particular, it prevents mmutrytounsyncpages() from marking an upper-level shadow page unsync and eventually triggering the BUG in ptelistremove().
[invert direction of the conditional. - Paolo]
In the Linux kernel, the following vulnerability has been resolved:
cgroup: Avoid iteration of dying tasks with zero refcount
The commit 260fbcb92bbea ("cgroup: Move dyingtasks cleanup from cgrouptaskrelease() to cgrouptaskfree()") extended the lifetime of tasks on the dyingtasks list. The iterators have provision to go through dyingtasks because of dying threadgroup leaders or explicit CSSTASKITERWITHDEAD, however, it was expected that such tasks can obtain a new reference (that is possible before cgrouptaskrelease()/puttaskstructrcuuser()). The tasks after cgrouptaskrelease() and before cgrouptaskfree() are subject to race when they may or may not have ->usage count > 0.
The race window is between csstaskiternext() invocations when csssetlock is released and we may arrive at a new ->taskpos. The iterator should not attempt to resurrect tasks whose ->usage count dropped to zero. (When that happens, puttaskstructrcucb() is already imminent and the returned taskstruct would could be used after free.)
As for the fix, we cannot simply check the signal->live count of a task on the dying list because that won't distinguish regular zombies waiting to be reaped from RCU remnant tasks that are going to be free'd. Therefore add an extra check to rule out ->usage==0 tasks from any iteration.
The repeat: loop in csstaskiteradvance() doesn't consider ->usage count, so add a new loop to csstaskiternext() to skip de-used tasks on the dyinglist.
Rough illustration of the possible race
R (reader of cgroup.procs) T (thread) L (group leader) --------------------------------- -------------------------------- -------------------------------- L exits, signal->live > 0 cgrouptaskdead(L) csssetskiptaskiters() // skips only cset->tasks listaddtail(&L->cglist, &cset->dyingtasks) csstaskiternext() take csssetlock csstaskiteradvance() leader && signal->live != 0 => it->taskpos = &L->cglist release csssetlock T exits --signal->live == 0 cgrouptaskdead(T) // csssetlock releasetask(T) cgrouptaskrelease(T) releasetask(L) // zapleader cgrouptaskrelease(L) puttaskstructrcuuser(L) ...RCU... puttaskstruct(L) L->usage = 0 / L still on dyingtasks / ...RCU... puttaskstruct(L) csstaskiternext() // another iteration take csssetlock it->taskpos = &L->cglist gettaskstruct(L) => addition on 0 drop csssetlock cgrouptaskfree(L) csssetskiptaskiters() // dying skip comes too late freetask(L) cgroupprocsshow() taskpidvnr(L)
In the Linux kernel, the following vulnerability has been resolved:
nvdimm: pmem: keep PREFLUSH before data writes
pmemsubmitbio() records a REQPREFLUSH error, but continues to copy the bio data and can later overwrite the error with a successful REQFUA flush. That lets data writes run after a failed preflush and can complete the bio successfully despite the failed ordering barrier.
Run the REQPREFLUSH flush synchronously before touching the bio data and complete the bio with the flush error if it fails. Keep asynchronous flush chaining for REQFUA. At that point, data copy has completed and the parent bio can wait for the chained flush bio.
In the Linux kernel, the following vulnerability has been resolved:
smb/server: fix tree connection leak in smb2treeconnect()
See the procedure below:
smb2treeconnect ksmbdtreeconnconnect xastore(&sess->treeconns, treeconn->id, treeconn) ksmbdcounterinc(KSMBDCOUNTERTREECONNS) ksmbdsharetreeconninc(sc) ksmbdiovpinrsp // fail status.ret = KSMBDTREECONNSTATUSNOMEM // do not disconnect treeconn
Disconnect the new tree connection if ksmbdiovpinrsp() fails.
In the Linux kernel, the following vulnerability has been resolved:
staging: rtl8723bs: fix mismatched free of HalData in rtwsdioif1init()
padapter->HalData is allocated via vzalloc(), but incorrectly freed using kfree() in the rtwsdioif1init() error path. Using kfree() to release this vmalloc-backed buffer can lead to memory corruption.
Use rtwhaldatadeinit() to pair the free correctly and free HalData with vfree().
The bug was first flagged by an experimental static analysis tool we are developing for kernel memory-management bugs. Manual inspection confirms that the issue is still present in current mainline.
An x8664 allyesconfig build showed no new warnings. As we do not have suitable RTL8723BS SDIO hardware to test with, no runtime testing was able to be performed.
In the Linux kernel, the following vulnerability has been resolved:
wifi: iwlwifi: mei: pass correct argument to function
The first argument to iwlmeiwritecyclicbuf() should be the cldev but the qhead pointer is passed instead. Fix it.
In the Linux kernel, the following vulnerability has been resolved:
usb: typec: ucsi: unregister debugfs entries on teardown
ucsiregister() creates per-instance debugfs entries, but ucsiunregister() keeps them around until ucsidestroy().
Drivers like ucsiglink that unregister/register the same UCSI instance across remoteproc restart then try to create an already existing debugfs directory and log:
debugfs: 'pmicglink.ucsi.0' already exists in 'ucsi'
Unregister debugfs entries as part of ucsiunregister(), and clear ucsi->debugfs after freeing it so repeated unregister paths remain safe.
drm/msm: Recover HW before retire hung submit
In the Linux kernel, the following vulnerability has been resolved:
staging: rtl8723bs: fix xmitframe/xmitbuf leaks on mgnt-frame error paths
issuebeacon(), issueprobersp() and issueasocrsp() obtain a management xmitframe together with its xmitbuf from the driver's fixed-size management-TX pools via allocmgtxmitframe(). On the normal path the frame is handed to dumpmgntframe(), which transfers ownership and eventually returns both objects to their pools (the frame and, for beacons, the buf in rtl8723bsmgntxmit(); other bufs via the pending-xmitbuf/TX-completion path).
Several error/edge paths return early after a successful allocmgtxmitframe() but before dumpmgntframe(), so ownership is never transferred and neither object is freed:
- issuebeacon(): beacon larger than 512 bytes - issueprobersp(): curnetwork->ielength > MAXIESZ - issueprobersp(): kzalloc() of the SSID scratch buffer fails - issueasocrsp(): pkttype is neither ASSOCRSP nor REASSOCRSP
Because allocmgtxmitframe() removes the frame and buf from their free lists (listdelinit) without placing them on any pending list, an orphaned pair is on no list and referenced by nobody, so it is only reclaimed at driver teardown. Repeated hits progressively exhaust the management-TX pools until allocmgtxmitframe() returns NULL and the interface can no longer send beacons or probe/assoc responses.
Free the frame and buffer on these paths, matching the existing correct error handling in issueassocreq().
In the Linux kernel, the following vulnerability has been resolved:
RDMA/srpt: Fix srptallocrwctxs() unwind counters
When srptallocrwctxs() fails partway through a multi-buffer indirect descriptor, the unwind path destroys RDMA contexts but leaves stale nrwctx and nrdma values (and a dangling rwctxs pointer). Later sqwravail accounting in srptqueueresponse() or srptwritepending() can then subtract the wrong number of send queue credits.
Reset the counters and clear rwctxs after freeing the heap allocation before returning an error.
bpf: Mark bpfrefcount field as unique
In the Linux kernel, the following vulnerability has been resolved:
ext4: fix transaction overflow during writeback
Commit 95ad8ee45cdb ("ext4: correct the reserved credits for extent conversion") was correct to note that we need to reserve enough credits for all extents possibly underlying a large folio. However it was too eager to reduce the number of reserved credits. Extent conversion may not only need to touch several leaf extent blocks, it may also need to split extents - for example a single large unwritten extent may need to be split into many small written ones in case of sparse folio dirtying. This can thus result not only in extent leaf modifications but also in a need to allocate new extent tree nodes. As a result the reserved transaction credits were not sufficient in some corner cases. Use ext4metatransblocks() for correct upper bound credit estimate.
ACPI: platform: Use acpibusgetprimarydevice()
In the Linux kernel, the following vulnerability has been resolved:
net: hsr: free learned nodes on device setup failure
hsrdevfinalize() can fail after a lower-device RX handler has already been registered (slave A is added before the failable slave B and interlink adds). RX handlers run in softirq regardless of the master's state, so frames received in that window can learn dynamic nodes into nodedb, and the error unwind never releases them.
Free both owned dynamic databases in the unwind, mirroring hsrdellink(). proxynodedb is provably empty on every current error exit (only interlink RX feeds it, and the interlink add is the last failable step) and is freed for symmetry. The order is safe: hsrdelport() unregisters each RX handler with synchronizenet() before hsrdelnodes() runs, which removes remaining entries with listdelrcu() and defers their release with callrcu() for readers already under RCU.
In the Linux kernel, the following vulnerability has been resolved:
netfilter: nfnatsip: rewind offset when NAT shrinks the packet
sashiko says: If mapaddr() changes the packet length, such as when the public NAT IP string is shorter or longer than the internal IP, coff will still point to the offset relative to the pre-mangled packet. If the packet shrinks, coff could overshoot the correct position, potentially causing the next ctsipparseheaderuri() call to silently skip bytes and miss subsequent Contact headers. Could this lead to a failure to NAT those subsequent headers and leak internal network details?
In the Linux kernel, the following vulnerability has been resolved:
wifi: mt76: mt7921: validate CLC firmware records
The CLC region is supplied by firmware, but the loader trusts the region count and each record length. A malformed image can make the region table pointer precede the firmware buffer, make the record loop fail to advance, or index phy->clc past its end. Validate the table and record bounds before dereferencing or copying.
In the Linux kernel, the following vulnerability has been resolved:
pppasync: drop the errored frame instead of resetting its headroom
pppreceivenonmpframe() prepends a two-byte direction tag before running the pass/active BPF filters:
(be16 )skbpush(skb, 2) = htons(PPPFILTERINBOUNDTAG);
Nothing on the receive path guarantees those two bytes of headroom. The frame-error path in pppasync's processinputpacket() resets a reused skb's headroom to zero while claiming to restore it to a freshly allocated state - but a fresh skb from devallocskb() carries NETSKBPAD:
err: if (skb) { / make skb appear as freshly allocated / skbtrim(skb, 0); skbreserve(skb, - skbheadroom(skb)); }
ap->rpkt still points at that skb, so the next frame is reassembled into it with no headroom at all. A peer that sends a bad-FCS frame followed by one beginning ff 03 then leaves a single byte of headroom by the time the filter tag is pushed, which lands one byte below skb->head:
skbuff: skbunderpanic: len:49 put:2 head:ffff888003c10000 data:ffff888003c0ffff tail:0x30 end:0x640 dev:<NULL> kernel BUG at net/core/skbuff.c:214! RIP: 0010:skbpanic+0x13e/0x230 Call Trace: skbpush+0xbd/0x100 pppreceivenonmpframe+0x48a/0x1d10 pppinput+0x4e9/0x2f80 pppasyncprocess+0x2a/0xe0 taskletactioncommon+0x20f/0x8a0 handlesoftirqs+0x18e/0x590 Kernel panic - not syncing: Fatal exception in interrupt
Zeroing the headroom violates the NETSKBPAD guarantee that devallocskb() gives the rest of the receive path. Besides the filter panic above, when CCP compression is enabled pppdecompressframe() hands skb->data - 2 to ->decompress()/->incomp(), which then reads out of bounds before skb->head for the same reason.
Rather than restore the headroom, drop the errored frame - as pppsynctty already does on its error path - and clear ap->rpkt so the next frame is reassembled into a fresh skb with proper headroom. This is simpler and fixes both the filter under-panic and the CCP out-of-bounds read.
The original V1 of this patch made room in pppreceivenonmpframe() with skbcowhead(); Eric pointed out that fixing the root cause in the transport is the right approach.
Found by fuzzing the PPP receive path with a mutating peer on a pty; it is an interesting (remote) DoS: root configures PPP, the peer supplies two crashing frames. The reproducer (repro-ppp-skb.c, unchanged from v1) panics in about a second, and returns cleanly with this applied.
EDAC/devicesysfs: Use kstrtouint() for pollmsec to prevent truncation
In the Linux kernel, the following vulnerability has been resolved:
drm/virtio: use the DMA API for resource backing on Xen
On a Xen PV domain page addresses bear no relation to the real machine addresses the host would have to use to reach it. virtioring.c handles this correctly, vringusemapapi() returns true for any xendomain() regardless of VIRTIOFACCESSPLATFORM.
virtio-gpu makes the same decision independently, but its copy looks only at the feature bit:
bool usedmaapi = !virtiohasdmaquirk(vgdev->vdev);
QEMU does not set iommuplatform on virtio-vga by default, so VIRTIOFACCESSPLATFORM is not negotiated, usedmaapi is false, and virtiogpuobjectshmeminit() describes the framebuffer's backing pages to the host with sgphys(). Those are guest-physical addresses. In a PV domain they resolve, on the host side, to pages belonging to some other domain, so the host scans out unrelated memory.
Move the decision into virtiogpuusedmaapi() and give it the xendomain() check, like vringusemapapi() has. This additionally enables the dmasyncsgtablefordevice() calls in virtgpuvq.c, which are required for correctness whenever swiotlb is in play.
Reproduced with a Xen 4.21 PV dom0 nested inside QEMU 8.2 with virtio-vga, on both a distro 6.8 kernel and 6.18 LTS. A PVH dom0 works fine and doesn't need this fix because it is identity-mapped, only PV dom0s are affected.
accel/qaic: Address potential out-of-bounds read in respworker()
In the Linux kernel, the following vulnerability has been resolved:
nvme-rdma: fix -EIO cleanup order in queuerq
On -EIO, the RDMA queuerq path reports a host path error and then still cleans up the command and unmaps the SQE DMA. The path error helper completes the request, so that is double cleanup and DMA unmap after the request is already complete.
Unmap the SQE first, then report the host path error. Skip the outer command cleanup on that path.
In the Linux kernel, the following vulnerability has been resolved:
nvmet-rdma: fix queue leak when connect backlog is exceeded
When pending disconnecting queues exceed the backlog limit, the connect path only drops the device reference and leaks the newly allocated queue and its IB resources.
In the Linux kernel, the following vulnerability has been resolved:
nvme: fix racy access to FDP placement id array
nvmequeryfdpinfo() is called per-path and therefore prone to races.
It populates head->nrplids/head->plids for fdp registration. But nothing protects that pair from concurrent access - two paths scanning the same namespace can race to populate it.
Avoid the race by moving this initialization work to nvmeallocnshead() which is called once per shared namespace.
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix REG INVARIANTS VIOLATION on speculative pointer arithmetic
Take the following unprivileged program as an example:
r0 = bpfmaplookupelem(...) / PTRTOMAPVALUE, offset 0 / ... 14: r0 += r1 / r1 is a bounded scalar / 15: r9 = r0
Loading it triggers a verifier warning from regboundssanitycheck():
verifier bug: REG INVARIANTS VIOLATION (alu): const subreg tnum out of sync with range bounds r64={.base=0x0, .size=0x0} r32={.base=0x0, .size=0xffffffff} varoff=(0x0, 0x0)
What happens:
1. Processing insn 14 (r0 += r1) in adjustptrminmaxvals(), the new offset is computed into dstreg's varoff and 32/64-bit ranges.
2. Because pointer registers do not track 32-bit subregister bounds, markreg32unbounded() first sets r32 to the full range; r32 is re-derived from the offset at the end of the function by regboundssync().
3. On the unprivileged path, sanitizeptralu() is called and, via sanitizespeculativepath() -> pushstack(), snapshots the current register state and schedules the next instruction (insn 15) to be verified directly as a speculative path.
4. That snapshot is taken between step 2 and the final regboundssync(): at this point dstreg's varoff still holds the (const) original offset while r32 has just been blanked to the full range, i.e. the two are out of sync. When the speculative path later verifies insn 15 (r9 = r0), the inconsistent state reaches regboundssanitycheck() and trips the warning.
varoff and the 32-bit range must always be consistent. There are two ways to keep the snapshot consistent:
1. sync varoff and r32 before the snapshot so they match, or 2. leave r32 at its original (already consistent) value and blank it only after the snapshot.
The whole point of sanitizeptralu() is to insert a harmless masking sequence that keeps the access in bounds under speculation, so the state it snapshots should faithfully represent that. Take approach 2: move markreg32unbounded() to after sanitizeptralu(), so the speculative snapshot keeps the pointer's original, consistent r32. The non-speculative path is unchanged: r32 is still blanked before the offset is applied and re-derived by regboundssync().
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix BPFFCPU validation for sparse CPU IDs
BPFFCPU stores the target CPU ID in the upper 32 bits of the map operation flags. bpfmapcheckopflags() currently compares that ID with numpossiblecpus(), which is the number of possible CPUs rather than a bound on CPU IDs.
On an arm64 QEMU guest with a CPU device-tree hole, the possible CPU mask was 0,2-3. A userspace program using raw bpf() syscalls creates a BPFMAPTYPEPERCPUARRAY and performs update and lookup operations for each CPU by setting BPFFCPU and the CPU ID in the flags.
With the old check, CPU 1 is incorrectly accepted while valid CPU 3 is rejected with -ERANGE. The CPU 1 update then reaches the per-CPU map access path and triggers:
Unable to handle kernel paging request at virtual address ... pc : pimemcpygeneric+0x5c/0x22c lr : bpfpercpuarrayupdate+0x2dc/0x2e8 Call trace: pimemcpygeneric bpfmapupdatevalue mapupdateelem sysbpf
Check the CPU ID against nrcpuids and cpupossible() instead. This rejects CPU IDs outside the valid range and CPUs absent from the possible mask, while allowing valid sparse CPU IDs.
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix percpu map update indexing with sparse CPU IDs
Per-CPU array, hash, and cgroup storage map updates without BPFFCPU or BPFFALLCPUS use a value buffer whose per-CPU slots are packed in possible-CPU order. The buffer is sized as:
roundup(valuesize, 8) numpossiblecpus()
The update paths iterate over possible CPUs, but use the logical CPU ID to calculate the source offset:
value + size cpu
This only works when possible CPU IDs are contiguous starting at zero.
For example, with a possible CPU mask of 0,2-3, the buffer contains three slots corresponding to CPUs 0, 2, and 3. CPU2 is therefore expected to use slot 1 and CPU3 slot 2. Instead, the current code uses slots 2 and 3 respectively, causing incorrect per-CPU values and an out-of-bounds read from the update buffer for CPU3.
The corresponding lookup paths already use a dense offset while iterating over possible CPUs. Do the same for the array, hash, and cgroup storage update paths, advancing the source offset once for each possible CPU. BPFFALLCPUS continues to use the same value for every CPU.
drm/gud: validate GUDROTATION0 is present in supported rotations
In the Linux kernel, the following vulnerability has been resolved:
printk: Don't WARN on kthreadrun failure.
Since kthreadcreateonnode() returns -EINTR upon SIGKILL, we should not use WARNON() in order to catch kthreadrun() failure.
In the Linux kernel, the following vulnerability has been resolved:
accel/amdxdna: Remove countedby from struct amdxdnacmdchain
struct amdxdnacmdchain contains a flexible array annotated with countedby(commandcount). Since the structure is stored in shared AMDXDNABOSHARE memory, userspace can modify commandcount concurrently. If commandcount is changed to zero, the bounds check generated from countedby may fail and trigger a kernel panic.
Remove countedby to avoid relying on the userspace-controlled commandcount for the flexible array bounds check.