Skip to content

Commit ff230c9

Browse files
Merge branch 'main' into ipvlan_flag
2 parents 286741c + c49e3ac commit ff230c9

File tree

11 files changed

+193
-60
lines changed

11 files changed

+193
-60
lines changed

src/link/af_spec/unspec.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,22 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
5656
nlas.push(match nla.kind() {
5757
k if k == u8::from(AddressFamily::Inet) as u16 => {
5858
AfSpecUnspec::Inet(
59-
VecAfSpecInet::parse(&NlaBuffer::new(&nla.value()))
60-
.context(err)?
61-
.0,
59+
VecAfSpecInet::parse(
60+
&NlaBuffer::new_checked(&nla.value())
61+
.context(err)?,
62+
)
63+
.context(err)?
64+
.0,
6265
)
6366
}
6467
k if k == u8::from(AddressFamily::Inet6) as u16 => {
6568
AfSpecUnspec::Inet6(
66-
VecAfSpecInet6::parse(&NlaBuffer::new(&nla.value()))
67-
.context(err)?
68-
.0,
69+
VecAfSpecInet6::parse(
70+
&NlaBuffer::new_checked(&nla.value())
71+
.context(err)?,
72+
)
73+
.context(err)?
74+
.0,
6975
)
7076
}
7177
kind => AfSpecUnspec::Other(DefaultNla::parse(&nla).context(

src/link/attribute.rs

Lines changed: 97 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -373,20 +373,41 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
373373
) -> Result<Self, DecodeError> {
374374
let payload = buf.value();
375375
Ok(match buf.kind() {
376-
IFLA_VFINFO_LIST => Self::VfInfoList(
377-
VecLinkVfInfo::parse(&NlaBuffer::new(payload))
378-
.context(format!("invalid IFLA_VFINFO_LIST {payload:?}"))?
376+
IFLA_VFINFO_LIST => {
377+
let err =
378+
|payload| format!("invalid IFLA_VFINFO_LIST {payload:?}");
379+
Self::VfInfoList(
380+
VecLinkVfInfo::parse(
381+
&NlaBuffer::new_checked(payload)
382+
.context(err(payload))?,
383+
)
384+
.context(err(payload))?
379385
.0,
380-
),
381-
IFLA_VF_PORTS => Self::VfPorts(
382-
VecLinkVfPort::parse(&NlaBuffer::new(payload))
383-
.context(format!("invalid IFLA_VF_PORTS {payload:?}"))?
386+
)
387+
}
388+
IFLA_VF_PORTS => {
389+
let err =
390+
|payload| format!("invalid IFLA_VF_PORTS {payload:?}");
391+
Self::VfPorts(
392+
VecLinkVfPort::parse(
393+
&NlaBuffer::new_checked(payload)
394+
.context(err(payload))?,
395+
)
396+
.context(err(payload))?
384397
.0,
385-
),
386-
IFLA_PORT_SELF => Self::PortSelf(
387-
LinkVfPort::parse(&NlaBuffer::new(payload))
388-
.context(format!("invalid IFLA_PORT_SELF {payload:?}"))?,
389-
),
398+
)
399+
}
400+
IFLA_PORT_SELF => {
401+
let err =
402+
|payload| format!("invalid IFLA_PORT_SELF {payload:?}");
403+
Self::PortSelf(
404+
LinkVfPort::parse(
405+
&NlaBuffer::new_checked(payload)
406+
.context(err(payload))?,
407+
)
408+
.context(err(payload))?,
409+
)
410+
}
390411
IFLA_PHYS_PORT_ID => {
391412
Self::PhysPortId(LinkPhysId::parse(payload).context(
392413
format!("invalid IFLA_PHYS_PORT_ID value {payload:?}"),
@@ -401,29 +422,37 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
401422
LinkWirelessEvent::parse(payload)
402423
.context(format!("invalid IFLA_WIRELESS {payload:?}"))?,
403424
),
404-
IFLA_PROTINFO => match interface_family {
405-
AddressFamily::Inet6 => Self::ProtoInfoInet6(
406-
VecLinkProtoInfoInet6::parse(&NlaBuffer::new(payload))
407-
.context(format!(
408-
"invalid IFLA_PROTINFO for AF_INET6 {payload:?}"
409-
))?
425+
IFLA_PROTINFO => {
426+
let err = |payload| {
427+
format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}")
428+
};
429+
match interface_family {
430+
AddressFamily::Inet6 => Self::ProtoInfoInet6(
431+
VecLinkProtoInfoInet6::parse(
432+
&NlaBuffer::new_checked(payload)
433+
.context(err(payload))?,
434+
)
435+
.context(err(payload))?
410436
.0,
411-
),
412-
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
413-
AddressFamily::Bridge => Self::ProtoInfoBridge(
414-
VecLinkProtoInfoBridge::parse(&NlaBuffer::new(payload))
437+
),
438+
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
439+
AddressFamily::Bridge => Self::ProtoInfoBridge(
440+
VecLinkProtoInfoBridge::parse(&NlaBuffer::new_checked(
441+
payload,
442+
)?)
415443
.context(format!(
416444
"invalid IFLA_PROTINFO for AF_INET6 {payload:?}"
417445
))?
418446
.0,
419-
),
420-
_ => Self::ProtoInfoUnknown(DefaultNla::parse(buf).context(
421-
format!(
422-
"invalid IFLA_PROTINFO for \
447+
),
448+
_ => Self::ProtoInfoUnknown(
449+
DefaultNla::parse(buf).context(format!(
450+
"invalid IFLA_PROTINFO for \
423451
{interface_family:?}: {payload:?}"
452+
))?,
424453
),
425-
)?),
426-
},
454+
}
455+
}
427456
IFLA_EVENT => Self::Event(
428457
LinkEvent::parse(payload)
429458
.context(format!("invalid IFLA_EVENT {payload:?}"))?,
@@ -565,10 +594,17 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
565594
.context("invalid IFLA_OPERSTATE value")?
566595
.into(),
567596
),
568-
IFLA_MAP => Self::Map(
569-
super::Map::parse(&MapBuffer::new(payload))
570-
.context(format!("Invalid IFLA_MAP value {:?}", payload))?,
571-
),
597+
IFLA_MAP => {
598+
let err =
599+
|payload| format!("Invalid IFLA_MAP value {:?}", payload);
600+
Self::Map(
601+
super::Map::parse(
602+
&MapBuffer::new_checked(payload)
603+
.context(err(payload))?,
604+
)
605+
.context(err(payload))?,
606+
)
607+
}
572608
IFLA_STATS => Self::Stats(
573609
super::Stats::parse(&StatsBuffer::new(
574610
expand_buffer_if_small(
@@ -597,24 +633,41 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
597633
)
598634
}
599635
IFLA_AF_SPEC => match interface_family {
600-
AddressFamily::Unspec => Self::AfSpecUnspec(
601-
VecAfSpecUnspec::parse(&NlaBuffer::new(&buf.value()))
602-
.context("invalid IFLA_AF_SPEC value for AF_UNSPEC")?
636+
AddressFamily::Unspec => {
637+
let err = "invalid IFLA_AF_SPEC value for AF_UNSPEC";
638+
Self::AfSpecUnspec(
639+
VecAfSpecUnspec::parse(
640+
&NlaBuffer::new_checked(&buf.value())
641+
.context(err)?,
642+
)
643+
.context(err)?
603644
.0,
604-
),
645+
)
646+
}
605647
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
606-
AddressFamily::Bridge => Self::AfSpecBridge(
607-
VecAfSpecBridge::parse(&NlaBuffer::new(&buf.value()))
608-
.context("invalid IFLA_AF_SPEC value for AF_BRIDGE")?
648+
AddressFamily::Bridge => {
649+
let err = "invalid IFLA_AF_SPEC value for AF_BRIDGE";
650+
Self::AfSpecBridge(
651+
VecAfSpecBridge::parse(
652+
&NlaBuffer::new_checked(&buf.value())
653+
.context(err)?,
654+
)
655+
.context(err)?
609656
.0,
610-
),
657+
)
658+
}
611659
_ => Self::AfSpecUnknown(payload.to_vec()),
612660
},
613-
IFLA_LINKINFO => Self::LinkInfo(
614-
VecLinkInfo::parse(&NlaBuffer::new(&buf.value()))
615-
.context("invalid IFLA_LINKINFO value")?
661+
IFLA_LINKINFO => {
662+
let err = "invalid IFLA_LINKINFO value";
663+
Self::LinkInfo(
664+
VecLinkInfo::parse(
665+
&NlaBuffer::new_checked(&buf.value()).context(err)?,
666+
)
667+
.context(err)?
616668
.0,
617-
),
669+
)
670+
}
618671
IFLA_XDP => {
619672
let err = "invalid IFLA_XDP value";
620673
let buf = NlaBuffer::new_checked(payload).context(err)?;

src/link/sriov/vf_list.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
3131
buf.value()
3232
))?;
3333
if nla.kind() == IFLA_VF_INFO {
34-
nlas.push(LinkVfInfo::parse(&NlaBuffer::new(nla.value()))?);
34+
nlas.push(LinkVfInfo::parse(&NlaBuffer::new_checked(
35+
nla.value(),
36+
)?)?);
3537
} else {
3638
log::warn!(
3739
"BUG: Expecting IFLA_VF_INFO in IFLA_VFINFO_LIST, \

src/link/sriov/vf_port.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
2020
buf.value()
2121
))?;
2222
if nla.kind() == IFLA_VF_PORT {
23-
nlas.push(LinkVfPort::parse(&NlaBuffer::new(nla.value()))?);
23+
nlas.push(LinkVfPort::parse(&NlaBuffer::new_checked(
24+
nla.value(),
25+
)?)?);
2426
} else {
2527
log::warn!(
2628
"BUG: Expecting IFLA_VF_PORT in IFLA_VF_PORTS, \

src/neighbour_table/attribute.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,17 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
110110
)
111111
.context(format!("invalid NDTA_STATS {payload:?}"))?,
112112
),
113-
NDTA_PARMS => Self::Parms(
114-
VecNeighbourTableParameter::parse(&NlaBuffer::new(payload))
115-
.context(format!("invalid NDTA_PARMS {payload:?}"))?
113+
NDTA_PARMS => {
114+
let err = |payload| format!("invalid NDTA_PARMS {payload:?}");
115+
Self::Parms(
116+
VecNeighbourTableParameter::parse(
117+
&NlaBuffer::new_checked(payload)
118+
.context(err(payload))?,
119+
)
120+
.context(err(payload))?
116121
.0,
117-
),
122+
)
123+
}
118124
NDTA_GC_INTERVAL => Self::GcInterval(
119125
parse_u64(payload).context("invalid NDTA_GC_INTERVAL value")?,
120126
),

src/route/next_hops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl<T: AsRef<[u8]>> RouteNextHopBuffer<T> {
6363
return Err(format!(
6464
"invalid RouteNextHopBuffer: length {} < {}",
6565
len,
66-
8 + self.length()
66+
self.length(),
6767
)
6868
.into());
6969
}

src/route/tests/route_flags.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use netlink_packet_utils::traits::{Emitable, Parseable};
88
use crate::route::flags::RouteFlags;
99
use crate::route::{
1010
RouteAttribute, RouteHeader, RouteMessage, RouteMessageBuffer,
11-
RouteProtocol, RouteScope, RouteType,
11+
RouteNextHopBuffer, RouteProtocol, RouteScope, RouteType,
1212
};
1313
use crate::AddressFamily;
1414

@@ -54,3 +54,15 @@ fn test_ipv6_add_route_onlink() {
5454

5555
assert_eq!(buf, raw);
5656
}
57+
58+
// Verify that [`RouteNextHopBuffer`] rejects the buffer when provided with
59+
// an invalid length.
60+
#[test]
61+
fn test_next_hop_max_buffer_len() {
62+
// Route next-hop buffer layout:
63+
// |byte0|byte1|byte2|byte3|byte4|byte5|byte6|byte7|bytes8+|
64+
// |-----|-----|-----|-----|-----|-----|-----|-----|-------|
65+
// | length |flags|hops | Interface Index |Payload|
66+
let buffer = [0xff, 0xff, 0, 0, 0, 0, 0, 0];
67+
assert!(RouteNextHopBuffer::new_checked(buffer).is_err());
68+
}

src/tc/filters/cls_u32.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ pub struct TcU32Selector {
177177
pub keys: Vec<TcU32Key>,
178178
}
179179

180-
buffer!(TcU32SelectorBuffer(TC_U32_SEL_BUF_LEN) {
180+
buffer!(TcU32SelectorBuffer {
181181
flags: (u8, 0),
182182
offshift: (u8, 1),
183183
nkeys: (u8, 2),
@@ -190,6 +190,35 @@ buffer!(TcU32SelectorBuffer(TC_U32_SEL_BUF_LEN) {
190190
keys: (slice, TC_U32_SEL_BUF_LEN..),
191191
});
192192

193+
impl<T: AsRef<[u8]>> TcU32SelectorBuffer<T> {
194+
pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
195+
let packet = Self::new(buffer);
196+
packet.check_buffer_length()?;
197+
Ok(packet)
198+
}
199+
200+
fn check_buffer_length(&self) -> Result<(), DecodeError> {
201+
let len = self.buffer.as_ref().len();
202+
if len < TC_U32_SEL_BUF_LEN {
203+
return Err(format!(
204+
"invalid TcU32SelectorBuffer: length {len} < {TC_U32_SEL_BUF_LEN}"
205+
)
206+
.into());
207+
}
208+
// Expect the buffer to be large enough to hold `nkeys`.
209+
let expected_len =
210+
((self.nkeys() as usize) * TC_U32_KEY_BUF_LEN) + TC_U32_SEL_BUF_LEN;
211+
if len < expected_len {
212+
return Err(format!(
213+
"invalid RouteNextHopBuffer: length {} < {}",
214+
len, expected_len,
215+
)
216+
.into());
217+
}
218+
Ok(())
219+
}
220+
}
221+
193222
impl Emitable for TcU32Selector {
194223
fn buffer_len(&self) -> usize {
195224
TC_U32_SEL_BUF_LEN + (self.nkeys as usize * TC_U32_KEY_BUF_LEN)

src/tc/filters/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod u32_flags;
66

77
pub use self::cls_u32::{
88
TcFilterU32, TcFilterU32Option, TcU32Key, TcU32Selector,
9+
TcU32SelectorBuffer,
910
};
1011
pub use self::matchall::{TcFilterMatchAll, TcFilterMatchAllOption};
1112
pub use u32_flags::{TcU32OptionFlags, TcU32SelectorFlags};

src/tc/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ pub use self::actions::{
2020
pub use self::attribute::TcAttribute;
2121
pub use self::filters::{
2222
TcFilterMatchAll, TcFilterMatchAllOption, TcFilterU32, TcFilterU32Option,
23-
TcU32Key, TcU32OptionFlags, TcU32Selector, TcU32SelectorFlags,
23+
TcU32Key, TcU32OptionFlags, TcU32Selector, TcU32SelectorBuffer,
24+
TcU32SelectorFlags,
2425
};
2526
pub use self::header::{TcHandle, TcHeader, TcMessageBuffer};
2627
pub use self::message::TcMessage;

src/tc/tests/filter_u32.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
filters::{TcU32OptionFlags, TcU32SelectorFlags},
1010
TcAttribute, TcFilterU32Option, TcHandle, TcHeader, TcMessage,
1111
TcMessageBuffer, TcOption, TcU32Key, TcU32Selector,
12+
TcU32SelectorBuffer,
1213
},
1314
AddressFamily,
1415
};
@@ -112,3 +113,23 @@ fn test_get_filter_u32() {
112113

113114
assert_eq!(buf, raw);
114115
}
116+
117+
// Verify that [`TcU32Selector`] fails to parse a buffer with an
118+
// invalid number of keys.
119+
#[test]
120+
fn test_tcu32_selector_invalid_nkeys() {
121+
// TC u32 selector buffer layout:
122+
// |byte0|byte1|byte2|byte3|byte4|byte5|byte6|byte7|
123+
// |-----|-----|-----|-----|-----|-----|-----|-----|
124+
// |flags|shift|nkeys|pad | offmask | off |
125+
// |-----|-----|-----|-----|-----|-----|-----|-----|
126+
// | offoff | hoff | hmask |
127+
// |-----|-----|-----|-----|-----|-----|-----|-----|
128+
// | keys |
129+
// | ... |
130+
let buffer = [
131+
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132+
0x00, 0x00, 0x00, 0x00,
133+
];
134+
assert!(TcU32SelectorBuffer::new_checked(buffer).is_err());
135+
}

0 commit comments

Comments
 (0)