Skip to content

Envoy ASSERT() due to regex rewrite path string contains \r#23448

Merged
htuch merged 1 commit intoenvoyproxy:mainfrom
yanjunxiang-google:fix_regex_rewrite_path
Oct 20, 2022
Merged

Envoy ASSERT() due to regex rewrite path string contains \r#23448
htuch merged 1 commit intoenvoyproxy:mainfrom
yanjunxiang-google:fix_regex_rewrite_path

Conversation

@yanjunxiang-google
Copy link
Copy Markdown
Contributor

@yanjunxiang-google yanjunxiang-google commented Oct 11, 2022

It is observed that Envoy crash in ASSERT() due to regex rewrite path string contains invalid character '\r'.

We should prohibit null characters \0, \r, \n in the regex rewrite substitution string. This is well guarded in most other cases like RouteAction:prefix_rewrite, but is missing in RouteAction:regex_rewrite:substitution.

Signed-off-by: Yanjun Xiang yanjunxiang@google.com

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional API Considerations:]

…characters.

Signed-off-by: Yanjun Xiang <yanjunxiang@google.com>
@repokitteh-read-only
Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @mattklein123
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #23448 was opened by yanjunxiang-google.

see: more, trace.

@yanjunxiang-google yanjunxiang-google changed the title fixing envoy crash due to regex rewrite path string contains invalid … Envoy crash due to regex rewrite path string contains \r Oct 11, 2022
@yanjunxiang-google
Copy link
Copy Markdown
Contributor Author

/assign @adisuissa

@yanjunxiang-google
Copy link
Copy Markdown
Contributor Author

yanjunxiang-google commented Oct 11, 2022

We are seeing an Envoy crash in ASSERT() with below trace:

==458==ERROR: AddressSanitizer: ABRT on unknown address 0x0539000001ca (pc 0x7f053ef4f18b bp 0x7ffc30b6cc90 sp 0x7ffc30b6c990 T0)
  | SCARINESS: 10 (signal)
  | #0 0x7f053ef4f18b in raise /build/glibc-eX1tMB/glibc-2.31/sysdeps/unix/sysv/linux/raise.c:51:1
  | #1 0x7f053ef2e858 in abort /build/glibc-eX1tMB/glibc-2.31/stdlib/abort.c:79:7
  | #2 0x17a3409 in Envoy::UnionStringBaseEnvoy::Http::HeaderStringValidator::setCopy(char const*, unsigned int) envoy/common/union_string.h:173:5
  | #3 0x179ae7f in setCopy envoy/common/union_string.h:179:42
  | #4 0x179ae7f in Envoy::Http::TypedHeaderMapImplEnvoy::Http::RequestHeaderMap::setInline(Envoy::Http::CustomInlineHeaderRegistry::Handle<(Envoy::Http::CustomInlineHeaderRegistry::Type)0>, absl::string_view) /proc/self/cwd/source/common/http/header_map_impl.h:440:19
  | #5 0x17928ba in setPath /proc/self/cwd/source/common/http/header_map_impl.h:479:3
  | #6 0x17928ba in Envoy::Http::TestRequestHeaderMapImpl::setPath(absl::string_view) /proc/self/cwd/test/test_common/utility.h:1074:3
  | #7 0x369854f in Envoy::Router::RouteEntryImplBase::finalizePathHeader(Envoy::Http::RequestHeaderMap&, absl::string_view, bool) const /proc/self/cwd/source/common/router/config_impl.cc:941:11
  | #8 0x36abd49 in Envoy::Router::PathRouteEntryImpl::rewritePathHeader(Envoy::Http::RequestHeaderMap&, bool) const /proc/self/cwd/source/common/router/config_impl.cc:1529:3
  | #9 0x3694c3e in Envoy::Router::RouteEntryImplBase::finalizeRequestHeaders(Envoy::Http::RequestHeaderMap&, Envoy::StreamInfo::StreamInfo const&, bool) const /proc/self/cwd/source/common/router/config_impl.cc:834:5
  | #10 0x172194f in TestOneProtoInput /proc/self/cwd/test/common/router/route_fuzz_test.cc:156:28
  | #11 0x172194f in LLVMFuzzerTestOneInput /proc/self/cwd/test/common/router/route_fuzz_test.cc:139:1
  | #12 0x57c96ab in main
  | #13 0x7f053ef300b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
  | #14 0x1663ced in _start
 

And the configuration to trigger this is:

route {
cluster: ""
regex_rewrite {
pattern {
regex: "%
"
}
substitution: "ty/envoy.\r$nigfig.rououte"
}
}

@yanjunxiang-google
Copy link
Copy Markdown
Contributor Author

/assign @htuch

// to capture group 2.
string substitution = 2;
string substitution = 2
[(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}];
Copy link
Copy Markdown
Member

@htuch htuch Oct 12, 2022

Choose a reason for hiding this comment

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

This is technically a breaking API change. I agree that \r in headers is invalid. Can you audit all the uses of RegexMatchAndSubstitute and figure out if HTTP_HEADER_VALUE is the right choice? I think some of them are paths, hosts and so on. It might turn out HTTP_HEADER_VALUE is sufficiently general to encompass them but I'm not sure, would be good to have a paper trail when making this kind of change.

Also, presumably we're only "crashing" in ASSERT mode, and this isn't a genuine security issue? Please clarify in the commit message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Alternatively, the validation can be done when processing the config in RouteEntryImplBase.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the comments!
There are six places using RegexMatchAndSubstitute:

  1. type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 2;
  2. type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 32;

    3)
    type.matcher.v3.RegexMatchAndSubstitute host_rewrite_path_regex = 35;

type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 9;

5)
type.matcher.v3.RegexMatchAndSubstitute regex_value_rewrite = 6

6)
type.matcher.v3.RegexMatchAndSubstitute regex_value_rewrite = 4;

It looks to me all of them are trying to using the "substitution" string in the RegexMatchAndSubstitute to replace some parts of the HTTP header. Thus "substitution" should not contain '\r', '\n', '\0', which [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}] is trying to guard against.

Regarding the alternative to implement the logic in RouteEntryImplBase, I would think leverage the pgv is able to guard all the cases above. Also it's widely used, like:

or

string prefix_rewrite = 5

Yeah, the crash only happens in ASSERT mode. Let me change the commit message. Also, it's triggered by incorrect Envoy configuration, which IIUC, can not be exploited by malicious client, thus I would think it's not a genuine security issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can RegexMatchAndSubstitute be used by the unified matcher?
If so, it may be used as an extension for a non-header regex substitution.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a good question. I don't see it yet. The original commit for RegexMatchAndSubstitute is #10050, which just use it for RouteAction.

If in the future people want to use it as unified matcher, they are aware that NULL characters can not be in the "substitution". Otherwise, they have to add their own proto field.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think it's possible to use RegexMatchAndSubstitute as a matcher in the unified matching API, since the unified matching API separates matching from actions, and RegexMatchAndSubstitute combines the two. But @snowp can probably tell us for sure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cc @snowp can you shed a light on whether RegexMatchAndSubstitute can be used as a matcher?
Generally speaking, is there a list of what types can be used in the unified matcher (both matchers and actions)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As Mark said the unified matcher doesn't support any form of rewrite, it performs a stateless matching which results in an action, which then needs to be acted upon. There's certainly possibilities to make it support some kind of mutability or state propagation from the matcher, but it's not there today

Per https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/common/matcher/v3/matcher.proto#envoy-v3-api-msg-config-common-matcher-v3-matcher-matcherlist-predicate-singlepredicate there's either a value_match which uses a StringMatcher or a custom match which supports using a registered match extension like the ones listed in the docs

@yanjunxiang-google yanjunxiang-google changed the title Envoy crash due to regex rewrite path string contains \r Envoy ASSERT() due to regex rewrite path string contains \r Oct 12, 2022
@mattklein123 mattklein123 removed their assignment Oct 13, 2022
@htuch
Copy link
Copy Markdown
Member

htuch commented Oct 13, 2022

LGTM - can I get another pair of eyes from @envoyproxy/api-shepherds to verify this technically breaking change is safe as there was no contractually valid way to use these rejected values?

@adisuissa
Copy link
Copy Markdown
Contributor

LGTM - can I get another pair of eyes from @envoyproxy/api-shepherds to verify this technically breaking change is safe as there was no contractually valid way to use these rejected values?

Per Snow's comment, and given that this type is only used for headers, I think this is a safe change.

@htuch htuch merged commit 23f3ee5 into envoyproxy:main Oct 20, 2022
@yanjunxiang-google yanjunxiang-google deleted the fix_regex_rewrite_path branch October 21, 2022 15:35
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.

6 participants