# vim:ft=apparmor
# ------------------------------------------------------------------
#
#    Copyright (C) 2020 Canonical Ltd.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of version 2 of the GNU General Public
#    License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
# Author: Jamie Strandboge <jamie@canonical.com>

abi <abi/4.0>,

include <tunables/global>

@{chromium} = {,ungoogled-}chromium{,-browser}

# We need 'flags=(attach_disconnected)' in newer chromium versions
profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconnected) {
  include <abstractions/audio>
  include <abstractions/cups-client>
  include <abstractions/dbus-session>
  include <abstractions/dbus-strict>
  include <abstractions/fonts>
  include <abstractions/gnome>
  include <abstractions/ibus>
  include <abstractions/mesa>
  include <abstractions/nameservice>
  include <abstractions/user-tmp>
  include <abstractions/vulkan>

  # This include specifies which ubuntu-browsers.d abstractions to use. Eg, if
  # you want access to productivity applications, adjust the following file
  # accordingly.
  include if exists <abstractions/ubuntu-browsers.d/chromium-browser>

  capability sys_admin,
  capability sys_chroot,
  capability sys_ptrace,

  userns,

  # UPower
  # Not sure why these are needed, so deny for now
  deny dbus (send)
       bus=system
       path=/org/freedesktop/UPower
       interface=org.freedesktop.DBus.Properties
       member=Get
       peer=(label=unconfined),
  deny dbus (send)
       bus=system
       path=/org/freedesktop/UPower/devices/*
       interface=org.freedesktop.DBus.Properties
       member=Get
       peer=(label=unconfined),
  deny dbus (send)
       bus=system
       path=/org/freedesktop/UPower
       interface=org.freedesktop.UPower
       member={EnumerateDevices,GetDisplayDevice}
       peer=(label=unconfined),

  dbus (send)
       bus=system
       path=/org/freedesktop/hostname1
       interface=org.freedesktop.DBus.Properties
       member=GetAll
       peer=(label=unconfined),

  dbus (receive)
       bus=system
       path=/org/freedesktop/login1
       interface=org.freedesktop.login1.Manager
       member={SessionNew,SessionRemoved}
       peer=(label=unconfined),

  dbus (send)
       bus=session
       path=/org/freedesktop/DBus
       interface=org.freedesktop.DBus
       member={AddMatch,GetNameOwner,Hello,NameHasOwner,RemoveMatch,StartServiceByName}
       peer=(name=org.freedesktop.DBus),

  dbus (send)
       bus=session
       path=/org/freedesktop/portal/desktop
       interface=org.freedesktop.DBus.Properties
       member=Get
       peer=(name=org.freedesktop.portal.Desktop),

  dbus (send)
       bus=session
       path=/org/freedesktop/Notifications
       interface=org.freedesktop.Notifications
       member={GetCapabilities,GetServerInformation}
       peer=(name=org.freedesktop.Notifications),

  dbus (send)
       bus=session
       path=/org/gtk/vfs/mounttracker
       interface=org.gtk.vfs.MountTracker
       member=ListMountableInfo
       peer=(label=unconfined),

  # Networking
  network inet stream,
  network inet6 stream,
  @{PROC}/@{pid}/net/if_inet6 r,
  @{PROC}/@{pid}/net/ipv6_route r,

  # Should maybe be in abstractions
  /etc/fstab r,
  /etc/mime.types r,
  /etc/mailcap r,
  /etc/mtab r,
  /etc/xdg/xubuntu/applications/defaults.list r,
  owner @{HOME}/.cache/thumbnails/** r,
  owner @{HOME}/.local/share/applications/defaults.list r,
  owner @{HOME}/.local/share/applications/mimeinfo.cache r,
  /tmp/.X[0-9]*-lock r,

  @{PROC}/self/exe ixr,
  @{PROC}/filesystems r,
  @{PROC}/pressure/{cpu,io,memory} r,
  @{PROC}/vmstat r,
  @{PROC}/ r,
  owner @{PROC}/@{pid}/task/@{tid}/stat r,
  owner @{PROC}/@{pid}/clear_refs w,
  owner @{PROC}/@{pid}/cmdline r,
  owner @{PROC}/@{pid}/io r,
  owner @{PROC}/@{pid}/mountinfo r,
  owner @{PROC}/@{pid}/setgroups w,
  owner @{PROC}/@{pid}/{uid,gid}_map w,
  owner @{PROC}/@{pid}/smaps r,
  @{PROC}/@{pid}/stat r,
  @{PROC}/@{pid}/statm r,
  owner @{PROC}/@{pid}/status r,
  owner @{PROC}/@{pid}/task/@{tid}/status r,
  deny @{PROC}/@{pid}/oom_{,score_}adj w,
  @{PROC}/sys/fs/inotify/max_user_watches r,
  @{PROC}/sys/kernel/yama/ptrace_scope r,
  @{PROC}/sys/net/ipv4/tcp_fastopen r,

  # Newer chromium needs these now
  /etc/udev/udev.conf r,
  # Chromium appears to want all "uevent" files under /sys/devices/
  /sys/devices/**/uevent r,
  /sys/devices/system/cpu/cpufreq/policy*/cpuinfo_max_freq r,
  /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq r,
  /sys/devices/system/cpu/kernel_max r,
  /sys/devices/system/cpu/possible r,
  /sys/devices/system/cpu/present r,
  /sys/devices/system/node/node*/meminfo r,
  /sys/devices/pci[0-9]*/**/bConfigurationValue r,
  /sys/devices/pci[0-9]*/**/boot_vga r,
  /sys/devices/pci[0-9]*/**/busnum r,
  /sys/devices/pci[0-9]*/**/class r,
  /sys/devices/pci[0-9]*/**/config r,
  /sys/devices/pci[0-9]*/**/descriptors r,
  /sys/devices/pci[0-9]*/**/device r,
  /sys/devices/pci[0-9]*/**/devnum r,
  /sys/devices/pci[0-9]*/**/irq r,
  /sys/devices/pci[0-9]*/**/manufacturer r,
  /sys/devices/pci[0-9]*/**/product r,
  /sys/devices/pci[0-9]*/**/resource r,
  /sys/devices/pci[0-9]*/**/revision r,
  /sys/devices/pci[0-9]*/**/serial r,
  /sys/devices/pci[0-9]*/**/subsystem_device r,
  /sys/devices/pci[0-9]*/**/subsystem_vendor r,
  /sys/devices/pci[0-9]*/**/vendor r,
  /sys/devices/pci[0-9]*/**/removable r,
  /sys/devices/pci[0-9]*/**/block/**/size r,
  /sys/devices/virtual/block/**/removable r,
  /sys/devices/virtual/block/**/size r,
  /sys/devices/virtual/tty/tty*/active r,
  # This is requested, but doesn't seem to actually be needed so deny for now
  deny /run/udev/data/** r,
  deny /sys/devices/virtual/dmi/id/* r,

  # Needed for the crash reporter
  owner @{PROC}/@{pid}/auxv r,

  # chromium mmaps all kinds of things for speed.
  /etc/passwd m,
  /usr/share/fonts/truetype/**/*.tt[cf] m,
  /usr/share/fonts/**/*.pfb m,
  /usr/share/mime/mime.cache m,
  /usr/share/icons/**/*.cache m,
  owner /{dev,run,var/run}/shm/pulse-shm* m,
  owner @{HOME}/.local/share/mime/mime.cache m,
  owner /tmp/** m,

  @{PROC}/sys/kernel/shmmax r,
  owner /{dev,run,var/run}/shm/{,.}org.chromium.* mrw,
  owner /{dev,run,var/run}/shm/shmfd-* mrw,

  /usr/lib/@{chromium}/*.pak mr,
  /usr/lib/@{chromium}/locales/* mr,

  # Noisy
  deny /usr/lib/@{chromium}/** w,
  deny /var/cache/fontconfig/ w,

  # Allow ptracing ourselves and our helpers
  ptrace (trace) peer=@{profile_name},
  ptrace (read, trace) peer=@{profile_name}//xdgsettings,
  ptrace (read, trace) peer=lsb_release,

  # Make browsing directories work
  / r,
  /**/ r,

  # Allow access to documentation and other files the user may want to look
  # at in /usr
  /usr/{include,share,src}** r,

  # Default profile allows downloads to ~/Downloads and uploads from ~/Public
  owner @{HOME}/ r,
  owner @{HOME}/Public/ r,
  owner @{HOME}/Public/* r,
  owner @{HOME}/Downloads/ r,
  owner @{HOME}/Downloads/* rw,

  # For migration
  owner @{HOME}/.mozilla/firefox/profiles.ini r,
  owner @{HOME}/.mozilla/firefox/*/prefs.js r,

  # Helpers
  /usr/bin/xdg-open ixr,
  /usr/bin/gnome-open ixr,
  /usr/bin/gvfs-open ixr,
  /usr/bin/kdialog ixr,
  # TODO: xfce

  # Importing firefox settings (requires 'r' access to @{HOME}/.mozilla/**
  # which is provided by abstractions/ubuntu-browsers.d/user-files).
  /etc/firefox/profile/bookmarks.html r,
  owner @{HOME}/.mozilla/** k,

  # Chromium configuration
  /etc/@{chromium}/** r,
  # Note: "~/.pki/{,nssdb/} w" is denied by private-files abstraction
  owner @{HOME}/.pki/nssdb/* rwk,
  owner @{HOME}/.cache/chromium/ rw,
  owner @{HOME}/.cache/chromium/** rw,
  owner @{HOME}/.cache/chromium/Cache/* mr,
  owner @{HOME}/.config/chromium/ rw,
  owner @{HOME}/.config/chromium/** rwk,
  owner @{HOME}/.config/chromium/**/Cache/* mr,
  owner @{HOME}/.config/chromium/Dictionaries/*.bdic mr,
  owner @{HOME}/.config/chromium/**/Dictionaries/*.bdic mr,

  # Widevine CDM plugin
  owner @{HOME}/.config/chromium/WidevineCdm/*/_platform_specific/*/libwidevinecdm.so mr,

  # Allow transitions to ourself, our sandbox, and crash handler
  @{exec_path} mrix,
  /usr/lib/@{chromium}/chrome-sandbox cx -> sandbox,
  /usr/lib/@{chromium}/chrome_crashpad_handler Cxr -> crashpad_handler,

  # Allow communicating with sandbox and crash handler
  unix (receive, send) peer=(label=@{profile_name}//sandbox),
  unix (receive, send) peer=(label=@{profile_name}//crashpad_handler),
  signal (receive) set=(cont) peer=@{profile_name}//crashpad_handler,

  /{usr/,}bin/ps Uxr,
  /usr/lib/@{chromium}/xdg-settings Cxr -> xdgsettings,
  /usr/bin/xdg-settings Cxr -> xdgsettings,
  /usr/bin/lsb_release Pxr -> lsb_release,

  # GSettings
  owner @{run}/user/[0-9]*/dconf/     rw,
  owner @{run}/user/[0-9]*/dconf/user rw,
  owner @{HOME}/.config/dconf/user r,

  # GVfs
  owner @{run}/user/[0-9]*/gvfsd/socket-* rw,

  # Magnet links
  /usr/bin/gio ixr,

  # Chrome Gnome Shell Integration
  /etc/chromium/native-messaging-hosts/org.gnome.chrome_gnome_shell.json r,
  /usr/bin/chrome-gnome-shell ixr,

  profile xdgsettings {
    include <abstractions/bash>
    include <abstractions/gnome>

    /{usr/,}bin/dash ixr,

    /etc/ld.so.cache r,
    /etc/xdg/** r,
    /usr/bin/xdg-settings r,
    /usr/lib/@{chromium}/xdg-settings r,
    /usr/share/applications/*.desktop r,
    /usr/share/applications/*.list r,

    # Checking default browser
    /{usr/,}bin/grep ixr,
    /{usr/,}bin/head ixr,
    /{usr/,}bin/readlink ixr,
    /{usr/,}bin/sed ixr,
    /{usr/,}bin/tr ixr,
    /{usr/,}bin/which ixr,
    /usr/bin/basename ixr,
    /usr/bin/cut ixr,

    # Setting the default browser
    /{usr/,}bin/mkdir ixr,
    /{usr/,}bin/mv ixr,
    /{usr/,}bin/touch ixr,
    /usr/bin/dirname ixr,
    /usr/bin/gconftool-2 ix,
    /usr/bin/[gm]awk ixr,
    /usr/bin/xdg-mime ixr,
    owner @{HOME}/.local/share/applications/ w,
    owner @{HOME}/.local/share/applications/mimeapps.list* rw,
  }

  profile sandbox {
    # Be fanatical since it is setuid root and don't use an abstraction
    /{usr/,}lib{,32,64}/libgcc_s.so* mr,
    /{usr/,}lib{,32,64}/@{multiarch}/libgcc_s.so* mr,
    /{usr/,}lib{,32,64}/libm-*.so* mr,
    /{usr/,}lib/@{multiarch}/libm-*.so* mr,
    /{usr/,}lib{,32,64}/libpthread-*.so* mr,
    /{usr/,}lib/@{multiarch}/libpthread-*.so* mr,
    /{usr/,}lib{,32,64}/libatomic.so* mr,
    /{usr/,}lib/@{multiarch}/libatomic.so* mr,
    /{usr/,}lib{,32,64}/libc.so.* mr,
    /{usr/,}lib/@{multiarch}/libc.so.* mr,
    /{usr/,}lib{,32,64}/libc-*.so* mr,
    /{usr/,}lib/@{multiarch}/libc-*.so* mr,
    /{usr/,}lib{,32,64}/libdl-*.so* mr,
    /{usr/,}lib/@{multiarch}/libdl-*.so* mr,
    /{usr/,}lib{,32,64}/libld-*.so* mr,
    /{usr/,}lib/@{multiarch}/libld-*.so* mr,
    /{usr/,}lib{,32,64}/librt-*.so* mr,
    /{usr/,}lib/@{multiarch}/librt-*.so* mr,
    /{usr/,}lib{,32,64}/ld-*.so* mr,
    /{usr/,}lib{,32,64}/@{multiarch}/ld-*.so* mr,
    /{usr/,}lib{,32,64}/tls/*/{cmov,nosegneg}/libm-*.so* mr,
    /{usr/,}lib{,32,64}/tls/*/{cmov,nosegneg}/libpthread-*.so* mr,
    /{usr/,}lib/tls/*/{cmov,nosegneg}/libc-*.so* mr,
    /usr/lib{,32,64}/libstdc++.so* mr,
    /usr/lib{,32,64}/@{multiarch}/libstdc++.so* mr,
    /etc/ld.so.cache r,

    # Required for dropping into PID namespace. Keep in mind that until the
    # process drops this capability it can escape confinement, but once it
    # drops CAP_SYS_ADMIN we are ok.
    capability sys_admin,

    # All of these are for sanely dropping from root and chrooting
    capability chown,
    capability fsetid,
    capability setgid,
    capability setuid,
    capability dac_override,
    capability sys_chroot,

    capability sys_ptrace,
    ptrace (read, readby),

    signal (receive) peer=unconfined,
    signal peer=@{profile_name},
    signal (receive, send) set=("exists"),
    signal (receive) peer=chromium_browser,

    unix (receive, send) peer=(label=chromium_browser),
    unix (create),
    unix peer=(label=@{profile_name}),
    unix (getattr, getopt, setopt, shutdown) addr=none,

    @{PROC}/ r,
    @{PROC}/@{pid}/ r,
    @{PROC}/@{pid}/fd/ r,
    deny @{PROC}/@{pid}/oom_adj w,
    deny @{PROC}/@{pid}/oom_score_adj w,
    @{PROC}/@{pid}/status r,
    @{PROC}/@{pid}/task/@{tid}/stat r,

    /usr/bin/@{chromium} r,
    /usr/lib/@{chromium}/@{chromium} Px,
    /usr/lib/@{chromium}/chrome-sandbox mr,

    /dev/null rw,

    owner /tmp/** rw,
  }

  profile crashpad_handler {
    include <abstractions/base>

    capability sys_ptrace,

    ptrace (read, trace) peer=chromium_browser,

    signal (send) set=(cont) peer=chromium_browser,

    unix (receive, send) peer=(label=chromium_browser),

    /usr/lib/@{chromium}/chrome_crashpad_handler ixr,

    /sys/devices/system/cpu/cpufreq/policy[0-9]*/scaling_{cur,max}_freq r,

    @{PROC}/sys/kernel/yama/ptrace_scope r,

    owner @{PROC}/@{pid}/fd/ r,
    owner @{PROC}/@{pid}/mem r,
    owner @{PROC}/@{pid}/stat r,
    owner @{PROC}/@{pid}/task/ r,
    owner @{PROC}/@{pid}/task/@{tid}/comm r,

    owner @{HOME}/.config/chromium/Crash?Reports/** rwk,
  }

  # Site-specific additions and overrides. See local/README for details.
  include if exists <local/chromium_browser>
}
