CVE-2026-16514 Overview
CVE-2026-16514 is an out-of-bounds read [CWE-125] in the Zephyr RTOS generalized Precision Time Protocol (gPTP) implementation. The flaw resides in gptp_mi_qualify_announce() within subsys/net/l2/ethernet/gptp/gptp_mi.c. The function iterates over the Path Trace TLV of an incoming IEEE 802.1AS Announce message using the attacker-controlled announce->steps_removed field as the loop bound, without validating against the actual TLV length. A layer-2 adjacent, unauthenticated attacker can trigger a read roughly 2 KB past the network buffer, faulting the receive thread.
Critical Impact
An adjacent-network attacker can send a single crafted gPTP Announce frame to trigger an out-of-bounds read and cause a denial of service in the networking RX thread on Zephyr builds with CONFIG_NET_GPTP enabled.
Affected Products
- Zephyr RTOS builds with the experimental CONFIG_NET_GPTP option enabled
- Time-Sensitive Networking (TSN) deployments using Zephyr's gPTP stack
- Audio Video Bridging (AVB) devices built on Zephyr
Discovery Timeline
- 2026-09-18 - CVE-2026-16514 published to NVD
- 2026-09-18 - Last updated in NVD database
Technical Details for CVE-2026-16514
Vulnerability Analysis
The gptp_mi_qualify_announce() function walks the Path Trace TLV of a received IEEE 802.1AS Announce message and compares each clock identity against the local one using memcmp(). The loop bound is derived exclusively from the wire field announce->steps_removed, which the stack accepts up to 254. The function never consults announce->tlv.len, the field that states how many clock identities the TLV actually carries.
Because path_sequence is the flexible member of the wire structure struct gptp_path_trace_tlv, and the GPTP_ANNOUNCE() macro yields a raw pointer into the received packet buffer, the memcmp() inside the loop can address memory well past the end of the received frame. The single length validator, GPTP_ANNOUNCE_CHECK_LEN(), requires the gPTP payload to be exactly 68 + tlv.len bytes. This check guarantees the extra data is absent rather than present, so it does not constrain the loop.
Root Cause
The root cause is missing input validation on a wire-format length. The code trusts steps_removed to represent the number of entries in path_sequence, but the true entry count is tlv.len / GPTP_CLOCK_ID_LEN. When these two values diverge, the loop dereferences memory beyond the packet buffer.
Attack Vector
An unauthenticated attacker on the same Ethernet segment sends a single Announce frame with tlv.len = 0 and steps_removed = 254. The frame passes the length check and traverses net_gptp_recv() → gptp_handle_msg() → gptp_mi_qualify_announce() without authentication. The loop then reads 255 entries of 8 bytes each, roughly 2 KB, past the end of the network buffer. If the overread crosses into unmapped or MPU-protected memory, the networking RX thread faults. Exposure is limited to layer-2 adjacency because gPTP frames use a link-local multicast address and are not routed.
return false;
}
- for (i = 0; i < len + 1; i++) {
- if (memcmp(announce->tlv.path_sequence[i],
- GPTP_DEFAULT_DS()->clk_id,
- GPTP_CLOCK_ID_LEN) == 0) {
+ /* The path_sequence array in the announce TLV has (tlv.len /
+ * GPTP_CLOCK_ID_LEN) entries. Iterating up to steps_removed+1
+ * without validating against the TLV length reads past the data.
+ */
+ {
+ uint16_t tlv_entries = net_ntohs(announce->tlv.len) / GPTP_CLOCK_ID_LEN;
+ uint16_t max_i = (uint16_t)(len + 1U);
+
+ if (max_i > tlv_entries) {
return false;
}
+
+ for (i = 0; i < max_i; i++) {
+ if (memcmp(announce->tlv.path_sequence[i],
+ GPTP_DEFAULT_DS()->clk_id,
+ GPTP_CLOCK_ID_LEN) == 0) {
+ return false;
+ }
+ }
}
if (GPTP_GLOBAL_DS()->selected_role[port] == GPTP_PORT_SLAVE) {
Source: Zephyr commit a2c882db7a57cf08a06b4d27bead22b07a9c3c61. The patch computes the true entry count as tlv.len / GPTP_CLOCK_ID_LEN and rejects the announce when steps_removed + 1 exceeds it.
Detection Methods for CVE-2026-16514
Indicators of Compromise
- Unexpected crashes or resets of the Zephyr networking RX thread on devices running gPTP
- IEEE 802.1AS Announce frames on the local segment declaring tlv.len = 0 while carrying a non-zero steps_removed value
- Bursts of gPTP traffic to the link-local multicast address originating from unauthorized hosts
Detection Strategies
- Capture gPTP traffic on TSN or AVB segments and flag Announce frames where steps_removed + 1 exceeds tlv.len / 8
- Monitor Zephyr device telemetry for MPU faults or hard faults originating in the networking stack after receipt of gPTP frames
- Correlate device reboots with the arrival of Announce messages from unexpected MAC addresses on the same L2 domain
Monitoring Recommendations
- Enable structured logging on net_gptp_recv() and gptp_handle_msg() code paths to record source MAC and TLV length values
- Alert on any host emitting gPTP Announce frames that is not an authorized grandmaster or bridge in the AVB domain
- Track health metrics of TSN endpoints and escalate repeated RX thread restarts as a potential exploitation attempt
How to Mitigate CVE-2026-16514
Immediate Actions Required
- Apply the upstream Zephyr patch from commit a2c882db7a57cf08a06b4d27bead22b07a9c3c61 to all builds with CONFIG_NET_GPTP enabled
- Inventory firmware images that enable CONFIG_NET_GPTP and prioritize those exposed to shared or untrusted layer-2 segments
- Restrict physical and logical access to TSN and AVB network segments to authorized devices only
Patch Information
The fix is committed to the Zephyr project in commit a2c882db7a57cf08a06b4d27bead22b07a9c3c61. Additional details are published in GitHub Security Advisory GHSA-mgxg-89rr-6855. The patch bounds the path_sequence loop by the declared TLV length and rejects Announce frames where steps_removed + 1 exceeds the true entry count.
Workarounds
- Disable CONFIG_NET_GPTP in Zephyr build configurations where gPTP is not required
- Isolate gPTP-capable devices on dedicated VLANs with strict MAC allowlisting to block unauthorized senders of link-local multicast traffic
- Deploy switch-level filters that drop malformed IEEE 802.1AS Announce frames before they reach endpoint devices
# Disable the experimental gPTP subsystem in prj.conf if not required
CONFIG_NET_GPTP=n
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.