我有一个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
现在有足够的信息吗?
答案 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
,这可能很危险。
在他的answer,BenjiWiebe州:
问题是我只设置了有效的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中,相当清楚地表明,执行过程的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
,它运行良好。