【经典论文】LSM:对Linux内核的通用安全支持

煤油灯科技2022-02-11 17:07

摘要

现有主流操作系统的访问控制机制不足以提供强大的系统安全性。增强的访问控制机制未能被主流操作系统所接受,部分原因是安全社区对正确的解决方案缺乏共识。由于通用操作系统必须满足广泛的用户需求,因此集成到这种系统中的任何访问控制机制都必须能够支持许多不同的访问控制模型。Linux安全模块(LSM)项目为主流Linux内核开发了一个轻量级、通用的访问控制框架,使得许多不同的访问控制模型能够实现为可加载的内核模块。许多现有的增强访问控制实现,包括Linux功能、增强安全性的Linux (SELinux)以及域和类型增强(DTE),已经被调整为使用LSM框架。本文介绍了LSM的设计和实现,并讨论了在提供一个真正通用的解决方案来最小化对Linux内核的影响方面所面临的挑战。

1 引言

三十多年来,操作系统保护机制在提供系统安全方面的关键作用已经被充分认知,然而现有主流操作系统的访问控制机制仍然不足以提供强大的安全性。尽管已经提出并实现了许多增强的访问控制模型和框架,但是,主流操作系统通常仍然缺乏对这些增强功能的支持。缺乏这种改进的部分原因是安全部门内部对正确的总体解决方案缺乏共识。

像许多其他通用操作系统一样,Linux内核只提供自由的访问控制,缺乏对增强的访问控制机制的任何直接支持。然而,Linux长期以来支持动态可加载内核模块,主要用于设备驱动程序,但也用于其他组件,如文件系统。原则上,增强的访问控制可以实现为Linux内核模块,允许支持许多不同的安全模型。

实际上,创建有效的安全模块是很困难的,因为内核不提供任何基础结构来允许内核模块调解对内核对象的访问。因此,内核模块通常重新分类到系统调用插入,以控制内核操作,这作为提供访问控制的方法有严重的局限性。此外,这些内核模块通常需要重新实现选定的内核功能,或者需要内核补丁来支持模块,从而降低了模块化组合的大部分价值。因此,许多项目已经为Linux内核实现了增强的访问控制框架或模型作为内核补丁。

在Linux内核2.5峰会上,NSA介绍了他们在安全增强Linux (SELinux) 上的工作,这是Linux内核中灵活访问控制架构的一种实现,并强调了主流Linux内核中对这种支持的需求。Linus Torvalds似乎接受了Linux内核需要通用访问控制框架的观点,但是他更倾向于一个新的基础架构,能为内核模块实现安全性提供必要的支持。这种方法可以避免在现有的竞争项目中进行选择。

为了响应Linus的引导,Linux安全模块(LSM)项目为主流Linux内核开发了一个轻量级、通用的访问控制框架,使得许多不同的访问控制模型能够作为可加载的kernel模块来实现。许多现有的增强访问控制实现,包括POSIX.1e能力、SELinux和域和类型强制(DTE),已经被调整为使用LSM框架。

LSM框架满足了用相同的Linux内核实现许多不同安全模型的目标,同时对Linux内核的影响最小。LSM的普遍性允许在不需要内核补丁的情况下有效地实现增强的访问控制。LSM还允许POSIX.1e功能的现有安全功能与基本内核完全分离。这使得有特殊需求的用户,如嵌入式系统开发人员,可以将安全特性降低到最低性能。它还支持开发POSIX.1e功能,以进一步独立于基础内核。

本文的其余部分组织如下。第二节阐述了LSM寻求解决的问题。第3节介绍了LSM的设计。第4节介绍了目前LSM的实施情况。第5节描述了LSM的运行状态,包括测试、性能开销和到目前为止为LSM构建的模块。第6节描述了开发过程中出现的问题,以及未来工作的计划。第7节描述了相关工作。第8节介绍了我们的结论。

2 问题:受限的设计空间

LSM的设计受到了Linux内核开发人员和各种Linux安全项目的实际和技术问题的限制。在关于该主题的电子邮件中,Linus Torvalds指定安全框架必须是:

  • 真正通用的,使用不同的安全模型仅仅是加载不同的kernel模块;
  • 概念简单、微创且高效;
  • 能够支持现有的POSIX.1e功能逻辑作为可选的安全模块。

各种Linux安全项目主要是为了确保安全框架足以允许它们将现有的安全功能重新实现为可加载的内核模块。新的模块化实现不得对所提供的安全性造成任何重大损失,并且应该几乎没有额外的性能开销。

大多数安全项目的核心功能是访问控制。然而,一些安全项目也需要其他类型的安全功能,例如安全审计或虚拟化环境。此外,在访问控制的灵活性范围上也存在显著差异。大多数安全项目只对进一步限制访问感兴趣,即能够拒绝现有的Linux自由访问控制逻辑通常允许的访问。然而,一些项目希望能够授予访问权限,而这通常会被现有的DAC逻辑拒绝;需要某种程度的这种许可行为来支持功能逻辑作为一个模块。一些安全项目希望将DAC逻辑迁移到安全模块中,以便替换它。

“LSM问题”是统一尽可能多的安全项目的功能需求,同时尽量减少对Linux内核的影响。所需特性的合集将具有很高的功能性,但也具有很强的侵入性,以至于主流的Linux社区无法接受。第3节介绍了LSM为同时平衡这些相互冲突的目标而做出的妥协。

3 LSM设计:对内核对象的间接访问

系统调用接口为用户空间提供了一个与内核交互的抽象过程,并且是一个诱人的间接访问的位置。事实上,重写系统调用查询表中的条目不需要内核修改,使用内核模块来间接调用这个接口就很简单。虽然这是一个很有吸引力的特性,但是间接系统调用接口为一般用途的安全框架(如LSM)提供了有限的价值。此级别的调节并不很理想化,可能需要代码重复,并且可能不能充分表达做出安全策略决策所需的完整上下文。

图1: LSM 钩子架构

LSM接口的基本抽象是间接访问内部的内核对象。LSM试图让模块回答这样一个问题“一个subject S可以在一个内部内核对象OBJ上执行一个内核操作OP吗? ”

LSM允许模块通过在访问之前在内核代码中放置钩子来间接访问内核对象,如图1所示。就在内核访问内部对象之前,钩子调用了LSM模块必须提供的函数。该模块可以让访问发生,也可以拒绝访问,并强制返回错误代码。

LSM框架利用内核的现有机制将用户提供的数据(通常是字符串、句柄或简化的数据结构)转换成内部数据结构。这避免了使用时间检查(TOCTTOU)竞争和低效的重复查找。它还允许LSM框架直接访问核心内核数据结构。通过这种方法,LSM框架可以在内核实际执行所请求的服务之前访问完整的内核上下文。这提高了访问控制粒度。

鉴于第2节中描述的受限设计空间,LSM项目选择将LSM设计的范围限制为支持现有Linux安全项目所需的核心访问控制功能。

这一限制使得LSM框架在概念上保持简单和最小侵入性,同时仍然满足许多安全项目的需求。它还加强了在Linux内核中采用LSM框架的合理性,因为内核开发人员更普遍地接受对增强访问控制的需求,而不是对审计等其他类型安全功能的需求。

“保持简单”设计决策的一个结果是,LSM钩子主要是限制性的:当kernel将要授予访问权限时,模块可能会拒绝访问,但是当内核拒绝访问时,不会咨询模块。这种设计简化的存在很大程度上是因为Linux内核在检测到错误情况时会提前“短路”许多决策。提供权威钩子(在这模块可以重写其中任何一个决策)将更多的钩子连接到Linux Kernel。

然而,POSIX.1e功能逻辑要求能够授权通常在粗粒度级别被拒绝的访问。为了支持作为安全模块的这个逻辑,LSM为这些非强制钩子提供了一些最低限度的支持,在这些钩子中,模块可以授予内核将要拒绝的访问权限。非强制钩子通常与简单的DAC检查相结合,并允许模块重写DAC限制。图2显示了一个用户访问请求,其中一个失败的用户标识检查可以被一个许可钩子覆盖。这些钩子被限制在内核already参考POSIX.1e支持的()函数的范围内。

图2:宽松的LSM钩子,允许安全策略覆盖DAC限制。

虽然LSM并不是为了明确支持安全审计而设计的,但是可以使用为访问控制提供的功能来支持某些形式的审计。例如,许多现有的Linux安全项目都支持审核其访问控制执行的访问检查。LSM还使支持这种审计。一些安全审计也可以通过现有的内核模块通过系统调用来支持,如SNARE项目。

许多安全模型要求将安全属性绑定到内核对象。为了促进这一点,LSM提供了附加到各种内部内核对象的不透明安全字段(详见第4.1.1节)。然而,模块完全负责管理这些字段,包括分配、解除分配和并发控制。

最后,模块组合对LSM设计提出了挑战。一方面,显然需要组成一些具有互补功能的模块。另一方面,已知完全通用的安全策略组合是难以处理的。因此,LSM允许模块堆叠,但将大部分工作推给模块本身。希望可堆叠的模块本身必须导出类似LSM的接口,并在适当的时候调用后续加载的模块。加载的第一个模块拥有对所有决策的最终控制权,决定何时调用任何其他模块以及如何组合它们的结果。

4 实现

本节描述LSM内核补丁的实现。它首先概述了4.1节中描述内核更改类型的实现。第4.2到4.7节讨论了各种内核对象或子系统的具体钩子。

4.1 实现概述

LSM内核补丁以五种主要方式修改内核。首先,它向某些内核数据结构添加了不透明的安全字段,如第4.1.1节所述。其次,该补丁在内核代码的不同点插入对安全钩子函数的调用,如第4.1.2节所述。第三,该补丁添加了一个通用安全系统调用,如第4.1.3节所述。第四,该补丁提供了允许内核模块注册和取消注册为安全模块的功能,如第4.1.4节所述。最后,该补丁将大部分功能逻辑转移到可选的安全模块中,如第4.1.5节所述。

表1:由LSM内核补丁和相应的抽象对象修改的内核数据结构.

4.1.1 不透明的安全字段

不透明的安全字段是void*指针,它使安全模块能够将安全信息与内核对象相关联。表1显示了由LSM内核补丁和相应的抽象对象修改的内核数据结构。

这些安全字段的设置和相关安全数据的管理由安全模块处理。LSM只提供了字段和一组对安全钩子的调用,这些调用可以由模块实现,以便根据需要管理安全字段。对于大多数类型的对象,定义了一个alloc安全钩子和一个free安全钩子,当相应的内核数据结构被分配和释放时,允许安全模块分配和释放安全数据。提供其他钩子来允许安全模块在必要时更新安全数据,例如,在成功的查找操作之后,可以使用后查找钩子来为索引节点设置安全数据。必须指出,LSM没有为安全领域提供任何锁定;这种锁定必须由安全模块执行。

由于某些对象会在安全模块初始化之前就存在,即使该模块内置于内核中,安全模块也必须处理预先存在的对象。几种方法都是可能的。最简单的方法是忽略这些对象,将它们视为模块控制之外的对象。这些对象只能由基本的Linux访问控制逻辑来控制。第二种方法是在模块初始化期间遍历内核数据结构,此时为所有预先存在的对象设置安全字段。这种方法需要非常小心地确保更新所有对象(例如,打开的文件可能在UNIX域套接字上等待进程接收),并确保执行适当的锁定。第三种法是在每次使用时测试预先存在的对象,然后在需要时为预先存在的对象设置安全字段。

4.1.2 对安全钩子函数的调用

如前一小节所述,LSM提供了一组对安全钩子的调用来管理内核对象的安全字段。它还提供了一组对安全钩子的调用来调解对这些对象的访问。这两组钩子函数都是通过全局安全操作表中的函数指针调用的。这个结构由一组子结构组成,这些子结构根据内核对象或子系统对相关的钩子进行分组,还包括一些用于系统操作的顶层钩子。每个钩子都根据内核对象和参数来定义,并且注意避免使用用户空间指针。

图3:vfs mkdir内核函数,一个安全钩子调用用于中介访问,一个安全钩子调用用于管理安全字段。 安全钩子由<->标记。 

图3显示了LSM内核补丁已经应用。这个内核函数用于创建新目录。对安全钩子函数的两次调用已经插入到这个函数中。第一个钩子调用,安全操作->索引节点操作-> mkdir,可以用来控制新建的能力目录。如果钩子返回一个错误状态,那么将不会创建新的目录,并且错误状态将传播给调用者。第二个钩子调用se-security ops-> inode ops-> post mkdir,可用于为新目录的节点内结构设置安全字段。这个钩子只能更新安全模块的状态;它不会影响退货状态。

尽管LSM还在Linux内核权限函数中插入了一个钩子调用,但是权限钩子不足以控制文件创建操作,因为它缺少潜在的重要信息,例如操作类型以及新文件的名称和模式。类似地,在Linux内核中插入一个钩子调用可能会创建函数是不够的,因为它仍然缺乏关于操作类型和模式的精确信息。因此,插入了一个钩子,其接口与相应的inode操作相同。

将这两个钩子插入vfs mkdir将插入dir->i操作-> mkdir调用。插入内部内核接口将为一些LSM钩子提供等效的功能。然而,这种插入也将允许通过内核模块实现更通用的功能。由于内核模块在历史上被允许使用GPL以外的许可证,基于插入的方法可能会对Linux内核开发者接受LSM提出根本性的挑战。

4.1.3 安全系统调用

LSM提供了一个通用的安全系统调用,允许安全模块为安全感知应用程序实现新的调用。尽管模块可以通过/proc文件系统项目或通过定义新的伪文件系统类型来导出信息和操作,但这种方法对于某些安全模块的需求来说是不够的。例如,SELinux模块提供了大量现有系统调用的扩展形式,允许应用程序指定或获取与内核对象和操作相关的安全信息。

安全系统调用是在现有的Linux sock- etcall系统调用之后形成的一个简单的多plexor。它需要以下ar-guments:(无符号int id,无符号int call,无符号long *args)。因为模块定义了系统调用的实现,所以它可以选择以自己喜欢的方式解释参数。这些参数旨在被模块解释为模块标识符、调用标识符和参数数组。默认情况下,LSM提供了一个sys security en- try point函数,它只需用参数调用一个sys security hook。不提供任何新调用的安全模块可以定义一个返回-ENOSYS的sys安全钩子函数。大多数想要提供新调用的安全模块可以将它们的调用实现放在这个钩子函数中。

在某些情况下,LSM提供的入口点功能可能不足以作为安全模块。例如,SELinux提供的一个新调用需要访问堆栈上的寄存器。SELinux模块实现自己的入口点函数来提供这种访问,并在模块初始化期间用系统调用表中的这个函数替换LSM入口点函数。

4.1.4 注册安全模块

LSM框架在内核引导过程中用一组虚拟钩子函数初始化,这些函数执行传统的UNIX超级用户语义。加载安全模块时,它必须通过调用注册安全函数向LSM框架注册自己。这个函数设置全局安全ops表来引用模块的钩子函数指针,导致内核调用安全模块进行访问控制决策。注册安全功能不会覆盖先前加载的模块。一旦安全模块被加载,它是否允许自己被卸载就成为一个决策。

如果安全模块被卸载,它必须使用取消注册安全性向框架取消注册。这只是用默认值替换了钩子函数,所以系统仍然有一些基本的安全措施。默认的钩子函数不使用不透明的安全字段,所以如果模块在重置不透明字段方面做得不好,就不应该保证系统的安全性。

如第3节所述,策略的总体形成比较棘手。虽然任意的策略组合会产生未定义的结果,但是可以开发安全模块,这样它们就可以用已定义的结果进行组合。为了保持框架简单,它意识到只有一个模块,默认模块或注册模块,即主模块。安全模块可以使用mod reg安全接口直接向主模块注册。这种注册由主模块控制,因此这是一个是否允许模块堆叠的决策。有了这个简单的接口,就可以在框架中不复杂地支持基本的模块堆叠。

4.1.5 能力

Linux内核目前为POSIX.1e功能子集提供支持。LSM项目的要求之一是将此功能转移到可选的安全模块,如第2节所述。POSIX.1e功能提供了一种机制来划分传统的超级用户权限,并将其分配给特定的进程。

从本质上讲,特权授予是一种许可的访问控制形式,因为它授予的访问权限将被拒绝。因此,LSM框架必须提供一个至少与Linux功能实现粒度相同的许可接口。LSM保留了内核中用于执行功能检查的现有功能接口,但将功能功能简化为LSM钩子的简单包装器,允许在安全模块中实现任何所需的逻辑。这种方法允许LSM利用大量(超过500个)现有的内核调用来支持并避免对内核的普遍改变。LSM还定义了钩子,允许将其他形式的能力检查和能力计算的逻辑封装在安全模块中。

一个进程能力集,一个简单的位向量,存储在任务结构中。因为LSM在任务结构中添加了一个不透明的安全字段,并钩子来管理该字段,所以可以将现有的位向量移动到该字段中。在LSM框架下,这种改变是合乎逻辑的,但这种改变并没有实施,以便于与其他模块堆叠。在LSM框架中堆叠安全模块的困难之一是需要共享不透明的安全字段。许多安全模块将希望与功能模块一起堆叠,因为功能逻辑已经集成到主流内核中有一段时间了,并且被一些应用程序(如命名的和sendmail)所依赖。在任务结构中保留能力位向量可以简化这种组合,但代价是为不需要使用它的模块浪费空间。

Linux内核对功能的支持还包括两个系统调用:capset和capget。为了与现有的应用程序保持兼容,LSM保留了这些系统调用,但是这些功能的核心功能逻辑已经被对LSM钩子的调用所取代。最终,这些调用应该通过安全系统调用来重新实现。这种变化对应用程序的影响应该很小,因为功能的可移植接口是通过libcap库,而不是直接使用这些调用。

LSM项目开发了一个能力安全模块,并将大部分核心能力逻辑移植到其中;然而,内核仍然显示出预先存在的Linux功能的痕迹。将位向量从任务结构本身移到不透明的安全字段,并重新定位系统调用接口,是使功能模块完全独立的唯一主要步骤。

4.2 任务钩子

LSM提供了一组任务钩子,使安全模块能够管理过程安全信息和控制过程操作。模块可以使用任务结构的安全字段来维护进程安全信息。任务钩子提供对进程间操作的控制,如kill,以及对当前进程上特权操作的控制,如setuid。任务钩子还提供了对资源管理操作的细粒度控制,如setrlimit和nice。

4.3 程序加载钩子

许多安全模块,包括Linux功能、DTE、SELinux和子域,都需要在执行新程序时执行权限更改的能力。因此,LSM提供了一组程序加载钩子,在执行操作的处理过程中,在关键点调用这些钩子。linux binprm结构的安全字段允许模块在程序加载期间维护安全信息。提供一个钩子以允许安全模块在加载程序之前初始化该安全信息并执行访问控制,并且提供第二个钩子以允许模块在新程序成功之后更新任务安全信息满载而归。这些钩子还可以用来控制程序执行中的固有状态,例如,重新验证打开的文件描述符。

4.4 进程间调用钩子

安全模块可以管理安全信息,并使用LSM仪表板组合仪表钩子对系统五仪表板组合仪表进行访问控制。IPC对象数据结构共享一个通用子结构kern ipc perm,并且只有指向这个子结构的指针被传递给现有的ipc perm函数来检查权限。因此,LSM给这个共享的子结构增加了一个安全字段。为了支持单个消息的安全信息,LSM还在消息结构中添加了一个安全字段。

LSM在现有的ipcperms函数中插入了一个钩子,这样安全模块就可以对每个现有的Linux IPC权限检查进行检查。然而,由于这些检查对于一些安全模块来说是不够的,LSM还在单独的IPC操作中插入了钩子。这些钩子提供了关于操作类型和具体论点的更详细的信息。它们还支持对通过System V消息队列发送的单个消息的细粒度控制。

4.5 文件系统钩子

对于文件操作,定义了三组钩子:文件系统钩子、信息节点钩子和文件钩子。LSM为每个相关的内核数据结构添加了一个安全字段:超级块、索引节点和文件。文件系统钩子使安全模块能够控制诸如安装和安装之类的操作。LSM通过在其中插入一个inode钩子来利用现有的权限功能,但是LSM还定义了许多其他inode钩子,以便对单个inode操作提供更细粒度的控制。一些文件钩子允许安全模块对文件操作执行额外的检查,例如读和写,以重新验证使用权限,从而支持权限分级或动态策略更改。还提供了一个钩子,允许安全模块通过套接字IPC控制打开文件描述符的接收。其他文件钩子提供了对操作的更细粒度的控制,例如fcntl和ioctl。

在inode和super block结构中放置安全字段的替代方法是将它们放置在dentry和vfsmount结构中。inode和超块结构与实际对象对应,独立于名称和名称空间。 dentry和vfsmount结构包含对相应索引节点或每个块的引用,并且与特定的名称或命名空间相关联。使用第一对结构可以避免对象混淆问题。这些结构的使用也提供了内核对象的更多覆盖,因为这些结构也表示非文件对象,如管道和套接字。这些数据结构在文件系统代码的任何地方都很容易得到,而第二组结构通常是不可用的。

4.6 网络钩子

应用层对网络的访问是通过一组套接字钩子来实现的。这些钩子包括所有套接字系统调用的插入,为所有基于套接字的协议提供粗略的中介覆盖。由于活动用户套接字具有关联的inode结构,因此没有向套接字结构或较低级别的sock结构添加单独的安全字段。由于套接字钩子允许网络流量相对于进程的一般中介,LSM显著扩展了内核的网络访问控制框架(它已经由Netfil- ter在网络层处理)。例如,sock rcv skb钩子允许入站数据包在其目的地应用程序方面进行中介,然后在相关的用户空间套接字上排队。

已经为IPv4、UNIX域和Netlink协议实现了额外的细粒度钩子,这些协议被认为是实现最低限度有用的系统所必需的。其他协议的类似钩子可以在稍后阶段实现。

网络数据在由sk buff(套接字缓冲区)结构封装的数据包中遍历堆栈。LSM在sk缓冲区结构中添加了一个安全字段,这样就可以在每个数据包的基础上跨网络层管理安全状态。为该安全域的生命周期管理提供了一组sk缓冲钩子。

硬件和软件网络设备由网络设备结构封装。在这个结构中添加了一个安全字段,这样就可以在每个设备的基础上获得安全状态。

由于实现一致的细粒度钩子所需的代码的侵入性,低级别网络支持组件(如路由表和流分类器)的覆盖范围有所限制。 对这些对象的访问可以在更高级别上进行(例如,使用ioctl),尽管TOCTTOU问题可能会降低粒度。

4.7 其他钩子

LSM提供了另外两组钩子:模块钩子和一组顶层系统钩子。模块钩子可用于控制创建、初始化和删除内核模块的内核操作。系统钩子可用于控制系统操作,如设置系统主机名、访问输入/输出端口和配置进程记帐。现有的Linux内核使用能力检查对这些操作中的许多操作提供了一些控制,但是这些检查只提供了不同操作之间的粗粒度区别,而不提供任何参数信息。

5 测试和功能

第5.1节调查了迄今为止为LSM创建的模块。第5.2节描述了我们对LSM的性能测试。虽然我们已经通过引导和运行LSM内核对其进行了测试,但我们还没有进行系统测试。然而,LSM社区的其他成员[45]已经开发了系统的LSM正确性测试程序。

5.1 模块

LSM只提供了实施增强访问控制策略的机制。因此,正是LSM模块实现了特定的策略,并且对于证明框架的功能性至关重要。下面简要介绍几个LSM模块:

  • SELinux Flask灵活访问控制架构的Linux实现,以及支持类型强制、基于角色的访问控制和可选的多级安全性的示例安全服务器。SELinux最初作为内核补丁实现,然后作为使用LSM的安全模块重新实现。SELinux可用于将进程限制在最低权限,保护进程和数据的完整性和机密性,以及支持应用程序安全需要。SELinux的通用性和全面性帮助推动了对LSM的需求。
  • DTE Linux 为Linux开发的域和类型强制的实现。像SELinux一样,DTE Linux最初是作为一个内核补丁实现的,然后被改编到LSM。加载该模块后,类型可以被签名为对象,域可以被签名为进程。DTE策略限制域之间以及从域到类型的访问。DTE Linux项目也为LSM的设计和实现提供了有用的输入。
  • LSM port of Openwall kernel patch Openwall内核补丁的LSM端口Open wall内核补丁提供了一组安全特性来保护系统免受常见攻击,例如缓冲区溢出和临时文件争用。一个支持Openwall补丁子集的模块正在开发中。例如,加载此模块后,受害程序将不被允许跟踪恶意符号链接。
  • POSIX.1e功能逻辑已经存在于Linux内核中,但是LSM内核补丁将这个逻辑清晰地分离到一个安全模块中。这种改变允许不需要这种功能的用户从他们的内核中省略它,并且它允许功能逻辑的开发更加独立于主内核。

5.2 性能开销

与标准的Linux内核相比,LSM框架的开销最小。用于对这一开销进行基准测试的LSM ker- nel包括POSIX.1e功能安全模块,以便在具有内置功能支持的未修改Linux内核和具有功能模块的LSM ker- nel之间提供公平的比较。

LSM框架旨在支持复杂的访问控制模型。这种模型产生的开销是LSM框架开销和实际策略执行开销的组合。策略实施不在LSM框架的范围内,但是增强的访问控制模块的性能影响仍然令人感兴趣。SELinux模块进行了基准测试,并与启用了网络过滤器的标准Linux内核进行了比较,以展示第5.2.3节中的模块性能示例。

过程测试,时间以秒为单位,越小越好:

表2:LMBench微基准测试,4处理器机器

5.2.1 微基准:LMBench

我们使用LMBench进行微基准标记。LM- Bench是专门为测量核心内核系统调用和工具(如文件访问、上下文切换和内存访问)的性能而开发的。LM- Bench在Linux内核的这些核心设施中建立和保持出色的性能方面特别有效。

表3: LMBench微基准测试,1台处理器机器

我们将标准的Linux 2.5.15内核与2.5.15内核应用了LSM补丁程序,并加载了去故障功能模块,在4处理器700 MHz奔腾至强计算机上运行,该计算机具有1 GB内存和超宽SCSI磁盘,结果如表2所示。大多数情况下,性能损失在实验噪声范围内。在某些情况下,LSM ker- nel的性能实际上超过了标准内核,我们将其归因于实验错误(通常是缓存冲突异常)。表2中AF Unix 18%的性能提升是不正常的,但是我们尚未发现测试问题。

表4: Linux Kernel构建微基准,单位为秒

最坏情况下,select()的开销为5.1%,open/close为2.7%,文件删除为3.1%。打开、关闭和删除结果是意料之中的,因为内核在路径名解析过程中会反复检查文件名每个元素的权限,从而放大了这些LSM钩子的开销。select()的性能损失是一个突出的优化机会,第5.2.3节中的mac- robenchmark实验证实了这一点。

使用UP内核运行同一台机器的类似结果如表3所示。人们还应该记住,这些是微基准数字;有关综合应用程序级影响,请参见第5.2.2节和第5.2.3节。

5.2.2 宏基准:内核编译

我们的第一个宏基准是广泛使用的内核编译基准,测量构建Linux内核的时间。我们使用SMP和UP内核在4处理器SMP机器(四个700 MHz至强处理器、1 GB内存、超宽SCSI磁盘)上运行了该测试。

单处理器测试执行命令时间make -j2 bzImage,4处理器测试执行命令时间make -j8 bzImage,结果如表4所示。结果是LSM补丁的开销基本为零,最坏的情况是0.3%。

5.2.3 宏基准:Webstone

使用Webstone,我们对一个典型的服务器应用程序——网络服务器——的开销进行了基准测试。我们收集的数据显示了加载了SELinux模块的基本LSM内核和LSM内核的开销。SELinux模块使用基于Netfilter的钩子,因此所有三个内核都编译了Netfilter支持,并且都基于2.5.7 Linux内核。

表5: UP Webstone将LSM与标准内核进行比较的结果。

表6: SMP Webstone将LSM与标准内核进行比较的结果。

标准内核是用网络过滤器支持编译的。LSM内核的编译支持基于网络过滤器的钩子,并使用默认的超级用户逻辑。SELinux内核的编译支持SELinux和基于网络过滤器的钩子。SELinux模块也与功能模块堆叠在一起,这是典型的SELinux配置。我们在具有384MB RAM的双550MHz Celeron上运行了这些测试。网卡是一个32位33MHzPCI总线上的千兆网络设备GA302T。网络服务器是Apache 1.3.22-0.6(最新的Red Hat 6.2)。

网络过滤器是这里的一个关键问题。在表5和表6的LSM基准中观察到的5-7%的开销比我们希望的要大。一个由LSM和网络过滤器组成的单独实验显示了更理想的1-2%的性能开销,但没有网络过滤器LSM钩子。这与第5.2.1节中观察到的最差情况下5%的TCP选择开销相一致,并确定网络过滤器LSM钩子对于优化至关重要。

表7中的UP基准测试数据显示SELinux连接速率增加了大约16%的开销,我们发现吞吐量也有类似的开销。表8中的SMP基准数据显示了大约21%的连接速率开销,我们在吞吐量中发现了类似的开销。SMP测试的更大开销可能是由于锁定问题。请注意,这些开销率是特定于SELinux模块(一个特别流行的模块)的,其他模块的性能成本会有所不同。

表7: UP Webstone将SELinux与标准kernel进行比较的结果。

表8: SMP Webstone将SELinux与标准kernel进行比较的结果。

6 讨论

既然LSM开始是为了满足其他独立项目的需求,那么可以理解的是,结果产生了一些突变属性。

许多安全模型需要某种方式将安全属性与系统对象相关联。因此,LSM将安全字段附加到许多内部内核对象上,以便模块可以附加并在以后引用与这些对象相关联的安全属性。

还希望持久地将安全属性绑定到文件。要无缝地做到这一点,需要扩展属性文件系统支持,这使得安全属性能够绑定到磁盘上的文件。然而,支持扩展属性是一个复杂的问题,既需要支持文件系统中的扩展属性,又需要支持Linux内核的VFS中的扩展属性层。LSM协调所有VFS扩展属性功能,如创建、列出和删除扩展属性。然而,扩展属性支持对于Linux内核来说是新的,并不是所有的文件系统都支持它。当文件系统缺少扩展属性支持时,需要持久扩展属性的模块可以使用元文件。

在尝试为安全性增强提供可插拔接口时,考虑将所有安全策略决策完全模块化是很有诱惑力的,也就是说,将所有涉及访问控制的内核逻辑移出内核,放到默认模块中。除了简单的模块一致性之外,这种方法还有显著的好处:特别是,它可以更容易地提供权威的钩子,而不是限制性的钩子,这反过来又可以支持更广泛的模块(参见第3节)。

然而,出于务实的原因,我们选择不模块化所有的安全决策。当前的Linux访问控制决策在内核中没有很好地隔离;它们与其他错误检查和转换逻辑混合在一起。因此,对Linux内核进行修补以删除所有访问控制逻辑将是高度侵入性的。实现这样的改变几乎肯定会带来安全漏洞,这对于将LSM引入更大的Linux社区来说不是一个好办法。

因此,我们推迟了所有访问控制逻辑的完全模块化。当前的LSM实现了侵入性小得多的限制性钩子,为最初引入Linux社区提供了一个最小侵入性的补丁。一旦LSM很好地建立起来,我们可能会重新考虑这个决定,并提出一个更激进的模块化架构。

最后,在设计LSM接口时,我们隐约意识到LSM构成了一个API,因此必须向程序员呈现一个逻辑一致的视图。LSM接口不仅构成了我们打算支持的模块所需的一组钩子,而且还构成了这些钩子的逻辑扩展,使得接口是规则的。在可能的情况下,特例被一般化,这样它们就不再特殊了。

7 相关工作

第7.1节描述了LSM环境下可扩展框架的一般领域,第7.2节描述了与通用访问控制框架相关的工作。

7.1 可扩展内核研究

在过去的20年里,对可扩展系统进行了大量的操作系统研究。遵循微内核的基本思想(寻求将内核中的大部分东西组件化),人们付出了巨大的努力来构建更多可以以各种方式扩展的单片内核:

  • Exokernel实际上只是微内核概念的逻辑扩展。基础内核没有提供物理设备的抽象,而是留给需要这些设备的应用程序。
  • SPIN允许将模块装入机柜,同时提供各种安全特性[7]。模块将被编写在Modula- 3中,它强制进行强类型检查,从而防止模块在其自己的数据结构之外行为不检。SPIN“磁盘轴”也受到时间限制,因此它们无法抢占CPU。抽象地说,主轴将注册为“ex- tend”或“specialize”内核事件,并将被添加到事件处理链中,这与通常处理中断的方式非常相似。
  • SCOUT旨在促进信息的连续流动(例如音频或视频流),并允许编解码器阶段组成适当组件的管道(或图形)。
  • Synthetix试图允许应用程序根据他们的临时需求来专门化操作系统。“特殊化”意味着相对于“准不变量”的优化:暂时成立,但最终变成假的属性。在某些情况下,准不变量是从应用程序行为中推断出来的,例如一个进程打开一个文件,导致一个专门的read()系统调用,该调用针对特定的进程和文件进行了优化。在其他情况下,使用声明性语言为内核指定了准不变量。

所有这些扩展设施都提供了某种形式的安全,以限制扩展可能对系统其余部分造成的潜在损害。 例如,这些安全属性可能允许多媒体应用程序扩展内核以支持更好的服务质量,同时限制多媒体扩展,以便它不会意外地破坏操作系统。 在内核扩展中对这种安全性的需求被不稳定的Microsoft Windows系统的现象所证实,据称这些系统之所以不稳定,部分原因是由于运行在内核空间中的糟糕的第三方设备驱动程序。

相比之下,LSM对模块没有任何限制,模块(通常)是用C语言编写的,可以完全、非类型化地访问内核的地址空间。唯一的“限制”是钩子大部分都是“限制性”的,这使得在应该拒绝访问时更难错误地授予访问权限。相反,LSM主要依赖程序员技能(模块需要用心编写内核代码)和根权限(只有根可以加载模块)。

应该注意的是,LSM可以逃脱这个薄弱的模块安全策略,正是因为LSM模块旨在执行安全策略。与服务质量等更通用的内核扩展不同,该系统完全受安全策略的支配。一个允许加载LSM模块的管理员已经决定相信模块提供者是善意的,并且擅长编程,因为安全策略引擎中的错误可能会带来灾难性的后果。对LSM模块的进一步健全性检查是多余的。

还需要注意的是,这是Linux模块的传统观点:将模块加载到内核中是有特权的,这是有原因的,在编写和选择内核模块时应该小心。LSM模块开发人员被告诫要特别小心的创建模块。LSM模块不仅在所有内核代码的完全授权下运行,而且特别值得信赖,可以正确实施安全策略。建议第三方审查LSM模块的源代码。

最后,我们注意到,与另一个大型模块化接口:VFS(虚拟文件系统)相比,LSM对Linux内核的干扰要小得多。很久以前,人们就认识到在Linux中支持多文件系统的必要性,因此构建了丰富的基础设施。内核的VFS层抽象了大多数文件系统的特性,这样内核的其他部分就可以访问文件系统,而无需知道正在使用什么类型的文件系统。有传闻说,VFS层是一个很难调试的函数指针的嵌套。这一困难可以部分解释为什么Linux社区希望LSM接口尽可能少地介入。

7.2 通用访问控制框架

提供高度通用的访问控制框架的挑战已经在通用访问控制框架(GFAC)和Flask体系结构中探讨过。RSBAC和SELinux项目已经将这两种架构实现为Linux kernel的补丁。美杜莎Medusa项目开发了自己的通用访问控制框架,并在Linux中实现。域和类型实施(DTE)提供了对可配置安全策略的支持,并且也在Linux中实现。

像这些以前的项目一样,LSM试图为Linux内核中的访问控制提供一般支持。然而,LSM的目标与这些项目不同,在LSM框架中产生了相应的差异。特别是,强调对基本Linux内核的最小影响、功能逻辑的分离,以及支持安全功能作为内核模块的需要,使LSM与之前的项目有所不同。

此外,由于LSM寻求支持广泛的现有Linux安全项目,它不能强加特定的访问控制架构,如Flask或GFAC或特定的模型,如DTE。为了提供最大的灵活性,LSM简单地将内核抽象和操作暴露给安全模块,允许各个模块实现它们想要的架构或模型。同样,由于不同的项目使用明显不同的方法将安全属性与文件相关联,LSM将文件标记支持完全交给了该模块。对于像SELinux或RSBAC这样的系统,这种方法引入了一个新的间接层次,这样即使是一般的访问控制架构和文件标记支持也将被封装在模块中,而不是直接集成到内核中。

8 结论

Linux内核支持模式位的经典UNIX安全策略,以及部分实现POSIX.1e草案“功能”标准,这在许多情况下是不够的。开源代码和广泛流行的结合使Linux成为增强安全项目的流行目标。因为有许多强大的安全增强功能可用,这看起来可行,但对于那些不能或不愿意部署自定义内核的用户来说,这是一个巨大的门槛。

Linux安全模块(LSM)项目的存在是为了通过提供一个标准的可加载模块接口来增强安全性,从而缓解这一进入壁垒。我们介绍了LSM接口的动机、设计和实现。LSM提供了一个足够丰富的接口来支持各种各样的安全模块,同时对Linux源代码的干扰最小,对Linux内核的性能开销最小。几个强大的安全模块已经为LSM做好了准备。

LSM目前被实现为标准Linux内核的补丁。正在为2.4稳定系列和2.5开发系列的最新版本维护补丁。LSM项目的目标是将该补丁作为2.5开发系列,并最终进入大多数Linux发行版。

9 可获得

LSM框架是作为Linux内核的补丁来维护的。源代码可从http://lsm.immunix.org免费获得。


---煤油灯科技victorlamp.com翻译整理---

完整附件下载:Linux Security Modules General Security Support for the Linux Kerne.pdf

你可能也喜欢这些文章

科技互联网,科技,资讯,动态,洞察,量子,计算,AI,人工智能,机器人,区块链,Web3,分布式,操作系统,OS,芯片,视频,深度,论文