Issue with Temporary Directories and Arch-Update
I'm using this Arch update helper arch-update. The problem is, when checking for updates, it creates a /tmp folder to sync pacman. The relevant code can be found here. This causes a bunch of logs for pacman as this is not the "expected" behaviour. They look like this:
apparmor="ALLOWED" operation="chown" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/core.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="chmod" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/core.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_src" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/core.db" comm="pacman" requested_mask="wrd" denied_mask="wrd" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_dest" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/core.db" comm="pacman" requested_mask="wc" denied_mask="wc" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="chown" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/extra.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="chmod" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/extra.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_src" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/extra.db" comm="pacman" requested_mask="wrd" denied_mask="wrd" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_dest" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/extra.db" comm="pacman" requested_mask="wc" denied_mask="wc" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="chown" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/multilib.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="chmod" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/multilib.db" comm="pacman" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_src" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/download-4tcJfb/multilib.db" comm="pacman" requested_mask="wrd" denied_mask="wrd" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
apparmor="ALLOWED" operation="rename_dest" class="file" profile="pacman" name="/tmp/arch-update-1000/checkupdates-z6wXD/sync/multilib.db" comm="pacman" requested_mask="wc" denied_mask="wc" fsuid=1000 ouid=1000 FSUID="user" OUID="user"
I don't know if it would make sense to create a profile for this specific program, or if there might be a better way to detect such behaviour more broadly.
I had tested arch-update some time ago for a couple of days but finally decided to continue using my own update script.
But anyway, here's the preliminary profile I created. Note that it's probably not yet complete nor finetuned - but it might help you to overcome your problems.
# apparmor.d - Full set of apparmor profiles
# Copyright (C) 2025 You <your@email>
# SPDX-License-Identifier: GPL-2.0-only
abi <abi/4.0>,
include <tunables/global>
@{exec_path} = @{bin}/arch-update
profile arch-update @{exec_path} flags=(complain) {
include <abstractions/base>
include <abstractions/python>
# set rlimit
# userns
# capability
# network
# mount
# remount
# umount
# pivot_root
# change_profile
# mqueue
# signal
# ptrace
# unix
# io_uring
# dbus
@{exec_path} mrix,
@{bin}/cat ix,
@{bin}/checkupdates rix,
@{bin}/checkservices rix,
@{bin}/cut rix,
@{bin}/env rix,
@{bin}/envsubst rix,
@{bin}/faked rix,
@{bin}/fakeroot rix,
@{bin}/file r,
@{bin}/flatpak Px,
@{bin}/gawk ix,
@{bin}/getopt rix,
@{bin}/gettext rix,
@{bin}/gettext.sh r,
@{bin}/gio rPx -> gio-launch-desktop,
@{bin}/grep rix,
@{bin}/ln ix,
@{bin}/mkdir ix,
@{bin}/mktemp ix,
@{bin}/mv ix,
@{bin}/pacdiff Px,
@{bin}/pacman Px,
@{bin}/pacman-conf Px,
@{bin}/paru Cx -> paru,
@{bin}/pgrep rix,
@{python_path} rix,
@{bin}/rm rix,
@{bin}/sed ix,
@{bin}/sudo rPx,
@{bin}/systemctl rix,
@{bin}/systemd-tty-ask-password-agent rPx,
@{bin}/touch ix,
@{bin}/tr ix,
@{bin}/wc rix,
@{lib}/gconv/gconv-modules.cache r,
@{lib}/modules/*/vmlinuz r,
@{lib}/utempter/utempter rPx,
# /usr/share
/usr/share/file/misc/magic.mgc r,
/usr/share/arch-update/lib/check.sh r,
/usr/share/arch-update/lib/common.sh r,
/usr/share/arch-update/lib/config.sh r,
/usr/share/makepkg/util/message.sh r,
/usr/share/makepkg/util/parseopts.sh r,
/usr/share/arch-update/lib/tray.py mrix,
/usr/share/arch-update/lib/tray.sh r,
# /etc
# /, /var, /boot
/ r,
/boot/vmlinuz-linux-cachyos r,
/boot/vmlinuz-linux-lts r,
# owner @{HOME}/
# @{user_cache_dirs}, @{user_config_dirs}, @{user_share_dirs}
owner @{user_config_dirs}/arch-update/arch-update.conf r,
owner @{user_state_dirs}/arch-update/current_updates_check rw,
owner @{user_state_dirs}/arch-update/last_updates_check rw,
owner @{user_state_dirs}/arch-update/last_updates_check_aur rw,
owner @{user_state_dirs}/arch-update/last_updates_check_flatpak rw,
owner @{user_state_dirs}/arch-update/last_updates_check_packages rw,
owner @{user_state_dirs}/arch-update/@{rand9} rw,
owner @{user_state_dirs}/arch-update/sed@{rand6} rw,
owner @{user_state_dirs}/arch-update/tray_icon rw,
# /tmp/, @{run}/, /dev/shm/
owner /tmp/arch-update-@{uid}/checkupdates-*/{,**} rw,
owner /tmp/arch-update-@{uid}/ w,
# @{sys}/
@{sys}/devices/system/cpu/possible r,
@{sys}/devices/system/node/ r,
# @{PROC}/
@{PROC}/ r,
@{PROC}/@{pid}/ r,
@{PROC}/@{pid}/cgroup r,
@{PROC}/@{pid}/cmdline r,
@{PROC}/@{pid}/maps r,
@{PROC}/@{pid}/stat r,
@{PROC}/@{pid}/status r,
@{PROC}/1/ r,
@{PROC}/1/cgroup r,
@{PROC}/1/cmdline r,
@{PROC}/1/stat r,
@{PROC}/1/status r,
@{PROC}/tty/drivers r,
# /dev/
owner /dev/pts/@{int} rw,
/dev/tty rw,
/dev/tty@{int} r,
# deny
profile paru flags=(complain) {
include <abstractions/base>
include <abstractions/nameservice-strict>
network inet dgram,
network inet6 dgram,
network inet6 stream,
network netlink raw,
@{bin}/paru mr,
@{bin}/fakeroot r,
@{bin}/git Px,
@{bin}/pacman Px,
@{bin}/gpg rPx,
@{bin}/gpgconf rPx,
@{bin}/gpgsm rPx,
@{bin}/pacman-conf rPx,
@{lib}/libfakeroot/ r,
@{lib}/libfakeroot/libfakeroot-0.so mr,
/etc/ca-certificates/extracted/tls-ca-bundle.pem r,
/etc/paru.conf r,
/var/lib/pacman/local/ r,
/var/lib/pacman/sync/* r,
@{sys}/fs/cgroup/user.slice/cpu.max r,
@{sys}/fs/cgroup/user.slice/user-@{uid}.slice/cpu.max r,
@{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/cpu.max r,
owner @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/app.slice/app-arch**/cpu.max r,
# owner @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/app.slice/app-arch\x2dupdate\x2dtray@@{hex32}.service/cpu.max r,
owner @{sys}/fs/cgroup/user.slice/user-@{uid}.slice/user@@{uid}.service/app.slice/cpu.max r,
owner @{user_state_dirs}/paru/ r,
owner @{user_state_dirs}/paru/devel.toml rw,
owner @{user_state_dirs}/paru/devel.toml.tmp rw,
/var/lib/pacman/local/** r,
owner @{PROC}/@{pid}/cgroup r,
}
include if exists <local/arch-update>
}
# vim:syntax=apparmor
Adding a profile for arch-update is probably the best solution. However, if the profile allow to transition to the main pacman profile (that would make sense). Then you still need to add something like: owner @{tmp}/arch-update-@{uid}/checkupdates-@{rand6}/sync/download-@{rand6}/core.db rw, in the pacman profile.