AppArmor is a Linux kernel module that implements Mandatory Access Control (MAC) policies through the Linux Security Modules (LSM) framework. It is similar to SELinux in that it provides a kernel-enforced mechanism to restrict application behavior, except that it primarily uses filesystem paths rather than inodes and labels in order to apply restrictions to running processes. Support for AppArmor must be compiled into the running Linux kernel in order for AppArmor restrictions to be enforced.

Stock Linux kernels since version 2.6.36 already ship with AppArmor support, however this support is removed in the kernels built and shipped by certain distributions, notably the ARM builds of Raspbian. (See § Enabling AppArmor on a Raspberry Pi for instructions to re-enable AppArmor support on Raspberry Pi hardware.) Popular Debian-based operating system distributions such as Ubuntu ship with AppArmor enabled by default. (Contrast with distributions such as CentOS that enable SELinux but not AppArmor by default.)

Installing AppArmor utilities

To interact with AppArmor, you will need to install several userland utilties. On a Debian-based distribution, these are provided in the apparmor-utils package. Install it with:

sudo apt update && sudo apt install apparmor-utils

Checking for AppArmor support

The aa-status utility (or apparmor_status, which is often a symbolic link to the aa-status binary) is a userland program that reports the status of AppArmor on the current system. On a system where AppArmor is supported in the kernel, the first line of output from this utility will read:

apparmor module is loaded.

If AppArmor is supported by your kernel but is not enabled, the second line of output from aa-status will read:

apparmor filesystem is not mounted.

In this case, you will need to enable AppArmor.

For a more granular assement, use the aa-enabled utility to check whether AppArmor is enabled. This utility reports the reason why AppArmor may not be enabled as its error code. See the aa-enabled(1) manual page for more information.

Enabling AppArmor

If your kernel supports AppArmor but it is not active, you must enable AppArmor in order to benefit from it. This situation most often occurs when the kernel supports AppArmor but is not configured to enable it by default. In this situation, AppArmor support must be explicitly enabled by instructing the bootloader to pass recognized command line parameters to the kernel upon its initialization.

In a typical configuration, the command line parameters are:

  • apparmor=1: This enables the AppArmor kernel module.
  • security=apparmor: This selects the AppArmor kernel module to be the currently enforcing Linux Security Module security model.

Enabling AppArmor via GRUB

If your system uses GNU GRUB as its bootloader, you can pass command line arguments to the kernel during the boot sequence.

Enabling AppArmor via GRUB for a single boot

To enable AppArmor for a single boot:

  1. Restart your computer.
  2. When the GRUB menu appears, press the e key to edit the currently selected entry.
  3. Find the kernel command line (the line that starts with linux), and append apparmor=1 security=apparmor to the end of it.
  4. Press the ESC key or the CTRL-x key combination to boot the system with the edited command line.

Enabling AppArmor for every boot

  1. Edit the /etc/default/grub file by appending apparmor=1 security=apparmor to the GRUB_CMDLINE_LINUX_DEFAULT variable.
  2. Execute update-grub(8) as the root user: sudo update-grub. This will rewrite your /boot/grub/grub.cfg file so that, when GRUB loads, it will include the AppArmor kernel command line parameters as part of the boot menu entries.
  3. Restart the system.

Enabling AppArmor on a Raspberry Pi

By default, the Raspberry Pi Foundation does not enable AppArmor in the Linux kernels of their Raspbian OS distributions for the Raspberry Pi single board computers due to performance overheard concerns. The impact that AppArmor has on a Raspberry Pi’s performance is not hugely significant, but is non-negligible. Moreover, relatively few users are aware of AppArmor’s benefits and only a handful of packages ship with developer-supplied AppArmor profiles. Unless these factors change, the Raspberry Pi Foundation’s evaluation is that AppArmor is not a great enough boon to Raspberry Pi users to enable it by default.

If an AppArmor profile is available for the software you wish to constrain, however, enabling AppArmor may prove worthwhile. An example of software whose developers provide an AppArmor profile is Tor. Enabling AppArmor may also prove worthwhile if you write your own AppArmor profile for a given process.

This section provides guidance for configuring, recompiling, and installing a custom Raspberry Pi kernel with AppArmor support enabled. It is largely based on the official Raspberry Pi documentation for building and configuring a custom kernel along with information gathered from Raspberry Pi support forum postings.

Cross-compiling the RPi kernel

While it is possible to build a new kernel directly on Raspberry Pi hardware itself, doing so takes significantly longer. This section describes the process of cross-compiling the Raspberry Pi’s Linux kernel on an Intel x86-compatible chipset. The instructions make use of a Vagrant-managed and VirtualBox-backed virtual machine running a 64-bit version of the Ubuntu operating system as the build environment. Ubuntu is chosen for its similarities to the Raspberry Pi’s own environment.

  1. Install VirtualBox.
  2. Install Vagrant.
  3. Define an Ubuntu virtual machine using Vagrant:
    mkdir rpi-kernel-build          # Make a new directory to house the VM.
    cd rpi-kernel-build             # Go to that directory.
    vagrant init -m ubuntu/bionic64 # Write a Vagrantfile configuration.
  4. Boot the virtual machine:
    vagrant up
  5. Enter the virtual machine over SSH:
    vagrant ssh
  6. Ensure the necessary build tools are installed. These include the git source code management (SCM) system and the bc precision calculator.
    sudo apt install git bc
  7. Next, download the kernel source code from the Raspberry Pi Foundation’s fork of the upstream Linux kernel. We’ll be doing this in the special /vagrant directory which is automatically synchronized between the guest virtual machine and the host physical machine.
    cd /vagrant
    # We have no need for downloading development history, so we
    # pass the `--depth 1` argument to `git clone`, which saves a
    # lot of disk space and bandwidth.
    git clone --depth 1
  8. Next, download the cross-compiling toolchain so that we can produce ARM-compatible machine code despite building on an Intel x86-based machine:
    git clone --depth 1
  9. Add the cross-compilation toolchain utilities to your shell’s executable search PATH variable so that the tools can be invoked by the build scripts:
    export PATH=\$PATH:$(pwd)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
  10. Change into the linux source code directory:
    cd linux
  11. Write the initial version of the (basic, default) .config kernel configuration file using the Raspberry Pi Foundation’s makefile targets:
    1. If you are building a kernel for the Pi 1, Pi Zero, Pi Zero W, or Compute Module (earlier than version 3) hardware models:
      # Invoke the `bcmrpi_defconfig` make target to create your `.config` file.
      make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
    2. If you are building a kernel for the Pi 2, Pi 3, Pi 3+, or Compute Module 3 hardware models:
      # Invoke the `bcm2709_defconfig` make target to create your `.config` file.
      make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
  12. Customize your .config file by using a configuration tool such as menuconfig (i.e., install the menuconfig dependencies, sudo apt install libncurses5-dev, and then invoke make menuconfig to start the configuration process) or by editing the .config file directly with a text editor (e.g., vim .config) so that it includes support for the AppArmor module. Doing so requires the following lines to be present and in your .config file:
  13. Compile the configured kernel (zImage), kernel modules (modules), and device tree blobs (dtbs) by invoking make with their targets through the cross-compilation toolchain:
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
  14. Next, build and write out (“install”) the kernel module directory hierarchy for the new kernel. This will create a lib/modules/$KERNEL_VERSION directory (where $KERNEL_VERSION is the version of the newly built kernel) at the $INSTALL_MOD_PATH location (the special /vagrant directory):
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/vagrant modules_install

    In this current directory, you should now have a new kernel with support for AppArmor (in the file named zImage), numerous device tree binary blobs (in the files that end with the .dtb extension), an overlays directory containing device tree overlay object files. In the $INSTALL_MOD_PATH directory (e.g., /vagrant), you will have a lib/ directory containing a modules/ directory containing the kernel modules for the built kernel.
  15. The kernel and device tree blob and overlay files, and probably the kernel modules as well, will need to be copied to the hard disk (i.e., the SD card) from which the Raspberry Pi will boot. This can be accomplished over a network connection with the use of, for example, scp(1) while the Raspberry Pi is running or directly onto the disk itself by removing the SD card from the Pi and making the disk’s filesystem available to your build computer through a USB port. Either way, the following table shows which file generated from the cross-compilation process should end up in which filesystem location on the Raspbery Pi’s SD card:
Built file or directory tree Ultimate destination on Raspberry Pi Notes
zImage /boot/kernel7.img For Pi 1, Pi Zero, Pi Zero W, or Compute Module (earlier than version 3) hardware models, the default kernel image file is /boot/kernel.img, not kernel7.img
*.dtb /boot/*.dtb
overlays/ /boot/overlays/
lib/modules/$KERNEL_VERSION /lib/modules/$KERNEL_VERSION Where $KERNEL_VERSION is the version of the kernel you built.

After copying the built files to their correct ultimate destinations as mapped in the table above, you should be able to reboot the Raspberry Pi, invoke the aa-status utility, and see that the AppArmor module is loaded into the running kernel as described in § Checking for AppArmor support. The next step is to begin § Installing AppArmor profiles

Building a new kernel on RPi hardware


Building with Ansible

The AnarchoTech NYC collective provides an AppArmor-enabled Linux kernel for the Raspberry Pi as part of their "common" baseline. The role’s default configuration will detect the absence of AppArmor on a Raspbian system and, if running on Raspberry Pi hardware, will automatically build and install a new kernel with AppArmor support enabled by default.

Enabling AppArmor at boot time on a Raspberry Pi

Assuming you have built a kernel with AppArmor support for a Raspberry Pi, you can enable AppArmor support by passing the apparmor=1 and security=apparmor options via the kernel command line. This may be necessary if aa-status reports output such as:

apparmor module is loaded.
apparmor filesystem is not mounted.

The above indicates the kernel supports AppArmor (i.e., the “apparmor module is loaded.”) but that it is currently not enabled (i.e., the “apparmor filesystem is not mounted.”). In such a situation, you can also confirm that this is the case by invoking aa-enabled, which should respond with No - disabled at boot..

On physical RPi devices, the bootloader is in the firmware (there is no separate bootloader such as GRUB) itself. It’s designed to read its kernel command line arguments from a file located at /boot/cmdline.txt. Simply append the AppArmor options to this file, and then reboot the Raspberry Pi. For example:

cat /boot/cmdline.txt <(echo " apparmor=1 security=apparmor") | tr -d "\n"

Installing AppArmor profiles

In order for AppArmor to constrain a given process, a profile must be loaded for that process. Few software packages ship with AppArmor profiles for the programs they deliver, however additional profiles may be available from your OS distribution’s default package repositories. On a Debian-based system, install them with:

sudo apt update && sudo apt install apparmor-profiles

# Additional AppArmor profiles are available in the apparmor-profiles-extra package.
sudo apt install apparmor-profiles-extra

AppArmor profiles are loaded from plain text files written in a DSL. See the apparmor.d(8) manual page for details regarding the syntax of an AppArmor profile file. These files can then be parsed and subsquently loaded into the kernel using the apparmor_parser utility.

AppArmor profile directory structure

By convention, AppArmor profile files should be placed into the /etc/apparmor.d directory. This directory is structured as follows:

  • /etc/apparmor.d/ – Base directory containing AppArmor profile files.
    • – Profile file for the /bin/ping executable. Files are named with a dot-separated notation that matches their installed filesystem path. (This is just a convention, see the contents of the file for the process to which the profile will actually be applied. See, for example, /etc/apparmor.d/system_tor.)
    • local/ – Conventional directory for site-specific overrides or extensions to a vendor’s AppArmor profile.
    • abstractions/
    • tunables/
    • disable/ – Directory containing symbolic links to profile files that are to be disabled (not enforced).
    • force-complain/

See also