Android System & AOSP Engineering/Android Security & SELinux

안드로이드 SELinux 보안의 핵심: neverallow 정책 개념 및 활용 가이드

임베디드 친구 2025. 5. 13. 17:36
반응형

안드로이드 시스템 개발을 하다 보면 기능을 구현하는 것만큼이나 중요한 것이 바로 '보안 경계'를 세우는 일입니다. 특히 커스텀 빌드를 진행할 때 특정 프로세스에 권한을 주려다 빌드가 실패하며 neverallow violated라는 에러 메시지를 마주하곤 합니다. 이는 안드로이드가 시스템의 무결성을 지키기 위해 설정해둔 최후의 보루인 'neverallow' 정책 때문입니다.

본 포스팅에서는 SELinux 보안의 핵심인 neverallow 정책의 개념과 기본 문법, 그리고 이를 활용하여 시스템 바이너리와 앱의 접근 권한을 강력하게 제어하는 방법에 대해 상세히 다루어 보겠습니다.

Generated by Gemini AI.

📌 핵심 요약 3줄

  1. 절대적 금지: neverallow는 상위 정책에서 allow 규칙이 추가되더라도 이를 무효화하고 빌드 시점에 차단하는 강력한 보안 강제 규칙입니다.
  2. 빌드 타임 검증: 정책 위반 시 런타임이 아닌 빌드 과정에서 즉시 에러를 발생시켜, 보안 취약점이 포함된 이미지가 생성되는 것을 사전에 방지합니다.
  3. 보안 아키텍처 완성: 시스템, 벤더, 앱 간의 권한 분리를 명확히 하여 권한 상승 공격이나 악성 코드의 시스템 침투를 원천 차단합니다.

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 };


💡 개발을 위한 팁

  1. 에러 로그 역추적: 빌드 중 neverallow violated가 발생하면, 에러 메시지에 명시된 allow 규칙이 어떤 .te 파일의 몇 번째 줄에서 호출되었는지 확인하세요.
  2. Attribute 활용: 개별 type에 대해 규칙을 세우기보다 domain, data_file_type 같은 속성(Attribute)을 활용하면 한 번의 선언으로 시스템 전체의 보안 일관성을 유지할 수 있습니다.
  3. 분리된 정책(Sepolicy) 관리: 안드로이드 8.0 이상에서는 시스템 정책과 벤더 정책이 분리되어 있습니다. neverallow 규칙을 세울 때 해당 도메인이 어느 파티션에 속하는지 명확히 구분해야 합니다.

⚠️ 흔히 하는 실수

[neverallow 정책 적용 시 주의사항]

실수 유형 상세 내용 해결 방안
무분별한 와일드카드(*) 사용 모든 권한(*)을 금지하여 시스템 동작에 필수적인 권한까지 막아버림 반드시 차단이 필요한 핵심 권한만 구체적으로 명시
빌드 에러 무시 시도 neverallow를 삭제하거나 우회하여 기능을 강제로 구현하려 함 보안 가이드라인 위반임. 도메인 전이(Transition)나 HAL을 통한 우회 검토
정책 위치 오류 시스템 정책 디렉터리에 벤더 전용 neverallow를 추가함 파티션별 소유권에 맞는 sepolicy 경로에 작성

4. 결론

neverallow 정책은 단순히 개발자를 괴롭히는 빌드 에러가 아니라, 안드로이드라는 거대한 OS가 수많은 위협으로부터 스스로를 보호하기 위해 선언한 '보안의 선'입니다. 시스템 서버, 벤더 바이너리, 그리고 일반 앱 간의 경계를 명확히 설정하는 것은 악성 코드나 권한 상승 공격을 예방하는 가장 효과적인 방법입니다.

안전한 안드로이드 시스템 개발을 위해 주기적으로 기존 정책의 neverallow 위반 여부를 점검하고, 새로운 기능을 추가할 때 보안 설계 단계부터 이 규칙을 적극적으로 활용해 보시기 바랍니다. 개발 중 풀리지 않는 SELinux 정책 갈등이 있다면 댓글로 남겨주세요! 함께 고민해 보겠습니다.

반응형