# Linux security

# Управление группами и пользователями

**Команды групп**

<table border="1" id="bkmrk-%D0%9A%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-gro" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 30.6253%;"></col><col style="width: 69.3747%;"></col></colgroup><thead><tr><td class="align-center">Команда</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>sudo adduser username</td><td>интерактивно создает пользователя с паролем и группой. Поведение настраивается в файлах /etc/adduser.conf Нельзя использовать в скриптах.

При помощи encryptfs-utils можно зашифровать домашнюю директорию

\--encrypt-home

</td></tr><tr><td>sudo useradd username</td><td>создает пользователя без группы и пароля. Поведение настраивается флагами и /etc/login.defs.

-m создает домашнюю директорию

-d определяет домашнюю директорию

-s определяет консоль по умолчанию

</td></tr><tr><td>groups</td><td>Список групп</td></tr><tr><td>sudo visudo</td><td>Настройка прав групп

-f fname определяет дополнительный файл из include директории

</td></tr><tr><td>sudo usermod -a -G sudo sergey</td><td>Добавить пользователя в группу sudo.

-a оставляет существующие группы. Без -a пользователь будет исключен из остальных групп

</td></tr><tr><td>sudo userdel username</td><td>Удалить пользователя

</td></tr><tr><td>last</td><td>Последние авторизовавшиеся пользователи

</td></tr></tbody></table>

**Информация о пользователях, паролях, группах**

/etc/passwd /etc/shadow /etc/group /etc/gshadow

Служба nss отвечает за хранение данных в любых хранилищах (вплоть до SQL). /etc/nsswitch.conf

Определение библиотек, установленных у службы nss

```
~$ find /lib/ -name 'libnss_*'
/lib/x86_64-linux-gnu/libnss_compat.so.2
/lib/x86_64-linux-gnu/libnss_files.so.2
/lib/x86_64-linux-gnu/libnss_hesiod.so.2
/lib/x86_64-linux-gnu/libnss_systemd.so.2
/lib/x86_64-linux-gnu/libnss_dns.so.2
```

**Настройка visudo**

<table border="1" id="bkmrk-%D0%AD%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-%23-%D0%9A" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 29.0922%;"></col><col style="width: 70.9078%;"></col></colgroup><thead><tr><td class="align-center">Элемент</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>\#</td><td>Комментарий</td></tr><tr><td>% в начале строки</td><td>Работа с группой. %sudo обозначает настройку группы sudo</td></tr><tr><td>Структура назначения прав</td><td>%sudo ALL=(ALL) ALL

обозначает, что группа sudo может выполнять на всех хостах от имени всех пользователей любые действия

</td></tr><tr><td>NOPASSWD:</td><td>без ввода пароля sudo

%sudo ALL=(ALL) NOPASSWD: ALL

</td></tr><tr><td>User\_Alias alias\_name = username1, username2</td><td>Псевдоним для имен пользователей.

User\_Alias WEBADMINS = sergey, dimitry

</td></tr><tr><td>Cmnd\_Alias alias\_name = cmnd1, cmnd2</td><td>Псевдоним для команд.

Cmnd\_Alias SOFTWARE /bin/apt /bin/apt-get

Если команда перечисляется без субкоманд, то пользователю даются права на все субкоманды. Иначе, при перечислении субкоманд - только на них. Но при добавлении субкоманд требуется указывать полную строку. Например, если указать /ust/bin/systemctl status, то пользователь будет иметь право вызвать эту команду, но она нефункциональна - требует имя сервиса, а его задать уже нельзя. Можно использовать \*

/ust/bin/systemctl status \*

/ust/bin/systemctl \* sshd

В списке могут быть и файлы, доступные для редактирования. Например   
/usr/bin/nano /etc/ssh/sshd\_config

</td></tr><tr><td>WEBADMINS ALL=(ALL) SOFTWARE</td><td>Пользователи WEBADMINS могут запускать команды SOFTWARE через sudo

</td></tr><tr><td>Host\_Alias MAILSERVERS = smtp</td><td>Используется при распространении единого файла sudoers на все машины в сети. Ограничивает хосты, где работает данное правило

WEBADMINS WEBSERVERS=(ALL) WEBCOMMANDS

</td></tr><tr><td>Defaults timestamp\_timeout = 0</td><td>Таймаут при необходимости ввода пароля sudo. Можно назначить только определенным пользователям

Defaults:dmitry timestamp\_timeout = 0

</td></tr><tr><td>@includedir dirname</td><td>для логического разбиения одного файла на группы. Подключается любой файл, если он не содержит в названии точку (.) или не заканчивается тильдой (~).   
Файлы анализируются в лексическом порядке. Например, /etc/sudoers.d/01\_first анализируется перед /etc/sudoers.d/10\_second.   
После анализа файлов в каталоге контроль возвращается к файлу, который содержал директиву @includedir.

</td></tr></tbody></table>

Получается нужны шаблоны для определения действий в зависимости от роли пользователей. Их может быть немало)

**Требования к паролю**

```
sudo apt install libpam-pwquality
```

Настройки требований к паролю в файле /etc/security/pwquality.conf

<table border="1" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-mi" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 34.9405%;"></col><col style="width: 65.1786%;"></col></colgroup><thead><tr><td class="align-center">Параметр</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>minlen=8</td><td>Минимальная длина пароля</td></tr><tr><td>minclass=3</td><td>Минимальное количество классов символов в пароле</td></tr></tbody></table>

Период обновления пароля

chage -l username

**Блокировка пароля при неправильном вводе**

Практически, нельзя устанавливать блокировку пароля после 3 неправильных вводов.

/etc/pam.d/login

# Firewall

Исходя из общей теории брандмауэров, можно сделать вывод: для enterprise решений каждый уровень модели TCP/IP должен быть защищен. Однако статичные правила работают неэффективно. Должны быть межуровневые взаимодействия, позволяющие передавать например информацию о подозрительной активности на уровне приложений, на уровень IP фильтрации и блокировать данную активность на уровне IP. Т е enterprise решение должно объединять в себе данные всех уровней в одну картину. Кроме этого, желательно объединение аппаратных и программных решений, т е данные о необходимости блокировки передаются между физическими устройствами.

**Политики блокировки**

Адреса - источники, которые нужно блокировать на внешнем интерфейсе

- Ваш IP адрес, lo
- IP адреса вашей локальной сети
- Частные адреса класса A, B и C
- Мультикастовые класса D и зарезервированные класса E
- Также можно блокировать Carrier-grade NAT сети (100.64.0.0-100.127.255.255) и TEST-NET (192.0.2.0-192.0.2.255)
- Есть стратегия блокировки ненадежных пулов (наверное, где-то есть список)
- Можно добавить блокировку бродкаста, но это редко используется

Возможно ограничение количества пакетов от источника, порты удаленного источника (&gt;1023), блокировка по флагу статуса TCP соединения (флаг должен быть SYN, не ACK).

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

netfilter - встроенный firewall. Консольные утилиты для управления netfilter:

- iptables - для v4 и v6 различные
- ebtables - mac briging правила
- arptables - правил трансляции arp

ufw - фронтенд для iptables

nftables - иная реализация

firewalld - реализация в RedHat

**Какой firewall сейчас активен**

Могут быть установлен и iptables, и nftables. Если вывод следующей команды не пустой, значит убедимся, что модуль nft активен:

```
sudo nft list ruleset
```

Проверяем модуль ядра:

```
lsmod | grep nf_tables
```

Если вывод типа

```
nf_tables             376832  114 nft_compat,nft_chain_nat
```

значит nftables загружен.

Модуль iptables еще присутствует в ядре, но как говорят - для вида.

```
sudo lsmod | grep ip_tables
ip_tables              32768  0
x_tables               65536  8 xt_conntrack,nft_compat,xt_tcpudp,xt_addrtype,xt_nat,xt_set,ip_tables,xt_MASQUERADE
```

Есть промежуточный пакет iptables-nft, который транслирует правила из iptables, Но работает именно nft. Однако редактировать nft таблицы с комментариями

```
# Warning: table ip filter is managed by iptables-nft, do not touch!
```

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

В Alt Linux, nft по умолчанию не установлен.

**Iptables**

<span style="color: rgb(224, 62, 45);">Существующие сессии ssh не блокируются.</span>

Состоит из 4 таблиц:

- Filter table Базовая защита, обычно используется
- NAT table
- Mangle table Изменение сетевых пакетов при их прохождении через брандмауэр
- Security table Используется в системах с установленным SELinux

Каждая таблица состоит из цепочек правил. Filter table состоит из цепочек INPUT, FORWARD, OUTPUT

Просмотр существующих таблиц

```
sudo iptables -L <имя цепочки или ничего> --line-numbers -v 
```

**Сохранение правил после перезагрузки сервера**

```
sudo apt install iptables-persistent
```

Затем сохраняем

```
sudo netfilter-persistent save
```

После этого правила сохраняются в /etc/iptables\*

**Структура команды**

```
iptables <option> <chain> <matching criteria> <target>
```

Пример:

```
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
```

<table border="1" id="bkmrk-%D0%90%D1%80%D0%B3%D1%83%D0%BC%D0%B5%D0%BD%D1%82-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5--a" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 21.8117%;"></col><col style="width: 78.1883%;"></col></colgroup><thead><tr><td class="align-center">Аргумент</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td colspan="2">Option параметры

</td></tr><tr><td>-A, -I</td><td>Добавить в конец или в определенное место цепочки.

-A INPUT

-I INPUT 1

</td></tr><tr><td>-R</td><td>заменить цепочку

</td></tr><tr><td>-P</td><td>Задает дефолтную политику для цепочки.

```
iptables -P FORWARD DROP
```

</td></tr><tr><td>-D цепочка номер</td><td>Удалить запись

```
sudo iptables -D DOCKER-USER 1
```

</td></tr><tr><td>-N</td><td>Создать пользовательскую цепочку правил

</td></tr><tr><td>-F, -X</td><td>Удалить цепочки / пользовательские цепочки

</td></tr><tr><td>-E</td><td>Переименовать пользовательскую цепочку

</td></tr><tr><td class="align-center" colspan="2">Matching criteria параметры</td></tr><tr><td>-m</td><td>Модуль.</td></tr><tr><td>--ctstate </td><td>Состояние пакета. Перечисляется через запятую без пробелов.</td></tr><tr><td>-p</td><td>Тип соединения, tcp/udp/icmp</td></tr><tr><td>--dport</td><td>порт назначения

\--dport ssh

с опцией -m можно перечислять через запятую без пробелов

```
-m multiport --dport 2049,1080,3128
```

-m должна идти строго после -p ...

через : диапазон портов, без multiport

</td></tr><tr><td>--port</td><td>Определяет и входящий, и исходящий порты

</td></tr><tr><td>-i -o</td><td>Интерфейс (входящий/исходящий)

-i lo

</td></tr><tr><td>-s -d</td><td>IP источника / приемника

</td></tr><tr><td>  
</td><td>Кроме этого, еще есть фильтры по:

- Текущее состояние соединения
- Список портов (поддерживаемых многопортовым модулем)
- MAC-адрес источника аппаратного Ethernet или физического устройства
- Тип адреса, тип пакета канального уровня или диапазон IP-адресов
- Различные части пакетов IPSec или политика IPSec
- Тип протокола ICMP
- Длина пакета
- Время получения пакета
- Каждый n-й пакет или случайные пакеты
- Идентификатор пользователя, группы, процесса или группы процессов отправителя пакета
- Поле типа обслуживания (TOS) заголовка IP (возможно, заданное в таблице управления)
- Раздел TTL заголовка IP
- Поле iptables mark (устанавливается в таблице управления)
- Соответствие пакетов с ограниченной скоростью

</td></tr><tr><td colspan="2">Target параметры

</td></tr><tr><td>-j</td><td>Действие при соблюдении условия

ACCEPT разрешить пакет

DROP тихо откинуть пакет

REJECT вернуть ответ о блокировании запрашивающей стороне

RETURN вернуть в родительскую цепочку. Используется в случае родительских / дочерних цепочек.

Еще есть очередь QUEUE

Может быть переход к пользовательской цепочке, с возвратом обратно

</td></tr><tr><td>-g</td><td>переход к другой цепочке без возврата обратно

</td></tr><tr><td>-c</td><td>Инициализация счетчиков

</td></tr></tbody></table>

В OUTPUT цепочке есть возможность фильтровать по пользователю, группе, процессу, заголовкам безопасности - полный цикл управления.

Также возможна настройка блокировки по времени. Также можно фильтровать каждый N пакет например для логирования. И это все на уровне ядра!

Разрешение доступа для ssh

```
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
```

Здесь для определения порта по названию использовался файл /etc/services То есть возможно прописать свое название службы в данный файл и использовать его в правилах.

```
cat /etc/services | grep http
# Updated from https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml .
http            80/tcp          www             # WorldWideWeb HTTP
https           443/tcp                         # http protocol over TLS/SSL
http-alt        8080/tcp        webcache        # WWW caching service
http-serg       8081/tcp                        # test server
```

Затем правилом разрешаем доступ по имени службы. Однако не понятно, почему нужно определять тип соединения. Похоже, что из файла берется только номер порта.

```
sudo iptables -I INPUT 1 -p tcp --dport http-serg -j ACCEPT
```

Разрешение доступа к lo

```
sudo iptables -I INPUT 1 -i lo -j ACCEPT
```

**Логирование**

Лог всех пакетов (и входящие, и исходящие), на порту 8090.

```
sudo iptables -A INPUT -p tcp --dport 8090 -j LOG --log-prefix "IPTABLES-8090-IN: "
sudo iptables -A INPUT -p udp --dport 8090 -j LOG --log-prefix "IPTABLES-8090-IN: "
sudo iptables -A OUTPUT -p tcp --sport 8090 -j LOG --log-prefix "IPTABLES-8090-OUT: "
sudo iptables -A OUTPUT -p udp --sport 8090 -j LOG --log-prefix "IPTABLES-8090-OUT: "
```

Лог только новых соединений:

```
sudo iptables -A INPUT -p tcp --dport 8090 -m conntrack --ctstate NEW -j LOG --log-prefix "NEW-8090-CONN: "
```

Просмотр лога в реальном времени:

```
sudo tail -f /var/log/syslog | grep "IPTABLES-8090"
# или
sudo tail -f /var/log/kern.log | grep "IPTABLES-8090"
```

**Блокировка по географическому признаку**

Работает на уровне ядра. Проверка установлен ли модуль.

```
lsmod | grep xt_geoip

sudo apt update
sudo apt install xtables-addons-common xtables-addons-source build-essential dkms
sudo modprobe xt_geoip
```

**Загрузка геобазы.**

Вариант 1 (не доделал)

[Страница создания аккаунта](https://www.maxmind.com/en/geolite2/signup) Из России пока что нельзя создать новую учетку. Надеюсь скоро все изменится. Создали учетку, Управление аккаунтом - Управление ключами лицензирования. Создаем новый ключ, скачиваем конфиг на всякий случай.

Создаем директорию и скачиваем текущую базу

```
mkdir -p /usr/share/xt_geoip
cd /usr/share/xt_geoip

wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=ВАШ_КЛЮЧ&suffix=zip" -O GeoLite2-Country-CSV.zip

unzip GeoLite2-Country-CSV.zip -d geolite
```

Теперь нужно преобразовать базу в требуемый формат. Но перед этим в ubuntu возникло несколько проблем. Одна с размещением скрипта.

```
dpkg -L xtables-addons-common | grep xt_geoip
/usr/bin/xt_geoip_query
/usr/lib/x86_64-linux-gnu/xtables/libxt_geoip.so
/usr/libexec/xtables-addons/xt_geoip_build
/usr/libexec/xtables-addons/xt_geoip_build_maxmind
/usr/libexec/xtables-addons/xt_geoip_dl
/usr/libexec/xtables-addons/xt_geoip_dl_maxmind
/usr/share/man/man1/xt_geoip_build.1.gz
/usr/share/man/man1/xt_geoip_build_maxmind.1.gz
/usr/share/man/man1/xt_geoip_dl.1.gz
/usr/share/man/man1/xt_geoip_dl_maxmind.1.gz
/usr/share/man/man1/xt_geoip_query.1.gz
```

Далее нужно было преобразовать в формат при помощи python скрипта, поскольку Ubuntu изменил формат для базы. Или -

Вариант 2

На [странице сервиса](https://db-ip.com/db/download/ip-to-country-lite) находим ссылку на текущую версию, скачиваем

```
wget https://download.db-ip.com/free/dbip-country-lite-2025-08.csv.gz -O dbip-country-lite.csv.gz
gunzip dbip-country-lite.csv.gz
```

**Преобразовываем базу данных (поиск размещения скрипта в Варианте 1)**

```
sudo /usr/libexec/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip dbip-country-lite.csv
```

**Пример разрешения / блокировки по геопризнаку**

```
sudo iptables -A INPUT -m geoip --src-cc RU -j ACCEPT
sudo iptables -A INPUT -m geoip --src-cc CN,IR,KP -j DROP
sudo iptables -A INPUT -p tcp --dport https -m geoip --src-cc RU -j ACCEPT
```

**Примеры настройки**

**Пример настройки iptables**

Политика:

- Разрешить доступ к службам http, https на докере для всех
- Разрешить все исходящие соединения
- Разрешить доступ для ip1
- Docker должен функционировать корректно
- Все остальное запретить

```
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -s 1.1.1.1 -j ACCEPT
sudo iptables -I INPUT 1 -p icmp --icmp-type echo-request -j ACCEPT

sudo iptables -A INPUT -i docker0 -j ACCEPT
sudo iptables -P INPUT DROP

sudo iptables -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A DOCKER-USER -s 1.1.1.1 -p tcp --dport 5432 -j ACCEPT
sudo iptables -A DOCKER-USER -p tcp --dport 5432 -j DROP
```

# Введение в Linux security modules

Система безопасности основана на дополнительном хуке (LSM hook) при вызове системных (ядерных) функций. Система модульная, и SELinux - один из модулей, который предоставляет функции безопасности. DAC система находится ниже. Стек вызовов функции:

[![se_high_overwiew.JPG](http://bobrobotirk.ru/uploads/images/gallery/2025-08/scaled-1680-/se-high-overwiew.JPG)](http://bobrobotirk.ru/uploads/images/gallery/2025-08/se-high-overwiew.JPG)

LSM hook не предоставляет функций безопасности - это просто хук. Далее идет вызов зарегистрированного модуля(ей) LSM Framework. В LSM Framework можно зарегистрировать один эксклюзивный модуль и неэксклюзивные.

<table id="bkmrk-%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C-%D0%9E%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8-%D0%93" style="width: 111.429%;"><thead><tr><th style="width: 23.1228%;">Модуль</th><th style="width: 33.0246%;">Особенности</th><th style="width: 35.271%;">Где используется</th><th style="width: 8.46246%;">Тип</th></tr></thead><tbody><tr><td style="width: 23.1228%;">**SELinux**</td><td style="width: 33.0246%;">Метки безопасности (label-based), очень гибкая и строгая политика</td><td style="width: 35.271%;">RHEL, Fedora, CentOS, Android</td><td style="width: 8.46246%;">Экск.</td></tr><tr><td style="width: 23.1228%;">**AppArmor**</td><td style="width: 33.0246%;">Основан на путях (path-based), проще в настройке</td><td style="width: 35.271%;">Ubuntu, Debian, openSUSE</td><td style="width: 8.46246%;">Экск.</td></tr><tr><td style="width: 23.1228%;">**Smack (Simplified Mandatory Access Control Kernel)**</td><td style="width: 33.0246%;">Проще, чем SELinux, тоже использует метки, но менее гибкий</td><td style="width: 35.271%;">Встроенные системы (Tizen, некоторые IoT-устройства)</td><td style="width: 8.46246%;">Экск.</td></tr><tr><td style="width: 23.1228%;">**TOMOYO Linux**</td><td style="width: 33.0246%;">Основной акцент на управление доступом на основе процессов и истории их действий (обучение)</td><td style="width: 35.271%;">Япония, встраиваемые системы</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**Yama**</td><td style="width: 33.0246%;">Маленький LSM для ограничения `ptrace` (трассировки процессов)</td><td style="width: 35.271%;">Включён в ядро по умолчанию (Ubuntu, Debian, Arch)</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**Landlock**</td><td style="width: 33.0246%;">Новый LSM (c 2021 г., Linux 5.13+), даёт приложениям возможность ограничивать **себя** (sandboxing)</td><td style="width: 35.271%;">Современные Debian/Ubuntu, используется для sandbox-браузеров и контейнеров</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**LoadPin**</td><td style="width: 33.0246%;">Гарантирует загрузку модулей ядра только из доверенной FS</td><td style="width: 35.271%;">Chromebook, сервера</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**Integrity (IMA/EVM)**</td><td style="width: 33.0246%;">Контроль целостности файлов (подписи, хэши)</td><td style="width: 35.271%;">Корпоративные Linux-системы</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**Lockdown**</td><td style="width: 33.0246%;">Ограничивает root-доступ к ядру (часть upstream ядра с 5.4)</td><td style="width: 35.271%;">Включён в Debian, Ubuntu, Fedora</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**Capability**</td><td style="width: 33.0246%;">Базовый модуль, модель минимально необходимых привилегий. Всегда включён.</td><td style="width: 35.271%;">  
</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**bpf**</td><td style="width: 33.0246%;">Контроль безопасности eBPF-программ</td><td style="width: 35.271%;">  
</td><td style="width: 8.46246%;">Неэкск.</td></tr><tr><td style="width: 23.1228%;">**ipe**</td><td style="width: 33.0246%;">Политики целостности (разрешение/запрет запуска бинарников)</td><td style="width: 35.271%;">  
</td><td style="width: 8.46246%;">Неэкск.</td></tr></tbody></table>

Список используемых LSM модулей

```
cat /sys/kernel/security/lsm
lockdown,capability,landlock,yama,apparmor,tomoyo,bpf,ipe,ima,evm
```

Естественно модули для непересекающихся задач не конфликтуют.

# Анализ исполняемого файла

ldd ./program

```
$ ldd /bin/ls
        linux-vdso.so.1 (0x00007fff2b9fe000)
        libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f3cdd5b3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3cdd1b0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3cdd7e0000)
```

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

readelf -d  
Читает динамическую таблицу ELF-файла и показывает список библиотек, от которых он зависит.

```
$ readelf -d /usr/bin/mate-calc | grep NEEDED
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libgtk-3.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libgdk-3.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libatk-1.0.so.0]
```

objdump -p

Аналогично readelf, но может показать больше контекста.

```
objdump -p /usr/bin/mate-calc | grep NEEDED                                                                                 
  NEEDED               libgtk-3.so.0
  NEEDED               libgdk-3.so.0
  NEEDED               libpango-1.0.so.0
  NEEDED               libatk-1.0.so.0
```

В рантайме — strace

Если вы хотите узнать, какие библиотеки реально подгружаются при запуске (в том числе через dlopen() во время работы):

```
strace -e open ./program 2>&1 | grep '\.so'
```

Если программа статически слинкована (т.е. все зависимости включены внутрь ELF), то ни ldd, ни readelf не покажут зависимостей.

Проверить это можно так:

```
file ./program
```

**Пример:**

```
# динамическая линковка
file /usr/bin/mate-calc                                                                                                     
/usr/bin/mate-calc: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=58d991a9b15b10d59d235c79b2132fde101cf1fc, for GNU/Linux 3.2.0, stripped

# статическая линковка
... statically linked ...
```

Пример анализа зависимостей для /usr/bin/grep.

1\. Проверим, какой это тип ELF-файла

```
file /usr/bin/grep
/usr/bin/grep: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter \
/lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped
```

Значит, это динамически слинкованный ELF, и у него есть внешние зависимости.

2\. Смотрим список зависимостей через ldd

```
ldd /usr/bin/grep
        linux-vdso.so.1 (0x00007fff43dfe000)
        libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f3f5a8b0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3f5a4a0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3f5aaf0000)
```

Интерпретация:

- libpcre2-8.so.0 — библиотека регулярных выражений PCRE2.
- libc.so.6 — стандартная библиотека C (glibc).
- ld-linux-x86-64.so.2 — динамический загрузчик ELF.

3\. Альтернатива: readelf -d

```
readelf -d /usr/bin/grep | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libpcre2-8.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
```

Это подтверждает те же зависимости.

4\. Проверим, какие библиотеки реально подгружаются при запуске (в том числе через dlopen())

```
strace -e openat /usr/bin/grep "test" /etc/passwd 2>&1 | grep '\.so'
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
```

5\. Проверим динамический загрузчик (интерпретатор ELF)

```
readelf -l /usr/bin/grep | grep 'interpreter'
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
```

Это та программа, которая первым делом загружает бинарь и его библиотеки.

Итог:

<table id="bkmrk-%D0%A2%D0%B8%D0%BF-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B8-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC"><thead><tr><th>Тип проверки</th><th>Инструмент</th><th>Что показывает</th></tr></thead><tbody><tr><td>Тип ELF</td><td>`file`</td><td>Статически или динамически слинкован</td></tr><tr><td>Динамические зависимости</td><td>`ldd`, `readelf -d`, `objdump -p`</td><td>Список библиотек</td></tr><tr><td>Реальные загрузки во время работы</td><td>`strace`</td><td>Библиотеки, подгружаемые во время исполнения</td></tr><tr><td>ELF-интерпретатор</td><td>`readelf -l`</td><td>Путь к динамическому загрузчику</td></tr></tbody></table>

Можно проверить, какие именно функции приложение импортирует из библиотек.

Теперь углубимся на уровень **символов (функций)**, которые исполняемый файл импортирует из библиотек — например, какие функции `grep` реально использует из `libc`, `libpcre2` и других.

**1. Проверим импортированные символы (динамически загружаемые функции)**

Для этого можно использовать:

```bash
readelf -Ws /usr/bin/grep | grep ' UND '

```

или короче:

```bash
readelf -Ws /usr/bin/grep | grep UND | less

```

- `-W` — показывает полные строки.
- `-s` — выводит таблицу символов.
- `UND` означает *undefined symbol* — то есть функция **определена в внешней библиотеке** (т.е. импортируется).

---

Пример вывода (сокращённо)

```
Num:    Value  Size Type    Bind   Vis      Ndx Name
  45: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strcmp@GLIBC_2.2.5
  72: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.2.5
  89: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND regexec@LIBPCRE2_8
 114: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.2.5
 132: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fprintf@GLIBC_2.2.5

```

**Расшифровка:**

- `strcmp`, `malloc`, `free`, `fprintf` → из `libc`
- `regexec` → из `libpcre2-8.so.0`

---

2\. Посчитать, сколько внешних символов программа импортирует

Можно примерно оценить так:

```bash
readelf -Ws /usr/bin/grep | grep ' UND ' | wc -l

```

Например, может вывести:

```
125

```

значит, `grep` использует около 125 внешних функций из библиотек.

---

3\. Уточнить, из какой именно библиотеки берётся символ

Команда `ldd` показывает пути библиотек, а `readelf` — имена функций, но если ты хочешь **увидеть, какой именно `.so` экспортирует нужную функцию**, можно воспользоваться `objdump` или `nm`.

Пример: узнать, где определена функция `regexec`

```bash
for lib in /lib/x86_64-linux-gnu/*.so*; do
    nm -D $lib 2>/dev/null | grep ' regexec$' && echo "→ $lib"
done

```

**Результат:**

```
000000000001f230 T regexec
→ /lib/x86_64-linux-gnu/libpcre2-8.so.0

```

---

4\. Альтернатива: `objdump -T`

Если хочешь посмотреть **все экспортируемые символы библиотеки**:

```bash
objdump -T /lib/x86_64-linux-gnu/libc.so.6 | grep printf

```

Это покажет строку вроде:

```
0000000000054350 g    DF .text  00000000000001a5  GLIBC_2.2.5 printf

```

 Резюме

<table id="bkmrk-%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0-%D0%9A%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-%D0%A7%D1%82%D0%BE-%D0%BF"><thead><tr><th>Задача</th><th>Команда</th><th>Что показывает</th></tr></thead><tbody><tr><td>Список импортированных функций</td><td>`readelf -Ws program</td><td>grep UND`</td></tr><tr><td>Кол-во импортов</td><td>`readelf -Ws program</td><td>grep UND</td></tr><tr><td>Где определён символ</td><td>`nm -D /lib/...</td><td>grep &lt;имя&gt;`</td></tr><tr><td>Все экспортируемые символы из .so</td><td>`objdump -T libname.so`</td><td>Список функций, предоставляемых библиотекой</td></tr></tbody></table>

---