nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/bin/bash |
2 | # |
||
3 | # Fuzz-testing script for TShark |
||
4 | # |
||
5 | # This script uses Editcap to add random errors ("fuzz") to a set of |
||
6 | # capture files specified on the command line. It runs TShark on |
||
7 | # each fuzzed file and checks for errors. The files are processed |
||
8 | # repeatedly until an error is found. |
||
9 | # |
||
10 | # Copyright 2013 Gerald Combs <gerald@wireshark.org> |
||
11 | # |
||
12 | # Wireshark - Network traffic analyzer |
||
13 | # By Gerald Combs <gerald@wireshark.org> |
||
14 | # Copyright 1998 Gerald Combs |
||
15 | # |
||
16 | # This program is free software; you can redistribute it and/or |
||
17 | # modify it under the terms of the GNU General Public License |
||
18 | # as published by the Free Software Foundation; either version 2 |
||
19 | # of the License, or (at your option) any later version. |
||
20 | # |
||
21 | # This program is distributed in the hope that it will be useful, |
||
22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
24 | # GNU General Public License for more details. |
||
25 | # |
||
26 | # You should have received a copy of the GNU General Public License |
||
27 | # along with this program; if not, write to the Free Software |
||
28 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
29 | |||
30 | TEST_TYPE="fuzz" |
||
31 | . `dirname $0`/test-common.sh || exit 1 |
||
32 | |||
33 | # Sanity check to make sure we can find our plugins. Zero or less disables. |
||
34 | MIN_PLUGINS=0 |
||
35 | |||
36 | # Did we catch a signal? |
||
37 | DONE=0 |
||
38 | |||
39 | # Perform a two pass analysis on the capture file? |
||
40 | TWO_PASS= |
||
41 | |||
42 | # Specific config profile ? |
||
43 | CONFIG_PROFILE= |
||
44 | |||
45 | # Run under valgrind ? |
||
46 | VALGRIND=0 |
||
47 | |||
48 | # Run under AddressSanitizer ? |
||
49 | ASAN=$CONFIGURED_WITH_ASAN |
||
50 | |||
51 | # Don't skip any byte from being changed |
||
52 | CHANGE_OFFSET=0 |
||
53 | |||
54 | # The maximum permitted amount of memory leaked. Eventually this should be |
||
55 | # worked down to zero, but right now that would fail on every single capture. |
||
56 | # Only has effect when running under valgrind. |
||
57 | MAX_LEAK=`expr 1024 \* 100` |
||
58 | |||
59 | # To do: add options for file names and limits |
||
60 | while getopts "2b:C:d:e:agp:P:o:" OPTCHAR ; do |
||
61 | case $OPTCHAR in |
||
62 | a) ASAN=1 ;; |
||
63 | 2) TWO_PASS="-2 " ;; |
||
64 | b) WIRESHARK_BIN_DIR=$OPTARG ;; |
||
65 | C) CONFIG_PROFILE="-C $OPTARG " ;; |
||
66 | d) TMP_DIR=$OPTARG ;; |
||
67 | e) ERR_PROB=$OPTARG ;; |
||
68 | g) VALGRIND=1 ;; |
||
69 | p) MAX_PASSES=$OPTARG ;; |
||
70 | P) MIN_PLUGINS=$OPTARG ;; |
||
71 | o) CHANGE_OFFSET=$OPTARG ;; |
||
72 | esac |
||
73 | done |
||
74 | shift $(($OPTIND - 1)) |
||
75 | |||
76 | ### usually you won't have to change anything below this line ### |
||
77 | |||
78 | ws_bind_exec_paths |
||
79 | ws_check_exec "$TSHARK" "$EDITCAP" "$CAPINFOS" "$DATE" "$TMP_DIR" |
||
80 | |||
81 | COMMON_ARGS="${CONFIG_PROFILE}${TWO_PASS}" |
||
82 | if [ $VALGRIND -eq 1 ]; then |
||
83 | RUNNER="`dirname $0`/valgrind-wireshark.sh" |
||
84 | COMMON_ARGS="-b $WIRESHARK_BIN_DIR $COMMON_ARGS" |
||
85 | declare -a RUNNER_ARGS=("" "-T") |
||
86 | # Valgrind requires more resources, so permit 1.5x memory and 3x time |
||
87 | # (1.5x time is too small for a few large captures in the menagerie) |
||
88 | MAX_CPU_TIME=`expr 3 \* $MAX_CPU_TIME` |
||
89 | MAX_VMEM=`expr 3 \* $MAX_VMEM / 2` |
||
90 | else |
||
91 | # Not using valgrind, use regular tshark. |
||
92 | # TShark arguments (you won't have to change these) |
||
93 | # n Disable network object name resolution |
||
94 | # V Print a view of the details of the packet rather than a one-line summary of the packet |
||
95 | # x Cause TShark to print a hex and ASCII dump of the packet data after printing the summary or details |
||
96 | # r Read packet data from the following infile |
||
97 | RUNNER="$TSHARK" |
||
98 | declare -a RUNNER_ARGS=("-nVxr" "-nr") |
||
99 | # Running with a read filter but without generating the tree exposes some |
||
100 | # "More than 100000 items in tree" bugs. |
||
101 | # Not sure if we want to add even more cycles to the fuzz bot's work load... |
||
102 | #declare -a RUNNER_ARGS=("${CONFIG_PROFILE}${TWO_PASS}-nVxr" "${CONFIG_PROFILE}${TWO_PASS}-nr" "-Yframe ${CONFIG_PROFILE}${TWO_PASS}-nr") |
||
103 | fi |
||
104 | |||
105 | |||
106 | # Make sure we have a valid test set |
||
107 | FOUND=0 |
||
108 | for CF in "$@" ; do |
||
109 | if [ "$OSTYPE" == "cygwin" ] ; then |
||
110 | CF=`cygpath --windows "$CF"` |
||
111 | fi |
||
112 | "$CAPINFOS" "$CF" > /dev/null 2>&1 && FOUND=1 |
||
113 | if [ $FOUND -eq 1 ] ; then break ; fi |
||
114 | done |
||
115 | |||
116 | if [ $FOUND -eq 0 ] ; then |
||
117 | cat <<FIN |
||
118 | Error: No valid capture files found. |
||
119 | |||
120 | Usage: `basename $0` [-2] [-b bin_dir] [-C config_profile] [-d work_dir] [-e error probability] [-o changes offset] [-g] [-a] [-p passes] capture file 1 [capture file 2]... |
||
121 | FIN |
||
122 | exit 1 |
||
123 | fi |
||
124 | |||
125 | PLUGIN_COUNT=`$TSHARK -G plugins | grep dissector | wc -l` |
||
126 | if [ $MIN_PLUGINS -gt 0 -a $PLUGIN_COUNT -lt $MIN_PLUGINS ] ; then |
||
127 | echo "Warning: Found fewer plugins than expected ($PLUGIN_COUNT vs $MIN_PLUGINS)." |
||
128 | exit 1 |
||
129 | fi |
||
130 | |||
131 | if [ $ASAN -ne 0 ]; then |
||
132 | echo -n "ASan enabled. Virtual memory limit is " |
||
133 | ulimit -v |
||
134 | else |
||
135 | echo "ASan disabled. Virtual memory limit is $MAX_VMEM" |
||
136 | fi |
||
137 | |||
138 | HOWMANY="forever" |
||
139 | if [ $MAX_PASSES -gt 0 ]; then |
||
140 | HOWMANY="$MAX_PASSES passes" |
||
141 | fi |
||
142 | echo -n "Running $RUNNER $COMMON_ARGS with args: " |
||
143 | printf "\"%s\" " "${RUNNER_ARGS[@]}" |
||
144 | echo "($HOWMANY)" |
||
145 | echo "" |
||
146 | |||
147 | # Clean up on <ctrl>C, etc |
||
148 | trap "DONE=1; echo 'Caught signal'" HUP INT TERM |
||
149 | |||
150 | |||
151 | # Iterate over our capture files. |
||
152 | PASS=0 |
||
153 | while [ \( $PASS -lt $MAX_PASSES -o $MAX_PASSES -lt 1 \) -a $DONE -ne 1 ] ; do |
||
154 | let PASS=$PASS+1 |
||
155 | echo "Starting pass $PASS:" |
||
156 | RUN=0 |
||
157 | |||
158 | for CF in "$@" ; do |
||
159 | if [ $DONE -eq 1 ]; then |
||
160 | break # We caught a signal |
||
161 | fi |
||
162 | RUN=$(( $RUN + 1 )) |
||
163 | if [ $(( $RUN % 50 )) -eq 0 ] ; then |
||
164 | echo " [Pass $PASS]" |
||
165 | fi |
||
166 | if [ "$OSTYPE" == "cygwin" ] ; then |
||
167 | CF=`cygpath --windows "$CF"` |
||
168 | fi |
||
169 | echo -n " $CF: " |
||
170 | |||
171 | "$CAPINFOS" "$CF" > /dev/null 2> $TMP_DIR/$ERR_FILE |
||
172 | RETVAL=$? |
||
173 | if [ $RETVAL -eq 1 ] ; then |
||
174 | echo "Not a valid capture file" |
||
175 | rm -f $TMP_DIR/$ERR_FILE |
||
176 | continue |
||
177 | elif [ $RETVAL -ne 0 -a $DONE -ne 1 ] ; then |
||
178 | # Some other error |
||
179 | ws_exit_error |
||
180 | fi |
||
181 | |||
182 | if [ $VALGRIND -eq 1 -a `ls -s $CF | cut -d' ' -f1` -gt 8000 ]; then |
||
183 | echo "Too big for valgrind" |
||
184 | continue |
||
185 | fi |
||
186 | |||
187 | DISSECTOR_BUG=0 |
||
188 | VG_ERR_CNT=0 |
||
189 | |||
190 | "$EDITCAP" -E $ERR_PROB -o $CHANGE_OFFSET "$CF" $TMP_DIR/$TMP_FILE > /dev/null 2>&1 |
||
191 | if [ $? -ne 0 ] ; then |
||
192 | "$EDITCAP" -E $ERR_PROB -o $CHANGE_OFFSET -T ether "$CF" $TMP_DIR/$TMP_FILE \ |
||
193 | > /dev/null 2>&1 |
||
194 | if [ $? -ne 0 ] ; then |
||
195 | echo "Invalid format for editcap" |
||
196 | continue |
||
197 | fi |
||
198 | fi |
||
199 | |||
200 | RUNNER_PIDS= |
||
201 | RUNNER_ERR_FILES= |
||
202 | for ARGS in "${RUNNER_ARGS[@]}" ; do |
||
203 | if [ $DONE -eq 1 ]; then |
||
204 | break # We caught a signal |
||
205 | fi |
||
206 | echo -n "($ARGS) " |
||
207 | echo -e "Command and args: $RUNNER $ARGS\n" > $TMP_DIR/$ERR_FILE |
||
208 | |||
209 | # Run in a child process with limits. |
||
210 | ( |
||
211 | # Set some limits to the child processes, e.g. stop it if |
||
212 | # it's running longer than MAX_CPU_TIME seconds. (ulimit |
||
213 | # is not supported well on cygwin - it shows some warnings - |
||
214 | # and the features we use may not all be supported on some |
||
215 | # UN*X platforms.) |
||
216 | ulimit -S -t $MAX_CPU_TIME -s $MAX_STACK |
||
217 | |||
218 | # Allow core files to be generated |
||
219 | ulimit -c unlimited |
||
220 | |||
221 | # Don't enable ulimit -v when using ASAN. See |
||
222 | # https://github.com/google/sanitizers/wiki/AddressSanitizer#ulimit--v |
||
223 | if [ $ASAN -eq 0 ]; then |
||
224 | ulimit -S -v $MAX_VMEM |
||
225 | fi |
||
226 | |||
227 | SUBSHELL_PID=$($SHELL -c 'echo $PPID') |
||
228 | |||
229 | "$RUNNER" $COMMON_ARGS $ARGS $TMP_DIR/$TMP_FILE \ |
||
230 | > /dev/null 2>> $TMP_DIR/$ERR_FILE.$SUBSHELL_PID |
||
231 | ) & |
||
232 | RUNNER_PID=$! |
||
233 | RUNNER_PIDS="$RUNNER_PIDS $RUNNER_PID" |
||
234 | RUNNER_ERR_FILES="$RUNNER_ERR_FILES $TMP_DIR/$ERR_FILE.$RUNNER_PID" |
||
235 | done |
||
236 | |||
237 | for RUNNER_PID in $RUNNER_PIDS ; do |
||
238 | wait $RUNNER_PID |
||
239 | RETVAL=$? |
||
240 | mv $TMP_DIR/$ERR_FILE.$RUNNER_PID $TMP_DIR/$ERR_FILE |
||
241 | |||
242 | # Uncomment the next two lines to enable dissector bug |
||
243 | # checking. |
||
244 | #grep -i "dissector bug" $TMP_DIR/$ERR_FILE \ |
||
245 | # > /dev/null 2>&1 && DISSECTOR_BUG=1 |
||
246 | |||
247 | if [ $VALGRIND -eq 1 -a $DONE -ne 1 ]; then |
||
248 | VG_ERR_CNT=`grep "ERROR SUMMARY:" $TMP_DIR/$ERR_FILE | cut -f4 -d' '` |
||
249 | VG_DEF_LEAKED=`grep "definitely lost:" $TMP_DIR/$ERR_FILE | cut -f7 -d' ' | tr -d ,` |
||
250 | VG_IND_LEAKED=`grep "indirectly lost:" $TMP_DIR/$ERR_FILE | cut -f7 -d' ' | tr -d ,` |
||
251 | VG_TOTAL_LEAKED=`expr $VG_DEF_LEAKED + $VG_IND_LEAKED` |
||
252 | if [ $? -ne 0 ] ; then |
||
253 | echo "General Valgrind failure." |
||
254 | VG_ERR_CNT=1 |
||
255 | elif [ "$VG_TOTAL_LEAKED" -gt "$MAX_LEAK" ] ; then |
||
256 | echo "Definitely + indirectly ($VG_DEF_LEAKED + $VG_IND_LEAKED) exceeds max ($MAX_LEAK)." |
||
257 | VG_ERR_CNT=1 |
||
258 | fi |
||
259 | if grep -q "Valgrind cannot continue" $TMP_DIR/$ERR_FILE; then |
||
260 | echo "Valgrind unable to continue." |
||
261 | VG_ERR_CNT=-1 |
||
262 | fi |
||
263 | fi |
||
264 | |||
265 | if [ $DONE -ne 1 -a \( $RETVAL -ne 0 -o $DISSECTOR_BUG -ne 0 -o $VG_ERR_CNT -ne 0 \) ] ; then |
||
266 | rm -f $RUNNER_ERR_FILES |
||
267 | ws_exit_error |
||
268 | fi |
||
269 | done |
||
270 | |||
271 | echo " OK" |
||
272 | rm -f $TMP_DIR/$TMP_FILE $TMP_DIR/$ERR_FILE |
||
273 | done |
||
274 | done |