# apparmor.d - Full set of apparmor profiles
# Copyright (C) 2023-2024 Alexandre Pujol <alexandre@pujol.io>
# SPDX-License-Identifier: GPL-2.0-only

abi <abi/3.0>,

include <tunables/global>

@{name} = torbrowser "tor browser"
@{lib_dirs} = @{HOME}/.tb/tor-browser/Browser/
@{data_dirs} = @{lib_dirs}/TorBrowser/Data/
@{config_dirs} = @{data_dirs}/Browser/*.default/
@{cache_dirs} = @{data_dirs}/Browser/Caches

@{exec_path} = @{lib_dirs}/firefox{,.real}
profile torbrowser @{exec_path} flags=(attach_disconnected) {
  include <abstractions/base>
  include <abstractions/audio-client>
  include <abstractions/bus-session>
  include <abstractions/bus-system>
  include <abstractions/bus/org.a11y>
  include <abstractions/bus/org.freedesktop.FileManager1>
  include <abstractions/bus/org.freedesktop.login1>
  include <abstractions/bus/org.freedesktop.portal.Desktop>
  include <abstractions/bus/org.freedesktop.RealtimeKit1>
  include <abstractions/bus/org.gtk.Private.RemoteVolumeMonitor>
  include <abstractions/desktop>
  include <abstractions/enchant>
  include <abstractions/fontconfig-cache-read>
  include <abstractions/graphics>
  include <abstractions/gstreamer>
  include <abstractions/nameservice-strict>
  include <abstractions/ssl_certs>
  include <abstractions/user-download-strict>
  include <abstractions/user-read-strict>

  # userns,

  capability sys_admin, # If kernel.unprivileged_userns_clone = 1
  capability sys_chroot, # If kernel.unprivileged_userns_clone = 1

  network inet stream,
  network inet6 stream,
  network netlink raw,

  signal (send) set=(term, kill) peer=torbrowser-*,

  deny dbus send bus=system path=/org/freedesktop/hostname1,

  @{exec_path} mrix,

  @{lib_dirs}/{,**}             r,
  @{lib_dirs}/*.so              mr,
  @{lib_dirs}/glxtest           rPx,
  @{lib_dirs}/plugin-container  rPx,
  @{lib_dirs}/vaapitest         rPx,

  /usr/share/@{name}/{,**} r,
  /usr/share/doc/{,**} r,
  /usr/share/homepage/{,**} r,
  /usr/share/xul-ext/kwallet5/* r,

  /etc/@{name}.d/{,**} r,
  /etc/mailcap r,
  /etc/mime.types r,
  /etc/opensc.conf r,
  /etc/sysconfig/proxy r,
  /etc/xdg/* r,
  /etc/xul-ext/kwallet5.js r,

  /var/lib/nscd/services r,

  owner @{lib_dirs}/.cache/{,**} rw,
  owner @{lib_dirs}/Downloads/{,**} rw,
  owner @{lib_dirs}/fonts/** r,

  owner @{config_dirs}/ rw,
  owner @{config_dirs}/** rwk,

  owner @{cache_dirs}/ rw,
  owner @{cache_dirs}/** rwk,

        /tmp/ r,
        /var/tmp/ r,
  owner @{tmp}/ rw,
  owner @{tmp}/* w,
  owner @{tmp}/Temp-@{uuid}/ rw,
  owner @{tmp}/Temp-@{uuid}/* rwk,
  owner @{tmp}/firefox/ rw,
  owner @{tmp}/firefox/* rwk,
  owner @{tmp}/@{name}/ rw,
  owner @{tmp}/@{name}/* rwk,
  owner @{tmp}/Temp-@{uuid}/ rw,
  owner "@{tmp}/Tor Project*/" rw,
  owner "@{tmp}/Tor Project*/**" rwk,
  owner "@{tmp}/Tor Project*" rwk,

  @{run}/mount/utab r,

  @{run}/udev/data/+input:input@{int} r,  # for mouse, keyboard, touchpad
  @{run}/udev/data/c13:@{int}  r,         # for /dev/input/*

  @{sys}/bus/ r,
  @{sys}/cgroup/cpu,cpuacct/user.slice/cpu.cfs_quota_us r,
  @{sys}/class/ r,
  @{sys}/class/**/ r,
  @{sys}/devices/@{pci}/ r,
  @{sys}/devices/@{pci}/drm/card@{int}/ r,
  @{sys}/devices/@{pci}/drm/renderD128/ r,
  @{sys}/devices/@{pci}/drm/renderD129/ r,
  @{sys}/devices/**/uevent r,
  @{sys}/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us r,
  @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/session-1.scope/cpu.max r,
  @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/**/cpu.max r,

  owner @{PROC}/@{pid}/cgroup r,
  owner @{PROC}/@{pid}/fd/ r,
  owner @{PROC}/@{pid}/gid_map w, # If kernel.unprivileged_userns_clone = 1
  owner @{PROC}/@{pid}/mountinfo r,
  owner @{PROC}/@{pid}/mounts r,
  owner @{PROC}/@{pid}/oom_score_adj w,
  owner @{PROC}/@{pid}/setgroups w, # If kernel.unprivileged_userns_clone = 1
  owner @{PROC}/@{pid}/smaps r,
  owner @{PROC}/@{pid}/stat r,
  owner @{PROC}/@{pid}/statm r,
  owner @{PROC}/@{pid}/task/ r,
  owner @{PROC}/@{pid}/task/@{tid}/comm rw,
  owner @{PROC}/@{pid}/task/@{tid}/stat r,
  owner @{PROC}/@{pid}/uid_map w, # If kernel.unprivileged_userns_clone = 1
  owner @{PROC}/@{pids}/cmdline r,
  owner @{PROC}/@{pids}/environ r,

        /dev/ r,
        /dev/hidraw@{int} rw,
        /dev/tty rw,
  owner /dev/shm/org.mozilla.ipc.@{pid}.@{int} rw,
  owner /dev/shm/wayland.mozilla.ipc.@{int} rw,
  owner /dev/tty@{int} rw, # File Inherit

  # Due to the nature of the browser, we silence much more than for Firefox.
  deny @{bin}/lsb_release x,
  deny /etc/group r,
  deny /etc/host.conf r,
  deny /etc/hosts r,
  deny /etc/machine-id r,
  deny /etc/mailcap r,
  deny /etc/nsswitch.conf r,
  deny /etc/os-release r,
  deny /etc/passwd r,
  deny /etc/resolv.conf r,
  deny /var/lib/dbus/machine-id r,
  deny /tmp/MozillaUpdateLock-* w,
  deny owner @{HOME}/.* r,
  deny owner @{user_config_dirs}/gtk-*/{,**} rw,
  deny owner @{user_share_dirs}/gvfs-metadata/{,*} r,
  deny owner @{run}/user/@{uid}/dconf/user rw,
  deny owner @{run}/user/@{uid}/gnome-shell-disable-extensions w,
  deny @{sys}/class/input/ r,
  deny @{sys}/devices/system/cpu/*/cache/index@{int}/size r,
  deny @{sys}/devices/system/cpu/cpufreq/policy@{int}/cpuinfo_max_freq r,
  deny @{sys}/devices/virtual/block/*/uevent r,
  deny @{PROC}/@{pid}/net/if_inet6 r,
  deny @{PROC}/@{pid}/net/route r,

  include if exists <local/torbrowser>
}