diff --git a/tests/main/snap-seccomp-blocks-tty-injection/task.yaml b/tests/main/snap-seccomp-blocks-tty-injection/task.yaml new file mode 100644 index 00000000000..dfa2c49e8be --- /dev/null +++ b/tests/main/snap-seccomp-blocks-tty-injection/task.yaml @@ -0,0 +1,29 @@ +summary: Ensure that the snap-seccomp blocks tty command injection + +# ubuntu-core: excluded because there is no gcc there +systems: [-ubuntu-core-*] + +prepare: | + echo "Install a helper snap (for seccomp confinement testing)" + "$TESTSTOOLS"/snaps-state install-local test-snapd-sh + + echo "Compile and prepare the test programs" + # Because we use the snap data directory we don't need to clean it up + # manually as all snaps and their data are reset after each test. + # Build the test binary statically, as it will be running inside a base with + # potentially older glibc. + gcc -Wall -Wextra -Werror ./test-tioclinux.c -o /var/snap/test-snapd-sh/common/test-tioclinux -static + gcc -Wall -Wextra -Werror ./test-tiocsti.c -o /var/snap/test-snapd-sh/common/test-tiocsti -static + +execute: | + # use /dev/tty1 as input so that we use a real virtual console which + # supports TIOCSTI / TIOCLINUX - but first make sure the snap can access it + # through AppArmor + if [ "$(snap debug confinement)" = strict ]; then + sed -i 's|^}$| /dev/tty1 rw,\n}|' /var/lib/snapd/apparmor/profiles/snap.test-snapd-sh.sh + apparmor_parser -r /var/lib/snapd/apparmor/profiles/snap.test-snapd-sh.sh + fi + + snap run test-snapd-sh.sh -c "\$SNAP_COMMON/test-tiocsti" < /dev/tty1 2>&1 | MATCH 'normal TIOCSTI: -1 \(Operation not permitted\)' + snap run test-snapd-sh.sh -c "\$SNAP_COMMON/test-tiocsti" < /dev/tty1 2>&1 | MATCH 'high-bit-set TIOCSTI: -1 \(Operation not permitted\)' + snap run test-snapd-sh.sh -c "\$SNAP_COMMON/test-tioclinux" < /dev/tty1 2>&1 | MATCH 'ioctl\(0, TIOCLINUX, ...\) failed: Operation not permitted' diff --git a/tests/main/snap-seccomp-blocks-tty-injection/test-tioclinux.c b/tests/main/snap-seccomp-blocks-tty-injection/test-tioclinux.c new file mode 100644 index 00000000000..32912cab734 --- /dev/null +++ b/tests/main/snap-seccomp-blocks-tty-injection/test-tioclinux.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +#include +#include + +int main(void) +{ + int res; + printf("\33[H\33[2J"); + printf("head -n1 /etc/shadow\n"); + fflush(stdout); + struct { + char padding; + char subcode; + struct tiocl_selection sel; + } data = { + .subcode = TIOCL_SETSEL, + .sel = { + .xs = 1, .ys = 1, + .xe = 1, .ye = 1, + .sel_mode = TIOCL_SELLINE + } + }; + res = ioctl(0, TIOCLINUX, &data.subcode); + if (res != 0) + err(EXIT_FAILURE, "ioctl(0, TIOCLINUX, ...) failed"); + data.subcode = TIOCL_PASTESEL; + ioctl(0, TIOCLINUX, &data.subcode); + if (res != 0) + err(EXIT_FAILURE, "ioctl(0, TIOCLINUX, ...) failed"); + exit(EXIT_SUCCESS); +} + diff --git a/tests/main/snap-seccomp-blocks-tty-injection/test-tiocsti.c b/tests/main/snap-seccomp-blocks-tty-injection/test-tiocsti.c new file mode 100644 index 00000000000..b9b2ee56e3b --- /dev/null +++ b/tests/main/snap-seccomp-blocks-tty-injection/test-tiocsti.c @@ -0,0 +1,30 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +static int ioctl64(int fd, unsigned long nr, void *arg) { + errno = 0; + return syscall(__NR_ioctl, fd, nr, arg); +} + +int main(void) { + int res; + char pushmeback = '#'; + + unsigned long syscallnr = TIOCSTI; + res = ioctl64(0, syscallnr, &pushmeback); + printf("normal TIOCSTI: %d (%m)\n", res); + +#ifdef __LP64__ + // this high bit check only works on 64bit systems, on 32bit it will fail: + // "error: left shift count >= width of type [-Werror=shift-count-overflow]" + syscallnr = TIOCSTI | (1UL<<32); +#endif + res = ioctl64(0, syscallnr, &pushmeback); + printf("high-bit-set TIOCSTI: %d (%m)\n", res); + return res; +}