LWN:给 io_uring 添加 audit 支持!

共 3938字,需浏览 8分钟

 ·

2021-06-27 10:17

关注了就能看到更多这么棒的文章哦~

Auditing io_uring

By Jonathan Corbet
June 3, 2021
DeepL assisted translation
https://lwn.net/Articles/858023/

io_uring 子系统于 2019 年首次推出以来,已经迅速成为执行高带宽的异步 I/O 操作的首选方式。它引起了许多开发人员的注意,包括最近那些关注安全更甚于性能的开发者。现在,安全社区的一些成员感叹在 io_uring 中缺乏考虑安全性,因此希望在这个领域中添加 audit 和 Linux security module 的支持来弥补这一缺陷。这个工作目前看来很困难,甚至引出了一个不那么让人高兴的后备解决方案。

Linux 的 audit 机制允许监控和记录系统中所有重要的活动。例如,有人想知道谁查看了一个特定的文件,那么具备 audit 功能的系统就可以提供这个答案。audit 能力是获得一些安全认证的必要条件,而这些认证又是在一些对安全比较敏感的环境中部署 Linux 的必要条件。其实相对来说只有一小部分 Linux 系统打开了 audit 功能,但发行版提供方几乎无一例外地在他们的内核中都启用了 audit。

audit 机制反过来又依赖分散于内核源代码中的许多 hook 代码。每当某一个人们可能感兴趣的事件发生时,就会通过适当的 hook 被报告给 audit 代码。然后 audit 子系统会根据一组从用户空间加载进来的规则来控制哪些事件需要被报告给用户空间。

在 io_uring 被开发出来时(当然现在仍是在进行中),开发人员对性能和功能非常关注。而 audit 这类的安全特性并不是他们的首要任务,所以他们当然也就忽略了要添加相关的 hook,或者说没有考虑过如何能在符合性能目标前提下也支持 audit。现在,io_uring 出现在更多发行版的内核之中了(也就是 audit 可能会被缺省启用的那些内核),因此安全相关的开发者开始有些担心了。如果 io_uring 成为了规避所有 audit 监控的一种方式,这对于维持安全认证来说不是一种好做法。

Adding security support

5 月下旬的时候,Paul Moore(audit 子系统的维护者)发布了一组补丁,向 io_uring 添加了 Linux security module(LSM)和 audit 功能。LSM 方面相对简单一些,因为 io_uring 执行的操作已经被 LSM hook 涵盖了,所以所需要做的只是增加两个新的 hook 来判断具体是哪种 io_uring 操作。具体来说,这两个 hook 控制(进程之间)共享信息,而这些信息就是存储在 ring buffer 中用于向内核传达操作请求的。详情请见 patch。patch set 中的这一部分似乎没有什么争议。

audit 代码则不一样了。因为 io_uring 的核心代码已经被仔细优化过了,希望能尽可能快地完成处理所有的 request 以及相应的结果。io_uring 的使用场景中可能会有每秒执行数百万次的 I/O 操作,所以这里增加任何开销都是不受欢迎的。如果在 ring buffer 的操作中添加 audit 相关的 hook 的话,就会拖慢了 io_uring 最关键的性能指标,因此引起 Pavel Begunkov 的负面评价:"所以,这组 patch 在最繁忙的函数之一的每个请求中都增加了两个带有 memory load 操作的 if(即 current->audit_context)。不可能接受这样的改动"。

Begunkov 建议,也许可以在运行时通过 patch 方式来加上 audit hook,就像 tracepoints 和 kprobes 的工作方式那样。Moore 回应说,audit 子系统不支持这样的 patch 方式,而且这样做可能会引起一些本质问题:"我感觉它会违反那些安全认证"。因此,这似乎不是一个可能的解决方向。

同时,io_uring 的维护者 Jens Axboe 做了一些测试。一个简单的 random-read 测试在使用了 audit hook 后,即使没有加载任何实际有效的 audit rule,速度也降低了近 5%。其他各类基准测试也得到了同样的结果,哪怕是在使用更新过之后的 patch set(尚未公开发布)也一样。为了 5% 的性能提升,内核开发者可能会需要数月的辛勤工作,如果因为 audit hook 而导致这么大的性能损失,对他们来说就是一颗苦果。

Axboe 指出,以前通过老的异步 I/O 系统调用接口启动 read 和 write 操作时,是不会被 audit 的。"在过去的二十年里,是不是说明这并不是一个问题?" 他同意一些操作(比如打开或删除文件)应该被 audit,但他认为对读写操作进行 audit 则 "只是纯粹的噪音,一点用都没有"。由于这些操作是对性能影响最大的操作,因此如果能让 audit hook 不影响这些操作,可能是一个解决方案。

Moore 提出了一个基于这个想法的方案,也就是只对特定的、精心选择的那些操作才会使能 audit hook。io_uring dispatcher 中有一个很方便的 switch 语句,可以很容易地用来只对需要关注的操作进行 audit 检测。他希望听听大家的意见,但到目前为止还没有多少回复。正如 Begunkov 指出的,一个很重要的问题是哪些操作需要进行 audit。对打开文件这个操作添加一个 audit 调用一般不太会影响到人们,而如果对 poll 这类操作添加 audit 的话则是另一回事了。Moore 已经提出了一组他认为值得 audit 的操作集合作为讨论的基础。

Threads and grumbles

如果幸运的话,这个解决方案会被大家都接受。根据 Moore 的说法,如果在 io_uring 中不能支持 audit 的话,那就更加不妙了:

如果我们不能在这里找到一个解决方案,我们将需要使 io_uring 和 audit 互不兼容,我认为这不符合用户的最佳利益,而且肯定会让发行版提供方头痛。

"头痛 "这个词并不特别准确。如果这两个功能是互不兼容的话,那么就不可能编译出一个能同时支持这两个功能的内核。因此,发行商将不得不提供两个不同的内核(他们总是竭力避免这种情况),或者从这两个功能中选择一个来支持。希望事情不会发展到这一步。

同时,双方的开发者都表达了一些不满,但安全开发者很明确地表示,他们更希望看到 audit 从一开始就设计在 io_uring 中。正如 Casey Schaufler 所说:

如果 audit 和 LSM 的需求在一开始就被包含到 io_uring 的设计中的话,那就会非常方便了。性能方面的影响可以直面去解决。否则的话,今后可能不得不重新进行改造了。

Richard Guy Briggs 也抱怨说:"许多安全方面的担心似乎总是事后才想到的,因此导致必须在后来补上。" 这两个评论的意思都是说,如果有足够的先见之明的话,现在遇到的困难本来是可以避免的。

这可能算是一个公平的批评意见。内核开发者在开发新的功能时,常常把安全问题留到今后考虑。对于像 audit 这样相对小众的功能来说更是如此,因为它一般不可能在开发系统中启用。内核社区对安全开发人员可能有点不友好,认为他们总是把安全放在第一位(居然超越了性能要求)。这样的一个讨论环境似乎就是告诉大家可以先把安全问题丢在一边、等以后再解决。

不过,也应该指出,io_uring 自 2019 年初以来一直在公开进行开发。它已经在邮件列表(和 LWN)中得到了大量的讨论,但安全社区并没有将这些信息作为他们应该尽快提出建议来支持 audit 的线索。很少有内核开发者能够在实现每秒百万次操作的 I/O 子系统的同时,还能设计好 security hook 并且不影响性能。也许 io_uring 的开发者从一开始就应该考虑安全问题,但他们也应该从一开始就得到帮助。

内核社区对于增加像 io_uring 这样的新功能时,很少有一些必须的规定,这一点很让人惊讶。理论上来说,新的系统调用应该要有 man page,但是真的哪天有 man page 先出现了的时候,人们肯定会感到惊讶。在一个有更多正规流程的项目中,就很有可能会坚持新功能在对 LSM 和 audit 等机制有了适当支持之前是不能合入的。这可能会迫使人们更早地与安全开发人员开始互动,从而避免发生这种问题。

但这并不是我们所处的世界。从来没有人会根据 check list 来逐项检查,确保在合并一个新的子系统之前,所有的工作都已经逐项完成了。因此,内核社区将不得不继续 “混日子”,尽其所能地支持所需的功能。这不会是最后一次出现这种要为了安全机制来改造现有的内核功能的事情。可以说,这不是最好的方法,但一般来说最终总还是能完成工作的。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~



浏览 23
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报