diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f740282 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.dockerignore +Dockerfile +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +pip-log.txt +pip-delete-this-directory.txt +*.log +.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7eaa488 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.7-slim + +WORKDIR /deepstate + +COPY . /deepstate + +RUN apt-get update \ + && apt-get install -y build-essential \ + gcc-multilib g++-multilib cmake \ + python3-setuptools libffi-dev z3 \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir build \ + && cd build \ + && cmake ../ \ + && make \ + && cd .. \ + && pip install claripy angr manticore \ + && python ./build/setup.py install + +CMD ["/bin/bash"] diff --git a/README.md b/README.md index d00e719..2aba31a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Slack Chat](http://empireslacking.herokuapp.com/badge.svg)](https://empireslacking.herokuapp.com/) -[![Build Status](https://travis-ci.org/trailofbits/deepstate.svg?branch=master)](https://travis-ci.org/trailofbits/deepstate) +[![Build Status](https://travis-ci.org/trailofbits/deepstate.svg?branch=master)](https://travis-ci.org/trailofbits/deepstate) DeepState is a framework that provides C and C++ developers with a common interface to various symbolic execution and fuzzing engines. Users can write one test harness using a Google Test-like API, then execute it using multiple backends without having to learn the complexities of the underlying engines. It supports writing unit tests and API sequence tests, as well as automatic test generation. Read more about the goals and design of DeepState in our [paper](https://agroce.github.io/bar18.pdf). @@ -131,6 +131,27 @@ argument to see all DeepState options. If you want to use DeepState in C/C++ code, you will likely want to run `sudo make install` from the `$DEEPSTATE/build` directory as well. The examples mentioned below (file system, databases) assume this has already been done. +### Docker + +You can also try out Deepstate with Docker. + +```bash +# Run container with a shared examples/ directory +# Note that `--rm` will make the container be deleted if you exit it +# (if you want to persist data from the container, use docker volumes) +# (we need to increase maximum stack size, so we use ulimit for that) +$ docker run --rm -it --ulimit stack=100000000:100000000 trailofbits/deepstate bash + +# Change to examples directory +root@b7e7bffce292:/deepstate# cd build/examples + +# Fuzz the Runlen example +root@b7e7bffce292:/deepstate/build/examples# deepstate-angr ./Runlen + +# Alternative Runlen example +root@b7e7bffce292:/deepstate/build/examples# ./Runlen --fuzz --exit_on_fail +``` + ## Usage DeepState consists of a static library, used to write test harnesses, @@ -297,8 +318,8 @@ DeepState where to put the generated tests, and if you want the (totally random and unlikely to be high-quality) passing tests, you need to add `--fuzz_save_passing`. -Note that while symbolic execution only works on Linux, without a -fairly complex cross-compilation process, the brute force fuzzer works +Note that while symbolic execution only works on Linux, without a +fairly complex cross-compilation process, the brute force fuzzer works on macOS or (as far as we know) any Unix-like system. ## A Note on MacOS and Forking @@ -350,7 +371,7 @@ CC=/usr/local/opt/llvm\@7/bin/clang CXX=/usr/local/opt/llvm\@7/bin/clang++ BUILD make install ``` -Other ways of getting an appropriate LLVM may also work. +Other ways of getting an appropriate LLVM may also work. On macOS, libFuzzer's normal output is not visible. Because libFuzzer does not fork to execute tests, there is no issue with fork speed on @@ -486,7 +507,7 @@ with some of the advantages of symbolic execution, but with more scalability. D After that, you can use Eclipser like this: -`deepstate-eclisper --timeout --output_test_dir ` +`deepstate-eclipser --timeout --output_test_dir ` In our experience, Eclipser is quite effective, often better than libFuzzer and sometimes better than AFL, despite having a much slower diff --git a/bin/setup.py.in b/bin/setup.py.in index 3bf0a14..e375d51 100644 --- a/bin/setup.py.in +++ b/bin/setup.py.in @@ -30,7 +30,7 @@ setuptools.setup( author_email="peter@trailofbits.com", license="Apache-2.0", keywords="tdd testing symbolic execution", - install_requires=[], #'claripy==7.8.6.16','angr==7.8.7.1', 'manticore'], + install_requires=['claripy', 'angr', 'manticore'], entry_points={ 'console_scripts': [ 'deepstate = deepstate.main_manticore:main', diff --git a/push/publish b/push/publish new file mode 100644 index 0000000..c29c7d3 --- /dev/null +++ b/push/publish @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Publishes the most recent web container to docker hubs repo. +# This script assumes docker push works. +# You must set up docker push on your own. + +set -eu + + +DOCKER_REPO="trailofbits/deepstate" +IMAGE_NAME="deepstate" +echo "IMAGE_NAME $IMAGE_NAME" + +IMAGE_ID=$(docker images $IMAGE_NAME:latest --format "{{.ID}}") + +if [ -n "$DOCKER_USERNAME" ]; then echo "Found username"; fi +if [ -n "$DOCKER_PASSWORD" ]; then echo "Found password"; fi + +if [ -n "$DOCKER_USERNAME" ] && [ -n "$DOCKER_PASSWORD" ]; then + echo "Logging in using ENV creds" + docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" +fi + +echo "Pushing image $IMAGE_NAME:$TRAVIS_BRANCH" +docker tag $IMAGE_ID $DOCKER_REPO +docker tag $IMAGE_ID ${DOCKER_REPO}:${TRAVIS_BUILD_NUMBER} +docker push $DOCKER_REPO +docker push ${DOCKER_REPO}:${TRAVIS_BUILD_NUMBER} diff --git a/push/run.sh b/push/run.sh new file mode 100644 index 0000000..e0c7c78 --- /dev/null +++ b/push/run.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -eu + +IMAGE_NAME="deepstate" +DEPLOY_BRANCHES="master" + +# Only process first job in matrix (TRAVIS_JOB_NUMBER ends with ".1") +if [[ ! $TRAVIS_JOB_NUMBER =~ \.1$ ]]; then + echo "Skipping deploy since it's not the first job in matrix" + exit 0 +fi + +# Don't process pull requests +# $TRAVIS_PULL_REQUEST will be the PR number or "false" if not a PR +if [[ -n "$TRAVIS_PULL_REQUEST" ]] && [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then + echo "Skipping deploy because it's a pull request" + exit 0 +fi + +# Only process branches listed in DEPLOY_BRANCHES +BRANCHES_TO_DEPLOY=($DEPLOY_BRANCHES) +if [[ ! " ${BRANCHES_TO_DEPLOY} " =~ " ${TRAVIS_BRANCH} " ]]; then + # whatever you want to do when arr contains value + echo "Branches to deploy: ${DEPLOY_BRANCHES}" + echo "Travis Branch: ${TRAVIS_BRANCH}" + + echo "Skipping deploy, not a branch to be deployed" + exit 0 +fi + +if [ $? = 0 ]; then + + # Get absolute path of dir where run.sh is located + SOURCE="${BASH_SOURCE[0]}" + while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located + done + export SCRIPTDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + + bash ${SCRIPTDIR}/build && + bash ${SCRIPTDIR}/publish + +fi