【问题标题】:setgid Operation not permittedsetgid 不允许操作
【发布时间】:2013-11-19 01:33:04
【问题描述】:

我有一个 C 程序,它使用组“agrp”的组 ID 调用 setgid(),当我尝试运行它时,它显示“不允许操作”。

该程序有以下ls -la列表:

-r-xr-s--x 1 root      agrp      7508 Nov 18 18:48 setgidprogram

我想要的是setgidprogram 能够访问拥有者otheruser 和组agrp 的文件,并且权限设置为u+rw,g+rw(用户和组可读写.)

我做错了什么? setgidprogram 是否也必须设置 setuid 位? (当我尝试它时,它起作用了。)

我正在运行 Fedora 19,并且我禁用了 SELinux。

编辑

下面是一些示例代码: wrap.c:

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
int main(void)
{
        struct group *grp = getgrnam("agrp");
        printf("%d\n",grp->gr_gid);
        if(setgid(grp->gr_gid) != 0)
        {
                printf("%s.\n", strerror(errno));
                return 1;
        }
        execl("/tmp/whoami_script.sh", NULL);
        printf("%s.\n", strerror(errno));
        return 0;
}

/tmp/whoami_script.sh:

#!/usr/bin/bash
id


$ ls -la /tmp/whoami_script.sh wrap
-r-xr-xr-x 1 root agrp   19 Nov 18 19:53 /tmp/whoami_script.sh
$ ./wrap
1234
uid=1000(auser) gid=1000(auser) groups=1000(auser),0(root),10(wheel)
---x--s--x 1 root agrp 7500 Nov 18 19:55 wrap

现在这些信息足够了吗?

【问题讨论】:

  • 文件系统是否在没有nosuid的情况下挂载?
  • 我不这么认为。其他 suid 程序运行良好。另外,这个程序是 sgid 而不是 suid。
  • 更新有点混乱。它显示了一个任何人都可以运行的程序/tmp/whoami_script.sh;更有效的测试会给它 550 个权限。但是,代码运行时的输出显示包装程序的 SGID-ness 没有生效; egid 没有任何条目,agrp 也没有任何条目(即使使用不同的名称 - 不要笑;我已经看到这种情况发生了,/etc/group 中有两个条目用于 GID 1234,名称不同,两者都“工作” ',但 lsid 等只报告两个名称之一)。因此,SGID 显然不适合您。
  • 请注意,Mac OS X 上的 mount 文档说“nosuid – 不允许 set-user-identifier 或 set-group-identifier 位生效”。在 Linux 上可能是一样的;没有单独的nosgid 选项。

标签: c linux permissions


【解决方案1】:

这段代码终于奏效了:

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
int main(void)
{
        gid_t g = getegid();
        if(setregid(g, g) != 0)
        {
                printf("Error setting GID: %s.\n", strerror(errno));
        }
        execl("/tmp/whoami_script.sh", "/tmp/whoami_script.sh", NULL);
        printf("Error: %s.\n", strerror(errno));
        return 0;
}

问题是我只设置了我的有效 GID,而不是我的真实 GID。因此,当我执行时,子进程以将 EGID 设置为 RGID 的方式启动。所以,在我的代码中,我使用了setregid,它工作得很好。

【讨论】:

    【解决方案2】:

    问题的原始版本显示该文件的权限为 6550。

    如果您不是root 用户或agrp 组中的用户,您需要能够使用该程序的公共执行权限——这是缺失的。由于它是二进制文件,因此您不需要读取权限。修复它:

    # chmod o+x setgidprogram
    

    # 表示“以 root 身份或通过sudo”或等效机制。)目前,只有已经拥有相关权限的人才能使用该程序。

    如果程序安装了SGIDagrp,则程序内部不需要尝试做setgid(agrp_gid)。有效的 GID 将是属于 agrp 的 GID,并且程序将能够像 agrp 的任何其他成员一样访问文件。

    也就是说,通常您可以成功执行空操作。例如,这段代码运行良好:

    #include <stdio.h>
    #include <unistd.h>
    #include "stderr.h"
    
    int main(int argc, char **argv)
    {
        err_setarg0(argv[argc-argc]);
    
        gid_t gid = getegid();
        if (setgid(gid) != 0)
            err_syserr("Failed to setgid(%d)\n", (int)gid);
        puts("OK");
        return 0;
    }
    

    (您只需要接受err_*() 函数会进行错误报告;argc-argc 技巧可以避免编译器针对其他未使用的参数argc 发出警告/错误。)

    如果你将程序设为 SUID root,那么 SGID 属性无关紧要;该程序将以 EUID root 运行,这意味着它(几乎)可以做任何事情。如果是 SUID root,您可能应该将 EUID 重置为真实的 UID:

    setuid(getuid());
    

    在调用其他程序之前。否则,您将调用另一个程序为root,这可能很危险。


    剖析 POSIX

    在他的answerBenjiWiebe 中声明:

    问题是我只设置了我的有效 GID,而不是我的真实 GID。因此,当我执行时,子进程以将 EGID 设置为 RGID 的方式启动。所以,在我的代码中,我使用了setregid(),它工作得很好。

    呸;哪个系统可以做到这一点? Linux试图保护?这不是 Unix 上经典的工作方式,这是肯定的。但是,POSIX 标准似乎在措辞上有回旋余地(对于execvp()):

    如果为包含新进程映像文件的文件系统设置了 ST_NOSUID 位,则新进程中的有效用户 ID、有效组 ID、保存的 set-user-ID 和保存的 set-group-ID 不变图片。否则,如果设置了新进程映像文件的set-user-ID模式位,则应将新进程映像的有效用户ID设置为新进程映像文件的用户ID。同样,如果设置了新进程映像文件的set-group-ID模式位,则新进程映像的有效组ID应设置为新进程映像文件的组ID。新进程映像的真实用户 ID、真实组 ID 和补充组 ID 应与调用过程映像的保持相同。新过程映像的有效用户ID和有效组ID应保存(作为保存的set-user-ID和保存的set-group-ID)供setuid()使用。

    如果我的解析正确,那么我们有很多场景:

    1. ST_NOSUID 已设置。
    2. ST_NOSUID 未设置,但在可执行文件上设置了 SUID 或 SGID 位。
    3. ST_NOSUID 未设置,但可执行文件上未设置 SUID 或 SGID biy。

    在情况1中,相当清楚地表明exec'd进程的EUID和EGID与原始进程相同(如果EUID和RUID在原始进程中不同,它们将在孩子)。

    在情况 2 中,如果在可执行文件上设置了 SUID 位,则 EUID 将设置为 SUID。同样,如果在可执行文件上设置了 SGID 位,则 EGID 将设置为 SGID。未指定如果设置了 SUID 位、未设置 SGID 位以及原始进程对 EGID 和 RGID 的值不同会发生什么;相反,它也没有指定如果设置了 SGID 位、未设置 SUID 位并且原始进程具有不同的 EUID 和 RUID 值会发生什么。

    情况 3,其中 SUID 和 SGID 位均未在可执行文件上设置,似乎也是未指定的行为。

    传统上,在 Unix 系统上,EUID 和 RUID 可能不同,如果可执行文件不使用自己的 SUID 或 SGID 覆盖 EUID 或 EGID,则差异将在多个(fork() 和)exec() 操作中继承位。然而,POSIX 标准是否强制或禁止这一点尚不清楚。这似乎是未指定的行为。基本原理部分没有提供有关意图的指导。

    如果我的阅读是正确的,那么我觉得有趣的是,ST_NOSUID 位意味着如果程序由运行 SUID 的进程启动,那么“无 SUID”文件系统上的程序将运行不同的真实有效的 UID(RUID 和 EUID),这似乎违反直觉。可执行文件上的 SUID 和 SGID 位设置为什么无关紧要(因此忽略可执行文件上的位),但保留 EUID 和 RUID 的继承值。

    【讨论】:

    • 糟糕。我曾尝试过,但忘记在帖子中包含它。修改后还是不行。
    • 当问题中的信息不准确时,总是很难回答问题!
    • 我在程序中所做的是执行一个需要agrp 组来执行它的程序。我这样做对吗?
    • 如果setgidprogram 是一个包装器,那么在选择通向被包装程序的路径时要相当谨慎,但您应该能够简单地execve() 使用正确参数列表的被包装程序,根本不需要打电话给setgid()。我刚刚创建了一个尝试setgid(getegid()) 的微观程序,它可以正常工作(在 Mac OS X 10.9 Mavericks 上测试)。
    猜你喜欢
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 2012-01-03
    • 2021-02-10
    • 2021-01-01
    • 2014-11-01
    • 2014-06-30
    • 2012-03-19
    相关资源
    最近更新 更多