我有一个从 C 源文件编译而来的可执行二进制文件
可执行文件具有 setuid 权限
我注意到,如果可执行文件的所有者是根, 我可以用
setuid(geteuid());
编译文件时设置真实UID我运行可执行文件的进程是根。然后,任何运行该可执行文件的人都可以将其运行为根。
但是,我注意到只有当可执行文件的所有者是根。当我尝试给予时,它不起作用测试用户可执行文件的所有权(并修复权限以再次包含 setuid)。阅读这些文档页面后(1,2,3)和阅读这个帖子,我注意到这setuid(new_euid)
是为了改变有效UID而不是真实UID运行可执行文件的进程的名称。碰巧的是,在特定情况下(有效UID是根),setuid(new_euid)
还设置真实UID和保存的UID运行可执行文件的进程new_euid
。
setreuid
我通过使用而不是解决了该问题setuid
,如下所示:
setreuid(geteuid(), geteuid());
这允许我设置真实UID该过程的有效UID(可执行文件的所有者)并重置有效UID到它的价值(冗余)。
我知道这在某些条件下会起作用,但在更改时setuid()
使用 、 或 不会减少混乱并且setreuid()
更setresuid()
合适seteuid()
真实UID,保存的UID, 或者有效UID因为它们总是有效,所以是理想的?
此外:据我所知,这seteuid()
似乎setuid()
与所解释的差异相同这里(有效UID是根)。这应该不允许 root 特权程序在删除它们后重新获得特权(因为所有 3 个 UID 将使用 更改为相同的值setuid()
)?那么setuid()
,即使与其他程序相比,我是否应该只使用root 特权程序setresuid()
?
我认为这setuid()
可以是安全的,因为它不允许 root 特权程序在删除后重新获得特权,但是可以使用其他提到的功能来实现该行为,从而减少混乱。
另一件事getuid()
返回真实UID过程的 whilesetuid()
旨在修改有效UID(除非有特权),这也令人困惑。
答案1
这一切背后可能有一些黑客历史。正如你所说,setreuid()
更清楚,因为它是标准中规定的,我会用它。接下来就是认真检查返回值,并用getuid()
和进行验证geteuid()
。
setresuid()
不在 POSIX 中,因此它可能不会广泛使用(不过 FreeBSD 和 OpenBSD 似乎有它)。如果实现setreuid()
与文档匹配,则无需显式设置保存的 UID,因为setreuid()
应该为您设置它:
如果正在设置真实用户ID(ruid不为-1),或者将有效用户ID设置为不等于真实用户ID的值,则应设置当前进程保存的set-user-ID等于新的有效用户ID。
话又说回来,如果可能的话,完全避免 setuid 程序而支持单独运行的特权进程并通过套接字与其通信可能是一个好主意。有一堆东西从一个进程继承给它的子进程,通过 setuid,特权较低的进程可以将它们设置为特权较高的进程。