SDB:AppArmor 高级用法
AppArmor 入门
简介
本指南旨在引导您了解 AppArmor 内部机制,以便更好地理解 AppArmor。如果用户只想使用发行版提供的 AppArmor,请参考发行版提供的文档。
AppArmor
AppArmor 是 Linux 安全模块的实现,它基于名称的访问控制。AppArmor 将单个程序限制在一组列出的文件和 posix 1003.1e 草案能力范围内。
AppArmor 的主要目标之一是易于理解和易于使用。为了帮助用户编写和维护策略,AppArmor 引入了一项按配置文件学习模式的功能。配置文件可以处于两种状态之一:学习模式(也称为“complaint 模式”)和强制模式(也称为“confined 模式”)。
学习模式是按配置文件配置的;运行在配置文件中的进程可以轻松地在学习模式和强制模式之间切换。只有未受限制的 root 进程才能切换学习模式。
内核补丁
AppArmor 内核补丁以方便与 quilt 一起使用的格式提供。这些补丁适用于最新的 kernel.org git 内核;git 快照或发布的内核可能在略微调整后即可工作。如果存在重大调整或补丁无法应用,请考虑尝试较旧或较新的内核。
下载并解压内核源代码后,应用所有 AppArmor 补丁;以下是使用 quilt 应用 AppArmor 补丁的示例
tar -zxvf apparmor.tar.gz ln -sf apparmor ~/path/to/kernel/sources/patches cd ~/path/to/kernel/sources quilt push -a
内核配置
配置您的内核;CONFIG_SECURITY_APPARMOR 必须设置为 'y' 或 'm'。'm' 接受更频繁的测试。禁用(或设置为模块)CONFIG_SECURITY_CAPABILITIES 和 CONFIG_SECURITY_SELINUX。
(如果您希望将 SELinux 或 Capabilities 编译到您的内核中,则必须将 selinux=0 capability.disable=1 添加到您的内核命令行 (grub, lilo, yaboot 等)。)
将 SELinux 设置为 permissive 模式是不够的。AppArmor 必须是唯一加载的 LSM。
Securityfs
AppArmor 使用内核标准的 securityfs 机制来加载策略并向系统管理员报告信息。securityfs 的常用挂载点是 /sys/kernel/security。
使用以下命令挂载它
mount securityfs -t securityfs /sys/kernel/security
挂载 securityfs 并加载 AppArmor 后,/sys/kernel/security/apparmor/profile 将列出加载到内核中的配置文件,以及标记配置文件是否处于强制模式或学习模式
$ sudo cat /sys/kernel/security/apparmor/profiles /usr/bin/opera (complain) /usr/lib/firefox/firefox.sh (complain) /sbin/lspci (enforce) ...
/sys/kernel/security/apparmor/control/ 控制 AppArmor 很少使用的功能
audit if '1', audit all actions by confined processes
complain if '1', allow all actions by confined processes, report
accesses not granted by policy
debug if '1', emit copius debugging
logsyscall if '1', use audit framework's syscall debugging, if audit
has been instructed to create per-task contexts.[1]
策略解析器
您需要 apparmor_parser 将 AppArmor 策略加载到内核中。只需在顶级目录中运行 'make' 即可构建 apparmor_parser。
构建解析器并加载 AppArmor 模块后,您可以使用解析器来编译和安装策略
echo "/tmp/ls { /tmp/ls rm, }" | ./apparmor_parser
加载配置文件到内核后,必须使用 --replace 选项
echo "/tmp/ls { /tmp/ls rm, }" | ./apparmor_parser --replace
即使不存在该名称的配置文件,也可以使用 --replace。
配置文件的结构
AppArmor 配置文件是一种简单的声明性语言;在 apparmor.d(5) manpage 中完全描述。配置文件通常存储在 /etc/apparmor.d/ 中。AppArmor 解析器支持简单的 cpp 风格
- 包含机制以允许共享策略片段。
一个简单的配置文件如下所示
/tmp/ls flags=(complain) {
# executable needs 'r' and mmap PROT_EXEC 'm'
/tmp/ls rm,
/lib/ld-2.5.so rmix,
/etc/ld.so.cache rm,
/lib/lib*.so* rm,
/dev/pts/* w,
/proc/meminfo r,
/var/run/nscd/socket w,
/var/run/nscd/passwd r,
/var/run/nscd/group r,
/tmp/ r,
}
第一个 "/tmp/ls" 是配置文件的名称。每当未受限制的进程执行 /tmp/ls 时,将自动使用此配置文件。
“flags=(complain)” 指示 AppArmor 模块允许所有操作并记录任何将被拒绝的事件(如果配置文件以强制模式加载)。
各个配置文件设置为 complain 或 enforcement 模式;这有助于用户在生产环境中逐步部署 AppArmor。要将配置文件置于 complain 模式,请添加 'flags=(complain)',如上所示,并使用 apparmor_parser --replace(或 initscript 的 restart 选项)重新加载配置文件。要将所有配置文件置于 complain 模式,您还可以使用上述 securityfs 中的 /sys/kernel/security/apparmor/control/complain 文件。
AppArmor 发行版包含两个小型工具,aa-enforce 和 aa-complain,它们会将配置文件设置为 enforce 或 complain 模式
# enforce firefox Setting /usr/lib/firefox/firefox.sh to enforce mode.
在配置文件的正文中,有任意数量的规则;这些规则使用受 shell 启发的 globbing 语法
? - any single character, except /
* - any number of characters excepting /
** - any number of characters including /
[abc] - one of a, b, or c
[a-c] - one of a, b, or c
{ab,cd} - alternation -- 'ab' or 'cd'
以 / 结尾的规则仅匹配目录。以 ? 或 * 结尾的规则不匹配目录。以 ** 结尾的规则匹配目录。一些示例
/tmp/* - all files directly in /tmp /tmp/*/ - all directories directly in /tmp /tmp/** - all files and directories underneath /tmp /tmp/**/ - all directories underneath /tmp
这些都不会匹配 /tmp/。
每个规则还指定了权限
r - read
w - write
ux - unconstrained execute
Ux - unconstrained execute -- scrub the environment
px - discrete profile execute
Px - discrete profile execute -- scrub the environment
ix - inherit execute
m - allow PROT_EXEC with mmap(2) calls
l - link
AppArmor 不需要执行访问权限才能允许目录遍历。
AppArmor 不需要目录上的 'w' 访问权限才能在目录中创建或重命名文件。相反,'w' 权限需要位于受限制的进程尝试创建或重命名的特定文件、目录、管道等上。
AppArmor 需要目录上的 'r' 访问权限才能调用 getdents()。
执行访问权限需要一个修饰符:'P' 或 'p' 指示 AppArmor 在进程执行带有指定程序的 exec() 时切换到不同的配置文件。'U' 或 'u' 指示 AppArmor 在进程执行带有指定程序的 exec() 时取消限制该进程。'i' 指示 AppArmor 即使存在指定程序的配置文件,也要保持当前配置文件。
“Px” 和 “Ux” 模式将使用内核的不安全 exec 设施来指示 glibc 清理环境。(“Px”、“px”、“Ux”、“ux” 更改进程可用的权限,就像 setuid 或 setgid 一样。权限可能与调用进程不同,无论是更严格还是更宽松。清理环境有助于防止例如 LD_PRELOAD 滥用。)
“m” 需要用于必须映射 PROT_EXEC 的库和可执行文件。这也有助于防止在无法使用“Px” 时进行例如 LD_PRELOAD 滥用。
要创建硬链接,配置文件需要新链接名称上的 'l' 访问权限。此外,新链接上的权限必须是目标的子集('l' 除外)。一些示例
/foo lr,
/bar r, link("bar", "foo") will succeed
/foo l,
/bar r, link("bar", "foo") will succeed, empty rights are subset of 'r'
/foo r,
/foo w,
/foo l,
/bar rw, link("bar", "foo") will succeed, 'rw' on both
/fo* r,
/f*o w,
/foo l,
/bar r, link("bar", "foo") will fail -- /foo has rw, /bar only r
任何包含新链接名称上执行修饰符 (PpUui) 的链接都必须与链接目标的权限完全匹配。(授予链接权限给程序不是常见的需求。)
AppArmor 还调解 POSIX 1003.1e 草案能力的使用;允许进程使用的能力只需在配置文件中列出,格式为“capability
# vim:syntax=apparmor
# Last Modified: Wed Mar 21 13:27:16 2007
#include <tunables/global>
/sbin/lspci {
#include <abstractions/base>
#include <abstractions/consoles>
capability sys_admin,
/sbin/lspci mr,
/sys/bus/pci/ r,
/sys/bus/pci/devices/ r,
/sys/devices/** r,
/usr/share/pci.ids r,
}
此配置文件使用 apparmor-profiles 包中包含的预定义包含文件。
日志记录
AppArmor 使用内核标准的 audit 设施来报告策略违规。当配置文件处于 complain 模式时,日志消息如下所示
type=APPARMOR msg=audit(1174506429.573:1789): PERMITTING r access to
/home/sarnold/ (ls(16504) profile /tmp/ls active /tmp/ls)
当配置文件处于 enforcement 模式时,日志消息如下所示
type=APPARMOR msg=audit(1174508205.298:1791): REJECTING r access to
/bin/ (ls(16552) profile /tmp/ls active /tmp/ls)
这些日志消息发送到内核审计设施;如果 auditd 未运行,则内核会将这些消息转发到 printk 以供 klogd 收集。必须使用 --with-apparmor 配置 auditd 以启用 #defines 将 AppArmor 的消息整数转换为字符串。
AppArmor 还记录进程生命周期中的一些重要事件,例如学习模式中的进程 fork 并通过 exec 更改域。这些其他事件,虽然与进程请求的权限没有直接关系,但有助于“genprof”配置文件生成工具重建何时需要特定访问权限——这允许该工具提出更相关和更有意义的策略建议。
手动生成配置文件
虽然我们的大多数用户预计会使用我们的配置文件工具生成配置文件,但也可以手动编写策略。本节提供了一个快速演练,用于为 firefox 生成一个简单的配置文件。
由于内核在向 AppArmor 提出策略问题之前会将符号链接解析为其“最终目标”,因此我们首先必须查看 /usr/bin/firefox 是否是符号链接或启动 firefox 的 shell 脚本;在我们的系统中,它是一个符号链接
# ls -l /usr/bin/firefox lrwxrwxrwx 1 root root 25 Mar 21 13:36 /usr/bin/firefox -> ../lib/firefox/firefox.sh
因此,我们将为 /usr/lib/firefox/firefox.sh 启动一个配置文件。此 shell 脚本将执行 firefox-bin,正如我们稍后将看到的那样;当它这样做时,我们将告诉 AppArmor 继承此配置文件。因此,firefox-bin 将在 /usr/lib/firefox/firefox.sh 的配置文件下执行。
为了开始,我们可以对 firefox 将需要的权限做出一些假设(既作为 shell 脚本,又作为相当复杂的 GUI 应用程序)
# cat /etc/apparmor.d/usr.lib.firefox.firefox.sh
/usr/lib/firefox/firefox.sh flags=(complain) {
/usr/lib/firefox/firefox.sh r,
/bin/bash rmix,
/lib/ld-2.5.so rmix,
/etc/ld.so.cache rm,
/lib/lib*.so* rm,
/usr/lib/lib*.so* rm,
}
# apparmor_parser --reload < /etc/apparmor.d/usr.lib.firefox.firefox.sh
Replacement succeeded for "/usr/lib/firefox/firefox.sh".
在启动 firefox 之前,启动 tail -F /var/log/audit/audit.log(或 /var/log/messages,或您的内核消息发送到的位置)。
在另一个终端中,启动 firefox。tail 将显示几百条 PERMITTING 规则
type=APPARMOR msg=audit(1174512269.026:1804): PERMITTING rw access to /dev/tty (firefox(16950) profile /usr/lib/firefox/firefox.sh active /usr/lib/firefox/firefox.sh) type=APPARMOR msg=audit(1174512269.026:1805): PERMITTING r access to /usr/share/locale/locale.alias (firefox(16950) profile /usr/lib/firefox/firefox.sh active /usr/lib/firefox/firefox.sh) type=APPARMOR msg=audit(1174512269.026:1806): PERMITTING r access to /usr/lib/locale/en_US.utf8/LC_IDENTIFICATION (firefox(16950) profile /usr/lib/firefox/firefox.sh active /usr/lib/firefox/firefox.sh)
等等。
因为我们希望此配置文件相对简单,所以我们将相对宽松;在配置文件中添加一些规则并重新加载
/dev/tty rw, /usr/share/locale/** r, /usr/lib/locale/** r,
现在重新运行 firefox。(无需一次处理所有日志条目。在 complain 模式下,AppArmor 仅报告配置文件中不存在的访问权限。这使得添加一些规则并重新运行应用程序以确定仍然需要哪些权限变得相当容易。)
重新运行后,我们得到更多消息
type=APPARMOR msg=audit(1174512791.236:5356): PERMITTING r access
to /usr/lib/gconv/gconv-modules.cache (firefox(17031) profile
/usr/lib/firefox/firefox.sh active /usr/lib/firefox/firefox.sh)
type=APPARMOR msg=audit(1174512791.236:5357): PERMITTING r access to
/proc/meminfo (firefox(17031) profile /usr/lib/firefox/firefox.sh
active /usr/lib/firefox/firefox.sh)
type=APPARMOR msg=audit(1174512791.240:5358): PERMITTING x access to
/bin/basename (firefox(17032) profile /usr/lib/firefox/firefox.sh
active /usr/lib/firefox/firefox.sh)
type=APPARMOR msg=audit(1174512791.240:5359): LOGPROF-HINT
changing_profile pid=17032
type=APPARMOR msg=audit(1174512791.240:5360): PERMITTING r access to
/bin/basename (firefox(17032) profile null-complain-profile active
null-complain-profile)
...
type=APPARMOR msg=audit(1174512791.240:5364): PERMITTING mr access to
/bin/basename (basename(17032) profile null-complain-profile active
null-complain-profile)
因此,现在我们添加一些规则
/usr/lib/gconv/** r, /proc/meminfo r, /bin/basename rmix,
我们为 /bin/basename 选择 'rmix'——就像大多数小型 shell 实用程序一样,basename 本身不应该有配置文件。为 basename 提供配置文件没有错,但这种配置文件的价值将非常有限——该配置文件需要整个文件系统的读取访问权限才能使 shell 脚本可靠地工作。当 basename 简单地从另一个配置文件继承时,它就没有比调用程序更多的或更少的权限——这通常是一个不错的权衡。
加载程序需要 'r' 和 'm' 访问权限才能执行 basename,我们使用 'ix' 来指定不进行域转换。内核日志仅报告 'r'、'm' 和 'x' 访问权限;我们必须自己决定 'x' 的 'p'、'i' 和 'u' 限定符。(再次,标准用户工具会提示用户做出此决定并给出决策后果——有关用户工具的详细信息,请参阅您的发行版文档。)
我们以这种方式继续,迭代地添加/更改规则,如日志所示;一些日志报告属性修改,例如
type=APPARMOR msg=audit(1174519157.851:10357): PERMITTING attribute (mode,ctime,) change to /home/sarnold/.gnome2_private/ (firefox-bin(17338) profile /usr/lib/firefox/firefox.sh active /usr/lib/firefox/firefox.sh)
这些需要在配置文件中用简单的 'w' 访问权限表示。
/home/*/.gnome2_private/ w,
经过九次迭代后,配置文件如下所示——我们已在每次迭代之间插入了空行
/usr/lib/firefox/firefox.sh flags=(complain) {
/usr/lib/firefox/firefox.sh r,
/bin/bash rmix,
/lib/ld-2.5.so rmix,
/etc/ld.so.cache rm,
/lib/lib*.so* rm,
/usr/lib/lib*.so* rm,
/dev/tty rw,
/usr/share/locale/** r,
/usr/lib/locale/** r,
/usr/lib/gconv/** r,
/proc/meminfo r,
/bin/basename rmix,
/usr/bin/file rmix,
/etc/magic r,
/usr/share/misc/magic.mgc r,
/bin/gawk rmix,
/usr/lib/firefox/firefox-bin rmix,
/usr/lib/firefox/lib*so rm,
/opt/gnome/lib/lib*so* rm,
/usr/share/X11/locale/* r,
/var/run/nscd/socket w,
/var/run/nscd/passwd r,
/usr/share/X11/locale/** r,
/home/*/.Xauthority r,
/usr/lib/gconv/*so m,
/home/*/.mozilla/** rw,
/etc/resolv.conf r,
/usr/lib/firefox/**.so rm,
/usr/lib/firefox/** r,
/etc/opt/gnome/** r,
/var/run/dbus/system_bus_socket w,
/etc/localtime r,
/opt/gnome/lib/**.so rm,
/var/cache/libx11/compose/* r,
/tmp/orbit-*/ w,
/dev/urandom r,
/tmp/ r,
/dev/null rw,
/opt/gnome/lib/GConf/2/gconfd-2 rmix,
/dev/log w,
/tmp/orbit-*/* w,
/tmp/gconfd-*/ r,
/tmp/gconfd-*/** rwl,
/home/*/.gconf/ r,
/home/*/.gconf/* rw,
/etc/fonts/** r,
/var/cache/fontconfig/* r,
/home/*/.fontconfig/** r,
/usr/share/ghostscript/fonts/** r,
/etc/passwd r,
/var/tmp/ r,
/bin/netstat rmix,
/home/*/.gnome2_private/ w,
/home/*/.gconfd/* rw,
/proc/net/ r,
/proc/net/* r,
/usr/share/fonts/** r,
/usr/lib/browser-plugins/ r,
/usr/lib/browser-plugins/** rm,
}
对配置文件中的条目进行排序可以帮助显示可以合并成更通用的规则的区域
/usr/lib/firefox/firefox.sh flags=(complain) {
/bin/basename rmix,
/bin/bash rmix,
/bin/gawk rmix,
/bin/netstat rmix,
/dev/log w,
/dev/null rw,
/dev/tty rw,
/dev/urandom r,
/etc/fonts/** r,
/etc/ld.so.cache rm,
/etc/localtime r,
/etc/magic r,
/etc/opt/gnome/** r,
/etc/passwd r,
/etc/resolv.conf r,
/home/*/.fontconfig/** r,
/home/*/.gconfd/* rw,
/home/*/.gconf/ r,
/home/*/.gconf/* rw,
/home/*/.gnome2_private/ w,
/home/*/.mozilla/** rw,
/home/*/.Xauthority r,
/lib/ld-2.5.so rmix,
/lib/lib*.so* rm,
/opt/gnome/lib/GConf/2/gconfd-2 rmix,
/opt/gnome/lib/lib*so* rm,
/opt/gnome/lib/**.so rm,
/proc/meminfo r,
/proc/net/ r,
/proc/net/* r,
/tmp/gconfd-*/ r,
/tmp/gconfd-*/** rwl,
/tmp/orbit-*/ w,
/tmp/orbit-*/* w,
/tmp/ r,
/usr/bin/file rmix,
/usr/lib/browser-plugins/ r,
/usr/lib/browser-plugins/** rm,
/usr/lib/firefox/firefox-bin rmix,
/usr/lib/firefox/firefox.sh r,
/usr/lib/firefox/lib*so rm,
/usr/lib/firefox/** r,
/usr/lib/firefox/**.so rm,
/usr/lib/gconv/** r,
/usr/lib/gconv/*so m,
/usr/lib/lib*.so* rm,
/usr/lib/locale/** r,
/usr/share/fonts/** r,
/usr/share/ghostscript/fonts/** r,
/usr/share/locale/** r,
/usr/share/misc/magic.mgc r,
/usr/share/X11/locale/* r,
/usr/share/X11/locale/** r,
/var/cache/fontconfig/* r,
/var/cache/libx11/compose/* r,
/var/run/dbus/system_bus_socket w,
/var/run/nscd/passwd r,
/var/run/nscd/socket w,
/var/tmp/ r,
}
在折叠一些规则为更通用和开放后
/usr/lib/firefox/firefox.sh flags=(complain) {
/bin/basename rmix,
/bin/bash rmix,
/bin/gawk rmix,
/bin/netstat rmix,
/dev/log w,
/dev/null rw,
/dev/tty rw,
/dev/urandom r,
/etc/fonts/** r,
/etc/ld.so.cache rm,
/etc/localtime r,
/etc/magic r,
/etc/opt/gnome/** r,
/etc/passwd r,
/etc/resolv.conf r,
/home/*/.fontconfig/** r,
/home/*/.gconfd/* rw,
/home/*/.gconf/ r,
/home/*/.gconf/* rw,
/home/*/.gnome2_private/ w,
/home/*/.mozilla/** rw,
/home/*/.Xauthority r,
/lib/ld-2.5.so rmix,
/lib/lib*.so* rm,
/opt/gnome/lib/GConf/2/gconfd-2 rmix,
/opt/gnome/lib/**.so* rm,
/proc/meminfo r,
/proc/net/ r,
/proc/net/* r,
/tmp/gconfd-*/ r,
/tmp/gconfd-*/** rwl,
/tmp/orbit-*/ w,
/tmp/orbit-*/* w,
/tmp/ r,
/usr/bin/file rmix,
/usr/lib/browser-plugins/ r,
/usr/lib/browser-plugins/** rm,
/usr/lib/firefox/firefox-bin rmix,
/usr/lib/firefox/firefox.sh r,
/usr/lib/firefox/** r,
/usr/lib/firefox/**.so rm,
/usr/lib/gconv/** r,
/usr/lib/gconv/*so m,
/usr/lib/lib*.so* rm,
/usr/lib/locale/** r,
/usr/share/** r,
/var/cache/fontconfig/* r,
/var/cache/libx11/compose/* r,
/var/run/dbus/system_bus_socket w,
/var/run/nscd/passwd r,
/var/run/nscd/socket w,
/var/tmp/ r,
}
说明
- [1] auditctl(8) 选项
-e;也许您的发行版也支持/etc/sysconfig/auditd或类似的用于持久配置