Android Live-LocK Daemon (llkd)

Android 10 bao gồm Android Live-LocK Daemon ( llkd ), được thiết kế để xử lý và giảm thiểu các bế tắc của hạt nhân. Thành phần llkd cung cấp một triển khai độc lập mặc định, nhưng bạn có thể tích hợp mã llkd vào một dịch vụ khác, như một phần của vòng lặp chính hoặc như một luồng riêng biệt.

Các tình huống phát hiện

llkd có hai tình huống phát hiện: Trạng thái D hoặc Z liên tục và chữ ký ngăn xếp liên tục.

Trạng thái D hoặc Z liên tục

Nếu một chuỗi ở trạng thái D (ngủ liên tục) hoặc Z (zombie) không có tiến trình chuyển tiếp lâu hơn ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , llkd sẽ giết tiến trình (hoặc quy trình mẹ ). Nếu quá trình quét tiếp theo cho thấy quá trình tương tự vẫn tiếp tục tồn tại, llkd xác nhận điều kiện khóa trực tiếp và điều khiển hạt nhân theo cách cung cấp báo cáo lỗi chi tiết nhất cho điều kiện đó.

llkd bao gồm một cơ quan giám sát tự báo động nếu llkd khóa; cơ quan giám sát tăng gấp đôi thời gian dự kiến ​​để chạy qua mainloop và lấy mẫu là mỗi ro.llk_sample_ms .

Chữ ký ngăn xếp liên tục

Đối với các bản phát hành userdebug, llkd có thể phát hiện các khóa trực tiếp của hạt nhân bằng cách sử dụng kiểm tra chữ ký ngăn xếp liên tục. Nếu một luồng ở bất kỳ trạng thái nào ngoại trừ Z có biểu tượng hạt nhân ro.llk.stack được liệt kê liên tục được báo cáo lâu hơn ro.llk.timeout_ms hoặc ro.llk.stack.timeout_ms , llkd sẽ giết quá trình (ngay cả khi có chuyển tiếp lập kế hoạch tiến độ). Nếu quá trình quét tiếp theo cho thấy quá trình tương tự vẫn tiếp tục tồn tại, llkd xác nhận điều kiện khóa trực tiếp và điều khiển hạt nhân theo cách cung cấp báo cáo lỗi chi tiết nhất cho điều kiện đó.

Kiểm tra lldk vẫn tiếp diễn liên tục khi điều kiện khóa trực tiếp tồn tại và tìm kiếm các chuỗi đã soạn " symbol+0x" hoặc " symbol.cfi+0x" trong tệp /proc/pid/stack trên Linux. Danh sách các ký hiệu nằm trong ro.llk.stack và mặc định là danh sách được phân tách bằng dấu phẩy của " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

Các ký hiệu phải đủ hiếm và tồn tại trong thời gian ngắn để trên một hệ thống điển hình, hàm chỉ được nhìn thấy một lần trong một mẫu trong khoảng thời gian chờ của ro.llk.stack.timeout_ms (các mẫu xảy ra mỗi ro.llk.check_ms ). Do thiếu bảo vệ ABA, đây là cách duy nhất để ngăn chặn kích hoạt sai. Hàm biểu tượng phải xuất hiện bên dưới hàm gọi khóa có thể cạnh tranh. Nếu ổ khóa nằm bên dưới hoặc trong chức năng biểu tượng, biểu tượng sẽ xuất hiện trong tất cả các quá trình bị ảnh hưởng, không chỉ quá trình gây ra khóa.

Phủ sóng

Việc triển khai mặc định của llkd không giám sát init , [kthreadd] hoặc [kthreadd] sinh ra. Để llkd bao gồm các chủ đề được tạo ra [kthreadd] :

  • Người lái xe không được ở trạng thái D liên tục,

HOẶC

  • Trình điều khiển phải có cơ chế để khôi phục luồng nếu nó bị giết bên ngoài. Ví dụ: sử dụng wait_event_interruptible() thay vì wait_event() .

Nếu một trong các điều kiện trên được đáp ứng, danh sách đen llkd có thể được điều chỉnh để bao gồm các thành phần hạt nhân. Kiểm tra ký hiệu ngăn xếp bao gồm một danh sách đen quy trình bổ sung để ngăn chặn các vi phạm riêng lẻ trên các dịch vụ chặn hoạt động ptrace .

Thuộc tính Android

llkd phản hồi với một số thuộc tính Android (được liệt kê bên dưới).

  • Thuộc tính có tên prop_ms tính bằng mili giây.
  • Các thuộc tính sử dụng dấu phân tách bằng dấu phẩy (,) cho danh sách sử dụng dấu phân tách hàng đầu để bảo toàn mục nhập mặc định, sau đó thêm hoặc trừ các mục nhập có tiền tố cộng (+) và dấu trừ (-) tùy chọn tương ứng. Đối với những danh sách này, chuỗi "false" đồng nghĩa với một danh sách trống và các mục nhập trống hoặc thiếu sử dụng giá trị mặc định được chỉ định.

ro.config.low_ram

Thiết bị được định cấu hình với bộ nhớ hạn chế.

ro.debuggable

Thiết bị được định cấu hình để gỡ lỗi người dùng hoặc bản dựng tương tác.

ro.llk.sysrq_t

Nếu thuộc tính là "eng", thì mặc định không phải là ro.config.low_ram hoặc ro.debuggable . Nếu đúng, hãy kết xuất tất cả các chủ đề ( sysrq t ).

ro.llk.enable

Cho phép bật trình nền khóa trực tiếp. Mặc định là sai.

llk.enable

Được đánh giá cho các bản dựng tương tác. Mặc định là ro.llk.enable .

ro.khungtask.enable

Cho phép bật trình nền [khungtask] . Mặc định là sai.

khungtask.enable

Được đánh giá cho các bản dựng tương tác. Mặc định là ro.khungtask.enable .

ro.llk.mlockall

Bật cuộc gọi đến mlockall() . Mặc định là sai.

ro.khungtask.timeout

[khungtask] giới hạn thời gian tối đa. Mặc định là 12 phút.

ro.llk.timeout_ms

D hoặc Z giới hạn thời gian tối đa. Mặc định là 10 phút. Nhân đôi giá trị này để đặt cơ quan giám sát cảnh báo cho llkd .

ro.llk.D.timeout_ms

D giới hạn thời gian tối đa. Mặc định là ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Z giới hạn thời gian tối đa. Mặc định là ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Kiểm tra giới hạn thời gian tối đa của các ký hiệu ngăn xếp liên tục. Mặc định là ro.llk.timeout_ms . Chỉ hoạt động trên bản dựng userdebug hoặc eng .

ro.llk.check_ms

Các mẫu chủ đề cho D hoặc Z. Mặc định là hai phút.

ro.llk.stack

Kiểm tra các ký hiệu ngăn xếp hạt nhân mà nếu liên tục xuất hiện có thể chỉ ra một hệ thống con bị khóa. Mặc định là cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable danh sách các ký hiệu hạt nhân được phân tách bằng dấu phẩy. Kiểm tra không thực hiện việc lập lịch chuyển tiếp ABA ngoại trừ bằng cách thăm dò mọi ro.llk_check_ms trong khoảng thời gian ro.llk.stack.timeout_ms , do đó, các biểu tượng ngăn xếp phải đặc biệt hiếm và thoáng qua (rất khó có khả năng một biểu tượng hiển thị liên tục trong tất cả mẫu của ngăn xếp). Kiểm tra sự trùng khớp cho " symbol+0x" hoặc " symbol.cfi+0x" trong mở rộng ngăn xếp. Chỉ có sẵn trên userdebug hoặc bản dựng eng ; lo ngại về bảo mật trên các bản dựng của người dùng dẫn đến các đặc quyền hạn chế ngăn cản việc kiểm tra này.

ro.llk.blacklist.process

llkd không xem các quá trình được chỉ định. Mặc định là 0,1,2 ( kernel , init[kthreadd] ) cộng với các tên tiến trình init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Một quy trình có thể là tham chiếu comm , cmdline hoặc pid . Giá trị mặc định tự động có thể lớn hơn kích thước thuộc tính tối đa hiện tại là 92.

ro.llk.blacklist.parent

llkd không theo dõi các tiến trình có (các) cha mẹ được chỉ định. Mặc định là 0,2,adbd&[setsid] ( kernel , [kthreadd]adbd chỉ dành cho setsid zombie). Dấu phân tách và (&) chỉ định rằng phần tử gốc chỉ bị bỏ qua khi kết hợp với quy trình con đích. Ký hiệu và được chọn vì nó không bao giờ là một phần của tên quy trình; tuy nhiên, một setprop trong shell yêu cầu ký hiệu và phải được thoát hoặc được trích dẫn, mặc dù tệp init rc nơi thường được chỉ định không có vấn đề này. Quy trình gốc hoặc quy trình đích có thể là tham chiếu comm , cmdline hoặc pid .

ro.llk.blacklist.uid

llkd không xem các quá trình khớp với (các) uid được chỉ định. Danh sách số hoặc tên được phân tách bằng dấu phẩy. Mặc định là trống hoặc sai.

ro.llk.blacklist.process.stack

llkd không giám sát tập hợp con quy trình được chỉ định cho chữ ký ngăn xếp khóa trực tiếp. Mặc định là các tên tiến trình init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Ngăn chặn vi phạm riêng biệt liên quan đến các quy trình chặn ptrace (vì không thể kiểm tra các quy trình này). Chỉ hoạt động trên bản dựng userdebug và eng . Để biết chi tiết về các loại bản dựng, hãy tham khảo Xây dựng Android .

Mối quan tâm về kiến ​​trúc

  • Thuộc tính được giới hạn trong 92 ký tự (tuy nhiên, điều này bị bỏ qua đối với các giá trị mặc định được xác định trong tệp include/llkd.h trong nguồn).
  • Daemon [khungtask] quá chung chung và chạy mã trình điều khiển ở trạng thái D. quá nhiều. Chuyển sang S sẽ làm cho (các) nhiệm vụ có thể giết được (và có thể phục hồi bởi trình điều khiển nếu cần).

Giao diện thư viện (tùy chọn)

Bạn có thể tùy chọn kết hợp llkd vào một daemon đặc quyền khác bằng cách sử dụng giao diện C sau từ thành phần libllkd :

#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void)   /* ms to sleep for next check */

Nếu tên luồng được cung cấp, một luồng sẽ tự động sinh ra, nếu không người gọi phải gọi llkCheckMilliseconds trong vòng lặp chính của nó. Hàm trả về khoảng thời gian trước cuộc gọi dự kiến ​​tiếp theo tới trình xử lý này.