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