커널 제어 흐름 무결성

제어 흐름 무결성(CFI)은 컴파일된 바이너리의 원래 제어 흐름 그래프에 관한 변경을 차단하는 보안 메커니즘으로, 이러한 공격을 실행하기 훨씬 어렵게 만듭니다.

Android 9에서는 CFI의 LLVM 구현을 더 많은 구성요소는 물론 커널에도 사용 설정했습니다. 시스템 CFI는 기본으로 사용되지만, 커널 CFI는 사용 설정해야 합니다.

LLVM의 CFI에는 링크 시점 최적화(LTO)를 통한 컴파일이 필요합니다. LTO는 링크 시점까지 객체 파일의 LLVM 비트코드 표현을 보존하여 컴파일러가 어떤 최적화를 실행할 수 있는지에 관해 더 나은 추론을 내릴 수 있게 해줍니다. LTO를 사용 설정하면 최종 바이너리의 크기가 축소되고 성능이 개선되지만 컴파일 시간은 증가합니다. Android에서 테스트할 때는 LTO 및 CFI 조합이 코드 크기 및 성능에 있어 미미한 수준의 오버헤드로 이어지며, 경우에 따라서는 둘 다 개선되기도 합니다.

CFI에 관한 기술적 세부정보, 그리고 정방향 제어 검사가 처리되는 방식은 LLVM 설계 문서를 참고하세요.

구현

kCFI 패치는 지원되는 모든 Android 커널 버전에 있습니다. CONFIG_CFI_CLANG 옵션은 kCFI를 사용 설정하며 GKI에 기본적으로 설정됩니다.

문제 해결

사용 설정 후에는 드라이버에 존재할 수 있는 유형 불일치 오류를 해결합니다. 호환되지 않는 함수 포인터를 통한 간접 함수 호출은 CFI를 트립합니다. CFI 장애가 감지되면 커널은 호출된 함수와 장애로 이어진 스택트레이스를 둘 다 포함하는 경고를 출력합니다. 함수 포인터가 항상 호출된 함수와 동일한 유형을 취하도록 하여 이를 수정하세요.

CFI 장애 디버그를 지원하려면 커널 패닉을 일으키는 대신 경고를 출력하는 CONFIG_CFI_PERMISSIVE를 사용 설정하세요. 프로덕션에는 허용 모드를 사용하면 안 됩니다.

유효성 검사

현재로서는 CFI 전용 CTS 테스트가 없습니다. 대신, CFI 사용 설정 여부와 상관없이 CTS 테스트가 통과되도록 하여 CFI가 기기에 영향을 미치지 않는지 확인하세요.