selinux.md: Add how to write actual policy rules
BUG=none.
TEST=scripts/preview_docs security/selinux.md
Change-Id: I4f566cd89249dad35ce92c3123c261dff9b10164
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/docs/+/2851105
Tested-by: Betul Soysal <betuls@google.com>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Nicole Anderson-Au <nvaa@google.com>
Commit-Queue: Betul Soysal <betuls@google.com>
diff --git a/security/selinux.md b/security/selinux.md
index 2bc408d..c6bd6c3 100644
--- a/security/selinux.md
+++ b/security/selinux.md
@@ -691,9 +691,138 @@
1. Write actual rules
- TODO
+ After creating a permissive domain for your daemon, now you need to write
+ actual rules before making the daemon domain SELinux enforcing.
+ Follow these steps to add the needed access rules:
- Go back to previous step to update SELinux tests for stateful files too.
+ - Build and flash a new image with the USE flag ‘selinux_develop’. You need
+ this flag to log permissive denials.
+
+ - Run all the tests that are related to your daemon on the test device.
+
+ - Check the SELinux violations logged at /var/log/audit/audit.log on your
+ test device and add the required access rules to the policy as explained in
+ [How to read the denials in audit logs].
+
+ - You can use 'audit2allow' script instead to define the access rules. Run
+ 'audit2allow’ script on the audit.log file in your chroot:
+
+ ```
+ audit2allow -xp /build/$BOARD/etc/selinux/arc/policy/policy.30 -i /path_to_audit_log/audit.log
+ ```
+
+ - Add the rules created by the audit2allow to the policy.
+
+ - Use macros where possible and group the rules that apply to the same file
+ context. Macros are defined in [base/imported/global_macros],
+ [base/imported/te_macros] and [chromeos/te_macros]. Find the appropriate
+ macro that includes all the access vectors reported by audit2allow. For
+ example if audit2allow generates the following allow rule:
+
+ ```
+ allow <DomainA> <ContextA>:file { getattr open read ioctl lock map }
+ ```
+
+ Use 'r_file_perms' macro instead:
+
+ ```
+ allow <DomainA> <ContextA>:file r_file_perms
+ ```
+
+ - emerge and deploy the updated policy and run the tests again. You might
+ want to remove /var/log/audit/audit.log file before running the tests to
+ avoid any confusion.
+
+ If you receive the same SELinux violation log despite adding the required
+ access rule this means you need to add an additional rule related to the
+ same violation. Right place to start the investigation is the audit logs at
+ '/var/log/audit/audit.log' and system log messages at '/var/log/messages'
+ together. Identify the step causing the violation. Examples could be the
+ need to define an ioctl or a key search permission requirement or you may
+ need to change how the file context is defined.
+
+ - Once the policy is complete for the specific board you are testing the
+ policy on, you need to make sure policy doesn't fail for other boards as
+ well. There are macros to restrict the scope of the access rules for
+ different cases. 'has_arc' or 'is_arc_vm' are the two examples for these
+ macros. For example, /home/root/hash/android-data/data directory only
+ exists if ARC is enabled on the device. Therefore if you need to define an
+ access rule for the file context 'media_rw_data_file' you need to use
+ ‘has_arc’ macro.
+
+ - If SELinux logs report a violation against an unlabeled or an unconfined
+ context define the context properly. Run the specific test triggering this
+ rule and identify the specific step to find out the unlabeled/unconfined
+ object. Label them properly following the steps defined in [File Contexts].
+
+ __Testing after adding new rules:__
+
+ - emerge and deploy selinux-policy after adding the new rules. Don't forget
+ to run `cros-workon --board_name=$BOARD --start selinux-policy` before
+ emerging the selinux-policy. And repeat the tests.
+
+ - Domain is ready to become enforcing once there are no more SELinux
+ violations logged at /var/log/audit/audit.log for your domain (or when
+ audit2allow doesn't generate any rules for your domain anymore).
+
+ - Remove 'permissive cros_tcsd' line to make the domain enforcing.
+
+ - If you've added or updated any file context you need to build a new image.
+ Even if you haven't changed any file context you still need to build a new
+ image without the USE flag 'selinux_develop' since the daemon will be
+ running in an enforcing domain (remember this flag is to log permissive
+ denials). if there is any missing access rule for the daemon that will
+ be logged since the daemon will be running in an enforcing domain.
+
+ - Repeat the tests. All the tests need to pass and no more violations should
+ be logged.
+
+ - If any of the tests fail and SELinux violations are logged for your
+ daemon, that is possibly because some of the violation logs were overridden
+ on audit.log when you were running the tests earlier. In this case you may
+ need to run the tests in smallers test sets. Or you can use a simple script
+ to filter out the logs you are looking for. A sample script could be like
+ this:
+
+ ```
+ #!/bin/bash
+
+ touch selinux_rules
+ chmod 666 selinux_rules
+ for (( i=1; i<=360; i++ ))
+ do
+ scp DUT://var/log/audit/audit.log ./audit.log
+ audit2allow -p /build/puff/etc/selinux/arc/policy/policy.30 -i ./audit.log | grep 'allow cros_cryptohomed' | tee -a selinux_rules
+ echo $i
+ sleep 30
+ done
+ ```
+
+ This script copies the audit.log file from a puff board, converts the
+ violation logs to allowrules, greps only the rules that are part of
+ cros_cryptohome domain policy and dumps them to a separate file. Repeat the
+ previous steps until all the tests are passing and no more violations are
+ logged on audit.log for your daemon.
+
+
+ - Before uploading the updated policy, make sure unit tests pass as well.
+ Android neverallow rules apply to Chrome OS since Chrome OS and Android
+ share the same kernel when Android is running in the ARC container. These
+ neverallow rules are not merged to the policy and don't take effect at
+ compile time. They are rather injected into the selinux-policy unit tests
+ and that's why you need to run the unit tests to test against the Android
+ neverallow rules:
+
+ ```
+ FEATURES=test emerge-DUT-with-ARC-Container selinux-policy
+ ```
+
+ - Note that the neverallow rules are not imported by the VM unittests like
+ amd64-generic or betty-pi-arc boards, so you need to use a physical ARC
+ container device build to run the unit tests for the updated policy.
+
+ After updating the policy, go back to previous step to update SELinux tests
+ for stateful files too.
If your process relates to after-login behavior, you may also need to update
`selinux_files_arc.go` and `selinux_files_non_arc.go`. Non-ARC specified
@@ -1024,3 +1153,10 @@
For Googlers, there's a nice introduction presentation slides how debugging
SELinux policies to refer to though it's for Android, at
[go/sepolicy-debug](https://goto.google.com/sepolicy-debug)
+
+[File Contexts]: https://chromium.googlesource.com/chromiumos/docs/+/main/security/selinux.md#File-Contexts
+[How to read the denials in audit logs]: https://chromium.googlesource.com/chromiumos/docs/+/main/security/selinux.md#How-to-read-the-denials-in-audit-logs
+
+[base/imported/global_macros]: https://source.corp.google.com/chromeos_public/src/platform2/sepolicy/policy/base/imported/global_macros
+[base/imported/te_macros]: https://source.corp.google.com/chromeos_public/src/platform2/sepolicy/policy/base/imported/te_macros
+[chromeos/te_macros]: https://source.corp.google.com/chromeos_public/src/platform2/sepolicy/policy/chromeos/te_macros