aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock24
-rw-r--r--Cargo.toml1
-rw-r--r--azalea-chat/src/component.rs3
-rw-r--r--azalea-protocol/Cargo.toml2
-rw-r--r--azalea-protocol/fuzz/.gitignore4
-rw-r--r--azalea-protocol/fuzz/Cargo.toml75
-rw-r--r--azalea-protocol/fuzz/README.md10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/clientbound_config.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/clientbound_game.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/clientbound_handshake.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/clientbound_login.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/clientbound_status.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/serverbound_config.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/serverbound_game.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/serverbound_handshake.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/serverbound_login.rs10
-rw-r--r--azalea-protocol/fuzz/fuzz_targets/serverbound_status.rs10
-rw-r--r--azalea-protocol/src/common/tags.rs4
-rw-r--r--azalea-protocol/src/read.rs33
-rw-r--r--azalea-registry/src/lib.rs2
20 files changed, 254 insertions, 4 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ee97e7bf..f6bb7b2e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -115,6 +115,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -456,6 +462,14 @@ dependencies = [
]
[[package]]
+name = "azalea-fuzz"
+version = "0.0.0"
+dependencies = [
+ "azalea-protocol",
+ "libfuzzer-sys",
+]
+
+[[package]]
name = "azalea-inventory"
version = "0.15.0+mc1.21.11"
dependencies = [
@@ -2163,6 +2177,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
+name = "libfuzzer-sys"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
+
+[[package]]
name = "libm"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 523a5c7a..824bac90 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ members = [
"azalea-language",
"azalea-physics",
"azalea-protocol",
+ "azalea-protocol/fuzz",
"azalea-registry",
"azalea-world",
]
diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs
index 637aafc7..c64ee559 100644
--- a/azalea-chat/src/component.rs
+++ b/azalea-chat/src/component.rs
@@ -408,6 +408,9 @@ impl<'de> Deserialize<'de> for FormattedText {
));
}
let json_array = json.as_array().unwrap();
+ if json_array.is_empty() {
+ return Ok(FormattedText::default());
+ }
// the first item in the array is the one that we're gonna return, the others
// are siblings
let mut component =
diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml
index 59991274..c7b0fd57 100644
--- a/azalea-protocol/Cargo.toml
+++ b/azalea-protocol/Cargo.toml
@@ -43,7 +43,7 @@ indexmap.workspace = true
reqwest = { workspace = true, optional = true, features = ["socks"] }
[features]
-default = ["online-mode"]
+default = ["online-mode", "connecting"]
connecting = []
online-mode = ["azalea-auth/online-mode", "dep:reqwest"]
bevy_ecs = ["dep:bevy_ecs", "azalea-entity/bevy_ecs", "azalea-core/bevy_ecs"]
diff --git a/azalea-protocol/fuzz/.gitignore b/azalea-protocol/fuzz/.gitignore
new file mode 100644
index 00000000..1a45eee7
--- /dev/null
+++ b/azalea-protocol/fuzz/.gitignore
@@ -0,0 +1,4 @@
+target
+corpus
+artifacts
+coverage
diff --git a/azalea-protocol/fuzz/Cargo.toml b/azalea-protocol/fuzz/Cargo.toml
new file mode 100644
index 00000000..37e4e606
--- /dev/null
+++ b/azalea-protocol/fuzz/Cargo.toml
@@ -0,0 +1,75 @@
+[package]
+name = "azalea-fuzz"
+version = "0.0.0"
+publish = false
+edition = "2024"
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+libfuzzer-sys = "0.4"
+azalea-protocol = { path = "..", default-features = false }
+
+[[bin]]
+name = "clientbound_config"
+path = "fuzz_targets/clientbound_config.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "clientbound_game"
+path = "fuzz_targets/clientbound_game.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "clientbound_handshake"
+path = "fuzz_targets/clientbound_handshake.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "clientbound_login"
+path = "fuzz_targets/clientbound_login.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "clientbound_status"
+path = "fuzz_targets/clientbound_status.rs"
+test = false
+doc = false
+bench = false
+
+
+[[bin]]
+name = "serverbound_config"
+path = "fuzz_targets/serverbound_config.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "serverbound_game"
+path = "fuzz_targets/serverbound_game.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "serverbound_handshake"
+path = "fuzz_targets/serverbound_handshake.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "serverbound_login"
+path = "fuzz_targets/serverbound_login.rs"
+test = false
+doc = false
+bench = false
+[[bin]]
+name = "serverbound_status"
+path = "fuzz_targets/serverbound_status.rs"
+test = false
+doc = false
+bench = false
diff --git a/azalea-protocol/fuzz/README.md b/azalea-protocol/fuzz/README.md
new file mode 100644
index 00000000..42ae188c
--- /dev/null
+++ b/azalea-protocol/fuzz/README.md
@@ -0,0 +1,10 @@
+Fuzzing for `azalea-protocol`.
+
+## Usage
+
+```sh
+cargo fuzz run clientbound_game # {clientbound,serverbound}_{config,game,handshake,login,status}
+# optionally, add `-s none` for a speedup at the cost of catching less memory safety issues
+# see https://appsec.guide/docs/fuzzing/rust/cargo-fuzz/#addresssanitizer
+```
+
diff --git a/azalea-protocol/fuzz/fuzz_targets/clientbound_config.rs b/azalea-protocol/fuzz/fuzz_targets/clientbound_config.rs
new file mode 100644
index 00000000..79ffd95b
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/clientbound_config.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::config::ClientboundConfigPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/clientbound_game.rs b/azalea-protocol/fuzz/fuzz_targets/clientbound_game.rs
new file mode 100644
index 00000000..a253a859
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/clientbound_game.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::game::ClientboundGamePacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/clientbound_handshake.rs b/azalea-protocol/fuzz/fuzz_targets/clientbound_handshake.rs
new file mode 100644
index 00000000..84061965
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/clientbound_handshake.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::handshake::ClientboundHandshakePacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ClientboundHandshakePacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/clientbound_login.rs b/azalea-protocol/fuzz/fuzz_targets/clientbound_login.rs
new file mode 100644
index 00000000..6339fcea
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/clientbound_login.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::login::ClientboundLoginPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ClientboundLoginPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/clientbound_status.rs b/azalea-protocol/fuzz/fuzz_targets/clientbound_status.rs
new file mode 100644
index 00000000..38264f64
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/clientbound_status.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::status::ClientboundStatusPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ClientboundStatusPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/serverbound_config.rs b/azalea-protocol/fuzz/fuzz_targets/serverbound_config.rs
new file mode 100644
index 00000000..d2a13d1d
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/serverbound_config.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::config::ServerboundConfigPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ServerboundConfigPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/serverbound_game.rs b/azalea-protocol/fuzz/fuzz_targets/serverbound_game.rs
new file mode 100644
index 00000000..8891485c
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/serverbound_game.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::game::ServerboundGamePacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ServerboundGamePacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/serverbound_handshake.rs b/azalea-protocol/fuzz/fuzz_targets/serverbound_handshake.rs
new file mode 100644
index 00000000..be3fca35
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/serverbound_handshake.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::handshake::ServerboundHandshakePacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ServerboundHandshakePacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/serverbound_login.rs b/azalea-protocol/fuzz/fuzz_targets/serverbound_login.rs
new file mode 100644
index 00000000..e0e4a384
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/serverbound_login.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::login::ServerboundLoginPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ServerboundLoginPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/fuzz/fuzz_targets/serverbound_status.rs b/azalea-protocol/fuzz/fuzz_targets/serverbound_status.rs
new file mode 100644
index 00000000..65429b29
--- /dev/null
+++ b/azalea-protocol/fuzz/fuzz_targets/serverbound_status.rs
@@ -0,0 +1,10 @@
+#![no_main]
+
+use std::io::Cursor;
+
+use azalea_protocol::{packets::status::ServerboundStatusPacket, read::deserialize_packet};
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = deserialize_packet::<ServerboundStatusPacket>(&mut Cursor::new(data));
+});
diff --git a/azalea-protocol/src/common/tags.rs b/azalea-protocol/src/common/tags.rs
index f22175ee..3f9a2ef2 100644
--- a/azalea-protocol/src/common/tags.rs
+++ b/azalea-protocol/src/common/tags.rs
@@ -19,11 +19,11 @@ pub struct Tags {
impl AzaleaRead for TagMap {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let length = u32::azalea_read_var(buf)? as usize;
- let mut data = IndexMap::with_capacity(length);
+ let mut data = IndexMap::new();
for _ in 0..length {
let tag_type = Identifier::azalea_read(buf)?;
let tags_count = i32::azalea_read_var(buf)? as usize;
- let mut tags_vec = Vec::with_capacity(tags_count);
+ let mut tags_vec = Vec::new();
for _ in 0..tags_count {
let tags = Tags::azalea_read(buf)?;
tags_vec.push(tags);
diff --git a/azalea-protocol/src/read.rs b/azalea-protocol/src/read.rs
index d6c8c65a..664e2593 100644
--- a/azalea-protocol/src/read.rs
+++ b/azalea-protocol/src/read.rs
@@ -401,3 +401,36 @@ where
Ok(Some(buf))
}
+
+#[cfg(test)]
+mod tests {
+ use std::io::Cursor;
+
+ use crate::{packets::game::ClientboundGamePacket, read::deserialize_packet};
+
+ #[test]
+ fn fuzzed_1() {
+ // oom: checks for unbounded TagMap
+ let _ = deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(
+ [132, 1, 255, 255, 255, 255, 255].as_slice(),
+ ));
+ }
+ #[test]
+ fn fuzzed_2() {
+ // oom: also checks for unbounded TagMap
+ let _ = deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(
+ [132, 1, 75, 0, 255, 255, 255, 255, 24, 0].as_slice(),
+ ));
+ }
+ #[test]
+ fn fuzzed_3() {
+ // panic: integer overflow in HolderSet::azalea_read
+ let _ = deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(
+ [
+ 94, 44, 157, 38, 61, 37, 37, 37, 37, 37, 37, 65, 128, 128, 1, 1, 255, 252, 128,
+ 128, 128, 128, 128, 128, 128, 40, 0,
+ ]
+ .as_slice(),
+ ));
+ }
+}
diff --git a/azalea-registry/src/lib.rs b/azalea-registry/src/lib.rs
index 1d146508..fa197412 100644
--- a/azalea-registry/src/lib.rs
+++ b/azalea-registry/src/lib.rs
@@ -133,7 +133,7 @@ pub enum HolderSet<D: Registry, Identifier: AzaleaRead + AzaleaWrite> {
}
impl<D: Registry, Identifier: AzaleaRead + AzaleaWrite> AzaleaRead for HolderSet<D, Identifier> {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
- let size = i32::azalea_read_var(buf)? - 1;
+ let size = i32::azalea_read_var(buf)?.wrapping_sub(1);
if size == -1 {
let key = Identifier::azalea_read(buf)?;
Ok(Self::Named {