AppArmor相关各脚本和服务解析(1)

  • 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这个分支。

本文篇幅较长了,其余部分将在后续文章中继续解析。

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/130860501