summaryrefslogtreecommitdiff
path: root/src/phy/fuzz_injector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/phy/fuzz_injector.rs')
-rw-r--r--src/phy/fuzz_injector.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/phy/fuzz_injector.rs b/src/phy/fuzz_injector.rs
new file mode 100644
index 0000000..6769d8e
--- /dev/null
+++ b/src/phy/fuzz_injector.rs
@@ -0,0 +1,129 @@
+use crate::phy::{self, Device, DeviceCapabilities};
+use crate::time::Instant;
+
+// This could be fixed once associated consts are stable.
+const MTU: usize = 1536;
+
+/// Represents a fuzzer. It is expected to replace bytes in the packet with fuzzed data.
+pub trait Fuzzer {
+ /// Modify a single packet with fuzzed data.
+ fn fuzz_packet(&self, packet_data: &mut [u8]);
+}
+
+/// A fuzz injector device.
+///
+/// A fuzz injector is a device that alters packets traversing through it according to the
+/// directions of a guided fuzzer. It is designed to support fuzzing internal state machines inside
+/// smoltcp, and is not for production use.
+#[allow(unused)]
+#[derive(Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct FuzzInjector<D: Device, FTx: Fuzzer, FRx: Fuzzer> {
+ inner: D,
+ fuzz_tx: FTx,
+ fuzz_rx: FRx,
+}
+
+#[allow(unused)]
+impl<D: Device, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx> {
+ /// Create a fuzz injector device.
+ pub fn new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector<D, FTx, FRx> {
+ FuzzInjector {
+ inner,
+ fuzz_tx,
+ fuzz_rx,
+ }
+ }
+
+ /// Return the underlying device, consuming the fuzz injector.
+ pub fn into_inner(self) -> D {
+ self.inner
+ }
+}
+
+impl<D: Device, FTx, FRx> Device for FuzzInjector<D, FTx, FRx>
+where
+ FTx: Fuzzer,
+ FRx: Fuzzer,
+{
+ type RxToken<'a> = RxToken<'a, D::RxToken<'a>, FRx>
+ where
+ Self: 'a;
+ type TxToken<'a> = TxToken<'a, D::TxToken<'a>, FTx>
+ where
+ Self: 'a;
+
+ fn capabilities(&self) -> DeviceCapabilities {
+ let mut caps = self.inner.capabilities();
+ if caps.max_transmission_unit > MTU {
+ caps.max_transmission_unit = MTU;
+ }
+ caps
+ }
+
+ fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
+ self.inner.receive(timestamp).map(|(rx_token, tx_token)| {
+ let rx = RxToken {
+ fuzzer: &mut self.fuzz_rx,
+ token: rx_token,
+ };
+ let tx = TxToken {
+ fuzzer: &mut self.fuzz_tx,
+ token: tx_token,
+ };
+ (rx, tx)
+ })
+ }
+
+ fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> {
+ self.inner.transmit(timestamp).map(|token| TxToken {
+ fuzzer: &mut self.fuzz_tx,
+ token: token,
+ })
+ }
+}
+
+#[doc(hidden)]
+pub struct RxToken<'a, Rx: phy::RxToken, F: Fuzzer + 'a> {
+ fuzzer: &'a F,
+ token: Rx,
+}
+
+impl<'a, Rx: phy::RxToken, FRx: Fuzzer> phy::RxToken for RxToken<'a, Rx, FRx> {
+ fn consume<R, F>(self, f: F) -> R
+ where
+ F: FnOnce(&mut [u8]) -> R,
+ {
+ self.token.consume(|buffer| {
+ self.fuzzer.fuzz_packet(buffer);
+ f(buffer)
+ })
+ }
+
+ fn meta(&self) -> phy::PacketMeta {
+ self.token.meta()
+ }
+}
+
+#[doc(hidden)]
+pub struct TxToken<'a, Tx: phy::TxToken, F: Fuzzer + 'a> {
+ fuzzer: &'a F,
+ token: Tx,
+}
+
+impl<'a, Tx: phy::TxToken, FTx: Fuzzer> phy::TxToken for TxToken<'a, Tx, FTx> {
+ fn consume<R, F>(self, len: usize, f: F) -> R
+ where
+ F: FnOnce(&mut [u8]) -> R,
+ {
+ self.token.consume(len, |buf| {
+ let result = f(buf);
+ self.fuzzer.fuzz_packet(buf);
+ result
+ })
+ }
+
+ fn set_meta(&mut self, meta: phy::PacketMeta) {
+ self.token.set_meta(meta)
+ }
+}