|
1 |
| -# example-swift |
| 1 | +[](https://travis-ci.org/fuzzitdev/example-swift) |
| 2 | +[](https://fuzzit.dev) |
2 | 3 |
|
3 |
| -A description of this package. |
| 4 | +# Continuous Fuzzing for Swift Example |
| 5 | + |
| 6 | +This is an example of how to integrate [libFuzzer](https://github.com/apple/swift/blob/master/docs/libFuzzerIntegration.rst) |
| 7 | +targets with the [Fuzzit](https://fuzzit.dev) Continuous Fuzzing Platform. |
| 8 | + |
| 9 | +This example will show the following steps: |
| 10 | +* [Building and running a simple libfuzzer target locally](#building-libfuzzer-target) |
| 11 | +* [Integrate the libFuzzer target with Fuzzit via Travis-CI](#integrating-with-fuzzit-from-ci) |
| 12 | + |
| 13 | +Result: |
| 14 | +* Fuzzit will run the fuzz targets continuously on a daily basis with the latest release. |
| 15 | +* Fuzzit will run regression tests on every pull-request with the generated corpus and crashes to catch bugs early on. |
| 16 | + |
| 17 | +Fuzzing for swift can help find both complex bugs, security bugs and correctness bugs. |
| 18 | + |
| 19 | +This tutorial focuses less on how to build libFuzzer targets and more on how to integrate the targets with Fuzzit. A lot of |
| 20 | +great information is available at the [libFuzzer Tutorial](https://llvm.org/docs/LibFuzzer.html) and [Swift libFuzzer](https://github.com/apple/swift/blob/master/docs/libFuzzerIntegration.rst). |
| 21 | + |
| 22 | +## Building libFuzzer Target |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | +### Understanding the bug |
| 27 | + |
| 28 | +The bug is located at `main.swift` in the following code |
| 29 | + |
| 30 | +```swift |
| 31 | + if |
| 32 | + buffer[0] == 0x46, |
| 33 | + buffer[1] == 0x55, |
| 34 | + buffer[2] == 0x5a, |
| 35 | + buffer[3] == 0x5a, |
| 36 | + buffer[4] == 0x49, |
| 37 | + buffer[5] == 0x65 |
| 38 | + { |
| 39 | + fatalError() |
| 40 | + } |
| 41 | +``` |
| 42 | + |
| 43 | +This is the simplest example to demonstrate how libFuzzer find a specified input (`FUZZIT`) that triggers `fatalErro` |
| 44 | +using guided code coverage fuzzing. |
| 45 | + |
| 46 | + |
| 47 | +### Setting up the development environment |
| 48 | + |
| 49 | +libFuzzer is built-in in swift toolchain in the latest development releases. We created a [docker](https://github.com/fuzzitdev/fuzzit/blob/master/docker/ubuntu/bionic/swift/Dockerfile) |
| 50 | +image with bionic-swift-5.1-dev and clang-9 hosted at `gcr.io/fuzzit-public/bionic-swift51` |
| 51 | + |
| 52 | +```bash |
| 53 | +docker run -it gcr.io/fuzzit-public/bionic-swift51:beb0e9b /bin/bash |
| 54 | + |
| 55 | +# Build libFuzzer target |
| 56 | +git clone https://github.com/fuzzitdev/example-swift |
| 57 | +cd example-swift |
| 58 | +swift build -c release -Xswiftc -sanitize=fuzzer -Xswiftc -parse-as-library |
| 59 | + |
| 60 | +# Run libFuzzer |
| 61 | +./.build/release/example-swift |
| 62 | +``` |
| 63 | + |
| 64 | +Will print the following output and stacktrace: |
| 65 | + |
| 66 | +```text |
| 67 | +==66== ERROR: libFuzzer: deadly signal |
| 68 | + #0 0x558dcccbfb2f in __sanitizer_print_stack_trace /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc:29:3 |
| 69 | + #1 0x558dccc3f798 in fuzzer::PrintStackTrace() /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:206:5 |
| 70 | + #2 0x558dccc29ff8 in fuzzer::Fuzzer::CrashCallback() /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:237:3 |
| 71 | + #3 0x558dccc29fbf in fuzzer::Fuzzer::StaticCrashSignalCallback() /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:209:6 |
| 72 | + #4 0x7f21dcf8688f (/lib/x86_64-linux-gnu/libpthread.so.0+0x1288f) |
| 73 | + #5 0x7f21dd4e6400 in $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtFTf4xxnnn_n (/usr/lib/swift/linux/libswiftCore.so+0x353400) |
| 74 | + #6 0x7f21dd2e0e38 in $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF (/usr/lib/swift/linux/libswiftCore.so+0x14de38) |
| 75 | + #7 0x558dcccc00fa in $s13example_swift6fuzzMe4data4sizes5Int32VSPys4Int8VG_AFtF (/app/example-swift/.build/x86_64-unknown-linux/release/example-swift+0xb10fa) |
| 76 | + #8 0x558dccc2b54a in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:571:15 |
| 77 | + #9 0x558dccc2ac95 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:480:3 |
| 78 | + #10 0x558dccc2c6ab in fuzzer::Fuzzer::MutateAndTestOne() /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:708:19 |
| 79 | + #11 0x558dccc2d385 in fuzzer::Fuzzer::Loop(std::Fuzzer::vector<std::Fuzzer::basic_string<char, std::Fuzzer::char_traits<char>, std::Fuzzer::allocator<char> >, fuzzer::fuzzer_allocator<std::Fuzzer::basic_string<char, std::Fuzzer::char_traits<char>, std::Fuzzer::allocator<char> > > > const&) /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:839:5 |
| 80 | + #12 0x558dccc26dab in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:764:6 |
| 81 | + #13 0x558dccc3fe32 in main /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/llvm/projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10 |
| 82 | + #14 0x7f21dc1e2b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) |
| 83 | + #15 0x558dccc21279 in _start (/app/example-swift/.build/x86_64-unknown-linux/release/example-swift+0x12279) |
| 84 | +
|
| 85 | +NOTE: libFuzzer has rudimentary signal handlers. |
| 86 | + Combine libFuzzer with AddressSanitizer or similar for better crash reports. |
| 87 | +SUMMARY: libFuzzer: deadly signal |
| 88 | +MS: 2 InsertByte-InsertRepeatedBytes-; base unit: 53bc6cb455c00ab402de0304ec2fb992cf8498bc |
| 89 | +0x46,0x55,0x5a,0x5a,0x49,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x3a,0x5a, |
| 90 | +FUZZIeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee:Z |
| 91 | +artifact_prefix='./'; Test unit written to ./crash-207ef2bb62cc2acee33ea863800c4aa638118df2 |
| 92 | +Base64: RlVaWkllZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZTpa |
| 93 | +
|
| 94 | +``` |
| 95 | + |
| 96 | +## Integrating with Fuzzit from CI |
| 97 | + |
| 98 | +The best way to integrate with Fuzzit is by adding a two stages in your Continuous Build system |
| 99 | +(like Travis CI or Circle CI). |
| 100 | + |
| 101 | +Fuzzing stage: |
| 102 | + |
| 103 | +* Build a fuzzing target |
| 104 | +* Download `fuzzit` cli |
| 105 | +* Authenticate via passing `FUZZIT_API_KEY` environment variable |
| 106 | +* Create a fuzzing job by uploading the fuzzing target |
| 107 | + |
| 108 | +Regression stage |
| 109 | +* Build a fuzzing target |
| 110 | +* Download `fuzzit` cli |
| 111 | +* Authenticate via passing `FUZZIT_API_KEY` environment variable OR defining the corpus as public. This way |
| 112 | +No authentication would be require and regression can be used for [forked PRs](https://docs.travis-ci.com/user/pull-requests#pull-requests-and-security-restrictions) as well |
| 113 | +* Create a local regression fuzzing job - This will pull all the generated corpuses and run them through |
| 114 | +the fuzzing binary. If new bugs are introduced this will fail the CI and alert |
| 115 | + |
| 116 | +Here is the relevant snippet from the [fuzzit.sh](https://github.com/fuzzitdev/example-swift/blob/master/fuzzit.sh) |
| 117 | +which is being run by [.travis.yml](https://github.com/fuzzitdev/example-swift/blob/master/.travis.yml) |
| 118 | + |
| 119 | +```bash |
| 120 | +wget -q -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.17/fuzzit_Linux_x86_64 |
| 121 | +chmod a+x fuzzit |
| 122 | + |
| 123 | +## upload fuzz target for long fuzz testing on fuzzit.dev server or run locally for regression |
| 124 | +./fuzzit create job --type ${1} --host bionic-swift51 fuzzitdev/example-swift ./.build/release/example-swift |
| 125 | +``` |
| 126 | + |
| 127 | +In production it is advised to download a pinned version of the [CLI](https://github.com/fuzzitdev/fuzzit) |
| 128 | +like in the example. In development you can use the latest version: |
| 129 | +https://github.com/fuzzitdev/fuzzit/releases/latest/download/fuzzit_${OS}_${ARCH}. |
| 130 | +Valid values for `${OS}` are: `Linux`, `Darwin`, `Windows`. |
| 131 | +Valid values for `${ARCH}` are: `x86_64` and `i386`. |
0 commit comments