Введение
Продолжаем серию рубрики Linux. В прошлой серии разобрали пользователей и группы – UID, GID, /etc/passwd. Теперь разберём что ядро делает с этими числами когда процесс пытается открыть файл или войти в директорию. Про права доступа легко выучить команды – chmod 755, chown user file – но не понимать что происходит под капотом. Тогда начинаются странные ситуации: «я же владелец, почему Permission denied?». Цель этой статьи – дать модель, а не только набор команд.
Вся статья построена на практике: каждый раздел можно пройти руками. Для большинства примеров достаточно обычного пользователя, для части нужен sudo. Где нужен – отмечено явно. Серия в основном под Ubuntu/Debian.
В конце статьи будет бонус который даст вам возможность изучить права доступа в Linux ещё доступнее и возможно проще.
1. Что такое права доступа и зачем они нужны
Linux – многопользовательская система. На одной машине одновременно работают процессы от разных пользователей: nginx читает файлы сайта, postgres работает со своими данными, разработчик ivan пишет код в своём каталоге. Без изоляции любой мог бы читать чужие ключи SSH, удалять чужие файлы, подменять конфиги сервисов.
Права доступа – механизм изоляции. Каждый файловый объект несёт метаданные: кто владелец, какая группа, кто что может делать. Метаданные хранятся в inode – структуре файловой системы которая описывает файл. Важно понимать: содержимое файла и его метаданные (включая права) хранятся раздельно. Когда вы делаете ls -la – вы читаете именно inode, а не сам файл.
Посмотрим на конкретный пример. Файл /etc/shadow хранит хеши паролей всех пользователей:
ls -la /etc/shadow
-rw-r----- 1 root shadow 1478 апр 16 12:03 /etc/shadow
Права гарантируют что читать его может только root и члены группы shadow. Обычный пользователь – нет. Разберём эту строку полностью, слева направо.
|
Часть |
Что означает |
|---|---|
|
|
тип файла и биты прав (разберём ниже) |
|
|
количество жёстких ссылок на файл |
|
|
владелец файла |
|
|
группа-владелец файла |
|
|
размер в байтах |
|
|
дата последнего изменения |
|
|
путь к файлу |
2. Модель UGO – три класса доступа
Стандартная модель Linux делит всех на три класса относительно конкретного файла.
U – User (владелец). Один конкретный пользователь. Когда создаёте файл – автоматически становитесь его владельцем. G – Group (группа). Одна конкретная группа. По умолчанию – primary group пользователя который создал файл. O – Others (остальные). Все кто не попал в первые два класса.
Для каждого из трёх классов устанавливается свой набор прав. Вот как это выглядит в выводе ls -la:
veil@veilos:~$ ls -ladrwxr-x---+ 19 veil veil 4096 апр 24 13:14 .
Первый символ – тип файла:
|
Символ |
Тип |
|---|---|
|
|
обычный файл |
|
|
директория |
|
|
символическая ссылка |
|
|
блочное устройство |
|
|
символьное устройство |
|
|
именованный канал (pipe) |
|
|
сокет |
Следующие 9 символов – три блока по три бита для U, G и O. Вернёмся к /etc/shadow:
- rw- r-- --- U G OU=rw- → владелец (root) читает и пишетG=r-- → группа (shadow) только читаетO=--- → все остальные – никаких прав
Каждый файл имеет ровно одного владельца и ровно одну группу – не двух, не список. Это ограничение стандартной модели UGO. Для более гибкого управления существуют ACL – разберём их в разделе 9.
3. Биты rwx – что они означают
Три бита в каждом блоке: r – read, w – write, x – execute. Установлен бит – операция разрешена. Сброшен (дефис) – запрещена. Смысл битов различается для файлов и директорий.
Для файлов
|
Бит |
Что разрешает |
|---|---|
|
|
читать содержимое ( |
|
|
изменять содержимое (редакторы, |
|
|
запускать как программу |
Для директорий
Здесь важно не путать – директория это тоже файл, просто специального типа. Биты работают иначе.
|
Бит |
Что разрешает |
|---|---|
|
|
читать список файлов внутри ( |
|
|
создавать и удалять файлы внутри |
|
|
входить ( |
На директориях бит х (проход) нужен, чтобы в дальнейшем войти через cd или обратиться к файлу по пути. r без x будет парадоксом, где список файлов через ls будет видно а открыть нельзя, поэтому r и x на директориях почти во многих случаях ставятся вместе.
4. Числовое и символьное представление
Существует два способа записывать права, и оба используются в реальной работе. Разберём оба.
Числовое (восьмеричное)
Каждый бит имеет числовое значение:
r = 4w = 2x = 1- = 0
Чтобы получить число для класса – складываем биты:
rwx = 4+2+1 = 7rw- = 4+2+0 = 6r-x = 4+0+1 = 5r-- = 4+0+0 = 4--- = 0+0+0 = 0
Итоговые права – три цифры, по одной для U, G, O:
755 → rwx r-x r-x644 → rw- r-- r--700 → rwx --- ---600 → rw- --- ---
777 означает что любой пользователь на системе может читать, изменять и запускать файл. На сервере где работают несколько пользователей – это дыра. Особенно опасно если это скрипт который запускается по cron от root – любой сможет подменить его содержимое. Используйте с осторожностью.
Шпаргалка по типовым комбинациям:
|
Права |
Символьно |
Когда применять |
|---|---|---|
|
|
|
Обычные файлы, конфиги |
|
|
|
Исполняемые файлы, директории |
|
|
|
Приватные ключи SSH, секреты |
|
|
|
Конфиги с паролями – группа читает, others нет |
|
|
|
Домашняя директория сервисного пользователя |
|
|
|
Директории сервисов |
|
|
|
Почти никогда – проблема безопасности |
Символьное
Удобно когда нужно добавить или убрать один бит не трогая остальные – не надо держать в голове итоговое число. Синтаксис: [кто][операция][что].
Кто: u – владелец, g – группа, o – остальные, a – все сразу (u+g+o).
Операция: + – добавить, - – убрать, = – установить точно (остальные биты сбросятся).
chmod u+x script.sh # добавить x владельцуchmod g-w file.txt # убрать w у группыchmod o=r file.txt # ровно r для others, остальное сбрасываетсяchmod a+x file.sh # добавить x всемchmod u+x,g-w file.txt # несколько операций через запятуюchmod go-rwx secret.txt # убрать всё у группы и others
Когда что удобнее: числовой – когда знаешь точное итоговое состояние. Символьный – когда хочешь изменить один бит не затрагивая остальные.
5. chmod – изменение прав
chmod (от change mode) – команда для изменения прав доступа.
# Числовым способомchmod 644 file.txtchmod 755 /var/www/htmlchmod 600 ~/.ssh/id_rsa# Символьным способомchmod u+x script.shchmod g+w shared/chmod o-rwx secret.txt# Рекурсивно для всего дерева каталоговchmod -R 750 /var/lib/app
Здесь есть типичная ловушка при настройке веб-серверов. Многие делают так:
chmod -R 755 /var/www/html
Эта команда поставит 755 на абсолютно все объекты – и директории, и файлы. Для директорий 755 нормально, им нужен x чтобы в них можно было входить. Но для файлов это означает что .html, .css, .jpg становятся исполняемыми – а этого не должно быть. Правильный способ – разделить файлы и директории:
# Директориям нужен x чтобы в них можно было входитьfind /var/www/html -type d -exec chmod 755 {} \;# Файлам x не нуженfind /var/www/html -type f -exec chmod 644 {} \;
После этого права будут корректные: директории – 755, файлы – 644, без лишнего x. Главное: не ставить права «на глаз» – всегда думайте кому реально нужен доступ.
6. chown и chgrp – смена владельца и группы
chown (от change owner) меняет владельца файла, группу, или оба сразу. chgrp (от change group) меняет только группу – по сути то же что chown :group, просто отдельная команда.
# Сменить только владельцаchown ivan file.txt# Сменить только группуchgrp developers file.txt# Сменить и владельца и группу сразуchown ivan:developers file.txt# Рекурсивноchown -R www-data:www-data /var/www/html
Обычный пользователь может поменять группу файла только на одну из своих собственных групп. Поменять владельца на другого пользователя – только root. Без этого ограничения можно было бы «подарить» вредоносный файл с SUID другому пользователю – и это стало бы простым способом эскалации привилегий.
7. Как ядро принимает решение о доступе
Это самый важный раздел статьи. Команды можно выучить, но без понимания алгоритма поведение системы будет казаться непредсказуемым. Особенно когда видишь Permission denied там где не ожидаешь.
7.1 Real vs Effective UID
Когда пользователь запускает программу, у процесса есть несколько идентификаторов. RUID (Real UID) – кто фактически запустил процесс. Не меняется в течение жизни процесса. EUID (Effective UID) – от чьего имени процесс работает прямо сейчас. Именно его проверяет ядро при обращении к файлу.
В большинстве случаев RUID == EUID. Но это различие становится важным при SUID – разберём в следующем разделе.
cat /proc/self/status | grep Uid
Uid: 1000 1000 1000 1000
Четыре числа в строке: Real UID, Effective UID, Saved UID (нужен для временного переключения прав), Filesystem UID (используется при проверке доступа к файлам – в большинстве случаев совпадает с EUID). Для понимания прав доступа ключевой – второй, EUID.
7.2 Алгоритм проверки прав
Когда процесс обращается к файлу, ядро проверяет права строго по порядку и останавливается на первом совпадении:
-
Если EUID = 0 (root) → доступ почти всегда разрешён
-
Если EUID совпадает с владельцем файла → используются права владельца
-
Если группа процесса (EGID или дополнительные группы) совпадает с группой файла → используются права группы
-
Во всех остальных случаях → используются права для остальных (others)
Система не комбинирует права – она берёт только один подходящий вариант и на этом заканчивает проверку.
7.3 Права не суммируются
Частая ловушка с которой сталкиваются многие. Допустим есть файл:
ls -la secret.txt# ----rwx--- 1 ivan developers secret.txt# U: --- G: rwx O: ---
Пользователь ivan является владельцем и одновременно входит в группу developers:
id ivan# uid=1001(ivan) gid=1001(ivan) groups=1001(ivan),1005(developers)
Но если ivan попробует прочитать файл – получит Permission denied. Почему? Ядро проверило: EUID процесса совпадает с UID файла – совпадение на шаге 2. Применило биты owner – ---. Остановилось. Биты group rwx даже не рассматривались. ivan является владельцем, но у владельца нет прав. Группа имеет полный доступ – но до неё проверка не дошла.
Решение – дать владельцу права явно:
chmod u+r secret.txt# или явно задать нужные праваchmod 740 secret.txt # u=rwx, g=r--, o=---
7.4 root и права
root (EUID=0) обходит проверку UGO для большинства операций – может читать любой файл, писать в любой файл независимо от прав. Но есть одно исключение: бит execute. Даже root не может запустить файл если ни у кого не установлен x:
chmod 644 script.shsudo ./script.sh# ./script.sh: Permission denied – даже для root
Чтобы запустить – сначала chmod +x script.sh, потом sudo ./script.sh. Это защита от случайного запуска: если x не установлен, файл не является исполняемым ни для кого, включая root.
8. Специальные биты – SUID, SGID, Sticky bit
Помимо стандартных rwx существуют три специальных бита. Каждый работает по-разному в зависимости от того – установлен он на файл или на директорию.
SUID (Set User ID)
При запуске файла с SUID процесс получает EUID = UID владельца файла, а не UID пользователя который его запустил. Пример – команда passwd. Обычный пользователь должен иметь возможность сменить свой пароль, а значит записать новый хеш в /etc/shadow. Но /etc/shadow доступен только root. SUID решает эту проблему: /usr/bin/passwd принадлежит root и имеет SUID – при запуске процесс временно получает EUID=0 и может писать в shadow.
ls -la /usr/bin/passwd# -rwsr-xr-x 1 root root 64152 Feb 6 /usr/bin/passwd
s вместо x в блоке владельца – SUID установлен. Заглавная S (без x) означает что SUID установлен но бит execute при этом не установлен – это подозрительная ситуация которой обычно не должно быть.
# Установить SUIDchmod u+s filechmod 4755 file # 4 – это SUID в числовом виде# Найти все файлы с SUID в системеfind / -perm -4000 -type f 2>/dev/null
SUID-бинарники – популярная цель при атаках на повышение привилегий. Если на стандартной утилите вроде vim, find или bash внезапно появился SUID – это серьёзный повод для расследования. Регулярно проверяйте список SUID-файлов и сравнивайте с эталоном.
Эталон – это список SUID-файлов, снятый в заведомо чистом состоянии системы (сразу после установки или после проверенного аудита). При следующих проверках вы сравниваете текущий список с ним и видите, что появилось нового.
SGID (Set Group ID)
SGID работает по-разному для файлов и директорий. На файл: процесс получает EGID = GID группы файла – аналог SUID но для группы. Используется редко. На директорию: все файлы и поддиректории созданные внутри автоматически наследуют группу этой директории, а не primary group создателя. Это ключевой механизм для совместной работы. В качестве примера возьмём несколько разработчиков которые работают с одной директорией. Без SGID каждый создаёт файлы со своей primary group – другие не могут их редактировать даже если входят в нужную группу. С SGID все файлы автоматически получают группу директории и все члены группы могут работать с ними без лишних телодвижений.
# Установить SGID на директориюchmod g+s /projectchmod 2755 /project # 2 – это SGID в числовом виде# Проверить – в выводе ls будет s вместо x в блоке группыls -la /project# drwxr-sr-x 2 ivan developers 4096 апр 29 /project
Sticky bit
Sticky bit решает конкретную проблему: если у пользователя есть право w на директорию – он может удалить из неё любой файл, даже чужой. На директорию: пользователь может удалить файл только если он является владельцем файла или владельцем директории. Просто иметь w на директорию – недостаточно. Пример – /tmp, где директория доступна на запись всем, но никто не должен удалять чужие файлы:
ls -la /# drwxrwxrwt 22 root root 4096 апр 29 19:07 tmp
t вместо x в блоке others – sticky bit установлен.
# Установить sticky bitchmod +t /sharedchmod 1777 /shared # 1 – это sticky bit в числовом виде
Сводная таблица
|
Бит |
Числовой |
Символьный |
На файл |
На директорию |
|---|---|---|---|---|
|
SUID |
|
|
EUID = UID владельца файла |
Нет эффекта |
|
SGID |
|
|
EGID = GID группы файла |
Новые файлы наследуют группу директории |
|
Sticky |
|
|
Нет эффекта |
Удалить файл может только его владелец |
Специальные биты идут первой цифрой в четырёхзначной записи:
chmod 4755 file # SUID + rwxr-xr-xchmod 2755 dir # SGID + rwxr-xr-xchmod 1777 dir # Sticky + rwxrwxrwxchmod 3755 dir # SGID + Sticky + rwxr-xr-x
9. ACL – когда стандартных прав недостаточно
Стандартная модель UGO имеет фундаментальное ограничение: один владелец и одна группа. Что если нужно дать доступ двум разным пользователям с разными правами? Например, пользователь maria должна читать и писать файл, пользователь sergei – только читать, а все остальные – ничего. В UGO это не реализовать. ACL (Access Control Lists) решают эту задачу – они позволяют прописать права для произвольного количества пользователей и групп на один объект.
Для начала проверим что пакет установлен:
apt list --installed 2>/dev/null | grep acl# Если пакета нет:sudo apt install acl
9.1 Просмотр ACL
getfacl file.txt# file: file.txt# owner: veil# group: veiluser::rw- ← права владельца (стандартные)group::r-- ← права группы (стандартные)other::r-- ← права остальных (стандартные)
Пока ACL не установлены – вывод совпадает с обычными правами. Как только добавляем ACL-запись, в выводе ls -la появляется символ + в конце строки прав:
ls -la file.txt# -rw-r--r--+ 1 veil veil 34045 апр 29 15:18 file.txt# ↑ этот плюс означает что на файле есть ACL
9.2 Установка ACL
# Дать конкретному пользователю права на файлsetfacl -m u:maria:rw file.txt# Дать группе права на директориюsetfacl -m g:backend:rx /var/www/api# Несколько записей сразуsetfacl -m u:maria:rw,g:backend:r file.txt# Удалить конкретную ACL-записьsetfacl -x u:maria file.txt# Удалить все ACL с файлаsetfacl -b file.txt
После добавления ACL для maria – getfacl покажет дополнительные строки:
getfacl file.txt# file: file.txt# owner: veil# group: veiluser::rw-user:maria:rw- ← ACL-запись для конкретного пользователяgroup::r--mask::rw- ← маска появилась автоматическиother::r--
9.3 Маска
Маска – это максимально возможные эффективные права для всех ACL-записей, кроме владельца и others. Если маска r-x, то даже ACL с rwx реально даст только r-x. Маска появляется автоматически при добавлении первой ACL-записи и расширяется когда вы добавляете записи с большими правами. Можно задать явно:
# Посмотреть маскуgetfacl file.txt | grep mask# Явно задать маскуsetfacl -m mask::rx file.txt
9.4 ACL по умолчанию – важный момент
Без флага -d ACL применяется только к уже существующим файлам. Новые файлы созданные в директории его не наследуют. Это частая ошибка – настроил ACL на директорию, а файлы которые потом создаются внутри его не получают.
Правильный паттерн – всегда два вызова:
# 1. Применить к существующим файлам и поддиректориямsetfacl -R -m g:developers:rwx /project# 2. Установить ACL по умолчанию – для всех новых файловsetfacl -d -m g:developers:rwx /project# Проверить – в выводе появятся строки default:getfacl /project# file: project# owner: ivan# group: ivanuser::rwxgroup::r-xother::r-xdefault:group:developers:rwx ← будет применяться к новым файлам
10. umask – права по умолчанию при создании файлов
Когда создаётся новый файл или директория – система не даёт максимально возможные права, а вычитает из них маску. Это и есть umask. Максимальные права при создании: файл – 666 (execute никогда не ставится автоматически), директория – 777.
# Посмотреть текущую маскуumask# 0022# Расчёт:# файл: 666 - 022 = 644 (rw-r--r--)# директория: 777 - 022 = 755 (rwxr-xr-x)
Строго говоря umask работает как побитовая операция исключения, а не простое вычитание. Разница проявляется если у вас нестандартные значения: например, 666 минус 033 математически даст 633, но побитовое исключение даст 644. Для стандартных значений (022, 027, 077) простое вычитание даёт верный результат и удобнее для понимания.
# Проверить на практикеumask 022touch newfile.txt && ls -la newfile.txt# -rw-r--r-- 1 ivan ivan 0 Mar 26 newfile.txt ← 644mkdir newdir && ls -la | grep newdir# drwxr-xr-x 2 ivan ivan 4096 Mar 26 newdir ← 755
Типичные значения
|
umask |
Файлы |
Директории |
Когда применять |
|---|---|---|---|
|
|
|
|
Стандарт – публичный доступ на чтение |
|
|
|
|
Усиленный – others вообще без доступа |
|
|
|
|
Параноидальный – только владелец |
Где настраивается
# Для текущей сессииumask 027# Глобально для всех пользователейgrep UMASK /etc/login.defs# UMASK 022# Для конкретного пользователяecho "umask 027" >> ~/.bashrc# Для сервиса через systemd unit-файл# [Service]# UMask=0027
Бонус и Заключение
Мы рассмотрели всё начиная от базовой модели UGO и битов rwx до алгоритма принятия решений ядром, специальных битов и ACL. Отдельно хочу поделиться полезным материалом на YouTube от Дмитрия с заданиями для самостоятельной отработки навыков, очень полезно тем, кто только начинает учить Linux.
Увидимся в следующей части серии!
Статья доступна на сайте opensophy. Статьи, блоги и документации в первую очередь выходят и обновляются на сайте с указанием автора и соавторов.
ссылка на оригинал статьи https://habr.com/ru/articles/1034474/