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:
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
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
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
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'
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).
Qt 5.10 recently (https:/ /github. com/qt/ qtbase/ commit/ 189e9c93d7ed422 02ad51507c8944d 64e9a7888d) 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 profile_ attach_ disconnected test-no- snap.sh test-tmp- linkat_ 1.0_amd64. snap
linkat/
linkat/main.c
linkat/test.sh
linkat/profile
linkat/
linkat/
linkat/
$ 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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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, /snap/test- tmp-linkat/ common/ {#,okular} * rwl,
@{HOME}
}
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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success
= Test confined with attach_disconnected = disconnected'
Loading apparmor profile for 'test_atch_
Policy for 'test_attach_ disconnected'
#include <tunables/global>
profile test_attach_ disconnected (attach_ disconnected) {
#include <abstractions/base>
/tmp/{#,okular}* rwl, /snap/test- tmp-linkat/ common/ {#,okular} * rwl,
@{HOME}
}
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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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: "test_attach_ disconnected" name="/tmp/#132105" pid=20542 comm="tmp-linkat" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000 "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" "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 "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"
May 18 13:53:29 localhost audit[20542]: AVC apparmor="DENIED" operation="link" info="Failed name lookup - deleted entry" error=-2 profile=
May 18 13:53:29 localhost audit[20542]: AVC apparmor="DENIED" operation="link" profile=
May 18 13:53:29 localhost audit[20543]: AVC apparmor="DENIED" operation="link" info="Failed name lookup - deleted entry" error=-2 profile=
May 18 13:53:29 localhost audit[20543]: AVC apparmor="DENIED" operation="link" profile=
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: NAME}=" test-tmp- linkat" tmp-linkat. test-tmp- linkat" (attach_ disconnected) { /snap/@ {SNAP_NAME} /common/ ** wl, snap/@{ SNAP_NAME} /common/ ** wl,
@{SNAP_
profile "snap.test-
owner @{HOME}
/var/
/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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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: NAME}=" test-tmp- linkat" tmp-linkat. test-tmp- linkat" (attach_ disconnected, complain) { /snap/@ {SNAP_NAME} /common/ ** wl, snap/@{ SNAP_NAME} /common/ ** wl,
@{SNAP_
profile "snap.test-
owner @{HOME}
/var/
/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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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: NAME}=" test-tmp- linkat" tmp-linkat. test-tmp- linkat" (attach_ disconnected, complain) {
@{SNAP_
profile "snap.test-
/** 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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat failed: No such file or directory
FAIL
= Test unconfined = tmp-linkat/ current/ bin/tmp- linkat /tmp
Running: aa-exec -p unconfined -- /snap/test-
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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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, /snap/test- tmp-linkat/ common/ {#,okular} * rwl,
@{HOME}
}
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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
opened fd: 3 [/proc/self/fd/3]
writing works
linkat success
= Test confined outside of snap with attach_disconnected = disconnected'
Loading apparmor profile for 'test_atch_
Policy for 'test_attach_ disconnected'
#include <tunables/global>
profile test_attach_ disconnected (attach_ disconnected) {
#include <abstractions/base>
/tmp/{#,okular}* rwl, /snap/test- tmp-linkat/ common/ {#,okular} * rwl,
@{HOME}
}
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/ snap/test- tmp-linkat/ common/
prefix: /home/jamie/
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: 20.21-generic 4.15.17 41.46-generic 4.13.16 145-generic 4.4.117 147.196- generic 3.13.11-ckt39
* 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-
* Ubuntu 4.13.0-
* Ubuntu 4.4.0-121.
* Ubuntu 3.13.0-
Ubuntu 12.04 kernel does not support O_TMPFILE (it is 3.2 and O_TMPFILE was added in 3.11).