Scudo

Scudo là một trình phân bổ bộ nhớ ở chế độ người dùng động hoặc trình phân bổ vùng nhớ khối xếp, được thiết kế để chống lại các lỗ hổng liên quan đến vùng nhớ khối xếp (chẳng hạn như tràn bộ đệm dựa trên vùng nhớ khối xếp, sử dụng sau khi giải phónggiải phóng hai lần) trong khi vẫn duy trì hiệu suất. Thư viện này cung cấp các hàm phân bổ và huỷ phân bổ C chuẩn (chẳng hạn như malloc và free), cũng như các hàm C++ gốc (chẳng hạn như new và delete).

Scudo là một công cụ giảm thiểu hơn là một công cụ phát hiện lỗi bộ nhớ hoàn chỉnh như AddressSanitizer (ASan).

Kể từ bản phát hành Android 11, scudo được dùng cho tất cả mã gốc (ngoại trừ trên các thiết bị có dung lượng bộ nhớ thấp, nơi jemalloc vẫn được dùng). Trong thời gian chạy, tất cả các lượt phân bổ và giải phóng vùng nhớ khối xếp gốc đều do Scudo xử lý cho tất cả các tệp thực thi và các phần phụ thuộc thư viện của chúng. Quá trình này sẽ bị huỷ nếu phát hiện thấy hành vi đáng ngờ hoặc hỏng hóc trong vùng nhớ khối xếp.

Scudo là nguồn mở và là một phần của dự án compiler-rt của LLVM. Bạn có thể xem tài liệu tại https://llvm.org/docs/ScudoHardenedAllocator.html. Môi trường thời gian chạy Scudo được phân phối trong chuỗi công cụ Android và tính năng hỗ trợ được thêm vào Soong và Make để cho phép dễ dàng bật trình phân bổ trong tệp nhị phân.

Bạn có thể bật hoặc tắt tính năng giảm thiểu bổ sung trong trình phân bổ bằng cách sử dụng các tuỳ chọn được mô tả bên dưới.

Tuỳ chỉnh

Bạn có thể xác định một số tham số của trình phân bổ trên cơ sở từng quy trình thông qua một số cách:

  • Tĩnh: Xác định hàm __scudo_default_options trong chương trình trả về chuỗi tuỳ chọn cần được phân tích cú pháp. Hàm này phải có nguyên mẫu sau: extern "C" const char *__scudo_default_options().
  • Linh hoạt: Sử dụng biến môi trường SCUDO_OPTIONS chứa chuỗi tuỳ chọn cần được phân tích cú pháp. Các tuỳ chọn được xác định theo cách này sẽ ghi đè mọi định nghĩa được thực hiện thông qua __scudo_default_options.

Bạn có thể chọn trong các phương án sau đây.

Lựa chọn 64 bit mặc định Mặc định 32 bit Mô tả
QuarantineSizeKb 256 64 Kích thước (tính bằng KB) của vùng cách ly dùng để trì hoãn việc phân bổ thực tế của các đoạn dữ liệu. Giá trị thấp hơn có thể làm giảm mức sử dụng bộ nhớ nhưng giảm hiệu quả của biện pháp giảm thiểu; giá trị âm sẽ quay lại giá trị mặc định. Việc đặt cả giá trị này và ThreadLocalQuarantineSizeKb thành 0 sẽ vô hiệu hoá hoàn toàn tính năng cách ly.
QuarantineChunksUpToSize 2048 512 Kích thước (tính bằng byte) mà tối đa là phạm vi có thể cách ly.
ThreadLocalQuarantineSizeKb 64 16 Kích thước (tính bằng KB) của bộ nhớ đệm trên mỗi luồng dùng để giảm tải vùng cách ly toàn cầu. Giá trị thấp hơn có thể làm giảm mức sử dụng bộ nhớ nhưng có thể làm tăng mức tranh chấp trên vùng cách ly toàn cầu. Việc đặt cả giá trị này và QuarantineSizeKb thành 0 sẽ tắt hoàn toàn tính năng cách ly.
DeallocationTypeMismatch false false Cho phép báo cáo lỗi khi Malloc/delete, mới/miễn phí, mới/xoá[]
DeleteSizeMismatch true true Bật tính năng báo cáo lỗi khi kích thước của tệp mới và tệp bị xoá không khớp.
ZeroContents false false Bật nội dung không có đoạn khi phân bổ và giải phóng.
allocator_may_return_null false false Chỉ định rằng trình phân bổ có thể trả về giá trị rỗng khi xảy ra lỗi có thể khôi phục, thay vì chấm dứt quy trình.
hard_rss_limit_mb 0 0 Khi RSS của quy trình đạt đến giới hạn này, quy trình sẽ chấm dứt.
soft_rss_limit_mb 0 0 Khi RSS của quy trình đạt đến giới hạn này, các lượt phân bổ tiếp theo sẽ không thành công hoặc trả về null (tuỳ thuộc vào giá trị của allocator_may_return_null), cho đến khi RSS giảm xuống để cho phép phân bổ mới.
allocator_release_to_os_interval_ms Không áp dụng 5000 Chỉ ảnh hưởng đến trình phân bổ 64 bit. Nếu được đặt, hãy cố gắng giải phóng bộ nhớ không sử dụng cho hệ điều hành, nhưng không thường xuyên hơn khoảng thời gian này (tính bằng mili giây). Nếu giá trị là âm, thì bộ nhớ sẽ không được giải phóng cho hệ điều hành.
abort_on_error true true Nếu được đặt, công cụ sẽ gọi abort() thay vì _exit() sau khi in thông báo lỗi.

Xác nhận kết quả

Hiện tại, chưa có thử nghiệm CTS nào dành riêng cho Scudo. Thay vào đó, hãy đảm bảo rằng các kiểm thử CTS đã vượt qua dù có bật Scudo hay không cho một tệp nhị phân nhất định để xác minh rằng tệp nhị phân đó không ảnh hưởng đến thiết bị.

Khắc phục sự cố

Nếu phát hiện thấy vấn đề không thể khôi phục, trình phân bổ sẽ hiển thị thông báo lỗi cho chỉ số mô tả lỗi chuẩn, sau đó chấm dứt quá trình. Các dấu vết ngăn xếp dẫn đến việc chấm dứt sẽ được thêm vào nhật ký hệ thống. Kết quả thường bắt đầu bằng Scudo ERROR:, theo sau là một bản tóm tắt ngắn về vấn đề cùng với mọi con trỏ.

Dưới đây là danh sách các thông báo lỗi hiện tại và nguyên nhân có thể gây ra các lỗi đó:

  • corrupted chunk header: Không xác minh được tổng kiểm của tiêu đề phân đoạn. Điều này có thể là do một trong hai nguyên nhân: tiêu đề bị ghi đè (một phần hoặc toàn bộ) hoặc con trỏ được truyền đến hàm không phải là một đoạn.
  • race on chunk header: Hai luồng khác nhau đang cố gắng thao tác cùng một tiêu đề cùng một lúc. Đây thường là triệu chứng của điều kiện tương tranh hoặc thiếu tính năng khoá chung khi thực hiện các thao tác trên khối đó.
  • invalid chunk state: Đoạn không ở trạng thái dự kiến cho một thao tác cụ thể, ví dụ: đoạn này không được phân bổ khi cố gắng giải phóng hoặc không bị cách ly khi cố gắng tái chế. Lỗi này thường xảy ra khi giải phóng hai lần.
  • misaligned pointer: Các yêu cầu căn chỉnh cơ bản được thực thi nghiêm ngặt: 8 byte trên nền tảng 32 bit và 16 byte trên nền tảng 64 bit. Nếu con trỏ được truyền đến các hàm của chúng ta không phù hợp với các hàm đó, thì con trỏ được truyền đến một trong các hàm sẽ không khớp.
  • allocation type mismatch: Khi bạn bật tuỳ chọn này, hàm giải phóng được gọi trên một đoạn phải khớp với loại hàm được gọi để phân bổ đoạn đó. Loại không khớp này có thể gây ra vấn đề bảo mật.
  • invalid sized delete: Khi sử dụng toán tử xoá có kích thước C++14 và bật tính năng kiểm tra không bắt buộc, sẽ có sự không khớp giữa kích thước được truyền khi phân bổ một khối và kích thước được yêu cầu khi phân bổ khối đó. Đây thường là vấn đề về trình biên dịch hoặc nhầm lẫn loại đối với đối tượng đang được giải phóng.
  • RSS limit exhausted: Đã vượt quá RSS tối đa được chỉ định (không bắt buộc).

Nếu đang gỡ lỗi sự cố trong chính hệ điều hành, bạn có thể sử dụng bản dựng hệ điều hành HWASan. Nếu đang gỡ lỗi một sự cố trong một ứng dụng, bạn cũng có thể sử dụng bản dựng ứng dụng HWASan.