Xem trang này để làm quen với các khái niệm về SELinux.
Kiểm soát quyền truy cập bắt buộc
Security Enhanced Linux (SELinux) là một hệ thống kiểm soát truy cập bắt buộc (MAC) cho hệ điều hành Linux. Là một hệ thống MAC, hệ thống này khác với hệ thống kiểm soát truy cập tuỳ ý (DAC) quen thuộc của Linux. Trong hệ thống DAC, tồn tại một khái niệm về quyền sở hữu, theo đó chủ sở hữu của một tài nguyên cụ thể sẽ kiểm soát các quyền truy cập liên quan đến tài nguyên đó. Điều này thường có độ chi tiết thấp và có thể dẫn đến việc leo thang đặc quyền ngoài ý muốn. Tuy nhiên, hệ thống MAC sẽ tham khảo ý kiến của một cơ quan trung ương để đưa ra quyết định về mọi nỗ lực truy cập.
SELinux được triển khai như một phần của khung Mô-đun bảo mật Linux (LSM), nhận dạng nhiều đối tượng hạt nhân và các hành động nhạy cảm được thực hiện trên các đối tượng đó. Tại thời điểm mỗi hành động này sẽ được thực hiện, một hàm hook LSM sẽ được gọi để xác định xem hành động đó có được phép hay không dựa trên thông tin về hành động đó được lưu trữ trong một đối tượng bảo mật không minh bạch. SELinux cung cấp một quy trình triển khai cho các lệnh gọi này và việc quản lý các đối tượng bảo mật này, kết hợp với chính sách riêng của SELinux, để xác định các quyết định truy cập.
Cùng với các biện pháp bảo mật khác của Android, chính sách kiểm soát quyền truy cập của Android giúp hạn chế đáng kể thiệt hại tiềm ẩn của các thiết bị và tài khoản bị xâm nhập. Việc sử dụng các công cụ như chế độ kiểm soát quyền truy cập bắt buộc và tuỳ ý của Android sẽ giúp bạn có một cấu trúc để đảm bảo phần mềm của bạn chỉ chạy ở cấp độ đặc quyền tối thiểu. Điều này giúp giảm tác động của các cuộc tấn công và giảm khả năng các quy trình sai ghi đè hoặc thậm chí truyền dữ liệu.
Trong Android 4.3 trở lên, SELinux cung cấp một cơ chế kiểm soát bắt buộc quyền truy cập (MAC) bao trùm các môi trường kiểm soát quyền truy cập tuỳ ý (DAC) truyền thống. Ví dụ: phần mềm thường phải chạy dưới dạng tài khoản người dùng gốc để ghi vào các thiết bị khối thô. Trong môi trường Linux truyền thống dựa trên DAC, nếu người dùng root bị xâm nhập, người dùng đó có thể ghi vào mọi thiết bị khối thô. Tuy nhiên, bạn có thể dùng SELinux để gắn nhãn các thiết bị này để quy trình được chỉ định đặc quyền gốc chỉ có thể ghi vào những thiết bị được chỉ định trong chính sách liên kết. Bằng cách này, quy trình không thể ghi đè dữ liệu và chế độ cài đặt hệ thống bên ngoài thiết bị khối thô cụ thể.
Hãy xem phần Trường hợp sử dụng để biết thêm ví dụ về các mối đe doạ và cách giải quyết bằng SELinux.
Các cấp độ thực thi
SELinux có thể được triển khai ở nhiều chế độ:
- Cho phép – Chính sách bảo mật SELinux không được thực thi, chỉ được ghi lại.
- Thực thi – Chính sách bảo mật được thực thi và ghi lại. Lỗi không thành công xuất hiện dưới dạng lỗi EPERM.
Lựa chọn này là lựa chọn nhị phân và xác định xem chính sách của bạn có thực hiện hành động hay chỉ cho phép bạn thu thập các lỗi có thể xảy ra. Permissive đặc biệt hữu ích trong quá trình triển khai.
Các loại, thuộc tính và quy tắc
Android dựa vào thành phần Thực thi loại (TE) của SELinux cho chính sách của mình. Điều này có nghĩa là tất cả các đối tượng (chẳng hạn như tệp, quy trình hoặc ổ cắm) đều có một loại được liên kết với chúng. Ví dụ: theo mặc định, một ứng dụng có loại untrusted_app
. Đối với một quy trình, loại của quy trình đó còn được gọi là miền. Bạn có thể chú giải một loại bằng một hoặc nhiều thuộc tính. Thuộc tính rất hữu ích khi bạn muốn tham chiếu đến nhiều loại cùng một lúc.
Các đối tượng được liên kết với các lớp (ví dụ: tệp, thư mục, đường liên kết tượng trưng, ổ cắm) và các loại quyền truy cập khác nhau cho mỗi lớp được biểu thị bằng quyền.
Ví dụ: quyền open
tồn tại cho lớp file
. Mặc dù các loại và thuộc tính thường xuyên được cập nhật trong chính sách SELinux của Android, nhưng các quyền và lớp được xác định tĩnh và hiếm khi được cập nhật trong một bản phát hành Linux mới.
Một quy tắc chính sách có dạng:
allow source target:class permissions;
trong đó:
- Nguồn – Loại (hoặc thuộc tính) của đối tượng trong quy tắc. Ai đang yêu cầu quyền truy cập?
- Mục tiêu – Loại (hoặc thuộc tính) của đối tượng. Bạn yêu cầu quyền truy cập vào nội dung nào?
- Lớp – Loại đối tượng (ví dụ: tệp, ổ cắm) đang được truy cập.
- Quyền – Thao tác (hoặc tập hợp các thao tác) (ví dụ: đọc, ghi) đang được thực hiện.
Ví dụ về một quy tắc:
allow untrusted_app app_data_file:file { read write };
Điều này có nghĩa là các ứng dụng được phép đọc và ghi các tệp được gắn nhãn app_data_file
. Có những loại khác dành cho ứng dụng. Ví dụ: isolated_app
được dùng cho các dịch vụ ứng dụng có isolatedProcess=true
trong tệp kê khai. Thay vì lặp lại quy tắc cho cả hai loại, Android sử dụng một thuộc tính có tên là appdomain
cho tất cả các loại bao gồm ứng dụng:
# Associate the attribute appdomain with the type untrusted_app. typeattribute untrusted_app appdomain; # Associate the attribute appdomain with the type isolated_app. typeattribute isolated_app appdomain; allow appdomain app_data_file:file { read write };
Khi bạn viết một quy tắc chỉ định tên thuộc tính, tên đó sẽ tự động mở rộng thành danh sách các miền hoặc loại được liên kết với thuộc tính. Một số thuộc tính đáng chú ý là:
domain
– thuộc tính được liên kết với tất cả các loại quy trình,file_type
– thuộc tính được liên kết với tất cả các loại tệp.
Macro
Đối với quyền truy cập vào tệp, có nhiều loại quyền cần cân nhắc. Ví dụ: quyền read
là không đủ để mở tệp hoặc gọi stat
trên tệp đó. Để đơn giản hoá việc xác định quy tắc, Android cung cấp một bộ macro để xử lý các trường hợp phổ biến nhất. Ví dụ: để thêm các quyền còn thiếu như open
, bạn có thể viết lại quy tắc ở trên như sau:
allow appdomain app_data_file:file rw_file_perms;
Hãy xem các tệp global_macros
và te_macros
để biết thêm ví dụ về các macro hữu ích. Bạn nên sử dụng macro bất cứ khi nào có thể để giảm khả năng xảy ra lỗi do bị từ chối cấp các quyền liên quan.
Sau khi xác định một loại, bạn cần liên kết loại đó với tệp hoặc quy trình mà loại đó đại diện. Hãy xem bài viết Triển khai SELinux để biết thêm thông tin chi tiết về cách thực hiện mối liên kết này. Để biết thêm thông tin về các quy tắc, hãy xem Sổ tay SELinux.
Ngữ cảnh và danh mục bảo mật
Khi gỡ lỗi các chính sách SELinux hoặc gắn nhãn tệp (bằng file_contexts
hoặc khi ls -Z
), bạn có thể gặp phải một ngữ cảnh bảo mật (còn gọi là nhãn). Ví dụ: u:r:untrusted_app:s0:c15,c256,c513,c768
. Bối cảnh bảo mật có định dạng:
user:role:type:sensitivity[:categories]
. Thông thường, bạn có thể bỏ qua các trường user
, role
và sensitivity
của một ngữ cảnh (xem phần Tính cụ thể). Trường type
được giải thích trong phần trước. categories
là một phần của tính năng hỗ trợ Bảo mật nhiều cấp (MLS) trong SELinux. Trên Android 12 trở lên, các danh mục được dùng để:
- Cách ly dữ liệu ứng dụng khỏi quyền truy cập của một ứng dụng khác,
- Tách biệt dữ liệu ứng dụng của người dùng thực này với người dùng thực khác.
Tính cụ thể
Android không sử dụng tất cả các tính năng do SELinux cung cấp. Khi đọc tài liệu bên ngoài, hãy lưu ý những điểm sau:
- Phần lớn các chính sách trong AOSP được xác định bằng Ngôn ngữ chính sách của nhân. Có một số trường hợp ngoại lệ khi sử dụng Ngôn ngữ trung gian chung (CIL).
- Không dùng người dùng SELinux. Người dùng duy nhất được xác định là
u
. Khi cần, người dùng thực tế sẽ được biểu thị bằng trường danh mục của một bối cảnh bảo mật. - Không dùng vai trò SELinux và tính năng Kiểm soát quyền truy cập dựa trên vai trò (RBAC). Hai vai trò mặc định được xác định và sử dụng:
r
cho chủ đề vàobject_r
cho đối tượng. - Không sử dụng mức độ nhạy cảm của SELinux. Độ nhạy
s0
mặc định luôn được đặt. - Không dùng các giá trị boolean của SELinux. Khi được tạo cho một thiết bị, chính sách này không phụ thuộc vào trạng thái của thiết bị. Việc này giúp đơn giản hoá quá trình kiểm tra và gỡ lỗi các chính sách.