Android는 OEM에서 자체 구현한 SELinux를 철저히 테스트할 것을 적극적으로 권장합니다. 제조업체가 SELinux를 구현하려면 먼저 테스트 기기 풀에 새 정책을 적용해야 합니다.
새 정책을 적용한 후에는 getenforce
명령어를 실행하여 SELinux가 기기에서 제대로 된 모드로 동작하는지 확인합니다.
그러면 전역 SELinux 모드가 시행 또는 허용으로 출력됩니다. 각 도메인의 SELinux 모드를 확인하려면 관련 파일을 검사하거나 /platform/system/sepolicy/tools/
에 위치한 최신 버전의 sepolicy-analyze
에 적절한 플래그(-p
)를 추가하여 실행합니다.
거부 로그 판독
오류를 확인하세요. 이 오류는 이벤트 로그로 dmesg
와 logcat
에 라우팅되고 기기에서 로컬로 조회할 수 있습니다. 제조업체는 공개 출시 전 허용 모드를 통해 기기에서 SELinux가 dmesg
에 출력한 내용을 검사하고 설정을 조정한 후, 시행 모드로 최종 전환합니다. SELinux 로그 메시지는 avc:
를 포함하므로 grep
을 이용해 쉽게 찾을 수 있습니다. cat /proc/kmsg
를 실행하여 진행 중인 거부 로그를 캡처하거나 cat /sys/fs/pstore/console-ramoops
를 실행하여 이전 부팅에서 남아 있는 거부 로그를 캡처하는 것이 가능합니다.
SELinux 오류 메시지에는 부팅이 완료된 후 로그를 지나치게 채우지 않도록 속도 제한이 적용됩니다. 관련 메시지를 모두 보려면 adb shell auditctl -r 0
를 실행하여 이 제한을 해제할 수 있습니다.
제조업체는 출력된 결과를 이용하여 시스템 사용자나 구성요소가 SELinux 정책을 위반했을 때 쉽게 식별할 수 있습니다. 그런 다음 소프트웨어와 SELinux 정책 중 하나 또는 둘 다를 변경하여 잘못된 동작을 바로잡을 수 있습니다.
특히 이러한 로그 메시지는 시행 모드에서 어떤 프로세스가 실패할지와 그 원인을 보여 줍니다. 예를 들면 다음과 같습니다.
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd" scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
다음과 같이 출력 내용을 해석합니다.
- 위
{ connectto }
는 실행 중인 작업을 나타냅니다. 문장 마지막의tclass
(unix_stream_socket
)와 함께 어떤 작업이 이루어졌는지 대략 알려 줍니다. 여기서는 무언가가 Unix 스트림 소켓에 연결하려고 했습니다. -
scontext (u:r:shell:s0)
는 어떤 컨텍스트가 작업을 시작했는지 알려 줍니다. 여기서는 셸로 실행된 무언가입니다. -
tcontext (u:r:netd:s0)
는 작업 대상의 컨텍스트를 알려 줍니다. 여기서는netd
가 소유한 unix_stream_socket입니다. - 윗부분의
comm="ping"
에서는 거부 로그가 생성되었을 때 실행 중이었던 작업에 관해 추가적으로 알아볼 수 있습니다. 여기서 이 정보는 매우 유용합니다.
다른 예시를 확인해 보겠습니다.
adb shell su root dmesg | grep 'avc: '
출력:
<5> type=1400 audit: avc: denied { read write } for pid=177 comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0 tcontext=u:object_r:kmem_device:s0 tclass=chr_file
이 거부 로그의 주요 요소는 다음과 같습니다.
- 작업 -
read write
또는setenforce
와 같이 시도한 작업이 대괄호로 강조표시되어 있습니다. - 행위자 -
scontext
(소스 컨텍스트) 항목은 행위자를 나타내며, 이 경우에는rmt_storage
데몬입니다. - 객체 -
tcontext
(대상 컨텍스트) 항목은 실행 중인 객체, 즉 여기에서는 kmem을 나타냅니다. - 결과 -
tclass
(대상 클래스) 항목은 실행 중인 객체의 유형을 나타내고 여기에서는chr_file
(문자 기기)입니다.
사용자 및 커널 스택 덤프
경우에 따라 이벤트 로그에 포함된 정보만으로는 거부 출처를 파악하기에 충분하지 않습니다. 커널 및 사용자 공간을 비롯한 호출 체인을 수집하면 거부가 발생한 원인을 이해하는 데 유용한 경우가 많습니다.
최근 커널은 avc:selinux_audited
라는 tracepoint를 정의합니다. Android simpleperf
를 사용하여 이 tracepoint를 사용 설정하고 호출 체인을 캡처합니다.
지원되는 구성
- Linux 커널 5.10 이상, 특히 Android 일반 커널 분기 mainline 및 android12-5.10이 지원됩니다.
android12-5.4 브랜치도 지원됩니다. 다음과 같이
simpleperf
를 사용하여 기기에 tracepoint가 정의되어 있는지 확인할 수 있습니다.adb root && adb shell simpleperf list | grep avc:selinux_audited
다른 커널 버전의 경우 커밋 dd81662 및 30969bc를 선택할 수도 있습니다. - 디버깅하는 이벤트를 재현할 수 있어야 합니다. 부팅 시간 이벤트는 simpleperf를 사용해 지원되지 않습니다. 하지만 서비스를 다시 시작하여 이벤트를 트리거할 수는 있습니다.
호출 체인 캡처
첫 번째 단계는 다음과 같이 simpleperf record
를 사용하여 이벤트를 기록하는 것입니다.
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
그러면 거부가 발생한 이벤트가 트리거됩니다. 그 후 기록을 중지해야 합니다. 이 예에서는 Ctrl-c
를 사용하여 샘플을 캡처했습니다.
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
마지막으로 simpleperf report
를 사용하여 캡처된 스택 트레이스를 검사할 수 있습니다.
예:
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph" [...] Children Self Command Pid Tid Shared Object Symbol 100.00% 0.00% dmesg 3318 3318 /apex/com.android.runtime/lib64/bionic/libc.so __libc_init | -- __libc_init | -- main toybox_main toy_exec_which dmesg_main klogctl entry_SYSCALL_64_after_hwframe do_syscall_64 __x64_sys_syslog do_syslog selinux_syslog slow_avc_audit common_lsm_audit avc_audit_post_callback avc_audit_post_callback
위의 호출 체인은 통합 커널 및 사용자 공간 호출 체인입니다. 이를 통해 사용자 공간에서 트레이스가 시작되어 거부가 발생하는 커널에 이르기까지 트레이스를 시작하여 코드 흐름을 더 잘 파악할 수 있습니다. simpleperf
에 관한 자세한 내용은 Simpleperf 실행 명령어 참조를 확인하세요.
허용 모드로 전환
SELinux 시행은 userdebug 또는 eng 빌드에서 ADB를 통해 사용 중지할 수 있습니다. 이렇게 하려면 먼저 adb root
를 실행하여 ADB를 루트로 전환합니다. 그런 다음 SELinux 시행을 사용 중지하려면 다음을 실행합니다.
adb shell setenforce 0
또는 초기에 기기를 불러오는 동안 커널 명령줄에서 다음을 실행합니다.
androidboot.selinux=permissive
androidboot.selinux=enforcing
또는 Android 12의 bootconfig를 통해 다음을 실행합니다.
androidboot.selinux=permissive
androidboot.selinux=enforcing
audit2allow 사용
audit2allow
도구는 dmesg
거부 로그를 이에 대응하는 SELinux 정책 구문으로 변환합니다. 따라서 SELinux 개발 속도를 크게 높일 수 있습니다.
사용하려면 다음을 실행하세요.
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
그래도 각각의 잠재적인 추가사항이 권한을 넘어설 수 있는지 조사해야 합니다. 예를 들어 앞에서 보았던 rmt_storage
거부 로그를 audit2allow
에 입력하면 다음과 같이 제안된 SELinux 정책 구문이 나옵니다.
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
이 정책은 rmt
가 커널 메모리에 쓸 수 있도록 허용합니다. 이는 명백한 보안 취약점입니다. audit2allow
구문은 시작점일 뿐일 때가 많습니다 이 구문을 사용한 후에 좋은 정책을 완성하려면 제대로 된 매크로를 통합하고 소스 도메인과 대상의 라벨을 변경해야 할 수도 있습니다. 때로는 거부 로그를 검토한 결과 정책이 아닌 문제의 애플리케이션을 수정해야 할 때도 있습니다.