Skip to content

Commit 98f027b

Browse files
RoyLinRoyLin
authored andcommitted
test: adversarial coverage for the untrusted SNI/DNS parsers
parse_sni: a ClientHello whose server_name name_len (0xffff) overruns the buffer must return None, not OOB-panic. parse_dns_qname: reject a compression pointer (never valid in a query) and a label length that runs past the buffer. Locks in the bounds-checks on parsers that consume raw network bytes from arbitrary processes (a panic there = collector DoS). Collector parser tests 3 -> 5.
1 parent 9c7690d commit 98f027b

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

a3s-observer-collector/src/main.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,35 @@ mod tests {
600600
assert_eq!(parse_dns_qname(&q).as_deref(), Some("api.anthropic.com"));
601601
assert_eq!(parse_dns_qname(&[0u8; 8]), None);
602602
}
603+
604+
#[test]
605+
fn parse_sni_rejects_malicious_name_len_without_panicking() {
606+
// Long enough to reach the extension walk, but the server_name name_len (0xffff) points
607+
// far past the buffer — a hand-rolled parser without bounds checks would OOB-panic here.
608+
let mut b = vec![0x16, 0x03, 0x01, 0x00, 0x00];
609+
b.extend_from_slice(&[0x01, 0x00, 0x00, 0x00]);
610+
b.extend_from_slice(&[0x03, 0x03]);
611+
b.extend_from_slice(&[0u8; 32]);
612+
b.push(0x00); // session_id len 0
613+
b.extend_from_slice(&[0x00, 0x02, 0x13, 0x01]); // cipher_suites
614+
b.extend_from_slice(&[0x01, 0x00]); // compression
615+
b.extend_from_slice(&[0x00, 0x09]); // extensions total len
616+
b.extend_from_slice(&[0x00, 0x00]); // ext type: server_name
617+
b.extend_from_slice(&[0x00, 0x05]); // ext len
618+
b.extend_from_slice(&[0x00, 0x03]); // server_name_list len
619+
b.push(0x00); // name_type
620+
b.extend_from_slice(&[0xff, 0xff]); // name_len 65535 — past the buffer
621+
assert_eq!(parse_sni(&b), None);
622+
}
623+
624+
#[test]
625+
fn parse_dns_rejects_compression_pointer_and_label_overrun() {
626+
let mut ptr = vec![0u8; 12];
627+
ptr.extend_from_slice(&[0xc0, 0x0c]); // compression pointer — never valid in a query
628+
assert_eq!(parse_dns_qname(&ptr), None);
629+
let mut overrun = vec![0u8; 12];
630+
overrun.push(50); // claims a 50-byte label...
631+
overrun.extend_from_slice(b"short"); // ...but only 5 bytes follow
632+
assert_eq!(parse_dns_qname(&overrun), None);
633+
}
603634
}

0 commit comments

Comments
 (0)