2

我正在尝试编写一个程序并将其与使用 Gtk+ 构建的 gui 集成。然而,将由 gui 调用的 exe 设置了 setuid 位。但是 gtk 不允许此 exe 按照 gtk 社区的规定运行。然而,他们说我们必须编写单独的帮助程序等等。我真的不明白那是什么意思。任何人都可以请阐明如何克服这个问题?我真的需要立即解决。

4

3 回答 3

4

第一个问题:为什么你的程序是setuid?编写 setuid 程序不是自称 Linux 新手应该玩的游戏。他们很危险。它们很有用——不要误会我的意思。但是它们很危险,而且很难安全地编写。

GTK+ 项目在“ GTK+ - Using setuid ”中非常直截了当地阐述了他们对 setuid 程序的看法。他们给出了他们的理由——好的理由。它们指出了如何避免问题:

在 GTK+ 团队看来,编写带有图形用户界面的 setuid 程序的唯一正确方法是拥有一个 setuid 后端,该后端通过管道等机制与非 setuid 图形用户界面进行通信,并考虑输入它收到不可信。

既然你应该写一个帮助程序,你找过例子吗?他们很可能是被给予的。您的程序本身是 GUI 应用程序吗?


我需要 root 权限 [...] 来打开一些外围设备,读取内存中可用的数据,然后关闭它们......如果没有 root 权限,这将无法完成......而且读取的数据也使用同时处理和显示GTK。

所以,这正是 GTK+ 团队描述的那种场景。您需要一个由 GUI 启动的小型 setuid 根程序,并通过管道或 Unix 域套接字或其他类似技术连接到它。

当您需要来自外围设备的数据时,您的主应用程序会向守护程序/帮助程序写入请求,然后等待包含数据的响应。

概括地说,您的 GUI 中将包含以下代码:

  • LaunchDaemon():这将创建管道(管道或套接字)、fork,并且子进程将在启动守护进程之前整理文件描述符(关闭它不需要的)。
  • RequestDaemon():这会将请求打包到守护程序/帮助程序,将信息写入守护程序,并读回响应。
  • TerminateDaemon():这将关闭与守护程序/帮助程序的连接;它会知道它没有更多的工作要做并且会退出。

同时,您的守护程序/帮助程序将:

  • 进入一个舒适的循环:
    • 从标准输入读取请求
    • 检查它的有效性
    • 执行请求
    • 格式化响应(错误或正常)
    • 将其写回主 GUI
    • 重复
  • 当它从输入中获取 EOF 时,它会终止。
  • 如果可能的话,它将打开设备一次,然后删除 root 权限。
    • 这最大限度地减少了遭受攻击的风险。
    • 如果程序不再以 root 身份运行,则不能滥用它来做只有 root 才能做的事情。
    • 打开文件后,不会再次检查权限(因此以 root 身份运行的守护程序可以打开文件,如果不重新打开文件,则丢弃其 root 权限)。

您仍然应该查看外围设备上的权限是否正确 - 或者为什么需要从只有 root 才能读取的东西中读取数据。

于 2011-01-16T15:08:10.340 回答
3

我认为当 GTK+ 团队在这里警告不要在 setuid 程序中使用 GTK+ 时,他们的心是正确的。但我有两个观察结果和一个解决方法。

首先,警告这种做法是一回事,而让这种做法看起来不可能完全是另一回事。想到设计师说“用户没有正当理由做 XXX”,然后特意让 XXX 成为不可能,这让我很恼火。风险预警,让用户承担风险。

其次,GTK+ 团队将“setuid”与“setuid root”混淆了。这是区分很重要的示例。在这个例子中,我不想扩大使用 GTK+ 的程序的权限,而是减少它们。在某些情况下,我希望能够运行 Firefox(好吧,iceweasel,但基本相同),因此它只能查看本地文件,没有网络功能。因此,我在我的 Linux 系统中设置了 iptables,以便特定(人为创建的)用户无法访问外部世界。无论我实际上是哪个用户,我都希望能够以该用户身份运行 Firefox。假设受限用户的 uid 和 gid 为 1234,下面的大体思路是可行的。将其构建为 setuid root。希望这可以帮助。

编辑 2014-02-22 15:13 UTC

我没有提到你可以用 0 代替每个 1234,你已经获得了 root 权限。有人可能会争辩说这完全是个坏主意,我想我可以理解这一点。

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int    ar_argc,
     char **ar_argv
    )
{
  setenv("HOME","/u/wally",1);

  /* Set other environment variables as appropriate. */

  if(setgid(1234))
  {
    fprintf(stderr,"setgid() fail\n");
    exit(1);
  };
  if(setuid(1234))
  {
    fprintf(stderr,"setuid() fail\n");
    exit(1);
  };

  /* Use execl() and friends, or system(), to do what you want here. */

  return 0;
}
于 2014-02-22T14:45:44.293 回答
0

通常,最好将系统设置为可以由非 root 用户打开设备文件,然后让正常的非 root 进程与它们对话。

于 2011-02-25T21:26:36.247 回答