]> git.proxmox.com Git - rustc.git/blob - src/libcompiler_builtins/compiler-rt/lib/asan/scripts/asan_device_setup
New upstream version 1.20.0+dfsg1
[rustc.git] / src / libcompiler_builtins / compiler-rt / lib / asan / scripts / asan_device_setup
1 #!/bin/bash
2 #===- lib/asan/scripts/asan_device_setup -----------------------------------===#
3 #
4 # The LLVM Compiler Infrastructure
5 #
6 # This file is distributed under the University of Illinois Open Source
7 # License. See LICENSE.TXT for details.
8 #
9 # Prepare Android device to run ASan applications.
10 #
11 #===------------------------------------------------------------------------===#
12
13 set -e
14
15 HERE="$(cd "$(dirname "$0")" && pwd)"
16
17 revert=no
18 extra_options=
19 device=
20 lib=
21 use_su=0
22
23 function usage {
24 echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
25 echo " --revert: Uninstall ASan from the device."
26 echo " --lib: Path to ASan runtime library."
27 echo " --extra-options: Extra ASAN_OPTIONS."
28 echo " --device: Install to the given device. Use 'adb devices' to find"
29 echo " device-id."
30 echo " --use-su: Use 'su -c' prefix for every adb command instead of using"
31 echo " 'adb root' once."
32 echo
33 exit 1
34 }
35
36 function adb_push {
37 if [ $use_su -eq 0 ]; then
38 $ADB push "$1" "$2"
39 else
40 local FILENAME=$(basename $1)
41 $ADB push "$1" "/data/local/tmp/$FILENAME"
42 $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null
43 $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""
44 $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""
45 fi
46 }
47
48 function adb_remount {
49 if [ $use_su -eq 0 ]; then
50 $ADB remount
51 else
52 local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`
53 if [ "$STORAGE" != "" ]; then
54 echo Remounting $STORAGE at /system
55 $ADB shell su -c "mount -o remount,rw $STORAGE /system"
56 else
57 echo Failed to get storage device name for "/system" mount point
58 fi
59 fi
60 }
61
62 function adb_shell {
63 if [ $use_su -eq 0 ]; then
64 $ADB shell $@
65 else
66 $ADB shell su -c "$*"
67 fi
68 }
69
70 function adb_root {
71 if [ $use_su -eq 0 ]; then
72 $ADB root
73 fi
74 }
75
76 function adb_wait_for_device {
77 $ADB wait-for-device
78 }
79
80 function adb_pull {
81 if [ $use_su -eq 0 ]; then
82 $ADB pull "$1" "$2"
83 else
84 local FILENAME=$(basename $1)
85 $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null
86 $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" &&
87 $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\""
88 fi
89 }
90
91 function get_device_arch { # OUT OUT64
92 local _outvar=$1
93 local _outvar64=$2
94 local _ABI=$(adb_shell getprop ro.product.cpu.abi)
95 local _ARCH=
96 local _ARCH64=
97 if [[ $_ABI == x86* ]]; then
98 _ARCH=i686
99 elif [[ $_ABI == armeabi* ]]; then
100 _ARCH=arm
101 elif [[ $_ABI == arm64-v8a* ]]; then
102 _ARCH=arm
103 _ARCH64=aarch64
104 else
105 echo "Unrecognized device ABI: $_ABI"
106 exit 1
107 fi
108 eval $_outvar=\$_ARCH
109 eval $_outvar64=\$_ARCH64
110 }
111
112 while [[ $# > 0 ]]; do
113 case $1 in
114 --revert)
115 revert=yes
116 ;;
117 --extra-options)
118 shift
119 if [[ $# == 0 ]]; then
120 echo "--extra-options requires an argument."
121 exit 1
122 fi
123 extra_options="$1"
124 ;;
125 --lib)
126 shift
127 if [[ $# == 0 ]]; then
128 echo "--lib requires an argument."
129 exit 1
130 fi
131 lib="$1"
132 ;;
133 --device)
134 shift
135 if [[ $# == 0 ]]; then
136 echo "--device requires an argument."
137 exit 1
138 fi
139 device="$1"
140 ;;
141 --use-su)
142 use_su=1
143 ;;
144 *)
145 usage
146 ;;
147 esac
148 shift
149 done
150
151 ADB=${ADB:-adb}
152 if [[ x$device != x ]]; then
153 ADB="$ADB -s $device"
154 fi
155
156 if [ $use_su -eq 1 ]; then
157 # Test if 'su' is present on the device
158 SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`
159 if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then
160 echo "ERROR: Cannot use 'su -c':"
161 echo "$ adb shell su -c \"echo foo\""
162 echo $SU_TEST_OUT
163 echo "Check that 'su' binary is correctly installed on the device or omit"
164 echo " --use-su flag"
165 exit 1
166 fi
167 fi
168
169 echo '>> Remounting /system rw'
170 adb_wait_for_device
171 adb_root
172 adb_wait_for_device
173 adb_remount
174 adb_wait_for_device
175
176 get_device_arch ARCH ARCH64
177 echo "Target architecture: $ARCH"
178 ASAN_RT="libclang_rt.asan-$ARCH-android.so"
179 if [[ -n $ARCH64 ]]; then
180 echo "Target architecture: $ARCH64"
181 ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"
182 fi
183
184 if [[ x$revert == xyes ]]; then
185 echo '>> Uninstalling ASan'
186
187 if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
188 echo '>> Pre-L device detected.'
189 adb_shell mv /system/bin/app_process.real /system/bin/app_process
190 adb_shell rm /system/bin/asanwrapper
191 elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then
192 # 64-bit installation.
193 adb_shell mv /system/bin/app_process32.real /system/bin/app_process32
194 adb_shell mv /system/bin/app_process64.real /system/bin/app_process64
195 adb_shell rm /system/bin/asanwrapper
196 adb_shell rm /system/bin/asanwrapper64
197 else
198 # 32-bit installation.
199 adb_shell rm /system/bin/app_process.wrap
200 adb_shell rm /system/bin/asanwrapper
201 adb_shell rm /system/bin/app_process
202 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
203 fi
204
205 echo '>> Restarting shell'
206 adb_shell stop
207 adb_shell start
208
209 # Remove the library on the last step to give a chance to the 'su' binary to
210 # be executed without problem.
211 adb_shell rm /system/lib/$ASAN_RT
212
213 echo '>> Done'
214 exit 0
215 fi
216
217 if [[ -d "$lib" ]]; then
218 ASAN_RT_PATH="$lib"
219 elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
220 ASAN_RT_PATH=$(dirname "$lib")
221 elif [[ -f "$HERE/$ASAN_RT" ]]; then
222 ASAN_RT_PATH="$HERE"
223 elif [[ $(basename "$HERE") == "bin" ]]; then
224 # We could be in the toolchain's base directory.
225 # Consider ../lib, ../lib/asan, ../lib/linux,
226 # ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux.
227 P=$(ls "$HERE"/../lib/"$ASAN_RT" \
228 "$HERE"/../lib/asan/"$ASAN_RT" \
229 "$HERE"/../lib/linux/"$ASAN_RT" \
230 "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \
231 "$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
232 if [[ -n "$P" ]]; then
233 ASAN_RT_PATH="$(dirname "$P")"
234 fi
235 fi
236
237 if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
238 echo ">> ASan runtime library not found"
239 exit 1
240 fi
241
242 if [[ -n "$ASAN_RT64" ]]; then
243 if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then
244 echo ">> ASan runtime library not found"
245 exit 1
246 fi
247 fi
248
249 TMPDIRBASE=$(mktemp -d)
250 TMPDIROLD="$TMPDIRBASE/old"
251 TMPDIR="$TMPDIRBASE/new"
252 mkdir "$TMPDIROLD"
253
254 RELEASE=$(adb_shell getprop ro.build.version.release)
255 PRE_L=0
256 if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
257 PRE_L=1
258 fi
259
260 if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
261
262 if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then
263 echo '>> Old-style ASan installation detected. Reverting.'
264 adb_shell mv /system/bin/app_process.real /system/bin/app_process
265 fi
266
267 echo '>> Pre-L device detected. Setting up app_process symlink.'
268 adb_shell mv /system/bin/app_process /system/bin/app_process32
269 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
270 fi
271
272 echo '>> Copying files from the device'
273 if [[ -n "$ASAN_RT64" ]]; then
274 adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
275 adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true
276 adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
277 adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true
278 adb_pull /system/bin/app_process64 "$TMPDIROLD" || true
279 adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true
280 adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
281 adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true
282 else
283 adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
284 adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
285 adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
286 adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
287 fi
288 cp -r "$TMPDIROLD" "$TMPDIR"
289
290 if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then
291 echo ">> Previous installation detected"
292 else
293 echo ">> New installation"
294 fi
295
296 echo '>> Generating wrappers'
297
298 cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
299 if [[ -n "$ASAN_RT64" ]]; then
300 cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"
301 fi
302
303 ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0
304
305 # The name of a symlink to libclang_rt.asan-$ARCH-android.so used in LD_PRELOAD.
306 # The idea is to have the same name in lib and lib64 to keep it from falling
307 # apart when a 64-bit process spawns a 32-bit one, inheriting the environment.
308 ASAN_RT_SYMLINK=symlink-to-libclang_rt.asan
309
310 function generate_zygote_wrapper { # from, to
311 local _from=$1
312 local _to=$2
313 if [[ PRE_L -eq 0 ]]; then
314 # LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is
315 # unset in the system environment since L.
316 local _ld_preload=$ASAN_RT_SYMLINK
317 else
318 local _ld_preload=\$LD_PRELOAD:$ASAN_RT_SYMLINK
319 fi
320 cat <<EOF >"$TMPDIR/$_from"
321 #!/system/bin/sh-from-zygote
322 ASAN_OPTIONS=$ASAN_OPTIONS \\
323 ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
324 LD_PRELOAD=$_ld_preload \\
325 exec $_to \$@
326
327 EOF
328 }
329
330 # On Android-L not allowing user segv handler breaks some applications.
331 if [[ PRE_L -eq 0 ]]; then
332 ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
333 fi
334
335 if [[ x$extra_options != x ]] ; then
336 ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
337 fi
338
339 # Zygote wrapper.
340 if [[ -f "$TMPDIR/app_process64" ]]; then
341 # A 64-bit device.
342 if [[ ! -f "$TMPDIR/app_process64.real" ]]; then
343 # New installation.
344 mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real"
345 mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real"
346 fi
347 generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real"
348 generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real"
349 else
350 # A 32-bit device.
351 generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32"
352 fi
353
354 # General command-line tool wrapper (use for anything that's not started as
355 # zygote).
356 cat <<EOF >"$TMPDIR/asanwrapper"
357 #!/system/bin/sh
358 LD_PRELOAD=$ASAN_RT_SYMLINK \\
359 exec \$@
360
361 EOF
362
363 if [[ -n "$ASAN_RT64" ]]; then
364 cat <<EOF >"$TMPDIR/asanwrapper64"
365 #!/system/bin/sh
366 LD_PRELOAD=$ASAN_RT_SYMLINK \\
367 exec \$@
368
369 EOF
370 fi
371
372 function install { # from, to, chmod, chcon
373 local _from=$1
374 local _to=$2
375 local _mode=$3
376 local _context=$4
377 local _basename="$(basename "$_from")"
378 echo "Installing $_to/$_basename $_mode $_context"
379 adb_push "$_from" "$_to/$_basename"
380 adb_shell chown root.shell "$_to/$_basename"
381 if [[ -n "$_mode" ]]; then
382 adb_shell chmod "$_mode" "$_to/$_basename"
383 fi
384 if [[ -n "$_context" ]]; then
385 adb_shell chcon "$_context" "$_to/$_basename"
386 fi
387 }
388
389 if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
390 # Make SELinux happy by keeping app_process wrapper and the shell
391 # it runs on in zygote domain.
392 ENFORCING=0
393 if adb_shell getenforce | grep Enforcing >/dev/null; then
394 # Sometimes shell is not allowed to change file contexts.
395 # Temporarily switch to permissive.
396 ENFORCING=1
397 adb_shell setenforce 0
398 fi
399
400 if [[ PRE_L -eq 1 ]]; then
401 CTX=u:object_r:system_file:s0
402 else
403 CTX=u:object_r:zygote_exec:s0
404 fi
405
406 echo '>> Pushing files to the device'
407
408 if [[ -n "$ASAN_RT64" ]]; then
409 install "$TMPDIR/$ASAN_RT" /system/lib 644
410 install "$TMPDIR/$ASAN_RT64" /system/lib64 644
411 install "$TMPDIR/app_process32" /system/bin 755 $CTX
412 install "$TMPDIR/app_process32.real" /system/bin 755 $CTX
413 install "$TMPDIR/app_process64" /system/bin 755 $CTX
414 install "$TMPDIR/app_process64.real" /system/bin 755 $CTX
415 install "$TMPDIR/asanwrapper" /system/bin 755
416 install "$TMPDIR/asanwrapper64" /system/bin 755
417
418 adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
419 adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
420 else
421 install "$TMPDIR/$ASAN_RT" /system/lib 644
422 install "$TMPDIR/app_process32" /system/bin 755 $CTX
423 install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
424 install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
425
426 adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
427
428 adb_shell rm /system/bin/app_process
429 adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
430 fi
431
432 adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
433 adb_shell chcon $CTX /system/bin/sh-from-zygote
434
435 if [ $ENFORCING == 1 ]; then
436 adb_shell setenforce 1
437 fi
438
439 echo '>> Restarting shell (asynchronous)'
440 adb_shell stop
441 adb_shell start
442
443 echo '>> Please wait until the device restarts'
444 else
445 echo '>> Device is up to date'
446 fi
447
448 rm -r "$TMPDIRBASE"