1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
|
#!/bin/bash
#
# $Id: fuzz-test.sh 42295 2012-04-27 17:58:06Z morriss $
# Fuzz-testing script for TShark
#
# This script uses Editcap to add random errors ("fuzz") to a set of
# capture files specified on the command line. It runs TShark on
# each fuzzed file and checks for errors. The files are processed
# repeatedly until an error is found.
# This needs to point to a 'date' that supports %s.
DATE=/bin/date
BASE_NAME=fuzz-`$DATE +%Y-%m-%d`-$$
# Directory containing binaries. Default current directory.
BIN_DIR=.
# Temporary file directory and names.
# (had problems with this on cygwin, tried TMP_DIR=./ which worked)
TMP_DIR=/tmp
if [ "$OSTYPE" == "cygwin" ] ; then
TMP_DIR=`cygpath --windows "$TMP_DIR"`
fi
TMP_FILE=$BASE_NAME.pcap
ERR_FILE=$BASE_NAME.err
# Loop this many times (< 1 loops forever)
MAX_PASSES=0
# Did we catch a signal?
DONE=0
# Perform a two pass analysis on the capture file?
TWO_PASS=
# Specific config profile ?
CONFIG_PROFILE=
# These may be set to your liking
# Stop the child process if it's running longer than x seconds
MAX_CPU_TIME=900
# Stop the child process if it's using more than y * 1024 bytes
MAX_VMEM=500000
# Stop the child process if its stack is larger than than z * 1024 bytes
# Windows XP: 2033
# Windows 7: 2034
# OS X 10.6: 8192
# Linux 2.6.24: 8192
# Solaris 10: 8192
MAX_STACK=2033
# Insert z times an error into the capture file (0.02 seems to be a good value to find errors)
ERR_PROB=0.02
# Trigger an abort if a dissector finds a bug.
# Uncomment to enable
# Note that if ABORT is enabled there will be no info
# output to stderr about the DISSECTOR_BUG.
# (There'll just be a core-dump).
###export WIRESHARK_ABORT_ON_DISSECTOR_BUG="True"
# To do: add options for file names and limits
while getopts ":b:d:e:C:Pp:" OPTCHAR ; do
case $OPTCHAR in
b) BIN_DIR=$OPTARG ;;
C) CONFIG_PROFILE="-C $OPTARG " ;;
d) TMP_DIR=$OPTARG ;;
e) ERR_PROB=$OPTARG ;;
p) MAX_PASSES=$OPTARG ;;
P) TWO_PASS="-P " ;;
esac
done
shift $(($OPTIND - 1))
# Tweak the following to your liking. Editcap must support "-E".
TSHARK="$BIN_DIR/tshark"
EDITCAP="$BIN_DIR/editcap"
CAPINFOS="$BIN_DIR/capinfos"
if [ "$BIN_DIR" = "." ]; then
export WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1
fi
# set some limits to the child processes, e.g. stop it if it's running longer then MAX_CPU_TIME seconds
# (ulimit is not supported well on cygwin and probably other platforms, e.g. cygwin shows some warnings)
ulimit -S -t $MAX_CPU_TIME -v $MAX_VMEM -s $MAX_STACK
ulimit -c unlimited
### usually you won't have to change anything below this line ###
# TShark arguments (you won't have to change these)
# n Disable network object name resolution
# V Print a view of the details of the packet rather than a one-line summary of the packet
# x Cause TShark to print a hex and ASCII dump of the packet data after printing the summary or details
# r Read packet data from the following infile
TSHARK_ARGS="${CONFIG_PROFILE}${TWO_PASS}-nVxr"
NOTFOUND=0
for i in "$TSHARK" "$EDITCAP" "$CAPINFOS" "$DATE" "$TMP_DIR" ; do
if [ ! -x $i ]; then
echo "Couldn't find $i"
NOTFOUND=1
fi
done
if [ $NOTFOUND -eq 1 ]; then
exit 1
fi
# Make sure we have a valid test set
FOUND=0
for CF in "$@" ; do
if [ "$OSTYPE" == "cygwin" ] ; then
CF=`cygpath --windows "$CF"`
fi
"$CAPINFOS" "$CF" > /dev/null 2>&1 && FOUND=1
if [ $FOUND -eq 1 ] ; then break ; fi
done
if [ $FOUND -eq 0 ] ; then
cat <<FIN
Error: No valid capture files found.
Usage: `basename $0` [-b bin_dir] [-C config_profile] [-p passes] [-d work_dir] [-P ] [-e error probability] capture file 1 [capture file 2]...
FIN
exit 1
fi
DISSECTOR_PLUGINS=`$TSHARK -G plugins | grep dissector | wc -l`
# 10 is an arbritary value.
if [ $DISSECTOR_PLUGINS -lt 10 ] ; then
echo "Error: Found fewer plugins than expected."
exit 1
fi
HOWMANY="forever"
if [ $MAX_PASSES -gt 0 ]; then
HOWMANY="$MAX_PASSES passes"
fi
echo "Running $TSHARK with args: $TSHARK_ARGS ($HOWMANY)"
echo ""
# Clean up on <ctrl>C, etc
trap "DONE=1; echo 'Caught signal'" HUP INT TERM
##############################################################################
### Set up environment variables for fuzz testing ###
##############################################################################
# Initialize (ep_ and se_) allocated memory to 0xBADDCAFE and freed memory
# to 0xDEADBEEF
export WIRESHARK_DEBUG_SCRUB_MEMORY=
# Use canaries in se_ allocations (off by default due to the memory usage)
export WIRESHARK_DEBUG_SE_USE_CANARY=
# Verify that ep_ and se_ allocated memory is not passed to certain routines
# which need the memory to be persistent.
export WIRESHARK_EP_VERIFY_POINTERS=
export WIRESHARK_SE_VERIFY_POINTERS=
# Turn on GLib memory debugging (since 2.13)
export G_SLICE=debug-blocks
# Cause glibc (Linux) to abort() if some memory errors are found
export MALLOC_CHECK_=3
# Cause FreeBSD (and other BSDs) to abort() on allocator warnings and
# initialize allocated memory (to 0xa5) and freed memory (to 0x5a). see:
# http://www.freebsd.org/cgi/man.cgi?query=malloc&apropos=0&sektion=0&manpath=FreeBSD+8.2-RELEASE&format=html
export MALLOC_OPTIONS=AJ
# MacOS options; see http://developer.apple.com/library/mac/releasenotes/DeveloperTools/RN-MallocOptions/_index.html
# Initialize allocated memory to 0xAA and freed memory to 0x55
export MallocPreScribble=1
export MallocScribble=1
# Add guard pages before and after large allocations
export MallocGuardEdges=1
# Call abort() if heap corruption is detected. Heap is checked every 1000
# allocations (may need to be tuned!)
export MallocCheckHeapStart=1000
export MallocCheckHeapEach=1000
export MallocCheckHeapAbort=1
# Call abort() if an illegal free() call is made
export MallocBadFreeAbort=1
# Iterate over our capture files.
PASS=0
while [ \( $PASS -lt $MAX_PASSES -o $MAX_PASSES -lt 1 \) -a $DONE -ne 1 ] ; do
PASS=`expr $PASS + 1`
echo "Starting pass $PASS:"
RUN=0
for CF in "$@" ; do
if [ $DONE -eq 1 ]; then
break # We caught a signal
fi
RUN=$(( $RUN + 1 ))
if [ $(( $RUN % 50 )) -eq 0 ] ; then
echo " [Pass $PASS]"
fi
if [ "$OSTYPE" == "cygwin" ] ; then
CF=`cygpath --windows "$CF"`
fi
echo -n " $CF: "
"$CAPINFOS" "$CF" > /dev/null 2> $TMP_DIR/$ERR_FILE
RETVAL=$?
if [ $RETVAL -eq 1 ] ; then
echo "Not a valid capture file"
rm -f $TMP_DIR/$ERR_FILE
continue
elif [ $RETVAL -ne 0 -a $DONE -ne 1 ] ; then
# Some other error
echo ""
echo " ERROR"
echo -e "Processing failed. Capture info follows:\n"
echo " Input file: $CF"
echo -e "stderr follows:\n"
cat $TMP_DIR/$ERR_FILE
exit 1
fi
DISSECTOR_BUG=0
"$EDITCAP" -E $ERR_PROB "$CF" $TMP_DIR/$TMP_FILE > /dev/null 2>&1
if [ $? -ne 0 ] ; then
"$EDITCAP" -E $ERR_PROB -T ether "$CF" $TMP_DIR/$TMP_FILE \
> /dev/null 2>&1
if [ $? -ne 0 ] ; then
echo "Invalid format for editcap"
continue
fi
fi
"$TSHARK" $TSHARK_ARGS $TMP_DIR/$TMP_FILE \
> /dev/null 2>> $TMP_DIR/$ERR_FILE
RETVAL=$?
# Uncomment the next two lines to enable dissector bug
# checking.
#grep -i "dissector bug" $TMP_DIR/$ERR_FILE \
# > /dev/null 2>&1 && DISSECTOR_BUG=1
if [ \( $RETVAL -ne 0 -o $DISSECTOR_BUG -ne 0 \) -a $DONE -ne 1 ] ; then
echo ""
echo " ERROR"
echo -e "Processing failed. Capture info follows:\n"
echo " Output file: $TMP_DIR/$TMP_FILE"
echo -e "stderr follows:\n"
cat $TMP_DIR/$ERR_FILE
exit 1
fi
echo " OK"
rm -f $TMP_DIR/$TMP_FILE $TMP_DIR/$ERR_FILE
done
done
|