Tính toàn vẹn của luồng điều khiển (CFI) là một cơ chế bảo mật không cho phép thay đổi biểu đồ luồng điều khiển ban đầu của tệp nhị phân được 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 đã kích hoạt triển khai CFI của LLVM trong nhiều thành phần hơn cũng như trong kernel. CFI hệ thống được bật theo mặc định, nhưng bạn cần bật CFI kernel.
CFI của LLVM yêu cầu biên dịch bằng Tối ưu hóa thời gian liên kết (LTO) . LTO bảo tồn biểu diễn mã bit LLVM của các tệp đối tượng cho đến thời gian liên kết, điều này cho phép trình biên dịch đưa ra lý do chính xác hơn về những gì có thể thực hiện tối ưu hóa. Việc kích hoạt LTO sẽ 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 làm tăng thời gian biên dịch. Khi thử nghiệm trên Android, sự kết hợp giữa LTO và CFI dẫn đến chi phí không đáng kể đối với kích thước và hiệu suất mã; trong một số trường hợp cả hai đều được cải thiện.
Để biết thêm chi tiết kỹ thuật về CFI và cách xử lý các kiểm tra kiểm soát chuyển tiếp khác, hãy xem tài liệu thiết kế LLVM .
Thực hiện
Các bản vá kCFI có trong tất cả các phiên bản nhân Android được hỗ trợ. Tùy chọn CONFIG_CFI_CLANG
kích hoạt kCFI và được đặt theo mặc định trong GKI.
Xử lý sự cố
Sau khi bật, hãy xử lý mọi lỗi không khớp về loại có thể tồn tại với trình điều khiển của chúng. Lệnh gọi hàm gián tiếp thông qua con trỏ hàm không tương thích sẽ ngắt CFI. Khi phát hiện lỗi CFI, kernel sẽ in ra 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. Hãy khắc phục điều này bằng cách đảm bảo con trỏ hàm luôn có cùng loại với hàm được gọi.
Để hỗ trợ gỡ lỗi các lỗi CFI, hãy bật CONFIG_CFI_PERMISSIVE
để in ra cảnh báo thay vì gây hoảng loạn cho kernel. Chế độ cho phép không được sử dụng trong sản xuất.
Thẩm định
Hiện tại, không có bài kiểm tra CTS cụ thể nào cho CFI. Thay vào đó, hãy đảm bảo rằng các bài kiểm tra CTS vượt qua khi bật hoặc không bật CFI để xác minh rằng CFI không ảnh hưởng đến thiết bị.