Android System & AOSP Engineering/Native Layer & Daemons

Android 시스템 개발: SELinux 정책 설정과 Android 10+ 보안 규격을 고려한 네이티브 데몬 등록 가이드

임베디드 친구 2025. 6. 23. 22:26
반응형

안녕하세요! 그동안 NDK 코드를 짜고 로컬 소켓을 열어 자바와 통신하는 미들웨어 기술을 다뤘다면, 오늘은 이를 상용 단말기나 디바이스에 완벽하게 빌드해 넣기 위한 가장 높은 장벽이자 최종 관문인 안드로이드 보안 프레임워크(SELinux & Android 10+ 시스템 정책)를 다뤄보고자 합니다.

기껏 완벽하게 기동하는 C/C++ 데몬 바이너리를 만들어 /system/bin에 밀어 넣고 init.rc에 서비스를 등록했는데, 정작 디바이스를 켜보니 로그캣에 Permission Denied만 가득 찍히며 데몬이 먹통이 되는 현상을 겪어보셨을 겁니다. 안드로이드는 리눅스 커널 위에 SELinux(강제 접근 제어)라는 아주 촘촘한 그물망을 씌워두었고, 버전이 올라갈 때마다 샌드박스 정책을 흉악할 정도로 강화하고 있기 때문인데요. 커널의 감시를 통과해 우리 데몬에게 합법적인 날개를 달아주는 sepolicy 가이드라인을 지금 바로 시작합니다!

Generated by Gemini AI.


📌 핵심 요약 3줄

  • init.rc 인프라 바인딩: /system/bin 등에 상주할 바이너리를 선언하고 고유 보안 라벨인 seclabel 컨텍스트를 설계하여 시스템 서비스로 등록합니다.
  • SELinux 도메인 아키텍처: 데몬 전용 .te(Type Enforcement) 파일과 file_contexts 맵을 설계하여 커널 자원 및 타겟 디렉터리에 대한 접근 허용(allow) 규칙을 정의합니다.
  • 모던 안드로이드 보안 대응: Scoped Storage, execmem 규격 억제에 대응하기 위한 -fPIC 독립 컴파일 기법 및 seccomp 시스템 콜 필터 구조를 파악합니다.

1. SELinux 아키텍처 및 Android 보안 메커니즘의 이해

리눅스의 전통적인 권한 관리가 "이 파일은 루트(Root) 계정 꺼니까 다 할 수 있어" 방식(DAC)이었다면, 안드로이드의 SELinux는 "루트 권한을 가진 프로세스라도 허용된 도메인 정책 규칙에 기재되어 있지 않으면 시스템 버퍼 접근조차 차단한다"는 강제 접근 제어(MAC) 방식을 고수합니다.

📊 SELinux 핵심 컨텍스트 4요소 레이아웃표

보안 컨텍스트 구성 요소 형식 표기 예시 시스템 아키텍처 관점에서의 핵심 의미
User (사용자) u 안드로이드 SELinux 시스템 환경에서는 단일 사용자 시스템으로 취급되므로 대개 u 고정값 사용
Role (역할) r / object_r 프로세스 주체일 때는 r(Role), 파일이나 소켓 등 객체 리소스일 때는 object_r 분기 지정
Type (타입/도메인) mydaemon / mydaemon_exec SELinux의 핵심. 프로세스가 속한 도메인 보안 영역과 리소스의 라벨 유형을 매핑하여 접근 제어의 기준점 구축
Sensitivity (보안 수준) s0 멀티 레벨 보안(MLS) 등급을 나타내며, 안드로이드 프레임워크 생태계에서는 기본 카테고리인 s0로 수렴됨

2. 시스템 서비스 등록을 위한 init.rc 셋업 가이드

안드로이드가 부팅될 때 커널 직속으로 네이티브 데몬을 상주 프로세스로 가동하기 위해서는 빌드 아키텍처 내 init.rc 스크립트에 정밀 선언을 기재해야 합니다.

코드 스니펫
 
# 서비스명과 구동할 바이너리의 시스템 물리 절대 경로 지정
service mydaemon /system/bin/mydaemon
    class main
    user system
    group system net_raw
    
    # [주의] 초안의 oneshot을 제거하여 프로세스가 죽더라도 init이 상시 모니터링하여 재가동하도록 설계
    # 이 서비스가 실행될 때 적용받을 전용 SELinux 도메인 컨텍스트 주입
    seclabel u:r:mydaemon:s0

3. SELinux .te 정책 스크립트 및 라벨링 매핑 구현

이제 시스템 가상 커널에 "우리 데몬은 위험한 녀석이 아니니 이 자원들은 만질 수 있게 허용해줘"라고 정책 파일(sepolicy)을 설계해 봅시다.

3.1 파일 컨텍스트 매핑 파일 설계 (file_contexts)

특정 디렉터리에 위치한 물리 바이너리 파일에 SELinux 실행 파일 전용 라벨을 강제 컴파일 매핑하는 선언입니다.

Plaintext
 
/system/bin/mydaemon      u:object_r:mydaemon_exec:s0

3.2 타입 인포스먼트 스크립트 코딩 (mydaemon.te)

프로세스 도메인과 실행 파일 도메인을 생성하고 상호 권한을 바인딩하는 핵심 정책 매크로 뼈대입니다.

코드 스니펫
 
# 1. 도메인 및 실행 파일 속성 구조 선언
type mydaemon, domain;
type mydaemon_exec, exec_type, file_type, system_file_type;

# 2. 매크로 함수를 통해 init 프로세스가 mydaemon_exec을 실행할 때 mydaemon 도메인으로 자동 전환되도록 브릿징
init_daemon_domain(mydaemon)

# 3. 비즈니스 가동에 필수적인 허용(allow) 규칙 구체화
# 데몬 스스로 네트워크 소켓 바인딩 및 시스템 시간 수정을 가능하게 선언
allow mydaemon self:capability { net_bind_service sys_time };

# 시스템 데이터 디렉터리 내의 폴더를 스캔하고 읽고 쓸 수 있는 권한 승인
allow mydaemon system_data_file:dir { search read write };
allow mydaemon system_data_file:file { create_file_perms };

4. Android 10 이상(API 29+) 보안 레벨 강화에 따른 대응 전략

모던 안드로이드 시스템 엔지니어링 환경에서는 구글의 샌드박스 정책 격리가 극대화되었습니다. 따라서 예전 레거시 단말기 개발 방식으로 데몬을 배치하면 빌드 도중 수많은 컴파일 오류를 뿜어냅니다.

📊 Android 10+ 주요 네이티브 보안 제약 조건 대응표

보안 강화 핵심 항목 플랫폼 정책 변화 내용 및 제약 개발 단계에서의 기술적 우회 및 올바른 대응책
(1) Scoped Storage 및 파일 시스템 격리 일반 앱의 데이터 루트인 /data 디렉터리에 대한 무차별적 Native 탐색이 완전히 차단됨 시스템 공유 보관소가 필요하다면 데몬 레이어에 MANAGE_EXTERNAL_STORAGE 권한의 컨텍스트 권한을 부여하거나 전용 앱 샌드박스 경로 패스로 통신 세션을 한정해야 함
(2) Untrusted App 도메인 전면 봉쇄 구글 플레이에 올라오는 일반 서드파티 앱 권한 그룹(untrusted_app)이 시스템 내부 파일(system_file) 영역에 쓰기 연산을 시도하는 행위를 neverallow 규칙으로 차단 일반 앱 화면에서 네이티브 데몬의 결과물 파일을 직접 수정하게 설계하면 안 되며, 전술했던 로컬 소켓(Local Socket) IPC 파이프라인을 통해서만 데이터를 가공 전달받게 아키텍처를 전면 수정해야 함
(3) W^X (Write XOR Execute) 규칙 엄격화 메모리 변조 해킹을 막기 위해 실행 권한이 있는 메모리 영역에 쓰기를 하거나(execmem), 실행 권한이 있는 스택을 가동하는 행위(execstack)를 차단 네이티브 바이너리 빌드 파이프라인(Android.bp 또는 CMake) 설정 시 위치 독립 실행 파일 컴파일러 옵션인 -fPIC 및 -pie 플래그를 필수로 바인딩하여 빌드해야 함
(4) seccomp 커널 필터 범위 확장 데몬이 커널을 향해 날리는 시스템 콜(Syscall) 중 취약점이 발생할 수 있는 특정 하위 시스템 콜 리스트를 원천 필터링 시스템 콜 오작동으로 인한 Crash 유발 시, AOSP 빌드 소스 내 services/seccomp 리스트에 데몬 전용 시스템 콜 허용 화이트리스트 스텁을 병합해 주어야 함

🛠️ 시스템 개발을 위한 꿀팁 (Tips)

  1. audit2allow 도구를 보물처럼 활용하세요: SELinux 정책을 맨땅에서 한 땀 한 땀 짜는 건 불가능에 가깝습니다. 먼저 단말기의 SELinux 모드를 임시 허용 모드(setenforce 0)로 돌려놓고 데몬을 구동하면, 시스템 로그캣에 "원래라면 차단했을 권한 에러 트래이스"가 avc: denied 문자열로 가득 찍힙니다. 이 로그 텍스트를 고스란히 긁어서 툴 체인의 audit2allow -i 로그파일.txt 명령어로 분석하면 우리 데몬에 딱 맞는 .te 소스코드가 자동으로 추출됩니다!
  2. neverallow 빌드 크래시 우회 규칙: AOSP 전체 소스코드 빌드 시 내가 작성한 allow 규칙이 안드로이드 순정 보안 소스에 정의된 neverallow (절대 허용 금지) 매크로와 정면 충돌하면 빌드가 아예 중단됩니다. 이럴 때는 순정 도메인을 직접 건드리기보다 내 데몬 전용 속성 속성(Attribute)을 커스텀하게 스펙인하여 별도의 독립 공유 도메인으로 격리 파싱하는 것이 정석입니다.
  3. oneshot 옵션의 올바른 선택: 디바이스 부팅 시 단 한 번 실행되고 소멸하는 초기화 스크립트 바이너리라면 oneshot이 맞지만, 백그라운드에서 상시 루프를 돌며 자바 앱과 소켓으로 상호작용해야 하는 상주형 사용자 정의 데몬에는 oneshot 플래그를 지워주어야 예기치 못한 메모리 쇼크로 데몬이 뻗었을 때 시스템 시스템(init)이 오토 리스타트를 보장해 줍니다.

⚠️ 흔히 하는 실수 (Common Mistakes)

  1. 상용 릴리즈 빌드에서 setenforce 0 방치: 개발 단계에서 SELinux 정책 짜기가 까다롭다고 해서 단말기 부팅 스크립트에 setenforce 0 (Permissive 모드)를 상시 적용해 둔 상태로 양산 릴리즈를 치면, 구글 인증(CTS) 통과가 불가능해질 뿐만 아니라 루트 권한 상승 해킹 공격에 단말기 전체 시스템 권한이 통째로 털리는 초대형 보안 사고가 터집니다. 운영 단계에선 무조건 Enforcing 상태에서 정책이 다 도는지 검증하세요.
  2. 바이너리 배치 시 system_file_type 속성 누락: Android 10 이상의 진영에서는 /system/bin에 복사되는 파일 라벨 선언문에 system_file_type 속성이 명시되어 있지 않으면, 부팅 타임에 init 프로세스가 아예 해당 경로의 파일 스트림 자체를 읽지 못하고 바이패스해 버리는 먹통 버그가 발생합니다.
  3. -fPIC 플래그 누락으로 인한 런타임 링크 에러: 구형 NDK Makefile을 그대로 복사해 와서 컴파일을 돌리다 보면 동적 메모리 위치 재배치 공유 플래그인 위치 독립 코드 컴파일 옵션이 누락되기 쉽습니다. 이 경우 런타임 가상머신 엔진 레이어에서 dlopen() failed: text relocations are not allowed 예외를 뿜으며 라이브러리 링크가 강제 파훼되니 반드시 최신 빌드 스크립트 규격을 준수하세요.

5. 결론

이번 포스팅에서는 안드로이드 로우레벨 시스템 미들웨어 개발의 파이널 게이트인 SELinux 권한 체계 아키텍처와 init.rc 연동 인프라, 그리고 Android 10 버전 이후부터 촘촘해진 통합 샌드박스 보안 규격의 대응 핵심 기술을 총망라해 다루어 보았습니다.

아무리 기가 막히게 작성된 C/C++ 통신 알고리즘을 확보했더라도 안드로이드 운영체제가 규정해 둔 고유의 보안 컨텍스트 도메인 시스템 패러다임을 이해하지 못하면 단말기 시스템 내부에서 단 1바이트의 데이터도 움직일 수 없습니다. 반대로 이 sepolicy 설계 메커니즘을 자유자재로 다룰 수만 있다면 하드웨어 제어권을 100% 통제하는 완벽한 인프라 디바이스 솔루션을 구현해 낼 수 있게 됩니다.

오늘 전해드린 안전한 보안 라벨링 가이드를 토대로 여러분의 커스텀 펌웨어 및 솔루션 컴포넌트를 무결하게 안착시켜 보시길 바라며, sepolicy 빌드 도중 매서운 neverallow 위반 크래시나 로그캣의 정체불명의 avc: denied 원인 분석으로 트래블슈팅에 어려움을 겪고 계신다면 망설임 없이 아래 댓글 창에 에러 로그를 남겨주세요. 꼼꼼하게 도메인 라벨을 진단해 드리겠습니다. 보안까지 완벽한 하이엔드 시스템 코딩 하세요!

반응형