On some systems /run is mounted as: tmpfs on /run type tmpfs (rw,nosuid,nodev,noexec,relatime,size=348508k,mode=755,inode64) and /var/run is then just a symlink: # ls -ld /var/run lrwxrwxrwx 1 root root 4 Apr 23 2024 /var/run -> /run But because we still think it's 2004 and FHS 2.3 is active we have a rule in our meson.build which constructs RUNSTATEDIR as the following: runstatedir = get_option('runstatedir') if runstatedir == '' runstatedir = localstatedir / 'run' endif which (if unspecified on meson setup line) results in "/var/run". This in turn means, when when we're generating an AppArmor profile for a domain with allowed paths it contains stuff like: /var/run/libvirt/qemu/swtpm/2-guest-swtpm.sock But because of the aforementioned symlink the real path is: /run/libvirt/qemu/swtpm/2-guest-swtpm.sock and thus AppArmor denies access: audit: type=1400 audit(1740480419.348:415): apparmor="DENIED" operation="connect" class="file" profile="libvirt-126f2720-6f8e-45ab-a886-ec9277079a67" name="/run/libvirt/qemu/swtpm/2-guest-swtpm.sock" pid=8080 comm="qemu-system-x86" requested_mask="wr" denied_mask="wr" fsuid=64055 ouid=64055 Fortunately, there's a nice trick: AppArmor profile variables. We already use some of them (@{PROC}, @{HOME}, @{multiarch}) and instead of RUNSTATEDIR we can use @{run} which is declared as: # cat /etc/apparmor.d/tunables/run @{run}=/run/ /var/run/ and thus covers both scenarios. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/security/virt-aa-helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index c255b64f35..eabc29e9cf 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1238,8 +1238,8 @@ get_files(vahControl * ctl) /* Unix socket for QEMU and swtpm to use */ virBufferAsprintf(&buf, - " \"%s/libvirt/qemu/swtpm/%s-swtpm.sock\" rw,\n", - RUNSTATEDIR, shortName); + " \"@{run}/libvirt/qemu/swtpm/%s-swtpm.sock\" rw,\n", + shortName); /* Paths for swtpm to use: give it access to its state * directory (state files and fsync on dir), log, and PID files. */ @@ -1253,8 +1253,8 @@ get_files(vahControl * ctl) " \"%s/log/swtpm/libvirt/qemu/%s-swtpm.log\" w,\n", LOCALSTATEDIR, ctl->def->name); virBufferAsprintf(&buf, - " \"%s/libvirt/qemu/swtpm/%s-swtpm.pid\" rw,\n", - RUNSTATEDIR, shortName); + " \"@{run}/libvirt/qemu/swtpm/%s-swtpm.pid\" rw,\n", + shortName); VIR_FREE(shortName); } @@ -1528,10 +1528,10 @@ main(int argc, char **argv) LOCALSTATEDIR, ctl->def->name); virBufferAsprintf(&buf, " \"%s/lib/libvirt/qemu/domain-%d-%.*s/*\" rw,\n", LOCALSTATEDIR, ctl->def->id, 20, ctl->def->name); - virBufferAsprintf(&buf, " \"%s/libvirt/**/%s.pid\" rwk,\n", - RUNSTATEDIR, ctl->def->name); - virBufferAsprintf(&buf, " \"%s/libvirt/**/*.tunnelmigrate.dest.%s\" rw,\n", - RUNSTATEDIR, ctl->def->name); + virBufferAsprintf(&buf, " \"@{run}/libvirt/**/%s.pid\" rwk,\n", + ctl->def->name); + virBufferAsprintf(&buf, " \"@{run}/libvirt/**/*.tunnelmigrate.dest.%s\" rw,\n", + ctl->def->name); } if (ctl->files) virBufferAdd(&buf, ctl->files, -1); -- 2.45.3