PHP-скрипт не может получить доступ к папке /tmp.

Вопрос или проблема

У меня нет open_basedir, PHP может получить доступ к /etc /usr /proc /home и т.д., но не к /tmp.

tmpfs подключен к /tmp (/tmp тип tmpfs (rw)). Это также причина, по которой я хочу использовать папку /tmp.

Мои файлы принадлежат http (пользователь для nginx и php) и доступны для чтения всеми.

sudo -u http cat /tmp/file работает, но ничего внутри PHP-скрипта нет (например, file_exist() или file()).

редактировать: ошибка в журнале:

PHP Warning:  file(/tmp/ydlw/pid): failed to open stream: No such file or directory in /srv/http/ydlw/status.php on line 267

редактировать2: я проверил проблему другим способом. Я сделал

touch("/tmp/boo");
file_exist("/tmp/boo");

и file_exist возвращает true, так что файл создан. Затем я посмотрел внутри /tmp, и никакого файла “boo” там не оказалось. Это то, чего я боялся, PHP не «видит» точку монтирования. Почему это происходит и как я могу это исправить?

Я нашел причину, ну, кто-то дал мне общий намек.

Это не вина PHP или tmpfs. Виноват был systemd и его система безопасности PrivateTmp.

Для тех, кто столкнулся с такой же проблемой, как и я, служба PHP (а возможно, и некоторые другие) имеют опцию PrivateTmp включенной в скрипте systemd (/usr/lib/systemd/system).

В этом случае создается новый /tmp и изолируется от другого. Все данные внутри удаляются, как только служба останавливается.

Это мера безопасности, так как /tmp может содержать много конфиденциальной информации, а PHP-скрипты не всегда безопасны.

Чтобы отключить это, просто скопируйте скрипт в /etc/systemd/system (чтобы избежать перезаписи ваших изменений после обновления) и установите для PrivateTmp значение false.

Вы также можете установить, чтобы две и более службы делили один и тот же /tmp с помощью JoinsNamespaceOf.

Для получения дополнительной информации > man systemd.exec

Я знаю, я немного запоздал, но сейчас я тоже над этим работаю, поэтому хочу добавить одну идею. Как написал @eephyne, PrivateTmp — это мера безопасности, выключение которой, возможно, не лучший выбор. Чтобы преодолеть проблему, когда одна служба не может получить доступ к файлам в /tmp другой службы, systemd предлагает опцию JoinsNamespaceOf=. Используя это, мы можем определить службы, которые делятся /tmp, /var/tmp… но изолированы от /tmp других служб.

Чтобы добавить JoinsNamespaceOf= к юнитам systemd, не редактируйте файлы юнитов напрямую, всегда используйте systemctl edit ..., чтобы избежать путаницы при обновлениях ОС.

Ответ или решение

Проблема доступа PHP-скрипта к каталогу /tmp

Проблема:

Вас тревожит, что PHP-скрипты не могут получить доступ к каталогу /tmp, несмотря на то, что ограничение open_basedir не установлено, и другие пути, такие как /etc, /usr и /proc, доступны. Вы отметили, что:

  • tmpfs смонтирован на /tmp с правами на запись (rw).
  • Файлы принадлежат пользователю HTTP, который является пользователем для nginx и PHP и доступны для чтения всем.
  • Запуск sudo -u http cat /tmp/file работает, но внутрь PHP возвращаются ошибки, подобные: PHP Warning: file(/tmp/ydlw/pid): failed to open stream: No such file or directory.

Позднее было установлено, что проблема связана с настройкой PrivateTmp в systemd. Давайте разберёмся, что это значит и как решить эту ситуацию.

Теория:

Systemd предоставляет ряд опций для повышения безопасности различных сервисов, в том числе PHP. Одной из таких опций является PrivateTmp. Данная опция создаёт изолированную временную файловую систему для процесса, что предотвращает доступ к глобальному /tmp. Таким образом, каждый сервис может использовать свой собственный приватный каталог временных файлов, и это исключает возможность доступа к процессам из других сервисов, снижая риск утечки информации.

Однако из-за этого механизма PHP-скрипты, работающие в контексте этой изолированной среды, не могут видеть файлы, которые находятся в общем /tmp, что может вызывать описанные вами проблемы.

Пример:

Если в настройках сервиса PHP или любого другого сервиса, который использует /tmp совместно, задана опция PrivateTmp=true, то каталоги временных файлов будут отделены и недоступны для доступа извне.

Чтобы проверить, действительно ли PrivateTmp является источником проблемы, можно временно установить для него значение false.

Применение:

Для изменения поведения службы PHP или другой службы:

  1. Копирование файла единицы из /usr/lib/systemd/system в /etc/systemd/system:

    Это необходимо сделать для предотвращения перезаписи настроек при обновлениях системы.

    sudo cp /usr/lib/systemd/system/<service_name> /etc/systemd/system/
  2. Изменение значения PrivateTmp:

    Вредное изменение конфигурации можно сделать обычным текстовым редактором, например, nano или vi.

    sudo nano /etc/systemd/system/<service_name>

    Найдите строку PrivateTmp=true и измените её на PrivateTmp=false.

  3. Перезагрузка службы:

    После изменений нужно перезапустить службу, чтобы они вступили в силу.

    sudo systemctl daemon-reload
    sudo systemctl restart <service_name>
  4. Альтернативный подход с JoinsNamespaceOf:

    Если у вас есть несколько служб, которым необходимо совместно использовать /tmp, вместо отключения PrivateTmp, вы можете использовать JoinsNamespaceOf. Это позволит нескольким службам разделять один и тот же временной каталог, не нарушая общей безопасности.

    Воспользуйтесь командой systemctl edit <service_name>, чтобы добавить строку JoinsNamespaceOf=<имя другой службы> в конфигурацию службы.

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

Заключение:

Использование systemd и его опции PrivateTmp — это эффективный способ увеличения безопасности серверной инфраструктуры. Однако, как и при любом другом изменении в настройках безопасности, следует тщательно взвесить все за и против, перед тем как менять параметры конфигурации службы. Если возможна альтернатива через JoinsNamespaceOf, это предпочтительнее с точки зрения безопасности.

Важно помнить о том, что изменения в службе через systemd лучше всего делать через стандартные команды управления systemctl, чтобы избежать проблем в будущем и сохранить конфигурации в обновлённом состоянии при системных обновлениях.

Оцените материал
Добавить комментарий

Капча загружается...