OsakaWebbie
OsakaWebbie

Reputation: 699

PHP: way to get the true /tmp path?

I'm moving my web app from CentOS 5 to CentOS 7, and new security features regarding the /tmp directory are breaking my code. I'm wondering how best to handle it.

I have PHP code that creates a LaTeX file, then executes commands to turn that into a PDF, and then serves that to the user with appropriate headers. Here are some of the relevant lines of code as it stands now:

$fileroot = "/tmp/addr".getmypid();
ob_start();
/* echo all the LaTeX stuff */
file_put_contents($fileroot.".tex",ob_get_contents());
ob_end_clean();
exec("cd /tmp;uplatex -interaction=batchmode --output-directory=/tmp $fileroot", $output, $return);

The settings in /usr/lib/systemd/system/php-fpm.service include PrivateTmp=true, which causes /tmp within PHP function calls to really be /tmp/systemd-private-6898f2d665d64b998981bc479ddc2306-php-fpm.service-KU8XML/tmp. Yikes! That's fine for security, but exec() uses the /tmp path literally, so it can't find the file that file_put_contents() just created. The PHP function sys_get_temp_dir() just returns /tmp, and I can't find any environment variables with that path in them. Is there a way to get that path programmatically? Or do I need to turn off PrivateTmp? Or is there a better way to do what I need to do? Yes, I could create my own special spot with wide-open permissions, but it seems like it should be cleaner to just use the normal temporary directory.

Upvotes: 5

Views: 10631

Answers (4)

Benjamin
Benjamin

Reputation: 568

Aleks G is the correct way, but if you still in trouble try this.

I've try "multi-user.target.wants" solution, it have worked but after restart, but at some point, PrivateTmp go back to true. Like my principal use of Apache2 is PHP, I finally edited php.ini and I've uncomment line sys_temp_dir.

By default system use temp dir assigned by function sys_get_temp_dir. Function sys_get_temp_dir will return "/tmp" but the truth is that your tmp files are storing at some path like /tmp/systemd-private-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-apache2.service-YYYYYY//tmp/*. So, what work for me was:

Edit php.ini (path can change between PHP versions)

sudo nano /etc/php/7.2/cli/php.ini

Then uncomment sys_temp_dir line

; Directory where the temporary files should be placed.
; Defaults to the system default (see sys_get_temp_dir)
sys_temp_dir = "/tmp"

Upvotes: 0

Christopher K.
Christopher K.

Reputation: 1195

I just had a similar issue. This is a way to find out the "real" temp path of a systemd service with PrivateTmp (in this case apache2):

 grep -oP ' /tmp/systemd-private-[^/]+-apache2[^/]+/tmp(?= /tmp)' /proc/`pgrep apache2 -o`/mountinfo

What it does:

  • search for the process id of the oldest apache2 process: pgrep apache2 -o
  • read the /proc/PID/mountinfo file, which contains the mount info as seen by this process
  • extract the private tmp folder with a regular expression using grep

It may be that with future systemd versions or different settings, the regex needs to be adjusted, if the naming is different. You may also just use ' /tmp[^ ]+(?= /tmp)' as the regex.

Note that it may not help you much to know the path. Private temp folders have strict permissions that only allow root access.

Upvotes: 3

Bas
Bas

Reputation: 780

I had the same issue (on CentOS) and fixt it with the following steps.

nano /usr/lib/systemd/system/httpd.service

Look in to the file and PrivateTmp=false to PrivateTmp=true

systemctl daemon-reload
service http restart

And you are ready2go

Upvotes: 1

Aleks G
Aleks G

Reputation: 57316

The way I see it, there are only two options:

  1. Do not use /tmp but a different directory instead, which you predefine in your application's config file. I have done something similar recently, where I used /var/run/myapplication directory instead of /tmp. (I had to add a cron job to clean it up as well.)

  2. Disable PrivateTmp in the php-frm service. Here's one way of doing this:

    # mkdir  /usr/lib/systemd/system/php-fpm.service.d
    # echo -e "[Service]\nPrivateTmp=no" > /etc/systemd/system/php-fpm.service.d/privatetmp.conf
    # systemctl daemon-reload
    # systemctl restart php-fpm
    
    # systemctl show php-fpm | grep PrivateTmp
    PrivateTmp=no
    

Upvotes: 4

Related Questions