Część CFI to mechanizm zabezpieczeń, który uniemożliwia wprowadzanie zmian w początkowym grafie przepływu sterowania w skompilowanym pliku binarnym, co znacznie utrudnia przeprowadzanie takich ataków.
W Androidzie 9 włączyliśmy implementację CFI w LLVM w większej liczbie komponentów, a także w rdzeniu. System CFI jest domyślnie włączony, ale musisz włączyć CFI jądra.
CFI LLVM wymaga kompilacji z optymalizacją w czasie łączenia (LTO). LTO zachowuje reprezentację kodu bitowego LLVM plików obiektów do czasu kompilacji, co pozwala kompilatorowi lepiej określić, jakie optymalizacje można wykonać. Włączenie LTO zmniejsza rozmiar końcowego pliku binarnego i poprawia wydajność, ale wydłuża czas kompilacji. Podczas testowania na Androidzie połączenie LTO i CFI spowodowało nieznaczne obciążenie rozmiarem kodu i wydajnością. W niektórych przypadkach obie te wartości uległy poprawie.
Więcej informacji technicznych na temat CFI oraz sposobu obsługi innych kontroli w przód znajdziesz w dokumentacji LLVM.
Implementacja
Poprawki kCFI są dostępne we wszystkich obsługiwanych wersjach jądra Androida. Opcja CONFIG_CFI_CLANG
włącza kCFI i jest domyślnie ustawiona w GKI.
Rozwiązywanie problemów
Po włączeniu usuń wszelkie błędy niezgodności typu, które mogą występować w przypadku ich sterowników. Pośrednie wywołanie funkcji za pomocą niezgodnego wskaźnika funkcji powoduje przerwanie CFI. Gdy wykryto błąd CFI, jądro wypisuje ostrzeżenie, które zawiera zarówno wywołaną funkcję, jak i wyświetlenie stosu, które doprowadziło do błędu. Aby to naprawić, sprawdź, czy wskaźniki funkcji mają zawsze ten sam typ co wywoływana funkcja.
Aby ułatwić debugowanie błędów CFI, włącz CONFIG_CFI_PERMISSIVE
,
który zamiast wywoływać panikę jądra wyświetla ostrzeżenie. Trybu zezwalającego nie można używać w środowisku produkcyjnym.
Weryfikacja
Obecnie nie ma testu CTS przeznaczonego specjalnie do CFI. Zamiast tego sprawdź, czy testy CTS są pozytywne z włączonym i wyłączonym CFI, aby upewnić się, że CFI nie wpływa na urządzenie.