Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 12.02 · 22 мин
Начальный
PermissionsrwxchmodsetuidsetgidstickyLinux

rwx-права — девять битов, которые управляют доступом к каждому файлу

Когда вы делаете ls -l и видите -rw-r--r-- — это девять битов в inode файла, которые kernel читает миллиарды раз в день. На каждом open(), на каждом read(), на каждом cd — kernel смотрит эти биты и решает «можно или нельзя». Понимание этой системы — абсолютная база Unix-мира, и одновременно одна из самых частых причин «у меня permission denied», на которые тратятся часы.

В этом уроке разберём: как kernel принимает решение, что значат rwx для разных типов файлов, как chmod конвертирует число в биты, и что делают волшебные setuid/setgid/sticky.


Девять битов и кому они соответствуют

Каждый файл в Linux имеет:

  • Владельца (user, owner) — один UID.
  • Группу — один GID.
  • Девять битов доступа — три набора по три (r, w, x).

Девять битов делятся на три категории:

-rwxr-xr-x
 ^^^^^^^^^
 u  g  o
  • u (user, owner) — права владельца.
  • g (group) — права группы файла.
  • o (other) — права всех остальных.

Когда процесс пытается открыть файл, kernel выполняет проверку:

  1. Если EUID процесса == UID владельца файла — проверяет биты u.
  2. Иначе, если GID файла есть среди групп процесса (primary или supplementary) — проверяет биты g.
  3. Иначе — проверяет биты o.

Важно: только ОДНА проверка. Если вы владелец и u-r не стоит, вы НЕ читаете файл, даже если o-r стоит. Это часто непонимают: «но other может читать, почему я не могу?» Потому что для kernel ваш категория — owner, и эта категория должна разрешить.

Какая из трёх категорий применяется к процессу
EUID == owner UID?Первый чек: процесс работает от имени владельца файла?
yes
Используем биты uПрименяются только биты u (первая тройка rwx). Биты g и o игнорируются
GID есть в моих группах?Если нет совпадения по UID -- проверяем GID. EGID процесса или supplementary groups
yes
Используем биты gПрименяются только биты g (вторая тройка). Биты u и o игнорируются
ИначеЕсли не owner и не group -- остаются only biты o
Используем биты oПрименяются биты o (третья тройка). Биты u и g игнорируются

Root (UID=0) — исключение. Он игнорирует обычные проверки прав (кроме особых случаев типа immutable bit и capabilities).


Что значат r, w, x для файлов

Для обычного файла:

  • r (read) — можно читать содержимое (cat, less, cp).
  • w (write) — можно изменять содержимое (echo > file, редактор сохраняет).
  • x (execute) — можно запускать как программу (./script.sh, ./binary).

Несколько неочевидных моментов:

  • w без r — редко полезно. Можно затереть, но не прочитать. Используется в логах, куда сервис должен только append’ить.
  • x на скрипте. Нужны и r, и x. Чтобы выполнить bash-скрипт, shell должен его прочитать.
  • x на бинарнике. Достаточно только x (kernel сам читает бинарник через специальный канал, не через права).
  • Удалить файл — это W на ДИРЕКТОРИИ, не на файле. См. ниже.
# Создать файл и поиграть с правами:
echo "secret" > /tmp/secret.txt
ls -l /tmp/secret.txt
# -rw-r--r-- 1 levoely levoely 7 May 18 12:00 /tmp/secret.txt

# Убрать чтение для других:
chmod o-r /tmp/secret.txt
ls -l /tmp/secret.txt
# -rw-r----- 1 levoely levoely 7 May 18 12:00 /tmp/secret.txt
# Группа всё ещё читает, others -- нет

# Полностью приватный (только мне):
chmod 600 /tmp/secret.txt
ls -l /tmp/secret.txt
# -rw------- 1 levoely levoely 7 May 18 12:00 /tmp/secret.txt

Что значат r, w, x для директорий

Для директорий значение битов меняется:

  • r (read) — можно ПОЛУЧИТЬ СПИСОК файлов (ls dir/). Без r вы не увидите, какие файлы там есть.
  • w (write) — можно СОЗДАВАТЬ и УДАЛЯТЬ файлы в этой директории (даже не свои!).
  • x (execute) — можно ВОЙТИ в директорию (cd) и обращаться к файлам по имени.

Это контр-интуитивно: чтобы удалить файл secret.txt, не нужны права на сам файл — нужны w на директории, в которой он лежит. Потому что «удалить» — это убрать запись из директории, не из файла.

mkdir /tmp/test
cd /tmp/test
touch myfile
chmod 000 myfile        # никаких прав на файл!
ls -l myfile
# ---------- 1 levoely levoely 0 May 18 12:00 myfile

cat myfile              # cannot open: permission denied (нет r)
echo "x" > myfile       # permission denied (нет w)

rm myfile               # СРАБОТАЕТ! Потому что у вас w на /tmp/test

Сочетание x без r на директории — интересный кейс. Вы можете обращаться к файлу по имени (если знаете), но ls запрещён. Иногда используется для shared-директорий, где никто не должен видеть, какие там файлы, но конкретные адреса работают:

chmod 711 /tmp/private   # x для всех, r только владельцу
touch /tmp/private/known_file
# Из другого аккаунта:
ls /tmp/private              # permission denied
cat /tmp/private/known_file  # works! если файл доступен сам

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

Девять битов — это число от 0 до 0777 в восьмеричной. Каждая тройка rwx — одна восьмеричная цифра:

БитыВосьмеричноеЧто значит
---0ничего
--x1только execute
-w-2только write
-wx3write + execute
r--4только read
r-x5read + execute
rw-6read + write
rwx7всё

Часто встречающиеся комбинации:

ModeСмысл
644rw-r—r— — обычный файл, владелец редактирует, все читают
600rw------- — приватный файл (SSH ключи, токены)
755rwxr-xr-x — исполняемая программа или директория
700rwx------ — приватная директория (например, ~/.ssh)
777rwxrwxrwx — НИКОГДА в production
666rw-rw-rw- — почти всегда плохая идея
chmod на практике: octal, symbolic notation и umask
# Восьмеричной записью:
chmod 644 file.txt
chmod 755 script.sh

# Символьной (mnemonic):
chmod u+x script.sh      # добавить execute владельцу
chmod g-w file.txt       # убрать write у группы
chmod o=r file.txt       # set: only read у others
chmod a+r file.txt       # all (u+g+o): добавить read
WARNING

‘chmod 777’ встречается в туториалах в стиле «помогло, теперь работает». Это маскировка проблемы. Любой пользователь в системе сможет переписать файл — катастрофа в production. Правильный путь: понять, какой UID/GID должен иметь доступ, и дать минимальные нужные права.


Setuid: программа выполняется от имени владельца

Бывают ситуации, когда обычному пользователю нужно временно получить root-права для конкретной операции. Классический пример — passwd: пользователь должен изменить свой пароль, который хранится в /etc/shadow (доступен только root для записи). Как это работает?

/usr/bin/passwd имеет специальный бит setuid (SUID). При запуске такой программы effective UID процесса становится UID владельца файла, а не запустившего:

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 May 18 12:00 /usr/bin/passwd
#    ^ маленькая s вместо x в позиции u-x = setuid bit

s в позиции execute владельца — это SUID. Файл принадлежит root, и при запуске EUID процесса становится 0 (root), хотя RUID остаётся вашим. Поэтому passwd может модифицировать /etc/shadow.

Это мощный механизм, но опасный. Каждая setuid-программа — потенциальная дыра в безопасности. Если в ней есть buffer overflow или command injection, атакующий получает права владельца (часто root).

# Найти все setuid-программы в системе:
find / -perm -4000 -type f 2>/dev/null
# Список обычно небольшой: passwd, sudo, ping, mount, su, ...

# Установить SUID:
chmod u+s /path/to/program  # или
chmod 4755 /path/to/program  # 4 = setuid

# Снять:
chmod u-s /path/to/program

В современном Linux setuid постепенно заменяют capabilities (следующий урок). Например, ping исторически был setuid root (чтобы открывать raw socket), теперь чаще имеет capability CAP_NET_RAW — более точечное право.


Setgid: программа выполняется от имени группы файла

Аналогично, но для группы. SGID-бит на исполняемом файле делает EGID = GID файла при запуске.

s в позиции execute группы:

ls -l /usr/bin/wall
# -rwxr-sr-x 1 root tty 36320 May 18 12:00 /usr/bin/wall
#         ^ s вместо x на g

Wall (write-to-all-users) имеет EGID=tty при запуске — получает право писать в терминалы всех пользователей.

Setgid на ДИРЕКТОРИИ имеет другой смысл: новые файлы в этой директории получают её GID, а не primary GID создателя. Это удобно для shared-папок проекта:

mkdir /shared
sudo chown :developers /shared
chmod 2775 /shared        # 2 = setgid в начале
# Теперь любой файл, созданный в /shared, имеет GID=developers,
# даже если создавший пользователь имеет primary group 'levoely'

Sticky bit: только владелец удалит свой файл

Помните: чтобы удалить файл, нужно w на ДИРЕКТОРИИ, а не на файле. Это значит, что в shared-директории с правами 777 кто угодно может удалить чужие файлы. Решение — sticky bit.

С sticky bit на директории файл может удалить только владелец файла (или владелец директории, или root). Видно как t в позиции execute для others:

ls -ld /tmp
# drwxrwxrwt 28 root root 4096 May 18 12:00 /tmp
#          ^ t = sticky bit

/tmp — классический пример. Любой может создавать файлы, но удалять только свои. Без sticky любой пользователь смог бы удалить чужой /tmp/foo.

# Установить sticky:
chmod +t /shared/dir   # или
chmod 1777 /shared/dir
# 1 = sticky в первой позиции

# Проверить:
ls -ld /shared/dir

Все 12 бит вместе

Полный набор: 9 базовых rwx + setuid + setgid + sticky. Кодируется четырёхзначным восьмеричным числом:

  • Первая цифра — setuid (4) + setgid (2) + sticky (1).
  • Остальные — стандартные u, g, o.
chmod 4755 /usr/bin/passwd   # setuid + 755
chmod 2775 /shared/projects  # setgid + 775
chmod 1777 /tmp              # sticky + 777
chmod 0644 /etc/hosts        # обычный (можно и просто 644)
Полная запись прав файла: 12 бит
setuidЗапустить как владельца файла. 4 в восьмеричной первой цифре
setgidЗапустить как группа файла. На директории -- inherit GID. 2 в восьмеричной
stickyТолько владелец удаляет (на директориях). 1 в восьмеричной
u: rwxПрава владельца (UID файла)
g: rwxПрава группы файла (GID файла)
o: rwxПрава всех остальных

Реальный пример отладки permission denied

# Что делать, если 'cat file.txt' даёт permission denied:

# 1. Что за файл -- права и владелец:
ls -l file.txt
# -rw-r----- 1 alice developers 245 May 18 12:00 file.txt

# 2. Какой у меня UID и группы:
id
# uid=1000(levoely) gid=1000(levoely) groups=1000(levoely),27(sudo)

# 3. Проверка:
#    - я owner? Нет (1000 != UID alice)
#    - я в группе developers? Нет (developers не среди моих групп)
#    - other rwx? --- (нет read для others)
# Результат: permission denied -- правильно.

# 4. Что я могу сделать:
# (a) Попросить alice сделать chmod o+r file.txt
# (b) Попросить admin'а добавить меня в группу developers
# (c) Если есть sudo -- 'sudo cat file.txt' (как root, видит всё)

# 5. Если файл должен быть доступен:
sudo chown alice:developers file.txt   # установить владельца
sudo chmod 640 file.txt                # u=rw, g=r, o=
sudo usermod -aG developers levoely    # добавить меня в группу
# Перелогиниться, чтобы новая группа применилась к shell

Попробуй сам

# 1. Создать файл и посмотреть права:
touch /tmp/exp.txt
ls -l /tmp/exp.txt
# Какой umask определил начальные права?
umask                # обычно 022 -> файлы по умолчанию 644

# 2. Поиграть с chmod:
chmod 600 /tmp/exp.txt
ls -l /tmp/exp.txt
chmod 644 /tmp/exp.txt
chmod a+x /tmp/exp.txt   # хотя это не скрипт, можно дать execute

# 3. Тест удаления через директорию:
mkdir /tmp/td
echo "important" > /tmp/td/file
chmod 000 /tmp/td/file
cat /tmp/td/file        # permission denied
rm /tmp/td/file         # сработает, у вас w на /tmp/td
ls /tmp/td              # пусто

# 4. Найти setuid-программы:
find /usr/bin /usr/sbin -perm -4000 -type f 2>/dev/null

# 5. Посмотреть права /tmp:
ls -ld /tmp
# Обратите внимание на 't' в конце

# 6. Эксперимент с sticky:
mkdir /tmp/shared
chmod 1777 /tmp/shared
ls -ld /tmp/shared       # drwxrwxrwt
# Создайте файл, попросите другого пользователя его удалить -- не получится

# 7. Найти все доступные для записи файлы в /etc (потенциальные риски):
find /etc -type f -perm -o=w 2>/dev/null
# Хорошо настроенная система покажет пустой результат

Проверка знанийKnowledge check
Сервер с веб-приложением на Python (бежит под uid=999 'webapp'). Пользователь 'levoely' (uid=1000) разместил конфиг в /opt/app/config.yaml, права '-rw-r----- 1 levoely staff'. Приложение падает при чтении файла. Какие 3 способа починить и какой 'правильный'?
ОтветAnswer
Проблема: webapp (uid=999) не владелец, не в группе staff, others не имеют r. Результат: permission denied. 3 способа починить: 1) chmod o+r /opt/app/config.yaml -- дать read всем. Быстро, но плохо: любой пользователь на сервере сможет прочитать config (там могут быть пароли, токены). Хуже всего, если это что-то вроде /etc/app/secrets.yaml. 2) chown levoely:webapp /opt/app/config.yaml + chmod 640 -- сменить group на webapp (если такая группа существует), дать g+r. Webapp читает через свою primary group. Минус: нужна группа webapp, и только webapp может читать. Если другие сервисы тоже должны -- усложняется. 3) usermod -aG staff webapp -- добавить webapp в группу staff. Webapp получает доступ через supplementary group. Минус: webapp получает доступ ко ВСЕМ файлам группы staff, не только к config -- может быть слишком широко. 4) Правильный путь -- разделить ответственности и принцип least privilege: - Создать выделенную группу config-readers (или app-config). - Положить config с правами 0640, владелец levoely, группа config-readers (chown levoely:config-readers). - Добавить webapp в config-readers (usermod -aG config-readers webapp). - При необходимости добавлять других читателей в эту группу, не меняя файл. Тогда у webapp точечное разрешение читать именно конфиги, без лишнего доступа. levoely может редактировать через u-bits. Other (root через sudo всё равно может) -- closed. Бонус: для secrets в production правильнее не файл на диске, а secret manager (Vault, AWS Secrets Manager, Kubernetes Secret) -- но это другая история. Если используем файл -- chmod 640 + dedicated group самый чистый вариант. Что точно НЕ делать: chmod 777 (раздать всем write -- катастрофа), chown root (тогда webapp не сможет даже как root прочитать, потому что бежит под webapp).

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4