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 function generate_zygote_wrapper { # from, to, asan_rt 306 local _from=$1 307 local _to=$2 308 local _asan_rt=$3 309 if [[ PRE_L -eq 0 ]]; then 310 # LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is 311 # unset in the system environment since L. 312 local _ld_preload=$_asan_rt 313 else 314 local _ld_preload=\$LD_PRELOAD:$_asan_rt 315 fi 316 cat <<EOF >"$TMPDIR/$_from" 317 #!/system/bin/sh-from-zygote 318 ASAN_OPTIONS=$ASAN_OPTIONS \\ 319 ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\ 320 LD_PRELOAD=$_ld_preload \\ 321 exec $_to \$@ 322 323 EOF 324 } 325 326 # On Android-L not allowing user segv handler breaks some applications. 327 if [[ PRE_L -eq 0 ]]; then 328 ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" 329 fi 330 331 if [[ x$extra_options != x ]] ; then 332 ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" 333 fi 334 335 # Zygote wrapper. 336 if [[ -f "$TMPDIR/app_process64" ]]; then 337 # A 64-bit device. 338 if [[ ! -f "$TMPDIR/app_process64.real" ]]; then 339 # New installation. 340 mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real" 341 mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real" 342 fi 343 generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT" 344 generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64" 345 else 346 # A 32-bit device. 347 generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT" 348 fi 349 350 # General command-line tool wrapper (use for anything that's not started as 351 # zygote). 352 cat <<EOF >"$TMPDIR/asanwrapper" 353 #!/system/bin/sh 354 LD_PRELOAD=$ASAN_RT \\ 355 exec \$@ 356 357 EOF 358 359 if [[ -n "$ASAN_RT64" ]]; then 360 cat <<EOF >"$TMPDIR/asanwrapper64" 361 #!/system/bin/sh 362 LD_PRELOAD=$ASAN_RT64 \\ 363 exec \$@ 364 365 EOF 366 fi 367 368 function install { # from, to, chmod, chcon 369 local _from=$1 370 local _to=$2 371 local _mode=$3 372 local _context=$4 373 local _basename="$(basename "$_from")" 374 echo "Installing $_to/$_basename $_mode $_context" 375 adb_push "$_from" "$_to/$_basename" 376 adb_shell chown root.shell "$_to/$_basename" 377 if [[ -n "$_mode" ]]; then 378 adb_shell chmod "$_mode" "$_to/$_basename" 379 fi 380 if [[ -n "$_context" ]]; then 381 adb_shell chcon "$_context" "$_to/$_basename" 382 fi 383 } 384 385 if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then 386 # Make SELinux happy by keeping app_process wrapper and the shell 387 # it runs on in zygote domain. 388 ENFORCING=0 389 if adb_shell getenforce | grep Enforcing >/dev/null; then 390 # Sometimes shell is not allowed to change file contexts. 391 # Temporarily switch to permissive. 392 ENFORCING=1 393 adb_shell setenforce 0 394 fi 395 396 if [[ PRE_L -eq 1 ]]; then 397 CTX=u:object_r:system_file:s0 398 else 399 CTX=u:object_r:zygote_exec:s0 400 fi 401 402 echo '>> Pushing files to the device' 403 404 if [[ -n "$ASAN_RT64" ]]; then 405 install "$TMPDIR/$ASAN_RT" /system/lib 644 406 install "$TMPDIR/$ASAN_RT64" /system/lib64 644 407 install "$TMPDIR/app_process32" /system/bin 755 $CTX 408 install "$TMPDIR/app_process32.real" /system/bin 755 $CTX 409 install "$TMPDIR/app_process64" /system/bin 755 $CTX 410 install "$TMPDIR/app_process64.real" /system/bin 755 $CTX 411 install "$TMPDIR/asanwrapper" /system/bin 755 412 install "$TMPDIR/asanwrapper64" /system/bin 755 413 else 414 install "$TMPDIR/$ASAN_RT" /system/lib 644 415 install "$TMPDIR/app_process32" /system/bin 755 $CTX 416 install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX 417 install "$TMPDIR/asanwrapper" /system/bin 755 $CTX 418 419 adb_shell rm /system/bin/app_process 420 adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process 421 fi 422 423 adb_shell cp /system/bin/sh /system/bin/sh-from-zygote 424 adb_shell chcon $CTX /system/bin/sh-from-zygote 425 426 if [ $ENFORCING == 1 ]; then 427 adb_shell setenforce 1 428 fi 429 430 echo '>> Restarting shell (asynchronous)' 431 adb_shell stop 432 adb_shell start 433 434 echo '>> Please wait until the device restarts' 435 else 436 echo '>> Device is up to date' 437 fi 438 439 rm -r "$TMPDIRBASE" 440