Where
-Infinity
0
Severity
4.2
AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L

The STM32WBA IEEE 802.15.4 driver in drivers/ieee802154/ieee802154stm32wba.c computed the packet length of a received frame as pktlen = rxframe->length - IEEE802154FCSLENGTH without first checking that the radio-reported length could hold an FCS. pktlen is a uint8t, so a reported length of 0 or 1 wrapped to 254 or 255. The only bound on the resulting value was ASSERTNOMSG(pktlen <= CONFIGNETBUFDATASIZE), which compiles to nothing in the default production configuration (CONFIGASSERT=n).

The length originates in the ST link-layer receive-done metadata (pmetadata->length, stored by stm32wba802154receivedone()), and ultimately in the PHY header of a frame received over the air, so it is influenced by any attacker within radio range of the device. Reaching the underflow requires the vendor link layer to surface a frame shorter than the FCS with no error; the driver performed no validation of its own on that value.

When the underflow occurs, stm32wba802154rxthread() calls netpktwrite(pkt, rxframe->psdu, pktlen) with a length of about 254 bytes against a receive buffer that holds at most one PHY packet (IEEE802154MAXPHYPACKETSIZE, 127 bytes). This reads roughly 128 bytes past the end of the radio receive buffer and copies that adjacent memory into a network packet that is submitted to the networking stack, giving an out-of-bounds read with a potential disclosure of adjacent RAM plus needless oversized packet allocation in the RX thread.

The fix rejects a frame whose reported length is smaller than IEEE802154FCSLENGTH before the subtraction, and replaces the compiled-out assertion with a runtime length check that drops oversized frames — matching the runtime check already present in drivers/ieee802154/ieee802154nrf5.c.

First published (updated )
Severity
5.9
Integer Underflow
AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H

The receive path of the NXP KW41Z IEEE 802.15.4 driver, kw41zrx() in drivers/ieee802154/ieee802154kw41z.c, computed the payload size as pktlen = len - KW41ZFCSLENGTH in a uint8t, where len is the frame length reported by the radio. The interrupt handler kw41zisr() obtained that length from the RXFRAMELENGTH field of the ZLL IRQSTS register — a copy of the PHY header length byte of the frame received over the air — and only rejected the value zero. A reported length of one therefore underflowed to pktlen == 255.

Because the packet is allocated with NETAFUNSPEC on a non-Ethernet L2, netpktrxallocwithbuffer() does not clamp the request to the interface MTU; with the default fixed-size buffer pool (CONFIGNETBUFFIXEDDATASIZE, CONFIGNETBUFDATASIZE=128) the allocation succeeded as a chain of two fragments. The subsequent register-to-buffer copy loops write into the first fragment only, so 255 bytes were written into a 128-byte netbuf data block, overrunning it by up to 127 bytes into adjacent network-buffer-pool memory, and reading up to 128 bytes past the end of the radio's PKTBUFFERRX register array.

The length field originates from an unauthenticated frame transmitted by any device within 802.15.4 radio range, and is captured by the hardware at PHY-header time — before frame filtering has completed — while the handler samples it after clearing the interrupt status, so an attacker flooding frames with a length byte of one can drive the underflow. The impact is memory corruption in the shared receive buffer pool from interrupt context, most plausibly a crash or corruption of other packets' data; the overflowing bytes are radio register contents rather than attacker-authored data, which bounds the integrity impact.

The fix rejects any length below KW41ZFCSLENGTH and additionally verifies netbuftailroom() of the first fragment before the copy loops, which also covers the CONFIGNETL2OPENTHREAD variant of the size computation.

First published (updated )
Severity
3.4
AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:L

The zbus proxy agent IPC backend in subsys/zbus/proxyagent/zbusproxyagentipc.c logged the channel name of a rejected inter-domain frame with a plain %s conversion. The frame type struct zbusproxymsg carries a fixed-size channelname[] array as its last member, and nothing in the transport guarantees the array is NUL-terminated. The only code that verifies termination is zbusproxyagentreceivecb() in subsys/zbus/proxyagent/zbusproxyagent.c, which rejects the frame in precisely those cases — so the warning printed a non-terminated buffer exactly on the error paths where the name had been found invalid (or, for an invalid messagesize, had not been inspected at all).

Any peer domain able to place a frame of sizeof(struct zbusproxymsg) bytes on the bound ipcservice endpoint can trigger it, by sending a frame with an out-of-range messagesize or with channelname[] containing no NUL byte. Reaching the code requires CONFIGZBUSPROXYAGENTIPC and logging built at warning level or above (the default), and requires control over the firmware of the peer domain — typically a second core on the same SoC.

The resulting strlen() inside the log packager walks past the end of the frame object until it finds a zero byte. With the icmsg backend the frame lives in a stack buffer of the IPC work-queue thread, so bytes of that thread's stack are rendered into the log message; with the rpmsg backends the scan continues through the shared vring memory. Impact is bounded to disclosure of a small amount of adjacent memory into the receiving domain's log sink, plus a possible fatal fault if the scan leaves a mapped region; the log packager's own -ENOSPC bound prevents the overrun from becoming a write. The fix bounds the conversion with %.s and MIN(msg->channelnamelen, sizeof(msg->channelname)).

First published (updated )
Severity
7.1
AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H

netrouteipv6packet() in subsys/net/ip/routeipv6.c resolved the nexthop's link-layer address with netnbrgetlladdr(nbr->idx) without first checking whether the neighbor cache entry actually had a linked link-layer address. An unresolved neighbor carries idx == NETNBRLLADDRUNKNOWN (0xff), and netnbrgetlladdr() in subsys/net/ip/nbr.c performs no runtime bounds check beyond a NETASSERT, returning &netneighborlladdr[255] — roughly 2.5 KB past the end of an array whose default size is CONFIGNETIPV6MAXNEIGHBORS (8). Because the returned pointer is never NULL, the following lladdr == NULL guard does not catch it.

The function is reached from ipv6routepacket() in subsys/net/ip/ipv6.c for every received unicast IPv6 packet whose destination is not a local address on the receiving interface; CONFIGNETIPV6ROUTE is enabled by default whenever the IPv6 neighbor cache is, so no router or forwarding configuration is needed. netrouteipv6getinfo() returns the packet's destination itself as the nexthop when a neighbor cache entry for it exists, and the cache lookup does not skip INCOMPLETE entries. An unauthenticated attacker on the same link can therefore force the unresolved state — for example by eliciting traffic to a spoofed, non-existent neighbor address so that netipv6sendns() creates an INCOMPLETE entry, or by sending a Router Advertisement with no source link-layer address option, which creates a persistently unresolved router neighbor — and then send a packet addressed to that neighbor.

The result is an out-of-bounds read at a fixed index past the neighbor link-layer address array. On builds with CONFIGASSERT enabled the assertion fires and the device panics, giving a repeatable remote denial of service. With assertions disabled, the stale out-of-bounds struct netlinkaddr drives a memcmp() over an attacker-uninfluenced length and, when its len byte passes the NETLINKADDRMAXLENGTH check, up to 8 bytes of unrelated static RAM are copied into the outgoing frame's destination link-layer address and transmitted on the link, disclosing them to any listener. There is no out-of-bounds write and the offset is not attacker-controlled, which bounds the impact.

First published (updated )
Severity
8.8
Integer Overflow
AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

dynamicobjectcreate() in kernel/userspace/userspace.c computed the backing allocation for a dynamically allocated kernel object as objsizeget(otype) + size, and for thread stack elements as STACKELEMENTDATASIZE(size) (a round-up plus fixed overhead), without checking either expression for unsigned wrap-around. A size close to SIZEMAX makes the computed total wrap to a very small value, so the heap chunk handed out is a few bytes while the object descriptor is still tagged with the full requested type and registered in the kernel object table.

The size argument reaches that arithmetic directly from user mode. kobjectallocsize() is declared syscall in include/zephyr/sys/kobject.h, its verifier zvrfykobjectallocsize() in kernel/userspace/userspacehandler.c is a bare pass-through, and zobjectalloc() only range-checks otype — nothing bounds size. The stack-element branch is additionally reachable through the kthreadstackalloc() syscall via kernel/dynamic.c. Because subsequent kernel-object validation checks only the object's type and initialization state, the undersized handle passes KSYSCALLOBJINIT()/KSYSCALLOBJNEVERINIT(), and the matching init syscall (for example kmutexinit(), kseminit(), or kthreadcreate()) then writes a complete object over the truncated allocation.

An unprivileged user-mode thread can therefore trigger a supervisor-mode out-of-bounds write into the kernel resource-pool heap, of a size and content it substantially controls, corrupting sysheap chunk metadata and adjacent kernel objects. Under CONFIGGENPRIVSTACKS the thread-stack branch additionally stores an attacker-influenced wild pointer as a user thread's privileged stack base. The practical result is escape from the CONFIGUSERSPACE sandbox — kernel-level code execution or at minimum kernel memory corruption and system compromise.

Exploitation requires CONFIGUSERSPACE together with CONFIGDYNAMICOBJECTS (also selected by CONFIGDYNAMICTHREAD under userspace), and a calling thread with an assigned resource pool. The fix rejects both overflowing computations and frees the partially built descriptor.

First published (updated )
Severity
8.1
Integer Underflow
AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H

ieee802154decipherdataframe() in subsys/net/l2/ieee802154/ieee802154frame.c computed payloadlen = netpktgetlen(pkt) - llhdrlen - authtaglen without first checking that the received frame is at least llhdrlen + authtaglen bytes long. All three variables are uint8t, so a frame whose payload is shorter than the configured authentication tag makes the subtraction wrap around to a large value (up to 255).

The wrapped length is passed unchanged to ieee802154decryptauth() and on to the CCM operation as cipherpkt.inlen/outbufmax, with apkt->tag pointing at frame + llhdrlen + payloadlen. Because the receive buffer is allocated to the exact length of the frame received from the radio driver, the crypto layer then reads several hundred bytes past the end of the packet buffer and writes the same number of decrypted bytes back over it in place. The frame's authentication tag is only verified after this processing has taken place, so no key material, association or prior authentication is needed — a single crafted short frame from any device in radio range is sufficient. Frame validation in ieee802154validateframe() does not prevent it: a data frame is accepted with a one-byte payload.

The result is an out-of-bounds read and an out-of-bounds write of up to roughly 240 bytes into the adjacent network-buffer pool, corrupting other packets or allocator metadata and typically faulting the target. The out-of-bounds content is not attacker-chosen (it is ciphertext XOR keystream over out-of-bounds memory) and the frame is dropped when tag verification fails, so the primary impact is memory corruption and denial of service rather than information disclosure.

Exposure is limited to configurations that enable the experimental CONFIGNETL2IEEE802154SECURITY option, select a crypto device via CONFIGNETL2IEEE802154SECURITYCRYPTODEVNAME, and have established a security session with a level other than IEEE802154SECURITYLEVELNONE; with security disabled or at level NONE the tag length is zero and no underflow occurs. The fix rejects frames shorter than llhdrlen + authtaglen before the subtraction, and adds the matching guard on the transmit side in ieee802154createdataframe().

First published (updated )
Severity
7.8
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

The system-call verifier for i3cdoccc() in drivers/i3c/i3chandlers.c validated the outer struct i3ccccpayload, the broadcast ccc.data buffer and the targets.payloads[] array, but did not validate the per-target data buffers those array elements point at. Each struct i3cccctargetpayload carries its own data pointer and datalen, and neither was passed through KSYSCALLMEMORY() before the payload was handed to zimpli3cdoccc() and on to the controller driver. The verifier also operated on the caller's live structure rather than a snapshot, so validated fields could be changed by a second user thread between the check and the driver's use — unlike the sibling zvrfyi3ctransfer(), which has always copied its message array first.

The defect is only present in CONFIGUSERSPACE builds, where drivers/i3c/i3chandlers.c is compiled. An unprivileged user-mode thread that has been granted access to the I3C controller device object — the ordinary way an application lets a user thread talk to I3C peripherals — can issue a direct CCC whose target payload data pointer names an arbitrary kernel address. Controller drivers dereference that pointer directly (for example drivers/i3c/i3cmcux.c, drivers/i3c/i3ccdns.c, drivers/i3c/i3cstm32.c, drivers/i3c/i3cnpcx.c), using rnw to decide direction.

A read CCC therefore causes the kernel-mode driver to write bus-received bytes into an attacker-chosen kernel address for an attacker-chosen length, and a write CCC transmits kernel memory out onto the I3C bus. The result is an out-of-bounds kernel write plus a kernel memory disclosure, i.e. escalation from a user-mode thread to supervisor privilege, defeating the isolation CONFIGUSERSPACE is meant to provide.

The fix introduces copycccanddo(), which snapshots the payload, copies the target array into kernel memory with kusermodeallocfromcopy() (bounding numtargets to fewer than 32), validates each per-target buffer with KSYSCALLMEMORY() according to rnw, and copies the driver-written numxfer and err fields back to the caller.

First published (updated )
Severity
7.8
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

The userspace verifier zvrfyrtiosqecopyingethandles() in subsys/rtio/rtiosyscalls.c (subsys/rtio/rtiohandlers.c before v4.3.0) validated the RTIO object handle and the sqes input array, but not the handle out-parameter. On the first loop iteration it executed handle = sqe, storing the kernel address of the newly acquired submission-queue entry through a pointer taken verbatim from user mode, with no KSYSCALLMEMORYWRITE check in front of it.

Any user-mode thread that has been granted a struct rtio kernel object can invoke the syscall with an arbitrary address in handle. That is the ordinary way an unprivileged thread uses the RTIO API, for example via sensorreadasyncmempool() or the async ADC helpers, which call rtiosqecopyingethandles() internally. The store happens in supervisor mode before any submission-entry validation, so it fires regardless of whether the SQE contents are subsequently rejected. Only builds with CONFIGUSERSPACE and CONFIGRTIO are affected; without CONFIGUSERSPACE the verifier is not compiled and the caller is already privileged.

The write address is fully attacker-chosen and the written value is a pointer into the caller's own RTIO ring, whose contents the caller controls (the following sqe = sqes[i] copies an attacker-supplied struct rtiosqe into that slot). This yields a write-what-where primitive placing a pointer to attacker-controlled data at any kernel address, sufficient to corrupt kernel function pointers, thread structures, or memory-domain partition tables, and thus to escalate from user mode to kernel mode, defeating the isolation boundary CONFIGUSERSPACE is meant to enforce. At minimum it is a reliable kernel memory-corruption and crash primitive. The reporter reproduced the write on qemux86: a KUSER thread changed a supervisor global from NULL to a live kernel SQE pointer.

The fix adds KSYSCALLMEMORYWRITE(handle, sizeof(handle)) (guarded by the existing optional-NULL semantics) before the loop, so the destination must lie in the calling thread's writable memory domain or the thread is terminated by KOOPS. The neighbouring verifier zvrfyrtiocqegetmempoolbuffer(), which checked its buff/bufflen out-parameters only for read although the implementation writes through them, was hardened separately by bea93400138 ("rtio: syscalls: validate output params as writable"); that residual was materially weaker, since a read check still confines the target to the caller's own memory domain.

First published (updated )
Severity
4.6
CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

The Zephyr PL011 UART driver (drivers/serial/uartpl011.c) contains an unbounded software loop in pl011irqtxenable() that repeatedly invokes the interrupt-driven application callback while the TX interrupt mask bit (PL011IMSCTXIM) is set, to work around the controller's level-transition TX-interrupt behavior.

When CTS hardware flow control is enabled (devicetree hw-flow-control or runtime UARTCFGFLOWCTRLRTSCTS) and the wired serial peer de-asserts CTS, the controller stops draining the TX FIFO; pl011fifofill() then returns 0 on every call while the application still has pending data and therefore never disables the TX interrupt. The loop condition never clears, so the thread that called uartirqtxenable() (e.g. h4send() in the Bluetooth HCI H4 driver) spins indefinitely, hanging the executing context and stalling the transport — a denial of service (CWE-835).

An attacker controlling the device attached to the UART's CTS line can trigger the hang by withholding CTS during transmission. Because that peer is the device wired to the UART — which may be a removable or external module (e.g. an off-board Bluetooth controller on the HCI H4 link) rather than a permanently-bonded on-PCB part — the attack vector is scored Adjacent (AV:A) rather than Physical; the security subcommittee should confirm the vector against the specific deployment. Impact is availability only; there is no memory-safety, confidentiality, or integrity consequence.

The vulnerable loop was introduced in commit b783bc8448ef (Feb 2025) and shipped in releases v4.1.0 through v4.4.0. The fix breaks out of the loop when CTS is blocking and arms the CTS modem-status interrupt to resume transmission when CTS re-asserts.

First published (updated )
Severity
7.1
Input Validation
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H

btsdpparseattribute() in subsys/bluetooth/host/classic/sdp.c validated only that the SDP record buffer held the type-marker byte plus the 2-byte attribute ID (a check of buf->len < 3) but then read a fourth byte, the data-element descriptor (type), via netbufsimplepullu8(). Because netbufsimplepullu8() dereferences buf->data[0] before its only bounds guard (an ASSERTNOMSG that compiles out when CONFIGASSERT is disabled, the production default), a record of exactly three bytes (0x09 followed by a 2-byte attribute ID) causes a one-byte read past the end of the logical buffer. The parser is reachable from inbound, remote-controlled data: a Bluetooth BR/EDR peer acting as an SDP server returns discovery-response records that are stored verbatim in the client receive buffer and parsed via the public btsdpgetattr()/btsdphasattr()/btsdprecordparse() helpers. The over-read is bounded to a single byte that is used only as an internal length selector and is never leaked to the attacker; subsequent length checks then reject the malformed record. Realistic impact is therefore limited to an edge-case denial of service (a fault only if the record ends exactly at a mapped-memory boundary, or a deterministic assert panic when CONFIGASSERT=y). Affects Zephyr v4.3.0 and v4.4.0; fixed by adding sizeof(type) to the length check.

First published (updated )
Severity
5.5
CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H

The Zephyr ext2 filesystem driver (subsys/fs/ext2) trusted the on-disk directory entry fields dereclen and denamelen when walking a directory block. ext2fetchdirentry() guarded only with denamelen > EXT2MAXFILENAME, but denamelen is a uint8t and EXT2MAXFILENAME is 255, so the check is always false; the function then memcpy'd up to 255 name bytes and the lookup/readdir paths advanced traversal by an unvalidated dereclen. Each directory block is read into a blocksize-sized slab buffer, and blockoff can be driven near the block end by preceding entries' reclen, so the 8-byte header read and the subsequent name memcpy can read up to ~263 bytes past the end of the block buffer into adjacent heap/slab memory. On the readdir path those bytes are returned to the caller in fsdirent.name, leaking adjacent kernel heap memory; a dereclen of 0 also causes a zero-progress infinite loop (denial of service), and the unlink path's memmove(de, next, nextreclen) over unvalidated records is an additional OOB read/write source. The defect is reached by any path-based operation (open, stat, unlink, rename, mkdir) or directory listing on a mounted ext2 volume, so a crafted or corrupted ext2 image on attacker-supplied storage (SD card, USB mass storage, or otherwise mounted image) triggers it. Affected: Zephyr ext2 from its introduction in v3.5.0 through v4.4.0. The fix validates reclen and namelen in the parser and rejects entries whose header does not fit the remaining block or whose reclen crosses the block boundary in every traversal caller.

First published (updated )
Severity
7.1
Use After Free
CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H

subsys/net/ip/ipv6mld.c:mldsend() read the packet interface via netpktiface(pkt) after netsenddata(pkt) returned successfully. Per the network stack's ownership contract (include/zephyr/net/netcore.h, and the explicit warning in subsys/net/ip/netcore.c:453-460 'do not use pkt after that call'), a successful send transfers ownership of the netpkt and the L2 driver frees it (e.g. ethernetsend() unrefs the packet on success, subsys/net/l2/ethernet/ethernet.c:790), returning it to its kmemslab.

The subsequent netpktiface(pkt) is therefore a read of a freed object; the recovered interface pointer is then dereferenced and incremented by the per-interface statistics path (netstats.h UPDATESTAT/SETSTAT) when CONFIGNETSTATISTICSPERINTERFACE is enabled. If the freed slot is concurrently reallocated, pkt->iface may read back as NULL (NULL-pointer dereference / crash) or as a stale/garbage pointer (stray increment write / memory corruption).

The path is reachable remotely on the local link without authentication: handlemldquery() (registered for NETICMPV6MLDQUERY) responds to a valid MLDv2 General Query (unspecified multicast address, hop limit 1) by calling sendmldreport() -> mldsend().

The result is a remotely triggerable denial of service of the networking stack, with a narrow possibility of memory corruption. The fix caches the interface in a local before sending and no longer touches the packet after netsenddata(). The IPv4/IGMP sibling (igmpsend) already used the corrected pattern.

First published (updated )
Severity
8.8
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L

A potential out-of-bounds write/read exists in the TLS socket connect path of the network sockets subsystem (subsys/net/lib/sockets/socketstls.c). When the TLS session cache is enabled, tlssessionstore() and tlssessionrestore() memcpy the caller-supplied address into a fixed-size buffer using the caller-controlled addrlen value without validating it against the destination size. struct netsockaddr is an opaque type, so an application can pass an addrlen larger than sizeof(struct netsockaddr) (for example 128 bytes into a 24-byte stack buffer), causing the memcpy to read and write past the end of the address memory used by the TLS session cache. This out-of-bounds write can lead to a crash and denial of service, and potentially to arbitrary code execution.

First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203