← All Disclosures

Summary

CubedOS.Transport_UDP.Messages.Send_Network_Message sends a fixed-size UDP buffer after copying five fewer payload bytes than the buffer requires. With the shipped 512-byte message size, every outbound datagram omits payload bytes 507–511 and replaces them with five bytes of uninitialized stack memory.

A receiving peer can therefore observe process memory that was never intended for transmission, while the sender silently corrupts the end of every payload. The issue was confirmed on CubedOS v1branch commit c402301.

Cause and Impact

The six-byte protocol header occupies buffer offsets 0–5. The faulty loop uses buffer indices 6 through Payload'Length, copying only 507 of 512 payload bytes, but Send_Socket transmits all 518 buffer bytes. Offsets 513–517 are consequently uninitialized stack data.

This is an information disclosure and message-integrity failure (CWE-200, CWE-908, and CWE-665). The proof of concept captured all three affected datagrams and confirmed that their final five bytes did not contain the payload sentinel.

How Pragmatic Found It

Pragmatic 0.2.1's EmptySync checker (CWE-585) put the UDP transport package under review. The checker looks for synchronization bodies that do no observable work, a common sign of incomplete implementation or refactoring. On CubedOS master, it reported the null-bodied Send_Lock.Wait entry:

$ ./bin/pragmatic -E=EmptySync -e=adb \
    cubedos/src/modules/cubedos-transport_udp-messages.adb

CWE,Checker,Filename,Line,Tool,Comments
585,EmptySync,cubedos/src/modules/cubedos-transport_udp-messages.adb,60,
Pragmatic Scanner 0.2.1,"Empty entry body imposes synchronization cost while
doing nothing observable. Likely incomplete refactoring; add a comment if the
empty body is intentional (e.g., a barrier-only sync)."

The synchronization finding was a review lead, not the eventual vulnerability claim. Following the message path through the flagged package exposed an uninitialized output Buffer, a payload-copy loop, and a Send_Socket call that transmits the whole buffer. Comparing their ranges showed the security defect: the six-byte header plus 512-byte payload requires 518 initialized bytes, but the loop performs only 507 payload copies and leaves five transmitted positions unwritten.

Fix

A patch is proposed upstream in pull request #68 and is available in the reporter's fork at commit 58f6bdc. It iterates over Message.Payload'Range and copies each byte to its corresponding buffer offset after the six-byte header. This preserves the existing datagram size and wire layout while ensuring that the complete payload is transmitted and every buffer byte is initialized.

The production-linked regression test rebuilt successfully and captured three 518-byte datagrams; each contained the expected c1 c2 c3 c4 c5 sentinel at offsets 513–517.

Project Status

The upstream project appears to be retired. Developer Peter Chapin noted that the planned SPARK cleanup had never occurred which would have also surfaced this issue. Pull request #68 makes the remediation available to any remaining upstream maintainers.

Severity

CVSS 4.0 Base Score: 6.9 (Medium)

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

References

Disclosure Timeline