proc_open权限问题

Permissions problems with proc_open

提问人:miken32 提问时间:12/15/2022 更新时间:12/15/2022 访问量:280

问:

以 root 身份运行以下 PHP 脚本时遇到权限问题:

#!/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;
}

如果不存在,或者由 root 拥有,脚本本身可以正常运行。但是,如果所有权更改为其他用户,则无论对文件的权限如何,都将失败。/tmp/foo.barproc_open

SELinux 已禁用,我们没有使用 ACL。我在 Alma Linux 9.1 上使用 PHP 7.4.33(我知道它很旧且不受支持,但这是 FreePBX 的要求)。

输出:

$ ./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

即使不考虑我是 root 的事实,组权限也应该允许我对文件进行完全访问。那么这是怎么回事呢?

PHP 权限

评论

0赞 hakre 12/15/2022
PHP 7.4.33 并不是很旧。它很可能是您的 Linux 发行版中受支持的版本。我的猜测是,对于文件模式应该替换为 .'w''a'
0赞 miken32 12/15/2022
我在这里减少的实际 FreePBX 代码使用追加模式,结果相同。(直到上个月,我才意识到 7.4 仍在获得安全更新!
1赞 hakre 12/15/2022
只是看到,错误只在 chown 之后,对吗?这是 /tmp,它有 setuid 或类似的东西。只有所有者有权访问该文件。请查阅您的系统管理手册,我的措辞可能不准确。这是因为传统的 /tmp 在系统上与所有用户共享,但他们不应泄露数据。使用 tmpfile(php) 拥有自己的文件,如果这是您要找的。IIRC proc_open 也接受流句柄。
1赞 Barmar 12/15/2022
这个问题似乎是特定于目录的,可能与它使用粘性位有关。如果我更改脚本以将文件放在我的主目录中,它可以正常工作。/tmp
1赞 miken32 12/15/2022
是的,这就是问题所在。在Unix和Linux上找到了这个答案: unix.stackexchange.com/a/503169/73390

答:

2赞 Barmar 12/15/2022 #1

这是由于目录上的权限。当 PHP 尝试打开文件进行写入时,它会出现错误。从文档:/tmpEACCESopen(2)

EACCES
如果指定了O_CREAT,则启用protected_fifos或protected_regular sysctl,文件已存在并且是 FIFO 或常规文件,文件的所有者既不是当前用户也不是包含目录的所有者,并且包含目录既是全局可写目录又是组可写且具有粘性。有关详细信息,请参见 和 中的说明。/proc/sys/fs/protected_fifos/proc/sys/fs/protected_regularproc(5)

/tmp设置了粘滞位,以便任何人都可以在那里创建文件,但用户只能删除自己的文件。虽然可以绕过此删除限制,但无法绕过上述签入。rootopen()

评论

0赞 miken32 12/15/2022
谢谢;我正在将我们的系统从 RHEL 6 迁移到 9,所以这对我来说是新的东西。
1赞 miken32 12/15/2022 #2

好的,我在不同的目录中尝试了这个,而不是 ,正如评论中建议的那样,它按预期工作。用它来磨练我的搜索词,我很快就能找到这个 U&L 答案。从内核 4.19 开始,内核参数可用。此参数:/tmpfs.protected_regular

不允许在世界可写粘滞目录中打开不属于用户的 FIFO 或常规文件,除非所有者与目录的所有者相同,或者打开文件时没有 O_CREAT 标志。目的是使数据欺骗攻击更加困难。

显然,默认情况下它是启用的。因此,由于它是全局可写的和粘性的,我不能触摸不属于我的文件——即使我是 root。作为记录,如果我必须禁用此功能:/tmp

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

但是我最好尝试以某种方式在代码中解决它。

评论

0赞 hakre 12/15/2022
我对 freepbx 的内在一无所知,但通常对于一个应用程序,可以配置临时目录,以便它不是系统目录,而是应用程序(以及执行应用程序的用户)的目录。XDG 浮现在脑海中,请检查 freepbx 是否支持 TEMPorary 文件的此配置或其他配置。此外,如果你是root用户,你不能在不禁用保护的情况下成为另一个用户吗?
0赞 miken32 12/15/2022
它在代码中被硬编码,而不是使用或其他东西;我可以 sudo,但记住很痛苦。由于文档说如果“[文件]所有者与目录的所有者相同”,我将起作用,我应该能够更改为root所有权并设置777 perms,这样FreePBX用户也可以使用它。/tmpmktemp()