Where
-Infinity
0
Severity
7.1
Use After Free
AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H

The Bluetooth host ATT layer (subsys/bluetooth/host/att.c) associates each in-flight ATT TX buffer with its owning channel via the static txmetadatastorage[] array (data->attchan = chan). When a buffer's last reference is dropped, its net-buf destroy callback defers the completion handling to the system workqueue (atttxdestroy -> atttxdestroyworkhandler -> attonsentcb -> btattsent), where btattsent dereferences the channel and its ATT context (sysslistget(&att->reqs)).

When a peer disconnects while an ATT PDU (a server notification/indication or any response) is still in flight in the controller TX path, L2CAP tears the channel down in l2capchandel(): it runs the disconnected callback and then the released callback (btattreleased), which frees the channel slab slot. Because the in-flight buffer is held by the connection TX path rather than the channel's own queue, its deferred destroy work can run after the channel has been freed. The attonsentcb guard intended to drop the stale callback itself dereferences meta->attchan, which is now a dangling pointer into a freed (and possibly reused) slab slot.

A remote peer with an ATT connection can drive this by disconnecting during routine ATT traffic; no pairing or user interaction is required to reach the ATT bearer. The result is a use-after-free read/write of freed channel memory, reliably crashing the Bluetooth host (denial of service) and, because the channel slab slot may be reused, potentially corrupting live memory.

The fix makes btattreleased() NULL the attchan field of every txmetadatastorage[] entry still referencing the channel before freeing it, so the deferred guard observes a NULL pointer and drops the callback. Teardown and the destroy work both run on the cooperative system workqueue, so the array update is serialized and needs no lock.

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

The hawkBit device management client in subsys/mgmt/hawkbit accumulates the body of an HTTP response from the update server into a heap buffer in responsejsoncb() (subsys/mgmt/hawkbit/hawkbit.c). The buffer is sized to hold the received body bytes but reserves no space for a terminating NUL. When the full response has arrived, the code writes responsedata[downloadedsize] = '\0' — and whenever the accumulated body length equals the allocation, that terminator lands one byte past the end of the heap object (a heap-based out-of-bounds write, CWE-122 / CWE-787).

The body length and fragmentation are taken directly from the parsed HTTP response (rsp->bodyfragstart / rsp->bodyfraglen) and are fully controlled by the remote hawkBit server, which chooses its own response length. The precise trigger depends on how the buffer grows, and both forms are remotely reachable. Since v4.0.0 the reallocation is sized to exactly downloadedsize + bodylen, so any response body larger than the 1100-byte initial buffer makes the out-of-bounds write deterministic; such response sizes are normal for hawkBit deployment metadata. Before v4.0.0 the buffer grew by doubling and the growth check ((downloadedsize + bodylen) > responsebuffersize) is false at equality, so a response body whose length is exactly the current allocation — 1100 bytes with the default initial buffer — skips the reallocation entirely and writes the terminator at responsedata[1100] of an 1100-byte object. The HTTP length-mismatch check does not catch this, because the declared and received lengths genuinely agree. Either form is reachable by a malicious, compromised, or man-in-the-middle update server (TLS is optional and, when enabled, does not protect against a hostile server), with no authentication of response content and no client-side length cap protecting the write.

The out-of-bounds write is a fixed single NUL byte immediately following the allocation, corrupting adjacent allocator metadata or the next allocation. The practical impact is heap corruption leading to denial of service (fault on a subsequent allocation or free), with the bounded, allocator-dependent possibility of further corruption. The fix sizes the buffer to the body length plus one and copies with memcpy, ensuring the terminator always lands within the allocation.

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

The OCPP 1.6 client in subsys/net/lib/ocpp parsed inbound WAMP RPC frames in parserpcmsg() (subsys/net/lib/ocpp/ocppj.c) using a hand-rolled helper, extractstringfield(), that copied the message's uid and action fields with strncpy(outbuf, token + 1, outlen - 1) and then scanned the result with strchr(outbuf, '"'). Because strncpy does not NUL-terminate the destination when the source is at least outlen - 1 (127) bytes long, the subsequent strchr reads past the 128-byte destination buffer into adjacent stack memory; if a " byte is found beyond the buffer, a one-byte out-of-bounds NUL write also occurs. A related defect in extractpayload() runs strchr/strrchr over the receive buffer, which may not be NUL-terminated when a maximal-length frame fills it.

The parsed bytes come directly from the OCPP central-system server over a websocket: the reader thread fills recvbuf via websocketrecvmsg() and calls parserpcmsg() on each inbound DATA frame (subsys/net/lib/ocpp/ocpp.c). A malicious or compromised central server, or an on-path attacker (OCPP is commonly deployed over plain ws://), can send an RPC frame whose uid or action field is 127+ bytes with no closing quote, triggering the out-of-bounds access.

The primary impact is a remotely triggerable denial of service: the unbounded scan can fault on an unmapped page, and the stray NUL write can corrupt adjacent stack state. The over-read data is not reflected to the peer, so disclosure is limited. The feature is EXPERIMENTAL and must be explicitly enabled (CONFIGOCPP). The fix replaces the manual parser with the bounds-respecting jsonmixedarrparse() and copies the extracted uid with an explicitly NUL-terminated buffer, eliminating both over-reads.

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

Zephyr's Bluetooth Mesh subnet key management leaks one PSA Crypto key slot on every subnet-key teardown. In subsys/bluetooth/mesh/subnet.c, netkeyscreate() imports the Private Beacon Key into a PSA key slot under CONFIGBTMESHPRIVBEACONS (enabled by default), but subnetkeysdestroy() guarded the matching psadestroykey() with CONFIGBTMESHV1d1. That Kconfig symbol was removed when explicit Mesh 1.0.1 support was dropped, so the destroy branch became permanently dead code and the import is never balanced by a destroy.

The imbalanced teardown is reached every time subnet keys are destroyed: deleting a subnet (Config Server NetKey Delete), completing a Key Refresh Procedure (which retires the old key set), and resetting/re-provisioning the node. The over-the-air triggers are processed only under the node's device key, so they are exercisable by the provisioner or network administrator that owns the node, reachable over the Bluetooth Mesh network.

With the default CONFIGMBEDTLSPSAKEYSLOTCOUNT of 16, repeated add/delete or key-refresh cycles exhaust the shared PSA key-slot pool after roughly a dozen rounds. Once exhausted, btmeshprivatebeaconkey() and thus subnet creation fail: the node can no longer add subnets or complete key refresh, and other PSA crypto consumers on the device may be starved, until the device is rebooted. The fix aligns the destroy guard with the import guard (CONFIGBTMESHPRIVBEACONS) so each slot is freed.

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

The DHCPv4 client helper netdhcpv4msgtypename() in subsys/net/lib/dhcpv4/dhcpv4.c indexes a static 8-element const char name table after a faulty bounds check. The guard used msgtype <= sizeof(name) instead of msgtype <= ARRAYSIZE(name); sizeof returns the byte size of the pointer array (32 on 32-bit, 64 on 64-bit targets) rather than the element count of 8, so message-type values from 9 up to that byte size pass the check and cause name[msgtype - 1] to read past the end of the array.

The msgtype value originates from the DHCP MESSAGE TYPE option, which is read as an unchecked raw byte from a received packet (netpktreadu8) and passed unmodified into the lookup. A DHCP server, or any host able to inject a spoofed DHCP reply onto the client's link, can therefore drive the index out of bounds. The out-of-range slot yields a garbage const char that is then dereferenced by a %s log conversion.

The lookup is reached only from a debug log statement (NETDBG / LOGDBG), so the out-of-bounds read is triggerable only when the DHCPv4 log module is built at DEBUG level (CONFIGNETDHCPV4LOGLEVELDBG), which is not the default configuration. When that condition holds, the result is an out-of-bounds read and a wild-pointer dereference: most likely a crash of the DHCP client (denial of service) and potentially disclosure of an adjacent pointer's contents through the log output. The fix replaces sizeof with ARRAYSIZE, restoring the correct 1..8 acceptance window.

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

Zephyr's Bluetooth host declares a GATT characteristic as two consecutive attributes: a Characteristic Declaration whose permission is hard-coded to BTGATTPERMREAD, and a Characteristic Value attribute that carries the application-specified security permissions (e.g. BTGATTPERMREADENCRYPT / READAUTHEN / READLESC). The public notify and indicate APIs explicitly accept either attribute, and passing the declaration is the documented, common idiom. Before sending each notification or indication, the host re-checks link security with btgattcheckperm() against params->attr in gattnotify(), gattindicate(), and gattnotifymultipleverifyparams() (subsys/bluetooth/host/gatt.c).

When the application passed the Characteristic Declaration attribute, the host correctly redirected the value handle but left params->attr pointing at the declaration, so the security check evaluated the declaration's permissions (no security required) instead of the value's. As a result the encryption/authentication/LESC requirement configured on the characteristic value was skipped. The Notify-Multiple path additionally used a mask that omitted the LE Secure Connections requirement.

A remote peer triggers the disclosure by connecting (optionally without pairing or encryption) and writing the Client Characteristic Configuration descriptor to enable notifications or indications, causing the server to emit the protected value over a link that has not reached the required security level. The impact is information disclosure / access-control bypass for characteristic values the application intended to expose only over a secured link; exposure depends on the application declaring encrypt/authen-required notify/indicate characteristics and on the CCC being writable at a lower security tier. There is no memory-safety or availability impact.

The fix adds btgattattrresolvevalue(), which maps a declaration attribute to the following value attribute before the permission check, and switches the Notify-Multiple path to the full BTGATTPERMREADENCRYPTMASK so the LESC requirement is also enforced.

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

Zephyr's IPv6 forwarding path re-sent routed unicast packets without ever decrementing the IPv6 hop limit. Both routing branches of ipv6routepacket() (subsys/net/ip) were affected: the explicit-route path (netroutepacket()) and the on-link cross-interface path (netroutepacketif()). Each set the packet forwarding flag and called netsenddata() with the hop limit untouched and no expiry check.

Per RFC 8200 the hop-limit decrement is the mechanism that bounds packet lifetime and terminates routing loops; without it, a device acting as an IPv6 router relays looping packets indefinitely. An on-path attacker who can induce or exploit a transient L3 loop turns it into a permanent forwarding storm, causing CPU/bandwidth resource exhaustion (availability DoS) on the forwarder and adjacent links; path-discovery and loop diagnostics that rely on hop-limit expiry are also defeated.

Affected configurations. In every affected release the forwarding path is reached via CONFIGNETROUTE (enabled by default when CONFIGNETIPV6NBRCACHE is set), together with CONFIGNETROUTING for cross-interface routing. Note that CONFIGNETIPV6FORWARDING and CONFIGNETIPV4FORWARDING — which appear in the fix and in this advisory's evidence notes — were introduced after v4.4.0, when the routing options were split and renamed; they do not exist in any affected release. When auditing a v4.4.1-or-earlier configuration, look for CONFIGNETROUTE and CONFIGNETROUTING.

IPv4 is not affected in any release. The IPv4 forwarding path (netrouteipv4packet() in routeipv4.c) was added after v4.4.0 and has never shipped in a release. Its TTL decrement and IPv4 header-checksum recomputation landed on main as part of the same fix, so the evidence notes below discuss it, but no released version is reachable by way of IPv4.

Affected releases are v1.8.0 through v4.4.1: v1.8.0 introduced netroutepacket() and v2.2.0 added netroutepacketif(), and neither decremented the hop limit. v4.3.1 carries the explicit-route fix but not the on-link one, so it is affected as well. Fixed on main by 7d8f1afa7345 (explicit-route path) and 589eadc74efa (on-link path).

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

The Zephyr Bluetooth GATT client CCC-write response handler gattwritecccrsp() in subsys/bluetooth/host/gatt.c invoked the application's params->subscribe() callback after it had already called params->notify(conn, params, NULL, 0).

Per the public GATT API, a notify callback with NULL data is the documented signal that the subscription has terminated and the btgattsubscribeparams struct may be freed or reused by the application; calling subscribe() on the struct afterwards is a use-after-free, including an indirect call through the freed params->subscribe function pointer.

The error branch is remotely (adjacent) reachable: a Zephyr device acting as a GATT client that calls btgattsubscribe() can be driven into this ordering when a connected GATT server peer answers the CCC write with an ATT Error Response (the peer-supplied error code flows through atterrorrsp -> atthandlersp into gattwritecccrsp).

For applications that free or recycle subscription parameters in their notification-termination handler, this results in memory corruption, a crash (denial of service), or potentially attacker-influenced control flow. The fix reorders the handler so the subscribe() callback runs before the terminating notify(NULL) in both the error and unsubscribe paths.

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

In the Synopsys DesignWare I2C driver (drivers/i2c/i2cdw.c) operating in target/slave mode, the rxfull interrupt handler gates the writerequested() callback on dw->state != CMDSEND, and dw->state is only reset to READY on a STOP interrupt. The STARTDET interrupt, whose handler in i2cdwslavereadclearintrbits() would reset the state on every (re)START, was never added to the enabled interrupt mask in i2cdwslaveregister(), so that recovery path was dead code.

As a result, if the STOP interrupt is lost (bus glitch/reset, or a concurrent master driving STOP) or the bus master issues a legal WRITE-repeated-START-WRITE sequence with the same direction, the driver remains in CMDSEND permanently and never invokes writerequested() again for the life of the target.

An I2C master on the same physical bus can deliberately trigger this, causing the I2C target function to malfunction for all subsequent write transactions and desynchronizing consumer framing state (e.g. MCTP-over-I2C), a recoverable-by-reset denial of service of the target peripheral.

The fix unmasks STARTDET so the state is reset at every bus (re)START. Impact is availability-only over a local board-level bus; no memory corruption results in the in-tree consumer, whose per-byte buffer write is independently bounds-checked.

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

The userspace verifier zvrfylogfilterset() for the logfilterset syscall in subsys/logging/logmgmt.c performed a signed comparison against the int16t srcid parameter: srcid < (int16t)logsrccntget(domainid). Any negative value for srcid (e.g. -1) trivially satisfied this check and was forwarded into zimpllogfilterset, where it propagated to filterset() and ultimately to getdynamicfilter(), which uses sourceid as an unsigned index into the linker-section array &TYPESECTIONSTART(logdynamic)[sourceid].filters.

After implicit conversion through uint32t, an int16t -1 becomes 0xFFFFFFFF, indexing logdynamic far out of bounds and causing the kernel to perform an OOB read and an OOB read-modify-write (LOGFILTERSLOTGET/SET) against memory adjacent to the logdynamic section.

The written value is a constrained 3-bit log level slot within the targeted 32-bit word, but the target address is attacker-chosen (a small negative offset from logdynamic) and the write occurs in supervisor mode following a syscall from an unprivileged user thread, providing a kernel memory-corruption / privilege-escalation primitive.

The defect is reachable on any build with CONFIGUSERSPACE=y and CONFIGLOGRUNTIMEFILTERING=y. Present from Zephyr v3.3.0 through v4.4.1. The fix replaces the signed bound check with an unsigned comparison: (uint32t)srcid < logsrccntget(domainid), which correctly rejects negative inputs.

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

In Zephyr's userspace dynamic-objects subsystem, threadidxalloc() in kernel/userspace/userspace.c allocated a new thread permission index from the global threadidxmap[] bitmap without holding listslock.

On SMP systems, two user-mode threads invoking the kobjectalloc(KOBJTHREAD) syscall concurrently can both observe the same low free bit, perform the same non-atomic RMW to clear it, and return the identical tidx.

The two newly created KOBJTHREAD objects are then assigned the same threadid, so the two user threads alias a single bit position in every kernel object's perms[] bitfield: any subsequent grant of access on a kernel object to one thread is implicitly a grant to the other, defeating userspace ACL isolation. A secondary lost-update window between the unlocked &=~BIT() in alloc and the locked |= BIT() in threadidxfree() can also leak entries from the thread-index pool.

The defect is reachable from any user-mode thread via the unrestricted syscall kobjectalloc and is gated on CONFIGUSERSPACE, CONFIGDYNAMICOBJECTS, and CONFIGSMP. The flaw was introduced when the per-thread permission index was added in 2018 and is present in every release up to and including v4.4.0. Fixed by holding listslock across the bitmap RMW and the permissions clear (and inlining the objlist traversal that previously took the lock itself).

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

The Zephyr ext2 file system validates the on-disk superblock in ext2verifydisksuperblock() (subsys/fs/ext2/ext2impl.c) before completing a mount. The validator checked the magic number, block size, revision and feature flags, but did not verify that the on-disk fields sblockspergroup and sinodespergroup are non-zero. Both fields are read directly from the image and are later used as divisors during mount-time initialization.

During mount, getngroups() divides and modulos sblockscount by sblockspergroup (reached via ext2fetchblockgroup() from ext2initfs()), and getitableentry() divides (ino - 1) by sinodespergroup when fetching the root inode (both in subsys/fs/ext2/ext2diskops.c). A superblock with either field set to zero therefore causes an integer division by zero during the mount sequence.

An attacker who can present a crafted ext2 image to a device that mounts ext2 — removable media such as an SD card or a USB mass-storage device — can trigger this. On ARMv7-M / ARMv8-M-mainline Cortex-M targets, divide-by-zero trapping is enabled (SCBCCRDIV0TRP), so the division raises a UsageFault that Zephyr treats as a fatal error, producing a denial of service. The impact is limited to availability; the malformed value is consumed only as a divisor.

The fix rejects a zero sblockspergroup or sinodespergroup in the superblock validator, returning -EINVAL so the mount fails before any block-group or inode I/O occurs.

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

The Classic (BR/EDR) L2CAP signaling handlers l2capbrconfreq() and l2capbrconfrsp() in subsys/bluetooth/host/classic/l2capbr.c validated the minimum command size against buf->len (the bytes remaining in the whole received PDU) instead of len (the per-command data length from the L2CAP signaling header). Because multiple signaling commands can be packed into one PDU, buf->len may exceed a command's len. An attacker can send a CONFREQ command with a header length smaller than the configuration-request structure (e.g. 0), followed by another command so that buf->len still satisfies the check. The check then passes incorrectly and optlen = len - sizeof(req) underflows the uint16t to a near-0xFFFF value. The configuration-option loop, which lacks an optlen-versus-buf->len guard, then walks far past the end of the pooled ACL receive buffer using netbuf pull primitives that perform no runtime bounds check, producing an out-of-bounds read of host memory and, when the out-of-bounds option bytes encode an MTU or flush-timeout option, an out-of-bounds write. The BR/EDR signaling channel is processed before pairing/encryption and an L2CAP channel to an L0 service such as SDP can be opened without pairing, so an unauthenticated peer within radio range that can establish an ACL connection can trigger the flaw, leading to memory corruption and denial of service (host/device crash). The defect is present in released versions including v4.4.0. The fix validates against len instead of buf->len in both handlers.

First published (updated )
Severity
5.5
Divide by Zero
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L

The DesignWare SPI driver (drivers/spi/spidw.c) computed the SPI BAUDR clock divider as info->clockfrequency / config->frequency without validating config->frequency.

spitransceive is a Zephyr syscall and its verify handler (drivers/spi/spihandlers.c) copies the caller-supplied spiconfig from userspace without checking the frequency field, so a userspace thread that has been granted access to a DesignWare SPI device kernel object can pass frequency = 0 and trigger an unsigned integer divide-by-zero in spidwconfigure().

On Cortex-M Mainline (SCB->CCR.DIV0TRP is set in zarmfaultinit()) and on ARC (a dedicated evdivzero vector) this raises a CPU exception, resulting in a kernel fault and local denial of service.

The fix rejects zero frequency and frequencies above clockfrequency / 2 (the DesignWare SSI databook minimum SCKDIV of 2) with -EINVAL. The defect affects all Zephyr releases up to and including v4.4.0; exploitation requires CONFIGUSERSPACE=y and an unprivileged thread already granted SPI driver permission. There is no memory-corruption or information-disclosure impact.

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

The MCTP-over-I2C+GPIO target binding in Zephyr (subsys/pmci/mctp/mctpi2cgpiotarget.c) processes pseudo-register writes from an I2C bus master byte-by-byte in mctpi2cgpiotargetwritereceived() without validating the order or the receive buffer. In the affected versions the MCTPI2CGPIORXMSGADDR (data) handler dereferences and writes through b->rxpkt without checking that the receive buffer was allocated: a controller that selects the data register and writes a byte without first sending the length register (which is what allocates the buffer) causes a write of an attacker-chosen byte through a NULL/unallocated mctppktbuf pointer (i.e. into a small attacker-advanceable offset above address 0), producing memory corruption or a hard fault.

The same handler also performs a write-then-check bounds test, allowing a one-byte heap overflow at data[255] when more than 255 data bytes are sent.

Because the I2C target callback is invoked with raw bytes supplied by whatever device is the bus master and the binding performs no authentication, a malicious or malfunctioning controller on the bus can trigger these without any prior protocol state, leading to memory corruption and/or denial of service on the target device.

The vulnerable code was introduced when the I2C+GPIO target binding was added and shipped in Zephyr v4.3.0 and v4.4.0. The fix defers allocation to the first data byte with a NULL check, treats a missing length as a zero-sized packet rejected by libmctp, and moves the bounds check before the store.

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

The CONFIGUSERSPACE syscall verifier zvrfykpoll() in kernel/poll.c allocates a kernel-side copy of the user-supplied kpollevent[] via zthreadmalloc() and then validates each event's object handle. Before this fix, validation used KOOPS(KSYSCALLOBJ(...)) inline inside the loop, which kills the calling thread without freeing eventscopy.

A user thread can pass numevents >= 1 with a forged object handle to leak the allocation; because newly spawned user threads inherit the parent's resourcepool (kernel/thread.c), an attacker spawns sacrificial threads to repeat the leak until the shared kernel heap is exhausted. Once depleted, legitimate kernel allocations from that pool (kqueue alloc nodes, kmsgq buffers, future kpoll calls, etc.) fail, causing a system-level denial of service.

The fix replaces each inline KOOPS with a conditional goto oopsfree so the buffer is freed before the thread is killed. Affects Zephyr releases from v1.12.0 (when kpoll was first exposed to user mode) through v4.4.1.

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

In Zephyr's Bluetooth Mesh PB-ADV provisioning bearer (subsys/bluetooth/mesh/pbadv.c), provmsgrecv() rescheduled the provisioning protocol watchdog timer unconditionally at the top of the function, before the FCS check and before the ADVLINKINVALID check. Once a provisioning attempt fails, provfailed() sets ADVLINKINVALID and the only recovery path is the protocol timer firing (protocoltimeout -> provlinkclose -> closelink -> resetadvlink and re-enabling of scanning and the unprovisioned device beacon).

A remote, unauthenticated attacker on the BLE advertising channel can first induce a provisioning failure (e.g. with a malformed generic-provisioning PDU) and then transmit any FCS-valid PB-ADV transaction PDU on the same link ID more often than once per protocol timeout (60 s, or 120 s for OOB input/output). Because each such packet reset the timer even on an invalidated link, protocoltimeout never fired, the dead link was never torn down, and the device remained pinned in an un-provisionable state with its unprovisioned beacon disabled and new Link Open requests rejected.

PB-ADV PDUs are processed without authentication and the FCS is a keyless CRC, so no pairing or prior trust is required and the attacker chooses the link ID itself. The impact is a persistent denial of provisioning/re-provisioning service; there is no memory-safety, confidentiality, or integrity impact.

The vulnerable code shipped in releases through v4.4.1. The fix moves the timer reschedule to after the ADVLINKINVALID check (and the FCS check before the reset) so an invalidated link can no longer be kept alive by incoming packets.

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

The NXP LPUART serial driver (drivers/serial/uartmcuxlpuart.c), when CONFIGUARTUSERUNTIMECONFIGURE is enabled, called LPUARTDeinit() at the start of mcuxlpuartconfigure(), which disables the LPUART peripheral clocks. The requested configuration is validated only afterwards (in mcuxlpuartconfigurebasic), and unsupported parity/data-bit/stop-bit/flow-control values return -ENOTSUP before the clock is re-enabled.

As a result, a uartconfigure() request with an unsupported configuration left the LPUART in a clock-disabled state; any subsequent access to LPUART registers (pollout/pollin, interrupt handling, or a later reconfigure) faults on the gated peripheral and escalates to a hard fault, crashing the system.

uartconfigure() is a Zephyr syscall whose verifier (zvrfyuartconfigure) only checks that cfg is readable user memory and forwards the caller-supplied configuration unchanged, so an unprivileged userspace thread with access to an LPUART device can deterministically trigger the fault, a persistent system-wide denial of service.

Introduced in v2.5.0 and present in all subsequent releases until this fix, which removes the LPUARTDeinit() call and instead only disables the transmitter/receiver, leaving the clock running.

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

subsys/net/lib/lwm2m/lwm2mpullcontext.c copied the firmware-update Package URI into a fixed static buffer (context.uri, size CONFIGLWM2MSWMGMTPACKAGEURILEN, default 128) with memcpy(context.uri, uri, LWM2MPACKAGEURILEN), copying exactly the destination size with no length validation. The Firmware-Update object stores the server-supplied Package URI (/5/0/1) in a 255-byte buffer, so a LwM2M management server (or an on-path attacker on a session lacking strong DTLS) can WRITE a URI of 128-254 characters; only the first 128 bytes are then copied into context.uri with no NUL terminator. That buffer is subsequently consumed as a C string by httpparserparseurl(context.uri, strlen(context.uri), ...), strlen-based CoAP URI-path/PROXY-URI option appends, and lwm2mparsepeerinfo(), causing an out-of-bounds read of adjacent static memory. The over-read bytes are appended to outbound CoAP requests (information disclosure of adjacent device memory to the server/proxy) and can crash the device (denial of service). The vulnerable copy was introduced by the pull-context refactor (first released in v3.0.0) and is present through v4.4.0; the default-on CONFIGLWM2MFIRMWAREUPDATEPULLSUPPORT path is affected. The fix adds a strlen(uri) >= sizeof(context.uri) check returning -ENOMEM and switches to strcpy(), guaranteeing a bounded, NUL-terminated buffer.

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

The CONFIGUSERSPACE verification handler for the kthreadnamecopy() system call (zvrfykthreadnamecopy() in kernel/thread.c) calls kobjectfind() on the caller-supplied thread pointer and then dereferences the returned struct kobject without checking it for NULL. kobjectfind() returns NULL whenever the supplied pointer is not a registered (static or dynamic) kernel object.

The pre-fix guard tested thread == NULL instead of ko == NULL, so an unprivileged user-mode thread that invokes kthreadnamecopy() with any non-NULL but unregistered pointer (e.g. an arbitrary address) passes the NULL test, after which the verifier reads ko->type through a NULL pointer.

Because the syscall verifier runs in supervisor mode, this NULL dereference is a kernel-mode fault that halts or reboots the system, allowing untrusted user code to crash the kernel across the userspace security boundary (denial of service). The marshaller passes the thread argument to the verifier without any prior KSYSCALLOBJ validation, so the bad pointer reaches the defect directly.

The flaw affects builds with CONFIGUSERSPACE and CONFIGTHREADNAME enabled and has been present since the special-case lookup was introduced around v2.0.0; it is present in v4.4.0 and earlier. The fix changes the guard to check the kobjectfind() return value (ko == NULL) before dereferencing it.

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

In Zephyr's kernel pipe implementation, the userspace syscall verifier zvrfykpipeinit() in kernel/pipe.c used KSYSCALLOBJ() (which requires the kernel object to already be initialized) instead of KSYSCALLOBJNEVERINIT() (which rejects an already-initialized object). As a result, on CONFIGUSERSPACE builds an unprivileged user thread that has been granted access to a kpipe object can invoke the kpipeinit syscall to re-initialize a pipe that is already in use.

zimplkpipeinit() unconditionally resets the ring buffer, sets pipe->waiting to 0, and re-initializes both wait queues (zwaitqinit on pipe->data and pipe->space) without waking or accounting for threads currently blocked on the pipe. Any thread already pended in kpiperead()/kpipewrite() is left orphaned: still marked pending with pendedon pointing at the cleared wait queue and with stale qnodedlist links into the (now re-initialized) embedded list head.

When such an orphaned waiter is later timed out or woken, the scheduler calls sysdlistremove() on its stale node, writing through dangling prev/next pointers into kernel wait-queue/scheduler structures, causing list corruption (an attacker-driven invalid kernel write), lost wakeups, indefinitely blocked threads, and silent data loss. The flaw lets a deprivileged user thread corrupt the state of a kernel object shared with other threads/partitions.

The fix switches the verifier to KSYSCALLOBJNEVERINIT(), matching the existing kmsgqinit verifier, so a user thread can no longer re-initialize a live pipe. The vulnerable code shipped in v4.1.0 and remained through v4.4.0.

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

On Xtensa SoCs built with CONFIGXTENSAMPU and CONFIGUSERSPACE, archbuffervalidate() in arch/xtensa/core/mpu.c — the architecture hook that verifies a user-mode-supplied buffer is accessible to the calling user thread with the requested permission — defaulted its return value to 0 (access permitted) and only set a denial result inside its per-MPU-region probe loop. When the rounded extent of the buffer wraps the 32-bit address space (size + alignment offset near SIZEMAX, or ROUNDUP(size + offset) overflowing to 0), the loop executes zero iterations and the function returns 0 = permitted without probing any MPU region.

The syscall-layer pre-checks (KSYSCALLMEMORYSIZECHECK / ZDETECTPOINTEROVERFLOW) only catch a raw addr+size wrap and do not cover the ROUNDUP-induced wrap, and the string path (archuserstringnlen -> archbuffervalidate) has no syscall-layer guard at all.

An unprivileged user-mode thread can therefore pass a crafted (addr, size) to any syscall that validates user buffers via kusermodefromcopy/tocopy or kusermodestringcopy and have validation succeed for memory it must not access; the kernel then reads from (disclosure) or, with write=1, writes to (corruption) attacker-chosen kernel or other-partition memory on the thread's behalf, enabling information disclosure, memory corruption, privilege escalation, and denial of service.

Affected from v3.7.0 (when Xtensa MPU userspace support was added) through v4.4.0. The fix changes the default to -EINVAL (deny by default), adds an explicit sizeaddoverflow check, and sets the success value only after the full range has been validated.

First published (updated )
Severity
4.6
Use After Free
AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

The Nuvoton NuMaker HSUSBD USB device-controller driver (drivers/usb/udc/udcnumaker.c) armed the control Data IN stage unconditionally (base->CEPTXCNT = len in numakerhsusbdeptrigger). Because the HSUSBD hardware cannot disarm a control Data IN already armed for a previous transfer, a USB host that cancels an in-flight control transfer (timeout) and then issues a new SETUP packet can drive the driver out of sync: stale data may be transmitted in the new transfer and the control endpoint can become permanently stuck NAK'ing every subsequent control transfer.

A malicious or buggy host (physical/adjacent attacker driving the bus) can repeatedly cancel-and-re-SETUP to wedge the device's USB control endpoint, denying service to the device's USB function (the device stops enumerating/responding on the control pipe) until a USB reset or re-plug. The flaw is an availability-only denial of service; the FIFO copy loops (bounded by netbuf length and the hardware BUFFULL flag) and the netbuf lifecycle are independent of the arming desync, so there is no out-of-bounds access, use-after-free, or information leak.

The fix monitors the IN-token and new-SETUP events (kevent) and only arms control Data IN when an IN token is present and no new SETUP has arrived, cancelling the current transfer on a new SETUP. Affects boards using the Nuvoton NuMaker HSUSBD controller (CONFIGUDCNUMAKER with DTHASNUVOTONNUMAKERHSUSBDENABLED); shipped in v4.4.0.

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

parseipv4() in subsys/net/ip/utils.c (reached via netipaddrparse() for strings of the form "a.b.c.d:port") copies the port substring into a fixed 17-byte stack buffer (char ipaddr[NETIPV4ADDRLEN + 1]) using a length of strlen - end - 1, where strlen is the full, unbounded input length and end is only the (<=15-byte) offset of the ':' delimiter. Because the destination size is never consulted, a crafted address string with a long suffix after the colon (e.g. "1.2.3.4:" followed by hundreds of bytes) causes an out-of-bounds stack write whose length and contents are fully attacker-controlled (memcpy of the suffix plus a trailing NUL), enabling memory corruption and at minimum a denial of service, and potentially control-flow hijack. The parser is reached from the standard socket API (zsockgetaddrinfo / literal-address resolution), DNS server-string configuration, and the eswifi Wi-Fi co-processor DNS-response path, so an application that resolves a network-influenced address string is exposed. The bug was introduced when the parser was added (Zephyr v1.9.0) and shipped in all releases through v4.4.0. The fix removes the unbounded copy and validates the port length before copying into a small dedicated buffer. Note: the equivalent IPv6 "[addr]:port" path in parseipv6() retains the same unbounded copy at this commit and remains a separate, still-reachable instance of the defect.

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

Zephyr's dynamic kernel-object tracking (kernel/userspace/userspace.c, formerly kernel/userspace.c) maintains a doubly-linked list (objlist) of dynamically allocated kernel objects. Iteration over this list in kobjectwordlistforeach() was performed under listslock using the SAFE iterator (which caches the next node), but list removal and freeing of nodes was performed under different, disjoint spinlocks: objfreelock in kobjectfree() and objlock in unrefcheck(). On an SMP system, while one CPU iterated objlist under listslock, another CPU could unlink and kfree() the dynobj node that the iterator had cached as its next pointer, causing the iterator to dereference freed kernel memory (use-after-free / dangling list traversal). All of the racing operations are reachable from unprivileged user-mode threads via system calls: kobjectalloc/kobjectallocsize and kobjectrelease drive removals through unrefcheck() (under objlock), while kthreadabort and thread creation drive the iteration through kthreadpermsallclear()/kthreadpermsinherit() (under listslock). A deprivileged user thread on a CONFIGSMP + CONFIGUSERSPACE build can therefore corrupt the kernel's object-tracking structures across the userspace security boundary, yielding kernel memory corruption (potential privilege escalation) or a kernel crash (denial of service). The fix removes objfreelock and serializes every objlist modification under listslock, including holding it across find+remove in kobjectfree() and around unrefcheck() in kthreadpermsclear(). Affects CONFIGSMP+CONFIGUSERSPACE+CONFIGDYNAMICOBJECTS configurations; the defect dates to the 2019 spinlockification (commit 8a3d57b6cc6, first released in v1.14.0) and shipped through v4.4.0.

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

The nRF70 Wi-Fi driver's power-save event handler nrfwifieventprocgetpowersaveinfo() in drivers/wifi/nrfwifi/src/wifimgmt.c copied TWT (Target Wake Time) flow entries from an nrfwifiumaceventpowersaveinfo event into the fixed-size twtflows[WIFIMAXTWTFLOWS] (8-element) array of a caller-supplied struct wifipsconfig, looping over event-provided numtwtflows without validating it against WIFIMAXTWTFLOWS or checking eventlen. When numtwtflows exceeds 8, the handler writes past the destination array (which is typically on the caller's stack, e.g. the wifi ps shell command) -- an out-of-bounds write of ~40-byte TWT entries -- and reads twtflowinfo[i] past the event buffer. The event is delivered by the nRF70 co-processor firmware in response to a host-initiated power-save GET, so reaching the overflow requires the firmware to emit a malformed or out-of-range event; the trust boundary is host-to-trusted-coprocessor rather than a direct remote-AP write, with over-the-air influence on the flow count being indirect and bounded by the 3-bit TWT flow-id space. Affected: builds with CONFIGNRF70STAMODE on releases through v4.4.0. The fix rejects events with numtwtflows > WIFIMAXTWTFLOWS or with eventlen shorter than the claimed entries, and adds a NULL check on the caller buffer.

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

In Zephyr's WireGuard subsystem (subsys/net/lib/wireguard), wgprocessdatamessage() in wgcrypto.c linearizes an inbound transport-data payload into a fixed pool buffer of CONFIGWIREGUARDBUFLEN bytes before decryption. The call netbuflinearize(buf->data, datalen, pkt->buffer, ..., datalen) passed the attacker-derived datalen as both the destination capacity and the copy length, defeating the function's internal len = min(len, dstlen) bound. datalen is derived from the received UDP datagram length and is only lower-bounded by wgctrlrecv() (no upper bound). When datalen exceeds CONFIGWIREGUARDBUFLEN — e.g. when the buffer length is lowered below the link MTU, on links with MTU above the buffer size, or via reassembled IPv4/IPv6 fragments that exceed it — the underlying memcpy writes past the end of the pool buffer, an out-of-bounds write (CWE-787). The overflow occurs before the Poly1305 authentication check, so it requires only a valid receiver session index rather than a valid authenticator, and is reachable by a malicious or compromised peer (or an on-path attacker driving an established session) over the network, yielding remote memory corruption and at minimum a reliable denial of service. The defect was present in the WireGuard implementation shipped in Zephyr 4.4.0. The fix adds an explicit datalen > CONFIGWIREGUARDBUFLEN rejection and corrects the linearize call to pass netbufmaxlen(buf) as the destination capacity.

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

In Zephyr's experimental USB host stack (CONFIGUSBHOSTSTACK), usbhdevicedisconnect() (subsys/usb/host/usbhdevice.c) freed the root usbdevice slab object without clearing the cached pointer ctx->root. The bus removal handler devremovedhandler() (subsys/usb/host/usbhcore.c) decides what to tear down solely from ctx->root, checking only that it is non-NULL.

Because UHC controller drivers (e.g. uhcmax3421e, uhcmcuxcommon) synthesize UHCEVTDEVREMOVED directly from physical bus line state with no debounce or state guard, an attacker with physical USB access (or a rogue device that bounces its connection) can deliver a second device-removed event after a root device disconnect. The handler then re-enters usbhdevicedisconnect() with the dangling pointer, locking a mutex inside the freed object (use-after-free), removing the freed node from the device list, and calling kmemslabfree() on the already-freed block (double-free). If the slab block has been reissued to a newly attached device in between, this corrupts a live object.

Impact is denial of service (crash) and memory corruption; the attack vector is physical/local. The flaw was introduced in v4.4.0 by the connect/disconnect refactor and is fixed by clearing ctx->root in usbhdevicedisconnect() before freeing.

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

The Dhara flash translation layer disk driver (drivers/disk/ftldhara.c) implemented the dharanand callbacks so that, on a flash error, the error code was written unconditionally through the caller-supplied dharaerrort err pointer (e.g. err = DHARAEECC in dharanandread, and similar in dharananderase/prog/copy).

The upstream Dhara library calls these callbacks with err == NULL along its journal-resume binary search: findlastcheckblock() invokes findcheckblock(j, mid, &found, NULL), which forwards the NULL pointer into dharanandread(). This path runs during diskftlaccessinit() -> dharamapresume() whenever the FTL disk is mounted/initialised.

If a flash read error (uncorrectable ECC, bad block, controller error) occurs on one of the probed checkpoint pages, the driver dereferences and writes to NULL, faulting the kernel (denial of service). The trigger is conditioned on the NAND medium content/health, which can be influenced by media wear, induced faults, or a corrupted/crafted on-flash image.

The fix routes all error assignments through the library's NULL-safe dharaseterror() helper. Affects Zephyr v4.4.0, where the driver was introduced.

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

Zephyr's DNS resolver detects mDNS (.local) queries in dnsresolvenameinternal() (subsys/net/lib/dns/resolve.c) with memcmp(strrchr(query, '.'), ".local", 7), which always reads a fixed 7 bytes from the suffix pointer. When the resolved hostname's final label is shorter than 7 bytes (e.g. names ending in .org, .com, .net, .io, or a trailing dot), the comparison reads 1-2 bytes past the string's NUL terminator.

The hostname (query) is the caller-supplied name passed through the standard getaddrinfo()/dnsgetaddrinfo()/dnsresolvename() path and is influenceable by operators or remote inputs (server names from configuration, parsed URLs, or app-facing interfaces).

On a tightly-sized buffer with no slack (for example a userspace getaddrinfo call where the hostname is copied with kusermodestringalloccopy to exactly strlen+1 bytes), the over-read crosses the allocation boundary; if that boundary is unmapped (guard page, memory-domain boundary under MPU, or an address sanitizer) the over-read faults, causing a denial of service. The over-read bytes are never returned, so there is no information disclosure.

The flaw is compiled only when CONFIGMDNSRESOLVER is enabled, exists since v1.10.0, and is fixed by replacing the fixed-length memcmp with a NUL-safe strcmp(ptr, ".local").

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