-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
HCM: guard Envoy from removal of critical response headers. #15658
Conversation
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
cc @asraa |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My 2 cents! Thank you so much for doing this!
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
ASSERT(response_encoder_->encode100ContinueHeaders(continue_headers).ok()); | ||
chargeStats(continue_headers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chargeStats
assumes that the required headers are present, so we need to change the order here and elsewhere.
still crashes when it is head request 😕 |
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
OK, now all the crashes disappeared. Will work on the unit / integration tests. |
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
filter_manager_callbacks_.encodeHeaders(headers, modified_end_stream); | ||
state_.non_100_response_headers_encoded_ = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change is necessary since there's a check of non_100_response_headers_encoded_ != false
in the local reply and it makes sense to keep that assertion.
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
I thikn you could probably add an ASSERT(checkRequiredResponseHeaders()) after Alyssa's code to reset. |
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Our test added in this PR has passed for QUIC now, but
protocol tests have started failing for not only QUIC but also htt1,2. Will take a look. |
OK I hope I fixed the problem. Our approach here would change the behavior slightly different from the one in #15648. That is the upstream client will never receive the RESET even if there's invalid status headers coming, and instead just send the 502 with 'protocol error'-ish message. |
I hope the latest commit efdc243 explains well :) |
@asraa @alyssawilk PTAL! :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code changes by themselves look OK to me. I'm just not 100% sure if they should all be handled with reset like QUIC was.
@alyssawilk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for tackling this! It'll be great to have Envoy even more robust.
// filter_manager_callbacks_.streamEnded() returns True here when the codec failed to encode | ||
// headers due to the lack of required response headers, and filter_manager_callbacks already sent | ||
// the local reply and ended the stream by itself. So in that case this function must be no-op. | ||
if (end_stream && !filter_manager_callbacks_.streamEnded()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where are we now calling maybeEndEncode after the stream already ended?
I'm not sure but my concern is we may have a problem we should be solving before we reach this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is when the local reply is sent (due to the missing requires response headers) in the ConnectionManagerImpl::ActiveStream::encodeHeaders
as filter_manager_callbacks.encodeHeaders
, and the filter manager then reaches maybeEndEncode
.
envoy/source/common/http/filter_manager.cc
Lines 1070 to 1072 in 174e51a
filter_manager_callbacks_.encodeHeaders(headers, modified_end_stream); | |
state_.non_100_response_headers_encoded_ = true; | |
maybeEndEncode(modified_end_stream); |
But yeah I think this made the code a little bit more complex so maybe we should just return the status from filter_manager_callbacks and send the LocalReply just before maybeEndEncode in FilterManager..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think I'd rather have the HCM encodeHeaders return a status, so the filter manager knows something has gone awry.
I think it's useful to retain checks in maybeEndEncode happening once to catch other weird corner case bugs.
cc @snowp for a second opinion.
encoder_.encodeHeaders(*headers_copy, end_stream); | ||
const auto status = encoder_.encodeHeaders(*headers_copy, end_stream); | ||
// simulate the connection manager's behavior to handle encoding failures. | ||
if (!status.ok()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a problem.
Is this added to fix the integration tests we had that Envoy successfully handed upstream responses with no status? I think it's now testing the upstream works, not that Envoy works, and we need some way to force the encoder to encode this for tests, even if it looks invalid.
I think this is why coverage is now failing, because we're no longer testing handling bad responses from upstream.
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
I'm waiting for the reply to #15658 (comment) since it might affect the other parts |
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
will work on the fix of test after the comment https://github.com/envoyproxy/envoy/pull/15658/files#r608174940 has reached consensus since it also affects the other parts |
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
… chain. (#16745) This is the rework of the previous PR (#15658). Additional Description: Previously, Envoy hasn't been guarded from the removal of critical response headers like :status. This happens when there's misbehaving filter chan, and especially this protection is important when users run their own extensions through Wasm. Resolves #13756 and ref: #15487. Testing: new integration tests Risk: low Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
… chain. (envoyproxy#16745) This is the rework of the previous PR (envoyproxy#15658). Additional Description: Previously, Envoy hasn't been guarded from the removal of critical response headers like :status. This happens when there's misbehaving filter chan, and especially this protection is important when users run their own extensions through Wasm. Resolves envoyproxy#13756 and ref: envoyproxy#15487. Testing: new integration tests Risk: low Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Signed-off-by: Takeshi Yoneda takeshi@tetrate.io
Commit Message: HCM: guard Envoy from removal of critical response headers.
Additional Description: Previously, Envoy hasn't been guarded from the removal of critical response headers like :status. This happens when there's misbehaving filter chan, and especially this protection is important when users run their own extensions through Wasm. Resolves #13756 and ref: #15487.
For the request path, Envoy is already guarded by
HeaderUtility::checkRequiredHeaders
and its error is gracefully handled in theonPoolReady
.Risk Level: high (change in the core feature's critical code path)
Testing: unittest && integration test
The following is the current crash path with uncaught exception:
envoy/source/common/http/conn_manager_impl.cc
Line 1463 in 25d5066
envoy/source/common/http/conn_manager_impl.cc
Line 771 in 25d5066
envoy/source/common/http/utility.cc
Lines 442 to 445 in 25d5066
and we've never reached the assertion for this here:
envoy/source/common/http/http2/codec_impl.cc
Line 237 in 25d5066