使用GTK+的Setuid

3

我正在尝试编写一个程序,并将其与使用Gtk+构建的gui集成。要调用的exe文件已设置了setuid位。然而,Gtk不允许此exe按照gtk社区指定的方式运行。他们说我们必须编写单独的帮助程序之类的东西,但我真的不明白这是什么意思。有人能否请解释一下如何解决这个问题?我真的需要一个即时的解决方案。

4个回答

4
我认为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
我忘了提到,您可以将每个1234替换为0,这样就得到了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;
}

1
为其他人添加最后一点:在该注释下添加“system(ar_argv [1]);”,将此代码保存为wally.c,然后: 切换到root(例如“sudo su”), 构建它(例如“gcc -o wally wally.c”), 设置setuid(例如“chmod +s wally”), 切换回普通用户(例如“exit”), 运行它(例如“./wally firefox”) - 8forty

4
第一个问题:为什么你的程序是setuid?编写setuid程序不是自称Linux新手应该玩的游戏。它们很危险。它们很有用 - 不要误解我。但是它们很危险且难以安全地编写。
GTK+项目在“GTK+ - 使用setuid”中非常直截了当地阐述了他们对setuid程序的看法。他们给出了他们的理由 - 是好的理由。他们指出了如何避免问题:
在GTK+团队的意见中,编写带有图形用户界面的setuid程序的唯一正确方法是拥有一个setuid后端,通过管道等机制与非setuid图形用户界面通信,并将其接收到的输入视为不受信任。
既然你应该编写一个辅助程序,那么你是否寻找过示例?很可能已经有人给出了示例。你的程序本身是GUI应用程序吗?
我需要root权限[...]来打开一些外围设备,读取其内存中可用的数据,然后关闭它们...这是无法在没有root权限的情况下完成的...同时使用GTK处理和显示读取的数据。
因此,这正是GTK+团队所描述的场景。您需要一个小的setuid root程序,由GUI启动,并通过管道或Unix域套接字等技术与之连接。
当您需要从外围设备获取数据时,您的主应用程序将向守护程序/助手写入请求,然后等待包含数据的响应。
概述而言,您的GUI中将有以下代码:
  • LaunchDaemon():这将创建管道或套接字等管道,fork子进程,并在启动守护进程之前对文件描述符进行排序(关闭不需要的文件描述符)。
  • RequestDaemon():这将打包一个请求到守护程序/助手,将信息写入守护程序,并读回响应。
  • TerminateDaemon():这将关闭与守护程序/助手的连接;它将知道自己没有更多的工作要做并退出。
同时,您的守护程序/助手程序将:
  • 进入一个舒适的循环中:
    • 从标准输入读取请求
    • 检查其有效性
    • 执行请求
    • 格式化响应(错误或正常)
    • 将其写回主GUI
    • 重复
  • 当从输入得到EOF时,它终止。
  • 如果可能的话,它会打开设备一次,然后放弃root权限。
    • 这可以最小化攻击风险。
    • 如果程序不再以root身份运行,则不能被滥用为只有root才能执行的任务。
    • 一旦文件打开,权限就不再检查(因此作为root运行的守护程序可以打开文件,然后丢弃其root权限,如果它不重新打开文件)。

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


  1. 是的,我是个新手...但我知道我的程序在做什么...它需要root权限才能运行,否则无法运行...
  2. 我正在网上寻找例子...有些人说我们必须使用套接字...我还在寻找一个好的例子...
  3. 是的...主GUI需要调用的另一个程序也是一个GTK程序...它需要在处理完几张图片后显示它们...但我的疑问仍然存在...什么是助手程序的确切含义?
- linuxnewbie
你的程序为什么需要root权限?不要编写需要root权限的GUI程序——它们太危险了(这是GTK+团队的主旨,我同意他们的看法;他们无法保证系统中没有毁灭性的安全漏洞,攻击者可以利用这些漏洞)。你的程序到底需要root权限做什么?你能否编写一个非GUI(小型)且设置了setuid的守护进程程序,该程序从你的GUI代码中获取请求,小心地执行需要root权限的操作,并将答复发送回请求(GUI)程序?如果不能,为什么不能? - Jonathan Leffler
我需要root权限,因为我需要打开一些外围设备并读取它们内存中可用的数据,然后关闭它们...这不能在没有root权限的情况下完成...同时,使用gtk处理和显示读取的数据。 - linuxnewbie

1
我的代码与DMA硬件(修改版的pigpio)紧密接口,以在树莓派上获得最高的时间精度。(应用于狗赛事计时和评判系统)
对于需要root访问权限的操作,使用守护进程很可能会引入无法接受的延迟,至少需要进行广泛的测试,以确保所有内容都满足绝对的时间精度要求。
该应用程序在独立的树莓派上运行,没有网络连接,没有人会通过ssh登录。
要实现替代方案并进行测试需要花费真正的金钱!
没有人比应用程序的开发者更能做出关于安全风险与其他应用考虑因素的明智决策。
我现在经常看到这种情况。安全问题变得如此重要,安全策略由那些无法考虑到所有受影响用例的人来执行。
太愚蠢了 - 所以我将使用sudo来运行。

0
通常情况下,最好设置系统以便设备文件可以被非root用户打开,然后让普通的非root进程与它们通信。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接