6

我有一个权限为 4750 的进程。我的 Linux 系统中存在两个用户。root 用户和 appz 用户。该进程继承了以“appz”用户身份运行的进程管理器的权限。

我有两个基本的例程:

void do_root (void)
{
        int status;
        status = seteuid (euid);
        if (status < 0) { 
        exit (status);
        }    
}

/* undo root permissions */
void undo_root (void)
{
int status;
        status = seteuid (ruid);
        if (status < 0) { 
                exit (status);
        }
        status = setuid(ruid);
        if (status < 0) { 
                exit (status);
        }
}

我的流程如下:

int main() {
 undo_root();
 do some stuff;
 do_root();
 bind( port 80); //needs root perm
 undo_root();
 while(1) {

    accept commads()
    if ( commands needs root user access)
    {
       do_root();
       execute();
       undo_root();

    }

 }

如您所见,我想以 root 身份执行一些命令。我正在尝试暂时放弃权限,如果任务需要 root 访问权限,我将命令包装在 do_root 和 undo_root 调用之间。

但是,我的程序似乎无法正常工作。

规范的方法是什么?

4

3 回答 3

6

老式的方法是在 do_root 和 undo_root 中使用 setreuid() 来交换 ruid 和 euid:

setreuid(geteuid(), getuid());

如果程序小到足以进行完整的安全审计,这是完全可以接受的。

新学校的方法要复杂得多,包括 fork() 关闭一个接受指示的子级,然后执行 setuid(getuid()) 以将 root 永久地放在父级中。孩子负责验证它收到的所有指令。对于足够大的程序,这会减少必须进行安全审计的代码量,并允许用户通过作业控制来管理进程或将其终止等。

于 2012-02-15T16:59:20.120 回答
5

有一篇由 Hao Chen、David Wagner 和 Drew Dean撰写的论文 ' Setuid Demystified '。它在 USENIX 2002 上发表。它详细描述了setuid()转换的工作原理(截至 2002 年正确)。非常值得一读(好几遍——我必须一两年才重读一遍)。

从根本上说,正如Petesh在评论中指出的那样,当具有 EUID 0 的进程使用 时setuid(nuid)nuid != 0没有办法返回root(EUID 0) 权限。而且,确实如此,这一点至关重要。否则,当您登录时,您登录的root过程无法将您限制为您自己的权限 - 您可以返回到root. 保存的 UID 使事情变得复杂,但我认为它不会影响 EUID 0 的单向陷阱setuid()

于 2012-02-15T16:53:34.567 回答
2

手册页显示setuid以下内容:

... 希望暂时放弃 root 权限的 set-user-ID-root 程序,假设一个非 root 用户的身份,然后重新获得 root 权限,不能使用 setuid()

这意味着您不能使用setuid(). 您必须使用seteuid(),并且可能,setreuid(). 有关详细信息,请参阅Setuid 程序示例。

于 2012-02-15T16:50:16.830 回答