1.再配置前,最好先安装下sudo apt install apparmor-*,我这ubuntu22.04默认有工具没装全
2.官方wiki:https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorMonitoring(较有用)
3.debian文档:https://manpages.debian.org/bookworm/apparmor/apparmor_parser.8.en.html(用处不太大)
4.一个成功可用的例子:
#include <tunables/global>
profile /home/lzs/workspace/test/test.sh {
/home/lzs/workspace/test/test.sh rk,
# ===== 核心修复 =====
# 1. 必须先声明拒绝规则
/home/lzs/workspace/** rwlk,
#audit deny /home/lzs/workspace/output/* rwxl,
#deny /home/lzs/workspace/output/.* rwkl,
# 2. 然后声明脚本权限
# 其他必要规则(如临时文件、库等)
/home/lzs/workspace/test/** rw,
deny /home/lzs/workspace/output/* rwkl,
capability dac_read_search,
/bin/sh ix,
/usr/bin/* ix,
/usr/lib/** rm,
/lib/** rm,
/etc/ld.so.cache r,
/usr/share/** r,
/etc/** r,
signal (receive) peer=/home/lzs/workspace/test/test.sh,
signal (receive) peer=unconfined, # 如果需要与其他未受限制的进程交互
/dev/pts/[0-9]* rw,
capability dac_override,
}
5.调试的经验:
在配置好了直接执行还无法生效时,可以使用aa-exec执行,先确保此方法直接执行生效了,再编写system服务,system服务也生效了,再来看直接执行未生效是否解决;此外使用tail -f /var/log/syslog时刻关注测试的脚本执行情况,通过ai解析排查;下面是几种加载apparmor策略的方式,其中system服务的,如果我配置好之后执行了sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh,实际上已经不用再在system服务中再次指定
如果想 不通过 aa-exec 但仍让 /home/lzs/workspace/test/test.sh 按定义好的 AppArmor 策略执行,可以通过以下方法实现。核心思路是 让脚本在启动时自动加载对应的 AppArmor 策略,或 利用系统服务或启动脚本强制应用策略。
方法 1:直接运行脚本时手动加载策略(推荐)
步骤
确保策略已加载到 AppArmor
使用 apparmor_parser 将策略文件加载到内核(无需通过 aa-exec):
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
-r 表示重新加载(如果策略已存在,先卸载再加载)。
确认策略已激活:
bash
sudo apparmor_status | grep test.sh
直接运行脚本
由于策略已加载到内核,脚本运行时会自动继承该策略的约束:
bash
sudo /home/lzs/workspace/test/test.sh
关键点:脚本必须以 与策略定义匹配的方式运行(如策略是针对 root 用户执行的,则需用 sudo)。
验证策略是否生效
检查日志确认脚本是否被策略限制:
bash
sudo dmesg | grep apparmor
如果策略生效,日志会显示 apparmor="ALLOWED" 或 apparmor="DENIED"(根据操作是否被允许)。
方法 2:通过 systemd 服务强制应用策略
如果脚本是作为服务运行的(如后台守护进程),可以在 systemd 单元文件中指定 AppArmorProfile,让系统自动加载策略。
步骤
创建或修改 systemd 服务文件
编辑 /etc/systemd/system/test-script.service:
ini
[Unit]
Description=Test Script with AppArmor
After=network.target
[Service]
Type=simple
ExecStart=/home/lzs/workspace/test/test.sh
User=root # 根据策略要求调整用户
AppArmorProfile=/etc/apparmor.d/home.lzs.workspace.test.test.sh # 指定策略路径
Restart=on-failure
[Install]
WantedBy=multi-user.target
重新加载 systemd 并启动服务
bash
sudo systemctl daemon-reload
sudo systemctl start test-script.service
sudo systemctl status test-script.service # 检查是否运行正常
验证策略是否生效
查看服务日志和 AppArmor 日志:
bash
journalctl -u test-script.service -f # 实时查看服务日志
sudo dmesg | grep apparmor # 检查 AppArmor 拒绝事件
方法 3:通过 cron 定时任务强制应用策略
如果脚本是通过 cron 运行的,可以在 crontab 中指定 AppArmor 策略(需结合 aa-exec 或手动加载策略)。
步骤
手动加载策略(与方法 1 相同)
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
编辑 crontab
直接运行脚本(策略已加载到内核):
bash
sudo crontab -e
添加任务(例如每分钟运行一次):
plaintext
-
-
-
-
- /home/lzs/workspace/test/test.sh
-
-
-
验证
检查 cron 日志和 AppArmor 日志:
bash
sudo tail -f /var/log/syslog | grep cron
sudo dmesg | grep apparmor
方法 4:通过 wrapper 脚本强制加载策略
创建一个包装脚本(wrapper),在运行目标脚本前先确保策略已加载。
步骤
创建包装脚本 /usr/local/bin/run-test-with-apparmor.sh
bash
#!/bin/bash
加载策略(如果未加载)
if ! sudo apparmor_status | grep -q “home.lzs.workspace.test.test.sh”; then
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
fi
运行目标脚本
sudo /home/lzs/workspace/test/test.sh
赋予执行权限
bash
sudo chmod +x /usr/local/bin/run-test-with-apparmor.sh
直接运行包装脚本
bash
sudo /usr/local/bin/run-test-with-apparmor.sh
6.一些调试记录(含问题)
New Chat
Document Hub
Image Studio
Recent Chats
Aparmor Debuggi
使用ifconfig修改IP
if [ ${ROS_VERS
如何将linux 编译的可执
变化点分析表完成的节点是
More...
chanalzs
Ernie 4.5 Turbo
为什么我配置了/etc/apparmor.d/home.lzs.workspace.test规则,对system服务和aa-exec执行都有效,命令行直接启动就无效呢,是终端有什么策略覆盖了么
要为通过 ros2 run 启动的 ROS 2 节点(如 camera_pkg 的 camera_node)配置 AppArmor 权限,需确保 AppArmor 规则能正确匹配 ROS 2 节点的实际执行路径。以下是详细步骤:
1. 确认节点的实际执行路径
ROS 2 的 ros2 run 会通过 Python 或原生二进制启动节点,具体路径取决于包的安装方式:
Python 脚本节点:通常位于 install/<pkg_name>/lib/<pkg_name>/<node_name> 或 ~/.ros/ 下的 Python 文件。
编译后的二进制节点:位于 install/<pkg_name>/lib/<pkg_name>/<node_name>。
查找路径的方法:
bash
# 方法1:通过 ros2 命令查找节点路径
ros2 pkg executables camera_pkg | grep camera_node
# 方法2:通过进程信息查找(启动节点后)
ps -aux | grep camera_node
假设输出路径为:
/home/lzs/ros2_ws/install/camera_pkg/lib/camera_pkg/camera_node
2. 创建 AppArmor 配置文件
根据节点的绝对路径创建配置文件,命名规则为:
/etc/apparmor.d/<替换路径中的斜杠为点>
例如:
bash
sudo nano /etc/apparmor.d/home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node
3. 编写 AppArmor 规则
在配置文件中定义权限,例如:
# 允许访问特定目录(如 /opt/ros_data)
/opt/ros_data/** rw,
# 允许访问设备(如摄像头)
/dev/video0 rw,
# 允许网络通信(ROS 2 默认使用 UDP/TCP)
network,
# 允许访问 ROS 2 日志目录
/home/lzs/.ros/log/** rw,
# 允许访问共享库(根据实际需要调整)
/usr/lib/** rm,
完整示例:
profile home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node {
# 文件访问
/opt/ros_data/** rw,
/home/lzs/.ros/log/** rw,
# 设备访问
/dev/video0 rw,
# 网络权限
network,
# 共享库
/usr/lib/** rm,
# 禁止访问其他敏感目录(可选)
deny /etc/** r,
deny /root/** rwk,
}
4. 加载配置
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node
5. 验证配置
检查进程是否受限制
启动节点后,通过以下命令验证:
bash
ps -Z | grep camera_node
输出应显示:
home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node
测试权限
正常情况:节点应能访问配置中允许的目录(如 /opt/ros_data)。
拒绝情况:尝试访问未授权的目录(如 /root)会被阻止,并在 /var/log/syslog 中记录:
bash
sudo grep apparmor /var/log/syslog | grep DENIED
6. 处理 ROS 2 的特殊情况
动态加载的 Python 节点
如果节点是 Python 脚本(通过 ros2 run 调用),需匹配 Python 解释器的路径:
bash
which python3
输出可能是 /usr/bin/python3,则配置文件应为:
/etc/apparmor.d/usr.bin.python3
并在规则中限制脚本路径:
profile usr.bin.python3 {
# 允许加载 ROS 2 Python 节点
/home/lzs/ros2_ws/install/camera_pkg/lib/camera_pkg/camera_node.py r,
/opt/ros/** r,
...
}
DDS 通信权限
ROS 2 依赖 DDS(如 Fast DDS、Cyclone DDS),可能需要额外网络规则:
# 允许 UDP 多播(ROS 2 默认使用)
network udp,
network raw,
7. 调试技巧
强制生成拒绝日志:在配置中添加 audit 标志:
profile home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node {
audit deny /tmp/** rw, # 记录对 /tmp 的拒绝操作
...
}
临时放宽权限:使用 complain 模式监控行为而不阻止:
bash
sudo aa-complain /etc/apparmor.d/home.lzs.ros2_ws.install.camera_pkg.lib.camera_pkg.camera_node
总结
确认节点路径:通过 ros2 pkg executables 或 ps 查找。
创建匹配的配置文件:替换路径中的 / 为 .。
定义精确权限:限制文件、设备、网络访问。
加载并验证:使用 apparmor_parser 和 ps -Z 检查。
处理 Python/DDS 特殊情况:根据实际运行时调整规则。
通过以上步骤,您可以为 ROS 2 节点配置严格的 AppArmor 权限,同时确保其正常运行。
Regenerate
如果我的进程是通过ros2 run 启动的,比如ros2 run camera_pkg camera_node,如何配置它指定目录的权限?
针对您配置的AppArmor规则在system服务和aa-exec下有效,但命令行直接启动无效的问题,可能的原因及解决方案如下:
1. 终端进程未继承AppArmor配置
现象:当通过命令行直接启动脚本时,终端进程(如bash或zsh)可能未加载对应的AppArmor配置,导致子进程(您的脚本)继承了终端的宽松策略。
验证方法:
使用ps -Z查看命令行启动的脚本进程的AppArmor模式:
bash
ps -Z -p $(pgrep -f test.sh)
如果输出显示unconfined,说明未加载配置。
对比system服务启动的进程:
bash
systemctl status <your_service> # 查看服务进程的AppArmor模式
解决方案:
显式指定配置文件:通过aa-exec强制加载配置:
bash
aa-exec -p /etc/apparmor.d/home.lzs.workspace.test.sh -- /home/lzs/workspace/test/test.sh
修改终端启动方式:在终端中直接使用apparmor_parser临时加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.sh
/home/lzs/workspace/test/test.sh # 再次尝试启动
2. 配置文件路径或命名不匹配
现象:AppArmor配置文件的命名必须与可执行文件的绝对路径严格匹配(斜杠替换为点)。例如:
脚本路径为/home/lzs/workspace/test/test.sh,则配置文件应为:
/etc/apparmor.d/home.lzs.workspace.test.test.sh
如果路径或文件名拼写错误,AppArmor会静默忽略配置。
验证方法:
检查配置文件是否存在:
bash
ls -l /etc/apparmor.d/home.lzs.workspace.test.test.sh
使用aa-status查看已加载的配置:
bash
sudo aa-status | grep test.sh
解决方案:
修正配置文件名,确保与脚本路径完全一致。
如果脚本通过相对路径启动,需在配置文件中使用绝对路径规则。
3. 终端环境变量或权限差异
现象:终端启动的脚本可能因环境变量(如PATH、USER)或权限不同,导致访问路径变化,从而绕过AppArmor规则。
验证方法:
在脚本中打印当前路径和环境变量:
bash
#!/bin/bash
echo "Current PATH: $PATH"
echo "Current USER: $USER"
# 触发被拒绝的操作(如访问/dev/pts/4)
对比system服务启动时的日志(/var/log/syslog或journalctl)。
解决方案:
在AppArmor配置中显式允许所需路径:
/dev/pts/[0-9]* rw,
限制脚本的环境变量(如通过env命令或systemd的Environment=选项)。
4. 终端的AppArmor模式覆盖
现象:某些终端模拟器(如gnome-terminal、tmux)可能以独立进程运行,并加载了不同的AppArmor配置(如unconfined)。
验证方法:
检查终端进程的AppArmor模式:
bash
ps -Z -p $(pgrep gnome-terminal) # 或其他终端模拟器
如果终端进程为unconfined,其子进程可能继承此模式。
解决方案:
为终端模拟器配置AppArmor规则(需谨慎操作,可能影响稳定性)。
改用aa-exec或systemd用户服务启动脚本。
推荐操作步骤
验证配置文件加载:
bash
sudo aa-status | grep test.sh
如果未加载,手动重新加载:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
检查进程模式:
bash
ps -Z -p $(pgrep -f test.sh)
确保输出包含home.lzs.workspace.test.test.sh。
简化测试:
创建一个最小化测试脚本:
bash
echo "#!/bin/bash" > /tmp/test_apparmor.sh
echo "touch /tmp/apparmor_test" >> /tmp/test_apparmor.sh
chmod +x /tmp/test_apparmor.sh
配置对应的AppArmor规则:
/tmp/test_apparmor.sh {
/tmp/apparmor_test w,
}
分别通过命令行和aa-exec测试:
bash
/tmp/test_apparmor.sh # 直接运行
aa-exec -p /etc/apparmor.d/tmp.test_apparmor -- /tmp/test_apparmor.sh
检查日志:
查看AppArmor拒绝日志:
bash
sudo grep apparmor /var/log/syslog
通过以上步骤,您应能定位到具体原因(如配置未加载、路径不匹配或终端环境问题)。如果问题仍存在,建议提供sudo aa-status和sudo grep apparmor /var/log/syslog的输出以便进一步分析。
为什么我配置了/etc/apparmor.d/home.lzs.workspace.test规则,对system服务和aa-exec执行都有效,命令行直接启动就无效呢,是终端有什么策略覆盖了么
这个错误表明你的 AppArmor 策略文件 /etc/apparmor.d/home.lzs.workspace.test.test.sh 存在 语法错误,具体是:
错误类型:syntax error, unexpected TOK_CAPABILITY, expecting TOK_END_OF_RULE
原因:在策略文件中,capability 规则的语法不正确,可能是:
缺少逗号(,)或分号(;)。
capability 规则放在了错误的位置(如 profile 定义之外)。
使用了错误的格式(如 capability=dac_override 而不是 capability dac_override,)。
如何修复?
1. 检查策略文件语法
运行以下命令检查语法:
bash
sudo apparmor_parser -Q /etc/apparmor.d/home.lzs.workspace.test.test.sh
如果仍有错误,请手动检查文件内容。
2. 正确的 capability 语法
在 AppArmor 策略中,capability 规则的正确写法是:
capability dac_override,
或(如果允许多个能力):
capability dac_override,
capability setuid,
注意:
每个 capability 规则必须以 逗号(,)结尾(除非是最后一行)。
不能写成 capability=dac_override(这是 auditctl 或 seccomp 的语法,不是 AppArmor)。
3. 示例修复
假设你的策略文件原本是这样的(错误示例):
# 错误写法(缺少逗号,或使用 `=`)
capability=dac_override
或
# 错误写法(`capability` 放在了错误的位置)
profile /home/lzs/workspace/test/test.sh {
/dev/pts/* rw,
capability=dac_override # ❌ 错误语法
}
修正后的写法:
bash
sudo nano /etc/apparmor.d/home.lzs.workspace.test.test.sh
修改为:
profile /home/lzs/workspace/test/test.sh {
# 允许访问伪终端
/dev/pts/[0-9]* rw,
# 允许 CAP_DAC_OVERRIDE 能力
capability dac_override,
# 其他规则...
}
4. 重新加载策略
修复后,重新加载 AppArmor 策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
如果仍然报错,请检查:
是否有多余的 { 或 }。
是否在 capability 之后漏掉了逗号。
5. 调试技巧
如果仍然不确定问题,可以:
简化策略文件,只保留最基本的规则:
profile /home/lzs/workspace/test/test.sh {
/dev/pts/[0-9]* rw,
capability dac_override,
}
逐行添加规则,直到找到导致错误的行。
常见 AppArmor 语法错误
错误类型 示例 修复方法
缺少逗号 capability dac_override 改为 capability dac_override,
错误位置 capability 放在 profile 之外 确保它在 { ... } 内部
拼写错误 capabilty(少了一个 i) 改为 capability
无效能力名 capability root, 改为 capability dac_override,
最终建议
确保 capability 规则在 profile { ... } 内部。
每个规则以逗号结尾(除非是最后一行)。
避免 = 符号(AppArmor 策略使用空格分隔,如 capability dac_override)。
使用 sudo apparmor_parser -Q 检查语法。
如果仍有问题,请提供完整的策略文件内容(cat /etc/apparmor.d/home.lzs.workspace.test.test.sh),我可以帮你进一步排查! 🚀
? 14 ? /etc/apparmor.d/home.lzs.workspace.test.test.sh in profile /etc/apparmor.d/home.lzs.workspace.test.test.sh ?AppArmor?????:syntax error, unexpected TOK_CAPABILITY, expecting TOK_END_OF_RULE
从新的日志来看,/home/lzs/workspace/test/test.sh 脚本又触发了 两个新的 AppArmor 拒绝事件:
拒绝访问 /dev/pts/4(伪终端设备):
apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/dev/pts/4" pid=171848 comm="test.sh" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
操作:尝试以读写模式 (wr) 打开 /dev/pts/4(通常用于终端交互)。
可能原因:脚本可能调用了 ssh、tmux、screen 或直接操作终端设备。
拒绝 dac_override 能力(绕过文件权限检查):
apparmor="DENIED" operation="capable" class="cap" profile="/home/lzs/workspace/test/test.sh" pid=171951 comm="test.sh" capability=1 capname="dac_override"
操作:脚本尝试使用 CAP_DAC_OVERRIDE 能力(通常用于 root 绕过文件读/写/执行权限检查)。
可能原因:脚本可能调用了 sudo、chmod 或直接尝试以 root 权限访问受限文件。
问题分析
1. 为什么脚本需要访问 /dev/pts/4?
如果脚本调用了 交互式命令(如 ssh、tmux、screen 或 gnome-terminal),这些程序会尝试打开终端设备 (/dev/pts/*)。
如果脚本本身是 后台服务(如 systemd 启动的),它可能不需要终端访问,但某些依赖库可能误触发。
2. 为什么脚本需要 dac_override 能力?
常见于:
脚本尝试用 root 权限修改文件权限(如 chmod 777 /some/file)。
脚本调用了 sudo 或直接调用了需要 root 的系统调用(如 setuid())。
某些工具(如 docker、wireshark)默认需要 CAP_DAC_OVERRIDE。
解决方案
1. 允许访问 /dev/pts/*
在 AppArmor 策略文件中添加:
bash
sudo nano /etc/apparmor.d/home.lzs.workspace.test.test.sh
添加以下规则:
# 允许访问伪终端(谨慎使用)
/dev/pts/[0-9]* rw,
然后重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 允许 dac_override 能力
在策略文件中添加:
# 允许 CAP_DAC_OVERRIDE(谨慎使用)
capability dac_override,
然后重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
⚠️ 注意:dac_override 是高权限操作,可能绕过文件系统安全检查,建议优先修复脚本逻辑,而非直接授权。
3. 检查脚本依赖
如果脚本调用了 ssh、tmux 或其他终端程序,考虑:
改用非交互模式(如 ssh -T 禁用终端分配)。
避免直接操作 /dev/pts/*(普通脚本通常不需要)。
如果脚本必须使用 dac_override,检查是否可以改用更安全的替代方案:
用 chmod 修改文件属主/组,而非直接 CAP_DAC_OVERRIDE。
用 sudo 提权特定命令(而非整个脚本)。
4. 调试脚本行为
用 strace 跟踪脚本的系统调用:
bash
sudo strace -f -e trace=file,capability /home/lzs/workspace/test/test.sh
重点关注:
是否真的需要 /dev/pts/4(可能是某个子进程触发的)。
是否真的需要 dac_override(可能是某个库或命令调用的)。
最佳实践建议
避免在脚本中直接操作终端设备(如 /dev/pts/*)。
避免滥用 CAP_DAC_OVERRIDE,改用 sudo 提权特定命令。
优先调整脚本逻辑,而非放宽 AppArmor 策略。
如果必须放宽策略,限制为最小必要权限(如仅允许特定路径或能力)。
常见问题
Q1:为什么 systemd 启动的脚本会触发这些限制?
如果 systemd 服务配置了 AppArmorProfile= 或系统默认启用了 AppArmor,所有通过 systemd 启动的进程都会受策略限制。
Q2:如何彻底禁用 AppArmor 对该脚本的限制?
将策略设为 unconfined(不推荐):
bash
echo "/home/lzs/workspace/test/test.sh { }" | sudo tee /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart apparmor
Q3:如果脚本是 Python/Bash 脚本,如何检查内部调用的命令?
用 bash -x 或 python -m trace 调试:
bash
bash -x /home/lzs/workspace/test/test.sh
或
bash
python -m trace --trace /home/lzs/workspace/test/test.py
最终结论
当前问题是由于 AppArmor 策略限制了脚本访问终端设备 (/dev/pts/4) 和使用高权限能力 (dac_override)。建议:
优先修改脚本,避免不必要的终端操作和高权限调用。
或调整 AppArmor 策略,仅放行必要权限(如 /dev/pts/* rw 和 capability dac_override)。
避免直接禁用 AppArmor,除非是临时调试。
如果仍有问题,请提供:
脚本内容(cat /home/lzs/workspace/test/test.sh)。
AppArmor 策略文件内容(sudo cat /etc/apparmor.d/home.lzs.workspace.test.test.sh)。
sudo aa-status 的输出。
(1753096428.192:945): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/dev/pts/4" pid=171848 comm="test.sh" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
Jul 21 19:13:53 lzs-Precision-3591 kernel: [ 9471.823660] audit: type=1400 audit(1753096433.206:946): apparmor="DENIED" operation="capable" class="cap" profile="/home/lzs/workspace/test/test.sh" pid=171951 comm="test.sh" capability=1 capname="dac_override"
从新的日志来看,/home/lzs/workspace/test/test.sh 脚本再次因 AppArmor 策略限制 被拒绝创建 /cat.log 文件(mknod 操作)。以下是更详细的解决方案:
问题分析
关键日志:
audit: type=1400 audit(1753096326.610:939): apparmor="DENIED" operation="mknod" class="file" profile="/home/lzs/workspace/test/test.sh" name="/cat.log" pid=170094 comm="test.sh" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
操作:mknod(创建文件或设备节点)。
目标文件:/cat.log(根目录下的文件,通常需要 root 权限)。
问题:AppArmor 策略 /home/lzs/workspace/test/test.sh 禁止了该操作。
可能原因:
脚本尝试 > 重定向或 mkfifo 创建 /cat.log,但 AppArmor 策略未授权。
/cat.log 位于 根目录 (/),普通用户(包括 root)可能无法直接写入(取决于系统权限)。
解决方案
1. 修改脚本,避免写入受限路径
最佳实践:不要在根目录 (/) 创建文件,改用 /tmp 或用户目录:
bash
#!/bin/bash
# 修改前(触发 AppArmor 拒绝)
echo "Test log" > /cat.log
# 修改后(推荐)
LOG_FILE="/tmp/cat.log" # 或 "$HOME/cat.log"
echo "Test log" > "$LOG_FILE"
2. 调整 AppArmor 策略(允许访问 /cat.log)
如果必须写入 /cat.log,需修改 AppArmor 策略:
找到策略文件:
bash
sudo find /etc/apparmor.d -name "*test.sh*" # 通常策略文件路径
如果找不到,可能是动态生成的临时策略,需检查 systemd 或 aa-autodep 的配置。
编辑策略文件(如 /etc/apparmor.d/home.lzs.workspace.test.test.sh):
bash
sudo nano /etc/apparmor.d/home.lzs.workspace.test.test.sh
添加允许规则:
# 允许写入 /cat.log(需确保路径正确)
/cat.log w,
# 或允许写入任意文件(宽松策略,不推荐)
/** w,
重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart test-script.service # 如果通过 systemd 运行
3. 检查文件系统权限
即使 AppArmor 允许,/cat.log 的父目录 (/) 可能禁止写入:
bash
ls -ld / # 检查根目录权限
如果权限为 drwxr-xr-x(默认),只有 root 可以写入。
解决方案:
使用 sudo 运行脚本(不推荐长期使用)。
改用 /tmp 或用户目录(推荐)。
4. 临时禁用 AppArmor(仅调试)
如果问题紧急,可临时将策略设为 complain 模式(允许操作但记录日志):
bash
sudo aa-complain /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart test-script.service
注意:生产环境不建议长期禁用安全策略。
调试步骤
确认脚本行为:
bash
sudo strace -f -e trace=file /home/lzs/workspace/test/test.sh # 查看文件操作
检查是否真的尝试创建 /cat.log。
检查 AppArmor 日志:
bash
sudo dmesg | grep apparmor # 查看最近拒绝记录
sudo aa-status # 确认策略是否加载
测试宽松策略:
如果调整策略后仍失败,尝试完全放行目录:
/home/lzs/workspace/test/** rw,
常见问题
Q1:为什么 systemd 执行脚本时会触发 AppArmor?
如果 systemd 服务配置了 AppArmorProfile= 或系统默认启用了 AppArmor,所有通过 systemd 启动的进程都会受策略限制。
Q2:如何永久禁用 AppArmor 对该脚本的限制?
删除或注释策略文件中的相关规则,然后重启 AppArmor:
bash
sudo rm /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart apparmor
Q3:如果 /cat.log 是符号链接,如何处理?
AppArmor 默认不跟踪符号链接,需在策略中添加目标路径的权限:
/real/path/to/cat.log w,
最终结论
根本原因是 AppArmor 策略禁止脚本创建 /cat.log。建议:
优先修改脚本,使用可写目录(如 /tmp)。
或调整 AppArmor 策略,显式允许对 /cat.log 的访问。
避免直接禁用 AppArmor,除非是临时调试。
如果仍有问题,请提供以下信息以便进一步分析:
脚本内容(cat /home/lzs/workspace/test/test.sh)。
AppArmor 策略文件内容(sudo cat /etc/apparmor.d/home.lzs.workspace.test.test.sh)。
sudo aa-status 的输出。
Jul 21 19:12:06 lzs-Precision-3591 kernel: [ 9365.219197] audit: type=1400 audit(1753096326.610:939): apparmor="DENIED" operation="mknod" class="file" profile="/home/lzs/workspace/test/test.sh" name="/cat.log" pid=170094 comm="test.sh" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
从日志来看,systemd 在执行 /home/lzs/workspace/test/test.sh 时触发了 AppArmor 拒绝,具体原因是脚本尝试创建文件 /cat.log(mknod 操作),但 AppArmor 策略禁止了该操作。
问题分析
错误原因:
脚本 /home/lzs/workspace/test/test.sh 试图创建或写入 /cat.log(可能是 > 重定向或 mkfifo 操作)。
AppArmor 策略 /home/lzs/workspace/test/test.sh 明确禁止了 mknod(文件创建)操作。
关键日志:
audit: type=1400 audit(1753096160.139:765): apparmor="DENIED" operation="mknod" class="file" profile="/home/lzs/workspace/test/test.sh" name="/cat.log" pid=166841 comm="test.sh" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
operation="mknod":脚本尝试创建文件。
name="/cat.log":目标文件路径。
requested_mask="c":请求 create 权限,但被策略拒绝。
解决方案
1. 修改 AppArmor 策略(推荐)
如果 /cat.log 是脚本必需的文件,需调整 AppArmor 策略以允许访问:
找到策略文件:
bash
sudo find /etc/apparmor.d -name "*test.sh*" # 通常策略文件路径
如果找不到,可能是动态生成的临时策略,需检查 systemd 或 aa-autodep 的配置。
编辑策略文件(如 /etc/apparmor.d/home.lzs.workspace.test.test.sh):
bash
sudo nano /etc/apparmor.d/home.lzs.workspace.test.test.sh
添加允许规则(根据实际需求选择):
# 允许写入 /cat.log(需确保路径正确)
/cat.log w,
# 或允许写入任意文件(宽松策略,不推荐)
/** w,
重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart test-script.service
2. 修改脚本路径(避免受限目录)
如果 /cat.log 是脚本生成的日志文件,建议改用可写目录(如 /tmp 或用户目录):
bash
#!/bin/bash
# 将硬编码路径改为可写目录
LOG_FILE="/tmp/cat.log" # 或 "$HOME/cat.log"
echo "Test log" > "$LOG_FILE"
3. 临时禁用 AppArmor(仅调试)
如果问题紧急,可临时将策略设为 complain 模式(允许操作但记录日志):
bash
sudo aa-complain /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart test-script.service
注意:生产环境不建议长期禁用安全策略。
4. 检查脚本是否真的需要 mknod
如果脚本中包含 mkfifo 或类似操作(创建命名管道),需明确在 AppArmor 策略中允许:
# 允许创建 FIFO 管道
/cat.log mknod,
调试步骤
确认脚本行为:
bash
sudo strace -f -e trace=file /home/lzs/workspace/test/test.sh # 查看文件操作
检查是否真的尝试创建 /cat.log。
检查 AppArmor 日志:
bash
sudo dmesg | grep apparmor # 查看最近拒绝记录
sudo aa-status # 确认策略是否加载
测试宽松策略:
如果调整策略后仍失败,尝试完全放行目录:
/home/lzs/workspace/test/** rw,
常见问题
Q1:为什么 systemd 执行脚本时会触发 AppArmor?
如果 systemd 服务配置了 AppArmorProfile= 或系统默认启用了 AppArmor,所有通过 systemd 启动的进程都会受策略限制。
Q2:如何永久禁用 AppArmor 对该脚本的限制?
删除或注释策略文件中的相关规则,然后重启 AppArmor:
bash
sudo rm /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart apparmor
Q3:如果 /cat.log 是符号链接,如何处理?
AppArmor 默认不跟踪符号链接,需在策略中添加目标路径的权限:
/real/path/to/cat.log w,
最终结论
根本原因是 AppArmor 策略禁止脚本创建 /cat.log。建议:
优先修改脚本,使用可写目录(如 /tmp)。
或调整 AppArmor 策略,显式允许对 /cat.log 的访问。
避免直接禁用 AppArmor,除非是临时调试。
如果仍有问题,请提供 cat /home/lzs/workspace/test/test.sh 和 sudo aa-status 的输出,以便进一步分析!
Jul 21 19:09:20 lzs-Precision-3591 kernel: [ 9198.743035] audit: type=1400 audit(1753096160.139:765): apparmor="DENIED" operation="mknod" class="file" profile="/home/lzs/workspace/test/test.sh" name="/cat.log" pid=166841 comm="test.sh" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
从日志来看,systemd 启动服务时遇到了 Exec format error(执行格式错误),这通常意味着:
脚本没有正确的 Shebang(如 #!/bin/bash),导致系统不知道如何解释该文件。
脚本的二进制格式与系统不兼容(如 Windows 换行符 \r\n 或错误的文件权限)。
脚本路径或文件本身损坏(如非可执行文件被误命名为 .sh)。
解决方案
1. 检查脚本的 Shebang 和内容
确保脚本第一行是有效的 Shebang(如 #!/bin/bash 或 #!/bin/sh),例如:
bash
#!/bin/bash
echo "Hello, this is a test script."
修复方法:
bash
sudo nano /home/lzs/workspace/test/test.sh # 编辑脚本,确保第一行是 Shebang
chmod +x /home/lzs/workspace/test/test.sh # 重新添加执行权限
2. 检查文件格式(是否包含 Windows 换行符)
如果脚本在 Windows 上编辑过,可能包含 \r\n 换行符,导致 Linux 无法解析。
检查方法:
bash
cat -v /home/lzs/workspace/test/test.sh # 查看是否有 `^M`(表示 Windows 换行符)
file /home/lzs/workspace/test/test.sh # 检查文件类型(应显示 "Bourne-Again shell script")
修复方法:
bash
sudo apt install dos2unix # 安装转换工具
dos2unix /home/lzs/workspace/test/test.sh # 转换换行符
3. 检查脚本是否为二进制文件或损坏
如果脚本不是文本文件(如误上传了二进制文件),systemd 会报 Exec format error。
检查方法:
bash
head -n 5 /home/lzs/workspace/test/test.sh # 查看前几行是否是可读的 shell 命令
修复方法:
如果文件损坏,重新创建脚本或从备份恢复。
4. 检查 systemd 服务配置
确保 test-script.service 中的 ExecStart 路径正确,且没有多余参数:
ini
[Service]
ExecStart=/home/lzs/workspace/test/test.sh # 确保路径正确,无引号或特殊字符
错误示例(会导致 Exec format error):
ini
ExecStart="/home/lzs/workspace/test/test.sh arg1" # systemd 会尝试将整个字符串当作二进制路径
正确写法(如需传递参数):
ini
ExecStart=/bin/bash /home/lzs/workspace/test/test.sh arg1
5. 检查 AppArmor 策略是否阻止执行
虽然 Exec format error 通常与脚本本身有关,但 AppArmor 策略如果限制了 exec 操作,也可能导致类似错误。
检查策略:
bash
sudo aa-status | grep test.sh # 确认策略是否允许执行
临时放宽策略:
bash
sudo aa-complain /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo systemctl restart test-script.service
调试步骤总结
验证脚本内容:
bash
head -n 3 /home/lzs/workspace/test/test.sh # 检查 Shebang 和基本语法
bash -n /home/lzs/workspace/test/test.sh # 检查语法错误(不执行)
手动运行脚本:
bash
sudo /home/lzs/workspace/test/test.sh # 测试是否能直接运行
检查 systemd 日志:
bash
journalctl -u test-script.service -b --no-pager # 查看最近启动日志
修复后重启服务:
bash
sudo systemctl daemon-reload
sudo systemctl restart test-script.service
常见问题补充
Q1:为什么 Exec format error 不提示具体原因?
systemd 的 EXEC 阶段错误通常直接返回内核级错误(如 ENOEXEC),不会详细说明是 Shebang 缺失、文件损坏还是权限问题。需手动排查。
Q2:如果脚本依赖环境变量怎么办?
在 systemd 服务文件中显式设置 Environment:
ini
[Service]
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="MY_VAR=value"
Q3:如何让 systemd 输出脚本的错误信息?
在服务文件中添加调试选项:
ini
[Service]
ExecStart=/bin/bash -x /home/lzs/workspace/test/test.sh # -x 打印执行过程
StandardOutput=journal
StandardError=journal
然后通过 journalctl -u test-script.service 查看详细输出。
最终结论
Exec format error 大概率是以下原因之一:
脚本缺少 Shebang(如 #!/bin/bash)。
脚本包含 Windows 换行符(\r\n)。
systemd 服务配置错误(如 ExecStart 格式不正确)。
按上述步骤检查后,服务应能正常启动。如果仍有问题,请提供 head -n 10 /home/lzs/workspace/test/test.sh 和 journalctl -u test-script.service -n 50 --no-pager 的输出以便进一步分析!
Jul 21 19:02:22 lzs-Precision-3591 systemd[158780]: test-script.service: Failed to execute /home/lzs/workspace/test/test.sh: Exec format error
Jul 21 19:02:22 lzs-Precision-3591 systemd[158780]: test-script.service: Failed at step EXEC spawning /home/lzs/workspace/test/test.sh: Exec format error
从日志来看,systemd 服务 test-script.service 启动失败,原因是 无法确定用户凭证(Failed to determine user credentials: No such process),并且在尝试以指定用户身份运行脚本时失败(Failed at step USER spawning)。这通常与 systemd 服务配置中的用户设置问题 或 脚本路径/权限问题 有关。
问题原因分析
User= 指定的用户不存在或无权限
服务文件中可能指定了 User=lzs 或其他用户,但该用户不存在,或用户的主目录/权限有问题。
如果未显式指定 User=,systemd 默认以 root 运行,但可能因环境问题失败。
脚本路径或权限问题
脚本 /home/lzs/workspace/test/test.sh 可能不存在、无执行权限,或路径包含特殊字符(如空格、中文)。
如果脚本依赖其他文件或环境变量,可能因 systemd 的默认环境限制而失败。
AppArmor 策略冲突
虽然策略已加载,但可能限制了 systemd 的某些操作(如访问 /proc 或 /sys),导致进程无法启动。
解决方案
1. 检查并修复服务文件配置
编辑 /etc/systemd/system/test-script.service,确保以下关键配置正确:
ini
[Unit]
Description=Test Script with AppArmor
After=network.target
[Service]
Type=simple
ExecStart=/home/lzs/workspace/test/test.sh # 确保路径绝对且无特殊字符
User=root # 或指定有效用户(如 lzs,需确认用户存在)
WorkingDirectory=/home/lzs/workspace/test # 可选:设置工作目录
AppArmorProfile=/etc/apparmor.d/home.lzs.workspace.test.test.sh # 确保策略路径正确
Restart=on-failure
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # 显式设置 PATH
[Install]
WantedBy=multi-user.target
关键修改点
User=:
如果脚本需要 root 权限,直接使用 User=root。
如果需普通用户,确保用户存在(如 User=lzs),并检查 /home/lzs 权限:
bash
sudo -u lzs ls /home/lzs/workspace/test/test.sh # 测试用户能否访问脚本
ExecStart=:
使用绝对路径,避免相对路径或环境变量(如 ~/)。
如果路径包含空格或特殊字符,用引号包裹:
ini
ExecStart="/home/lzs/My Scripts/test.sh"
Environment="PATH=...":
systemd 默认环境较简洁,显式设置 PATH 避免脚本找不到命令。
2. 检查脚本权限和内容
确保脚本有执行权限且内容无错误:
bash
chmod +x /home/lzs/workspace/test/test.sh # 添加执行权限
chown root:root /home/lzs/workspace/test/test.sh # 如果以 root 运行,确保所有者正确
测试脚本能否手动运行
bash
sudo /home/lzs/workspace/test/test.sh # 以 root 运行(与服务配置一致)
如果手动运行失败,需先修复脚本问题(如依赖缺失、语法错误)。
3. 重新加载 systemd 并启动服务
bash
sudo systemctl daemon-reload # 重新加载服务文件
sudo systemctl reset-failed test-script.service # 清除之前的失败状态
sudo systemctl start test-script.service
sudo systemctl status test-script.service --no-pager # 查看详细状态
检查日志
bash
journalctl -u test-script.service -f # 实时查看服务日志
sudo dmesg | grep apparmor # 检查 AppArmor 是否拒绝操作
4. 调试技巧
如果仍失败,可临时修改服务文件以获取更多信息:
ini
[Service]
...
StandardOutput=journal # 输出到 journalctl
StandardError=journal
然后通过 journalctl -u test-script.service 查看完整错误。
常见问题补充
Q1:为什么 User= 导致失败?
如果用户不存在或用户的主目录不可访问(如 /home/lzs 权限为 700 且脚本依赖其他文件),systemd 会无法切换用户。
解决:检查用户是否存在:
bash
id lzs # 如果用户不存在,需创建用户或改用 root
Q2:AppArmor 策略是否影响服务启动?
如果策略禁止了 systemd 的某些操作(如 fork() 或访问 /proc),可能导致进程无法创建。
解决:临时放宽策略测试:
bash
sudo aa-complain /etc/apparmor.d/home.lzs.workspace.test.test.sh # 切换为 complain 模式
sudo systemctl restart test-script.service
如果服务启动成功,说明原策略需调整(如添加 ptrace read, 或 /proc/** rw,)。
总结
检查服务文件:确保 User=、ExecStart=、PATH 配置正确。
验证脚本权限:确保脚本可执行且依赖完整。
查看日志:通过 journalctl 和 dmesg 定位具体错误。
调试策略:如怀疑 AppArmor 限制,临时切换为 complain 模式测试。
按上述步骤操作后,服务应能正常启动。如果仍有问题,请提供 journalctl -u test-script.service 的完整日志以便进一步分析!
Jul 21 18:57:50 lzs-Precision-3591 systemd[1]: Started Test Script with AppArmor.
Jul 21 18:57:50 lzs-Precision-3591 systemd[154009]: test-script.service: Failed to determine user credentials: No such process
Jul 21 18:57:50 lzs-Precision-3591 systemd[154009]: test-script.service: Failed at step USER spawning /home/lzs/workspace/test/test.sh: No such process
从你的 sudo apparmor_status | grep test.sh 输出可以看出,AppArmor 策略 /home/lzs/workspace/test/test.sh 已经加载到内核并处于 enforce(强制)模式。这意味着:
策略已生效,脚本运行时会自动受该策略约束。
无需通过 aa-exec,直接运行脚本即可应用策略。
接下来如何验证策略是否真正生效?
1. 直接运行脚本并检查日志
bash
sudo /home/lzs/workspace/test/test.sh
然后查看 AppArmor 日志,确认是否有 ALLOWED 或 DENIED 记录:
bash
sudo dmesg | grep apparmor
或使用 aa-logprof(需安装 apparmor-utils):
bash
sudo aa-logprof
这会分析最近的 AppArmor 日志,并提示是否有策略违规。
2. 测试策略是否限制脚本行为
如果策略限制了某些操作(如禁止访问 /etc/shadow),可以在脚本中添加测试代码:
bash
#!/bin/bash
echo "Testing AppArmor policy..."
cat /etc/shadow # 如果策略禁止,会触发 DENIED 日志
然后运行脚本并检查日志:
bash
sudo /home/lzs/workspace/test/test.sh
sudo dmesg | grep apparmor
如果策略生效,你会看到类似:
[ 1234.567890] audit: type=1400 audit(1234567890.123:123): apparmor="DENIED" operation="open" profile="/home/lzs/workspace/test/test.sh" name="/etc/shadow" pid=1234 comm="cat" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
3. 如果策略未生效?
可能原因
策略路径不匹配
确保策略文件中的路径 /home/lzs/workspace/test/test.sh 与实际脚本路径完全一致(包括大小写和符号链接)。
检查策略文件内容:
bash
cat /etc/apparmor.d/home.lzs.workspace.test.test.sh
策略未正确加载
重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
确认策略状态:
bash
sudo apparmor_status | grep test.sh
脚本运行方式与策略不匹配
如果策略限定 root 用户执行,但脚本以普通用户运行,策略不会生效。确保:
bash
sudo /home/lzs/workspace/test/test.sh
总结
策略已加载(apparmor_status 显示正常),直接运行脚本即可应用策略。
验证策略是否生效:
运行脚本后检查 dmesg | grep apparmor。
测试策略限制的操作(如访问禁止的文件)。
如果策略未生效:
检查策略路径是否匹配。
重新加载策略。
确保脚本以正确的用户(如 root)运行。
现在你可以直接运行脚本,AppArmor 会自动应用策略限制!
sudo apparmor_status | grep test.sh
/home/lzs/workspace/test/test.sh
如果想 不通过 aa-exec 但仍让 /home/lzs/workspace/test/test.sh 按定义好的 AppArmor 策略执行,可以通过以下方法实现。核心思路是 让脚本在启动时自动加载对应的 AppArmor 策略,或 利用系统服务或启动脚本强制应用策略。
方法 1:直接运行脚本时手动加载策略(推荐)
步骤
确保策略已加载到 AppArmor
使用 apparmor_parser 将策略文件加载到内核(无需通过 aa-exec):
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
-r 表示重新加载(如果策略已存在,先卸载再加载)。
确认策略已激活:
bash
sudo apparmor_status | grep test.sh
直接运行脚本
由于策略已加载到内核,脚本运行时会自动继承该策略的约束:
bash
sudo /home/lzs/workspace/test/test.sh
关键点:脚本必须以 与策略定义匹配的方式运行(如策略是针对 root 用户执行的,则需用 sudo)。
验证策略是否生效
检查日志确认脚本是否被策略限制:
bash
sudo dmesg | grep apparmor
如果策略生效,日志会显示 apparmor="ALLOWED" 或 apparmor="DENIED"(根据操作是否被允许)。
方法 2:通过 systemd 服务强制应用策略
如果脚本是作为服务运行的(如后台守护进程),可以在 systemd 单元文件中指定 AppArmorProfile,让系统自动加载策略。
步骤
创建或修改 systemd 服务文件
编辑 /etc/systemd/system/test-script.service:
ini
[Unit]
Description=Test Script with AppArmor
After=network.target
[Service]
Type=simple
ExecStart=/home/lzs/workspace/test/test.sh
User=root # 根据策略要求调整用户
AppArmorProfile=/etc/apparmor.d/home.lzs.workspace.test.test.sh # 指定策略路径
Restart=on-failure
[Install]
WantedBy=multi-user.target
重新加载 systemd 并启动服务
bash
sudo systemctl daemon-reload
sudo systemctl start test-script.service
sudo systemctl status test-script.service # 检查是否运行正常
验证策略是否生效
查看服务日志和 AppArmor 日志:
bash
journalctl -u test-script.service -f # 实时查看服务日志
sudo dmesg | grep apparmor # 检查 AppArmor 拒绝事件
方法 3:通过 cron 定时任务强制应用策略
如果脚本是通过 cron 运行的,可以在 crontab 中指定 AppArmor 策略(需结合 aa-exec 或手动加载策略)。
步骤
手动加载策略(与方法 1 相同)
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
编辑 crontab
直接运行脚本(策略已加载到内核):
bash
sudo crontab -e
添加任务(例如每分钟运行一次):
plaintext
* * * * * /home/lzs/workspace/test/test.sh
验证
检查 cron 日志和 AppArmor 日志:
bash
sudo tail -f /var/log/syslog | grep cron
sudo dmesg | grep apparmor
方法 4:通过 wrapper 脚本强制加载策略
创建一个包装脚本(wrapper),在运行目标脚本前先确保策略已加载。
步骤
创建包装脚本 /usr/local/bin/run-test-with-apparmor.sh
bash
#!/bin/bash
# 加载策略(如果未加载)
if ! sudo apparmor_status | grep -q "home.lzs.workspace.test.test.sh"; then
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
fi
# 运行目标脚本
sudo /home/lzs/workspace/test/test.sh
赋予执行权限
bash
sudo chmod +x /usr/local/bin/run-test-with-apparmor.sh
直接运行包装脚本
bash
sudo /usr/local/bin/run-test-with-apparmor.sh
常见问题与解决
Q1:直接运行脚本后,AppArmor 日志没有记录?
可能原因:
策略未正确加载(检查 sudo apparmor_status)。
脚本未触发策略限制的操作(如仅读取允许的文件)。
解决:
重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
在脚本中添加测试操作(如尝试读取策略禁止的文件):
bash
cat /etc/shadow # 如果策略禁止,会触发 DENIED 日志
Q2:策略生效但脚本无法正常运行?
可能原因:
策略过于严格,阻止了脚本必需的操作(如访问 /tmp 或库文件)。
解决:
编辑策略文件,添加缺失的权限(如 /tmp/** rw,)。
重新加载策略:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
总结
方法 适用场景 是否需要 aa-exec 关键步骤
直接运行(手动加载策略) 临时测试或简单脚本 ❌ 否 1. sudo apparmor_parser -r /path/to/profile
2. 直接运行脚本
systemd 服务 后台守护进程 ❌ 否 1. 在服务文件中指定 AppArmorProfile
2. sudo systemctl start service
cron 定时任务 定时执行的脚本 ❌ 否 1. 手动加载策略
2. 在 crontab 中直接运行脚本
包装脚本 需要额外逻辑(如自动加载策略) ❌ 否 1. 创建包装脚本
2. 在包装脚本中加载策略并运行目标脚本
推荐方案:
临时测试 → 方法 1(直接运行 + 手动加载策略)。
生产环境 → 方法 2(systemd 服务)或方法 4(包装脚本)。
定时任务 → 方法 3(cron + 手动加载策略)。
我想不通过aa-exec但也让我的test.sh也按定义好的策略执行应该怎么办
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh 的作用是 以指定的 AppArmor 配置文件(/home/lzs/workspace/test/test.sh)加载安全策略,并执行该脚本。其中,aa-exec 是 AppArmor 提供的工具,用于在特定安全上下文中运行程序。以下是详细解析:
1. 命令组成与作用
sudo
以超级用户权限执行后续命令,确保 AppArmor 策略加载和脚本执行具有足够权限。
aa-exec
AppArmor 的核心工具,用于在指定的安全策略(profile)下运行程序。其作用包括:
加载策略:根据 -p 参数指定的路径,加载对应的 AppArmor 配置文件。
限制进程行为:确保进程仅能访问策略中明确定义的资源(如文件、网络、信号等)。
隔离风险:若脚本尝试执行策略禁止的操作(如读取未授权文件),AppArmor 会阻止并记录日志。
-p /home/lzs/workspace/test/test.sh
指定要加载的 AppArmor 策略文件路径。该文件定义了脚本 /home/lzs/workspace/test/test.sh 的权限规则(如允许读取哪些文件、发送哪些信号等)。
-- /home/lzs/workspace/test/test.sh
-- 是分隔符,表示后续参数为要执行的程序及其参数。此处直接运行脚本本身。
2. 典型应用场景
安全加固脚本执行
若脚本需要访问敏感资源(如系统文件、数据库),但直接运行可能因权限过高导致风险,可通过 AppArmor 策略限制其行为。例如:
plaintext
# 示例策略片段(/home/lzs/workspace/test/test.sh)
/home/lzs/workspace/test/test.sh r, # 允许读取脚本自身
/bin/sh ix, # 允许执行 shell
/var/log/app.log w, # 允许写入日志文件
signal (receive) peer=unconfined, # 允许接收信号
deny /etc/shadow r, # 禁止读取密码文件
通过 aa-exec 加载此策略后,脚本仅能执行允许的操作,其他行为(如读取 /etc/shadow)会被阻止。
调试 AppArmor 策略
在开发策略时,可通过 aa-exec 临时加载策略并测试脚本行为,观察日志确认是否符合预期。例如:
bash
sudo aa-exec -p /etc/apparmor.d/usr.bin.cat -- cat /home/lzs/workspace/output/test.txt
若策略未允许读取该文件,日志会记录 apparmor="DENIED" operation="open"。
3. 对比直接运行脚本的差异
执行方式 权限控制 安全上下文 适用场景
直接运行 ./test.sh 依赖系统默认权限(如用户、组) 无额外限制 普通脚本,无需安全隔离
sudo aa-exec -p ... -- ... 由 AppArmor 策略显式定义 进程受策略约束,行为可审计 高风险脚本,需精细权限控制
4. 常见问题与解决
策略文件不存在或路径错误
若 -p 指定的路径无效,aa-exec 会报错:
bash
Error: Unable to load profile /home/lzs/workspace/test/test.sh
解决:检查路径是否正确,或使用 sudo apparmor_parser -r /path/to/profile 手动加载策略。
策略未允许操作
若脚本尝试执行策略禁止的操作(如读取 /etc/shadow),日志会记录拒绝事件:
bash
sudo dmesg | grep apparmor
解决:编辑策略文件,添加所需权限(如 /etc/shadow r,),然后重新加载。
aa-exec 未安装
若系统未安装 AppArmor 工具包,会提示命令未找到。
解决:安装 AppArmor:
bash
sudo apt-get install apparmor apparmor-utils # Debian/Ubuntu
sudo yum install apparmor apparmor-utils # RHEL/CentOS
总结
sudo aa-exec -p /path/to/profile -- /path/to/script 的作用是 在 AppArmor 策略的严格约束下执行脚本,确保进程行为符合安全规范。它适用于需要隔离风险、精细控制权限的场景,是 Linux 系统安全加固的重要工具之一。
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh 的作用是啥,aa-exec的作用?
这个错误表明 AppArmor 拒绝了 cat 进程(由 /home/lzs/workspace/test/test.sh 触发)读取 /home/lzs/workspace/output/test.txt 文件。以下是详细分析和解决方案:
错误原因
文件访问被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其调用的命令(如 cat)尝试读取 /home/lzs/workspace/output/test.txt,但 AppArmor 配置未明确允许。
文件所有者是 ouid=1000(普通用户),而进程以 fsuid=0(root)运行,可能触发权限检查。
可能的原因
脚本中直接或间接调用了 cat 读取该文件(例如 cat /home/lzs/workspace/output/test.txt)。
AppArmor 配置未包含对 /home/lzs/workspace/output/ 目录的读取权限。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对目标文件的读取权限:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许读取目标文件(关键修改)
/home/lzs/workspace/output/test.txt r,
# 如果需要访问整个目录
/home/lzs/workspace/output/** r,
# 其他必要规则(如临时目录、库路径等)
/lib/** r,
/usr/lib/** r,
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要读取该文件
确认脚本中是否有直接或间接调用 cat 或其他工具读取该文件的代码:
bash
grep -n "cat /home/lzs/workspace/output/test.txt" /home/lzs/workspace/test/test.sh
如果不需要读取该文件,移除相关代码。
如果需要,确保 AppArmor 配置中明确允许访问。
3. 检查文件权限
确认文件 /home/lzs/workspace/output/test.txt 的权限是否允许 root 用户读取:
bash
ls -l /home/lzs/workspace/output/test.txt
如果权限不足(如仅用户 1000 可读),可以调整权限:
bash
sudo chmod 644 /home/lzs/workspace/output/test.txt # 允许所有用户读取
或调整所有者:
bash
sudo chown root:root /home/lzs/workspace/output/test.txt
4. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的文件或操作:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未允许访问 /home/lzs/workspace/output/test.txt,导致 cat 命令被阻止。
推荐操作:
在 AppArmor 配置中添加 /home/lzs/workspace/output/test.txt r, 或 /home/lzs/workspace/output/** r,。
检查文件权限和所有者,确保 root 用户可以读取。
如果不需要读取该文件,移除脚本中的相关代码。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及文件读取的片段。
ls -l /home/lzs/workspace/output/test.txt 的输出。
Jul 21 18:42:35 lzs-Precision-3591 kernel: [ 7593.887966] audit: type=1400 audit(1753094555.277:439): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/home/lzs/workspace/output/test.txt" pid=138066 comm="cat" requested_mask="r" denied_mask="r" fsuid=0 ouid=1000
这个错误表明 AppArmor 拒绝了 sh 进程(由 /home/lzs/workspace/test/test.sh 触发)接收 SIGINT(中断信号,通常是 Ctrl+C 触发的信号)。以下是详细分析和解决方案:
错误原因
信号接收被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其子进程(如 sh)尝试接收 SIGINT 信号(例如用户按下 Ctrl+C),但 AppArmor 配置未明确允许。
通常,SIGINT 是进程间通信(IPC)的一部分,AppArmor 默认可能限制某些信号的传递。
可能的原因
脚本中调用了某些命令(如 trap 或直接处理信号),但 AppArmor 配置未包含信号接收规则。
可能是脚本尝试向自身或其他进程发送/接收信号,但 AppArmor 策略阻止了这一行为。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对信号接收的权限:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许接收信号(关键修改)
signal (receive) peer=/home/lzs/workspace/test/test.sh,
signal (receive) peer=unconfined, # 如果需要与其他未受限制的进程交互
# 其他必要规则(如临时目录、库路径等)
/lib/** r,
/usr/lib/** r,
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要处理信号
如果脚本中使用了 trap 或其他信号处理逻辑(例如捕获 SIGINT),确保 AppArmor 允许相关操作:
bash
grep -n "trap" /home/lzs/workspace/test/test.sh
如果不需要信号处理,可以移除相关代码。
如果需要,确保 AppArmor 配置中明确允许信号接收。
3. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行(包括 Ctrl+C 中断):
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
4. 检查进程间通信(IPC)需求
如果脚本涉及多进程通信(如 & 后台进程、wait 等),可能需要更宽松的信号规则:
plaintext
signal (receive) peer=unconfined, # 允许与未受限制的进程交互
signal (send) peer=unconfined, # 允许发送信号
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的信号或操作:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
在另一个终端尝试发送 SIGINT(Ctrl+C),检查是否被正确处理。
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本行为是否符合预期。
总结
根本原因:AppArmor 配置未允许 /home/lzs/workspace/test/test.sh 接收 SIGINT 信号,导致中断操作被阻止。
推荐操作:
在 AppArmor 配置中添加 signal (receive) peer=/home/lzs/workspace/test/test.sh,。
检查脚本中是否需要信号处理逻辑,移除不必要的代码。
如果涉及多进程通信,放宽信号规则(如允许与 unconfined 进程交互)。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及信号处理或多进程通信的片段。
audit.log 或 dmesg 中的完整错误上下文。
Jul 21 18:41:19 lzs-Precision-3591 kernel: [ 7518.120257] audit: type=1400 audit(1753094479.509:427): apparmor="DENIED" operation="signal" class="signal" profile="/home/lzs/workspace/test/test.sh" pid=136798 comm="sh" requested_mask="receive" denied_mask="receive" signal=int peer="/home/lzs/workspace/test/test.sh"
这个错误表明 AppArmor 拒绝了 cat 进程(由 /home/lzs/workspace/test/test.sh 触发)读取 /usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo 文件,这是 GNU C 库(glibc)的中文语言翻译文件(用于错误消息本地化)。以下是详细分析和解决方案:
错误原因
文件访问被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其调用的命令(如 cat)尝试读取 /usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo,但 AppArmor 配置未明确允许。
该文件是 glibc 的多语言支持文件,通常由系统工具(如 gettext 或 cat)在输出本地化错误消息时访问。
可能的原因
脚本中调用了某些命令(如 cat、grep 或其他输出错误消息的工具),这些工具尝试加载本地化翻译文件。
AppArmor 配置未包含对 /usr/share/locale-langpack/ 目录的访问规则。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对 /usr/share/locale-langpack/ 目录的读取权限:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许读取语言翻译文件(关键修改)
/usr/share/locale-langpack/** r,
# 其他必要规则(如临时目录、库路径等)
/lib/** r,
/usr/lib/** r,
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要访问语言文件
如果脚本不需要本地化支持(如输出中文错误消息),可能是某个命令(如 cat)间接触发了访问。建议:
使用 strace 跟踪脚本执行,确认哪个命令触发了文件访问:
bash
sudo strace -f -e openat /home/lzs/workspace/test/test.sh 2>&1 | grep locale-langpack
如果发现无关命令触发了访问,考虑移除或替换该命令(例如,避免使用 cat 读取可能触发本地化的文件)。
3. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
4. 检查系统语言环境配置
确认当前语言环境是否设置为中文(zh_CN):
bash
locale
如果不需要中文本地化,可以临时切换为英文环境:
bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
但更推荐在 AppArmor 配置中显式允许语言文件访问,因为其他工具可能仍会尝试加载翻译。
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的文件或操作:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未允许访问 /usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo,导致本地化相关操作被阻止。
推荐操作:
在 AppArmor 配置中添加 /usr/share/locale-langpack/** r,。
使用 strace 确认触发访问的具体命令。
如果不需要本地化支持,可以忽略此错误(但更推荐显式允许访问)。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及输出或文件读取的片段。
strace 或 audit.log 中的完整错误上下文。
Jul 21 18:39:39 lzs-Precision-3591 kernel: [ 7418.323933] audit: type=1400 audit(1753094379.713:399): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo" pid=135098 comm="cat" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
这个错误表明 AppArmor 拒绝了 sleep 进程(由 /home/lzs/workspace/test/test.sh 触发)读取 /etc/ld.so.cache 文件,这是 Linux 动态链接库的缓存文件。以下是详细分析和解决方案:
错误原因
文件访问被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其调用的命令(如 sleep)尝试读取 /etc/ld.so.cache,但 AppArmor 配置未明确允许。
/etc/ld.so.cache 是动态链接器(ld.so)使用的缓存文件,通常由 root 拥有(ouid=0),且需要读权限(requested_mask="r")。
可能的原因
脚本中调用了某些命令(如 ldconfig、动态链接的可执行文件),间接触发了对 /etc/ld.so.cache 的读取。
AppArmor 配置未包含对系统关键文件(如 /etc/ld.so.cache)的访问规则。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对 /etc/ld.so.cache 的读取权限:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许读取 /etc/ld.so.cache(关键修改)
/etc/ld.so.cache r,
# 其他必要规则(如临时目录、库路径等)
/lib/** r,
/usr/lib/** r,
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要访问 /etc/ld.so.cache
如果脚本未直接调用动态链接库相关命令,可能是某个子进程(如 sleep)间接触发了访问。建议:
使用 strace 跟踪脚本执行,确认哪个命令触发了文件访问:
bash
sudo strace -f -e openat /home/lzs/workspace/test/test.sh 2>&1 | grep ld.so.cache
如果发现无关命令触发了访问,考虑移除或替换该命令。
3. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
4. 检查系统库路径权限
确保动态链接库路径(如 /lib/、/usr/lib/)的权限正确:
bash
ls -ld /lib /usr/lib /etc/ld.so.cache
正常情况下,/etc/ld.so.cache 应为 -rw-r--r--(644),所有者可为 root。
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的文件或操作:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未允许访问 /etc/ld.so.cache,导致动态链接相关操作被阻止。
推荐操作:
在 AppArmor 配置中添加 /etc/ld.so.cache r,。
使用 strace 确认触发访问的具体命令。
如果不需要动态链接库操作,移除脚本中相关命令。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及动态链接或库调用的片段。
strace 或 audit.log 中的完整错误上下文。
(1753094292.167:364): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/etc/ld.so.cache" pid=133598 comm="sleep" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
这个错误表明 AppArmor 拒绝了 sh 进程使用 dac_read_search 能力(Capability 2),这是 Linux 的另一种权限控制机制,通常用于绕过文件读权限检查(如以 root 身份读取受限文件)。以下是详细分析和解决方案:
错误原因
dac_read_search 能力被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其调用的命令(如 sh)尝试使用 dac_read_search 能力(Capability 2),但 AppArmor 配置未明确允许。
此能力通常用于:
以 root 身份读取无权限的文件(如 /etc/shadow)。
绕过目录的执行权限检查(如 cd 到无 x 权限的目录)。
脚本可能尝试访问受限文件或目录
例如:读取 /etc/shadow、访问 /root/ 目录或调用需要 root 读权限的命令。
AppArmor 默认严格限制
除非显式配置,否则 AppArmor 会阻止进程使用任何特权能力。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对 dac_read_search 能力的允许:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许使用 dac_read_search 能力(关键修改)
capability dac_read_search,
# 其他必要规则(如文件访问、临时目录等)
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要特权读取
如果脚本不需要读取受限文件,可能是误调用了需要 root 读权限的命令(如 cat /etc/shadow)。建议:
审查脚本内容,移除不必要的特权操作。
使用 strace 跟踪脚本执行,确认哪个命令触发了能力请求:
bash
sudo strace -f -e capset /home/lzs/workspace/test/test.sh
3. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
4. 替代方案:使用 sudo 明确授权
如果脚本必须读取受限文件(如 /etc/shadow),建议:
在 AppArmor 配置中严格限制可访问的文件路径(避免过度放权)。
通过 sudo 单独授权特定命令(而非全局 dac_read_search):
bash
# 在脚本中替换特权命令为:
sudo cat /etc/shadow
在 /etc/sudoers 中配置精细权限(使用 visudo):
plaintext
lzs ALL=(root) NOPASSWD: /usr/bin/cat /etc/shadow
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的能力或文件:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未允许 dac_read_search 能力,导致脚本无法读取受限文件或目录。
推荐操作:
如果脚本确实需要特权读取,修改 AppArmor 配置添加 capability dac_read_search,。
如果不需要特权读取,检查脚本并移除相关操作。
使用 strace 或 sudo 精确控制特权命令。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及文件读取或特权命令的片段。
strace 或 audit.log 中的完整错误上下文。
Jul 21 18:28:47 lzs-Precision-3591 kernel: [ 6766.411522] audit: type=1400 audit(1753093727.799:192): apparmor="DENIED" operation="capable" class="cap" profile="/home/lzs/workspace/test/test.sh" pid=123916 comm="sh" capability=2 capname="dac_read_search"
这个错误表明 AppArmor 拒绝了 sh 进程使用 dac_override 能力(Capability),这是 Linux 的一种权限控制机制,通常用于绕过文件权限检查(如以 root 身份读写无权限的文件)。以下是详细分析和解决方案:
错误原因
dac_override 能力被拒绝
您的脚本 /home/lzs/workspace/test/test.sh 或其调用的命令(如 sh)尝试使用 dac_override 能力(Capability 1),但 AppArmor 配置未明确允许。
此能力通常用于:
以 root 身份修改文件所有者/权限(如 chown、chmod)。
绕过普通用户的文件读/写限制。
脚本可能执行了特权操作
例如:尝试修改 /etc/ 下的文件、访问受限设备或调用需要 root 权限的命令。
AppArmor 默认严格限制
除非显式配置,否则 AppArmor 会阻止进程使用任何特权能力。
解决方案
1. 修改 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对 dac_override 能力的允许:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许使用 dac_override 能力(关键修改)
capability dac_override,
# 其他必要规则(如文件访问、临时目录等)
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 检查脚本是否真的需要特权
如果脚本不需要修改文件权限或所有者,可能是误调用了需要 root 权限的命令(如 chown、systemctl)。建议:
审查脚本内容,移除不必要的特权操作。
使用 strace 跟踪脚本执行,确认哪个命令触发了能力请求:
bash
sudo strace -f -e capset /home/lzs/workspace/test/test.sh
3. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
4. 替代方案:使用 sudo 明确授权
如果脚本必须执行特权操作(如修改系统文件),建议:
在 AppArmor 配置中严格限制可访问的文件路径(避免过度放权)。
通过 sudo 单独授权特定命令(而非全局 dac_override):
bash
# 在脚本中替换特权命令为:
sudo chown root:root /path/to/file
在 /etc/sudoers 中配置精细权限(使用 visudo):
plaintext
lzs ALL=(root) NOPASSWD: /bin/chown root:root /specific/path
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的能力或文件:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未允许 dac_override 能力,导致脚本无法执行特权操作。
推荐操作:
如果脚本确实需要特权,修改 AppArmor 配置添加 capability dac_override,。
如果不需要特权,检查脚本并移除相关操作。
使用 strace 或 sudo 精确控制特权命令。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
脚本中涉及文件操作或特权命令的片段。
strace 或 audit.log 中的完整错误上下文。
Jul 21 18:24:53 lzs-Precision-3591 kernel: [ 6532.392636] audit: type=1400 audit(1753093493.778:184): apparmor="DENIED" operation="capable" class="cap" profile="/home/lzs/workspace/test/test.sh" pid=119923 comm="sh" capability=1 capname="dac_override"
这个错误表明 AppArmor 再次拒绝了 sh 进程访问 /etc/locale.alias 文件,这是国际化(i18n)配置的另一个关键文件。以下是详细分析和解决方案:
错误原因
AppArmor 配置未覆盖 /etc/locale.alias
您的 AppArmor 配置文件 /home/lzs/workspace/test/test.sh 未明确允许访问 /etc/locale.alias,导致 glibc 在初始化语言环境时被阻止。
国际化文件依赖链
当脚本或其调用的程序(如 sh)尝试加载语言环境时,会依次访问:
/etc/locale.alias(别名映射文件)
/usr/share/locale/(基础翻译文件)
/usr/share/locale-langpack/(扩展翻译文件)
之前解决了 /usr/share/locale-langpack/ 的访问问题,但未覆盖 /etc/locale.alias。
脚本以 root 身份运行(fsuid=0)
通过 sudo aa-exec 运行的脚本继承了 root 权限,但 AppArmor 仍会按配置文件限制访问,即使对 root 生效。
解决方案
1. 更新 AppArmor 配置文件
编辑 /etc/apparmor.d/home.lzs.workspace.test.test.sh,添加对 /etc/locale.alias 的读取权限:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许访问国际化文件(关键修改)
/etc/locale.alias r, # 新增:允许读取别名文件
/usr/share/locale/** r,
/usr/share/locale-langpack/** r,
# 其他必要规则(如临时文件、库等)
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 验证文件权限
确认 /etc/locale.alias 对所有用户可读(通常应为 644):
bash
ls -l /etc/locale.alias
输出示例:
plaintext
-rw-r--r-- 1 root root 2500 Oct 10 10:00 /etc/locale.alias
如果权限不足(如 600),需修复权限:
bash
sudo chmod 644 /etc/locale.alias
3. 临时绕过国际化(测试用)
如果脚本不需要国际化支持,强制使用 C 语言环境(避免加载任何 .mo 或别名文件):
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- env LC_ALL=C /home/lzs/workspace/test/test.sh
如果问题解决,说明确实是国际化文件访问导致的问题,需按方案 1 调整 AppArmor 规则。
4. 检查系统语言环境配置
确认系统默认语言环境是否有效:
bash
locale
如果输出包含 LANG= 或 LC_*= 但指向无效路径(如已删除的语言包),可能导致频繁访问国际化文件。重置为通用配置:
bash
sudo update-locale LANG=en_US.UTF-8
5. 监控 AppArmor 日志
实时查看拒绝事件,确认是否还有其他被阻止的文件:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg:
bash
dmesg | grep apparmor
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未放行 /etc/locale.alias,导致语言环境初始化失败。
推荐操作:
修改 AppArmor 配置,添加 /etc/locale.alias r 规则。
确保文件权限为 644。
如果不需要国际化,通过 env LC_ALL=C 临时绕过。
检查系统语言环境配置是否有效。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
locale 命令的输出。
ls -l /etc/locale.alias 的输出。
[ 6418.227931] audit: type=1400 audit(1753093379.613:177): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/etc/locale.alias" pid=117949 comm="sh" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
这个错误表明 AppArmor 拒绝了 sh 进程访问 /usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo 文件,导致脚本可能因国际化(i18n)文件加载失败而异常终止。以下是详细分析和解决方案:
错误原因
AppArmor 配置限制
您的 AppArmor 配置文件 /home/lzs/workspace/test/test.sh 未明确允许访问 /usr/share/locale-langpack/ 目录下的文件。
当脚本或其调用的程序(如 sh)尝试读取国际化文件(如 libc.mo)时,AppArmor 会阻止访问。
脚本依赖国际化文件
脚本或其调用的命令(如 echo、printf 或其他工具)可能依赖 glibc 的国际化支持,需要加载 .mo 文件(多语言翻译文件)。
路径未覆盖
默认情况下,AppArmor 配置可能仅放行了脚本本身和必要的二进制文件,但未包含 /usr/share/locale* 等路径。
解决方案
1. 修改 AppArmor 配置文件
编辑或创建 AppArmor 配置文件(如 /etc/apparmor.d/home.lzs.workspace.test.test.sh),添加对国际化文件的访问规则:
plaintext
# /etc/apparmor.d/home.lzs.workspace.test.test.sh
profile /home/lzs/workspace/test/test.sh {
# 允许读取脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行 /bin/sh 和相关命令
/bin/sh ix,
/usr/bin/* ix,
# 允许访问国际化文件(关键修改)
/usr/share/locale/** r,
/usr/share/locale-langpack/** r,
# 其他必要规则(如临时文件、库等)
/tmp/** rw,
/var/tmp/** rw,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
2. 临时放宽 AppArmor 限制(测试用)
如果问题紧急,可以临时切换 AppArmor 到 complain 模式(仅记录不阻止):
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
测试脚本是否能正常运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
确认无报错后,再调整配置文件并切换回 enforce 模式:
bash
sudo aa-enforce /home/lzs/workspace/test/test.sh
3. 检查脚本是否依赖特定语言环境
如果脚本不需要国际化支持,可以强制使用 C 语言环境(避免加载 .mo 文件):
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- env LC_ALL=C /home/lzs/workspace/test/test.sh
如果问题解决,说明确实是国际化文件访问导致的问题,需按方案 1 调整 AppArmor 规则。
4. 验证 AppArmor 日志
实时监控 AppArmor 拒绝事件:
bash
sudo tail -f /var/log/audit/audit.log | grep apparmor
或使用 dmesg 查看最近日志:
bash
dmesg | grep apparmor
5. 检查文件是否存在
确认被拒绝的文件路径是否存在:
bash
ls -l /usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo
如果路径不存在,可能是系统未安装完整的语言包。安装中文语言包(Ubuntu/Debian):
bash
sudo apt install language-pack-zh-hans
验证步骤
更新 AppArmor 配置后,重新加载并测试:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
检查是否仍有 DENIED 日志:
bash
sudo dmesg | grep apparmor
如果问题解决,确认脚本输出是否符合预期。
总结
根本原因:AppArmor 配置未放行 /usr/share/locale* 路径,导致脚本无法加载国际化文件。
推荐操作:
修改 AppArmor 配置,添加 /usr/share/locale/** r 和 /usr/share/locale-langpack/** r 规则。
如果不需要国际化,通过 env LC_ALL=C 临时绕过。
检查系统是否安装了完整的语言包。
如果问题仍未解决,请提供以下信息:
完整的 AppArmor 配置文件内容。
ls -l /usr/share/locale-langpack/zh_CN/LC_MESSAGES/ 的输出。
脚本中是否显式调用了需要国际化的命令(如 gettext)。
[ 6101.855345] audit: type=1400 audit(1753093063.239:163): apparmor="DENIED" operation="open" class="file" profile="/home/lzs/workspace/test/test.sh" name="/usr/share/locale-langpack/zh_CN/LC_MESSAGES/libc.mo" pid=112383 comm="sh" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
这个错误表明 aa-exec 虽然成功启动了,但目标脚本 /home/lzs/workspace/test/test.sh 没有可执行权限,导致无法运行。以下是详细分析和解决方案:
错误原因
文件权限不足
脚本文件 /home/lzs/workspace/test/test.sh 可能缺少可执行权限(x 权限)。
即使通过 aa-exec 指定了 AppArmor 配置,系统仍会检查基本的文件权限。
AppArmor 配置未生效
如果配置文件未正确加载,aa-exec 可能无法按预期限制或放行权限(但当前错误是基础权限问题,与 AppArmor 无关)。
文件系统挂载为 noexec
如果 /home 或脚本所在分区挂载时添加了 noexec 选项,即使文件有 x 权限也无法执行(较少见)。
解决方案
1. 添加可执行权限
运行以下命令为脚本添加可执行权限:
bash
chmod +x /home/lzs/workspace/test/test.sh
再次尝试通过 aa-exec 运行:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
2. 检查文件权限和所有者
确认脚本的所有者和权限:
bash
ls -l /home/lzs/workspace/test/test.sh
输出示例:
plaintext
-rwxr-xr-- 1 lzs lzs 120 Oct 10 10:00 /home/lzs/workspace/test/test.sh
确保所有者(lzs)有 rwx 权限,其他用户至少有 rx 权限(如果通过 sudo 运行,通常不受其他用户权限影响)。
3. 验证 AppArmor 配置
如果脚本仍无法运行,可能是 AppArmor 配置限制了访问。检查配置文件是否包含对脚本路径的明确允许:
plaintext
# /etc/apparmor.d/home.lzs.workspace.test.test.sh
profile /home/lzs/workspace/test/test.sh {
# 允许读取和执行脚本本身
/home/lzs/workspace/test/test.sh r,
# 允许执行脚本(如果通过解释器运行)
/bin/bash ix,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
4. 检查文件系统挂载选项
确认分区是否挂载为 noexec:
bash
mount | grep /home
如果输出包含 noexec,需重新挂载为可执行(需 root 权限):
bash
sudo mount -o remount,exec /home
注意:修改挂载选项可能影响安全性,建议优先修复文件权限。
5. 直接运行测试
绕过 aa-exec 直接运行脚本,确认是否为 AppArmor 问题:
bash
/home/lzs/workspace/test/test.sh
如果仍报 Permission denied,则问题与 AppArmor 无关,需检查文件权限或 SELinux(如果启用)。
6. 检查 SELinux 状态(如适用)
如果系统启用 SELinux,可能阻止执行:
bash
getenforce
如果输出为 Enforcing,尝试临时禁用测试:
bash
sudo setenforce 0
/home/lzs/workspace/test/test.sh
若问题解决,需调整 SELinux 策略而非 AppArmor。
验证步骤
确认脚本权限:
bash
ls -l /home/lzs/workspace/test/test.sh
尝试直接运行:
bash
/home/lzs/workspace/test/test.sh
通过 aa-exec 运行并检查 AppArmor 日志:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
sudo dmesg | grep apparmor
总结
根本原因:脚本文件缺少可执行权限(x),或文件系统挂载为 noexec。
推荐操作:
运行 chmod +x /home/lzs/workspace/test/test.sh。
确认文件权限和所有者正确。
检查 AppArmor 配置是否允许执行脚本。
排除文件系统或 SELinux 的干扰。
如果问题仍未解决,请提供以下信息:
ls -l /home/lzs/workspace/test/test.sh 的输出。
mount | grep /home 的输出。
sudo aa-status 中是否显示您的配置已加载。
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
/bin/sh: /home/lzs/workspace/test/test.sh: Permission denied
这个错误表明 aa-exec 在尝试运行 /home/lzs/workspace/test/test.sh 时,系统无法找到动态链接库 libtinfo.so.6。这通常是由于环境配置问题或库文件缺失导致的。以下是详细的解决方案:
错误原因分析
动态链接库缺失
libtinfo.so.6 是 ncurses 或 libtinfo 库的一部分,通常由 libncurses6 或 libtinfo6 软件包提供。
如果系统未安装该库,或安装的版本不匹配(如 libtinfo.so.5 而非 libtinfo.so.6),会导致此错误。
aa-exec 的环境隔离
aa-exec 会以指定的 AppArmor 配置启动进程,但可能不会继承完整的用户环境(如 LD_LIBRARY_PATH),导致动态链接器无法找到库文件。
脚本解释器问题
如果 test.sh 的 shebang(如 #!/bin/bash)指向的解释器依赖 libtinfo.so.6,但该库在 aa-exec 的环境中不可见,也会触发此错误。
解决方案
1. 安装缺失的库
Ubuntu/Debian:
bash
sudo apt update
sudo apt install libtinfo6 # 或 libncurses6
CentOS/RHEL:
bash
sudo yum install ncurses-libs
Arch Linux:
bash
sudo pacman -S ncurses
2. 检查库文件是否存在
确认库文件是否已安装但路径未包含在动态链接器的搜索路径中:
bash
ldconfig -p | grep libtinfo.so.6
如果无输出,尝试手动创建符号链接(假设库文件实际存在但版本不同):
bash
sudo ln -s /usr/lib/libtinfo.so.5 /usr/lib/libtinfo.so.6
注意:此方法需确保库版本兼容,否则可能导致运行时错误。
3. 显式指定库路径
在运行 aa-exec 前,临时设置 LD_LIBRARY_PATH 包含库文件所在目录:
bash
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
替换 /usr/lib/x86_64-linux-gnu 为实际的库路径(可通过 ldconfig -v | grep libtinfo 查找)。
4. 直接运行脚本(绕过 aa-exec 测试)
先确认脚本本身能否正常运行:
bash
/home/lzs/workspace/test/test.sh
如果同样报错,说明问题与 AppArmor 无关,需修复环境依赖。
5. 检查 AppArmor 配置
如果库文件路径受限(如 /usr/lib 未在配置中允许),需在 AppArmor 配置文件中添加规则:
plaintext
# /etc/apparmor.d/home.lzs.workspace.test.test.sh
profile /home/lzs/workspace/test/test.sh {
# 允许访问库文件路径
/usr/lib/** rm,
/lib/** rm,
}
重新加载配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
6. 使用 strace 调试
跟踪进程启动过程,定位库加载失败的具体原因:
bash
strace -f -e openat sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh 2>&1 | grep libtinfo
验证步骤
确认库文件已安装且路径正确:
bash
ls -l /usr/lib*/libtinfo.so*
尝试直接运行脚本(不通过 aa-exec)以排除环境问题。
使用 LD_DEBUG=libs 查看动态链接器行为:
bash
LD_DEBUG=libs sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
总结
根本原因:aa-exec 的环境缺少 libtinfo.so.6 库,或动态链接器无法找到该库。
推荐操作:
安装 libtinfo6 或兼容版本。
通过 LD_LIBRARY_PATH 显式指定库路径。
检查 AppArmor 配置是否限制了必要的库访问路径。
如果问题仍未解决,请提供以下信息以便进一步分析:
操作系统版本(cat /etc/os-release)。
ldconfig -p | grep libtinfo 的输出。
完整的 aa-exec 命令及错误日志。
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
/bin/sh: error while loading shared libraries: libtinfo.so.6: cannot open shared object file: No such file or directory
从您提供的命令和输出来看,虽然您尝试重新加载 AppArmor 配置文件(sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh),但目标脚本 test.sh 仍然以 unconfined 模式运行,未受到您定义的 AppArmor 配置文件的限制。以下是详细分析和解决方案:
问题原因
配置文件未正确关联到进程
您的配置文件路径为 /etc/apparmor.d/home.lzs.workspace.test.test.sh,但 AppArmor 要求配置文件中的 profile 名称必须与目标进程的路径或名称严格匹配。
当前 ps -auxZ 输出显示 test.sh 以 unconfined 运行,说明 AppArmor 未识别到对应的配置文件。
配置文件可能未生效
如果配置文件语法错误或路径不匹配,apparmor_parser 可能静默失败(即使未报错)。
解决方案
1. 检查配置文件内容
确保配置文件中声明的 profile 名称与目标脚本的路径或名称一致。例如:
plaintext
# /etc/apparmor.d/home.lzs.workspace.test.test.sh
profile /home/lzs/workspace/test/test.sh {
# 您的规则(如 deny)
deny /home/lzs/workspace/output/** rwkl,
}
关键点:profile 后的路径必须与 ps -auxZ 中显示的进程路径(/home/lzs/workspace/test/test.sh)完全一致。
2. 强制重新加载并验证语法
删除缓存后重新加载配置:
bash
sudo rm /etc/apparmor.d/cache/home.lzs.workspace.test.test.sh
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
检查语法错误:
bash
sudo apparmor_parser -Q /etc/apparmor.d/home.lzs.workspace.test.test.sh
3. 确认配置是否生效
列出已加载的配置,检查是否包含您的配置文件:
bash
sudo apparmor_status | grep test.sh
如果配置未加载,可能是路径或名称不匹配。
4. 直接指定进程的 AppArmor 配置
如果脚本是通过解释器(如 bash)运行的,可能需要为解释器(如 /usr/bin/bash)定义配置,或通过 aa-exec 强制绑定配置:
bash
sudo aa-exec -p /home/lzs/workspace/test/test.sh -- /home/lzs/workspace/test/test.sh
5. 调试模式
启用调试日志,观察配置加载过程:
bash
sudo apparmor_parser -v --debug /etc/apparmor.d/home.lzs.workspace.test.test.sh
验证步骤
重启脚本并检查状态
重新运行脚本后,通过以下命令确认其 AppArmor 状态:
bash
ps -auxZ | grep test.sh
预期输出应显示配置文件名称(如 home.lzs.workspace.test.test.sh),而非 unconfined。
触发违规测试
在脚本中添加尝试访问受限路径的操作(如 cat /etc/shadow),然后检查审计日志:
bash
sudo dmesg | grep apparmor
常见问题
配置文件命名规则
AppArmor 默认将配置文件路径中的 / 替换为 .(如 /etc/apparmor.d/home.lzs.workspace.test.test.sh 对应配置名 home.lzs.workspace.test.test.sh)。确保 profile 声明与之一致。
解释器脚本的限制
如果 test.sh 是通过 bash test.sh 运行的,AppArmor 可能仅限制 bash 而非脚本本身。建议直接为脚本路径定义配置。
总结
当前问题表明 AppArmor 配置文件未正确关联到 test.sh 进程。请按以下顺序排查:
确认配置文件中的 profile 名称与脚本路径一致。
强制重新加载配置并检查语法。
使用 aa-exec 或直接路径确保进程受配置限制。
通过审计日志验证规则是否生效。
如果仍有问题,请提供配置文件内容和 sudo apparmor_parser -v --debug 的输出以便进一步分析。
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
lzs@lzs-Precision-3591:~/workspace/test$ ps -aux -Z | grep unconfined | grep test
unconfined kernoops 1545 0.0 0.0 13092 2120 ? Ss 16:36 0:00 /usr/sbin/kerneloops --test
unconfined lzs 97467 0.0 0.0 13516 3872 pts/1 S+ 18:03 0:00 sh test.sh
unconfined lzs 98592 0.0 0.0 12644 2288 pts/2 S+ 18:04 0:00 grep --color=auto test
追踪 AppArmor 违规行为
AppArmor 会将事件记录到系统的审计日志中。对于 Ubuntu 16.04 及更早版本的系统,此功能默认由 systemd 处理;对于 SuSE/SLES 系统,日志位于 /var/log/audit/audit.log。重新加载配置文件后,您应能看到许多类似于以下 wkhtmltopdf 的记录:
1月12日 17:01:57 ip-192-0-2-121 audit[19164]: AVC apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/local/bin/wkhtmltopdf" pid=19164 comm="apparmor_parser"
在较新版本的 AppArmor 中,记录可能如下:
1月12日 17:01:57 ip-192-0-2-121 audit[19164]: AVC apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" operation="profile_replace" profile="unconfined" name="/usr/local/bin/wkhtmltopdf" pid=19164 comm="apparmor_parser"
违规行为会显示在同一日志中:
1月12日 17:42:03 ip-192-0-2-121 audit[19164]: AVC apparmor="DENIED" operation="open" profile="/usr/local/bin/wkhtmltopdf" name="/etc/passwd" pid=12112 comm="wkhtmltopdf" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
此记录表明,AppArmor 阻止了尝试读取 /etc/passwd 的操作。
翻译:Track AppArmor violations
AppArmor will log events to the system’s audit-log. For Ubuntu systems 16.04 and older this by default is handled in systemd. For SuSE/SLES system, this is found in /var/log/audit/audit.log. After reloading your profiles you should see many entries similar to this wkhtmltopdf one:
Jan 12 17:01:57 ip-192-0-2-121 audit[19164]: AVC apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/local/bin/wkhtmltopdf" pid=19164 comm="apparmor_parser"
Or in newer AppArmor versions:
Jan 12 17:01:57 ip-192-0-2-121 audit[19164]: AVC apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" operation="profile_replace" profile="unconfined" name="/usr/local/bin/wkhtmltopdf" pid=19164 comm="apparmor_parser"
Violations will show up the same log:
Jan 12 17:42:03 ip-192-0-2-121 audit[19164]: AVC apparmor="DENIED" operation="open" profile="/usr/local/bin/wkhtmltopdf" name="/etc/passwd" pid=12112 comm="wkhtmltopdf" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
Which shows that AppArmor denied an attempt to read /etc/passwd.
从您提供的日志来看,AppArmor 并未实际加载或更新您的配置文件,而是跳过了替换操作(profile_replace),原因是当前配置与已加载的配置完全相同(same as current profile, skipping)。这解释了为什么您的 deny 规则未生效——配置根本未被重新加载。
问题原因分析
配置未修改
如果您直接运行 sudo apparmor_parser 加载同一个配置文件,而文件内容未更改,AppArmor 会检测到配置无变化并跳过加载。
日志中的 profile="unconfined" 表示当前进程(apparmor_parser)本身未受 AppArmor 限制,但目标配置 /home/lzs/workspace/test/test.sh 的加载被跳过。
配置路径或名称不匹配
确保您加载的配置文件路径与日志中的 name="/home/lzs/workspace/test/test.sh" 完全一致。
如果配置文件中声明的名称(如 profile 或 path)与文件名或目标路径不符,可能导致加载失败。
语法错误未被检测
如果配置文件存在语法错误,apparmor_parser 可能会静默失败(尤其是使用 --debug 时)。建议显式检查语法:
bash
sudo apparmor_parser -Q /etc/apparmor.d/home.lzs.workspace.test.test.sh
解决方案
1. 强制重新加载配置
使用 -r(replace)或 -R(reload)选项强制覆盖现有配置:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
如果仍提示 same as current profile,说明文件内容确实未变化。
2. 检查配置文件内容
确保配置文件中明确声明了目标路径,例如:
plaintext
profile /home/lzs/workspace/test/test.sh {
# 您的规则(包括 deny)
deny /home/lzs/workspace/output/** rwkl,
}
关键点:配置文件中的 profile 名称必须与日志中的 name="..." 一致。
3. 验证配置是否生效
检查当前加载的配置:
bash
sudo apparmor_status | grep test.sh
或查看进程的 AppArmor 状态:
bash
ps auxZ | grep test.sh # 检查目标进程的配置文件是否匹配
4. 调试模式深入检查
使用 --debug 时,添加 -v 参数输出详细日志:
bash
sudo apparmor_parser -v --debug /etc/apparmor.d/home.lzs.workspace.test.test.sh
观察输出中是否有 Parsed rules 或 Rejected rules 的提示。
5. 临时切换到 Complain 模式
如果怀疑规则过于严格导致配置未加载,先切换到 complain 模式记录违规行为:
bash
sudo aa-complain /home/lzs/workspace/test/test.sh
运行脚本后检查日志:
bash
sudo dmesg | grep apparmor
常见误区
文件名与配置内容不一致
例如:配置文件名为 home.lzs.workspace.test.test.sh,但内部声明的 profile 名为 test.sh,可能导致加载异常。
通配符冲突
如果同时存在 /** 和 deny 规则,宽泛的 allow 可能覆盖 deny。建议优先测试精简规则。
未重启服务
修改配置后,重启 AppArmor 服务以确保生效:
bash
sudo systemctl restart apparmor
下一步建议
确认配置文件内容:检查 deny 规则是否在正确的 profile 块内。
强制重新加载:使用 -r 或删除旧配置后再加载:
bash
sudo rm /etc/apparmor.d/cache/home.lzs.workspace.test.test.sh
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
检查日志:通过 audit.log 或 journalctl 确认是否有 DENIED 记录。
如果问题仍未解决,请提供以下信息以便进一步诊断:
完整的配置文件内容(去除敏感信息)。
运行 sudo aa-status 的输出。
触发 deny 规则的具体操作(如执行的命令或脚本行为)。
Jul 21 16:16:21 lzs-Precision-3591 audit[1204181]: AVC apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" profile="unconfined" name="/home/lzs/workspace/test/test.sh" pid=1204181 comm="apparmor_parser"
Jul 21 16:16:21 lzs-Precision-3591 kernel: audit: type=1400 audit(1753085781.059:149): apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" profile="unconfined" name="/home/lzs/workspace/test/test.sh" pid=1204181 comm="apparmor_parser"
针对您提供的 apparmor_parser --debug 输出和 deny 规则未生效的问题,结合AppArmor的配置原理和常见调试方法,以下是可能的原因和解决方案:
1. 规则语法问题
问题:AppArmor的deny规则需要明确匹配路径和权限,且路径通配符需谨慎使用。
您的配置中 link: (/**) 允许所有路径的符号链接创建,这可能覆盖了其他deny规则。
如果deny规则的路径或权限不匹配实际访问行为,规则不会生效。
解决方案:
精确路径:替换/**为具体路径,例如:
plaintext
deny /home/lzs/workspace/output/** l, # 仅禁止输出目录的符号链接
明确权限:确保deny的权限(如r、w、x、l等)与操作匹配。例如,禁止读取需显式写deny /path r,。
2. 规则作用域冲突
问题:AppArmor规则按顺序匹配,后续规则可能覆盖前面的deny。
如果allow规则在deny之后,或包含更宽泛的路径(如/**),会导致deny失效。
解决方案:
调整规则顺序:将deny规则放在allow之前,或使用更具体的路径。
避免通配符滥用:减少/**的使用,改用精确路径或目录级通配(如/path/*)。
3. 配置文件未重新加载
问题:修改配置文件后未重新加载,导致旧规则生效。
解决方案:
重新加载配置文件:
bash
sudo apparmor_parser -r /etc/apparmor.d/home.lzs.workspace.test.test.sh
或重启AppArmor服务:
bash
sudo systemctl restart apparmor
4. 工作模式影响
问题:若配置文件处于complain模式,deny规则仅记录违规行为而不阻止操作。
解决方案:
检查当前模式:
bash
sudo aa-status
切换到enforce模式:
bash
sudo aa-enforce /etc/apparmor.d/home.lzs.workspace.test.test.sh
5. 日志排查
问题:AppArmor的违规行为通常记录在日志中,但未被查看。
解决方案:
查看系统日志:
bash
sudo journalctl -xe | grep apparmor
或审计日志:
bash
sudo cat /var/log/audit/audit.log | grep apparmor
根据日志中的DENIED信息调整规则。
6. 测试建议
最小化测试:创建一个仅包含deny规则的简单配置文件,逐步添加其他规则,定位冲突点。
示例配置:
plaintext
/home/lzs/workspace/test/test.sh {
# 仅允许读取脚本自身
/home/lzs/workspace/test/test.sh r,
# 禁止输出目录的所有操作
deny /home/lzs/workspace/output/** rwkl,
# 允许特定文件读取(可选)
/home/lzs/workspace/input/data.txt r,
}
总结
您的deny规则未生效可能是由于路径通配符过于宽泛、规则顺序冲突或配置未重新加载。建议按以下步骤排查:
检查日志确认违规行为是否被记录。
精简路径通配符,避免/**覆盖deny。
重新加载配置并切换到enforce模式。
通过最小化测试验证规则效果。
如果问题仍未解决,可提供具体的deny规则和日志片段,以便进一步分析。
为什么我上面的deny未生效
It looks like you're debugging an AppArmor profile for a shell script located at /home/lzs/workspace/test/test.sh. The output you've shared shows the parsed AppArmor profile rules for this script. Here's a breakdown of what this means:
Debug Output Explanation:
Profile Name:
Name: /home/lzs/workspace/test/test.sh
This is the name of the AppArmor profile, which corresponds to the path of the executable (test.sh).
Mode:
The Mode field is empty in the first line, which might indicate the default enforcement mode (likely enforce or complain depending on how the profile was loaded).
Entries:
The profile contains two main access rules:
First Entry:
Mode: rk:rk Name: (/home/lzs/workspace/test/test.sh)
This grants the script read (r) and execute (k) permissions on itself (/home/lzs/workspace/test/test.sh).
rk:rk means the profile allows the script to be read and executed by the owner (likely lzs).
Second Entry:
Mode: ralk:ralk Name: (/home/lzs/workspace/output/**)
link: (/**)
This grants read (r), append (a), link (l), and execute (k) permissions on all files and directories under /home/lzs/workspace/output/**.
ralk:ralk suggests the owner (likely lzs) has these permissions.
The link: (/**) part indicates that the script can also create or follow symbolic links anywhere in the filesystem (/**), which is a broad permission and could be a security concern.
Observations:
Broad Permissions:
The link: (/**) rule is very permissive and could allow the script to bypass filesystem restrictions by creating or following symlinks anywhere. This is often undesirable from a security standpoint.
The ralk permissions on /home/lzs/workspace/output/** are also quite broad, allowing the script to read, append to, link, and execute files in that directory.
Potential Issues:
If this is a test script, the broad permissions might be intentional, but in a production environment, you'd typically want to restrict access further (e.g., only allow reading/writing to specific files or directories).
The link: (/**) rule is particularly risky and should be reviewed.
Recommendations:
Restrict Symlink Permissions:
If the script doesn't need to create or follow symlinks outside of /home/lzs/workspace/output/, remove the link: (/**) rule or restrict it to a specific directory.
Narrow Down Permissions:
Instead of /** for links, specify a more restrictive path, e.g.:
link: (/home/lzs/workspace/output/**)
Similarly, review whether append (a) and execute (k) are truly needed for files in /home/lzs/workspace/output/**.
Test in Complain Mode:
Before enforcing the profile, run AppArmor in complain mode to log potential violations without blocking them:
sudo aa-complain /home/lzs/workspace/test/test.sh
After testing, you can switch back to enforce mode:
sudo aa-enforce /home/lzs/workspace/test/test.sh
Audit the Profile:
Use aa-logprof to analyze logs and refine the profile:
sudo aa-logprof
Example of a More Restrictive Profile:
If the script only needs to read itself and write to specific files in /home/lzs/workspace/output/, a tighter profile might look like this:
/home/lzs/workspace/test/test.sh {
# Allow reading and executing the script itself
/home/lzs/workspace/test/test.sh rk,
# Allow reading and writing to specific files in output/
/home/lzs/workspace/output/ r,
/home/lzs/workspace/output/** rw,
# Deny symlinks outside of output/ (or restrict further)
deny /home/lzs/workspace/output/** l,
}
Let me know if you'd like help refining this profile further!
sudo apparmor_parser --debug /etc/apparmor.d/home.lzs.workspace.test.test.sh
----- Debugging built structures -----
Name: /home/lzs/workspace/test/test.sh
Mode:
--- Entries ---
Mode: rk:rk Name: (/home/lzs/workspace/test/test.sh)
Mode: ralk:ralk Name: (/home/lzs/workspace/output/**)
link: (/**)
Writing Desk
Document Hub
Image Studio
Translation
Prompts
AI-generated content cannot be guaranteed to be accurate. Please refer to the "Terms of Service" and "Privacy Policy" for details.