Skip to content

Commit 3e33a87

Browse files
author
t
committed
fix(git-remote): reject malformed pkt-line length headers instead of flushing
A non-UTF-8 or non-hex 4-byte length prefix was collapsed to 0000 via unwrap_or, so a garbled header was handled exactly like a flush -- masking corrupted/desynchronized protocol input and letting accumulated have lines go out as a synthesized flush round. Propagate the parse error instead; a real 0000 still parses as a valid flush. (#192)
1 parent 6e78eb2 commit 3e33a87

1 file changed

Lines changed: 32 additions & 2 deletions

File tree

  • crates/git-remote-gitlawb/src

‎crates/git-remote-gitlawb/src/main.rs‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,15 @@ fn read_upload_pack_round<R: Read>(stdin: &mut R) -> Result<(Vec<u8>, RoundEnd)>
447447
Err(e) => return Err(e.into()),
448448
}
449449

450-
let len_hex = std::str::from_utf8(&len_bytes).unwrap_or("0000");
451-
let pkt_len = usize::from_str_radix(len_hex, 16).unwrap_or(0);
450+
// A malformed 4-byte length header must NOT be silently collapsed to a
451+
// 0000 flush (#192 F5): that masks corrupted/desynchronized protocol input
452+
// and can emit accumulated have lines as a synthesized flush round.
453+
let Ok(len_hex) = std::str::from_utf8(&len_bytes) else {
454+
bail!("malformed pkt-line length prefix: non-UTF-8 bytes {len_bytes:02x?}");
455+
};
456+
let Ok(pkt_len) = usize::from_str_radix(len_hex, 16) else {
457+
bail!("malformed pkt-line length prefix: non-hex {len_hex:?}");
458+
};
452459

453460
if pkt_len == 0 {
454461
// Flush pkt "0000": this round is complete.
@@ -1979,6 +1986,29 @@ mod tests {
19791986
);
19801987
}
19811988

1989+
/// #192 F5: a non-hex length header (e.g. "zzzz") is a malformed frame and must
1990+
/// be rejected, not silently collapsed to a 0000 flush.
1991+
#[test]
1992+
fn read_upload_pack_round_rejects_non_hex_length() {
1993+
let mut r = io::Cursor::new(b"zzzzdone\n".to_vec());
1994+
let err = read_upload_pack_round(&mut r).unwrap_err();
1995+
assert!(
1996+
err.to_string().to_lowercase().contains("pkt-line"),
1997+
"unexpected error: {err}"
1998+
);
1999+
}
2000+
2001+
/// #192 F5: a non-UTF-8 length header must be rejected, not treated as a flush.
2002+
#[test]
2003+
fn read_upload_pack_round_rejects_non_utf8_length() {
2004+
let mut r = io::Cursor::new(vec![0xffu8, 0xff, 0xff, 0xff]);
2005+
let err = read_upload_pack_round(&mut r).unwrap_err();
2006+
assert!(
2007+
err.to_string().to_lowercase().contains("pkt-line"),
2008+
"unexpected error: {err}"
2009+
);
2010+
}
2011+
19822012
/// G2: an immediately-empty upload-pack request (EOF at the opening round, with
19832013
/// a 200 advertisement) skips the POST entirely.
19842014
#[test]

0 commit comments

Comments
 (0)