为什么 SETUID 在 Raspberry Pi 上不起作用?
Why does SETUID not work on Raspberry Pi?
我正在尝试创建一个可以 运行 作为用户的关机命令,i.c,一个不是 运行 root 用户的 flask 网页。听起来很简单,只需在 SETUID 脚本中输入 shutdown
命令即可。因为 SETUID 不适用于 shell 脚本,我从 C 程序创建了一个可执行文件。
问题是这在目标机器上不起作用,Raspberry Pi 零 W。我在我的 Ubuntu 20.4 电脑上测试了同样的东西,运行完美无瑕。所以这个方法本身似乎是正确的,但是有一个raspberry pi问题。
圆周率运行这个OS:
cat /etc/issue
-->
Raspbian GNU/Linux 10 \n \l
这是usershutdown.c:
#include <stdio.h>
#include <stdlib.h>
int main(){
system("/sbin/poweroff");
}
这些是可执行文件的权限:
-rwsr-xr-x 1 root root 7988 Dec 20 23:59 usershutdown
我检查了 /etc/fstab 中根磁盘的挂载选项,我在其中添加了 ,suid
并重新启动:
PARTUUID=738a4d67-02 / ext4 defaults,noatime,suid 0 1
这些是按预期调用 exec 时 Pi 上的错误消息:
$ ./usershutdown
Failed to set wall message, ignoring: Interactive authentication required.
Failed to power off system via logind: Interactive authentication required.
Failed to open initctl fifo: Permission denied
Failed to talk to init daemon.
$
这就是 Pi 上的工作原理,当以 root/sudo 调用 exec 时,与它的 ssh 连接关闭并且设备无错误地关闭:
$ sudo ./usershutdown
$ Connection to picamhq closed by remote host.
Connection to picamhq closed.
$
我该如何解决这个问题?
system()
运行 通过 shell 运行程序,并且 运行 从任何 setuid 程序运行 shell 从安全角度来看是极其危险的;用户可以通过多种方式劫持它来做其他事情(例如,查找滥用 IFS
的方法)。为了缓解这种情况,常用的 shells 将尝试注意它们何时处于 setuid 下 运行(通过注意 real and effective uids are different)并删除特权。
因此,更安全的替代方法是通过 execle
运行 poweroff
。 (execl
也可以,但是传递不受您控制的环境变量是有风险的,因此最好让您的程序设置一个已知安全的环境。)
您的 setuid 程序仍然存在问题,运行任何人都可以使用,因此服务器上的任何非特权本地用户都可以将其关闭。您需要确保它只能由您的应用 运行 所在的用户执行。由于文件的所有者必须是 root
setuid 才能工作,这将需要对组进行一些处理。
您可以通过设置 sudo
来避免所有这些麻烦和风险,以允许您的应用程序的用户 运行 poweroff
命令而无需密码,使用 NOPASSWD
/etc/sudoers
中的指令。这将:
仅限所需用户使用
清洁环境
避免必须维护额外的 setuid 程序所固有的风险(例如,未来的 libc 错误,或者您想要添加功能等)
我正在尝试创建一个可以 运行 作为用户的关机命令,i.c,一个不是 运行 root 用户的 flask 网页。听起来很简单,只需在 SETUID 脚本中输入 shutdown
命令即可。因为 SETUID 不适用于 shell 脚本,我从 C 程序创建了一个可执行文件。
问题是这在目标机器上不起作用,Raspberry Pi 零 W。我在我的 Ubuntu 20.4 电脑上测试了同样的东西,运行完美无瑕。所以这个方法本身似乎是正确的,但是有一个raspberry pi问题。
圆周率运行这个OS:
cat /etc/issue
-->
Raspbian GNU/Linux 10 \n \l
这是usershutdown.c:
#include <stdio.h>
#include <stdlib.h>
int main(){
system("/sbin/poweroff");
}
这些是可执行文件的权限:
-rwsr-xr-x 1 root root 7988 Dec 20 23:59 usershutdown
我检查了 /etc/fstab 中根磁盘的挂载选项,我在其中添加了 ,suid
并重新启动:
PARTUUID=738a4d67-02 / ext4 defaults,noatime,suid 0 1
这些是按预期调用 exec 时 Pi 上的错误消息:
$ ./usershutdown
Failed to set wall message, ignoring: Interactive authentication required.
Failed to power off system via logind: Interactive authentication required.
Failed to open initctl fifo: Permission denied
Failed to talk to init daemon.
$
这就是 Pi 上的工作原理,当以 root/sudo 调用 exec 时,与它的 ssh 连接关闭并且设备无错误地关闭:
$ sudo ./usershutdown
$ Connection to picamhq closed by remote host.
Connection to picamhq closed.
$
我该如何解决这个问题?
system()
运行 通过 shell 运行程序,并且 运行 从任何 setuid 程序运行 shell 从安全角度来看是极其危险的;用户可以通过多种方式劫持它来做其他事情(例如,查找滥用 IFS
的方法)。为了缓解这种情况,常用的 shells 将尝试注意它们何时处于 setuid 下 运行(通过注意 real and effective uids are different)并删除特权。
因此,更安全的替代方法是通过 execle
运行 poweroff
。 (execl
也可以,但是传递不受您控制的环境变量是有风险的,因此最好让您的程序设置一个已知安全的环境。)
您的 setuid 程序仍然存在问题,运行任何人都可以使用,因此服务器上的任何非特权本地用户都可以将其关闭。您需要确保它只能由您的应用 运行 所在的用户执行。由于文件的所有者必须是 root
setuid 才能工作,这将需要对组进行一些处理。
您可以通过设置 sudo
来避免所有这些麻烦和风险,以允许您的应用程序的用户 运行 poweroff
命令而无需密码,使用 NOPASSWD
/etc/sudoers
中的指令。这将:
仅限所需用户使用
清洁环境
避免必须维护额外的 setuid 程序所固有的风险(例如,未来的 libc 错误,或者您想要添加功能等)