Index: lib/asan/scripts/asan_device_setup.bat =================================================================== --- lib/asan/scripts/asan_device_setup.bat +++ lib/asan/scripts/asan_device_setup.bat @@ -0,0 +1,487 @@ +@ECHO OFF +REM ===- lib/asan/scripts/asan_device_setup -----------------------------------===# +REM +REM The LLVM Compiler Infrastructure +REM +REM This file is distributed under the University of Illinois Open Source +REM License. See LICENSE.TXT for details. +REM +REM Prepare Android device to run ASan applications. +REM +REM ===------------------------------------------------------------------------===# +SETLOCAL EnableExtensions EnableDelayedExpansion +SET HERE=%~dp0 +SET revert=no +SET extra_options= +SET device= +SET lib= +SET use_su=0 +SET ADB=%ANDROID_HOME%\platform-tools\adb.exe +IF %HERE:~-1%==\ SET HERE=%HERE:~0,-1% + +:parseArgsLoop +IF NOT "%1"=="" ( + IF "%1"=="--revert" ( + SET revert=yes + SHIFT + GOTO :parseArgsLoop + ) + IF "%1"=="--extra-options" ( + IF "%2"=="" ( + ECHO --extra-options requires an argument. + GOTO :END + ) + SET extra_options=%2 + SHIFT + SHIFT + GOTO :parseArgsLoop + ) + IF "%1"=="--lib" ( + IF "%2"=="" ( + ECHO "--lib requires an argument." + GOTO :END + ) + set lib="%2" + SHIFT + SHIFT + GOTO :parseArgsLoop + ) + IF "%1"=="--device" ( + IF "%2"=="" ( + ECHO "--device requires an argument." + GOTO :END + ) + SET device="%2" + SHIFT + SHIFT + GOTO :parseArgsLoop + ) + IF "%1"=="--use-su" ( + SET use_su=1 + SHIFT + GOTO :parseArgsLoop + ) + GOTO :usage +) + +IF NOT "%device%"=="" ( + SET ADB=%ADB% -s %device% |rem +) + +IF %use_su%==1 ( + REM Test if 'su' is present on the device + FOR /F "delims=" %%I IN ( '%ADB% shell su -c "echo foo" "2>&1"' ) DO (SET SU_TEST_OUT=%%I) + IF NOT "%SU_TEST_OUT%"=="foo" ( + ECHO ERROR: Cannot use 'su -c': + ECHO $ adb shell su -c "echo foo" + ECHO Check that 'su' binary is correctly installed on the device or omit + ECHO --use-su flag + GOTO :END + ) +) + +ECHO ">> Remounting /system rw" + +CALL :adb_wait_for_device +CALL :adb_root +CALL :adb_wait_for_device +CALL :adb_remount +CALL :adb_wait_for_device + +CALL :get_device_arch + +ECHO Target architecture: %ARCH% + +SET ASAN_RT=libclang_rt.asan-%ARCH%-android.so +IF NOT "%ARCH64%"=="" ( + ECHO Target architecture: %ARCH64% + SET ASAN_RT64=libclang_rt.asan-%ARCH64%-android.so + ) + +IF "%revert%"=="yes" ( + CALL :run_revert + GOTO :END +) + +SET useLibPath= +IF NOT ("%lib%"=="") IF EXIST ("%lib%\*") SET useLibPath=1 +IF "%useLibPath%"=="1" ( + SET ASAN_RT_PATH=%lib% +) ELSE ( + IF EXIST "%lib%" ( + IF "%lib%"=="*%ASAN_RT%" ( + FOR %%F IN ("%lib%") DO SET ASAN_RT_PATH=%%~dpF + ) + ) ELSE ( + IF EXIST "%HERE%/%ASAN_RT%" ( + SET ASAN_RT_PATH=%HERE% + ) else ( + FOR /d %%d IN ("%HERE%") DO SET baseName=%%~nxd + IF "!baseName!"=="bin" ( + REM We could be in the toolchain's base directory. + REM Consider ../lib, ../lib/asan, ../lib/linux, + REM ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux. + IF EXIST "%HERE%\..\lib\%ASAN_RT%" SET ASAN_RT_PATH=%HERE%\..\lib + IF EXIST "%HERE%\..\lib\asan\%ASAN_RT%" SET ASAN_RT_PATH=%HERE%\..\lib\asan + IF EXIST "%HERE%\..\lib\linux\%ASAN_RT%" SET ASAN_RT_PATH=%HERE%\..\lib\linux + FOR /d %%a IN ("%HERE%\..\lib\clang\*") DO ( IF EXIST "%%~fa\lib\linux\%ASAN_RT%" SET ASAN_RT_PATH=%%~fa\lib\linux) + FOR /d %%a IN ("%HERE%\..\lib64\clang\*") DO ( IF EXIST "%%~fa\lib\linux\%ASAN_RT%" SET ASAN_RT_PATH=%%~fa\lib\linux) + ) + ) + ) +) + +IF NOT EXIST "%ASAN_RT_PATH%\%ASAN_RT%" ( + IF "%ASAN_RT64%"=="" ( + ECHO ">>ASan runtime library not found" + GOTO :END + ) +) + +IF NOT "%ASAN_RT64%"=="" ( + IF NOT EXIST "%ASAN_RT_PATH%\%ASAN_RT64%" ( + ECHO ">> ASan runtime library not found" + GOTO :END + ) +) + +SET TMPDIRBASE=%~nx0_%time::=.% +SET TMPDIROLD=%TMPDIRBASE%/old +SET TMPDIR=%TMPDIRBASE%/new +mkdir "%TMPDIROLD%" + +ECHO "made %TMPDIROLD% + +CALL :adb_shell getprop ro.build.version.release +SET RELEASE=%OUT% +SET PRE_L=0 +CALL :adb_shell "ls -l /system/bin/app_process" +IF "%OUT:-> app_process=%"=="%OUT%" SET PRE_L=1 + +IF "%PRE_L%"=="1" ( + CALL :adb_pull /system/bin/app_process.real NUL + IF %ERRORLEVEL% == 0 ( + ECHO ">> Old-style ASan installation detected. Reverting." + CALL :adb_shell "mv /system/bin/app_process.real /system/bin/app_process" + ) + + ECHO ">> Pre-L device detected. Setting up app_process symlink." + CALL :adb_shell "mv /system/bin/app_process /system/bin/app_process32" + CALL :adb_shell "ln -s /system/bin/app_process32 /system/bin/app_process" +) + +ECHO ">> Copying files from the device" +IF NOT "%ASAN_RT64%"=="" ( + CALL :adb_pull /system/lib/"%ASAN_RT%" "%TMPDIROLD%" + CALL :adb_pull /system/lib64/"%ASAN_RT64%" "%TMPDIROLD%" + CALL :adb_pull /system/bin/app_process32 "%TMPDIROLD%" + CALL :adb_pull /system/bin/app_process32.real "%TMPDIROLD%" + CALL :adb_pull /system/bin/app_process64 "%TMPDIROLD%" + CALL :adb_pull /system/bin/app_process64.real "%TMPDIROLD%" + CALL :adb_pull /system/bin/asanwrapper "%TMPDIROLD%" + CALL :adb_pull /system/bin/asanwrapper64 "%TMPDIROLD%" +) ELSE ( + CALL :adb_pull /system/lib/%ASAN_RT% %TMPDIROLD% + CALL :adb_pull /system/bin/app_process32 %TMPDIROLD% + CALL :adb_pull /system/bin/app_process.wrap %TMPDIROLD% + CALL :adb_pull /system/bin/asanwrapper %TMPDIROLD% +) +xcopy /s/e /I "%TMPDIROLD%" "%TMPDIR%" + +SET prevInstall= +IF EXIST "%TMPDIR%/app_process.wrap" SET prevInstall=1 +IF EXIST "%TMPDIR%/app_process64.real" SET prevInstall=1 +IF DEFINED prevInstall ( + ECHO ">> Previous installation detected" +) ELSE ( + ECHO ">> New installation" +) + +ECHO ">> Generating wrappers" +xcopy /s/e /I "%ASAN_RT_PATH%/%ASAN_RT%" "%TMPDIR%" +IF NOT "%ASAN_RT64%"=="" ( + xcopy /s/e /I "%ASAN_RT_PATH%/%ASAN_RT64%" "%TMPDIR%" +) + +SET ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0 +REM On Android-L not allowing user segv handler breaks some applications. +IF %PRE_L%==0 ( + SET ASAN_OPTIONS=%ASAN_OPTIONS%,allow_user_segv_handler=1 +) + +IF NOT x%extra_options%==x ( + SET ASAN_OPTIONS=%ASAN_OPTIONS%,%extra_options% +) + +REM Zygote wrapper. +IF EXIST "%TMPDIR%/app_process64" ( + REM A 64-bit device. + IF NOT EXIST "%TMPDIR%/app_process64.real" ( + REM New installation. + move /y "%TMPDIR%/app_process32" "%TMPDIR%/app_process32.real" + move /y "%TMPDIR%/app_process64" "%TMPDIR%/app_process64.real" + ) + CALL :generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "%ASAN_RT%" + CALL :generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "%ASAN_RT64%" +) ELSE ( + REM A 32-bit device. + CALL :generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "%ASAN_RT%" +) + +REM General command-line tool wrapper (use for anything that's not started as +REM zygote). +( + ECHO #!/system/bin/sh + ECHO LD_PRELOAD=%ASAN_RT% + ECHO exec $@ +) >"%TMPDIR%/asanwrapper" + +IF NOT "%ASAN_RT64%"=="" ( +( + ECHO #!/system/bin/sh + ECHO LD_PRELOAD=%ASAN_RT64% + ECHO exec $@ +) >"%TMPDIR%/asanwrapper64" +) + +SET DIFFERENTFOLDER=0 +FOR %%a IN ("%TMPDIRBASE%\new\*") DO IF NOT EXIST "%TMPDIRBASE%/old/%%~na" SET DIFFERENTFOLDER=1 +IF "%DIFFERENTFOLDER%"=="1" ( + REM Make SELinux happy by keeping app_process wrapper and the shell + REM it runs on in zygote domain. + SET ENFORCING=0 + CALL :adb_shell getenforce + IF "%OUT%"=="Enforcing" ( + REM Sometimes shell is not allowed to change file contexts. + REM Temporarily switch to permissive. + SET ENFORCING=1 + CALL :adb_shell setenforce 0 + ) + + IF %PRE_L%==1 ( + SET CTX=u:object_r:system_file:s0 + ) ELSE ( + SET CTX=u:object_r:zygote_exec:s0 + ) + + ECHO ">> Pushing files to the device" + + IF NOT "%ASAN_RT64%"=="" ( + CALL :install "%TMPDIR%/%ASAN_RT%" /system/lib 644 + CALL :install "%TMPDIR%/%ASAN_RT64%" /system/lib64 644 + CALL :install "%TMPDIR%/app_process32" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/app_process32.real" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/app_process64" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/app_process64.real" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/asanwrapper" /system/bin 755 + CALL :install "%TMPDIR%/asanwrapper64" /system/bin 755 + ) ELSE ( + CALL :install "%TMPDIR%/%ASAN_RT%" /system/lib 644 + CALL :install "%TMPDIR%/app_process32" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/app_process.wrap" /system/bin 755 %CTX% + CALL :install "%TMPDIR%/asanwrapper" /system/bin 755 %CTX% + + CALL :adb_shell rm /system/bin/app_process + CALL :adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process + ) + + CALL :adb_shell cp /system/bin/sh /system/bin/sh-from-zygote + CALL :adb_shell chcon %CTX% /system/bin/sh-from-zygote + + if "%ENFORCING%"=="1" ( + CALL :adb_shell setenforce 1 + ) + + ECHO ">> Restarting shell (asynchronous)" + CALL :adb_shell stop + CALL :adb_shell start + + ECHO ">> Please wait until the device restarts" +) ELSE ( + ECHO ">> Device is up to date" +) + +RMDIR /S /Q "%TMPDIRBASE%" + + +REM Done with "main" logic +ECHO DONE! +goto :END + +REMStart defining functions +:usage + ECHO usage: %~nx0 [--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. +goto :END + +:adb_push + IF %use_su%==0 ( + "%ADB%" push "%1" "%2" |REM + ) ELSE ( + FOR /F %%i IN ("%1") DO @SET FILENAME=%%~nxi + "%ADB%" push "%1" "/data/local/tmp/%FILENAME%" |REM + "%ADB%" shell su -c "rm \\\"%2/%FILENAME%\\\"" >nul 2>&1 |REM + "%ADB%" shell su -c "cat \\\"/data/local/tmp/%FILENAME%\\\" > \\\"%2/%FILENAME%\\\"" |REM + "%ADB%" shell su -c "rm \\\"/data/local/tmp/%FILENAME%\\\"" |REM + ) +EXIT /B 0 + +:adb_remount + IF %use_su%==0 ( + "%ADB%" remount |REM + GOTO :doneLoop + ) + IF %use_su%==1 ( + SET STORAGE= + FOR /F "delims=" %%I IN ( '%ADB% shell mount "2>&1"' ) DO ( + SET VAR=%%I + SET TEST=!VAR:system=! + IF NOT "!TEST!"=="%%I" ( + SET STORAGE=%%I + ECHO Remounting !STORAGE! at /system + "%ADB%" shell su -c "mount -o remount,rw !STORAGE! /system" |REM + GOTO :doneLoop + ) + ) + echo Failed to get storage device name for "/system" mount point + :doneLoop +EXIT /B 0 + +:adb_shell + SET OUT= + IF %use_su%==0 ( + FOR /F "delims=" %%I in ('%ADB% shell %* "2>&1"') DO SET "OUT=%%I" + ) + IF %use_su%==1 ( + FOR /F "delims=" %%I in ('%ADB% shell su -c %* "2>&1"') DO SET "OUT=%%I" + ) +EXIT /B 0 + +:adb_root + IF %use_su%==0 ( + "%ADB%" root|REM + ) +EXIT /B 0 + +:adb_wait_for_device + "%ADB%" wait-for-device |REM +EXIT /B 0 + +:adb_pull + IF %use_su%==0 ( + %ADB% pull "%~1" "%~2" >nul 2>&1 + ) + IF %use_su%==1 ( + FOR /F %%i IN ("%~1") DO @SET FILENAME=%%~nxi + %ADB% shell rm "/data/local/tmp/!FILENAME!" >nul 2>&1 + %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" 2>nul && %ADB% shell "rm \"/data/local/tmp/!FILENAME!\"" + ) +EXIT /B 0 + +:get_device_arch +REM OUT OUT64 + CALL :adb_shell getprop ro.product.cpu.abi + SET _ABI=%OUT% + SET ARCH= + SET ARCH64= + IF NOT "%_ABI:x86=%"=="%_ABI%" ( + SET ARCH=i686 + ) + IF NOT "%_ABI:armeabi=%"=="%_ABI%" ( + SET ARCH=arm + ) + IF NOT "%_ABI:arm64-v8a=%"=="%_ABI%" ( + SET ARCH=arm + SET ARCH64=aarch64 + ) + IF "%ARCH%"=="" ( + ECHO Unrecognized device ABI: %_ABI% + GOTO :END + ) +EXIT /B 0 + +:run_revert + SETLOCAL + ECHO ">> Uninstalling ASan" + + SET DIDREVERT=no + CALL :adb_shell "ls -l /system/bin/app_process" + IF "%OUT:-> app_process=%"=="%OUT%" ( + SET DIDREVERT=yes + ECHO ">>Pre-L device detected." + CALL :adb_shell "mv /system/bin/app_process.real /system/bin/app_process" + CALL :adb_shell "rm /system/bin/asanwrapper" + ) + CALL :adb_shell "ls -l /system/bin/app_process64.real" + IF "%OUT:No such file or directory=%"=="%OUT%" ( + SET DIDREVERT=yes + ECHO ">>64-bit device detected." + CALL :adb_shell "mv /system/bin/app_process32.real /system/bin/app_process32" + CALL :adb_shell "mv /system/bin/app_process64.real /system/bin/app_process64" + CALL :adb_shell "rm /system/bin/asanwrapper" + CALL :adb_shell "rm /system/bin/asanwrapper64" + ) + IF "!DIDREVERT!"=="no" ( + ECHO ">>32-bit device detected." + CALL :adb_shell "rm /system/bin/app_process.wrap" + CALL :adb_shell "rm /system/bin/asanwrapper" + CALL :adb_shell "rm /system/bin/app_process" + CALL :adb_shell "ln -s /system/bin/app_process32 /system/bin/app_process" + ) + ECHO ">> Restarting shell" + CALL :adb_shell stop + CALL :adb_shell start + + REM Remove the library on the last step to give a chance to the 'su' binary to + REM be executed without problem. + CALL :adb_shell rm /system/lib/%ASAN_RT% + + ECHO ">> Done" +EXIT /B 0 + +:install + REM from, to, chmod, chcon + SETLOCAL + SET _from=%~1 + SET _to=%~2 + SET _mode=%~3 + SET _context=%~4 + FOR /d %%d IN ("%_from%") DO SET _basename=%%~nxd + ECHO "Installing %_to%/%_basename% %_mode% %_context%" + CALL :adb_push "%_from%" "%_to%/%_basename%" + CALL :adb_shell chown root.shell "%_to%/%_basename%" + IF NOT "%_mode%"=="" CALL :adb_shell chmod "%_mode%" "%_to%/%_basename%" + IF NOT "%_context%"=="" CALL :adb_shell chcon "%_context%" "%_to%/%_basename%" +EXIT /B 0 + +:generate_zygote_wrapper +REM from, to, asan_rt + SETLOCAL + SET _from=%~1 + SET _to=%~2 + SET _asan_rt=%~3 + IF %PRE_L%==0 ( + REM LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is + REM unset in the system environment since L. + SET _ld_preload=%_asan_rt% + ) ELSE ( + SET _ld_preload=\%LD_PRELOAD%:%_asan_rt% + ) + ( + ECHO #!/system/bin/sh-from-zygote + ECHO ASAN_OPTIONS=%ASAN_OPTIONS% + ECHO ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b + ECHO LD_PRELOAD=%_ld_preload% + ECHO exec %_to% $@ + ) >"%TMPDIR%/%_from%" +EXIT /B 0 + + +:END \ No newline at end of file