登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

AppArmor 为什么同一程序换路径后权限不同

来源:17golang原创

时间:2026-11-11 08:48:42 177浏览 收藏

程序只是从 /usr/local/bin/reportd 复制到 /opt/reportd,权限却突然不同,通常不是“同名程序被识别成了另一个对象”,而是 AppArmor 的 profile attachment 没有匹配新的可执行文件路径。自动套用 profile 看的是 exec 时的路径匹配;profile 文件名和程序显示名并不能代替这个条件。

先查实际执行的 ELF 路径,再查 profile 是否已经加载并挂到进程;只有确认已经匹配后,才去判断是文件规则拒绝。单纯把规则体写得更宽,解决不了 attachment 没命中的问题。
要点速览
  • attachment 是 profile 自动套用到可执行文件的路径条件,精确路径换了,匹配就可能消失。
  • “没有 profile 标签”和“有标签但出现 DENIED”是两类问题,排查入口不同。
  • 安装路径确实有多个固定选择时再用受控 glob,优先保留明确边界。
AppArmor 的权限规则本身是和程序的存储路径强绑定的,同一份可执行文件移动到不同文件夹下运行时,会匹配到完全不同的安全配置规则,最终出现权限表现不一致的情况。
这不是程序本身的逻辑变更,也不是系统 BUG,是 AppArmor 设计之初就默认的路径绑定匹配特性,只要修改对应策略文件里的路径规则,就能让不同位置的同程序继承统一权限。

AppArmor 自动匹配看的不是程序名字,而是 attachment

AppArmor profile 可以有一个便于识别的名称,也可以带 attachment。attachment 描述的是哪些可执行文件路径会在 profile 加载后自动套用它。比如下面的写法把自动匹配条件限定为一个绝对路径:

profile reportd /usr/local/bin/reportd {
    # 这里只放程序需要的文件访问规则,路径匹配由 profile 头部决定
    /var/lib/reportd/** rw,
}

这个 profile 的规则体允许访问 /var/lib/reportd/ 下的内容,但不等于它会自动约束所有名为 reportd 的文件。程序若从 /opt/reportd 启动,前面的 attachment 没有命中,进程可能仍显示为 unconfined;此时你看到的“权限变宽”其实是 profile 没有挂上。

AppArmor profile attachment 将 usr local bin reportd 匹配到 profile 而 opt reportd 未匹配的路径关系说明图
图1:AppArmor 路径 attachment 关系说明图,不是运行截图。

换路径后的排查顺序:先看实际执行文件,再看标签和规则

我排这类问题时会先把“程序从哪里启动”钉死。软链接、复制安装、服务文件中的 ExecStart,以及脚本的 shebang,都可能让你以为运行的是一个路径,内核实际执行的却是另一个路径。下面的命令只负责收集事实,不会修改 profile:

# 查看命令解析到的文件和软链接目标
command -v reportd
readlink -f "$(command -v reportd)"

# 查看指定 PID 当前的 AppArmor 标签
cat /proc/1234/attr/current

# 查看已加载的 profile 名称和模式
sudo aa-status

如果实际路径是 /opt/reportd,而标签仍是 unconfined,优先检查 attachment 是否覆盖它,以及 profile 是否在你启动程序前已经加载。AppArmor 通常在 exec 时完成约束,程序已经启动后再加载匹配 profile,不会把当前进程 retroactively 变成受限状态。

如果标签已经是目标 profile,再看内核审计记录中的 profile=、name= 和操作类型。此时出现 DENIED 才说明路径匹配成功但规则体缺少相应权限;把它和“标签根本没换上”分开,修复方向会完全不同。

AppArmor 实际路径 profile label 与 DENIED 审计记录区分未匹配和规则拒绝的边界说明图
图2:路径、标签与拒绝记录的边界说明图,不是运行截图。

精确路径与受控通配符怎么选

如果发布包只允许安装在一个位置,精确 attachment 最容易审查:路径变更就让部署流程同步更新 profile。若确实存在两个或多个固定目录,可以把选择写进 attachment,例如 /{usr/local/bin,opt}/reportd,但要确认目标发行版和当前 parser 对该写法的行为,不要把“目录通配”当成无条件兼容。

现象优先检查处理方向
标签是 unconfined实际 ELF 路径、attachment、加载时机修正路径条件或加载顺序
已有目标 profile 标签但 DENIED审计记录的 name 与操作补最小必要规则
规则改了却行为不变是否重新加载 profile、是否重启进程确认加载结果后重新 exec

生产环境我更愿意先列出允许的安装路径,再逐个写入 attachment,而不是直接使用覆盖范围很大的 /**。路径条件越宽,越难判断哪个副本被自动套用,也越容易把本来应该隔离的程序纳入同一 profile。

相关问题

profile 文件名和 profile 名称必须等于可执行文件名吗?

不必须。文件名主要方便管理,profile 名称也可以与程序不同;自动套用是否发生,关键仍是 attachment 或显式的 profile 切换方式。

为什么 aa-status 显示 profile 已加载,进程仍是 unconfined?

“已加载”只说明策略进入内核,不代表当前进程的 exec 路径命中了 attachment。先用 readlink -f 确认实际路径,再对照 profile 头部。

只补一条文件读取规则能修复换路径问题吗?

不能。如果问题是 attachment 没匹配,规则体根本没有机会约束该进程。先让正确的 profile 标签出现,再处理具体的 DENIED。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>