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

abi <abi/4.0>,

include <tunables/global>

@{exec_path} = @{lib}/packagekitd
@{att} = /att/packagekitd/
profile packagekitd /{,usr/}lib{,exec,32,64}/packagekitd flags=(attach_disconnected,attach_disconnected.path=@{att}) {
  include <abstractions/attached/base>

  include <abstractions/bus-system>
  include <abstractions/bus/system/org.freedesktop.login1>
  include <abstractions/bus/system/org.freedesktop.PolicyKit1>
  include <abstractions/attached/nameservice-strict>
  include <abstractions/network-manager-observe>
  include <abstractions/ssl_certs>

  capability audit_write,
  capability chown,
  capability dac_override,
  capability dac_read_search,
  capability fowner,
  capability fsetid,
  capability kill,
  capability mknod,
  capability net_admin,
  capability setfcap,
  capability setgid,
  capability setuid,
  capability sys_chroot,
  capability sys_nice,

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

  signal send set=int peer=apt-methods-*,
  signal send set=term peer=systemd-inhibit,

  #aa/dbus own bus=system name=org.freedesktop.PackageKit path=/**
  include <abstractions/bus/system/own>
  dbus bind bus=system name=org.freedesktop.PackageKit{,.*},
  dbus receive bus=system path=/**
       interface=org.freedesktop.PackageKit{,.*}
       peer=(name="@{busname}"),
  dbus send bus=system path=/**
       interface=org.freedesktop.PackageKit{,.*}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  # DBus.Properties: reply to properties request from anyone
  dbus (send receive) bus=system path=/**
       interface=org.freedesktop.DBus.Properties
       member={Get,GetAll,Set,PropertiesChanged}
       peer=(name="{@{busname},org.freedesktop.DBus}"),
  # DBus.Introspectable: allow clients to introspect the service
  dbus receive bus=system path=/**
       interface=org.freedesktop.DBus.Introspectable
       member=Introspect
       peer=(name="@{busname}"),
  # DBus.ObjectManager: allow clients to enumerate sources
  dbus receive bus=system path=/**
       interface=org.freedesktop.DBus.ObjectManager
       member=GetManagedObjects
       peer=(name="{@{busname},org.freedesktop.PackageKit{,.*}}"),
  dbus send bus=system path=/**
       interface=org.freedesktop.DBus.ObjectManager
       member={InterfacesAdded,InterfacesRemoved}
       peer=(name="{@{busname},org.freedesktop.DBus}"),


  @{exec_path} mr,

  # &packagekitd//gpg not bare gpg: avoids clash with the unrelated groups/gpg/gpg profile
  @{bin}/gpg{,2}         cx -> &packagekitd//gpg,
  @{bin}/gpgconf         cx -> &packagekitd//gpg,
  @{bin}/gpgsm           cx -> &packagekitd//gpg,

  @{sh_path}            rix,
  @{bin}/cp             rix,
  @{bin}/echo           rix,
  @{bin}/gdbus          rix,
  @{bin}/gzip           rix,
  @{bin}/id             rix,
  @{sbin}/ldconfig      rix, # TODO: rcx
  @{bin}/mkdir          rix,
  @{bin}/repo2solv      rix,
  @{bin}/tar            rix,
  @{bin}/test           rix,
  @{bin}/touch          rix,

  @{bin}/appstreamcli                px,
  @{bin}/fc-cache                    px,
  @{bin}/glib-compile-schemas        px,
  @{bin}/install-info                px,
  @{bin}/ischroot                    px,
  @{bin}/pgrep                       px,
  @{bin}/systemctl                   cx -> systemctl,
  @{bin}/systemd-inhibit             px,
  @{bin}/xdg-mime                    px,
  @{bin}/update-desktop-database     px,
  @{bin}/update-mime-database        px,
  @{lib}/cnf-update-db               px,

  # %posttrans/%triggerin scriptlets: selinux-policy relabel hooks run regardless of active LSM

  @{bin}/rm                          rix,
  @{bin}/readlink                    rix,
  @{bin}/getent                      rix,
  @{bin}/{,e}grep                    rix,
  @{bin}/tail                        rix,
  @{bin}/tr                          rix,
  @{bin}/cut                         rix,
  @{bin}/find                        rix,
  @{bin}/{m,g,}awk                   rix,
  @{bin}/selinuxenabled              pux, # TODO: write the profile
  @{bin}/semodule                    pux, # TODO: write the profile
  @{bin}/setsebool                   pux, # TODO: write the profile
  @{bin}/alternatives                pux, # TODO: write the profile
  @{bin}/firewall-cmd                pux, # TODO: write the profile
  @{bin}/killall                     pux, # TODO: write the profile
  @{bin}/udevadm                     cx -> udevadm,
  @{sbin}/service                    pux, # TODO: write the profile
  @{lib}/systemd/systemd-update-helper pux, # TODO: write the profile
  @{lib}/selinux/varrun-convert.sh   pux, # TODO: write the profile
  @{bin}/systemd-tmpfiles            px,
  @{bin}/gtk-update-icon-cache       px,
  @{bin}/systemd-run                 px,
  @{bin}/systemd-sysusers            px,
  @{bin}/journalctl                  px,
  @{bin}/kernel-install               px,
  @{bin}/kmod                         px,
  @{bin}/gio-querymodules-{32,64}    px -> gio-querymodules,

  #aa:lint ignore=too-wide
  # Install/update packages
  / r,
  /*{,/} rw,
  @{efi}/** rwl,
  /etc/** rwl,
  /opt/** rwl,
  @{run}/** rw,
  /srv/** rwl,
  /usr/** rwlk,
  /var/** rwlk,

  owner @{tmp}/packagekit* rw,

  # rwlk not rw: gnupg's dotlock protocol under libdnf5's tmp gnupg home needs l/k too

  owner @{tmp}/libdnf5.@{rand6}/{,**} rwlk,

  owner @{tmp}/key.@{rand6} rw,

  owner @{tmp}/tmpdir.@{rand6}/{,**} rw,

  owner @{tmp}/librepo-tmp-@{rand6} rw,

  @{att}@{run}/dnf/ rw,
  @{run}/dnf/ rw,
  @{att}@{run}/dnf/rpmtransaction.lock rwk,
  @{run}/dnf/rpmtransaction.lock rwk,

  # SELinux translation daemon socket dir, cleaned up by the relabel scriptlets above

  @{att}@{run}/setrans/ rw,
  @{run}/setrans/ rw,

  # Local .rpm install: reads a user-owned file as root, so no "owner" prefix (fsuid=0 != ouid)

  @{HOME}/**.rpm r,
  @{MOUNTS}/**.{rpm,RPM} r,

  @{att}@{run}/systemd/inhibit/@{int}.ref rw,

  owner @{run}/systemd/users/@{uid} r,

  owner /dev/shm/AP_0x@{rand6}/{,**} rw,
  owner /dev/shm/ r,

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

        @{PROC}/@{pids}/cgroup r,
        @{PROC}/@{pids}/mountinfo r,
        @{PROC}/sys/kernel/random/uuid r,
        @{PROC}/@{pid}/cmdline r,
  owner @{PROC}/@{pid}/fd/ r,
  owner @{PROC}/@{pid}/mounts r,
  owner @{PROC}/@{pid}/loginuid r,
  owner @{PROC}/@{pid}/comm r,

  /dev/ptmx r,
  /dev/tty rw,

  profile gpg {
    include <abstractions/attached/base>
    include <abstractions/attached/nameservice-strict>

    capability dac_read_search,
    capability mknod,

    @{bin}/gpg{,2}  mr,
    @{bin}/gpgconf  mr,
    @{bin}/gpgsm    mr,

    @{bin}/gpg-agent rix,
    @{bin}/scdaemon  rix,
    @{lib}/{,gnupg/}scdaemon rix,

    /etc/gcrypt/hwf.deny r,

    @{HOME}/@{XDG_GPG_DIR}/*.conf r,

    
    owner @{tmp}/key.@{rand6} rw,

    owner @{tmp}/libdnf5.@{rand6}/{,**} rwlk,

    owner @{tmp}/librepo-tmp-@{rand6} rw, # file_inherit

    @{lib}/sysimage/rpm/.rpm.lock w,

    /var/cache/PackageKit/@{int}/metadata/*/{,tmpdir.@{rand6}/}repodata/* rw, # file_inherit

    owner @{run}/user/@{uid}/gnupg/ r,
    owner @{run}/user/@{uid}/gnupg/ rwlk -> @{run}/user/@{uid}/gnupg/**,

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

    include if exists <local/packagekitd_gpg>
  }

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

    capability net_admin,

    include if exists <local/packagekitd_systemctl>
  }


  profile udevadm {
    include <abstractions/attached/base>
    include <abstractions/app/udevadm>

    include if exists <local/packagekitd_udevadm>
  }

  include if exists <local/packagekitd>
}

# vim:syntax=apparmor
