From 6b851312d8a76fc7f0aa30d8f7abbe68ef6cc171 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Sat, 15 May 2021 00:23:04 -0400 Subject: [PATCH] Add fuzzing, fix integer underflow --- .gitignore | 4 +- README.md | 2 + fuzz/Cargo.lock | 588 ++++++++++++++++++++++++++++++++++++++++++++ fuzz/Cargo.toml | 17 ++ fuzz/in/1.xml | 1 + fuzz/in/2.xml | 1 + fuzz/in/3.xml | 1 + fuzz/in/4.xml | 1 + fuzz/in/5.xml | 1 + fuzz/in/6.xml | 1 + fuzz/in/7.xml | 5 + fuzz/src/main.rs | 57 +++++ fuzz/xml.dict | 72 ++++++ src/lib.rs | 6 + src/main.rs | 6 +- src/stanzafilter.rs | 16 +- 16 files changed, 771 insertions(+), 8 deletions(-) create mode 100644 fuzz/Cargo.lock create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/in/1.xml create mode 100644 fuzz/in/2.xml create mode 100644 fuzz/in/3.xml create mode 100644 fuzz/in/4.xml create mode 100644 fuzz/in/5.xml create mode 100644 fuzz/in/6.xml create mode 100644 fuzz/in/7.xml create mode 100644 fuzz/src/main.rs create mode 100644 fuzz/xml.dict create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore index 0264c41..f350a81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target/ **/*.rs.bk .idea -**/*.kate-swp \ No newline at end of file +**/*.kate-swp +**/out/ +**/core.* diff --git a/README.md b/README.md index 61f56c6..30bae42 100644 --- a/README.md +++ b/README.md @@ -132,3 +132,5 @@ To build a reverse proxy only, but supporting all of STARTTLS/TLS/QUIC, run: `ca #### License GNU/AGPLv3 - Check LICENSE.md for details + +Thanks [rxml](https://github.com/horazont/rxml) for afl-fuzz seeds diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..fd4ed39 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,588 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "afl" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5023646d631c14f4b24425600280676437b2c39d58f9cce91a6187e7af929f4" +dependencies = [ + "cc", + "clap", + "libc", + "rustc_version", + "xdg", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cpufeatures" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "281f563b2c3a0e535ab12d81d3c5859045795256ad269afa7c19542585b68f93" +dependencies = [ + "libc", +] + +[[package]] +name = "die" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8634d5e6139f7364a4e99bd718b2f511f2f25863146360e70909bc45a016290" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "futures" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" + +[[package]] +name = "futures-executor" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" + +[[package]] +name = "futures-macro" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" + +[[package]] +name = "futures-task" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" + +[[package]] +name = "futures-util" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +dependencies = [ + "autocfg", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "fuzz" +version = "0.1.0" +dependencies = [ + "afl", + "rxml", + "sha256", + "tokio", + "xmpp-proxy", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "libc" +version = "0.2.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "mio" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + +[[package]] +name = "rxml" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4656aeb6f77b1ba20d3702069ce92551fa01fe0c02449cec92f014d665cd4021" + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "sha256" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f336ed3354742b51d11c47dc0403bf81229548f2e130fcd21ccc471433334a" +dependencies = [ + "hex", + "sha2", +] + +[[package]] +name = "slab" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tokio" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" + +[[package]] +name = "xmpp-proxy" +version = "1.0.0" +dependencies = [ + "anyhow", + "die", + "futures", + "serde", + "serde_derive", + "tokio", + "toml", +] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..2f80c22 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "fuzz" +version = "0.1.0" +authors = ["moparisthebest "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +afl = "*" +xmpp-proxy = { version = "*", default-features = false, features = [] } +tokio = { version = "1.4", features = ["net", "rt", "rt-multi-thread", "macros", "io-util"] } +sha256 = "1.0.2" +rxml = "0.1.0" + +[patch.crates-io] +xmpp-proxy = { path = "../" } diff --git a/fuzz/in/1.xml b/fuzz/in/1.xml new file mode 100644 index 0000000..18c355f --- /dev/null +++ b/fuzz/in/1.xml @@ -0,0 +1 @@ + diff --git a/fuzz/in/2.xml b/fuzz/in/2.xml new file mode 100644 index 0000000..4f2f45c --- /dev/null +++ b/fuzz/in/2.xml @@ -0,0 +1 @@ + diff --git a/fuzz/in/3.xml b/fuzz/in/3.xml new file mode 100644 index 0000000..24d108a --- /dev/null +++ b/fuzz/in/3.xml @@ -0,0 +1 @@ + diff --git a/fuzz/in/4.xml b/fuzz/in/4.xml new file mode 100644 index 0000000..e264df2 --- /dev/null +++ b/fuzz/in/4.xml @@ -0,0 +1 @@ + diff --git a/fuzz/in/5.xml b/fuzz/in/5.xml new file mode 100644 index 0000000..5c5f162 --- /dev/null +++ b/fuzz/in/5.xml @@ -0,0 +1 @@ + diff --git a/fuzz/in/6.xml b/fuzz/in/6.xml new file mode 100644 index 0000000..f23dccf --- /dev/null +++ b/fuzz/in/6.xml @@ -0,0 +1 @@ +with somecontent mixed into them diff --git a/fuzz/in/7.xml b/fuzz/in/7.xml new file mode 100644 index 0000000..8b4bac1 --- /dev/null +++ b/fuzz/in/7.xml @@ -0,0 +1,5 @@ + + + & + + diff --git a/fuzz/src/main.rs b/fuzz/src/main.rs new file mode 100644 index 0000000..17f9963 --- /dev/null +++ b/fuzz/src/main.rs @@ -0,0 +1,57 @@ +#[macro_use] +extern crate afl; +extern crate xmpp_proxy; + +use std::io; +use std::io::Cursor; + +use tokio::runtime::Runtime; + +use xmpp_proxy::{StanzaFilter, StanzaReader}; + +fn main_gen_test_cases() { + fuzz!(|data: &[u8]| { + let rt = Runtime::new().unwrap(); + + rt.block_on(async { + let mut filter = StanzaFilter::new(262_144); + let mut stanza_reader = StanzaReader(Cursor::new(data)); + while let Ok(Some(stanza)) = stanza_reader.next(&mut filter).await { + use rxml::EventRead; + let mut fp = rxml::FeedParser::new(); + let stanza_vec = &stanza.to_vec(); + fp.feed(stanza_vec); + fp.feed_eof(); + let result = fp.read_all_eof(|_ev| { + //println!("got event: {:?}", ev); + }); + // true indicates eof + if let Ok(result) = result { + if result { + // wow, afl generated us valid XML, lets output it as a test case + let fname = sha256::digest_bytes(&stanza); + std::fs::create_dir_all("/tmp/afl_test_gen/").unwrap(); + std::fs::write("/tmp/afl_test_gen/".to_owned() + &fname, &stanza).unwrap(); + } else { + // more data is required, stanzafilter should never let this happen, let's panic + panic!("more data required?"); + } + } + } + }) + }); +} + +fn main() { + fuzz!(|data: &[u8]| { + let rt = Runtime::new().unwrap(); + + rt.block_on(async { + let mut filter = StanzaFilter::new(262_144); + let mut stanza_reader = StanzaReader(Cursor::new(data)); + while let Ok(Some(_stanza)) = stanza_reader.next(&mut filter).await { + //ret.push(to_str(stanza).to_string()); + } + }) + }); +} diff --git a/fuzz/xml.dict b/fuzz/xml.dict new file mode 100644 index 0000000..8127aa2 --- /dev/null +++ b/fuzz/xml.dict @@ -0,0 +1,72 @@ +# +# AFL dictionary for XML +# ---------------------- +# +# Several basic syntax elements and attributes, modeled on libxml2. +# +# Created by Michal Zalewski +# + +attr_encoding=" encoding=\"1\"" +attr_generic=" a=\"1\"" +attr_href=" href=\"1\"" +attr_standalone=" standalone=\"no\"" +attr_version=" version=\"1\"" +attr_xml_base=" xml:base=\"1\"" +attr_xml_id=" xml:id=\"1\"" +attr_xml_lang=" xml:lang=\"1\"" +attr_xml_space=" xml:space=\"1\"" +attr_xmlns=" xmlns=\"1\"" + +entity_builtin="<" +entity_decimal="" +entity_external="&a;" +entity_hex="" + +string_any="ANY" +string_brackets="[]" +string_cdata="CDATA" +string_col_fallback=":fallback" +string_col_generic=":a" +string_col_include=":include" +string_dashes="--" +string_empty="EMPTY" +string_empty_dblquotes="\"\"" +string_empty_quotes="''" +string_entities="ENTITIES" +string_entity="ENTITY" +string_fixed="#FIXED" +string_id="ID" +string_idref="IDREF" +string_idrefs="IDREFS" +string_implied="#IMPLIED" +string_nmtoken="NMTOKEN" +string_nmtokens="NMTOKENS" +string_notation="NOTATION" +string_parentheses="()" +string_pcdata="#PCDATA" +string_percent="%a" +string_public="PUBLIC" +string_required="#REQUIRED" +string_schema=":schema" +string_system="SYSTEM" +string_ucs4="UCS-4" +string_utf16="UTF-16" +string_utf8="UTF-8" +string_xmlns="xmlns:" + +tag_attlist="" +tag_doctype="" +tag_open_close="" +tag_open_exclamation="" +tag_xml_q="" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7852bdf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +mod stanzafilter; +pub use stanzafilter::*; + +pub fn to_str(buf: &[u8]) -> std::borrow::Cow<'_, str> { + String::from_utf8_lossy(buf) +} diff --git a/src/main.rs b/src/main.rs index 9274744..29a2f48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,8 @@ use slicesubsequence::*; mod stanzafilter; use stanzafilter::*; +use xmpp_proxy::to_str; + #[cfg(feature = "quic")] mod quic; #[cfg(feature = "quic")] @@ -136,10 +138,6 @@ pub enum AllowedType { Any, } -fn to_str(buf: &[u8]) -> std::borrow::Cow<'_, str> { - String::from_utf8_lossy(buf) -} - async fn shuffle_rd_wr( in_rd: R, in_wr: W, diff --git a/src/stanzafilter.rs b/src/stanzafilter.rs index b177a22..462a3b2 100644 --- a/src/stanzafilter.rs +++ b/src/stanzafilter.rs @@ -26,6 +26,16 @@ pub struct StanzaFilter { state: StanzaState, } +#[inline(always)] +fn checked_sub(i: usize, s: usize) -> Result { + // i.checked_sub(s).ok_or_else(||anyhow::anyhow!("invalid stanza")) + if s > i { + bail!("invalid stanza") + } else { + Ok(i - s) + } +} + impl StanzaFilter { pub fn new(buf_size: usize) -> StanzaFilter { StanzaFilter { @@ -77,7 +87,7 @@ impl StanzaFilter { _ => self.state = InsideTag, }, InsideTagFirstChar => match b { - b'/' => self.tag_cnt -= 2, + b'/' => self.tag_cnt = checked_sub(self.tag_cnt, 2)?, b'!' => self.state = ExclamationTag(self.cnt + 7), // 7 is length of b"[CDATA[" b'?' | b'>' | b'\'' | b'"' => bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])), _ => self.state = InsideTag, @@ -87,7 +97,7 @@ impl StanzaFilter { if self.buf[self.cnt - 1] == b'/' { // state can't be InsideTag unless we are on at least the second character, so can't go out of range // self-closing tag - self.tag_cnt -= 1; + self.tag_cnt = checked_sub(self.tag_cnt, 1)?; } if self.tag_cnt == 0 { return self.stanza_end(); @@ -124,7 +134,7 @@ impl StanzaFilter { if idx == self.cnt { if self.last_equals(b"[CDATA[")? { self.state = InsideCDATA; - self.tag_cnt -= 1; // cdata not a tag + self.tag_cnt = checked_sub(self.tag_cnt, 1)?; // cdata not a tag } else { bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])); }