skip to Main Content

I’m having permissions problems when running the following PHP script as root:

#!/usr/bin/php
<?php
$ph = proc_open('whoami', [['pipe','r'],['pipe','w'],['file','/tmp/foo.bar', 'w']], $fds);
if ($ph) {
    echo 'command output: ' . stream_get_contents($fds[1]);
    proc_close($ph);
} else {
    echo 'proc_open failed' . PHP_EOL;
}

The script itself runs fine if /tmp/foo.bar doesn’t exist, or is owned by root. But if ownership is changed to another user, proc_open will fail regardless of permissions on the file.

SELinux is disabled, and we are not using ACLs. I’m using PHP 7.4.33 (I know it’s old and unsupported, but it’s a requirement for FreePBX) on Alma Linux 9.1.

Output:

$ ./test.php
command output: root
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root     root     4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root     root     4.0K Dec 14 16:48 ..
-rw-r--r--   1 root     root        0 Dec 14 16:57 foo.bar
$ chown admin /tmp/foo.bar
$ ./test.php
proc_open failed
$ chmod 777 /tmp/foo.bar
$ ./test.php
proc_open failed
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root     root     4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root     root     4.0K Dec 14 16:48 ..
-rwxrwxrwx   1 admin    root        0 Dec 14 16:57 foo.bar
$ tail -2 /var/log/php.log
[14-Dec-2022 16:57:17 America/Toronto] PHP Warning:  proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3
[14-Dec-2022 16:57:28 America/Toronto] PHP Warning:  proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3

Even disregarding the fact that I’m root, group permissions should allow me full access to the file. So what’s going on?

2

Answers


  1. Chosen as BEST ANSWER

    Ok I tried this in a different directory than /tmp, as suggested in comments, and it worked as expected. Using that to hone my search terms I was able pretty quickly to find this U&L answer. Beginning with kernel 4.19 the fs.protected_regular kernel parameter was made available. This parameter:

    Disallows open of FIFOs or regular files not owned by the user in world writable sticky directories, unless the owner is the same as that of the directory or the file is opened without the O_CREAT flag. The purpose is to make data spoofing attacks harder.

    Apparently it's enabled by default. So because /tmp is world-writable and sticky, I can't touch files that aren't mine – even if I'm root. For the record, if I have to disable this feature:

    sysctl fs.protected_regular=0
    echo 'fs.protected_regular=0' > /etc/sysctl.d/90-writabletemp.conf
    

    But I'll be better off trying to work around it in the code somehow.


  2. This is due to the permissions on the /tmp directory. When PHP tries to open the file for writing, it gets the EACCES error. From the documentation of open(2):

    EACCES
    Where O_CREAT is specified, the protected_fifos or protected_regular sysctl is enabled, the file already exists and is a FIFO or regular file, the owner of the file is neither the current user nor the owner of the containing directory, and the containing directory is both world- or group-writable and sticky. For details, see the descriptions of /proc/sys/fs/protected_fifos and /proc/sys/fs/protected_regular in proc(5).

    /tmp has the sticky bit set so that anyone can create files there, but users can only delete their own files. Although root can bypass this deletion restriction, it can’t bypass the above check in open().

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search