Zephyr OS Fragmented Network Buffers: Check the Actual Byte Count Returned by Linearization

Copying bytes out of a fragmented buffer chain does not guarantee that the requested byte count was available. In Zephyr OS, net_buf_linearize returns the number it actually copied. A caller that proceeds using the requested length can parse leftover destination bytes as though they came from the network.

This article examines Zephyr v4.4.0 linearization and proposes a parser boundary check. It does not claim that a particular network service was tested or vulnerable. The focus is the copy contract between a fragment chain and a contiguous destination, rather than protocol-specific validation.

Linearization diagram tracks requested length, destination capacity, available fragments and checking the returned byte count.
Original conceptual engineering diagram. Proposed review method, not a measured result.

Preserve three separate lengths

The versioned buffer implementation first caps the requested count by destination capacity. It then walks the source fragments to find the requested offset and copies until the capped count is satisfied or the chain ends. Its return value is the actual copied count. It does not turn a short copy into a negative errno result.

Keep the desired field length, destination capacity and actual copied length distinct. For a fixed-size protocol header, acceptance normally requires the actual count to equal that header's required size. A positive value alone merely establishes that some bytes were copied.

The public network-buffer header defines the chain-based interface and size-based result. This buffer representation is not a promise that the complete packet is contiguous behind the first fragment's data pointer. Do not replace a deliberate chain copy with a raw structure cast simply because short test packets happen to fit in one fragment.

Diagnose which boundary shortened the copy

Suppose a hypothetical decoder needs an eight-byte header. If it supplies a six-byte destination, an actual six-byte result is consistent with its own capacity limit even when the source contains the whole header. That is a caller allocation or contract problem, not evidence of a truncated network packet.

If the destination is large enough but only five source bytes remain after the requested offset, the result can instead reflect source exhaustion. Record the offset, requested count, destination capacity and chain's available data when distinguishing these cases. An offset at or beyond the available end can yield no bytes without an errno-style failure code.

Avoid diagnosing this by printing the entire destination array. A reused destination may contain bytes from a previous operation beyond the copied prefix. Clearing the buffer can make diagnostics easier, but it cannot turn those cleared bytes into received data or justify accepting a short header.

Advance the parser only after the intended check

For a fixed field, reject or defer processing until the required count is available according to the surrounding protocol's reassembly rules. Do not advance a cursor by the requested size after a short result. If the design intentionally processes variable-size chunks, advance by the actual count and keep the remaining requirement explicit.

These are different parser contracts. A message reassembler may legitimately wait for more fragments, while a decoder handed a supposedly complete frame may need to reject it. The copy function cannot decide which interpretation is correct for the application.

Keep source lifetime and ownership stable during inspection and copying. Length checks performed on a chain that another context concurrently changes do not establish a reliable bound for the subsequent copy. Use the synchronization and buffer ownership supplied by the surrounding subsystem rather than assuming a read-only helper freezes the source.

Test across the fragment boundary

A proposed regression fixture should place the same header wholly in one fragment, split it across two fragments, start it at an offset within the first fragment, and remove its final byte. Add a deliberately undersized destination to distinguish caller capacity failure from missing source data.

Require identical decoded values for the complete cases and no accepted header for the incomplete cases. The resulting contract is straightforward: the returned count establishes which bytes exist in the contiguous copy, and the parser applies its own completeness rule before interpreting them.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *