mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-08-04 23:28:01 +00:00
test: extract fuzzing oracles into another crate
This commit is contained in:
parent
60bc72f873
commit
04924757cb
12 changed files with 168 additions and 105 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
|
15
crates/ironrdp-fuzzing/Cargo.toml
Normal file
15
crates/ironrdp-fuzzing/Cargo.toml
Normal 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
|
16
crates/ironrdp-fuzzing/src/generators/mod.rs
Normal file
16
crates/ironrdp-fuzzing/src/generators/mod.rs
Normal 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,
|
||||
}
|
5
crates/ironrdp-fuzzing/src/lib.rs
Normal file
5
crates/ironrdp-fuzzing/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#[macro_use]
|
||||
extern crate arbitrary;
|
||||
|
||||
pub mod generators;
|
||||
pub mod oracles;
|
98
crates/ironrdp-fuzzing/src/oracles/mod.rs
Normal file
98
crates/ironrdp-fuzzing/src/oracles/mod.rs
Normal 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,
|
||||
);
|
||||
}
|
|
@ -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
9
fuzz/Cargo.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue