Nhà cung cấp ban đầu

Quá trình init có các quyền gần như không bị hạn chế và sử dụng các tập lệnh đầu vào từ cả phân vùng hệ thống và nhà cung cấp để khởi tạo hệ thống trong quá trình khởi động. Quyền truy cập này gây ra một lỗ hổng lớn trong sự phân chia hệ thống/nhà cung cấp Treble, vì các tập lệnh của nhà cung cấp có thể hướng dẫn init truy cập các tệp, thuộc tính, v.v. không tạo thành một phần của giao diện nhị phân ứng dụng của nhà cung cấp hệ thống ổn định (ABI).

Nhà cung cấp init được thiết kế để đóng lỗ hổng này bằng cách sử dụng miền Linux (SELinux) được tăng cường bảo mật riêng biệt vendor_init để chạy các lệnh được tìm thấy trong /vendor với các quyền dành riêng cho nhà cung cấp.

Cơ chế

Nhà cung cấp init phân nhánh sớm một quy trình con của init trong quá trình khởi động với ngữ cảnh SELinux u:r:vendor_init:s0 . Ngữ cảnh SELinux này có ít quyền hơn đáng kể so với ngữ cảnh init mặc định và quyền truy cập của nó bị giới hạn ở các tệp, thuộc tính, v.v. dành riêng cho nhà cung cấp hoặc một phần của ABI của nhà cung cấp hệ thống ổn định.

Init kiểm tra từng tập lệnh mà nó tải để xem liệu đường dẫn của nó có bắt đầu bằng /vendor hay không và nếu có, hãy gắn thẻ cho nó bằng dấu hiệu cho biết các lệnh của nó phải được chạy trong ngữ cảnh init của nhà cung cấp. Mỗi nội dung init được chú thích bằng một boolean xác định xem lệnh có phải được chạy trong quy trình con init của nhà cung cấp hay không:

  • Hầu hết các lệnh truy cập vào hệ thống tệp đều được chú thích để chạy trong quy trình con init của nhà cung cấp và do đó phải tuân theo SEPolicy init của nhà cung cấp.
  • Hầu hết các lệnh tác động đến trạng thái init nội bộ (ví dụ: khởi động và dừng dịch vụ) đều được chạy trong quy trình init thông thường. Các lệnh này được biết rằng tập lệnh của nhà cung cấp đang yêu cầu chúng thực hiện việc xử lý các quyền không phải SELinux của riêng chúng.

Vòng xử lý chính của init chứa kiểm tra xem nếu một lệnh được chú thích để chạy trong quy trình con của nhà cung cấp và bắt nguồn từ tập lệnh của nhà cung cấp, thì lệnh đó sẽ được gửi qua giao tiếp giữa các quá trình (IPC) tới quy trình con init của nhà cung cấp, chạy lệnh và gửi kết quả trở lại init.

Sử dụng nhà cung cấp ban đầu

Init của nhà cung cấp được bật theo mặc định và các hạn chế của nó áp dụng cho tất cả các tập lệnh init có trong phân vùng /vendor . Nhà cung cấp init phải minh bạch đối với các nhà cung cấp có tập lệnh không chỉ truy cập vào các tệp, thuộc tính của hệ thống, v.v.

Tuy nhiên, nếu các lệnh trong tập lệnh của nhà cung cấp nhất định vi phạm các hạn chế khởi tạo của nhà cung cấp thì các lệnh đó sẽ không thành công. Các lệnh bị lỗi có một dòng trong nhật ký kernel (hiển thị bằng dmesg) từ init cho biết lỗi. Quá trình kiểm tra SELinux đi kèm với bất kỳ lệnh nào bị lỗi do chính sách SELinux. Ví dụ về lỗi bao gồm kiểm tra SELinux:

type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0
init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied

Nếu một lệnh không thành công, có hai lựa chọn:

  • Nếu lệnh không thành công do hạn chế dự kiến ​​(chẳng hạn như nếu lệnh đang truy cập vào tệp hệ thống hoặc thuộc tính), thì lệnh phải được triển khai lại theo cách thân thiện với Treble, chỉ đi qua các giao diện ổn định. Quy tắc Neverallow ngăn chặn việc thêm quyền truy cập vào các tệp hệ thống không thuộc ABI ổn định của nhà cung cấp hệ thống.
  • Nếu nhãn SELinux là mới và chưa được cấp quyền trong hệ thống vendor_init.te cũng như các quyền bị loại trừ thông qua quy tắc không bao giờ cho phép, thì nhãn mới có thể được cấp quyền trong vendor_init.te dành riêng cho thiết bị.

Đối với các thiết bị khởi chạy trước Android 9, các quy tắc không bao giờ cho phép có thể được bỏ qua bằng cách thêm thuộc tính loại data_between_core_and_vendor_violators vào tệp vendor_init.te dành riêng cho thiết bị.

Vị trí mã

Phần lớn logic cho IPC init của nhà cung cấp nằm trong system/core/init/subcontext.cpp .

Bảng lệnh nằm trong lớp BuiltinFunctionMap trong system/core/init/buildins.cpp và bao gồm các chú thích cho biết liệu lệnh có phải chạy trong quy trình con init của nhà cung cấp hay không.

SEPolicy cho init của nhà cung cấp được chia thành các thư mục riêng tư ( system/sepolicy/private/vendor_init.te ) và công khai ( system/sepolicy/public/vendor_init.te ) trong system/sepolicy.