Skip to content

Commit b9dc5d9

Browse files
authored
router: disallow :path/host rewriting in request_headers_to_add. (#4220)
We have dedicated alternative mechanisms for this in RouteAction, it can confuse other actions (e.g. prefix_rewrite). Fixes oss-fuzz issue https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9995. Risk level: Low Testing: Unit tests and corpus entry added. Signed-off-by: Harvey Tuch <htuch@google.com>
1 parent 0c91011 commit b9dc5d9

File tree

7 files changed

+90
-2
lines changed

7 files changed

+90
-2
lines changed

api/envoy/api/v2/core/base.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ message HeaderValue {
146146
// Header name/value pair plus option to control append behavior.
147147
message HeaderValueOption {
148148
// Header name/value pair that this option applies to.
149-
HeaderValue header = 1;
149+
HeaderValue header = 1 [(validate.rules).message.required = true];
150150

151151
// Should the value be appended? If true (default), the value is appended to
152152
// existing values.

docs/root/configuration/http_conn_man/headers.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,11 @@ route, virtual host, and/or global route configuration level. See the relevant :
438438
<config_http_conn_man_route_table>` and :ref:`v2 <envoy_api_msg_RouteConfiguration>` API
439439
documentation.
440440

441+
No *:*-prefixed pseudo-header may be modified via this mechanism. The *:path*
442+
and *:authority* headers may instead be modified via mechanisms such as
443+
:ref:`prefix_rewrite <envoy_api_field_route.RouteAction.prefix_rewrite>` and
444+
:ref:`host_rewrite <envoy_api_field_route.RouteAction.host_rewrite>`.
445+
441446
Headers are appended to requests/responses in the following order: weighted cluster level headers,
442447
route level headers, virtual host level headers and finally global level headers.
443448

@@ -502,4 +507,4 @@ Supported variable names are:
502507
- header:
503508
key: "x-request-start"
504509
value: "%START_TIME(%s.%3f)%"
505-
append: true
510+
append: true

docs/root/intro/version_history.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ Version history
4848
<envoy_api_field_route.Route.request_headers_to_add>` with *authorization:
4949
token2* applied.
5050
* http: response filters not applied to early error paths such as http_parser generated 400s.
51+
* http: restrictions added to reject *:*-prefixed pseudo-headers in :ref:`custom
52+
request headers <config_http_conn_man_headers_custom_request_headers>`.
5153
* http: :ref:`hpack_table_size <envoy_api_field_core.Http2ProtocolOptions.hpack_table_size>` now controls
5254
dynamic table size of both: encoder and decoder.
5355
* listeners: added the ability to match :ref:`FilterChain <envoy_api_msg_listener.FilterChain>` using

source/common/router/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ envoy_cc_library(
214214
":header_formatter_lib",
215215
"//include/envoy/http:header_map_interface",
216216
"//source/common/config:base_json_lib",
217+
"//source/common/http:headers_lib",
217218
"//source/common/protobuf:utility_lib",
218219
],
219220
)

source/common/router/header_parser.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string>
77

88
#include "common/common/assert.h"
9+
#include "common/http/headers.h"
910
#include "common/protobuf/utility.h"
1011

1112
#include "absl/strings/str_cat.h"
@@ -36,6 +37,18 @@ std::string unescape(absl::string_view sv) { return absl::StrReplaceAll(sv, {{"%
3637
// RequestInfoHeaderFormatter.
3738
HeaderFormatterPtr
3839
parseInternal(const envoy::api::v2::core::HeaderValueOption& header_value_option) {
40+
const std::string& key = header_value_option.header().key();
41+
// PGV constraints provide this guarantee.
42+
ASSERT(!key.empty());
43+
// We reject :path/:authority rewriting, there is already a well defined mechanism to
44+
// perform this in the RouteAction, and doing this via request_headers_to_add
45+
// will cause us to have to worry about interaction with other aspects of the
46+
// RouteAction, e.g. prefix rewriting. We also reject other :-prefixed
47+
// headers, since it seems dangerous and there doesn't appear a use case.
48+
if (key[0] == ':') {
49+
throw EnvoyException(":-prefixed headers may not be modified");
50+
}
51+
3952
const bool append = PROTOBUF_GET_WRAPPED_OR_DEFAULT(header_value_option, append, true);
4053

4154
absl::string_view format(header_value_option.header().value());

test/common/router/config_impl_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,33 @@ response_headers_to_remove: ["x-global-remove"]
915915
ContainerEq(config.internalOnlyHeaders()));
916916
}
917917

918+
// Validate that we can't add :-prefixed request headers.
919+
TEST(RouteMatcherTest, TestRequestHeadersToAddNoPseudoHeader) {
920+
for (const std::string& header : {":path", ":authority", ":method", ":scheme", ":status",
921+
":protocol", ":no-chunks", ":status"}) {
922+
const std::string yaml = fmt::format(R"EOF(
923+
name: foo
924+
virtual_hosts:
925+
- name: www2
926+
domains: ["*"]
927+
request_headers_to_add:
928+
- header:
929+
key: {}
930+
value: vhost-www2
931+
append: false
932+
)EOF",
933+
header);
934+
935+
NiceMock<Server::Configuration::MockFactoryContext> factory_context;
936+
NiceMock<Envoy::RequestInfo::MockRequestInfo> request_info;
937+
938+
envoy::api::v2::RouteConfiguration route_config = parseRouteConfigurationFromV2Yaml(yaml);
939+
940+
EXPECT_THROW_WITH_MESSAGE(TestConfigImpl config(route_config, factory_context, true),
941+
EnvoyException, ":-prefixed headers may not be modified");
942+
}
943+
}
944+
918945
TEST(RouteMatcherTest, Priority) {
919946
std::string json = R"EOF(
920947
{
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
config {
2+
virtual_hosts {
3+
name: "regex"
4+
domains: "bat.com"
5+
domains: "*"
6+
domains: "w.lyft.com"
7+
routes {
8+
match {
9+
regex: "/"
10+
}
11+
route {
12+
cluster: "regex"
13+
prefix_rewrite: "ewrote"
14+
}
15+
request_headers_to_add {
16+
header {
17+
key: "\177\177\177\177\177\177\177\177"
18+
}
19+
}
20+
}
21+
}
22+
request_headers_to_add {
23+
header {
24+
key: ":path"
25+
value: "`"
26+
}
27+
append {
28+
}
29+
}
30+
request_headers_to_add {
31+
header {
32+
key: "`"
33+
value: "`"
34+
}
35+
append {
36+
}
37+
}
38+
validate_clusters {
39+
}
40+
}

0 commit comments

Comments
 (0)