嵌入式 Linux 和 IoT 软件更新的关键考虑因素

Mirai 僵尸网络攻击奴役了安全性差的联网嵌入式设备,这再次切实地例证了在将嵌入式设备上线之前确保安全性的重要性。Mirai 的一种新变种已导致约一百万德国电信客户的网络中断,原因是路由器安全性差。这些嵌入式设备中有许多运行嵌入式 Linux 的变体;通常,如今的发行版大小约为 16MB。

不幸的是,Linux 内核虽然应用非常广泛,但也远非对关键安全漏洞免疫。事实上,在 2016 年 Linux 安全峰会的一次演讲中,Kees Cook 重点介绍了 Linux 内核中两个关键安全漏洞的例子:一个存在于 2.6.1 到 3.15 的内核版本中,另一个存在于 3.4 到 3.14 的内核版本中。他还表明,无数高危漏洞不断被发现和解决——在他的数据集中超过 30 个。

图 1. Linux 内核修复时间

尽管开发团队的流程和实践显然对嵌入式产品软件的(不)安全性具有至关重要的影响,但软件项目的代码库大小与错误和漏洞的数量之间也存在明显的关联。Steve McConnell 在《代码大全》中指出,每 1000 行代码中存在 1-25 个错误和漏洞,变量由团队的实践决定。军用认证产品由于更严格的安全实践和质量测试,通常处于较低端,而消费电子产品不幸地处于较高端,原因是更注重功能和上市时间。

经验丰富的软件开发人员始终寻求通过重构和重用库中的功能来减小代码库的大小,但是随着对每个产品中更多功能和智能的永无止境的需求,嵌入式设备中的软件量显然只会增长。这也必然意味着也会有更多的错误和漏洞。

由此可见,对于具有一定智能水平的嵌入式设备,特别是对于联网设备而言,拥有远程部署错误和安全修复程序以及新功能的方法显然是必需的。

本文进一步深入探讨了将软件更新部署到嵌入式设备(尤其是嵌入式 Linux)的具体要求和解决方案设计。

嵌入式行业软件更新的现状

作为 Mender 工作的一部分,我们正在对许多软件工程师和团队进行访谈,以便更好地了解当今嵌入式产品中如何进行软件更新。在其中一系列访谈中,我们与 30 位嵌入式软件工程师进行了交谈,主要收获如下所述。

在第一个问题中,我们只是询问今天是否正在将其软件更新部署到其嵌入式产品中,如果是,使用了哪些工具(图 2)。

图 2. 关于是否正在将软件更新部署到嵌入式产品以及如果部署了,使用了哪些工具的调查回复

45.5% 的受访者表示,从未将其更新部署到他们的产品中。他们将新软件交付给客户的唯一方法是制造带有新软件的硬件并将硬件运送给客户。

大约另一半,54.5% 的人表示,他们确实有一种更新其嵌入式产品的方法,但是该方法是内部构建的。这也包括本地更新,即技术人员需要亲自前往设备并从外部介质(例如 USB 闪存驱动器)更新软件。另一个类别是启用了远程更新的设备,但是您一次只能更新一个设备,这实际上排除了任何批量更新。最后,有些人有能力以高度自动化的方式将批量更新部署到所有设备。

这里的主要发现之一是,几乎没有人重复使用第三方软件更新程序——他们都在重新发明轮子!

其次,我们询问了部署软件更新的首选方法是什么(图 3)。您可以将嵌入式更新程序大致分为基于映像或基于软件包的更新程序。基于映像的更新程序将在块级别上工作,并且可以替换整个分区或存储设备。基于软件包的更新程序在文件级别上工作,其中一些更新程序(如 RPM/YUM)在 Linux 桌面和服务器环境中也很出名。

图 3. 软件更新方法调查结果

基于映像的更新程序通常在嵌入式领域具有明显的偏好。这主要是因为它们通常在更新过程中提供原子性。原子性意味着 1) 更新始终是完全应用或根本未应用,并且 2) 除了软件更新程序之外,任何其他组件都看不到部分更新。此属性对于嵌入式更新程序非常重要,因为嵌入式设备可能随时断电或重新启动,并且在更新过程中断电不应导致设备变砖或无法使用。基于映像的更新程序的另一个声明的关键优势是跨设备的一致性,这意味着由于 1:1 的软件副本,您可以更自信地依赖测试环境中的行为与生产环境中的行为相同。

基于软件包的方法通常无法实现原子更新,但是它们也有一些优点。更新的安装时间更短,并且使用的带宽量也可能小于基于映像的更新。最后,由于许多人开发了自己的内部更新程序,并且已经拥有来自其构建系统的软件包,因此基于软件包的更新系统通常可以更快地从头开始开发。

嵌入式环境

熟悉 Linux 桌面和服务器系统的人可能会问,为什么我们不只是使用我们从这些系统中了解的相同工具和流程,包括软件包管理器(如 rpm、dpkg)、VM 和容器来执行软件更新。要理解这一点,重要的是要了解嵌入式设备在应用软件更新方面有何不同

不可靠的电源

我已经提到了嵌入式系统的这一属性,这是一个广为人知的问题:嵌入式设备通常会随时断电。例如,智能便携式音频系统可能会在房屋内移动时被拔掉电源。便携式 GPS 的电池可能会耗尽,或者在某些天气条件下变得不可靠。汽车中的车载信息娱乐系统可能会在汽车启动或停止时断断续续地断电。在电池供电设备中,此问题会放大,因为更新过程本身会消耗大量电池电量并导致电量耗尽。

嵌入式系统的设计方式必须使其能够容忍任何给定时间的电源故障。电源可靠性的缺乏与典型的数据中心环境形成鲜明对比,在数据中心环境中,多个冗余电源系统将确保永远不会断电。

不可靠的网络

嵌入式设备通常使用某种无线技术连接。尽管 Wi-Fi 用于某些设备中,但更常见的是使用具有更长范围但数据速率较低的无线标准,例如 3G、LoRa、Sigfox 和基于 IEEE 802.15.4(低速率无线个人区域网络)的协议。

人们很容易假设,随着技术的进步,高速无线网络将被嵌入式设备普遍采用,就像智能手机发生的情况一样,现在您可以流式传输高清 YouTube 视频。但是,请记住,智能手机和典型嵌入式设备的用例始终会有很大不同。例如,一种用于测量和优化作物产量的农业设备需要大量的连接,并且即使在没有 3G 覆盖的地方也应能工作。此外,需要发送的数据量非常低——每天可能只有几个关于地球温度和湿度测量值的数据点。因此,人们应该假设嵌入式设备,尤其是工业设备,始终会具有有限的网络数据速率。

此外,无线网络经常且间歇性地丢失连接——例如,当设备移动到覆盖范围低的区域(如地下)时。

尽管低数据速率和间歇性连接可能是难以解决的设计问题,但一旦出现问题,它们通常很容易识别。

公共无线网络上的安全问题更加隐晦且难以暴露。在软件更新的背景下,有无数个内部更新程序未能正确验证更新的示例,从而允许攻击者在更新进行时注入恶意代码。

昂贵的物理访问

一旦发生无法远程修复的大规模问题,修复它的成本通常非常高。原因是嵌入式设备通常在地理位置上分布广泛。

例如,智能电网设备的制造商可以将这些设备安装在多个国家/地区的数千个家庭中。如果 Linux 内核的更新存在无法远程修复的关键问题,则向所有这些家庭派遣服务技术人员或要求客户将设备寄回供应商的成本可能会高得令人望而却步。

2015 年菲亚特克莱斯勒吉普切诺基安全漏洞事件提供了一个近期大规模召回的真实案例。在本例中,召回了 140 万辆汽车。修复此问题的成本肯定在数亿美元范围内,甚至可能达到数十亿美元。

五到十年设备寿命

技术发展非常迅速,更换智能手机和笔记本电脑等常见消费电子设备通常每两到三年更换一次。

但是,高端音响系统和电视等更昂贵的消费设备更换频率较低。不直接与人交互的工业设备通常具有更长的寿命。例如,工厂车间使用的机器人或电网设备很容易达到十年寿命。

总之,在嵌入式环境中,人们需要非常警惕设备“变砖”的风险。这不仅很容易由于电源和网络属性而发生,而且也是一个非常昂贵的恢复局面。

嵌入式软件更新程序的关键标准

现在您更熟悉嵌入式环境了,让我们考虑一下这对嵌入式软件更新程序的影响。

强大而安全

如您所见,在嵌入式环境中,电源和网络都可能非常不可靠且不安全。嵌入式更新程序必须具有一些属性和功能才能充分应对这些挑战。

原子更新

数据库行业非常熟悉原子事务的概念——ACID 中的“A”,其中一组操作要么全部完成,要么全部不完成。数据库理论中此要求的经典示例是在线事务。当一个用户向另一个用户转账时,只有在您也成功地将钱添加到另一个帐户时,才应从一个帐户中扣款。

对于嵌入式更新程序而言,此属性也非常重要,以便处理间歇性更新错误,例如突然断电。对于嵌入式更新程序,原子属性可以分为两部分定义

  • 更新始终是完全完成根本未完成

  • 没有软件组件(更新程序除外)会看到部分安装的更新

您可以看到,在桌面环境中部署软件更新的常用方法不满足此原子性要求。例如,当您安装 rpm 软件包时,许多文件会在整个文件系统中写入和修改,如果您在安装过程中突然拔下桌面电源,它们将处于不一致且可能无法恢复的状态——正在更新的应用程序可能根本无法启动。

一致的部署

减轻设备变砖风险的一种重要方法是在将新软件更新发布到生产环境之前对其进行广泛的测试。但是,为了依赖测试结果,您需要一个尽可能与生产环境相同的测试环境。这是通用操作中的一个经典问题,无论是对于嵌入式设备还是数据中心,测试环境都会与生产环境不同,因此更改在测试环境中运行良好,但在发布到生产环境时会导致严重的停机时间。这就是全映像更新在嵌入式领域如此普遍的原因之一。如果您的整个根文件系统在测试环境和生产环境中逐块相同,那么就可以保证相似性。将此与使用 rpm 软件包的部署进行对比,rpm 软件包可能依赖于在测试环境和生产环境中以及甚至在整个生产环境中都具有不同版本或补丁的库。随着时间的推移,这种设计通常会导致生产部署因不一致且难以诊断的原因而失败。

更新前的真实性检查

从安全的角度来看,非常重要的是要知道软件是否来自授权来源,或者攻击者是否可能将恶意软件注入到更新中。在无数案例中,嵌入式设备只是广播它们安装更新的意愿,任何响应者都能够将他们选择的软件注入到设备中。

确保一定程度真实性的基本方法是利用传输中安全协议(如 TLS)。如果操作正确,这将确保更新在从更新服务器传输到设备的过程中不会被修改。

但是,更强大的端到端方法是将加密真实性元数据嵌入为更新本身的一部分。通常采用一种代码签名形式,其中数字签名由授权机构创建并在设备上验证。

代码签名优于仅依赖传输中安全性的主要优势之一是,对更新进行签名的授权机构可以与托管更新的服务器分离。例如,QA 部门的某人可以离线签署更新。这减少了更新服务器被入侵时的攻击面,因为攻击者仍然只能部署已由 QA 部门签名的更新。

对于对性能敏感的设备,应考虑消息身份验证码 (MAC) 或椭圆曲线签名等加密机制,因为与 RSA 或 DSA 相比,它们在相同的安全级别下提供更高效的验证。

更新后的健全性检查

嵌入式设备通常是单用途的,并且仅运行一个主要应用程序,尽管在某些情况下,它们可以运行多个应用程序。在任何一种情况下,在部署更新后检查此类应用程序的运行状况都很重要。它们是否正在运行?它们是否具有网络访问权限?用户是否可以在设备上成功地与它们交互?

软件更新不应仅因为设备启动而被认为是成功的;还应该有一种集成自定义应用程序健全性检查的方法。最后,更新程序应通用地涵盖的关键检查是:是否可以部署另一个更新?

如果任何这些检查失败,更新程序应具有回滚到以前的已知工作软件的能力,以便在诊断和解决问题的同时避免停机。

部署软件更新的通用工作流程如图 4 所示。

图 4. 部署软件更新的通用工作流程

与现有开发工作流程集成

如果您是一个人从头开始进行嵌入式/IoT 项目,则您可能可以选择所有您最喜欢的工具和流程。但是,一旦有多人协作处理同一项目,尤其是如果软件更新在考虑之前已经开发了产品,那么软件更新过程与开发工作流程良好集成就非常重要。

乍一看,这对于更新程序来说可能看起来像是一个奇怪的标准,但是许多软件更新方法都需要完全替换现有的开发工作流程。商业更新程序工具通常作为“平台”的一部分提供,其中更新程序与完整的设备操作系统、云后端和其他设备管理功能捆绑在一起。对于现有产品,这可能会带来重大挑战,因为需要更换设备操作系统,可能还需要同时更换构建系统、版本控制和相关的 QA 流程。

对于内部更新程序,此标准通常会被隐式地考虑在内,因为团队倾向于从他们拥有的东西开始,并查看开发和集成更新程序到其中的最短路径是什么。由于现有的构建系统倾向于轻松输出 rpm 或 opkg 等软件包,因此这是一种集成良好且被许多内部更新程序选择的方法。但是,如我先前所述,基于软件包的更新在鲁棒性方面存在重大缺陷。

带宽

正如我之前提到的,嵌入式设备通常使用某种低数据速率无线连接进行连接。需要较少带宽的更新过程将优于需要更多带宽的更新过程,仅仅是因为部署更新的成本更低且花费的时间更少。

压缩是减少带宽的首要功能,因为根据更新的类型和可压缩性,这可以将更新的大小减少一半或更多。还有各种基于增量的更新机制可以用来进一步减少带宽使用量。

更新期间的停机时间

在部署更新时,希望设备上的停机时间尽可能短。可接受的停机时间量显然取决于嵌入式设备的用例。它是必须 24x7 全天候运行的电网的一部分,还是晚上不使用的消费音频系统?

部署更新的方法对所需的停机时间影响最大。例如,对于全映像更新,可以从维护模式部署更新或使用双 A/B 根文件系统方法。维护模式方法的工作原理是重新启动到维护分区,将更新安装到根文件系统分区,然后再次重新启动到根文件系统分区;在此期间,设备都不可用。在双 A/B 根文件系统方法中,更新安装到非活动根文件系统,而设备可以继续使用。在这种情况下,停机时间仅在重新启动到更新后的(先前非活动的)分区期间。图 5 显示了双 A/B 根文件系统分区更新设计。

图 5. 双 A/B 根文件系统分区更新设计

部署管理

如您所见,对于嵌入式更新程序客户端,需要在设备端做出许多设计选择和权衡。

但是,一旦在嵌入式设备上安装并运行了更新程序客户端,管理所有这些客户端的问题就会变得显而易见。如何在 1,000 个这些嵌入式设备上安装新更新?它们正在运行哪个版本的软件?您如何知道更新是否在所有地方都成功安装,并且是否有失败更新的日志?

这些用例通常由更新管理服务器处理,以便可以在设备群中管理更新。

结论

为了将软件更新部署到 IoT 设备,需要考虑许多设计权衡。尽管从历史上看,大多数团队都决定实施其内部更新程序,但是最近出现了几个用于嵌入式 Linux 的开源软件更新程序,这意味着我们应该能够停止重新发明轮子。

资源

SWUpdate 是一个非常灵活的客户端嵌入式更新程序,用于全映像更新,根据 GPL 版本 2.0+ 获得许可。

Mender 是本文作者参与的项目,专注于易用性,由客户端更新程序和带有 UI 的管理服务器组成,并根据 Apache License 2.0 获得许可。

加载 Disqus 评论