commit d888faed5a4a5004a1fcdb7efb071ca840254b3e
parent b7d278484ebbb8c923fb3b956dcf2a3dbaf4dfee
Author: MTRNord <mtrnord1@gmail.com>
Date: Sun, 14 Aug 2022 02:24:33 +0200
Properly do the arbitrary json
Diffstat:
4 files changed, 66 insertions(+), 170 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -16,11 +16,18 @@ afl = "*"
arbitrary = {version = "1", features = ["derive"]}
cfg-if = "0.1"
fuzzcheck = {git = "https://github.com/MTRNord/fuzzcheck-rs.git", branch = "patch-1"}
+fuzzcheck_serde_json_generator = {version = "0.1.0", git = "https://github.com/teymour-aldridge/fuzzcheck_generators.git", branch = "main"}
once_cell = "1.13.0"
reqwest = {version = "0.11.11", features = ["blocking", "json", "gzip"]}
serde = {version = "1.0", features = ["derive"]}
serde_json = "1.0.83"
+[patch.crates-io]
+fuzzcheck = {git = "https://github.com/MTRNord/fuzzcheck-rs.git", branch = "patch-1"}
+
+[patch.'https://github.com/loiclec/fuzzcheck-rs']
+fuzzcheck = {git = "https://github.com/MTRNord/fuzzcheck-rs.git", branch = "patch-1"}
+
[features]
default = ["fuzzing", "password_auth"]
fuzzing = []
diff --git a/src/fuzzTargets/createRoom.rs b/src/fuzzTargets/createRoom.rs
@@ -1,7 +1,8 @@
#![allow(non_snake_case)]
-use matrix_fuzz::{client, secrets::ACCESS_TOKEN, types::create_room::CreateRoomMagicJSON};
+//use matrix_fuzz::{client, secrets::ACCESS_TOKEN, types::create_room::CreateRoomMagicJSON};
fn main() {
+ /*
afl::fuzz_nohook!(|data: CreateRoomMagicJSON| {
let mut data = data;
// HACK due to https://github.com/matrix-org/synapse/issues/13510
@@ -51,9 +52,9 @@ fn main() {
if content.contains("M_ROOM_IN_USE")
|| content.contains("Invalid characters in room alias")
|| content.contains("':' is not permitted in the room alias name. Please note this expects a local part — 'wombat', not '#wombat:example.com'.")
- || content.contains("M_UNSUPPORTED_ROOM_VERSION")
- || content.contains("Invalid user_id")
- || content.contains("is not a valid preset")
+ || content.contains("M_UNSUPPORTED_ROOM_VERSION")
+ || content.contains("Invalid user_id")
+ || content.contains("is not a valid preset")
|| content.contains("You are not allowed to set others state")
{
return;
@@ -63,5 +64,5 @@ fn main() {
panic!("Content: {:?}", content);
}
}
- });
+ });*/
}
diff --git a/src/lib.rs b/src/lib.rs
@@ -61,7 +61,7 @@ fn login() -> String {
mod tests {
use reqwest::header::{HeaderValue, CONTENT_TYPE};
- use crate::types::create_room::{CreateRoomMagic, CreateRoomMagicJSON};
+ use crate::types::create_room::CreateRoomMagicJSON;
#[test]
#[no_coverage]
@@ -77,7 +77,7 @@ mod tests {
#[test]
#[no_coverage]
fn null_in_room() {
- let content = CreateRoomMagic {
+ let content = CreateRoomMagicJSON {
name: Some("a".to_string()),
room_alias_name: Some("\0".to_string()),
visibility: Some("a".to_string()),
@@ -112,26 +112,11 @@ mod tests {
.send();
assert!(resp.is_err())
}
-
- #[test]
- #[no_coverage]
- fn converter() {
- let content = std::fs::read_to_string(
- "./fuzz/tests::fuzz_create_room/artifacts/36d21e863bdd02f6.json",
- )
- .unwrap();
- let typed = serde_json::from_str::<CreateRoomMagic>(&content).unwrap();
- let typed_json: CreateRoomMagicJSON = (&typed).into();
- println!("{}", serde_json::to_string(&typed_json).unwrap());
- }
}
#[cfg(all(fuzzing, test))]
mod tests {
- use crate::types::{
- create_room::{CreateRoomMagic, CreateRoomMagicJSON},
- LoginPostReq,
- };
+ use crate::types::{create_room::CreateRoomMagicJSON, LoginPostReq};
fn login(data: &LoginPostReq) -> bool {
let mut json_data = data.clone();
@@ -152,28 +137,28 @@ mod tests {
}
if let Some(user) = &json_data.user {
- if user.contains("\0") {
- json_data.user = Some(user.replace("\0", ""));
+ if user.contains('\0') {
+ json_data.user = Some(user.replace('\0', ""));
}
}
if let Some(medium) = &json_data.medium {
- if medium.contains("\0") {
- json_data.medium = Some(medium.replace("\0", ""));
+ if medium.contains('\0') {
+ json_data.medium = Some(medium.replace('\0', ""));
}
}
if let Some(address) = &json_data.address {
- if address.contains("\0") {
- json_data.address = Some(address.replace("\0", ""));
+ if address.contains('\0') {
+ json_data.address = Some(address.replace('\0', ""));
}
}
if let Some(user) = &json_data.user {
- if user.contains("\0") {
- json_data.user = Some(user.replace("\0", ""));
+ if user.contains('\0') {
+ json_data.user = Some(user.replace('\0', ""));
}
}
/*if let Some(password) = &json_data.password {
- if password.contains("\0") {
- json_data.password = Some(password.replace("\0", ""));
+ if password.contains('\0' {
+ json_data.password = Some(password.replace('\0', ""));
}
}*/
@@ -222,28 +207,29 @@ mod tests {
assert!(!result.found_test_failure);
}
- fn create_room(data: &CreateRoomMagic) -> bool {
- let mut json_data: CreateRoomMagicJSON = data.into();
+ fn create_room(data: &CreateRoomMagicJSON) -> bool {
+ let mut json_data = data.clone();
+ for mut state in &mut json_data.initial_state {
+ if state.content.is_array()
+ || state.content.is_boolean()
+ || state.content.is_null()
+ || state.content.is_string()
+ {
+ state.content = serde_json::Value::Object(serde_json::Map::new());
+ }
+ }
+
// FIXME: We probably should set it to null and not do a false positive
// HACK due to https://github.com/matrix-org/synapse/issues/13510
if let Some(room_alias_name) = &json_data.room_alias_name {
if room_alias_name.contains('\0') {
- json_data.room_alias_name = Some(room_alias_name.replace("\0", ""));
+ json_data.room_alias_name = Some(room_alias_name.replace('\0', ""));
}
}
// HACK due to NUL in type or state_key
- if let Some(initial_state) = &mut json_data.initial_state {
- initial_state
- .retain(|state| !(state._type.contains('\0') || state.state_key.contains('\0')));
- // for state in initial_state {
- // if state._type.contains('\0') {
- // return;
- // }
- // if state.state_key.contains('\0') {
- // return;
- // }
- // }
- }
+ json_data
+ .initial_state
+ .retain(|state| !(state._type.contains('\0') || state.state_key.contains('\0')));
/*// HACK due to https://github.com/matrix-org/synapse/issues/13511
if let Some(pids) = &data.invite_3pid {
@@ -274,7 +260,8 @@ mod tests {
|| content.contains("M_UNSUPPORTED_ROOM_VERSION")
|| content.contains("Invalid user_id")
|| content.contains("is not a valid preset")
- || content.contains("You are not allowed to set others state")
+ || content.contains("You are not allowed to set others state")
+ || content.contains("JSON integer out of range")
{
return true;
}
diff --git a/src/types/create_room.rs b/src/types/create_room.rs
@@ -1,88 +1,28 @@
use arbitrary::Arbitrary;
-use fuzzcheck::DefaultMutator;
+use fuzzcheck::{DefaultMutator, Mutator};
+use fuzzcheck_serde_json_generator::json_value_mutator;
use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
+use serde_json::Value;
-#[derive(Clone, Serialize, Deserialize, Debug, Default, Arbitrary)]
-pub struct CreateRoomMagicJSON {
- #[serde(skip_serializing_if = "Option::is_none")]
- pub creation_content: Option<HashMap<String, String>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub initial_state: Option<Vec<StateEventJSON>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub invite: Option<Vec<String>>,
- // Due to https://github.com/matrix-org/synapse/issues/13512
- //#[serde(skip_serializing_if = "Option::is_none")]
- //pub invite_3pid: Option<Vec<Invite3pid>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub is_direct: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub name: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub preset: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub room_alias_name: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub room_version: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub topic: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub visibility: Option<String>,
-}
-
-// FIXME: This is stupid hacky.
-impl From<&CreateRoomMagic> for CreateRoomMagicJSON {
- #[no_coverage]
- fn from(item: &CreateRoomMagic) -> Self {
- let mut creation_content = HashMap::new();
- if let Some(mut creation_content_keys) = item.creation_content_keys.clone() {
- if let Some(mut creation_content_values) = item.creation_content_values.clone() {
- if creation_content_keys.len() > creation_content_values.len() {
- creation_content_keys.truncate(creation_content_values.len());
- } else {
- creation_content_values.truncate(creation_content_keys.len());
- }
- for (key, value) in creation_content_keys
- .iter()
- .zip(creation_content_values.iter())
- {
- creation_content.insert(key.to_string(), value.to_string());
- }
- }
- }
+type ValueMutator = impl Mutator<Value>;
- CreateRoomMagicJSON {
- invite: item.invite.clone(),
- initial_state: item
- .initial_state
- .clone()
- .map(|initial_state| initial_state.into_iter().map(Into::into).collect()),
- is_direct: item.is_direct,
- name: item.name.clone(),
- preset: item.preset.clone(),
- room_alias_name: item.room_alias_name.clone(),
- room_version: item.room_version.clone(),
- topic: item.topic.clone(),
- visibility: item.visibility.clone(),
- creation_content: if item.creation_content_keys.is_none()
- || item.creation_content_values.is_none()
- {
- None
- } else {
- Some(creation_content)
- },
- }
- }
+fn creation_content_skip(value: &Value) -> bool {
+ value.is_string()
+ || value.is_i64()
+ || value.is_boolean()
+ || value.is_array()
+ || value.is_null()
+ || value.is_u64()
}
-#[derive(Clone, Serialize, Deserialize, Debug, Default, DefaultMutator, Arbitrary)]
-pub struct CreateRoomMagic {
- #[serde(skip_serializing_if = "Option::is_none")]
- pub creation_content_keys: Option<Vec<String>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub creation_content_values: Option<Vec<String>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub initial_state: Option<Vec<StateEvent>>,
+#[derive(Clone, Serialize, Deserialize, Debug, Default, DefaultMutator)]
+pub struct CreateRoomMagicJSON {
+ #[serde(skip_serializing_if = "creation_content_skip")]
+ #[field_mutator(ValueMutator = { json_value_mutator() })]
+ pub creation_content: Value,
+ //#[serde(skip_serializing_if = "Option::is_none")]
+ // Required for more fuzzing results
+ pub initial_state: Vec<StateEventJSON>,
#[serde(skip_serializing_if = "Option::is_none")]
pub invite: Option<Vec<String>>,
// Due to https://github.com/matrix-org/synapse/issues/13512
@@ -112,49 +52,10 @@ pub struct Invite3pid {
pub medium: String,
}
-#[derive(Clone, Serialize, Deserialize, Debug, Default, Arbitrary)]
+#[derive(Clone, Serialize, Deserialize, Debug, Default, DefaultMutator)]
pub struct StateEventJSON {
- pub content: HashMap<String, String>,
- #[serde(rename = "type")]
- pub _type: String,
- pub state_key: String,
-}
-
-// FIXME: This is stupid hacky.
-impl From<StateEvent> for StateEventJSON {
- #[no_coverage]
- fn from(item: StateEvent) -> Self {
- let mut content = HashMap::new();
- let mut item_clone = item.clone();
- if item_clone.content_keys.len() > item_clone.content_values.len() {
- item_clone
- .content_keys
- .truncate(item_clone.content_values.len());
- } else {
- item_clone
- .content_values
- .truncate(item_clone.content_keys.len());
- }
- for (key, value) in item_clone
- .content_keys
- .iter()
- .zip(item_clone.content_values.iter())
- {
- content.insert(key.to_string(), value.to_string());
- }
-
- StateEventJSON {
- content,
- _type: item._type.clone(),
- state_key: item.state_key,
- }
- }
-}
-
-#[derive(Clone, Serialize, Deserialize, Debug, DefaultMutator, Default, Arbitrary)]
-pub struct StateEvent {
- pub content_keys: Vec<String>,
- pub content_values: Vec<String>,
+ #[field_mutator(ValueMutator = {json_value_mutator()})]
+ pub content: Value,
#[serde(rename = "type")]
pub _type: String,
pub state_key: String,