传统文件权限只管「谁能碰这个文件」,管不了「谁在什么场景下能碰」。SELinux 补的就是这一层:它给每个进程、文件、目录、端口贴上标签,只按标签对标签的规则放行。这篇讲清 SELinux 的上下文结构、三种模式、模式切换的代价,以及标签被破坏后的几种修复手段,最后用一个真实故障收尾。文中命令名与选项均注明英文原意,完整清单见文末《附:命令英文全称速查表》。
本文概要:
| 项目 | 内容 |
|---|---|
| 文章主题 | SELinux 的类型强制机制:上下文五字段 → 三种模式 → 模式切换 → 标签损坏修复 → 策略布尔值 → 故障实例 |
| 所属类别 | Linux 系统管理 → 网络安全 → SELinux 强制访问控制 |
| 知识关键字 | SELinux · context · type · targeted · enforcing · permissive · disabled · getenforce · setenforce · /etc/selinux/config · restorecon · semanage fcontext · /.autorelabel · getsebool · setsebool · boolean |
概念图给出「进程标签 → 策略比对 → 资源标签」的主链路。概要表里的关键字分别落在:上下文与类型在第二章,模式与切换在第三章,标签修复手段在第四章,布尔值开关在第五章,故障实例在第六章。
一、SELinux 解决什么问题
1.1 文件权限管不到的地方
文件权限控制了哪些用户或用户组可以访问哪些文件,但没有限定访问文件的方式。
一个典型场景:结构化数据文件本该只允许特定程序写入,但只要有写权限,其他编辑器同样能打开并修改它,改坏了也没人拦。文件权限只管谁可以读、写、执行,管不了「怎么用」。
1.2 SELinux 的思路
Security Enhanced Linux(安全增强的 Linux)是一个额外的系统安全层。它的主要目标是防止已遭泄露的系统服务访问用户数据。
设想 Web 服务器进程被攻破,攻击者拿到进程权限,也就是 apache 用户与 apache 组的权限。此时它对文档根目录 /var/www/html 有读取权限,还能访问 /tmp、/var/tmp 以及其他任何全局可写的目录------这就是横向扩散的起点。
SELinux 的做法是强制执行一组访问规则,明确定义进程与资源之间允许的操作。每个进程、文件、目录和端口都带专门的安全标签,称为 SELinux 上下文(context) 。SELinux 策略用上下文来判断某个进程能否访问某个文件、目录或端口;除非有显式规则授予权限,默认情况下策略不允许任何交互。
这套机制叫类型强制(T ype E nforcement)。RHEL / CentOS 默认策略是 targeted,只对关键网络服务做强制,其余进程不受限。
二、SELinux 上下文
2.1 上下文的五个字段

上下文的完整写法是 用户:角色:类型:敏感度,用冒号分隔,跟在文件路径前面:
text
unconfined_u : object_r : httpd_sys_content_t : s0 /var/www/html/file2
用户 角色 类型 敏感度 文件
| 字段 | 含义 | 关注度 |
|---|---|---|
| SELinux 用户 | 身份标识,与 Linux 用户不是一回事 | 低 |
| 角色(Role) | 固定为 object_r 时对象是文件 |
低 |
| 类型(Type) | targeted 策略真正用于判权的字段 | 高 |
| 敏感度(Level) | 从 s0 起,只有多级安全(MLS)策略才细分 | 低 |
类型名通常以 _t 结尾,这是判断上下文是否「对」的关键。几个常见标签:
| 对象 | 上下文类型 |
|---|---|
| Web 服务器守护进程 | httpd_exec_t |
| Web 服务器网页文件 | httpd_sys_content_t |
| Web 服务器监听端口 | http_port_t |
/tmp、/var/tmp |
tmp_t |
2.2 默认策略下的放行与拒绝
- SELinux 默认策略允许
apache进程访问/var/www/html下的文件,以及其他带httpd_sys_content_t上下文的目录; - 策略禁止它访问标签不匹配的目录;
- 在 SELinux 保护下,
apache进程不允许访问/tmp与/var/tmp,因为这两处的标签是tmp_t,与默认策略不匹配。
这就是上一节那个扩散场景被堵住的原理:即使进程权限足够,标签不匹配就过不去。
2.3 查看与设置上下文
许多处理文件的命令都带 -Z 选项,用于显示或设置 SELinux 上下文。
-Z 用法速查表
| 写法 | 作用 | 说明(英文原意) |
|---|---|---|
ps -Z |
查看进程的上下文 | 常配合 -C 进程名 精确筛选 |
ls -Z |
查看文件或目录的上下文 | --- |
cp -Z |
复制时把目标文件设为默认上下文 | Z = SELinux context |
mkdir -Z |
新建目录时设为默认上下文 | --- |
id -Z |
查看当前登录用户的上下文 | --- |
bash
# 只看 sshd 进程的上下文,输出既有受限域也有不受限域
[root@zhb-m1 ~]# ps -C sshd -Z
LABEL PID TTY TIME CMD
system_u:system_r:sshd_t:s0-s0:c0.c1023 951 ? 00:00:00 sshd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 1276 ? 00:00:00 sshd
system_u:system_r:sshd_t:s0-s0:c0.c1023 1261 ? 00:00:00 sshd
# 查看家目录的标签
[root@zhb-m1 ~]# ls -Z /home
unconfined_u:object_r:user_home_dir_t:s0 zhb
sshd_t 是受限域,unconfined_t 是不受限域------同一个进程名出现两种标签,说明 SELinux 是按「进程实例 + 策略」贴标签的,不是按程序名一刀切。
三、SELinux 的三种模式

| 模式 | 行为 | 用途 |
|---|---|---|
| enforcing(强制) | 强制执行访问控制规则,规则没明确允许就拒绝访问,并写入日志 | 默认模式,生产环境 |
| permissive(宽容) | 加载策略并处于活动状态,但不强制执行,只记录访问违规 | 测试与排错 |
| disabled(禁用) | 完全关闭 SELinux,不拒绝、不记录 | 排障临时手段 |
⚠️ 注意 :enforcing 与 permissive 之间可以随时在线互切,不需要重启 ;但只要跨到 disabled,或从 disabled 切回来,都必须重启系统。生产环境不要长期停在 permissive,它只记录不拦截,等于没有防护。
3.1 查看与临时切换
模式命令速查表
| 写法 | 作用 | 说明(英文原意) |
|---|---|---|
getenforce |
查看当前模式 | get enforcement |
sestatus |
查看更详细的状态 | 含策略名、配置文件设定值、挂载点 |
setenforce 0 / setenforce Permissive |
临时切到宽容模式 | 只改当前运行状态 |
setenforce 1 / setenforce Enforcing |
临时切回强制模式 | --- |
bash
[root@zhb-m1 ~]# getenforce
Enforcing
# 临时切到宽容模式
[root@zhb-m1 ~]# setenforce 0
# 等价写法
[root@zhb-m1 ~]# setenforce Permissive
# 切回强制模式
[root@zhb-m1 ~]# setenforce 1
3.2 永久修改默认模式
改配置文件 /etc/selinux/config:
bash
[root@zhb-m1 ~]# vim /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted
| 配置项 | 取值 | 含义 |
|---|---|---|
SELINUX |
enforcing / permissive / disabled |
全局默认模式 |
SELINUXTYPE |
targeted / mls |
加载哪种策略;targeted 只约束关键服务,mls 对所有进程细分域 |
3.3 用内核启动参数指定模式
在 GRUB 引导时向内核传参,可在系统启动阶段就定下模式:
| 参数 | 含义 |
|---|---|
enforcing=1 |
强制模式 |
enforcing=0 |
许可(宽容)模式 |
selinux=0 |
彻底禁用 SELinux |
selinux=1 |
启用 SELinux;已写 enforcing= 时可省略 |
⚠️ 注意 :
/etc/selinux/config里写SELINUX=disabled的做法在新内核上已被标记为弃用 ------内核钩子仍会执行,只是不加载策略、不做拒绝,行为与真正关闭并不完全一致。要彻底关掉,应使用内核参数selinux=0,它会覆盖配置文件里的设定。
四、标签损坏怎么修
SELinux 的绝大多数「怪问题」都源于标签不对。官方手册给出的判断信号是:日志里出现 file_t,通常意味着文件系统标签出了严重问题。
⚠️ 注意 :
chcon改的是文件当前的标签,重打标签(relabel)或restorecon后会被还原 。要长期生效,必须先用semanage fcontext把规则写进策略,再用restorecon应用。
标签修复用法速查表
| 写法 | 作用 | 说明(英文原意) |
|---|---|---|
restorecon -Rv /var/www/ |
按策略恢复默认标签 | -R ecursive 递归,-verbose 显示改动 |
restorecon -nvr /home |
只检查、不改动 | -no-change 干跑模式 |
restorecon -F /path |
强制重设完整上下文 | Force,连用户、角色、范围一起改 |
semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?" |
为目录树登记默认标签 | add 新增记录 |
semanage fcontext -l |
列出全部上下文规则 | --- |
semanage fcontext -m -t ... /path |
修改已有记录 | modify |
semanage fcontext -d -t ... /path |
删除记录 | delete |
chcon -t httpd_sys_content_t /var/www/html/a.html |
临时改标签 | ch ange context,relabel 后丢失 |
touch /.autorelabel 后重启 |
全盘重新打标签 | 开关文件,重启时生效 |
场景一:把自定义目录纳入 Web 目录的规则
bash
# 先登记规则,再应用到现有文件
[root@zhb-m1 ~]# semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
[root@zhb-m1 ~]# restorecon -Rv /web
场景二:只是想看看哪些文件的标签不对
bash
[root@zhb-m1 ~]# restorecon -nvr /home
场景三:整机标签疑似错乱
创建开关文件后重启,SELinux 会在启动时自动重新标记整个文件系统:
bash
[root@zhb-m1 ~]# touch /.autorelabel
[root@zhb-m1 ~]# reboot
⚠️ 注意:重新标记是一次全盘扫描,耗时长取决于文件数量与大小,重启后要留足时间让它跑完,中途断电中断会留下更乱的标签。
场景四:服务读不到自己的配置与数据文件
同一个坑换一种服务就会再踩一次:把文件挪个位置、或新建一个数据目录,文件权限(chmod / chown)看着都没问题,服务就是读不到。原因是每种服务在策略里都注册了自己的类型,路径一变,标签就不再匹配。
| 服务 | 它要读的东西 | 应有的类型 |
|---|---|---|
| Web(Apache / Nginx) | 站点目录与网页文件 | httpd_sys_content_t |
| DNS(BIND / named) | 区域文件 | named_zone_t |
| 数据库(MariaDB) | 数据目录 | mysqld_db_t |
排查分两步走------先看当前标签,再看策略期望它是什么:
bash
# 1. 看文件现在是什么标签
[root@zhb-m1 ~]# ls -Z /var/named/*.zone
unconfined_u:object_r:var_t:s0 /var/named/zhb.cloud.zone
# 2. 查策略里这个路径应该是什么标签
[root@zhb-m1 ~]# semanage fcontext -l | grep named_zone_t
/var/named(/.*)? all files system_u:object_r:named_zone_t:s0
两步一对比,var_t 与 named_zone_t 的差别就是服务读不到文件的原因。修法与场景一相同 :用 semanage fcontext 登记、再 restorecon 应用;服务自己的默认路径(如 /var/named)本来就登记好了,把文件放回原位往往比改标签更省事。
五、策略布尔值:不关 SELinux 也能放开单个功能
标签修对了、服务还是起不来,剩下的高频原因就是策略布尔值(boolean)没打开。布尔值是策略预留的开关,用来在不改标签、不关 SELinux 的前提下,放开某一类被策略写死的操作。比如允许 httpd 读取家目录、连数据库,或允许 ftp 写文件。
标签管的是「哪个进程能碰哪个资源」,布尔值管的是「这条已被允许/禁止的规则要不要打开」。两者互补:标签错就修标签,规则本就在策略里、只是默认关着,就改布尔值。
bash
# 列出与 httpd 相关的全部布尔值及当前取值
[root@zhb-m1 ~]# getsebool -a | grep httpd
# 查询单个布尔值
[root@zhb-m1 ~]# getsebool httpd_enable_homedirs
# 临时打开,重启后失效
[root@zhb-m1 ~]# setsebool httpd_enable_homedirs on
# 永久打开
[root@zhb-m1 ~]# setsebool -P httpd_enable_homedirs on
布尔值用法速查表
| 写法 | 作用 | 说明(英文原意) |
|---|---|---|
getsebool -a |
列出全部布尔值及其取值 | get s ELinux bool ean,常配合 grep 服务名 缩小范围 |
getsebool 名称 |
查询单个布尔值 | 只看 on / off |
setsebool 名称 on |
临时打开 | 只改内存里的当前值,重启回到策略默认 |
setsebool -P 名称 on |
永久打开 | -Persistent,写入策略,重启仍生效 |
semanage boolean -l |
列出布尔值及用途说明 | 比 getsebool 多一列描述,用来判断该不该动这一项 |
semanage boolean -m --on 名称 |
修改布尔值 | m odify,与 setsebool -P 等效 |
⚠️ 注意 :
setsebool不加-P只对当前运行状态生效,重启就还原------这是排错时最容易被忽略的一步:测试时用不带-P的写法确认有效,再补上-P固化。反过来,不确定某个开关的作用时,先用semanage boolean -l看描述,不要凭名字猜。
六、故障实例:破解 root 密码后登录失败
在 SELinux 为 enforcing 的环境里破解 root 密码,过程中会替换或修改 /etc/shadow。如果破解完成后没有执行 touch /.autorelabel,重启后用正确的密码登录会失败。
原因是被修改过的 /etc/shadow 文件标签已经不匹配策略,用户验证程序读不到它------密码(内容)明明是对的,文件(标签)却过不去。这就是「文件权限没问题、SELinux 拦住」的典型表现。
处理办法是在系统启动时给内核补参数:
text
selinux=1 enforcing=0
先进宽容模式让系统起得来、能登录,再修标签:
bash
# 恢复 /etc/shadow 的默认标签
[root@zhb-m1 ~]# restorecon -v /etc/shadow
# 或整机重新打标签后重启
[root@zhb-m1 ~]# touch /.autorelabel
[root@zhb-m1 ~]# reboot
处理完把模式改回 enforcing,并核对一遍结果:
bash
[root@zhb-m1 ~]# getenforce
Enforcing
[root@zhb-m1 ~]# ls -Z /etc/shadow
system_u:object_r:shadow_t:s0 /etc/shadow
附:命令英文全称速查表
| 命令 / 缩写 | 英文全称 / 原意 | 作用 |
|---|---|---|
SELinux |
Security Enh anced Linux | 内核级强制访问控制安全模块 |
getenforce |
get enforcement | 查看当前模式 |
setenforce |
set enforcement | 临时切换模式 |
sestatus |
S ELinux status | 查看详细状态 |
restorecon |
restore context | 按策略恢复文件默认标签 |
chcon |
ch ange context | 临时修改文件标签 |
semanage |
s ELinux manage | 管理策略元素(含上下文规则与布尔值) |
fcontext |
f ile context | 文件上下文规则 |
getsebool |
get s ELinux boolean | 查询策略布尔值 |
setsebool |
set s ELinux boolean | 修改策略布尔值(-P 永久) |
boolean |
boolean | 策略布尔值,策略里的开关 |
ps |
p rocess status | 查看进程(-Z 看上下文) |
context |
context | 安全上下文,即安全标签 |
type |
type | 类型,targeted 策略的判权字段 |
enforcing |
enforcing | 强制模式,按策略拦截 |
permissive |
permissive | 宽容模式,只记录不拦截 |
targeted |
targeted | 默认策略,只约束关键网络服务 |
MLS |
M ulti-L evel Security | 多级安全策略 |
relabel |
relabel | 重新打标签 |
📚 参考资料(官方文档 · 中英双语)
英文原版(man7.org)
中文版
其余手册在服务器上直接查,不依赖网络、不占链接数:
bash
man 8 selinux # SELinux 总体说明与文件标签
man 8 getenforce # 查看当前模式
man 8 setenforce # 临时切换模式
man 8 restorecon # 恢复默认上下文
man 8 semanage-fcontext # 登记文件上下文规则
man 8 semanage-boolean # 列出与修改策略布尔值
man 8 booleans # 布尔值机制说明与 getsebool / setsebool
总结 :SELinux 的判权依据只有一条------进程的标签能不能碰目标的标签 ,文件权限在这一层之外。排错时先
getenforce看模式、ls -Z/ps -Z看标签:标签不对就用restorecon恢复、用semanage fcontext登记规则;标签没问题、规则却被默认关着,就去查布尔值,用setsebool -P开门。别把关掉 SELinux 当长期方案。觉得有用可以收藏,遇到过 SELinux 拦服务的情况欢迎在评论区聊聊排查过程。
