Зачем нужны спецбиты
Обычная схема rwxr-xr-x отвечает на вопрос «кто что может». Но иногда
нужно дать не-root юзеру временно делать привилегированную операцию:
поменять свой пароль (запись в /etc/shadow, доступен только root),
открыть raw-сокет для ping, монтировать через mount. Для этого Linux
вводит три спецбита поверх rwx.
Где они в ls -l
Спецбиты заменяют x в выводе ls -l:
-rwsr-xr-x root root /usr/bin/passwd # SUID (s в позиции owner-x)
-rwxr-sr-x root tty /usr/bin/wall # SGID (s в позиции group-x)
drwxrwxrwt root root /tmp # sticky (t в позиции other-x)
Если бит стоит, а x не было - заглавная буква (S/T): «бит выставлен,
но execute не работает». Часто опечатка в chmod.
Числовое представление в chmod: ставится четвёртой цифрой слева:
| Бит | Значение | Пример |
|---|---|---|
| SUID | 4 | chmod 4755 |
| SGID | 2 | chmod 2755 |
| sticky | 1 | chmod 1777 |
Можно складывать: chmod 6755 = SUID+SGID. Текстовая форма: chmod u+s,
g+s, +t.
SUID - запуск с правами владельца
При запуске бинаря с SUID-битом effective UID процесса становится UID владельца файла (не запускающего). Если файл принадлежит root - процесс получает root-права на время своего выполнения.
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root ... /usr/bin/passwd
Юзер serge запускает passwd → effective UID становится 0 (root) → запись
в /etc/shadow (доступна только root) разрешена → пароль меняется.
Без SUID невозможно было бы сделать passwd, sudo, mount, su.
Критически важные нюансы Linux:
-
На скриптах SUID игнорируется. Ядро Linux намеренно игнорирует SUID на shebang-скриптах из-за TOCTOU race condition (между чтением shebang и exec интерпретатора файл может быть подменён). Только ELF-бинари. Если нужен «root-скрипт» - обернуть в C/Go-бинарь либо sudo.
-
SUID не работает на ФС смонтированных с
nosuid. Стандартная практика безопасности -mount -o nosuid /home,/tmp. Проверить:findmnt | grep nosuid. -
SUID - security smell в современных системах. Современная замена - capabilities: дать процессу только конкретную капабилу (CAP_NET_RAW для ping вместо полного root). На современных дистрибутивах
/usr/bin/pingуже не SUID, а имеетcap_net_raw=ep.
SGID - два разных режима
На бинаре - то же что SUID, но для группы
Effective GID = группа файла. Используется для бинарей которые читают файл, доступный только определённой группе:
ls -l /usr/bin/wall
# -rwxr-sr-x root tty ...
▸wall пишет в tty всех юзеров (группа tty), не имея root
На каталоге - наследование группы (gid inheritance)
ЭТО ВАЖНЕЕ. Новые файлы создаваемые в каталоге получают группу каталога, а не primary group создателя. Используется для shared-папок:
sudo mkdir /srv/team
sudo chown root:devs /srv/team
sudo chmod 2775 /srv/team # SGID + rwxrwxr-x
# Теперь:
cd /srv/team
touch foo.txt
ls -l foo.txt
# -rw-rw-r-- 1 serge devs ... foo.txt ← группа devs, не serge
Без SGID файлы получили бы primary group юзера (часто serge:serge),
и другие члены команды не смогли бы их редактировать.
Sticky bit - защита от удаления чужого
На каталоге с правами rwx любой юзер может удалить любой файл
внутри (потому что удаление = модификация каталога, а не файла). Для
shared-папок типа /tmp это проблема - Алиса может стереть файл Боба.
Sticky bit меняет правило: удалить файл из каталога может только владелец файла (или root).
ls -ld /tmp
# drwxrwxrwt 22 root root ... /tmp ← `t` в конце = sticky
# Создать sticky-каталог:
sudo mkdir /shared
sudo chmod 1777 /shared
На обычных файлах sticky не имеет смысла на современных Linux (исторически означал «держать в swap», давно неактуально).
Аудит - найти все SUID/SGID на хосте
# все SUID-файлы
sudo find / -xdev -perm -4000 -type f 2>/dev/null
# все SGID-файлы
sudo find / -xdev -perm -2000 -type f 2>/dev/null
# SUID или SGID
sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null
Флаг -xdev - не уходить за пределы текущей ФС (важно: иначе перейдёт в
/proc, /sys, NFS-монтировки).
Любой новый SUID-файл на проде = повод разобраться.
Эталонный набор обычно: passwd, sudo, mount, umount, su,
chsh, chfn, newgrp, pkexec, chage. Дистро-специфичные могут
быть, но всё что не оттуда - подозрительно.
Удалить SUID/SGID/sticky
chmod u-s /path/to/file # снять SUID
chmod g-s /path/to/file # снять SGID
chmod -t /path/to/dir # снять sticky
Или числом: chmod 0755 явно сбрасывает спецбиты в 0.