Android настоятельно рекомендует OEM-производителям тщательно тестировать свои реализации SELinux. Поскольку производители внедряют SELinux, им следует сначала применить новую политику к тестовому пулу устройств.
 После применения новой политики убедитесь, что SELinux работает в правильном режиме на устройстве, выполнив команду getenforce .
 Это печатает глобальный режим SELinux: Enforcing или Permissive. Чтобы определить режим SELinux для каждого домена, вы должны изучить соответствующие файлы или запустить последнюю версию sepolicy-analyze с соответствующим ( -p ) флагом, присутствующим в /platform/system/sepolicy/tools/ .
Чтение отказов
 Проверьте наличие ошибок, которые перенаправляются в виде журналов событий в dmesg и logcat и доступны для локального просмотра на устройстве. Производителям следует изучить выходные данные SELinux для dmesg на этих устройствах и уточнить настройки перед публичным выпуском в разрешительном режиме и, в конечном итоге, переключиться в принудительный режим. Сообщения журнала SELinux содержат avc: поэтому их легко найти с помощью grep . Можно захватить текущие журналы отказов, запустив cat /proc/kmsg или захватить журналы отказов из предыдущей загрузки, запустив cat /sys/fs/pstore/console-ramoops .
С помощью этого вывода производители могут легко определить, когда системные пользователи или компоненты нарушают политику SELinux. Затем производители могут исправить это плохое поведение, изменив программное обеспечение, политику SELinux или и то, и другое.
В частности, эти сообщения журнала указывают, какие процессы могут завершиться сбоем в принудительном режиме и почему. Вот пример:
avc: denied  { connectto } for  pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
Интерпретируйте этот вывод следующим образом:
-  { connectto }выше представляет предпринимаемое действие. Вместе сtclassв конце (unix_stream_socket) он примерно говорит вам, что к чему было сделано. В данном случае что-то пыталось подключиться к потоковому сокету unix.
-  scontext (u:r:shell:s0)говорит вам, какой контекст инициировал действие. В данном случае это что-то, работающее как оболочка.
-  tcontext (u:r:netd:s0)сообщает вам контекст цели действия. В данном случае это unix_stream_socket, принадлежащийnetd.
-  comm="ping"вверху дает вам дополнительную подсказку о том, что выполнялось в момент создания отказа. В данном случае это очень хорошая подсказка.
Другой пример:
adb shell su root dmesg | grep 'avc: '
Вывод:
<5> type=1400 audit: avc:  denied  { read write } for  pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file
Вот ключевые элементы этого отрицания:
-  Action — в скобках выделено предпринятое действие, read writeилиsetenforce.
-  Актер — scontext(исходный контекст) представляет актера, в данном случае демонаrmt_storage.
-  Объект — tcontext(целевой контекст) представляет объект, над которым выполняется действие, в данном случае kmem.
-  Результат . Запись tclass(целевой класс) указывает тип обрабатываемого объекта, в данном случае этоchr_file(символьное устройство).
Сброс пользовательских стеков и стеков ядра
В некоторых случаях информация, содержащаяся в журнале событий, недостаточна для точного определения источника отказа. Часто бывает полезно собрать цепочку вызовов, включая ядро и пространство пользователя, чтобы лучше понять, почему произошел отказ.
 Последние ядра определяют точку трассировки с именем avc:selinux_audited . Используйте Android simpleperf , чтобы включить эту точку трассировки и захватить цепочку вызовов.
Поддерживаемая конфигурация
-  Ядро Linux >= 5.10, в частности поддерживаются ветки Android Common Kernel mainline и android12-5.10 . Также поддерживается ветка android12-5.4 . Вы можете использовать simpleperf, чтобы определить, определена ли точка трассировки на вашем устройстве:adb root && adb shell simpleperf list | grep avc:selinux_audited. Для других версий ядра вы можете выбрать коммиты dd81662 и 30969bc .
- Должна быть возможность воспроизвести событие, которое вы отлаживаете. События времени загрузки не поддерживаются при использовании simpleperf; однако вы все еще можете перезапустить службу, чтобы вызвать событие.
Захват цепочки звонков
 Первый шаг — записать событие, используя simpleperf record :
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
 Затем должно сработать событие, вызвавшее отказ. После этого запись следует остановить. В этом примере с помощью Ctrl-c образец должен был быть захвачен:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
 Наконец, simpleperf report можно использовать для проверки захваченной трассировки стека. Например:
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children  Self     Command  Pid   Tid   Shared Object                                   Symbol
100.00%   0.00%    dmesg    3318  3318  /apex/com.android.runtime/lib64/bionic/libc.so  __libc_init
       |
       -- __libc_init
          |
           -- main
              toybox_main
              toy_exec_which
              dmesg_main
              klogctl
              entry_SYSCALL_64_after_hwframe
              do_syscall_64
              __x64_sys_syslog
              do_syslog
              selinux_syslog
              slow_avc_audit
              common_lsm_audit
              avc_audit_post_callback
              avc_audit_post_callback
 Приведенная выше цепочка вызовов представляет собой унифицированную цепочку вызовов ядра и пользовательского пространства. Это дает вам лучшее представление о потоке кода, запуская трассировку из пользовательского пространства вплоть до ядра, где происходит отказ. Дополнительные сведения о simpleperf см. в справочнике по исполняемым командам Simpleperf .
Переход на разрешительный
 Принудительное использование SELinux можно отключить через ADB в сборках userdebug или eng. Для этого сначала переключите ADB на root, запустив adb root . Затем, чтобы отключить принудительное использование SELinux, запустите:
adb shell setenforce 0
Или в командной строке ядра (во время раннего запуска устройства):
androidboot.selinux=permissiveandroidboot.selinux=enforcing
Или через bootconfig в Android 12:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
Использование аудита2разрешить
 Инструмент audit2allow принимает отказы dmesg и преобразует их в соответствующие заявления политики SELinux. Таким образом, это может значительно ускорить разработку SELinux.
Чтобы использовать его, запустите:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
 Тем не менее, необходимо внимательно изучить каждое потенциальное дополнение на предмет превышения разрешений. Например, подача audit2allow показанного ранее отказа rmt_storage приводит к следующему предлагаемому заявлению политики SELinux:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
 Это дало бы rmt возможность записывать память ядра, что является вопиющей дырой в безопасности. Часто операторы audit2allow являются лишь отправной точкой. После использования этих утверждений вам может потребоваться изменить исходный домен и метку цели, а также включить соответствующие макросы, чтобы получить правильную политику. Иногда рассматриваемый отказ вообще не должен приводить к каким-либо изменениям политики; скорее приложение-нарушитель должно быть изменено.
