Каждый файл и каталог в Linux принадлежит кому-то и решает, кого пускать. Когда сервис не может прочитать свой конфиг, пользователь жалуется на отказ в записи, а скрипт внезапно работает с чужими правами, корень почти всегда здесь, в модели доступа. В этом уроке разберем, как ядро решает можно или нельзя, как читать ls -l, менять права через chmod в обоих видах, задавать значения по умолчанию через umask, переназначать владельца через chown и chgrp, и зачем нужны три специальных бита: SUID, SGID и sticky.

Как это работает
У каждого файла есть владелец (UID) и группа (GID). Права делятся на три категории: владелец (user), группа (group) и все остальные (other). Для каждой категории три флага: чтение (r), запись (w) и выполнение (x). Итого девять бит плюс три специальных, которые держат в отдельном четвертом разряде.
Когда процесс обращается к файлу, ядро смотрит на его эффективный UID и GID. Если UID процесса совпадает с владельцем файла, применяются права владельца и больше ничего. Не совпал владелец, но GID входит в группу файла, применяются права группы. Иначе действуют права other. Категории не складываются: подходит первая совпавшая. Из этого вытекает ловушка, владелец может иметь меньше прав, чем группа, и ядро не даст ему права группы.
Смысл r, w, x различается для файлов и каталогов. Для файла: r читать содержимое, w изменять, x запускать как программу. Для каталога: r получить список имен внутри, w создавать, удалять и переименовывать записи, x входить внутрь и обращаться к конкретным именам. Поэтому каталог без x бесполезен, даже если r стоит: имена видны, но ни в один файл не зайти. А удаление файла зависит не от прав на сам файл, а от w на каталог, в котором он лежит.
Права хранятся числом. Каждой категории соответствует восьмеричная цифра: r=4, w=2, x=1, складываем. rwx это 4+2+1=7, rw- это 6, r-x это 5. Так 755 значит rwxr-xr-x, а 644 значит rw-r--r--. Это и есть числовая запись, которую любит chmod.
umask работает наоборот: это маска битов, которые надо снять с базовых прав при создании. База для файлов 666 (без x, файлы по умолчанию не исполняемые), для каталогов 777. Из базы вычитаются биты маски. При типичной umask 022 новый файл получит 666 минус 022 равно 644, каталог 777 минус 022 равно 755. Технически это не вычитание, а побитовое AND с инверсией маски, но для round-чисел совпадает.
Команды и примеры
Читаем вывод ls -l. Первый символ это тип (- файл, d каталог, l ссылка), дальше три тройки rwx для user, group, other.
Код: Выделить всё
$ ls -l report.sh
-rwxr-xr-x 1 anna devs 482 jun 14 10:20 report.sh
| | | | |
| | | | +-- группа devs
| | | +------- владелец anna
| | +----------- other: r-x
| +-------------- group: r-x
+----------------- user: rwx
Код: Выделить всё
chmod 644 file.conf # rw-r--r--
chmod 755 script.sh # rwxr-xr-x
chmod u+x script.sh # добавить владельцу выполнение
chmod go-w shared.txt # снять запись у группы и остальных
chmod a=r public.txt # ровно r--r--r-- всем
chmod -R u+rwX,go+rX www/ # рекурсивно; большая X ставит x только там,
# где он уже есть или это каталог (умно для дерева)
umask смотрим и задаем. Без аргумента печатает текущую маску, с -S в символьном виде.
Код: Выделить всё
$ umask
0022
$ umask -S
u=rwx,g=rx,o=rx
$ umask 027 # новые файлы 640, каталоги 750 (other без доступа)
Меняем владельца и группу. chown умеет и то и другое сразу через двоеточие, chgrp только группу.
Код: Выделить всё
chown anna file.txt # сменить владельца
chown anna:devs file.txt # владелец и группа разом
chown :devs file.txt # только группа (как chgrp)
chgrp devs file.txt # то же через отдельную команду
chown -R www-data:www-data /var/www/site # Debian/Ubuntu веб-сервер
chown -R apache:apache /var/www/html # RHEL/Fedora веб-сервер
Специальные биты. SUID (4) на исполняемом файле запускает его с правами владельца файла, а не запускающего, классика это /usr/bin/passwd (пишет в /etc/shadow от root). SGID (2) на файле запускает с группой владельца; на каталоге важнее, новые файлы внутри наследуют группу каталога, а не первичную группу создателя, это рабочая лошадка общих папок. Sticky (1) на каталоге запрещает удалять чужие файлы, даже если есть w на каталог, удалять может только владелец файла или root, как в /tmp.
Код: Выделить всё
chmod u+s installer # SUID, в ls: rwsr-xr-x
chmod 4755 installer # то же числом (4 в старшем разряде)
chmod g+s teamdir # SGID на каталоге, наследование группы
chmod 2775 teamdir # drwxrwsr-x
chmod +t /srv/upload # sticky, в ls: drwxrwxrwt
chmod 1777 /srv/upload # классический режим общей папки
Частые грабли
- chmod 777 как лекарство от любого отказа. Это дыра: писать сможет кто угодно. Почти всегда правильный ответ не 777, а корректный владелец через chown.
- Категории не складываются. Если ты владелец, но у владельца нет w, ядро не даст тебе прав группы, хотя ты в ней. Лечится сменой прав владельцу, а не добавлением себя в группу.
- Каталог с r без x: видишь имена в ls, но не можешь зайти и прочитать файлы. И наоборот, x без r дает доступ к файлу по точному имени без листинга.
- Удаление файла зависит от w на каталог, а не на файл. Файл с правами 000 спокойно удаляется, если у тебя есть запись в каталоге и нет sticky.
- Рекурсивный chmod -R 755 на дереве с файлами делает все файлы исполняемыми. Используй символьную X вместо строчной x.
- SUID на скриптах не работает: ядро Linux игнорирует SUID для интерпретируемых файлов из соображений безопасности, бит срабатывает только на бинарниках.
- Забытый SGID на общей папке: файлы создаются с личной группой автора, и коллеги не могут их редактировать. Ставь g+s на каталог заранее.
- chown по UID, которого нет в системе: файл станет orphaned, ls покажет голое число вместо имени.
- Создай файл touch t1, посмотри ls -l, переведи права в число и обратно в rwx устно, потом проверь stat -c '%a %A' t1.
- Задай umask 077, создай touch t2 и mkdir d2, сравни их права с t1 и объясни разницу для файла и каталога.
- Сделай общую папку: sudo mkdir /srv/team, sudo chown root:devs /srv/team, sudo chmod 2775 /srv/team. Создай внутри файл и убедись, что его группа devs, а не твоя личная.
- Добавь sticky на эту папку (chmod +t), от второго пользователя попробуй удалить чужой файл и поймай отказ.
- Найди в системе все SUID-бинарники: find /usr/bin -perm -4000 -type f -ls, объясни, почему passwd в списке.
- Сними у скрипта право на выполнение через chmod a-x и запусти ./script, разбери сообщение об ошибке.
- Какому числовому значению соответствует rwxr-x---, и что оно разрешает каждой из трех категорий?
- При umask 027 какие права получит новый обычный файл и какие новый каталог? Покажите расчет.
- Чем отличается действие SGID на исполняемом файле от действия SGID на каталоге?
- Пользователь состоит в группе файла, но первая совпавшая категория это владелец, у которого нет записи. Сможет ли он писать в файл и почему?
- Что именно запрещает sticky bit на каталоге и кто все же может удалить файл в нем?
- Почему chmod -R 755 на дереве с обычными файлами считается ошибкой и какой ключ chmod решает проблему?