Permissive 模式下 SELinux 不阻止操作只记录日志;若 httpd 被拒,实际可能是 Enforcing 模式、上下文错误、布尔值未启用或进程标签不匹配,需结合 audit.log、ps -eZ、semanage 和 restorecon 综合排查。

getenforce 返回 Permissive 但 SELinux 仍拒绝 httpd 访问?
Permissive 模式下 SELinux 不会真正阻止操作,只记录拒绝日志。如果你看到 httpd_t 被 denied,说明实际运行模式仍是 Enforcing,或者你误判了 getenforce 输出——它可能返回 Permissive,但某个域(如 httpd_t)被单独设为 enforcing(极少见),更常见的是你没刷新上下文或没看对日志源。
- 先确认真实模式:
getenforce输出必须是Enforcing才会触发 deny;若真是Permissive,avc: denied只会出现在/var/log/audit/audit.log或/var/log/messages中,不会阻断请求 - 检查是否在容器或 systemd 服务中运行:systemd 可能覆盖 SELinux 上下文,用
ps -eZ | grep httpd确认进程实际标签是否为system_u:system_r:httpd_t:s0 - 别只信终端输出——重启 httpd 后再跑
getenforce,避免旧 shell 缓存结果
检查 httpd 相关布尔值是否启用
即使 SELinux 是 Enforcing 模式,很多 httpd 行为受布尔值控制,比如访问 NFS、连接网络、读取用户家目录等。默认多数为 off,需手动开启。
- 列出所有与 httpd 相关的布尔值:
semanage boolean -l | grep httpd - 常用关键布尔值(按需启用):
-
httpd_can_network_connect:允许 httpd 发起外部 HTTP/HTTPS 请求(如 curl、file_get_contents) -
httpd_can_network_connect_db:允许连接 MySQL/PostgreSQL(非本地 socket 场景) -
httpd_read_user_content:允许读取~user/public_html -
httpd_enable_homedirs:启用用户家目录作为 Web 根(配合httpd_read_user_content)
-
- 启用示例:
setsebool -P httpd_can_network_connect on(-P持久化,否则重启后失效)
从 audit.log 提取真实拒绝原因并生成策略
光看 denied 日志不够,得定位具体被拒的资源类型(文件、端口、capability)、动作(read、write、name_connect)和上下文。直接靠布尔值“试错”效率低,应以日志为依据。
- 复现一次失败请求,然后执行:
ausearch -m avc -ts recent | audit2why(recent可换为时间如10 minutes ago) - 若输出含
Would be allowed by...,说明对应布尔值当前是 off,按提示启用即可 - 若提示
This is a generic policy module...或建议用audit2allow,说明需要自定义策略:ausearch -m avc -ts recent | audit2allow -M myhttpdsemodule -i myhttpd.pp
- 注意:不要无脑
audit2allow -a -M,它会合并所有 AVC,可能引入过度宽松规则
文件/目录上下文不匹配导致 denied
SELinux 拒绝常不是因为布尔值,而是文件本身没打对标签。例如把 PHP 文件放到 /var/www/html 外,或用 cp 复制时没带 -Z,导致 context 是 unconfined_u:object_r:user_home_t:s0 而非 system_u:object_r:httpd_sys_content_t:s0。
- 查文件上下文:
ls -Z /path/to/file - 修复 Web 内容目录标准上下文:
semanage fcontext -a -t httpd_sys_content_t "/srv/myapp(/.*)?",再运行restorecon -Rv /srv/myapp - 临时测试可改单个文件:
chcon -t httpd_sys_content_t /tmp/test.php(不持久) - 若用了
rsync或scp部署,加-aZ参数保留上下文
最易忽略的是:布尔值生效需对应进程已重启,且文件上下文必须匹配——哪怕 httpd_can_network_connect 开了,如果 PHP 脚本文件本身是 admin_home_t,SELinux 会先因类型不匹配拒绝执行,根本到不了网络连接那步。










