Created
January 11, 2019 14:17
-
-
Save S1GSEGV/2b69e19900dd7ea95e0c9d4b881f9984 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
#===- lib/asan/scripts/asan_device_setup -----------------------------------===# | |
# | |
# The LLVM Compiler Infrastructure | |
# | |
# This file is distributed under the University of Illinois Open Source | |
# License. See LICENSE.TXT for details. | |
# | |
# Prepare Android device to run ASan applications. | |
# | |
#===------------------------------------------------------------------------===# | |
set -e | |
HERE="$(cd "$(dirname "$0")" && pwd)" | |
revert=no | |
extra_options= | |
device= | |
lib= | |
use_su=0 | |
function usage { | |
echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]" | |
echo " --revert: Uninstall ASan from the device." | |
echo " --lib: Path to ASan runtime library." | |
echo " --extra-options: Extra ASAN_OPTIONS." | |
echo " --device: Install to the given device. Use 'adb devices' to find" | |
echo " device-id." | |
echo " --use-su: Use 'su -c' prefix for every adb command instead of using" | |
echo " 'adb root' once." | |
echo | |
exit 1 | |
} | |
function adb_push { | |
if [ $use_su -eq 0 ]; then | |
$ADB push "$1" "$2" | |
else | |
local FILENAME=$(basename $1) | |
$ADB push "$1" "/data/local/tmp/$FILENAME" | |
$ADB shell su -c "rm \\\"$2\\\"" >&/dev/null | |
$ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" \> \\\"$2\\\"" | |
$ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\"" | |
fi | |
} | |
function adb_remount { | |
if [ $use_su -eq 0 ]; then | |
$ADB remount | |
else | |
local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` | |
if [ "$STORAGE" != "" ]; then | |
echo Remounting $STORAGE at /system | |
$ADB shell su -c "mount -o remount,rw $STORAGE /system" | |
else | |
echo Failed to get storage device name for "/system" mount point | |
fi | |
fi | |
} | |
function adb_shell { | |
if [ $use_su -eq 0 ]; then | |
$ADB shell $@ | |
else | |
$ADB shell su -c "$*" | |
fi | |
} | |
function adb_root { | |
if [ $use_su -eq 0 ]; then | |
$ADB root | |
fi | |
} | |
function adb_wait_for_device { | |
$ADB wait-for-device | |
} | |
function adb_pull { | |
if [ $use_su -eq 0 ]; then | |
$ADB pull "$1" "$2" | |
else | |
local FILENAME=$(basename $1) | |
$ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null | |
$ADB shell su -c "cat \\\"$1\\\" \> \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB shell su -c "chown root.shell \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB shell su -c "chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" | |
# $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\\\"" && | |
# $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" | |
fi | |
} | |
function get_device_arch { # OUT OUT64 | |
local _outvar=$1 | |
local _outvar64=$2 | |
local _ABI=$(adb_shell getprop ro.product.cpu.abi) | |
local _ARCH= | |
local _ARCH64= | |
if [[ $_ABI == x86* ]]; then | |
_ARCH=i686 | |
elif [[ $_ABI == armeabi* ]]; then | |
_ARCH=arm | |
elif [[ $_ABI == arm64-v8a* ]]; then | |
_ARCH=arm | |
_ARCH64=aarch64 | |
else | |
echo "Unrecognized device ABI: $_ABI" | |
exit 1 | |
fi | |
eval $_outvar=\$_ARCH | |
eval $_outvar64=\$_ARCH64 | |
} | |
while [[ $# > 0 ]]; do | |
case $1 in | |
--revert) | |
revert=yes | |
;; | |
--extra-options) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--extra-options requires an argument." | |
exit 1 | |
fi | |
extra_options="$1" | |
;; | |
--lib) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--lib requires an argument." | |
exit 1 | |
fi | |
lib="$1" | |
;; | |
--device) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--device requires an argument." | |
exit 1 | |
fi | |
device="$1" | |
;; | |
--use-su) | |
use_su=1 | |
;; | |
*) | |
usage | |
;; | |
esac | |
shift | |
done | |
ADB=${ADB:-adb} | |
if [[ x$device != x ]]; then | |
ADB="$ADB -s $device" | |
fi | |
if [ $use_su -eq 1 ]; then | |
# Test if 'su' is present on the device | |
SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` | |
SU_TEST_OUT=`echo ${SU_TEST_OUT//[[:space:]]}` | |
if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then | |
echo "ERROR: Cannot use 'su -c':" | |
echo "$ adb shell su -c \"echo foo\"" | |
echo $SU_TEST_OUT | |
echo "Check that 'su' binary is correctly installed on the device or omit" | |
echo " --use-su flag" | |
exit 1 | |
fi | |
fi | |
echo '>> Remounting /system rw' | |
adb_wait_for_device | |
adb_root | |
adb_wait_for_device | |
adb_remount | |
adb_wait_for_device | |
get_device_arch ARCH ARCH64 | |
echo "Target architecture: $ARCH" | |
ASAN_RT="libclang_rt.asan-$ARCH-android.so" | |
if [[ -n $ARCH64 ]]; then | |
echo "Target architecture: $ARCH64" | |
ASAN_RT64="libclang_rt.asan-$ARCH64-android.so" | |
fi | |
#New Added. ZW | |
RELEASE=$(adb_shell getprop ro.build.version.release) | |
PRE_L=0 | |
if echo "$RELEASE" | grep '^4\.' >&/dev/null; then | |
PRE_L=1 | |
fi | |
ANDROID_O=0 | |
if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then | |
# 8.0.x is for Android O | |
ANDROID_O=1 | |
fi | |
if [[ x$revert == xyes ]]; then | |
echo '>> Uninstalling ASan' | |
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then | |
echo '>> Pre-L device detected.' | |
adb_shell mv /system/bin/app_process.real /system/bin/app_process | |
adb_shell rm /system/bin/asanwrapper | |
elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then | |
# 64-bit installation. | |
adb_shell mv /system/bin/app_process32.real /system/bin/app_process32 | |
adb_shell mv /system/bin/app_process64.real /system/bin/app_process64 | |
adb_shell rm /system/bin/asanwrapper | |
adb_shell rm /system/bin/asanwrapper64 | |
else | |
# 32-bit installation. | |
adb_shell rm /system/bin/app_process.wrap | |
adb_shell rm /system/bin/asanwrapper | |
adb_shell rm /system/bin/app_process | |
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process | |
fi | |
if [[ ANDROID_O -eq 1 ]]; then | |
adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt | |
fi | |
echo '>> Restarting shell' | |
adb_shell stop | |
adb_shell start | |
# Remove the library on the last step to give a chance to the 'su' binary to | |
# be executed without problem. | |
adb_shell rm /system/lib/$ASAN_RT | |
echo '>> Done' | |
exit 0 | |
fi | |
if [[ -d "$lib" ]]; then | |
ASAN_RT_PATH="$lib" | |
elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then | |
ASAN_RT_PATH=$(dirname "$lib") | |
elif [[ -f "$HERE/$ASAN_RT" ]]; then | |
ASAN_RT_PATH="$HERE" | |
elif [[ $(basename "$HERE") == "bin" ]]; then | |
# We could be in the toolchain's base directory. | |
# Consider ../lib, ../lib/asan, ../lib/linux, | |
# ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux. | |
P=$(ls "$HERE"/../lib/"$ASAN_RT" \ | |
"$HERE"/../lib/asan/"$ASAN_RT" \ | |
"$HERE"/../lib/linux/"$ASAN_RT" \ | |
"$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \ | |
"$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) | |
if [[ -n "$P" ]]; then | |
ASAN_RT_PATH="$(dirname "$P")" | |
fi | |
fi | |
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then | |
echo ">> ASan runtime library not found" | |
exit 1 | |
fi | |
if [[ -n "$ASAN_RT64" ]]; then | |
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then | |
echo ">> ASan runtime library not found" | |
exit 1 | |
fi | |
fi | |
TMPDIRBASE=$(mktemp -d -t template) | |
TMPDIROLD="$TMPDIRBASE/old" | |
TMPDIR="$TMPDIRBASE/new" | |
mkdir "$TMPDIROLD" | |
RELEASE=$(adb_shell getprop ro.build.version.release) | |
PRE_L=0 | |
if echo "$RELEASE" | grep '^4\.' >&/dev/null; then | |
PRE_L=1 | |
fi | |
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then | |
if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then | |
echo '>> Old-style ASan installation detected. Reverting.' | |
adb_shell mv /system/bin/app_process.real /system/bin/app_process | |
fi | |
echo '>> Pre-L device detected. Setting up app_process symlink.' | |
adb_shell mv /system/bin/app_process /system/bin/app_process32 | |
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process | |
fi | |
echo '>> Copying files from the device' | |
if [[ -n "$ASAN_RT64" ]]; then | |
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true | |
adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process64 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true | |
else | |
echo "Pulling from device" "$TMPDIROLD" | |
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true | |
echo "finish pulling" | |
fi | |
cp -r "$TMPDIROLD" "$TMPDIR" | |
if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then | |
echo ">> Previous installation detected" | |
else | |
echo ">> New installation" | |
fi | |
echo '>> Generating wrappers' | |
cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" | |
if [[ -n "$ASAN_RT64" ]]; then | |
cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/" | |
fi | |
ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0 | |
# The name of a symlink to libclang_rt.asan-$ARCH-android.so used in LD_PRELOAD. | |
# The idea is to have the same name in lib and lib64 to keep it from falling | |
# apart when a 64-bit process spawns a 32-bit one, inheriting the environment. | |
ASAN_RT_SYMLINK=symlink-to-libclang_rt.asan | |
function generate_zygote_wrapper { # from, to | |
local _from=$1 | |
local _to=$2 | |
if [[ PRE_L -eq 0 ]]; then | |
# LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is | |
# unset in the system environment since L. | |
local _ld_preload=$ASAN_RT_SYMLINK | |
else | |
local _ld_preload=\$LD_PRELOAD:$ASAN_RT_SYMLINK | |
fi | |
cat <<EOF >"$TMPDIR/$_from" | |
#!/system/bin/sh-from-zygote | |
ASAN_OPTIONS=$ASAN_OPTIONS \\ | |
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\ | |
LD_PRELOAD=$_ld_preload \\ | |
exec $_to \$@ | |
EOF | |
} | |
# On Android-L not allowing user segv handler breaks some applications. | |
# Since ~May 2017 this is the default setting; included for compatibility with | |
# older library versions. | |
if [[ PRE_L -eq 0 ]]; then | |
ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" | |
fi | |
if [[ x$extra_options != x ]] ; then | |
ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" | |
fi | |
# Zygote wrapper. | |
if [[ -f "$TMPDIR/app_process64" ]]; then | |
# A 64-bit device. | |
if [[ ! -f "$TMPDIR/app_process64.real" ]]; then | |
# New installation. | |
mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real" | |
mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real" | |
fi | |
generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" | |
generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" | |
else | |
# A 32-bit device. | |
generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" | |
fi | |
# General command-line tool wrapper (use for anything that's not started as | |
# zygote). | |
cat <<EOF >"$TMPDIR/asanwrapper" | |
#!/system/bin/sh | |
LD_PRELOAD=$ASAN_RT_SYMLINK \\ | |
exec \$@ | |
EOF | |
if [[ -n "$ASAN_RT64" ]]; then | |
cat <<EOF >"$TMPDIR/asanwrapper64" | |
#!/system/bin/sh | |
LD_PRELOAD=$ASAN_RT_SYMLINK \\ | |
exec \$@ | |
EOF | |
fi | |
function install { # from, to, chmod, chcon | |
local _from=$1 | |
local _to=$2 | |
local _mode=$3 | |
local _context=$4 | |
local _basename="$(basename "$_from")" | |
echo "Installing $_to/$_basename $_mode $_context" | |
adb_push "$_from" "$_to/$_basename" | |
adb_shell chown root.shell "$_to/$_basename" | |
if [[ -n "$_mode" ]]; then | |
adb_shell chmod "$_mode" "$_to/$_basename" | |
fi | |
if [[ -n "$_context" ]]; then | |
adb_shell chcon "$_context" "$_to/$_basename" | |
fi | |
} | |
if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then | |
# Make SELinux happy by keeping app_process wrapper and the shell | |
# it runs on in zygote domain. | |
ENFORCING=0 | |
if adb_shell getenforce | grep Enforcing >/dev/null; then | |
# Sometimes shell is not allowed to change file contexts. | |
# Temporarily switch to permissive. | |
ENFORCING=1 | |
adb_shell setenforce 0 | |
fi | |
if [[ PRE_L -eq 1 ]]; then | |
CTX=u:object_r:system_file:s0 | |
else | |
CTX=u:object_r:zygote_exec:s0 | |
fi | |
echo '>> Pushing files to the device' | |
if [[ -n "$ASAN_RT64" ]]; then | |
install "$TMPDIR/$ASAN_RT" /system/lib 644 | |
install "$TMPDIR/$ASAN_RT64" /system/lib64 644 | |
install "$TMPDIR/app_process32" /system/bin 755 $CTX | |
install "$TMPDIR/app_process32.real" /system/bin 755 $CTX | |
install "$TMPDIR/app_process64" /system/bin 755 $CTX | |
install "$TMPDIR/app_process64.real" /system/bin 755 $CTX | |
install "$TMPDIR/asanwrapper" /system/bin 755 | |
install "$TMPDIR/asanwrapper64" /system/bin 755 | |
adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK | |
adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK | |
adb_shell rm -f /system/lib64/$ASAN_RT_SYMLINK | |
adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK | |
else | |
install "$TMPDIR/$ASAN_RT" /system/lib 644 | |
install "$TMPDIR/app_process32" /system/bin 755 $CTX | |
install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX | |
install "$TMPDIR/asanwrapper" /system/bin 755 $CTX | |
adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK | |
adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK | |
adb_shell rm /system/bin/app_process | |
adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process | |
fi | |
adb_shell cp /system/bin/sh /system/bin/sh-from-zygote | |
adb_shell chcon $CTX /system/bin/sh-from-zygote | |
if [[ ANDROID_O -eq 1 ]]; then | |
# For Android O, the linker namespace is temporarily disabled. | |
adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved | |
fi | |
if [ $ENFORCING == 1 ]; then | |
adb_shell setenforce 1 | |
fi | |
echo '>> Restarting shell (asynchronous)' | |
adb_shell stop | |
adb_shell start | |
echo '>> Please wait until the device restarts' | |
else | |
echo '>> Device is up to date' | |
fi | |
rm -r "$TMPDIRBASE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment