(U)通过“exec”和“sudo”安装.用户是NOPASSWD的“sudoer”


(U)Mounting through "exec" with "sudo". The user is a "sudoer" with NOPASSWD

我已经看过这两个:

  • PHP:挂载 USB 设备
  • 通过 php"exec"挂载时出错

但是,我的问题似乎有所不同。


我构建了一个广泛的库,用于调用Linux CLI工具。它是围绕proc_open建造的,它是家庭和POSIX

正在使用它成功执行所有(直到我遇到这个mount/umount错误)CLI 工具。

现在,我正在构建一个 RAID 设置例程,它涉及 partprobeparted - rmmklabelmkpartmdadm - 停止零超级块创建ddmkfs并最终mount/umount

实际上有两个优雅的例程,一个用于组装 RAID,另一个用于拆卸。

正如标题所说,问题依赖于mountumount。上面列出的其他工具及其命令已成功执行。

环境

Arch Linux - Linux

stone 3.11.6-1-ARCH #1 SMP PREEMPT 周五 10 月 18 日 23:22:36 CEST 2013 x86_64 GNU/Linux.

拱门正在运行systemd - 可能是以某种方式影响了安装。

运行mod_php(最新)的 Apache Web 服务器(最新)。阿帕奇以http:http运行。

httpwheel组中,wheels是闺鸟 - %wheel ALL=(ALL) NOPASSWD: ALL .
请不要在webserver开始讨论完整的根功能 - 该单元是 NAS,它运行自定义 WebOS,并且仅用于内部网。即使有黑客攻击尝试 - 这些尝试很可能会破坏整个系统,这对客户来说是不健康的。NAS 是 Mobotix IP 摄像机的存储, 它运行大量依赖服务,并且这些单元已经部署在 30 多个对象中,没有问题.简而言之,webserver不是为网络服务,而是为操作系统服务。

在写作之前,我添加了,为了快速测试,明确地http sudoers - http ALL=(ALL) NOPASSWD: ALL - 不起作用。

问题

在 RAID 组装过程中运行的最后一个命令是 mount /dev/md/stone':supershare /mnt/supershare ,它返回的退出代码为 0

执行后续装载会导致:

mount: /dev/md127 is already mounted or /mnt/supershare busy
/dev/md127 is already mounted on /mnt/supershare

退出代码为 32 。因此,阵列安装在某处。

在上述mount之后执行umount /dev/md/stone':supershare,返回退出代码 0 。执行后续umount会导致:

umount: /dev/md/stone:supershare: not mounted

上面的命令是使用 sudo 自动运行的。

因此,它已成功安装并成功卸载,但是...我在 TTY0 上以root身份登录,在执行mount操作后运行lsblk,但我没有看到mountpoint

NAME      MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda         8:0    0  55.9G  0 disk
├─sda1      8:1    0     1M  0 part
├─sda2      8:2    0     1G  0 part  [SWAP]
├─sda3      8:3    0    12G  0 part  /
└─sda4      8:4    0  16.6G  0 part  /home
sdb         8:16   0 931.5G  0 disk
└─sdb1      8:17   0   899M  0 part
  └─md127   9:127  0   1.8G  0 raid0
sdc         8:32   0 931.5G  0 disk
└─sdc1      8:33   0   899M  0 part
  └─md127   9:127  0   1.8G  0 raid0

尝试从 TTY0 执行相同的mount命令会成功挂载它(lsblk 在之后显示)。


如果我使用 CLI 工具mount它,然后运行 mount -l 并使用 CLI 工具lsblk,则挂载点是可见的。

立即以 root 身份从 TTY0 运行这两个命令,不显示挂载点。


重新启动,重置所有挂载(非自动挂载),然后,从 TTY0 挂载并从 TTY0 运行lsblk将显示挂载点。

然后,使用 CLI 工具运行lsblk,显示挂载点。

然后,使用 CLI 工具运行umount,退出代码0 - 已卸载。

再次使用 CLI 工具运行lsblk,不显示挂载点。

从 TTY0 运行lsblk,仍会显示挂载点。


似乎当mount/umount使用我的 CLI 工具运行时,它会私下执行sudo会话运行器的命令。

umount 在 TTY0 挂载后,确实会卸载它,但再次 - 私下。


从 TTY0 http登录并在从 CLI 工具挂载 RAID 后运行lsblk,则不会显示挂载点。这否定了"为sudo会话运行器私下执行"。


我还在IBM的中找到了一个材料:

mount 命令使用实际用户 ID(而不是有效用户 ID)来确定用户是否具有适当的访问权。系统组成员可以发出设备装载,前提是他们对装载点和/etc/file systems 文件中指定的装载具有写入访问权限。具有 root 用户权限的用户可以发出任何挂载命令


我希望我已经解释得足够好并且不会太混乱,我也希望你们能够帮助我在这里解决问题。


更新 (2013-10-28)

我尝试在 Web 上下文之外使用 CLI 工具进行测试,一个简单的 PHP 文件,我将与root和自定义用户一起执行。

在这两种情况下,装载和卸载都成功。所以,它一定是Apache执行命令的东西,但是,我不明白为什么其他命令有效。

问题

是什么导致了这个问题,我该如何克服它?

简而言之,麻烦已经解决。

阿帕奇的相应systemd服务,PrivateTmp=true指令。显然,该指令使用新的文件系统命名空间执行进程。


这个问题在尝试调试和解决问题时,在互联网上催生了许多其他帖子。

  1. https://unix.stackexchange.com/questions/97897/sudo-mount-from-webserver-apache-by-mod-php-result-not-visible-by-root
  2. https://bbs.archlinux.org/viewtopic.php?id=172072
  3. https://unix.stackexchange.com/questions/98182/a-process-run-as-root-when-performing-mount-is-mounting-for-self-how-to-ma/98191#98191

每一个都源于我在这个过程中学到的东西。

我从获取有关mount从事EUID工作的更深入的信息开始。很快,我发现我的简单sudo调用实际上没有用EUID 0执行。这导致我对如何做到这一点提出了多个疑问,作为回报,催生了命令语法,如sudo -i 'su' -c 'mount /dev/sdb1 /mnt/firstone'和其他衍生物。

由于解决方案没有成功,我看得更远。

我开始考虑尝试将条目添加到/etc/fstab,这导致我遇到了大量权限问题。此外,sudo和我的 CLI 工具被证明是不完整的。让我们带来大武器 - 让我们用-DBIG_SECURITY_HOLE编译 Apache,也称为,让 Apache 可以按root运行。

让我们将条目附加到tab,让我们尝试挂载...和。。。失败!

经过无数次的测试、查询等等,我偶然发现了per process mount,这些把我带到了这里,并向我打开了namespaces的维度。

好的,这解释了一切 - 检查/proc/<pid>/mounts验证它,现在,让我们更深入地啃咬,看看如何克服它。

同样,经过多次尝试但没有成功,我开始根据我对命名空间的新知识发布问题。缩小问题范围并变得更加技术化(至少我认为我做到了),这最终导致了一个用户 hiciu 向我指出systemd方向,特别是 Apaches 服务 - PrivateTmp

瞧!。。。显然systemd可以强制使用新的命名空间。

我有同样奇怪的 apache 行为,花了 3 天多的时间没有任何工作解决方案。然后幸运的是,我找到了这篇文章,正如您所描述的那样,PrivateTmp 导致了这个问题。就我而言,我尝试从 php 挂载驱动器:

<?php
...
exec("sudo mount /dev/sda1 /mnt/drive", $output, $ret);
...
?>

当我从 Web 浏览器运行上面的代码时,exec 函数返回 0(成功),我什至可以在代码中列出映射驱动器:

exec("ls /mnt/drive", $o, $r);
foreach ($o as $line){
  echo $line.'<BR>';
}

但是当我尝试从cli搜索映射驱动器时,我看不到它。我尝试了所有内容,包括更改权限,更改php.ini等。直到现在,改变

PrivateTmp=false

/lib/systemd/system/apache2.service

能解决问题。非常感谢您的分享!

它正在搜索这个,看起来这种行为是通过 chroot 从 php 实现和检测的:

 system('ischroot;echo $?');

设置PrivateTmp=true时给出0(说'你在chroot中'),在PrivateTemp=false时给出1。