Análisis de scripts y servicios relacionados con AppArmor (1)

  • apparmor.service

apparmor.service es un servicio relacionado con apparmor. Los archivos se encuentran en /lib/systemd/system/ y /usr/lib/systemd/system/, y el contenido es el siguiente:

[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

El más importante de estos es /lib/apparmor/apparmor.systemd.

  • apparmor.systemd

El archivo apparmor.systemd se encuentra en la ruta /lib/apparmor/ y el contenido es el siguiente:

#!/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"

Tome /lib/apparmor/apparmor.systemd reload en /lib/systemd/system/apparmor.service arriba como ejemplo para analizar el script.

(1) Mire primero el primer párrafo. El fragmento de código es el siguiente:

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=$?
    ;;

Independientemente de si el parámetro detrás de /lib/apparmor/apparmor.systemd es reiniciar, recargar o recargar a la fuerza, ingresará este código.

1) Primero verifique si /usr/bin/systemd-detect-virt existe y es ejecutable. Este es un archivo binario que existe en mi computadora, como se muestra a continuación:

$ ls -l /usr/bin/systemd-detect-virt 
-rwxr-xr-x 1 root root 23416  2月15日 00:36 /usr/bin/systemd-detect-virt

Referencia: systemd-detect-virt Chinese Manual - systemd Chinese Manual - Documentación de desarrollo - Blog de Wenjiang

systemd-detect-virt se utiliza para detectar si el entorno operativo del sistema es un entorno virtualizado y para detectar qué entorno virtualizado es, como qué máquina virtual o contenedor.

2) A continuación, ejecute los comandos relacionados con systemd-detect-virt para la detección.

Dónde: la opción --container solo detecta contenedores (virtualización de kernel compartida).

El resultado de ejecutar este comando en el sistema del autor es:

$ systemd-detect-virt --quiet --container
$ 

Es decir, el juicio de la declaración if en el script anterior es falso, la declaración en él no se ejecutará y la declaración if se omitirá y se ejecutará.

3) A continuación, ejecute la sentencia de apparmor_restart.

apparmor_restart es una función, en /lib/apparmor/rc.apparmor.functions, el código es el siguiente:

apparmor_restart() {
    if ! is_apparmor_loaded ; then
        apparmor_start
        rc=$?
        return "$rc"
    fi

    __apparmor_restart
    return $?
}

La función apparmor_start está en el mismo archivo (/lib/apparmor/rc.apparmor.functions), el código es el siguiente:

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
}

La función __apparmor_restart también está en el mismo archivo (/lib/apparmor/rc.apparmor.functions), el código es el siguiente:

__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"
}

La función is_apparmor_loaded también está en /lib/apparmor/rc.apparmor.functions, el código es el siguiente:

is_apparmor_loaded() {
    if ! is_securityfs_mounted ; then
        mount_securityfs
    fi

if [ -f "${SFS_MOUNTPOINT}/profiles" ]; then
    return 0
fi

    is_apparmor_present

    return $?
}

La función is_securityfs_mounted también está en lib/apparmor/rc.apparmor.functions, el código es el siguiente:

is_securityfs_mounted() {
    test -d "$SECURITYFS" -a -d /sys/fs/cgroup/systemd || grep -q securityfs /proc/filesystems && grep -q securityfs /proc/mounts
    return $?
}

La función is_apparmor_present también está en lib/apparmor/rc.apparmor.functions, el código es el siguiente:

# Test if the apparmor "module" is present.
is_apparmor_present() {
    [ -d /sys/module/apparmor ]
}

En el sistema del autor, existe el directorio /sys/module/apparmor, como se muestra a continuación:

$ ls /sys/module/apparmor -ld
drwxr-xr-x 3 root root 0  5月22日 13:47 /sys/module/apparmor

Por lo tanto, el resultado de la ejecución de la función is_apparmor_present es 0.

En realidad, ejecute el comando de recarga /lib/apparmor/apparmor.systemd en /lib/systemd/system/apparmor.service, el resultado es el siguiente:

$ sudo /lib/apparmor/apparmor.systemd reload
Restarting AppArmor
Reloading AppArmor profiles 

De esta forma, se puede ver que el script en realidad toma la rama de apparmor_restart -> __apparmor_restart -> parse_profiles.

Este artículo es demasiado largo, y el resto se seguirá analizando en artículos posteriores.

Supongo que te gusta

Origin blog.csdn.net/phmatthaus/article/details/130860501
Recomendado
Clasificación