Skip to content

Commit 2cdf7b7

Browse files
authored
Handle overflow reading near the end of a transceiver page (#258)
- Promote u8s to u16s for math when computing the bounds of a large memory access, to fix overflow and reads right at the end of a page. - Fixes #235
1 parent 44a949c commit 2cdf7b7

1 file changed

Lines changed: 97 additions & 4 deletions

File tree

dpd/src/transceivers/tofino_impl.rs

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,15 +3589,29 @@ where
35893589
offset: u8,
35903590
len: u8,
35913591
) -> Result<Vec<Self>, ControllerError> {
3592-
let end = offset + len;
3592+
let offset = u16::from(offset);
3593+
let len = u16::from(len);
3594+
let end = offset.checked_add(len).expect("offset and len are u8s");
35933595
(offset..end)
35943596
.step_by(usize::from(Self::SIZE))
35953597
.map(|new_offset| {
3598+
// The addition used to find the bounds of this range is done
3599+
// with u16s, so the new offset could be larger than a u8. Check
3600+
// that it fits first. If not, we've stepped past the end of the
3601+
// valid range. Use u8::MAX here, and let the call to
3602+
// build_one() fail with the right error type.
3603+
let offset = new_offset.try_into().unwrap_or(u8::MAX);
3604+
35963605
// The length is up to SIZE, or the remainder of the entire
35973606
// operation, whichever is smaller.
3598-
let remainder = end - new_offset;
3599-
let new_len = Self::SIZE.min(remainder);
3600-
Self::build_one(page, new_offset, new_len)
3607+
let remainder =
3608+
end.checked_sub(new_offset).expect("new_offset <= end");
3609+
let new_len = u16::from(Self::SIZE)
3610+
.min(remainder)
3611+
.try_into()
3612+
.expect("min of SIZE and rem must be a u8");
3613+
3614+
Self::build_one(page, offset, new_len)
36013615
})
36023616
.collect()
36033617
}
@@ -3664,6 +3678,7 @@ mod tests {
36643678
use transceiver_controller::Identifier;
36653679
use transceiver_controller::IdentifierResult;
36663680
use transceiver_controller::ReadResult;
3681+
use transceiver_controller::TransceiverError;
36673682

36683683
fn logger() -> Logger {
36693684
let decorator =
@@ -5049,4 +5064,82 @@ mod tests {
50495064
};
50505065
assert_eq!(data, expected_data);
50515066
}
5067+
5068+
#[test]
5069+
fn handle_large_op_at_the_end_of_lower_page() {
5070+
let offset = 112;
5071+
let len = 16;
5072+
let page = mgmt::cmis::Page::Lower;
5073+
let read_args = mgmt::MemoryRead::build_many(page, offset, len).expect(
5074+
"Should handle offset / len reads to the end of the lower page",
5075+
);
5076+
assert_eq!(read_args.len(), 2);
5077+
assert!(read_args.iter().all(|rd| rd.len() == len / 2));
5078+
}
5079+
5080+
#[test]
5081+
fn handle_large_op_at_the_end_of_upper_page() {
5082+
let offset = 240;
5083+
let len = 16;
5084+
let page = mgmt::cmis::Page::Upper(
5085+
mgmt::cmis::UpperPage::new_unbanked(0).unwrap(),
5086+
);
5087+
let read_args = mgmt::MemoryRead::build_many(page, offset, len).expect(
5088+
"Should handle offset / len reads to the end of the upper page",
5089+
);
5090+
assert_eq!(read_args.len(), 2);
5091+
assert!(read_args.iter().all(|rd| rd.len() == len / 2));
5092+
}
5093+
5094+
#[test]
5095+
fn fail_if_large_op_reads_past_the_end_of_the_lower_page() {
5096+
let offset = 112;
5097+
let len = 18;
5098+
let page = mgmt::cmis::Page::Lower;
5099+
let err = mgmt::MemoryRead::build_many(page, offset, len)
5100+
.expect_err("Should fail rather than panicking");
5101+
assert!(matches!(
5102+
err,
5103+
ControllerError::Transceiver(TransceiverError::Mgmt(
5104+
mgmt::Error::InvalidMemoryAccess { .. }
5105+
))
5106+
));
5107+
5108+
let len = u8::MAX;
5109+
let err = mgmt::MemoryRead::build_many(page, offset, len)
5110+
.expect_err("Should fail rather than panicking");
5111+
assert!(matches!(
5112+
err,
5113+
ControllerError::Transceiver(TransceiverError::Mgmt(
5114+
mgmt::Error::InvalidMemoryAccess { .. }
5115+
))
5116+
));
5117+
}
5118+
5119+
#[test]
5120+
fn fail_if_large_op_reads_past_the_end_of_the_upper_page() {
5121+
let offset = 240;
5122+
let len = 19;
5123+
let page = mgmt::cmis::Page::Upper(
5124+
mgmt::cmis::UpperPage::new_unbanked(0).unwrap(),
5125+
);
5126+
let err = mgmt::MemoryRead::build_many(page, offset, len)
5127+
.expect_err("Should fail rather than panicking");
5128+
assert!(matches!(
5129+
err,
5130+
ControllerError::Transceiver(TransceiverError::Mgmt(
5131+
mgmt::Error::InvalidMemoryAccess { .. }
5132+
))
5133+
));
5134+
5135+
let len = u8::MAX;
5136+
let err = mgmt::MemoryRead::build_many(page, offset, len)
5137+
.expect_err("Should fail rather than panicking");
5138+
assert!(matches!(
5139+
err,
5140+
ControllerError::Transceiver(TransceiverError::Mgmt(
5141+
mgmt::Error::InvalidMemoryAccess { .. }
5142+
))
5143+
));
5144+
}
50525145
}

0 commit comments

Comments
 (0)