SELinux 유효성 검사

Android는 OEM에서 자체 구현한 SELinux를 철저히 테스트할 것을 적극적으로 권장합니다. 제조업체가 SELinux를 구현하려면 먼저 테스트 기기 풀에 새 정책을 적용해야 합니다.

새 정책을 적용한 후에는 getenforce 명령어를 실행하여 SELinux가 기기에서 제대로 된 모드로 동작하는지 확인합니다.

그러면 전역 SELinux 모드가 시행 또는 허용인지 출력합니다. 각 도메인의 SELinux 모드를 확인하려면 관련 파일을 검사합니다. 또는 /platform/system/sepolicy/tools/에 위치한 최신 버전의 sepolicy-analyze에 적절한 플래그(-p)를 추가하여 실행합니다.

거부 로그 판독

오류를 확인하세요. 이 오류는 이벤트 로그로 dmesglogcat에 라우팅되고 기기에서 로컬로 조회할 수 있습니다. 제조업체는 공개 출시 전 허용 모드를 통해 기기에서 SELinux가 dmesg에 출력한 내용을 검사하고 설정을 조정한 후, 시행 모드로 최종 전환합니다. SELinux 로그 메시지는 avc:를 포함하므로 grep을 이용해 쉽게 찾을 수 있습니다. cat /proc/kmsg를 실행하여 진행 중인 거부 로그를 캡처하거나 cat /sys/fs/pstore/console-ramoops를 실행하여 이전 부팅에서 남아 있는 거부 로그를 캡처하는 것이 가능합니다.

제조업체는 출력된 결과를 이용하여 시스템 사용자나 구성요소가 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(문자 기기)입니다.

허용 모드로 전환

SELinux 시행은 userdebug 또는 eng 빌드에서 ADB를 통해 사용 중지할 수 있습니다. 이렇게 하려면 먼저 adb root를 실행하여 ADB를 루트로 전환합니다. 그런 다음 SELinux 시행을 사용 중지하려면 다음을 실행합니다.

    adb shell setenforce 0
    

또는 초기에 기기를 불러오는 동안 커널 명령줄에서 다음을 실행합니다.

    androidboot.selinux=permissive
    androidboot.selinux=enforcing
    

audit2allow 사용

selinux/policycoreutils/audit2allow 도구는 dmesg 거부를 이에 대응하는 SELinux 정책 구문으로 변환합니다. 따라서 SELinux 개발 속도를 크게 높일 수 있습니다. audit2allow는 Android 소스 경로의 일부로 제공되며 소스로부터 Android를 빌드할 때 자동으로 컴파일됩니다.

사용하려면 다음을 실행하세요.

    adb pull /sys/fs/selinux/policy
    adb logcat -b all -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 구문은 시작점일 뿐일 때가 많습니다 이 구문을 사용한 후에 좋은 정책을 완성하려면 제대로 된 매크로를 통합하고 소스 도메인과 대상의 라벨을 변경해야 할 수도 있습니다. 때로는 거부를 검토한 결과 정책이 아닌 문제의 애플리케이션을 수정해야 할 때도 있습니다.