Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic due to the max headers capacity #700

Open
DDtKey opened this issue Jul 18, 2023 · 1 comment
Open

Panic due to the max headers capacity #700

DDtKey opened this issue Jul 18, 2023 · 1 comment
Labels

Comments

@DDtKey
Copy link
Contributor

DDtKey commented Jul 18, 2023

This method

h2/src/frame/headers.rs

Lines 830 to 922 in 6a75f23

fn load(
&mut self,
src: &mut BytesMut,
max_header_list_size: usize,
decoder: &mut hpack::Decoder,
) -> Result<(), Error> {
let mut reg = !self.fields.is_empty();
let mut malformed = false;
let mut headers_size = self.calculate_header_list_size();
macro_rules! set_pseudo {
($field:ident, $val:expr) => {{
if reg {
tracing::trace!("load_hpack; header malformed -- pseudo not at head of block");
malformed = true;
} else if self.pseudo.$field.is_some() {
tracing::trace!("load_hpack; header malformed -- repeated pseudo");
malformed = true;
} else {
let __val = $val;
headers_size +=
decoded_header_size(stringify!($field).len() + 1, __val.as_str().len());
if headers_size < max_header_list_size {
self.pseudo.$field = Some(__val);
} else if !self.is_over_size {
tracing::trace!("load_hpack; header list size over max");
self.is_over_size = true;
}
}
}};
}
let mut cursor = Cursor::new(src);
// If the header frame is malformed, we still have to continue decoding
// the headers. A malformed header frame is a stream level error, but
// the hpack state is connection level. In order to maintain correct
// state for other streams, the hpack decoding process must complete.
let res = decoder.decode(&mut cursor, |header| {
use crate::hpack::Header::*;
match header {
Field { name, value } => {
// Connection level header fields are not supported and must
// result in a protocol error.
if name == header::CONNECTION
|| name == header::TRANSFER_ENCODING
|| name == header::UPGRADE
|| name == "keep-alive"
|| name == "proxy-connection"
{
tracing::trace!("load_hpack; connection level header");
malformed = true;
} else if name == header::TE && value != "trailers" {
tracing::trace!(
"load_hpack; TE header not set to trailers; val={:?}",
value
);
malformed = true;
} else {
reg = true;
headers_size += decoded_header_size(name.as_str().len(), value.len());
if headers_size < max_header_list_size {
self.fields.append(name, value);
} else if !self.is_over_size {
tracing::trace!("load_hpack; header list size over max");
self.is_over_size = true;
}
}
}
Authority(v) => set_pseudo!(authority, v),
Method(v) => set_pseudo!(method, v),
Scheme(v) => set_pseudo!(scheme, v),
Path(v) => set_pseudo!(path, v),
Protocol(v) => set_pseudo!(protocol, v),
Status(v) => set_pseudo!(status, v),
}
});
if let Err(e) = res {
tracing::trace!("hpack decoding error; err={:?}", e);
return Err(e.into());
}
if malformed {
tracing::trace!("malformed message");
return Err(Error::MalformedMessage);
}
Ok(())
}
panics if the number of headers is too high

It's directly related to hyperium/http#603

@seanmonstar
Copy link
Member

I notice there is a guard in there that if the size is over max_header_list_size, it won't get appended to the HeaderMap. Is what you've noticed when there's a bunch of tiny headers?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants