Comment 0 for bug 1772097

Revision history for this message
Jamie Strandboge (jdstrand) wrote :

Qt 5.10 recently (https://github.com/qt/qtbase/commit/189e9c93d7ed42202ad51507c8944d64e9a7888d) started using something akin to the following for creating temp files:

fd = open("/tmp", O_RDWR | O_DIRECTORY | O_CLOEXEC | O_TMPFILE)
write(fd, "...")
linkat(AT_FDCWD, "/proc/self/fd/<fd for O_TMPFILE>", AT_FDCWD, "/tmp/...", AT_SYMLINK_FOLLOW)

I diagnosis was provided here: https://forum.snapcraft.io/t/qt-5-10-linkat-denials-broken-kde-snaps/5484/10

Attached is a simple reproducer that demonstrates that apparmor works fine with this for unconfined and non-attach_disconnected profiles, but using attach_disconnected breaks the above with denials that cannot be allowed with policy. Eg:

$ tar -zxvf ./linkat.tar.gz
linkat/
linkat/main.c
linkat/test.sh
linkat/profile
linkat/profile_attach_disconnected
linkat/test-no-snap.sh
linkat/test-tmp-linkat_1.0_amd64.snap

$ cd ./linkat
$ ./test-no-snap.sh
= Test unconfined =
Running: aa-exec -p unconfined -- ./tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

Running: aa-exec -p unconfined -- ./tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

= Test confined =
Loading apparmor profile for 'test'

Policy for 'test'
#include <tunables/global>

profile test {
  #include <abstractions/base>

  /tmp/{#,okular}* rwl,
  @{HOME}/snap/test-tmp-linkat/common/{#,okular}* rwl,
}

Running: aa-exec -p test -- ./tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

Running: aa-exec -p test -- ./tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

= Test confined with attach_disconnected =
Loading apparmor profile for 'test_atch_disconnected'

Policy for 'test_attach_disconnected'
#include <tunables/global>

profile test_attach_disconnected (attach_disconnected) {
  #include <abstractions/base>

  /tmp/{#,okular}* rwl,
  @{HOME}/snap/test-tmp-linkat/common/{#,okular}* rwl,
}

Running: aa-exec -p test_attach_disconnected -- ./tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

Running: aa-exec -p test_attach_disconnected -- ./tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

FAIL: some tests failed
[1]

The failing test shows this in the logs:
May 18 13:53:29 localhost audit[20542]: AVC apparmor="DENIED" operation="link" info="Failed name lookup - deleted entry" error=-2 profile="test_attach_disconnected" name="/tmp/#132105" pid=20542 comm="tmp-linkat" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000
May 18 13:53:29 localhost audit[20542]: AVC apparmor="DENIED" operation="link" profile="test_attach_disconnected" name="/tmp/okular_DHqFKd.ps" pid=20542 comm="tmp-linkat" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000 target="/tmp/#132105"
May 18 13:53:29 localhost audit[20543]: AVC apparmor="DENIED" operation="link" info="Failed name lookup - deleted entry" error=-2 profile="test_attach_disconnected" name="/home/jamie/snap/test-tmp-linkat/common/#12871268" pid=20543 comm="tmp-linkat" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000
May 18 13:53:29 localhost audit[20543]: AVC apparmor="DENIED" operation="link" profile="test_attach_disconnected" name="/home/jamie/snap/test-tmp-linkat/common/okular_DHqFKd.ps" pid=20543 comm="tmp-linkat" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000 target="/home/jamie/snap/test-tmp-linkat/common/#12871268"

Unfortunately, this breaks snaps using Qt 5.10 as there is no workaround (attach_disconnected is required due to how the snap's mountspace is setup). Eg:

$ ./test.sh
= Test strict mode snap (per-snap mount namespace with strict) =
test-tmp-linkat 1.0 installed

Grepping for relevant policy:
@{SNAP_NAME}="test-tmp-linkat"
profile "snap.test-tmp-linkat.test-tmp-linkat" (attach_disconnected) {
  owner @{HOME}/snap/@{SNAP_NAME}/common/** wl,
  /var/snap/@{SNAP_NAME}/common/** wl,
  /tmp/** mrwlkix,

Running: test-tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

Running: test-tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

= Test devmode mode snap (per-snap mount namespace with complain) =
test-tmp-linkat 1.0 installed

Grepping for relevant policy:
@{SNAP_NAME}="test-tmp-linkat"
profile "snap.test-tmp-linkat.test-tmp-linkat" (attach_disconnected,complain) {
  owner @{HOME}/snap/@{SNAP_NAME}/common/** wl,
  /var/snap/@{SNAP_NAME}/common/** wl,
  /tmp/** mrwlkix,

Running: test-tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

Running: test-tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

= Test class mode snap (global mount namespace loose with complain) =
test-tmp-linkat 1.0 installed

Grepping for relevant policy:
@{SNAP_NAME}="test-tmp-linkat"
profile "snap.test-tmp-linkat.test-tmp-linkat" (attach_disconnected,complain) {
  /** rwlkm,

Running: test-tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

Running: test-tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

= Test unconfined =
Running: aa-exec -p unconfined -- /snap/test-tmp-linkat/current/bin/tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

Running: aa-exec -p unconfined -- /snap/test-tmp-linkat/current/bin/tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

= Test confined outside of snap =
Loading apparmor profile for 'test'

Policy for 'test'
#include <tunables/global>

profile test {
  #include <abstractions/base>

  /tmp/{#,okular}* rwl,
  @{HOME}/snap/test-tmp-linkat/common/{#,okular}* rwl,
}

Running: aa-exec -p test -- /snap/test-tmp-linkat/current/bin/tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

Running: aa-exec -p test -- /snap/test-tmp-linkat/current/bin/tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success

= Test confined outside of snap with attach_disconnected =
Loading apparmor profile for 'test_atch_disconnected'

Policy for 'test_attach_disconnected'
#include <tunables/global>

profile test_attach_disconnected (attach_disconnected) {
  #include <abstractions/base>

  /tmp/{#,okular}* rwl,
  @{HOME}/snap/test-tmp-linkat/common/{#,okular}* rwl,
}

Running: aa-exec -p test_attach_disconnected -- /snap/test-tmp-linkat/current/bin/tmp-linkat /tmp
prefix: /tmp
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

Running: aa-exec -p test_attach_disconnected -- /snap/test-tmp-linkat/current/bin/tmp-linkat /home/jamie/snap/test-tmp-linkat/common/
prefix: /home/jamie/snap/test-tmp-linkat/common/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL

FAIL: some tests failed
[1]

The reduced test case (ie, test-no-snap.sh) was confirmed to have this bug on:
* Linux version 4.16.0-1-amd64 (<email address hidden>) (gcc version 7.3.0 (Debian 7.3.0-17)) #1 SMP Debian 4.16.5-1 (2018-04-29)
* Ubuntu 4.15.0-20.21-generic 4.15.17
* Ubuntu 4.13.0-41.46-generic 4.13.16
* Ubuntu 4.4.0-121.145-generic 4.4.117
* Ubuntu 3.13.0-147.196-generic 3.13.11-ckt39

Ubuntu 12.04 kernel does not support O_TMPFILE (it is 3.2 and O_TMPFILE was added in 3.11).