SELinux 管的是带标签的访问:进程域、文件、端口等。本文有两条线——和 Web 后台权限管理怎么类比、哪里不能硬套;以及如何读懂 user:role:type:level,日常真正盯哪一段。顺带讲清 SELinux 初始化:进程如何拿到初始域,以及和「换域」的差别。
叙事默认按 Fedora Targeted 工作站;严格策略只作对照一句。排障故事见 Cursor Remote SSH 与 SELinux。域从哪来、exec 如何换域,见续篇 SELinux 的 type_transition。
适用读者
读本文前需要这些底子,否则后面的类比、初始化和域会对不上号。
- Linux 操作基础:会用终端;知道用户 / 文件权限(owner、group、other 或 ACL)。
- 对系统的理解:分得清用户态与内核;知道服务由谁拉起(如 systemd)、配置大致在哪、日志大致在哪;明白「发行版默认策略」(本文按 Fedora Targeted)和自己手改不是一回事。
- 对进程模型的理解:进程如何被创建(fork / exec);父子进程与可执行文件的关系;服务常以守护进程长期运行。后文的「初始域 / 换域」都挂在这条链上。
- 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 权限的类比
整篇对照钉在这里:后面「初始化」和「四段标签」都会回扣这张表。
能类比的部分:
- Type(第三段) ≈ Web 里的「身份 / 工种」(如
httpd_t、shadow_t) - 策略里的
allow规则 ≈ 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(含第三段域)的过程。常见两条路,都和域直接相关:
- 用户会话初始化(Linux 登录触发):SSH、GDM、
login;su/sudo有时也会改会话 context。PAM + SELinux 把 Linux 用户映射到 SELinux User、默认 Role,并给出该 Role 允许的初始域(如unconfined_t/user_t)。 - 服务 / 程序域初始化(exec 或 systemd 拉起):新进程不简单继承父进程域,而是按 type_transition,从可执行文件的
*_exec_t落到服务域*_t(如httpd_exec_t→httpd_t)。这是多数 confined 服务「初始域」的来源。
和域的关联可以记成:
- 初始化结束时,进程一定已经落在某个域里(第三段已定)
- 之后若再
exec触发 transition,叫换域,不是「又登录一次」 - Role 管「允许进哪些域」;初始化 / 换域时要过这道闸;真正干活后看的是当前域
| 会话初始化 | 服务 / 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。
- 文件例:
system_u:object_r:httpd_sys_content_t:s0 - 进程例:
system_u:system_r:httpd_t:s0
会话侧的 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 也通过。
小结
- SELinux 是内核 MAC;DAC 通过后再审;未明确 allow 则拒绝
- 域 = 进程主体的 Type;Role = 能进哪些域的档位(细节见「名词解释」)
- TE = Type Enforcement,用 Type / 域判能不能操作;这才是日常权限表
- AVC = 审计日志里的裁决记录(常见
avc: denied),用scontext/tcontext对上主客体 Type - SELinux 初始化 = 进程拿到起始 context(含初始域);会话走登录映射,服务多走 type_transition;之后再 transition 叫换域
- Web role = 权限包;SELinux Role = 域档位——初始化/换域时管「能进哪些 Type」,日常读写主要不靠它
- 主体几乎是进程域;日常盯 Type;前两段多为背景;第四段看场景
概念清楚之后,真实机器上的 AVC 长什么样,可以对照 Cursor 连不上家里 PC:Fedora 与 SELinux。想继续挖「服务域怎么来、transition 与 allow 如何配合」,读 SELinux 的 type_transition。