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 { # OUTVAR 92 local _outvar=$1 93 local _ABI=$(adb_shell getprop ro.product.cpu.abi) 94 local _ARCH= 95 if [[ $_ABI == x86* ]]; then 96 _ARCH=i686 97 elif [[ $_ABI == armeabi* ]]; then 98 _ARCH=arm 99 else 100 echo "Unrecognized device ABI: $_ABI" 101 exit 1 102 fi 103 eval $_outvar=\$_ARCH 104} 105 106while [[ $# > 0 ]]; do 107 case $1 in 108 --revert) 109 revert=yes 110 ;; 111 --extra-options) 112 shift 113 if [[ $# == 0 ]]; then 114 echo "--extra-options requires an argument." 115 exit 1 116 fi 117 extra_options="$1" 118 ;; 119 --lib) 120 shift 121 if [[ $# == 0 ]]; then 122 echo "--lib requires an argument." 123 exit 1 124 fi 125 lib="$1" 126 ;; 127 --device) 128 shift 129 if [[ $# == 0 ]]; then 130 echo "--device requires an argument." 131 exit 1 132 fi 133 device="$1" 134 ;; 135 --use-su) 136 use_su=1 137 ;; 138 *) 139 usage 140 ;; 141 esac 142 shift 143done 144 145ADB=${ADB:-adb} 146if [[ x$device != x ]]; then 147 ADB="$ADB -s $device" 148fi 149 150if [ $use_su -eq 1 ]; then 151 # Test if 'su' is present on the device 152 SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` 153 if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then 154 echo "ERROR: Cannot use 'su -c':" 155 echo "$ adb shell su -c \"echo foo\"" 156 echo $SU_TEST_OUT 157 echo "Check that 'su' binary is correctly installed on the device or omit" 158 echo " --use-su flag" 159 exit 1 160 fi 161fi 162 163echo '>> Remounting /system rw' 164adb_wait_for_device 165adb_root 166adb_wait_for_device 167adb_remount 168adb_wait_for_device 169 170get_device_arch ARCH 171echo "Target architecture: $ARCH" 172ASAN_RT="libclang_rt.asan-$ARCH-android.so" 173 174if [[ x$revert == xyes ]]; then 175 echo '>> Uninstalling ASan' 176 177 if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then 178 echo '>> Pre-L device detected.' 179 adb_shell mv /system/bin/app_process.real /system/bin/app_process 180 adb_shell rm /system/bin/asanwrapper 181 else 182 adb_shell rm /system/bin/app_process.wrap 183 adb_shell rm /system/bin/asanwrapper 184 adb_shell rm /system/bin/app_process 185 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process 186 fi 187 188 echo '>> Restarting shell' 189 adb_shell stop 190 adb_shell start 191 192 # Remove the library on the last step to give a chance to the 'su' binary to 193 # be executed without problem. 194 adb_shell rm /system/lib/$ASAN_RT 195 196 echo '>> Done' 197 exit 0 198fi 199 200if [[ -d "$lib" ]]; then 201 ASAN_RT_PATH="$lib" 202elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then 203 ASAN_RT_PATH=$(dirname "$lib") 204elif [[ -f "$HERE/$ASAN_RT" ]]; then 205 ASAN_RT_PATH="$HERE" 206elif [[ $(basename "$HERE") == "bin" ]]; then 207 # We could be in the toolchain's base directory. 208 # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux. 209 P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) 210 if [[ -n "$P" ]]; then 211 ASAN_RT_PATH="$(dirname "$P")" 212 fi 213fi 214 215if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then 216 echo ">> ASan runtime library not found" 217 exit 1 218fi 219 220TMPDIRBASE=$(mktemp -d) 221TMPDIROLD="$TMPDIRBASE/old" 222TMPDIR="$TMPDIRBASE/new" 223mkdir "$TMPDIROLD" 224 225RELEASE=$(adb_shell getprop ro.build.version.release) 226PRE_L=0 227if echo "$RELEASE" | grep '^4\.' >&/dev/null; then 228 PRE_L=1 229fi 230 231if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then 232 233 if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then 234 echo '>> Old-style ASan installation detected. Reverting.' 235 adb_shell mv /system/bin/app_process.real /system/bin/app_process 236 fi 237 238 echo '>> Pre-L device detected. Setting up app_process symlink.' 239 adb_shell mv /system/bin/app_process /system/bin/app_process32 240 adb_shell ln -s /system/bin/app_process32 /system/bin/app_process 241fi 242 243echo '>> Copying files from the device' 244adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true 245adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true 246adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true 247cp -r "$TMPDIROLD" "$TMPDIR" 248 249if [[ -f "$TMPDIR/app_process.wrap" ]]; then 250 echo ">> Previous installation detected" 251else 252 echo ">> New installation" 253fi 254 255echo '>> Generating wrappers' 256 257cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" 258 259# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup, 260# which may or may not be a real bug (probably not). 261ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0 262 263# On Android-L not allowing user segv handler breaks some applications. 264if [[ PRE_L -eq 0 ]]; then 265 ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" 266fi 267 268if [[ x$extra_options != x ]] ; then 269 ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" 270fi 271 272# Zygote wrapper. 273cat <<EOF >"$TMPDIR/app_process.wrap" 274#!/system/bin/sh-from-zygote 275ASAN_OPTIONS=$ASAN_OPTIONS \\ 276LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\ 277exec /system/bin/app_process32 \$@ 278 279EOF 280 281# General command-line tool wrapper (use for anything that's not started as 282# zygote). 283cat <<EOF >"$TMPDIR/asanwrapper" 284#!/system/bin/sh 285LD_PRELOAD=$ASAN_RT \\ 286exec \$@ 287 288EOF 289 290if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then 291 echo '>> Pushing files to the device' 292 adb_push "$TMPDIR/$ASAN_RT" /system/lib/ 293 adb_push "$TMPDIR/app_process.wrap" /system/bin 294 adb_push "$TMPDIR/asanwrapper" /system/bin 295 296 adb_shell rm /system/bin/app_process 297 adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process 298 299 adb_shell chown root.shell \ 300 /system/lib/"$ASAN_RT" \ 301 /system/bin/app_process.wrap \ 302 /system/bin/asanwrapper 303 adb_shell chmod 644 \ 304 /system/lib/"$ASAN_RT" 305 adb_shell chmod 755 \ 306 /system/bin/app_process.wrap \ 307 /system/bin/asanwrapper 308 309 # Make SELinux happy by keeping app_process wrapper and the shell 310 # it runs on in zygote domain. 311 ENFORCING=0 312 if adb_shell getenforce | grep Enforcing >/dev/null; then 313 # Sometimes shell is not allowed to change file contexts. 314 # Temporarily switch to permissive. 315 ENFORCING=1 316 adb_shell setenforce 0 317 fi 318 319 adb_shell cp /system/bin/sh /system/bin/sh-from-zygote 320 321 if [[ PRE_L -eq 1 ]]; then 322 CTX=u:object_r:system_file:s0 323 else 324 CTX=u:object_r:zygote_exec:s0 325 fi 326 adb_shell chcon $CTX \ 327 /system/bin/sh-from-zygote \ 328 /system/bin/app_process.wrap \ 329 /system/bin/app_process32 330 331 if [ $ENFORCING == 1 ]; then 332 adb_shell setenforce 1 333 fi 334 335 echo '>> Restarting shell (asynchronous)' 336 adb_shell stop 337 adb_shell start 338 339 echo '>> Please wait until the device restarts' 340else 341 echo '>> Device is up to date' 342fi 343 344rm -r "$TMPDIRBASE" 345