mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 08:22:33 +00:00
104 lines
3.4 KiB
Rust
104 lines
3.4 KiB
Rust
#![no_main]
|
|
use libfuzzer_sys::fuzz_target;
|
|
use pumpkin_protocol::bedrock::packet_decoder::BedrockBatchDecoder;
|
|
use pumpkin_protocol::bedrock::server::{
|
|
SAnimate, SBlockPickRequest, SClientCacheBlobStatus, SClientCacheStatus, SCommandRequest,
|
|
SContainerClose, SEmote, SEmoteList, SInteraction, SInventoryTransaction, SItemStackRequest,
|
|
SLoadingScreen, SLogin, SMobEquipment, SModalFormResponse, SPacketViolationWarning,
|
|
SPlayerAction, SPlayerAuthInput, SPlayerHotbar, SRequestAbility, SRequestChunkRadius,
|
|
SRequestNetworkSettings, SResourcePackResponse, SRespawn, SSetLocalPlayerAsInitialized,
|
|
SSetPlayerInventoryOptions, SText,
|
|
};
|
|
use pumpkin_protocol::serial::{PacketRead, PacketReadSlice};
|
|
use std::io::Cursor;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helper: Run every Serverbound packet's read method.
|
|
// ---------------------------------------------------------------------------
|
|
fn fuzz_serverbound_packets(payload: &[u8]) {
|
|
let mut cursor = Cursor::new(payload);
|
|
|
|
macro_rules! run_read {
|
|
($($packet:ty),* $(,)?) => {
|
|
$(
|
|
cursor.set_position(0);
|
|
let _ = <$packet>::read(&mut cursor);
|
|
)*
|
|
};
|
|
}
|
|
|
|
macro_rules! run_read_slice {
|
|
($($packet:ty),* $(,)?) => {
|
|
$(
|
|
let mut slice = payload;
|
|
let _ = <$packet>::read_slice(&mut slice);
|
|
)*
|
|
};
|
|
}
|
|
|
|
// Standard Bedrock Serverbound Packets (PacketRead)
|
|
run_read!(
|
|
SAnimate,
|
|
SBlockPickRequest,
|
|
SClientCacheBlobStatus,
|
|
SClientCacheStatus,
|
|
SCommandRequest,
|
|
SContainerClose,
|
|
SEmote,
|
|
SEmoteList,
|
|
SInteraction,
|
|
SInventoryTransaction,
|
|
SItemStackRequest,
|
|
SLoadingScreen,
|
|
SLogin,
|
|
SMobEquipment,
|
|
SModalFormResponse,
|
|
SPacketViolationWarning,
|
|
SPlayerAction,
|
|
SPlayerAuthInput,
|
|
SPlayerHotbar,
|
|
SRequestAbility,
|
|
SRequestChunkRadius,
|
|
SRequestNetworkSettings,
|
|
SResourcePackResponse,
|
|
SRespawn,
|
|
SSetLocalPlayerAsInitialized,
|
|
SSetPlayerInventoryOptions,
|
|
SText,
|
|
);
|
|
|
|
// Bedrock Serverbound Packets supporting zero-copy PacketReadSlice
|
|
run_read_slice!(SCommandRequest, SEmote, SModalFormResponse, SText,);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Fuzz Target
|
|
// ---------------------------------------------------------------------------
|
|
fuzz_target!(|data: &[u8]| {
|
|
if data.len() < 2 {
|
|
return;
|
|
}
|
|
|
|
// Split data for decoder configuration vs raw payload
|
|
let threshold_raw = data[0];
|
|
let stream_data = &data[1..];
|
|
|
|
let mut decoder = BedrockBatchDecoder::new();
|
|
|
|
// Setup Decoder
|
|
if threshold_raw > 0 {
|
|
// Assuming your CompressionThreshold is a wrapper around u32
|
|
decoder.set_compression((threshold_raw as u32).try_into().unwrap());
|
|
}
|
|
// 1. Fuzz the Decoder (Framing/VarInts/Bitmasks)
|
|
let mut decoder_cursor = Cursor::new(stream_data.to_vec());
|
|
if let Ok(raw_packet) = decoder.get_game_packet(&mut decoder_cursor) {
|
|
// If framed correctly, fuzz the internal payload
|
|
fuzz_serverbound_packets(&raw_packet.payload);
|
|
}
|
|
|
|
// 2. Shotgun Fuzz
|
|
// Pass raw data directly to all readers to catch panics in the parsers
|
|
fuzz_serverbound_packets(stream_data);
|
|
});
|