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

HpackDecoder treats invalid pseudo-headers as stream level errors #8046

Merged

Conversation

bryce-anderson
Copy link
Contributor

@bryce-anderson bryce-anderson commented Jun 22, 2018

Motivation:

The HTTP/2 spec dictates that invalid pseudo-headers should cause the
request/response to be treated as malformed (8.1.2.1), and the recourse
for that is to treat the situation as a stream error of type
PROTOCOL_ERROR (8.1.2.6). However, we're treating them as a connection
error with the connection being immediately torn down and the HPACK
state potentially being corrupted.

Modifications:

The HpackDecoder now throws a StreamException for validation failures
and throwing is deffered until the end of of the decode phase to ensure
that the HPACK state isn't corrupted by returning early.

Result:

Behavior more closely aligned with the HTTP/2 spec.

Fixes #8043.

@bryce-anderson bryce-anderson force-pushed the issue_8043_HeaderValidationError branch from 3c84618 to 92bc5cc Compare June 22, 2018 16:35

// we have read all of our headers. See if we have exceeded our maxHeaderListSize. We must
// we have read all of our headers so now perform validation steps. We must
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this switches to the imperative mid-sentence, which feels awkward

Copy link

@nepthar nepthar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@@ -551,6 +556,14 @@ public void appendToHeaderList(CharSequence name, CharSequence value) {
if (!exceededMaxLength) {
headers.add(name, value);
}
// Only consider the first validation exception
if (validate && validationException == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this conditional and the one above be else if?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I must be misunderstanding your suggestion. If it was an else if with the conditional above it would not validate unless exceededMaxLength == true, in which case it doesn't matter.

I was deliberate in letting the header be added even if validation was going to fail since there is a world where we would be interested in the results, but I could see wanting to refactor the checks such that we only add the header if it passes both checks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryce-anderson yeah I think only adding the header if it passes the checks would be a good idea as otherwise we will not use these anyway right ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the common (maybe all) case they will just be discarded. For the case of exceededMaxLength == true it made sense not to store it since it was too big, but the invalid pseudo-header case is less obvious. I'll change it to not add if it fails either validation if for nothing else than to be consistent.

@@ -119,24 +120,25 @@
* This method assumes the entire header block is contained in {@code in}.
*/
public void decode(int streamId, ByteBuf in, Http2Headers headers, boolean validateHeaders) throws Http2Exception {
Http2HeadersSink sink = new Http2HeadersSink(headers, maxHeaderListSize);
decode(in, sink, validateHeaders);
Http2HeadersSink sink = new Http2HeadersSink(streamId, headers, maxHeaderListSize, validateHeaders);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it wasn't introduced by this PR but it would be nice to not have to introduce object allocation for each decode. Seems like this can be handled as local state in the now private decode method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind if we defer this for a later commit? I think the private decode method is really heavy at this time and don't really want to add more state to it, at least as part of another behavior change.

fwiw, I suspect this is a really good candidate for stack allocation and even if it's not, it's super short lived garbage that only happens once on a complete HEADERS block.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am +1 to defer this for a followup as its not introduced by this change

Motivation:

The HTTP/2 spec dictates that invalid pseudo-headers should cause the
request/response to be treated as malformed (8.1.2.1), and the recourse
for that is to treat the situation as a stream error of type
PROTOCOL_ERROR (8.1.2.6). However, we're treating them as a connection
error with the connection being immediately torn down and the HPACK
state potentially being corrupted.

Modifications:

The HpackDecoder now throws a StreamException for validation failures
and throwing is deffered until the end of of the decode phase to ensure
that the HPACK state isn't corrupted by returning early.

Result:

Behavior more closely aligned with the HTTP/2 spec.

Fixes netty#8043.
@bryce-anderson bryce-anderson force-pushed the issue_8043_HeaderValidationError branch from 92bc5cc to 16301ad Compare June 22, 2018 20:00
@normanmaurer normanmaurer merged commit 8f01259 into netty:4.1 Jun 26, 2018
@normanmaurer
Copy link
Member

@bryce-anderson thanks!

@normanmaurer normanmaurer added this to the 4.1.26.Final milestone Jun 26, 2018
@normanmaurer normanmaurer self-assigned this Jun 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid HTTP2 pseudo-headers kill the session instead of being treated as malformed
5 participants