C++ 不允许使用第二个setuid

C++ 不允许使用第二个setuid,c++,c,linux,C++,C,Linux,如果我在循环中调用setuid以成为root用户并重置uid,这只会工作一次。 我有以下代码: #include <stdio.h> #include <sys/types.h> #include <unistd.h> int my_func(int i) { int current_uid = getuid(); int ret; fprintf(stderr, "### i=%d ##

如果我在循环中调用setuid以成为root用户并重置uid,这只会工作一次。 我有以下代码:

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

int my_func(int i) {
    int current_uid = getuid();
    int ret;
    fprintf(stderr,
                    "###  i=%d   ###:  My UID is: %d. My GID is: %d,   before 'system(id)'\n",
                    i, current_uid, getgid());
    system("/usr/bin/id");

    fprintf(stderr,"\n\n###  i=%d   ###:  before 'setuid(0)'\n", i);
    if (setuid(0)) {
        perror("setuid");
        return 1;
    }
    fprintf(stderr,"after 'setuid(0)'\n\n");

    //I am now root!
    fprintf(stderr,
                    "###  i=%d   ###:  I an now root:  My UID is: %d. My GID is: %d,   before 'system(id)'\n",
                    i, getuid(), getgid());
    system("/usr/bin/id");


    //Time to drop back to regular user priviledges
    fprintf(stderr,"\n\nbefore 'setuid(%d)'\n",current_uid);
    ret=setuid(current_uid);
    fprintf(stderr,
                    "###  i=%d   ###:  My UID is: %d. My GID is: %d,   before 'system(id)\n",
                    i, getuid(), getgid());
    system("/usr/bin/id");
}

int main(void) {
    int i;
    for (i=0;i<3;i++) {
        my_func(i);
        sleep(5);
        fprintf(stderr,"\n\n");
    }
    return 0;
}
#包括
#包括
#包括
int my_func(int i){
int current_uid=getuid();
int ret;
fprintf(标准,
“###i=%d####:我的UID是:%d。我的GID是:%d,在'system(id)'之前”\n”,
i、 当前uid,getgid());
系统(“/usr/bin/id”);
fprintf(stderr,“\n\n####i=%d###:在'setuid(0)'\n'之前”,i);
if(setuid(0)){
佩罗尔(“setuid”);
返回1;
}
fprintf(stderr,“在'setuid(0)'之后”\n\n”);
//我现在是根!
fprintf(标准,
“###i=%d####:我现在是root:我的UID是:%d。我的GID是:%d,在'system(id)'之前”\n”,
i、 getuid(),getgid());
系统(“/usr/bin/id”);
//回到常规用户权限的时间到了
fprintf(stderr,“\n\n在“setuid(%d)”\n之前”,当前的\u uid);
ret=setuid(当前\u uid);
fprintf(标准,
“###i=%d####:我的UID是:%d。我的GID是:%d,在'system(id)\n'之前”,
i、 getuid(),getgid());
系统(“/usr/bin/id”);
}
内部主(空){
int i;

对于(i=0;i一旦您通过使用setuid更改为非root用户而放弃root权限,您就不再具有使用setuid再次成为root用户所需的权限。

Linux(与其他unix一样)存储两个值:您的真实用户id(由setuid设置)与您的登录名相对应,不受s位的更改;您的有效用户id(由seteuid设置),在执行设置了s位的程序时更改。允许使用setuid(),您的真实用户id或有效用户id必须为零,但如果您使用setuid()删除权限(从0更改为其他任何内容),您的有效用户id也将更改。因此,您的第一个setuid(1203)也将有效用户id设置为1203,这将阻止您以后重新获得权限

要多次从根用户更改为根用户,您必须使用setreuid()调用来交换两者-setreuid(1203,0)将实际用户id更改为1203,将有效用户id更改为0,从而允许您稍后将uid设置为0

请注意,只要这两个uid中的任何一个为0,您就具有root权限。当uid=1203和euid=0时,您创建的文件将属于您(用户id 1203),但您仍具有root访问权限。因此,请仔细检查您的程序是否存在安全隐患


如果您需要在整个程序中时不时地进行根访问,那么创建一个pipe()、fork()会更安全关闭保留根权限的子进程,删除父进程中的权限,并在需要作为根用户执行某些操作时向子进程发送一些命令。这样,您只需对子进程进行安全审计,这可能比您的整个程序小得多。

实际上,Linux有四个:real,effective、 您可以使用
setresuid(uid、euid、suid)
setresgid(gid、egid、sgid)
在真实、有效和保存的用户ID之间进行更改。您可以将root保留为保存的标识,然后在任何真实和有效标识之间进行更改,只要您先切换到root。文件系统标识很少使用,基本上遵循有效标识。有关更多信息,请参阅手册页:和