Tính toàn vẹn của luồng kiểm soát (CFI) là một cơ chế bảo mật không cho phép thay đổi biểu đồ luồng kiểm soát ban đầu của tệp nhị phân đã biên dịch, khiến việc thực hiện các cuộc tấn công như vậy trở nên khó khăn hơn đáng kể.
Trong Android 9, chúng tôi đã bật tính năng triển khai CFI của LLVM trong nhiều thành phần hơn và cũng trong hạt nhân. System CFI (CFI hệ thống) bật theo mặc định, nhưng bạn cần bật CFI hạt nhân.
CFI của LLVM yêu cầu biên dịch bằng Tối ưu hoá thời gian liên kết (LTO). LTO giữ nguyên mã bit LLVM của các tệp đối tượng cho đến thời gian liên kết, cho phép trình biên dịch lý luận tốt hơn về những hoạt động tối ưu hoá có thể thực hiện. Việc bật LTO sẽ làm giảm kích thước của tệp nhị phân cuối cùng và cải thiện hiệu suất, nhưng sẽ làm tăng thời gian biên dịch. Trong quá trình kiểm thử trên Android, việc kết hợp LTO và CFI dẫn đến mức hao tổn không đáng kể đối với kích thước mã và hiệu suất; trong một số trường hợp, cả hai đều được cải thiện.
Để biết thêm thông tin kỹ thuật về CFI và cách xử lý các bước kiểm tra điều khiển chuyển tiếp khác, hãy xem tài liệu thiết kế LLVM.
Triển khai
Các bản vá kCFI có trong tất cả phiên bản hạt nhân Android được hỗ trợ. Tuỳ chọn CONFIG_CFI_CLANG
bật kCFI và được đặt theo mặc định trong GKI.
Khắc phục sự cố
Sau khi bật, hãy xử lý mọi lỗi không khớp loại có thể xảy ra với trình điều khiển. Lệnh gọi hàm gián tiếp thông qua con trỏ hàm không tương thích sẽ kích hoạt CFI. Khi phát hiện lỗi CFI, hạt nhân sẽ in một cảnh báo bao gồm cả hàm được gọi và dấu vết ngăn xếp dẫn đến lỗi. Khắc phục vấn đề này bằng cách đảm bảo con trỏ hàm luôn có cùng kiểu với hàm được gọi.
Để hỗ trợ gỡ lỗi các lỗi CFI, hãy bật CONFIG_CFI_PERMISSIVE
. Thao tác này sẽ in ra một cảnh báo thay vì gây ra sự cố kernel panic. Không được sử dụng chế độ cho phép trong phiên bản chính thức.
Xác nhận kết quả
Hiện tại, chưa có quy trình kiểm thử CTS dành riêng cho CFI. Thay vào đó, hãy đảm bảo rằng các bài kiểm thử CTS đã vượt qua cả khi bật và không bật CFI để xác minh rằng CFI không ảnh hưởng đến thiết bị.