Skip to content

Added check for pseudo-headers in trailers#13603

Merged
normanmaurer merged 7 commits intonetty:4.1from
isaacrivriv:add-pseudo-header-trailer-check
Oct 19, 2023
Merged

Added check for pseudo-headers in trailers#13603
normanmaurer merged 7 commits intonetty:4.1from
isaacrivriv:add-pseudo-header-trailer-check

Conversation

@isaacrivriv
Copy link
Contributor

Motivation:
According to the RFC for HTTP2 on Section 8.1.2.1, 'Pseudo-header fields MUST NOT appear in trailers. Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed (Section 8.1.2.6).'

Modifications:
Updated Http2Decoder to check trailers for Pseudo-Headers and treat them as invalid requests according to RFC 7540 Section 8.1.2.6

Result:
After this change, requests with Pseudo-Headers sent inside trailers will be treated as malformed and a stream error is thrown.
Fixes: #13602

Motivation:
According to the RFC for HTTP2 on Section 8.1.2.1, 'Pseudo-header fields MUST NOT appear in trailers. Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed (Section 8.1.2.6).'

Modifications:
Updated Http2Decoder to check trailers for Pseudo-Headers and treat them
as invalid requests according to RFC 7540 Section 8.1.2.6

Result:
After this change, requests with Pseudo-Headers sent inside trailers
will be treated as malformed and a stream error is thrown
@normanmaurer
Copy link
Member

@isaacrivriv did you sign our icla ? https://netty.io/s/icla ?

@isaacrivriv
Copy link
Contributor Author

Yes it should have been signed already! I followed the steps in the developer guide and signed it before pushing the PR

Co-authored-by: Norman Maurer <norman_maurer@apple.com>
Copy link
Contributor

@bryce-anderson bryce-anderson left a comment

Choose a reason for hiding this comment

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

A few small suggestions but otherwise looks good!

Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

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

The (old) RFC 7540 has:

Pseudo-header fields defined for requests MUST NOT appear
in responses; pseudo-header fields defined for responses MUST NOT
appear in requests. Pseudo-header fields MUST NOT appear in
trailers.

Where are we doing that first part? I'd expect to see the mirror of this logic elsewhere. Do we just not have that logic anywhere?

@normanmaurer
Copy link
Member

@isaacrivriv please let us know once this is ready for review again

@isaacrivriv
Copy link
Contributor Author

Sorry for the delay, got back to this again this week. I'm not seeing code where Netty validates that sending pseudo-headers in a request/response. I created issue #13646 to follow up. I tried a quick test locally to add code to verify but a lot of the tests started failing. Will verify this but in the mean time I will push the clean up comments for this specific issue

@isaacrivriv isaacrivriv force-pushed the add-pseudo-header-trailer-check branch from a56dc1f to 7396915 Compare October 3, 2023 19:51
@isaacrivriv
Copy link
Contributor Author

Should be ready for review, tagged you all when you get a chance. Thanks!

@isaacrivriv isaacrivriv force-pushed the add-pseudo-header-trailer-check branch from 7396915 to d2a175d Compare October 3, 2023 20:09
As suggested, removed unused import, used iterator instead of header.names(), updated header name in tests for case where `randomString` can generate a string with a colon at the start, and updated comments to match newer RFC

Co-authored-by: Bryce Anderson <bryce_anderson@apple.com>
@isaacrivriv isaacrivriv force-pushed the add-pseudo-header-trailer-check branch from d2a175d to 8ecc840 Compare October 5, 2023 20:13
@isaacrivriv
Copy link
Contributor Author

Should be ready for review again

@normanmaurer
Copy link
Member

@vietj PTAL as well

Copy link
Member

@normanmaurer normanmaurer left a comment

Choose a reason for hiding this comment

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

one nit. ...

Comment on lines 406 to 418
} else {
// Need to check trailers don't contain pseudo headers. According to RFC 9113
// Trailers MUST NOT include pseudo-header fields (Section 8.3).
if (!headers.isEmpty()) {
for (Iterator<Entry<CharSequence, CharSequence>> iterator =
headers.iterator(); iterator.hasNext();) {
if (Http2Headers.PseudoHeaderName.hasPseudoHeaderFormat(iterator.next().getKey())) {
throw streamError(stream.id(), PROTOCOL_ERROR,
"Found invalid Pseudo-Header in trailers");
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
} else {
// Need to check trailers don't contain pseudo headers. According to RFC 9113
// Trailers MUST NOT include pseudo-header fields (Section 8.3).
if (!headers.isEmpty()) {
for (Iterator<Entry<CharSequence, CharSequence>> iterator =
headers.iterator(); iterator.hasNext();) {
if (Http2Headers.PseudoHeaderName.hasPseudoHeaderFormat(iterator.next().getKey())) {
throw streamError(stream.id(), PROTOCOL_ERROR,
"Found invalid Pseudo-Header in trailers");
}
}
}
}
} else if (!headers.isEmpty()) {
// Need to check trailers don't contain pseudo headers. According to RFC 9113
// Trailers MUST NOT include pseudo-header fields (Section 8.3).
for (Iterator<Entry<CharSequence, CharSequence>> iterator =
headers.iterator(); iterator.hasNext();) {
if (Http2Headers.PseudoHeaderName.hasPseudoHeaderFormat(iterator.next().getKey())) {
throw streamError(stream.id(), PROTOCOL_ERROR,
"Found invalid Pseudo-Header in trailers");
}
}
}

@vietj
Copy link
Contributor

vietj commented Oct 6, 2023

I cannot see any test that triggers the bug that is fixed here, only existing test modifications that do not affect it

@isaacrivriv isaacrivriv force-pushed the add-pseudo-header-trailer-check branch 2 times, most recently from 18f2f5a to 4d85799 Compare October 14, 2023 04:02
connection decoder for verifying trailer headers.
@normanmaurer
Copy link
Member

I did some cleanup and added a test case /cc @vietj

Copy link
Member

@idelpivnitskiy idelpivnitskiy left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!
One minor suggestion:

@normanmaurer normanmaurer added this to the 4.1.101.Final milestone Oct 19, 2023
@normanmaurer normanmaurer merged commit 2657079 into netty:4.1 Oct 19, 2023
@normanmaurer
Copy link
Member

@isaacrivriv thanks a lot!

normanmaurer added a commit that referenced this pull request Oct 19, 2023
Motivation:
According to the RFC for HTTP2 on Section 8.1.2.1, 'Pseudo-header fields
MUST NOT appear in trailers. Endpoints MUST treat a request or response
that contains undefined or invalid pseudo-header fields as malformed
(Section 8.1.2.6).'

Modifications:
Updated Http2Decoder to check trailers for Pseudo-Headers and treat them
as invalid requests according to RFC 7540 Section 8.1.2.6

Result:
After this change, requests with Pseudo-Headers sent inside trailers
will be treated as malformed and a stream error is thrown.

Fixes: #13602

---------

Co-authored-by: Norman Maurer <norman_maurer@apple.com>
Co-authored-by: Bryce Anderson <bryce_anderson@apple.com>
"Multiple content-length headers received");
}
}
} else if (validateHeaders && !headers.isEmpty()) {

Choose a reason for hiding this comment

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

This change broke users of grpc-netty.

grpc/grpc-java#10663

This is clearly a grpc-netty bug so there's no action required in Netty - I just wanted to comment here to make the maintainers aware of this issue.

// Need to check trailers don't contain pseudo headers. According to RFC 9113
// Trailers MUST NOT include pseudo-header fields (Section 8.3).
for (Iterator<Entry<CharSequence, CharSequence>> iterator =
headers.iterator(); iterator.hasNext();) {
Copy link
Member

Choose a reason for hiding this comment

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

@ejona86 @pkoenig10 The usage of isEmpty was fixed in grpc/grpc-java#10663 and #13717, but we did not look closely enough at the problem, because on this line we also call the iterator() method on the Http2Headers, which AbstractHttp2Headers still does not implement: https://github.com/grpc/grpc-java/blob/75492c8b36c9392d94dfce09fc132ce88c94325e/netty/src/main/java/io/grpc/netty/AbstractHttp2Headers.java#L499

Copy link
Member

Choose a reason for hiding this comment

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

I see there's already a grpc-java issue on this: grpc/grpc-java#10837

Copy link
Member

Choose a reason for hiding this comment

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

This looks like it was supposed to be fixed in 1.55.0 with grpc/grpc-java#9979. The report I got was using 1.51.1, and grpc/grpc-java#10837 reports using 1.30.2, so this is probably not an issue for those who are on newer versions!

Copy link
Member

Choose a reason for hiding this comment

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

Oh that's great to hear. I saw the issue this morning as felt, "oh no." Glad it is already added. (Although obviously, better than recently being added would have been "always had been implemented"... We should re-run the benchmarks to see how much of a performance difference it makes to use our own impl, although benchmarking garbage creation is terribly difficult to get meaningful results.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Malformed requests with Pseudo Headers in trailers

9 participants