AddressSanitizer (ASan)
AddressSanitizer(ASan)는 소프트웨어 테스트, 특히 퍼징 중에 널리 사용되는 메모리 오류 탐지 도구입니다. 버퍼 오버플로우, use-after-free 오류 및 기타 메모리 안전 위반과 같이 눈에 띄지 않을 수 있는 메모리 손상 버그를 탐지하는 데 도움을 줍니다.
개요
ASan은 메모리 취약점을 식별하는 데 효과적이기 때문에 퍼징에서 표준적인 방법으로 사용됩니다. 컴파일 타임에 코드를 계측하여 메모리 할당 및 접근을 추적하고, 런타임에 불법적인 작업을 탐지합니다.
주요 개념
| 개념 | 설명 |
|---|---|
| 계측 | ASan은 컴파일 중 메모리 작업에 런타임 검사를 추가합니다 |
| 섀도 메모리 | 할당 상태를 추적하기 위해 20TB의 가상 메모리를 매핑합니다 |
| 성능 비용 | 계측되지 않은 코드에 비해 약 2-4배 속도 저하 |
| 탐지 범위 | 버퍼 오버플로우, use-after-free, 이중 해제, 메모리 누수 탐지 |
적용 시기
다음과 같은 경우 이 기술을 적용하세요:
- 메모리 안전 취약점을 찾기 위해 C/C++ 코드를 퍼징할 때
- 안전하지 않은 블록(unsafe blocks)이 있는 Rust 코드를 테스트할 때
- 메모리 손상 관련 크래시를 디버깅할 때
- 메모리 오류가 의심되는 단위 테스트를 실행할 때
다음과 같은 경우 이 기술을 건너뛰세요:
- 프로덕션 코드를 실행할 때 (ASan은 보안을 낮출 수 있습니다)
- 플랫폼이 Windows 또는 macOS인 경우 (ASan 지원이 제한적입니다)
- 성능 오버헤드가 사용 사례에 허용되지 않을 때
- FFI 없이 순수 안전 언어(예: 순수 Go, 순수 Java)를 퍼징할 때
빠른 참조
| 작업 | 명령어/패턴 |
|---|---|
| ASan 활성화 (Clang/GCC) | -fsanitize=address |
| 상세 출력 활성화 | ASAN_OPTIONS=verbosity=1 |
| 누수 탐지 비활성화 | ASAN_OPTIONS=detect_leaks=0 |
| 오류 시 강제 종료 | ASAN_OPTIONS=abort_on_error=1 |
| 여러 옵션 사용 | ASAN_OPTIONS=verbosity=1:abort_on_error=1 |
단계별 가이드
1단계: ASan으로 컴파일
코드를 -fsanitize=address 플래그로 컴파일하고 링크하세요:
clang -fsanitize=address -g -o my_program my_program.c
-g 플래그는 ASan이 오류를 탐지할 때 더 나은 스택 추적을 위해 권장됩니다.
2단계: ASan 옵션 구성
ASAN_OPTIONS 환경 변수를 설정하여 ASan 동작을 구성하세요:
export ASAN_OPTIONS=verbosity=1:abort_on_error=1:detect_leaks=0
3단계: 프로그램 실행
ASan으로 계측된 바이너리를 실행하세요. 메모리 오류가 탐지되면 ASan이 상세한 보고서를 출력합니다:
./my_program
4단계: 퍼저 메모리 제한 조정
ASan은 약 20TB의 가상 메모리를 필요로 합니다. 퍼저의 메모리 제한을 비활성화하세요:
- libFuzzer:
-rss_limit_mb=0 - AFL++:
-m none
일반적인 패턴
패턴: 기본 ASan 통합
사용 사례: ASan을 사용한 표준 퍼징 설정
이전:
clang -o fuzz_target fuzz_target.c
./fuzz_target
이후:
clang -fsanitize=address -g -o fuzz_target fuzz_target.c
ASAN_OPTIONS=verbosity=1:abort_on_error=1 ./fuzz_target
패턴: ASan과 단위 테스트
사용 사례: 단위 테스트 스위트에 ASan 활성화
이전:
gcc -o test_suite test_suite.c -lcheck
./test_suite
이후:
gcc -fsanitize=address -g -o test_suite test_suite.c -lcheck
ASAN_OPTIONS=detect_leaks=1 ./test_suite
고급 사용법
팁과 요령
| 팁 | 도움이 되는 이유 |
|---|---|
-g 플래그 사용 | 디버깅을 위한 상세한 스택 추적 제공 |
verbosity=1 설정 | 프로그램 시작 전 ASan이 활성화되었는지 확인 |
| 퍼징 중 누수 탐지 비활성화 | 누수 탐지는 즉각적인 크래시를 유발하지 않으며 출력을 복잡하게 만듦 |
abort_on_error=1 활성화 | 일부 퍼저는 _exit() 대신 abort()를 필요로 함 |
ASan 보고서 이해
ASan이 메모리 오류를 탐지하면 다음을 포함한 상세 보고서를 출력합니다:
- 오류 유형: 버퍼 오버플로우, use-after-free 등
- 스택 추적: 오류가 발생한 위치
- 할당/해제 추적: 메모리가 할당되거나 해제된 위치
- 메모리 맵: 오류 주변의 섀도 메모리 상태
ASan 보고서 예시:
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff4 at pc 0x00000048e6a3
READ of size 4 at 0x60300000eff4 thread T0
#0 0x48e6a2 in main /path/to/file.c:42
샌나타이저 결합
ASan은 포괄적인 탐지를 위해 다른 샌나타이저와 결합할 수 있습니다:
clang -fsanitize=address,undefined -g -o fuzz_target fuzz_target.c
플랫폼별 고려 사항
Linux: 최고의 성능으로 완전한 ASan 지원 macOS: 제한적 지원, 일부 기능이 작동하지 않을 수 있음 Windows: 실험적 지원, 프로덕션 퍼징에는 권장되지 않음
안티 패턴
| 안티 패턴 | 문제 | 올바른 접근법 |
|---|---|---|
| 프로덕션에서 ASan 사용 | 애플리케이션을 덜 안전하게 만들 수 있음 | 테스트에만 ASan 사용 |
| 메모리 제한을 비활성화하지 않음 | 퍼저가 20TB 가상 메모리로 인해 프로세스를 종료할 수 있음 | -rss_limit_mb=0 또는 -m none 설정 |
| 누수 보고서 무시 | 메모리 누수는 리소스 관리 문제를 나타냄 | 퍼징 캠페인 종료 시 누수 보고서 검토 |
도구별 가이드
libFuzzer
퍼저와 주소 샌나타이저를 모두 사용하여 컴파일:
clang++ -fsanitize=fuzzer,address -g harness.cc -o fuzz
무제한 RSS로 실행:
./fuzz -rss_limit_mb=0
통합 팁:
- 항상
-fsanitize=fuzzer와-fsanitize=address를 함께 사용하세요 - 크래시 보고서의 상세한 스택 추적을 위해
-g를 사용하세요 - 더 나은 크래시 처리를 위해
ASAN_OPTIONS=abort_on_error=1을 고려하세요
참고: libFuzzer: AddressSanitizer
AFL++
AFL_USE_ASAN 환경 변수 사용:
AFL_USE_ASAN=1 afl-clang-fast++ -g harness.cc -o fuzz
무제한 메모리로 실행:
afl-fuzz -m none -i input_dir -o output_dir ./fuzz
통합 팁:
AFL_USE_ASAN=1이 자동으로 적절한 컴파일 플래그를 추가합니다- AFL++의 메모리 제한을 비활성화하려면
-m none을 사용하세요 - 큰 커버리지 맵을 가진 프로그램의 경우
AFL_MAP_SIZE를 고려하세요
cargo-fuzz (Rust)
--sanitizer=address 플래그 사용:
cargo fuzz run fuzz_target --sanitizer=address
또는 fuzz/Cargo.toml에서 구성:
[profile.release]
opt-level = 3
debug = true
통합 팁:
- ASan은 안전하지 않은 Rust 코드 또는 FFI 경계를 퍼징하는 데 유용합니다
- 안전한 Rust 코드는 컴파일러가 이미 많은 오류를 방지하므로 큰 이점을 얻지 못할 수 있습니다
- 안전하지 않은 블록, 원시 포인터 및 C 라이브러리 바인딩에 집중하세요
참고: cargo-fuzz: AddressSanitizer
honggfuzz
ASan으로 컴파일하고 honggfuzz와 링크:
honggfuzz -i input_dir -o output_dir -- ./fuzz_target_asan
타겟 컴파일:
hfuzz-clang -fsanitize=address -g target.c -o fuzz_target_asan
통합 팁:
- honggfuzz는 ASan과 바로 잘 작동합니다
- 샌나타이저와 함께 더 나은 커버리지를 위해 피드백 기반 모드를 사용하세요
- ASan이 메모리 사용량을 증가시키므로 메모리 사용량을 모니터링하세요
문제 해결
| 문제 | 원인 | 해결책 |
|---|---|---|
| 퍼저가 즉시 프로세스 종료 | ASan의 20TB 가상 메모리보다 메모리 제한이 너무 낮음 | -rss_limit_mb=0 (libFuzzer) 또는 -m none (AFL++) 사용 |
| "ASan runtime not initialized" | 잘못된 링크 순서 또는 누락된 런타임 | 컴파일 및 링크 모두에서 -fsanitize=address가 사용되었는지 확인 |
| 누수 보고서로 출력 복잡 | LeakSanitizer가 기본적으로 활성화됨 | ASAN_OPTIONS=detect_leaks=0 설정 |
| 낮은 성능 (>4배 속도 저하) | 디버그 모드 또는 최적화되지 않은 빌드 | -fsanitize=address와 함께 -O2 또는 -O3로 컴파일 |
| ASan이 명백한 버그를 탐지하지 못함 | 바이너리가 계측되지 않음 | ASAN_OPTIONS=verbosity=1로 ASan이 시작 정보를 출력하는지 확인 |
| 오탐 | 인터셉터 충돌 | 특정 라이브러리와 관련된 알려진 문제는 ASan FAQ 확인 |
관련 기술
이 기술을 사용하는 도구
| 기술 | 적용 방법 |
|---|---|
| libfuzzer | 통합 퍼징 및 메모리 오류 탐지를 위해 -fsanitize=fuzzer,address로 컴파일 |
| aflpp | 컴파일 중 AFL_USE_ASAN=1 환경 변수 사용 |
| cargo-fuzz | Rust 퍼즈 타겟에 대해 ASan을 활성화하려면 --sanitizer=address 플래그 사용 |
| honggfuzz | ASan 계측 퍼징을 위해 타겟을 -fsanitize=address로 컴파일 |
관련 기술
| 기술 | 관계 |
|---|---|
| undefined-behavior-sanitizer | 포괄적인 버그 탐지(정의되지 않은 동작 + 메모리 오류)를 위해 ASan과 함께 자주 사용됨 |
| fuzz-harness-writing | 하네스는 ASan이 탐지한 크래시를 처리하고 오탐을 피하도록 설계되어야 함 |
| coverage-analysis | 커버리지 기반 퍼징은 ASan이 메모리 오류를 탐지할 수 있는 코드 경로를 트리거하는 데 도움 |
리소스
주요 외부 리소스
Google Sanitizers 위키의 AddressSanitizer
공식 ASan 문서는 다음을 다룹니다:
- 알고리즘 및 구현 세부 사항
- 탐지된 오류 유형의 전체 목록
- 성능 특성 및 오버헤드
- 플랫폼별 동작
- 알려진 제한 사항 및 비호환성
모든 샌나타이저에서 공유하는 일반 구성 플래그:
verbosity: 진단 출력 수준 제어log_path: 샌나타이저 출력을 파일로 리디렉션symbolize: 보고서에서 심볼 해석 활성화/비활성화external_symbolizer_path: 사용자 정의 심볼라이저 사용
ASan별 구성 옵션:
detect_leaks: 메모리 누수 탐지 제어abort_on_error: 오류 시abort()호출 vs_exit()호출detect_stack_use_after_return: 스택 use-after-return 버그 탐지check_initialization_order: 초기화 순서 버그 찾기
일반적인 함정과 해결책:
- 링크 순서 문제
- 다른 도구와의 충돌
- 플랫폼별 문제
- 성능 튜닝 팁
Clang별 가이드:
- 컴파일 플래그 및 옵션
- 다른 Clang 기능과의 상호 작용
- 지원되는 플랫폼 및 아키텍처
GCC별 ASan 문서:
- GCC별 플래그 및 동작
- Clang 구현과의 차이점
- GCC의 플랫폼 지원
AddressSanitizer: 고속 주소 위생 검사기 (USENIX 논문)
기술적 세부 사항이 포함된 원본 연구 논문:
- 섀도 메모리 알고리즘
- 가상 메모리 요구 사항(역사적으로 16TB, 현재 약 20TB)
- 성능 벤치마크
- 설계 결정 및 트레이드오프