From ecf82c71766f23a83dda6951d68f8bd684b2432e Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Sun, 29 Jan 2023 21:18:22 +0000 Subject: [PATCH] docs: initial documentation website. --- .gitlab-ci.yml | 17 ++++ docs/assets/favicon.png | Bin 0 -> 19010 bytes docs/concepts.md | 30 ++++++ docs/configuration.md | 106 ++++++++++++++++++++ docs/development/guidelines.md | 128 ++++++++++++++++++++++++ docs/development/index.md | 99 +++++++++++++++++++ docs/development/structure.md | 173 +++++++++++++++++++++++++++++++++ docs/enforce.md | 17 ++++ docs/index.md | 39 ++++++++ docs/install.md | 89 +++++++++++++++++ docs/issues.md | 46 +++++++++ docs/recovery.md | 27 +++++ docs/report.md | 14 +++ docs/usage.md | 121 +++++++++++++++++++++++ docs/variables.md | 97 ++++++++++++++++++ mkdocs.yml | 137 ++++++++++++++++++++++++++ requirements.txt | 3 + 17 files changed, 1143 insertions(+) create mode 100644 docs/assets/favicon.png create mode 100644 docs/concepts.md create mode 100644 docs/configuration.md create mode 100644 docs/development/guidelines.md create mode 100644 docs/development/index.md create mode 100644 docs/development/structure.md create mode 100644 docs/enforce.md create mode 100644 docs/index.md create mode 100644 docs/install.md create mode 100644 docs/issues.md create mode 100644 docs/recovery.md create mode 100644 docs/report.md create mode 100644 docs/usage.md create mode 100644 docs/variables.md create mode 100644 mkdocs.yml create mode 100644 requirements.txt diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 080a248b..499ac9e3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ stages: - test - build - preprocess + - deploy # Code Linter @@ -128,3 +129,19 @@ preprocess-ubuntu: - apt-get install -y apparmor apparmor-profiles - dpkg --install $PKGDEST/* - apparmor_parser --preprocess /etc/apparmor.d 1> /dev/null + + +# Deploy the documentation +# ------------------------ + +pages: + stage: deploy + image: python + script: + - pip install -r requirements.txt + - mkdocs build --verbose --site-dir public + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..11ee3307f0fd4efff4f035ea4217c28f49197998 GIT binary patch literal 19010 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 I*dXwK0jgDDA^-pY literal 0 HcmV?d00001 diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 00000000..14e5417e --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,30 @@ +--- +title: Concepts +--- + +# Concepts + +*One profile a day keeps the hacker away* + +There are over 50000 Linux packages and even more applications. It is simply not +possible to write an AppArmor profile for all of them. Therefore, a question arises: + +**What to confine and why?** + +We take inspiration from the [Android/ChromeOS Security Model][android_model] and +we apply it to the Linux world. Modern [Linux security distribution][clipos] usually +consider an immutable core base image with a carefully set of selected applications. +Everything else should be sandboxed. Therefore, this project tries to confine all +the *core* applications you will usually find in a Linux system: all systemd services, +xwayland, network, bluetooth, your desktop environment... Non-core user applications +are out of scope as they should be sandboxed using a dedicated tool (minijail, +bubblewrap, toolbox...). + +This is fundamentally different from how AppArmor is usually used on Linux server +as it is common to only confine the applications that face the internet and/or the users. + + +[android_model]: https://arxiv.org/pdf/1904.05572 +[clipos]: https://clip-os.org/en/ +[write xor execute]: https://en.wikipedia.org/wiki/W%5EX + diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..f8b91307 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,106 @@ +--- +title: Configuration +--- + +## AppArmor + +As there are a lot of rules, it is recommended to enable caching AppArmor profiles. +In `/etc/apparmor/parser.conf`, add `write-cache` and `Optimize=compress-fast`. + +```sh +echo 'write-cache' | sudo tee /etc/apparmor/parser.conf +echo 'Optimize=compress-fast' | sudo tee /etc/apparmor/parser.conf +``` + +!!! info + + See [Speed up AppArmor Start] on the Arch Wiki for more information: + [Speed up AppArmor Start]: https://wiki.archlinux.org/title/AppArmor#Speed-up_AppArmor_start_by_caching_profiles + + +## Personal directories + +This project is designed in such a way that it is easy to personalize the +directory your program can access by defining a few variables. + +The profiles heavily use the (largely extended) XDG directory variables defined +in the **[Variables Reference](/variables)** page. + +??? note "XDG variables overview" + + See **[Variables Reference](/variables)** page for more. + + | Description | Name | Value | + |-------------|:----:|---------| + | Desktop | `@{XDG_DESKTOP_DIR}` | `Desktop` | + | Download | `@{XDG_DOWNLOAD_DIR}` | `Downloads` | + | Templates | `@{XDG_TEMPLATES_DIR}` | `Templates` | + | Public | `@{XDG_PUBLICSHARE_DIR}` | `Public` | + | Documents | `@{XDG_DOCUMENTS_DIR}` | `Documents` | + | Music | `@{XDG_MUSIC_DIR}` | `Music` | + | Pictures | `@{XDG_PICTURES_DIR}` | `Pictures` | + | Videos | `@{XDG_VIDEOS_DIR}` | `Videos` | + | Books | `@{XDG_BOOKS_DIR}` | `Books` | + | Projects | `@{XDG_PROJECTS_DIR}` | `Projects` | + | Screenshots | `@{XDG_SCREENSHOTS_DIR}` | `@{XDG_PICTURES_DIR}/Screenshots` | + | Sync | `@{XDG_SYNC_DIR}` | `Sync` | + | Torrents | `@{XDG_TORRENTS_DIR}` | `Torrents` | + | Vm | `@{XDG_VM_DIR}` | `.vm` + | Wallpapers | `@{XDG_WALLPAPERS_DIR}` | `@{XDG_PICTURES_DIR}/Wallpapers` | + +You can personalize these values with by creating a file such as: +`/etc/apparmor.d/tunables/xdg-user-dirs.d/local` where you define your own +personal directories. Example: +```sh +@{XDG_VIDEOS_DIR}+="Films" +@{XDG_MUSIC_DIR}+="Musique" +@{XDG_PICTURES_DIR}+="Images" +@{XDG_BOOKS_DIR}+="BD" "Comics" +@{XDG_PROJECTS_DIR}+="Git" "Papers" +``` + +Then restart the apparmor service to reload the profiles in the kernel: +```sh +sudo systemctl restart apparmor.service +``` + +**Examples** + +- For git support, you may want to add your `GO_PATH` in the `XDG_PROJECTS_DIR`: + ```sh + @{XDG_PROJECTS_DIR}+="go" + ``` +- If you use Keepass, personalize `XDG_PASSWORD_STORE_DIR` with your password directory. Eg: + ```sh + @{XDG_PASSWORD_STORE_DIR}+="@{HOME}/.keepass/" + ``` +- Add pacman integration with your AUR helper. Eg for `yay`: + ```sh + @{user_pkg_dirs}+=@{user_cache_dirs}/yay/ + ``` + +## Local profile extensions + +You can extend any profile with your own rules by creating a file in the +`/etc/apparmor.d/local/` directory with the name of your profile. For example, +to extend the `foo` profile, create a file `/etc/apparmor.d/local/foo` and add +your rules in it. + +**Example** + +- `child-open`, a profile that allows other program to open resources (URL, + picture, books...) with some predefined GUI application. To allow it to open + URL with Firefox, create the file `/etc/apparmor.d/local/child-open` with: + ```sh + /{usr/,}bin/firefox rPx, + ``` + **NB:** This is an example, no need to add Firefox into `child-open`, it is already there. + +!!! note + + `rPx` allows transition to the Firefox profile. Use `rPUx` to allow + transition to an unconfined state if you do not have the profile for a + given program. + + +Then, reload the apparmor rules with `sudo systemctl restart apparmor`. diff --git a/docs/development/guidelines.md b/docs/development/guidelines.md new file mode 100644 index 00000000..96aee3fe --- /dev/null +++ b/docs/development/guidelines.md @@ -0,0 +1,128 @@ +--- +title: Guidelines +--- + +## Common structure + +AppArmor profiles can be written without any specific guidelines. However, +when you work with over 1400 profiles, you need a common structure among all the +profiles. + +The logic behind it is that if a rule is present in a profile, it should only be +in one place, making profile review easier. + +For example, if a program needs to run executables binary. The rules allowing it +can only be in a specific rule block (just after the `@{exec_path} mr,` rule). It +is therefore easy to ensure some profile features such as: + +* A profile has access to a given resource +* A profile enforces a strict [write xor execute] (W^X) policy. + +It also improves compatibilities and makes personalization easier thanks to the +use of more variables. + +## Guidelines + +!!! note + + This profile guideline is still evolving, feel free to propose improvement + as long as it does not vary too much from the existing rules. + +In order to ensure a common structure across the profiles, all new profile **must** +follow the guidelines presented here. + +The rules in the profile should be sorted in rule ***block*** as follow: + +- `include` +- `set rlimit` +- `capability` +- `network` +- `mount` +- `remount` +- `umount` +- `pivot_root` +- `change_profile` +- `signal` +- `ptrace` +- `unix` +- `dbus` +- `file` +- local include + +This rule order is taken from AppArmor with minor changes as we tend to: + +- Divide the file block in multiple subcategories +- Put the block with the longer rules (`files`, `dbus`) after the other blocks + +### The file blocks + +The file block should be sorted as follow: + +- `@{exec_path} mr`, the entry point of the profile +- The binaries and library required: + - `/{usr/,}bin/`, `/{usr/,}lib/`, `/opt/`... + - It is the only place where you can have `mr`, `rix`, `rPx`, `rUx`, `rPUX` rules. +- The shared resources: `/usr/share`... +- The system configuration: `/etc`... +- The system data: `/var`... +- The user data: `owner @{HOME}/`... +- The user configuration, cache and in general all dotfiles +- Temporary and runtime data: `/tmp/`, `@{run}/`, `/dev/shm/`... +- Sys files: `@{sys}/`... +- Proc files: `@{PROC}/`... +- Dev files: `/dev/`... +- Deny rules: `deny`... + +### The dbus block + + +The dbus block should be sorted as follow: + +- The system bus should be sorted *before* the session bus +- The bind rules should be sorted *after* the send & receive rules + +For DBus, try to determine peer's label when possible. E.g.: +``` +dbus send bus=session path=/org/freedesktop/DBus + interface=org.freedesktop.DBus + member={RequestName,ReleaseName} + peer=(name=org.freedesktop.DBus, label=dbus-daemon), +``` +If there is no predictable label it can be omitted. + +### Profiles rules + +`bin, sbin & lib` + +: - Do not use: `/usr/lib` or `/usr/bin` but `/{usr/,}bin/` or `/{usr/,}lib/` + - Do not use: `/usr/sbin` or `/sbin` but `/{usr/,}{s,}bin/`. + +`Variables` + +: Always use the apparmor variables. + +`Sort` + +: In a rule block, the rule shall be alphabetically sorted. + +`Sub profile` + +: Sub profile should comes at the end of a profile. + +`Similar purpose` + +: When some file access share similar purpose, they may be sorted together. Eg: + ``` + /etc/machine-id r, + /var/lib/dbus/machine-id r, + ``` + + +## Additional recommended documentation + +* [The AppArmor Core Policy Reference](https://gitlab.com/apparmor/apparmor/-/wikis/AppArmor_Core_Policy_Reference) +* [The AppArmor.d man page](https://man.archlinux.org/man/apparmor.d.5) +* [F**k AppArmor](https://presentations.nordisch.org/apparmor/#/) +* [A Brief Tour of Linux Security Modules](https://www.starlab.io/blog/a-brief-tour-of-linux-security-modules) + +[write xor execute]: https://en.wikipedia.org/wiki/W%5EX diff --git a/docs/development/index.md b/docs/development/index.md new file mode 100644 index 00000000..61b05c88 --- /dev/null +++ b/docs/development/index.md @@ -0,0 +1,99 @@ +--- +title: Development +--- + +# Development + +You want to contribute to `apparmor.d`, **thank a lot for this.** Feedbacks, +contributors, pull requests are all very welcome. You will find in this page all +the useful information needed to contribute. + +??? info "How to contribute" + + 1. If you don't have git on your machine, [install it][git]. + 2. Fork this repo by clicking on the fork button on the top of this page. + 3. Clone the repository and go to the directory: + ```sh + git clone https://github.com/this-is-you/apparmor.d.git + cd apparmor.d + ``` + 4. Create a branch: + ``` + git checkout -b my_contribution + ``` + 5. Make the changes and commit: + ``` + git add + git commit -m "A message for sum up my contribution" + ``` + 6. Push changes to GitHub: + ``` + git push origin my_contribution + ``` + 7. Submit your changes for review: If you go to your repository on GitHub, + you'll see a Compare & pull request button, fill and submit the pull request. + + +## Project rules + +`Rule 1: Mandatory Access Control` + +: As these are mandatory access control policies only what it explicitly required + should be authorized. Meaning, you should **not** allow everything (or a large area) + and blacklist some sub areas. + +`Rule 2: Do not break a program` + +: A profile **should not break a normal usage of the confined software**. It can + be complex as simply running the program for your own use case is not always + exhaustive of the program features and required permissions. + +`Rule 3: Do not confine everything` + +: Some programs should not be confined by a MAC policy. + + + +## Add a profile + +!!! danger "Warning" + + Following the [profile guidelines](guidelines) is **mandatory** for all new profiles. + + +1. To add a new profile `foo`, add the file `foo` in [`apparmor.d/profile-a-f`][profiles-a-f]. + If your profile is part of a large group of profiles, it can also go in + [`apparmor.d/groups`][groups]. + +2. Write the profile content, the rules depend of the confined program, + Here is the bare minimum for the program `foo`: +``` sh +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2023 You +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = /{usr/,}bin/foo +profile foo @{exec_path} { + include + + @{exec_path} mr, + + include if exists +} +``` + + +3. You can automatically set the `complain` flag on your profile by editing the file [`dists/flags/main.flags`][flags] and add a new line with: `foo complain` + +4. Build & install for your distribution. + + +[git]: https://help.github.com/articles/set-up-git/ + +[flags]: https://github.com/roddhjav/apparmor.d/blob/master/dists/flags/main.flags +[profiles-a-f]: https://github.com/roddhjav/apparmor.d/blob/master/apparmor.d/profiles-a-f +[groups]: https://github.com/roddhjav/apparmor.d/blob/master/apparmor.d/groups diff --git a/docs/development/structure.md b/docs/development/structure.md new file mode 100644 index 00000000..28ce2f68 --- /dev/null +++ b/docs/development/structure.md @@ -0,0 +1,173 @@ +--- +title: Structure +--- + +Description of common structure found across various AppArmor profiles + + +## Program to not confine + +Some programs should not be confined by themselves. For example, tools such as +`ls`, `rm`, `diff` or `cat` do not have profile in this project. Let's see why. + +These are general tools that in a general context can legitimately access any +file in the system. Therefore, the confinement of such tools by a global +profile would at best be minimal at worst be a security theater. + +It gets even worse. Let's say, we write a profile for `cat`. Such a profile +would need access to `/etc/`. We will add the following rule: +```sh + /etc/{,**} rw, +``` + +However, as `/etc` can contain sensitive files, we now want to explicitly +prevent access to these sensitive files. Problems: + +1. How do we know the exhaustive list of *sensitive files* in `/etc`? +2. How do we ensure access to these sensitive files are not required? +3. This breaks the principle of mandatory access control. + See the [first rule of this project][project-rules] that is to only allow + what is required. Here we allow everything and blacklist some paths. + +It creates even more issues when we want to use this profile in other profiles. +Let's take the example of `diff`. Using this rule: `/{,usr/}bin/diff rPx,` will +restrict access to the very generic and not very confined `diff` profile. +Whereas most of the time, we want to restrict `diff` to some specific file in +our profile: + +* In `dpkg`, an internal child profile (`rCx -> diff`), allows `diff` to only + access etc config files: + +!!! note "" + + [apparmor.d/apparmor.d/groups/apt/dpkg](https://github.com/roddhjav/apparmor.d/blob/accf5538bdfc1598f1cc1588a7118252884df50c/apparmor.d/groups/apt/dpkg#L123) + ``` aa linenums="123" + profile diff { + ``` + +* In `pass`, as it is a dependency of pass. Here `diff` inherit pass profile + and has the same access than the pass profile, so it will be allowed to diff + password files because more than a generic `diff` it is a `diff` for the pass + password manager: + +!!! note "" + + [apparmor.d/apparmor.d/profiles-m-r/pass](https://github.com/roddhjav/apparmor.d/blob/accf5538bdfc1598f1cc1588a7118252884df50c/apparmor.d/profiles-m-r/pass#L20 + ) + ``` aa linenums="20" + /{usr/,}bin/diff rix, + ``` + +**What if I still want to protect these programs?** + +You do not protect this program. *Protect the usage you have of these tools*. +In practice, it means that you should put your development's terminal in a +sandbox managed with [Toolbox] + +!!! example "To sum up" + + 1. Do not create profile for programs such as: `rm`, `ls`, `diff`, `cd`, `cat` + 2. Do not create profile for the shell: `bash`, `sh`, `dash`, `zsh` + 3. Use [Toolbox]. + +[project-rules]: /development/#project-rules +[Toolbox]: https://containertoolbx.org/ + + + +## Abstractions + +This project and the apparmor profile official project provide a large selection +of abstractions to be included in profiles. They should be used. + +For instance, to allow download directory access, instead of writing: +```sh +owner @{HOME}/@{XDG_DOWNLOAD_DIR}/{,**} rw, +``` + +You should write: +```sh +include +``` + + +## Children profiles + +Usually, a child profile is in the [`children`][children] group. They have +the following note: + +!!! quote + + Note: This profile does not specify an attachment path because it is + intended to be used only via `"Px -> child-open"` exec transitions + from other profiles. + +[children]: https://github.com/roddhjav/apparmor.d/blob/master/apparmor.d/groups/children + +Here is an overview of the current children profile: + +1. **`child-open`**: To opens resources. Instead of allowing the run of all + software in `/{usr/,}bin/`, the purpose of this profile is to list all GUI + program that can open resources. Ultimately, only sandbox manager programs + such as `bwrap`, `snap`, `flatpak`, `firejail` should be present here. Until + this day, this profile will be a controlled mess. + +2. **`child-pager`**: Simple access to pager such as `pager`, `less` and `more`. + This profile supposes the pager is reading its data from stdin, not from a + file on disk. + +3. **`child-systemctl`**: Common systemctl action. Do not use it too much as most + of the time you will need more privilege than what this profile is giving you. + + +## Udev rules + +See the **[kernel docs][kernel]** to check the major block and char numbers used in `/run/udev/data/`. + +Special care must be given as some as sometime udev numbers are allocated +dynamically by the kernel. Therefore, the full range must be allowed: + +!!! note "" + + [apparmor.d/groups/virt/libvirtd](https://github.com/roddhjav/apparmor.d/blob/15e33a1fe6654f67a187cd5157c9968061b9511e/apparmor.d/groups/virt/libvirtd#L179-L184) + ``` aa linenums="179" + @{run}/udev/data/c23[4-9]:[0-9]* r, # For dynamic assignment range 234 to 254 + @{run}/udev/data/c24[0-9]:[0-9]* r, + @{run}/udev/data/c25[0-4]:[0-9]* r, + @{run}/udev/data/c3[0-9]*:[0-9]* r, # For dynamic assignment range 384 to 511 + @{run}/udev/data/c4[0-9]*:[0-9]* r, + @{run}/udev/data/c5[0-9]*:[0-9]* r, + ``` + +[kernel]: https://raw.githubusercontent.com/torvalds/linux/master/Documentation/admin-guide/devices.txt + + +## Full system policy + +!!! quote + + AppArmor is also capable of being used for full system policy + where processes are by default not running under the `unconfined` + profile. This might be useful for high security environments or + embedded systems. + + *Source: [AppArmor Wiki][apparmor-wiki]* + +This feature is only enabled when the `--full` option is passed to +the `configure` script. The profiles for full system policies are maintained in +the **[`_full`][_full]** group. It consists of two extra main profiles: + +1. **`init`**: For systemd as PID 1 +2. **`systemd`**: For systemd as user + +All core required applications that need to be started by systemd (both as user +or root) need to be present in these profiles. + +!!! danger + + Full system policy is still under early development, do not run it outside a + development VM! **You have been warned!!!** + + +[apparmor-wiki]: https://gitlab.com/apparmor/apparmor/-/wikis/FullSystemPolicy +[_full]: https://github.com/roddhjav/apparmor.d/blob/master/apparmor.d/groups/_full diff --git a/docs/enforce.md b/docs/enforce.md new file mode 100644 index 00000000..79221fb6 --- /dev/null +++ b/docs/enforce.md @@ -0,0 +1,17 @@ +--- +title: Enforce Mode +--- + +# Enforce Mode + +The default package configuration installs all profiles in *complain* mode. +Once you tested them and it works fine, you can easily switch to *enforce* mode. +To do this, edit `PKGBUILD` on Archlinux or `debian/rules` on Debian and remove +the `--complain` option to the configure script. Then build the package as usual: +```diff +- ./configure --complain ++ ./configure +``` + +Do not worry, the profiles that are not considered stable are kept in complain mode. +They can be tracked in the [`dists/flags`](https://github.com/roddhjav/apparmor.d/tree/master/dists/flags) directory. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..1050dec7 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,39 @@ +--- +title: AppArmor.d +--- + +# AppArmor.d + +**Full set of AppArmor profiles** + +!!! danger "Help Wanted" + + This project is still in its early development. Help is very welcome + see [Development](development/) + +**AppArmor.d** is a set of over 1400 AppArmor profiles which aims is to confine +most of Linux base applications and processes. + +**Purpose** + +- Confine all root processes such as all `systemd` tools, `bluetooth`, `dbus`, + `polkit`, `NetworkManager`, `OpenVPN`, `GDM`, `rtkit`, `colord`. +- Confine all Desktop environments +- Confine all user services such as `Pipewire`, `Gvfsd`, `dbus`, `xdg`, `xwayland` +- Confine some *"special"* user applications: web browser, file browser... +- Should not break a normal usage of the confined software +- Fully tested (Work in progress) + +See the [Concepts](concepts) page for more detail on the architecture. + +**Goals** + +- Target both desktop and server +- Support all distributions that support AppArmor: + * Currently: + - :material-arch: Archlinux + - :material-ubuntu: Ubuntu 22.04 + - :material-debian: Debian 11 + * Not (yet) tested on openSUSE +- Support all major desktop environments: + * Currently only :material-gnome: Gnome diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 00000000..207e704e --- /dev/null +++ b/docs/install.md @@ -0,0 +1,89 @@ +--- +title: Installation +--- + +!!! danger + + In order to not break your system, the default package configuration install + all profiles in complain mode. They can be enforced later. + See the [Enforce Mode](/enforce) page. + +## Requirements + +**AppArmor** + +An `apparmor` based Linux distribution is required. The basic profiles and +abstractions shipped with AppArmor must be installed. + +**Desktop environment** + +The following desktop environments are supported: + + - [x] :material-gnome: Gnome + +Also, please note wayland has better support than xorg. + +**Build dependencies** + +* Go +* Rsync + +## :material-arch: Archlinux + +`apparmor.d-git` is available in the [Arch User Repository][aur]: +```sh +git clone https://aur.archlinux.org/apparmor.d-git.git +cd apparmor.d-git +makepkg -s +sudo pacman -U apparmor.d-*.pkg.tar.zst \ + --overwrite etc/apparmor.d/tunables/global \ + --overwrite etc/apparmor.d/tunables/xdg-user-dirs \ + --overwrite etc/apparmor.d/abstractions/trash +``` + +The overwrite options are only required on the first install. You can use `yay` +or your preferred AUR install method to update it. + +!!! note + + The following Archlinux based distributions are supported: + + - [x] CachyOS + - [x] EndeavourOS + - [x] :material-manjaro: Manjaro Linux + + +## :material-ubuntu: Ubuntu & :material-debian: Debian + + +Build the package from sources: +```sh +sudo apt install apparmor-profiles build-essential config-package-dev debhelper golang-go rsync git +git clone https://github.com/roddhjav/apparmor.d.git +cd apparmor.d +dpkg-buildpackage -b -d --no-sign +sudo dpkg -i ../apparmor.d_*_all.deb +``` + + +## Partial install + +!!! warning + + Partial installation is discouraged because profile dependencies are + not fetched. You may need to either switch desired `rPx` rules to `rPUx` + (fallback to unconfined) or install these related profiles. + (PR is welcome see [#77](https://github.com/roddhjav/apparmor.d/issues/77)) + +For test purposes, you can install a specific profile with the following commands. +Abstractions, tunables, and most of the OS dependent post-processing is managed. + +```sh +./configure --complain +make +sudo make profile-names... +``` + +[aur]: https://aur.archlinux.org/packages/apparmor.d-git +[repo]: https://repo.pujol.io/ +[keys]: https://repo.pujol.io/gpgkey diff --git a/docs/issues.md b/docs/issues.md new file mode 100644 index 00000000..24905ed9 --- /dev/null +++ b/docs/issues.md @@ -0,0 +1,46 @@ +--- +title: Known issues +--- + +# Known issues + +!!! info + + Known bugs are tracked on the meta issue **[#75](https://github.com/roddhjav/apparmor.d/issues/74)**. + + +### Pacman "could not get current working directory" + +```sh +$ sudo pacman -Syu +... +error: could not get current working directory +:: Processing package changes... +... +``` + +This is **a feature, not a bug!** It can safely be ignored. Pacman tries to get +your current directory. You will only get this error when you run pacman in your +home directory. + +According the Archlinux guideline, on Archlinux, packages cannot install files +under `/home/`. Therefore the [`pacman`][pacman] profile purposely does not +allow access of your home directory. This is + +This provides a basic protection against some package (on the AUR) that may have +rogue install script. + +[pacman]: https://github.com/roddhjav/apparmor.d/blob/master/apparmor.d/groups/pacman/pacman + + +### Gnome can be very slow to start. + +[Gnome](https://github.com/roddhjav/apparmor.d/issues/80) can be slow to start. +This is a Known bugs help is very welcome. + +The complexity is that: + +- It works fine without AppArmor +- It works fine on most system (including test VM) +- It seems to be dbus related +- On archlinux, the dbus mediation is not enabled. So, there is nothing special to allow. diff --git a/docs/recovery.md b/docs/recovery.md new file mode 100644 index 00000000..48ec71e5 --- /dev/null +++ b/docs/recovery.md @@ -0,0 +1,27 @@ +--- +title: System Recovery +--- + +# System Recovery + +Issue in some core profiles like the systemd suite, or the desktop environment +can fully break your system. This should not happen a lot, but if it does here +is the process to recover your system on Archlinux: + +1. Boot from a Archlinux live USB +1. If you root partition is encryped, decrypt it: `cryptsetup open /dev/ vg0` +1. Mount your root partition: `mount /dev/ /mnt` +1. Chroot into your system: `arch-chroot /mnt` +1. Check the AppArmor messages to see what profile is faulty: `aa-log` +1. Temporarily fix the issue with either: + - When only one profile is faultily, remove it: `rm /etc/apparmor.d/` + - Otherwise, you can also remove the package: `pacman -R apparmor.d` + - Alternatively, you may temporarily disable apparmor as it will allow you to + boot and study the log: `systemctl disable apparmor` +1. Exit, unmount, and reboot: + ```sh + exit + umount -R /mnt + reboot + ``` +1. Create an issue and report the output of `aa-log` diff --git a/docs/report.md b/docs/report.md new file mode 100644 index 00000000..0507abc7 --- /dev/null +++ b/docs/report.md @@ -0,0 +1,14 @@ +--- +title: Report AppArmor logs +--- + +# Report AppArmor logs + +The **[aa-log](/usage/#apparmor-log)** tool reports all AppArmor `DENIED` and +`ALLOWED`. It should be used to fix AppArmor related issues. + +When creating [an issue on Github][newissue]. Please ensure you post a link to +the [paste] of the AppArmor audit log: `/var/log/audit/audit.log`. + +[newissue]: https://github.com/roddhjav/apparmor.d/issues/new +[paste]: https://pastebin.com/ diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..c0ae423a --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,121 @@ +--- +title: Usage +--- + +## Enabled profiles + +Once installed and with the rules enabled, you can ensure the rules are loaded +with: +```sh +sudo aa-status +``` + +It should give something like: +``` +apparmor module is loaded. +1441 profiles are loaded. +112 profiles are in enforce mode. + ... +0 profiles are in kill mode. +0 profiles are in unconfined mode. +155 processes have profiles defined. +14 processes are in enforce mode. + ... +141 processes are in complain mode. + ... +0 processes are unconfined but have a profile defined. +0 processes are in mixed mode. +0 processes are in kill mode. +``` + +You can also list the current processes alongside with their security profile with: +```sh +ps auxZ +``` + +Most of the processes should then be confined: +``` +unconfined root /usr/lib/systemd/systemd --switched-root --system --deserialize 33 +systemd-udevd (complain) root /usr/lib/systemd/systemd-udevd +systemd-journald (complain) root /usr/lib/systemd/systemd-journald +rngd (complain) root /usr/bin/rngd -f +systemd-timesyncd (complain) systemd+ /usr/lib/systemd/systemd-timesyncd +auditd (complain) root /sbin/auditd +acpid (complain) root /usr/bin/acpid --foreground --netlink +dbus-daemon (complain) dbus /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only +power-profiles-daemon (complain) root /usr/lib/power-profiles-daemon +systemd-logind (complain) root /usr/lib/systemd/systemd-logind +systemd-machined (complain) root /usr/lib/systemd/systemd-machined +NetworkManager (complain) root /usr/bin/NetworkManager --no-daemon +polkitd (complain) polkitd /usr/lib/polkit-1/polkitd --no-debug +gdm (complain) root /usr/bin/gdm +accounts-daemon (complain) root /usr/lib/accounts-daemon +rtkit-daemon (complain) rtkit /usr/lib/rtkit-daemon +packagekitd (complain) root /usr/lib/packagekitd +colord (complain) colord /usr/lib/colord +unconfined user /usr/lib/systemd/systemd --user +unconfined user (sd-pam) +gdm-wayland-session (complain) user /usr/lib/gdm-wayland-session /usr/bin/gnome-session +gnome-session-binary (complain) user /usr/lib/gnome-session-binary +gnome-session-ctl (complain) user /usr/lib/gnome-session-ctl --monitor +gnome-session-binary (complain) user /usr/lib/gnome-session-binary --systemd-service --session=gnome +gnome-shell (complain) user /usr/bin/gnome-shell +... +ps (complain) user ps auxZ +``` + +??? info "Hide the kernel thread in `ps`" + + To hide the kernel thread in `ps` use `ps auxZ | grep -v '\[.*\]'`. You can + add an alias in your shell: + ```sh + alias p="ps auxZ | grep -v '\[.*\]'" + ``` + + +## AppArmor Log + +Ensure that `auditd` is installed and running on your system in order to read +AppArmor log from `/var/log/audit/audit.log`. Then you can see the log with the +provided command `aa-log` allowing you to review AppArmor generated messages in +a colorful way. + +Other AppArmor userspace tools such as `aa-enforce`, `aa-complain`, and `aa-logprof` +should work as expected. + + +### Basic use + +To read the AppArmor log from `/var/log/audit/audit.log`: +```sh +aa-log +``` + +To optionally filter a given profile name: `aa-log ` (zsh will +autocomplete the profile name): +``` +aa-log dnsmasq +DENIED dnsmasq open /proc/sys/kernel/osrelease comm=dnsmasq requested_mask=r denied_mask=r +DENIED dnsmasq open /proc/1/environ comm=dnsmasq requested_mask=r denied_mask=r +DENIED dnsmasq open /proc/cmdline comm=dnsmasq requested_mask=r denied_mask=r +``` + +!!! info + + Other logs file in `/var/log/audit/` can easily be checked: `aa-log -f 1` + parses `/var/log/audit/audit.log.1`. + + +### Help + +``` +aa-log [-h] [-s] [-f file] [profile] + + Review AppArmor generated messages in a colorful way. + It can be given an optional profile name to filter the output with. + + -f file + Set a logfile or a suffix to the default log file. (default "/var/log/audit/audit.log") + -h Show this help message and exit. + -s Parse systemd dbus logs. +``` diff --git a/docs/variables.md b/docs/variables.md new file mode 100644 index 00000000..5b37ea19 --- /dev/null +++ b/docs/variables.md @@ -0,0 +1,97 @@ +--- +title: Variables References +--- + +## XDG directories + +### User directories + +| Description | Name | Value | +|-------------|:----:|---------| +| Desktop | `@{XDG_DESKTOP_DIR}` | `Desktop` | +| Download | `@{XDG_DOWNLOAD_DIR}` | `Downloads` | +| Templates | `@{XDG_TEMPLATES_DIR}` | `Templates` | +| Public | `@{XDG_PUBLICSHARE_DIR}` | `Public` | +| Documents | `@{XDG_DOCUMENTS_DIR}` | `Documents` | +| Music | `@{XDG_MUSIC_DIR}` | `Music` | +| Pictures | `@{XDG_PICTURES_DIR}` | `Pictures` | +| Videos | `@{XDG_VIDEOS_DIR}` | `Videos` | +| Books | `@{XDG_BOOKS_DIR}` | `Books` | +| Projects | `@{XDG_PROJECTS_DIR}` | `Projects` | +| Screenshots | `@{XDG_SCREENSHOTS_DIR}` | `@{XDG_PICTURES_DIR}/Screenshots` | +| Sync | `@{XDG_SYNC_DIR}` | `Sync` | +| Torrents | `@{XDG_TORRENTS_DIR}` | `Torrents` | +| Vm | `@{XDG_VM_DIR}` | `.vm` +| Wallpapers | `@{XDG_WALLPAPERS_DIR}` | `@{XDG_PICTURES_DIR}/Wallpapers` | + +### Dotfiles + +| Description | Name | Value | +|-------------|:----:|---------| +| SSH | `@{XDG_SSH_DIR}` | `.ssh` | +| GPG | `@{XDG_GPG_DIR}` | `.gnupg` | +| Passwords | `@{XDG_PASSWORD_STORE_DIR}` | `.password-store` | +| Cache | ` @{XDG_CACHE_HOME}` | `.cache` | +| Config | `@{XDG_CONFIG_HOME}` | `.config` | +| Data | `@{XDG_DATA_HOME}` | `.local/share` | +| Bin | `@{XDG_BIN_HOME}` | `.local/bin` | +| Lib | `@{XDG_LIB_HOME}` | `.local/lib` | + +### Full configuration path + +| Description | Name | Value | +|-------------|:----:|---------| +| Cache | `@{user_cache_dirs}` | `@{HOME}/@{XDG_CACHE_HOME}` | +| Config | `@{user_config_dirs}` | `@{HOME}/@{XDG_CONFIG_HOME}` | +| Share | `@{user_share_dirs}` | ` @{HOME}/.local/share/` | +| Bin | `@{user_bin_dirs}` | `@{HOME}/@{XDG_BIN_HOME}` | +| Lib | `@{user_lib_dirs}` | `@{HOME}/@{XDG_LIB_HOME}` | +| Build | `@{user_build_dirs}` | `/tmp/` | +| Tmp | `@{user_tmp_dirs}` | `@{run}/user/@{uid} /tmp/` | +| Packages | `@{user_pkg_dirs}` | `/tmp/pkg/` | + +### Full user path + +| Description | Name | Value | +|-------------|:----:|---------| +| Books | `@{user_books_dirs}` | `@{HOME}/@{XDG_BOOKS_DIR} @{MOUNTS}/@{XDG_BOOKS_DIR}` | +| Documents | `@{user_documents_dirs}` | `@{HOME}/@{XDG_DOCUMENTS_DIR} @{MOUNTS}/@{XDG_DOCUMENTS_DIR}` | +| Download | `@{user_download_dirs}` | `@{HOME}/@{XDG_DOWNLOAD_DIR} @{MOUNTS}/@{XDG_DOWNLOAD_DIR}` | +| Music | `@{user_music_dirs}` | `@{HOME}/@{XDG_MUSIC_DIR} @{MOUNTS}/@{XDG_MUSIC_DIR}` | +| Pictures | `@{user_pictures_dirs}` | `@{HOME}/@{XDG_PICTURES_DIR} @{MOUNTS}/@{XDG_PICTURES_DIR}` | +| Projects | `@{user_projects_dirs}` | `@{HOME}/@{XDG_PROJECTS_DIR} @{MOUNTS}/@{XDG_PROJECTS_DIR}` | +| Public | `@{user_publicshare_dirs}` | `@{HOME}/@{XDG_PUBLICSHARE_DIR} @{MOUNTS}/@{XDG_PUBLICSHARE_DIR}` | +| Sync | `@{user_sync_dirs}` | `@{HOME}/@{XDG_SYNC_DIR} @{MOUNTS}/*/@{XDG_SYNC_DIR}` | +| Templates | `@{user_templates_dirs}` | `@{HOME}/@{XDG_TEMPLATES_DIR} @{MOUNTS}/@{XDG_TEMPLATES_DIR}` | +| Torrents | `@{user_torrents_dirs}` | `@{HOME}/@{XDG_TORRENTS_DIR} @{MOUNTS}/@{XDG_TORRENTS_DIR}` | +| Videos | `@{user_videos_dirs}` | `@{HOME}/@{XDG_VIDEOS_DIR} @{MOUNTS}/@{XDG_VIDEOS_DIR}` | +| Vm | `@{user_vm_dirs}` | `@{HOME}/@{XDG_VM_DIR} @{MOUNTS}/@{XDG_VM_DIR}` +| Password | `@{user_password_store_dirs}` | `@{HOME}/@{XDG_PASSWORD_STORE_DIR} @{MOUNTS}/@{XDG_PASSWORD_STORE_DIR}` | + + +## System variables + +!!! warning + + Do not modify these variables unless you know what you are doing + +| Description | Name | Value | +|-------------|:----:|---------| +| Root Home | `@{HOMEDIRS}` | `/home/` | +| Home directories | `@{HOME}` | `@{HOMEDIRS}/*/ /root/` | +| Current Process id | `@{pid}` | `[0-9]*` | +| Processes ids | `@{pids}` | `[0-9]*` | +| User id | `@{uid}` | `[0-9]*` | +| Thread id | `@{tid}` | `[0-9]*` | +| Root Mountpoints | `@{MOUNTDIRS}` | `/media/ @{run}/media/ /mnt/` | +| Mountpoints directories | `@{MOUNTS}` | `@{MOUNTDIRS}/*/` | +| Universally unique identifier | `@{uuid}` | `[0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*` | +| Hexadecimal | `@{hex}` | `[0-9a-fA-F]*` | +| Libexec *(Archlinux)* | `@{libexec}` | `/{usr/,}lib` | +| Libexec *(Debian/Ubuntu)* | `@{libexec}` | `/{usr/,}libexec` | +| multi-arch library | `@{multiarch}` | `*-linux-gnu*` | +| Proc | `@{PROC}` | `/proc/` | +| Run | `@{run}` | `/run/ /var/run/` | +| Sys | `@{sys}` | `/sys/` | +| Flatpack export | `@{flatpak_exports_root}` | `{flatpak/exports,flatpak/{app,runtime}/*/*/*/*/export}` | +| System wide share | `@{system_share_dirs}` | `/{usr,usr/local,var/lib/@{flatpak_exports_root}}/share` | diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..3b8f3fc7 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,137 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (c) 2021-2023 Alexandre Pujol +# SPDX-License-Identifier: GPL-2.0-only + +# Project information +site_name: AppArmor.d +site_url: https://apparmord.pujol.io +site_author: Alexandre Pujol +site_description: >- + Full set of AppArmor profiles + +# Repository +repo_name: roddhjav/apparmor.d +repo_url: https://github.com/roddhjav/apparmor.d +edit_uri: edit/main/docs/ + +# Copyright +copyright: Copyright © 2021-2023 Alexandre Pujol + +# Configuration +theme: + name: material + logo: assets/favicon.png + favicon: assets/favicon.png + palette: + - scheme: default + primary: white + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + - scheme: slate + primary: brown + accent: deep orange + toggle: + icon: material/brightness-4 + name: Switch to light mode + icon: + repo: fontawesome/brands/github + edit: material/file-edit-outline + view: material/file-eye-outline + features: + - content.action.edit + - content.action.view + - content.code.annotate + - content.code.copy + - navigation.expand + - navigation.footer + - navigation.indexes + - navigation.sections + - navigation.tabs + - navigation.top + - search.highlight + - search.share + - search.suggest + +# Plugins +plugins: + - search + - git-revision-date-localized: + enable_creation_date: true + fallback_to_build_date: true + +# Customization +extra: + social: + - icon: fontawesome/brands/twitter + link: https://twitter.com/roddhjav + - icon: fontawesome/brands/github + link: https://github.com/roddhjav/apparmor.d + - icon: fontawesome/brands/gitlab + link: https://gitlab.com/roddhjav/apparmor.d + - icon: fontawesome/solid/up-right-from-square + link: https://pujol.io + +# Extensions +markdown_extensions: + - abbr + - admonition + - attr_list + - def_list + - footnotes + - md_in_html + - toc: + permalink: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.mark + - pymdownx.tilde + - pymdownx.details + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.keys + - pymdownx.magiclink: + repo_url_shorthand: true + user: squidfunk + repo: mkdocs-material + - pymdownx.smartsymbols + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + +# Page tree +nav: + - Home: + - index.md + - Getting Started: + - concepts.md + - install.md + - configuration.md + - usage.md + - Advanced: + - variables.md + - enforce.md + - Troubleshooting: + - issues.md + - report.md + - recovery.md + - Development: + - development/index.md + - Architecture: + - development/guidelines.md + - development/structure.md + - Tests: + - development/tests.md diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..80b68e38 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +mkdocs +mkdocs-git-revision-date-localized-plugin +mkdocs-material