Bài viết này mô tả cách Android xử lý các vấn đề về khả năng tương thích với chính sách của bản cập nhật qua mạng (OTA) nền tảng, trong đó chế độ cài đặt SELinux của nền tảng mới có thể khác với chế độ cài đặt SELinux của nhà cung cấp cũ.
Thiết kế chính sách SELinux dựa trên Treble xem xét sự khác biệt nhị phân giữa chính sách nền tảng và nhà cung cấp; giao thức này sẽ trở nên phức tạp hơn nếu các phân vùng của nhà cung cấp tạo ra các phần phụ thuộc, chẳng hạn như platform
< vendor
< oem
.
Trong Android 8.0 trở lên, chính sách chung của SELinux được chia thành các thành phần riêng tư và công khai. Thành phần công khai bao gồm chính sách và cơ sở hạ tầng liên quan, được đảm bảo có sẵn cho một phiên bản nền tảng. Chính sách này sẽ được hiển thị cho trình ghi chính sách của nhà cung cấp để cho phép nhà cung cấp tạo tệp chính sách của nhà cung cấp. Khi kết hợp với chính sách do nền tảng cung cấp, tệp này sẽ tạo ra một chính sách đầy đủ chức năng cho thiết bị.
- Để tạo phiên bản, chính sách công khai của nền tảng đã xuất sẽ được viết dưới dạng thuộc tính.
- Để dễ dàng viết chính sách, các loại đã xuất sẽ được chuyển đổi thành thuộc tính có phiên bản trong quá trình tạo chính sách. Các loại công khai cũng có thể được sử dụng trực tiếp trong các quyết định gắn nhãn do tệp ngữ cảnh của nhà cung cấp cung cấp.
Android duy trì mối liên kết giữa các loại cụ thể đã xuất trong chính sách nền tảng và các thuộc tính có phiên bản tương ứng cho từng phiên bản nền tảng. Điều này đảm bảo rằng khi các đối tượng được gắn nhãn bằng một loại, đối tượng đó sẽ không vi phạm hành vi được đảm bảo theo chính sách công khai của nền tảng trong phiên bản trước. Việc liên kết này được duy trì bằng cách cập nhật tệp liên kết cho mỗi phiên bản nền tảng. Tệp này lưu giữ thông tin về thành viên thuộc tính cho mỗi loại được xuất trong chính sách công khai.
Quyền sở hữu và gắn nhãn đối tượng
Khi tuỳ chỉnh chính sách trong Android 8.0 trở lên, bạn phải xác định rõ quyền sở hữu cho từng đối tượng để tách biệt chính sách của nền tảng và nhà cung cấp. Ví dụ: nếu nhà cung cấp gắn nhãn /dev/foo
và nền tảng sau đó gắn nhãn /dev/foo
trong một OTA tiếp theo, thì sẽ có hành vi không xác định. Đối với
SELinux, điều này thể hiện dưới dạng xung đột gắn nhãn. Nút thiết bị chỉ có thể có một nhãn duy nhất phân giải đến nhãn được áp dụng gần đây nhất. Kết quả là:
- Các quy trình cần quyền truy cập vào nhãn đã áp dụng không thành công sẽ mất quyền truy cập vào tài nguyên.
- Các quy trình có quyền truy cập vào tệp có thể bị lỗi do tạo sai nút thiết bị.
Các thuộc tính hệ thống cũng có khả năng xảy ra xung đột tên, điều này có thể dẫn đến hành vi không xác định trên hệ thống (cũng như đối với việc gắn nhãn SELinux). Sự xung đột giữa nhãn nền tảng và nhãn nhà cung cấp có thể xảy ra với bất kỳ đối tượng nào có nhãn SELinux, bao gồm cả các thuộc tính, dịch vụ, quy trình, tệp và ổ cắm. Để tránh những vấn đề này, hãy xác định rõ quyền sở hữu đối với các đối tượng này.
Ngoài xung đột nhãn, tên loại/thuộc tính SELinux cũng có thể xung đột. Việc xung đột tên loại/thuộc tính sẽ luôn dẫn đến lỗi trình biên dịch chính sách.
Không gian tên loại/thuộc tính
SELinux không cho phép nhiều nội dung khai báo cùng một loại/thuộc tính. Chính sách có nội dung khai báo trùng lặp sẽ không biên dịch được. Để tránh xung đột tên loại và thuộc tính, tất cả các nội dung khai báo của nhà cung cấp phải được đặt tên không gian bắt đầu bằng vendor_
.
type foo, domain; → type vendor_foo, domain;
Quyền sở hữu thuộc tính hệ thống và nhãn quy trình
Cách tốt nhất để tránh xung đột nhãn là sử dụng không gian tên thuộc tính. Để dễ dàng xác định các thuộc tính nền tảng và tránh xung đột tên khi đổi tên hoặc thêm các thuộc tính nền tảng đã xuất, hãy đảm bảo tất cả các thuộc tính của nhà cung cấp đều có tiền tố riêng:
Loại tài sản | Tiền tố được chấp nhận |
---|---|
thuộc tính điều khiển | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor.
|
read-writable | vendor. |
chỉ có thể đọc | ro.vendor. ro.boot. ro.hardware.
|
liên tục | persist.vendor. |
Nhà cung cấp có thể tiếp tục sử dụng ro.boot.*
(có trong cmdline hạt nhân) và ro.hardware.*
(một thuộc tính rõ ràng liên quan đến phần cứng).
Tất cả dịch vụ của nhà cung cấp trong tệp init rc phải có vendor.
cho các dịch vụ trong tệp init rc của các phân vùng không phải hệ thống. Các quy tắc tương tự cũng được áp dụng cho nhãn SELinux cho các thuộc tính của nhà cung cấp (vendor_
cho các thuộc tính của nhà cung cấp).
Quyền sở hữu tệp
Việc ngăn chặn xung đột tệp là một thách thức vì chính sách của nền tảng và nhà cung cấp thường cung cấp nhãn cho tất cả hệ thống tệp. Không giống như việc đặt tên loại, việc đặt tên không gian cho tệp không thực tế vì nhiều tệp trong số đó do hạt nhân tạo ra. Để ngăn chặn các xung đột này, hãy làm theo hướng dẫn đặt tên cho hệ thống tệp trong phần này. Đối với Android 8.0, đây là các đề xuất không có biện pháp thực thi kỹ thuật. Trong tương lai, các đề xuất này sẽ được Bộ kiểm thử nhà cung cấp (VTS) thực thi.
Hệ thống (/system)
Chỉ hình ảnh hệ thống mới phải cung cấp nhãn cho các thành phần /system
thông qua file_contexts
, service_contexts
, v.v. Nếu nhãn cho các thành phần /system
được thêm vào chính sách /vendor
, thì bạn có thể không cập nhật được OTA chỉ dành cho khung.
Nhà cung cấp (/vendor)
Chính sách SELinux của AOSP đã gắn nhãn các phần của phân vùng vendor
mà nền tảng tương tác, cho phép ghi các quy tắc SELinux để các quy trình nền tảng có thể giao tiếp và/hoặc truy cập vào các phần của phân vùng vendor
. Ví dụ:
Đường dẫn /vendor |
Nhãn do nền tảng cung cấp | Quy trình của nền tảng tuỳ thuộc vào nhãn |
---|---|---|
/vendor(/.*)?
|
vendor_file
|
Tất cả ứng dụng HAL trong khung, ueventd , v.v.
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat , appdomain , v.v.
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat , installd , idmap , v.v.
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server , zygote , idmap , v.v.
|
Do đó, bạn phải tuân thủ các quy tắc cụ thể (được thực thi thông qua neverallows
) khi gắn nhãn các tệp bổ sung trong phân vùng vendor
:
vendor_file
phải là nhãn mặc định cho tất cả tệp trong phân vùngvendor
. Chính sách nền tảng yêu cầu điều này để truy cập vào các phương thức triển khai HAL truyền qua.- Tất cả
exec_types
mới được thêm vào phân vùngvendor
thông qua SEPolicy của nhà cung cấp phải có thuộc tínhvendor_file_type
. Điều này được thực thi thông qua neverallows. - Để tránh xung đột với các bản cập nhật nền tảng/khung trong tương lai, hãy tránh gắn nhãn các tệp khác ngoài
exec_types
trong phân vùngvendor
. - Tất cả phần phụ thuộc thư viện cho các HAL cùng quy trình do AOSP xác định phải được gắn nhãn là
same_process_hal_file.
Procfs (/proc)
Bạn chỉ có thể gắn nhãn cho các tệp trong /proc
bằng nhãn genfscon
. Trong Android 7.0, cả chính sách nền tảng và nhà cung cấp đều sử dụng genfscon
để gắn nhãn tệp trong procfs
.
Đề xuất: Chỉ sử dụng nhãn chính sách nền tảng /proc
.
Nếu các quy trình vendor
cần quyền truy cập vào các tệp trong /proc
hiện được gắn nhãn bằng nhãn mặc định (proc
), thì chính sách của nhà cung cấp
không nên gắn nhãn rõ ràng cho các tệp đó mà thay vào đó nên sử dụng loại
proc
chung để thêm quy tắc cho các miền của nhà cung cấp. Điều này cho phép các bản cập nhật nền tảng thích ứng với các giao diện nhân trong tương lai được hiển thị thông qua procfs
và gắn nhãn rõ ràng cho các giao diện đó nếu cần.
Debugfs (/sys/kernel/debug)
Bạn có thể gắn nhãn Debugfs
trong cả file_contexts
và genfscon
. Trong Android 7.0 đến Android 10, cả nền tảng và nhãn nhà cung cấp đều là debugfs
.
Trong Android 11, bạn không thể truy cập hoặc gắn debugfs
trên các thiết bị sản xuất. Nhà sản xuất thiết bị nên xoá debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Bạn có thể gắn nhãn Tracefs
trong cả file_contexts
và genfscon
. Trong Android 7.0, chỉ có nhãn nền tảng tracefs
.
Đề xuất: Chỉ nền tảng mới có thể gắn nhãn tracefs
.
Sysfs (/sys)
Bạn có thể gắn nhãn cho các tệp trong /sys
bằng cả file_contexts
và genfscon
. Trong Android 7.0, cả nền tảng và nhà cung cấp đều sử dụng genfscon
để gắn nhãn tệp trong sysfs
.
Đề xuất: Nền tảng có thể gắn nhãn các nút sysfs
không dành riêng cho thiết bị. Nếu không, chỉ nhà cung cấp mới có thể gắn nhãn tệp.
tmpfs (/dev)
Các tệp trong /dev
có thể được gắn nhãn trong file_contexts
. Trong Android 7.0, cả tệp nhãn nền tảng và nhà cung cấp đều có tại đây.
Đề xuất: Nhà cung cấp chỉ có thể gắn nhãn cho các tệp trong /dev/vendor
(ví dụ: /dev/vendor/foo
, /dev/vendor/socket/bar
).
Rootfs (/)
Các tệp trong /
có thể được gắn nhãn trong file_contexts
. Trong Android 7.0, cả tệp nhãn nền tảng và nhà cung cấp đều ở đây.
Đề xuất: Chỉ hệ thống mới có thể gắn nhãn tệp trong /
.
Dữ liệu (/data)
Dữ liệu được gắn nhãn thông qua tổ hợp file_contexts
và seapp_contexts
.
Đề xuất: Không cho phép gắn nhãn nhà cung cấp bên ngoài /data/vendor
. Chỉ nền tảng mới có thể gắn nhãn cho các phần khác của /data
.
Phiên bản nhãn Genfs
Kể từ cấp độ API của nhà cung cấp 202504, các nhãn SELinux mới hơn được gán bằng genfscon
trong system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil
là không bắt buộc đối với các phân vùng nhà cung cấp cũ. Điều này cho phép các phân vùng của nhà cung cấp cũ giữ nguyên cách triển khai SEPolicy hiện có. Việc này do biến Makefile BOARD_GENFS_LABELS_VERSION
kiểm soát và được lưu trữ trong /vendor/etc/selinux/genfs_labels_version.txt
.
Ví dụ:
-
Trong API cấp nhà cung cấp 202404, theo mặc định, nút
/sys/class/udc
được gắn nhãn làsysfs
. -
Kể từ API cấp nhà cung cấp 202504,
/sys/class/udc
được gắn nhãn làsysfs_udc
.
Tuy nhiên, /sys/class/udc
có thể đang được các phân vùng của nhà cung cấp sử dụng bằng API cấp 202404, với nhãn sysfs
mặc định hoặc nhãn dành riêng cho nhà cung cấp. Việc gắn nhãn /sys/class/udc
là sysfs_udc
một cách vô điều kiện có thể làm hỏng khả năng tương thích với các phân vùng của nhà cung cấp này. Bằng cách đánh dấu BOARD_GENFS_LABELS_VERSION
, nền tảng sẽ tiếp tục sử dụng các nhãn và quyền trước đó cho các phân vùng nhà cung cấp cũ.
BOARD_GENFS_LABELS_VERSION
có thể lớn hơn hoặc bằng cấp độ API của nhà cung cấp. Ví dụ: các phân vùng của nhà cung cấp sử dụng API cấp 202404 có thể đặt BOARD_GENFS_LABELS_VERSION
thành 202504 để sử dụng các nhãn mới được giới thiệu trong 202504. Xem danh sách
nhãn genfs dành riêng cho 202504.
Khi gắn nhãn nút genfscon
, nền tảng phải xem xét các phân vùng nhà cung cấp cũ và triển khai cơ chế dự phòng để đảm bảo khả năng tương thích khi cần. Nền tảng có thể sử dụng các thư viện chỉ dành cho nền tảng để truy vấn phiên bản nhãn genfs.
-
Trên mã gốc, hãy sử dụng
libgenfslabelsversion
. Hãy xemgenfslabelsversion.h
để biết tệp tiêu đề củalibgenfslabelsversion
. -
Trên Java, hãy sử dụng
android.os.SELinux.getGenfsLabelsVersion()
.
Thuộc tính tương thích
Chính sách SELinux là sự tương tác giữa các loại nguồn và đích đến cho các lớp đối tượng và quyền cụ thể. Mọi đối tượng (quy trình, tệp, v.v.) chịu ảnh hưởng của chính sách SELinux chỉ có thể có một loại, nhưng loại đó có thể có nhiều thuộc tính.
Chính sách chủ yếu được viết theo các loại hiện có:
allow source_type target_type:target_class permission(s);
Điều này có hiệu quả vì chính sách được viết dựa trên kiến thức về tất cả các loại nội dung. Tuy nhiên, nếu chính sách của nhà cung cấp và chính sách của nền tảng sử dụng các loại cụ thể và nhãn của một đối tượng cụ thể chỉ thay đổi trong một trong các chính sách đó, thì chính sách còn lại có thể chứa chính sách đã có hoặc mất quyền truy cập trước đó. Ví dụ:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Có thể thay đổi thành:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Mặc dù chính sách của nhà cung cấp sẽ giữ nguyên, nhưng v_domain
sẽ mất quyền truy cập do thiếu chính sách cho loại sysfs_A
mới.
Bằng cách xác định chính sách theo các thuộc tính, chúng ta có thể cung cấp cho đối tượng cơ bản một loại có thuộc tính tương ứng với chính sách cho cả nền tảng và mã của nhà cung cấp. Bạn có thể thực hiện việc này cho tất cả các loại để tạo một chính sách thuộc tính hiệu quả, trong đó các loại cụ thể không bao giờ được sử dụng. Trong thực tế, điều này chỉ bắt buộc đối với các phần chính sách trùng lặp giữa nền tảng và nhà cung cấp. Các phần này được xác định và cung cấp dưới dạng chính sách công khai của nền tảng được xây dựng như một phần của chính sách nhà cung cấp.
Việc xác định chính sách công khai dưới dạng thuộc tính có phiên bản đáp ứng hai mục tiêu về khả năng tương thích với chính sách:
- Đảm bảo mã của nhà cung cấp tiếp tục hoạt động sau khi cập nhật nền tảng. Được thực hiện bằng cách thêm thuộc tính vào các loại cụ thể cho các đối tượng tương ứng với các thuộc tính mà mã của nhà cung cấp dựa vào, đồng thời duy trì quyền truy cập.
- Khả năng ngừng sử dụng chính sách. Điều này được thực hiện bằng cách phân định rõ ràng các nhóm chính sách thành các thuộc tính có thể bị xoá ngay khi phiên bản tương ứng không còn được hỗ trợ. Bạn có thể tiếp tục phát triển trong nền tảng này, vì biết rằng chính sách cũ vẫn có trong chính sách của nhà cung cấp và sẽ tự động bị xoá khi/nếu chính sách đó được nâng cấp.
Khả năng ghi chính sách
Để đạt được mục tiêu không yêu cầu kiến thức về các thay đổi cụ thể đối với phiên bản để phát triển chính sách, Android 8.0 bao gồm mối liên kết giữa các loại chính sách công khai của nền tảng và các thuộc tính của các loại chính sách đó. Loại foo
được liên kết với thuộc tính foo_vN
, trong đó N
là phiên bản được nhắm đến. vN
tương ứng với biến bản dựng PLATFORM_SEPOLICY_VERSION
và có dạng MM.NN
, trong đó MM
tương ứng với số SDK nền tảng và NN
là phiên bản cụ thể của chính sách bảo mật nền tảng.
Các thuộc tính trong chính sách công khai không được tạo phiên bản, mà tồn tại dưới dạng API mà nền tảng và chính sách của nhà cung cấp có thể xây dựng để giữ cho giao diện giữa hai phân vùng ổn định. Cả người viết chính sách của nền tảng và nhà cung cấp đều có thể tiếp tục viết chính sách như hiện tại.
Chính sách công khai của nền tảng được xuất dưới dạng allow source_foo target_bar:class
perm;
được đưa vào chính sách của nhà cung cấp. Trong quá trình biên dịch (bao gồm cả phiên bản tương ứng), tệp này được chuyển đổi thành chính sách sẽ chuyển đến phần nhà cung cấp của thiết bị (hiển thị trong Ngôn ngữ trung gian phổ biến (CIL) đã chuyển đổi):
(allow source_foo_vN target_bar_vN (class (perm)))
Vì chính sách của nhà cung cấp không bao giờ đi trước nền tảng, nên bạn không nên quan tâm đến các phiên bản trước đó. Tuy nhiên, chính sách nền tảng sẽ cần biết chính sách của nhà cung cấp có hiệu lực từ khi nào, bao gồm các thuộc tính cho loại của chính sách đó và đặt chính sách tương ứng với các thuộc tính có phiên bản.
Sự khác biệt về chính sách
Việc tự động tạo thuộc tính bằng cách thêm _vN
vào cuối mỗi loại sẽ không có tác dụng nếu không liên kết các thuộc tính với các loại trên các điểm khác biệt về phiên bản. Android duy trì mối liên kết giữa các phiên bản cho các thuộc tính và mối liên kết của các loại với các thuộc tính đó. Việc này được thực hiện trong các tệp ánh xạ nêu trên bằng các câu lệnh, chẳng hạn như (CIL):
(typeattributeset foo_vN (foo))
Nâng cấp nền tảng
Phần sau đây trình bày chi tiết các trường hợp nâng cấp nền tảng.
Cùng loại
Tình huống này xảy ra khi một đối tượng không thay đổi nhãn trong các phiên bản chính sách.
Điều này cũng tương tự đối với các loại nguồn và mục tiêu và có thể được thấy với /dev/binder
, được gắn nhãn binder_device
trên tất cả các bản phát hành. Giá trị này được biểu thị trong chính sách đã chuyển đổi như sau:
binder_device_v1 … binder_device_vN
Khi nâng cấp từ v1
→ v2
, chính sách nền tảng phải chứa:
type binder_device; -> (type binder_device) (in CIL)
Trong tệp ánh xạ v1 (CIL):
(typeattributeset binder_device_v1 (binder_device))
Trong tệp ánh xạ v2 (CIL):
(typeattributeset binder_device_v2 (binder_device))
Trong chính sách dành cho nhà cung cấp phiên bản 1 (CIL):
(typeattribute binder_device_v1) (allow binder_device_v1 …)
Trong chính sách dành cho nhà cung cấp phiên bản 2 (CIL):
(typeattribute binder_device_v2) (allow binder_device_v2 …)
Loại mới
Tình huống này xảy ra khi nền tảng đã thêm một loại mới. Điều này có thể xảy ra khi thêm các tính năng mới hoặc trong quá trình tăng cường chính sách.
- Tính năng mới. Khi loại đang gắn nhãn cho một đối tượng trước đây không tồn tại (chẳng hạn như quy trình dịch vụ mới), mã của nhà cung cấp trước đây không tương tác trực tiếp với đối tượng đó nên không có chính sách tương ứng nào. Thuộc tính mới tương ứng với loại không có thuộc tính trong phiên bản trước, do đó, sẽ không cần mục nhập trong tệp ánh xạ nhắm đến phiên bản đó.
- Căng thẳng chính sách. Khi loại này thể hiện việc tăng cường chính sách, thuộc tính loại mới phải liên kết lại với một chuỗi thuộc tính tương ứng với thuộc tính trước đó (tương tự như ví dụ trước về việc thay đổi
/sys/A
từsysfs
thànhsysfs_A
). Mã nhà cung cấp dựa vào một quy tắc cho phép truy cập vàosysfs
và cần đưa quy tắc đó vào làm thuộc tính của loại mới.
Khi nâng cấp từ v1
→ v2
, chính sách nền tảng phải chứa:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
Trong tệp ánh xạ v1 (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
Trong tệp ánh xạ v2 (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
Trong chính sách dành cho nhà cung cấp phiên bản 1 (CIL):
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Trong chính sách dành cho nhà cung cấp phiên bản 2 (CIL):
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Các loại đã xoá
Tình huống (hiếm gặp) này xảy ra khi một loại bị xoá, điều này có thể xảy ra khi đối tượng cơ bản:
- Vẫn tồn tại nhưng có nhãn khác.
- Bị nền tảng gỡ bỏ.
Trong quá trình nới lỏng chính sách, một loại sẽ bị xoá và đối tượng được gắn nhãn bằng loại đó sẽ được gắn một nhãn khác, đã tồn tại. Đây là quá trình hợp nhất các ánh xạ thuộc tính: Mã của nhà cung cấp vẫn phải có thể truy cập vào đối tượng cơ bản theo thuộc tính mà mã đó từng sở hữu, nhưng phần còn lại của hệ thống hiện phải có thể truy cập vào đối tượng đó bằng thuộc tính mới.
Nếu thuộc tính được chuyển sang là thuộc tính mới, thì việc gắn nhãn lại sẽ giống như trong trường hợp loại mới, ngoại trừ việc khi sử dụng nhãn hiện có, việc thêm loại thuộc tính cũ sẽ khiến các đối tượng khác cũng được gắn nhãn bằng loại này mới có thể truy cập được. Về cơ bản, đây là những gì nền tảng thực hiện và được coi là một sự đánh đổi chấp nhận được để duy trì khả năng tương thích.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Ví dụ về Phiên bản 1: Rút gọn các loại (xoá sysfs_A)
Khi nâng cấp từ v1
→ v2
, chính sách nền tảng phải chứa:
type sysfs; (type sysfs) (in CIL)
Trong tệp ánh xạ v1 (CIL):
(typeattributeset sysfs_v1 (sysfs)) (type sysfs_A) # in case vendors used the sysfs_A label on objects (typeattributeset sysfs_A_v1 (sysfs sysfs_A))
Trong tệp ánh xạ v2 (CIL):
(typeattributeset sysfs_v2 (sysfs))
Trong chính sách dành cho nhà cung cấp phiên bản 1 (CIL):
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
Trong chính sách dành cho nhà cung cấp phiên bản 2 (CIL):
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Ví dụ Phiên bản 2: Xoá hoàn toàn (loại foo)
Khi nâng cấp từ v1
→ v2
, chính sách nền tảng phải chứa:
# nothing - we got rid of the type
Trong tệp ánh xạ v1 (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
Trong tệp ánh xạ v2 (CIL):
# nothing - get rid of it
Trong chính sách dành cho nhà cung cấp phiên bản 1 (CIL):
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
Trong chính sách dành cho nhà cung cấp phiên bản 2 (CIL):
(typeattribute sysfs_v2) (allow sysfs_v2 …)
Lớp/quyền mới
Tình huống này xảy ra khi bản nâng cấp nền tảng giới thiệu các thành phần chính sách mới không có trong các phiên bản trước. Ví dụ: khi Android thêm trình quản lý đối tượng servicemanager
tạo các quyền thêm, tìm và liệt kê, các trình nền của nhà cung cấp muốn đăng ký bằng servicemanager
cần có các quyền không có sẵn. Trong Android 8.0, chỉ chính sách nền tảng mới có thể thêm các lớp và quyền mới.
Để cho phép tất cả các miền có thể được tạo hoặc mở rộng theo chính sách của nhà cung cấp sử dụng lớp mới mà không bị cản trở, chính sách nền tảng cần bao gồm một quy tắc tương tự như:
allow {domain -coredomain} *:new_class perm;
Thậm chí, bạn có thể phải đưa ra chính sách cho phép truy cập vào tất cả các loại giao diện (chính sách công khai) để đảm bảo hình ảnh của nhà cung cấp có quyền truy cập. Nếu điều này dẫn đến chính sách bảo mật không được chấp nhận (như có thể xảy ra với các thay đổi đối với trình quản lý dịch vụ), thì có thể bạn sẽ phải buộc nâng cấp nhà cung cấp.
Xoá lớp/quyền
Tình huống này xảy ra khi một trình quản lý đối tượng bị xoá (chẳng hạn như trình quản lý đối tượng ZygoteConnection
) và không gây ra vấn đề. Lớp trình quản lý đối tượng và các quyền có thể vẫn được xác định trong chính sách cho đến khi phiên bản nhà cung cấp không còn sử dụng lớp đó nữa. Việc này được thực hiện bằng cách thêm các định nghĩa vào tệp ánh xạ tương ứng.
Tuỳ chỉnh nhà cung cấp cho các loại mới/được gắn nhãn lại
Các loại nhà cung cấp mới là cốt lõi của việc phát triển chính sách nhà cung cấp vì chúng cần thiết để mô tả các quy trình, tệp nhị phân, thiết bị, hệ thống con và dữ liệu được lưu trữ mới. Do đó, bạn phải cho phép tạo các loại do nhà cung cấp xác định.
Vì chính sách của nhà cung cấp luôn là chính sách cũ nhất trên thiết bị, nên bạn không cần tự động chuyển đổi tất cả các loại nhà cung cấp thành thuộc tính trong chính sách. Nền tảng không dựa vào bất kỳ nội dung nào được gắn nhãn trong chính sách của nhà cung cấp vì nền tảng không có kiến thức về nội dung đó; tuy nhiên, nền tảng sẽ cung cấp các thuộc tính và loại công khai mà nền tảng sử dụng để tương tác với các đối tượng được gắn nhãn bằng các loại này (chẳng hạn như domain
, sysfs_type
, v.v.). Để nền tảng tiếp tục tương tác chính xác với các đối tượng này, bạn phải áp dụng các thuộc tính và loại một cách thích hợp, đồng thời có thể cần thêm các quy tắc cụ thể vào các miền có thể tuỳ chỉnh (chẳng hạn như init
).
Thay đổi về thuộc tính cho Android 9
Các thiết bị nâng cấp lên Android 9 có thể sử dụng các thuộc tính sau, nhưng các thiết bị chạy Android 9 không được sử dụng.
Thuộc tính của lỗi vi phạm
Android 9 bao gồm các thuộc tính liên quan đến miền sau:
data_between_core_and_vendor_violators
. Thuộc tính cho tất cả các miền vi phạm yêu cầu không chia sẻ tệp theo đường dẫn giữavendor
vàcoredomains
. Các quy trình của nền tảng và nhà cung cấp không được sử dụng tệp trên ổ đĩa để giao tiếp (ABI không ổn định). Đề xuất:- Mã nhà cung cấp phải sử dụng
/data/vendor
. - Hệ thống không được sử dụng
/data/vendor
.
- Mã nhà cung cấp phải sử dụng
system_executes_vendor_violators
. Thuộc tính cho tất cả các miền hệ thống (ngoại trừinit
vàshell domains
) vi phạm yêu cầu không thực thi tệp nhị phân của nhà cung cấp. Việc thực thi tệp nhị phân của nhà cung cấp có API không ổn định. Nền tảng không được thực thi trực tiếp tệp nhị phân của nhà cung cấp. Đề xuất:- Các phần phụ thuộc nền tảng như vậy trên tệp nhị phân của nhà cung cấp phải nằm sau các HAL HIDL.
HOẶC
coredomains
cần quyền truy cập vào tệp nhị phân của nhà cung cấp nên được chuyển sang phân vùng của nhà cung cấp và do đó, không còn làcoredomain
nữa.
- Các phần phụ thuộc nền tảng như vậy trên tệp nhị phân của nhà cung cấp phải nằm sau các HAL HIDL.
Thuộc tính không đáng tin cậy
Các ứng dụng không đáng tin cậy lưu trữ mã tuỳ ý không được có quyền truy cập vào các dịch vụ HwBinder, ngoại trừ những dịch vụ được coi là đủ an toàn để truy cập từ các ứng dụng như vậy (xem các dịch vụ an toàn bên dưới). Có hai lý do chính dẫn đến việc này:
- Máy chủ HwBinder không thực hiện xác thực ứng dụng vì HIDL hiện không hiển thị thông tin UID của phương thức gọi. Ngay cả khi HIDL hiển thị dữ liệu như vậy, nhiều dịch vụ HwBinder hoạt động ở cấp thấp hơn ứng dụng (chẳng hạn như HAL) hoặc không được dựa vào danh tính ứng dụng để uỷ quyền. Do đó, để đảm bảo an toàn, giả định mặc định là mọi dịch vụ HwBinder đều coi tất cả ứng dụng khách của mình là được uỷ quyền như nhau để thực hiện các thao tác do dịch vụ cung cấp.
- Máy chủ HAL (một tập hợp con của các dịch vụ HwBinder) chứa mã có tỷ lệ sự cố bảo mật cao hơn so với các thành phần
system/core
và có quyền truy cập vào các lớp thấp hơn của ngăn xếp (tất cả các lớp xuống phần cứng), do đó tăng cơ hội bỏ qua mô hình bảo mật Android.
Dịch vụ an toàn
Các dịch vụ an toàn bao gồm:
same_process_hwservice
. Theo định nghĩa, các dịch vụ này chạy trong quy trình của ứng dụng và do đó có quyền truy cập giống như miền ứng dụng nơi quy trình chạy.coredomain_hwservice
. Các dịch vụ này không gây ra rủi ro liên quan đến lý do #2.hal_configstore_ISurfaceFlingerConfigs
. Dịch vụ này được thiết kế dành riêng cho mọi miền.hal_graphics_allocator_hwservice
. Các thao tác này cũng được cung cấp bởi dịch vụ Liên kếtsurfaceflinger
, các ứng dụng được phép truy cập.hal_omx_hwservice
. Đây là phiên bản HwBinder của dịch vụ Bindermediacodec
mà các ứng dụng được phép truy cập.hal_codec2_hwservice
. Đây là phiên bản mới hơn củahal_omx_hwservice
.
Thuộc tính có thể sử dụng
Tất cả hwservices
không được coi là an toàn đều có thuộc tính untrusted_app_visible_hwservice
. Các máy chủ HAL tương ứng có thuộc tính untrusted_app_visible_halserver
. Các thiết bị chạy Android 9 KHÔNG ĐƯỢC sử dụng thuộc tính untrusted
.
Việc nên làm:
- Thay vào đó, các ứng dụng không đáng tin cậy nên giao tiếp với một dịch vụ hệ thống giao tiếp với HIDL HAL của nhà cung cấp. Ví dụ: các ứng dụng có thể giao tiếp với
binderservicedomain
, sau đómediaserver
(là mộtbinderservicedomain
) sẽ giao tiếp vớihal_graphics_allocator
.HOẶC
- Các ứng dụng cần quyền truy cập trực tiếp vào HAL
vendor
phải có miền chính sách bảo mật do nhà cung cấp xác định riêng.
Kiểm thử thuộc tính tệp
Android 9 bao gồm các kiểm thử thời gian xây dựng để đảm bảo tất cả tệp ở các vị trí cụ thể đều có các thuộc tính thích hợp (chẳng hạn như tất cả tệp trong sysfs
đều có thuộc tính sysfs_type
bắt buộc).
Chính sách công của nền tảng
Chính sách công khai của nền tảng là cốt lõi của việc tuân thủ mô hình kiến trúc Android 8.0 mà không chỉ duy trì sự hợp nhất của các chính sách nền tảng từ phiên bản 1 và 2. Nhà cung cấp sẽ thấy một tập hợp con của chính sách nền tảng chứa các loại và thuộc tính có thể sử dụng cũng như các quy tắc về các loại và thuộc tính đó. Sau đó, các loại và thuộc tính này sẽ trở thành một phần của chính sách nhà cung cấp (tức là vendor_sepolicy.cil
).
Các loại và quy tắc được tự động dịch trong chính sách do nhà cung cấp tạo thành attribute_vN
sao cho tất cả các loại do nền tảng cung cấp đều là thuộc tính có phiên bản (tuy nhiên, các thuộc tính không có phiên bản). Nền tảng này chịu trách nhiệm ánh xạ các loại cụ thể mà nền tảng cung cấp vào các thuộc tính thích hợp để đảm bảo chính sách của nhà cung cấp tiếp tục hoạt động và các quy tắc được cung cấp cho một phiên bản cụ thể được đưa vào. Việc kết hợp chính sách công khai của nền tảng và chính sách của nhà cung cấp đáp ứng mục tiêu của mô hình cấu trúc Android 8.0 là cho phép các bản dựng nền tảng và nhà cung cấp độc lập.
Liên kết đến chuỗi thuộc tính
Khi sử dụng thuộc tính để liên kết với các phiên bản chính sách, một loại sẽ liên kết với một hoặc nhiều thuộc tính, đảm bảo rằng bạn có thể truy cập vào các đối tượng được gắn nhãn bằng loại đó thông qua các thuộc tính tương ứng với các loại trước đó.
Việc duy trì mục tiêu ẩn thông tin phiên bản khỏi trình ghi chính sách có nghĩa là tự động tạo các thuộc tính có phiên bản và chỉ định các thuộc tính đó cho các loại thích hợp. Trong trường hợp phổ biến của các loại tĩnh, việc này rất đơn giản: type_foo
liên kết với type_foo_v1
.
Đối với thay đổi nhãn đối tượng như sysfs
→ sysfs_A
hoặc mediaserver
→ audioserver
, việc tạo mối liên kết này không hề đơn giản (và được mô tả trong các ví dụ ở trên). Người duy trì chính sách nền tảng phải xác định cách tạo mối liên kết tại các điểm chuyển đổi cho đối tượng. Để làm được điều này, bạn cần hiểu mối quan hệ giữa các đối tượng và nhãn được chỉ định cho các đối tượng đó, đồng thời xác định thời điểm mối liên kết này xảy ra. Để có khả năng tương thích ngược, bạn cần quản lý độ phức tạp này ở phía nền tảng. Đây là phân vùng duy nhất có thể nâng cấp.
Bản cập nhật phiên bản
Để đơn giản hoá, nền tảng Android sẽ phát hành phiên bản sepolicy khi một nhánh phát hành mới được cắt. Như mô tả ở trên, số phiên bản nằm trong PLATFORM_SEPOLICY_VERSION
và có dạng MM.nn
, trong đó MM
tương ứng với giá trị SDK và nn
là một giá trị riêng tư được duy trì trong /platform/system/sepolicy.
. Ví dụ: 19.0
cho Kitkat, 21.0
cho Lollipop, 22.0
cho Lollipop-MR1 23.0
cho Marshmallow, 24.0
cho Nougat, 25.0
cho Nougat-MR1, 26.0
cho Oreo, 27.0
cho Oreo-MR1 và 28.0
cho Android 9.
Uprev không phải lúc nào cũng là số nguyên. Ví dụ: nếu một bản sửa lỗi MR cho một phiên bản cần có thay đổi không tương thích trong system/sepolicy/public
nhưng không cần có thay đổi API, thì phiên bản chính sách bảo mật đó có thể là: vN.1
. Phiên bản có trong nhánh phát triển là 10000.0
không bao giờ được sử dụng trong thiết bị vận chuyển.
Android có thể ngừng sử dụng phiên bản cũ nhất khi nâng cấp. Để biết thời điểm ngừng sử dụng một phiên bản, Android có thể thu thập số lượng thiết bị có chính sách của nhà cung cấp chạy phiên bản Android đó và vẫn nhận được các bản cập nhật lớn của nền tảng. Nếu con số này thấp hơn một ngưỡng nhất định, thì phiên bản đó sẽ không được dùng nữa.
Tác động của nhiều thuộc tính đối với hiệu suất
Như mô tả trong https://github.com/SELinuxProject/cil/issues/9, số lượng lớn các thuộc tính được chỉ định cho một loại sẽ dẫn đến các vấn đề về hiệu suất trong trường hợp thiếu bộ nhớ đệm chính sách.
Đây được xác nhận là vấn đề trong Android, vì vậy, các thay đổi đã được thực hiện đối với Android 8.0 để xoá các thuộc tính do trình biên dịch chính sách thêm vào chính sách, cũng như xoá các thuộc tính không dùng đến. Những thay đổi này đã giải quyết các vấn đề hồi quy về hiệu suất.
chính sách công về sản phẩm và chính sách công về system_ext
Kể từ Android 11, các phân vùng system_ext
và product
được phép xuất các loại công khai được chỉ định của chúng sang phân vùng nhà cung cấp. Giống như chính sách công khai của nền tảng, nhà cung cấp sử dụng các loại và quy tắc được tự động dịch thành các thuộc tính có phiên bản, ví dụ: từ type
thành type_N
, trong đó N
là phiên bản của nền tảng mà phân vùng của nhà cung cấp được xây dựng dựa trên đó.
Khi các phân vùng system_ext
và product
dựa trên cùng một phiên bản nền tảng N
, hệ thống xây dựng sẽ tạo các tệp ánh xạ cơ sở đến system_ext/etc/selinux/mapping/N.cil
và product/etc/selinux/mapping/N.cil
, chứa các ánh xạ nhận dạng từ type
đến type_N
. Nhà cung cấp có thể truy cập vào type
bằng thuộc tính có phiên bản type_N
.
Trong trường hợp chỉ các phân vùng system_ext
và product
được cập nhật, giả sử từ N
thành N+1
(hoặc mới hơn), trong khi nhà cung cấp vẫn ở N
, thì nhà cung cấp có thể mất quyền truy cập vào các loại phân vùng system_ext
và product
. Để tránh bị hỏng, các phân vùng system_ext
và product
phải cung cấp các tệp ánh xạ từ các loại cụ thể thành các thuộc tính type_N
. Mỗi đối tác có trách nhiệm duy trì các tệp ánh xạ, nếu họ sẽ hỗ trợ nhà cung cấp N
bằng các phân vùng system_ext
và product
N+1
(hoặc mới hơn).
Để làm được điều đó, đối tác cần:
- Sao chép các tệp ánh xạ cơ sở đã tạo từ các phân vùng
N
,system_ext
vàproduct
vào cây nguồn của các phân vùng đó. - Sửa đổi các tệp ánh xạ nếu cần.
-
Cài đặt
tệp ánh xạ vào các phân vùng
system_ext
vàproduct
củaN+1
(hoặc mới hơn).
Ví dụ: giả sử N
system_ext
có một loại công khai tên là foo_type
. Sau đó, system_ext/etc/selinux/mapping/N.cil
trong phân vùng N
system_ext
sẽ có dạng như sau:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
Nếu bar_type
được thêm vào N+1
system_ext và nếu bar_type
được liên kết với foo_type
cho nhà cung cấp N
, thì bạn có thể cập nhật N.cil
từ
(typeattributeset foo_type_N (foo_type))
tới
(typeattributeset foo_type_N (foo_type bar_type))
rồi cài đặt vào phân vùng N+1
system_ext.
Nhà cung cấp N
có thể tiếp tục truy cập vào N+1
foo_type
và bar_type
của system_ext.
Gắn nhãn ngữ cảnh SELinux
Để hỗ trợ sự khác biệt giữa chính sách bảo mật của nền tảng và nhà cung cấp, hệ thống sẽ tạo các tệp ngữ cảnh SELinux theo cách khác nhau để tách biệt các tệp này.
Ngữ cảnh tệp
Android 8.0 đã đưa ra những thay đổi sau đây cho file_contexts
:
- Để tránh thêm chi phí biên dịch trên thiết bị trong quá trình khởi động,
file_contexts
sẽ không còn tồn tại ở dạng tệp nhị phân. Thay vào đó, các tệp này là tệp văn bản biểu thức chính quy có thể đọc được, chẳng hạn như{property, service}_contexts
(như các tệp trước phiên bản 7.0). file_contexts
được chia giữa hai tệp:plat_file_contexts
file_context
nền tảng Android không có nhãn dành riêng cho thiết bị, ngoại trừ việc gắn nhãn các phần của phân vùng/vendor
phải được gắn nhãn chính xác để đảm bảo các tệp sepolicy hoạt động đúng cách.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/plat_file_contexts
trên thiết bị và đượcinit
tải vào lúc bắt đầu cùng với nhà cung cấpfile_context
.
vendor_file_contexts
file_context
dành riêng cho thiết bị được tạo bằng cách kết hợpfile_contexts
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị.- Phải được cài đặt tại
/vendor/etc/selinux/vendor_file_contexts
trong phân vùngvendor
và đượcinit
tải vào khi bắt đầu cùng với nền tảngfile_context
.
Ngữ cảnh thuộc tính
Trong Android 8.0, property_contexts
được chia giữa hai tệp:
plat_property_contexts
property_context
nền tảng Android không có nhãn dành riêng cho thiết bị.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/plat_property_contexts
và đượcinit
tải vào lúc bắt đầu cùng vớiproperty_contexts
của nhà cung cấp.
vendor_property_contexts
property_context
dành riêng cho thiết bị được tạo bằng cách kết hợpproperty_contexts
có trong các thư mục doBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị.- Phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/vendor_property_contexts
và được tải bằnginit
khi bắt đầu cùng với nền tảngproperty_context
Ngữ cảnh dịch vụ
Trong Android 8.0, service_contexts
được phân chia giữa các tệp sau:
plat_service_contexts
service_context
dành riêng cho nền tảng Android choservicemanager
.service_context
không có nhãn dành riêng cho thiết bị.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/plat_service_contexts
và được tải bằngservicemanager
khi bắt đầu cùng với nhà cung cấpservice_contexts
.
vendor_service_contexts
service_context
dành riêng cho thiết bị được tạo bằng cách kết hợpservice_contexts
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị.- Phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/vendor_service_contexts
và được tải bằngservicemanager
khi bắt đầu cùng với nền tảngservice_contexts
. - Mặc dù
servicemanager
tìm kiếm tệp này tại thời điểm khởi động, nhưng đối với thiết bịTREBLE
tuân thủ đầy đủ,vendor_service_contexts
KHÔNG ĐƯỢC tồn tại. Điều này là do tất cả hoạt động tương tác giữa các quy trìnhvendor
vàsystem
PHẢI thông quahwservicemanager
/hwbinder
.
plat_hwservice_contexts
hwservice_context
nền tảng Android chohwservicemanager
không có nhãn dành riêng cho thiết bị.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/plat_hwservice_contexts
và được tải bằnghwservicemanager
khi bắt đầu cùng vớivendor_hwservice_contexts
.
vendor_hwservice_contexts
hwservice_context
dành riêng cho thiết bị được tạo bằng cách kết hợphwservice_contexts
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị.- Phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/vendor_hwservice_contexts
và đượchwservicemanager
tải khi khởi động cùng vớiplat_service_contexts
.
vndservice_contexts
service_context
dành riêng cho thiết bị chovndservicemanager
được tạo bằng cách kết hợpvndservice_contexts
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trongBoardconfig.mk
của thiết bị.- Tệp này phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/vndservice_contexts
và đượcvndservicemanager
tải khi khởi động.
Ngữ cảnh Seapp
Trong Android 8.0, seapp_contexts
được chia giữa hai tệp:
plat_seapp_contexts
seapp_context
nền tảng Android không có thay đổi nào dành riêng cho thiết bị.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/plat_seapp_contexts.
vendor_seapp_contexts
- Tiện ích dành riêng cho thiết bị cho nền tảng
seapp_context
được tạo bằng cách kết hợpseapp_contexts
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị. - Phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/vendor_seapp_contexts
.
- Tiện ích dành riêng cho thiết bị cho nền tảng
Quyền MAC
Trong Android 8.0, mac_permissions.xml
được chia giữa hai tệp:
- Nền tảng
mac_permissions.xml
mac_permissions.xml
nền tảng Android không có thay đổi nào dành riêng cho thiết bị.- Phải nằm trong phân vùng
system
tại/system/etc/selinux/.
mac_permissions.xml
không phải nền tảng- Tiện ích dành riêng cho thiết bị cho nền tảng
mac_permissions.xml
được tạo từmac_permissions.xml
có trong các thư mục đượcBOARD_SEPOLICY_DIRS
trỏ đến trong tệpBoardconfig.mk
của thiết bị. - Phải nằm trong phân vùng
vendor
tại/vendor/etc/selinux/.
- Tiện ích dành riêng cho thiết bị cho nền tảng