Skip to content

Commit

Permalink
Open source DangSan
Browse files Browse the repository at this point in the history
  • Loading branch information
Erik van der Kouwe committed Mar 19, 2017
0 parents commit 78006af
Show file tree
Hide file tree
Showing 398 changed files with 88,726 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*~
*.swp
gperftools/*
/autosetup.dir/
/run-*.sh
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# DangSan

DangSan instruments programs written in C or C++ to invalidate pointers
whenever a block of memory is freed, preventing dangling pointers.
Instead, whenever such a pointer is dereferenced, it refers to unmapped memory
and results in a crash. As a consequence, attackers can no longer exploit
dangling pointers.

For more information, see the paper "DangSan: Scalable Use-after-free
Detection" by Erik van der Kouwe, Vinod Nigade, and Cristiano Giuffrida,
presented at the EuroSys 2017 conference.

## Terminology

To explain our system to automatically build DangSan and instrument programs,
we will use the following terms: instance and target.

An instance is a compiler configuration used to instrument a program.
Instances provided by this repository are:

* baseline-lto compiles a program without instrumentation, using LLVM with
link-time optimizations and using the base version of tcmalloc;
* dangsan instruments the program with our pointer tracker;
* dangsan-stats instruments the program using a static library that tracks
various statistics about DangSan's work (this instance should not be used
for performance measurements).

A target is a program to be instrumented by DangSan. We include support for two
targets by default:

* parsec is the PARSEC 3.0 benchmarking suite;
* spec-cpu2006 is the SPEC CPU2006 benchmarking suite.

## Prerequistes

DangSan runs on Linux and was tested on Ubuntu 16.04.2 LTS 64-bit.
It requires a number of packages to be installed, depending on the particular
Linux distribution used. In case of Ubuntu 16.04.2 LTS, the following command
installs the required packages (on a clean server installation):

sudo apt-get install bison build-essential gettext git pkg-config python ssh subversion

Our prototype includes scripts to instrument the SPEC CPU2006 and PARSEC
benchmarks. While PARSEC is open source and automatically downloaded installed
by our scripts, SPEC CPU2006 is not freely available and must be supplied
by the user.

Our prototype requires about 22GB of disk space, which includes about 2GB
for the SPEC CPU2006 installation and about 11GB for the PARSEC installation.
Both of these are optional.

## Installation

First, obtain the DangSan source code:

git clone https://github.com/vusec/dangsan.git

The following command automatically installs remaining dependencies locally
(no need for root access), builds DangSan, builds all targets for all instances,
and generate scripts to run the targets conveniently:

cd dangsan
PATHSPEC=/path/to/spec/cpu2006 ./autosetup.sh

To control which targets are built, set and export the TARGETS environment
variable to a space-separated (possibly empty) list of desired targets.
Currently supported options are parsec and spec-cpu2006. The default is to build
all targets.

When building the SPEC CPU2006 target, PATHSPEC must point to an existing
SPEC CPU2006 installation. We recommend creating a fresh installation for
DangSan to use because we need to apply some (very minor) patches.

## Running benchmarks

After building DangSan and the desired targets, the targets can be executed
using the run scripts generated in the root directory of the DangSan repository.
The run scripts pass along parameters to the run utility supplied by the
benchmarking suite to allow the user to specify the benchmark and any other
settings. There is a separate run script for each instance. For example,
run-parsec-dangsan.sh runs the parsec target instrumented with DangSan.

For example, to run the bzip2 benchmark from SPEC CPU2006 instrumented by
DangSan, use the following command:

./run-spec-cpu2006-dangsan.sh 401.bzip2

To run the blackscholes benchmark from PARSEC in a baseline configuration
using 16 threads, use the following command:

./run-parsec-baseline-lto.sh -p parsec.blackscholes -n 16 -i native

Lists of available benchmarks can be found in
autosetup/targets/{parsec,spec-cpu2006}/benchmarks.inc.

## Analyzing results

The run scripts write logs to the standard output. To analyze the results after
running a number of benchmarks, redirect each output to a separate file and pass
the names of output files (or, alternatively, the name of the directory
containing the output files) to scripts/analyze-logs.py.
288 changes: 288 additions & 0 deletions autosetup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
#!/bin/bash

set -e

: ${PATHROOT:="$PWD"}
if [ ! -f "$PATHROOT/autosetup.sh" ]; then
echo "Please execute from the root of the repository or set PATHROOT" >&2
exit 1
fi

source "$PATHROOT/autosetup/config.inc"
source "$PATHROOT/autosetup/paths.inc"

corecount="`grep '^processor' /proc/cpuinfo|wc -l`"
[ "$corecount" -le "$JOBSMAX" ] || corecount="$JOBSMAX"

: ${EXTRA_CFLAGS:=""}
: ${EXTRA_LDFLAGS:=""}
: ${JOBS="$corecount"}
: ${NO_PACKAGES:=0}
: ${NO_PERL:=0}

# framework
: ${VERSIONGPERFTOOLS=c46eb1f3d2f7a2bdc54a52ff7cf5e7392f5aa668}

# packages
: ${VERSIONAUTOCONF=autoconf-2.68}
: ${VERSIONAUTOMAKE=automake-1.15}
: ${VERSIONBASH=bash-4.3}
: ${VERSIONBINUTILS=binutils-2.26.1}
: ${VERSIONCMAKE=cmake-3.4.1}
: ${VERSIONCMAKEURL=v3.4}
: ${VERSIONCOREUTILS=coreutils-8.22}
: ${VERSIONLIBTOOL=libtool-2.4.6}
: ${VERSIONLIBUNWIND=libunwind-1.2-rc1}
: ${VERSIONLLVM:=251286}
: ${VERSIONLLVMPATCH:=3.8}
: ${VERSIONM4=m4-1.4.18}
: ${VERSIONMAKE=make-4.2}
: ${VERSIONPERL=perl-5.8.8} # set to 'none' to avoid Perl install
: ${VERSIONPERLURL=5.0}

# targets
: ${VERSIONPARSEC:=parsec-3.0}
: ${VERSIONPARSECURL:=3.0}

PATHBINUTILS="$PATHAUTOPACKSRC/$VERSIONBINUTILS"
PATHLIBUNWIND="$PATHAUTOPACKSRC/$VERSIONLIBUNWIND"

export PATH="$PATHAUTOPREFIX/bin:$PATH"

logdir="$(dirname "$PATHLOG")"
[ -e "$logdir" ] || mkdir -p "$logdir"
exec 5> "$PATHLOG"

run()
{
echo -------------------------------------------------------------------------------- >&5
echo "command: $*" >&5
echo "\$PATH: $PATH" >&5
echo "\$LD_LIBRARY_PATH: $LD_LIBRARY_PATH" >&5
echo "working dir: $PWD" >&5
echo -------------------------------------------------------------------------------- >&5
success=0
if [ "$logsuffix" = "" ]; then
pathlog="$PATHLOG"
"$@" >&5 2>&5 && success=1
else
pathlog="$PATHLOG.$logsuffix.txt"
echo "logging to $pathlog" >&5
"$@" > "$pathlog" 2>&1 && success=1
fi
if [ "$success" -ne 0 ]; then
echo "[done]" >&5
else
echo "Command '$*' failed in directory $PWD with exit code $?, please check $pathlog for details" >&2
exit 1
fi
}

runscript_common_start()
{
echo "#!/bin/bash"
echo "set -e"
echo "export LD_LIBRARY_PATH=\"$prefixlib:$PATHAUTOPREFIX/lib:\$LD_LIBRARY_PATH\""
echo "export PATH=\"$PATHAUTOPREFIX/bin:\$PATH\""
echo "export TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD=281474976710656"
[ -z "$CONFIG_SAFESTACK_OPTIONS" ] || echo "export SAFESTACK_OPTIONS=$CONFIG_SAFESTACK_OPTIONS"
echo "PATHROOT=\"$PATHROOT\""
echo ": \${RUNSCRIPTVERBOSE=0}"
echo ""
echo "echo \"[autosetup-runscript] target=$target\""
echo "echo \"[autosetup-runscript] instancename=$instancename\""
echo "echo \"[autosetup-runscript] cmd=\$*\""
echo "echo \"[autosetup-runscript] cwd=\`pwd\`\""
echo "echo \"[autosetup-runscript] LD_LIBRARY_PATH=\$LD_LIBRARY_PATH\""
echo "echo \"[autosetup-runscript] PATH=\$PATH\""
echo "echo \"[autosetup-runscript] PATHROOT=$PATHROOT\""
echo "echo \"[autosetup-runscript] commit=`git log -n1 --oneline`\""
echo "echo \"[autosetup-runscript] kernel=\`uname -s\`\""
echo "echo \"[autosetup-runscript] kernel-release=\`uname -r\`\""
echo "echo \"[autosetup-runscript] kernel-version=\`uname -v\`\""
echo "echo \"[autosetup-runscript] machine=\`uname -m\`\""
echo "echo \"[autosetup-runscript] node=\`uname -n\`\""
echo "if [ \"\$RUNSCRIPTVERBOSE\" -ne 0 ]; then"
echo "echo \"[autosetup-runscript] meminfo-start\""
echo "cat /proc/meminfo"
echo "echo \"[autosetup-runscript] meminfo-end\""
echo "echo \"[autosetup-runscript] cpuinfo-start\""
echo "cat /proc/cpuinfo"
echo "echo \"[autosetup-runscript] cpuinfo-end\""
echo "fi"
echo "echo \"[autosetup-runscript] date-start=\`date +%Y-%m-%dT%H:%M:%S\`\""
echo ""
}

runscript_common_end()
{
echo ""
echo "echo \"[autosetup-runscript] date-end=\`date +%Y-%m-%dT%H:%M:%S\`\""
}

echo "Creating directories"
run mkdir -p "$PATHAUTOFRAMEWORKSRC"
run mkdir -p "$PATHAUTOPACKSRC"
run mkdir -p "$PATHAUTOSCRIPTSBUILD"
run mkdir -p "$PATHAUTOSCRIPTSRUN"
run mkdir -p "$PATHAUTOSTATE"
run mkdir -p "$PATHAUTOTARGETSRC"

export CFLAGS="-I$PATHAUTOPREFIX/include"
export CPPFLAGS="-I$PATHAUTOPREFIX/include"
export LDFLAGS="-L$PATHAUTOPREFIX/lib"

if [ "$NO_PACKAGES" -eq 0 ]; then
# build bash to override the system's default shell
source "$PATHROOT/autosetup/packages/bash.inc"

# build a sane version of coreutils
source "$PATHROOT/autosetup/packages/coreutils.inc"

# build binutils to ensure we have gold
source "$PATHROOT/autosetup/packages/binutils-gold.inc"

# build make
source "$PATHROOT/autosetup/packages/make.inc"

# build m4
source "$PATHROOT/autosetup/packages/m4.inc"

# build autoconf
source "$PATHROOT/autosetup/packages/autoconf.inc"

# build automake
source "$PATHROOT/autosetup/packages/automake.inc"

# build libtool
source "$PATHROOT/autosetup/packages/libtool.inc"

# build cmake, needed to build LLVM
source "$PATHROOT/autosetup/packages/cmake.inc"

# gperftools requires libunwind
source "$PATHROOT/autosetup/packages/libunwind.inc"

# we need a patched LLVM
source "$PATHROOT/autosetup/packages/llvm.inc"
fi

# Build baseline version of gperftools
echo "downloading gperftools"
cd "$PATHAUTOFRAMEWORKSRC"
if [ ! -d gperftools/.git ]; then
run git clone https://github.com/gperftools/gperftools.git
cd gperftools
run git checkout "$VERSIONGPERFTOOLS"
fi
cd "$PATHAUTOFRAMEWORKSRC/gperftools"
if [ ! -f .autosetup.patched-gperftools-speedup ]; then
run patch -p1 < "$PATHROOT/patches/GPERFTOOLS_SPEEDUP.patch"
touch .autosetup.patched-gperftools-speedup
fi
[ -f configure ] || run autoreconf -fi

echo "preparing gperftools-metalloc"
cd "$PATHROOT/gperftools-metalloc"
[ -f configure ] || run autoreconf -fi

for instance in $INSTANCES; do
if [ ! -f "$PATHROOT/autosetup/passes/$instance.inc" ]; then
echo "error: unknown pass: $instance" >&2
exit 1
fi
source "$PATHROOT/autosetup/passes/$instance.inc"

case "$CONFIG_MALLOC" in
default)
# no gperftools
;;
tcmalloc)
# standard tcmalloc
echo "building gperftools-$instance"
run mkdir -p "$PATHAUTOFRAMEWORKOBJ/gperftools-$instance"
cd "$PATHAUTOFRAMEWORKOBJ/gperftools-$instance"
[ -f Makefile ] || run "$PATHAUTOFRAMEWORKSRC/gperftools/configure" --prefix="$PATHAUTOPREFIXBASE/$instance"
run make -j"$JOBS"
run make install
;;
tcmalloc-metalloc)
# modified tcmalloc
echo "building metapagetable-$instance"
cd "$PATHROOT/metapagetable"
export METALLOC_OPTIONS="-DFIXEDCOMPRESSION=$CONFIG_FIXEDCOMPRESSION -DMETADATABYTES=$CONFIG_METADATABYTES -DDEEPMETADATA=$CONFIG_DEEPMETADATA"
[ "true" = "$CONFIG_DEEPMETADATA" ] && METALLOC_OPTIONS="$METALLOC_OPTIONS -DDEEPMETADATABYTES=$CONFIG_DEEPMETADATABYTES"
[ -n "$CONFIG_ALLOC_SIZE_HOOK" ] && METALLOC_OPTIONS="$METALLOC_OPTIONS -DALLOC_SIZE_HOOK=$CONFIG_ALLOC_SIZE_HOOK"
metapagetabledir="$PATHAUTOFRAMEWORKOBJ/metapagetable-$instance"
run make OBJDIR="$metapagetabledir" config
run make OBJDIR="$metapagetabledir" -j"$JOBS"

# Build patched gperftools for new allocator
echo "building gperftools-$instance"
run mkdir -p "$PATHAUTOFRAMEWORKOBJ/gperftools-$instance"
cd "$PATHAUTOFRAMEWORKOBJ/gperftools-$instance"
[ -f Makefile ] || run "$PATHROOT/gperftools-metalloc/configure" --prefix="$PATHAUTOPREFIXBASE/$instance"
run make METAPAGETABLEDIR="$metapagetabledir" -j"$JOBS"
run make METAPAGETABLEDIR="$metapagetabledir" install

echo "building staticlib-$instance"
cd "$PATHROOT/staticlib"
run make METAPAGETABLEDIR="$metapagetabledir" OBJDIR="$PATHAUTOFRAMEWORKOBJ/staticlib-$instance" $CONFIG_STATICLIB_MAKE -j"$JOBS"
;;
*)
echo "error: pass $instance does not define CONFIG_MALLOC" >&2
exit 1
;;
esac
done

echo "building llvm-plugins"
cd "$PATHROOT/llvm-plugins"
run make -j"$JOBS" GOLDINSTDIR="$PATHAUTOPREFIX" TARGETDIR="$PATHLLVMPLUGINS"

echo "initializing targets"
for target in $TARGETS; do
if [ ! -d "$PATHROOT/autosetup/targets/$target" ]; then
echo "error: unknown target: $target" >&2
exit 1
fi
if [ -f "$PATHROOT/autosetup/targets/$target/init.inc" ]; then
source "$PATHROOT/autosetup/targets/$target/init.inc"
fi
done

echo "building nothp"
cd "$PATHROOT/nothp"
run make

# Configure targets
for instance in $INSTANCES; do
instancename="$instance$INSTANCESUFFIX"
source "$PATHROOT/autosetup/passes/$instance.inc"

cflagsbl="$cflags"
[ "$blacklist" = "" ] || cflagsbl="$cflagsbl -fsanitize-blacklist=$blacklist"

for target in $TARGETS; do
echo "configuring $target-$instancename"

if [ -f "$PATHROOT/autosetup/targets/$target/config.inc" ]; then
source "$PATHROOT/autosetup/targets/$target/config.inc"
fi
done
done

# Build targets
for instance in $INSTANCES; do
instancename="$instance$INSTANCESUFFIX"

for target in $TARGETS; do
echo "building $target-$instancename"

if [ -f "$PATHROOT/autosetup/targets/$target/build.inc" ]; then
source "$PATHROOT/autosetup/targets/$target/build.inc"
fi
done
done

echo done
Loading

0 comments on commit 78006af

Please sign in to comment.