Tính đến năm 2016, khoảng 86% tất cả các lỗ hổng trên Android liên quan đến an toàn bộ nhớ. Hầu hết các lỗ hổng được khai thác bởi những kẻ tấn công thay đổi luồng điều khiển bình thường của một ứng dụng để thực hiện các hoạt động độc hại tùy ý với tất cả các đặc quyền của ứng dụng bị khai thác. 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 các thay đổi đối với đồ thị luồng điều khiển ban đầu của một 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 khó hơn đáng kể.
Trong Android 8.1, chúng tôi đã kích hoạt việc triển khai CFI của LLVM trong ngăn xếp phương tiện. Trong Android 9, chúng tôi đã bật CFI trong nhiều thành phần hơn và cả hạt nhân. CFI hệ thống được 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 với Tối ưu hóa thời gian liên kết (LTO) . LTO duy trì biểu diễn mã bit LLVM của các tệp đối tượng cho đến thời điểm liên kết, điều này cho phép trình biên dịch lý luận tốt hơn về những gì tối ưu hóa có thể được thực hiện. Bật LTO 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 tăng thời gian biên dịch. Trong thử nghiệm trên Android, sự kết hợp của LTO và CFI dẫn đến chi phí cho kích thước và hiệu suất mã không đáng kể; 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 điều khiển chuyển tiếp khác, hãy xem tài liệu thiết kế LLVM .
Ví dụ và nguồn
CFI được cung cấp bởi trình biên dịch và thêm thiết bị vào hệ nhị phân trong thời gian biên dịch. Chúng tôi hỗ trợ CFI trong chuỗi công cụ Clang và hệ thống xây dựng Android trong AOSP.
CFI được bật theo mặc định cho các thiết bị Arm64 cho tập hợp các thành phần trong /platform/build/target/product/cfi-common.mk
. Nó cũng được bật trực tiếp trong một tập hợp các tệp makefiles / blueprint của các thành phần đa phương tiện, chẳng hạn như /platform/frameworks/av/media/libmedia/Android.bp
và /platform/frameworks/av/cmds/stagefright/Android.mk
.
Hệ thống triển khai CFI
CFI được bật theo mặc định nếu bạn sử dụng Clang và hệ thống xây dựng Android. Vì CFI giúp giữ an toàn cho người dùng Android, bạn không nên vô hiệu hóa nó.
Trên thực tế, chúng tôi đặc biệt khuyến khích bạn bật CFI cho các thành phần bổ sung. Các ứng cử viên lý tưởng là mã gốc đặc quyền hoặc mã gốc xử lý đầu vào của người dùng không đáng tin cậy. Nếu bạn đang sử dụng clang và hệ thống xây dựng Android, bạn có thể bật CFI trong các thành phần mới bằng cách thêm một vài dòng vào tệp trang điểm hoặc tệp kế hoạch chi tiết của mình.
Hỗ trợ CFI trong trang điểm
Để bật CFI trong tệp tạo, chẳng hạn như /platform/frameworks/av/cmds/stagefright/Android.mk
, hãy thêm:
LOCAL_SANITIZE := cfi # Optional features LOCAL_SANITIZE_DIAG := cfi LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
-
LOCAL_SANITIZE
chỉ định CFI làm chất khử trùng trong quá trình xây dựng. -
LOCAL_SANITIZE_DIAG
bật chế độ chẩn đoán cho CFI. Chế độ chẩn đoán in ra thông tin gỡ lỗi bổ sung trong logcat khi gặp sự cố, điều này rất hữu ích trong khi phát triển và thử nghiệm các bản dựng của bạn. Tuy nhiên, hãy đảm bảo loại bỏ chế độ chẩn đoán trên các bản dựng sản xuất. -
LOCAL_SANITIZE_BLACKLIST
cho phép các thành phần vô hiệu hóa có chọn lọc thiết bị CFI cho các chức năng riêng lẻ hoặc tệp nguồn. Bạn có thể sử dụng danh sách đen như một phương sách cuối cùng để khắc phục bất kỳ sự cố nào mà người dùng gặp phải có thể tồn tại. Để biết thêm chi tiết, hãy xem mục Tắt CFI .
Hỗ trợ CFI trong các tệp kế hoạch chi tiết
Để bật CFI trong tệp kế hoạch chi tiết, chẳng hạn như /platform/frameworks/av/media/libmedia/Android.bp
, hãy thêm:
sanitize: { cfi: true, diag: { cfi: true, }, blacklist: "cfi_blacklist.txt", },
Xử lý sự cố
Nếu bạn đang bật CFI trong các thành phần mới, bạn có thể gặp một số vấn đề với lỗi không khớp loại chức năng và lỗi không khớp loại mã lắp ráp .
Lỗi không khớp kiểu hàm xảy ra do CFI hạn chế các lệnh gọi gián tiếp chỉ nhảy đến các hàm có cùng kiểu động với kiểu tĩnh được sử dụng trong cuộc gọi. CFI hạn chế các lệnh gọi hàm thành viên ảo và không ảo để chỉ nhảy đến các đối tượng là một lớp dẫn xuất của kiểu tĩnh của đối tượng được sử dụng để thực hiện cuộc gọi. Điều này có nghĩa là, khi bạn có mã vi phạm một trong hai giả định này, công cụ đo lường mà CFI thêm vào sẽ bị hủy bỏ. Ví dụ: dấu vết ngăn xếp cho thấy một SIGABRT và logcat chứa một dòng về tính toàn vẹn của luồng điều khiển tìm ra sự không phù hợp.
Để khắc phục điều này, hãy đảm bảo rằng hàm được gọi có cùng kiểu đã được khai báo tĩnh. Đây là hai CL mẫu:
- Bluetooth : / c / platform / system / bt / + / 532377
- NFC : / c / platform / system / nfc / + / 527858
Một vấn đề khác có thể xảy ra là cố gắng kích hoạt CFI trong mã có chứa các lệnh gọi gián tiếp đến hợp ngữ. Vì mã lắp ráp không được nhập, điều này dẫn đến kiểu không khớp.
Để khắc phục điều này, hãy tạo các trình bao bọc mã gốc cho mỗi cuộc gọi hợp ngữ và cung cấp cho các trình bao bọc cùng một chữ ký hàm như trình kiểm tra cuộc gọi. Sau đó, trình bao bọc có thể gọi trực tiếp mã lắp ráp. Vì các chi nhánh trực tiếp không được CFI hỗ trợ (chúng không thể được bổ nhiệm lại trong thời gian chạy và do đó không gây ra rủi ro bảo mật), điều này sẽ khắc phục sự cố.
Nếu có quá nhiều hàm hợp ngữ và tất cả chúng không thể sửa được, bạn cũng có thể đưa vào danh sách đen tất cả các hàm chứa lời gọi gián tiếp đến hợp ngữ. Điều này không được khuyến khích vì nó vô hiệu hóa kiểm tra CFI trên các chức năng này, do đó mở ra bề mặt tấn công.
Tắt CFI
Chúng tôi không quan sát thấy bất kỳ chi phí hiệu suất nào, vì vậy bạn không cần phải tắt CFI. Tuy nhiên, nếu có tác động từ phía người dùng, bạn có thể vô hiệu hóa CFI có chọn lọc cho các chức năng riêng lẻ hoặc tệp nguồn bằng cách cung cấp tệp danh sách đen của trình vệ sinh tại thời điểm biên dịch. Danh sách đen hướng dẫn trình biên dịch tắt thiết bị đo CFI ở các vị trí được chỉ định.
Hệ thống xây dựng Android cung cấp hỗ trợ cho danh sách đen từng thành phần (cho phép bạn chọn tệp nguồn hoặc các chức năng riêng lẻ sẽ không nhận được thiết bị CFI) cho cả Make và Soong. Để biết thêm chi tiết về định dạng của tệp danh sách đen, hãy xem tài liệu Clang ngược dòng .
Thẩm định
Hiện tại, không có bài kiểm tra CTS nào dành riêng cho CFI. Thay vào đó, hãy đảm bảo rằng các bài kiểm tra CTS vượt qua khi có hoặc không bật CFI để xác minh rằng CFI không ảnh hưởng đến thiết bị.