2

我正在扩展一些在 GNU / Linux (Ubuntu 14.04) 下运行并由一个manager进程和几个worker进程组成的软件(我不是其中的作者)。管理器可以通过我可以在配置文件中指定的命令行来启动一个工作器。

启动一个worker后,manager使用管道与它通信。出于安全原因,我们决定让工作人员在与经理不同的用户下运行(让我们称他们为manager-userand worker-user)。这是通过编写一个小包装脚本来实现的,该脚本可以切换用户su并启动一个新的工作人员。在此之后,管理器可以通过管道与工作进程进行通信。这种方法已经工作了好几个月了。

作为 的替代方案su,我们考虑使用该setuid位来运行工人。所以我们编写了一个C包装器,可以由管理器调用来启动一个工作器。如果我们将包装器配置为由 拥有manager-user,则工作程序将正确启动(但当然,权限错误)。如果我们将包装器配置为归其所有worker-user并设置该setuid位,那么工作器将启动但随后退出,因为它们无法连接到管理器。

所以我的问题是:运行setuid可执行文件如何影响父进程和子进程创建的管道的权限?难道是通过 setuid-wrapper 启动的工作进程没有打开管理器管道的权限(或相反)?如果是这种情况,我们如何更改这些权限?

我几乎没有使用经验,setuid因此欢迎提供任何信息/解释。

4

2 回答 2

4

Unixpipe可以命名或不命名。命名管道被实现为一个文件,它具有标准的用户、组和世界所有权权限位。

未命名的管道也具有权限,但这些权限受 、 和 的约束euidegid并且umask在创建管道时就已到位。

因此,如果您worker-usersetuid另一个具有不同组权限的用户,除非egid与主进程相同,否则它将无法使用用户或组权限来访问由父进程创建的管道。

当然,对于某些umask值,未命名管道世界权限将允许进程通过管道进行通信,但任何进程都可以读取/写入该管道。未命名比命名管道更安全,但授予任何管道世界权限并不是一个好的安全实践。

这个用例的一个可能的解决方案(希望两个通信进程在不同的用户下运行)是让manager-userworker-user进程都在同一个组中,并umask在创建管道时清除 group-perm 位,以便两个进程都可以读取和写入未命名管道。

因此,如果

  1. manager-user集团拥有team
  2. worker-user也属于team,
  3. 两个进程都清除了它们的组umask位(没有1x..的值7x
  4. 在创建未命名管道之前

然后manager-user应该能够在未命名的管道上写入并且worker-user应该能够读取它(反之亦然,取决于管道的使用方式),即使它们作为单独的用户运行。

有关权限位的详细信息,请参阅man页面。chmod

于 2015-07-29T18:17:30.400 回答
0

使用该函数使用匿名管道,如下所示(示例是从德语 Wikipediapipe()借来的):

# check the link above for #includes and const definitons

int main(void) {
    int fd[2], n, i;
    pid_t pid;
    char line[MAX_CHARS];

    // Create the pipe
    if (pipe(fd) < 0)
        fprintf(stderr, "Failed to create pipe()");

    // Fork child
    if ((pid = fork()) > 0) {
        // Parent process

        close(fd[0]);
        fprintf(stdout, "Parent : ");
        fgets(line, MAX_CHARS, stdin);
        write(fd[1], line, strlen(line));

        if (waitpid(pid, NULL, 0) < 0)
            fprintf(stderr, "Error: waitpid()");
    }

    else {
        // Child process
        close(fd[1]);
        n = read(fd[0], line, MAX_CHARS);

        for (i = 0; i < n; i++)
            line[i] = toupper(line[i]);
        fprintf(stderr, "Child : ");

        write(STDOUT_FILENO, line, n);
    }
    exit(0);
}

上面的程序创建了一个单向管道,其中父进程持有读端,子进程持有写端。

于 2015-07-29T18:11:44.750 回答