如何在AppArmor配置文件中允许程序执行特定的系统调用?
美国、香港服务器
如何在AppArmor配置文件中允许程序执行特定的系统调用?
12-29 来源:
在 AppArmor 配置文件中允许程序执行特定系统调用,核心是通过 syscall 规则精准声明允许的系统调用名称 / 编号,同时遵循「最小权限原则」—— 仅开放程序必需的系统调用,拒绝所有未显式允许的调用(Ubuntu 24.04 需依赖 AppArmor 3.0+ 版本,默认已满足)。以下是完整配置方法、示例和关键注意事项:
一、核心前提:理解 AppArmor 系统调用控制
1. 适用条件
AppArmor 对系统调用的限制需满足:
配置文件需启用 abi 声明(适配系统内核版本,Ubuntu 24.04 默认可用);
仅支持 Linux 内核 4.15+ 的系统调用过滤(Ubuntu 24.04 内核 6.8 完全兼容);
系统调用规则需写在进程配置块内,优先级高于默认拒绝规则。
2. 核心语法
允许特定系统调用的规则格式:
apparmor
# 单系统调用
syscall [调用名称/编号],
# 多个系统调用(逗号分隔)
syscall [调用1], [调用2], [调用3],
# 带条件的系统调用(如仅允许特定参数)
syscall [调用名称] args=[参数条件],
关键说明:
调用名称:优先使用标准系统调用名(如 openat、socket、fork),而非编号(更易维护);
末尾逗号:规则末尾必须加逗号(,),否则语法报错;
参数条件(可选):精准限制系统调用的参数(如仅允许 socket 创建 TCP 套接字)。
二、步骤 1:确定程序需要的系统调用
编写规则前,需先梳理程序依赖的系统调用(避免遗漏导致程序崩溃),常用方法:
方法 1:用 strace 追踪程序的系统调用
bash
运行
# 追踪程序所有系统调用,输出到日志文件
sudo strace -o myapp_syscalls.log -e trace=all /usr/local/bin/myapp
# 查看日志,筛选程序实际调用的系统调用
cat myapp_syscalls.log | grep -E "^[a-z]+" | sort | uniq
示例输出(程序常用系统调用):
plaintext
openat
read
write
close
socket
connect
fork
execve
方法 2:参考系统调用列表
Linux 系统调用可通过 man syscalls 查看,或访问 Linux Syscall Table 核对名称 / 编号。
三、步骤 2:配置文件中允许特定系统调用(示例)
以下以自定义程序 /usr/local/bin/myapp 为例,演示不同场景的系统调用允许规则。
场景 1:允许单个系统调用(如 openat)
需求:仅允许程序执行 openat(打开文件)系统调用。配置文件 /etc/apparmor.d/usr.local.bin.myapp 内容:
apparmor
/usr/local/bin/myapp {
# 基础系统库/程序自身权限(必选)
/lib/** r,
/usr/lib/** r,
/usr/local/bin/myapp mr,
# 允许单个系统调用:openat
syscall openat,
# 敏感目录拒绝+兜底规则
deny /etc/shadow r,
deny /** w,
}
场景 2:允许多个系统调用(如文件操作类)
需求:允许程序执行文件相关的 openat、read、write、close 系统调用。核心规则:
apparmor
/usr/local/bin/myapp {
# 基础权限(省略)
# 允许多个系统调用(逗号分隔)
syscall openat, read, write, close,
# 兜底规则
deny /** w,
}
场景 3:允许带参数条件的系统调用(精准控制)
需求:仅允许程序通过 socket 系统调用创建 TCP 套接字(禁止 UDP/RAW 等)。核心规则(需指定 args 条件):
apparmor
/usr/local/bin/myapp {
# 基础权限(省略)
# 允许socket调用,且仅创建AF_INET(IPv4)+SOCK_STREAM(TCP)套接字
syscall socket args=(domain=AF_INET, type=SOCK_STREAM),
# 允许connect调用(配合socket使用)
syscall connect,
# 兜底规则
deny network udp,
deny /** w,
}
常用 args 条件说明:
系统调用 常用参数条件 示例
socket domain=AF_INET(IPv4)、type=SOCK_STREAM(TCP)、type=SOCK_DGRAM(UDP) args=(domain=AF_INET, type=SOCK_STREAM)
openat flags=O_RDONLY(只读打开)、mode=0644(文件权限) args=(flags=O_RDONLY)
场景 4:允许特定类别系统调用(批量)
AppArmor 支持按「系统调用类别」批量允许(需启用 abi 声明),示例:
apparmor
/usr/local/bin/myapp {
# 声明ABI(适配内核版本)
# 允许所有文件操作类系统调用(类别名:file)
syscall @file,
# 允许所有网络类系统调用(类别名:net)
# syscall @net,
# 基础权限+兜底规则
/lib/** r,
deny /** w,
}
常用系统调用类别:
类别名 包含的系统调用
@file 文件操作(openat、read、write、close、unlink 等)
@net 网络操作(socket、connect、bind、send、recv 等)
@process 进程操作(fork、execve、wait4 等)
四、关键注意事项(避免配置失效 / 程序崩溃)
1. 必须声明 ABI(批量类别 / 参数条件需用)
若使用系统调用类别(如 @file)或参数条件(args),需在配置块顶部声明 ABI 版本:
apparmor
/usr/local/bin/myapp {
# 声明ABI(Ubuntu 24.04 用 3.0)
# 其他规则...
}
2. 避免过度开放系统调用
禁止直接允许 @all(所有系统调用)或高危调用(如 ptrace、execve 除非必需),示例:
apparmor
# 错误:过度开放,存在提权风险
syscall @all,
# 正确:仅开放必需的调用
syscall openat, read, write,
3. 系统调用与文件 / 网络权限联动
允许系统调用后,需同步开放对应的文件 / 网络权限,否则程序仍会报错:示例:允许 socket 系统调用,但未开放 network tcp,程序仍无法联网。
五、验证系统调用规则是否生效
步骤 1:加载配置文件
bash
运行
# 编译检查语法
sudo apparmor_parser -vW /etc/apparmor.d/usr.local.bin.myapp
# 重新加载AppArmor
sudo systemctl reload apparmor
# 切换为强制模式
sudo aa-enforce /etc/apparmor.d/usr.local.bin.myapp
步骤 2:测试未授权系统调用
故意让程序执行未允许的系统调用(如 ptrace),查看 AppArmor 拦截日志:
bash
运行
sudo grep -i apparmor /var/log/syslog | grep myapp
示例拦截日志(规则生效):
plaintext
apparmor="DENIED" operation="syscall" profile="/usr/local/bin/myapp" name="ptrace" pid=1234 comm="myapp" requested_mask="x" denied_mask="x"
步骤 3:验证授权调用是否正常
运行程序,触发已允许的系统调用(如 openat 打开配置文件),若程序正常运行且无 DENIED 日志,说明规则配置正确。
六、调试:补充缺失的系统调用
若程序因系统调用被拦截崩溃,按以下步骤排查:
切换到 complain 模式(仅记录日志,不拦截):
bash
运行
sudo aa-complain /etc/apparmor.d/usr.local.bin.myapp
运行程序并触发所有业务操作;
查看日志,提取被拒绝的系统调用:
bash
运行
sudo grep -i "syscall" /var/log/syslog | grep myapp
在配置文件中补充对应的 syscall 规则,重新加载即可。
总结
允许程序执行特定系统调用的核心逻辑:
用 strace 追踪程序必需的系统调用;
在配置文件中通过 syscall 规则声明(单调用 / 多调用 / 带参数);
编译加载后,先投诉模式调试,再强制模式上线;
验证拦截未授权调用、允许授权调用。
三二互联专业提供香港VPS,美国VPS主机,香港云服务器租用等业务香港美国到大陆CN2 GIA速度最快