Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/route/next_hops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl<T: AsRef<[u8]>> RouteNextHopBuffer<T> {
return Err(format!(
"invalid RouteNextHopBuffer: length {} < {}",
len,
8 + self.length()
self.length(),
)
.into());
}
Expand Down
14 changes: 13 additions & 1 deletion src/route/tests/route_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use netlink_packet_utils::traits::{Emitable, Parseable};
use crate::route::flags::RouteFlags;
use crate::route::{
RouteAttribute, RouteHeader, RouteMessage, RouteMessageBuffer,
RouteProtocol, RouteScope, RouteType,
RouteNextHopBuffer, RouteProtocol, RouteScope, RouteType,
};
use crate::AddressFamily;

Expand Down Expand Up @@ -54,3 +54,15 @@ fn test_ipv6_add_route_onlink() {

assert_eq!(buf, raw);
}

// Verify that [`RouteNextHopBuffer`] rejects the buffer when provided with
// an invalid length.
#[test]
fn test_next_hop_max_buffer_len() {
// Route next-hop buffer layout:
// |byte0|byte1|byte2|byte3|byte4|byte5|byte6|byte7|bytes8+|
// |-----|-----|-----|-----|-----|-----|-----|-----|-------|
// | length |flags|hops | Interface Index |Payload|
let buffer = [0xff, 0xff, 0, 0, 0, 0, 0, 0];
assert!(RouteNextHopBuffer::new_checked(buffer).is_err());
}
31 changes: 30 additions & 1 deletion src/tc/filters/cls_u32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub struct TcU32Selector {
pub keys: Vec<TcU32Key>,
}

buffer!(TcU32SelectorBuffer(TC_U32_SEL_BUF_LEN) {
buffer!(TcU32SelectorBuffer {
flags: (u8, 0),
offshift: (u8, 1),
nkeys: (u8, 2),
Expand All @@ -190,6 +190,35 @@ buffer!(TcU32SelectorBuffer(TC_U32_SEL_BUF_LEN) {
keys: (slice, TC_U32_SEL_BUF_LEN..),
});

impl<T: AsRef<[u8]>> TcU32SelectorBuffer<T> {
pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
let packet = Self::new(buffer);
packet.check_buffer_length()?;
Ok(packet)
}

fn check_buffer_length(&self) -> Result<(), DecodeError> {
let len = self.buffer.as_ref().len();
if len < TC_U32_SEL_BUF_LEN {
return Err(format!(
"invalid TcU32SelectorBuffer: length {len} < {TC_U32_SEL_BUF_LEN}"
)
.into());
}
// Expect the buffer to be large enough to hold `nkeys`.
let expected_len =
((self.nkeys() as usize) * TC_U32_KEY_BUF_LEN) + TC_U32_SEL_BUF_LEN;
if len < expected_len {
return Err(format!(
"invalid RouteNextHopBuffer: length {} < {}",
len, expected_len,
)
.into());
}
Ok(())
}
}

impl Emitable for TcU32Selector {
fn buffer_len(&self) -> usize {
TC_U32_SEL_BUF_LEN + (self.nkeys as usize * TC_U32_KEY_BUF_LEN)
Expand Down
1 change: 1 addition & 0 deletions src/tc/filters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod u32_flags;

pub use self::cls_u32::{
TcFilterU32, TcFilterU32Option, TcU32Key, TcU32Selector,
TcU32SelectorBuffer,
};
pub use self::matchall::{TcFilterMatchAll, TcFilterMatchAllOption};
pub use u32_flags::{TcU32OptionFlags, TcU32SelectorFlags};
3 changes: 2 additions & 1 deletion src/tc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub use self::actions::{
pub use self::attribute::TcAttribute;
pub use self::filters::{
TcFilterMatchAll, TcFilterMatchAllOption, TcFilterU32, TcFilterU32Option,
TcU32Key, TcU32OptionFlags, TcU32Selector, TcU32SelectorFlags,
TcU32Key, TcU32OptionFlags, TcU32Selector, TcU32SelectorBuffer,
TcU32SelectorFlags,
};
pub use self::header::{TcHandle, TcHeader, TcMessageBuffer};
pub use self::message::TcMessage;
Expand Down
21 changes: 21 additions & 0 deletions src/tc/tests/filter_u32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
filters::{TcU32OptionFlags, TcU32SelectorFlags},
TcAttribute, TcFilterU32Option, TcHandle, TcHeader, TcMessage,
TcMessageBuffer, TcOption, TcU32Key, TcU32Selector,
TcU32SelectorBuffer,
},
AddressFamily,
};
Expand Down Expand Up @@ -112,3 +113,23 @@ fn test_get_filter_u32() {

assert_eq!(buf, raw);
}

// Verify that [`TcU32Selector`] fails to parse a buffer with an
// invalid number of keys.
#[test]
fn test_tcu32_selector_invalid_nkeys() {
// TC u32 selector buffer layout:
// |byte0|byte1|byte2|byte3|byte4|byte5|byte6|byte7|
// |-----|-----|-----|-----|-----|-----|-----|-----|
// |flags|shift|nkeys|pad | offmask | off |
// |-----|-----|-----|-----|-----|-----|-----|-----|
// | offoff | hoff | hmask |
// |-----|-----|-----|-----|-----|-----|-----|-----|
// | keys |
// | ... |
let buffer = [
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
assert!(TcU32SelectorBuffer::new_checked(buffer).is_err());
}