与 systemv init 相比,systemd 的安全含义是什么?

信息安全 linux
2021-08-22 23:15:09

我刚刚开始学习init系统,所以我只知道两者的高级特性。

我注意到很多人对 systemd 大惊小怪,甚至有人声称创建 systemd 是为了故意引入漏洞!

我最常看到的论点是 systemd 引入了一个新的、大型(且不熟悉)的攻击向量。另一方面,在我看来,像 systemd 这样的系统实际上是一件好事,因为它是标准化的代码,而不是临时的初始化脚本。在这方面,我看到了与内核的相似之处。当然,每个人都可以创建自己的易于阅读的操作系统,但重复使用相同的代码让大量的眼球都在监视它不是更好吗?

我在正确的轨道上吗?有没有我没有考虑的问题?

3个回答

(大多数情况下)人们不会故意注入漏洞,它们是偶然发生的。随着代码量的增加,缺陷的数量也在增加。但它不仅仅是大小 - 错误的数量随着代码复杂性增加,并且它比线性增加得更快。所以更多的代码对安全来说是个坏消息。

systemd 的攻击面比 initd 大得多——默认配置有多个接口。

对我来说最大的烦恼是设计理念。其目的是 systemd 为分销商提供更统一的方式来整合服务。但这意味着从系统管理员那里移除对系统的控制(除了替换一个复杂但很好理解的生态系统的影响之外)。它故意使使用 initd 可以完成的事情变得困难或不可能实现(请注意,在 initd 下运行的服务管理器有很多选项 - djb daemontools、upstart、initng、rund、procd、openrc....限制 sysv rc init 系统的并行化/依赖问题)。

启动 unix 系统的许多逻辑都是在 shell 脚本中实现的。这使得不仅可以更轻松地对操作进行逆向工程,还可以对其进行检测和扩展功能。Systemd 将更多逻辑移动到二进制文件中,并且更多地依赖于复杂且记录不充分的配置。

故意降低系统管理员的控制级别和不支持系统管理员的任务相结合,使他们更难以完成他们的工作 - 这包括确保系统的安全性。

PID 1 中所有这些复杂性的进一步后果意味着您必须更频繁地重新启动系统。除了对可用性的影响之外,这还意味着您的系统会经历一系列临时状态——这可能会暂时暴露在稳态系统上难以检测到的漏洞。使用 daemon-reexec 来解决这个问题会带来一系列新问题。

终身仁慈的独裁者模式似乎适用于 linux 内核,但开源行业的其他部分并不是这样运作的。事实上,也许是一个例外证明了这一规则——开源之所以有效,是因为没有人负责,而不是尽管没有人负责。Systemd 假设控制了 linux 系统中的许多功能,但它作为一个相对较小的社区运行。根据pwnie奖,它似乎有点内向:代码上没有太多的眼球:当有人对代码提出担忧时,没有人在听。

Systemd 实际上是几个部分的集合,为了使比较有意义,您必须比较实际相互对应的部分。

让我们先来看看 SysV init:这是一个非常小的程序,它作为启动后的第一个进程运行,它执行一些非常基本的设置,然后读取配置文件/etc/inittab(出口。它还打开了一些通信通道(/dev/initctl信号处理程序),使更改当前运行级别成为可能,更改当前运行级别将导致运行其他一些程序,再次按照配置/etc/inittab

就是这样。显然,这并没有很大的攻击面,仅仅是因为它几乎什么都不做。另一方面,实际管理典型系统所需的其他一切都委托给外部程序:如何启动和停止特定服务(例如 Web 服务器、数据库、网络...)、服务之间的依赖关系(即首先启动数据库,只有 Web 服务器),更复杂的监控(看门狗功能),特权删除和沙盒,按需服务激活(例如 inetd),挂载文件系统,...... Systemd 集成了大部分功能,因此更复杂。

现在,将这些东西集成到一个中心位置具有降低整体复杂性和脆弱性的巨大潜力,从而使系统更加安全。采取各种“沙盒”功能,包括特权删除、限制对某些目录的访问、私有临时目录、设置单独的命名空间、网络隔离……对于 systemd,这些作为设置服务环境的一部分非常容易实现,这- 作为服务经理 - 无论如何都必须这样做。相反,使用 SysV init,则必须使用单独的程序;实际上,这将是一组 shell 脚本,或者将其集成到各个服务中,从而将“有风险”的代码传播到更多地方。

此外,systemd 为系统管理员提供了轻松设置这些功能的方法(配置文件中的几行代码),使他们不必自己实现它们(在某些情况下甚至可能涉及修改和重新编译服务!)。当然,在实践中,这意味着它们根本没有被使用。从安全的角度来看,与 SysV init 一起使用的图灵完备的 shell 脚本相比,ini 样式的配置格式也是一个优势。

至于 systemd 背后的开发模型:与替代方案相比,我认为这是一个优势,因为开发(和广泛的测试!)发生在一个中心位置,这与以前主要是分发特定代码的混合形成鲜明对比。甚至 SysV init 核心本身在不同的发行版中也不同,因为它的上游可以被认为是死的。与其他人所说的相反,systemd 上游实际上非常敏感,并且对合理的变更请求持开放态度。

也就是说,我可以看到情况有所不同的一种情况,即不需要 systemd 提供的功能,例如,如果您想构建一个路由器或一个简单的网络网关,其中所需的服务集是预先知道的,并且永远不会改变。即使在那里,您也可能想要利用易于使用的沙盒功能,而这无论如何都是不适用于绝大多数系统的特殊情况。

至于眼球的事情——从历史上看,RHEL 核心的初始化 RC 脚本等等,基本的“SYS V”初始化克隆,并不是以极其稳健的方式编写的,它不像他们做了一个白板状态机设计在那里。而且您无法在大多数主要发行版中只为它发送补丁。如果您的 init 上没有写出的规范和真正的软件设计,您会发现人们害怕更改它。

然而,脆弱性的影响非常小,单个任务的大小也是如此。运行脚本。运行下一个。没有任何临时文件。在内部保持无状态,除非运行计数器使事情朝着所需的“目标”或朝着相反的方向发展。

除了 init 命令或 telinit 外,没有其他接口。在一个适当的 unix 中,一个 init 0 simpy 结束 init,让你陷入困境。Linux(为了方便和方便不阅读手册的人的生活)已经远离了简单的设计,而且似乎从来没有考虑过(抱歉)初始化克隆应该是一种“MIL -SPEC”质量。

现在我们有同样的事情,这些问题再次不是最重要的,但现在它在处理任务中占据了很大一部分,在它与内核的接口方面,因为它可供非 root 用户访问,并且在它在启动任务完成时处理输入。

这些仅仅是差异。问题是,强化或失败的安全/失败的操作状态等方面似乎不被视为核心事物。有一些针对该方向的措施(即如果被恶意流量丢弃,则自动重新生成)但不是很多

现在让我们假设开发过程和对关注点的响应会发生变化。那将会很酷。(与一些备用初始化一起工作,我认为这不会发生,因为其他初始化都没有以任何方式充满敌意)

然后我们就剩下一个问题:多眼球的事情是有问题的。在正常的init系统中,由于缺少接口,“攻击向量”正在获取一个init脚本,只有root才能做到。然后它被允许做任何它认为必要的事情,并且你在作者的摆布下,即放弃 privs 去。如果他知道如何使用 su,那就是 su,如果他不知道,那就是 sudo,以此类推。但是他攻击你的初始化系统的唯一方法是,如果他在里面放了一些覆盖二进制/脚本的东西。他甚至不会轻易“坚持”在里面它,因为当下一个脚本运行时,他要导出的任何变量都会被压缩。这种语言(sh,理想情况下,仅限 POSIX)已经到了每 10 年就有一个 sec 漏洞的地步,通常根本没有。而且,我想强调一点——攻击的东西太少了,而且在系统启动后他也无法攻击它。

这些差异是存在的。他们可能会引起担心或不担心。但“共享代码库”的论点大多没有实际意义。您摆脱不良 priv-drop 包装器的论点有两个讨论点。第一,那些要么是糟糕的设计(本地 nat 是一件事)要么是必需品(ssh);第二,在 sw 世界中,我们已经了解到,对于任何与安全相关的问题,我们都需要将其列为最糟糕的问题,而不是过度解决它比不解决。这没有发生。

现在很少有人在寻找漏洞利用,但这对于 sec 研究人员来说并不是一个有趣的话题。一旦发生这种情况并遇到数十亿安装的设备未打补丁的基础,我有点担心。我们可能会在科技界受益。对于从我们的系统所做的任何事情中受益的人来说,自动重启服务变得越来越普遍(因为显然对于非 HA 设置来说阅读 daemontools 太难了),但我不想在附近并且需要证明我们是否在我们的 init 中重复了一些像 CodeRed 这样的狗屎。

向我展示如何关闭,而不是在启动时运行单个(!)shell 脚本。对策变得有点复杂。至于 daemon-reexec 我仍然想知道为什么 azypper ps -s之后仍然会在内存中看到旧的 systemd 部分。

我已经跳过了与 SMF 的比较——其中一个 systemd 开发人员称为“Solaris”或与 AIX 类似,如二进制日志记录和 SRC。SMF 有一个非常开放、包容、深思熟虑和记录在案的设计过程,我认为这就是最大的不同之处。不知道这将如何被修补。