Skip to content
New issue

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

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

Already on GitHub? # 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?

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

No branches or pull requests

2 participants