안드로이드 시스템 개발을 하다 보면 기능을 구현하는 것만큼이나 중요한 것이 바로 '보안 경계'를 세우는 일입니다. 특히 커스텀 빌드를 진행할 때 특정 프로세스에 권한을 주려다 빌드가 실패하며 neverallow violated라는 에러 메시지를 마주하곤 합니다. 이는 안드로이드가 시스템의 무결성을 지키기 위해 설정해둔 최후의 보루인 'neverallow' 정책 때문입니다.
본 포스팅에서는 SELinux 보안의 핵심인 neverallow 정책의 개념과 기본 문법, 그리고 이를 활용하여 시스템 바이너리와 앱의 접근 권한을 강력하게 제어하는 방법에 대해 상세히 다루어 보겠습니다.

📌 핵심 요약 3줄
- 절대적 금지: neverallow는 상위 정책에서 allow 규칙이 추가되더라도 이를 무효화하고 빌드 시점에 차단하는 강력한 보안 강제 규칙입니다.
- 빌드 타임 검증: 정책 위반 시 런타임이 아닌 빌드 과정에서 즉시 에러를 발생시켜, 보안 취약점이 포함된 이미지가 생성되는 것을 사전에 방지합니다.
- 보안 아키텍처 완성: 시스템, 벤더, 앱 간의 권한 분리를 명확히 하여 권한 상승 공격이나 악성 코드의 시스템 침투를 원천 차단합니다.
1. neverallow 정책의 정의와 필요성
SELinux에서 allow가 "무엇을 할 수 있는가"를 정의한다면, neverallow는 "절대로 해서는 안 되는 것"을 선언합니다.
[allow와 neverallow의 핵심 차이점]
| 구분 | allow (허용 규칙) | neverallow (절대 금지 규칙) |
| 주요 목적 | 프로세스 실행에 필요한 권한 부여 | 보안 취약점 예방 및 권한 남용 방지 |
| 적용 시점 | 런타임(접근 제어 수행) | 빌드 타임(정책 정적 분석 시 검사) |
| 강제성 | 정책 파일에 정의된 범위 내 허용 | 어떤 allow 규칙도 이 규칙을 이길 수 없음 |
| 위반 결과 | 권한 부족으로 인한 기능 동작 실패 | neverallow violated 에러로 빌드 실패 |
2. neverallow 기본 문법 및 구성
정책 파일(.te)에서 사용되는 문법은 일반적인 allow 규칙과 유사하지만, 그 영향력은 훨씬 강력합니다.
기본 문법:
neverallow [Source_Type] [Target_Type]:[Class] { [Permissions] };
[neverallow 문법 구성 요소 해설]
| 요소 | 설명 | 예시 |
| Source Type | 접근을 시도하는 주체(도메인/속성) | untrusted_app, system_server |
| Target Type | 접근 대상이 되는 리소스 타입 | data_file_type, sysfs |
| Class | 객체의 종류 | file, dir, unix_stream_socket |
| Permissions | 금지할 구체적인 행위 | read, write, execute, ioctl |
3. 보안 강화를 위한 활용 사례
시스템의 주요 파티션과 자원을 보호하기 위해 실제로 적용되는 예시들입니다.
3.1. 벤더 바이너리의 시스템 영역 접근 제한
벤더 파티션의 바이너리가 시스템 영역의 실행 파일을 수정하거나 실행하는 것을 막아 'Treble' 구조의 독립성을 유지합니다.
neverallow vendor_exec system_file_type:file { write execute_no_trans };
3.2. 일반 앱의 민감 자원 접근 차단
서드파티 앱이 커널 파라미터(sysfs)를 직접 수정하여 기기 설정을 임의로 변경하는 것을 방지합니다.
neverallow untrusted_app sysfs:file { write append };
💡 개발을 위한 팁
- 에러 로그 역추적: 빌드 중 neverallow violated가 발생하면, 에러 메시지에 명시된 allow 규칙이 어떤 .te 파일의 몇 번째 줄에서 호출되었는지 확인하세요.
- Attribute 활용: 개별 type에 대해 규칙을 세우기보다 domain, data_file_type 같은 속성(Attribute)을 활용하면 한 번의 선언으로 시스템 전체의 보안 일관성을 유지할 수 있습니다.
- 분리된 정책(Sepolicy) 관리: 안드로이드 8.0 이상에서는 시스템 정책과 벤더 정책이 분리되어 있습니다. neverallow 규칙을 세울 때 해당 도메인이 어느 파티션에 속하는지 명확히 구분해야 합니다.
⚠️ 흔히 하는 실수
[neverallow 정책 적용 시 주의사항]
| 실수 유형 | 상세 내용 | 해결 방안 |
| 무분별한 와일드카드(*) 사용 | 모든 권한(*)을 금지하여 시스템 동작에 필수적인 권한까지 막아버림 | 반드시 차단이 필요한 핵심 권한만 구체적으로 명시 |
| 빌드 에러 무시 시도 | neverallow를 삭제하거나 우회하여 기능을 강제로 구현하려 함 | 보안 가이드라인 위반임. 도메인 전이(Transition)나 HAL을 통한 우회 검토 |
| 정책 위치 오류 | 시스템 정책 디렉터리에 벤더 전용 neverallow를 추가함 | 파티션별 소유권에 맞는 sepolicy 경로에 작성 |
4. 결론
neverallow 정책은 단순히 개발자를 괴롭히는 빌드 에러가 아니라, 안드로이드라는 거대한 OS가 수많은 위협으로부터 스스로를 보호하기 위해 선언한 '보안의 선'입니다. 시스템 서버, 벤더 바이너리, 그리고 일반 앱 간의 경계를 명확히 설정하는 것은 악성 코드나 권한 상승 공격을 예방하는 가장 효과적인 방법입니다.
안전한 안드로이드 시스템 개발을 위해 주기적으로 기존 정책의 neverallow 위반 여부를 점검하고, 새로운 기능을 추가할 때 보안 설계 단계부터 이 규칙을 적극적으로 활용해 보시기 바랍니다. 개발 중 풀리지 않는 SELinux 정책 갈등이 있다면 댓글로 남겨주세요! 함께 고민해 보겠습니다.
'Android System & AOSP Engineering > Android Security & SELinux' 카테고리의 다른 글
| AOSP 보안 가이드라인을 준수하는 SELinux 정책 검토 및 분석 방법 (0) | 2025.05.15 |
|---|---|
| SELinux 정책 최적화 가이드: 성능과 보안을 모두 잡는 5가지 기법 (0) | 2025.05.14 |
| 안드로이드 SELinux 디버깅 완벽 가이드: dmesg와 logcat 활용법 (0) | 2025.05.12 |
| 안드로이드 SELinux 정책 생성 가이드: audit2allow 활용법 및 검증 정리 (0) | 2025.05.11 |
| 안드로이드 SELinux avc: denied 로그 분석 및 해결 완벽 가이드 (0) | 2025.05.10 |