From 9245e9409aeb5bb3e31b7f7c0e125583d1318465 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 5 Nov 2018 12:59:31 -0800 Subject: [PATCH] fix(header): fix panic when parsing header names larger than 64kb --- src/proto/h1/role.rs | 16 +++++++++++++--- tests/server.rs | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 83384b84e4..de1299dcfd 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -104,7 +104,7 @@ impl Http1Transaction for Server { Version::HTTP_10 }; - record_header_indices(bytes, &req.headers, &mut headers_indices); + record_header_indices(bytes, &req.headers, &mut headers_indices)?; headers_len = req.headers.len(); //(len, subject, version, headers_len) } @@ -590,7 +590,7 @@ impl Http1Transaction for Client { } else { Version::HTTP_10 }; - record_header_indices(bytes, &res.headers, &mut headers_indices); + record_header_indices(bytes, &res.headers, &mut headers_indices)?; let headers_len = res.headers.len(); (len, status, version, headers_len) }, @@ -918,7 +918,11 @@ struct HeaderIndices { value: (usize, usize), } -fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &mut [HeaderIndices]) { +fn record_header_indices( + bytes: &[u8], + headers: &[httparse::Header], + indices: &mut [HeaderIndices] +) -> Result<(), ::error::Parse> { let bytes_ptr = bytes.as_ptr() as usize; // FIXME: This should be a single plain `for` loop. @@ -945,6 +949,10 @@ fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &m cfg(all(target_arch = "arm", target_feature = "v7", target_feature = "neon")) for (header, indices) in (headers.iter().zip(indices.iter_mut())) { { + if header.name.len() >= (1 << 16) { + debug!("header name larger than 64kb: {:?}", header.name); + return Err(::error::Parse::TooLarge); + } let name_start = header.name.as_ptr() as usize - bytes_ptr; let name_end = name_start + header.name.len(); indices.name = (name_start, name_end); @@ -956,6 +964,8 @@ fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &m } } } + + Ok(()) } // Write header names as title case. The header name is assumed to be ASCII, diff --git a/tests/server.rs b/tests/server.rs index 6cb5054e27..883bc9a005 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -1024,6 +1024,24 @@ fn returning_1xx_response_is_error() { rt.block_on(fut).expect_err("1xx status code should error"); } +#[test] +fn header_name_too_long() { + let server = serve(); + + let mut req = connect(server.addr()); + let mut write = Vec::with_capacity(1024 * 66); + write.extend_from_slice(b"GET / HTTP/1.1\r\n"); + for _ in 0..(1024 * 65) { + write.push(b'x'); + } + write.extend_from_slice(b": foo\r\n\r\n"); + req.write_all(&write).unwrap(); + + let mut buf = [0; 1024]; + let n = req.read(&mut buf).unwrap(); + assert!(s(&buf[..n]).starts_with("HTTP/1.1 431 Request Header Fields Too Large\r\n")); +} + #[test] fn upgrades() { use tokio_io::io::{read_to_end, write_all};