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 13set -e 14 15HERE="$(cd "$(dirname "$0")" && pwd)" 16 17revert=no 18extra_options= 19device= 20lib= 21use_su=0 22 23function 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 36function 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 48function 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 62function adb_shell { 63 if [ $use_su -eq 0 ]; then 64 $ADB shell $@ 65 else 66 $ADB shell su -c "$*" 67 fi 68} 69 70function adb_root { 71 if [ $use_su -eq 0 ]; then 72 $ADB root 73 fi 74} 75 76function adb_wait_for_device { 77 $ADB wait-for-device 78} 79 80function 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 91function 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 112while [[ $# > 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 149done 150 151ADB=${ADB:-adb} 152if [[ x$device != x ]]; then 153 ADB="$ADB -s $device" 154fi 155 156if [ $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 167fi 168 169echo '>> Remounting /system rw' 170adb_wait_for_device 171adb_root 172adb_wait_for_device 173adb_remount 174adb_wait_for_device 175 176get_device_arch ARCH ARCH64 177echo "Target architecture: $ARCH" 178ASAN_RT="libclang_rt.asan-$ARCH-android.so" 179if [[ -n $ARCH64 ]]; then 180 echo "Target architecture: $ARCH64" 181 ASAN_RT64="libclang_rt.asan-$ARCH64-android.so" 182fi 183 184RELEASE=$(adb_shell getprop ro.build.version.release) 185PRE_L=0 186if echo "$RELEASE" | grep '^4\.' >&/dev/null; then 187 PRE_L=1 188fi 189ANDROID_O=0 190if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then 191 # 8.0.x is for Android O 192 ANDROID_O=1 193fi 194 195if [[ x$revert == xyes ]]; then 196 echo '>> Uninstalling ASan' 197 198 if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then 199 echo '>> Pre-L device detected.' 200 adb_shell mv /system/bin/app_process.real /system/bin/app_process 201 adb_shell rm /system/bin/asanwrapper 202 elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then 203 # 64-bit installation. 204 adb_shell mv /system/bin/app_process32.real /system/bin/app_process32 205 adb_shell mv /system/bin/app_process64.real /system/bin/app_process64 206 adb_shell rm /system/bin/asanwrapper 207 adb_shell rm /system/bin/asanwrapper64 208 else 209 # 32-bit installation. 210 adb_shell rm /system/bin/app_process.wrap 211 adb_shell rm /system/bin/asanwrapper 212 adb_shell rm /system/bin/app_process 213 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process 214 fi 215 216 if [[ ANDROID_O -eq 1 ]]; then 217 adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt 218 fi 219 220 echo '>> Restarting shell' 221 adb_shell stop 222 adb_shell start 223 224 # Remove the library on the last step to give a chance to the 'su' binary to 225 # be executed without problem. 226 adb_shell rm /system/lib/$ASAN_RT 227 228 echo '>> Done' 229 exit 0 230fi 231 232if [[ -d "$lib" ]]; then 233 ASAN_RT_PATH="$lib" 234elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then 235 ASAN_RT_PATH=$(dirname "$lib") 236elif [[ -f "$HERE/$ASAN_RT" ]]; then 237 ASAN_RT_PATH="$HERE" 238elif [[ $(basename "$HERE") == "bin" ]]; then 239 # We could be in the toolchain's base directory. 240 # Consider ../lib, ../lib/asan, ../lib/linux, 241 # ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux. 242 P=$(ls "$HERE"/../lib/"$ASAN_RT" \ 243 "$HERE"/../lib/asan/"$ASAN_RT" \ 244 "$HERE"/../lib/linux/"$ASAN_RT" \ 245 "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \ 246 "$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) 247 if [[ -n "$P" ]]; then 248 ASAN_RT_PATH="$(dirname "$P")" 249 fi 250fi 251 252if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then 253 echo ">> ASan runtime library not found" 254 exit 1 255fi 256 257if [[ -n "$ASAN_RT64" ]]; then 258 if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then 259 echo ">> ASan runtime library not found" 260 exit 1 261 fi 262fi 263 264TMPDIRBASE=$(mktemp -d) 265TMPDIROLD="$TMPDIRBASE/old" 266TMPDIR="$TMPDIRBASE/new" 267mkdir "$TMPDIROLD" 268 269if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then 270 271 if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then 272 echo '>> Old-style ASan installation detected. Reverting.' 273 adb_shell mv /system/bin/app_process.real /system/bin/app_process 274 fi 275 276 echo '>> Pre-L device detected. Setting up app_process symlink.' 277 adb_shell mv /system/bin/app_process /system/bin/app_process32 278 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process 279fi 280 281echo '>> Copying files from the device' 282if [[ -n "$ASAN_RT64" ]]; then 283 adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true 284 adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true 285 adb_pull /system/bin/app_process32 "$TMPDIROLD" || true 286 adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true 287 adb_pull /system/bin/app_process64 "$TMPDIROLD" || true 288 adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true 289 adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true 290 adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true 291else 292 adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true 293 adb_pull /system/bin/app_process32 "$TMPDIROLD" || true 294 adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true 295 adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true 296fi 297cp -r "$TMPDIROLD" "$TMPDIR" 298 299if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then 300 echo ">> Previous installation detected" 301else 302 echo ">> New installation" 303fi 304 305echo '>> Generating wrappers' 306 307cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" 308if [[ -n "$ASAN_RT64" ]]; then 309 cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/" 310fi 311 312ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0 313 314function generate_zygote_wrapper { # from, to, asan_rt 315 local _from=$1 316 local _to=$2 317 local _asan_rt=$3 318 if [[ PRE_L -eq 0 ]]; then 319 # LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is 320 # unset in the system environment since L. 321 local _ld_preload=$_asan_rt 322 else 323 local _ld_preload=\$LD_PRELOAD:$_asan_rt 324 fi 325 cat <<EOF >"$TMPDIR/$_from" 326#!/system/bin/sh-from-zygote 327ASAN_OPTIONS=$ASAN_OPTIONS \\ 328ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\ 329LD_PRELOAD=$_ld_preload \\ 330exec $_to \$@ 331 332EOF 333} 334 335# On Android-L not allowing user segv handler breaks some applications. 336if [[ PRE_L -eq 0 ]]; then 337 ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" 338fi 339 340if [[ x$extra_options != x ]] ; then 341 ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" 342fi 343 344# Zygote wrapper. 345if [[ -f "$TMPDIR/app_process64" ]]; then 346 # A 64-bit device. 347 if [[ ! -f "$TMPDIR/app_process64.real" ]]; then 348 # New installation. 349 mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real" 350 mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real" 351 fi 352 generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT" 353 generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64" 354else 355 # A 32-bit device. 356 generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT" 357fi 358 359# General command-line tool wrapper (use for anything that's not started as 360# zygote). 361cat <<EOF >"$TMPDIR/asanwrapper" 362#!/system/bin/sh 363LD_PRELOAD=$ASAN_RT \\ 364exec \$@ 365 366EOF 367 368if [[ -n "$ASAN_RT64" ]]; then 369 cat <<EOF >"$TMPDIR/asanwrapper64" 370#!/system/bin/sh 371LD_PRELOAD=$ASAN_RT64 \\ 372exec \$@ 373 374EOF 375fi 376 377function install { # from, to, chmod, chcon 378 local _from=$1 379 local _to=$2 380 local _mode=$3 381 local _context=$4 382 local _basename="$(basename "$_from")" 383 echo "Installing $_to/$_basename $_mode $_context" 384 adb_push "$_from" "$_to/$_basename" 385 adb_shell chown root.shell "$_to/$_basename" 386 if [[ -n "$_mode" ]]; then 387 adb_shell chmod "$_mode" "$_to/$_basename" 388 fi 389 if [[ -n "$_context" ]]; then 390 adb_shell chcon "$_context" "$_to/$_basename" 391 fi 392} 393 394if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then 395 # Make SELinux happy by keeping app_process wrapper and the shell 396 # it runs on in zygote domain. 397 ENFORCING=0 398 if adb_shell getenforce | grep Enforcing >/dev/null; then 399 # Sometimes shell is not allowed to change file contexts. 400 # Temporarily switch to permissive. 401 ENFORCING=1 402 adb_shell setenforce 0 403 fi 404 405 if [[ PRE_L -eq 1 ]]; then 406 CTX=u:object_r:system_file:s0 407 else 408 CTX=u:object_r:zygote_exec:s0 409 fi 410 411 echo '>> Pushing files to the device' 412 413 if [[ -n "$ASAN_RT64" ]]; then 414 install "$TMPDIR/$ASAN_RT" /system/lib 644 415 install "$TMPDIR/$ASAN_RT64" /system/lib64 644 416 install "$TMPDIR/app_process32" /system/bin 755 $CTX 417 install "$TMPDIR/app_process32.real" /system/bin 755 $CTX 418 install "$TMPDIR/app_process64" /system/bin 755 $CTX 419 install "$TMPDIR/app_process64.real" /system/bin 755 $CTX 420 install "$TMPDIR/asanwrapper" /system/bin 755 421 install "$TMPDIR/asanwrapper64" /system/bin 755 422 else 423 install "$TMPDIR/$ASAN_RT" /system/lib 644 424 install "$TMPDIR/app_process32" /system/bin 755 $CTX 425 install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX 426 install "$TMPDIR/asanwrapper" /system/bin 755 $CTX 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 [[ ANDROID_O -eq 1 ]]; then 436 # For Android O, due to b/38114603, the linker namespace is temporarily 437 # disabled 438 adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved 439 fi 440 441 if [ $ENFORCING == 1 ]; then 442 adb_shell setenforce 1 443 fi 444 445 echo '>> Restarting shell (asynchronous)' 446 adb_shell stop 447 adb_shell start 448 449 echo '>> Please wait until the device restarts' 450else 451 echo '>> Device is up to date' 452fi 453 454rm -r "$TMPDIRBASE" 455