LLVM 새니타이저
Android 사이트 참고
LLVM 새니타이저 이란?
Android를 빌드하는 데 사용되는 컴파일러 인프라인 LLVM에는 정적 및 동적 분석을 처리하는 여러 구성요소가 포함되어 있습니다. 이러한 구성요소 중 특히 AddressSanitizer 및 UndefinedBehaviorSanitizer와 같은 새니타이저는 Android를 분석하는 데 광범위하게 사용할 수 있습니다. 새니타이저는 external/compiler-rt에 포함된 컴파일러 기반의 계측 구성요소로서 개발 및 테스트 과정에서 버그를 없애고 Android를 개선하는 데 사용할 수 있습니다. Android의 현재 새니타이저는 많은 메모리 오용 버그와 잠재적 위험성이 있는 정의되지 않은 동작을 발견하고 진단할 수 있습니다.
AddressSanitizer 및 UndefinedBehaviorSanitizer와 같은 새니타이저를 사용 설정하여 Android 빌드를 부팅하고 실행하는 것이 좋습니다. 이 페이지에서는 AddressSanitizer, UndefinedBehaviorSanitizer 및 KernelAddressSanitizer를 소개하고 Android 빌드 시스템 내에서 어떻게 사용할 수 있는지 보여주며, 이러한 새니타이저를 사용 설정하여 네이티브 구성요소를 빌드하는 Android.mk 및 Android.bp 파일의 예를 제시합니다.
AddressSanitizer
AddressSanitizer(ASan)는 런타임 시 C/C++ 코드에서 여러 유형의 메모리 오류를 감지하는 컴파일러 기반의 계측 기능입니다. ASan은 다음과 같은 여러 클래스의 메모리 오류를 감지할 수 있습니다.
범위를 벗어난 메모리 액세스
Double free
Use-after-free
Android는 전체 빌드 수준에서의 Asan 계측과 asanwrapper를 사용하는 앱 수준을 허용합니다.
AddressSanitizer는 alloca, malloc 및 free를 포함한 모든 메모리 관련 함수 호출의 계측과 모든 변수 및 할당된 메모리 영역 패딩을 읽히거나 쓰일 때 ASan 콜백을 트리거하는 메모리와 결합합니다.
ASan에서는 계측을 사용하여 double-free, use-after-scope, use-after-return, use-after-free와 같은 잘못된 메모리 사용 버그를 감지하고, 메모리 영역 패딩은 범위를 벗어난 읽기 또는 쓰기를 감지합니다. 이 패딩 영역에서 읽기 또는 쓰기가 발생하면 ASan은 이를 포착하고 호출 스택, 섀도 메모리 맵, 메모리 위반 유형, 읽거나 쓴 내용, 위반을 초래한 명령, 메모리 내용을 비롯한 메모리 위반을 진단하는 데 도움을 주는 정보를 출력합니다.
버그 발견 프로세스는 특히 힙 프라이밍 또는 경합 상태 취약점 공격과 같이 특수 설정 또는 고급 기법이 필요한 버그의 경우 비결정적으로 보일 수 있습니다. 이러한 버그의 상당수는 즉시 드러나지 않으며 실제 근본 원인인 메모리 위반이 발생한 후 수천 개의 명령이 진행된 후에야 드러날 수 있습니다. ASan은 모든 메모리 관련 함수를 계측하고 ASan 콜백을 트리거하지 않으면 액세스할 수 없는 영역이 있는 데이터를 패딩합니다. 즉, 비정상 종료를 초래하는 손상이 발생할 때까지 기다리는 것이 아니라 메모리 위반이 발생하는 순간에 메모리 위반을 포착합니다. 이러한 방식은 버그 발견 및 근본 원인 진단에 매우 유용합니다.
타겟 기기에서 ASAN이 작동하는지 확인하기 위해 Android에는 asan_test 실행 파일이 포함되어 있습니다. asan_test 실행 파일은 타겟 기기에서 ASAN 기능을 테스트 및 검증하여 각 테스트의 상태가 포함된 진단 메시지를 제공합니다. ASAN Android 빌드를 사용하는 경우 실행 파일은 기본적으로 /data/nativetest/asan_test/asan_test
또는 /data/nativetest64/asan_test/asan_test
에 있습니다.
UndefinedBehaviorSanitizer
UndefinedBehaviorSanitizer(UBSan)는 컴파일 시간을 계측하여 다양한 유형의 정의되지 않은 동작을 검사합니다. UBSan은 여러 정의되지 않은 동작을 감지할 수 있고, Android는 bool, bounds, enum, float-cast-overflow, float-divide-by-zero, integer-divide-by-zero, nonnull-attribute, null, return, returns-nonnull-attribute, shift-base, shift-exponent, signed-integer-overflow, unreachable, unsigned-integer-overflow, vla-bound를 지원합니다. unsigned-integer-overflow의 경우 엄밀하게 말하면 정의되지 않은 동작은 아니지만, 잠재적인 integer-overflow 취약점을 제거하기 위해 새니타이저에 포함되어 미디어 서버 구성요소를 비롯한 많은 Android 모듈에서 사용됩니다.
구현
Android 빌드 시스템에서는 UBSan을 전역 또는 로컬에서 사용 설정할 수 있습니다. UBSan을 전역에서 사용 설정하려면 Android.mk에서 SANITIZE_TARGET을 설정합니다. UBSan을 모듈별 수준에서 사용 설정하려면 LOCAL_SANITIZE를 설정하고 Android.mk에서 찾고자 하는 정의되지 않은 동작을 지정합니다. 예:
Android 빌드 시스템은 makefile처럼 청사진 파일의 세부 진단을 아직 지원하지 않습니다. 다음은 청사진(Android.bp)과 거의 동일하게 작성된 코드입니다.
UBSan 단축키
Android에는 일련의 새니타이저를 동시에 사용 설정할 수 있는 두 가지 손쉬운 방법으로 integer
및 default-ub
를 제공합니다. integer는 integer-divide-by-zero
, signed-integer-overflow
및 unsigned-integer-overflow
를 지원합니다. default-ub
는 검사 시 bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable 및 vla-bound의 컴파일러 성능 문제를 최소화합니다. integer 새니타이저 클래스는 SANITIZE_TARGET 및 LOCAL_SANITIZE에서 사용할 수 있지만 default-ub는 SANITIZE_TARGET에서만 사용할 수 있습니다.
오류 신고 개선
Android의 기본 UBSan 구현은 정의되지 않은 동작이 발생할 때 지정된 함수를 호출합니다. 기본적으로 이 함수는 중단됩니다. 하지만 2016년 10월부터 Android UBSan은 발생한 정의되지 않은 동작의 유형, 파일 및 소스 코드 행 정보를 비롯한 더 세부적인 오류 신고 기능을 제공하는 런타임 라이브러리 옵션을 제공합니다. 정수 검사가 포함된 오류 신고 기능을 사용하려면 다음을 Android.mk 파일에 추가합니다.
LOCAL_SANITIZE 값은 빌드하는 동안 새니타이저를 사용 설정합니다. LOCAL_SANITIZE_DIAG는 지정된 새니타이저의 진단 모드를 사용 설정합니다. LOCAL_SANITIZE 및 LOCAL_SANITIZE_DIAG를 서로 다른 값으로 설정할 수 있지만, LOCAL_SANITIZE의 검사만 사용 설정됩니다. 검사가 LOCAL_SANITIZE에 지정되지 않았지만 LOCAL_SANITIZE_DIAG에 지정되어 있으면 검사는 사용 설정되지 않으며 진단 메시지도 제공되지 않습니다.
다음은 UBSan 런타임 라이브러리에서 제공하는 정보의 예시입니다.
Kernel Address Sanitizer
LLVM 기반의 사용자 공간 구성요소 새니타이저와 마찬가지로 Android에는 Kernel Address Sanitizer(KASAN)가 포함되어 있습니다. KASAN은 커널 및 컴파일 시간 수정 기능을 결합하여 버그 탐색 및 근본 원인 분석을 단순화하는 계측 시스템을 제공합니다.
KASAN은 커널에서 여러 유형의 메모리 위반을 감지할 수 있습니다. 또한 스택, 힙 및 전역 변수에서의 범위를 벗어난 읽기 및 쓰기와 use-after-free 및 double free를 감지할 수 있습니다.
ASAN과 마찬가지로 KASAN은 런타임 시 메모리 액세스를 추적하기 위해 컴파일 시점의 메모리 함수 계측과 섀도 메모리의 조합을 사용합니다. KASAN에서 커널 메모리 공간의 8분의 1은 메모리 액세스가 유효한지 아닌지를 결정하는 섀도 메모리 전용입니다.
KASAN은 x86_64 및 arm64 아키텍처에서 지원됩니다. 4.0부터 업스트림 커널의 일부였으며 Android 3.18 기반 커널로 백포트되었습니다. KASAN은 4.9.2를 기반으로 하여 gcc로 컴파일된 Android 커널에서 테스트되었습니다.
KASAN 외에도 kcov는 테스트에 유용한 또 다른 커널 수정 기능입니다. kcov는 커널에서 커버리지 기반 퍼징 테스트를 지원하기 위해 개발되었습니다. 이는 syscall 입력 값으로 커버리지를 측정하며 syzkaller와 같은 퍼징 시스템에서 유용합니다.
구현
KASAN 및 kcov가 사용 설정된 커널을 컴파일하려면 커널 빌드 구성에 다음 빌드 플래그를 추가합니다.
그리고 다음을 삭제합니다.
그런 다음 평소와 같이 커널을 빌드하고 플래시합니다. KASAN 커널은 원래 커널보다 훨씬 큽니다. 가능한 경우 부트 매개변수와 부트로더 설정을 수정합니다.
커널을 플래시한 후 KASAN이 사용 설정되어 실행 중인지 커널 부트 로그를 확인합니다. 커널은 다음과 같이 KASAN의 메모리 맵 정보로 시작합니다.
그리고 버그가 다음과 같이 표시됩니다.
또한 커널에서 모듈을 사용 설정하는 경우 test_kasan 커널 모듈을 로드하여 추가로 테스트할 수 있습니다. 모듈은 범위를 벗어난 메모리 액세스 및 use-after-free를 시도하며, 타겟 기기에서 KASAN을 테스트하는 데 유용합니다.
출처 : 바로가기
Last updated