Apparmor profile for Qubes available!

So after many test and reading documentation about the syntax for apparmor i finally create some apparmor profiles specially for Qubes.

The goal of this post is to increase the security of a normal user without affecting his experience this the number #1 priority

For now there is only two profiles but i’m planning to add other profiles such as Brave,Librewolf,Mullvad-Browser,Network-Manager (for sys-net) and more !

  1. Start your debian template
  2. I recommend to use the kicksecure repository to get their apparmor package
  3. Do
 echo "Types: deb
URIs: https://deb.kicksecure.com
Suites: trixie
Components: main contrib non-free
Enabled: yes
Signed-By: /usr/share/keyrings/derivative.asc" | sudo tee /etc/apt/sources.list.d/derivative.sources

Or if you prefer to use their tor repository you can do

echo "Types: deb
URIs: tor+https://deb.kicksecure.com
Suites: trixie
Components: main contrib non-free
Enabled: yes
Signed-By: /usr/share/keyrings/derivative.asc" | sudo tee /etc/apt/sources.list.d/derivative.sources

You could use their onion repository here but updating packages in the future will be very slow.

By using the tor repository you will need sys-whonix or the tor package installed in your system to install their packages.

  1. Then open your terminal and install those packages in the debian template run
sudo apt-get -y install apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra apparmor-profiles-kicksecure
  1. Shutdown the template

In order to make apparmor works correctly in Qubes you need to run this commands in dom0 :

qvm-prefs x kernelopts "swiotlb=2048 security=apparmor"

Replace “x” by the name of your template

  1. Start your templateVM open a terminal and confirm apparmor is running by doing as root
sudo aa-enabled

It must say “Yes” in that case you can continue the guide otherwise you have done something wrong.

  1. As root run this command to install the firefox apparmor profile
echo "abi <abi/4.0>,

include <tunables/global>

# This profile allows everything and only exists to give the
# application a name instead of having the label "unconfined"


profile firefox /{usr/lib/firefox{,-esr,-beta,-devedition,-nightly},opt/firefox}/firefox{,-esr,-bin} {
  include <abstractions/audio>
  include <abstractions/totem>
  include if exists <local/firefox>

  capability sys_admin,
  capability sys_chroot,
  capability sys_ptrace,

  deny / r,
  deny /home/user/Desktop**/ r,
  deny /home/user/Documents**/ r,
  deny /home/user/Pictures**/ r,
  deny /home/user/QubesIncoming**/ r,
  deny /home/user/Templates**/ r,
  deny /home/user/Videos**/ r,
  deny /home/user/Music**/ r,
  deny owner /home/*/.bash_logout r,
  deny owner /home/*/.bashrc r,
  deny owner /home/user/.profile r,
  deny owner /home/user/.xsession-errors r,

  /dev/udmabuf rw,
  /etc/dconf/db/local r,
  /etc/dconf/profile/user r,
  /etc/firefox/policies/policies.json r,
  /etc/ld.so.cache r,
  /etc/ld.so.preload r,
  /etc/mime.types r,
  /proc/pressure/memory r,
  /sys/devices/system/cpu/* r,
  /sys/devices/system/cpu/** r,
  /sys/fs/cgroup/user.slice/user-1000.slice/** r,
  /usr/bin/update-desktop-database mrix,
  /usr/bin/update-mime-database mrix,
  /usr/lib/firefox/crashhelper mrix,
  /usr/lib/firefox/firefox-bin mrix,
  /usr/lib/firefox/glxtest mrix,
  /var/cache/fontconfig/ rw,
  owner /home/user/.cache/mesa_shader_cache/* rw,
  owner /home/user/.cache/mesa_shader_cache/** r,
  owner /home/user/.cache/mesa_shader_cache/** w,
  owner /home/user/.cache/mozilla/ rw,
  owner /home/user/.cache/mozilla/*/ rw,
  owner /home/user/.cache/mozilla/firefox/** k,
  owner /home/user/.cache/mozilla/firefox/** r,
  owner /home/user/.cache/mozilla/firefox/** w,
  owner /home/user/.cache/mozilla/firefox/*/ rw,
  owner /home/user/.config/* r,
  owner /home/user/.config/* w,
  owner /home/user/.config/dconf/* r,
  owner /home/user/.config/mozilla/ rw,
  owner /home/user/.config/mozilla/** k,
  owner /home/user/.config/mozilla/** r,
  owner /home/user/.config/mozilla/** w,
  owner /home/user/.config/pulse/ rw,
  owner /home/user/.local/share/applications/ rw,
  owner /home/user/.local/share/applications/* w,
  owner /home/user/.local/share/mime/ rw,
  owner /home/user/.local/share/mime/packages/ rw,
  owner /home/user/.local/share/mime/packages/* w,
  owner /home/user/.zcompdump r,
  owner /home/user/Downloads/* r,
  owner /home/user/Downloads/* w,
  owner /proc/*/* w,
  owner /proc/*/cgroup r,
  owner /proc/*/cmdline r,
  owner /proc/*/stat r,
  owner /proc/*/task/** r,
  owner /run/user/1000/dconf/* rw,
  owner /run/user/1000/pulse/ rw,

  userns,

} " | sudo tee /etc/apparmor.d/firefox 

  1. For Nautilus (file manager) do
echo "include <tunables/global>

profile nautilus /usr/bin/nautilus {
  include <abstractions/gio-open>
  include <abstractions/hosts_access>
  include <abstractions/nvidia>
  include <abstractions/totem>
  include if exists <local/nautilus>

  deny /*/ r,
  deny owner /home/user/.xsession-errors r,

  /dev/udmabuf rw,
  /etc/dconf/db/local r,
  /etc/dconf/profile/user r,
  /home/user/firefox rw,
  /sys/devices/system/cpu/** r,
  /usr/bin/qvm-open-in-vm Ux,
  /usr/bin/x86_64-linux-gnu-cpp-14 r,
  /usr/lib/qubes/qvm-copy-to-vm.gnome Ux,
  owner /home/** rw,
  owner /home/*/.bash_logout r,
  owner /home/*/.bashrc r,
  owner /home/*/.config/gtk-3.0/bookmarks w,
  owner /home/*/.config/gtk-4.0/* r,
  owner /home/*/.local/share/Trash/files/ rw,
  owner /home/*/.local/share/Trash/info/ rw,
  owner /home/*/.profile r,
  owner /home/*/Desktop/Documents/ rw,
  owner /home/*/Documents/Music/ rw,
  owner /home/*/Music/Videos/ rw,
  owner /home/user/.cache/mesa_shader_cache/** k,
  owner /home/user/.cache/mesa_shader_cache/** r,
  owner /home/user/.cache/mesa_shader_cache/** w,
  owner /home/user/.cache/mesa_shader_cache/*/ w,
  owner /home/user/.config/dconf/* r,
  owner /home/user/.local/share/Trash/ rw,
  owner /home/user/.local/share/nautilus/** k,
  owner /home/user/.local/share/nautilus/** rw,
  owner /home/user/.zcompdump r,
  owner /home/user/Documents/ rw,
  owner /home/user/Downloads/ r,
  owner /run/user/1000/dconf/* r,
  owner /run/user/1000/dconf/* w,
  owner /usr/share/nautilus-python/**/ rw,

  userns,

} " | sudo tee /etc/apparmor.d/nautilus
  1. Then run
sudo aa-enforce /etc/apparmor.d/nautilus && sudo aa-enforce /etc/apparmor.d/firefox
  1. If a error appear about a protocol you can ignore this error i don’t know why exactly it happen but run the 9 commands again until it stop complaining i had to run it 2 or 3 times to work
  2. It’s done now firefox and nautilus is running under apparmor with strict permissions

F.A.Q

“Do Qubes copy-vm menu entry works ?”

Yes i’ve tried and it works without any issue

Can i use firejail with your profiles ?

You shouldn’t do it in fact using firejail will only increase the possibility of an attack the creator of Firejail has said himself this

Don't use this on enterprise servers, or any other multiuser system. Firejail was built for single-user desktops.

Maybe you could use firejail with my apparmor profiles but i didn’t test to see if it works and i will never do it because i’ve tested firejail for a long time with Qubes and some applications wasn’t properly starting with firejail so it was running without any protection which make firejail useless for example Nautilus wasn’t launching with firejail so i have to find a trick to force Nautilus to run under firejail which is frustrating to do. There is a good reason why Tails , Whonix or Secureblue do not rely on firejail to secure a system they rely only on Apparmor or Selinux or Secureblue.

What’s the main advantage of using those apparmor profiles ?”

They increase the security of your system and reduce the possibility of an attack a lot more

For example Firefox can’t access to the root filsystem , Firefox can’t access the folder “QubesIncoming” (I’m not sure if a website can still see if the folder is present with javascript or something else i need a expert to tell me)

The only folder firefox can access is the Downloads folder.

Nautilus do not have internet access and can’t access to the root filesystem nautilus can only access to all folder inside the home directory.

The apparmor profile for Firefox and Nautilus is maybe not perfect if this is the case just tell me i will try my best to fix everything.

I think i will create a github repo in the future for the future apparmor profiles and maintain those profiles as long QubesOS survive. The next profile i’m planning to add will be Network-Manager and Brave and Thunar. But first i need to see if people have some issue with the firefox and nautilus profile.

Edit : Just to make sure your appvm and dispvm is really using apparmor go to the settings of both vm and click on “Services” then select “apparmor” and click on “apply”. It might be possible the apparmor service doesn’t appear in the list of Services in that case click on “(custom…)” and click on “Add” then type “apparmor” and apply.

Edit 2 : Added a explanation to tell the users to not use firejail

Edit 3 : I removed the “deny network” rule it make nautilus doesn’t work at all i will find a another way

5 Likes

Update : I added “Deny network,” in the nautilus profile the first profile was allowing network now it doesn’t. So now it’s impossible nautilus reach the network.

I’ve seen apparmor have a lot of rules to manage network connection here we could use that later to make sys-net more secure in the future i won’t lie i will need help for that my technical knowledge about how linux network work is limited specially on Qubes

Also i think we could use those rules to make browser such as Firefox and Brave more private by denying any telemetry from Brave and Firefox ? But it’s unclear to me what could happen in the future if we block know telemetry maybe the user could not anymore reach internet ?

Maybe you could take a look at apparmor profiles from ezjail too, it’s not easy to get a profile done right.

1 Like

Here are also good examples for apparmor profiles.

1 Like

Yeah apparmor is not easy it took me so many hours to create the apparmor profile for firefox and make some test… Have you tried my apparmor profiles ? Have you met any issue ? I’d like to have some feeback it would be great

Thanks i have tried multiples times his apparmor profile but it wasn’t working for me on Qubes but i forget to take a look at the syntax he’s using i will copy some value from him

It would be nice if Debian and Kicksecure templates already came with AppArmor. Or does it work by default in Kicksecure template?

Kicksecure came with apparmor and some profile enabled by default but there is no profile configured properly for Qubes

Update i have created a codeberg repository dkzkz/apparmor-qubes: Apparmor profile for debian template in Qubes - Codeberg.org

I will put any profile in the repository before put a profile in the repository i will test it to make sure no one have any problem

1 Like

I checked Kicksecure template – it includes apparmor profiles for all browsers from Browser Choice: Brave, Chromium, Mullvad, Firefox, and Tor.

Can you do as sudo cat /etc/apparmor.d/brave and sudo cat /etc/apparmor.d/firefox ? Then copy and paste the content here of both i need to see the content because i don’t think they’re enabled and configured or maybe i’m wrong ? I’m not using kicksecure so i don’t know.

Update brave apparmor profile is finished codeberg seem to be down so i uploaded the brave profile here

PS : The brave apparmor profile can’t run some extensions like keepassxc because brave is using command like @{bin}/touch and the cat command to make some extensions work but i think it’s insecure to allow a browser to do such things so i removed them. If you think it’s a bad idea from me to do that then tell me i will change that

I think i will create a another brave apparmor profile with those permissions to let a user use extensions i don’t know if it’s a good idea to do…

I could disable tor in brave with the apparmor profile but i don’t know if i should do it or not we could talk about that in the future

Like the firefox profile the brave profile can’t see the content of every home folder including QubesIncoming except Downloads brave can’t access to the content of all root filesystems

Next profile coming up : Librewolf , Bitwarden , Proton-pass

include <tunables/global>

@{name}            = brave{,-beta,-dev,-bin}
@{domain}          = com.brine.Brave org.chromium.Chromium
@{lib_dirs}        = /opt/brave{-bin,.com}{,/@{name}}
@{USER}            = user                # ← replace with the actual login name
@{config_dirs}     = @{HOME}/.config/BraveSoftware/Brave-Browser{,-Beta,-Dev}
@{cache_dirs}      = @{HOME}/.cache/BraveSoftware/Brave-Browser{,-Beta,-Dev}
@{user_config_dirs}= @{HOME}/.config
@{exec_path}       = @{lib_dirs}/@{name}

profile brave @{exec_path} flags=(attach_disconnected) {
  include <abstractions/audio>
  include <abstractions/bash>
  include <abstractions/postfix-common>
  include <abstractions/totem>
  include if exists <local/brave>

  deny capability dac_override,

  capability sys_admin,
  capability sys_ptrace,

  ptrace read peer=Xorg,
  ptrace read peer=unconfined,
  ptrace trace peer=brave,

  deny / r,
  deny @{HOME}/Desktop**/      r,
  deny @{HOME}/Documents**/    r,
  deny @{HOME}/Pictures**/     r,
  deny @{HOME}/QubesIncoming**/ r,
  deny @{HOME}/Templates**/    r,
  deny @{HOME}/Videos**/       r,
  deny owner @{HOME}/.bash_logout r,
  deny owner @{HOME}/.bashrc      r,
  deny owner @{HOME}/.config/mimeapps.list.new w,

  /dev/udmabuf                         rw,
  /etc/dconf/db/local                  r,
  /etc/dconf/profile/*                 r,
  /etc/ld.so.cache                     r,
  /etc/ld.so.preload                   r,
  /etc/opt/chrome/native-messaging-hosts/* r,
  @{HOME}/.config/BraveSoftware/Brave-Browser/biahpgbdmdkfgndcmfiipgcebobojjkp/** mrix,
  /opt/brave.com/brave/brave           mrix,
  /opt/brave.com/brave/chrome-sandbox mrix,
  /opt/brave.com/brave/chrome_crashpad_handler mrix,

  @{PROC}/*/stat          r,
  @{PROC}/*/statm         r,
  @{PROC}/*/task/**      r,
  /proc/sys/fs/inotify/max_user_watches r,
  /proc/sys/kernel/yama/ptrace_scope    r,

  /sys/devices/system/cpu/*   r,
  /sys/devices/system/cpu/**  r,
  /sys/devices/virtual/tty/** r,

  /usr/bin/basename          mrix,
  /usr/bin/cut               mrix,
  /usr/bin/dash              ix,
  /usr/bin/gawk              mrix,
  /usr/bin/grep              mrix,
  /usr/bin/head              mrix,
  /usr/bin/ln                mrix,
  /usr/bin/mkdir             mrix,
  /usr/bin/mktemp            mrix,
  /usr/bin/realpath          mrix,
  /usr/bin/sed               mrix,
  /usr/bin/tr                mrix,
  /usr/bin/update-desktop-database mrix,
  /usr/bin/xdg-desktop-menu mrix,
  /usr/bin/xdg-icon-resource mrix,
  /usr/bin/xdg-mime          mrix,
  /usr/bin/xdg-settings      mrix,

  /usr/share/chromium/extensions/ r,
  /var/cache/fontconfig/          rw,
  /{media,mnt,opt,srv}/**        mr,

  @{PROC}                         r,
  @{PROC}/@{pids}/                r,
  @{exec_path}                    mrix,

  owner "@{HOME}/.config/BraveSoftware/Brave-Browser/Crash Reports/*" k,
  owner "@{HOME}/.config/BraveSoftware/Brave-Browser/Crash Reports/*" rw,

  owner /dev/shm/*               r,
  owner /dev/shm/*               w,
  owner /etc/opt/chrome/         rw,
  owner @{HOME}/.cache/BraveSoftware/          rw,
  owner @{HOME}/.cache/BraveSoftware/**        rw,
  owner @{HOME}/.cache/BraveSoftware/**/       rw,
  owner @{HOME}/.cache/mesa_shader_cache/*     rw,
  owner @{HOME}/.cache/mesa_shader_cache/**    r,
  owner @{HOME}/.cache/mesa_shader_cache/**    w,

  owner @{HOME}/.config/BraveSoftware/Brave-Browser/          rw,
  owner @{HOME}/.config/BraveSoftware/Brave-Browser/*        w,
  owner @{HOME}/.config/BraveSoftware/Brave-Browser/**       k,
  owner @{HOME}/.config/BraveSoftware/Brave-Browser/**       rw,
  owner @{HOME}/.config/BraveSoftware/Brave-Browser/*/       rw,
  owner @{HOME}/.config/dconf/*                               r,

  owner /opt/brave.com/brave/extensions/ mrw,

  owner @{PROC}/*/clear_refs   w,
  owner @{PROC}/*/cmdline      r,
  owner @{PROC}/*/gid_map      w,
  owner @{PROC}/*/mem          r,
  owner @{PROC}/*/setgroups    w,
  owner @{PROC}/*/smaps_rollup r,
  owner @{PROC}/*/uid_map      w,

  owner /run/user/1000/dconf/* rw,
  owner /run/user/1000/pulse/* rw,

  owner @{HOME}/.pki/               rw,
  owner @{HOME}/.pki/*/             rw,
  owner @{HOME}/.pki/nssdb/*        k,
  owner @{HOME}/.pki/nssdb/*        r,
  owner @{HOME}/.pki/nssdb/*        w,

  owner @{HOME}/Desktop/*          w,
  owner @{HOME}/Downloads/*        r,
  owner @{HOME}/Downloads/*        w,

  owner @{PROC}/@{pid}/fd/          r,
  owner @{PROC}/@{pid}/oom_{,score_}adj rw,

  owner @{cache_dirs}/BraveSoftware/ rw,
  owner @{config_dirs}/BraveSoftware/ rw,
  owner @{config_dirs}/WidevineCdm/libwidevinecdm.so mrw,
  owner @{user_config_dirs}/BraveSoftware/ rw,

  userns,
}

2 Likes

It’s unclear to me if it is a good idea to tell the user to do

apparmor_parser -r /path/to/your_profile

This load the apparmor policy we are using into the kernel to enforce the security at 100% but i don’t know if a future update from Debian could break the system of user template so i would not recommend to do it. But i will use the apparmor_parser -r myself and make some test for 1 month to see if it’s ok to do