facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.41k stars 1.83k forks source link

graphql-syntax: Parser crash `graphql_syntax::parse_document_with_features` #4575

Open nathaniel-brough opened 10 months ago

nathaniel-brough commented 10 months ago

NOTE: This bug report is part of a trial for using fuzz-harnesses, see https://github.com/facebook/relay/issues/4566#issuecomment-1883491254 for more context. This bug was found using the fuzz harness in #4565.

Steps to reproduce


use arbitrary::Arbitrary;
use common::SourceLocationKey;
use graphql_syntax::parse_document_with_features;
use graphql_syntax::ParserFeatures;

fn main() {
    let _res = parse_document_with_features("\"\"", SourceLocationKey::Generated, ParserFeatures { fragment_argument_capability: None});
};

My approximation of the information that you'll get from google/oss-fuzz if this where integrated.

Stacktrace and error input

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3595924902
INFO: Loaded 1 modules   (288424 inline 8-bit counters): 288424 [0x559aea3e8100, 0x559aea42e7a8), 
INFO: Loaded 1 PC tables (288424 PCs): 288424 [0x559aea42e7a8,0x559aea895228), 
INFO:      126 files found in /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/fuzz/corpus/fuzz_parser
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: seed corpus: files: 126 min: 4b max: 8b total: 677b rss: 44Mb
#128    INITED cov: 864 ft: 1419 corp: 105/557b exec/s: 0 rss: 51Mb
#159    NEW    cov: 866 ft: 1421 corp: 106/565b lim: 8 exec/s: 0 rss: 52Mb L: 8/8 MS: 1 CrossOver-
thread '<unnamed>' panicked at /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/src/parser.rs:116:25:
called `Result::unwrap()` on an `Err` value: ()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
==437520== ERROR: libFuzzer: deadly signal
    #0 0x559ae933f311 in __sanitizer_print_stack_trace /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
    #1 0x559ae9fde049 in fuzzer::PrintStackTrace() /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerUtil.cpp:210:38
    #2 0x559ae9fc9415 in fuzzer::Fuzzer::CrashCallback() /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:233:18
    #3 0x559ae9fc9415 in fuzzer::Fuzzer::CrashCallback() /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:228:6
    #4 0x7f3a58f50d9f  (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x38d9f) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #5 0x7f3a58f9fb1b in __pthread_kill_implementation (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x87b1b) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #6 0x7f3a58f50cf5 in gsignal (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x38cf5) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #7 0x7f3a58f3a8b9 in abort (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x228b9) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #8 0x559aea08f856 in std::sys::unix::abort_internal::hb88d147b24444ccb /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/sys/unix/mod.rs:375:14
    #9 0x559ae9295de6 in std::process::abort::h48da3a1587f663a3 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/process.rs:2279:5
    #10 0x559ae9fc3664 in libfuzzer_sys::initialize::_$u7b$$u7b$closure$u7d$$u7d$::hb85733ac7a5d2d57 /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/src/lib.rs:91:9
    #11 0x559aea084325 in _$LT$alloc..boxed..Box$LT$F$C$A$GT$$u20$as$u20$core..ops..function..Fn$LT$Args$GT$$GT$::call::h1171429379e58ebd /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/alloc/src/boxed.rs:2030:9
    #12 0x559aea084325 in std::panicking::rust_panic_with_hook::he8cd11bc79b74e48 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:783:13
    #13 0x559aea084071 in std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::he1868b3475576648 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:657:13
    #14 0x559aea0815d5 in std::sys_common::backtrace::__rust_end_short_backtrace::h9210389720f5c16a /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/sys_common/backtrace.rs:171:18
    #15 0x559aea083dcf in rust_begin_unwind /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:645:5
    #16 0x559ae92992c4 in core::panicking::panic_fmt::hfbd09a125111b8b4 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/core/src/panicking.rs:72:14
    #17 0x559ae9299902 in core::result::unwrap_failed::h946d94eb68f1c3af /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/core/src/result.rs:1649:5
    #18 0x559ae954e4e7 in core::result::Result$LT$T$C$E$GT$::unwrap::h0d1f63693aa4e58d /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/core/src/result.rs:1073:23
    #19 0x559ae954e4e7 in graphql_syntax::parser::Parser::parse_document::hacae4139e593fa4d /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/src/parser.rs:116:16
    #20 0x559ae95b087b in graphql_syntax::parse_document_with_features::hc35ddc8d183e458d /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/src/lib.rs:51:5
    #21 0x559ae93b23a3 in fuzz_parser::_::__libfuzzer_sys_run::hbcfe1f90ad32aaed /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/fuzz/fuzz_targets/fuzz_parser.rs:20:11
    #22 0x559ae93b13db in rust_fuzzer_test_input /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/src/lib.rs:297:60
    #23 0x559ae9fbdd38 in libfuzzer_sys::test_input_wrap::_$u7b$$u7b$closure$u7d$$u7d$::hc1ebeb1e5434c8ae /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/src/lib.rs:61:9
    #24 0x559ae9fbdd38 in std::panicking::try::do_call::h6689f7f2ac49fcc9 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:552:40
    #25 0x559ae9fc3877 in __rust_try libfuzzer_sys.16b8e11d1125706d-cgu.0
    #26 0x559ae9fc2931 in std::panicking::try::hd5c10ed80d3d2169 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panicking.rs:516:19
    #27 0x559ae9fc2931 in std::panic::catch_unwind::h15c7e6ee02f461d0 /rustc/75c68cfd2b9870f2953b62d250bd7d0564a7b56d/library/std/src/panic.rs:142:14
    #28 0x559ae9fc2931 in LLVMFuzzerTestOneInput /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/src/lib.rs:59:22
    #29 0x559ae9fc9949 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:612:15
    #30 0x559ae9fd1015 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:514:22
    #31 0x559ae9fd1ed2 in fuzzer::Fuzzer::MutateAndTestOne() /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:758:25
    #32 0x559ae9fd2cb7 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerLoop.cpp:903:21
    #33 0x559ae9ff2df1 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerDriver.cpp:912:10
    #34 0x559ae9299cd2 in main /home/nathaniel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/libfuzzer/FuzzerMain.cpp:20:30
    #35 0x7f3a58f3bb0d in __libc_start_call_main (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x23b0d) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #36 0x7f3a58f3bbc8 in __libc_start_main@GLIBC_2.2.5 (/nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6+0x23bc8) (BuildId: 2b9ebcc534a497a5e424c017f310e087ec14b7b6)
    #37 0x559ae9299e34 in _start (/home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_parser+0x786e34)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 1 ChangeBinInt-; base unit: 6e7eeba9c78e762c704e57ca8897628e612cfc84
0x22,0x22,0xc3,0xf5,0xff,0xdc,
\"\"\303\365\377\334
artifact_prefix='/home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/fuzz/artifacts/fuzz_parser/'; Test unit written to /home/nathaniel/projects/github.com/silvergasp/relay/compiler/crates/graphql-syntax/fuzz/artifacts/fuzz_parser/crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac
Base64: IiLD9f/c

────────────────────────────────────────────────────────────────────────────────

Failing input:

    fuzz/artifacts/fuzz_parser/crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac

Output of `std::fmt::Debug`:

    Ctx {
        source: "\"\"",
        features: ParserFeatures {
            fragment_argument_capability: None,
        },
    }

Reproduce with:

    cargo fuzz run fuzz_parser fuzz/artifacts/fuzz_parser/crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac

Minimize test case with:

    cargo fuzz tmin fuzz_parser fuzz/artifacts/fuzz_parser/crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac

Crash file

OSS-fuzz will automatically minimise the test-case so there is no need to run cargo fuzz tmin. crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac.txt

To reproduce using cargo fuzz simply run;

cd compiler/crates/graphql-syntax
cargo fuzz run fuzz_parser path/to/downloaded/crash-3fc82c59c003bc1e84d1fc3bbc47019819f1ecac.txt
captbaritone commented 10 months ago

Neat!

Looks like its coming from here: https://github.com/facebook/relay/blob/0a9d473edeee122b1837d579b4e2268c5b2cd641/compiler/crates/graphql-syntax/src/lexer.rs#L171

Maybe we need some way to propagate this error state up to the parent lexer. Looks like logos can return a result type from the callback?

https://docs.rs/logos/latest/logos/index.html#callbacks

nathaniel-brough commented 10 months ago

Seems reasonable. I'm not familiar with the logos crate, though it looks pretty nice. It'll take me a little while to get up to speed, in terms of understanding the code well enough to do bugfixes. Ironically it's easier to write a fuzzer than it is to understand the code that you are fuzzing. If you don't get to it in the meantime, I'll start looking into bug-fixes next week. But I'll ping here before I start :)