Viết chính sách SELinux

Dự án mã nguồn mở Android (AOSP) cung cấp chính sách cơ sở vững chắc cho các ứng dụng và dịch vụ phổ biến trên tất cả các thiết bị Android. Những người đóng góp cho AOSP thường xuyên tinh chỉnh chính sách này. Chính sách cốt lõi dự kiến ​​sẽ chiếm khoảng 90–95% chính sách cuối cùng trên thiết bị với các tùy chỉnh dành riêng cho thiết bị chiếm 5–10% còn lại. Bài viết này tập trung vào các tùy chỉnh dành riêng cho thiết bị này, cách viết chính sách dành riêng cho thiết bị và một số cạm bẫy cần tránh trong quá trình thực hiện.

Đưa lên thiết bị

Trong khi viết chính sách dành riêng cho thiết bị, hãy làm theo các bước sau.

Chạy ở chế độ cho phép

Khi thiết bị ở chế độ cho phép , các từ chối sẽ được ghi lại nhưng không được thực thi. Chế độ cho phép rất quan trọng vì hai lý do:

  • Chế độ cho phép đảm bảo rằng việc đưa ra chính sách không làm trì hoãn các tác vụ đưa ra thiết bị ban đầu khác.
  • Một sự từ chối cưỡng bức có thể che giấu những lời từ chối khác. Ví dụ: quyền truy cập tệp thường đòi hỏi phải tìm kiếm thư mục, mở tệp và sau đó đọc tệp. Trong chế độ thực thi, chỉ xảy ra việc từ chối tìm kiếm thư mục. Chế độ cho phép đảm bảo tất cả các từ chối đều được nhìn thấy.

Cách đơn giản nhất để đưa thiết bị vào chế độ cho phép là sử dụng dòng lệnh kernel . Điều này có thể được thêm vào tệp BoardConfig.mk của thiết bị: platform/device/<vendor>/<target>/BoardConfig.mk . Sau khi sửa đổi dòng lệnh, thực hiện make clean , sau đó make bootimage và flash image khởi động mới.

Sau đó, xác nhận chế độ cho phép với:

adb shell getenforce

Hai tuần là khoảng thời gian hợp lý để ở chế độ cho phép toàn cầu. Sau khi giải quyết phần lớn các từ chối, hãy quay lại chế độ thực thi và giải quyết các lỗi khi chúng xuất hiện. Các miền vẫn tạo ra các từ chối hoặc dịch vụ vẫn đang trong quá trình phát triển mạnh có thể tạm thời được đưa vào chế độ cho phép, nhưng hãy chuyển chúng trở lại chế độ thực thi càng sớm càng tốt.

Thực thi sớm

Trong chế độ thực thi, các từ chối đều được ghi lại và thực thi. Cách tốt nhất là đưa thiết bị của bạn vào chế độ thực thi càng sớm càng tốt. Việc chờ tạo và thực thi chính sách dành riêng cho thiết bị thường dẫn đến sản phẩm có lỗi và trải nghiệm người dùng không tốt. Bắt đầu đủ sớm để tham gia dogfood và đảm bảo kiểm tra đầy đủ chức năng trong quá trình sử dụng trong thế giới thực. Bắt đầu sớm đảm bảo những lo ngại về an ninh sẽ giúp đưa ra các quyết định thiết kế. Ngược lại, việc cấp quyền chỉ dựa trên những từ chối được quan sát là một cách tiếp cận không an toàn. Sử dụng thời gian này để thực hiện kiểm tra bảo mật của thiết bị và ghi lại các lỗi đối với hành vi không được phép.

Xóa hoặc xóa chính sách hiện có

Có một số lý do chính đáng để tạo chính sách dành riêng cho thiết bị ngay từ đầu trên thiết bị mới, bao gồm:

Giải quyết các trường hợp từ chối các dịch vụ cốt lõi

Các từ chối do dịch vụ cốt lõi tạo ra thường được giải quyết bằng cách ghi nhãn tệp. Ví dụ:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

được giải quyết hoàn toàn bằng cách dán nhãn chính xác /dev/kgsl-3d0 . Trong ví dụ này, tcontextdevice . Điều này thể hiện bối cảnh mặc định trong đó mọi thứ trong /dev đều nhận được nhãn “ thiết bị ” trừ khi được gán nhãn cụ thể hơn. Chỉ cần chấp nhận đầu ra từ Audit2allow ở đây sẽ dẫn đến một quy tắc không chính xác và quá dễ dãi.

Để giải quyết loại vấn đề này, hãy đặt cho tệp một nhãn cụ thể hơn, trong trường hợp này là gpu_device . Không cần thêm quyền vì máy chủ trung gian đã có các quyền cần thiết trong chính sách cốt lõi để truy cập gpu_device.

Các tệp dành riêng cho thiết bị khác cần được gắn nhãn bằng các loại được xác định trước trong chính sách cốt lõi:

Nói chung, việc cấp quyền cho nhãn mặc định là sai. Nhiều quyền trong số này không được phép theo quy tắc không bao giờ cho phép , nhưng ngay cả khi không bị cấm một cách rõ ràng, cách tốt nhất là cung cấp một nhãn cụ thể.

Dán nhãn các dịch vụ mới và từ chối địa chỉ

Các dịch vụ do ban đầu khởi chạy bắt buộc phải chạy trong miền SELinux của riêng chúng. Ví dụ sau đặt dịch vụ “foo” vào miền SELinux của chính nó và cấp cho nó quyền.

Dịch vụ này được khởi chạy trong init. device .rc tệp init. device .rc dưới dạng:

service foo /system/bin/foo
    class core
  1. Tạo một tên miền mới "foo"

    Tạo file device/ manufacturer / device-name /sepolicy/foo.te với nội dung sau:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    Đây là mẫu ban đầu cho miền foo SELinux, nơi bạn có thể thêm các quy tắc dựa trên các hoạt động cụ thể được thực hiện bởi tệp thực thi đó.

  2. Nhãn /system/bin/foo

    Thêm phần sau vào device/ manufacturer / device-name /sepolicy/file_contexts :

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Điều này đảm bảo tệp thực thi được dán nhãn chính xác để SELinux chạy dịch vụ trong miền thích hợp.

  3. Xây dựng và flash hình ảnh khởi động và hệ thống.
  4. Tinh chỉnh các quy tắc SELinux cho miền.

    Sử dụng từ chối để xác định các quyền cần thiết. Công cụ Audit2allow cung cấp các hướng dẫn tốt nhưng chỉ sử dụng nó để cung cấp thông tin cho việc viết chính sách. Đừng chỉ sao chép đầu ra.

Chuyển về chế độ thực thi

Bạn có thể khắc phục sự cố ở chế độ cho phép nhưng hãy chuyển về chế độ thực thi càng sớm càng tốt và cố gắng duy trì ở đó.

Lỗi thường gặp

Dưới đây là một số giải pháp cho các lỗi phổ biến xảy ra khi viết chính sách dành riêng cho thiết bị.

Lạm dụng phủ định

Quy tắc ví dụ sau đây giống như khóa cửa trước nhưng vẫn để cửa sổ mở:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

Mục đích rất rõ ràng: tất cả mọi người trừ ứng dụng của bên thứ ba đều có thể có quyền truy cập vào thiết bị gỡ lỗi.

Quy tắc này có sai sót ở một số điểm. Việc loại trừ untrusted_app là điều dễ thực hiện vì tất cả các ứng dụng có thể tùy ý chạy các dịch vụ trong miền isolated_app . Tương tự, nếu miền mới cho ứng dụng của bên thứ ba được thêm vào AOSP, chúng cũng sẽ có quyền truy cập vào scary_debug_device . Quy định quá dễ dãi. Hầu hết các miền sẽ không được hưởng lợi từ việc có quyền truy cập vào công cụ gỡ lỗi này. Quy tắc đáng lẽ phải được viết để chỉ cho phép các miền yêu cầu quyền truy cập.

Gỡ lỗi các tính năng trong sản xuất

Các tính năng gỡ lỗi không được có trên các bản dựng sản xuất cũng như chính sách của chúng.

Cách thay thế đơn giản nhất là chỉ cho phép tính năng gỡ lỗi khi SELinux bị tắt trên các bản dựng eng/userdebug, chẳng hạn như adb rootadb shell setenforce 0 .

Một giải pháp thay thế an toàn khác là kèm theo các quyền gỡ lỗi trong câu lệnh userdebug_or_eng .

Bùng nổ quy mô chính sách

Đặc điểm của Chính sách SEAndroid thực tế mô tả một xu hướng đáng lo ngại về sự phát triển của các tùy chỉnh chính sách thiết bị. Chính sách dành riêng cho thiết bị phải chiếm 5–10% chính sách tổng thể chạy trên thiết bị. Các tùy chỉnh trong phạm vi 20%+ gần như chắc chắn chứa các miền đặc quyền và chính sách đã chết.

Chính sách lớn không cần thiết:

  • Thực hiện một cú đánh kép vào bộ nhớ khi chính sách nằm trong đĩa RAM và cũng được tải vào bộ nhớ kernel.
  • Lãng phí dung lượng ổ đĩa do yêu cầu hình ảnh khởi động lớn hơn.
  • Ảnh hưởng đến thời gian tra cứu chính sách thời gian chạy.

Ví dụ sau đây cho thấy hai thiết bị trong đó chính sách dành riêng cho nhà sản xuất bao gồm 50% và 40% chính sách trên thiết bị. Việc viết lại chính sách đã mang lại những cải tiến đáng kể về bảo mật mà không làm mất chức năng, như minh họa bên dưới. (Các thiết bị AOSP Shamu và Flounder được đưa vào để so sánh.)

Hình 1: So sánh kích thước chính sách dành riêng cho thiết bị sau khi kiểm tra bảo mật.

Hình 1 . So sánh kích thước chính sách dành riêng cho thiết bị sau khi kiểm tra bảo mật.

Trong cả hai trường hợp, chính sách đã giảm đáng kể cả về kích thước và số lượng quyền. Việc giảm quy mô chính sách gần như hoàn toàn là do loại bỏ các quyền không cần thiết, nhiều quyền trong số đó có thể là các quy tắc do audit2allow tạo ra và được thêm vào chính sách một cách bừa bãi. Miền chết cũng là một vấn đề đối với cả hai thiết bị.

Cấp khả năng dac_override

Từ chối dac_override có nghĩa là quá trình vi phạm đang cố truy cập vào một tệp có quyền người dùng/nhóm/thế giới unix không chính xác. Giải pháp thích hợp là hầu như không bao giờ cấp quyền dac_override . Thay vào đó hãy thay đổi quyền unix trên tệp hoặc quy trình . Một số miền như init , voldinstalld thực sự cần khả năng ghi đè quyền của tệp unix để truy cập tệp của các quy trình khác. Xem blog của Dan Walsh để được giải thích sâu hơn.