test: extract fuzzing oracles into another crate

This commit is contained in:
Benoît CORTIER 2023-05-10 20:19:07 -04:00 committed by Benoît Cortier
parent 60bc72f873
commit 04924757cb
12 changed files with 168 additions and 105 deletions

11
Cargo.lock generated
View file

@ -1560,6 +1560,15 @@ dependencies = [
"ironrdp-async",
]
[[package]]
name = "ironrdp-fuzzing"
version = "0.0.0"
dependencies = [
"arbitrary",
"ironrdp-graphics",
"ironrdp-pdu",
]
[[package]]
name = "ironrdp-graphics"
version = "0.1.0"
@ -1649,10 +1658,10 @@ name = "ironrdp-testsuite-core"
version = "0.0.0"
dependencies = [
"anyhow",
"arbitrary",
"array-concat",
"hex",
"ironrdp-connector",
"ironrdp-fuzzing",
"ironrdp-graphics",
"ironrdp-input",
"ironrdp-pdu",

View file

@ -25,6 +25,7 @@ expect-test = "1"
ironrdp-async = { version = "0.1", path = "crates/ironrdp-async" }
ironrdp-connector = { version = "0.1", path = "crates/ironrdp-connector" }
ironrdp-futures = { version = "0.1", path = "crates/ironrdp-futures" }
ironrdp-fuzzing = { path = "crates/ironrdp-fuzzing" }
ironrdp-graphics = { version = "0.1", path = "crates/ironrdp-graphics" }
ironrdp-input = { version = "0.1", path = "crates/ironrdp-input" }
ironrdp-pdu-generators = { path = "crates/ironrdp-pdu-generators" }

View file

@ -0,0 +1,15 @@
[package]
name = "ironrdp-fuzzing"
version = "0.0.0"
edition = "2021"
description = "Provides test case generators and oracles for use with IronRDP fuzzing"
publish = false
[lib]
doctest = false
test = false
[dependencies]
arbitrary = { version = "1", features = ["derive"] }
ironrdp-graphics.workspace = true
ironrdp-pdu.workspace = true

View file

@ -0,0 +1,16 @@
//! Test case generators.
//!
//! Test case generators take raw, unstructured input from a fuzzer
//! (e.g. libFuzzer) and translate that into a structured test case (e.g. a
//! valid RDP PDU).
//!
//! These are generally implementations of the `Arbitrary` trait, or some
//! wrapper over an external tool, such that the wrapper implements the
//! `Arbitrary` trait for the wrapped external tool.
#[derive(Arbitrary, Debug)]
pub struct BitmapInput<'a> {
pub src: &'a [u8],
pub width: u8,
pub height: u8,
}

View file

@ -0,0 +1,5 @@
#[macro_use]
extern crate arbitrary;
pub mod generators;
pub mod oracles;

View file

@ -0,0 +1,98 @@
//! Oracles.
//!
//! Oracles take a test case and determine whether we have a bug. For example,
//! one of the simplest oracles is to take a RDP PDU as our input test case,
//! encode and decode it, and (implicitly) check that no assertions
//! failed or segfaults happened. A more complicated oracle might compare the
//! result of two different implementations for the same thing, and
//! make sure that the two executions are observably identical (differential fuzzing).
//!
//! When an oracle finds a bug, it should report it to the fuzzing engine by
//! panicking.
use crate::generators::BitmapInput;
pub fn pdu_decode(data: &[u8]) {
use ironrdp_pdu::mcs::*;
use ironrdp_pdu::nego::*;
use ironrdp_pdu::rdp::*;
use ironrdp_pdu::*;
let _ = decode::<ConnectionRequest>(data);
let _ = decode::<ConnectionConfirm>(data);
let _ = decode::<McsMessage>(data);
let _ = ConnectInitial::from_buffer(data);
let _ = ConnectResponse::from_buffer(data);
let _ = ClientInfoPdu::from_buffer(data);
let _ = capability_sets::CapabilitySet::from_buffer(data);
let _ = headers::ShareControlHeader::from_buffer(data);
let _ = decode::<pcb::PreconnectionBlob>(data);
let _ = server_error_info::ServerSetErrorInfoPdu::from_buffer(data);
let _ = gcc::ClientGccBlocks::from_buffer(data);
let _ = gcc::ServerGccBlocks::from_buffer(data);
let _ = gcc::ClientClusterData::from_buffer(data);
let _ = gcc::ConferenceCreateRequest::from_buffer(data);
let _ = gcc::ConferenceCreateResponse::from_buffer(data);
let _ = server_license::ClientNewLicenseRequest::from_buffer(data);
let _ = server_license::ClientPlatformChallengeResponse::from_buffer(data);
let _ = server_license::InitialServerLicenseMessage::from_buffer(data);
let _ = server_license::ServerLicenseRequest::from_buffer(data);
let _ = server_license::InitialServerLicenseMessage::from_buffer(data);
let _ = server_license::ServerPlatformChallenge::from_buffer(data);
let _ = vc::ChannelPduHeader::from_buffer(data);
let _ = fast_path::FastPathHeader::from_buffer(data);
let _ = fast_path::FastPathUpdatePdu::from_buffer(data);
let _ = fast_path::FastPathUpdate::from_buffer_with_code(data, fast_path::UpdateCode::SurfaceCommands);
let _ = surface_commands::SurfaceCommand::from_buffer(data);
let _ = surface_commands::SurfaceBitsPdu::from_buffer(data);
let _ = surface_commands::FrameMarkerPdu::from_buffer(data);
let _ = surface_commands::ExtendedBitmapDataPdu::from_buffer(data);
let _ = surface_commands::BitmapDataHeader::from_buffer(data);
let _ = codecs::rfx::Headers::from_buffer(data);
let _ = codecs::rfx::FrameAcknowledgePdu::from_buffer(data);
let _ = codecs::rfx::ContextPdu::from_buffer(data);
let _ = codecs::rfx::FrameBeginPdu::from_buffer(data);
let _ = codecs::rfx::FrameEndPdu::from_buffer(data);
let _ = codecs::rfx::RegionPdu::from_buffer(data);
let _ = codecs::rfx::TileSetPdu::from_buffer(data);
let _ = codecs::rfx::RfxRectangle::from_buffer(data);
let _ = codecs::rfx::Quant::from_buffer(data);
let _ = codecs::rfx::Tile::from_buffer(data);
let _ = codecs::rfx::SyncPdu::from_buffer(data);
let _ = codecs::rfx::CodecVersionsPdu::from_buffer(data);
let _ = codecs::rfx::ChannelsPdu::from_buffer(data);
let _ = codecs::rfx::Channel::from_buffer(data);
let _ = input::InputEventPdu::from_buffer(data);
let _ = input::InputEvent::from_buffer(data);
let _ = decode::<bitmap::rdp6::BitmapStream>(data);
}
pub fn rle_decompress_bitmap(input: BitmapInput) {
let mut out = Vec::new();
let _ = ironrdp_graphics::rle::decompress_24_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_16_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_15_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_8_bpp(input.src, &mut out, input.width, input.height);
}
pub fn rdp6_decode_bitmap_stream_to_rgb24(input: BitmapInput) {
use ironrdp_graphics::rdp6::BitmapStreamDecoder;
let mut out = Vec::new();
let _ = BitmapStreamDecoder::default().decode_bitmap_stream_to_rgb24(
input.src,
&mut out,
input.width as usize,
input.height as usize,
);
}

View file

@ -2,7 +2,7 @@
name = "ironrdp-testsuite-core"
version = "0.0.0"
edition = "2021"
description = "IronRDP test suite."
description = "IronRDP test suite"
publish = false
autotests = false
@ -16,22 +16,21 @@ path = "tests/main.rs"
harness = true
[dependencies]
ironrdp-pdu.workspace = true
ironrdp-graphics.workspace = true
arbitrary = { version = "1", features = ["derive"] }
anyhow = "1"
array-concat = "0.5.2"
ironrdp-pdu.workspace = true
lazy_static = "1.4.0"
paste = "1"
[dev-dependencies]
hex = "0.4.3"
ironrdp-connector.workspace = true
ironrdp-session.workspace = true
ironrdp-fuzzing.workspace = true
ironrdp-graphics.workspace = true
ironrdp-input.workspace = true
ironrdp-rdcleanpath.workspace = true
proptest.workspace = true
rstest.workspace = true
hex = "0.4.3"
ironrdp-session.workspace = true
pretty_assertions = "1.3.0"
proptest.workspace = true
rdp-rs = { git = "https://github.com/citronneur/rdp-rs", rev = "7ac880d7efb7f05efef3c84476f7c24f4053e0ea" }
rstest.workspace = true

9
fuzz/Cargo.lock generated
View file

@ -234,11 +234,18 @@ dependencies = [
[[package]]
name = "ironrdp-fuzz"
version = "0.0.0"
dependencies = [
"ironrdp-fuzzing",
"libfuzzer-sys",
]
[[package]]
name = "ironrdp-fuzzing"
version = "0.0.0"
dependencies = [
"arbitrary",
"ironrdp-graphics",
"ironrdp-pdu",
"libfuzzer-sys",
]
[[package]]

View file

@ -1,8 +1,8 @@
[package]
name = "ironrdp-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
publish = false
[package.metadata]
cargo-fuzz = true
@ -14,10 +14,8 @@ members = ["."]
debug = 1
[dependencies]
ironrdp-pdu = { path = "../crates/ironrdp-pdu" }
ironrdp-graphics = { path = "../crates/ironrdp-graphics" }
ironrdp-fuzzing = { path = "../crates/ironrdp-fuzzing" }
libfuzzer-sys = "0.4"
arbitrary = { version = "1", features = ["derive"] }
[[bin]]
name = "pdu_decoding"

View file

@ -1,22 +1,7 @@
#![no_main]
use ironrdp_graphics::rdp6::BitmapStreamDecoder;
use libfuzzer_sys::fuzz_target;
#[derive(arbitrary::Arbitrary, Debug)]
struct Input<'a> {
src: &'a [u8],
width: u8,
height: u8,
}
fuzz_target!(|input: Input<'_>| {
let mut out = Vec::new();
let _ = BitmapStreamDecoder::default().decode_bitmap_stream_to_rgb24(
input.src,
&mut out,
input.width as usize,
input.height as usize,
);
fuzz_target!(|input: ironrdp_fuzzing::generators::BitmapInput<'_>| {
ironrdp_fuzzing::oracles::rdp6_decode_bitmap_stream_to_rgb24(input);
});

View file

@ -1,65 +1,7 @@
#![no_main]
use ironrdp_pdu::mcs::*;
use ironrdp_pdu::nego::*;
use ironrdp_pdu::rdp::*;
use ironrdp_pdu::*;
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
let _ = decode::<ConnectionRequest>(data);
let _ = decode::<ConnectionConfirm>(data);
let _ = decode::<McsMessage>(data);
let _ = ConnectInitial::from_buffer(data);
let _ = ConnectResponse::from_buffer(data);
let _ = ClientInfoPdu::from_buffer(data);
let _ = capability_sets::CapabilitySet::from_buffer(data);
let _ = headers::ShareControlHeader::from_buffer(data);
let _ = decode::<pcb::PreconnectionBlob>(data);
let _ = server_error_info::ServerSetErrorInfoPdu::from_buffer(data);
let _ = gcc::ClientGccBlocks::from_buffer(data);
let _ = gcc::ServerGccBlocks::from_buffer(data);
let _ = gcc::ClientClusterData::from_buffer(data);
let _ = gcc::ConferenceCreateRequest::from_buffer(data);
let _ = gcc::ConferenceCreateResponse::from_buffer(data);
let _ = server_license::ClientNewLicenseRequest::from_buffer(data);
let _ = server_license::ClientPlatformChallengeResponse::from_buffer(data);
let _ = server_license::InitialServerLicenseMessage::from_buffer(data);
let _ = server_license::ServerLicenseRequest::from_buffer(data);
let _ = server_license::InitialServerLicenseMessage::from_buffer(data);
let _ = server_license::ServerPlatformChallenge::from_buffer(data);
let _ = vc::ChannelPduHeader::from_buffer(data);
let _ = fast_path::FastPathHeader::from_buffer(data);
let _ = fast_path::FastPathUpdatePdu::from_buffer(data);
let _ = fast_path::FastPathUpdate::from_buffer_with_code(data, fast_path::UpdateCode::SurfaceCommands);
let _ = surface_commands::SurfaceCommand::from_buffer(data);
let _ = surface_commands::SurfaceBitsPdu::from_buffer(data);
let _ = surface_commands::FrameMarkerPdu::from_buffer(data);
let _ = surface_commands::ExtendedBitmapDataPdu::from_buffer(data);
let _ = surface_commands::BitmapDataHeader::from_buffer(data);
let _ = codecs::rfx::Headers::from_buffer(data);
let _ = codecs::rfx::FrameAcknowledgePdu::from_buffer(data);
let _ = codecs::rfx::ContextPdu::from_buffer(data);
let _ = codecs::rfx::FrameBeginPdu::from_buffer(data);
let _ = codecs::rfx::FrameEndPdu::from_buffer(data);
let _ = codecs::rfx::RegionPdu::from_buffer(data);
let _ = codecs::rfx::TileSetPdu::from_buffer(data);
let _ = codecs::rfx::RfxRectangle::from_buffer(data);
let _ = codecs::rfx::Quant::from_buffer(data);
let _ = codecs::rfx::Tile::from_buffer(data);
let _ = codecs::rfx::SyncPdu::from_buffer(data);
let _ = codecs::rfx::CodecVersionsPdu::from_buffer(data);
let _ = codecs::rfx::ChannelsPdu::from_buffer(data);
let _ = codecs::rfx::Channel::from_buffer(data);
let _ = input::InputEventPdu::from_buffer(data);
let _ = input::InputEvent::from_buffer(data);
let _ = decode::<bitmap::rdp6::BitmapStream>(data);
ironrdp_fuzzing::oracles::pdu_decode(data);
});

View file

@ -2,18 +2,6 @@
use libfuzzer_sys::fuzz_target;
#[derive(arbitrary::Arbitrary, Debug)]
struct Input<'a> {
src: &'a [u8],
width: u8,
height: u8,
}
fuzz_target!(|input: Input<'_>| {
let mut out = Vec::new();
let _ = ironrdp_graphics::rle::decompress_24_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_16_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_15_bpp(input.src, &mut out, input.width, input.height);
let _ = ironrdp_graphics::rle::decompress_8_bpp(input.src, &mut out, input.width, input.height);
fuzz_target!(|input: ironrdp_fuzzing::generators::BitmapInput<'_>| {
ironrdp_fuzzing::oracles::rle_decompress_bitmap(input);
});