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

# Security objectives of the steam profiles:
# - Ensure no user data is accessed by either steam or steam games
# - Limit what steam/games can access to the host
#
# Overall architecture of the steam profiles:
# steam
# ├── steam//check           # Requirements check (sandboxed)
# ├── steam//web             # steamwebhelper (sandboxed)
# ├── steam-fossilize        # Update shader cache
# ├── steam-runtime          # Launcher tasks up to the creation of the sandbox
# │   ├── steam-game-native  # Native games
# │   └── steam-game-proton  # Proton games (sandboxed)
# ├── steam-gameoverlayui    # Steam game overlay
# └── steamerrorreporter     # Error reporter

abi <abi/3.0>,

include <tunables/global>

@{arch} = amd64 i386
@{runtime} = SteamLinuxRuntime_sniper
@{share_dirs} = @{user_share_dirs}/Steam @{HOME}/.steam/debian-installation
@{lib_dirs} = @{share_dirs}/ubuntu@{int2}_{32,64}
@{runtime_dirs} = @{lib_dirs}/steam-runtime{,-sniper}
@{app_dirs} = @{share_dirs}/steamapps/common/

@{exec_path} = @{share_dirs}/steam.sh
profile steam @{exec_path} flags=(attach_disconnected,mediate_deleted) {
  include <abstractions/base>
  include <abstractions/audio-client>
  include <abstractions/consoles>
  include <abstractions/dconf-write>
  include <abstractions/desktop>
  include <abstractions/disks-read>
  include <abstractions/fontconfig-cache-write>
  include <abstractions/graphics>
  include <abstractions/nameservice-strict>
  include <abstractions/ssl_certs>
  include <abstractions/video>

  capability sys_ptrace,

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

  ptrace read,
  ptrace trace peer=steam,

  signal send peer=steam-game,
  signal send peer=steam-launcher,
  signal send peer=steam//journalctl,
  signal send peer=steam//web,

  unix,

  @{exec_path} mrix,

  @{sh_path}                    rix,
  @{coreutils_path}             rix,
  @{open_path}                  rPx -> child-open,
  @{bin}/getopt                 rix,
  @{bin}/journalctl             rPx -> systemctl,
  @{bin}/ldconfig               rix,
  @{bin}/ldd                    rix,
  @{bin}/lsb_release            rPx -> lsb_release,
  @{bin}/lsof                   rix,
  @{bin}/lspci                  rCx -> lspci,
  @{bin}/tar                    rix,
  @{bin}/which{,.debianutils}   rix,
  @{bin}/xdg-icon-resource      rPx,
  @{bin}/xdg-user-dir           rix,
  @{bin}/xz                     rix,
  @{bin}/zenity                 rix,
  @{lib}/@{multiarch}/ld-*.so*  rix,
  @{lib}/ld-linux.so*           rix,

  @{lib_dirs}/**                mr,
  @{lib_dirs}/*driverquery      rix,
  @{lib_dirs}/fossilize_replay  rpx, # steam-fossilize
  @{lib_dirs}/gameoverlayui     rpx, # steam-gameoverlayui
  @{lib_dirs}/reaper            rpx, # steam-runtime
  @{lib_dirs}/steam*            rix,

  @{app_dirs}/@{runtime}/*entry-point rpx -> steam-runtime,

  @{share_dirs}/linux{32,64}/steamerrorreporter rpx, # steamerrorreporter

  @{runtime_dirs}/*entry-point                                                      rix,
  @{runtime_dirs}/@{arch}/@{bin}/srt-logger                                         rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-check-requirements                   rcx -> check,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-dialog{,-ui}                         rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-identify-library-abi                 rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-input-monitor                        rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-launch-*                             rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-launcher-interface-@{int}            rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-launcher-service                     rpx, # steam-launcher
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-libcurl-*                            rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-steam-remote                         rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-supervisor                           rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-system-info                          rix,
  @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-urlopen                              rix,
  @{runtime_dirs}/@{lib}/steam-runtime-tools-@{int}/@{multiarch}-*                  rix,
  @{runtime_dirs}/pressure-vessel/@{bin}/pressure-vessel-*                          rix,
  @{runtime_dirs}/pressure-vessel/@{lib}/steam-runtime-tools-@{int}/@{multiarch}-*  rix,
  @{runtime_dirs}/pressure-vessel/@{lib}/steam-runtime-tools-@{int}/srt-bwrap       rcx -> web,
  @{runtime_dirs}/run{,.sh}                                                         rix,
  @{runtime_dirs}/setup.sh                                                          rix,

  @{lib}/os-release rk,

  /usr/share/fonts/** rk,

  /etc/lsb-release r,
  /etc/machine-id r,
  /etc/timezone r,

  /var/lib/dbus/machine-id r,

  / r,
  @{bin}/ r,
  @{lib}/ r,
  /etc/ r,
  /home/ r,
  /usr/ r,
  /usr/local/ r,
  /usr/local/lib/ r,

  /var/ r,
  /var/tmp/ r,

  owner @{HOME}/ r,
  owner @{HOME}/.steam/{,**} rw,
  owner @{HOME}/.steam/registry.vdf rwk,
  owner @{HOME}/.steampath rw,
  owner @{HOME}/.steampid rw,

  owner @{share_dirs}/ rw,
  owner @{share_dirs}/** rwlk -> @{share_dirs}/**,

  owner @{user_games_dirs}/ rw,
  owner @{user_games_dirs}/** rwlk -> @{user_games_dirs}/**,

  owner @{user_config_dirs}/@{XDG_GAMESSTUDIO_DIR}/ rw,
  owner @{user_config_dirs}/@{XDG_GAMESSTUDIO_DIR}/** rwlk,
  owner @{user_config_dirs}/autostart/ r,
  owner @{user_config_dirs}/cef_user_data/{,**} r,
  owner @{user_config_dirs}/cef_user_data/Dictionaries/* rw,
  owner @{user_config_dirs}/cef_user_data/WidevineCdm/** mrw,

  owner @{user_share_dirs}/@{XDG_GAMESSTUDIO_DIR}/ rw,
  owner @{user_share_dirs}/@{XDG_GAMESSTUDIO_DIR}/** rwlk,
  owner @{user_share_dirs}/applications/*.desktop w,
  owner @{user_share_dirs}/icons/hicolor/**/apps/steam*.png rw,
  owner @{user_share_dirs}/vulkan/implicit_layer.d/steam*.json rwk,

        @{tmp}/ r,
  owner @{tmp}/#@{int} rw,
  owner @{tmp}/@{XDG_GAMESSTUDIO_DIR}/ rw,
  owner @{tmp}/@{XDG_GAMESSTUDIO_DIR}/** rwlk,
  owner @{tmp}/dumps/ rw,
  owner @{tmp}/dumps/** rwk,
  owner @{tmp}/gdkpixbuf-xpm-tmp.@{rand6} rw,
  owner @{tmp}/glx-icds-@{rand6}/{,**} rw,
  owner @{tmp}/runtime-info.txt.@{rand6} rwk,
  owner @{tmp}/steam/ rw,
  owner @{tmp}/steam/** rwk,
  owner @{tmp}/steam@{rand6}/{,**} rw,
  owner @{tmp}/vdpau-drivers-@{rand6}/{,**} rw,

  owner /dev/shm/fossilize-*-@{int}-@{int} rw,
  owner /dev/shm/u@{uid}-Shm_@{hex6} rw,
  owner /dev/shm/u@{uid}-Shm_@{hex6}@{h} rw,
  owner /dev/shm/u@{uid}-Shm_@{hex8} rw,
  owner /dev/shm/u@{uid}-ValveIPCSharedObj-Steam rwk,
  owner /dev/shm/ValveIPCSHM_@{uid} rw,

  owner @{run}/user/@{uid}/ r,

  @{run}/udev/data/+pci:* r,              # Identifies all PCI devices (CPU, GPU, Network, Disks, USB, etc.)

  @{run}/udev/data/c13:@{int} r,          # for /dev/input/*
  @{run}/udev/data/n@{int} r,

  @{sys}/ r,
  @{sys}/bus/ r,
  @{sys}/class/ r,
  @{sys}/class/hidraw/ r,
  @{sys}/class/input/ r,
  @{sys}/class/net/ r,
  @{sys}/class/power_supply/ r,
  @{sys}/devices/ r,
  @{sys}/devices/**/input/input@{int}/ r,
  @{sys}/devices/**/input/input@{int}/properties r,
  @{sys}/devices/**/input@{int}/ r,
  @{sys}/devices/**/input@{int}/capabilities/* r,
  @{sys}/devices/**/power_supply/{AC,BAT@{int},hidpp_battery_@{int}}/{,*} r,
  @{sys}/devices/**/report_descriptor r,
  @{sys}/devices/**/uevent r,
  @{sys}/devices/@{pci}/boot_vga r,
  @{sys}/devices/@{pci}/sound/card@{int}/input@{int}/properties r,
  @{sys}/devices/system/ r,
  @{sys}/devices/system/cpu/cpu@{int}/ r,
  @{sys}/devices/virtual/dmi/id/bios_vendor r,
  @{sys}/devices/virtual/dmi/id/bios_version r,
  @{sys}/devices/virtual/dmi/id/product_name r,
  @{sys}/devices/virtual/dmi/id/sys_vendor r,
  @{sys}/devices/virtual/net/*/ r,
  @{sys}/kernel/ r,
  @{sys}/power/suspend_stats/success rk,

        @{PROC}/ r,
        @{PROC}/@{pid}/comm rk,
        @{PROC}/@{pid}/fdinfo/@{int} r,
        @{PROC}/@{pid}/net/* r,
        @{PROC}/@{pid}/stat r,
        @{PROC}/1/cgroup r,
        @{PROC}/locks r,
        @{PROC}/sys/kernel/sched_autogroup_enabled r,
        @{PROC}/sys/kernel/unprivileged_userns_clone r,
        @{PROC}/sys/net/ipv6/conf/all/disable_ipv6 r,
        @{PROC}/sys/user/max_user_namespaces r,
        @{PROC}/version r,
  owner @{PROC}/@{pid}/autogroup rw,
  owner @{PROC}/@{pid}/cmdline rk,
  owner @{PROC}/@{pid}/environ r,
  owner @{PROC}/@{pid}/fd/ r,
  owner @{PROC}/@{pid}/fd/@{int} rw,
  owner @{PROC}/@{pid}/mem r,
  owner @{PROC}/@{pid}/mounts r,
  owner @{PROC}/@{pid}/task/ r,
  owner @{PROC}/@{pid}/task/@{tid}/children r,
  owner @{PROC}/@{pid}/task/@{tid}/comm rw,

  /dev/input/ r,
  /dev/uinput w,

  deny /opt/** r,

  profile web flags=(attach_disconnected,mediate_deleted,complain) {
    include <abstractions/base>
    include <abstractions/audio-client>
    include <abstractions/common/bwrap>
    include <abstractions/dconf-write>
    include <abstractions/desktop>
    include <abstractions/fontconfig-cache-write>
    include <abstractions/graphics>
    include <abstractions/nameservice-strict>
    include <abstractions/video>

    capability dac_read_search,
    capability sys_chroot,

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

    ptrace trace peer=steam//web,

    signal receive set=(cont kill term) peer=steam,

    unix receive type=stream,

    @{bin}/getopt     rix,
    @{bin}/gzip       rix,
    @{bin}/ldconfig   rix,
    @{bin}/localedef  rix,
    @{bin}/readlink   rix,
    @{bin}/true       rix,

    @{lib_dirs}/**                             mr,
    @{lib_dirs}/steamwebhelper                 rix,
    @{lib_dirs}/steamwebhelper_sniper_wrap.sh  rix,

    @{runtime_dirs}/pressure-vessel/@{bin}/steam-runtime-launcher-interface-@{int}  rix,
    @{runtime_dirs}/pressure-vessel/@{lib}/steam-runtime-tools-@{int}/srt-bwrap     mr,

    @{lib}/pressure-vessel/from-host/**  rix,
    @{run}/host/@{bin}/*                 rix,
    @{run}/host/@{lib}/**                rix,

    @{share_dirs}/config/cefdata/WidevineCdm/**/linux_*/libwidevinecdm.so mr,

    @{runtime_dirs}/var/tmp-@{rand6}/usr/.ref w,

    @{run}/host/{,**} r,

    /etc/machine-id r,

    @{lib}/ r,
    /usr/local/lib/ r,
    /var/tmp/ r,

    owner /bindfile@{rand6} rw,

    owner /var/cache/ldconfig/aux-cache* rw,
    owner /var/pressure-vessel/ldso/* rw,

    owner @{HOME}/.pki/ rw,
    owner @{HOME}/.pki/nssdb/ rw,
    owner @{HOME}/.pki/nssdb/{cert9,key4}.db rwk,
    owner @{HOME}/.pki/nssdb/{cert9,key4}.db-journal rw,
    owner @{HOME}/.pki/nssdb/pkcs11.txt rw,

    owner @{lib_dirs}/.cef-* wk,

    owner @{share_dirs}/{,**} r,
    owner @{share_dirs}/clientui/** k,
    owner @{share_dirs}/config/** rwk,
    owner @{share_dirs}/logs/** rwk,
    owner @{share_dirs}/public/** k,

          @{tmp}/ r,
    owner @{tmp}/#@{int} rw,
    owner @{tmp}/.org.chromium.Chromium.@{rand6} rw,
    owner @{tmp}/dumps/ rw,
    owner @{tmp}/dumps/** rwk,
    owner @{tmp}/pressure-vessel-*-@{rand6}/ rw,
    owner @{tmp}/pressure-vessel-*-@{rand6}/** rwlk -> @{tmp}/pressure-vessel-*-@{rand6}/**,
    owner @{tmp}/steam_chrome_shmem_uid@{uid}_spid@{int} rw,

          /dev/shm/ r,
    owner /dev/shm/.org.chromium.Chromium.@{rand6} rw,
    owner /dev/shm/u@{uid}-Shm_@{hex4}@{h} rw,
    owner /dev/shm/u@{uid}-Shm_@{hex6} rw,
    owner /dev/shm/u@{uid}-Shm_@{hex6}@{h} rw,
    owner /dev/shm/u@{uid}-Shm_@{hex8} rw,
    owner /dev/shm/u@{uid}-ValveIPCSharedObj-Steam rwk,
    owner /dev/shm/ValveIPCSHM_@{uid} rw,

    owner @{run}/pressure-vessel/** r,

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

    @{sys}/bus/ r,
    @{sys}/bus/*/devices/ r,
    @{sys}/class/*/ r,
    @{sys}/devices/**/report_descriptor r,
    @{sys}/devices/**/uevent r,
    @{sys}/devices/@{pci}/usb@{int}/**/{idVendor,idProduct,interface} r,
    @{sys}/devices/system/cpu/kernel_max r,
    @{sys}/devices/virtual/tty/tty@{int}/active r,

          @{PROC}/ r,
          @{PROC}/@{pid}/stat r,
          @{PROC}/sys/fs/inotify/max_user_watches r,
          @{PROC}/sys/kernel/yama/ptrace_scope r,
    owner @{PROC}/@{pid}/cmdline r,
    owner @{PROC}/@{pid}/mem r,
    owner @{PROC}/@{pid}/oom_score_adj w,
    owner @{PROC}/@{pid}/statm r,
    owner @{PROC}/@{pid}/task/ r,
    owner @{PROC}/@{pid}/task/@{tid}/comm r,
    owner @{PROC}/@{pid}/task/@{tid}/status r,

    /dev/ r,
    /dev/hidraw@{int} rw,
    /dev/tty rw,

    include if exists <local/steam_web>
  }

  profile check flags=(attach_disconnected,mediate_deleted,complain) {
    include <abstractions/base>
    include <abstractions/common/bwrap>
    include <abstractions/nameservice-strict>

    capability dac_read_search,

    unix receive type=stream,

    @{bin}/true rix,

    @{lib_dirs}/**                                                   mr,
    @{runtime_dirs}/@{arch}/@{bin}/steam-runtime-check-requirements  mr,
    @{runtime_dirs}/@{lib}/steam-runtime-tools-@{int}/srt-bwrap      rix,

    / r,

    owner @{HOME}/.steam/root r,
    owner @{HOME}/.steam/steam r,

    owner @{share_dirs}/ r,

    @{PROC}/@{pid}/cgroup r,

    include if exists <local/steam_check>
  }

  profile lspci flags=(attach_disconnected,mediate_deleted,complain) {
    include <abstractions/base>
    include <abstractions/consoles>
    include <abstractions/nameservice-strict>

    unix receive type=stream,

    @{bin}/lspci mr,

    owner @{HOME}/.steam/steam.pipe r,

    @{sys}/bus/pci/devices/ r,
    @{sys}/bus/pci/slots/ r,
    @{sys}/bus/pci/slots/@{int}/address r,
    @{sys}/devices/@{pci}/** r,

    owner /dev/shm/ValveIPCSHM_@{uid} rw,

    include if exists <local/steam_lspci>
  }

  profile systemctl {
    include <abstractions/base>
    include <abstractions/app/systemctl>

    /{run,var}/log/journal/ r,
    /{run,var}/log/journal/@{hex32}/ r,
    /{run,var}/log/journal/@{hex32}/system.journal* r,
    /{run,var}/log/journal/@{hex32}/system@@{hex}.journal* r,
    /{run,var}/log/journal/@{hex32}/user-@{hex}.journal* r,

    include if exists <local/steam_systemctl>
  }

  include if exists <local/steam>
}

# vim:syntax=apparmor
