- apparmor.service
apparmor.service是apparmor相关的服务,文件位于/lib/systemd/system/和/usr/lib/systemd/system/路径下,内容如下:
[Unit]
Description=Load AppArmor profiles
DefaultDependencies=no
Before=sysinit.target
After=local-fs.target
After=systemd-journald-audit.socket
RequiresMountsFor=/var/cache/apparmor
AssertPathIsReadWrite=/sys/kernel/security/apparmor/.load
ConditionSecurity=apparmor
Documentation=man:apparmor(7)
Documentation=https://gitlab.com/apparmor/apparmor/wikis/home/
# Don't start this unit on the Ubuntu Live CD
ConditionPathExists=!/rofs/etc/apparmor.d
# Don't start this unit on the Debian Live CD when using overlayfs
ConditionPathExists=!/run/live/overlay/work
[Service]
Type=oneshot
ExecStart=/lib/apparmor/apparmor.systemd reload
ExecReload=/lib/apparmor/apparmor.systemd reload
# systemd maps 'restart' to 'stop; start' which means removing AppArmor confinement
# from running processes (and not being able to re-apply it later).
# Upstream systemd developers refused to implement an option that allows overriding
# this behaviour, therefore we have to make ExecStop a no-op to error out on the
# safe side.
#
# If you really want to unload all AppArmor profiles, run aa-teardown
ExecStop=/bin/true
RemainAfterExit=yes
[Install]
WantedBy=sysinit.target
其中最为主要的是/lib/apparmor/apparmor.systemd。
- apparmor.systemd
apparmor.systemd文件位于/lib/apparmor/路径下,内容如下:
#!/bin/sh
# ----------------------------------------------------------------------
# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Novell, Inc.
# ----------------------------------------------------------------------
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
aa_action()
{
echo "$1"
shift
"$@"
return $?
}
aa_log_warning_msg()
{
echo "Warning: $*"
}
aa_log_failure_msg()
{
echo "Error: $*"
}
aa_log_action_start()
{
echo "$@"
}
aa_log_action_end()
{
printf ""
}
aa_log_daemon_msg()
{
echo "$@"
}
aa_log_skipped_msg()
{
echo "Skipped: $*"
}
aa_log_end_msg()
{
printf ""
}
# source apparmor function library
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
# shellcheck source=rc.apparmor.functions
. "${APPARMOR_FUNCTIONS}"
else
aa_log_failure_msg "Unable to find AppArmor initscript functions"
exit 1
fi
case "$1" in
start)
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
aa_log_daemon_msg "Not starting AppArmor in container"
aa_log_end_msg 0
exit 0
fi
apparmor_start
rc=$?
;;
stop)
apparmor_stop
rc=$?
;;
restart|reload|force-reload)
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
aa_log_daemon_msg "Not starting AppArmor in container"
aa_log_end_msg 0
exit 0
fi
apparmor_restart
rc=$?
;;
try-restart)
apparmor_try_restart
rc=$?
;;
kill)
apparmor_kill
rc=$?
;;
status)
apparmor_status
rc=$?
;;
*)
exit 1
;;
esac
exit "$rc"
以上边/lib/systemd/system/apparmor.service中的/lib/apparmor/apparmor.systemd reload为例进行脚本解析。
(1)先来看第一段。代码片段如下:
restart|reload|force-reload)
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
aa_log_daemon_msg "Not starting AppArmor in container"
aa_log_end_msg 0
exit 0
fi
apparmor_restart
rc=$?
;;
甭管是/lib/apparmor/apparmor.systemd后边的参数是restart、reload还是force-reload,都会进入这段代码。
1)一上来先检测/usr/bin/systemd-detect-virt是否存在并且是否可执行。这是一个二进制文件,笔者电脑中确实存在,如下所示:
$ ls -l /usr/bin/systemd-detect-virt
-rwxr-xr-x 1 root root 23416 2月15日 00:36 /usr/bin/systemd-detect-virt
参考:systemd-detect-virt 中文手册 - systemd 中文手册 - 开发文档 - 文江博客
systemd-detect-virt用于检测系统的运行环境是否为虚拟化环境,以及更进一步检测是哪种虚拟化环境,比如是哪种虚拟机或哪种容器。
2)接下来执行systemd-detect-virt相关命令进行检测。
其中:--container选项仅检测容器 (共享内核虚拟化)。
在笔者系统中运行此命令的结果为:
$ systemd-detect-virt --quiet --container
$
也就是说上边脚本中的if语句的判断为假,并不会执行其中的语句,会跳过if语句往下执行。
3)接下来执行到apparmor_restart这一句。
apparmor_restart是一个函数,在/lib/apparmor/rc.apparmor.functions中,代码如下:
apparmor_restart() {
if ! is_apparmor_loaded ; then
apparmor_start
rc=$?
return "$rc"
fi
__apparmor_restart
return $?
}
apparmor_start函数在同文件(/lib/apparmor/rc.apparmor.functions)中,代码如下:
apparmor_start() {
aa_log_daemon_msg "Starting AppArmor"
if ! is_apparmor_present ; then
aa_log_failure_msg "Starting AppArmor - failed, To enable AppArmor, ensure your kernel is configured with CONFIG_SECURITY_APPARMOR=y the n add 'security=apparmor apparmor=1' to the kernel command line"
aa_log_end_msg 1
return 1
elif ! is_apparmor_loaded ; then
aa_log_failure_msg "Starting AppArmor - AppArmor control files aren't available under /sys/kernel/security/, please make sure securityfs is mounted."
aa_log_end_msg 1
return 1
fi
if [ ! -w "$SFS_MOUNTPOINT/.load" ] ; then
aa_log_failure_msg "Loading AppArmor profiles - failed, Do you have the correct privileges?"
aa_log_end_msg 1
return 1
fi
# if there is anything in the profiles file don't load
if ! read -r _ < "$SFS_MOUNTPOINT/profiles"; then
parse_profiles load
else
aa_log_skipped_msg ": already loaded with profiles."
return 0
fi
aa_log_end_msg 0
return 0
}
__apparmor_restart函数也在同文件(/lib/apparmor/rc.apparmor.functions)中,代码如下:
__apparmor_restart() {
if [ ! -w "$SFS_MOUNTPOINT/.load" ] ; then
aa_log_failure_msg "Loading AppArmor profiles - failed, Do you have the correct privileges?"
return 4
fi
aa_log_daemon_msg "Restarting AppArmor"
parse_profiles reload
rc=$?
aa_log_end_msg "$rc"
return "$rc"
}
is_apparmor_loaded函数同样在/lib/apparmor/rc.apparmor.functions中,代码如下:
is_apparmor_loaded() {
if ! is_securityfs_mounted ; then
mount_securityfs
fi
if [ -f "${SFS_MOUNTPOINT}/profiles" ]; then
return 0
fi
is_apparmor_present
return $?
}
is_securityfs_mounted函数也在lib/apparmor/rc.apparmor.functions中,代码如下:
is_securityfs_mounted() {
test -d "$SECURITYFS" -a -d /sys/fs/cgroup/systemd || grep -q securityfs /proc/filesystems && grep -q securityfs /proc/mounts
return $?
}
is_apparmor_present函数也在lib/apparmor/rc.apparmor.functions中,代码如下:
# Test if the apparmor "module" is present.
is_apparmor_present() {
[ -d /sys/module/apparmor ]
}
笔者的系统中,/sys/module/apparmor目录是存在的,如下所示:
$ ls /sys/module/apparmor -ld
drwxr-xr-x 3 root root 0 5月22日 13:47 /sys/module/apparmor
因此,is_apparmor_present函数执行结果即返回值为0。
实际执行/lib/systemd/system/apparmor.service中的/lib/apparmor/apparmor.systemd reload命令,结果如下:
$ sudo /lib/apparmor/apparmor.systemd reload
Restarting AppArmor
Reloading AppArmor profiles
这样就可以看出,脚本实际上走的是apparmor_restart -> __apparmor_restart -> parse_profiles这个分支。
本文篇幅较长了,其余部分将在后续文章中继续解析。