Skip to content

fix(outgoing): keep homa_tx_skb_alloc frag length arithmetic signed - #98

Open
randomizedcoder wants to merge 1 commit into
PlatformLab:mainfrom
randomizedcoder:fix/outgoing-frag-signedness
Open

randomizedcoder wants to merge 1 commit into
PlatformLab:mainfrom
randomizedcoder:fix/outgoing-frag-signedness

Conversation

@randomizedcoder

Copy link
Copy Markdown

Signedness: mixed-sign min() in homa_tx_skb_alloc()

The per-fragment copy length is:

int frag_bytes;
frag_bytes = min(skb_frag_size(msg_frag) - bytes_to_skip, bytes_left);

skb_frag_size() returns unsigned int, so skb_frag_size(msg_frag) - bytes_to_skip is unsigned, while bytes_left and the frag_bytes result are int — a mixed-sign min().

The skip loop just above guarantees bytes_to_skip < skb_frag_size(msg_frag), so on current builds the value is always correct — this is a robustness / consistency fix, not a live miscompile. But the shape is fragile: if that invariant ever broke, the unsigned subtraction would wrap to a huge positive length and the mixed-sign comparison would select it as the "minimum".

Fix

-		int frag_bytes;
-
-		frag_bytes = min(skb_frag_size(msg_frag) - bytes_to_skip,
-				 bytes_left);
+		int frag_avail, frag_bytes;
+
+		/* skb_frag_size() is unsigned; keep the min() operands signed
+		 * (matching bytes_left and frag_bytes) so a mixed-sign compare
+		 * can't turn an underflow into a huge positive length.
+		 */
+		frag_avail = (int)skb_frag_size(msg_frag) - bytes_to_skip;
+		frag_bytes = min(frag_avail, bytes_left);

Frag sizes are page-scale (≤ 64 KB), well within int, so the cast is safe.

Verification (regression)

No behavior change on current compilers, so the gate is the existing behavioral suite: the homa_outgoing unit tests stay green (52/52), including every homa_tx_skb_alloc__* case that checks fragment offsets and sizes.

This one is a defensive/readability change — happy to drop it if you'd rather leave the line as-is.

In homa_tx_skb_alloc() the per-frag length is computed as:

    frag_bytes = min(skb_frag_size(msg_frag) - bytes_to_skip, bytes_left);

skb_frag_size() is unsigned, so the first argument is unsigned while
bytes_left (and the frag_bytes result) are int -- a mixed-sign min(). The
skip loop guarantees bytes_to_skip < skb_frag_size() today, so the value
is correct; but should that invariant ever break, the unsigned subtraction
would wrap to a huge positive length and the mixed-sign comparison would
happily pick it. Compute the available bytes as a signed int first, so
min() compares two ints and an underflow stays negative (and loses the
min).

Pure refactor of the arithmetic's type; no behavior change. The
homa_outgoing unit suite stays green (52/52), including all the
homa_tx_skb_alloc frag offset/size checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant