欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux下程序拥有可以提升root权限,需要提升权限可通过fork子进程去完成

程序员文章站 2022-05-10 09:39:15
...

1.程序拥有可提升root权限的方法

sudo -S setcap cap_setuid+ep 应用程序

如果sudo执行失败,将用户加入sudo权限组中。

2.为了保证每次权限可以多次使用,通过fork子进程去完成相应的任务。

切换权限用户使用的函数是setuid();

#include <stdio.h>

int main()
{
	uid_t cur_uid = 0;
	
	cur_uid = getuid();
	
	//切换到root权限
	if (setuid(0) < 0)
	{
		fprintf(stderr, "The switch to root user failed!");
		return -1;
	}
	
	//执行需要在root权限的操作
	
	//为了安全,将权限降回去
	if (setuid(cur_uid) < 0)
	{
		fprintf(stderr, "Recovery process user failed!");
		return -1;
	}
	
	return 0;
}

使用上面的代码存在一个问题,将权限提升到root权限的时候执行完相应的操作,在降回去普通用户,将无法再次提升到root权限。想知道详细的可以阅读setuid()的机制。

这里作者实现一个类似popen的可读函数,该函数通过fork出子进程提升到root权限,执行root权限才能执行的命令,通过创建管道的方式,将结果传回给主进程。通过这样的方式,就可以保证主进程的特殊权限一直存在,可以重复使用。

static FILE *readpopen(const char *cmd)
{
    int pipefd[2];
    int pid_t;
    uid_t cur_uid = 0;

    if(cmd == NULL)
    {
        fprintf(stderr,"readpopen() param error");
        return NULL;
    }

    //创建管道
    if(pipe(pipefd) < 0)
    {
        fprintf(stderr, "readpopen() pipe create error");
        return NULL;
    }

    pid_t = fork();
    if(pid_t < 0)
        return NULL;

    if(0 == pid_t)
    {
        cur_uid = getuid();
        if (setuid(0) < 0)
        {
            fprintf(stderr, "The switch to root user failed!");
            return NULL;
        }
        close(pipefd[0]);
        dup2(pipefd[1], STDOUT_FILENO);
        close(pipefd[1]);
        execl("/bin/bash", "sh", "-c", cmd, (char *)NULL);
        /* Recovery process user privilege */
        if (setuid(cur_uid) < 0)
        {
            fprintf(stderr, "The switch to user failed!");
            return NULL;
        }
        exit(0);
    }
    waitpid(pid_t, NULL, 0);

    close(pipefd[1]);
    return fdopen(pipefd[0], "r");
}