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