来自APUE
#include <grp.h> /* on Linux */ int setgroups(int ngroups, const gid_t grouplist[]);
超级用户可以调用
setgroups
函数来为调用进程设置补充组ID列表:grouplist包含组ID数组,ngroups指定数组中元素的数量。 ngroups的值不能大于NGROUPS_MAX。#include <grp.h> /* on Linux and Solaris */ int initgroups(const char *username, gid_t basegid);
一个人必须是超级用户才能打电话给
initgroups()
,因为它叫setgroups()
。
决定必须用超级用户调用setgroups()
和initgroups()
的机制是什么?
“机制”是指与以下内容相似或相似的内容。在Linux中,我了解到我们可以根据访问控制列表(ACL)确定进程对文件的可访问性:
谢谢。
APUE中的措辞可能有点不精确;它是程序员的教程指南,而不是法律纲要。任何过程都可以调用setgroups()
或initgroups()
。但是如果进程没有root权限,那么该函数只会将errno
设置为EPERM
并返回错误指示。
显然,权限测试无法使用用户权限完成。库函数只是系统调用的一个薄包装器,测试在内核中完成。
值得一提的是,这是谷歌在被问及Linux系统调用机制时给我的第一个热门话题:http://www.linux.it/~rubini/docs/ksys/。但也许你有更好的资源。
在Linux中,如果一个进程有CAP_SETGID
capability,内核将尊重setgid()
,setegid()
,setregid()
,setresgid()
和setgroups()
调用(除非被像SELinux这样的Linux安全模块拒绝)。
非特权用户可以通过两种主要机制获得功能:
文件系统功能更有趣,对服务/应用程序很有用。它们只适用于二进制文件,而不是脚本,因为内核将功能更新为执行二进制文件的机制的一部分; shell使用完全不同的完全用户空间机制来解释脚本。
(文件系统必须支持扩展属性。必须使用user_xattr
挂载选项挂载某些文件系统,如ext2,ext3和reiserfs,以启用扩展属性.ext4,xfs,jfs,btrfs和zfs都应使用默认挂载选项支持扩展属性一些Linux发行版如Debian和Ubuntu已经依赖于扩展属性和文件系统功能。)
注意:您可以使用getcap
和lsattr
实用程序来检查二进制文件系统功能和扩展属性。在我的Ubuntu 16.04.4 LTS系统上,/usr/bin/systemd-detect-virt
二进制文件具有允许且有效的CAP_DAC_OVERRIDE和CAP_SYS_PTRACE功能。
在实践中使用文件系统功能非常容易,但为了安全操作,首先应仔细考虑安全隐患:它是一个功能强大的工具,但您(开发人员,包管理员和/或系统管理员)负责确保它是使用正确。
例如,如果要安装受信任的/usr/bin/yourprog
并且需要CAP_SETGID功能,那么您需要做的就是为该二进制文件设置允许且有效的功能。为此,您可以使用root权限运行setcap cap_setgid=pe /usr/bin/yourprog
。 (在Debian .deb软件包安装脚本中,通常在安装后脚本中运行。)
你可以看看actual code for setgroups。它是这样开始的:
SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
{
struct group_info *group_info;
int retval;
if (!may_setgroups())
return -EPERM;
// other stuff
}
这是may_setgroups
:
bool may_setgroups(void)
{
struct user_namespace *user_ns = current_user_ns();
return ns_capable(user_ns, CAP_SETGID) &&
userns_may_setgroups(user_ns);
}
如果你没有使用用户命名空间,这里是userns_may_setgroups
:
static inline bool userns_may_setgroups(const struct user_namespace *ns)
{
return true;
}
所以:如果你没有setgroups
能力,EPERM
将返回CAP_SETGID
错误。
推论:如果你有setgroups
能力,你可以打电话给CAP_SETGID
。
Root自动具有所有功能(因此root可以调用setgroups
),但是如果你不是root用户并且你具有CAP_SETGID
功能,你也可以调用它。