# apparmor.d - Full set of apparmor profiles
# Copyright (C) 2022-2024 Alexandre Pujol <alexandre@pujol.io>
# SPDX-License-Identifier: GPL-2.0-only
# LOGPROF-SUGGEST: no
# NEEDS-VARIABLE: name
# NEEDS-VARIABLE: lib_dirs
# NEEDS-VARIABLE: config_dirs
# NEEDS-VARIABLE: cache_dirs

# Full set of rules for all firefox based browsers. It works as a *function*
# and requires some variables to be provided as *arguments* and set in the
# header of the calling profile. Example:
#
# !!! quote ""
#
#     ```
#     @{path} = /org/mozilla/firefox
#     @{name} = firefox{,.sh,-esr,-bin}
#     @{lib_dirs} = @{lib}/@{name} /opt/@{name}
#     @{config_dirs} = @{HOME}/.mozilla/
#     @{cache_dirs} = @{user_cache_dirs}/mozilla/
#     ```
#

  abi <abi/4.0>,

  include <abstractions/audio-client>
  include <abstractions/avahi-observe>
  include <abstractions/bus/session/org.freedesktop.portal.FileChooser>
  include <abstractions/bus/system/org.freedesktop.RealtimeKit1>
  include <abstractions/bus/system/org.freedesktop.timedate1>
  include <abstractions/camera>
  include <abstractions/cups-client>
  include <abstractions/dconf-write>
  include <abstractions/desktop>
  include <abstractions/devices-u2f>
  include <abstractions/enchant>
  include <abstractions/fontconfig-cache-read>
  include <abstractions/graphics>
  include <abstractions/gstreamer>
  include <abstractions/gvfs>
  include <abstractions/mpris>
  include <abstractions/attached/nameservice-strict>
  include <abstractions/network-manager-observe>
  include <abstractions/pcscd>
  include <abstractions/power-profiles>
  include <abstractions/screen-inhibit>
  include <abstractions/screensaver>
  include <abstractions/search-provider>
  include <abstractions/ssl_certs>
  include <abstractions/sys/dmi>
  include <abstractions/sys/input>
  include <abstractions/thumbnails-cache-read>
  include <abstractions/udev/input>
  include <abstractions/uim>
  include <abstractions/upower-observe>

  userns,

  capability sys_ptrace,

  # Needed with sysctl_kernel_unprivileged_userns_clone = 1
  capability sys_admin,
  capability sys_chroot,

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

  unix type=stream addr=none,

  ptrace trace peer=@{profile_name},

  signal (send) set=(term, kill) peer=@{profile_name}-*,

  @{sh_path}                 rix,
  @{bin}/basename            rix,
  @{bin}/dirname             rix,
  @{bin}/expr                rix,

  @{lib_dirs}/{,**}             r,
  @{lib_dirs}/*.so              mr,
  @{lib_dirs}/crashreporter     rpx,
  @{lib_dirs}/minidump-analyzer rpx,
  @{lib_dirs}/pingsender        rpx,
  @{lib_dirs}/plugin-container  rpx,

  # Desktop integration
  @{bin}/lsb_release            rpx,

  /usr/share/@{name}/{,**} r,
  /usr/share/doc/{,**} r,
  /usr/share/mozilla/extensions/{,**} r,
  /usr/share/webext/{,**} r,
  /usr/share/xul-ext/kwallet5/* r,

  /etc/@{name}/{,**} r,
  /etc/fstab r,
  /etc/lsb-release r,
  /etc/mailcap r,
  /etc/sysconfig/proxy r,
  /etc/xdg/* r,
  /etc/xul-ext/kwallet5.js r,

  /var/lib/nscd/services r,

  owner @{HOME}/ r,

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

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

        /tmp/ rw,
        /var/tmp/ r,
  owner @{tmp}/@{name}/ rw,
  owner @{tmp}/@{name}/* rwk,
  owner @{tmp}/@{rand6}.tmp rw,
  owner @{tmp}/firefox/ rw,
  owner @{tmp}/firefox/* rwk,
  owner @{tmp}/mozilla* rw,
  owner @{tmp}/mozilla*/ rw,
  owner @{tmp}/mozilla*/* rwk,
  owner @{tmp}/remote-settings-startup-bundle- rw,
  owner @{tmp}/remote-settings-startup-bundle-.tmp rw,
  owner @{tmp}/Temp-@{uuid}/ rw,
  owner @{tmp}/Temp-@{uuid}/* rwk,
  owner @{tmp}/tmp-*.xpi rw,
  owner @{tmp}/tmpaddon rw,
  owner @{tmp}/tmpaddon-@{int} r,

  owner /dev/shm/org.chromium.@{rand6} rw,
  owner /dev/shm/org.mozilla.ipc.@{pid}.@{int} rw,
  owner /dev/shm/wayland.mozilla.ipc.@{int} rw,

  @{run}/mount/utab r,

  @{sys}/devices/virtual/dmi/id/product_sku r,

        @{sys}/bus/ 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}/devices/power/events/energy-* r,
        @{sys}/devices/power/type r,
        @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/cpu.max r,
        @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/session-@{word}.scope/cpu.max r,
  owner @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/**/cpu.max r,

  # Network interface information
  @{PROC}/@{pid}/net/arp r,
  @{PROC}/@{pid}/net/if_inet6 r,
  @{PROC}/@{pid}/net/route r,

  # Pressure Stall Information interface
  @{PROC}/pressure/cpu r,
  @{PROC}/pressure/io r,
  @{PROC}/pressure/memory r,

  # Allow reading cgroup membership information for process introspection
  owner @{PROC}/@{pid}/cgroup r,

  # Allow reading command line arguments for process identification
  owner @{PROC}/@{pid}/cmdline r,
  owner @{PROC}/@{pid}/comm r,

  # Allow reading our own environment variables
  owner @{PROC}/@{pid}/environ r,

  # Allow listing file descriptors
  owner @{PROC}/@{pid}/fd/ r,

  # Needed with sysctl_kernel_unprivileged_userns_clone = 1
  owner @{PROC}/@{pid}/gid_map w,
  owner @{PROC}/@{pid}/setgroups w,
  owner @{PROC}/@{pid}/uid_map w,

  # This is an information leak but disallowing it leads to developer confusion
  # when using the chromium content api file chooser due to a (harmless) glib
  # warning and the noisy AppArmor denial.
  owner @{PROC}/@{pid}/mounts r,
  owner @{PROC}/@{pid}/mountinfo r,

  # Reads of oom_adj and oom_score_adj are safe
  owner @{PROC}/@{pid}/oom_adj r,
  owner @{PROC}/@{pid}/oom_score_adj r,

  # This allows raising the OOM score of other processes owned by the user.
  owner @{PROC}/@{pid}/oom_score_adj w,

  # Per man(5) proc, the kernel enforces that a thread may only modify its comm
  # value or those in its thread group.
  owner @{PROC}/@{pid}/task/@{tid}/comm rw,

  # Allow reading of a summary of the memory use of a process
  owner @{PROC}/@{pid}/smaps r,
  owner @{PROC}/@{pid}/smaps_rollup r,

  # Provide statistical information about our own processes/threads
  owner @{PROC}/@{pid}/stat r,
  owner @{PROC}/@{pid}/statm r,
  owner @{PROC}/@{pid}/task/ r,
  owner @{PROC}/@{pid}/task/@{tid}/stat r,
  owner @{PROC}/@{pid}/task/@{tid}/status r,

        /dev/tty rw,
  owner /dev/tty@{u8} rw, # File Inherit

  # Silencer
  deny dbus bus=system path=/org/freedesktop/hostname1,
  deny dbus bus=system path=/org/freedesktop/login1,
  deny /tmp/MozillaUpdateLock-* w,
  deny owner @{HOME}/.* r,
  deny @{run}/user/@{uid}/gnome-shell-disable-extensions w,

  profile crashhelper flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
    include <abstractions/attached/base>

    unix (send receive) type=seqpacket, # peer=(label=---),
    unix (send receive) type=seqpacket peer=(label=@{name}),
    unix (send receive) type=seqpacket peer=(label=@{name}//gxtest),

    @{lib_dirs}/crashhelper mr,

    owner "@{config_dirs}/" w,
    owner "@{config_dirs}/@{name}/" rw,
    owner "@{config_dirs}/@{name}/Crash Reports/" rw,
    owner "@{config_dirs}/@{name}/Crash Reports/crash_helper_server.log" rw,

    include if exists <abstractions/app/firefox_crashhelper.d>
  }

  profile crashreporter flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
    include <abstractions/attached/base>
    include <abstractions/dconf-write>
    include <abstractions/desktop>
    include <abstractions/fontconfig-cache-read>
    include <abstractions/graphics>
    include <abstractions/attached/nameservice-strict>

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

    unix (send receive) type=seqpacket peer=(label=@{name}),
    unix (send receive) type=seqpacket peer=(label=@{name}//gxtest),

    signal receive peer=@{name},

    @{lib_dirs}/crashreporter mrix,

    @{bin}/curl rix,
    @{bin}/mv   rix,

    @{firefox_path}               rpx,
    @{lib_dirs}/minidump-analyzer rpx,

    owner @{config_dirs}/@{name}/*.*/crashes/{,**} rw,
    owner @{config_dirs}/@{name}/*.*/crashes/events/@{uuid} rw,
    owner @{config_dirs}/@{name}/*.*/extensions/*.xpi r,
    owner @{config_dirs}/@{name}/*.*/minidumps/{,**} rw,
    owner @{config_dirs}/@{name}/*.*/minidumps//@{uuid}.{dmp,extra} r,
    owner @{config_dirs}/@{name}/*.*/prefs.js r,
    owner @{config_dirs}/@{name}/*.*/storage-sync-v2.sqlite-shm r,
    owner @{config_dirs}/@{name}/*.*/storage/default/* r,
    owner @{config_dirs}/@{name}/Crash?Reports/{,**} rwk,
    owner @{config_dirs}/@{name}/Pending?Pings/@{uuid}.json w,
    owner @{config_dirs}/@{name}/Profile*/*.sqlite-shm r,

    owner @{cache_dirs}/@{name}/*.*/** r,

          /tmp/ r,
      /var/tmp/ r,
    owner @{tmp}/@{hex}.{dmp,extra} rw,
    owner @{tmp}/@{name}/.parentlock w,
    owner @{tmp}/crashreporter@{int}-request@{int}.json rw,

    owner /dev/shm/org.mozilla.ipc.@{int}.@{int} r,

    owner @{PROC}/@{pid}/cgroup r,
    owner @{PROC}/@{pid}/cmdline r,
    owner @{PROC}/@{pid}/mountinfo r,

    include if exists <abstractions/app/firefox_crashreporter.d>
  }

  profile gxtest flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
    include <abstractions/attached/base>
    include <abstractions/bus-system>
    include <abstractions/graphics>
    include <abstractions/attached/nameservice-strict>
    include <abstractions/wayland-strict>
    include <abstractions/X-strict>

    network netlink raw,

    unix type=stream addr=none,
    unix (send receive) type=seqpacket peer=(label=@{name}),
    unix (send receive) type=seqpacket peer=(label=@{name}//crashhelper),

    @{lib_dirs}/glxtest mr,
    @{lib_dirs}/gfxtest mr,

    / r,

    owner @{cache_dirs}/@{name}/*/startupCache/scriptCache-* r,
    owner @{cache_dirs}/@{name}/*/startupCache/startupCache* r,

    owner @{config_dirs}/@{name}/*/.parentlock rw,
    owner @{config_dirs}/*/.parentlock rw,

    owner @{tmp}/@{name}/.parentlock rw,
    owner @{tmp}/org.mozilla.@{name}/.parentlock rw,

    owner @{PROC}/@{pid}/cmdline r,

    include if exists <abstractions/app/firefox_gxtest.d>
  }

  profile vaapitest flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
    include <abstractions/attached/base>
    include <abstractions/graphics>
    include <abstractions/attached/nameservice-strict>

    network netlink raw,

    @{lib_dirs}/vaapitest mr,

    owner @{tmp}/@{name}/.parentlock rw,

          @{PROC}/version r,
    owner @{PROC}/@{pid}/task/@{tid}/comm w,

    deny @{config_dirs}/@{name}/*/.parentlock rw,
    deny @{config_dirs}/@{name}/*/startupCache/** r,
    deny @{user_cache_dirs}/mozilla/@{name}/*/startupCache/* r,
    deny @{user_share_dirs}/gnome-shell/session.gvdb rw,

    include if exists <abstractions/app/firefox_vaapitest.d>
  }

  include if exists <abstractions/app/firefox.d>

# vim:syntax=apparmor
