Skip to content

Commit ba0ab03

Browse files
authored
Add bounds checking for apob_read (#2484)
This PR adds bounds checking when obtaining space for the requested APOB read buffer. Previously, this was not explicitly checked, and could lead to a panic (and restart) of the `host-sp-comms` task. This PR also fixes `ringbuf` logging for `host-sp-comms`, which could sometimes report a success to the ring buffer when in fact the action errored out.
1 parent 6b98f9f commit ba0ab03

4 files changed

Lines changed: 59 additions & 33 deletions

File tree

app/cosmo/base.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ features = ["stm32h753", "usart6", "baud_rate_3M", "hardware_flow_control", "vla
258258
uses = ["usart6", "dbgmcu"]
259259
interrupts = {"usart6.irq" = "usart-irq"}
260260
priority = 9
261-
max-sizes = {flash = 70000, ram = 65536}
261+
max-sizes = {flash = 74000, ram = 65536}
262262
stacksize = 5400
263263
start = true
264264
task-slots = ["sys", { cpu_seq = "cosmo_seq" }, "hf", "control_plane_agent", "net", "packrat", "i2c_driver", { spi_driver = "spi2_driver" }, "sprot", "auxflash"]

app/gimlet/base.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ features = ["stm32h753", "uart7", "baud_rate_3M", "hardware_flow_control", "vlan
243243
uses = ["uart7", "dbgmcu"]
244244
interrupts = {"uart7.irq" = "usart-irq"}
245245
priority = 8
246-
max-sizes = {flash = 70000, ram = 65536}
246+
max-sizes = {flash = 72000, ram = 65536}
247247
stacksize = 5376
248248
start = true
249249
task-slots = ["sys", { cpu_seq = "gimlet_seq" }, "hf", "control_plane_agent", "net", "packrat", "i2c_driver", { spi_driver = "spi2_driver" }, "sprot"]

task/host-sp-comms/src/main.rs

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,10 @@ impl ServerImpl {
12691269
fn apob_read(&mut self, sequence: u64, offset: u64, size: u64) {
12701270
use drv_hf_api::ApobReadError;
12711271
use host_sp_messages::ApobReadResult;
1272+
1273+
// NOTE: This ONLY checks we are not out of bounds for `usize`,
1274+
// we will check if the requested size can be honored later in
1275+
// the `fill` closure.
12721276
let Ok(size) = usize::try_from(size) else {
12731277
self.tx_buf.encode_response(
12741278
sequence,
@@ -1285,33 +1289,37 @@ impl ServerImpl {
12851289
);
12861290
return;
12871291
};
1292+
1293+
// closure for performing the actual apob read
1294+
let fill = |buf: &mut [u8]| {
1295+
// Did the user pass in a reasonable size?
1296+
let Some(rbuf) = buf.get_mut(..size) else {
1297+
return Err(SpToHost::ApobRead(ApobReadResult::InvalidSize));
1298+
};
1299+
1300+
// If successful: return the number of bytes read
1301+
let err = match self.hf.apob_read(offset, rbuf) {
1302+
Ok(n) => return Ok(n),
1303+
Err(e) => e,
1304+
};
1305+
1306+
// Something went wrong, ringbuf the error, and convert
1307+
// the error types
1308+
ringbuf_entry!(Trace::ApobReadError { offset, err });
1309+
let read_err = match err {
1310+
ApobReadError::NotImplemented => ApobReadResult::NotImplemented,
1311+
ApobReadError::InvalidState => ApobReadResult::InvalidState,
1312+
ApobReadError::NoValidApob => ApobReadResult::NoValidApob,
1313+
ApobReadError::InvalidOffset => ApobReadResult::InvalidOffset,
1314+
ApobReadError::InvalidSize => ApobReadResult::InvalidSize,
1315+
ApobReadError::ReadFailed => ApobReadResult::ReadFailed,
1316+
};
1317+
Err(SpToHost::ApobRead(read_err))
1318+
};
12881319
self.tx_buf.try_encode_response(
12891320
sequence,
12901321
&SpToHost::ApobRead(ApobReadResult::Ok),
1291-
|buf| match self.hf.apob_read(offset, &mut buf[..size]) {
1292-
Ok(n) => Ok(n),
1293-
Err(err) => {
1294-
ringbuf_entry!(Trace::ApobReadError { offset, err });
1295-
Err(SpToHost::ApobRead(match err {
1296-
ApobReadError::NotImplemented => {
1297-
ApobReadResult::NotImplemented
1298-
}
1299-
ApobReadError::InvalidState => {
1300-
ApobReadResult::InvalidState
1301-
}
1302-
ApobReadError::NoValidApob => {
1303-
ApobReadResult::NoValidApob
1304-
}
1305-
ApobReadError::InvalidOffset => {
1306-
ApobReadResult::InvalidOffset
1307-
}
1308-
ApobReadError::InvalidSize => {
1309-
ApobReadResult::InvalidSize
1310-
}
1311-
ApobReadError::ReadFailed => ApobReadResult::ReadFailed,
1312-
}))
1313-
}
1314-
},
1322+
fill,
13151323
);
13161324
}
13171325

task/host-sp-comms/src/tx_buf.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,17 +271,35 @@ impl TxBuf {
271271
sequence: sequence | SEQ_REPLY,
272272
};
273273

274-
ringbuf_entry!(Trace::Response {
275-
now: sys_get_timer().now,
276-
sequence: header.sequence,
277-
message: *response
278-
});
274+
// The caller's closure *may* change what the actual response is! The
275+
// passed in `response` is only valid if `try_serialize` returns `Ok`,
276+
// otherwise the new error type is returned. This closure intercepts the
277+
// caller's closure, and logs *after* that closure has run, so we can
278+
// accurately log what the response was.
279+
let outer_fill_data = |buf: &mut [u8]| {
280+
let res = fill_data(buf);
281+
let msg = match &res {
282+
Ok(_n) => *response,
283+
Err(e) => *e,
284+
};
285+
ringbuf_entry!(Trace::Response {
286+
now: sys_get_timer().now,
287+
sequence: header.sequence,
288+
message: msg
289+
});
290+
res
291+
};
279292

280293
// Serializing can only fail if we pass unexpected types as `response`,
281294
// but we're using `SpToHost` for both the response and error, so it
282295
// cannot fail.
283-
host_sp_messages::try_serialize(self.msg, &header, response, fill_data)
284-
.unwrap_lite()
296+
host_sp_messages::try_serialize(
297+
self.msg,
298+
&header,
299+
response,
300+
outer_fill_data,
301+
)
302+
.unwrap_lite()
285303
}
286304

287305
// Encodes `self.msg[..msg_len]` with corncobs.

0 commit comments

Comments
 (0)