UndefinedBehaviorSanitizer

UnfinedBehaviorSanitizer (UBSan) thực hiện công cụ đo lường thời gian biên dịch để kiểm tra các loại hành vi không xác định khác nhau. Trong khi UBSan có khả năng phát hiện nhiều lỗi hành vi không xác định thì Android lại hỗ trợ:

  • căn chỉnh
  • bool
  • giới hạn
  • liệt kê
  • tràn-đổ-tràn
  • float-chia-cho-không
  • số nguyên chia cho 0
  • thuộc tính không có giá trị
  • vô giá trị
  • trở lại
  • trả về thuộc tính không null
  • cơ sở thay đổi
  • số mũ dịch chuyển
  • tràn số nguyên đã ký
  • không thể truy cập được
  • tràn số nguyên không dấu
  • giới hạn vla

tràn số nguyên không dấu, mặc dù hành vi không được xác định về mặt kỹ thuật, được bao gồm trong trình khử trùng và được sử dụng trong nhiều mô-đun Android, bao gồm các thành phần máy chủ phương tiện, để loại bỏ mọi lỗ hổng tràn số nguyên tiềm ẩn.

Thực hiện

Trong hệ thống xây dựng Android, bạn có thể kích hoạt UBSan trên toàn cầu hoặc cục bộ. Để bật UBSan trên toàn cầu, hãy đặt SANITIZE_TARGET trong Android.mk. Để bật UBSan ở cấp độ mỗi mô-đun, hãy đặt LOCAL_SANITIZE và chỉ định các hành vi không xác định mà bạn muốn tìm kiếm trong Android.mk. Ví dụ:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

Và cấu hình kế hoạch chi tiết tương đương (Android.bp):

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            misc_undefined: [
                "alignment",
                "bounds",
                "null",
                "unreachable",
                "integer",
            ],
        },
    },

}

Phím tắt UBSan

Android cũng có hai phím tắt, integerdefault-ub , để kích hoạt một bộ chất khử trùng cùng một lúc. số nguyên cho phép integer-divide-by-zero , signed-integer-overflowunsigned-integer-overflow . default-ub cho phép kiểm tra có vấn đề về hiệu suất trình biên dịch ở mức tối thiểu: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound . Lớp khử trùng số nguyên có thể được sử dụng với SANITIZE_TARGET và LOCAL_SANITIZE, trong khi lớp default-ub chỉ có thể được sử dụng với SANITIZE_TARGET.

Báo cáo lỗi tốt hơn

Việc triển khai UBSan mặc định của Android sẽ gọi một hàm được chỉ định khi gặp phải hành vi không xác định. Theo mặc định, chức năng này bị hủy bỏ. Tuy nhiên, bắt đầu từ tháng 10 năm 2016, UBSan trên Android có thư viện thời gian chạy tùy chọn cung cấp báo cáo lỗi chi tiết hơn, bao gồm loại hành vi không xác định gặp phải, thông tin về tệp và dòng mã nguồn. Để bật tính năng báo cáo lỗi này bằng kiểm tra số nguyên, hãy thêm phần sau vào tệp Android.mk:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

Giá trị LOCAL_SANITIZE cho phép khử trùng trong quá trình xây dựng. LOCAL_SANITIZE_DIAG bật chế độ chẩn đoán cho chất khử trùng được chỉ định. Có thể đặt LOCAL_SANITIZE và LOCAL_SANITIZE_DIAG thành các giá trị khác nhau nhưng chỉ những kiểm tra đó trong LOCAL_SANITIZE mới được bật. Nếu kiểm tra không được chỉ định trong LOCAL_SANITIZE nhưng được chỉ định trong LOCAL_SANITIZE_DIAG thì kiểm tra không được bật và thông báo chẩn đoán sẽ không được cung cấp.

Dưới đây là ví dụ về thông tin được cung cấp bởi thư viện thời gian chạy UBSan:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Vệ sinh tràn số nguyên

Tràn số nguyên ngoài ý muốn có thể gây ra lỗi bộ nhớ hoặc lỗ hổng tiết lộ thông tin trong các biến liên quan đến truy cập bộ nhớ hoặc phân bổ bộ nhớ. Để giải quyết vấn đề này, chúng tôi đã thêm tính năng khử trùng tràn số nguyên có chữ ký và không dấu Und xác địnhBehaviorSanitizer (UBSan) của Clang để tăng cường khung phương tiện trong Android 7.0. Trong Android 9, chúng tôi đã mở rộng UBSan để bao gồm nhiều thành phần hơn và cải thiện khả năng hỗ trợ hệ thống xây dựng cho nó.

Điều này được thiết kế để bổ sung các bước kiểm tra xung quanh các phép tính/hướng dẫn số học—có thể tràn—để hủy bỏ một quá trình một cách an toàn nếu xảy ra tràn. Những công cụ khử trùng này có thể giảm thiểu toàn bộ loại lỗi hỏng bộ nhớ và lỗ hổng tiết lộ thông tin trong đó nguyên nhân cốt lõi là do tràn số nguyên, chẳng hạn như lỗ hổng Stagefright ban đầu.

Ví dụ và nguồn

Khử trùng tràn số nguyên (IntSan) do trình biên dịch cung cấp và thêm công cụ đo lường vào tệp nhị phân trong thời gian biên dịch để phát hiện lỗi tràn số học. Nó được bật theo mặc định trong nhiều thành phần khác nhau trên toàn bộ nền tảng, ví dụ /platform/external/libnl/Android.bp .

Thực hiện

IntSan sử dụng bộ khử trùng tràn số nguyên có dấu và không dấu của UBSan. Giảm thiểu này được kích hoạt ở cấp độ mỗi mô-đun. Nó giúp giữ an toàn cho các thành phần quan trọng của Android và không nên tắt.

Chúng tôi đặc biệt khuyến khích bạn bật Khử trùng Tràn Số nguyên 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 phân tích dữ liệu đầu vào không đáng tin cậy của người dùng. Có một chi phí hoạt động nhỏ liên quan đến bộ khử trùng phụ thuộc vào cách sử dụng mã và mức độ phổ biến của các phép tính số học. Mong đợi một tỷ lệ phần trăm chi phí nhỏ và kiểm tra xem hiệu suất có phải là vấn đề đáng lo ngại hay không.

Hỗ trợ IntSan trong makefiles

Để bật IntSan trong tệp tạo tệp, hãy thêm:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE lấy một danh sách các bộ khử trùng được phân tách bằng dấu phẩy, với integer_overflow là một tập hợp các tùy chọn được đóng gói sẵn cho các bộ khử trùng tràn số nguyên có dấu và không dấu riêng lẻ với BLOCKLIST mặc định .
  • LOCAL_SANITIZE_DIAG bật chế độ chẩn đoán cho chất khử trùng. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm vì chế độ này sẽ không dừng khi tràn, phủ nhận hoàn toàn lợi ích bảo mật của việc giảm thiểu. Xem Khắc phục sự cố để biết thêm chi tiết.
  • LOCAL_SANITIZE_BLOCKLIST cho phép bạn chỉ định tệp BLOCKLIST để ngăn chặn việc dọn dẹp các chức năng và tệp nguồn. Xem Khắc phục sự cố để biết thêm chi tiết.

Nếu bạn muốn kiểm soát chi tiết hơn, hãy bật riêng các chất khử trùng bằng một hoặc cả hai cờ:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

Hỗ trợ IntSan trong các tệp bản thiết kế

Để bật tính năng khử trùng tràn số nguyên trong tệp kế hoạch chi tiết, chẳng hạn như /platform/external/libnl/Android.bp , hãy thêm:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Giống như các tệp tạo, thuộc tính integer_overflow là một tập hợp các tùy chọn được đóng gói sẵn cho các trình khử trùng tràn số nguyên có dấu và không dấu riêng lẻ với BLOCKLIST mặc định .

Bộ thuộc tính diag đoán sẽ kích hoạt chế độ chẩn đoán cho chất khử trùng. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm. Chế độ chẩn đoán không hủy bỏ khi tràn, điều này phủ nhận hoàn toàn lợi thế bảo mật của việc giảm thiểu trong các bản dựng của người dùng. Xem Khắc phục sự cố để biết thêm chi tiết.

Thuộc tính BLOCKLIST cho phép đặc tả tệp BLOCKLIST cho phép các nhà phát triển ngăn chặn việc làm sạch các chức năng và tệp nguồn. Xem Khắc phục sự cố để biết thêm chi tiết.

Để kích hoạt từng chất khử trùng, hãy sử dụng:

   sanitize: {
          misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"],
          diag: {
              misc_undefined: ["signed-integer-overflow",
                               "unsigned-integer-overflow",],
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Xử lý sự cố

Nếu bạn đang bật tính năng dọn dẹp tràn số nguyên trong các thành phần mới hoặc dựa vào các thư viện nền tảng đã có tính năng dọn dẹp tràn số nguyên, thì bạn có thể gặp phải một số vấn đề với tình trạng tràn số nguyên lành tính gây ra tình trạng hủy bỏ. Bạn nên kiểm tra các thành phần đã bật tính năng khử trùng để đảm bảo có thể phát hiện các lỗi tràn lành tính.

Để tìm, hủy bỏ do quá trình dọn dẹp trong các bản dựng của người dùng, hãy tìm kiếm SIGABRT gặp sự cố với thông báo Hủy bỏ cho biết UBSan đã phát hiện lỗi tràn, chẳng hạn như:

pid: ###, tid: ###, name: Binder:###  >>> /system/bin/surfaceflinger <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: sub-overflow'

Dấu vết ngăn xếp phải bao gồm hàm gây ra việc hủy bỏ, tuy nhiên, tình trạng tràn xảy ra trong các hàm nội tuyến có thể không hiển thị rõ ràng trong dấu vết ngăn xếp.

Để dễ dàng xác định nguyên nhân gốc rễ hơn, hãy bật chẩn đoán trong thư viện kích hoạt thao tác hủy bỏ và cố gắng tái tạo lỗi. Khi bật chẩn đoán, quá trình sẽ không bị hủy mà thay vào đó sẽ tiếp tục chạy. Việc không hủy bỏ giúp tối đa hóa số lần tràn lành tính trong một đường dẫn thực thi cụ thể mà không cần phải biên dịch lại sau khi sửa từng lỗi. Chẩn đoán tạo ra thông báo lỗi bao gồm số dòng và tệp nguồn khiến lệnh hủy bỏ:

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Sau khi xác định được phép toán số học có vấn đề, hãy đảm bảo rằng lỗi tràn là lành tính và có chủ đích (ví dụ: không có ý nghĩa bảo mật). Bạn có thể giải quyết việc hủy bỏ chất khử trùng bằng cách:

  • Tái cấu trúc code để tránh tràn ( ví dụ )
  • Tràn rõ ràng thông qua các hàm __buildin_*_overflow của Clang ( ví dụ )
  • Vô hiệu hóa quá trình khử trùng trong hàm bằng cách chỉ định thuộc tính no_sanitize ( ví dụ )
  • Vô hiệu hóa việc khử trùng một chức năng hoặc tệp nguồn thông qua tệp BLOCKLIST ( ví dụ )

Bạn nên sử dụng giải pháp chi tiết nhất có thể. Ví dụ: một hàm lớn có nhiều phép toán số học và một phép toán tràn duy nhất nên được cấu trúc lại một phép toán thay vì toàn bộ hàm BLOCKLISTed.

Các kiểu phổ biến có thể dẫn đến tình trạng tràn lành tính bao gồm:

  • Truyền ngầm định trong đó xảy ra tràn không dấu trước khi được truyền sang loại đã ký ( ví dụ )
  • Xóa danh sách liên kết làm giảm chỉ số vòng lặp khi xóa ( ví dụ )
  • Gán loại không dấu cho -1 thay vì chỉ định giá trị tối đa thực tế ( ví dụ )
  • Vòng lặp giảm số nguyên không dấu trong điều kiện ( example , example )

Các nhà phát triển nên đảm bảo rằng các trường hợp chất khử trùng phát hiện tràn rằng nó thực sự lành tính, không có tác dụng phụ ngoài ý muốn hoặc các tác động bảo mật trước khi vô hiệu hóa quá trình khử trùng.

Vô hiệu hóa IntSan

Bạn có thể tắt IntSan bằng BLOCKLIST hoặc thuộc tính chức năng. Tắt một cách tiết kiệm và chỉ khi việc tái cấu trúc mã không hợp lý hoặc nếu có vấn đề về hiệu năng.

Xem tài liệu Clang ngược dòng để biết thêm thông tin về cách tắt IntSan với các thuộc tính chức năngđịnh dạng tệp BLOCKLIST . DANH SÁCH CHẶN phải nằm trong phạm vi chất khử trùng cụ thể bằng cách sử dụng tên phần chỉ định chất khử trùng mục tiêu để tránh ảnh hưởng đến các chất khử trùng khác.

Thẩm định

Hiện tại, không có thử nghiệm CTS nào dành riêng cho Vệ sinh Tràn Số nguyên. Thay vào đó, hãy đảm bảo rằng các bài kiểm tra CTS vượt qua dù có hoặc không có bật IntSan để xác minh rằng nó không ảnh hưởng đến thiết bị.

Vệ sinh giới hạn

BoundsSanitizer (BoundSan) thêm công cụ đo lường vào các tệp nhị phân để chèn các kiểm tra giới hạn xung quanh việc truy cập mảng. Những kiểm tra này được thêm vào nếu trình biên dịch không thể chứng minh tại thời điểm biên dịch rằng quyền truy cập sẽ an toàn và liệu kích thước của mảng có được biết trong thời gian chạy hay không, để có thể kiểm tra lại nó. Android 10 triển khai BoundSan trong Bluetooth và codec. BoundSan được trình biên dịch cung cấp và được bật theo mặc định trong nhiều thành phần khác nhau trên toàn bộ nền tảng.

Thực hiện

BoundSan sử dụng chất khử trùng giới hạn của UBSan . Giảm thiểu này được kích hoạt ở cấp độ mỗi mô-đun. Nó giúp giữ an toàn cho các thành phần quan trọng của Android và không nên bị tắt.

Chúng tôi thực sự khuyến khích bạn kích hoạt BoundSan 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 phức tạp có chức năng phân tích dữ liệu đầu vào không đáng tin cậy của người dùng. Chi phí hiệu năng liên quan đến việc bật BoundSan phụ thuộc vào số lượng truy cập mảng không thể được chứng minh là an toàn. Trung bình mong đợi một tỷ lệ phần trăm chi phí nhỏ và kiểm tra xem hiệu suất có phải là vấn đề đáng lo ngại hay không.

Kích hoạt BoundSan trong các tệp bản thiết kế

BoundSan có thể được kích hoạt trong các tệp bản thiết kế bằng cách thêm "bounds" vào thuộc tính khử trùng misc_undefined cho các mô-đun nhị phân và thư viện:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
chẩn đoán

Thuộc tính diag cho phép chế độ chẩn đoán cho chất khử trùng. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm. Chế độ chẩn đoán không hủy bỏ khi tràn, điều này phủ nhận lợi thế bảo mật của việc giảm thiểu và mang lại chi phí hiệu suất cao hơn, do đó, chế độ này không được khuyến nghị cho các bản dựng sản xuất.

DANH SÁCH CHẶN

Thuộc tính BLOCKLIST cho phép đặc tả tệp BLOCKLIST mà nhà phát triển có thể sử dụng để ngăn chặn việc làm sạch các chức năng và tệp nguồn. Chỉ sử dụng thuộc tính này nếu hiệu suất là mối quan tâm và các tệp/chức năng được nhắm mục tiêu đóng góp đáng kể. Kiểm tra thủ công các tệp/chức năng này để đảm bảo rằng việc truy cập mảng được an toàn. Xem Khắc phục sự cố để biết thêm chi tiết.

Kích hoạt BoundSan trong tệp tạo tệp

BoundSan có thể được kích hoạt trong các tệp tạo tệp bằng cách thêm "bounds" vào biến LOCAL_SANITIZE cho các mô-đun nhị phân và thư viện:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE chấp nhận danh sách chất khử trùng được phân tách bằng dấu phẩy.

LOCAL_SANITIZE_DIAG bật chế độ chẩn đoán. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm. Chế độ chẩn đoán không hủy bỏ khi tràn, điều này phủ nhận lợi thế bảo mật của việc giảm thiểu và mang lại chi phí hiệu suất cao hơn, do đó, chế độ này không được khuyến nghị cho các bản dựng sản xuất.

LOCAL_SANITIZE_BLOCKLIST cho phép đặc tả tệp BLOCKLIST cho phép các nhà phát triển ngăn chặn việc làm sạch các chức năng và tệp nguồn. Chỉ sử dụng thuộc tính này nếu hiệu suất là mối quan tâm và các tệp/chức năng được nhắm mục tiêu đóng góp đáng kể. Kiểm tra thủ công các tệp/chức năng này để đảm bảo rằng việc truy cập mảng được an toàn. Xem Khắc phục sự cố để biết thêm chi tiết.

Vô hiệu hóa BoundSan

Bạn có thể tắt BoundSan trong các hàm và tệp nguồn bằng BLOCKLIST hoặc thuộc tính hàm. Tốt nhất là luôn bật BoundSan, vì vậy chỉ tắt nó nếu chức năng hoặc tệp đang tạo ra một lượng lớn chi phí hoạt động và nguồn đã được xem xét thủ công.

Để biết thêm thông tin về cách vô hiệu hóa BoundSan với các thuộc tính chức năngđịnh dạng tệp BLOCKLIST , hãy tham khảo tài liệu Clang LLVM. Phạm vi DANH SÁCH CHẶN cho chất khử trùng cụ thể bằng cách sử dụng tên phần chỉ định chất khử trùng mục tiêu để tránh ảnh hưởng đến các chất khử trùng khác.

Thẩm định

Không có bài kiểm tra CTS cụ thể nào cho BoundSan. 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 BoundSan để xác minh rằng nó không ảnh hưởng đến thiết bị.

Xử lý sự cố

Kiểm tra kỹ lưỡng các thành phần sau khi kích hoạt BoundSan để đảm bảo rằng mọi truy cập ngoài giới hạn không bị phát hiện trước đó đều được giải quyết.

Lỗi BoundSan có thể dễ dàng được xác định vì chúng bao gồm thông báo hủy bỏ Tombstone sau:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

Khi chạy ở chế độ chẩn đoán, tệp nguồn, số dòng và giá trị chỉ mục sẽ được in thành logcat . Theo mặc định, chế độ này không đưa ra thông báo hủy bỏ. Xem lại logcat để kiểm tra xem có lỗi nào không.

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'