Kiểm soát tính toàn vẹn của luồng

Tính đến năm 2016, khoảng 86% tất cả các lỗ hổng bảo mật trên Android liên quan đến vấn đề an toàn bộ nhớ liên quan. Hầu hết các lỗ hổng bảo mật đều bị kẻ tấn công khai thác bằng cách thay đổi luồng kiểm soát của một ứng dụng để thực hiện các hoạt động độc hại tuỳ ý bằng mọi đặc quyền của ứng dụng bị khai thác. Quy trình kiểm soát tính toàn vẹn (CFI) là một cơ chế bảo mật không cho phép thay đổi đối với biểu đồ luồng điều khiển gốc của tệp nhị phân được biên dịch, khiến tệp khó hơn đáng kể để thực hiện các cuộc tấn công như vậy.

Trong Android 8.1, chúng tôi đã cho phép triển khai CFI của LLVM trong ngăn xếp nội dung đa phương tiện. Trong Trên Android 9, chúng tôi đã bật CFI trong nhiều thành phần hơn và cả nhân. CFI của hệ thống là 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 hoá thời gian liên kết (LTO). LTO lưu giữ bản trình bày mã bit LLVM của các tệp đối tượng cho đến khi link-time, cho phép trình biên dịch giải thích rõ hơn về những hoạt động tối ưu hoá có thể thực hiện được. Việc bật LTO giúp 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 cao hơn nhưng lại làm tăng thời gian biên dịch. Trong khi thử nghiệm trên Android, tổ hợp củ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ã; theo phong cách cả hai trường hợp đều được cải thiện.

Để biết thêm thông tin kỹ thuật về CFI và các hoạt động kiểm tra kiểm soát chuyển tiếp khác đã xử lý, hãy xem thiết kế LLVM .

Ví dụ và nguồn

CFI do trình biên dịch cung cấp và thêm khả năng đo lường vào tệp nhị phân trong khoảng thời gian 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.

Theo mặc định, CFI được bật cho các thiết bị Arm64 đối với tập hợp các thành phần trong /platform/build/target/product/cfi-common.mk. Tính năng này cũng được bật trực tiếp trong một nhóm các thành phần phương tiện truyền thông tệp makefile/bản vẽ tệp, chẳng hạn như /platform/frameworks/av/media/libmedia/Android.bp/platform/frameworks/av/cmds/stagefright/Android.mk.

Triển khai CFI của hệ thống

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 tắt tính năng này.

Trên thực tế, bạn nên bật CFI cho các thành phần khác. Các ứng viên lý tưởng là mã gốc có đặc quyền hoặc mã gốc có khả năng xử lý hoạt động đầu vào không đáng tin cậy của người dùng. Nếu đ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 makefile của bạn hoặc tệp bản thiết kế.

Hỗ trợ CFI trong tệp tạo

Để bật CFI trong một tệp tạo, chẳng hạn như /platform/frameworks/av/cmds/stagefright/Android.mk, thêm:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt

  • LOCAL_SANITIZE chỉ định CFI làm trình dọn dẹp trong bản 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 trong quá trình Sự cố, rất hữu ích trong khi phát triển và kiểm thử các bản dựng. Nhãn hiệu hãy nhớ xoá chế độ chẩn đoán trên các bản dựng chính thức.
  • LOCAL_SANITIZE_BLACKLIST cho phép các thành phần có thể chọn lọc tắt khả năng đo lường CFI cho các hàm riêng lẻ hoặc tệp nguồn. Bạn có thể sử dụng danh sách cấm như một phương án cuối cùng để khắc phục bất kỳ vấn đề nào mà người dùng gặp phải có thể tồn tại. Để biết thêm thông tin, hãy xem Tắt CFI.

Hỗ trợ CFI trong tệp bản thiết kế

Để bật CFI trong tệp bản thiết kế, chẳng hạn như /platform/frameworks/av/media/libmedia/Android.bp, thêm:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

Khắc phục sự cố

Nếu đang bật CFI trong các thành phần mới, bạn có thể gặp phải một số vấn đề với lỗi không khớp loại hàmloại mã tập hợp không khớp "lỗi..

Lỗi không khớp loại hàm xảy ra do CFI hạn chế lệnh gọi gián tiếp chỉ chuyển đến các hàm có cùng kiểu động với kiểu tĩnh dùng trong . CFI hạn chế các lệnh gọi hàm thành viên ảo và không ảo để chỉ chuyển cho 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 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 điều sau giả định, thì khả năng đo lường mà CFI thêm sẽ bị huỷ. Ví dụ: dấu vết ngăn xếp cho thấy SIGABRT và logcat chứa một dòng về luồng điều khiển tính toàn vẹn khi tìm thấy dữ liệu không khớp.

Để khắc phục vấn đề này, hãy đảm bảo rằng hàm được gọi có cùng loại được khai báo tĩnh. Dưới đây là hai ví dụ về CL:

Một vấn đề khác có thể xảy ra là cố gắng bật CFI trong mã có chứa gián tiếp lệnh gọi đến tập hợp. Do mã tập hợp không được nhập, điều này dẫn đến một loại không khớp.

Để khắc phục vấn đề này, hãy tạo trình bao bọc mã gốc cho mỗi lệnh gọi tập hợp và cung cấp cho phương thức trình bao bọc chữ ký hàm giống như poiner gọi. Sau đó, trình bao bọc có thể trực tiếp gọi mã tập hợp. Bởi vì các nhánh trực tiếp không được đo lường bởi CFI (không thể xác định lại trong thời gian chạy và do đó không gây ra rủi ro bảo mật), thao tác này sẽ khắc phục được vấn đề.

Nếu có quá nhiều hàm tập hợp và không thể khắc phục được tất cả, bạn có thể đồng thời đưa tất cả các hàm chứa lệnh gọi gián tiếp đến tập hợp vào danh sách cấm. Đây là không nên dùng vì chế độ này tắt các hoạt động kiểm tra CFI trên các hàm này, do đó mở bề mặt tấn công.

Tắt CFI

Chúng tôi không quan sát thấy bất kỳ mức hao tổn hiệu suất nào, vì vậy, bạn không cần vô hiệu hoá CFI. Tuy nhiên, nếu có tác động đối với người dùng, bạn có thể chọn vô hiệu hoá CFI cho các hàm riêng lẻ hoặc các tệp nguồn bằng cách cung cấp tệp danh sách đen của trình dọn dẹp vào thời gian biên dịch. Danh sách đen hướng dẫn trình biên dịch tắt CFI khả năng đo lường ở những vị trí cụ thể.

Hệ thống xây dựng Android hỗ trợ các danh sách cấm theo mỗi 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 CFI đo lường) cho cả Make và Soong. Để biết thêm chi tiết về định dạng của danh sách đen, hãy xem tệp upstream Tài liệu Clang.

Xác nhận kết quả

Hiện tại, không có thử nghiệm CTS nào cụ thể cho CFI. Thay vào đó, hãy đảm bảo rằng Các bài kiểm thử CTS đạt có hoặc không bật CFI để xác minh rằng CFI không ảnh hưởng thiết bị.