# Профиль приложений

Профиль приложений - это механизм, предоставляемый KernelSU для настройки конфигурации различных приложений.

Для приложений, получивших права root (т.е. имеющих возможность использовать `su`), App Profile может также называться Root Profile. Он позволяет настраивать правила `uid`, `gid`, `groups`, `capabilities` и `SELinux` команды `su`, тем самым ограничивая привилегии пользователя root. Например, она может предоставлять сетевые права только приложениям межсетевого экрана, отказывая в праве доступа к файлам, или предоставлять права shell вместо полного root-доступа для приложений freeze: **сохранение власти в рамках принципа наименьших привилегий*.

Для обычных приложений, не имеющих прав root, App Profile может управлять поведением ядра и системы модулей по отношению к этим приложениям. Например, он может определять, следует ли обращать внимание на модификации, возникающие в результате работы модулей. На основе этой конфигурации ядро и система модулей могут принимать решения, например, выполнять операции, аналогичные "скрытию".

## Корневой профиль

### UID, GID и группы

В системах Linux существуют два понятия: пользователи и группы. Каждый пользователь имеет идентификатор пользователя (UID), а пользователь может принадлежать к нескольким группам, каждая из которых имеет свой идентификатор группы (GID). Эти идентификаторы используются для идентификации пользователей в системе и определяют, к каким системным ресурсам они могут получить доступ.

Пользователи с UID, равным 0, называются корневыми пользователями, а группы с GID, равным 0, - корневыми группами. Группа пользователей root, как правило, обладает самыми высокими системными привилегиями.

В случае системы Android каждое приложение является отдельным пользователем (исключая сценарии с общим UID) с уникальным UID. Например, `0` представляет пользователя root, `1000` - `system`, `2000` - ADB shell, а UID в диапазоне от 10000 до 19999 - обычные приложения.

:::info
Здесь упомянутый UID не совпадает с концепцией нескольких пользователей или рабочих профилей в системе Android. На самом деле рабочие профили реализуются путем разделения диапазона UID. Например, 10000-19999 представляет собой основного пользователя, а 110000-119999 - рабочий профиль. Каждое обычное приложение среди них имеет свой уникальный UID.
:::

Каждое приложение может иметь несколько групп, причем GID представляет собой основную группу, которая обычно совпадает с UID. Другие группы называются дополнительными. Определенные разрешения контролируются через группы, например, разрешения на доступ к сети или доступ к Bluetooth.

Например, если мы выполним команду `id` в оболочке ADB, то результат может выглядеть следующим образом:

```sh
oriole:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),1078(ext_data_rw),1079(ext_obb_rw),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid),3012(readtracefs) context=u:r:shell:s0
```

Здесь UID равен `2000`, а GID (идентификатор основной группы) также равен `2000`. Кроме того, он входит в несколько дополнительных групп, таких как `inet` (указывает на возможность создания сокетов `AF_INET` и `AF_INET6`) и `sdcard_rw` (указывает на права чтения/записи на SD-карту).

Корневой профиль KernelSU позволяет настраивать UID, GID и группы для корневого процесса после выполнения команды `su`. Например, в корневом профиле корневого приложения можно установить его UID на `2000`, что означает, что при использовании `su` фактические разрешения приложения будут находиться на уровне оболочки ADB. Группа `inet` может быть удалена, что не позволит команде `su` получить доступ к сети.

:::tip Примечание
Профиль приложений контролирует только разрешения корневого процесса после использования `su`; он не контролирует разрешения самого приложения. Если приложение запросило разрешение на доступ к сети, оно может получить доступ к сети даже без использования `su`. Удаление группы `inet` из `su` только предотвращает доступ `su` к сети.
:::

Корневой профиль реализуется в ядре и не зависит от добровольного поведения root-приложений, в отличие от переключения пользователей или групп через `su`, предоставление прав `su` полностью зависит от пользователя, а не от разработчика.

### Привилегии

Привилегии - это механизм разделения привилегий в Linux.

В традиционных реализациях UNIX для проверки прав доступа выделяются две категории процессов: привилегированные процессы (эффективный идентификатор пользователя равен 0 и называется суперпользователем или root) и непривилегированные процессы (эффективный UID которых не равен нулю).  Привилегированные процессы обходят все проверки прав ядра, в то время как непривилегированные процессы подвергаются полной проверке прав на основе учетных данных процесса (обычно: эффективный UID, эффективный GID и список дополнительных групп).

Начиная с версии Linux 2.2, в Linux привилегии, традиционно ассоциируемые с суперпользователем, разделены на отдельные единицы, называемые возможностями, которые могут быть независимо включены и выключены.

Каждая способность представляет собой одну или несколько привилегий. Например, `CAP_DAC_READ_SEARCH` представляет собой возможность обхода проверок прав на чтение файлов, а также прав на чтение и выполнение каталогов. Если пользователь с эффективным UID `0` (пользователь root) не имеет возможности `CAP_DAC_READ_SEARCH` или более высоких возможностей, это означает, что, хотя он и является пользователем root, он не может читать файлы по своему усмотрению.

Корневой профиль KernelSU позволяет настраивать возможности корневого процесса после выполнения `su`, тем самым добиваясь частичного предоставления "прав root". В отличие от вышеупомянутых UID и GID, некоторые root-приложения после использования `su` требуют UID, равный `0`. В таких случаях ограничение возможностей данного root-пользователя с UID `0` может ограничить их разрешенные операции.

:::tip Настоятельная рекомендация
В документе привелегий Linux [официальной документации](https://man7.org/linux/man-pages/man7/capabilities.7.html) дается подробное объяснение возможностей, представленных каждой привелегией. Если вы собираетесь настраивать привелегии, настоятельно рекомендуется сначала прочитать этот документ.
:::

### SELinux

SELinux - это мощный механизм обязательного контроля доступа (MAC). Он работает по принципу **запрет по умолчанию**: любое действие, не разрешенное в явном виде, запрещается.

SELinux может работать в двух глобальных режимах:

1. Разрешительный режим: События запрета регистрируются, но не выполняются.
2. Принудительный режим: События запрета регистрируются и выполняются.

:::warning Предупреждение
Современные системы Android в значительной степени опираются на SELinux для обеспечения общей безопасности системы. Настоятельно не рекомендуется использовать пользовательские системы, работающие в "разрешительном режиме", поскольку это не дает существенных преимуществ перед полностью открытой системой.
:::

Объяснение полной концепции SELinux является сложным и выходит за рамки данного документа. Рекомендуется сначала разобраться в его работе с помощью следующих ресурсов:

1. [Wikipedia](https://en.wikipedia.org/wiki/Security-Enhanced_Linux)
2. [Red Hat: Что такое SELinux?](https://www.redhat.com/en/topics/linux/what-is-selinux)
3. [ArchLinux: SELinux](https://wiki.archlinux.org/title/SELinux)

Корневой профиль KernelSU позволяет настраивать SELinux-контекст корневого процесса после выполнения команды `su`. Для этого контекста могут быть заданы специальные правила управления доступом, позволяющие осуществлять тонкий контроль над правами root.

В типичных сценариях, когда приложение выполняет команду `su`, оно переключает процесс на домен SELinux с **неограниченным доступом**, например `u:r:su:s0`. С помощью профиля Root Profile этот домен может быть переключен на пользовательский домен, например `u:r:app1:s0`, и для него может быть определен ряд правил:

```sh
type app1
enforce app1
typeattribute app1 mlstrustedsubject
allow app1 * * *
```

Обратите внимание, что правило `allow app1 * * *` используется только в демонстрационных целях. На практике это правило не должно широко использоваться, поскольку оно мало чем отличается от разрешительного режима.

### Эскалация

При неправильной настройке корневого профиля может возникнуть сценарий эскалации: ограничения, накладываемые корневым профилем, могут непреднамеренно не сработать.

Например, если предоставить права root пользователю ADB shell (что является обычным случаем), а затем предоставить права root обычному приложению, но настроить его профиль root с UID 2000 (это UID пользователя ADB shell), то приложение может получить полный доступ root, выполнив команду `su` дважды:

1. При первом выполнении команды `su` будет применен профиль App Profile и произойдет переход на UID `2000` (adb shell) вместо `0` (root).
2. При втором выполнении команды `su`, поскольку UID равен `2000`, а в конфигурации вы предоставили доступ root к UID `2000` (adb shell), приложение получит полные привилегии root.

:::warning Примечание
Такое поведение вполне ожидаемо и не является ошибкой. Поэтому мы рекомендуем следующее:

Если вам действительно необходимо предоставить права root в ADB (например, как разработчику), не рекомендуется изменять UID на `2000` при настройке корневого профиля. Лучше использовать `1000` (система).
:::

## Некорневой профиль

### Размонтирование модулей

KernelSU предоставляет бессистемный механизм модификации системных разделов, реализуемый через монтирование overlayfs. Однако некоторые приложения могут быть чувствительны к такому поведению. Поэтому мы можем выгрузить модули, смонтированные в этих приложениях, установив опцию "размонтирование модулей".

Кроме того, в интерфейсе настроек менеджера KernelSU имеется переключатель "размонтирование модулей по умолчанию". По умолчанию этот переключатель **включен**, что означает, что KernelSU или некоторые модули будут выгружать модули для данного приложения, если не будут применены дополнительные настройки. Если вам не нравится эта настройка или если она влияет на определенные приложения, у вас есть следующие возможности:

1. Оставить переключатель "размонтирование модулей по умолчанию" и индивидуально отключить опцию "размонтирование модулей" в профиле приложений для приложений, требующих загрузки модулей (действует как "белый список").
2. Отключить переключатель "размонтирование модулей по умолчанию" и индивидуально включить опцию "размонтирование модулей" в App Profile для приложений, требующих выгрузки модулей (действует как "черный список").

:::info
В устройствах, использующих ядро версии 5.10 и выше, выгрузку модулей выполняет само ядро. Однако для устройств с ядром версии ниже 5.10 этот переключатель является лишь опцией конфигурации, и KernelSU сам по себе не предпринимает никаких действий. Некоторые модули, например, Zygisksu, могут использовать этот переключатель для определения необходимости выгрузки модулей.
:::
