Posted on February 4, 2023 at 10:00 UTC,
filed under the category
Uncategorized.
Tags:
PHP,
Last year I migrated this (and other sites) off a DreamHost VPS, which is a managed VPS product that
does not offer much control over server configuration, to an unmanaged VPS at
Vultr running Rocky Linux.
The server runs nginx and PHP using the FastCGI Process
Manager. Rocky Linux, being a RedHat/CentOS-based
distribution, also runs with SELinux
enabled. SELinux greatly improves the security architecture of the system, but it does sometimes
create obscure problems that take some time to debug. This post will discuss one such problems.
The issue was that PHP file uploads, such as in the bug tracker, were failing to upload, but there
were no obvious error messages in the PHP error log.
When an <input type="file">
is used to submit a HTTP POST
request, PHP reads the uploaded stream into a
temporary file, and it stores
the name of the temporary file in $_FILES['userfile']['tmp_name']
. Unless the upload_tmp_dir
php.ini variable is specified, the files will be put into the default temporary
directory, which in this case was /tmp
.
In addition, the systemd unit file for the php-fpm service
specifies
PrivateTmp=true
. This option
“sets up a new file system namespace for the executed processes and mounts private /tmp/ and
/var/tmp/ directories inside it that are not shared by processes outside of the namespace”. In
practice, that means that php-fpm runs with /tmp mounted from something like
/tmp/systemd-private-026f628ae5ca469eb0213f719ca482-php-fpm.service-blDUvc
outside of the
namespace.
The issue is that php-fpm does not have permission to write this location because of SELinux. To
fix this, I needed to adjust the system SELinux policy to permit php-fpm to write to that
location. To do this, I issued the following command:
sudo semanage fcontext -a '(/var)?/tmp/systemd-private-(.+)-php-fpm\.service-(.*)/tmp(/.*)?' -t httpd_tmp_t
… which specifies a regular expression to the PrivateTmp
path to be treated as the httpd_tmp_t
SELinux label. That grants php-fpm the authority to write files to that directory, which is mounted
at /tmp
for the process.
After adjusting the policy, PHP file uploads worked like normal. The main confusing bit was that
there were no error messages printed to SELinux log nor the PHP log.