Khả năng tương thích với chính sách

Trang này mô tả cách Android xử lý các vấn đề về khả năng tương thích chính sách với các bản cập nhật nền tảng không dây (OTA), trong đó các chế độ cài đặt SELinux mới của nền tảng có thể khác với các chế độ cài đặt SELinux cũ của nhà cung cấp.

Quyền sở hữu và gắn nhãn đối tượng

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ãn chính sách của nhà cung cấp /dev/foo và nhãn chính sách của nền tảng /dev/foo trong một OTA tiếp theo, thì sẽ có hành vi không xác định như bị từ chối ngoài dự kiến hoặc nghiêm trọng hơn là lỗi khởi động. Đối với SELinux, điều này biểu hiện dưới dạng xung đột về việc gắn nhãn. Nút thiết bị chỉ có thể có một nhãn duy nhất phân giải thành bất kỳ nhãn nào được áp dụng sau cùng. Kết quả là:

  • Các quy trình cần có quyền truy cập vào nhãn không được áp dụ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ị gián đoạn vì nút thiết bị không chính xác đã được tạo.

Xung đột giữa nhãn nền tảng và nhãn nhà cung cấp có thể xảy ra đối với mọi đối tượng có nhãn SELinux, bao gồm 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 của các đối tượng này.

Không gian tên loại/thuộc tính

Ngoài các xung đột về nhãn, tên thuộc tính và loại SELinux cũng có thể xung đột. SELinux không cho phép khai báo nhiều lần cùng một loại và thuộc tính. Một chính sách có các khai báo trùng lặp sẽ không biên dịch được. Để tránh xung đột về tên thuộc tính và loại, bạn nên bắt đầu tất cả các khai báo của nhà cung cấp bằng tiền tố vendor_. Ví dụ: nhà cung cấp nên sử dụng type vendor_foo, domain; thay vì type foo, domain;.

Quyền sở hữu tệp

Việc ngăn chặn xung đột cho các tệp là một thách thức vì cả chính sách của nền tảng và nhà cung cấp đều thường cung cấp nhãn cho tất cả các hệ thống tệp. Không giống như việc đặt tên kiểu, việc đặt không gian tên cho các tệp là không thực tế vì nhiều tệp trong số đó được tạo bởi nhân. Để tránh những 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à những đề xuất không có biện pháp thực thi kỹ thuật. Trong tương lai, những đề xuất này sẽ được thực thi bằng Vendor Test Suite (VTS).

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 của nhà cung cấp, thì có thể không thực hiện được bản cập nhật OTA chỉ dành cho khung.

Nhà cung cấp (/vendor)

Chính sách SELinux của AOSP đã gắn nhãn cho các phần của phân vùng vendor mà nền tảng tương tác. Điều này cho phép viết các quy tắc SELinux cho các quy trình của nền tảng để có thể giao tiếp hoặc truy cập vào các phần của phân vùng vendor. Ví dụ:

/vendor path 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 theo 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ả các tệp trong phân vùng vendor. Chính sách nền tảng yêu cầu điều này để truy cập vào các chế độ triển khai HAL truyền qua.
  • Tất cả exec_types mới được thêm vào phân vùng vendor thông qua chính sách của nhà cung cấp đều phải có thuộc tính vendor_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ùng vendor.
  • Tất cả các phần phụ thuộc thư viện cho các HAL cùng quy trình do AOSP xác định đều 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ả nền tảng và chính sách nhà cung cấp đều dùng genfscon để gắn nhãn cho các tệp trong procfs.

Đề xuất: Chỉ có nhãn chính sách của nền tảng /proc. Nếu các quy trình của nhà cung cấp cầ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 được gắn nhãn rõ ràng cho các tệp đó mà thay vào đó phải sử dụng loại proc chung để thêm các quy tắc cho 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 điều chỉnh các giao diện hạt 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 đó khi cần.

Debugfs (/sys/kernel/debug)

Debugfs có thể được gắn nhãn trong cả file_contextsgenfscon. Trong Android 7.0 đến Android 10, cả nhãn nền tảng và nhà cung cấp 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)

Tracefs có thể được gắn nhãn trong cả file_contextsgenfscon. 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_contextsgenfscon. Trong Android 7.0, cả nền tảng và nhà cung cấp đều dùng genfscon để gắn nhãn cho các tệp trong sysfs.

Đề xuất: Nền tảng có thể gắn nhãn cho 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)

Bạn có thể gắn nhãn cho các tệp trong /dev trong file_contexts. Trong Android 7.0, cả nền tảng và tệp nhãn của nhà cung cấp đều ở đâ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 (/)

Bạn có thể gắn nhãn cho các tệp trong / 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 cho các tệp trong /.

Dữ liệu (/data)

Dữ liệu được gắn nhãn thông qua sự kết hợp giữa file_contextsseapp_contexts.

Đề xuất: Không cho phép gắn nhãn của 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

Bắt đầu từ cấp độ API của nhà cung cấp 202504, các nhãn SELinux mới hơn được chỉ định 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 vendor cũ hơn. Điều này cho phép các phân vùng vendor cũ giữ lại chế độ triển khai SEPolicy hiện có. Việc này được kiểm soát bằng biến Makefile BOARD_GENFS_LABELS_VERSION được lưu trữ trong /vendor/etc/selinux/genfs_labels_version.txt.

Ví dụ:

  • Trong cấp độ API nhà cung cấp 202404, nút /sys/class/udc được gắn nhãn sysfs theo mặc định.
  • Kể từ cấp độ API 202504 của nhà cung cấp, /sys/class/udc được gắn nhãn sysfs_udc.

Tuy nhiên, /sys/class/udc có thể đang được các phân vùng vendor sử dụng cấp độ API 202404, có thể là 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/udcsysfs_udc vô điều kiện có thể làm mất khả năng tương thích với các phân vùng vendor này. Bằng cách kiểm tra 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 vendor 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 vendor sử dụng cấp độ API 202404 có thể đặt BOARD_GENFS_LABELS_VERSION thành 202504 để áp 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 các nút genfscon, nền tảng phải xem xét các phân vùng vendor cũ hơn và triển khai các cơ chế dự phòng để đảm bảo khả năng tương thích khi cần. Nền tảng này 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.

Chính sách công của nền tảng

Chính sách SELinux của nền tảng được chia thành chính sách riêng tư và công khai. Chính sách công khai của nền tảng bao gồm các loại và thuộc tính luôn có sẵn cho cấp độ API của nhà cung cấp, đóng vai trò là API giữa nền tảng và nhà cung cấp. Chính sách này được cung cấp cho người viết chính sách của nhà cung cấp để cho phép nhà cung cấp tạo các tệp chính sách của nhà cung cấp. Khi kết hợp với chính sách riêng tư của nền tảng, chính sách này sẽ tạo ra một chính sách hoạt động đầy đủ cho thiết bị. Chính sách công khai của nền tảng được xác định trong system/sepolicy/public.

Ví dụ: loại vendor_init, đại diện cho quy trình khởi động trong bối cảnh của nhà cung cấp, được xác định trong system/sepolicy/public/vendor_init.te:

type vendor_init, domain;

Nhà cung cấp có thể tham khảo loại vendor_init để viết các quy tắc chính sách tuỳ chỉnh:

# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)

Thuộc tính về khả năng tương thích

Chính sách SELinux là một hoạt động tương tác giữa các loại nguồn và đích cho các lớp đối tượng và quyền cụ thể. Mỗi đối tượng (ví dụ: quy trình, tệp) 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 này chủ yếu được viết theo các loại hiện có. Trong đó, cả vendor_initdebugfs đều là các loại:

allow vendor_init debugfs:dir { mounton };

Đ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. 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ể, đồng thời 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 mà trước đây đã dựa vào. Ví dụ: giả sử các nút sysfs của nhãn chính sách nền tảng là sysfs:

/sys(/.*)? u:object_r:sysfs:s0

Chính sách của nhà cung cấp cấp quyền truy cập vào /sys/usb, được gắn nhãn là sysfs:

allow vendor_init sysfs:chr_file rw_file_perms;

Nếu chính sách nền tảng thay đổi thành nhãn /sys/usbsysfs_usb, thì chính sách của nhà cung cấp vẫn giữ nguyên, nhưng vendor_init sẽ mất quyền truy cập vào /sys/usb do thiếu chính sách cho loại sysfs_usb mới:

/sys/usb u:object_r:sysfs_usb:s0

Để giải quyết vấn đề này, Android giới thiệu khái niệm về các thuộc tính theo phiên bản. Tại thời gian biên dịch, hệ thống xây dựng sẽ tự động dịch các loại công khai của nền tảng được dùng trong chính sách của nhà cung cấp thành các thuộc tính có phiên bản này. Bản dịch này được bật bằng cách ánh xạ các tệp liên kết một thuộc tính có phiên bản với một hoặc nhiều loại công khai trên nền tảng.

Ví dụ: giả sử /sys/usb được gắn nhãn là sysfs trong chính sách nền tảng 202504 và chính sách của nhà cung cấp 202504 cấp quyền truy cập vendor_init vào /sys/usb. Trong trường hợp này:

  • Chính sách của nhà cung cấp viết một quy tắc allow vendor_init sysfs:chr_file rw_file_perms;, vì /sys/usb được gắn nhãn là sysfs trong chính sách của nền tảng 202504. Khi hệ thống xây dựng biên dịch chính sách của nhà cung cấp, hệ thống sẽ tự động dịch quy tắc thành allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. Các thuộc tính vendor_init_202504sysfs_202504 tương ứng với các loại vendor_initsysfs. Đây là các loại do nền tảng xác định.
  • Hệ thống xây dựng sẽ tạo một tệp ánh xạ danh tính /system/etc/selinux/mapping/202504.cil. Vì cả phân vùng systemvendor đều sử dụng cùng phiên bản 202504, nên tệp ánh xạ chứa các ánh xạ danh tính từ type_202504 đến type. Ví dụ: vendor_init_202504 được liên kết với vendor_initsysfs_202504 được liên kết với sysfs:
    (typeattributeset sysfs_202504 (sysfs))
    (typeattributeset vendor_init_202504 (vendor_init))
    ...

Khi phiên bản được tăng từ 202504 lên 202604, một tệp ánh xạ mới cho các phân vùng 202504 vendor sẽ được tạo trong system/sepolicy/private/compat/202504/202504.cil, được cài đặt vào /system/etc/selinux/mapping/202504.cil cho các phân vùng 202604 trở lên system. Ban đầu, tệp ánh xạ này chứa các ánh xạ nhận dạng, như đã mô tả trước đó. Nếu một nhãn mới sysfs_usb cho /sys/usb được thêm vào chính sách nền tảng 202604, thì tệp ánh xạ sẽ được cập nhật để ánh xạ sysfs_202504 với sysfs_usb:

(typeattributeset sysfs_202504 (sysfs sysfs_usb))
(typeattributeset vendor_init_202504 (vendor_init))
...

Bản cập nhật này cho phép quy tắc chính sách của nhà cung cấp được chuyển đổi allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms; tự động cấp quyền truy cập vendor_init vào loại sysfs_usb mới.

Để duy trì khả năng tương thích với các phân vùng vendor cũ, bất cứ khi nào một loại công khai mới được thêm vào, loại đó phải được ánh xạ đến ít nhất một trong các thuộc tính có phiên bản trong tệp ánh xạ system/sepolicy/private/compat/ver/ver.cil hoặc được liệt kê trong system/sepolicy/private/compat/ver/ver.ignore.cil để cho biết rằng không có loại nào khớp trong các phiên bản nhà cung cấp trước đó.

Sự kết hợp giữa chính sách nền tảng, chính sách của nhà cung cấp và tệp ánh xạ cho phép hệ thống cập nhật mà không cần cập nhật chính sách của nhà cung cấp. Ngoài ra, quá trình chuyển đổi thành các thuộc tính có phiên bản sẽ diễn ra tự động, vì vậy, chính sách của nhà cung cấp không cần phải xử lý việc tạo phiên bản, mà vẫn sử dụng các loại công khai như cũ.

chính sách công về hệ thống_ext và chính sách công về sản phẩm

Kể từ Android 11, các phân vùng system_extproduct được phép xuất các loại công khai được chỉ định sang phân vùng vendor. Giống như chính sách công khai của nền tảng, chính sách của 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_ver, trong đó ver là cấp độ API của nhà cung cấp của phân vùng vendor.

Khi các phân vùng system_extproduct dựa trên cùng một phiên bản nền tảng ver, hệ thống xây dựng sẽ tạo các tệp ánh xạ cơ sở thành system_ext/etc/selinux/mapping/ver.cilproduct/etc/selinux/mapping/ver.cil, chứa các ánh xạ nhận dạng từ type đến type_ver. Chính sách của nhà cung cấp có thể truy cập vào type bằng thuộc tính có phiên bản type_ver.

Trong trường hợp chỉ có các phân vùng system_extproduct được cập nhật, chẳng hạn như ver thành ver+1 (hoặc phiên bản mới hơn), trong khi phân vùng vendor vẫn ở ver, thì chính sách của nhà cung cấp có thể mất quyền truy cập vào các loại phân vùng system_extproduct. Để ngăn tình trạng phân mảnh, các phân vùng system_extproduct 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_ver. Mỗi đối tác chịu trách nhiệm duy trì các tệp ánh xạ, nếu họ hỗ trợ phân vùng ver vendor bằng ver+1 (hoặc phiên bản mới hơn) system_ext và phân vùng product.

Để cài đặt các tệp ánh xạ vào system_ext và phân vùng product, các nhà triển khai thiết bị hoặc nhà cung cấp dự kiến sẽ:

  1. Sao chép các tệp ánh xạ cơ sở đã tạo từ các phân vùng ver system_extproduct vào cây nguồn của chúng.
  2. Sửa đổi các tệp liên kết nếu cần.
  3. Cài đặt các tệp ánh xạ vào ver+1 (hoặc phiên bản mới hơn) system_ext và các phân vùng product.

Ví dụ: giả sử phân vùng 202504 system_ext có một loại công khai tên là foo_type. Sau đó, system_ext/etc/selinux/mapping/202504.cil trong phân vùng 202504 system_ext sẽ có dạng như sau:

(typeattributeset foo_type_202504 (foo_type))
(expandtypeattribute foo_type_202504 true)
(typeattribute foo_type_202504)

Nếu bar_type được thêm vào system_ext 202604 và nếu bar_type được liên kết với foo_type cho phân vùng 202504 vendor, thì 202504.cil có thể được cập nhật từ (typeattributeset foo_type_202504 (foo_type)) thành (typeattributeset foo_type_202504 (foo_type bar_type)) rồi cài đặt vào phân vùng system_ext 202604. Phân vùng 202504 vendor có thể tiếp tục truy cập vào foo_typebar_type của 202604 system_ext.

Các thay đổi về thuộc tính đối với 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 ngay từ đầu thì không được.

Thuộc tính của đối tượng vi phạm

Android 9 có 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ữa vendorcoredomains. Các quy trình của nền tảng và nhà cung cấp không được sử dụng các tệp trên đĩa để giao tiếp (ABI không ổn định). Đề xuất:
    • Mã nhà cung cấp nên sử dụng /data/vendor.
    • Hệ thống không nên sử dụng /data/vendor.
  • system_executes_vendor_violators. Thuộc tính cho tất cả các miền hệ thống (ngoại trừ initshell domains) vi phạm yêu cầu không thực thi các tệp nhị phân của nhà cung cấp. Việc thực thi các 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 các 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 các tệp nhị phân của nhà cung cấp phải nằm sau HIDL HAL.

      HOẶC

    • coredomains cần có quyền truy cập vào các tệp nhị phân của nhà cung cấp sẽ được chuyển sang phân vùng vendor và do đó, không còn là coredomain nữa.

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 phép 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). Hai lý do chính dẫn đến việc này là:

  1. Các máy chủ HwBinder không thực hiện xác thực máy khách vì HIDL hiện không hiển thị thông tin UID của người gọi. Ngay cả khi HIDL hiển thị dữ liệu đó, nhiều dịch vụ HwBinder hoạt động ở cấp độ thấp hơn cấp độ của các ứ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ả các ứng dụng của mình là được uỷ quyền ngang nhau để thực hiện các thao tác do dịch vụ cung cấp.
  2. Các 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ệ xảy ra vấn đề 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 (cho đến phần cứng), do đó làm 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. Các dịch vụ này (theo định nghĩa) chạy trong quy trình của ứng dụng và do đó có quyền truy cập tương tự như miền ứng dụng mà quy trình chạy.
  • coredomain_hwservice. Những dịch vụ này không gây ra rủi ro liên quan đến lý do số 2.
  • hal_configstore_ISurfaceFlingerConfigs. Dịch vụ này được thiết kế riêng để mọi miền đều có thể sử dụng.
  • hal_graphics_allocator_hwservice. Các thao tác này cũng được cung cấp bởi dịch vụ surfaceflinger Binder mà 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ụ mediacodec Binder 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ủa hal_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ị ra mắt bằng Android 9 KHÔNG ĐƯỢC sử dụng thuộc tính untrusted.

Đề xuất:

  • Thay vào đó, các ứng dụng không đáng tin cậy sẽ giao tiếp với một dịch vụ hệ thống giao tiếp với HAL HIDL 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ột binderservicedomain) lần lượt giao tiếp với hal_graphics_allocator.

    HOẶC

  • Các ứng dụng cần có quyền truy cập trực tiếp vào HAL vendor phải có miền sepolicy do nhà cung cấp xác định riêng.

Thử nghiệm thuộc tính tệp

Android 9 có các kiểm thử thời gian xây dựng để đảm bảo tất cả các tệp ở những vị trí cụ thể đều có các thuộc tính phù hợp (chẳng hạn như tất cả các tệp trong sysfs đều có thuộc tính sysfs_type bắt buộc).

Gắn nhãn bối cảnh SELinux

Để hỗ trợ việc phân biệt sepolicy 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 để tách biệt chúng.

Ngữ cảnh tệp

Android 8.0 đã giới thiệu những thay đổi sau đối với file_contexts:

  • Để tránh hao tổn 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 tồn tại ở dạng nhị phân. Thay vào đó, chúng 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ư trước phiên bản 7.0).
  • file_contexts được chia thành 2 tệp:
    • plat_file_contexts
      • Nền tảng Android file_context không có nhãn dành riêng cho thiết bị, ngoại trừ việc gắn nhãn cho các phân vùng /vendor. Bạn phải gắn nhãn chính xác cho các phân vùng này để đả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à được init tải khi khởi động cùng với file_context của nhà cung cấp.
    • vendor_file_contexts
      • file_context dành riêng cho thiết bị được tạo bằng cách kết hợp file_contexts có trong các thư mục mà BOARD_SEPOLICY_DIRS trỏ đến trong các tệp Boardconfig.mk của thiết bị.
      • Phải được cài đặt tại /vendor/etc/selinux/vendor_file_contexts trong phân vùng vendor và được init tải khi bắt đầu cùng với file_context nền tảng.

Ngữ cảnh của thuộc tính

Trong Android 8.0, property_contexts được chia thành 2 tệp:

  • plat_property_contexts
    • Nền tảng Android property_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_property_contexts và được init tải khi bắt đầu cùng với property_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ợp property_contexts có trong các thư mục mà BOARD_SEPOLICY_DIRS trỏ đến trong các tệp Boardconfig.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 init tải khi khởi động cùng với property_context của nền tảng

Bối cảnh dịch vụ

Trong Android 8.0, service_contexts được chia thành các tệp sau:

  • plat_service_contexts
    • service_context dành riêng cho nền tảng Android cho servicemanager. 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 servicemanager tải khi khởi động cùng với service_contexts của nhà cung cấp.
  • vendor_service_contexts
    • service_context dành riêng cho thiết bị được tạo bằng cách kết hợp service_contexts có trong các thư mục mà BOARD_SEPOLICY_DIRS trỏ đến trong các tệp Boardconfig.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 servicemanager tải khi bắt đầu cùng với service_contexts của nền tảng.
    • 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 một thiết bị TREBLE hoàn toàn tuân thủ, 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ình vendorsystem PHẢI diễn ra thông qua hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • Nền tảng Android hwservice_context cho hwservicemanager 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 hwservicemanager tải khi khởi động cùng với vendor_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ợp hwservice_contexts có trong các thư mục mà BOARD_SEPOLICY_DIRS trỏ đến trong các tệp Boardconfig.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à được hwservicemanager tải khi khởi động cùng với plat_service_contexts.
  • vndservice_contexts
    • service_context dành riêng cho thiết bị cho vndservicemanager được tạo bằng cách kết hợp vndservice_contexts có trong các thư mục được chỉ đến bởi BOARD_SEPOLICY_DIRS trong Boardconfig.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à được vndservicemanager tải khi khởi động.

Ngữ cảnh Seapp

Trong Android 8.0, seapp_contexts được chia thành 2 tệp:

  • plat_seapp_contexts
    • Nền tảng Android seapp_context không có thay đổi 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ị đối với nền tảng seapp_context được tạo bằng cách kết hợp seapp_contexts có trong các thư mục được chỉ đến bởi BOARD_SEPOLICY_DIRS trong các tệp Boardconfig.mk của thiết bị.
    • Phải nằm trong phân vùng vendor tại /vendor/etc/selinux/vendor_seapp_contexts.

Quyền truy cập MAC

Trong Android 8.0, mac_permissions.xml được chia thành 2 tệp:

  • Nền tảng mac_permissions.xml
    • Nền tảng Android mac_permissions.xml không có thay đổi dành riêng cho thiết bị.
    • Phải nằm trong phân vùng system tại /system/etc/selinux/.
  • Không phải nền tảng mac_permissions.xml
    • Phần mở rộng dành riêng cho thiết bị đối với nền tảng mac_permissions.xml được tạo từ mac_permissions.xml có trong các thư mục được chỉ đến bằng BOARD_SEPOLICY_DIRS trong các tệp Boardconfig.mk của thiết bị.
    • Phải nằm trong phân vùng vendor tại /vendor/etc/selinux/.

Các thay đổi về bộ nhớ dùng chung cho Android 17

Kể từ Android 17, các thiết bị chạy bằng các thuộc tính sau phải bật khả năng được chính sách quy định memfd_class và cập nhật chính sách liên quan đến bộ nhớ dùng chung để hỗ trợ các đối tượng lớp memfd_file:

  • Cấp độ API nhà cung cấp 202604 trở lên để tạo cơ hội cho nhà cung cấp và OEM cập nhật chính sách nhà cung cấp nhằm hỗ trợ memfd. Tính năng này cũng cho phép các thiết bị hiện có nâng cấp lên các phiên bản Android cao hơn mà không cần cập nhật phân vùng của nhà cung cấp.
  • android16-6.12 trở lên, vì những nhân đó hỗ trợ tính năng memfd_class. Đây là tính năng bắt buộc để triển khai chính sách chi tiết cho memfd.

Bật khả năng chính sách memfd_class

Cho đến gần đây, SELinux đã gắn nhãn memfd là một tệp có cùng loại với hệ thống tệp hỗ trợ của tệp đó – tmpfs. Điều này khiến bạn không thể phân biệt một memfd với một tệp khác trên một điểm gắn kết tmpfs theo quan điểm chính sách. Giờ đây, SELinux gắn nhãn memfd bằng ngữ cảnh bảo mật của quy trình phân bổ và memfds được coi là các đối tượng lớp memfd_file. Chức năng này được bảo vệ bằng khả năng chính sách memfd_class để duy trì khả năng tương thích ngược với các môi trường không gian người dùng cũ.

Để bật khả năng chính sách memfd_class, hãy tạo một tệp policy_capabilities trong BOARD_VENDOR_SEPOLICY_DIRS. Tệp này phải chứa mục sau:

# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;

Sau đó, hãy tạo lại hình ảnh và cài đặt ROM cho thiết bị để xác minh rằng tính năng này đã được bật.

Xác minh rằng bạn đã bật chức năng chính sách memfd_class

Dùng lệnh sau để kiểm tra trạng thái của chức năng chính sách memfd_class:

adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'

Nếu kết quả là 1, thì chức năng chính sách memfd_class sẽ được bật. Nếu không, tính năng này sẽ không được bật.

Chuyển chính sách hiện có sang memfd

Một số quy trình đã sử dụng macro tmpfs_domain() trong chính sách của chúng để truy cập và đặt tên cho memfds, ví dụ:

# foo.te
tmpfs_domain(foo)

Điều này có nghĩa là:

# foo.te
type_transition foo tmpfs:file foo_tmpfs;
allow foo foo_tmpfs:file { read write getattr map };

và cho phép quy trình bar truy cập vào memfds của quy trình foo như sau:

# bar.te
allow bar foo_tmpfs:file { read write getattr map };

Khi bật tính năng chính sách memfd_class, bạn không cần dùng macro tmpfs_domain() nữa, vì chính sách nền tảng đã được cập nhật để cho phép mọi quy trình tạo và sử dụng memfds riêng, như bạn thấy ở đây:

# system/sepolicy/private/domain.te
allow domain self:memfd_file { create read write getattr map };

memfds do quy trình foo tạo có thể được truy cập bởi quy trình bar như sau:

# bar.te
allow bar foo:memfd_file { read write getattr map };

Chính sách của nền tảng đã được cập nhật để tính đến các cách sử dụng hiện tại của memfd. Tuy nhiên, bạn phải cập nhật chính sách dành riêng cho nhà cung cấp và thiết bị sử dụng nhãn tmpfs để sử dụng memfd_file. Nếu chính sách được chia sẻ giữa các SoC hoặc thiết bị không có cấp độ API 202604 trở lên của nhà cung cấp, thì bạn nên giữ lại chính sách tmpfs cũ cùng với chính sách memfd_file mới để đảm bảo khả năng tương thích.

Xác định các lệnh từ chối AVC liên quan đến memfd

Bạn có thể truy xuất các yêu cầu từ chối liên quan đến Memfd bằng lệnh sau:

adb shell logcat -d -b events | grep memfd

từ chối avc với tmpfs làm mục tiêu

Ví dụ sau đây cho thấy một quy trình đã gặp phải trường hợp từ chối avc khi cố gắng ghi vào một memfd mà quy trình đó không có quyền ghi:

audit(0.0:539): avc:  denied  { write } for  comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0

Khi tính năng chính sách memfd_class được bật, ngữ cảnh mục tiêu của memfd là ngữ cảnh bảo mật của quy trình phân bổ, không phải tmpfs và lớp mục tiêu là memfd_file, không phải file. Do đó, nếu bạn thấy avc từ chối liên quan đến memfd, trong đó memfd được đề cập được gắn nhãn là tệp tmpfs, thì tức là bạn chưa bật chức năng chính sách memfd_class.

từ chối avc với memfd_file làm lớp mục tiêu

Ví dụ sau đây cho thấy một trường hợp từ chối avc mà một quy trình gặp phải khi cố gắng ghi vào một memfd mà quy trình đó không có quyền ghi, đồng thời khả năng chính sách memfd_class đã được bật, cũng như một dòng bổ sung mà logd phát ra sau khi từ chối với cùng dấu thời gian:

audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file

auditd  : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)

Dấu thời gian trùng khớp cho biết Decoded path for … log có liên quan đến lệnh từ chối avc có dấu thời gian 0.0.86. Nhật ký này giải mã chuỗi thập lục phân từ giá trị đường dẫn trong lệnh từ chối avc và cung cấp tên của vùng nhớ memfd. Tên này có thể hữu ích để hiểu vùng đệm nào đang được chia sẻ. Ngữ cảnh nguồn và ngữ cảnh đích rất hữu ích để hiểu những quy trình cần dùng chung bộ nhớ. Từ ví dụ trước, rõ ràng là quy trình mediaserver cần có khả năng truy cập vào memfds của mediaextractor. Do đó, chính sách phù hợp là:

# mediaserver.te
allow mediaserver mediaextractor:memfd_file { getattr read write map };

Nội dung cập nhật về miền bảo mật trong Android 17

API ASharedMemory_create() trong Android 17 triển khai logic có điều kiện để chọn giữa trình điều khiển ashmem cũ và khung memfd để phân bổ bộ nhớ dùng chung.

Đối với những thiết bị đáp ứng các yêu cầu về memfd (API của nhà cung cấp từ 202604 trở lên và kernel android16-6.12 trở lên), API sẽ đánh giá targetSdkVersion của ứng dụng gọi. Nếu phiên bản SDK mục tiêu là 37 trở lên, thì memfd sẽ được phân bổ. Điều này giúp nhà phát triển khắc phục những vấn đề mà họ gặp phải khi nâng cấp phiên bản SDK mục tiêu.

Nếu thiết bị không đáp ứng các điều kiện tiên quyết memfd's, thì ASharedMemory sẽ quay lại ashmem. Việc này giúp duy trì khả năng tương thích cho các thiết bị đã nâng cấp có phân vùng hoặc nhân của nhà cung cấp cũ.

Để thực thi quá trình chuyển đổi này, chính sách SELinux của nền tảng sẽ chặn các ứng dụng nhắm đến SDK phiên bản 37 trở lên trong các miền bảo mật platform_app, priv_appuntrusted_app mở /dev/ashmem và gọi các lệnh ioctl ashmem trên memfd. Việc này được thực hiện bằng cách phân chia các miền ứng dụng đó dựa trên phiên bản SDK mục tiêu. Điều này giới thiệu các miền bảo mật platform_app_36, priv_app_36untrusted_app_34. Cùng với các miền ứng dụng khác, các miền này vẫn giữ lại quyền mở ashmem và khả năng gọi các lệnh ioctl ashmem trên memfds.

Trong một bản phát hành Android trong tương lai, nhóm ứng dụng giữ lại quyền mở thiết bị ashmem và gọi các lệnh ioctl ashmem trên memfds sẽ giảm xuống chỉ còn platform_app_36, priv_app_36untrusted_app_34 cũng như các miền ứng dụng không đáng tin cậy cho các phiên bản SDK cũ.

Bạn phải cập nhật các chính sách SELinux tuỳ chỉnh của nhà cung cấp hoặc OEM cho những ứng dụng ghim phiên bản SDK mục tiêu để phù hợp với những thay đổi về miền này, như được trình bày chi tiết trong các phần sau.

Nội dung cập nhật miền SELinux platform_app

Miền platform_app được phân tách dựa trên targetSdkVersion của ứng dụng. Các ứng dụng nền tảng nhắm đến SDK phiên bản 37 trở lên được chỉ định miền platform_app, trong khi những ứng dụng nhắm đến SDK phiên bản 36 trở xuống sử dụng platform_app_36. Miền platform_app_36 vẫn có khả năng mở /dev/ashmem để đảm bảo khả năng tương thích ngược. Để đơn giản hoá việc quản lý chính sách trên cả hai miền, hãy sử dụng thuộc tính platform_app_all.

Hãy cân nhắc trường hợp ứng dụng nền tảng sample-plat-app cần đọc và ghi từ /dev/foo_device. Chính sách SELinux hiện có của nhà cung cấp có thể có dạng như sau:

# This will only allow sample-plat-app to access the device if it
# is placed in the platform_app domain (i.e. target SDK version is 37 or higher).
allow platform_app foo_device:chr_file rw_file_perms;

Tuy nhiên, nếu sample-plat-app được ghim ở phiên bản SDK mục tiêu 36, thì nó sẽ được đặt trong miền platform_app_36 và chính sách SELinux từ trước sẽ không áp dụng, đồng thời bạn sẽ thấy lỗi từ chối AVC sau đây:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Để khắc phục vấn đề đó, bạn có thể cập nhật chính sách như sau vì ứng dụng phải luôn có quyền truy cập vào nút thiết bị:

# This allows sample-plat-app to access the device independent of
# target SDK version.
allow platform_app_all foo_device:chr_file rw_file_perms;

Có thể có những trường hợp mà platform_app_all không hoạt động. Ví dụ: nếu bạn sử dụng macro hal_client_domain() với platform_app_all, chính sách sẽ không biên dịch được. Điều này là do platform_app_all là một thuộc tính và hal_client_domain() sẽ cố gắng đính kèm một thuộc tính khác vào thuộc tính này, điều này là không thể:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

Trong những trường hợp đó, bạn phải sử dụng trực tiếp loại platform_app_36, vì vậy, chính sách của bạn có nội dung sau:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

# platform_app_36.te
hal_client_domain(platform_app_36, hal_foo)

Các bản cập nhật miền SELinux priv_app

Miền priv_app được phân tách dựa trên targetSdkVersion của ứng dụng. Các ứng dụng đặc quyền nhắm đến SDK phiên bản 37 trở lên được chỉ định miền priv_app, trong khi những ứng dụng nhắm đến SDK phiên bản 36 trở xuống sử dụng priv_app_36. Miền priv_app_36 vẫn có khả năng mở /dev/ashmem để đảm bảo khả năng tương thích ngược. Để đơn giản hoá việc quản lý chính sách trên cả hai miền, hãy sử dụng thuộc tính priv_app_all.

Hãy cân nhắc trường hợp ứng dụng nền tảng sample-priv-app cần đọc và ghi từ /dev/foo_device. Chính sách SELinux hiện có của nhà cung cấp có thể có dạng như sau:

# This will only allow sample-priv-app to access the device if it
# is placed in the priv_app domain (i.e. target SDK version is 37 or higher).
allow priv_app foo_device:chr_file rw_file_perms;

Tuy nhiên, nếu sample-priv-app được ghim ở phiên bản SDK mục tiêu 36, thì nó sẽ được đặt trong miền priv_app_36 và chính sách SELinux từ trước sẽ không áp dụng, đồng thời bạn sẽ thấy lỗi từ chối AVC sau đây:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Để khắc phục vấn đề đó, bạn có thể cập nhật chính sách như sau vì ứng dụng phải luôn có quyền truy cập vào nút thiết bị:

# This allows sample-priv-app to access the device independent of
# target SDK version.
allow priv_app_all foo_device:chr_file rw_file_perms;

Có thể có những trường hợp mà priv_app_all không hoạt động. Ví dụ: nếu bạn sử dụng macro hal_client_domain() với priv_app_all, chính sách sẽ không biên dịch được. Điều này là do priv_app_all là một thuộc tính và hal_client_domain() sẽ cố gắng đính kèm một thuộc tính khác vào thuộc tính này, điều này là không thể:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

Trong những trường hợp đó, bạn phải sử dụng trực tiếp loại priv_app_36, vì vậy, các tệp chính sách của bạn sẽ có dạng như sau:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

# priv_app_36.te
hal_client_domain(priv_app_36, hal_foo)

Nội dung cập nhật miền SELinux untrusted_app

Miền untrusted_app được phân tách dựa trên targetSdkVersion của ứng dụng. Các ứng dụng không đáng tin cậy nhắm đến SDK phiên bản 37 trở lên được chỉ định miền untrusted_app, trong khi những ứng dụng nhắm đến SDK phiên bản 34-36 (bao gồm cả 34 và 36) được chỉ định miền untrusted_app_34 mới. Miền untrusted_app_34 cũng như các miền untrusted_app_X (trong đó "X" là phiên bản SDK mục tiêu cũ) vẫn có khả năng mở `/dev/ashmem` để tương thích ngược.