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

# GNOME JavaScript interpreter. It is used to run some gnome internal app
# as well as third party extensions.
#
# Therefore, by default, some extension are confined under this profile. To fix
# this, the various programs using gjs must never run gjs as module, they need
# to run it as executable with a specific script.
#
# This currently concerns:
# - gnome-extension-ding (used to not be started as a module)
# - org.gnome.ScreenSaver (simple dbus service)
# - org.gnome.Shell.Extensions (full UI app, requires gnome-strict, graphics, ...)
# - org.gnome.Shell.Notifications (simple dbus service)
# - org.gnome.Shell.Screencast (simple dbus service)

abi <abi/4.0>,

include <tunables/global>

@{exec_path} = @{bin}/gjs-console
@{att} = /att/gjs/
profile gjs /{,usr/}bin/gjs-console  flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
  include <abstractions/attached/base>
  include <abstractions/bus-session>
  include <abstractions/bus/org.gnome.Shell.Introspect>
  include <abstractions/attached/consoles>
  include <abstractions/dconf-write>
  include <abstractions/fontconfig-cache-read>

  # Only needed by org.gnome.Shell.Extensions
  include <abstractions/gnome-strict>
  include <abstractions/graphics>
  include <abstractions/nameservice-strict>

  # Only needed by gnome-extension-ding
  include <abstractions/bus-system>
  include <abstractions/bus/net.hadess.SwitcherooControl>
  include <abstractions/bus/org.freedesktop.FileManager1>
  include <abstractions/bus/session/org.gnome.ArchiveManager1>
  include <abstractions/bus/session/org.gnome.Nautilus.FileOperations2>
  include <abstractions/bus/session/org.gtk.Private.RemoteVolumeMonitor>
  include <abstractions/bus/session/org.gtk.vfs.Daemon>
  include <abstractions/bus/session/org.gtk.vfs.Metadata>

  unix type=stream peer=(label=gnome-shell),

  signal receive set=(term hup) peer=gdm,

  include <abstractions/bus/session/own>

  dbus bind bus=session name=com.rastersoft.ding{,.*},
  dbus receive bus=session path=/com/rastersoft/ding{,/**}
       interface=com.rastersoft.ding{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/com/rastersoft/ding{,/**}
       interface=com.rastersoft.ding{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/com/rastersoft/ding{,/**}
       interface=org.gtk.Actions
       peer=(name="@{busname}"),
  dbus send bus=session path=/com/rastersoft/ding{,/**}
       interface=org.gtk.Actions
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/com/rastersoft/ding{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/com/rastersoft/ding{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/com/rastersoft/ding{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},com.rastersoft.ding{,.*}}"),
  dbus send bus=session path=/com/rastersoft/ding{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  unix type=stream addr=none peer=(label=gnome-shell, addr=none),

  dbus (send receive) bus=session path=/com/rastersoft/dingextension{,/**}
       interface=com.rastersoft.dingextension{,.*}
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus (send receive) bus=session path=/com/rastersoft/dingextension{,/**}
       interface=org.gtk.Actions
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus (send receive) bus=session path=/com/rastersoft/dingextension{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus send bus=session path=/com/rastersoft/dingextension{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus send bus=session path=/com/rastersoft/dingextension{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus receive bus=session path=/com/rastersoft/dingextension{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},com.rastersoft.dingextension{,.*}}", label=gnome-shell),
  dbus send bus=session path=/org/freedesktop/DBus
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name=org.freedesktop.DBus, label="@{p_dbus_session}"),
  dbus send bus=session path=/org/freedesktop/DBus
       interface=org.freedesktop.DBus*
       peer=(name=org.freedesktop.DBus, label="@{p_dbus_session}"),
  dbus send bus=system path=/org/freedesktop/DBus
       interface=org.freedesktop.DBus*
       peer=(name=org.freedesktop.DBus, label="@{p_dbus_system}"),

  include <abstractions/bus/session/own>

  dbus bind bus=session name=org.gnome.Shell.Screencast{,.*},
  dbus receive bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.gnome.Shell.Screencast{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.gnome.Shell.Screencast{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.gnome.Shell.Screencast{,.*}}"),
  dbus send bus=session path=/org/gnome/Shell/Screencast{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  unix type=stream addr=none peer=(label=gnome-shell, addr=none),

  dbus (send receive) bus=session path=/org/gnome/Mutter/ScreenCast{,/**}
       interface=org.gnome.Mutter.ScreenCast{,.*}
       peer=(name="{@{busname},org.gnome.Mutter.ScreenCast{,.*}}", label=gnome-shell),
  dbus (send receive) bus=session path=/org/gnome/Mutter/ScreenCast{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.gnome.Mutter.ScreenCast{,.*}}", label=gnome-shell),
  dbus send bus=session path=/org/gnome/Mutter/ScreenCast{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="{@{busname},org.gnome.Mutter.ScreenCast{,.*}}", label=gnome-shell),
  dbus send bus=session path=/org/gnome/Mutter/ScreenCast{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.gnome.Mutter.ScreenCast{,.*}}", label=gnome-shell),
  dbus receive bus=session path=/org/gnome/Mutter/ScreenCast{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.gnome.Mutter.ScreenCast{,.*}}", label=gnome-shell),

  include <abstractions/bus/session/own>

  dbus bind bus=session name=org.freedesktop.Notifications{,.*},
  dbus receive bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.Notifications{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.Notifications{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.freedesktop.Notifications{,.*}}"),
  dbus send bus=session path=/org/freedesktop/Notifications{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  include <abstractions/bus/session/own>

  dbus bind bus=session name=org.gnome.ScreenSaver{,.*},
  dbus receive bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.gnome.ScreenSaver{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.gnome.ScreenSaver{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.gnome.ScreenSaver{,.*}}"),
  dbus send bus=session path=/org/gnome/ScreenSaver{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  include <abstractions/bus/session/own>

  dbus bind bus=session name=org.gnome.Shell.Extensions{,.*},
  dbus receive bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.gnome.Shell.Extensions{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.gnome.Shell.Extensions{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.gnome.Shell.Extensions{,.*}}"),
  dbus send bus=session path=/org/gnome/Shell/Extensions{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  include <abstractions/bus/session/own>

  dbus bind bus=session name=org.gnome.Shell.Notifications{,.*},
  dbus receive bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.gnome.Shell.Notifications{,.*}
       peer=(name="@{busname}"),
  dbus send bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.gnome.Shell.Notifications{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus (send receive) bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  dbus receive bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  dbus receive bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.gnome.Shell.Notifications{,.*}}"),
  dbus send bus=session path=/org/gnome/Shell/Notifications{,/**}
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),

  @{exec_path} mrix,

  # gnome-extension-ding
  @{sh_path}                   rix,
  @{bin}/env                   rix,
  @{bin}/gnome-control-center  rpx,
  @{bin}/nautilus              rpx,

  @{lib}/@{multiarch}/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner  rcx -> gstreamer,
  @{lib}/@{multiarch}/gstreamer-1.0/gst-plugin-scanner               rcx -> gstreamer,
  @{lib}/gstreamer-1.0/gst-plugin-scanner                            rcx -> gstreamer,

  /usr/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/{service/daemon.js,gsconnect-preferences} rpx,
  @{user_share_dirs}/gnome-shell/extensions/gsconnect@andyholmes.github.io/{service/daemon.js,gsconnect-preferences} rpx,

  /usr/share/gnome-shell/{,**} r,
  /usr/share/xkeyboard-config-2/{,**} r,
  /usr/share/thumbnailers/{,**} r,

  owner @{gdm_cache_dirs}/gstreamer-1.0/ w,
  owner @{gdm_cache_dirs}/gstreamer-@{int}.@{int}/ w,
  owner @{gdm_cache_dirs}/gstreamer-@{int}.@{int}/registry.@{arch}.bin{,.tmp@{rand6}} rw,

  owner @{HOME}/ r,

  owner @{user_cache_dirs}/gjs_repl_history rw,
  owner @{user_cache_dirs}/gjs_repl_history-@{int}.tmp rw,

  owner @{user_share_dirs}/gnome-shell/extensions/{,**} r,
  owner @{user_share_dirs}/nautilus/scripts/ r,

  # To register extensions
  owner @{user_config_dirs}/**/NativeMessagingHosts/ r,
  owner @{user_config_dirs}/**/NativeMessagingHosts/org.gnome.shell.extensions.*.json w,
  owner @{user_config_dirs}/**/NativeMessagingHosts/org.gnome.shell.extensions.*.json.@{rand6} rw,
  owner @{user_share_dirs}/applications/org.gnome.Shell.Extensions.*.desktop w,
  owner @{user_share_dirs}/applications/org.gnome.Shell.Extensions.*.desktop.@{rand6} w,
  owner @{user_share_dirs}/dbus-1/services/ r,
  owner @{user_share_dirs}/dbus-1/services/org.gnome.Shell.Extensions.*.service w,
  owner @{user_share_dirs}/dbus-1/services/org.gnome.Shell.Extensions.*.service.@{rand6} rw,
  owner @{user_share_dirs}/icons/**/org.gnome.Shell.Extensions.*.svg w,
  owner @{user_share_dirs}/icons/**/org.gnome.Shell.Extensions.*.svg.@{rand6} w,
  owner @{user_share_dirs}/icons/**/org.gnome.Shell.Extensions.GSConnect.svg w,
  owner @{user_share_dirs}/icons/**/org.gnome.Shell.Extensions.GSConnect.svg.@{rand6} w,

  owner @{user_desktop_dirs}/ r,
  owner @{user_templates_dirs}/ r,

  owner @{PROC}/@{pid}/mounts r,
  owner @{PROC}/@{pid}/stat r,
  owner @{PROC}/@{pid}/task/ r,
  owner @{PROC}/@{pid}/task/@{tid}/comm rw,
  owner @{PROC}/@{pid}/task/@{tid}/stat r,

  /dev/ r,
  /dev/dri/ r,

  deny @{user_share_dirs}/gvfs-metadata/* r,

  profile gstreamer flags=(attach_disconnected,attach_disconnected.path=@{att},complain) {
    include <abstractions/attached/base>
    include <abstractions/bus-session>
    include <abstractions/bus/session/org.gtk.vfs.MountTracker>
    include <abstractions/camera>
    include <abstractions/fonts>
    include <abstractions/graphics>
    include <abstractions/gstreamer>
    include <abstractions/media-control>
    include <abstractions/wayland>
    include <abstractions/X-strict>

    network (bind create getattr setopt getopt) netlink raw,

    dbus receive bus=session path=/
         interface=org.freedesktop.DBus.Introspectable
         member=Introspect
         peer=(name=@{busname}, label=gnome-shell),

    @{lib}/@{multiarch}/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner mr,
    @{lib}/@{multiarch}/gstreamer-1.0/gst-plugin-scanner mr,
    @{lib}/gstreamer-1.0/gst-plugin-scanner mr,

    owner @{desktop_cache_dirs}/nvidia/GLCache/ rw,
    owner @{desktop_cache_dirs}/nvidia/GLCache/** rwk,

    @{run}/udev/data/c@{dynamic}:@{int} r,  # For dynamic assignment range 234 to 254, 384 to 511

    @{sys}/devices/**/uevent r,

    include if exists <local/gjs_gstreamer>
  }

  include if exists <local/gjs>
}

# vim:syntax=apparmor
