Không xác địnhHành vi Sanitizer (UBSan) thực hiện đo lường thời gian biên dịch để kiểm tra nhiều loại hành vi không xác định. Mặc dù UBSan có khả năng phát hiện nhiều lỗi hành vi không xác định, Android hỗ trợ:
- căn chỉnh
- bool
- ranh giới
- enum
- float-cast-overflow
- dấu phẩy động chia cho 0
- số nguyên chia cho 0
- thuộc tính không rỗng
- null
- câu lệnh trả về
- trả về thuộc tính không rỗng
- phím shift cơ sở
- số mũ-di-chuyển
- ký-số-nguyên-tràn
- không truy cập được
- Không có dấu-số-nguyên-tràn
- bị ràng buộc bởi vla
Không có dấu-số-nguyên-tràn, mặc dù về mặt kỹ thuật là không xác định có trong trình dọn dẹp và được sử dụng trong nhiều mô-đun Android, bao gồm các thành phần mediaserver để loại bỏ mọi lệnh tràn số nguyên tiềm ẩn lỗ hổng bảo mật.
Triển khai
Trong hệ thống xây dựng Android, bạn có thể bậ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 tại cho 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 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 sơ đồ thiết kế 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", ], }, }, }
Lối tắt UBSan
Android cũng có 2 lối tắt là integer
và
default-ub
để bật cùng một lúc một trình dọn dẹp. số nguyên
bật integer-divide-by-zero
,
signed-integer-overflow
và unsigned-integer-overflow
.
default-ub
bật các bước kiểm tra có trình biên dịch tối thiểu
vấn đề về hiệu suất: bool, integer-divide-by-zero, return,
returns-nonnull-attribute, shift-exponent, unreachable and vla-bound
. Chiến lược phát hành đĩa đơn
có thể sử dụng lớp trình dọn dẹp số nguyên với SANITIZE_TARGET và LOCAL_SANITIZE,
trong khi mặc định-ub chỉ có thể sử dụng với SANITIZE_TARGET.
Báo cáo lỗi hiệu quả hơn
Quy trình triển khai UBSan mặc định của Android 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, hàm này bị huỷ. Tuy nhiên, bắt đầu từ tháng 10 năm 2016, UBSan trên Android có một thư viện thời gian chạy tuỳ 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, tệp và thông tin dòng mã nguồn. Cách kích hoạt lỗi này báo cáo có kiểm tra số nguyên, thêm phần sau đây vào tệp Android.mk:
LOCAL_SANITIZE:=integer LOCAL_SANITIZE_DIAG:=integer
Giá trị LOCAL_SANITIZE sẽ bật trình dọn dẹp trong quá trình tạo. LOCAL_SANITIZE_DIAG bật chế độ chẩn đoán cho trình dọn dẹp được chỉ định. Đó là đặt LOCAL_SANITIZE và LOCAL_SANITIZE_DIAG thành các giá trị khác nhau, nhưng chỉ những bước kiểm tra đó trong LOCAL_SANITIZE mới được bật. Nếu việc kiểm tra không được chỉ định trong LOCAL_SANITIZE nhưng được chỉ định trong LOCAL_SANITIZE_DIAG, nên chế độ kiểm tra này chưa đượ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 do thư viện thời gian chạy UBSan cung cấp:
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')
Dọn dẹp tràn số nguyên
Tình trạng tràn số nguyên ngoài ý muốn có thể gây hỏng bộ nhớ hoặc gây hỏng thông tin lỗ hổng bảo mật thông tin công bố trong các biến liên quan đến quyền truy cập bộ nhớ hoặc phân bổ bộ nhớ. Để ngăn chặn điều này, chúng tôi đã thêm tính năng Clang UndefinedBehaviorSanitizer (UBSan) trình dọn dẹp tràn số nguyên đã ký và chưa ký vào làm cứng khung nội dung đa 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ó.
API này được thiết kế để thêm các bước kiểm tra về số học thao tác& tràn – để huỷ một tiến trình một cách an toàn nếu tràn xảy ra. Các trình dọn dẹp này có thể giảm thiểu toàn bộ tình trạng hỏng bộ nhớ và lỗ hổng bảo mật tiết lộ thông tin, trong đó nguyên nhân gốc rễ là một số nguyên bị tràn, chẳng hạn như lỗ hổng bảo mật Stagefright ban đầu.
Ví dụ và nguồn
Dọn dẹp tràn số nguyên (IntSan) do trình biên dịch cung cấp và thêm vào
khả năng đo lường vào tệp nhị phân trong thời gian biên dịch để phát hiện dữ liệu số học
bị tràn. Tính năng này được bật theo mặc định trong các thành phần khác nhau trên toàn bộ
nền tảng, ví dụ:
/platform/external/libnl/Android.bp
.
Triển khai
IntSan sử dụng trình dọn dẹp tràn số nguyên đã ký và chưa ký của UBSan. Chiến dịch này tính năng giảm thiểu được bật ở cấp độ từng mô-đun. Giúp giữ lại các thành phần quan trọng của Android là an toàn và không được vô hiệu hoá.
Bạn nên bật tính năng Dọn dẹp tràn số nguyên để thành phần. Các ứng viên lý tưởng là mã gốc có đặc quyền hoặc mã gốc phân tích cú pháp hoạt động đầu vào không đáng tin cậy của người dùng. Có mức hao tổn hiệu suất nhỏ liên quan đến với trình dọn dẹp phụ thuộc vào việc sử dụng mã và mức độ phổ biến của phép tính số học. Dự kiến mức hao tổn thấp và thử nghiệm xem thì hiệu suất.
Hỗ trợ IntSan trong tệp makefile
Để bật IntSan trong một tệp makefile, 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 trình dọn dẹp được phân tách bằng dấu phẩy, vớiinteger_overflow
là một tập hợp các tuỳ chọn đóng gói sẵn cho trình dọn dẹp tràn số nguyên đã ký và chưa ký riêng lẻ bằng mặc định DANH SÁCH CHẶN.LOCAL_SANITIZE_DIAG
bật chế độ chẩn đoán cho dung dịch vệ sinh. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm vì chế độ này sẽ không huỷ bỏ tràn, phủ định hoàn toàn lợi thế bảo mật của giảm thiểu rủi ro. Xem phần Khắc phục sự cố để biết thêm chi tiết.LOCAL_SANITIZE_BLOCKLIST
cho phép bạn chỉ định BLOCKLIST để ngăn việc dọn dẹp các hàm 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 từng trình dọn dẹp 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 dọn dẹp tràn số nguyên trong tệp bản thiết kế, chẳng hạn như
/platform/external/libnl/Android.bp
!
thêm:
sanitize: { integer_overflow: true, diag: { integer_overflow: true, }, BLOCKLIST: "modulename_BLOCKLIST.txt", },
Giống như tệp make, thuộc tính integer_overflow
được đóng gói sẵn
tập hợp tuỳ chọn cho từng lệnh tràn số nguyên đã ký và chưa ký
trình dọn dẹp bằng mặc định
DANH SÁCH CHẶN.
Tập hợp thuộc tính diag
bật chế độ chẩn đoán cho
dung dịch vệ sinh. Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm. Chế độ chẩn đoán không
huỷ bỏ tràn, việc này làm mất hoàn toàn lợi thế bảo mật của
trong bản dựng người dùng. Hãy xem phần Khắc phục sự cố để biết thêm thông tin chi tiết.
Thuộc tính BLOCKLIST
cho phép chỉ định thông số của tệp BLOCKLIST
cho phép nhà phát triển ngăn chặn các hàm và tệp nguồn
đã được dọn dẹp. Xem phần Khắc phục sự cố để
thông tin chi tiết bổ sung.
Để bật riêng từng trình dọn dẹp, 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", },
Khắc phục 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 đã dọn dẹp tràn số nguyên, bạn có thể gặp phải một số vấn đề về việc tràn số nguyên vô hại gây ra trường hợp bị huỷ. Bạn nên kiểm thử các thành phần được bật tính năng dọn dẹp để đảm bảo có thể hiển thị các vùng tràn không gây hại.
Để tìm, lượt huỷ do tính năng dọn dẹp trong bản dựng người dùng gây ra, hãy tìm kiếm
SIGABRT
gặp sự cố với thông báo Huỷ bỏ cho biết đã phát hiện tràn
của UBSan, 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'
Tuy nhiên, dấu vết ngăn xếp phải bao gồm hàm gây ra việc huỷ tình trạng tràn xảy ra trong hàm cùng dòng có thể không rõ ràng trong dấu vết ngăn xếp.
Để xác định nguyên nhân gốc rễ dễ dàng hơn, hãy bật tính năng chẩn đoán trong thư viện kích hoạt huỷ bỏ và tìm cách tái hiện lỗi. Với đã bật chẩn đoán, quá trình này sẽ không huỷ bỏ mà thay vào đó tiếp tục chạy. Việc không huỷ giúp tối đa hoá số lượng tràn viền trong một đường dẫn thực thi cụ thể mà không phải biên dịch lại sau khi sửa từng lỗi. Công cụ Chẩn đoán đưa ra một thông báo lỗi bao gồm số dòng và nguồn tệp khiến bạn bị huỷ:
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 phép toán số học có vấn đề, hãy đảm bảo rằng lỗi tràn là vô hại và có chủ đích (ví dụ: không có ý nghĩa bảo mật). Bạn có thể giải quyết trình dọn dẹp huỷ bằng cách:
- Tái cấu trúc mã để tránh tràn (ví dụ)
- Tràn một cách rõ ràng thông qua __vành_*_overflow của Clang hàm (ví dụ)
- Tắt tính năng dọn dẹp trong hàm bằng cách chỉ định thuộc tính
no_sanitize
(ví dụ) - Tắt tính năng dọn dẹp một tệp hàm hoặc tệp nguồn thông qua tệp BLOCKLIST (ví dụ)
Bạn nên dùng giải pháp chi tiết nhất có thể. Ví dụ: phần lớn hàm có nhiều phép tính số học và một phép toán tràn phải tái cấu trúc một thao tác thay vì toàn bộ hàm Đã đưa vào BLOCKLIST.
Các kiểu phổ biến có thể dẫn đến tràn dịch vụ lành tính bao gồm:
- Ngụ ý truyền trong đó xảy ra tình trạng tràn không có chữ ký trước khi truyền tới một loại có dấu (ví dụ)
- Thao tác xoá danh sách được liên kết sẽ làm giảm chỉ mục vòng lặp khi xoá (ví dụ)
- Chỉ định một kiểu chưa có chữ ký 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 (ví dụ, ví dụ)
Nhà phát triển nên đảm bảo rằng các trường hợp mà công cụ dọn dẹp phát hiện trình đơn bổ sung cho thấy nó thực sự vô hại, không có tác dụng phụ hoặc bảo mật ngoài ý muốn trước khi tắt tính năng dọn dẹp.
Tắt IntSan
Bạn có thể vô hiệu hoá IntSan bằng BLOCKLIST hoặc các thuộc tính hàm. Tắt một cách thận trọng và chỉ khi tái cấu trúc mã là không hợp lý hoặc nếu có mức hao tổn hiệu suất có vấn đề.
Xem tài liệu Clang ngược dòng để biết thêm thông tin về cách tắt IntSan có hàm thuộc tính và BLOCKLIST định dạng. BLOCKLISTing phải được giới hạn trong trình dọn dẹp cụ thể bằng cách sử dụng tên các phần chỉ định chất làm sạch mục tiêu để tránh ảnh hưởng đến dung dịch vệ sinh.
Xác nhận kết quả
Hiện tại, không có kiểm thử CTS nào dành riêng cho Dọn dẹp tràn số nguyên. Thay vào đó, hãy đảm bảo rằng các bài kiểm thử CTS đạt có hoặc không có IntSan được bật để xác minh để đảm bảo không ảnh hưởng đến thiết bị.
Dọn dẹp giới hạn
BoundsSanitizer (BoundSan) thêm khả năng đo lường vào tệp nhị phân để chèn giới hạn cho phép kiểm tra quyền truy cập mảng. Các bước kiểm tra này sẽ đượ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 hoạt động truy cập sẽ an toàn và nếu kích thước của mảng trong thời gian chạy để có thể kiểm tra lại. Android 10 triển khai BoundSan ở Bluetooth và bộ mã hoá và giải mã. BoundSan được cung cấp bởi trình biên dịch và được bật bằng mặc định trong các thành phần khác nhau trên toàn bộ nền tảng.
Triển khai
BoundSan sử dụng UBSan's trình dọn dẹp giới hạn. Giải pháp giảm thiểu này được bật ở cấp độ từng mô-đun. Điều này giúp ích cho bảo mật và không được vô hiệu hoá các thành phần quan trọng của Android.
Bạn nên bật BoundSan cho các thành phần bổ sung. Các ứng viên lý tưởng là mã gốc có đặc quyền hoặc mã gốc phức tạp có khả năng phân tích cú pháp hoạt động đầu vào không đáng tin cậy của người dùng. Chi phí hiệu suất 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ể chứng minh được là an toàn. Dự kiến mức hao tổn trung bình nhỏ và thử nghiệm xem hiệu suất có phải là vấn đề không.
Bật BoundSan trong tệp bản thiết kế
Bạn có thể bật BoundSan trong tệp bản thiết kế bằng cách thêm "bounds"
vào thuộc tính dọn dẹp misc_undefined
cho tệp nhị phân và thư viện
mô-đun:
sanitize: { misc_undefined: ["bounds"], diag: { misc_undefined: ["bounds"], }, BLOCKLIST: "modulename_BLOCKLIST.txt",
chẩn đoán
Thuộc tính diag
bật chế độ chẩn đoán cho trình dọn dẹp.
Chỉ sử dụng chế độ chẩn đoán trong quá trình thử nghiệm. Chế độ chẩn đoán không huỷ bỏ
tràn, làm mất lợi thế về bảo mật của giải pháp giảm thiểu và mang lại
chi phí hiệu suất cao hơn, vì vậy, bạn không nên sử dụng tính năng này cho các bản dựng chính thức.
DANH SÁCH CHẶN
Thuộc tính BLOCKLIST
cho phép quy cách của BLOCKLIST
tệp mà nhà phát triển có thể dùng để ngăn chặn các hàm và tệp nguồn
đã được dọn dẹp. Chỉ sử dụng thuộc tính này nếu bạn quan tâm đến hiệu suất và mục tiêu
tệp/hàm đóng góp đáng kể. Kiểm tra các tệp/chức năng này theo cách thủ công
để đảm bảo rằng hoạt động truy cập mảng được an toàn. Xem phần Khắc phục sự cố để biết thêm
chi tiết.
Bật BoundSan trong tệp makefile
Bạn có thể bật BoundSan trong tệp makefile bằng cách thêm "bounds"
vào biến LOCAL_SANITIZE
đối với 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 trình dọn dẹp được phân tách bằng
dấu phẩy.
LOCAL_SANITIZE_DIAG
bật chế độ chẩn đoán. Sử dụng thông tin chẩn đoán
chỉ trong quá trình thử nghiệm. Chế độ chẩn đoán không huỷ bỏ khi bị tràn
làm mất lợi thế về bảo mật của giải pháp giảm thiểu và dẫn đến
chi phí hiệu suất, vì vậy, bạn không nên sử dụng chế độ này cho các bản dựng chính thức.
LOCAL_SANITIZE_BLOCKLIST
cho phép chỉ định một BLOCKLIST
tệp cho phép nhà phát triển ngăn chặn các hàm và tệp nguồn
đã được dọn dẹp. Chỉ sử dụng thuộc tính này nếu bạn quan tâm đến hiệu suất và mục tiêu
tệp/hàm đóng góp đáng kể. Kiểm tra các tệp/chức năng này theo cách thủ công
để đảm bảo rằng hoạt động truy cập mảng được an toàn. Xem phần Khắc phục sự cố để biết thêm
chi tiết.
Tắt BoundSan
Bạn có thể tắt BoundSan trong các hàm và tệp nguồn bằng BLOCKLIST hoặc các thuộc tính hàm. Tốt nhất là bạn nên bật BoundSan, vì vậy chỉ vô hiệu hoá nó nếu hàm hoặc tệp đó đang tạo ra một lượng lớn chi phí hiệu suất và nguồn đã được xem xét theo cách thủ công.
Để biết thêm thông tin về cách vô hiệu hoá BoundSan bằng hàm thuộc tính và BLOCKLIST , hãy tham khảo tài liệu Clang LLVM. Xác định phạm vi Tạo BLOCKLIST cho trình dọn dẹp cụ thể bằng cách sử dụng tên phần chỉ định nhắm đến chất làm sạch để tránh làm ảnh hưởng đến các chất khử trùng khác.
Xác nhận kết quả
Không có kiểm tra CTS nào cụ thể cho BoundSan. Thay vào đó, hãy đảm bảo rằng CTS các bài kiểm thử đạt có hoặc không bật BoundSan để xác minh rằng nó không ảnh hưởng thiết bị.
Khắc phục sự cố
Kiểm tra kỹ các thành phần sau khi bật BoundSan để đảm bảo rằng bất kỳ truy cập ngoài giới hạn chưa phát hiện được xử lý.
Lỗi BoundSan có thể dễ dàng được xác định vì chúng bao gồm như sau thông báo huỷ tombstone:
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à chỉ mục
được in ra logcat
. Theo mặc định, chế độ này không
gửi thông báo huỷ. Kiểm tra logcat
để kiểm tra xem có bất kỳ
.
external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'