我有一个从 C 源文件编译的可执行二进制文件
可执行文件具有 setuid 权限
我注意到,如果可执行文件的所有者是root,我可以使用
setuid(geteuid());
在编译文件以将运行可执行文件的进程的真实 UID设置为root时。然后,运行可执行文件的任何人都可以以root身份运行它。
但是,我注意到只有当可执行文件的所有者是root时才会发生这种情况。当我尝试授予test_user可执行文件的所有权(并修复权限以再次包含 setuid)时,它不起作用。在阅读了这些文档页面(1、2、3)并阅读了这篇文章后,我注意到这setuid(new_euid)
是为了更改有效 UID而不是运行可执行文件的进程的真实 UID。只是碰巧,在特定情况下(有效的 UID是 root),setuid(new_euid)
还设置了真实的 UID和保存的 UID运行可执行文件的进程到new_euid
.
我通过使用setreuid
代替解决了这个问题setuid
,如下:
setreuid(geteuid(), geteuid());
这允许我将进程的真实 UID设置为有效 UID(可执行文件的所有者)并将有效 UID重置为其值(冗余)。
我知道这在某些条件下会起作用,但同样适用于使用,或更改真实 UID、保存的 UID或有效的 UIDsetuid()
时更容易混淆,因为它们总是有效?setreuid()
setresuid()
seteuid()
此外:我知道这seteuid()
似乎与此处setuid()
解释的差异相同(有效的 UID是 root)。这应该不允许 root 特权程序在删除它们后重新获得特权(因为所有 3 个 UID 都将使用 更改为相同的值)?那么我是否应该只使用root 特权程序,即使它与例如相比不那么清楚?setuid()
setuid()
setresuid()
我认为这setuid()
可能是安全的,因为它不允许 root 特权程序在删除后重新获得特权,但是可以使用其他提到的功能来实现这种行为,而不会造成太大的混乱。
另一件事getuid()
返回进程的真实 UID,同时setuid()
用于修改有效 UID(除非特权),这也令人困惑。
这一切背后可能有一些骇人听闻的历史。正如您所说,
setreuid()
更清晰,并且由于它在标准中指定,我会使用它。然后虔诚地检查返回值,然后进行getuid()
验证geteuid()
。setresuid()
不在 POSIX 中,所以它可能没有那么广泛可用(不过,FreeBSD 和 OpenBSD 似乎有它)。如果实现setreuid()
匹配文档,您不需要显式设置保存的 UID,因为setreuid()
应该为您设置它:再说一次,如果可能的话,完全避免使用 setuid 程序来支持例如单独运行的特权进程并通过套接字与其通信可能是一个好主意。有很多东西从一个进程继承给它的子进程,并且使用 setuid,特权较低的人可以将它们设置为特权较高的人。