Откуда у нового файла именно эти права: механика umask
Вы создаёте файл — а у него оказывается 644. Создаёте каталог рядом — а у него 755. Ни разу не запускали chmod, но права почему-то именно такие, и на другом сервере при вроде бы той же команде получаются другие цифры. Дело не в магии и не в дистрибутиве — это работает umask, маска, которая молча вычитает часть прав у каждого нового файла и каталога в момент создания. Разберёмся, как именно она считает и почему от неё зависит, будет ли у свежего файла право на выполнение.
Содержание
Что программа запрашивает при создании файла
Когда процесс создаёт файл — через системный вызов open() с флагом O_CREAT или через creat() — он передаёт ядру желаемый режим доступа (mode). Для подавляющего большинства программ, которые просто открывают новый файл на запись (текстовый редактор, лог, конфиг, дамп базы), этот запрошенный режим — 0666, то есть rw-rw-rw-: чтение и запись для всех трёх категорий (владелец, группа, остальные), но ни одного бита на выполнение.
Это не случайность. У новосозданного файла с данными нет причины быть исполняемым — это просто последовательность байт. Право на выполнение имеет смысл только для того, что действительно предполагается запускать: скомпилированный бинарник, скрипт, библиотеку. Поэтому в стандартный запрос на создание файла бит x не закладывается вообще — ни для кого. Если файлу нужно быть исполняемым, это отдельное, осознанное действие: либо программа явно запрашивает 0777 (так иногда делают компиляторы и установщики для бинарников), либо вы сами добавляете chmod +x после того, как файл уже создан.
С каталогами всё иначе. Когда процесс создаёт каталог через mkdir(), запрошенный режим по умолчанию — 0777, то есть rwxrwxrwx. Здесь бит x заложен сразу и для всех, потому что для каталога он означает не «выполнение», а право «войти» в него — пройти через него при разрешении пути, заглянуть внутрь по имени файла (это отдельная история от бита r, который даёт право *перечислить* содержимое). Каталог без x бесполезен даже своему создателю: в него нельзя зайти, из него нельзя прочитать файл по имени, хотя ls при желании ещё может показать список имён, если есть r. Поэтому мкdir честно просит x сразу для всех — предполагается, что зайти в только что созданный каталог вы, скорее всего, захотите.
Итого: 0666 для файлов и 0777 для каталогов — это не итоговые права, а именно *запрос*, стартовая точка, из которой umask дальше что-то вычитает.
Механика вычитания: не минус, а логическое И с отрицанием
Слово «маска» здесь буквальное. umask — это трёхразрядное восьмеричное число (иногда четырёхразрядное, если учитывать биты setuid/setgid/sticky, но для повседневной работы хватает трёх), где каждый установленный бит означает «этот бит доступа запрещён у новых файлов и каталогов». Формула:
итоговые_права = запрошенные_права AND (NOT umask)
Это побитовая операция, а не арифметическое вычитание — и разница принципиальна, потому что бит либо есть, либо его нет, а десятичное вычитание может дать неверный результат на смешанных значениях. Возьмём не самый круглый пример: umask 027 и запрошенные права файла 666.
Переведём в биты по три на категорию (владелец / группа / остальные):
666 = rw-rw-rw- = 110 110 110
027 = ---w-rwx = 000 010 111
NOT 027 (в пределах 3x3 бит) = 111 101 000
110 110 110 (запрошено: 666)
AND
111 101 000 (инверсия umask 027)
-------------
110 100 000 = 640 = rw-r-----
Итог — 640: владельцу чтение и запись, группе только чтение, остальным ничего. Обратите внимание: umask 027 не «отнимает 27» от 666 арифметически (получилось бы 639, что вообще не является допустимой комбинацией прав) — она гасит конкретные биты: бит записи у группы и биты чтения/записи/выполнения у остальных. Именно поэтому в umask нет понятия «отрицательных» или «переносимых» разрядов — каждый восьмеричный разряд обрабатывается независимо, бит за битом.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверСчитаем на трёх типичных значениях
Возьмём три umask, которые реально встречаются на серверах, и посчитаем, что получится для файла (запрос 666) и для каталога (запрос 777).
| umask | Файл (из 666) | Каталог (из 777) | Смысл |
|---|---|---|---|
022 | 644 = rw-r--r-- | 755 = rwxr-xr-x | группа и остальные — только чтение, без записи |
002 | 664 = rw-rw-r-- | 775 = rwxrwxr-x | группа получает запись наравне с владельцем, остальные — только чтение |
077 | 600 = rw------- | 700 = rwx------ | доступ только владельцу, ни группе, ни остальным ничего |
022 — типичное значение для интерактивной сессии обычного пользователя на многих дистрибутивах: файлы читаемы всеми, но пишет в них только владелец. 002 часто встречается там, где применяется схема «приватной группы пользователя» (когда у каждого пользователя есть своя группа с тем же именем, а рабочие каталоги имеют общую групповую принадлежность) — она разрешает участникам одной группы писать в общие файлы без chmod после каждого создания. 077 — параноидальный вариант для каталогов с секретами (ключи, приватные конфиги), где даже члены своей группы не должны видеть содержимое.
Обратите внимание на асимметрию: при 022 файл получает 644 (без x вообще, потому что в запросе 666 бита x не было и вычитать было нечего), а каталог — 755 (с x у всех, потому что запрос 777 этот бит содержал, а umask 022 его не трогает — она гасит только биты записи для группы/остальных). Это прямое следствие того, что обсуждали в первом разделе: umask никогда не *добавляет* биты, только вычитает те, что были в запросе. Если файлу изначально не запрошено право на выполнение, никакая umask его не подарит — и наоборот, никакая umask не сделает исполняемым то, что программа не просила исполняемым.
Где живёт значение umask и почему оно не одно на сервере
Здесь начинаются практические грабли. umask — это не глобальная константа системы, а атрибут процесса, который наследуется от родителя к потомку при fork()/exec(). Это значит, что на одном сервере одновременно могут действовать разные значения umask в разных контекстах, и «одинаковая» команда, запущенная в разных местах, даст разные права на выходе.
Основные источники, где umask задаётся или переопределяется:
- Интерактивная shell-сессия. Обычно umask выставляется в
/etc/profile,/etc/bash.bashrcдля всех пользователей и может быть переопределена в персональных~/.bash_profile,~/.profile,~/.bashrc. Проверить текущее значение просто:
umask # показать в восьмеричном виде
umask -S # показать в символьном виде, rwx
- PAM и
/etc/login.defs. Модульpam_umaskможет выставлять umask при входе в систему на основании директивыUMASKв/etc/login.defs, причём поведение зависит отUSERGROUPS_ENAB: если включена схема приватных групп, для обычных пользователей может действовать002вместо системного022, даже если вlogin.defsпрописано другое значение по умолчанию — это одна из самых частых причин, когда «на одном сервере всё как обычно, а на другом права другие», хотя оба сервера вроде бы одного дистрибутива. - systemd-юниты. У сервиса, запущенного через systemd, своя umask, не имеющая отношения к тому, что прописано в
.bashrcпользователя, от имени которого он работает. По умолчанию это обычно0022, но её можно явно задать в юните:
[Service]
UMask=0027
Это значит: файлы, которые создаёт демон (логи, сокеты, временные файлы), получат права по этой маске независимо от того, какая umask настроена в интерактивном шелле того же пользователя.
- cron. Классический cron не читает
~/.bashrcвообще — задания запускаются в минимальном окружении, и umask там часто отличается от интерактивной сессии того же пользователя. Если нужна конкретная маска, её задают прямо в crontab:UMASK— не везде поддерживаемая директива, надёжнее явно вызватьumask 022первой строкой в самом скрипте задания. su,su -,sudo,sudo -i.su -(с дефисом, «логин-шелл») обычно инициализирует окружение заново, включая umask через PAM, а простойsuбез дефиса может унаследовать umask родительского процесса.sudoпо умолчанию тоже не гарантированно пересоздаёт umask по правилам целевого пользователя — поведение зависит от настроек PAM и версии sudo, так что при подозрениях проще явно проверитьumaskпосле входа, чем полагаться на память.- Docker-контейнеры. Процесс внутри контейнера получает umask от своего init-процесса — как правило
0022, если entrypoint-скрипт явно её не меняет вызовомumask. При этом файлы, скопированные в образ инструкциейCOPY/ADDна этапе сборки, вообще не создаются черезopen()внутри работающего процесса — им права назначает сборщик образа напрямую (можно явно указать черезCOPY --chmod=), и umask здесь ни при чём: это не рантайм-создание файла, а разметка слоя образа.
Практика: что из этого следует на общем сервере
Из механики выше вытекает несколько вещей, которые стоит держать в голове, когда несколько человек или сервисов работают с одной файловой системой.
Копирование не всегда сохраняет права. Когда вы копируете файл командой cp без флага -p, целевой файл — это новый файл, создаваемый через open(), и на него действует umask *текущего* процесса-копировщика, а не права файла-источника. cp -p, rsync -a, tar с сохранением атрибутов — все они специально обходят этот путь и переносят исходный режим явно через chmod после создания. Если у вас после переноса данных права на файлах внезапно оказались не такими, как на исходной машине — это именно та механика; подробный разбор похожего случая на живых данных есть в статье про то, как права доступа терялись при переносе двух терабайт.
Общие каталоги команды держатся на комбинации umask и SGID. Если несколько пользователей одной группы пишут в общий каталог, одной umask 002 недостаточно — она даёт группе право записи, но группой нового файла по умолчанию становится основная группа *создателя*, а не группа каталога. Чтобы новые файлы автоматически наследовали группу каталога, на сам каталог ставят бит SGID: chmod g+s /shared/dir. Тогда umask 002 + SGID вместе дают ожидаемый эффект: любой участник группы создаёт файлы, доступные на запись остальным участникам. Это один из практических инструментов, которыми пользуются, когда нужно дать команде доступ к серверу без выдачи root — общий каталог с правильной группой и SGID часто закрывает задачу без единой лишней привилегии.
umask действует в момент создания, а не постфактум. Права, которые получает файл, фиксируются в его inode сразу при создании — там же, где хранятся владелец, группа и прочие метаданные записи. Если позже изменить umask, это никак не повлияет на уже существующие файлы — только на те, что будут созданы после изменения. О том, что вообще происходит при появлении новой записи на файловой системе и почему это завязано на выделение inode, подробнее в статье про инод и создание файла.
Явный chmod в коде программы обходит umask лишь частично. Если приложение вызывает open(path, O_CREAT, 0755), запрашивая права 755 напрямую, это всё равно проходит через ту же формулу с текущей umask — то есть при umask 022 результат будет 755 AND ~022 = 755 (ничего не меняется, потому что запрошенные биты и так не пересекались с маской), а вот при umask 077 тот же вызов даст уже 700. Многие установщики и системы сборки пакетов знают об этом и после создания файла делают отдельный явный chmod(), чтобы гарантированно получить нужный режим независимо от umask процесса, который их запустил — это самый надёжный способ не зависеть от окружения.
NFS и Samba могут вообще перебить локальную umask. Сетевые файловые системы нередко настраиваются с опциями вроде force user/force group/create mask (Samba) — сервер в этом случае переопределяет итоговые права независимо от того, что насчитала umask клиента. Если результат на смонтированном ресурсе не совпадает с тем, что вы посчитали по формуле выше — сначала проверьте настройки экспорта на стороне сервера, а не ищите ошибку в клиентском окружении.
Git не хранит umask, а хранит только бит исполняемости. В индексе git запоминает режим файла упрощённо — либо 100644 (обычный файл), либо 100755 (исполняемый), остальные биты прав определяются umask системы при checkout. Поэтому один и тот же репозиторий на разных серверах с разными umask может дать файлам разные фактические права (644 против 640), при этом бит x, если он был закоммичен, сохранится на обеих машинах одинаково — это разные механизмы, и путать их не стоит.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли посмотреть, какие права получит новый файл, не создавая его?
Прямого системного вызова для этого нет, но можно просто посчитать вручную: возьмите базовый запрос (666 для файла, 777 для каталога) и примените текущую umask по формуле из статьи — либо запустите umask -S, чтобы сразу увидеть символьное представление действующей маски.
umask 000 — это то же самое, что chmod 777?
Нет. umask 000 означает «ничего не вычитать», то есть новые файлы получат ровно запрошенные права — 666 для обычного файла и 777 для каталога, но не более того. Она не задаёт права напрямую и не может поднять права выше того, что программа изначально запросила при создании.
Почему у файла, скачанного через wget или curl, права 644, хотя umask у меня 022 — это же должно совпадать?
Совпадает: 666 AND ~022 = 644, это ожидаемый результат для обычного файла. Если вы ждали других прав, вероятно, вы путаете значение umask с итоговым режимом — это разные числа, и результат всегда нужно получать применением формулы, а не подстановкой значения umask как есть.
Как сделать так, чтобы все новые файлы в конкретном каталоге сразу получали нужные права, не полагаясь на umask процесса?
Для каталога с общим доступом надёжнее использовать POSIX ACL по умолчанию: setfacl -d -m g:teamgroup:rw /shared/dir задаёт права, которые будут применяться к новым файлам в этом каталоге независимо от umask создающего их процесса — это более точный инструмент, чем полагаться на то, что umask у всех участников настроена одинаково.
Влияет ли umask root на то, какие права получают файлы, создаваемые системными сервисами?
Да, если сервис запущен от root и не задаёт UMask= явно в своём systemd-юните, он унаследует umask родительского процесса — обычно это umask, с которым стартовал сам systemd (PID 1), а не какого-то конкретного администратора. Для предсказуемости лучше не полагаться на наследование, а прописывать UMask= явно в юните каждого сервиса, где это важно.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →