In the Linux kernel, the following vulnerability has been resolved:
NFSD: remove flawed WARNONONCE from nfsdmodecheck
The header for commit e75b23f9e323 ("nfsd: check dcanlookup in fhverify of directories") details the assumption that justified adding the WARNONONCE to nfsdmodecheck(), that assumption is invalid (in the case of NFS reexport).
When NFSD exports an NFS filesystem it is very possible for nfsdmodecheck() to encounter a @dentry that doesn't have iop->lookup (see nfsfhget()'s NFSATTRFATTRMOUNTPOINT and NFSATTRFATTRV4REFERRAL handling, and dflagsforinode()).
So remove nfsdmodecheck()'s WARNONONCE(). The nfserrnotdir return on that branch must stay. It guards the subsequent lookuponeunlocked() -> lookupslow() path, which calls inode->iop->lookup() with no NULL check, so returning nfserrnotdir is what keeps a client LOOKUP into such a @dentry from dereferencing a NULL method pointer.
In the Linux kernel, the following vulnerability has been resolved:
KEYS: trusted: Fix TPM teardown ordering
trustedtpmexit() drops the TPM chip reference and frees the digest array before unregistering the trusted key type. keytypelookup() holds keytypessem for reading until the key operation finishes, while unregisterkeytype() takes it for writing. It therefore provides the synchronization point that must precede backend teardown.
The current order permits this interleaving:
CPU 0 CPU 1 trustedtpmexit() keytypelookup("trusted") putdevice(&chip->dev) trustedtpmseal() kfree(digests) pcrlock() unregisterkeytype() tpmpcrextend(..., digests)
CPU 1 can consequently dereference the freed digest array. The chip can also be released before callbacks stop using it.
KASAN reported:
BUG: KASAN: slab-use-after-free in tpmpcrextend+0x1f0/0x200 Read of size 2 at addr ffff88810872d000 by task poc/89 Call Trace: tpmpcrextend+0x1f0/0x200 pcrlock+0x42/0x70 [trusted] trustedtpmseal+0x1b6/0x570 [trusted] trustedinstantiate+0x293/0x340 [trusted] keyinstantiateandlink+0xb2/0x2b0 keycreateorupdate+0x61e/0xb50 dosysaddkey+0x1b8/0x310 Allocated by task 88: kmallocnoprof+0x1a7/0x490 dooneinitcall+0xa1/0x390 doinitmodule+0x2df/0x840 Freed by task 90: kfree+0x131/0x3c0 trustedtpmexit+0x59/0xa0 [trusted] dosysdeletemodule+0x346/0x510
Move unregisterkeytype() before releasing either resource. This stops new lookups and waits for in-flight key operations to finish before the backend state is destroyed.
In the Linux kernel, the following vulnerability has been resolved:
nfsd: fix BUGON in nfsd4alloclayoutstateid on racing delegation revoke
nfsd4alloclayoutstateid reads fp->fidelegfile without holding filock when the parent stateid is a delegation. A concurrent delegation revoke via the laundromat can clear fidelegfile under filock, causing nfsdfileget() to return NULL and triggering the BUGON.
This race is client-reachable: two NFS clients can trigger it by having one hold a delegation while another opens the same file to force a recall. When the first client doesn't respond to the recall, the laundromat revokes it. A concurrent LAYOUTGET from any client using the delegation stateid hits the race window.
Fix this by taking filock around the fidelegfile read in the SCTYPEDELEG path, matching the locking discipline of the findanyfile() arm, and replacing the BUGON with a graceful error return that cleans up the partially-initialized layout stateid.
In the Linux kernel, the following vulnerability has been resolved:
NFSD: Prevent client use-after-free during delegation revoke
A delegation stateid holds only a bare pointer to its owning nfs4client and does not keep it alive. The client survives its stateids only because destroyclient() drains cldelegations and clrevoked before freeclient() runs.
nfs4laundromat() breaks that invariant: it unhashes an expired delegation from cldelegations, drops deleglock, then revokedelegation() relinks it onto clrevoked under cllock. In that window the delegation is on neither list, so clienthasstate() can report no remaining state.
Every teardown path first requires clrpcusers to be zero, but the laundromat holds no such reference. A client whose recalled delegation has just timed out can therefore reach freeclient() while revokedelegation() is still about to dereference cllock, a use-after-free.
Pin the client with clrpcusers across the revoke so teardown blocks until it completes, then reap the delegation from clrevoked. A client already expiring reaps its own, so skip it and leave the delegation on delrecalllru.
In the Linux kernel, the following vulnerability has been resolved:
ceph: fix UAF in kickflushingcaps() on cf entry freed during unlock
listforeachentry() iterates ci->icapflushlist but drops icephlock to send cap messages. During the unlock window, handlecapflushack() can acquire icephlock, detach cf entries with tid <= flushtid from the list, release icephlock, and free them via cephfreecapflush() outside any lock. When the original thread reacquires icephlock and the for-loop macro advances via cf = listnextentry(cf, ilist), it dereferences cf->ilist.next on freed memory.
The race timeline:
kickflushingcaps() handlecapflushack() ----------------------- ----------------------- holds icephlock <--- iterates to cf (tid=10) prepares FLUSH message drops icephlock <--- sendcap() ── FLUSH(tid=10) MDS sends FLUSHACK(tid=10) ---> acquires icephlock cf->tid(10) <= flushtid(10), detaches cf from icapflushlist drops icephlock cephfreecapflush(cf) <- frees it! acquires icephlock <--- for-loop advances: cf = listnextentry(cf, ilist) -- UAF on freed cf->ilist.next
The cf was just sent by kickflushingcaps itself via sendcap(). The MDS may respond with FLUSHACK quickly enough that handlecapflushack() frees cf before kickflushingcaps can finish the iteration.
Fix by converting to a manual while loop: save the next pointer under icephlock before dropping it, then use the saved pointer after reacquiring, so the potentially-freed cf is never accessed again.
In the Linux kernel, the following vulnerability has been resolved:
nfsd: reject out-of-range useconds in NFSv2 SETATTR/CREATE
The NFSv2 sattr decoder converts the wire useconds to nanoseconds in svcxdrdecodesattr():
iap->iaatime.tvnsec = tmp2 NSECPERUSEC;
tmp2 is a u32 and NSECPERUSEC is 1000, so the product is computed in unsigned long. On ILP32 that is 32 bits, and an out-of-range useconds value such as 4294968 wraps to tvnsec == 704. The corruption therefore happens during decode, before any proc function can inspect the value, and a later range check on tvnsec would see an in-range result and accept it. Rejecting in the decoder yields an RPC GARBAGEARGS reply. NFSv2 defines no NFSERRINVAL, so there is no NFS-level status to return for a malformed time argument, and the check cannot move to the proc function the way the v3/v4 nsec range checks do.
Guard the raw useconds before the multiplication and reject values greater than 1000000. useconds == 1000000 is kept: it is the Sun convention for "set to the current server time", and the in-tree Linux NFSv2 client emits it in both the atime and the mtime field for a plain touch / utimes(file, NULL) (see encodesattr() and xdrencodecurrentservertime() in fs/nfs/nfs2xdr.c). Rejecting 1000000 would turn that common operation into a hard decode failure for both SETATTR and CREATE. 1000000 NSECPERUSEC is 10^9, which does not wrap on ILP32, so the Sun convention value passes through safely. Only genuinely out-of-range values (> 1000000) are rejected. The atime and mtime guards are therefore symmetric.
The decoder only applied the Sun convention in the mtime block, which clears ATTRATIMESET|ATTRMTIMESET when mtime useconds == 1000000. If a client puts 1000000 in the atime field but not in the mtime field, the atime block stored an out-of-range tvnsec (10^9) and left ATTRATIMESET set, so the bogus value reached the filesystem. Apply the convention in the atime block as well, clearing ATTRATIMESET so the server uses its current time and ignores the value. Only ATTRATIMESET is cleared there. The mtime block keeps its existing behavior, where 1000000 means "set both atime and mtime to now".
[ cel: various tweaks, addenda, and clean-ups ]
ceph: bound numexporttargets array for mds info v2/v3
In the Linux kernel, the following vulnerability has been resolved:
ata: libata-scsi: fix DSM TRIM for sector sizes larger than 2048 bytes
atascsiwritesamexlat() translates a SCSI WRITE SAME command with the UNMAP bit set into an ATA DATA SET MANAGEMENT TRIM command. The TRIM descriptor is built by ataformatdsmtrimdescr() into the 2048-byte atascsirbuf staging buffer, and the number of bytes copied is compared against the logical sector size by the caller:
size = ataformatdsmtrimdescr(scmd, trmax, block, nblock); if (size != len) / len == sdp->sectorsize / goto invalidparamlen;
ataformatdsmtrimdescr() clamps the copy length to ATASCSIRBUFSIZE (2048). On a device whose logical sector size exceeds that (e.g. a 4Kn device, where sectorsize == 4096) the function can never return more than 2048, while the caller expects it to return sectorsize. The comparison therefore always fails, so every TRIM is rejected with "Parameter list length error" and WARNON() splats on each attempt. TRIM / discard is thus completely broken on such devices.
The descriptor was incorrectly sized from the logical sector size. A DSM TRIM payload is a list of 512-byte pages, each holding up to ATAMAXTRIMRNUM (64) LBA Range Entries, and is independent of the logical sector size. The Block Limits VPD page already advertises a single such page as the maximum WRITE SAME length (65535 ATAMAXTRIMRNUM logical blocks), so the block layer never sends a request that needs more than one page.
Emit exactly one 512-byte page, independent of the logical sector size, and transfer only that page (COUNT == 1). For a 512-byte-sector device this is unchanged; devices with larger logical sectors now work instead of failing every TRIM.
In the Linux kernel, the following vulnerability has been resolved:
smb: client: clear ce->tgthint in freetgts()
When freetgts() frees all structures in ce->tlist, ce->tgthint is left pointing to one of the freed cachedfstgt structures.
If ce->tgthint is not reset before it is used later, it results in a use-after-free.
Set ce->tgthint to NULL in freetgts() after the elements are freed to reflect that no elements remain.
In the Linux kernel, the following vulnerability has been resolved:
smb: client: reject a tree connect response whose byte count is too small
CIFSTCon() bounds its strnlen() over the byte area with the server's ByteCount minus two, which for ByteCount 0 or 1 goes negative as an int and converts to a huge sizet. The later subtraction wraps the u16 bytesleft, and that is what bounds cifsstrndupfromutf16(): a bound of up to 65535 against a ~16 KB cifsreqpoolp object runs off the end of the slab object, and the bytes reach userspace through tcon->nativeFileSystem in /proc/fs/cifs/DebugData.
Reject a byte area too small for what the parser consumes. Two bytes is the least it can consume, and no conformant response carries fewer. The new trace point is the 129th smbeiotrace entry, which mode(byte) cannot represent, so the attribute goes with it.
In the Linux kernel, the following vulnerability has been resolved:
bpf: Disable preemption in bpfgetstack
getperfcallchain() returns a per-CPU perfcallchainentry buffer and releases its recursion slot via putcallchainentry() before returning, so nothing keeps the entry reserved while bpfgetstack() consumes it below.
A preemptible BPF program (e.g. a non-sleepable raw tracepoint program on a PREEMPT kernel, which runs under migratedisable() but not preemptdisable()) can be scheduled out between obtaining the entry and the copy. Another task scheduled on the same CPU then reuses the same per-CPU buffer and overwrites trace->nr with a larger value. copylen is then computed from the inflated trace->nr and can exceed the caller's buffer, causing an out-of-bounds write in the memcpy() and in the buildid path.
The rcureadlock() taken here alone does not prevent this. It is only taken on the mayfault path, and under CONFIGPREEMPTRCU it does not disable preemption; it merely keeps perf's callchain buffer array alive (freed via callrcu()) and does nothing to stop another task from reusing the entry.
Disable preemption around obtaining the callchain entry and copying it into the caller's buffer, so the entry cannot be reused underneath us and trace->nr stays bounded by maxdepth. Build ID resolution may fault and is therefore deferred until after preemption is re-enabled; by then the instruction pointers have already been copied into buf, so it operates only on that private copy. Note, preemptdisable() also subsumes the buffer-lifetime guarantee the rcureadlock() provided, since a preempt-disabled section is an RCU read-side critical section for the callchain buffers' callrcu() reclaim.
[ changed Fixes: commit ]
In the Linux kernel, the following vulnerability has been resolved:
ip6tunnel: use skbcowhead() in ip6tnlxmit()
ip6tnlxmit() may need to expand headroom before it can push the outer IPv6 and optional encap headers. It currently does that with skbreallocheadroom(), copies skb->sk ownership, consumes the original skb, and then continues processing with the replacement skb kept only in its local variable.
That is safe only if the helper cannot fail afterwards. But this helper still has post-reallocation error exits. collectmd tunnels reject non-NONE encap after the replacement, and ip6tnlencap() can also fail later. In those cases the helper returns an error to its callers while the caller still only has the original skb pointer.
Both ip6tnlstartxmit() and the IPv6 GRE paths free the caller skb on error, so they can end up freeing an skb that ip6tnlxmit() already consumed.
Use skbcowhead() instead. It provides the required headroom and writability without privately replacing the caller-owned skb, so later error returns cannot leave callers with a stale pointer.
The Ethernet users, ip6gretap and ip6erspan, clear IFFTXSKBSHARING and already call skbcowhead() before entering ip6tnlxmit(). They do not rely on the removed skbshared() reallocation. This also makes the IPv6 tunnel path consistent with iptunnelxmit().
In the Linux kernel, the following vulnerability has been resolved:
libnvdimm/labels: Prevent integer overflow in ndlabelvalidate()
The on-media namespace index field nslot is a u32 read from the DIMM label storage area. ndlabelvalidate() bounds it against the config area size, but sizeofnamespacelabel() returns unsigned, so the product nslot labelsize is evaluated in 32-bit and wraps modulo 2^32 before the comparison. A crafted nslot passes the bound and is then used as the loop trip count in ndlabeldatainit(), whose memset() walks off the end of the configsize buffer: an out-of-bounds write.
The field is not trusted -- it comes from the medium, or from userspace via NDCMDSETCONFIGDATA. Evaluate the product in 64-bit so the bound check is exact; conforming labels are unaffected.
The check was safe when introduced by commit 4a826c83db4e ("libnvdimm: namespace indices: read and validate"): it multiplied by sizeof(struct ndnamespacelabel), a sizet, so on a 64-bit build the product did not wrap. Commit 564e871aa66f ("libnvdimm, label: add v1.2 nvdimm label definitions") narrowed it to 32 bits when the label size became a runtime value read via sizeofnamespacelabel().
In the Linux kernel, the following vulnerability has been resolved:
nouveau/gem: reserve the bo in the info ioctl around the vma lookup
In the non-uvmm path, there could be a race between the info lookup finding the vma, and the gem close path closing the vma leading to a use-after-free.
Spotted with the help of Opus 4.6.
In the Linux kernel, the following vulnerability has been resolved:
SUNRPC: svcauthgss: enforce krb5 token minimum length
svcauthgssunwrappriv() validates only an upper bound on the wire-supplied opaque length before handing the buffer to gssunwrap():
if (len > xdrstreamremaining(xdr)) goto unwrapfailed; offset = xdrstreampos(xdr); ... majstat = gssunwrap(ctx, offset, offset + len, buf);
The wire value len flows unchanged as the upper bound into the krb5 unwrap path, so a len in [0, 16] passes this check and is handed to gssunwrap(). For a krb5 v2 context that lands in gsskrb5unwrapv2(), which reads the 16-byte RFC 4121 token header fields at ptr+4 and ptr+6 and then calls rotateleft() before any integrity check. With a sub-header length the header reads run past the token, and rotateleft()'s shift %= buf->len path can divide by zero when buf->len has been driven to zero by the truncated token. A header-only token (len == 16) is equally invalid: with a non-zero RRC field and the opaque blob ending at the XDR buffer boundary, rotateleft() builds a zero-length subbuffer, reaching the same division.
Reject the token at the server entry point before it reaches the krb5 unwrap core. A valid sealed RFC 4121 token must contain the 16-byte header plus at least some encrypted payload.
Fix by adding a minimum-length check immediately after the existing upper-bound check:
if (len <= GSSKRB5TOKHDRLEN) goto unwrapfailed;
In the Linux kernel, the following vulnerability has been resolved:
mpls: reload header after pskbmaypull()
mplsselectmultipath() calls mplsmultipathhash() to choose a nexthop when an MPLS route has multiple nexthops. While walking the MPLS label stack, the hash routine caches hdr for the current label. After finding the bottom-of-stack label, it calls pskbmaypull() before reading the inner IP header.
If an skb is constructed with the inner IP header in nonlinear data and insufficient tailroom in the linear head, pskbmaypull() calls pskbexpandhead() to replace the skb head and free the old one. This leaves hdr pointing to freed memory. The IPv6 path can invalidate hdr again when it performs a second pull for the larger header.
The issue was found through static analysis. A reproducer sending a legal Geneve packet through a bareudp/MPLS multipath setup triggered the same KASAN report in 2 of 2 unpatched runs:
BUG: KASAN: slab-use-after-free in mplsselectmultipath Read of size 1 at addr ffff88800ecc6e20 by task ksoftirqd/1/23
Call Trace: mplsselectmultipath mplsforward netifreceiveskblistcore netifreceiveskblistinternal napicompletedone grocellpoll napipoll netrxaction
Freed by task 23: kfree pskbexpandhead pskbpulltail mplsselectmultipath
Reload hdr from the current skb head after each successful pull before deriving the inner IPv4 or IPv6 header pointer.
In the Linux kernel, the following vulnerability has been resolved:
SUNRPC: fix gssxdecoptionarray error path bugs
Four coupled defects in the gssx XDR option-array decoder make the error paths unsafe: a NULL deref in the caller, a refcount leak on the decoded groupinfo, and a latent use-after-free that the leak fix would otherwise expose.
gssxdecoptionarray() sets oa->count = 1 before allocating oa->data. If that allocation fails, -ENOMEM is returned with oa->count == 1 and oa->data == NULL. All other error paths jump to freeoa: which frees oa->data and NULLs it but also leaves oa->count == 1. The caller trusts the count:
gsspacceptseccontextupcall() gssxdecacceptseccontext() gssxdecoptionarray() / fails, count=1 data=NULL / data = res.options.data[0].value / NULL deref /
Independently, freecreds: releases the partially decoded svccred with a bare kfree(creds). gssxdeclinuxcreds() installs a groupsalloc() result into creds->crgroupinfo; that object is kvmalloc-backed and refcounted, and only putgroupinfo() reaches kvfree(). A plain kfree(creds) drops the wrapper and leaks the groupinfo allocation.
The natural fix for the leak is to call freesvccred(creds) before kfree(creds), but freesvccred() invokes putgroupinfo() on creds->crgroupinfo unconditionally when non-NULL. The existing outfreegroups: path in gssxdeclinuxcreds() already called groupsfree() on that pointer without clearing it, so once freesvccred() is wired in, the subsequent putgroupinfo() would touch freed memory.
Fix all four together:
- Move the oa->count = 1 assignment below the oa->data allocation so it is never set when oa->data is NULL. - Reset oa->count to 0 at freeoa: so count and data stay coherent and the caller sees an empty option array. - Call freesvccred(creds) before kfree(creds) at freecreds: so the refcounted crgroupinfo is released. freesvccred() either NULL-guards each field explicitly (crgroupinfo has an if() check) or delegates to a helper that is NULL-safe itself (kfree for the string fields, gssmechput() which guards with if(gm) at gssmechswitch.c:342), so it is safe to call on a partially decoded svccred where only cruid/crgid/crgroupinfo have been written and everything else is zero from kzalloc. - In gssxdeclinuxcreds()'s outfreegroups: path, release crgroupinfo with putgroupinfo() rather than groupsfree() so the teardown matches freesvccred()'s refcount-aware path, and clear the pointer so a later freesvccred() on the same creds does not release it a second time.
In the Linux kernel, the following vulnerability has been resolved:
svcrdma: Fix pclforeachsegment for empty chunks
When a parsed chunk list contains a chunk whose chsegcount is zero, pclforeachsegment computes its inclusive upper bound as &chunk->chsegments[chsegcount - 1]. chsegcount is u32, so the subtraction wraps to 0xFFFFFFFF and the bound lands far past the chsegments flex array. The loop body then walks unrelated memory at sizeof(struct svcrdmasegment) stride until it faults.
A zero-segcount chunk is reachable from the wire: xdrcheckwritechunk() only rejects segcount values greater than rcmaxpages, and pclallocwrite() links a freshly allocated chunk onto rcwritepcl/rcreplypcl before its segment-fill loop runs, so a Write or Reply chunk advertising zero segments leaves chsegcount == 0 on the list. When the transport has negotiated Send-With-Invalidate, svcrdmagetinvrkey() iterates all four PCLs with pclforeachsegment and dereferences segment->rshandle on each iteration, turning the underflow into an out-of-bounds read and a general protection fault.
xdrcheckwritelist / xdrcheckreplychunk pclallocwrite() chunk = pclallocchunk(...) / chsegcount = 0 / listaddtail(&chunk->chlist, &pcl->clchunks) / fill loop iterates zero times for wire segcount 0 /
svcrdmagetinvrkey() pclforeachchunk(rcwritepcl) pclforeachsegment(segment, chunk) pos <= &chsegments[0u - 1u] / 0xFFFFFFFF / segment->rshandle / OOB read -> GPF /
Fix by switching the macro to a half-open upper bound that uses chsegcount directly. For chsegcount == 0 the loop start equals the loop end and the body is skipped; for chsegcount > 0 the iteration range is unchanged. All six existing call sites in net/sunrpc/xprtrdma/svcrdmarecvfrom.c and net/sunrpc/xprtrdma/svcrdmarw.c remain correct under the new bound, so no caller changes are needed.
In the Linux kernel, the following vulnerability has been resolved:
svcrdma: Reject inline replies that overflow the pull-up buffer
An RPC-over-RDMA client can request a reply, such as an NFS READ payload, without providing a Write list or a Reply chunk to carry it. When such a reply needs more scatter/gather entries than the device's Send Queue supports, svcrdmapullupneeded() selects pull-up and svcrdmapullupreplymsg() linearizes the whole reply into sctxt->scxprtbuf. That buffer is only scmaxreqsize bytes, while the reply on this path is bounded only by the client's request, so svcrdmaxblinearize() copies past the end of the buffer and corrupts adjacent slab memory. The oversized length is then stored in scsges[0].length and posted, so the device also reads beyond the mapped region.
The SGE-exhaustion branch is the only pull-up path that can exceed the buffer: the threshold branch pulls up only replies smaller than RPCRDMAPULLUPTHRESH, and replies that fit the device's SGE budget are sent directly without linearization. Make svcrdmapullupneeded() report -E2BIG when the reply it would pull up cannot fit scmaxreqsize, and fail the request with ERRCHUNK as RFC 8166 Section 4.5.3 directs rather than dropping the connection.
The helper no longer answers a simple yes/no question: it now reports pull-up, no pull-up, or -E2BIG for a reply too large to linearize. Rename svcrdmapullupneeded() to svcrdmacheckpullup() so its name no longer implies a boolean predicate.
In the Linux kernel, the following vulnerability has been resolved:
sctp: fix NULL deref on untransmitted RECONF completion
sctpprocessstrresetoutreq(), sctpprocessstrresetaddstrmout() and sctpprocessstrresetresp() complete a pending stream reconfiguration request by stopping the reconf timer on the transport it was sent on:
t = asoc->strresetchunk->transport; if (timerdelete(&t->reconftimer)) sctptransportput(t);
chunk->transport is assigned by sctppacketappendchunk() when the chunk is appended to an outbound packet, and sctpoutqflushctrl() arms the reconf timer at that same point. A request already published in asoc->strresetchunk but not yet transmitted has neither, so completing it dereferences NULL.
Two ways to get there. sctpsendasconfdelip() sets asoc->srcoutofasocok without sending anything when the address being removed is the association's last one, and sctpoutqflushctrl() then leaves every non-ASCONF control chunk queued; as only sctpprocessasconfack() clears that flag, it persists. An unprivileged process that removes such an address and then asks for a stream reset panics the kernel from softirq. A peer needs neither ASCONF nor local help: sctpcmdinterpreter() uncorks the outqueue only once the whole packet has been processed, so a reply built while walking a RECONF chunk stays untransmitted for the rest of that walk, and one RECONF chunk carrying [Incoming SSN Reset Request, Outgoing SSN Reset Request, Response] -- or two RECONF chunks in one packet -- reaches the same dereference.
KASAN: null-ptr-deref in range [0x00000000000001e8-0x00000000000001ef] RIP: 0010:timerdelete+0x67/0x110 Call Trace: <IRQ> sctpprocessstrresetaddstrmout (net/sctp/stream.c:832) sctpsfdoreconf (net/sctp/smstatefuns.c:4212) sctpdosm (net/sctp/smsideeffect.c:1172) sctpassocbhrcv (net/sctp/associola.c:1044) sctprcv (net/sctp/input.c:243) iplocaldeliver (net/ipv4/ipinput.c:262) processbacklog (net/core/dev.c:6680) </IRQ>
A response can only acknowledge a request that was actually sent, so do not match asoc->strresetchunk while chunk->transport is NULL. Guarding the lookup covers all three completion sites.
In the Linux kernel, the following vulnerability has been resolved:
nvme-tcp: reject a read that transferred too few bytes
nvmetcprecvdata() completes a request once the current C2HData PDU has been consumed. Nothing compares the total bytes received against the length the command asked for: struct nvmetcprequest has no receive-side counter, queue->dataremaining is per queue, and blkmqendrequest() completes for blkrqbytes(rq) unconditionally with no residual concept anywhere above.
A controller can therefore answer a 4096-byte read with 512 bytes and have it reported as a complete read; user space then gets 4096 bytes of which 3584 are whatever was already in the page. I reproduced that with a test target.
Count the bytes received and refuse to complete a successful read whose count does not match, at the two NVMETCPFDATASUCCESS paths and in nvmetcpprocessnvmecqe(). The success test shifts req->status right by one, because the driver keeps the wire value there and shifts it on completion, so the check must see what the completion path will see. Only REQOPREAD is checked, because there the length comes from the sectors the request covers; a passthrough command is built by its submitter, which picks both command and buffer, so the kernel has nothing to compare against.
In the Linux kernel, the following vulnerability has been resolved:
nvme: zero the discard fallback page
nvmesetupdiscard() always maps sizeof(struct nvmedsmrange) NVMEDSMMAXRANGES = 4096 bytes as the DSM payload however many ranges the command declares, because some devices ignore the 'Number of Ranges' field - the Fixes: commit records two that read past the declared ranges. A single-range discard fills only the first 16 bytes.
Normally the buffer comes from kzalloc() and the other 4080 bytes are zero. When that allocation fails the code falls back to the per-controller ctrl->discardpage, which nvmeinitctrl() obtains with allocpage(GFPKERNEL) and nothing ever zeroes, so those 4080 bytes are whatever the page last held and are handed to the controller. Reaching it requires the kzalloc(GFPATOMIC | GFPNOWARN) to fail, that is memory pressure; it is not remotely triggerable. Failing the allocation under KMSAN reproduces it, with the leaked tail full of vmemmap struct page pointers. The extent in the report is a partial transfer of the payload, not the whole 4096 bytes; the 16-byte boundary in it is the one declared range:
[ 11.991601] BUG: KMSAN: uninit-value in dmamapphys+0x14c8/0x1900 [ 11.991969] dmamapphys+0x14c8/0x1900 [ 11.992220] dmamappageattrs+0xcf/0x130 [ 11.992485] e1000xmitframe+0x4099/0x6d10 [ 11.992768] devhardstartxmit+0x22f/0xa80 [ 11.993068] schdirectxmit+0x35c/0xcb0 [ 11.993315] devqueuexmit+0x1ee5/0x5eb0 [ 11.993608] ipfinishoutput2+0x1903/0x1c30 [ 11.993881] ipfinishoutput+0x288/0x870 [ 11.994125] ipoutput+0x15e/0x400 [ 11.994365] ipqueuexmit+0x1e85/0x1fb0 [ 11.994639] ipqueuexmit+0x60/0x80 [ 11.994899] tcptransmitskb+0x4e71/0x5fa0 [ 11.995210] tcpwritexmit+0x3a36/0x9160 [ 11.995533] tcppushpendingframes+0xc5/0x3c0 [ 11.995854] tcppush+0x7dc/0x840 [ 11.996076] tcpsendmsglocked+0x766c/0x8400 [ 11.996371] tcpsendmsg+0x4b/0x90 [ 11.996572] inetsendmsg+0x134/0x2a0 [ 11.996823] socksendmsg+0x265/0x360 [ 11.997076] socksendmsg+0x100/0x1e0 [ 11.997293] nvmetcptrysend+0x196f/0x6370 [ 11.997605] nvmetcpqueuerq+0x1d54/0x20b0 [ 11.997882] blkmqdispatchrqlist+0x5ee/0x2e50 [ 11.998175] blkmqscheddispatchrequests+0x16dc/0x24a0 [ 11.998539] blkmqscheddispatchrequests+0x11b/0x2c0 [ 11.998865] blkmqrunworkfn+0x13b/0x280 [ 11.999146] processscheduledworks+0x966/0x1ad0 [ 11.999465] workerthread+0xe44/0x1480 [ 11.999709] kthread+0x53b/0x600 [ 11.999927] retfromfork+0x29f/0x7c0 [ 12.000191] retfromforkasm+0x1a/0x30 [ 12.000460] [ 12.000558] Uninit was created at: [ 12.000788] allocfrozenpagesnoprof+0x8bf/0xd30 [ 12.001096] allocpagesmpol+0x1d0/0x5f0 [ 12.001326] allocpagesnoprof+0x102/0x290 [ 12.001627] nvmeinitctrl+0x5a3/0x9f0 [ 12.001891] nvmetcpcreatectrl+0xd75/0x19b0 [ 12.002170] nvmfdevwrite+0x4c68/0x4fd0 [ 12.002426] vfswrite+0x587/0x1a10 [ 12.002636] x64syswrite+0x207/0x4f0 [ 12.002874] x64syscall+0x2ff0/0x3ea0 [ 12.003123] dosyscall64+0x147/0x3b0 [ 12.003400] entrySYSCALL64afterhwframe+0x77/0x7f [ 12.003680] [ 12.003777] Bytes 16-2843 of 2844 are uninitialized [ 12.004068] Memory access of size 2844 starts at ffff888109f82000 [ 12.004412] [ 12.004530] CPU: 0 UID: 0 PID: 101 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMECTL-gf5098b6bae76 #1 PREEMPT(lazy) [ 12.005127] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, archcaps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 12.005762] Workqueue: kblockd blkmqrunworkfn [ 12.006073] =====================================================
Allocate the page with GFPZERO. The single allocation site covers every use of it: bytes no discard has written stay zero, and bytes one did write hold that controller's own range list, which it has already been sent.
In the Linux kernel, the following vulnerability has been resolved:
sctp: stop processing a packet once its association is deleted
sctpendpointbhrcv() looks the association up only when chunk->asoc is NULL, and caches the result in chunk->asoc and chunk->transport without taking a reference.
A packet that matches no association is handed to the endpoint, so a peer can bundle COOKIE ECHO, SHUTDOWN and SHUTDOWN ACK in one packet. The COOKIE ECHO creates the association, the SHUTDOWN chunk caches it, and with the outqueue empty the SHUTDOWN ACK reaches sctpsfdo92final(), so the association and its transports are freed.
The endpoint loop has no counterpart to the asoc->base.dead check in sctpassocbhrcv(). The next chunk writes to lasttimeheard in the freed transport and is then passed to sctpdosm() with the freed association. The transport is freed through RCU, so this needs the packet to come off the socket backlog, where the loop runs in task context.
The endpoint loop cannot do the same check: it holds no reference on the association, so reading asoc->base.dead would itself be a use-after-free. Mark the packet for discard in the command interpreter, just before it deletes the association. That is also before sctpinqfree() releases the chunk on the association receive path.
sctpsfdo524dupcook() issues SCTPCMDDELETETCB for the temporary association, while the one the packet belongs to stays alive. A restarting peer can bundle DATA behind its COOKIE ECHO, so compare against chunk->asoc and leave that case alone.
In the Linux kernel, the following vulnerability has been resolved:
mmc: via-sdmmc: cancel card-detect work on remove
Disabling the device interrupt and freeing the IRQ prevents new card-detect work from being queued, but carddetwork already queued by the handler can still run after viasdremove() returns. viasdccarddetect() recovers the host through containerof() and dereferences its MMIO base; once remove() returns the host can be freed, so that work would touch freed memory.
Cancel carddetwork after freeing the IRQ and before cancelling finishbhwork, which the card-detect handler can also queue. carddetwork can re-enable the interrupt through viaresetpcictrl(); mask it again afterwards.
This issue was found by an in-house static analysis tool and confirmed by manual code review.
In the Linux kernel, the following vulnerability has been resolved:
net/smc: fix use-after-free in smcrxpipebufrelease()
smcrxsplice() hands RMB pages to a pipe and takes a socket reference per entry so the smcsock stays alive until the reader finishes. The connection does not: a concurrent close runs smcconnfree(), which releases the receive buffer back to the link group pool.
smcrxpipebufrelease() tests skstate before taking the socket lock. The state can change between the test and the lock, and smcrxupdatecons() then dereferences conn->rmbdesc and walks conn->lgr, which smcconnfree() has already released. On the isregerr path smcrbufunuse() frees the descriptor outright, so this is a use-after-free.
Take the socket lock first and test conn->freed instead. smcconnfree() sets that flag before releasing anything, and every caller holds the socket lock. The two paths exclude each other: either the pipe release runs first with everything valid, or it sees the flag and skips the update.
In the Linux kernel, the following vulnerability has been resolved:
NTB: ntbtransport: Reject oversized TX buffers
ntbprocesstx() handles an oversized buffer by calling txhandler() with a NULL data pointer and returning success. ntbnetdev therefore neither frees the skb in its completion callback nor takes its enqueue error path, leaking it.
Reject oversized buffers in ntbtransporttxenqueue() before acquiring a queue entry and return -EMSGSIZE. The caller retains ownership of the buffer, and the preceding netdev patch frees the skb when enqueue returns this permanent error.
In the Linux kernel, the following vulnerability has been resolved:
serial: amba-pl011: synchronize DMA teardown
dmaengineterminateall() does not wait for a running callback, so the TX callback can still touch the TX buffer after it is freed. The RX poll timer reads the RX buffers without the port lock.
Switch to dmaengineterminatesync() and delete the RX timer before freeing the buffers.
In the Linux kernel, the following vulnerability has been resolved:
Input: synaptics-rmi4 - fix F55 transmitter electrode count typo
During F55 sensor detection, the transmitter (TX) electrode count was incorrectly assigned the value of the receiver (RX) electrode count due to copy-paste typos.
This incorrect value was then propagated to the driver data and used by F54 to determine the diagnostics report size. On devices with more RX than TX electrodes, this inflated the perceived TX count, leading to incorrect report size calculations and potential out-of-bounds buffer accesses.
Fix the typos by correctly assigning the TX electrode counts.
In the Linux kernel, the following vulnerability has been resolved:
vsock/virtio: flush works in dependency order
virtiovsockremove() stops the virtqueues and then flushes each work item before freeing the enclosing virtiovsock. The current order does not account for dependencies between those items: txwork may queue sendpktwork, and sendpktwork may queue rxwork.
In particular, sendpktwork can set restartrx and release txlock. The remove path can then stop the queues and flush rxwork before sendpktwork queues it. Although the later sendpktwork flush waits for that producer to finish, nothing waits for the newly queued rxwork, so kfree(vsock) can race with it.
KASAN reported:
BUG: KASAN: slab-use-after-free in virtiotransportrxwork+0x487/0x4b0 Read of size 8 at addr ffff888114c2b008 by task kworker/1:1/47 Workqueue: virtiovsock virtiotransportrxwork Call Trace: virtiotransportrxwork+0x487/0x4b0 processonework+0x688/0x1120 workerthread+0x45b/0xd10 Allocated by task 1: virtiovsockprobe+0xef/0x6b0 Freed by task 84: kfree+0x131/0x3c0 virtiovsockremove+0xd1/0x100
Flush the works in producer-to-consumer order. virtiovsockvqsdel() has already disabled the queue callbacks and cleared the run flags, so after txwork and sendpktwork are drained, no source remains that can queue rxwork after its flush.
In the Linux kernel, the following vulnerability has been resolved:
wifi: mwifiex: Detach sync cmd buffer on interrupted wait
mwifiex synchronous commands keep the caller-provided data buffer in cmdnode->databuf. Several callers pass stack-allocated objects there.
If waiteventinterruptibletimeout() is interrupted, the caller can return and release that stack object while the firmware command is still the current command. A late firmware response then reaches the normal response handler, which can copy data through cmdnode->databuf into the stale stack address.
This fixes a stack corruption observed during repeated association and disassociation cycles. The panic trace showed the command wait being interrupted immediately before a bad pointer dereference:
cmdwaitq terminated: -512 Unable to handle kernel paging request at virtual address 002c583837384662 Kernel panic - not syncing: stack-protector: Kernel stack is corrupted ... Tainted: [M]=MACHINECHECK
The fault address decodes as little-endian ASCII:
0x002c583837384662 -> "bF878X,\0"
which is a fragment of the VERSIONEXT firmware string exposed as debugfs "verext":
w8997o-V4, RF878X, FP92, 16.92.21.p153.7
The same runs also showed corrupted control data containing:
0x2400372e333531 -> "153.7\0$"
which is the tail of the same VERSIONEXT string. This points at a late VERSIONEXT response writing through a stale stack-backed databuf after the interrupted wait returned.
After cancelling pending commands on an interrupted or timed-out wait, detach the caller-owned data buffer from the still-current command. This preserves the existing command cancellation behaviour while preventing a late response from writing through a pointer whose lifetime ended with the waiting caller.
Tested on an i.MX8MP board using an 88W8997.