Search code examples
phppermissions

Permissions problems with proc_open


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?


Solution

  • 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().