See how linux compares to other vendors in security performance
In the Linux kernel, the following vulnerability has been resolved:
ksmbd: fix heap out-of-bounds write in krb5authenticate()
In krb5authenticate(), outlen is calculated to determine available headroom in responsebuf for the incoming Kerberos AP-REP token. However, when SMB2SESSIONSETUP is processed as a non-first element of a compounded SMB2 request, the calculation omits work->nextsmb2rsphdroff.
This causes outlen to overstate remaining buffer headroom by the cumulative size of prior responses in the compound chain. Consequently, the length check in ksmbdkrb5authenticate() (outlen <= resp->spnegobloblen) passes erroneously, allowing memcpy() to write the AP-REP blob past the end of responsebuf into adjacent kernel heap memory.
Fix this by subtracting work->nextsmb2rsphdroff when computing outlen, ensuring it accurately reflects physical remaining buffer space.
In the Linux kernel, the following vulnerability has been resolved:
KVM: x86: Use active memslots for the per-vCPU MMIO cache
KVM tags the per-vCPU MMIO cache with a memslot generation so that a memslot update invalidates cached MMIO information. Both the fill and validation paths use kvmmemslots(), which unconditionally selects address space 0, even when the vCPU is running in SMM and using address space 1.
Commit 56f17dd3fbc4 ("kvm: x86: fix stale mmio cache bug") added the memslot generation to the cache key so that a memslot update could not leave a stale entry valid. When commit 699023e23965 ("KVM: x86: add SMM to the MMU role, support SMRAM address space") added the SMM address space, these helpers were not converted to use the active memslots.
Consequently, an update to the SMM memslots can leave an entry from the old SMM address space apparently valid after the vCPU returns to the normal address space. A guest can then cause an access to valid RAM at the same GFN to be returned to userspace as KVMEXITMMIO.
Completing that exit through the VMM's RAM address space writes the backing page without going through KVM's write-tracking path. If the page backs a nested EPT table, KVM can continue using shadow translations derived from the old contents. The WARNONONCE() in kvmmmuwriteprotectfault() catches this invalid cache and memslot combination.
Use the vCPU's active memslots when caching and validating the entry. Memslot generations are unique across address spaces, so the generation also distinguishes the normal and SMM views. This matches the MMIO SPTE cache, which already uses kvmvcpumemslots().
On an unpatched current-mainline kernel, a regression test that fills the cache in SMM and updates only the SMM memslots fails the intended RAM write and triggers the kvmmmuwriteprotectfault() warning. With this change, the same test completes the RAM write without a warning. The x86/smmtest, setmemoryregiontest, and memslotmodificationstresstest selftests also pass.
bnxten: fix DMA mapping length for padded small packets
In the Linux kernel, the following vulnerability has been resolved:
ipv4: udp: Create exceptions before socket matching
Currently, when ICMP Fragmentation Needed and Redirect Message packets are locally delivered and quote a UDP packet, a FIB nexthop exception (FNHE) is only created if the kernel can match the UDP packet to an existing socket.
This behavior allows off-path attackers to conduct a side-channel attack on the FNHE cache in order to discover the ephemeral port used by a connected UDP socket.
Commit 6457378fe796 ("ipv4: use siphash instead of Jenkins in fnhehashfun()") and commit 67d6d681e15b ("ipv4: make exception cache less predictible") tried to mitigate such attacks by making it harder for attackers to discover hash collisions in the FNHE cache and by randomizing the number of exceptions a hash bucket can hold, respectively. Unfortunately, both of the mitigations can be bypassed.
Instead, mitigate such attacks by always creating a FNHE, even before trying to find a matching socket. Do that by calling ipv4updatepmtu() and ipv4redirect(), the helpers used when the quoted packet did not originate from a socket.
This means that guesses (right or wrong) from an off-path attacker will always result in a FNHE being created or updated in the cache that the attacker can observe.
Pass an oif of 0, in a similar fashion to icmperr(). This is also the oif used by the socket path for sockets that are not bound to a device.
Note that this does not allow attackers to create FNHEs that they could not create before, as both helpers can already be reached with little to no validation. For example, by sending an ICMP error that quotes an ICMP Echo Reply or one that quotes a UDP source port that matches a wildcard socket.
Also note that in the good case (matched socket) the above scheme comes at the cost of an extra route lookup, as the no socket helpers perform their own lookup before the one performed by ipv4skupdatepmtu() / ipv4skredirect(). When the two resolve to different nexthops, it also results in two exceptions being created for the same destination IP. One in the FNHE cache of the nexthop resolved by the no socket helpers and another in the FNHE cache of the nexthop used by the socket.
In the Linux kernel, the following vulnerability has been resolved:
cipso: adjust cached option offsets when removing CIPSO
cipsov4skbuffdelattr() removes the CIPSO bytes but does not adjust cached offsets for options that follow them.
For example, with a valid 10-byte CIPSO option followed by a seven-byte RR option, parsing records rr at offset 30. Removing CIPSO moves RR to offset 20, while the cached offset remains 30. Consumers such as ipforwardoptions() and ipoptionsecho() then access the wrong bytes; the latter may interpret packet data as the option length and copy it into fixed-size option storage.
Mirror cipsov4delopt() and subtract cipsolen from the srr, rr, ts and routeralert offsets when they follow CIPSO. cipsolen is the distance the first memmove() shifts those options. The later header move and network-header reset relocate the bytes and their offset base together.
In the Linux kernel, the following vulnerability has been resolved:
wireguard: noise: reject response consumption after intermediate initiation
Two threads begin processing the identical response message, received twice. The first thread, A, runs. While it's running, the second one, B, gets partway through, and during that slow calculation, or even while blocking on downwrite(), A completes and then also a handshake initiation that's already been queued up runs in thread C, which itself takes that same downwrite(). The handshake initiation creation succeeds, and sets the state back to waiting-for-response, and calls upwrite(), at which point thread B resumes, because either its finished its calculations or was finally allowed to acquire downwrite(). Thread B then copies the state back to the peer, and begins a new session, using that state, which is the same session as the one made in thread A.
Thread A Thread B Thread C
downread() sA = handshake->state memcpy(cA, handshake->crypto) upread() if (sA != 1) goto fail slowcrypto(cA) downread() sB = handshake->state memcpy(cB, handshake->crypto) upread() if (sB != 1) goto fail slowcrypto(cB) downwrite() if (sA != handshake->state) goto fail memcpy(handshake->crypto, cA) handshake->state = 2 upwrite() downwrite() if (handshake->state != 2) goto fail derivesession(handshake->crypto) upwrite() downwrite() slowcrypto(handshake->crypto) handshake->state = 1 upwrite() downwrite() if (sB != handshake->state) goto fail memcpy(handshake->crypto, cB) handshake->state = 2 upwrite() downwrite() if (handshake->state != 2) goto fail derivesession(handshake->crypto) upwrite()
This seems basically impossible to hit in a meaningful way in practice, but ensure that it absolutely cannot happen by comparing the ephemeral private key that's on the stack with the latest one that the peer's handshake state has.
In the Linux kernel, the following vulnerability has been resolved:
strparser: make sure strprecv isn't running before tearing down the parser
The comment above strpdone() claims that if strp is stopped, strprecv will no longer be called. That's only true if the caller has a mechanism (eg locking) to guarantee that strprecv() calls that started before strpstop() have completed by the time we call strpdone().
This adds a dummy locksock/releasesock pair to guarantee that any in-flight strprecv() (which runs under either bhlocksock or locksock, depending if it's called from ->skdataready or strpwork) has completed.
Only espintcp can be affected by this race condition, but this patch makes sure no future user of strp can have the bug.
This could crash on strp->sk ("general mode" of strp), but this mode has been here for 9 years and has never been used. It'll be gone soon, no point worrying about it.
Switch the stopped/paused/etc bits to u8's to avoid races between strpstop() and strppause/unpause().
A reproducer has been published and turns the possible UAF into an exploit [1].
In the Linux kernel, the following vulnerability has been resolved:
tipc: destroy topsrv workqueues before closing connections
tipctopsrvstop() closed subscriber connections while the topology server's send and receive workqueues were still running. Socket callbacks and subscription events could then queue more work, and in-flight send/recv work could drop the last connection reference during the connidr walk.
That race produced several teardown failures: refcountt addition on 0 from connget() on a connection whose release was blocked on idrlock, a subsequent use-after-free in tipcconnclose(), queuework() on an already destroyed workqueue from the listener data-ready callback, and an RCU stall in tipctopsrvexitnet() while the walk spun under idrlock.
Clear srv->listener under idrlock so it acts as a shutdown flag, skip queuework() once it is NULL, destroy the workqueues to flush in-flight work, and only then close the remaining connections. Refuse tipcconnlookup() after that flag is cleared, and drop idrlock when the teardown walk finds no connection, so an in-flight subscription event cannot pin idrinuse while the walk holds the lock.
v3 supersedes the narrower in-thread diff Tung Quang Nguyen posted on 2026-09-23. It keeps his teardown order and adds the lookup refusal and the empty-idr unlock.
In the Linux kernel, the following vulnerability has been resolved:
tipc: hold a reference to nodes found by link name
tipcnodefindbyname() returns a node after dropping its RCU read lock without taking a reference. The LINKSET, LINKGET and LINKRESETSTATS handlers then lock and access the node, racing with timer-driven cleanup of a down peer. Generic netlink serialization does not exclude the node timer.
The following interleaving can leave a handler using a freed node:
CPU 0: find the node under RCU and release the node read lock CPU 1: tipcnodetimeout() clears the links and unlinks the down node CPU 1: drop the list and timer references, queuing tipcnodefree() CPU 0: leave the RCU read-side critical section CPU 1: complete the grace period and free the node CPU 0: acquire the node lock through the stale pointer
LINKSET also uses the node's media address after releasing the node lock, when passing queued packets to tipcbearerxmit().
KASAN on v7.3-rc5 reported:
BUG: KASAN: slab-use-after-free in rawreadlockbh Write of size 4 at addr ffff88807e06f008 by task poc/92 Call Trace: rawreadlockbh kernel/locking/spinlock.c:287 tipcnlnodesetlink net/tipc/node.c:2475 genlfamilyrcvmsgdoit net/netlink/genetlink.c:1114 genlrcvmsg net/netlink/genetlink.c:1209 netlinkrcvskb net/netlink/afnetlink.c:2575
Allocated by task 0: tipcnodecreate net/tipc/node.c:539 tipcnodecheckdest net/tipc/node.c:1196 tipcdiscrcv net/tipc/discover.c:252
Freed by task 92: kfree mm/slub.c:6801 rcucore kernel/rcu/tree.c:2919
Last potentially related work creation: callrcucommon.constprop.0 kernel/rcu/tree.c:3181 tipcnodetimeout net/tipc/node.c:814
Acquire a reference to the selected node with krefgetunlesszero() before leaving RCU, returning NULL if the node has already been released. Release that reference on every caller exit after the last node access, including transmission in LINKSET. Keep the existing link lookup order and locking so concurrent link removal still takes the existing error paths.
In the Linux kernel, the following vulnerability has been resolved:
fsverity: RCU-delay the freeing of struct fsverityinfo
fsveritygetinfo() calls rhashtablelookupfast(), which just uses rcureadlock() and doesn't directly synchronize with fsverityremoveinfo().
For the same inode this isn't a problem: its fsverityinfo is removed only at inode eviction time or upon failure to enable verity, when the inode no longer needs its fsverityinfo and it will no longer be accessed via that inode.
However, this is broken and can cause a use-after-free for concurrent fsveritygetinfo() for different inodes. Those rely on following fsverityinfo::rhashhead in the rhashtable under rcureadlock() only. They also use fsverityinfo::inode to do the key comparison.
Fix this by RCU-delaying the freeing of 'struct fsverityinfo' after it's been removed from the rhashtable.
In the Linux kernel, the following vulnerability has been resolved:
gpio: mpsse: fix race when arming the IRQ poll worker
gpiompsseirqenable() arms the poll worker before publishing it: schedulework() runs before the worker is added to priv->workers. If gpiompssedisconnect() walks the list in that window it misses the worker, and once disconnect returns, the USB core frees mpssepriv while the orphaned gpiompssepoll() work keeps accessing it, causing a use-after-free.
Fix this by publishing and arming the worker in one irqspin critical section. Teardown walks the same list under irqspin, so a worker found on the list is guaranteed to be armed, and cancelworksync() handles it whether it is queued or running.
A worker armed after the disconnect walk would still be missed, so also set a new priv->dying flag under irqspin before the teardown walk, and check it in the same critical section, freeing it via kfreercu() instead when the device is going away, since kfree() would be called with the IRQ core's raw spinlock held and may sleep on PREEMPTRT. schedulework() is safe to call with irqspin held, and the next probe gets a fresh mpssepriv, so the flag never needs to be cleared.
This issue was found by an in-house static analysis tool.
In the Linux kernel, the following vulnerability has been resolved:
gve: fix XSK buffer leak on error descriptor
When the error bit is set in the RX completion descriptor, the bufstate and its attached buffer should be freed. In the case of AFXDP ZC, the XSK buffer was not freed, leading to a leak.
This issue was caught by LLM.
In the Linux kernel, the following vulnerability has been resolved:
iouring/net: populate CONNECT filter fields for 24-byte sockaddrin6
ioconnectbpfpopulate() fills connect.port and connect.v6addr for AFINET6 only when addrlen >= sizeof(struct sockaddrin6), i.e. 28 bytes.
The IPv6 connect paths accept SIN6LENRFC2133 (24 bytes), which already holds sin6port and sin6addr. ioconnect() passes addrlen to the socket layer unchanged.
At addrlen 24 the filter sees family AFINET6 with port and address zero, while the kernel connects to the real destination. A filter that denies an IPv6 port or address is bypassed. Denying connect.port == P rejects [::1]:P with -EACCES at addrlen 28 but connects at addrlen 24.
Use SIN6LENRFC2133 as the threshold. sin6scopeid stays zero when absent.
The threshold mismatch was found by an AI coding assistant (Claude Code) comparing this hook against the net/ipv6 length checks on my instructions; it also drafted the reproducer and this patch. I verified the bypass and the fix in a VM on 7.3-rc6 and that 7.2 has the same code.
In the Linux kernel, the following vulnerability has been resolved:
net/smc: protect clcsock lifetime in smcgetname
smcgetname() dereferences smc->clcsock without holding clcsockreleaselock. Link-group termination can release the CLC socket through smccloseactiveabort() while the SMC socket is still open, for example after shutdown(SHUTWR).
A getsockname() caller can load smc->clcsock, then the termination worker can clear the pointer and call sockrelease() before the caller accesses clcsock->ops or invokes getname(). This causes a use-after-free; if the worker clears the pointer before the load, it causes a NULL dereference. The syscall's file reference keeps the SMC socket alive but does not prevent asynchronous release of its CLC socket.
KASAN reported the following with test-only timing instrumentation:
BUG: KASAN: slab-use-after-free in smcgetname+0x19e/0x1b0 Read of size 8 at addr ffff888109abb4e0 by task poc/103 Call Trace: smcgetname+0x19e/0x1b0 dogetsockname+0xe5/0x170 sysgetsockname+0x8c/0x100
Allocated by task 95: sockallocinode+0x1e/0x280 sockalloc+0x3d/0x240 sockcreate+0x7e/0x430 smccreate+0x121/0x240
Freed by task 0: kmemcachefree+0xcc/0x340 rcucore+0x50a/0x1850
Last potentially related work creation: evict+0x446/0x6c0 smcclcsockrelease+0xa8/0xd0 smccloseactiveabort+0x26a/0x3a0 smclgrterminate.part.0+0x137/0x2e0
Hold clcsockreleaselock across the pointer check and the getname() callback to serialize with smcclcsockrelease(). Return -EBADF if the CLC socket has already been released, preserving the existing peer state check and the callback's return value otherwise.
In the Linux kernel, the following vulnerability has been resolved:
net: skbuff: don't leave stale bytes in skbcopyandcsumbits()
When skbcopyandcsumbits() reaches unreadable frags it returns 0 after copying only the linear part, and the rest of the caller's buffer is left as it was. The callers copy into a buffer that is about to go out on the wire: an ICMP error quoting the offending packet, or a driver's TX bounce buffer in skbcopyandcsumdev(). Neither buffer is zeroed beforehand, so whatever was in memory there gets sent.
Zero the part of the buffer we didn't fill. The checksum usually won't match the data any more, so the receiver will usually drop the packet, but either way it no longer carries anything it shouldn't. Only zero for a positive @len, a negative one from a broken caller must not turn into a huge memset().
In the Linux kernel, the following vulnerability has been resolved:
riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp
Under CONFIGSHADOWCALLSTACK, handleexception() reloads the kernel shadow call stack pointer (gp) only when the trap came from userspace. It made that decision with scsloadcurrentiftaskchanged, which compares the trap-time tp (read back from sscratch into s5) against the current tp:
beq \prev, tp, skipscs scsloadcurrent skipscs:
tp is a user-writable register. A user task that sets tp to the linear-map address of its own taskstruct (¤t) before trapping makes the comparison succeed (can achieve by brute force with KASLR enable under our test), so the kernel skips scsloadcurrent and keeps running with the gp that userspace left in place. Under CONFIGSHADOWCALLSTACK gp is the shadow call stack pointer and loadglobalpointer is a no-op, so the compiler-emitted "sd ra, -8(gp)" / "ld ra, -8(gp)" in every non-leaf function then write to, and return through, an attacker-controlled address -- an unprivileged kernel arbitrary-write and control-flow-hijack primitive. The poisoned gp is saved to taskstruct.scssp on return, so the reload is skipped on every subsequent entry as well.
Decide "came from userspace" from the hardware sstatus.SPP bit (already in s1 at this point) instead of from tp, mirroring the check that retfromexception already uses a few instructions later. SPP is written by hardware on trap entry and cannot be forged from U-mode. Legitimate behaviour is unchanged: user entries (SPP=0) reload the task shadow call stack, nested kernel entries (SPP=1) skip it.
In the Linux kernel, the following vulnerability has been resolved:
riscv: errata: select RISCVALTERNATIVEEARLY for THEAD GHOSTWRITE
errataprobeghostwrite() only marks the CPU as vulnerable when it is called at the RISCVALTERNATIVESEARLYBOOT stage, and the mitigation in ghostwriteenablemitigation() only takes effect if the vulnerable state was recorded before the boot alternatives are patched.
The early boot stage is only executed when CONFIGRISCVALTERNATIVEEARLY is enabled, which currently is only selected by ERRATATHEADMAE. In a kernel built with ERRATATHEADGHOSTWRITE=y but ERRATATHEADMAE=n, the early alternatives never run, so ghostwritestate is never set to VULNERABLE: ghostwriteenablemitigation() returns false, xtheadvector remains enabled, and sysfs reports "Not affected" on a vulnerable T-Head C9xx CPU.
Select RISCVALTERNATIVEEARLY from ERRATATHEADGHOSTWRITE so that the vulnerability is detected in the early boot stage and the default mitigation is applied.
In the Linux kernel, the following vulnerability has been resolved:
riscv: futex: untag the user pointer before the atomic access
accessok() checks untaggedaddr(uaddr), but archfutexatomicopinuser() and futexatomiccmpxchginatomic() hand the raw uaddr to the inline asm amoswap/amoadd/.../lr.w+sc.w through the "+m" (uaddr) operand. When the tagged address ABI is enabled (CONFIGRISCVISASUPM, prctl PRSETTAGGEDADDRCTRL with PMLEN != 0), those two addresses differ: a user pointer whose top PMLEN bits hold a tag passes accessok() after untagging, but the atomic is then performed on the still-tagged raw address.
Supervisor-mode data accesses are not subject to the U-mode pointer masking (that is governed by menvcfg.PMM, which the kernel does not set), so hardware does not strip the tag for the kernel's own access. With Sv57 and PMLEN=16 the tag bits overlap the canonical-address bits, so a tagged pointer can name a canonical kernel virtual address (e.g. in the linear map) whose untagged form is a valid user address. An unprivileged process can thus make FUTEXWAKEOP perform an atomic read-modify-write on an arbitrary kernel address, with the matching FUTEXOPCMP result serving as a read oracle.
getuser()/putuser()/rawcopy{to,from}user() already untag the pointer after the accessok() check; do the same in the futex helpers so the atomic operates on the address that was actually validated.
In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: hcisync: Fix command skb lifetime during scan setup
During PA sync scan setup, hcilesetextscanparamsync() gets the address used for the PALINK lookup from hcisentcmddata(). The returned pointer borrows storage from sentcmd or reqskb, without holding a reference to either skb.
The scan worker runs on reqworkqueue while hcicmdwork() runs on the separate device workqueue. After the scan worker loads sentcmd, the command worker can free and replace it before hcisentcmddata() dereferences the skb. The command payload can also be freed between returning from the helper and comparing the address. The connection lookup's RCU critical section does not protect the command skb.
KASAN reported:
BUG: KASAN: slab-use-after-free in hcisentcmddata+0x27c/0x2f0 Workqueue: hci0 hcicmdsyncwork Call Trace: hcisentcmddata+0x27c/0x2f0 hcilesetscanparamsync+0x43a/0x850 hcipassivescansync+0xb09/0x1460 hciupdatepassivescansync+0x47c/0x6e0 hcilepacreatesync+0x200/0xa70 hcicmdsyncwork+0x13c/0x290
Allocated by task 95: skbclone+0x13f/0x340 hcicmdwork+0x2a9/0x7e0
Freed by task 95: kmemcachefree+0xba/0x3a0 hcicmdwork+0x29c/0x7e0
Use hdev->lock to serialize the address snapshot with sentcmd replacement. Protect reqskb replacement and completion cleanup with the same lock because the helper falls back to that skb. Copy the address before releasing the lock and use the copy for the existing RCU-protected connection lookup. Release the mutex before sending or waiting for commands, preserving the lookup and completion ordering.
In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: ISO: Reject concurrent BIS listener setup
isosocklisten() drops the socket lock before calling isolistenbis() to preserve the hdev->lock ordering. Two concurrent listen() calls on the same broadcast socket can therefore both observe BTBOUND. Caller A can attach connA and release the locks, then caller B can acquire them and attach connB before A publishes BTLISTEN.
isochanadd() checks whether connB already has a socket, but not whether the socket already has a connection. The second attachment overwrites isopi(sk)->conn, leaking the connA reference and leaving connA->sk intact. Socket teardown follows connB, so later events on connA can cause a stale socket access.
Recheck BTBOUND and require isopi(sk)->conn to be NULL after taking both the HCI device and socket locks in isolistenbis(). The connection check also covers the interval between attachment and publication of BTLISTEN. Reject a competing setup with -EBADFD through the existing unlock path before allocating another connection.
A recorded KASAN report from an instrumented kernel shows:
BUG: KASAN: slab-use-after-free in isosockhold+0x119/0x1f0 Call Trace: isosockhold+0x119/0x1f0 isoconndel+0xe4/0x270 hcidisconncompleteevt+0x351/0x8c0 hcieventpacket+0x71b/0xb20 hcirxwork+0x293/0x730
Allocated by task 93: skprotalloc+0x113/0x220 skalloc+0x2b/0x6d0 btsockalloc+0x29/0x370 isosockalloc.constprop.0+0x19/0x300 isosockcreate+0x94/0x100
Freed by task 93: kfree+0x121/0x3c0 skdestruct+0x42b/0x540 isosockrelease+0x29d/0x340 sockrelease+0xa1/0x260 sockclose+0x10/0x20
Bluetooth: ISO: Serialize concurrent connect calls
In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: SCO: serialise scoconn lifetime against scorecvscodata()
scorecvscodata() upgrades the weak hcon->scodata back-pointer to a strong reference under hdev->lock:
hcidevlock(hdev); hcon = hciconnhashlookuphandle(hdev, handle); ... conn = scoconnholdunlesszero(hcon->scodata); hcidevunlock(hdev);
but the pointer is cleared from the other side without that lock. When the last scoconn reference is dropped, scoconnfree() ran
conn->hcon->scodata = NULL;
with no hdev->lock held, so the RX path could read hcon->scodata and call krefgetunlesszero() on an scoconn that was concurrently freed:
BUG: KASAN: slab-use-after-free in scoconnholdunlesszero+0xbe/0x160 Write of size 4 by task kworker/u17:0 Workqueue: hci0 hcirxwork Call Trace: scoconnholdunlesszero+0xbe/0x160 scorecvscodata+0x13f/0x490 hcirxwork+0x3af/0x730
krefgetunlesszero() only guards against a zero refcount, not against the backing memory already being freed.
Give hcon->scodata an actual reference on the scoconn it points to, so the object cannot be freed while the pointer is still installed, and only clear and drop it from scoconndel(), which runs under hdev->lock (its callers, scoconnectcfm() and scodisconncfm(), hold it). The reader in scorecvscodata() also takes hdev->lock, so the store and the read are now serialised: the RX path either observes NULL or a reference that is guaranteed to stay valid until it drops its own.
scoconnadd() no longer hands its krefinit() reference to the caller as the connection's only reference; that initial reference is the one owned by hcon->scodata, and callers get their own via scoconnhold().
Because the scoconn can now outlive the socket (the association keeps it alive until the link goes down), the hciconn can no longer be dropped from scoconnfree() without regressing socket close: closing a connected SCO socket must still tear the link down. Move hciconn ownership to the socket instead: scochanadd() takes an hciconn reference and it is released from scochandel() and scosockdestruct(), exactly once. The scoconn no longer owns an hciconn reference, so scoconnadd() stops consuming one and scoconnect() drops the hciconnectsco() reference on every path; scoconnectcfm() no longer needs its hciconnhold() dance.
drm/i915/gem: Prevent overstepping exec array boundary
drm/vmwgfx: validate pitch coming from userspace
In the Linux kernel, the following vulnerability has been resolved:
drm/xe: Fix stale pinnedlink entry when fb-pin performs the final unpin
xebopinexternal() and xebounpinexternal() maintain the bo's pinnedlink list membership in xe->pinned.late.external, based on whether the current call is the outermost pin or the final unpin. However, the same external bo's pincount can also be raised and lowered directly by xepinfbvma()/xeunpinfbvma(), which pin the bo as a display scanout buffer without going through xebopinexternal()/xebounpinexternal() at all, and have no notion of, or ownership over, pinnedlink.
If a bo is pinned both externally (e.g. dma-buf export) and as an fb, and the external unpin happens first, xebounpinexternal() correctly observes pincount > 1 and leaves the bo on pinnedlink. When the fb unpin later performs the true last unpin (pincount 1 -> 0), it never touches pinnedlink, leaving the bo linked on xe->pinned.late.external indefinitely. Once the bo is subsequently freed, this stale list entry points into freed memory, corrupting the list and risking a use-after-free the next time the list is walked or spliced.
The backup object pin/unpin sites in xebonotifierpreparepinned()/ xebonotifierunpreparepinned() have the same bypass characteristic, though they never add their bo to a pinned list, so are not affected by this particular list-corruption issue.
Move the pinnedlink removal into xeboaccountunpin(), which already runs on every unpin path (kernel, external, framebuffer, backup object) right before the true 1 -> 0 pincount transition. Since listdelinit() only operates on the node itself, this removal is list-agnostic and safe to perform regardless of which list (external or kernelbopresent) the bo happens to be linked on, or which code path is performing the final unpin. Drop the now-redundant explicit listdelinit() calls in xebounpinexternal() and xebounpin().
v2: - New patch
v3: - Rebased on changes to previous patch.
(cherry picked from commit ca58d36a1f93af586ee93b340c9f9fd81312cc01)
In the Linux kernel, the following vulnerability has been resolved:
namespace: reset the old parent's ->overmount in mntchangemountpoint()
umountmnt() resets ->overmount of the parent when it unmounts the mount that overmounts it. mntchangemountpoint() doesn't. It moves the mount to its new parent and leaves the old one pointing at it.
For a mount that is moved beneath in attachrecursivemnt() that doesn't matter. The new mount has already reset ->overmount of the old parent by the time the old top mount is moved onto it.
It matters for reparent() though. propagateumount() moves a surviving overmount onto the first ancestor that isn't going to be unmounted. The mount it was taken from is unmounted immediately afterwards. If a file descriptor keeps that unmounted mount alive ->overmount points at the moved mount. That's a dangling pointer and UAF as the moved mount is unmounted and freed.
dolockmount() follows ->overmount from the target path under mountlock. With a file descriptor on such a mount as the target of a mount beneath topmostovermount() walks into the freed mount and dolockmount() takes references on whatever it finds there.
So reset ->overmount of the old parent in mntchangemountpoint() the same way umountmnt() does. A mount's ->overmount is then always a mount that is attached to it.
In the Linux kernel, the following vulnerability has been resolved:
namespace: don't inherit MNTUMOUNT in clonemnt()
MNTUMOUNT gets raised on a mount that umounttree() or umountone() has taken out of its namespace. It's never cleared. detachmounts() unhooks a mount that carries it instead of unmounting it.
disconnectmount() lets an unmounted child stay attached only if its parent carries it. propagateumount() takes it as the sign that a mount is going to be unmounted when it decides what else can be unmounted, where a chain of locked mounts ends and where a for reparenting an overmount.
clonemnt() copies the flags of the source and only masks MNTINTERNALFLAGS which doesn't include MNTUMOUNT. A mount that was lazily unmounted but is kept alive by a file descriptor can still be copied when its root is an nsfs or pidfs file because maycopytree() accepts those before checking whether the source is mounted at all:
mount --bind /proc/self/ns/net /tmp/x exec 3< /tmp/x umount -l /tmp/x mount --bind /proc/self/fd/3 /tmp/y
The mount on /tmp/y is attached to the caller's namespace with MNTUMOUNT already set and every copy of it inherits the flag again.
That causes a number of bugs:
- Unlink its mountpoint from a mount namespace where it isn't one. detachmounts() takes it for a mount that was unmounted earlier, unhooks it from its parent and drops the reference the namespace holds on it. It stays in the namespace with one reference too few and as its own parent, so it can't be unmounted through the file descriptor anymore and the namespace never finds it again. When the namespace goes away it's leaked and points to a freed struct mntnamespace that maychangepropagation() and anonnsroot() read on the next propagation change or mountsetattr() through the file descriptor.
- Make it shared and unmount a peer. tracetransfers() follows the flag from the peer into it and strips it from its peer group.
- Let a propagated umount reach it. gathercandidates() marks it with TUMOUNTCANDIDATE but never puts it on the candidate list, so the mark is never cleared and every later propagated umount skips it. If it's the parent of a locked mount handlelocked() takes it as the cutoff and commits the locked child that should have stayed and disconnectmount() leaves that child attached to it, unmounted under a mounted parent, which is what disconnectmount() exists to prevent. When the namespace goes away umounttree() visits the child a second time. And once detachmounts() has made it its own parent reparent() never finds the end of the chain of unmounted parents.
A clone is a new mount that has never been unmounted. Add MNTUMOUNT to MNTINTERNALFLAGS so clonemnt() never copies it. And warn when umounttree() reaches a mount that already has it set.
In the Linux kernel, the following vulnerability has been resolved:
namespace: queue a mount only once for mount notifications
mntnotifyadd() puts a mount on notifylist. It doesn't check whether the mount is on the list already. That's fine as long as every mount is queued at most once per namespacesem hold. It isn't.
propagateumount() moves a surviving overmount off a stack of mounts that are going away and queues it as moved. shrinksubmounts() and markmountsforexpiry() call umounttree() for several mounts under a single namespacesem hold. So the second umounttree() can take down exactly the mount the first one reparented, reparent it once more and so end up queueing it a second time.
The second listaddtail() cuts the mounts queued in between out of the list while the head still points at the last of them. notifymntlist() then only visits that one mount and the others are freed after the grace period with notifylist still pointing at them. Every later mount operation on the host walks freed memory:
BUG: KASAN: slab-use-after-free in listaddvalidorreport Read of size 8 at addr ffff8881003d57e0 by task notifydq/162 listaddvalidorreport+0x15c/0x1a0 mntaddtons+0x322/0x890 attachrecursivemnt.isra.0+0xf2a/0x1a00 pathmount+0x139c/0x1d40
This needs a mount with MNTSHRINKABLE to bind from. That's what finishautomount() creates (submounts of NFS, AFS and CIFS and the tracefs mount below debugfs). Bind mounts inherit the flag. A mount namespace with a FANMARKMNTNS mark does the rest and root in a user namespace can have both.
Initialize tonotify in allocvfsmnt() and leave a mount alone that is queued already. mntnotify() looks at the state the mount has when the list is drained so a single entry per mount is enough. The move event for a mount that is unmounted under the same hold is lost. That's fine. The detach is what matters.
In the Linux kernel, the following vulnerability has been resolved:
namespace: keep covered mounts covered in OPENTREENAMESPACE
opentree(OPENTREENAMESPACE) creates a new mount namespace from a copy of the tree at the given path. The caller needs to be privileged over its current user namespace because the new mount namespace will be owned by it. It doesn't need to be privileged over the mount namespace the tree is copied from. An unprivileged user just needs to create a user namespace first.
The copy follows the rules of a detached bind mount. Without ATRECURSIVE only the mount itself is cloned and its children are left out. With ATRECURSIVE unbindable mounts are skipped. Both is fine when the caller has privileges over the source mount namespace because it could unmount those mounts anyway. Not so for an unprivileged user in that mount namespace. For them a mount namespace copy is what unshare() does. copymntns() copies everything including unbindable mounts and lockmnttree() makes sure nothing can be unmounted in the copy. Nothing that was covered gets revealed.
createnewnamespace() only does the locking and so the covered content is right there in the new mount namespace:
# mount -t tmpfs none /tmp/otn; mkdir /tmp/otn/covered # echo hidden > /tmp/otn/covered/under.txt # mount -t tmpfs none /tmp/otn/covered
uid 1000, after unshare(CLONENEWUSER): fd = opentree(ATFDCWD, "/tmp/otn", OPENTREENAMESPACE); setns(fd, CLONENEWNS); open("/covered/under.txt", ORDONLY) -> "hidden"
Covering paths with mounts is how container runtimes mask parts of /proc and /sys and how admins hide things.
When the caller's user namespace doesn't own the source mount namespace copy the way unshare() does and refuse a non-recursive copy of a mount that has anything mounted below the requested directory and copy unbindable mounts in a recursive copy. A caller that is privileged over the source mount namespace sees no change.
In the Linux kernel, the following vulnerability has been resolved:
namespace: don't let a pseudo dentry become the root of a mount
dallocpseudo() hands out dentries for pipes, sockets and other files that are never anyone's child or parent. They carry DCACHENORCU and dentryfree() frees them right away because no lockless path walk can ever reach them. That holds as long as such a dentry isn't the root of a mount. But bind mounting /proc/self/fd/<fd> of such a file does exactly that.
Most callers of allocfilepseudo() put their files on kernel-internal mounts and maycopytree() refuses those. bpftokencreate() doesn't. It places the token file on the bpffs mount the caller handed it and that mount is in the caller's mount namespace so the clone goes through:
mount --bind /proc/self/fd/<token> <file> opentree(tokfd, "", ATEMPTYPATH | OPENTREECLONE) + movemount()
followmountrcu() then loads ->mntroot of that mount, reads dseq and dflags of the dentry and only then checks mountlock. The dentry can be gone by then. The final mntput() of an unmounted parent unhooks a child that stayed attached to it under mountlock alone. When the child's holder does the final put right after that the root is dput() and freed immediately while a walker that found the mount hashed still looks at it.
Refuse to clone a mount with a DCACHENORCU dentry as its root. Nothing sensible can be done with a bind mount of a bpf token anyway.