请阅读这篇长篇介绍以了解我对为什么我们需要可执行二进制文件的 SUID 权限的担忧。
- Linux 中的进程使用其 EUID 来了解自身的有效用户 ID。
- 此用户的权限用于决定此进程如何与其他文件交互(例如,此进程是否可以写入文件)
考虑通过更改密码的场景/usr/bin/passwd
现实生活中的 Linux
- 密码存储在
/etc/shadow
. 此文件root
拥有权限 (rw-------
) - 如果
$passwd
有权限rwx--x--x
,这意味着只有root才能改变passwd程序的逻辑。 userA
运行程序时,一个进程passwd
以RUID = EUID = userA开始
结果是:程序将运行。passwd
进程已启动,但无法更改密码,因为其EUID为userA且userA无法写入/etc/shadow
.
这是需要 SUID 权限的时候。SUID允许在执行二进制文件以创建该进程时设置进程的EUID 。EUID将设置为该二进制文件的所有者。
- 为所有者设置SUID 权限
/usr/bin/passwd
使任何用户启动的任何进程的EUID都采用EUIDpasswd
root
- 由于
root
可以写入/etc/shadow
,任何用户都可以使用该passwd
程序启动一个可以更改的passwd
进程/etc/shadow
有SUID 权限,因为在 Linux 中,进程的EUID不会硬设置为可执行二进制文件的所有者(运行时将创建该进程)
我理想中的 Linux
无需SUID 权限。如果可执行文件binA由userA创建(并拥有) ,则任何可以执行binA的用户都将创建一个EUID = userA的进程。
在修改密码的场景下,这个思路的逻辑如下:
- root是所有者,
/usr/bin/passwd
只有root可以更改其逻辑。 - 里面的逻辑
/usr/bin/passwd
只允许用户更改其密码,而不能更改其他人的密码。 - 其他用户不能修改
/usr/bin/passwd
,只有root可以。 /etc/shadow
只能由root
结果是:非特权用户userA
可以执行$passwd
. 他会创建一个passwd
流程。此进程具有EUID = root,因此它可以写入shadow
文件。
有了这个理论,我们可以实现:每个人都可以在没有SUID 权限的情况下更改自己的密码(并且只能更改自己的密码)。
您的两个示例都说明了 setuid 的工作原理。但是,在您的“理想 Linux”中,每个可执行文件都以可执行文件所有者的 EUID 开头,这将使您系统上的每个可执行文件都成为 setuid 可执行文件。
这显然会导致很多问题,仅举几例:
setuid()
如果程序不应该具有任何额外权限,则每个 root 拥有的可执行文件都需要进行 UID 检查并调用将进程的 EUID 设置回非 root;用户不能将可执行文件提供给其他用户,因为该进程会以错误的 EUID 运行;配置错误和不良做法会产生严重后果(例如chmod 777
现在还允许访问用户拥有的任何文件)。这些还有更多。没有 setuid 二进制文件的正常权限需要一些其他机制来允许非特权用户执行特权操作。Setuid 二进制文件允许这样的特权提升和访问控制在程序逻辑中实现。
标记的答案完美地回答了我的问题。我放在这里的是额外的逻辑,有助于我解释关于更改密码场景的SUID 权限的存在。
在 Linux 中,可执行的 bin 文件应该由不同的用户运行。
尽管许多用户应该能够使用同一个 bin 文件,但由该 bin 文件启动的进程应该对文件具有不同的权限。
在 Linux 中,每个进程都有RUID。RUID是启动该进程的用户的 ID 。按照这个逻辑,进程的RUID应该是该进程使用文件权限的用户(例如,进程根据其RUID用户可以对该文件执行的操作来决定它可以对该文件执行什么操作)。
但是,在更改密码的情况下,仅RUID是不够的,因为:
/etc/shadow
文件不能被除root之外的任何人修改。/usr/bin/passwd
可执行的 bin 文件来完成。该程序的逻辑确保低权限用户只能更改他的密码。/usr/bin/passwd
,他将启动一个RUID为userA的passwd
进程。/etc/shadow
,所以他启动的passwd
进程也无法写入该文件。在 Linux 中,进程对文件的权限取自EUID对该文件的权限。
使用EUID,root现在可以使用SUID 权限来允许userA启动一个将EUID设置为root的
passwd
进程。这有效地允许用户A启动的进程修改文件。passwd
/etc/shadow