vsz*_*vsz 35 setuid privileges
一个巨大的应用程序需要在某个特定时间对需要 root 权限的文件执行少量写入。它不是真正的文件,而是作为文件暴露给 Linux 的硬件接口。
为了避免为整个应用程序授予 root 权限,我编写了一个 bash 脚本来执行关键任务。例如,以下脚本将启用硬件接口的端口 17 作为输出:
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
Run Code Online (Sandbox Code Playgroud)
但是,由于suid我系统上的 bash 脚本被禁用,我想知道实现这一目标的最佳方法是什么。
使用此处介绍的一些解决方法
sudo从主应用程序调用脚本,并相应地编辑 sudoers 列表,以避免在调用脚本时需要密码。授予 sudo 权限让我有点不舒服echo。
只需编写一个 C 程序,使用fprintf,并将其设置为 suid root。对字符串和文件名进行硬编码,并确保只有 root 可以编辑它。或者从文本文件中读取字符串,同样确保没有人可以编辑该文件。
我没有想到的其他一些解决方案比上面介绍的更安全或更简单?
cas*_*cas 33
您无需授予sudo访问权限echo。事实上,这是没有意义的,因为例如使用sudo echo foo > bar,重定向是作为原始用户而不是 root 完成的。
使用 调用小脚本sudo,NOPASSWD:仅允许需要访问它的用户访问该脚本(和任何其他类似脚本)。
这始终是使用sudo. 将少量需要 root 权限的命令隔离到它们自己的单独脚本中,并允许不受信任或部分受信任的用户仅以 root 身份运行该脚本。
小sudo脚本不应该从用户那里获取参数(或输入)(即它调用的任何其他程序都应该有硬编码的选项和参数),或者它应该非常小心地验证它必须的任何参数/输入接受用户。
在验证中保持偏执——而不是寻找“已知的坏”事物来排除,只允许“已知的好”事物并在任何不匹配或错误或任何甚至远程可疑的情况下中止。
验证应尽可能早地在脚本中进行(最好在以 root 身份执行任何其他操作之前)。
当我第一次写这个答案时,我真的应该提到这一点,但如果你的脚本是一个 shell 脚本,它必须正确引用所有变量。以任何方式引用包含用户提供的输入的变量时要特别小心,但不要假设某些变量是安全的,引用它们全部。
包括由用户潜在地控制(例如环境变量"$PATH","$HOME","$USER"等。并且,包括绝对"$QUERY_STRING"和"HTTP_USER_AGENT"等在一个CGI脚本)。事实上,只需引用它们。如果您必须构造带有多个参数的命令行,请使用数组来构建 args 列表并引用 - "${myarray[@]}"。
我是否经常说“全部引用”?记住它。做吧。
jpa*_*jpa 16
检查 gpio 文件的所有者:
ls -l /sys/class/gpio/
Run Code Online (Sandbox Code Playgroud)
很可能,您会发现它们归组所有gpio:
-rwxrwx--- 1 root gpio 4096 Mar 8 10:50 export
...
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您只需将您的用户添加到gpio组中即可授予访问权限,而无需 sudo:
sudo usermod -aG gpio myusername
Run Code Online (Sandbox Code Playgroud)
您需要注销并在此之后重新登录才能使更改生效。
对此的一种解决方案(特别是在 Linux 桌面上使用,但也适用于其他情况)是使用D-Bus激活以 root身份运行的小型服务,并使用polkit进行授权。这就是 polkit 的设计初衷;从其介绍性文件:
polkit 提供了一个授权 API,旨在供特权程序(“MECHANISMS”)使用,为非特权程序(“CLIENTS”)提供服务。有关系统架构和大图,请参阅 polkit 手册页。
大的、无特权的程序不会执行您的帮助程序,而是会在总线上发送请求。您的助手可以作为在系统启动时启动的守护程序运行,或者更好地由 systemd 根据需要激活。然后,该助手将使用 polkit 来验证请求是否来自授权位置。(或者,在这种情况下,如果感觉有点矫枉过正,您可以使用其他一些硬编码的身份验证/授权机制。)
我找到了一篇关于通过 D-Bus 进行通信的很好的基本文章,虽然我还没有对其进行测试,但这似乎是将 polkit 添加到 mix 的基本示例。
在这种方法中,不需要标记 setuid。
一种方法是制作一个用 C 编写的 setuid-root 程序,它只执行需要的操作,仅此而已。在您的情况下,它根本不需要查看任何用户输入。
#include <unistd.h>
#include <string.h>
#include <stdio.h> // for perror(3)
// #include ... more stuff for open(2)
static void write_str_to_file(const char*fn, const char*str) {
int fd = open(fn, O_WRONLY)
if (-1 == fd) {
perror("opening device file"); // make this a CPP macro instead of function so you can use string concat to get the filename into the error msg
exit(1);
}
int err = write(fd, str, strlen(str));
// ... error check
err = close(fd);
// ... error check
}
int main(int argc, char**argv) {
write_string_to_file("/sys/class/gpio/export", "17");
write_string_to_file("/sys/class/gpio/gpio17/direction", "out");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
没有办法通过环境变量或任何东西来破坏它,因为它所做的只是进行几个系统调用。
缺点:您应该检查每个系统调用的返回值。
好处:错误检查真的很容易:如果有任何错误,只需perror退出:以非零状态退出。如果有错误,请使用 进行调查strace。你不需要这个程序本身来提供非常好的错误消息。