我对基于 *NIX 的操作系统完全陌生。让我困惑的事情之一是进程或程序可能会执行setuid(0)
然后执行特权操作并恢复到其正常的 uid。
我的问题是 *NIX 中防止任何任意进程拥有 root 的机制是什么?
如果我编写一个简单的 C 程序,在什么条件下调用setuid(0)
该调用会成功,在什么条件下会失败?
答案1
基本思想是进程只能减少其特权。进程可能无法获得任何特权。有一个例外:一个过程执行具有 setuid 或 setgid 标志集的文件中的程序将获得此标志表示的特权。
请注意,此机制不允许程序以提升的权限运行任意代码。唯一可以使用提升权限运行的代码是 setuid/setgid 可执行文件。
root 用户,即 id 为 0 的用户,比其他任何用户都拥有更高的特权。用户 0 的进程可以执行任何操作。 (第 0 组并不特殊。)
大多数进程以相同的权限继续运行。使用户登录或启动守护程序的程序以 root 身份启动,然后放弃所有权限并以用户身份执行所需的程序(例如,用户的登录 shell 或会话管理器或守护程序)。 Setuid(或 setgid)程序可以作为目标用户和组进行操作,但许多程序会根据它们正在执行的操作,使用我现在要描述的机制在调用者的权限和它们自己的附加权限之间进行切换。
每一个进程有三个用户ID: 这真实的用户 ID (RUID),有效的用户 ID (EUID),以及已保存用户 ID (SUID)。这个想法是,一个进程可以暂时获得特权,然后在不再需要它们时放弃它们,并在再次需要它们时重新获得它们。有一个类似的机制团体,具有真实组ID(RGID)、有效组ID(EGID)、保存组ID(SGID)和补充组。他们的工作方式是:
- 大多数程序自始至终都保留相同的真实 UID 和 GID。主要的例外是登录程序(和守护程序启动程序),它们将其 RUID 和 RGID 从 root 切换到目标用户和组。
- 文件访问,以及需要root权限的操作,查看有效UID和GID。特权程序通常会根据是否正在执行特权操作来切换其有效 ID。
- 保存的 ID 允许来回切换有效 ID。程序可以在保存的ID和真实ID之间切换其有效ID。
需要使用 root 权限执行某些操作的程序通常会在其 EUID 设置为 RUID 的情况下运行,但seteuid
在运行需要权限的操作之前调用将其 EUID 设置为 0,并seteuid
在之后再次调用 EUID 更改回 RUID。seteuid(0)
即使当时的 EUID 不为 0,为了执行调用,SUID 也必须为 0。
可以使用相同的机制来获得组权限。一个典型的例子是本地用户保存高分的游戏。游戏可执行文件是 setgid games
。当游戏开始时,其 EGID 设置为games
,但会更改回 RGID,以免冒险执行用户通常不允许执行的任何操作。当游戏即将保存高分时,它会暂时将其EGID更改为games
。这边走:
- 由于高分文件需要普通用户没有的权限,因此向高分文件添加条目的唯一方法就是玩游戏。
- 如果游戏中存在安全漏洞,最糟糕的情况就是向该
games
组授予用户权限,让他们在高分上作弊。 - 如果游戏中存在不会导致程序调用该
setegid
函数的错误,例如仅导致游戏写入非预期文件的错误,则该错误不允许在高分上作弊,因为游戏不会没有权限在不调用 的情况下写入高分文件setegid
。
我上面写的是描述一个基本的传统Unix系统。一些现代系统还具有其他功能来补充传统的 Unix 特权模型。这些功能是对基本用户/组有效/真实系统的补充,有时会与其交互。我不会详细介绍这些附加功能,但我只会提到 Linux 安全模型的三个功能。
- 执行许多操作的权限是通过能力而不是用户 ID 0。例如,更改用户 ID 需要 能力
CAP_SETUID
,而不是拥有用户 ID 0。以用户 ID 0 运行的程序将获得所有能力,除非他们不走寻常路,并且以用户 ID 0 运行的程序CAP_SETUID
可以获得 root 权限,所以在实践中以 root 身份运行和拥有CAP_SETUID
是等效的。 - Linux 有几个安全框架这可以限制进程可以执行的操作,即使该进程以用户 ID 0 运行。对于某些安全框架,与传统的 Unix 模型和功能不同,进程可能会由于
execve
安全框架的配置而不是由于可执行文件元数据中的标志。 - Linux 有用户 命名空间。在命名空间中以 root 身份运行的进程仅拥有该命名空间内的权限。
答案2
除了用户 ID 之外,进程还与有效用户 ID 相关联。当执行 setuid root 程序时su
,有效 uid 被设置为 0,但真实 uid 保持不变。顾名思义,有效 uid 是用于权限检查的 uid,真实 uid 只是告诉我们“我们到底是谁”。有效 uid 等于 0 的进程可以成功调用setuid(0)
将真实 uid 更改为零。
答案3
为了使 setuid(some_uid) 起作用,需要满足以下条件:
- 可执行文件的文件需要由 some_uid 1拥有。
- 可执行文件需要具有 setuid 权限。
可以使用以下命令授予或删除 setuid 权限chmod
:
chmod u+s execuables_file_name
chmod u-s execuables_file_name
显示文件权限时可以看到setuid权限,因为s
如果授予setuid权限,执行权限将被替换。
> ll execuables_file_name
-rwsrwxr-x 1 root root 0 Sep 30 17:23 execuables_file_name*
如果由于某种原因所有者用户没有执行权限,那么它将显示为大写的 S:
> ll execuables_file_name
-rwSrwxr-x 1 root root 0 Sep 30 17:23 execuables_file_name*
注意脚本是完全不同的野兽。
彻底的权限指南。
1. 如果转换到启动进程的用户 ID,setuid(some_uid) 也会成功