Integralność przepływu sterowania (CFI) to mechanizm zabezpieczeń, który uniemożliwia wprowadzanie zmian w oryginalnym grafie przepływu sterowania skompilowanego pliku binarnego, co znacznie utrudnia przeprowadzanie takich ataków.
Od Androida 9 możesz włączyć CFI w jądrze.
Jądro systemu Linux ma 2 różne implementacje CFI:
- w przypadku Linuksa 6.0 i starszych wersji – Clang CFI, która opiera się na Clang LTO,
- w przypadku Linuksa 6.1 i nowszych wersji – Clang KCFI.
Clang CFI wymaga kompilacji z optymalizacją czasu łączenia (LTO). LTO zachowuje reprezentację kodu bitowego LLVM plików obiektowych do czasu łączenia, co pozwala kompilatorowi lepiej określić, jakie optymalizacje można zastosować. Podczas testów w Androidzie połączenie LTO i CFI spowodowało znikome obciążenie rozmiaru kodu i wydajności. Włączenie LTO znacznie wydłuża jednak czas kompilacji jądra.
Clang KCFI nie wymaga LTO, więc nowsze jądra Androida korzystają z CFI bez obciążenia związanego z czasem kompilacji LTO.
Implementacja
CFI jest kontrolowana przez opcję CONFIG_CFI_CLANG, która włącza Clang CFI lub Clang KCFI.
Więcej informacji technicznych o CFI i sposobie obsługi innych kontroli przepływu sterowania znajdziesz w dokumentacji projektu LLVM. KCFI jest tam określana jako -fsanitize=kcfi.
Rozwiązywanie problemów
Po włączeniu CFI rozwiąż wszelkie błędy niezgodności typów, które mogą występować w sterownikach. Pośrednie wywołanie funkcji za pomocą niezgodnego wskaźnika funkcji powoduje wyzwolenie CFI. Gdy zostanie wykryty błąd CFI, jądro wyświetli ostrzeżenie, które zawiera zarówno wywołaną funkcję, jak i ślad stosu, który doprowadził do błędu. Aby to naprawić, upewnij się, że wskaźniki funkcji zawsze mają ten sam typ co wywoływana funkcja.
Aby ułatwić debugowanie błędów CFI, włącz CONFIG_CFI_PERMISSIVE, która wyświetla ostrzeżenie zamiast powodować panikę jądra. Trybu permisywnego nie należy używać w środowisku produkcyjnym.
Weryfikacja
Obecnie nie ma testów CTS przeznaczonych specjalnie do CFI. Zamiast tego upewnij się, że testy CTS przechodzą z włączoną i wyłączoną CFI, aby sprawdzić, czy CFI nie ma wpływu na urządzenie.