Skip to content

Commit 1bb7704

Browse files
committed
fix(mmds): Reject X-Forwarded-For in case-insensitive way
As EC2 IMDS does, MMDS denies PUT requests if X-Forwarded-For header is included, but it was validated only in a case-sensitive way. However, it is defined that HTTP headers are case-insensitive. We should deny it regardless of its case. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent d45e458 commit 1bb7704

File tree

3 files changed

+31
-19
lines changed

3 files changed

+31
-19
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ and this project adheres to
5858
- [#5260](https://github.com/firecracker-microvm/firecracker/pull/5260): Fixed a
5959
bug allowing the block device to starve all other devices when backed by a
6060
sufficiently slow drive.
61+
- [#XXXX](https://github.com/firecracker-microvm/firecracker/pull/XXXX): Fixed
62+
MMDS to reject PUT requests containing `X-Forwarded-For` header regardless of
63+
its casing (e.g. `x-forwarded-for`).
6164

6265
## [1.12.0]
6366

src/vmm/src/mmds/mod.rs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,13 @@ fn respond_to_put_request(mmds: &mut Mmds, request: Request) -> Response {
235235
let custom_headers = request.headers.custom_entries();
236236

237237
// Reject `PUT` requests that contain `X-Forwarded-For` header.
238-
if custom_headers.contains_key(REJECTED_HEADER) {
239-
let error_msg = RequestError::HeaderError(HttpHeaderError::UnsupportedName(
240-
REJECTED_HEADER.to_string(),
241-
))
242-
.to_string();
238+
if let Some((header, __)) = custom_headers
239+
.iter()
240+
.find(|(k, _)| k.to_lowercase() == REJECTED_HEADER)
241+
{
242+
let error_msg =
243+
RequestError::HeaderError(HttpHeaderError::UnsupportedName(header.to_string()))
244+
.to_string();
243245
return build_response(
244246
request.http_version(),
245247
StatusCode::BadRequest,
@@ -733,19 +735,25 @@ mod tests {
733735
assert_eq!(actual_response.content_type(), MediaType::PlainText);
734736

735737
// Test unsupported `X-Forwarded-For` header
736-
let request = Request::try_from(
737-
b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
738-
X-Forwarded-For: 203.0.113.195\r\n\r\n",
739-
None,
740-
)
741-
.unwrap();
742-
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
743-
expected_response.set_content_type(MediaType::PlainText);
744-
expected_response.set_body(Body::new(
745-
"Invalid header. Reason: Unsupported header name. Key: X-Forwarded-For".to_string(),
746-
));
747-
let actual_response = convert_to_response(mmds.clone(), request);
748-
assert_eq!(actual_response, expected_response);
738+
for header in ["X-Forwarded-For", "x-forwarded-for", "X-fOrWaRdEd-FoR"] {
739+
#[rustfmt::skip]
740+
let request = Request::try_from(
741+
format!(
742+
"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
743+
{header}: 203.0.113.195\r\n\r\n"
744+
)
745+
.as_bytes(),
746+
None,
747+
)
748+
.unwrap();
749+
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
750+
expected_response.set_content_type(MediaType::PlainText);
751+
expected_response.set_body(Body::new(format!(
752+
"Invalid header. Reason: Unsupported header name. Key: {header}"
753+
)));
754+
let actual_response = convert_to_response(mmds.clone(), request);
755+
assert_eq!(actual_response, expected_response);
756+
}
749757

750758
// Test invalid path
751759
let request = Request::try_from(

src/vmm/src/mmds/token_headers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use std::result::Result;
77
use micro_http::{HttpHeaderError, RequestError};
88

99
/// Header rejected by MMDS.
10-
pub const REJECTED_HEADER: &str = "X-Forwarded-For";
10+
/// Defined in lowercase since HTTP headers are case-insensitive.
11+
pub const REJECTED_HEADER: &str = "x-forwarded-for";
1112

1213
/// `X-metadata-token` header might be used by HTTP clients to specify a token in order to
1314
/// authenticate to the session. This is used for GET requests issued by the guest to MMDS only.

0 commit comments

Comments
 (0)