안드로이드 시스템을 개발하면서 새로운 하드웨어 추상화 계층(HAL)이나 백그라운드 서비스, 혹은 특정 기능을 수행하는 바이너리를 추가할 때 가장 먼저 마주하는 난관은 역시 SELinux(Security-Enhanced Linux)입니다.
단순히 소스코드를 빌드하고 실행 파일(Binary)을 배치하는 것만으로는 부족합니다. 안드로이드의 강제 접근 제어(MAC) 체계 안에서 해당 서비스가 어떤 이름표(Label)를 달고, 어떤 권한으로 동작할지 명확히 정의해주어야 합니다. 오늘은 실무에서 가장 빈번하게 사용되는 서비스, 바이너리, 그리고 파일 시스템에 대한 SELinux 정책 정의 방법을 상세히 살펴보겠습니다.

📌 핵심 요약 3줄
- 서비스/바이너리 격리: 각 실행 파일은 전용 도메인(domain)과 실행 타입(exec_type)을 할당받아 시스템의 다른 영역과 격리되어야 합니다.
- 권한의 명시: allow 규칙을 통해 프로세스가 자기 자신이나 파일 시스템, 타 도메인과 상호작용할 수 있는 최소한의 권한을 부여합니다.
- 컨텍스트 매핑: file_contexts를 통해 물리적 경로에 저장된 파일이 설계한 SELinux 라벨을 입도록 매핑하는 과정이 필수입니다.
1. SELinux 정책 구성 요소 비교
정의하려는 대상에 따라 필요한 정책 파일과 주요 설정 항목이 달라집니다.
| 대상 구분 | 주요 설정 파일 | 핵심 매크로/규칙 | 주요 목적 |
| 서비스 (Service) | *.te, file_contexts | init_daemon_domain() | 시스템 서비스의 상시 가동 및 도메인 전환 |
| 바이너리 (Binary) | *.te, file_contexts | domain_auto_trans() | 특정 시점에 실행되는 도구의 권한 제어 |
| 파일 시스템 (File) | file.te, file_contexts | type ..., file_type; | 특정 경로 및 파일에 대한 접근 라벨링 |
2. 서비스 및 바이너리 정책 정의법
2.1 서비스(Service) 도메인 생성
백그라운드에서 상시 실행되는 서비스나 HAL을 위한 정책입니다.
# my_service.te
# 1. 도메인 및 실행 파일 타입 정의
type my_service, domain;
type my_service_exec, exec_type, vendor_file_type, file_type;
# 2. init이 실행할 때 도메인 전환 허용
init_daemon_domain(my_service)
# 3. 타 서비스(예: system_server)와의 통신 허용
allow system_server my_service:process { signal };
2.2 바이너리(Binary) 실행 권한 정의
특정 작업을 수행하고 종료되는 바이너리에 대한 제어입니다.
# my_binary.te
type my_binary, domain;
type my_binary_exec, exec_type, file_type;
# 3. 실행 시 프로세스 권한 부여
allow my_binary self:process { fork execmem };
allow my_binary self:capability { net_admin };
2.3 물리적 경로 매핑 (file_contexts)
정의한 도메인이 실제 파일과 연결되도록 매핑합니다.
# file_contexts
/vendor/bin/my_service u:object_r:my_service_exec:s0
/system/bin/my_binary u:object_r:my_binary_exec:s0
3. 파일 시스템(File System) 정책 정의법
특정 디렉터리나 설정 파일에 대한 접근 권한을 관리합니다.
3.1 파일 타입 선언 및 권한 부여
# my_data.te
# 파일 타입 정의 (data_file_type 속성 추가)
type my_data_file, file_type, data_file_type;
# 서비스가 해당 파일을 읽고 쓸 수 있도록 허용
allow my_service my_data_file:dir { rw_dir_perms };
allow my_service my_data_file:file { rw_file_perms };
3.2 파일 경로 지정
# file_contexts
/data/vendor/my_app(/.*)? u:object_r:my_data_file:s0
4. SELinux 정책 빌드 및 검증
설정을 마친 후에는 아래의 절차를 통해 시스템에 반영합니다.
- 정책 빌드: AOSP 환경에서 mm 혹은 m sepolicy를 통해 정책을 컴파일합니다.
- 로그 확인: adb shell "dmesg | grep avc" 명령어로 권한 거부 발생 여부를 실시간 모니터링합니다.
- 라벨 확인: ls -Z 명령어를 통해 파일에 의도한 라벨(u:object_r:my_data_file:s0)이 제대로 붙었는지 확인합니다.
🛠️ 개발자를 위한 팁 & 흔히 하는 실수
✅ 개발 팁 (Best Practices)
- 매크로 활용: read, write, open을 일일이 쓰는 대신 rw_file_perms와 같은 표준 매크로를 사용하면 오타를 줄이고 가독성을 높일 수 있습니다.
- 최소 권한의 원칙: self:capability { dac_override }와 같은 강력한 권한은 가급적 피하고, 파일의 소유권이나 그룹을 먼저 조정하는 것이 보안상 유리합니다.
❌ 흔히 하는 실수 (Common Mistakes)
- Vendor/System 구분 오류: Android 8.0 이상(Project Treble)에서는 vendor와 system 정책이 분리되어 있습니다. Vendor 서비스라면 반드시 vendor_file_type 속성을 실행 파일 타입에 추가해야 빌드 에러가 발생하지 않습니다.
- Context 매핑 정규식: file_contexts에서 /data/my_dir/로 정의하면 해당 디렉터리 자체에만 라벨이 붙습니다. 하위 파일까지 적용하려면 반드시 (/.*)? 정규식을 뒤에 붙여주어야 합니다.
- Neverallow 위반: 구글이 정의한 보안 규칙(neverallow)을 위반하는 정책을 추가하면 빌드 타임에 에러가 발생합니다. 이때는 정책을 억지로 뚫기보다 설계가 보안 가이드를 준수하는지 먼저 검토해야 합니다.
5. 결론
Android SELinux 정책은 서비스와 바이너리, 그리고 파일 시스템이라는 세 축이 유기적으로 맞물려 돌아가야 합니다. 오늘 살펴본 도메인 정의와 컨텍스트 매핑 방법을 정확히 숙지한다면, "Permission Denied"의 늪에서 벗어나 보다 안전하고 완성도 높은 안드로이드 시스템을 개발하실 수 있을 것입니다.
오늘 포스팅이 도움 되셨길 바라며, 추가로 궁금한 점은 댓글로 남겨주세요!
'Android System & AOSP Engineering > Android Security & SELinux' 카테고리의 다른 글
| AOSP SELinux 정책 설정: BOARD_SEPOLICY_DIRS vs PRODUCT_PRIVATE_SEPOLICY_DIRS 차이점 완벽 정리 (0) | 2025.05.05 |
|---|---|
| AOSP SELinux 정책(sepolicy) 빌드 및 적용 가이드: 기초부터 트러블슈팅까지 (0) | 2025.05.04 |
| Android SELinux 설정 가이드: domain 정의부터 file_contexts 적용까지 (0) | 2025.05.01 |
| Android SELinux 정책 문법 완벽 정리: type, allow, neverallow 예제 가이드 (0) | 2025.04.30 |
| Android SELinux avc: denied 로그 분석 및 해결 완벽 가이드 (0) | 2025.04.29 |