关于 SELinux 的宽泛介绍

尚未完工。但鉴于总是要查 SELinux 的笔记,所以决定先行放出。

访问控制

Linux 操作系统上有两种访问控制:自主访问控制(Discretionary Access Control,DAC)强制访问控制(Mandatory Access Control,MAC)。讨论两者的异同之前,需要明确几个概念:

  • 用户(user):人(碳基高等灵长类生物)
  • 主体(subject):OS 中以某用户身份执行的进程
  • 客体(object):OS 中的各种资源(如文件、sockets、设备等)

DAC 的策略是由资源的所有者来决定他人对该资源的访问权限。标准 Linux 安全是一种 DAC:文件的所有者可以对文件的读、写、执行权限进行设定;其他用户或进程要操作该文件,则需要基于所有者的设定进行鉴权。总的来说,DAC 将对资源的访问控制依托于资源所有者用户自身的审慎和理性上。

DAC 的这套权限控制有两个缺陷。首先,人自身也会犯错,也是有局限性的。其次,系统中实际运行的是程序,而“相信用户”和“相信该用户的程序”还是有区别的。例如,用户 A 给了用户 B 一个自己信任的程序 P,由于 B 信任 A,于是 B 就信任 P,然而有可能 A 和 B 都不知道 P 是有问题的。这还是出于 A 仅有过失而无恶意的情况。还有一种涉及恶意的场景:假设用户 U 可读写一个机密的客体 O,而用户 U’ 本身无权访问 O 却想要去访问,那么用户 U’ 可以先制作如下程序:

11. 创建客体 O'
22. 赋予 U 写 O' 的权限
33. 赋予 U' 读 O' 的权限
44. 将 O 的内容拷贝至 O'

随后,将该程序包装成用户 U 乐见的模样(如游戏、音乐、图片等),诱使用户 U 去执行。这样一来,用户 U’ 就(通过客体 O’)访问到了客体 O 的内容。这样的程序也被称为特洛伊木马(Trojan Horse)

而基于 MAC 的理念——信息和资源属于一个组织而非创造者个体,资源的访问权限就应该是由该组织集中制定的一整套完整的策略来定义,组织内外的所有人对资源的访问都要遵从这套策略。MAC 有多种方案,常见的有类型增强(Type Enforcement, TE)多级安全(Multi-Level Security, MLS)。这两者在 SELinux 上都有实现。

SELinux 为 MAC 的一种实现,Linux Kernel 上的其他实现还包括 AppArmorSmackTOMOYO 等。不过据作者所知,名气最大,使用最广泛的还要数 SELinux。

SELinux 架构

SELinux 的 LSM 架构:

SELinux 的 LSM 架构

位于用户空间的客体管理器:

客体管理器

来自《SELinux by Example: Using Security Enhanced Linux》 的 Section 3.1 和 3.2。

更详细的架构图,见《SELinux Notebook》 的 Figure 2.2。

安全上下文(Security Context)

所有操作系统的访问控制都是以与客体和主体相关联的某种访问控制属性为基础的。在 SELinux 中,访问控制属性被称为安全上下文。所有客体(文件、进程间通讯通道、套接字、网络主机等)和主体(进程)都有与其关联的安全上下文。一个安全上下文由四部分组成:用户、角色、类型和等级,格式如下:

1User:Role:Type:Sensitivity[:Category][  -   Sensitivity [:Category]]
2---------------▼--------------------▼-------▼---------------------▼
3               |       level        |   -   |       level         |
4                                    | range |

安全上下文中的用户和角色标识符除了对强制有一点约束之外对类型强制访问控制策略没什么影响。

  • 对于进程,用户和角色标识符显得更有意义,因为它们是用于控制类型和用户标识符的联合体,这样就会与 Linux 用户账号关联起来;
  • 对于客体,用户和角色标识符几乎很少使用。为了规范管理,客体的角色常常是 object_r,客体的用户往往是创建客体的进程的用户标识符,它们在访问控制上没什么作用。

标准 Linux 安全中的用户 ID 和安全上下文中的用户标识符之间的区别: 就技术而论,它们是正交标识符,分别用于标准的和安全增强的访问控制机制,这两者之间的任一相互关联都是通过登陆进程按照规范严格规定的,而不是通过 SELinux 策略直接强制实施的。

类型强制(Type Enforcement,TE)访问控制

在 SELinux 中,所有访问都必须明确授权。不管进程的用户/组 ID 是什么,SELinux 默认不允许任何访问。因此在 SELinux 中,没有默认的超级用户(如标准 Linux 中的 root 用户),要通过使用 allow 规则授予某个主体类型(或称)对某个客体类型的访问权限:

1allow user_t bin_t : file {read execute getattr};

多级/多类安全(Multi-Level/Multi-Category Security, MLS/MCS)

MLS/MCS 特性是可选的,在类型强制(TE)的基础上增加额外的安全校验,会使用到安全上下文中的 LEVEL 字段,其中包含 Sensitivity 和 Category 信息。从相关资料来看,目前已经比较少提 MCS 了,基本上用 MLS 同时指代两者。

可参考:

参考资料


各类 SELinux 策略文件及相互关系

各 SELinux 策略文件转化路径

(上图出自 Sven Vermeulen 的博客 Where does CIL play in the SELinux system? ,其中图片链接已断,图片文件是用网页时光机 找回来的。特此说明。)

一套 SELinux 策略会涉及到多种类型的文件。这些文件会被分模块编译,最终汇聚形成一个二进制的策略文件。模块们和其构成的策略文件会共同组织成一个 Policy Store。这个说法在 GentooFedora 的 Wiki 以及 The SELinux Notebook 中有被提到,可以理解为一套套制作好的策略集。一个系统中可以存在多份 Policy Store,由 /etc/selinux/config 中的 SELINUXTYPE 指定,方便管理员在不同策略套之间进行切换。如今比较常见的有 targetedmls 等。

当前系统正在使用的某个策略模块文件位于 /var/lib/selinux/targeted/active/modules/100/<module_name>/hll1,将 hll 通过 bzip2 解压缩后便可获得 .pp 文件。

不同策略文件之间具体的转换方法:

  • 生成 .te 文件

    1grep postdrop /var/log/audit/audit.log | audit2allow -M postfixlocal
    
  • .te to mod

    1checkmodule -M -m -o postfixlocal.mod postfixlocal.te
    
  • mod to .pp

    1semodule_package -o postfixlocal.pp -m postfixlocal.mod
    
  • .pp to cil

    1/usr/libexec/selinux/hll/pp XXX.pp XXX.cil
    

反其道而行,各策略文件的解码方法:

  • extract cil file

    1semodule -c -E acct
    
  • extract pp file

    1semodule -H -E acct
    
  • pp to mod

    1semodule_unpackage postgreylocal.pp postgreylocal.mod
    
  • disassemble pp/mod to human-readable

    1sedismod postgreylocal.pp
    2sedismod postgreylocal.mod
    

是否加载进内核?

.fc 文件

.fc 文件不会被加载进内核,而是会由 semanage 转换为 file_contexts{,.homedirs} 文件,保存在 /etc/selinux/targeted/contexts/files/ 目录下。restoreconmatchpathcon 为了确定某个路径上的文件的标签,会按以下顺序查询这些文件中的相关记录:

  1. file_contexts.local(由系统管理员在运行时通过 semanage 生成)
  2. file_contexts.homedirs
  3. file_contexts

Check 4.7.3. How File Context is Determined of SELinux User’s and Administrator’s Guide to get more relevant information.

te and other policy files

However, .te files will be compiled (eventually) into the binary policy.31 or policy.32 bulk, which is loaded into the kernel through /load under selinuxfs’s mount point when running load_policy. Use strace load_policy to see the detailed process.

Reference

https://serverfault.com/a/321422

https://plautrba.fedorapeople.org/how-to-compare-two-selinux-modules.html

https://fedoraproject.org/wiki/Changes/SELinuxPolicyStoreMigration

https://selinuxproject.org/page/ConfigurationFiles

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-working_with_selinux-selinux_contexts_labeling_files#how-file-context-is-determined

man semodule(8)

Out-of-date, or imcompatible with us:

https://wiki.gentoo.org/wiki/SELinux/Tutorials/How_is_the_policy_provided_and_loaded

Policy Loading During Boot

49.7.3. THE ROLE OF POLICY IN THE BOOT PROCESS , Deployment Guide of RHEL 5.

Chapter 49. Security and SELinux , Deployment Guide of RHEL 5.

  • After kernel is initialized, policies are loaded by init process.
  • init checks /proc/filesystems to see if kernel supports selinuxfs.
  • init needs to re-execute itself (remember the code of Android’s init? the second round/function?)

userland tools

1# ausearch
2ausearch -m AVC,USER_AVC,SELINUX_ERR -ts today # 10:09, recent, ...
3
4# setroubleshoot related
5journalctl -t setroubleshoot --since=[time]
6
7# sealert
8sealert -l [message_ID]

https://access.redhat.com/articles/2191331

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/troubleshooting-problems-related-to-selinux_using-selinux

1sesearch --all -s test_cap_userns_t | less

https://pagure.io/freeipa/issue/8513

1semanage module -l

https://serverfault.com/a/521082

1semodule -v -i test_policy/test_policy.pp test_mlsconstrain.cil test_overlay_defaultrange.cil test_userfaultfd.cil

Reference

实现细节

https://www.imperialviolet.org/2009/07/14/selinux.html

(建议从 4.1 版本入手,代码相对简单,没太多复杂的数据结构。sidtab 基本能看懂。)


  1. 这里的 HLL 是指 High Level Language,即便 .pp 文件与高级语言毫不相干。根据 Sven Vermeulen 的博客 ,如此命名的原因是原本期待未来会出现多种安全框架,这些框架会带有各自的用于制定安全策略的高级语言,并且还有将这些高级语言转换成 CIL 文件的编译器/引擎。 ↩︎


一个由动态库对其他动态库的依赖导致的问题
CVE-2021-43057 分析