setgid不允许操作

时间:2013-11-19 01:33:04

标签: c linux permissions

我有一个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

现在有足够的信息吗?

2 个答案:

答案 0 :(得分:1)

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

如果您不是用户root或组agrp,则需要能够使用该程序的公共执行权限 - 缺少这些权限。由于它是二进制文件,因此您不需要读取权限。解决它:

# chmod o+x setgidprogram

#表示'作为root或通过sudo'或等效机制。)就目前而言,只有已拥有相关权限的人才能使用该程序。

如果程序安装了SGID agrp,则程序无需在内部尝试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。
  4. 在案例1中,相当清楚地表明,执行过程的EUID和EGID与原始过程中的相同(如果EUID和RUID在原始过程中不同,则它们将在孩子)。

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

    案例3,其中SUID和SGID位都没有设置在可执行文件上,似乎也是未指定的行为。

    在Unix系统上经典,EUID和RUID可能不同,如果可执行文件没有覆盖EUID或EGID,则差异将在多个(fork()和)exec()操作中继承。拥有SUID或SGID位。但是,目前尚不清楚POSIX标准是否强制要求或禁止这一点;它似乎是未指明的行为。理由部分没有提供有关意图的指导。

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

答案 1 :(得分: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,它运行良好。