Triển khai SELinux

SELinux được thiết lập để từ chối theo mặc định, nghĩa là mọi quyền truy cập mà SELinux có một hook trong kernel đều phải được cho phép rõ ràng theo chính sách. Điều này có nghĩa là tệp chính sách bao gồm một lượng lớn thông tin về các quy tắc, loại, lớp, quyền và nhiều thông tin khác. Việc xem xét đầy đủ về SELinux nằm ngoài phạm vi của tài liệu này, nhưng việc hiểu cách viết các quy tắc chính sách hiện là điều cần thiết khi đưa ra các thiết bị Android mới. Đã có rất nhiều thông tin về SELinux. Hãy xem phần Tài liệu hỗ trợ để biết các tài nguyên được đề xuất.

Các tệp chính

Để bật SELinux, hãy tích hợp kernel Android mới nhất rồi kết hợp các tệp có trong thư mục system/sepolicy. Khi được biên dịch, các tệp đó sẽ bao gồm chính sách bảo mật kernel SELinux và bao gồm hệ điều hành Android ngược dòng.

Nhìn chung, bạn không nên sửa đổi trực tiếp các tệp system/sepolicy. Thay vào đó, hãy thêm hoặc chỉnh sửa các tệp chính sách dành riêng cho thiết bị của riêng bạn trong thư mục /device/manufacturer/device-name/sepolicy. Trong Android 8.0 trở lên, các thay đổi mà bạn thực hiện đối với các tệp này chỉ ảnh hưởng đến chính sách trong thư mục nhà cung cấp của bạn. Để biết thêm thông tin chi tiết về việc tách sepolicy công khai trong Android 8.0 trở lên, hãy xem bài viết Tuỳ chỉnh SEPolicy trong Android 8.0+. Bất kể phiên bản Android nào, bạn vẫn đang sửa đổi các tệp này:

Tệp chính sách

Các tệp kết thúc bằng *.te là các tệp nguồn chính sách SELinux, xác định các miền và nhãn của chúng. Bạn có thể cần tạo các tệp chính sách mới trong /device/manufacturer/device-name/sepolicy, nhưng bạn nên cố gắng cập nhật các tệp hiện có nếu có thể.

Tệp ngữ cảnh

Tệp ngữ cảnh là nơi bạn chỉ định nhãn cho các đối tượng của mình.

  • file_contexts gán nhãn cho các tệp và được nhiều thành phần không gian người dùng sử dụng. Khi bạn tạo các chính sách mới, hãy tạo hoặc cập nhật tệp này để gán nhãn mới cho các tệp. Để áp dụng file_contexts, hãy xây dựng lại hình ảnh hệ thống tệp hoặc chạy restorecon trên tệp cần được gắn lại nhãn. Khi nâng cấp, các thay đổi đối với file_contexts sẽ tự động được áp dụng cho các phân vùng hệ thống và dữ liệu người dùng trong quá trình nâng cấp. Các thay đổi cũng có thể tự động được áp dụng khi nâng cấp lên các phân vùng khác bằng cách thêm các lệnh gọi restorecon_recursive vào tệp init.board.rc sau khi phân vùng được gắn ở chế độ đọc-ghi.
  • genfs_contexts gán nhãn cho các hệ thống tệp, chẳng hạn như proc hoặc vfat không hỗ trợ các thuộc tính mở rộng. Cấu hình này được tải như một phần của chính sách kernel nhưng các thay đổi có thể không có hiệu lực đối với các inode trong lõi, yêu cầu khởi động lại hoặc huỷ gắn và gắn lại hệ thống tệp để áp dụng đầy đủ thay đổi. Các nhãn cụ thể cũng có thể được gán cho các điểm gắn cụ thể, chẳng hạn như vfat bằng cách sử dụng tuỳ chọn context=mount.
  • property_contexts gán nhãn cho các thuộc tính hệ thống Android để kiểm soát những quy trình có thể đặt các thuộc tính đó. Cấu hình này được quy trình init đọc trong quá trình khởi động.
  • service_contexts gán nhãn cho các dịch vụ trình liên kết Android để kiểm soát những quy trình có thể thêm (đăng ký) và tìm (tra cứu) tham chiếu trình liên kết cho dịch vụ. Cấu hình này được quy trình servicemanager đọc trong quá trình khởi động.
  • seapp_contexts gán nhãn cho các quy trình ứng dụng và /data/data thư mục. Cấu hình này được quy trình zygote đọc trên mỗi lần khởi chạy ứng dụng và bởi installd trong quá trình khởi động.
  • mac_permissions.xml gán thẻ seinfo cho các ứng dụng dựa trên chữ ký và tên gói (không bắt buộc). Sau đó, thẻ seinfo có thể được dùng làm khoá trong tệp seapp_contexts để gán nhãn cụ thể cho tất cả các ứng dụng có thẻ seinfo đó. Cấu hình này được system_server đọc trong quá trình khởi động.
  • keystore2_key_contexts gán nhãn cho các không gian tên Keystore 2. Các không gian tên này được trình nền keystore2 thực thi. Keystore luôn cung cấp các không gian tên dựa trên UID/AID. Keystore 2 cũng thực thi các không gian tên được xác định theo sepolicy. Bạn có thể xem nội dung mô tả chi tiết về định dạng và quy ước của tệp này tại đây.

Makefile BoardConfig.mk

Sau khi chỉnh sửa hoặc thêm các tệp chính sách và ngữ cảnh, hãy cập nhật /device/manufacturer/device-name/BoardConfig.mk makefile để tham chiếu đến thư mục con sepolicy và từng tệp chính sách mới. Để biết thêm thông tin về các biến BOARD_SEPOLICY, hãy xem system/sepolicy/README tệp.

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

Sau khi xây dựng lại, thiết bị của bạn sẽ được bật SELinux. Giờ đây, bạn có thể tuỳ chỉnh các chính sách SELinux để phù hợp với các nội dung bổ sung của riêng bạn cho hệ điều hành Android như mô tả trong phần Tuỳ chỉnh hoặc xác minh thiết lập hiện có như trình bày trong phần Xác thực.

Khi các tệp chính sách mới và bản cập nhật BoardConfig.mk được áp dụng, các chế độ cài đặt chính sách mới sẽ tự động được tích hợp vào tệp chính sách kernel cuối cùng. Để biết thêm thông tin về cách sepolicy được xây dựng trên thiết bị, hãy xem Xây dựng sepolicy.

Triển khai

Cách bắt đầu sử dụng SELinux:

  1. Bật SELinux trong kernel: CONFIG_SECURITY_SELINUX=y
  2. Thay đổi tham số kernel_cmdline hoặc bootconfig để:
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    hoặc
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    Điều này chỉ dành cho quá trình phát triển ban đầu của chính sách cho thiết bị. Sau khi bạn có chính sách khởi động ban đầu, hãy xoá tham số này để thiết bị của bạn thực thi hoặc không vượt qua CTS.
  3. Khởi động hệ thống ở chế độ cho phép và xem những trường hợp bị từ chối gặp phải khi khởi động:
    Trên Ubuntu 14.04 trở lên:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    Trên Ubuntu 12.04:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. Đánh giá kết quả đầu ra để tìm các cảnh báo tương tự như init: Warning! Service name needs a SELinux domain defined; please fix! Xem Xác thực để biết hướng dẫn và công cụ.
  5. Xác định các thiết bị và các tệp mới khác cần được gắn nhãn.
  6. Sử dụng nhãn hiện có hoặc nhãn mới cho các đối tượng của bạn. Hãy xem các tệp *_contexts để biết cách các mục được gắn nhãn trước đó và sử dụng kiến thức về ý nghĩa của nhãn để gán nhãn mới. Tốt nhất là, đây là nhãn hiện có phù hợp với chính sách, nhưng đôi khi cần có nhãn mới và các quy tắc để truy cập vào nhãn đó là cần thiết. Thêm nhãn vào các tệp ngữ cảnh thích hợp.
  7. Xác định các miền/quy trình cần có miền bảo mật riêng. Bạn có thể cần viết một chính sách hoàn toàn mới cho từng miền/quy trình. Ví dụ: tất cả các101 dịch vụ được tạo từ init, đều phải có miền bảo mật riêng. Các lệnh sau đây giúp tiết lộ những dịch vụ vẫn đang chạy (nhưng TẤT CẢ các dịch vụ đều cần được xử lý như vậy):
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. Xem xét init.device.rc để xác định mọi miền không có loại miền. Hãy cung cấp cho chúng một miền sớm trong quá trình phát triển của bạn để tránh thêm các quy tắc vào init hoặc gây nhầm lẫn cho các quyền truy cập init với các quyền truy cập trong chính sách riêng của chúng.
  9. Thiết lập BOARD_CONFIG.mk để sử dụng các biến BOARD_SEPOLICY_*. Hãy xem README trong system/sepolicy để biết thông tin chi tiết về cách thiết lập.
  10. Kiểm tra tệp init.device.rc và fstab.device và đảm bảo rằng mọi lần sử dụng mount đều tương ứng với hệ thống tệp được gắn nhãn đúng cách hoặc tuỳ chọn context= mount được chỉ định.
  11. Xem xét từng trường hợp bị từ chối và tạo chính sách SELinux để xử lý đúng cách từng trường hợp. Hãy xem các ví dụ trong Tuỳ chỉnh.

Bạn nên bắt đầu với các chính sách trong AOSP rồi xây dựng dựa trên các chính sách đó để tuỳ chỉnh theo ý mình. Để biết thêm thông tin về chiến lược chính sách và xem xét kỹ hơn một số bước này, hãy xem bài viết Viết chính sách SELinux.

Trường hợp sử dụng

Dưới đây là các ví dụ cụ thể về các lỗ hổng cần xem xét khi tạo phần mềm của riêng bạn và các chính sách SELinux liên quan:

Symlink: Vì symlink xuất hiện dưới dạng tệp, nên chúng thường được đọc dưới dạng tệp, điều này có thể dẫn đến các lỗ hổng. Ví dụ: một số thành phần có đặc quyền, chẳng hạn như init, thay đổi quyền của một số tệp, đôi khi là quá mở.

Sau đó, kẻ tấn công có thể thay thế các tệp đó bằng các symlink để mã hoá các tệp mà chúng kiểm soát, cho phép kẻ tấn công ghi đè các tệp tuỳ ý. Nhưng nếu biết rằng ứng dụng của bạn không bao giờ đi qua symlink, bạn có thể cấm ứng dụng đó làm như vậy bằng SELinux.

Tệp hệ thống: Hãy xem xét lớp tệp hệ thống chỉ nên được sửa đổi bởi máy chủ hệ thống. Tuy nhiên, vì netd, initvold chạy dưới dạng gốc, nên chúng có thể truy cập vào các tệp hệ thống đó. Vì vậy, nếu netd bị xâm phạm, thì nó có thể xâm phạm các tệp đó và có khả năng xâm phạm chính máy chủ hệ thống.

Với SELinux, bạn có thể xác định các tệp đó là tệp dữ liệu máy chủ hệ thống. Do đó, miền duy nhất có quyền đọc/ghi đối với các tệp đó là máy chủ hệ thống. Ngay cả khi netd bị xâm phạm, nó cũng không thể chuyển đổi miền sang miền máy chủ hệ thống và truy cập vào các tệp hệ thống đó mặc dù nó chạy dưới dạng gốc.

Dữ liệu ứng dụng: Một ví dụ khác là lớp các hàm phải chạy dưới dạng gốc nhưng không được truy cập vào dữ liệu ứng dụng. Điều này cực kỳ hữu ích vì bạn có thể đưa ra các khẳng định trên phạm vi rộng, chẳng hạn như một số miền không liên quan đến dữ liệu ứng dụng bị cấm truy cập vào Internet.

setattr: Đối với các lệnh như chmodchown, bạn có thể xác định tập hợp các tệp mà miền được liên kết có thể thực hiện setattr. Mọi thứ bên ngoài tập hợp đó đều có thể bị cấm thực hiện các thay đổi này, ngay cả ở dạng gốc. Vì vậy, một ứng dụng có thể chạy chmodchown đối với các tệp được gắn nhãn app_data_files nhưng không phải shell_data_files hoặc system_data_files.