32 配置文件组件和语法 #
构建 AppArmor 配置文件来限制应用程序的操作非常简单且直观。AppArmor 附带了多种工具来帮助创建配置文件。您无需编程或处理脚本。管理员唯一需要执行的任务是为每个需要强化的应用程序确定最严格的访问和执行权限策略。
只有在软件配置或所需的活动范围发生变化时才有必要更新或修改应用程序配置文件。AppArmor 提供了直观的工具来处理配置文件的更新和修改。
选择要构建配置文件的程序后,您就作好了构建 AppArmor 配置文件的准备。要执行此操作,必须了解配置文件的组件和语法。AppArmor 配置文件包含多个可帮助您构建简单且可重用配置文件代码的构建基块:
- Include 文件
Include 语句用于提取其他 AppArmor 配置文件的组成部分,可简化新配置文件的结构。
- 抽象
抽象是按常见应用程序任务分组的 include 语句。
- 程序块
程序块是包含专用于程序套件的配置文件块的 include 语句。
- 功能项
功能项是任何 POSIX.1e (https://en.wikipedia.org/wiki/POSIX#POSIX.1) Linux 功能的配置文件项,可用于精细控制允许受限制进程通过需要特权的系统调用执行哪些操作。
- 网络访问控制项
网络访问控制项基于地址类型和地址族调解网络访问。
- 局部变量定义
局部变量定义路径的快捷方式。
- 文件访问控制项
文件访问控制项指定应用程序可访问的文件集。
- rlimit 项
rlimit 项用于设置和控制应用程序的资源限制。
如需有关确定要构建配置文件的程序的帮助,请参见第 31.2 节 “确定要使其免疫的程序”。要开始使用 YaST 构建 AppArmor 配置文件,请转到第 34 章 “使用 YaST 构建和管理配置文件”。要使用 AppArmor 命令行界面构建配置文件,请转到第 35 章 “从命令行构建配置文件”。
有关创建 AppArmor 配置文件的更多细节,请参见 man 5 apparmor
。
32.1 分解 AppArmor 配置文件 #
要介绍配置文件的构成以及创建配置文件的过程,最简单的方法就是显示示例配置文件的细节,本例使用了名为 /usr/bin/foo
的虚构应用程序的配置文件:
#include <tunables/global>1 # a comment naming the application to confine /usr/bin/foo2 {3 #include <abstractions/base>4 capability setgid5, network inet tcp6, link /etc/sysconfig/foo -> /etc/foo.conf,7 /bin/mount ux, /dev/{,u}8random r, /etc/ld.so.cache r, /etc/foo/* r, /lib/ld-*.so* mr, /lib/lib*.so* mr, /proc/[0-9]** r, /usr/lib/** mr, /tmp/ r,9 /tmp/foo.pid wr, /tmp/foo.* lrw, /@{HOME}10/.foo_file rw, /@{HOME}/.foo_lock kw, owner11 /shared/foo/** rw, /usr/bin/foobar Cx,12 /bin/** Px -> bin_generic,13 # a comment about foo's local (children) profile for /usr/bin/foobar. profile /usr/bin/foobar14 { /bin/bash rmix, /bin/cat rmix, /bin/more rmix, /var/log/foobar* rwl, /etc/foobar r, } # foo's hat, bar. ^bar15 { /lib/ld-*.so* mr, /usr/bin/bar px, /var/spool/* rwl, } }
此语句加载包含变量定义的文件。 | |
受限制程序的规范化路径。 | |
花括号 ( | |
此指令提取 AppArmor 配置文件的组件以简化配置文件。 | |
功能项语句可启用每个 29 POSIX.1e 草案功能。 | |
确定允许应用程序进行哪种网络访问的指令。有关详细信息,请参考 第 32.5 节 “网络访问控制”。 | |
链接对规则,指定链接的源和目标。有关更多信息,请参见第 32.7.6 节 “链接对”。 | |
此处的花括号 ( | |
路径项,指定程序可以访问文件系统的哪些区域。路径项的第一部分指定文件的绝对路径(包括正则表达式通配),第二部分指示允许的访问模式(例如 | |
此变量将扩展为一个无需更改整个配置文件即可更改的值。 | |
拥有者条件规则,授予对用户所拥有文件的读写权限。有关更多信息,请参考第 32.7.8 节 “拥有者条件规则”。 | |
此项定义了到本地配置文件 | |
目标为位于全局范围内的 bin_generic 配置文件的命名配置文件转换。有关详细信息,请参见第 32.12.7 节 “命名配置文件转换”。 | |
本地配置文件 | |
此部分引用了应用程序的“帽子”子配置文件。有关 AppArmor ChangeHat 功能的更多细节,请参见第 36 章 “使用 ChangeHat 构建 Web 应用程序的配置文件”。 |
为程序创建配置文件后,此程序只可访问配置文件中指定的文件、模式和 POSIX 功能。这些限制是对 Linux 访问控制的补充。
示例::
要获得 CAP_CHOWN
功能,程序必须能够在常规 Linux 访问控制下访问 CAP_CHOWN
(通常为 root
拥有的进程),并且其配置文件中必须设置 chown
功能。与此类似,要能够写入 /foo/bar
文件,程序的文件属性中必须设置正确的用户 ID 和模式位,并且其配置文件中必须设置 /foo/bar w
。
违反 AppArmor 规则的尝试将记录在 /var/log/audit/audit.log
(如果已安装 audit
软件包)、/var/log/messages
中,或仅记录在 journalctl
中(如果未安装传统的 syslog)。AppArmor 规则通常可防止攻击发挥作用,因为必要的文件不可访问。此外,在任何情况下,AppArmor 限制都可以禁止攻击者可能对 AppArmor 所允许的文件集进行的破坏。
32.2 配置文件类型 #
AppArmor 可识别四种不同类型的配置文件:标准配置文件、未关联的配置文件、本地配置文件和帽子。标准配置文件和未关联的配置文件是独立的配置文件,各自存储在 /etc/apparmor.d/
下的某个文件中。本地配置文件和帽子是在父配置文件内部嵌入的子配置文件,用于针对应用程序的子任务提供更严格或备选的限制。
32.2.1 标准配置文件 #
默认的 AppArmor 配置文件将按其名称关联到程序,因此,配置文件的名称必须与其要限制的应用程序的路径相匹配。
/usr/bin/foo { ... }
每当未受限进程执行 /usr/bin/foo
时,就会自动使用此配置文件。
32.2.2 未关联的配置文件 #
未关联的配置文件不会驻留在文件系统名称空间中,因此不会自动关联到应用程序。未关联的配置文件的名称前面带有关键字 profile
。您可以自由选择配置文件名称,但存在以下限制:名称不得以 :
或 .
字符开头。如果名称包含空格,必须将它括在引号中。如果名称以 /
开头,则将该配置文件视为标准配置文件,因此以下两个配置文件是相同的:
profile /usr/bin/foo { ... } /usr/bin/foo { ... }
系统永远不会自动使用未关联的配置文件,也不能通过 Px
规则将其他配置文件转换为未关联的配置文件。需使用命名配置文件转换(请参见第 32.12.7 节 “命名配置文件转换”)或 change_profile
规则(请参见第 32.2.5 节 “更改规则”)将其关联到程序。
一般不应由系统范围的配置文件(例如 /bin/bash
)限制的系统实用程序的专用配置文件适合采用未关联的配置文件。它们还可用于设置角色或限制用户。
32.2.3 本地配置文件 #
本地配置文件可让您方便地针对受限制应用程序启动的实用程序提供专门的限制。其指定方式类似于标准配置文件,不过,它们嵌入于父配置文件中,并以 profile
关键字开头:
/parent/profile { ... profile /local/profile { ... } }
要转换为本地配置文件,请使用 cx
规则(请参见第 32.12.2 节 “离散本地配置文件执行模式 (cx)”)或命名配置文件转换(请参见第 32.12.7 节 “命名配置文件转换”)。
32.2.4 帽子 #
AppArmor“帽子”属于本地配置文件,它们存在一些额外的限制,以及允许使用 change_hat
转换到这些配置文件的隐式规则。有关详细说明,请参见第 36 章 “使用 ChangeHat 构建 Web 应用程序的配置文件”。
32.2.5 更改规则 #
AppArmor 提供了 change_hat
和 change_profile
规则,用于控制域转换。change_hat
通过在配置文件中定义帽子来指定,而 change_profile
规则会引用另一个配置文件,并以关键字 change_profile
开头:
change_profile -> /usr/bin/foobar,
change_hat
和 change_profile
都提供应用程序导向的配置文件转换,而无需启动单独的应用程序。change_profile
在加载的任何配置文件之间均提供通用的单向转换。change_hat
提供可回转的父子转换,其中,应用程序可从父配置文件切换到帽子配置文件,如果它提供正确的机密密钥,则稍后可恢复为父配置文件。
change_profile
最适合用于应用程序需要经历可信设置阶段,随后可以降低其特权级别的情况。在启动阶段映射或打开的任何资源在配置文件发生更改后仍可访问,但新配置文件将限制新资源的打开,并限制在转变之前打开的某些资源。具体而言,在功能和文件资源(前提是它们未经过内存映射)可能受限的情况下,内存资源仍然可用。
change_hat
最适合用于应用程序需运行不提供应用程序资源(例如 Apache 的 mod_php
)直接访问途径的虚拟机或解释器的情况。由于 change_hat
将返回机密密钥存储在应用程序的内存中,因此在特权降级阶段,不应具有直接访问内存的权限。正确分隔文件访问权限也很重要,因为帽子可以限制对文件句柄的访问,但不会关闭文件句柄。如果应用程序在进行缓冲并通过缓冲提供对所打开文件的访问,内核可能看不到对这些文件的访问,因此新配置文件不会限制此类访问。
change_hat
和 change_profile
域转换没有通过执行完成的域转换安全,因为它们不会影响进程的内存映射,也不会关闭已打开的资源。
32.3 Include 语句 #
Include 语句是可提取其他 AppArmor 配置文件的组件以简化配置文件的指令。Include 文件会检索程序的访问权限。通过使用 include,您可以向程序赋予访问其它程序也需要的目录路径和文件的权限。使用 include 可减小配置文件的大小。
Include 语句通常以井号 (#
) 开头。这会造成混淆,因为配置文件中的注释也使用井号。因此,仅当不存在前置 #(##include
是注释)并且 #
与 include
之间不存在空格(#
include
是注释)时,才将 #include
视为 include。
您也可以使用不带前导 #
的 include
。
include "/etc/apparmor.d/abstractions/foo"
等同于使用
#include "/etc/apparmor.d/abstractions/foo"
由于 include 遵循 C 预处理器语法,因此不含尾随的“,”,这与大多数 AppArmor 规则一样。
您可以通过在语法中进行细微的更改来修改 include
的行为。如果在包含路径两侧使用 ""
,则会指示解析器执行绝对或相对路径查找。
include "/etc/apparmor.d/abstractions/foo" # absolute path include "abstractions/foo" # relative path to the directory of current file
在使用相对路径 include 时,如果包含了文件,则会将此文件视为其 include 的当前新文件。例如,假设您在 /etc/apparmor.d/bar
文件中操作,则
include "abstractions/foo"
会包含文件 /etc/apparmor.d/abstractions/foo
。如果
include "example"
包含在 /etc/apparmor.d/abstractions/foo
文件中,则此语句将包含 /etc/apparmor.d/abstractions/example
。
使用 <>
会指定按顺序尝试 include 路径(由 -I
指定,默认为 /etc/apparmor.d
目录)。假设 include 路径为
-I /etc/apparmor.d/ -I /usr/share/apparmor/
则 include 语句
include <abstractions/foo>
会尝试 /etc/apparmor.d/abstractions/foo
,如果该文件不存在,则会下一次尝试 /usr/share/apparmor/abstractions/foo
。
可以通过将 -I
传递给 apparmor_parser
或者通过在 /etc/apparmor/parser.conf
中设置 include 路径,来手动覆盖默认 include 路径:
Include /usr/share/apparmor/ Include /etc/apparmor.d/
允许多个项,其提取顺序与在 apparmor_parser
命令行中使用 -I
或 --Include
时的顺序相同。
如果 include 以“/”结尾,则会将它视为目录 include,并会包含该目录中的所有文件。
为帮助您构建应用程序的配置文件,AppArmor 提供了三类 include:抽象、程序块和 tunable。
32.3.1 抽象 #
抽象是按常见应用程序任务分组的 include。这些任务包括访问身份验证机制、访问名称服务例程、一般的图形要求以及系统统计。这些抽象中列出的文件特定于指定的任务。如果程序需要其中某个文件,则也需要抽象文件中列出的其他文件(取决于程序的本地配置和具体要求)。可以在 /etc/apparmor.d/abstractions
中找到抽象。
32.3.2 程序块 #
program-chunks 目录 (/etc/apparmor.d/program-chunks
) 包含某些专用于程序套件的配置文件块,这些块在套件外部一般没有作用,因此,配置文件向导(aa-logprof
和 aa-genprof
)从不建议在配置文件中使用这些块。目前,程序块仅适用于 postfix 程序套件。
32.3.3 Tunables #
tunables 目录 (/etc/apparmor.d/tunables
) 包含全局变量定义。在配置文件中使用时,这些变量将扩展为一个无需更改整个配置文件即可更改的值。请将应该可供每个配置文件使用的所有 tunable 定义添加到 /etc/apparmor.d/tunables/global
。
32.4 功能项 (POSIX.1e) #
功能规则很简单,就是 capability
一词后接 POSIX.1e 功能名称(如 capabilities(7)
手册页中所定义)。您可以在单条规则中列出多个功能,或者仅使用关键字 capability
授予所有已实现的功能。
capability dac_override sys_admin, # multiple capabilities capability, # grant all capabilities
32.5 网络访问控制 #
AppArmor 允许基于地址类型和地址族调解网络访问。下面将说明网络访问规则语法:
network [[<domain>1][<type2>][<protocol3>]]
支持的域: | |
支持的类型: | |
支持的协议: |
AppArmor 工具仅支持族和类型规范。AppArmor 模块仅在 “ACCESS DENIED” 消息中发出 network DOMAIN
TYPE
。配置文件生成工具(YaST 和命令行)仅输出这些内容。
下面的示例说明可在 AppArmor 配置文件中使用的可能网络相关规则。AppArmor 工具目前不支持最后两条规则的语法。
network1, network inet2, network inet63, network inet stream4, network inet tcp5, network tcp6,
32.6 配置文件名称、标志、路径和通配 #
通过指定程序可执行文件的完整路径来将配置文件关联到相应程序。例如,由以下语句定义的标准配置文件(参见第 32.2.1 节 “标准配置文件”)
/usr/bin/foo { ... }
下列各节介绍在命名配置文件、将某个配置文件放入其他现有配置文件的环境中,或者指定文件路径时可以运用的若干有用技巧。
AppArmor 明确区分目录路径名和文件路径名。对需要明确区分的任何目录路径使用尾随 /
:
/some/random/example/* r
允许对
/some/random/example
目录中的文件进行读取访问。/some/random/example/ r
仅允许对该目录进行读取访问。
/some/**/ r
授予对
/some
下的任何目录(但不包括 /some/ 本身)的读取访问权限。/some/random/example/** r
授予对
/some/random/example
下的文件和目录(但不包括 /some/random/example/ 本身)的读取访问权限。/some/random/example/**[^/] r
授予对
/some/random/example
下的文件的读取访问权限。明确排除目录 ([^/]
)。
通配(亦称为常规表达式匹配)是您在修改目录路径时使用通配符将一组文件或子目录包含在内的情况。使用通配语法可以指定文件资源,类似于常用的外壳(例如 csh、Bash 和 zsh)使用的通配语法。
|
代替任意数目的任何字符, 示例:任意数目的路径元素。 |
|
代替任意数目的字符,包括 示例:任意数目的路径元素,包括整个目录。 |
|
代替任意单个字符, |
|
代替单个
示例:匹配 |
|
代替单个 |
|
扩展为一条匹配
示例:匹配 |
|
代替除 |
32.6.1 配置文件标志 #
配置文件标志控制相关配置文件的行为。您可以通过手动编辑配置文件定义来将配置文件标志添加到其中。请参见以下语法:
/path/to/profiled/binary flags=(list_of_flags) { [...] }
可以使用以逗号“,”或空格“ ”分隔的多个标志。配置文件标志有三种基本类型:模式、相对和附加标志。
模式标志为 complain
(允许并记录非法访问)。如果省略该标志,则配置文件处于 enforce
模式(强制执行策略)。
将整个配置文件设置为控诉模式的更灵活的方式是在 /etc/apparmor.d/force-complain/
目录中基于该配置文件创建一个符号链接。
ln -s /etc/apparmor.d/bin.ping /etc/apparmor.d/force-complain/bin.ping
相对标志为 chroot_relative
(指出配置文件相对于 chroot 而不是名称空间)或 namespace_relative
(默认值,表示路径相对于 chroot 外部)。这两个标志是互斥的。
附加标志由两对互斥的标志构成:attach_disconnected
或 no_attach_disconnected
(确定解析为名称空间外部的路径名是否附加到根目录,即,它们的开头是否包含“/”字符),以及 chroot_attach
或 chroot_no_attach
(在 chroot 环境中访问位于 chroot 外部但在名称空间内部的文件时,控制路径名生成)。
32.6.2 在配置文件中使用变量 #
AppArmor 允许在配置文件中使用变量来包含路径。使用全局变量可使配置文件具有可移植性,使用局部变量可以创建路径的快捷方式。
举个典型的示例,在用户主目录挂载到不同位置的网络方案中,全局变量就很方便。您无需在所有受影响的配置文件中修改主目录的路径,而只需更改变量的值。全局变量在 /etc/apparmor.d/tunables
下定义,需要通过 include 语句来使用。在 /etc/apparmor.d/tunables/home
文件中可以找到此用例的变量定义(@{HOME}
和 @{HOMEDIRS}
)。
局部变量在配置文件的头部定义。这样便于提供 chroot 路径的基础,例如:
@{CHROOT_BASE}=/tmp/foo /sbin/rsyslogd { ... # chrooted applications @{CHROOT_BASE}/var/lib/*/dev/log w, @{CHROOT_BASE}/var/log/** w, ... }
在下面的示例中,@{HOMEDIRS} 会列出所有用户主目录的存储位置,@{HOME} 是主目录的空格分隔列表。接下来,@{HOMEDIRS} 会按用于存储用户主目录的两个新特定位置进行扩展。
@{HOMEDIRS}=/home/ @{HOME}=@{HOMEDIRS}/*/ /root/ [...] @{HOMEDIRS}+=/srv/nfs/home/ /mnt/home/
在当前的 AppArmor 工具中,只能在手动编辑和维护配置文件时使用变量。
32.6.3 模式匹配 #
配置文件名称可以包含通配表达式,这样配置文件便可匹配多个二进制文件。
以下示例适用于 foo
二进制文件驻留在 /usr/bin
或 /bin
中的系统。
/{usr/,}bin/foo { ... }
在以下示例中,对可执行文件 /bin/foo
进行匹配时,/bin/foo
配置文件是完全匹配项,因此已将其选中。对于可执行文件 /bin/fat
,配置文件 /bin/foo
不匹配,但由于 /bin/f*
配置文件比 /bin/**
更具体(泛化程度更低),因此选择了 /bin/f*
配置文件。
/bin/foo { ... } /bin/f* { ... } /bin/** { ... }
有关配置文件名称通配示例的详细信息,请参见 AppArmor 手册页 man 5 apparmor.d,
以及“Globbing
”一节。
32.6.4 名称空间 #
名称空间用于提供不同的配置文件集。例如,一个配置文件集用于系统,另一个配置文件集用于 chroot 环境或容器。名称空间是分层的 — 名称空间可以看到其子项,但子项看不到其父项。名称空间的名称以冒号 :
开头,后接一个字母数字字符串、一个尾随冒号 :
和一个可选的双斜线 //
,例如
:childNameSpace://
加载到子名称空间的配置文件以其名称空间名称为前缀(从父项的角度看):
:childNameSpace://apache
可以通过 change_profile
API 或命名配置文件转换进入名称空间:
/path/to/executable px -> :childNameSpace://apache
32.6.5 配置文件命名和附件规范 #
配置文件可以有一个名称和一个附件规范。这样,您便可为配置文件指定一个比包含模式匹配(请参见第 32.6.3 节 “模式匹配”)的名称更有意义且符合逻辑的名称,便于用户/管理员识别。例如,默认配置文件
/** { ... }
可命名为
profile default /** { ... }
另外,可为包含模式匹配的配置文件命名。例如:
/usr/lib64/firefox*/firefox-*bin { ... }
可命名为
profile firefox /usr/lib64/firefox*/firefox-*bin { ... }
32.6.6 别名规则 #
别名规则提供了另一种操作站点特定布局的配置文件路径映射的方式。它们是另一种修改路径的方式(一种方式是使用变量),在解析变量后执行。别名规则告知要将具有相同源前缀的规则看作是规则位于目标前缀处。
alias /home/ -> /usr/home/
对 /home/
进行前缀匹配的所有规则都提供对 /usr/home/
的访问权限。例如:
/home/username/** r,
也允许访问
/usr/home/username/** r,
利用别名,您无需重新编写规则即可快速重新映射它们。它们可确保源路径仍可供访问 — 在本示例中,别名规则确保 /home/
下的路径仍可供访问。
使用alias
规则可以同时指向多个目标。
alias /home/ -> /usr/home/ alias /home/ -> /mnt/home/
在当前的 AppArmor 工具中,只能在手动编辑和维护配置文件时使用别名规则。
在文件 /etc/apparmor.d/tunables/alias
中插入全局别名定义。
32.7 文件权限访问模式 #
文件权限访问模式包括以下模式的组合:
|
读取模式 |
|
写入模式(与 |
|
追加模式(与 |
|
文件锁定模式 |
|
链接模式 |
|
链接对规则(不能与其他访问模式结合使用) |
32.7.1 读取模式 (r) #
允许程序拥有读取资源的权限。需要对外壳脚本和其他解释内容授予读取访问权限,该权限确定正在执行的进程是否可以进行核心转储。
32.7.2 写入模式 (w) #
允许程序拥有写入资源的权限。将被取消链接(删除)的文件必须拥有此权限。
32.7.3 追加模式 (a) #
允许程序写入到文件的末尾。与 w
模式相反,追加模式不包含重写数据、重命名或去除文件的功能。追加权限通常用于需要能够写入日志文件,但不应该能够操作日志文件中任何现有数据的应用程序。由于追加权限是与写入模式关联的权限的子集,w
和 a
权限标志不能结合使用,它们是互斥的。
32.7.4 文件锁定模式 (k) #
应用程序可以采用文件锁。在以前的 AppArmor 版本中,如果应用程序有权访问文件,AppArmor 便允许锁定文件。通过使用独立的文件锁定模式,AppArmor 可确保仅对需要锁定的文件进行锁定,如此可增强安全性,因为在多种拒绝服务攻击场景中都可以使用锁定。
32.7.5 链接模式 (l) #
链接模式调解对硬链接的访问。创建链接后,目标文件的访问权限必须与所创建的链接相同(但目标不需要链接访问权限)。
32.7.6 链接对 #
链接模式授予链接到任意文件的权限,前提是该链接具有目标所授予的权限的子集(子集权限测试)。
/srv/www/htdocs/index.html rl,
通过指定源和目标,链接对规则可让您更好地控制创建硬链接的方式。默认情况下,链接对规则不会强制执行链接子集权限测试,而标准规则链接权限则需要进行此测试。
link /srv/www/htdocs/index.html -> /var/www/index.html
要强制让规则要求进行该测试,可使用 subset
关键字。以下规则是等效的:
/var/www/index.html l, link subset /var/www/index.html -> /**,
YaST 和命令行工具目前不支持链接对规则。要使用这些规则,请手动编辑配置文件。使用工具更新此类配置文件是安全的操作,因为这种方式不会改动链接对项。
32.7.7 可选的 allow
和 file
规则 #
allow
前缀是可选的,如果未指定并且不使用 deny
(参见第 32.7.9 节 “拒绝规则”)关键字,则按惯常隐式应用该前缀。
allow file /example r, allow /example r, allow network,
您还可以使用可选的 file
关键字。如果您省略该关键字并且不存在其他以某个关键字(例如 network
或 mount
)开头的规则类型,则自动隐式应用该前缀。
file /example/rule r,
等效于
/example/rule r,
下面的规则授予对所有文件的访问权限:
file,
等效于
/** rwmlk,
文件规则可以使用前导或尾随权限。不应将权限指定为尾随权限,而应在规则的开头使用。这一点非常重要,因为这样可使文件规则的行为类似于任何其他规则类型。
/path rw, # old style rw /path, # leading permission file rw /path, # with explicit 'file' keyword allow file rw /path, # optional 'allow' keyword added
32.7.8 拥有者条件规则 #
可以扩展文件规则,使其可以按条件应用于文件的拥有者用户(fsuid 需与文件的 uid 相匹配)。要实现此目的,需在规则的前面添加 owner
关键字。拥有者条件规则像普通的文件规则一样不断累积。
owner /home/*/** rw
将文件所有权条件与链接规则结合使用时,将针对目标文件执行所有权测试,因此,用户必须拥有该文件才能链接到该文件。
拥有者条件规则被视为普通文件规则的子集。如果某个普通文件规则与某个拥有者条件文件规则重叠,这两条规则将会合并。参见以下示例。
/foo r, owner /foo rw, # or w,
这些规则会合并 — 结果是每个人均具有 r
权限,只有拥有者具有 w
权限。
要指定除文件拥有者以外的每个人,请使用关键字 other
。
owner /foo rw, other /foo r,
32.7.9 拒绝规则 #
拒绝规则可用于批注已知拒绝或使其静止。配置文件生成工具不会询问有关拒绝规则所处理的已知拒绝的信息。发生拒绝后,此类拒绝不会显示在审计日志中,以使日志文件保持精简。如果不需要此行为,请在拒绝项的前面添加关键字 audit
。
此外,还可以将拒绝规则与允许规则结合使用。这样,您便可以先指定一条宽泛的允许规则,然后再去掉几个不应允许的已知文件。拒绝规则还可与拥有者规则结合使用来拒绝用户拥有的文件。下面的示例允许对 users 目录中的任何内容进行读写访问,但不允许对 .ssh/
文件进行写入访问:
deny /home/*/.ssh/** w, owner /home/*/** rw,
一般不建议大量使用拒绝规则,因为这会大大增加理解配置文件的作用的难度。不过,审慎使用拒绝规则可以简化配置文件。因此,工具只会生成拒绝特定文件的配置文件,而不会在拒绝规则中使用通配。要添加使用通配的拒绝规则,请手动编辑配置文件。使用工具更新此类配置文件是安全的操作,因为这种方式不会改动拒绝项。
32.8 挂载规则 #
AppArmor 可以限制挂载和卸载操作,包括文件系统类型和挂载标志。规则语法基于 mount
命令语法,以 mount
、remount
或 umount
关键字开头。条件是可选项,如果不指定条件,则认为要匹配所有项。例如,不指定文件系统表示要匹配所有文件系统。
可以使用 options=
或 options in
指定条件。
options=
指定必须完全符合的条件。规则
mount options=ro /dev/foo -E /mnt/,
匹配
#
mount -o ro /dev/foo /mnt
但不匹配
#
mount -o ro,atime /dev/foo /mnt
#
mount -o rw /dev/foo /mnt
options in
要求至少使用一个所列的挂载选项。规则
mount options in (ro,atime) /dev/foo -> /mnt/,
匹配
#
mount -o ro /dev/foo /mnt
#
mount -o ro,atime /dev/foo /mnt
#
mount -o atime /dev/foo /mnt
但不匹配
#
mount -o ro,sync /dev/foo /mnt
#
mount -o ro,atime,sync /dev/foo /mnt
#
mount -o rw /dev/foo /mnt
#
mount -o rw,noatime /dev/foo /mnt
#
mount /dev/foo /mnt
如果使用多个条件,规则将为每组选项授予权限。规则
mount options=ro options=atime
匹配
#
mount -o ro /dev/foo /mnt
#
mount -o atime /dev/foo /mnt
但不匹配
#
mount -o ro,atime /dev/foo /mnt
单独的挂载规则是不同的,选项不会累积。规则
mount options=ro, mount options=atime,
与下列规则不等效
mount options=(ro,atime), mount options in (ro,atime),
下面的规则允许在 /mnt/
上将 /dev/foo
挂载为只读模式并使用 inode 访问时间,或者允许使用“nodev”和“user”的某种组合在 /mnt/
上挂载 /dev/foo
。
mount options=(ro, atime) options in (nodev, user) /dev/foo -> /mnt/,
允许
#
mount -o ro,atime /dev/foo /mnt
#
mount -o nodev /dev/foo /mnt
#
mount -o user /dev/foo /mnt
#
mount -o nodev,user /dev/foo /mnt
32.9 Pivot Root 规则 #
AppArmor 可以限制对根文件系统的更改。语法为
pivot_root [oldroot=OLD_ROOT] NEW_ROOT
在“pivot_root”规则中指定的路径必须以“/”结尾,因为它们是目录。
# Allow any pivot pivot_root, # Allow pivoting to any new root directory and putting the old root # directory at /mnt/root/old/ pivot_root oldroot=/mnt/root/old/, # Allow pivoting the root directory to /mnt/root/ pivot_root /mnt/root/, # Allow pivoting to /mnt/root/ and putting the old root directory at # /mnt/root/old/ pivot_root oldroot=/mnt/root/old/ /mnt/root/, # Allow pivoting to /mnt/root/, putting the old root directory at # /mnt/root/old/ and transition to the /mnt/root/sbin/init profile pivot_root oldroot=/mnt/root/old/ /mnt/root/ -> /mnt/root/sbin/init,
32.10 PTrace 规则 #
AppArmor 支持限制 ptrace 系统调用。ptrace 规则将会累积,因此,授予的 ptrace 权限是全部所列 ptrace 规则权限的并集。如果某条规则未指定访问列表,则会隐式授予权限。
trace
和 tracedby
权限控制 ptrace(2);read
和 readby
控制 proc(5) 文件系统访问、kcmp(2)、futexes (get_robust_list(2)) 和 perf 跟踪事件。
要允许 ptrace 操作,跟踪进程和被跟踪进程都需要有正确的权限。也就是说,跟踪进程需要有 trace
权限,被跟踪进程需要有 tracedby
权限。
示例 AppArmor PTrace 规则:
# Allow all PTrace access ptrace, # Explicitly allow all PTrace access, ptrace (read, readby, trace, tracedby), # Explicitly deny use of ptrace(2) deny ptrace (trace), # Allow unconfined processes (eg, a debugger) to ptrace us ptrace (readby, tracedby) peer=unconfined, # Allow ptrace of a process running under the /usr/bin/foo profile ptrace (trace) peer=/usr/bin/foo,
32.11 信号规则 #
AppArmor 支持限制进程间的信号。AppArmor 信号规则会累积,因此,授予的信号权限是全部所列信号规则权限的并集。如果规则未明确指明访问列表,则隐式应用 AppArmor 信号权限。
发送方进程和接收方进程都必须拥有正确的权限。
示例信号规则:
# Allow all signal access signal, # Explicitly deny sending the HUP and INT signals deny signal (send) set=(hup, int), # Allow unconfined processes to send us signals signal (receive) peer=unconfined, # Allow sending of signals to a process running under the /usr/bin/foo # profile signal (send) peer=/usr/bin/foo, # Allow checking for PID existence signal (receive, send) set=("exists"), # Allow us to signal ourselves using the built-in @{profile_name} variable signal peer=@{profile_name}, # Allow two real-time signals signal set=(rtmin+0 rtmin+32),
32.12 执行模式 #
执行模式(也称为配置文件转换)包括以下模式:
|
离散配置文件执行模式 |
|
离散本地配置文件执行模式 |
|
未受限执行模式 |
|
继承执行模式 |
|
允许使用 |
32.12.1 离散配置文件执行模式 (px) #
此模式要求为在 AppArmor 域转换时执行的资源定义一个离散安全配置文件。如果未定义配置文件,则会拒绝访问。
与 Ux
、ux
、px
和 ix
不兼容。
32.12.2 离散本地配置文件执行模式 (cx) #
类似于 Px
,但 Cx
不搜索全局配置文件集,而只搜索当前配置文件的本地配置文件。应用程序可以通过这种配置文件转换获得助手应用程序的备用配置文件。
目前,Cx 转换仅可在顶层配置文件中使用,不能在帽子和子配置文件中使用。将来会去除这项限制。
与 Ux
、ux
、Px
、px
、cx
和 ix
不兼容。
32.12.3 未受限执行模式 (ux) #
允许程序执行资源,不对被执行的资源应用任何 AppArmor 配置文件。此模式可用于使被限制的程序能够执行需要特权的操作,如重新引导计算机等。通过在其他可执行文件中添加具有特权的部分并授予未受限的执行权限,您可以避开对全部受限制进程强制施加的限制。允许根进程不受限制意味着它可以更改 AppArmor 策略本身。有关限制内容的详细信息,请参见 apparmor(7)
手册页。
此模式与 ux
、px
、Px
和 ix
不兼容。
32.12.4 不安全的执行模式 #
仅在特殊情况下才使用小写版本的执行模式 — px
、cx
、ux
。这些模式不会整理 LD_PRELOAD
等变量的环境。因此,调用域可能会对被调用资源产生过度影响。仅当绝对必须以非受限方式运行子项并且必须使用 LD_PRELOAD
时,才使用这些模式。任何使用此类模式的配置文件几乎都不会提供任何安全性。使用这些模式需自负后果。
32.12.5 继承执行模式 (ix) #
当构建了配置文件的程序执行指定程序时,ix
会阻止 execve(2)
上的常规 AppArmor 域转换。相反,被执行的资源继承当前配置文件。
当被限制的程序需要调用其它被限制的程序时此模式非常实用,无须获得目标程序配置文件的权限或失去当前配置文件的权限。没有任何版本会整理环境,因为 ix
执行不会更改特权。
与 cx
、ux
和 px
不兼容。隐式表示 m
。
32.12.6 允许可执行映射 (m) #
此模式允许使用 mmap(2)
的 PROT_EXEC
标志将文件映射到内存中。此标志将页面标示为可执行。某些体系结构使用此标志来提供不可执行的数据页面,这可以增加恶意利用的企图的困难度。AppArmor 使用此模式来限制可由行为正常的程序(或者强制实施不可执行内存访问控制的体系结构上的所有程序)用作库的文件,并限制为 ld(1)
指定的无效 -L
标志,以及为 ld.so(8)
指定的 LD_PRELOAD
和 LD_LIBRARY_PATH
所产生的影响。
32.12.7 命名配置文件转换 #
默认情况下,px
和 cx
(也包括其清洁执行变体)会转换到名称与可执行文件名称匹配的配置文件。使用命名配置文件转换,您可以指定要转换到的配置文件。如果多个二进制文件需要共享单个配置文件,或者这些二进制文件需要使用的配置文件不同于其名称指定的配置文件,此方法将非常有用。命名配置文件转换可与 cx
、Cx
、px
和 Px
一起使用。目前,每个配置文件仅可具有 12 个命名配置文件转换。
命名配置文件转换使用 ->
来指示需要转换到的配置文件的名称:
/usr/bin/foo { /bin/** px -> shared_profile, ... /usr/*bash cx -> local_profile, ... profile local_profile { ... } }
与通配模式一起使用时,常规转换提供“一对多”关系 — /bin/** px
转换为 /bin/ping
、/bin/cat
等,具体取决于正在运行的程序。
命名转换提供“多对一”关系 — 所有程序不管其名称是什么,只要与规则匹配,都将转换为指定的配置文件。
命名配置文件转换具有模式 Nx
,因此会显示在日志中。要转换到的配置文件的名称列于 name2
字段中。
32.12.8 配置文件转换的回退模式 #
px
和 cx
转换会指定硬依赖项 — 如果指定的配置文件不存在,则执行将会失败。使用继承回退时,执行将会成功,但会继承当前配置文件。要指定继承回退,可将 ix
与 cx
、Cx
、px
和 Px
相结合,形成 cix
、Cix
、pix
和 Pix
模式。
/path Cix -> profile_name,
或
Cix /path -> profile_name,
其中 -> profile_name
是可选的。
如果您添加非受限 ux
模式,同样也可以这样做,最终形成的模式为 cux
、CUx
、pux
和 PUx
。如果未找到指定的配置文件,这些模式允许回退到“未受限”。
/path PUx -> profile_name,
或
PUx /path -> profile_name,
其中 -> profile_name
是可选的。
您也可以对命名配置文件转换使用回退模式。
32.12.9 执行模式中的变量设置 #
选择 Px、Cx 或 Ux 执行模式之一时,请注意在子进程继承这些模式之前,以下环境变量会从环境中去除。因此,如果向依赖于以下任何变量的应用程序或进程应用的配置文件带有 Px、Cx 或 Ux 标志,这些应用程序或进程将不再可正常运行:
GCONV_PATH
GETCONF_DIR
HOSTALIASES
LD_AUDIT
LD_DEBUG
LD_DEBUG_OUTPUT
LD_DYNAMIC_WEAK
LD_LIBRARY_PATH
LD_ORIGIN_PATH
LD_PRELOAD
LD_PROFILE
LD_SHOW_AUXV
LD_USE_LOAD_BIAS
LOCALDOMAIN
LOCPATH
MALLOC_TRACE
NLSPATH
RESOLV_HOST_CONF
RES_OPTIONS
TMPDIR
TZDIR
32.12.10 safe
和 unsafe
关键字 #
您可以对规则使用 safe
和 unsafe
关键字来取代执行模式的大小写修饰符。例如,
/example_rule Px,
等同于下列任何一项
safe /example_rule px, safe /example_rule Px, safe px /example_rule, safe Px /example_rule,
规则
/example_rule px,
等同于下列任何一项
unsafe /example_rule px, unsafe /example_rule Px, unsafe px /example_rule, unsafe Px /example_rule,
safe
/unsafe
关键字是互斥的,可在文件规则中的 owner
关键字后面使用,因此,规则关键字的顺序如下
[audit] [deny] [owner] [safe|unsafe] file_rule
32.13 资源限制控制 #
AppArmor 可以设置和控制应用程序的资源限制(rlimit,也称为 ulimit)。默认情况下,AppArmor 不会控制应用程序的 rlimit,而是控制限制配置文件中指定的这些限制。有关资源限制的详细信息,请参见 setrlimit(2)
、ulimit(1)
或 ulimit(3)
手册页。
AppArmor 会利用系统的 rlimit,因此不会另外提供审计(正常情况下会发生审计)。此外,它不能提高系统设置的 rlimit,AppArmor rlimit 只能降低应用程序的当前资源限制。
进程的子项会继承这些值,即使转换到了新配置文件或者应用程序变得不受限制,这些值也会保留。因此,当应用程序转换到新配置文件时,该配置文件可以进一步降低应用程序的 rlimit。
AppArmor 的 rlimit 规则可以调解应用程序硬限制的设置(如果应用程序尝试提高这些限制)。应用程序不能将硬限制提高到超过配置文件中所指定的限制的水平。提高的硬限制不会像设置的值那样会被继承,因此,当应用程序转换到新配置文件时,它可以任意提高其限制(只要不超过配置文件中指定的值)。
AppArmor 的 rlimit 控制除了会确保应用程序的软限制小于或等于应用程序的硬限制外,不会在其他方面影响软限制。
AppArmor 硬限制规则一般采用如下格式:
set rlimit RESOURCE <= value,
其中 RESOURCE 和 VALUE 将替换为以下值:
cpu
CPU 时间限制,以秒为单位。
fsize
、data
、stack
、core
、rss
、as
、memlock
、msgqueue
以字节为单位的数字,或者带后缀的数字,例如,该后缀可以是 K/KB(千字节)、M/MB(兆字节)、G/GB(千兆字节)
rlimit data <= 100M,
fsize
,nofile
,locks
,sigpending
,nproc
,rtprio
大于或等于 0 的数字
nice
-20 到 19 之间的值
nproc rlimit 的处理方式不同于所有其他 rlimit。它不指示标准进程 rlimit,而是控制在任意时间可基于配置文件运行的最大进程数。如果超过限制,基于配置文件创建新进程将会失败,直到当前正在运行的进程数减少。
目前无法使用工具将 rlimit 规则添加到配置文件中。可将 rlimit 控制添加到配置文件的唯一方法是使用文本编辑器手动编辑配置文件。工具仍会处理包含 rlimit 规则的配置文件,并且不会去除这些规则,因此,使用工具更新包含这些规则的配置文件是安全的操作。
32.14 审计规则 #
AppArmor 提供用于审计给定规则的功能,如此,当匹配这些规则时,审计日志中会显示审计消息。要对给定的规则启用审计消息,可在规则的前面添加 audit
关键字:
audit /etc/foo/* rw,
如果只希望审计给定的权限,可将该规则分割为两条规则。在以下示例中,打开文件向其写入数据时会生成审计消息,但打开文件读取数据时,则不会生成消息:
audit /etc/foo/* w, /etc/foo/* r,
并非每次对文件执行读取或写入操作时都会生成审计消息,只有在打开文件进行读取或写入操作时才生成消息。
可将审计控制与 owner
/other
条件文件规则结合使用,以便在用户访问他们拥有/不拥有的文件时提供审计:
audit owner /home/*/.ssh/** rw, audit other /home/*/.ssh/** r,