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= 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 30 exit 1 31} 32 33function get_device_arch { # OUTVAR 34 local _outvar=$1 35 local _ABI=$($ADB shell getprop ro.product.cpu.abi) 36 local _ARCH= 37 if [[ $_ABI == x86* ]]; then 38 _ARCH=i686 39 elif [[ $_ABI == armeabi* ]]; then 40 _ARCH=arm 41 else 42 echo "Unrecognized device ABI: $_ABI" 43 exit 1 44 fi 45 eval $_outvar=\$_ARCH 46} 47 48while [[ $# > 0 ]]; do 49 case $1 in 50 --revert) 51 revert=yes 52 ;; 53 --extra-options) 54 shift 55 if [[ $# == 0 ]]; then 56 echo "--extra-options requires an argument." 57 exit 1 58 fi 59 extra_options="$1" 60 ;; 61 --lib) 62 shift 63 if [[ $# == 0 ]]; then 64 echo "--lib requires an argument." 65 exit 1 66 fi 67 lib="$1" 68 ;; 69 --device) 70 shift 71 if [[ $# == 0 ]]; then 72 echo "--device requires an argument." 73 exit 1 74 fi 75 device="$1" 76 ;; 77 *) 78 usage 79 ;; 80 esac 81 shift 82done 83 84ADB=${ADB:-adb} 85if [[ x$device != x ]]; then 86 ADB="$ADB -s $device" 87fi 88 89echo '>> Remounting /system rw' 90$ADB root 91$ADB wait-for-device 92$ADB remount 93$ADB wait-for-device 94 95get_device_arch ARCH 96echo "Target architecture: $ARCH" 97ASAN_RT="libclang_rt.asan-$ARCH-android.so" 98 99if [[ x$revert == xyes ]]; then 100 echo '>> Uninstalling ASan' 101 102 if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then 103 echo '>> Pre-L device detected.' 104 $ADB shell mv /system/bin/app_process.real /system/bin/app_process 105 $ADB shell rm /system/bin/asanwrapper 106 $ADB shell rm /system/lib/$ASAN_RT 107 else 108 $ADB shell rm /system/bin/app_process.wrap 109 $ADB shell rm /system/bin/asanwrapper 110 $ADB shell rm /system/lib/$ASAN_RT 111 $ADB shell rm /system/bin/app_process 112 $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process 113 fi 114 115 echo '>> Restarting shell' 116 $ADB shell stop 117 $ADB shell start 118 119 echo '>> Done' 120 exit 0 121fi 122 123if [[ -d "$lib" ]]; then 124 ASAN_RT_PATH="$lib" 125elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then 126 ASAN_RT_PATH=$(dirname "$lib") 127elif [[ -f "$HERE/$ASAN_RT" ]]; then 128 ASAN_RT_PATH="$HERE" 129elif [[ $(basename "$HERE") == "bin" ]]; then 130 # We could be in the toolchain's base directory. 131 # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux. 132 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) 133 if [[ -n "$P" ]]; then 134 ASAN_RT_PATH="$(dirname "$P")" 135 fi 136fi 137 138if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then 139 echo ">> ASan runtime library not found" 140 exit 1 141fi 142 143TMPDIRBASE=$(mktemp -d) 144TMPDIROLD="$TMPDIRBASE/old" 145TMPDIR="$TMPDIRBASE/new" 146mkdir "$TMPDIROLD" 147 148RELEASE=$($ADB shell getprop ro.build.version.release) 149PRE_L=0 150if echo "$RELEASE" | grep '^4\.' >&/dev/null; then 151 PRE_L=1 152fi 153 154if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then 155 156 if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then 157 echo '>> Old-style ASan installation detected. Reverting.' 158 $ADB shell mv /system/bin/app_process.real /system/bin/app_process 159 fi 160 161 echo '>> Pre-L device detected. Setting up app_process symlink.' 162 $ADB shell mv /system/bin/app_process /system/bin/app_process32 163 $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process 164fi 165 166echo '>> Copying files from the device' 167$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true 168$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true 169$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true 170cp -r "$TMPDIROLD" "$TMPDIR" 171 172if [[ -f "$TMPDIR/app_process.wrap" ]]; then 173 echo ">> Previous installation detected" 174else 175 echo ">> New installation" 176fi 177 178echo '>> Generating wrappers' 179 180cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" 181 182# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup, 183# which may or may not be a real bug (probably not). 184ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0 185 186# On Android-L not allowing user segv handler breaks some applications. 187if $ADB shell 'echo $LD_PRELOAD' | grep libsigchain.so >&/dev/null; then 188 ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" 189fi 190 191if [[ x$extra_options != x ]] ; then 192 ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" 193fi 194 195# Zygote wrapper. 196cat <<EOF >"$TMPDIR/app_process.wrap" 197#!/system/bin/sh-from-zygote 198ASAN_OPTIONS=$ASAN_OPTIONS \\ 199LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\ 200exec /system/bin/app_process32 \$@ 201 202EOF 203 204# General command-line tool wrapper (use for anything that's not started as 205# zygote). 206cat <<EOF >"$TMPDIR/asanwrapper" 207#!/system/bin/sh 208LD_PRELOAD=$ASAN_RT \\ 209exec \$@ 210 211EOF 212 213if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then 214 echo '>> Pushing files to the device' 215 $ADB push "$TMPDIR/$ASAN_RT" /system/lib/ 216 $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap 217 $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper 218 219 $ADB shell rm /system/bin/app_process 220 $ADB shell ln -s /system/bin/app_process.wrap /system/bin/app_process 221 222 $ADB shell chown root.shell \ 223 /system/lib/"$ASAN_RT" \ 224 /system/bin/app_process.wrap \ 225 /system/bin/asanwrapper 226 $ADB shell chmod 644 \ 227 /system/lib/"$ASAN_RT" 228 $ADB shell chmod 755 \ 229 /system/bin/app_process.wrap \ 230 /system/bin/asanwrapper 231 232 # Make SELinux happy by keeping app_process wrapper and the shell 233 # it runs on in zygote domain. 234 ENFORCING=0 235 if $ADB shell getenforce | grep Enforcing >/dev/null; then 236 # Sometimes shell is not allowed to change file contexts. 237 # Temporarily switch to permissive. 238 ENFORCING=1 239 $ADB shell setenforce 0 240 fi 241 242 $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote 243 244 if [[ PRE_L -eq 1 ]]; then 245 CTX=u:object_r:system_file:s0 246 else 247 CTX=u:object_r:zygote_exec:s0 248 fi 249 $ADB shell chcon $CTX \ 250 /system/bin/sh-from-zygote \ 251 /system/bin/app_process.wrap \ 252 /system/bin/app_process32 253 254 if [ $ENFORCING == 1 ]; then 255 $ADB shell setenforce 1 256 fi 257 258 echo '>> Restarting shell (asynchronous)' 259 $ADB shell stop 260 $ADB shell start 261 262 echo '>> Please wait until the device restarts' 263else 264 echo '>> Device is up to date' 265fi 266 267rm -r "$TMPDIRBASE" 268