根据我的理解,当bash
(或任何进程,只要我不故意更改此行为)运行时,它将具有(以及其他信息)登录用户的补充组列表。
以下是ps
的补充组的结果bash
:
PID COMMAND SUPGRP
1409 bash adm dialout cdrom plugdev lpadmin admin sambashare chris
chris
是登录用户的主要组,那么为什么它被列为补充组的一部分呢?
答案1
initgroup()
,通常调用的 libc 函数登录设置以您的名义运行的进程的补充组列表的应用程序会将主要组 ID 添加到该列表中。
如果没有,这将是一个安全问题,因为这将为您提供一种通过与其他组之一创建 setgid 可执行文件来放弃对该组的访问权限的方法,并执行该文件以丢失您的主 gid(该可执行文件将必须要求setgid()
真实的 gid 也发生变化),这将使您能够访问已被明确拒绝访问您的主要组的资源。
例子:
$ ls -l file
-rw----r-- 1 root chazelas 7 Dec 12 15:33 file
我的主要 gid 的访问被拒绝:
$ cat file
cat: file: Permission denied
现在,让我们像我一样启动一个 shell,其中补充组 id 不包含该组,看看如果login
不将该组添加到我们的补充组 id 列表中我们可以做什么:
$ sudo perl -le '$( = $) = "1000 2"; $< = $> = 1000; exec zsh'
$ ps -o rgroup,egroup,supgrp -p $$
RGROUP EGROUP SUPGRP
chazelas chazelas bin
$ id -a
uid=1000(chazelas) gid=1000(chazelas) groups=1000(chazelas),2(bin)
1000在gid、egid中,但不在补充组列表中。由于我也是 的成员bin
,因此我可以创建一个 setgidbin
可执行文件:
$ cp -f /usr/bin/env .
$ chgrp bin env
$ chmod g+s env
$ ./env perl -U -le '$( = $); exec qw(/usr/bin/id -a)'
uid=1000(chazelas) gid=2(bin) groups=2(bin)
我用的perl
是setgid()
($( = $)
)。然后我就失去了该chazelas
小组的成员资格。所以:
$ ./env perl -U -le '$( = $); exec qw(cat file)'
secret
通过将组添加到补充列表,login
确保您无法退出它(因为只有 root 可以更改该列表,并且它不受 setgid 可执行文件的执行影响)。
答案2
因为有东西把它放在那里。 (我知道,不太令人满意。)
POSIX 承担getgroups()
系统调用就是它
是否由实现定义获取组()还返回有效组 ID组列表大批。
在 Linux (4.9) 上,getgroups()
返回值中不包含有效 GID /proc/$pid/status
,.ps
在 Debian 上,显示时似乎也没有添加它,但id
确实添加了。
如果使用 显式添加相同的 GID setgroups()
,则会列出它。
答案3
解释:
如果您正在寻找解释,手册页始终是一个不错的起点。看man ps
:
sugrp 补充组的 SUPGRP 组名称(如果有)。请参阅 getgroups(2)。
然后,自然地,[man getgroups][1]
:
getgroups()
返回列表中调用进程的补充组 ID。参数大小应设置为列表指向的缓冲区中可以存储的最大项目数。如果调用进程是超过 size 的补充组的成员,则会产生错误。 未指定调用进程的有效组ID是否包含在返回的列表中。 (因此,应用程序还应该调用 getegid(2) 并添加或删除结果值。)
应用:
因此,您应该并且可能从列中的值中ps -eo pid,user,args,sgroup,supgrp
减去列中的值。这是仅获得补充组的方法。SGROUP
SUPGRP
笔记:
事实上,正如评论中指出的那样,ps
不会调用。getgroups()
看伊尔卡丘'沙斯蒂芬·查泽拉斯的答案在技术上都是正确的并且解释得很好。这个答案只是想说,预计补充组可能包含主要基团。