brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.4 KiB · 4948679 Raw
467 lines · plain
1#!/usr/bin/env bash2#===- 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-exception7#8# Prepare Android device to run ASan applications.9#10#===------------------------------------------------------------------------===#11 12set -e13 14HERE="$(cd "$(dirname "$0")" && pwd)"15 16revert=no17extra_options=18device=19lib=20use_su=021 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    echo32    exit 133}34 35function adb_push {36  if [ $use_su -eq 0 ]; then37    $ADB push "$1" "$2"38  else39    local FILENAME=$(basename $1)40    $ADB push "$1" "/data/local/tmp/$FILENAME"41    $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null42    $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""43    $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""44  fi45}46 47function adb_remount {48  if [ $use_su -eq 0 ]; then49    $ADB remount50  else51    local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`52    if [ "$STORAGE" != "" ]; then53      echo Remounting $STORAGE at /system54      $ADB shell su -c "mount -o rw,remount $STORAGE /system"55    else56      echo Failed to get storage device name for "/system" mount point57    fi58  fi59}60 61function adb_shell {62  if [ $use_su -eq 0 ]; then63    $ADB shell $@64  else65    $ADB shell su -c "$*"66  fi67}68 69function adb_root {70  if [ $use_su -eq 0 ]; then71    $ADB root72  fi73}74 75function adb_wait_for_device {76  $ADB wait-for-device77}78 79function adb_pull {80  if [ $use_su -eq 0 ]; then81    $ADB pull "$1" "$2"82  else83    local FILENAME=$(basename $1)84    $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null85    $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  fi88}89 90function get_device_arch { # OUT OUT6491    local _outvar=$192    local _outvar64=$293    local _ABI=$(adb_shell getprop ro.product.cpu.abi)94    local _ARCH=95    local _ARCH64=96    if [[ $_ABI == x86* ]]; then97        _ARCH=i68698    elif [[ $_ABI == armeabi* ]]; then99        _ARCH=arm100    elif [[ $_ABI == arm64-v8a* ]]; then101        _ARCH=arm102        _ARCH64=aarch64103    else104        echo "Unrecognized device ABI: $_ABI"105        exit 1106    fi107    eval $_outvar=\$_ARCH108    eval $_outvar64=\$_ARCH64109}110 111while [[ $# > 0 ]]; do112  case $1 in113    --revert)114      revert=yes115      ;;116    --extra-options)117      shift118      if [[ $# == 0 ]]; then119        echo "--extra-options requires an argument."120        exit 1121      fi122      extra_options="$1"123      ;;124    --lib)125      shift126      if [[ $# == 0 ]]; then127        echo "--lib requires an argument."128        exit 1129      fi130      lib="$1"131      ;;132    --device)133      shift134      if [[ $# == 0 ]]; then135        echo "--device requires an argument."136        exit 1137      fi138      device="$1"139      ;;140    --use-su)141      use_su=1142      ;;143    *)144      usage145      ;;146  esac147  shift148done149 150ADB=${ADB:-adb}151if [[ x$device != x ]]; then152    ADB="$ADB -s $device"153fi154 155if [ $use_su -eq 1 ]; then156  # Test if 'su' is present on the device157  SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`158  if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then159    echo "ERROR: Cannot use 'su -c':"160    echo "$ adb shell su -c \"echo foo\""161    echo $SU_TEST_OUT162    echo "Check that 'su' binary is correctly installed on the device or omit"163    echo "            --use-su flag"164    exit 1165  fi166fi167 168echo '>> Remounting /system rw'169adb_wait_for_device170adb_root171adb_wait_for_device172adb_remount173adb_wait_for_device174 175get_device_arch ARCH ARCH64176echo "Target architecture: $ARCH"177ASAN_RT="libclang_rt.asan-$ARCH-android.so"178if [[ -n $ARCH64 ]]; then179  echo "Target architecture: $ARCH64"180  ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"181fi182 183RELEASE=$(adb_shell getprop ro.build.version.release)184PRE_L=0185if echo "$RELEASE" | grep '^4\.' >&/dev/null; then186    PRE_L=1187fi188ANDROID_O=0189if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then190    # 8.0.x is for Android O191    ANDROID_O=1192fi193 194if [[ x$revert == xyes ]]; then195    echo '>> Uninstalling ASan'196 197    if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then198      echo '>> Pre-L device detected.'199      adb_shell mv /system/bin/app_process.real /system/bin/app_process200      adb_shell rm /system/bin/asanwrapper201    elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then202      # 64-bit installation.203      adb_shell mv /system/bin/app_process32.real /system/bin/app_process32204      adb_shell mv /system/bin/app_process64.real /system/bin/app_process64205      adb_shell rm /system/bin/asanwrapper206      adb_shell rm /system/bin/asanwrapper64207    else208      # 32-bit installation.209      adb_shell rm /system/bin/app_process.wrap210      adb_shell rm /system/bin/asanwrapper211      adb_shell rm /system/bin/app_process212      adb_shell ln -s /system/bin/app_process32 /system/bin/app_process213    fi214 215    if [[ ANDROID_O -eq 1 ]]; then216      adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt217    fi218 219    echo '>> Restarting shell'220    adb_shell stop221    adb_shell start222 223    # Remove the library on the last step to give a chance to the 'su' binary to224    # be executed without problem.225    adb_shell rm /system/lib/$ASAN_RT226 227    echo '>> Done'228    exit 0229fi230 231if [[ -d "$lib" ]]; then232    ASAN_RT_PATH="$lib"233elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then234    ASAN_RT_PATH=$(dirname "$lib")235elif [[ -f "$HERE/$ASAN_RT" ]]; then236    ASAN_RT_PATH="$HERE"237elif [[ $(basename "$HERE") == "bin" ]]; then238    # 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" ]]; then247        ASAN_RT_PATH="$(dirname "$P")"248    fi249fi250 251if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then252    echo ">> ASan runtime library not found"253    exit 1254fi255 256if [[ -n "$ASAN_RT64" ]]; then257  if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then258    echo ">> ASan runtime library not found"259    exit 1260  fi261fi262 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; then269 270    if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then271        echo '>> Old-style ASan installation detected. Reverting.'272        adb_shell mv /system/bin/app_process.real /system/bin/app_process273    fi274 275    echo '>> Pre-L device detected. Setting up app_process symlink.'276    adb_shell mv /system/bin/app_process /system/bin/app_process32277    adb_shell ln -s /system/bin/app_process32 /system/bin/app_process278fi279 280echo '>> Copying files from the device'281if [[ -n "$ASAN_RT64" ]]; then282  adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true283  adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true284  adb_pull /system/bin/app_process32 "$TMPDIROLD" || true285  adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true286  adb_pull /system/bin/app_process64 "$TMPDIROLD" || true287  adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true288  adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true289  adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true290else291  adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true292  adb_pull /system/bin/app_process32 "$TMPDIROLD" || true293  adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true294  adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true295fi296cp -r "$TMPDIROLD" "$TMPDIR"297 298if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then299    echo ">> Previous installation detected"300else301    echo ">> New installation"302fi303 304echo '>> Generating wrappers'305 306cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"307if [[ -n "$ASAN_RT64" ]]; then308  cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"309fi310 311ASAN_OPTIONS=start_deactivated=1312 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 falling315# apart when a 64-bit process spawns a 32-bit one, inheriting the environment.316ASAN_RT_SYMLINK=symlink-to-libclang_rt.asan317 318function generate_zygote_wrapper { # from, to319  local _from=$1320  local _to=$2321  if [[ PRE_L -eq 0 ]]; then322    # LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is323    # unset in the system environment since L.324    local _ld_preload=$ASAN_RT_SYMLINK325  else326    local _ld_preload=\$LD_PRELOAD:$ASAN_RT_SYMLINK327  fi328  cat <<EOF >"$TMPDIR/$_from"329#!/system/bin/sh-from-zygote330ASAN_OPTIONS=$ASAN_OPTIONS \\331ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\332LD_PRELOAD=$_ld_preload \\333exec $_to "\$@"334 335EOF336}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 with340# older library versions.341if [[ PRE_L -eq 0 ]]; then342    ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"343fi344 345if [[ x$extra_options != x ]] ; then346    ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"347fi348 349# Zygote wrapper.350if [[ -f "$TMPDIR/app_process64" ]]; then351  # A 64-bit device.352  if [[ ! -f "$TMPDIR/app_process64.real" ]]; then353    # New installation.354    mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real"355    mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real"356  fi357  generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real"358  generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real"359else360  # A 32-bit device.361  generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32"362fi363 364# General command-line tool wrapper (use for anything that's not started as365# zygote).366cat <<EOF >"$TMPDIR/asanwrapper"367#!/system/bin/sh368LD_PRELOAD=$ASAN_RT_SYMLINK \\369exec \$@370 371EOF372 373if [[ -n "$ASAN_RT64" ]]; then374  cat <<EOF >"$TMPDIR/asanwrapper64"375#!/system/bin/sh376LD_PRELOAD=$ASAN_RT_SYMLINK \\377exec \$@378 379EOF380fi381 382function install { # from, to, chmod, chcon383  local _from=$1384  local _to=$2385  local _mode=$3386  local _context=$4387  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" ]]; then392    adb_shell chmod "$_mode" "$_to/$_basename"393  fi394  if [[ -n "$_context" ]]; then395    adb_shell chcon "$_context" "$_to/$_basename"396  fi397}398 399if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then400    # Make SELinux happy by keeping app_process wrapper and the shell401    # it runs on in zygote domain.402    ENFORCING=0403    if adb_shell getenforce | grep Enforcing >/dev/null; then404        # Sometimes shell is not allowed to change file contexts.405        # Temporarily switch to permissive.406        ENFORCING=1407        adb_shell setenforce 0408    fi409 410    if [[ PRE_L -eq 1 ]]; then411        CTX=u:object_r:system_file:s0412    else413        CTX=u:object_r:zygote_exec:s0414    fi415 416    echo '>> Pushing files to the device'417 418    if [[ -n "$ASAN_RT64" ]]; then419      install "$TMPDIR/$ASAN_RT" /system/lib 644420      install "$TMPDIR/$ASAN_RT64" /system/lib64 644421      install "$TMPDIR/app_process32" /system/bin 755 $CTX422      install "$TMPDIR/app_process32.real" /system/bin 755 $CTX423      install "$TMPDIR/app_process64" /system/bin 755 $CTX424      install "$TMPDIR/app_process64.real" /system/bin 755 $CTX425      install "$TMPDIR/asanwrapper" /system/bin 755426      install "$TMPDIR/asanwrapper64" /system/bin 755427 428      adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK429      adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK430      adb_shell rm -f /system/lib64/$ASAN_RT_SYMLINK431      adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK432    else433      install "$TMPDIR/$ASAN_RT" /system/lib 644434      install "$TMPDIR/app_process32" /system/bin 755 $CTX435      install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX436      install "$TMPDIR/asanwrapper" /system/bin 755 $CTX437 438      adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK439      adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK440 441      adb_shell rm /system/bin/app_process442      adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process443    fi444 445    adb_shell cp /system/bin/sh /system/bin/sh-from-zygote446    adb_shell chcon $CTX /system/bin/sh-from-zygote447 448    if [[ ANDROID_O -eq 1 ]]; then449      # For Android O, the linker namespace is temporarily disabled.450      adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved451    fi452 453    if [ $ENFORCING == 1 ]; then454        adb_shell setenforce 1455    fi456 457    echo '>> Restarting shell (asynchronous)'458    adb_shell stop459    adb_shell start460 461    echo '>> Please wait until the device restarts'462else463    echo '>> Device is up to date'464fi465 466rm -r "$TMPDIRBASE"467