Linux 安全 - LSM机制

文章目录

  • 前言
  • 一、LSM起源
  • 二、LSM简介
    • 2.1 MAC
    • 2.2 LSM特征
  • 三、Major and Minor LSMs
    • 3.1 Major LSMs
    • 3.2 Minor LSMs
    • 3.3 BPF LSM
  • 四、LSM 框架
  • 五、LSM Capabilities Module
  • 六、LSM hooks 说明
  • 参考资料

前言

在这两篇文章中介绍了 Linux 安全机制 Credentials :

Linux 安全 - SUID机制
Linux 安全 - Capabilities机制

接下来这篇文章介绍 Linux 中LSM安全凭证机制。

Linux系统也会有大量的软件漏洞,通过有效使用访问控制是减轻软件漏洞的重要方法之一。
Linux安全模块(LSM)通过提供一个通用的安全策略模块框架来解决这个问题。

一、LSM起源

在2001年3月,美国国家安全局(NSA)在第2.5版Linux内核峰会上介绍了安全增强型Linux(SELinux)。SELinux是在Linux内核中实现灵活和细粒度强制访问控制的一种方法,最初作为独立的内核补丁实现。其他几个安全项目(例如RSBAC、Medusa)也为Linux内核开发了灵活的访问控制架构,而且各种项目还开发了特定的Linux访问控制模型(例如LIDS、DTE、SubDomain)。每个项目都开发和维护自己的内核补丁,以满足其安全需求。

SELinux是由NSA开发的最著名和广泛使用的安全项目之一。它最初以独立的内核补丁形式存在,与Linux主线内核是分离的。这种方法使得SELinux能够引入和集成其特定的安全功能。

作为对NSA演讲的回应,Linus Torvalds发表了一系列讲话,描述了他愿意考虑纳入主流Linux内核的安全框架。

Linus Torvalds的建议旨在为Linux内核引入一个通用的安全框架。该框架将提供一组安全钩子,允许对内核对象的操作进行控制。这样一来,开发人员可以编写可加载内核模块,利用这些安全钩子来实现所需的访问控制和安全策略。

此外,Linus还提到在内核数据结构中增加一组不透明的安全字段,用于维护对象的安全属性。这些字段可以存储与安全相关的信息,例如对象的标签或访问权限。通过在数据结构中引入这些字段,可以实现对对象的细粒度访问控制,并将安全属性与对象关联起来。

Linus还提到了将Linux能力代码迁移到上述安全框架的可能性。Linux能力是一种轻量级访问控制机制,用于授予进程特定的权限,而不是完全依赖于用户的权限。将能力代码移到模块中可以更好地组织和管理安全功能,并为开发人员提供更大的灵活性。

Linux安全模块(LSM)项目是由WireX启动的,目的是开发这样一个框架。LSM是由几个安全项目(包括Immunix、SELinux、SGI和Janus)以及Greg Kroah Hartman和James Morris等几个人共同开发的,旨在开发实现该框架的Linux内核补丁。这项工作于2003年12月被纳入主流。接下来概述了 framework 和 capabilities 安全模块。

二、LSM简介

LSM ,全称为 Linux Security Modules , LSM 其实是一个在内核各个安全模块的基础上提出(抽象出)的轻量级安全访问控制框架。该框架只是提供一个支持安全模块的接口,本身不能增强系统安全性,具体的工作交给各安全模块来做,比如SELinux、AppArmor等。

LSM框架提供了一种模块化架构,该架构提供了内置在内核中的“钩子”,并允许安装安全模块,从而加强了访问控制。

Linux 安全 - LSM机制_第1张图片

LSM 在 Linux 内核安全相关的关键路径上预置了一批 hook 点,从而实现了内核和安全模块的解耦,使不同的安全模块可以自由地在内核中加载/卸载,无需修改原有的内核代码就可以加入安全检查功能。

LSM通过允许安全模块插入到内核中的关键点上,实施细粒度的访问控制,从而提高了系统的安全性。安全模块可以根据自身的安全策略、规则和需求来扩展和定制访问控制机制,以适应不同的应用场景和安全要求。

2.1 MAC

Linux安全模块(LSM)是集成到内核中的框架,用于提供实现强制访问控制(Mandatory access control - MAC)模块所需的组件,而无需每次更改内核源代码。

Linux Mandatory Access Control (MAC) 是 Linux 系统中的一种访问控制机制,用于强制执行系统中的安全策略。MAC 通过对系统资源(如文件、进程、网络通信等)的访问进行限制,确保只有经过授权的实体可以执行特定操作。

MAC 提供了比传统的基于用户和组的访问控制更为细粒度的控制。它基于安全策略和标签,为每个资源分配安全上下文,并在访问请求发生时对这些上下文进行检查。这种访问控制是强制性的,意味着即使用户具有特定权限,也必须符合安全策略才能访问资源。

2.2 LSM特征

LSM是直接编译到内核中的代码,使用LSM框架。它的目的是通过在内核执行系统调用之前插入检查来保护系统的安全性。

LSM框架旨在允许安全模块在检查点上插入钩子,以便在每个操作中检查当前执行的安全策略是否允许该操作。

安全模块将钩子插入到这些检查点上,以对每个操作进行检查,判断当前强制执行的安全策略是否允许该操作。

LSM框架可以阻止对重要的内核对象(例如文件、索引节点、任务结构、凭证和进程间通信对象等)的访问。

通过LSM框架,可以实现对内核操作的细粒度访问控制,并确保系统的安全性。不同的安全模块可以通过LSM框架来扩展和定制内核安全策略,从而满足特定的安全需求。常见的LSM模块包括SELinux(Security-Enhanced Linux)、AppArmor、Smack等,它们可以提供额外的安全保护层,限制对敏感资源的访问,并增强系统的安全性。

三、Major and Minor LSMs

3.1 Major LSMs

主要的Linux安全模块(LSM)是可从用户空间加载可配置策略的强制访问控制(MAC)实现。它们提供了更高级的访问控制和安全执行功能。

过去,由于每个LSM都假定对受保护的内核对象中嵌入的安全上下文指针和安全标识符具有独占访问权,因此一次只能使用一个LSM。这个限制意味着多个LSM可能会干扰彼此的安全策略。因此,Linux内核引入了LSM堆叠的概念,其中一个LSM可以堆叠在另一个LSM之上,提供额外的安全功能。然而,一次只能激活和执行一个LSM的策略。

以下是一些主要的LSM示例:

(1)SELinux(Security-Enhanced Linux):SELinux是最知名且广泛使用的LSM之一。它提供了一个灵活的MAC框架,基于安全标签和策略实施细粒度访问控制。SELinux使用一组规则和策略来限制进程的权限并限制其对资源的访问。

(2)SMACK(Simplified Mandatory Access Control Kernel):SMACK是一种简化的MAC LSM,注重简单性和易用性。它使用文件标签来实施访问控制策略,并根据这些标签保护资源。

(3)AppArmor:AppArmor是另一个常用的LSM,它使用基于路径的安全配置文件来实施访问控制。它允许管理员为各个应用程序或进程定义特定的安全策略,限制其功能和对资源的访问。

(4)TOMOYO Linux:TOMOYO Linux注重易用性,强调“参考策略”的原则。它使用基于域和路径的策略来控制访问并保护系统。

Ubuntu、OpenSUSE、SUSE、Debian等发行版中默认AppArmor,以及RHEL、Fedora、CentOS等发行版中默认SELinux。

这些主要的LSM提供了不同的MAC和访问控制方法,允许管理员选择最适合其安全要求和策略的LSM。每个LSM都具有其自己的功能、配置选项和管理工具,有助于保护Linux内核并保护系统资源。

Major LSMs一次只能使用一个LSM。

3.2 Minor LSMs

次要的Linux安全模块(LSM)实现特定的安全功能,并堆叠在主要的LSM之上,通常需要较少的安全上下文。

次要的LSM通常只包含用于启用/禁用选项的标志,而不是像主要LSM那样具有从用户空间加载的策略文件,作为系统引导的一部分。

以下是一些次要的LSM示例:

(1)Yama:Yama是一个次要的LSM,提供了额外的安全功能,如禁止调试进程、禁止进程追踪和限制进程能够发送的信号等。

(2)loadPin:loadPin是一个次要的LSM,用于限制动态加载内核模块的能力。它允许仅允许特定的进程或用户加载内核模块,从而增加系统的安全性。

(3)SetSafeID:SetSafeID是一个次要的LSM,用于限制进程的有效用户ID (EUID) 和有效组ID (EGID) 的设置。它可以防止恶意进程提升权限或进行其他潜在的安全攻击。

(4)Lockdown:Lockdown是一个次要的LSM,用于增强系统的安全性,限制对关键功能的访问。它可以阻止对/sysfs文件系统的写入、禁止加载内核模块和修改内核命令行参数等。

这些次要的LSM提供了特定的安全功能,可以通过堆叠在主要的LSM之上来增强系统的安全性。它们通常具有较少的安全上下文,并且只包含用于启用/禁用选项的标志,而不需要从用户空间加载策略文件。

Minor LSMs一次可以使用多个LSM。

$ cat /sys/kernel/security/lsm 
lockdown,capability,landlock,yama,apparmor

3.3 BPF LSM

Linux 于 5.7内核版本引入 BPF LSM,目前用于提供审计(Audit)、性能(Perf)等可观测数据功能的内核基础设施与访问控制执行(即LSMs)是分离的。增强审计信息需要对审计系统、其策略语言和用户空间组件进行内核修改。此外,基于新增的可观测数据构建MAC(强制访问控制)策略需要对各种LSM和它们各自的策略语言进行修改。本次发布引入了一种新的LSM,允许将BPF程序附加到LSM钩子上,从而实现了统一和动态的(不需要重新编译内核)审计和MAC策略。

这种新的LSM允许将BPF程序与LSM钩子关联,从而实现了审计和访问控制策略的统一。它使得可观测数据能够无缝集成到访问控制决策和策略执行中。

在3.1说到,对于AppArmor、SELinux和Smack等安全模块,它们在初始化时会将自己设置为独占模块(LSM_FLAG_EXCLUSIVE标志)。这意味着系统中不能同时注册具有LSM_FLAG_EXCLUSIVE标志的两个安全模块。因此,不能同时使用以下任意两个(SELinux、AppArmor、Smack)安全模块。

而BPF-LSM是可叠加的LSM,因此可以与AppArmor或SELinux同时使用。

BPF-LSM允许和AppArmor或SELinux一起使用,它实现了一种叠加机制,允许多个安全模块同时加载和使用。BPF-LSM特别用于启用BPF(Berkeley Packet Filter)程序进行安全强制,并且它可以与其他安全模块(如AppArmor或SELinux)共存。

因此,虽然由于其独占性质,不能同时注册任意两个SELinux、AppArmor和Smack安全模块,但可以和AppArmor或SELinux一起使用BPF-LSM,以提供额外的安全功能。

四、LSM 框架

LSM(Linux Security Modules)框架提供了一个通用的内核框架,用于支持安全模块。尤其是,LSM框架主要专注于支持访问控制模块,尽管未来的发展可能会解决其他安全需求,如沙盒化。LSM框架本身并不提供任何额外的安全性,它只提供了支持安全模块的基础设施。LSM框架是可选的,需要启用CONFIG_SECURITY选项。

LSM框架在内核数据结构中包括安全字段,并在关键点的内核代码中调用钩子函数来管理安全字段和执行访问控制。它还添加了用于注册安全模块的函数。接口/sys/kernel/security/lsm报告了一个以逗号分隔的安全模块列表,这些模块在系统上是活动的。

$ cat /sys/kernel/security/lsm 
lockdown,capability,landlock,yama,apparmor

LSM安全字段是以void*指针的形式实现的。这些数据被称为“blob”,可以由框架或使用它的各个安全模块进行管理。通常由框架管理多个安全模块使用的安全blob。
(1)对于进程和程序执行的安全信息,安全字段包含在struct task_struct和struct cred中。

struct task_struct {
	......
#ifdef CONFIG_SECURITY
	/* Used by LSM modules for access restriction: */
	void				*security;
#endif
	......
}
struct cred {
	.....
#ifdef CONFIG_SECURITY
	void		*security;	/* subjective LSM security */
#endif
	......
}

(2)对于文件系统安全信息,struct super_block中包含一个安全字段。

struct super_block {
	......
#ifdef CONFIG_SECURITY
	void                    *s_security;
#endif
	......
}

(3)对于管道、文件和套接字的安全信息,安全字段包含在struct inode和struct file中。

struct inode {
	......
#ifdef CONFIG_SECURITY
	void			*i_security;
#endif
	......
}
struct file {
	......
#ifdef CONFIG_SECURITY
	void			*f_security;
#endif
	......
}

(4)对于System V IPC的安全信息,安全字段被添加到struct kern_ipc_perm和struct msg_msg中。

此外,struct msg_msg、struct msg_queue和struct shmid_kernel的定义被移动到头文件(根据情况包括/linux/msg.h和include/linux/shm.h)中,以允许安全模块使用这些定义。

对于数据包和网络设备的安全信息,结构体struct sk_buff和struct scm_cookie中添加了安全字段。与其他安全模块数据不同,这里使用的数据是32位整数。安全模块需要将这些值映射或以其他方式与实际的安全属性关联起来。

(5)在struct sk_buff中,安全字段用于存储与数据包相关的安全信息。这些信息可以是源地址、目标地址、协议类型、端口号等与网络安全相关的属性。

(6)在struct scm_cookie中,安全字段用于存储与套接字控制消息(SCM)相关的安全信息。SCM用于在进程之间传递控制信息,如文件描述符、权限等。安全字段可以用于标识和验证传递的SCM是否符合安全策略。

LSM钩子以lists的形式进行维护。每个钩子都有一个对应的list,并且按照CONFIG_LSM指定的顺序调用这些钩子。每个钩子的详细文档都包含在include/linux/lsm_hooks.h头文件中。

在LSM框架中,钩子函数用于在关键的内核代码点进行安全检查和访问控制。每个钩子函数都与特定的安全操作相关联,如文件访问、进程创建、网络通信等。通过注册钩子函数,安全模块可以介入到这些操作中,并根据自身的逻辑进行安全决策和控制。

通过维护钩子函数的列表,LSM框架确保安全模块按照指定的顺序被调用。这是为了满足安全策略中可能存在的依赖和优先级要求。列表中的每个钩子函数都有特定的功能和用途,其详细文档可以在include/linux/lsm_hooks.h头文件中找到。

这种钩子机制使得安全模块能够以可插拔的方式集成到内核中,通过注册和实现特定的钩子函数,实现对访问控制和安全决策的定制化操作。

LSM框架提供了一种接近一般安全模块堆叠的机制。它定义了security_add_hooks()函数,每个安全模块通过该函数传递一个struct security_hooks_list结构,将其添加到相应的列表中。然而,LSM框架本身并没有提供一种机制来移除已注册的钩子。

/*
 * Security module hook list structure.
 * For use with generic list macros for common operations.
 */
struct security_hook_list {
	struct hlist_node		list;
	struct hlist_head		*head;
	union security_list_options	hook;
	char				*lsm;
} __randomize_layout;

/**
 * security_add_hooks - Add a modules hooks to the hook lists.
 * @hooks: the hooks to add
 * @count: the number of hooks to add
 * @lsm: the name of the security module
 *
 * Each LSM has to register its hooks with the infrastructure.
 */
void __init security_add_hooks(struct security_hook_list *hooks, int count,
				char *lsm)
{
	int i;

	for (i = 0; i < count; i++) {
		hooks[i].lsm = lsm;
		hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
	}

	.....
	
}

虽然SELinux安全模块曾经实现了一种自我移除的方式,但该功能已被弃用。这意味着一旦安全模块被注册到LSM框架中,目前的LSM框架没有提供一种标准的机制来动态地移除已注册的安全模块或其钩子函数。

这意味着一旦安全模块被加载并注册到LSM框架中,它们将一直存在,除非重新编译内核或重新配置并重新启动系统。因此,安全模块的加载和卸载通常需要在系统启动期间进行,并且在运行时不太可能动态地添加或删除安全模块。

钩子可以分为两个主要类别:用于管理安全字段的钩子和用于执行访问控制的钩子。第一类钩子的示例包括security_inode_alloc()和security_inode_free()。这些钩子用于为inode对象分配和释放安全结构。第二类钩子的示例是security_inode_permission()钩子。该钩子在访问一个inode时检查权限。

第一类钩子用于处理与安全字段的分配、释放和管理相关的操作。在这些钩子中,安全模块可以执行与内核数据结构相关的初始化、清理和管理工作。例如,在inode对象分配时,安全模块可以为其分配相应的安全结构,并在释放时释放相应的资源。

第二类钩子用于执行访问控制操作,检查对内核对象的访问权限。在这些钩子中,安全模块可以根据自身的策略和规则,对访问请求进行安全决策。例如,在访问一个inode对象时,安全模块可以检查请求者是否具有足够的权限来执行所请求的操作,并根据需要允许或拒绝访问。

五、LSM Capabilities Module

LSM Capabilities Module 是将POSIX.1e功能逻辑以安全模块的形式维护在security/commoncap.c文件中。Capabilities Module使用lsm_info描述的order字段来标识它作为第一个注册的安全模块。与其他模块不同,The capabilities security module不使用通用的安全blob。这是基于历史原因以及对开销、复杂性和性能的考虑。

Capabilities Module以特定的方式管理和实施POSIX.1e功能集。POSIX.1e功能是一种细粒度的权限控制机制,允许进程在不具有完全根特权的情况下执行特定的操作。例如,一个具有特定功能的进程可以执行网络配置或文件系统操作,而无需以完全特权的身份运行。

Capabilities Module通过实现特定的功能检查函数,如cap_inode_permission()和cap_task_prctl(),来处理与功能相关的安全检查和访问控制。这些函数在关键的内核代码点被调用,以确保进程的功能操作符合定义的权限。

由于Capabilities Module不使用通用的安全blob,它可以避免一些开销和复杂性。此外,Capabilities Module还关注性能问题,以确保功能检查的效率。

这种设计决策是基于历史和性能考虑的结果,以提供一种轻量级的功能实施机制。Capabilities Module作为LSM框架的一部分,为内核的安全性和访问控制提供了POSIX.1e功能的支持。

六、LSM hooks 说明

大多数由LSM提供的钩子需要返回一个整数值(有些返回void):
(1)返回"0"相当于授权通过
(2)返回ENOMEM表示内存不足
(3)返回EACCESS表示根据安全策略拒绝访问
(4)返回EPERM表示需要特权才能执行此操作

LSM提供的钩子可以分为两种不同类型:
(1)基于对象的钩子(Object based hooks):这些钩子与内核对象相关,例如C结构,如inodes(索引节点)、文件或套接字。访问授权将基于这些对象属性进行判断和控制。
(2)基于路径的钩子(Path based hooks):这些钩子与文件路径相关。它们用于处理与文件路径相关的安全检查和访问控制。

基于对象的钩子主要关注特定内核对象的访问控制,而基于路径的钩子则更侧重于处理文件路径级别的访问控制。

这些钩子为LSM提供了灵活性和可扩展性,使安全模块能够介入到内核操作的关键点上,并根据自身的安全策略和规则进行安全决策。通过返回适当的整数值,安全模块可以指示授权通过、拒绝访问或者其他错误情况,以便内核在相应的操作中采取适当的措施。

参考资料

Linux 5.4.18

https://static.lwn.net/kerneldoc/security/lsm.html

你可能感兴趣的:(系统安全,linux,c语言,系统安全)