Skip to content

Commit 082c578

Browse files
authored
Merge branch 'main' into vsock-latency-perf
2 parents 0aebe4a + a481d51 commit 082c578

57 files changed

Lines changed: 658 additions & 161 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cargo/audit.toml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
[advisories]
2-
# The `paste` dependency is transitively included via `gdbstub`.
3-
# While the crate is archived/unmaintained, the author considers it feature-complete
4-
# and functionally stable. gdbstub will be update once they migrate
5-
# to an alternative solution.
6-
# See https://github.com/daniel5151/gdbstub/issues/168
7-
ignore = ["RUSTSEC-2024-0436"]
2+
ignore = [
3+
# The `paste` dependency is transitively included via `gdbstub`.
4+
# While the crate is archived/unmaintained, the author considers it feature-complete
5+
# and functionally stable. gdbstub will be update once they migrate
6+
# to an alternative solution.
7+
# See https://github.com/daniel5151/gdbstub/issues/168
8+
"RUSTSEC-2024-0436",
9+
10+
# `rand` unsoundness when a custom logger re-enters `rand::rng()`/`thread_rng()`
11+
# during ThreadRng reseeding. Firecracker is not affected:
12+
# - uuid (1.23.0): does not enable `fast-rng` or `rng-rand` features, so it uses
13+
# `getrandom` directly and never calls into rand.
14+
# - proptest: uses rand 0.9 with `default-features = false` and does not enable
15+
# the `thread_rng` feature, so the affected functions are not compiled in.
16+
# See https://rustsec.org/advisories/RUSTSEC-2026-0097.html
17+
"RUSTSEC-2026-0097",
18+
]

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ and this project adheres to
1414
support for Vsock Unix domain socket path overriding on snapshot restore. More
1515
information can be found in the
1616
[docs](docs/vsock.md/#unix-domain-socket-renaming).
17+
- [#5824](https://github.com/firecracker-microvm/firecracker/pull/5824): Add
18+
optional rate limiting to serial console output, configurable via the
19+
`rate_limiter` field on `PUT /serial`. A new metric is exposed under `uart`:
20+
`rate_limiter_dropped_bytes`.
21+
- [#5799](https://github.com/firecracker-microvm/firecracker/pull/5799): Add
22+
per-callsite rate limiting for error, warn, and info level log messages. Each
23+
callsite independently allows up to 10 messages per 5-second window. When
24+
logging resumes after suppression, a warn-level summary reports the count of
25+
suppressed messages. A new `rate_limited_log_count` metric tracks the total
26+
number of suppressed messages.
1727

1828
### Changed
1929

docs/device-api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ BadRequest - HTTP response.
3232
| `vsock` | O | O | O | O | O | O | O | O | O |
3333
| `entropy` | O | O | O | O | O | O | **R** | O | O |
3434
| `pmem/{id}` | O | O | O | O | O | O | O | **R** | O |
35+
| `serial` | O | **R** | O | O | O | O | O | O | O |
3536

3637
## Input Schema
3738

@@ -106,6 +107,8 @@ specification:
106107
| | path_on_host | O | O | O | O | O | O | O | **R** | O |
107108
| | root_device | O | O | O | O | O | O | O | **R** | O |
108109
| | read_only | O | O | O | O | O | O | O | **R** | O |
110+
| `SerialConfig` | serial_out_path | O | O | O | O | O | O | O | O | O |
111+
| | rate_limiter | O | O | O | O | O | O | O | O | O |
109112
| `MemoryHotplugConfig` | total_size_mib | O | O | O | O | O | O | O | O | **R** |
110113
| | slot_size_mib | O | O | O | O | O | O | O | O | **R** |
111114
| | block_size_mi | O | O | O | O | O | O | O | O | **R** |
@@ -115,7 +118,7 @@ specification:
115118
either virtio-block or vhost-user-block devices.
116119

117120
\*\* The `TokenBucket` can be configured with any combination of virtio-net,
118-
virtio-block and virtio-rng devices.
121+
virtio-block, virtio-rng and serial devices.
119122

120123
## Output Schema
121124

docs/prod-host-setup.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ recommended.
2727

2828
Firecracker implements the 8250 serial device, which is visible from the guest
2929
side and is tied to the Firecracker/non-daemonized jailer process stdout.
30-
Without proper handling, because the guest has access to the serial device, this
31-
can lead to unbound memory or storage usage on the host side. Firecracker does
32-
not offer users the option to limit serial data transfer, nor does it impose any
33-
restrictions on stdout handling. Users are responsible for handling the memory
34-
and storage usage of the Firecracker process stdout. We suggest using any
35-
upper-bounded forms of storage, such as fixed-size or ring buffers, using
36-
programs like `journald` or `logrotate`, or redirecting to `/dev/null` or a
37-
named pipe. Furthermore, we do not recommend that users enable the serial device
38-
in production. To disable it in the guest kernel, use the `8250.nr_uarts=0` boot
39-
argument when configuring the boot source. Please be aware that the device can
40-
be reactivated from within the guest even if it was disabled at boot.
30+
Without proper handling, because the guest has access to the serial device. This
31+
can lead to unbound memory or storage usage on the host side. Users are
32+
responsible for handling the memory and storage usage of the Firecracker process
33+
stdout. We recommend using the rate limiter for the serial data transfer that
34+
Firecracker offers or any upper-bounded forms of storage, such as fixed-size or
35+
ring buffers, using programs like `journald` or `logrotate`, or redirecting to
36+
`/dev/null` or a named pipe. Furthermore, we do not recommend that users enable
37+
the serial device in production. To disable it in the guest kernel, use the
38+
`8250.nr_uarts=0` boot argument when configuring the boot source. Please be
39+
aware that the device can be reactivated from within the guest even if it was
40+
disabled at boot.
4141

4242
If Firecracker's `stdout` buffer is non-blocking and full (assuming it has a
4343
bounded size), any subsequent writes will fail, resulting in data loss, until

src/firecracker/src/api_server/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use parsed_request::{ParsedRequest, RequestAction};
1717
use serde_json::json;
1818
use utils::time::{ClockType, get_time_us};
1919
use vmm::logger::{
20-
METRICS, ProcessTimeReporter, debug, error, info, update_metric_with_elapsed_time, warn,
20+
METRICS, ProcessTimeReporter, debug, error_unrestricted, info_unrestricted,
21+
update_metric_with_elapsed_time, warn_unrestricted,
2122
};
2223
use vmm::rpc_interface::{ApiRequest, ApiResponse, VmmAction};
2324
use vmm::seccomp::BpfProgramRef;
@@ -81,7 +82,7 @@ impl ApiServer {
8182
}
8283

8384
server.start_server().expect("Cannot start HTTP server");
84-
info!("API server started.");
85+
info_unrestricted!("API server started.");
8586

8687
// Store process start time metric.
8788
process_time_reporter.report_start_time();
@@ -98,7 +99,7 @@ impl ApiServer {
9899
}
99100
Err(err) => {
100101
// print request error, but keep server running
101-
error!("API Server error on retrieving incoming request: {}", err);
102+
error_unrestricted!("API Server error on retrieving incoming request: {}", err);
102103
continue;
103104
}
104105
};
@@ -108,7 +109,7 @@ impl ApiServer {
108109
let response = server_request
109110
.process(|request| self.handle_request(request, request_processing_start_us));
110111
if let Err(err) = server.respond(response) {
111-
error!("API Server encountered an error on response: {}", err);
112+
error_unrestricted!("API Server encountered an error on response: {}", err);
112113
};
113114

114115
let delta_us = get_time_us(ClockType::Monotonic) - request_processing_start_us;
@@ -131,13 +132,13 @@ impl ApiServer {
131132
}
132133
};
133134
if let Some(message) = parsing_info.take_deprecation_message() {
134-
warn!("{}", message);
135+
warn_unrestricted!("{}", message);
135136
response.set_deprecation();
136137
}
137138
response
138139
}
139140
Err(err) => {
140-
error!("{:?}", err);
141+
error_unrestricted!("{:?}", err);
141142
err.into()
142143
}
143144
}
@@ -179,7 +180,7 @@ impl ApiServer {
179180
{
180181
let elapsed_time_us =
181182
update_metric_with_elapsed_time(metric, request_processing_start_us);
182-
info!("'{}' API request took {} us.", action, elapsed_time_us);
183+
info_unrestricted!("'{}' API request took {} us.", action, elapsed_time_us);
183184
}
184185
response
185186
}

src/firecracker/src/api_server/parsed_request.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::fmt::Debug;
66
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
77
use serde::ser::Serialize;
88
use serde_json::Value;
9-
use vmm::logger::{Level, error, info, log_enabled};
9+
use vmm::logger::{Level, error_unrestricted, info_unrestricted, log_enabled};
1010
use vmm::rpc_interface::{VmmAction, VmmActionError, VmmData};
1111

1212
use super::ApiServer;
@@ -71,7 +71,7 @@ impl TryFrom<&Request> for ParsedRequest {
7171
request_uri.as_str(),
7272
request.body.as_ref(),
7373
);
74-
info!("The API server received a {description}.");
74+
info_unrestricted!("The API server received a {description}.");
7575

7676
// Split request uri by '/' by doing:
7777
// 1. Trim starting '/' characters
@@ -153,14 +153,14 @@ impl ParsedRequest {
153153
where
154154
T: ?Sized + Serialize + Debug,
155155
{
156-
info!("The request was executed successfully. Status code: 200 OK.");
156+
info_unrestricted!("The request was executed successfully. Status code: 200 OK.");
157157
let mut response = Response::new(Version::Http11, StatusCode::OK);
158158
response.set_body(Body::new(serde_json::to_string(body_data).unwrap()));
159159
response
160160
}
161161

162162
pub(crate) fn success_response_with_mmds_value(body_data: &Value) -> Response {
163-
info!("The request was executed successfully. Status code: 200 OK.");
163+
info_unrestricted!("The request was executed successfully. Status code: 200 OK.");
164164
let mut response = Response::new(Version::Http11, StatusCode::OK);
165165
let body_str = match body_data {
166166
Value::Null => "{}".to_string(),
@@ -176,7 +176,9 @@ impl ParsedRequest {
176176
match request_outcome {
177177
Ok(vmm_data) => match vmm_data {
178178
VmmData::Empty => {
179-
info!("The request was executed successfully. Status code: 204 No Content.");
179+
info_unrestricted!(
180+
"The request was executed successfully. Status code: 204 No Content."
181+
);
180182
Response::new(Version::Http11, StatusCode::NoContent)
181183
}
182184
VmmData::MachineConfiguration(machine_config) => {
@@ -200,14 +202,14 @@ impl ParsedRequest {
200202
Err(vmm_action_error) => {
201203
let mut response = match vmm_action_error {
202204
VmmActionError::MmdsLimitExceeded(_err) => {
203-
error!(
205+
error_unrestricted!(
204206
"Received Error. Status code: 413 Payload too large. Message: {}",
205207
vmm_action_error
206208
);
207209
Response::new(Version::Http11, StatusCode::PayloadTooLarge)
208210
}
209211
_ => {
210-
error!(
212+
error_unrestricted!(
211213
"Received Error. Status code: 400 Bad Request. Message: {}",
212214
vmm_action_error
213215
);

src/firecracker/src/api_server/request/serial.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub(crate) fn parse_put_serial(body: &Body) -> Result<ParsedRequest, RequestErro
2121
mod tests {
2222
use std::path::PathBuf;
2323

24+
use vmm::vmm_config::TokenBucketConfig;
25+
2426
use super::*;
2527
use crate::api_server::parsed_request::tests::vmm_action_from_request;
2628

@@ -30,6 +32,28 @@ mod tests {
3032

3133
let expected_config = SerialConfig {
3234
serial_out_path: Some(PathBuf::from("serial")),
35+
rate_limiter: None,
36+
};
37+
assert_eq!(
38+
vmm_action_from_request(parse_put_serial(&Body::new(body)).unwrap()),
39+
VmmAction::ConfigureSerial(expected_config)
40+
);
41+
}
42+
43+
#[test]
44+
fn test_parse_put_serial_with_rate_limiter() {
45+
let body = r#"{
46+
"serial_out_path": "serial",
47+
"rate_limiter": {"size": 1024, "one_time_burst": 65536, "refill_time": 1000}
48+
}"#;
49+
50+
let expected_config = SerialConfig {
51+
serial_out_path: Some(PathBuf::from("serial")),
52+
rate_limiter: Some(TokenBucketConfig {
53+
size: 1024,
54+
one_time_burst: Some(65536),
55+
refill_time: 1000,
56+
}),
3357
};
3458
assert_eq!(
3559
vmm_action_from_request(parse_put_serial(&Body::new(body)).unwrap()),

src/firecracker/src/api_server_adapter.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex};
88
use std::thread;
99

1010
use event_manager::{EventOps, Events, MutEventSubscriber, SubscriberOps};
11-
use vmm::logger::{ProcessTimeReporter, error, info, warn};
11+
use vmm::logger::{ProcessTimeReporter, error_unrestricted, info_unrestricted, warn_unrestricted};
1212
use vmm::rpc_interface::{
1313
ApiRequest, ApiResponse, BuildMicrovmFromRequestsError, PrebootApiController,
1414
RuntimeApiController, VmmAction,
@@ -115,20 +115,20 @@ impl MutEventSubscriber for ApiServerAdapter {
115115
}
116116
}
117117
Err(TryRecvError::Empty) => {
118-
warn!("Got a spurious notification from api thread");
118+
warn_unrestricted!("Got a spurious notification from api thread");
119119
}
120120
Err(TryRecvError::Disconnected) => {
121121
panic!("The channel's sending half was disconnected. Cannot receive data.");
122122
}
123123
};
124124
} else {
125-
error!("Spurious EventManager event for handler: ApiServerAdapter");
125+
error_unrestricted!("Spurious EventManager event for handler: ApiServerAdapter");
126126
}
127127
}
128128

129129
fn init(&mut self, ops: &mut EventOps) {
130130
if let Err(err) = ops.add(Events::new(&self.api_event_fd, EventSet::IN)) {
131-
error!("Failed to register activate event: {}", err);
131+
error_unrestricted!("Failed to register activate event: {}", err);
132132
}
133133
}
134134
}
@@ -174,7 +174,7 @@ pub(crate) fn run_with_api(
174174
return Err(ApiServerError::FailedToBindAndRunHttpServer(err));
175175
}
176176
};
177-
info!("Listening on API socket ({bind_path:?}).");
177+
info_unrestricted!("Listening on API socket ({bind_path:?}).");
178178

179179
let api_kill_switch_clone = api_kill_switch
180180
.try_clone()

src/firecracker/src/main.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ use utils::validators::validate_instance_id;
2828
use vmm::arch::host_page_size;
2929
use vmm::builder::StartMicrovmError;
3030
#[cfg(feature = "fuzzing")]
31-
use vmm::logger::warn;
31+
use vmm::logger::warn_unrestricted;
3232
use vmm::logger::{
33-
LOGGER, LoggerConfig, METRICS, ProcessTimeReporter, StoreMetric, debug, error, info,
33+
LOGGER, LoggerConfig, METRICS, ProcessTimeReporter, StoreMetric, debug, error_unrestricted,
34+
info_unrestricted,
3435
};
3536
use vmm::persist::SNAPSHOT_VERSION;
3637
use vmm::resources::VmResources;
@@ -106,13 +107,13 @@ impl From<MainError> for FcExitCode {
106107
fn main() -> ExitCode {
107108
let result = main_exec();
108109
if let Err(err) = result {
109-
error!("{err}");
110+
error_unrestricted!("{err}");
110111
eprintln!("Error: {err:?}");
111112
let exit_code = FcExitCode::from(err) as u8;
112-
error!("Firecracker exiting with error. exit_code={exit_code}");
113+
error_unrestricted!("Firecracker exiting with error. exit_code={exit_code}");
113114
ExitCode::from(exit_code)
114115
} else {
115-
info!("Firecracker exiting successfully. exit_code=0");
116+
info_unrestricted!("Firecracker exiting successfully. exit_code=0");
116117
ExitCode::SUCCESS
117118
}
118119
}
@@ -135,9 +136,9 @@ fn main_exec() -> Result<(), MainError> {
135136
// We're currently using the closure parameter, which is a &PanicInfo, for printing the
136137
// origin of the panic, including the payload passed to panic! and the source code location
137138
// from which the panic originated.
138-
error!("Firecracker {}", info);
139+
error_unrestricted!("Firecracker {}", info);
139140
if let Err(err) = stdin.lock().set_canon_mode() {
140-
error!(
141+
error_unrestricted!(
141142
"Failure while trying to reset stdin to canonical mode: {}",
142143
err
143144
);
@@ -147,7 +148,7 @@ fn main_exec() -> Result<(), MainError> {
147148

148149
// Write the metrics before aborting.
149150
if let Err(err) = METRICS.write() {
150-
error!("Failed to write metrics while panicking: {}", err);
151+
error_unrestricted!("Failed to write metrics while panicking: {}", err);
151152
}
152153
}));
153154

@@ -329,10 +330,10 @@ fn main_exec() -> Result<(), MainError> {
329330
module,
330331
})
331332
.map_err(MainError::LoggerInitialization)?;
332-
info!("Running Firecracker v{FIRECRACKER_VERSION}");
333+
info_unrestricted!("Running Firecracker v{FIRECRACKER_VERSION}");
333334

334335
#[cfg(feature = "fuzzing")]
335-
warn!(
336+
warn_unrestricted!(
336337
"This Firecracker binary was built with the `fuzzing` feature enabled. This disables \
337338
security-critical randomness and relaxes error handling. DO NOT use in production."
338339
);
@@ -537,12 +538,12 @@ pub fn enable_ssbd_mitigation() {
537538

538539
if ret < 0 {
539540
let last_error = std::io::Error::last_os_error().raw_os_error().unwrap();
540-
error!(
541+
error_unrestricted!(
541542
"Could not enable SSBD mitigation through prctl, error {}",
542543
last_error
543544
);
544545
if last_error == libc::EINVAL {
545-
error!("The host does not support SSBD mitigation through prctl.");
546+
error_unrestricted!("The host does not support SSBD mitigation through prctl.");
546547
}
547548
}
548549
}
@@ -604,7 +605,7 @@ fn build_microvm_from_json(
604605
)
605606
.map_err(BuildFromJsonError::StartMicroVM)?;
606607

607-
info!("Successfully started microvm that was configured from one single json");
608+
info_unrestricted!("Successfully started microvm that was configured from one single json");
608609

609610
Ok(vmm)
610611
}

0 commit comments

Comments
 (0)