SELinux 概念

发布于

SELinux 管的是带标签的访问:进程域、文件、端口等。本文有两条线——和 Web 后台权限管理怎么类比、哪里不能硬套;以及如何读懂 user:role:type:level,日常真正盯哪一段。顺带讲清 SELinux 初始化:进程如何拿到初始域,以及和「换域」的差别。

叙事默认按 Fedora Targeted 工作站;严格策略只作对照一句。排障故事见 Cursor Remote SSH 与 SELinux。域从哪来、exec 如何换域,见续篇 SELinux 的 type_transition。

适用读者

读本文前需要这些底子,否则后面的类比、初始化和域会对不上号。

  1. Linux 操作基础:会用终端;知道用户 / 文件权限(owner、group、other 或 ACL)。
  2. 对系统的理解:分得清用户态与内核;知道服务由谁拉起(如 systemd)、配置大致在哪、日志大致在哪;明白「发行版默认策略」(本文按 Fedora Targeted)和自己手改不是一回事。
  3. 对进程模型的理解:进程如何被创建(fork / exec);父子进程与可执行文件的关系;服务常以守护进程长期运行。后文的「初始域 / 换域」都挂在这条链上。
  4. Web 开发者的权限逻辑:做过后台权限就够——用户、角色(权限组)、资源、能否读写某操作;知道「先定身份,再查权限表」。

不要求写过 SELinux 策略,也不要求事先会排障。文中 「名词解释」 会说明 域 和 AVC(日志里常见的拒绝记录)。若以上都熟,读完名词解释后可以从「管什么」往下读。

名词解释

先钉两个后文会反复出现的词,再进正题。

域

域(domain)= 进程作为主体时的 Type(第三段)。

文件、端口的 Type 常叫客体类型;进程在发起操作,同一套 Type 习惯上叫「域」。例如 httpd_t:既是 Type,也是「httpd 进程所在的安全域」。说「进程在某个域里跑」,等于说「这个进程的 Type 是某某 _t」。

它和 SELinux Role(第二段) 不在同一层:

域(第三段 Type) Role(第二段)
是什么 进程「现在是哪种工种」 「这张工牌允许进哪些工种」
日常裁决 TE:allow 域 客体type:class perm 一般不直接判读文件
约束 谁能对谁做什么 哪个 Role 允许关联哪些域

运行时怎么看:ps -Z 里类似 system_u:system_r:httpd_t:s0,第三段 httpd_t 就是域。SELinux 初始化给出会话或服务进程的起始域;之后 exec / 服务启动时的 type_transition 是在换域(Role 常不变)。之后每次读写,主要按当前域做 TE;Role 多在初始化或换域时卡「能不能进这个域」。

AVC

AVC 常出现在审计日志里,是你和 SELinux「吵架」时最先看到的东西。

全称可以记成 Access Vector Cache 相关事件:内核做完 TE 裁决后,把「谁对谁做了什么、结果如何」记下来。口语里说的 AVC,多半指日志里的 avc: denied(偶尔也有 granted)。它通常落在 /var/log/audit/audit.log,也可用 ausearch -m avc 捞;Cockpit 的 SELinux 页本质也是在展示这类记录。

一条拒绝里最要紧的几项(名字因工具略有出入,意思不变):

字段 含义
scontext 主体完整标签(谁在动手,重点看域 / Type)
tcontext 客体完整标签(碰的是谁)
tclass 客体类别,如 file、tcp_socket
denied / comm 等 被拒的 permission,以及进程名等线索

读 AVC 就是在还原:哪个域想对哪个类型做哪个操作,策略里没有 allow,于是被拒。 能认字段、对上「域 / TE / 白名单」即可;audit2allow、boolean、改 file context 留给排障文,例如 Cursor Remote SSH 与 SELinux。

SELinux 管什么

进程(其 Type 又称域)、文件/目录、网络端口是最常见的三类;socket、IPC 等也会被标类型,本文不展开。它不是另起一套防火墙,而是在内核里强制规定:带某类标签的主体,对带某类标签的客体,能不能做某类操作。

默认模型是白名单:策略里没有明确 allow 的,就拒绝。不是「没写禁止就放行」;Enforcing 下未授权即 deny,日志里常见为 AVC(见「名词解释」)。

和 Web 权限的类比

整篇对照钉在这里:后面「初始化」和「四段标签」都会回扣这张表。

能类比的部分:

Role 一词撞名,不能硬套:

Web 管理系统的 role SELinux 的 Role(第二段)
本质 一组权限的打包,方便给用户批量分配策略 能进入哪些进程域的档位,不是那捆 allow
日常地位 权限模型的核心抽象 Targeted 工作站上常像背景板;文件几乎总是 object_r
真正像「权限组」的是 role 挂的那堆 permission 某个 domain type 被 allow 的整套能力(TE),不是 Role 字段

策略不等于角色。SELinux Role 不是 Web 的「权限组」。Web role 方便打包分配;SELinux 日常裁决看的是 Type + TE allow。严格用户映射(user_u / staff_u)时 Role 才会明显卡人——本文主场景可以当背景板,但名字要认清,否则四段标签会读懵。

SELinux 初始化

刚说清 Role / User 不是 Web 那套,接着讲它们和域何时被安上。核心问题只有一个:进程第一次带着哪个域开始跑?

SELinux 初始化,指的是主体拿到完整初始 context(含第三段域)的过程。常见两条路,都和域直接相关:

  1. 用户会话初始化(Linux 登录触发):SSH、GDM、login;su / sudo 有时也会改会话 context。PAM + SELinux 把 Linux 用户映射到 SELinux User、默认 Role,并给出该 Role 允许的初始域(如 unconfined_t / user_t)。
  2. 服务 / 程序域初始化(exec 或 systemd 拉起):新进程不简单继承父进程域,而是按 type_transition,从可执行文件的 *_exec_t 落到服务域 *_t(如 httpd_exec_t → httpd_t)。这是多数 confined 服务「初始域」的来源。

和域的关联可以记成:

会话初始化 服务 / exec 初始化
触发 用户登录系统 execve、systemd 拉服务等
主要定 User + Role + 会话初始域 新进程的 域(Type),常靠 type_transition
例子 SSH 后 unconfined_u:unconfined_r:unconfined_t:s0 nginx → system_u:system_r:httpd_t:s0

不要把任意贴标签都叫「初始化」的全部:文件按路径/继承得到客体 Type,是另一条线;本节说的是进程域从哪来。回扣上一节:初始化定的是「SELinux 身份档位 + 起始域」;Web 里给账号挂 role(权限包)不是同一件事。

为什么需要它

DAC(owner / group / other,以及 ACL)过了之后,root 或能力足够的进程几乎全能。被攻破的经常是以特权跑的服务;SELinux 用域隔离挡住「服务身份」的横向移动——就算进程是 root,httpd_t 也不能随便读 shadow_t。

弱密码、登录后乱搞只是次要例子,别把它理解成「主要防弱口令」。在 Targeted 下,管理员会话常常是 unconfined_*,日常运维几乎不被拦;真正被关住的是 confined 服务域。流程上:DAC 通过后,还要再过内核里的强制访问控制(MAC)。

两套审查流程

没有 SELinux 时,请求过完 DAC 就结束:

flowchart LR
  req[进程请求] --> dac[DAC检查]
  dac -->|拒绝| deny1[拒绝]
  dac -->|通过| allow1[允许]

开启 SELinux(Enforcing)时,DAC 通过后还要走类型强制;拒绝会留下 AVC:

flowchart LR
  req2[进程请求] --> dac2[DAC检查]
  dac2 -->|拒绝| deny2[拒绝]
  dac2 -->|通过| selinux[SELinux_TE]
  selinux -->|拒绝| avc[AVC_deny]
  selinux -->|通过| allow2[允许]

先 DAC,再 SELinux。Permissive 模式仍会记拒绝,但默认放行——本文默认按 Enforcing 理解。拒绝如何记进日志,见「名词解释」里的 AVC。

谁负责执行

裁决在内核 LSM(SELinux)里做。Nginx、sshd、systemd 都在用户态;systemd 是用户态根,负责拉起用户态进程,但不做最终 MAC 裁决。策略由用户态工具加载进内核,运行时由内核强制执行。

标签与主客体

文件、进程、端口在内核侧都有 security context(标签)。进程标签不是简单复制二进制文件的类型:可执行文件常见 *_exec_t;父进程 execve() 时,策略里的 type_transition 把新进程变成域类型 *_t(如 httpd_exec_t → httpd_t)。

主 / 客体是运行时角色:发起操作的是主体(几乎总是进程域);被操作的是客体(文件、端口、另一进程等)。同一 type 在一次访问里可以是主体,在另一次里是客体。

端口是客体(如 http_port_t),不是主体;入站网卡流量也不构成「网络主体」——后续动作的主体仍是处理连接的进程。

策略做什么

这里说的核心机制叫 TE(Type Enforcement,类型强制):规定哪些 type 对哪些 type、在哪个 object class 上、有哪些 permission。例如:

allow httpd_t httpd_sys_content_t:file read;

这才接近 Web 里的「权限表」,不是第二段 Role。日常绝大多数放行 / AVC deny 都是 TE 在裁决。发行版 Targeted 策略已经很全;日常运维多是改资源标签,很少改策略本身——操作细节留给后文。

四段标签

完整格式是 user:role:type:level。

会话侧的 User / Role / 初始域多在 SELinux 初始化时定下;文件侧头两段常常是 system_u:object_r。

第一段 User

这是 SELinux 用户,不是 /etc/passwd 里的账号。登录时 Linux 用户被映射进几个大框,常见有 system_u(服务 / 系统资源)、unconfined_u(管理员会话)、user_u(受限用户)。Targeted 工作站上日常关注度低。

第二段 Role

死资源几乎总是 object_r;活进程才是 system_r / unconfined_r / user_r。再次强调:它不等于 Web 的权限组。

Role 会参与,但参与的是另一道闸,不是每次读文件时先查「角色里挂了哪些权限」。

时机 Role 是否参与 在干什么
会话 / 服务初始化 是 定 User → 允许哪些 Role → 该 Role 能关联哪些初始域
日常 open / read / bind 基本不靠它 TE 看 Type:主体域对客体类型有没有 allow
切换角色 / 进入高权限域 是 限制当前 Role 能不能变成某种进程身份(如 user_r 进不了某些管理域)
文件标签上的 object_r 形式上有 标明「这是客体」,不是给文件挂权限包

初始化时:策略约束「这个 SELinux User 能用哪些 Role」,以及「这个 Role 能关联哪些 Type(域)」。进程落盘的初始 context 必须落在这些约束里,例如会话 unconfined_u:unconfined_r:unconfined_t:s0,或服务 system_u:system_r:httpd_t:s0。

访问裁决时:进程读文件,内核主要跑 TE(httpd_t 能不能读 shadow_t),一般不会像 Web 那样先展开 Role 里的权限列表。Targeted 下你若是 unconfined_r,档位很宽,所以会觉得第二段「没参与」——其实是几乎总是放行那一档,不是字段摆设。

真正卡人时多半是受限用户(user_r)或严格映射:就算 DAC 允许,也可能禁止 transition 到管理域。看文件标签时几乎不用盯这一段;排「能不能读某个文件」优先看第三段 Type。

第三段 Type

TE(Type Enforcement) 的核心字段:主体域、客体类型都看这里。进程侧的 Type 又称域(见「名词解释」)。日常几乎唯一要盯的一段;ls -Z / ps -Z 先看第三段。对应前面类比里最像 Web「身份」的那一维。

第四段 Level

MLS / MCS 敏感度与类别,写作 s0、s0:c1,c2 等。桌面 Targeted 常为 s0;容器隔离时 MCS 才关键。工作站日常关注度低。若启用了多级检查,通行条件是:TE 通过,并且 MLS/MCS 也通过。

小结

概念清楚之后,真实机器上的 AVC 长什么样,可以对照 Cursor 连不上家里 PC:Fedora 与 SELinux。想继续挖「服务域怎么来、transition 与 allow 如何配合」,读 SELinux 的 type_transition。

评论

可对整篇留言,或划选正文中的句子后评论该段。

登录后即可发表评论。

  • 还没有公开评论。
↑