From 6a6bd97910c088ba817e2622dfc2506fa92af3cd Mon Sep 17 00:00:00 2001 From: emaxx-g Date: Thu, 27 Jun 2024 16:05:42 +0000 Subject: [PATCH] Add redoxfs fuzzer for FUSE interface --- Cargo.toml | 3 + fuzz/.gitignore | 4 + fuzz/Cargo.lock | 753 ++++++++++++++++++++++++++ fuzz/Cargo.toml | 30 + fuzz/fuzz_targets/fuse_fuzz_target.rs | 338 ++++++++++++ src/lib.rs | 4 +- src/mount/fuse.rs | 4 +- src/mount/mod.rs | 4 +- 8 files changed, 1136 insertions(+), 4 deletions(-) create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.lock create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/fuzz_targets/fuse_fuzz_target.rs diff --git a/Cargo.toml b/Cargo.toml index ce397fd8fd..3f58274407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,3 +69,6 @@ std = [ fuser = { version = "0.12.0", optional = true } libc = { version = "0.2", optional = true } time = { version = "0.1", optional = true } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000000..1a45eee776 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000000..295e5e0c80 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,753 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "argon2" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25df3c03f1040d0069fcd3907e24e36d59f9b6fa07ba49be0eb25a794f036ba7" +dependencies = [ + "base64ct", + "blake2", +] + +[[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 = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "endian-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad847bb2094f110bbdd6fa564894ca4556fd978958e93985420d680d3cb6d14" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fuser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5910691a0ececcc6eba8bb14029025c2d123e96a53db1533f6a4602861a5aaf7" +dependencies = [ + "libc", + "log", + "memchr", + "page_size", + "pkg-config", + "smallvec", + "users", + "zerocopy", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall 0.5.2", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "range-tree" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384c2842d4e069d5ccacf5fe1dca4ef8d07a5444329715f0fc3c61813502d4d1" + +[[package]] +name = "redox-path" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_termios" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + +[[package]] +name = "redoxfs" +version = "0.6.4" +dependencies = [ + "aes", + "argon2", + "base64ct", + "endian-num", + "env_logger", + "fuser", + "getrandom", + "libc", + "libredox 0.1.3", + "log", + "range-tree", + "redox-path", + "redox_syscall 0.5.2", + "seahash", + "termion", + "time", + "uuid", +] + +[[package]] +name = "redoxfs-fuzz" +version = "0.0.0" +dependencies = [ + "anyhow", + "arbitrary", + "fuser", + "libfuzzer-sys", + "nix", + "redoxfs", + "tempfile", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termion" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d" +dependencies = [ + "libc", + "libredox 0.0.2", + "numtoa", + "redox_termios", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "users" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[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 = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000000..e8e2c9bca4 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "redoxfs-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[features] +default = [] +log = [] + +[package.metadata] +cargo-fuzz = true + +[dependencies] +anyhow = "1.0.86" +arbitrary = { version = "1.3.2", features = ["derive"] } +fuser = { version = "0.12.0" } +libfuzzer-sys = "0.4" +nix = { version = "0.29.0", features = ["fs"] } +tempfile = "3.10.1" + +[dependencies.redoxfs] +path = ".." + +[[bin]] +name = "fuse_fuzz_target" +path = "fuzz_targets/fuse_fuzz_target.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/fuse_fuzz_target.rs b/fuzz/fuzz_targets/fuse_fuzz_target.rs new file mode 100644 index 0000000000..cef49d038c --- /dev/null +++ b/fuzz/fuzz_targets/fuse_fuzz_target.rs @@ -0,0 +1,338 @@ +//! Fuzzer that exercises random file system operations against a FUSE-mounted redoxfs. + +#![no_main] + +use anyhow::{ensure, Result}; +use fuser; +use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target, Corpus}; +use nix::sys::statvfs::statvfs; +use std::{ + fs::{self, File, FileTimes, OpenOptions}, + io::{Read, Seek, SeekFrom, Write}, + os::unix::fs::{self as unix_fs, PermissionsExt}, + path::{Path, PathBuf}, + thread, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; +use tempfile; + +use redoxfs::{mount::fuse::Fuse, DiskSparse, FileSystem}; + +/// Maximum size for files and buffers. Chosen arbitrarily with fuzzing performance in mind. +const MAX_SIZE: u64 = 10_000_000; +/// Limit on the number of remounts in a single test case. Chosen arbitrarily with fuzzing +/// performance in mind: remounts are costly. +const MAX_MOUNT_SEQUENCES: usize = 3; + +/// An operation to be performed by the fuzzer. +#[derive(Arbitrary, Clone, Debug)] +enum Operation { + Chown { + path: PathBuf, + uid: Option, + gid: Option, + }, + CreateDir { + path: PathBuf, + }, + HardLink { + original: PathBuf, + link: PathBuf, + }, + Metadata { + path: PathBuf, + }, + Read { + path: PathBuf, + }, + ReadDir { + path: PathBuf, + }, + ReadLink { + path: PathBuf, + }, + RemoveDir { + path: PathBuf, + }, + RemoveFile { + path: PathBuf, + }, + Rename { + from: PathBuf, + to: PathBuf, + }, + SeekRead { + path: PathBuf, + seek_pos: u64, + buf_size: usize, + }, + SeekWrite { + path: PathBuf, + seek_pos: u64, + buf_size: usize, + }, + SetLen { + path: PathBuf, + size: u64, + }, + SetPermissions { + path: PathBuf, + readonly: Option, + mode: Option, + }, + SetTimes { + path: PathBuf, + accessed_since_epoch: Option, + modified_since_epoch: Option, + }, + Statvfs {}, + SymLink { + original: PathBuf, + link: PathBuf, + }, + Write { + path: PathBuf, + buf_size: usize, + }, +} + +/// Parameters for mounting the file system and operations to be performed afterwards. +#[derive(Arbitrary, Clone, Debug)] +struct MountSequence { + squash: bool, + operations: Vec, +} + +/// The whole input to a single fuzzer invocation. +#[derive(Arbitrary, Clone, Debug)] +struct TestCase { + disk_size: u64, + reserved_size: u64, + mount_sequences: Vec, +} + +/// Creates the disk for backing the Redoxfs. +fn create_disk(temp_path: &Path, disk_size: u64) -> DiskSparse { + let disk_path = temp_path.join("disk.img"); + DiskSparse::create(disk_path, disk_size).unwrap() +} + +/// Creates an empty Redoxfs. +fn create_redoxfs(disk: DiskSparse, reserved_size: u64) -> bool { + let password = None; + let reserved = vec![0; reserved_size as usize]; + let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + FileSystem::create_reserved( + disk, + password, + &reserved, + ctime.as_secs(), + ctime.subsec_nanos(), + ) + .is_ok() +} + +/// Mounts an existing Redoxfs, runs the callback and performs the unmount. +fn with_redoxfs_mount(temp_path: &Path, disk: DiskSparse, squash: bool, callback: F) +where + F: FnOnce(&Path) + Send + 'static, +{ + let password = None; + let block = None; + let mut fs = FileSystem::open(disk, password, block, squash).unwrap(); + + let mount_path = temp_path.join("mount"); + fs::create_dir_all(&mount_path).unwrap(); + let mut session = fuser::Session::new(Fuse { fs: &mut fs }, &mount_path, &[]).unwrap(); + let mut unmounter = session.unmount_callable(); + + let join_handle = thread::spawn(move || { + callback(&mount_path); + unmounter.unmount().unwrap(); + }); + + session.run().unwrap(); + join_handle.join().unwrap(); +} + +fn get_path_within_fs(fs_path: &Path, path_to_add: &Path) -> Result { + ensure!(path_to_add.is_relative()); + ensure!(path_to_add + .components() + .all(|c| c != std::path::Component::ParentDir)); + Ok(fs_path.join(path_to_add)) +} + +fn do_operation(fs_path: &Path, op: &Operation) -> Result<()> { + match op { + Operation::Chown { path, uid, gid } => { + let path = get_path_within_fs(fs_path, path)?; + unix_fs::chown(path, *uid, *gid)?; + } + Operation::CreateDir { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::create_dir(path)?; + } + Operation::HardLink { original, link } => { + let original = get_path_within_fs(fs_path, original)?; + let link = get_path_within_fs(fs_path, link)?; + fs::hard_link(original, link)?; + } + Operation::Metadata { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::metadata(path)?; + } + Operation::Read { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::read(path)?; + } + Operation::ReadDir { path } => { + let path = get_path_within_fs(fs_path, path)?; + let _ = fs::read_dir(path)?.count(); + } + Operation::ReadLink { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::read_link(path)?; + } + Operation::RemoveDir { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::remove_dir(path)?; + } + Operation::RemoveFile { path } => { + let path = get_path_within_fs(fs_path, path)?; + fs::remove_file(path)?; + } + Operation::Rename { from, to } => { + let from = get_path_within_fs(fs_path, from)?; + let to = get_path_within_fs(fs_path, to)?; + fs::rename(from, to)?; + } + Operation::SeekRead { + path, + seek_pos, + buf_size, + } => { + ensure!(*buf_size as u64 <= MAX_SIZE); + let path = get_path_within_fs(fs_path, path)?; + let mut file = File::open(path)?; + file.seek(SeekFrom::Start(*seek_pos))?; + let mut buf = vec![0; *buf_size]; + file.read(&mut buf)?; + } + Operation::SeekWrite { + path, + seek_pos, + buf_size, + } => { + ensure!(*seek_pos <= MAX_SIZE); + ensure!(*buf_size as u64 <= MAX_SIZE); + let path = get_path_within_fs(fs_path, path)?; + let mut file = OpenOptions::new().write(true).open(path)?; + file.seek(SeekFrom::Start(*seek_pos))?; + let buf = vec![0; *buf_size]; + file.write(&buf)?; + } + Operation::SetLen { path, size } => { + let path = get_path_within_fs(fs_path, path)?; + let file = OpenOptions::new().write(true).open(path)?; + file.set_len(*size)?; + } + Operation::SetPermissions { + path, + readonly, + mode, + } => { + let path = get_path_within_fs(fs_path, path)?; + let metadata = fs::metadata(&path)?; + let mut perms = metadata.permissions(); + if let Some(readonly) = readonly { + perms.set_readonly(*readonly); + } + if let Some(mode) = mode { + perms.set_mode(*mode); + } + fs::set_permissions(path, perms)?; + } + Operation::SetTimes { + path, + accessed_since_epoch, + modified_since_epoch, + } => { + let path = get_path_within_fs(fs_path, path)?; + let file = File::options().write(true).open(path)?; + let mut times = FileTimes::new(); + if let Some(accessed_since_epoch) = accessed_since_epoch { + if let Some(accessed) = UNIX_EPOCH.checked_add(*accessed_since_epoch) { + times = times.set_accessed(accessed); + } + } + if let Some(modified_since_epoch) = modified_since_epoch { + if let Some(modified) = UNIX_EPOCH.checked_add(*modified_since_epoch) { + times = times.set_modified(modified); + } + } + file.set_times(times)?; + } + Operation::Statvfs {} => { + statvfs(fs_path)?; + } + Operation::SymLink { original, link } => { + let original = get_path_within_fs(fs_path, original)?; + let link = get_path_within_fs(fs_path, link)?; + unix_fs::symlink(original, link)?; + } + Operation::Write { path, buf_size } => { + ensure!(*buf_size as u64 <= MAX_SIZE); + let path = get_path_within_fs(fs_path, path)?; + let buf = vec![0; *buf_size]; + fs::write(path, &buf)?; + } + } + Ok(()) +} + +fuzz_target!(|test_case: TestCase| -> Corpus { + if test_case.disk_size > MAX_SIZE + || test_case.reserved_size > MAX_SIZE + || test_case.mount_sequences.len() > MAX_MOUNT_SEQUENCES + { + return Corpus::Reject; + } + + let temp_dir = tempfile::Builder::new() + .prefix("fuse_fuzz_target") + .tempdir() + .unwrap(); + + #[cfg(feature = "log")] + eprintln!("create fs"); + let disk = create_disk(temp_dir.path(), test_case.disk_size); + if !create_redoxfs(disk, test_case.reserved_size) { + // File system creation failed (e.g., due to insufficient space) so we bail out, still + // exercising this code path is useful. + return Corpus::Keep; + } + + for mount_seq in test_case.mount_sequences.iter() { + #[cfg(feature = "log")] + eprintln!("mount fs"); + + let disk = create_disk(temp_dir.path(), test_case.disk_size); + let operations = mount_seq.operations.clone(); + with_redoxfs_mount(temp_dir.path(), disk, mount_seq.squash, move |fs_path| { + for operation in operations.iter() { + #[cfg(feature = "log")] + eprintln!("do operation {operation:?}"); + + let _result = do_operation(fs_path, operation); + + #[cfg(feature = "log")] + eprintln!("operation result {:?}", _result.err()); + } + }); + + #[cfg(feature = "log")] + eprintln!("unmounted fs"); + } + Corpus::Keep +}); diff --git a/src/lib.rs b/src/lib.rs index a65f32bd61..cc3c7b878c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,8 +48,10 @@ mod disk; mod filesystem; mod header; mod key; -#[cfg(feature = "std")] +#[cfg(all(feature = "std", not(fuzzing)))] mod mount; +#[cfg(all(feature = "std", fuzzing))] +pub mod mount; mod node; mod record; mod transaction; diff --git a/src/mount/fuse.rs b/src/mount/fuse.rs index ae6e1c00e5..83312e35bb 100644 --- a/src/mount/fuse.rs +++ b/src/mount/fuse.rs @@ -27,12 +27,12 @@ const NULL_TIME: Duration = Duration::new(0, 0); pub fn mount( mut filesystem: filesystem::FileSystem, mountpoint: P, - mut callback: F, + callback: F, ) -> io::Result where D: Disk, P: AsRef, - F: FnMut(&Path) -> T, + F: FnOnce(&Path) -> T, { let mountpoint = mountpoint.as_ref(); diff --git a/src/mount/mod.rs b/src/mount/mod.rs index eff489f3fa..d3bb6ea953 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -1,5 +1,7 @@ -#[cfg(not(target_os = "redox"))] +#[cfg(all(not(target_os = "redox"), not(fuzzing)))] mod fuse; +#[cfg(all(not(target_os = "redox"), fuzzing))] +pub mod fuse; #[cfg(not(target_os = "redox"))] pub use self::fuse::mount;