在C中运行setuid程序的正确方法

时间:2012-02-15 16:42:19

标签: c linux security setuid

我有一个权限为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之间。

然而,似乎我的程序无效。

这样做的规范方法是什么?

3 个答案:

答案 0 :(得分:6)

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

setreuid(geteuid(), getuid());

如果程序足够小,可以进行完整的安全审核,那么这是完全可以接受的。

新学校的方式要复杂得多,并且涉及fork()关闭一个孩子,该孩子接受以root身份做什么的指令,然后做setuid(getuid())以永久地在父母中删除root。负责验证它收到的所有指令。对于足够大的程序,这会丢弃必须进行安全审计的代码量,并允许用户使用作业控制来管理进程或将其终止等等。

答案 1 :(得分:5)

陈浩,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()的单向陷阱。

答案 2 :(得分:2)

setuid手册页说明如下:

  

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

意味着您无法使用setuid()。您必须使用seteuid(),并且可能使用setreuid()。有关详细信息,请参阅Setuid Program Example