传统文件权限只管「谁能碰这个文件」,管不了「谁在什么场景下能碰」。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 策略用上下文来判断某个进程能否访问某个文件、目录或端口;除非有显式规则授予权限,默认情况下策略不允许任何交互。
这套机制叫类型强制(TypeEnforcement)。RHEL / CentOS 默认策略是targeted,只对关键网络服务做强制,其余进程不受限。
二、SELinux 上下文
2.1 上下文的五个字段
上下文的完整写法是用户:角色:类型:敏感度,用冒号分隔,跟在文件路径前面:
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 | 查看当前登录用户的上下文 | — |
# 只看 sshd 进程的上下文,输出既有受限域也有不受限域[root@zhb-m1 ~]# ps -C sshd -ZLABEL PID TTY TIME CMD system_u:system_r:sshd_t:s0-s0:c0.c1023951? 00:00:00 sshd unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c10231276? 00:00:00 sshd system_u:system_r:sshd_t:s0-s0:c0.c10231261? 00:00:00 sshd# 查看家目录的标签[root@zhb-m1 ~]# ls -Z /homeunconfined_u:object_r:user_home_dir_t:s0 zhbsshd_t是受限域,unconfined_t是不受限域——同一个进程名出现两种标签,说明 SELinux 是按「进程实例 + 策略」贴标签的,不是按程序名一刀切。
三、SELinux 的三种模式
| 模式 | 行为 | 用途 |
|---|---|---|
| enforcing(强制) | 强制执行访问控制规则,规则没明确允许就拒绝访问,并写入日志 | 默认模式,生产环境 |
| permissive(宽容) | 加载策略并处于活动状态,但不强制执行,只记录访问违规 | 测试与排错 |
| disabled(禁用) | 完全关闭 SELinux,不拒绝、不记录 | 排障临时手段 |
⚠️注意:enforcing 与 permissive 之间可以随时在线互切,不需要重启;但只要跨到 disabled,或从 disabled 切回来,都必须重启系统。生产环境不要长期停在 permissive,它只记录不拦截,等于没有防护。
3.1 查看与临时切换
模式命令速查表
| 写法 | 作用 | 说明(英文原意) |
|---|---|---|
getenforce | 查看当前模式 | getenforcement |
sestatus | 查看更详细的状态 | 含策略名、配置文件设定值、挂载点 |
setenforce 0/setenforce Permissive | 临时切到宽容模式 | 只改当前运行状态 |
setenforce 1/setenforce Enforcing | 临时切回强制模式 | — |
[root@zhb-m1 ~]# getenforceEnforcing# 临时切到宽容模式[root@zhb-m1 ~]# setenforce 0# 等价写法[root@zhb-m1 ~]# setenforce Permissive# 切回强制模式[root@zhb-m1 ~]# setenforce 13.2 永久修改默认模式
改配置文件/etc/selinux/config:
[root@zhb-m1 ~]# vim /etc/selinux/configSELINUX=enforcingSELINUXTYPE=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/ | 按策略恢复默认标签 | -Recursive 递归,-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 | 临时改标签 | changecontext,relabel 后丢失 |
touch /.autorelabel后重启 | 全盘重新打标签 | 开关文件,重启时生效 |
场景一:把自定义目录纳入 Web 目录的规则
# 先登记规则,再应用到现有文件[root@zhb-m1 ~]# semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"[root@zhb-m1 ~]# restorecon -Rv /web场景二:只是想看看哪些文件的标签不对
[root@zhb-m1 ~]# restorecon -nvr /home场景三:整机标签疑似错乱
创建开关文件后重启,SELinux 会在启动时自动重新标记整个文件系统:
[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 |
排查分两步走——先看当前标签,再看策略期望它是什么:
# 1. 看文件现在是什么标签[root@zhb-m1 ~]# ls -Z /var/named/*.zoneunconfined_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 写文件。
标签管的是「哪个进程能碰哪个资源」,布尔值管的是「这条已被允许/禁止的规则要不要打开」。两者互补:标签错就修标签,规则本就在策略里、只是默认关着,就改布尔值。
# 列出与 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 | 列出全部布尔值及其取值 | getsELinuxboolean,常配合grep 服务名缩小范围 |
getsebool 名称 | 查询单个布尔值 | 只看on/off |
setsebool 名称 on | 临时打开 | 只改内存里的当前值,重启回到策略默认 |
setsebool -P 名称 on | 永久打开 | -Persistent,写入策略,重启仍生效 |
semanage boolean -l | 列出布尔值及用途说明 | 比getsebool多一列描述,用来判断该不该动这一项 |
semanage boolean -m --on 名称 | 修改布尔值 | modify,与setsebool -P等效 |
⚠️注意:
setsebool不加-P只对当前运行状态生效,重启就还原——这是排错时最容易被忽略的一步:测试时用不带-P的写法确认有效,再补上-P固化。反过来,不确定某个开关的作用时,先用semanage boolean -l看描述,不要凭名字猜。
六、故障实例:破解 root 密码后登录失败
在 SELinux 为 enforcing 的环境里破解 root 密码,过程中会替换或修改/etc/shadow。如果破解完成后没有执行touch /.autorelabel,重启后用正确的密码登录会失败。
原因是被修改过的/etc/shadow文件标签已经不匹配策略,用户验证程序读不到它——密码(内容)明明是对的,文件(标签)却过不去。这就是「文件权限没问题、SELinux 拦住」的典型表现。
处理办法是在系统启动时给内核补参数:
selinux=1 enforcing=0先进宽容模式让系统起得来、能登录,再修标签:
# 恢复 /etc/shadow 的默认标签[root@zhb-m1 ~]# restorecon -v /etc/shadow# 或整机重新打标签后重启[root@zhb-m1 ~]# touch /.autorelabel[root@zhb-m1 ~]# reboot处理完把模式改回 enforcing,并核对一遍结果:
[root@zhb-m1 ~]# getenforceEnforcing[root@zhb-m1 ~]# ls -Z /etc/shadowsystem_u:object_r:shadow_t:s0 /etc/shadow附:命令英文全称速查表
| 命令 / 缩写 | 英文全称 / 原意 | 作用 |
|---|---|---|
SELinux | SecurityEnhancedLinux | 内核级强制访问控制安全模块 |
getenforce | getenforcement | 查看当前模式 |
setenforce | setenforcement | 临时切换模式 |
sestatus | SELinuxstatus | 查看详细状态 |
restorecon | restorecontext | 按策略恢复文件默认标签 |
chcon | changecontext | 临时修改文件标签 |
semanage | sELinuxmanage | 管理策略元素(含上下文规则与布尔值) |
fcontext | filecontext | 文件上下文规则 |
getsebool | getsELinuxboolean | 查询策略布尔值 |
setsebool | setsELinuxboolean | 修改策略布尔值(-P永久) |
boolean | boolean | 策略布尔值,策略里的开关 |
ps | processstatus | 查看进程(-Z看上下文) |
context | context | 安全上下文,即安全标签 |
type | type | 类型,targeted 策略的判权字段 |
enforcing | enforcing | 强制模式,按策略拦截 |
permissive | permissive | 宽容模式,只记录不拦截 |
targeted | targeted | 默认策略,只约束关键网络服务 |
MLS | Multi-LevelSecurity | 多级安全策略 |
relabel | relabel | 重新打标签 |
📚 参考资料(官方文档 · 中英双语)
英文原版(man7.org)
- selinux(8) 手册:模式、策略与文件标签
- booleans(8) 手册:策略布尔值的查询与修改
中文版
- 开启或关闭 SELinux(阿里云 ECS 文档)
其余手册在服务器上直接查,不依赖网络、不占链接数:
man8selinux# SELinux 总体说明与文件标签man8getenforce# 查看当前模式man8setenforce# 临时切换模式man8restorecon# 恢复默认上下文man8semanage-fcontext# 登记文件上下文规则man8semanage-boolean# 列出与修改策略布尔值man8booleans# 布尔值机制说明与 getsebool / setsebool总结:SELinux 的判权依据只有一条——进程的标签能不能碰目标的标签,文件权限在这一层之外。排错时先
getenforce看模式、ls -Z/ps -Z看标签:标签不对就用restorecon恢复、用semanage fcontext登记规则;标签没问题、规则却被默认关着,就去查布尔值,用setsebool -P开门。别把关掉 SELinux 当长期方案。觉得有用可以收藏,遇到过 SELinux 拦服务的情况欢迎在评论区聊聊排查过程。