Тема 04

Пользователи, группы и права доступа

Пользователи, группы и права доступа

В предыдущих темах мы создавали файлы и каталоги, копировали и просматривали их. В теме 2 уже встречался вывод ls -l, в котором после типа записи стоит строка из десяти символов вроде -rw-r--r--. Эта тема объясняет, что означает эта строка и кто решает, может ли программа прочитать файл, записать в него или запустить. Вопрос «кому что разрешено» старше Linux: система UNIX в 1970-х годах задумывалась как многопользовательская, и её модель защиты стала образцом для последующих систем 1.

Изложение построено от общего к частному. Сначала рассмотрим, как система представляет пользователей и группы и где хранятся эти сведения: файлы /etc/passwd, /etc/group и /etc/shadow. Затем обсудим суперпользователя root, команды su и sudo и причины, по которым работать под root не следует. Основная часть темы посвящена правам доступа к файлам и каталогам, их записи в символьном и восьмеричном виде, маске umask и специальным битам setuid, setgid и sticky. Завершает тему обзор управления учётными записями и списков контроля доступа.

Целевая среда курса — Ubuntu 24.04. Примеры этой темы выполнены в учебной системе Ubuntu 22.04 под учётной записью student, которая входит в группу sudo. Пароль для sudo в этой среде запрашивается, поэтому команды, требующие прав администратора, приведены как пример вывода и помечены явно. Для команд темы вывод в Ubuntu 24.04 совпадает, кроме сообщений adduser, о которых сказано отдельно.

Пользователи и группы в многопользовательской системе

Зачем системе учётные записи

Система, которой пользуются несколько людей и несколько служб, должна знать, кто именно выполняет действие. Учётная запись (англ. user account) — это запись о субъекте, от имени которого выполняются процессы и которому принадлежат файлы. Человек входит в систему под своим именем, веб-сервер работает под отдельной служебной записью, почтовые и системные службы — под собственными записями. Служебные записи обычно не имеют пароля и не позволяют интерактивного входа: их оболочка указывает на /usr/sbin/nologin, программу, которая сразу отказывает во входе.

Группа (англ. group) — именованное множество учётных записей. Права можно выдать группе, а не каждому пользователю отдельно. Если над документами отдела работают пять сотрудников, достаточно одной группы, в которую входят все пять, и одного правила на каталог с документами.

UID и GID: как система видит пользователя

Ядро не работает с именами. Для него пользователь — это число UID (англ. user identifier), а группа — число GID (англ. group identifier). Имена существуют для людей и переводятся в числа по файлам системы. Проверка прав выполняется по числам: если файл принадлежит пользователю с UID 1000, доступ к нему получит процесс, у которого эффективный UID равен 1000. Учётная запись root имеет UID 0, и ядро распознаёт её именно по этому числу, а не по имени.

У каждого процесса есть основная группа и список дополнительных групп. Команда id показывает все эти сведения для текущего пользователя:

id
uid=1000(student) gid=1000(student) groups=1000(student),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(kvm),117(netdev),120(libvirt),122(wireshark),999(docker)

Поле uid=1000(student) содержит число и имя, то же для gid. Поле groups перечисляет все группы, в том числе основную. Группа adm (4) даёт право читать журналы системы в /var/log, группа sudo (27) — право пользоваться командой sudo. Группа docker (999) заслуживает отдельного внимания: её члены могут запускать контейнеры с доступом к файловой системе хоста, что фактически равносильно правам root. Поэтому включать пользователя в такие группы нужно осознанно.

По соглашению системные учётные записи и группы получают числа меньше 1000, пользовательские — начиная с 1000. Конкретные границы задаются в файле /etc/login.defs и могут отличаться в других дистрибутивах.

Файлы /etc/passwd и /etc/group

Сведения об учётных записях хранятся в текстовом файле /etc/passwd. Каждая строка описывает одну учётную запись и состоит из семи полей, разделённых двоеточиями. Посмотрим первые строки файла и строку пользователя student:

head -n 3 /etc/passwd
grep '^student:' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
student:x:1000:1000:,,,:/home/student:/bin/bash

Смысл полей показан в таблице.

№ поляПример из строки studentСодержание
1studentимя учётной записи (логин)
2xместо для пароля; x означает, что хеш пароля хранится в /etc/shadow
31000UID — числовой идентификатор пользователя
41000GID основной группы пользователя
5,,,поле комментария (GECOS): полное имя, комната, телефоны; пустые значения разделены запятыми
6/home/studentдомашний каталог
7/bin/bashоболочка, которая запускается при входе

Строка root содержит UID 0 и GID 0, а строка daemon — оболочку /usr/sbin/nologin, то есть учётную запись службы, которая не предназначена для входа. Поле пароля в этих строках состоит из одного символа x, а не из настоящего хеша, и это сделано намеренно, как будет показано ниже.

Группы описаны в файле /etc/group. Его строка тоже содержит четыре поля: имя группы, место для пароля (обычно x), GID и список дополнительных членов группы через запятую:

grep -E '^(root|sudo|student):' /etc/group
root:x:0:
sudo:x:27:student
student:x:1000:

Строка sudo показывает, что пользователь student является дополнительным членом группы с GID 27. Строка student имеет пустой список членов, хотя student состоит в собственной группе. Это не ошибка: основная группа пользователя задаётся полем GID в /etc/passwd, и в список членов её обычно не записывают. Поэтому отсутствие имени в списке группы не означает отсутствия членства. Надёжнее смотреть на результат команды id.

Почему пароль хранится в /etc/shadow

Файл /etc/passwd должен читать любой пользователь: программы берут из него имена, домашние каталоги и оболочки. Если бы хеши паролей хранились в нём, любой пользователь получил бы возможность перебирать пароли на своей машине без ограничений. Поэтому хеши вынесены в отдельный файл /etc/shadow, доступный только суперпользователю и группе shadow:

ls -l /etc/passwd /etc/shadow
cat /etc/shadow
-rw-r--r-- 1 root root    1773 Mar 16  2026 /etc/passwd
-rw-r----- 1 root shadow   985 Mar 16  2026 /etc/shadow
cat: /etc/shadow: Permission denied

Команда cat завершилась отказом «Permission denied»: обычный пользователь не имеет права читать этот файл. Права rw-r----- будут разобраны ниже. Для иллюстрации формата приведём строку того же файла. Это пример вывода: реальный файл читается только root, а значения условные.

student:$y$j9T$условная.соль$условный.хеш:20001:0:99999:7:::

Поля здесь такие: имя пользователя; хеш пароля в формате $идентификатор$соль$хеш, где идентификатор $y$ означает алгоритм yescrypt, а $6$ — SHA-512; дата последней смены пароля в днях, прошедших с 1 января 1970 года; минимальный и максимальный срок действия пароля; количество дней предупреждения; срок неактивности; дата окончания действия учётной записи и одно зарезервированное поле. Пустое поле означает, что параметр не задан. Пароль в файле не хранится: хранится результат односторонней функции от пароля и соли. При входе система вычисляет тот же результат для введённого пароля и сравнивает. Соль — случайная строка, добавляемая к паролю; благодаря ей одинаковые пароли дают разные хеши, и заранее вычисленные таблицы для перебора бесполезны. Подробное описание форматов даёт справочная страница shadow(5) 4; общие принципы хранения паролей в UNIX-системах изложены в руководстве по администрированию 3.

Заметим, что поле пароля в /etc/passwd содержит x именно потому, что настоящий хеш находится в /etc/shadow. Если бы в поле стоял хеш, его могли бы прочитать все.

Команды id, groups и who

Команда id показывает UID и группы конкретного пользователя, если его имя передано аргументом: id root выведет данные root. Команда groups печатает только имена групп текущего пользователя:

groups
student adm dialout cdrom floppy sudo audio dip video plugdev kvm netdev libvirt wireshark docker

Команда who показывает, кто сейчас работает в системе; краткое описание базовых команд учётных записей дано в учебнике 2. Вывод зависит от состояния системы; пример вывода для одного открытого терминала:

student     pts/0        2026-10-12 13:02 (:0)

Здесь pts/0 — псевдотерминал, через который вошёл пользователь, а (:0) — источник входа. В сеансе, где других входов нет, who ничего не выводит. Такой вывод не означает ошибки.

Суперпользователь и принцип минимальных привилегий

Учётная запись root

Учётная запись root имеет UID 0. Ядро Linux пропускает для неё большинство проверок прав доступа: root может читать и изменять любой файл, завершать любой процесс, менять владельца файлов и загружать модули ядра. Такая учётная запись нужна для администрирования, но её возможности безграничны, поэтому практика администрирования сводится к тому, чтобы использовать их как можно реже и только для конкретных задач 3.

В Ubuntu пароль root по умолчанию не задан, то есть вход напрямую под root закрыт. Администратором становится пользователь, входящий в группу sudo, и привилегии он получает через команду sudo с собственным паролем.

su и sudo

Команда su (англ. switch user) запускает оболочку от имени другого пользователя. Без аргументов она переключает на root и требует пароль root; su - дополнительно создаёт окружение входа, как при настоящем входе в систему. Поскольку пароль root в Ubuntu не задан, su для администрирования применяется редко.

Команда sudo (англ. superuser do) выполняет одну команду от имени root или другого пользователя, предварительно проверив право текущего пользователя. Проверка выполняется по собственному паролю, а правила задаются в файле /etc/sudoers и в каталоге /etc/sudoers.d/. Действие записывается в журнал, поэтому по журналу можно узнать, кто и что выполнял с правами администратора.

Поведение sudo без интерактивного запроса удобно проверить флагом -n, который не спрашивает пароль и сразу завершается с ошибкой, если пароль нужен:

sudo -n true
echo "код возврата: $?"
sudo: a password is required
код возврата: 1

Команда true ничего не делает и завершается с кодом 0 при успехе. Здесь она не выполнена, потому что sudo не получил пароль. Код возврата 1 говорит о неудаче, и это именно та ситуация, которую можно встретить, если попробовать sudo в скрипте без предварительного ввода пароля.

Почему не работать под root

Работа под root постоянно, даже для удобства, создаёт три опасности. Первая — ошибки без ограничений. Команды вроде rm не спрашивают подтверждения ни у обычного пользователя, ни у root, но обычного пользователя от последствий опечатки защищают права: удалить он может только то, что ему разрешено. Для root таких ограничений нет. Команда rm -rf с пустой переменной в пути, рассматриваемая в теме 15, под root может стереть систему целиком.

Вторая опасность — вредоносные программы. Любая программа, запущенная под root, получает полный доступ к системе. Если пользователь запустил под root файл из сомнительного источника, злоумышленник получил систему.

Третья опасность — незаметное искажение прав. Файл, созданный под root, принадлежит root, и обычный пользователь не может его изменить. Рассмотрим типичный пример: пользователь, забыв sudo в одной команде и добавив его в другой, получает файл, который потом не может редактировать.

sudo touch /home/student/notes.txt
ls -l /home/student/notes.txt
echo "строка" >> /home/student/notes.txt
-rw-r--r-- 1 root root 0 Oct 12 13:40 /home/student/notes.txt
bash: /home/student/notes.txt: Permission denied

Это пример вывода: команда требует пароля администратора и на учебной машине не выполнялась. Вывод показывает, что файл принадлежит root, а запись от имени student отклонена. Исправляется это командой sudo chown student /home/student/notes.txt, но правильнее не создавать файлы от имени root вовсе.

Принцип, которому следует эта практика, называется принципом минимальных привилегий (англ. principle of least privilege): процесс или пользователь получает только те права, которые нужны для текущей задачи, и не больше. Администратор, который пользуется sudo только для конкретных команд, применяет этот принцип на практике.

Файл sudoers — обзор

Правила sudo записываются в файл /etc/sudoers и в файлы каталога /etc/sudoers.d/. Строка правила описывает, какой пользователь на каком хосте и от чьего имени может выполнять какие команды. В Ubuntu по умолчанию встречается строка вида %sudo ALL=(ALL:ALL) ALL: символ % означает группу, и члены группы sudo могут выполнять любые команды от имени любого пользователя. Пример строки приведён для понимания; сам файл читается только root.

Редактировать sudoers напрямую опасно: ошибка в синтаксисе может закрыть доступ к sudo. Поэтому файл открывают командой sudo visudo, которая проверяет синтаксис перед сохранением. Подробные правила описаны в справочной странице sudoers(5) и sudo(8) 4.

Права доступа к файлам и каталогам

Три класса пользователей и три вида прав

Каждый файл и каталог имеет владельца (пользователя) и группу-владельца. Права доступа задаются для трёх классов: владелец (англ. user, u), группа (англ. group, g) и все остальные (англ. others, o). Для каждого класса существуют три вида прав: чтение (англ. read, r), запись (англ. write, w) и выполнение (англ. execute, x). Значение прав в числовой форме: r — 4, w — 2, x — 1.

Ядро проверяет права по строгому порядку. Если пользователь совпадает с владельцем файла, применяются только права владельца, даже если права группы или остальных окажутся шире. Если пользователь не владелец, но входит в группу-владельца, применяются права группы. Во всех остальных случаях применяются права остальных. Этот порядок важен: владелец, у которого нет права чтения, не может прочитать свой файл, даже если группа и остальные могут.

Разбор строки -rwxr-x---

Строка прав, которую показывает ls -l, состоит из десяти символов. Первый символ задаёт тип записи: - — обычный файл, d — каталог, l — символическая ссылка. Остальные девять символов разбиты на три группы по три: права владельца, группы и остальных. Разберём строку -rwxr-x---, которую создадим командой chmod:

touch g
chmod 750 g
ls -l g
-rwxr-x--- 1 student student 0 Oct 12 13:22 g

Разбор этой строки приведён в таблице.

ПозицииСимволыКлассПраваЗначение в восьмеричной записи
1-тип записиобычный файл—
2–4rwxвладелецчтение, запись, выполнение7 (4 + 2 + 1)
5–7r-xгруппачтение, выполнение; записи нет5 (4 + 1)
8–10---остальныеникаких прав0

Иллюстрация ниже показывает ту же строку: каждый символ связан с классом и видом права.

Разбор строки прав -rwxr-x---: первый символ задаёт тип записи, три следующих группы по три символа соответствуют владельцу, группе и остальным; под каждой группой указано значение в восьмеричной записи 7, 5 и 0
Строка прав -rwxr-x--- и её восьмеричная запись 750: владелец 7, группа 5, остальные 0

На рисунке видно, что дефис в позиции отсутствующего права заменяет букву. Поэтому r-x означает чтение и выполнение без записи, а --- означает полное отсутствие прав. Восьмеричная запись 750 получается сложением значений по каждому классу: 7 для владельца, 5 для группы, 0 для остальных. Этот переход от строки к числу понадобится при изучении chmod.

Права файла и права каталога

Смысл каждого вида права зависит от того, что за объект перед нами. Для файла права описывают действия с его содержимым. Для каталога они описывают действия с его записями, то есть с именами файлов внутри него. Таблица сводит оба случая.

ПравоДля файлаДля каталога
r (чтение)читать содержимое файла (cat, редактор)получить список имён (ls)
w (запись)изменять содержимое файласоздавать, переименовывать и удалять записи (имена) внутри каталога
x (выполнение)запускать файл как программу или скриптвходить в каталог (cd), обращаться к записям по имени

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

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

mkdir dir
echo data > dir/f.txt
chmod 400 dir
ls dir
ls -l dir
cat dir/f.txt
f.txt
ls: cannot access 'dir/f.txt': Permission denied
total 0
-????????? ? ? ? ?            ? f.txt
cat: dir/f.txt: Permission denied

Права r-- на каталог позволили получить список имён: ls dir вывел f.txt. Однако ls -l не смог прочитать атрибуты файла, потому что для этого нужно право x на каталог. Поэтому вместо прав появились знаки вопроса, а cat отказал в чтении. Заметим, что сообщение об ошибке относится к записи dir/f.txt, хотя сам файл не виноват.

Теперь проверим обратную ситуацию — право x без права r:

chmod 100 dir
ls dir
cat dir/f.txt
cd dir && pwd
ls: cannot open directory 'dir': Permission denied
data
/home/student/perm-demo/dir

Список имён не получен, потому что для него нужно право r. Однако cat dir/f.txt сработал: путь из известного имени вычисляется при праве x, а содержимое файла читается по его собственным правам. Команда cd тоже работает. Такой каталог удобен как «почтовый ящик», в который можно положить файл, но нельзя просмотреть его содержимое. Этим пользуются на практике, хотя такой приём всегда требует осторожности.

Наконец, проверим право записи без права r:

chmod 300 dir
ls -ld dir
ls dir
touch dir/new
d-wx------ 2 student student 4096 Oct 12 13:22 dir
ls: cannot open directory 'dir': Permission denied

Команда touch dir/new выполнилась без ошибки: право wx позволяет создавать записи, хотя список записей недоступен. Все три эксперимента подтверждают, что права каталога и права файла — разные вещи и проверяются раздельно.

Проход по пути: зачем каталогу право x

Когда программа обращается к файлу по пути вроде /home/student/projects/report.txt, ядро проходит весь путь по шагам. На каждом каталоге оно проверяет право x, и только после этого обращается к файлу, проверяя его права r или w. Если хотя бы на одном шаге права x нет, доступ отказывается, даже если файл открыт для всех.

Путь /home/student/projects/report.txt: на каждом каталоге от корня до projects проверяется право x, затем на файле проверяется право r; на одном из каталогов право x отсутствует, и доступ отказан
Проход по пути к файлу: право x нужно на каждом каталоге, право r — на самом файле

Из этого следует практическое правило. Чтобы выдать доступ к файлам в каталоге /srv/share, недостаточно дать права на сам каталог share: нужно убедиться, что каталог /srv тоже допускает проход. Путь всегда проверяется целиком, и ошибка в одном звене делает недоступным всё дерево внутри.

Числовая и символьная запись прав

chmod в символьной записи

Команда chmod (англ. change mode) меняет права файла или каталога. Символьная запись состоит из трёх частей: класс (u, g, o или a — все), оператор (+ добавить, - убрать, = задать точно) и вид права (r, w, x). Несколько изменений разделяются запятыми.

chmod u+x g
chmod go-w g
chmod a+r g
chmod u=rwx,g=rx,o= g
stat -c '%a %A %n' g
750 -rwxr-x--- g

Команды семейства GNU Coreutils, в том числе chmod, ls и stat, описаны в официальном руководстве 6. Команда stat -c '%a %A %n' выводит восьмеричные права, символьные права и имя файла, поэтому её удобно использовать для проверки результата. Последняя запись u=rwx,g=rx,o= задаёт права точно: владелец — rwx, группа — rx, остальные — ничего, и результат совпал с исходной строкой -rwxr-x---. Оператор = удобен тем, что не зависит от предыдущего состояния файла.

Восьмеричная запись

Восьмеричная запись задаёт права тремя цифрами, каждая из которых относится к одному классу. Цифра равна сумме значений прав: r — 4, w — 2, x — 1. Например, цифра 6 означает rw- (4 + 2), 5 — r-x (4 + 1), 0 — отсутствие прав. Тройка 750 означает владелец 7 (rwx), группа 5 (r-x), остальные 0 (---). Ведущий ноль допустим и ничего не меняет: 0640 то же самое, что 640.

chmod 640 g
stat -c '%a %A %n' g
640 -rw-r----- g

Восьмеричная запись компактна и точна, поэтому её предпочитают в скриптах и конфигурациях. Символьная запись удобнее для точечного изменения одного права. Опасной практикой считается выдача chmod 777: она даёт полный доступ всем пользователям системы и почти всегда маскирует реальную проблему с владельцем или группой. Ключ -R меняет права рекурсивно и требует внимательности: если указать её для всего /, результат будет разрушительным. Перед рекурсивной сменой прав стоит проверить путь командой ls.

chown и chgrp

Команда chown меняет владельца файла, а chgrp — группу-владельца. Смена владельца требует прав root, потому что иначе пользователь мог бы «передать» свой файл другому и обойти квоты или учёт. Смена группы разрешена владельцу файла, если он входит в целевую группу. Это позволяет пользователю распределять свои файлы между группами, в которых он состоит.

Смена владельца выполняется от имени администратора. Пример вывода (на учебной машине не выполнялся):

sudo chown alice report.txt
ls -l report.txt
-rw-r--r-- 1 alice student 0 Oct 12 13:45 report.txt

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

mkdir share
chgrp adm share
ls -ld share
drwxr-xr-x 2 student adm 4096 Oct 12 13:22 share

Группа adm в этой системе есть, и student в неё входит, поэтому chgrp сработал. Если указать группу, в которую пользователь не входит, команда завершится отказом «Operation not permitted».

umask и права новых файлов

Права нового файла не задаются вручную, а определяются маской umask. Маска — это набор битов, которые снимаются (сбрасываются) в базовых правах при создании. Базовые права равны 666 для файлов и 777 для каталогов. Файлы не получают права выполнения по умолчанию, поэтому базовое значение для них 666, а не 777. Текущую маску показывает команда umask:

umask
umask -S
0022
u=rwx,g=rx,o=rx

Маска 0022 в символьной форме -S означает «запретить запись группе и остальным». Вычисление выполняется по цифрам: в каждой цифре базового значения сбрасываются биты, которые установлены в той же позиции маски. Формально это побитовая операция «базовые права И НЕ маска». Для масок 022, 027 и 077 результат совпадает с обычным вычитанием, поэтому его удобно записывать как разность. Для маски 022 получаем:

  • файлы: 666 − 022 = 644, то есть rw-r--r--;
  • каталоги: 777 − 022 = 755, то есть rwxr-xr-x.

Проверим на практике с маской 027, где группе запрещена запись, а остальным запрещено всё:

umask 027
touch f027
mkdir d027
ls -ld d027
ls -l f027
drwxr-x--- 2 student student 4096 Oct 12 13:22 d027
-rw-r----- 1 student student 0 Oct 12 13:22 f027

Расчёт для маски 027 такой: файлы 666 − 027 = 640 (rw-r-----), каталоги 777 − 027 = 750 (rwxr-x---). Совпадение с выводом подтверждает расчёт. Для маски 077 получаем 600 и 700, то есть доступ только владельцу. Арифметическое вычитание работает не всегда: при маске 033 оно дало бы для файлов 633, но маска лишь сбрасывает биты w и x, а бита x у файла и так нет, поэтому реальный результат — 644 (rw-r--r--). Проверим это и сразу вернём маску к значению по умолчанию 022, чтобы следующие примеры не зависели от опыта:

umask 033
touch f033
stat -c '%a %A %n' f033
umask 022
644 -rw-r--r-- f033

Маска действует только на вновь создаваемые объекты и не меняет права существующих файлов. Маску задают в профиле оболочки, о котором пойдёт речь в теме 8; значение по умолчанию 022 в большинстве дистрибутивов обеспечивает защиту от записи чужими пользователями.

Специальные биты

setuid

Кроме девяти основных битов, у файла есть три специальных бита: setuid, setgid и sticky. Они записываются в четвёртой (старшей) восьмеричной цифре: setuid — 4, setgid — 2, sticky — 1. В символьной записи setuid проявляется буквой s в позиции x владельца, setgid — s в позиции x группы, sticky — t в позиции x остальных.

Бит setuid на исполняемом файле означает, что программа при запуске получает права владельца файла, а не запустившего её пользователя. Классический пример — команда passwd, которая меняет пароль и записывает результат в /etc/shadow, принадлежащий root. Обычный пользователь не может писать в этот файл, но passwd с битом setuid выполняется с эффективным UID 0 на время своей работы 5.

ls -l /usr/bin/passwd
find /usr/bin -perm -4000 -type f 2>/dev/null | head -n 5
-rwsr-xr-x 1 root root 59976 Feb  6  2024 /usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/pkexec
/usr/bin/su
/usr/bin/sudo

В строке прав -rwsr-xr-x буква s стоит на месте x владельца, значит, бит setuid установлен и x тоже установлен. Если бы x не было, буква была бы заглавной S, что означает бессмысленный бит. Команда find с параметром -perm -4000 находит все файлы с установленным setuid. Порядок вывода find зависит от файловой системы, а head -n 5 оставляет только первые пять найденных файлов, поэтому сама passwd в этот фрагмент не попала. Список показывает, что такие программы — это команды, связанные с учётными записями и правами: gpasswd, su, sudo, mount, а также passwd.

Setuid требует осторожности. Ошибка в такой программе даёт злоумышленнику права владельца, поэтому программы с setuid должны быть минимальными и тщательно проверенными. Заметим также, что Linux игнорирует бит setuid на скриптах оболочки: такие скрипты запускаются с правами пользователя, который их вызвал.

setgid

Бит setgid действует по-разному для файлов и каталогов. Для исполняемого файла он означает запуск с правами группы-владельца файла. Для каталога он важнее: новые файлы и подкаталоги, создаваемые внутри, наследуют группу каталога, а не основную группу создавшего пользователя. Это свойство используется для общих каталогов отдела, где все файлы должны принадлежать одной группе, независимо от того, кто их создал.

Проверим на примере общего каталога share, который был создан и передан группе adm в разделе о chgrp. Группу adm выбрали потому, что пользователь в неё входит:

chmod 2775 share
ls -ld share
touch share/report.txt
ls -l share
drwxrwsr-x 2 student adm 4096 Oct 12 13:22 share
total 0
-rw-r--r-- 1 student adm 0 Oct 12 13:22 report.txt

Восьмеричная цифра 2 в 2775 включает setgid. В строке прав буква s стоит на месте x группы. Файл report.txt создан пользователем student, но его группа — adm, то есть группа каталога. Без setgid файл получил бы группу student. Системный пример того же механизма — каталог почты /var/mail с группой mail:

ls -ld /var/mail
drwxrwsr-x 2 root mail 4096 Jan  7  2025 /var/mail

sticky bit

Sticky bit (англ. «липкий бит») на каталоге ограничивает удаление и переименование записей. Без него каждый, кто имеет право записи в каталог, может удалить любой файл в нём, даже чужой. С sticky bit удалить или переименовать запись может только владелец файла, владелец каталога или root. Классический пример — каталог /tmp, в который пишут все пользователи системы:

ls -ld /tmp
drwxrwxrwt 70 root root 16384 Oct 12 13:22 /tmp

Права drwxrwxrwt означают, что все могут создавать файлы в /tmp, но буква t на месте x остальных не даёт удалить чужие файлы. Восьмеричная запись этого режима — 1777, где цифра 1 задаёт sticky bit. Проверим его на собственном каталоге:

mkdir st
chmod +t st
stat -c '%a %A %n' st
1755 drwxr-xr-t st

Заметим разницу: буква t в верхнем регистре T означает, что sticky bit установлен, но право x у остальных отсутствует. Строчная t показывает, что право x есть. Этот нюанс связан с тем же принципом, что и у setuid.

Специальные биты в строке ls -l: буква s на месте x владельца означает setuid, буква s на месте x группы — setgid, буква t на месте x остальных — sticky bit; для каждого указано восьмеричное значение 4, 2 и 1
Специальные биты и их отображение в строке прав: setuid, setgid и sticky

Рисунок показывает, где в строке прав располагаются специальные биты. Заметим, что все три бита занимают те же позиции, что и обычные права x, поэтому их легко спутать с обычным выполнением. Сравнение s и S или t и T позволяет отличить установленный бит от установленного x.

Управление учётными записями и ACL

Создание пользователей и групп

Создание учётных записей и групп требует прав администратора. В Ubuntu для этого есть интерактивная команда adduser и низкоуровневая useradd. Ниже приведён пример вывода adduser (на учебной машине не выполнялся, вывод соответствует версии Ubuntu 22.04; в Ubuntu 24.04 те же сообщения начинаются с префикса info:, а кавычки вокруг имён прямые):

sudo adduser alice
Adding user `alice' ...
Adding new group `alice' (1001) ...
Adding new user `alice' (1001) with group `alice' ...
Creating home directory `/home/alice' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for alice
Enter the new value, or press ENTER for the default
...
Is the information correct? [Y/n] Y

Команда создала группу alice с GID 1001, учётную запись с UID 1001, домашний каталог и запросила пароль. Сведения о новом пользователе появятся в /etc/passwd и /etc/group строками, которые мы разобрали выше.

Добавление пользователя в дополнительную группу выполняется командой usermod. Ключ -a (append) обязателен: без него -G заменит весь список дополнительных групп указанным, и пользователь потеряет членство в остальных группах.

sudo groupadd projectteam
sudo usermod -aG projectteam alice
id alice

Пример вывода (не выполнялся на учебной машине):

uid=1001(alice) gid=1001(alice) groups=1001(alice),1002(projectteam)

Смена пароля своей учётной записи выполняется командой passwd без аргументов, а смена пароля другого пользователя — sudo passwd alice. Изменения членства в группах вступают в силу при следующем входе в систему; в текущем сеансе можно переключить группу командой newgrp.

Пароли и служебные учётные записи

Команда passwd меняет хеш в /etc/shadow и поэтому сама запускается с битом setuid, рассмотренным выше. Служебным учётным записям пароль обычно не назначают, а оболочку ставят /usr/sbin/nologin. Такую запись можно заблокировать командой sudo usermod -L имя и разблокировать командой sudo usermod -U имя; блокировка добавляет в хеш недопустимый префикс, поэтому пароль не может совпасть. Эти команды относятся к администрированию и выполняются только по сценарию администратора.

Списки контроля доступа (ACL) — обзор

Стандартных девяти битов не всегда достаточно. Если нужно дать право записи в каталог двум конкретным пользователям, не входящим в одну группу, применяются списки контроля доступа (англ. access control list, ACL). ACL позволяет задать права отдельным пользователям и группам сверх классов владелец, группа и остальные. Команды setfacl и getfacl входят в пакет acl, который в Ubuntu устанавливается командой sudo apt install acl.

Признаком наличия ACL служит знак + в конце строки прав. Ниже показан вывод для файла с правами 644 после команды setfacl -m u:alice:rw- report.txt (проверено с существующим пользователем вместо alice):

-rw-rw-r--+ 1 student student 0 Oct 12 13:50 report.txt

Подробный вид ACL показывает getfacl:

# file: report.txt
# owner: student
# group: student
user::rw-
user:alice:rw-
group::r--
mask::rw-
other::r--

Строка user:alice:rw- даёт пользователю alice права, которых нет ни у группы-владельца, ни у остальных. Строка mask ограничивает максимальные права для всех именованных записей. ACL не заменяет обычные права, а дополняет их, поэтому при сложной схеме доступа разобраться в ней труднее. Для курса достаточно понимать принцип и уметь распознать признак +; подробности оставлены для самостоятельного изучения по справочной странице acl(5) 4.

Мандатный контроль доступа: AppArmor и SELinux

Ограничения дискреционного контроля (DAC vs MAC)

Классическая модель прав Linux и POSIX ACL относится к дискреционному управлению доступом (англ. Discretionary Access Control, DAC): владелец файла по своему усмотрению решает, кому предоставить права чтения, записи или выполнения. Однако у DAC есть фундаментальная слабость — всемогущество суперпользователя и процессов, запущенных от его имени. Если веб-сервер Nginx или СУБД скомпрометированы через уязвимость переполнения буфера (RCE), процесс с правами root получает неограниченный доступ ко всей операционной системе.

Для нейтрализации этой угрозы разработан мандатный контроль доступа (англ. Mandatory Access Control, MAC) на базе архитектуры модулей безопасности ядра LSM (Linux Security Modules) 58. В модели MAC централизованная политика безопасности диктуется ядром и действует принудительно, даже если процесс запущен от имени root:

  • суперпользователь не может обойти ограничения политики MAC;
  • скомпрометированный демон веб-сервера не может прочитать файл /etc/shadow или домашние каталоги пользователей, даже если права DAC формально разрешают чтение;
  • процессы изолируются в минимально необходимых им доменах выполнения (принцип минимальных привилегий).

Режимы работы и реализации: AppArmor и SELinux

В мире Linux закрепились две ведущие системы MAC 78:

  1. AppArmor (по умолчанию в Ubuntu, Debian, SUSE): ориентирован на пути к файлам. Для каждой защищаемой программы в каталоге /etc/apparmor.d/ создаётся текстовый профиль, описывающий разрешённые исполняемые файлы, сетевые сокеты и пути к файлам с флагами доступа (r — чтение, w — запись, px — запуск с отдельным профилем).

    • Профиль может находиться в одном из двух режимов: Enforce (нарушения блокируются ядром с записью в системный журнал) или Complain (нарушения только логируются без блокировки, что применяется при отладке).
    • Текущее состояние профилей проверяется командой sudo aa-status. Перевести профиль в строгий режим можно утилитой sudo aa-enforce /path/to/profile.
  2. SELinux (Security-Enhanced Linux, по умолчанию в RHEL, CentOS, Rocky Linux, Fedora): архитектура строгой типизации (Type Enforcement), разработанная Агентством национальной безопасности США (NSA) 8. В SELinux каждый объект системы (файл, процесс, сокет, порт) маркируется многокомпонентной меткой — контекстом безопасности:

    user:role:type:level
    

    Для безопасности ключевую роль играет поле type (тип файла или домен процесса). Например, файл веб-страницы маркируется типом httpd_sys_content_t, а процесс веб-сервера исполняется в домене httpd_t. Ядро разрешает процессу httpd_t чтение только тех файлов, тип которых явно указан в матрице политик. Если атакующий через уязвимость веб-сервера пытается прочитать файл базы данных с типом postgresql_db_t, ядро немедленно блокирует операцию на уровне системного вызова, генерируя событие AVC (Access Vector Cache) Denial.

    • Просмотр контекстов безопасности выполняется флагом -Z стандартных утилит: ls -Z /var/www или ps -eZ | grep nginx.
    • Режимы SELinux: Enforcing (принудительное соблюдение), Permissive (только журналирование) и Disabled. Проверить режим позволяет команда getenforce, а временно переключить — sudo setenforce 0 (Permissive) или sudo setenforce 1 (Enforcing). Восстановление эталонных меток на файловой системе выполняется утилитой restorecon -Rv /path.

Модульная подсистема аутентификации PAM

В ранних версиях UNIX каждая программа, требующая проверки подлинности (login, passwd, su), содержала собственный закрытый код чтения /etc/passwd и проверки паролей. Это исключало гибкую модернизацию: добавление биометрии, LDAP, смарт-карт или двухфакторной аутентификации (2FA) требовало перекомпиляции десятков системных утилит.

Эту проблему решила архитектура PAM (Pluggable Authentication Modules) Самара и Шемерса 9, стандартизованная в Linux. Программа передаёт задачу проверки подлинности библиотеке PAM, а логика проверки задаётся декларативными конфигурационными файлами в каталоге /etc/pam.d/.

Структура конфигурации /etc/pam.d/

Каждой службе соответствует отдельный конфигурационный файл (например, /etc/pam.d/login, /etc/pam.d/sshd, /etc/pam.d/sudo). Каждая строка конфигурации состоит из четырёх полей:

тип_модуля    флаг_управления    имя_библиотеки_модуля    [параметры]
  1. Тип модуля (Management Group):

    • auth: аутентификация пользователя (запрос пароля, токена, биометрии) и установка полномочий (credentials);
    • account: авторизация учётной записи (не истёк ли срок действия пароля, разрешён ли вход в данное время суток);
    • password: смена пароля (проверка на сложность по словарю, проверка длины и истории повторов);
    • session: подготовка и очистка окружения пользователя (монтирование домашнего каталога, настройка лимитов limits.conf, вывод приветствия).
  2. Флаги управления (Control Flags):

    • required: модуль обязателен к успешному прохождению. В случае неудачи проверка продолжается по остальным модулям цепочки (чтобы нарушитель не догадался по времени ответа, где именно произошёл сбой), но итоговый вердикт будет отрицательным.
    • requisite: модуль критически обязателен. При первой же ошибке цепочка немедленно прерывается с отказом в доступе.
    • sufficient: если этот модуль вернул успех (и ни один из предшествующих required не завершился сбоем), цепочка завершается успехом без проверки последующих модулей.
    • optional: результат модуля игнорируется, если только он не является единственным в цепочке.

Защита от атак подбора паролей: модуль pam_faillock

Для защиты от атак полного перебора паролей (англ. brute-force attacks) в Linux используется модуль pam_faillock (пришедший на смену pam_tally2). Модуль отслеживает число последовательных неудачных попыток ввода пароля для каждого пользователя и блокирует учётную запись на заданное время.

Типовое включение в /etc/pam.d/system-auth или common-auth:

auth    required    pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth    sufficient  pam_unix.so try_first_pass
auth    [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900

Параметр deny=5 блокирует вход после 5 неверных попыток, а unlock_time=900 автоматически снимает блокировку через 15 минут (900 секунд). Администратор может просмотреть счётчик заблокированных пользователей утилитой faillock --user <имя> и сбросить блокировку командой faillock --user <имя> --reset.

Итоги темы

Пользователи в Linux представлены числами UID и GID, а имена существуют для людей и переводятся в числа по файлам /etc/passwd и /etc/group. Хеши паролей вынесены в /etc/shadow, который читает только root, поскольку файл /etc/passwd должен быть доступен всем. Суперпользователь root обладает почти неограниченными возможностями, поэтому администрирование выполняют через sudo, а повседневную работу ведут под обычной учётной записью, соблюдая принцип минимальных привилегий.

Права доступа задаются для владельца, группы и остальных тремя видами rwx. Смысл прав зависит от объекта: для файла они управляют содержимым, для каталога — списком имён и входом в каталог. Право x на каталог необходимо для прохода по любому пути внутри него, и отсутствие этого права делает недоступным всё содержимое, даже при разрешённом чтении файлов. Права задаются командой chmod в символьной или восьмеричной записи, а права новых файлов определяются маской umask, которая сбрасывает биты в базовых значениях 666 и 777.

Специальные биты setuid, setgid и sticky меняют поведение программ и каталогов: setuid позволяет программе работать с правами владельца, setgid — сохранять группу общего каталога, sticky — защищать чужие файлы в общих каталогах вроде /tmp. Эти механизмы объясняют, как устроены многие системные команды и почему они требуют осторожности. Следующая тема переходит к перенаправлениям и конвейерам, где права проявляются при записи в файлы, и покажет, как системные процессы получают доступ к потокам ввода-вывода.

Литература

  1. Ritchie D. M., Thompson K. The UNIX Time-Sharing System. — Communications of the ACM, 1974, Vol. 17, No. 7, С. 365–375, DOI: 10.1145/361011.361061.
  2. Shotts W. The Linux Command Line: A Complete Introduction. 2nd ed. — No Starch Press, 2019. Открытая версия: https://linuxcommand.org/tlcl.php
  3. Nemeth E., Snyder G., Hein T. R., Whaley B., Mackin D. UNIX and Linux System Administration Handbook. 5th ed. — Addison-Wesley, 2017.
  4. The Linux man-pages project. — https://man7.org/linux/man-pages/
  5. Kerrisk M. The Linux Programming Interface. — No Starch Press, 2010.
  6. Free Software Foundation. GNU Coreutils Manual. — https://www.gnu.org/software/coreutils/manual/
  7. Bauer M. Inspecting and Enforcing Linux Security with AppArmor. — Linux Journal, 2006.
  8. Spencer R., et al. The Architecture of the Security-Enhanced Linux (SELinux) Kernel. — Proceedings of the 2003 USENIX Security Symposium, 2003.
  9. Samar V., Schemers R. Unified Login with Pluggable Authentication Modules (PAM). — Open Software Foundation, 1995.