LWN:Fedora 和 pkexec!
共 5393字,需浏览 11分钟
·
2022-03-09 19:45
关注了就能看到更多这么棒的文章哦~
Fedora and pkexec
By Jake Edge
February 2, 2022
DeepL assisted translation
https://lwn.net/Articles/883547/
pkexec 中那个烦人的漏洞已经在 Linux 世界中激起了涟漪,引出了对底层 polkit 授权工具包(authorization toolkit)的大量安全更新。它也引出了最近在 Fedora 开发邮件列表中关于 pkexec(用来以另一个用户的身份运行程序)是否真的有必要、或者说是否在某些或所有发行版中有必要的讨论。但是 pkexec 被许多不同的 Fedora 组件所使用,尤其是在桌面版本 Fedora 中,在需要以另一个用户的权限运行程序时,它也许是一个比其他选项更好的选择。
Adam Williamson 在 PwnKit 漏洞披露的第二天提出了这个问题。正如他所指出的,这是一个长期存在的(从 2009 年第一个版 pkexec 开始)本地 root 权限升级问题。这让他开始思考:
这个问题和周围的一些评论,促使我想知道——为什么 `pkexec'仍然有必要存在?尤其是,为什么它仍然是我们在每一个 Fedora 安装中都默认使用的东西?
我的印象中,pkexec 是一个让我们摆脱 consolehelper 的笨办法:一些应用没有被改写成在 policykit 下的正确方式,他们仍然希望整个应用以 root 身份运行,而 pkexec 是实现这一目的的一种方法。
consolehelper 是另外一个允许用户以其他用户身份运行代码的程序,而 PolicyKit 是 polkit 的旧称。2013 年的时候,Fedora Usermode Migration 这个功能的设计目标就是将 consolehelper 的所有用户者都转移到 polkit。Williamson 想知道,当前的 Fedora 中有哪些部分仍然需要 pkexec(毕竟其更像是一个拼凑的用法)。但是,由于它被包含在 polkit 软件包中,而 polkit 的使用非常广泛,也许可以把 pkexec 分割成一个 sub-package,只在真正需要它的地方安装,这是他的建议。
在后续的讨论中,Williamson 指出,根据 Usermode migration 的 bug ticket 看来它还没有完成。Fedora 中仍有 15 个软件包需要 consolehelper。Peter Robinson 说,其中大部分 "似乎是历史遗留" 软件包,没有再被普遍使用了。
Michael J Gruber 开玩笑地问,他是否应该把他的软件包从 pkexec 切换到使用基于 consolehelper 的 beesu 包装过的 su 命令上去,因为 beesu 在 Fedora 中仍然存在。但 Williamson 说他可不建议这么做:
并不是说 pkexec 在本质上比任何其他做差不多的事情(也就是提示输入某个密码,然后以 root 身份运行整个应用程序)的工具更糟糕。不幸的是 pkexec 碰巧有一个巨大的安全缺陷,但如果有人决定仔细检查进去的话,其他做同样事情的工具没准也有安全缺陷。问题是,*整个设计* 就不是最优的。
他说,我们的想法是,应该让应用程序转而使用 polkit 提供的其他机制,以进行他们的特权操作。对于那些不进行这种改变的应用程序来说,pkexec 是一个 "不那么好的第二选择",可以让它们能继续工作。删除 consolehelper 是为了减少发行版需要注意的 "以 root 身份运行命令" 的工具的总数,尽管这还没有完全完成。"从 pkexec 切换到其他任何 '以 root 身份运行东西'的工具都不能算是改进。"
如果你无论如何都要以 root 身份运行程序, pkexec 可能比使用 sudo 或其他选项更好,Lennart Poettering 认为。pkexec 已经使用 polkit 进程间通信(IPC)机制来请求以 root 身份运行二进制文件,这在他看来是一个优越的模式:
我的意思是,polkit 有一些问题,但我非常肯定,"pkexec" 本身我认为并不是大问题。或者换个说法:像 su/sudo/setpriv/runuser/suid binaries 这些工具的整个理念才是[有问题的]:也就是说,我非常肯定,如果我们能系统地禁止通过 execve() 获得权限,而把重点放在把权限操作委托给 IPC 服务上,我们会过得更好——当然,这种做法与传统 UNIX 相比有很大区别。
[…] "pkexec "是一个 短小 的程序,它实际上只运行了很少的特权代码。这使得它比 "sudo" 这个[巨大的]代码怪物要好上许多倍。它有一个更小的 安全规模(security footprint),而且比 "sudo" 更容易 review。这实际上是很有价值的。
但是 Sam Varshavchik 反对这样的观点,他不认为把特权操作转移到 IPC 机制(比如 socket)的另一端,真的会解决什么根本问题。当前的问题是,一些以 root 身份运行的程序有 bug:
在 suid[也就是 setuid]二进制文件中可被利用的 bug,如果出现在等价的无 suid 的程序中,也同样可以被利用,攻击方式完全相同。如果你在 suid 二进制文件中由于精心设计的命令行参数或环境变量而导致缓冲区溢出,那么如果你用一个相同的 bug-for-bug 实现来替换 suid 二进制文件,使用 socket 来仔细传递相同的环境变量或参数给本地 root 权限的二进制程序,并且产生相同的缓冲区溢出,那么你猜怎么着:你仍然有相同的漏洞。
suid 不是问题所在。execve 执行的程序将继承环境变量以及打开的文件描述符,也许还有一些其他的东西,而一个接受 socket 连接的独立 daemon 程序是没有这些东西的。但这些是大多数漏洞利用的东西,所以清理掉环境变量和已打开的文件描述符可以弥补这个漏洞。要利用其他内容的话,攻击者就需要更加费力了。
然而,Poettering 并不这样看。在执行 setuid 二进制文件时,会有大量的状态变化,而且这些状态会随着时间的推移而增加:
setuid/setgid 的问题在于,被调用的特权进程继承了很多隐含的状态和上下文,而人们并没有真正意识到、或完全理解这些状态和上下文。也就是说,它不仅仅是 env vars 和 argv[],还包括 cgroup membership、audit fields 字段、security context 安全上下文、打开的 fds、子进程 pids、父进程 pids、cpu mask、IO/CPU 调度优先级、各种 prctl()设置、tty 控制、signal mask+handler,…等等。甚至不清楚什么会被继承下来,因为进程一直在不断增加更多的属性。
如果你通过 IPC 来对特定的操作进行特权执行,你就会得到保证,无论做什么,都是在一个定义良好的、原始的执行环境中完成的,不会隐性地泄露上下文。IPC 消息是 全部的 脆弱攻击面了,这是我们能做到的最小的攻击面。这很好。
Varshavchik 说,虽然所有这些上下文和状态都存在于 setuid 程序中,但根本问题是在程序本身:
而这些都没有任何区别,除非代码本身也有一个潜在的逻辑错误。而这将是真正的问题。那么,问题就来了,有多少漏洞利用了这些特别的资源,比如 cgroup members、tty control 以及所有其他那些不被注意的属性?我想可能有几个,但我想不起来了。另一方面,完成 execve("/bin/bash") 的漏洞也同样有效,因为 root 守护进程中有同样的潜在 bug,可以通过其前端或 suid 程序触发。一个经过消毒的环境不会有什么帮助。
但对于 setuid 程序来说,完全净化环境是很难或不可能做到的,Poettering 说。有许多相互交互的属性是由 setuid 二进制程序的调用者(也就是攻击者)控制的,而且这个数字还在不断增加:
你可能*希望*没有通过所有这些代码的交互引入错误,但我想说的是,"struct task "和内核中的相关对象一直在被扩展,而那些没有预料到这些添加物的 suid 程序将被暴露在其中,而且即使他们想重置它们,也不能理智地重置,因为通常开发人员不能展望未来(而且 cgroup 的东西甚至根本不能合理地重置)。
Varshavchik 想拿到一些数据依据,来证明这里设想的各种漏洞的情况。他和 Poettering 来回讨论了一阵有什么算是合适的数据,但没有真正达成一致。Poettering 在结束他对这个子话题的参与时指出,他可以理解 "你对 suid 和 sudo 的热爱",但他和其他人认为它们是 "一个非常糟糕的主意"。Varshavchik 认为他并不是对这些机制感到着迷:
我说不上喜欢或者不喜欢 suid + sudo,就跟我喜欢我的螺丝刀差不多。我对这两者都不感冒。两者都只是工具。两者都可以被人们正确使用。两者也都可以被人们以错误的方式使用。但是,并不会因为这一点而用扳手来替代螺丝刀。
Demi Marie Obenour 建议,被一个 setuid 二进制文件继承哪些状态信息,应该由该二进制文件来选择。"状态的继承绝对应该是精心选择过的,但某些 audit 数据可能例外,如 audit user ID"。从事 Linux audit 系统开发工作的 Steve Grubb 说,audit 依赖于二进制文件继承 security context 和 audit 信息,所以现有的 polkit 机制是不够的。如果采用 kdbus 这样的内核机制,那么这个问题就可以避免了。就目前的情况来看,polkit "不能满足我们的安全要求":
[……]因为 policy 是千变万化的 javascript, 而不是一些可以被什么扫描程序来检查的一些固定配置,所以无法确定应该允许哪些状态,拒绝哪些状态。而且决定是否能访问,也并不经过 audit 系统。因此,我们对那些使用了 IPC 启动的应用程序,很少能了解它的访问控制以及信息流情况。
Setuid 可能对某些人来说是很令人讨厌的。但它的属性是众所周知的,完全可以对平台提供一定程度的保证。
他并不是唯一一个抱怨 polkit 的 JavaScript 配置机制的人,因为这被许多人看作是一个糟糕的设计决策。同时,Andrew Lutomirski 说,实现一个内核内的 IPC 机制是很困难的问题。他对 setuid 也有一些想法:
我希望在 Linux 内核中看到一个很好的 IPC 安全模型,但我还没有见过可靠的提案出来。这个问题是 非常难的 。
至于 setuid,我强烈认为 setuid 无论是在过去和现在都是一个错误。执行一个进程不应该增加权限。
回到他最初的主题,Williamson 指出,这个话题的讨论已经很清楚地表明,目前至少有一些 Fedora 的桌面版之类的发布(spin)需要 pkexec,不过:"这不是一个容易回答的问题,因为我们的打包系统并没有区分哪些东西需要 polkit 哪些东西需要 pkexec 。" Fedora 项目负责人 Matthew Miller 认为这至少是可以修改的:"我想,第一步可能是把 pkexec 拆成一个 subpackage,然后逐渐消灭对它的依赖。"
这就是目前为止的所有情况了。把 pkexec 拿出来它打包,似乎是一个好的计划,不管它是否应该慢慢地从实际使用中移除出去。如果出现另一个漏洞,也会更加容易地追查哪些其他 package 在使用它。长期来说,转向更多的或完全是 polkit 式的权限提升功能可能不一定会实现。在这条道路上的共识尚未完全弄清楚,而且这也是一个发行版中不希望看到大量改动的领域,至少不太会有很多代码 review。
就像大多数(所有?)漏洞一样,真正的罪魁祸首是缺乏对代码的集中安全审查(focused security review)。对于 setuid 二进制文件以及其他那些以 root 身份运行的代码来说,review 应该是必须的,但目前还不清楚是否有大量密集的 review 正在进行。每当另一个影响广泛的漏洞出现时,我们就会被提醒,但相关的影响似乎很快都会消失,事情又恢复了 "正常"。这是一个相当令人担忧的状态。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~