summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2021-07-03 00:55:02 +0200
committerDmitry V. Levin <ldv@strace.io>2021-07-16 18:57:21 +0000
commit7592a0eeab2588162c1741077053f8a052c8418f (patch)
tree630269c633e97514ecc09e0f5f87f7ed5fd9ff5c
parentf001287e0c4b30adf2cfaaecab43908d5dee2b68 (diff)
downloadstrace-7592a0eeab2588162c1741077053f8a052c8418f.tar.gz
Implement landlock_{add_rule,create_ruleset,restrict_self} syscall decoding
Introduced by Linux commit v5.13-rc1~71^2~4. * bundled/linux/include/uapi/linux/landlock.h: New file, copied from headers_install'ed Linux kernel v5.13. * bundled/Makefile.am (EXTRA_DIST): Add it. * src/Makefile.am (libstrace_a_SOURCES): Add landlock.c. * src/landlock.c: New file. * src/linux/generic/syscallent-common.h([BASE_NR + 444], [BASE_NR + 445], [BASE_NR + 446]): New entries, for landlock_create_ruleset, landlock_add_rule, and landlock_restrict_self, respectively. * src/pathtrace.c (pathtrace_match_set): Handle SEN_landlock_add_rule, SEN_landlock_create_ruleset, and SEN_landlock_restrict_self. * src/xlat/landlock_create_ruleset_flags.in: New xlat. * src/xlat/landlock_rule_types.in: Likewise. * src/xlat/landlock_ruleset_access_fs.in: Likewise. * tests/Makefile.am (check_PROGRAMS): Add landlock_create_ruleset-success and landlock_create_ruleset-success-y. (DECODER_TESTS): Add landlock_create_ruleset-success.test. * tests/gen_tests.in (landlock_add_rule, landlock_add_rule-y, landlock_create_ruleset, landlock_create_ruleset-success-y, landlock_create_ruleset-y, landlock_restrict_self, landlock_restrict_self-y): New tests. * tests/landlock_add_rule.c: New file. * tests/landlock_add_rule-y.c: Likewise. * tests/landlock_create_ruleset-success.c: Likewise. * tests/landlock_create_ruleset-success-y.c: Likewise. * tests/landlock_create_ruleset.c: Likewise. * tests/landlock_create_ruleset-y.c: Likewise. * tests/landlock_restrict_self.c: Likewise. * tests/landlock_restrict_self-y.c: Likewise. * tests/landlock_create_ruleset-success.test: New test. * tests/pure_executables.list: Add landlock_add_rule, landlock_add_rule-y, landlock_create_ruleset, landlock_create_ruleset-y, landlock_restrict_self, and landlock_restrict_self-y. * tests/.gitignore: Add landlock_add_rule, landlock_add_rule-y, landlock_create_ruleset, landlock_create_ruleset-success, landlock_create_ruleset-success-y, landlock_create_ruleset-y, landlock_restrict_self, and landlock_restrict_self-y. * NEWS: Mention it. Co-authored-by: Dmitry V. Levin <ldv@strace.io>
-rw-r--r--NEWS2
-rw-r--r--bundled/Makefile.am1
-rw-r--r--bundled/linux/include/uapi/linux/landlock.h137
-rw-r--r--src/Makefile.am1
-rw-r--r--src/landlock.c124
-rw-r--r--src/linux/generic/syscallent-common.h4
-rw-r--r--src/pathtrace.c3
-rw-r--r--src/xlat/landlock_create_ruleset_flags.in2
-rw-r--r--src/xlat/landlock_rule_types.in3
-rw-r--r--src/xlat/landlock_ruleset_access_fs.in14
-rw-r--r--tests/.gitignore8
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/gen_tests.in7
-rw-r--r--tests/landlock_add_rule-y.c7
-rw-r--r--tests/landlock_add_rule.c132
-rw-r--r--tests/landlock_create_ruleset-success-y.c4
-rw-r--r--tests/landlock_create_ruleset-success.c2
-rwxr-xr-xtests/landlock_create_ruleset-success.test13
-rw-r--r--tests/landlock_create_ruleset-y.c4
-rw-r--r--tests/landlock_create_ruleset.c140
-rw-r--r--tests/landlock_restrict_self-y.c4
-rw-r--r--tests/landlock_restrict_self.c83
-rwxr-xr-xtests/pure_executables.list6
23 files changed, 704 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 8050523fc..3c38fe7bd 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@ Noteworthy changes in release ?.?? (????-??-??)
PTRACE_SETREGS, PTRACE_SETREGS64, PTRACE_GETFPREGS, and PTRACE_SETFPREGS
requests.
* Implemented powerpc System Call Vectored ABI support.
+ * Implemented decoding of landlock_add_rule, landlock_create_ruleset,
+ and landlock_restrict_self syscalls introduced in Linux 5.13.
* Enhanced decoding of perf_event_open syscall.
* Updated lists of BPF_*, IORING_*, KEXEC_*, KEY_*, KVM_*, NT_*, PR_*,
PTRACE_*, RTM_*, RTPROT_*, TRAP_*, UFFD_*, UFFDIO_*, and V4L2_* constants.
diff --git a/bundled/Makefile.am b/bundled/Makefile.am
index f0fd8711b..fcb712081 100644
--- a/bundled/Makefile.am
+++ b/bundled/Makefile.am
@@ -54,6 +54,7 @@ EXTRA_DIST = \
linux/include/uapi/linux/kcmp.h \
linux/include/uapi/linux/kexec.h \
linux/include/uapi/linux/keyctl.h \
+ linux/include/uapi/linux/landlock.h \
linux/include/uapi/linux/libc-compat.h \
linux/include/uapi/linux/loop.h \
linux/include/uapi/linux/memfd.h \
diff --git a/bundled/linux/include/uapi/linux/landlock.h b/bundled/linux/include/uapi/linux/landlock.h
new file mode 100644
index 000000000..bebb42928
--- /dev/null
+++ b/bundled/linux/include/uapi/linux/landlock.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Landlock - User space API
+ *
+ * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
+ * Copyright © 2018-2020 ANSSI
+ */
+
+#ifndef _LINUX_LANDLOCK_H
+#define _LINUX_LANDLOCK_H
+
+#include <linux/types.h>
+
+/**
+ * struct landlock_ruleset_attr - Ruleset definition
+ *
+ * Argument of sys_landlock_create_ruleset(). This structure can grow in
+ * future versions.
+ */
+struct landlock_ruleset_attr {
+ /**
+ * @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_)
+ * that is handled by this ruleset and should then be forbidden if no
+ * rule explicitly allow them. This is needed for backward
+ * compatibility reasons.
+ */
+ __u64 handled_access_fs;
+};
+
+/*
+ * sys_landlock_create_ruleset() flags:
+ *
+ * - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI
+ * version.
+ */
+#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
+
+/**
+ * enum landlock_rule_type - Landlock rule type
+ *
+ * Argument of sys_landlock_add_rule().
+ */
+enum landlock_rule_type {
+ /**
+ * @LANDLOCK_RULE_PATH_BENEATH: Type of a &struct
+ * landlock_path_beneath_attr .
+ */
+ LANDLOCK_RULE_PATH_BENEATH = 1,
+};
+
+/**
+ * struct landlock_path_beneath_attr - Path hierarchy definition
+ *
+ * Argument of sys_landlock_add_rule().
+ */
+struct landlock_path_beneath_attr {
+ /**
+ * @allowed_access: Bitmask of allowed actions for this file hierarchy
+ * (cf. `Filesystem flags`_).
+ */
+ __u64 allowed_access;
+ /**
+ * @parent_fd: File descriptor, open with ``O_PATH``, which identifies
+ * the parent directory of a file hierarchy, or just a file.
+ */
+ __s32 parent_fd;
+ /*
+ * This struct is packed to avoid trailing reserved members.
+ * Cf. security/landlock/syscalls.c:build_check_abi()
+ */
+} __attribute__((packed));
+
+/**
+ * DOC: fs_access
+ *
+ * A set of actions on kernel objects may be defined by an attribute (e.g.
+ * &struct landlock_path_beneath_attr) including a bitmask of access.
+ *
+ * Filesystem flags
+ * ~~~~~~~~~~~~~~~~
+ *
+ * These flags enable to restrict a sandboxed process to a set of actions on
+ * files and directories. Files or directories opened before the sandboxing
+ * are not subject to these restrictions.
+ *
+ * A file can only receive these access rights:
+ *
+ * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file.
+ * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access.
+ * - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access.
+ *
+ * A directory can receive access rights related to files or directories. The
+ * following access right is applied to the directory itself, and the
+ * directories beneath it:
+ *
+ * - %LANDLOCK_ACCESS_FS_READ_DIR: Open a directory or list its content.
+ *
+ * However, the following access rights only apply to the content of a
+ * directory, not the directory itself:
+ *
+ * - %LANDLOCK_ACCESS_FS_REMOVE_DIR: Remove an empty directory or rename one.
+ * - %LANDLOCK_ACCESS_FS_REMOVE_FILE: Unlink (or rename) a file.
+ * - %LANDLOCK_ACCESS_FS_MAKE_CHAR: Create (or rename or link) a character
+ * device.
+ * - %LANDLOCK_ACCESS_FS_MAKE_DIR: Create (or rename) a directory.
+ * - %LANDLOCK_ACCESS_FS_MAKE_REG: Create (or rename or link) a regular file.
+ * - %LANDLOCK_ACCESS_FS_MAKE_SOCK: Create (or rename or link) a UNIX domain
+ * socket.
+ * - %LANDLOCK_ACCESS_FS_MAKE_FIFO: Create (or rename or link) a named pipe.
+ * - %LANDLOCK_ACCESS_FS_MAKE_BLOCK: Create (or rename or link) a block device.
+ * - %LANDLOCK_ACCESS_FS_MAKE_SYM: Create (or rename or link) a symbolic link.
+ *
+ * .. warning::
+ *
+ * It is currently not possible to restrict some file-related actions
+ * accessible through these syscall families: :manpage:`chdir(2)`,
+ * :manpage:`truncate(2)`, :manpage:`stat(2)`, :manpage:`flock(2)`,
+ * :manpage:`chmod(2)`, :manpage:`chown(2)`, :manpage:`setxattr(2)`,
+ * :manpage:`utime(2)`, :manpage:`ioctl(2)`, :manpage:`fcntl(2)`,
+ * :manpage:`access(2)`.
+ * Future Landlock evolutions will enable to restrict them.
+ */
+#define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
+#define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)
+#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
+#define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3)
+#define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4)
+#define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5)
+#define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6)
+#define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7)
+#define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8)
+#define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9)
+#define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)
+#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
+#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
+
+#endif /* _LINUX_LANDLOCK_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 02fa00a6d..4699aae5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -168,6 +168,7 @@ libstrace_a_SOURCES = \
keyctl_kdf_params.h \
kill_save_errno.h \
kvm.c \
+ landlock.c \
largefile_wrappers.h \
ldt.c \
link.c \
diff --git a/src/landlock.c b/src/landlock.c
new file mode 100644
index 000000000..561b603fb
--- /dev/null
+++ b/src/landlock.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <linux/landlock.h>
+
+#include "xlat/landlock_create_ruleset_flags.h"
+#include "xlat/landlock_rule_types.h"
+#include "xlat/landlock_ruleset_access_fs.h"
+
+static void
+print_landlock_ruleset_attr(struct tcb *tcp, const kernel_ulong_t addr,
+ const kernel_ulong_t size)
+{
+ struct {
+ uint64_t handled_access_fs;
+ } attr;
+
+ if (size < offsetofend(typeof(attr), handled_access_fs)) {
+ printaddr(addr);
+ return;
+ }
+
+ if (umoven_or_printaddr(tcp, addr, MIN(size, sizeof(attr)), &attr))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_FLAGS(attr, handled_access_fs, landlock_ruleset_access_fs,
+ "LANDLOCK_ACCESS_FS_???");
+
+ if (size > offsetofend(typeof(attr), handled_access_fs)) {
+ tprint_arg_next();
+ tprint_more_data_follows();
+ }
+
+ tprint_struct_end();
+}
+
+SYS_FUNC(landlock_create_ruleset)
+{
+ kernel_ulong_t attr = tcp->u_arg[0];
+ kernel_ulong_t size = tcp->u_arg[1];
+ unsigned int flags = tcp->u_arg[2];
+ int fd_flag = flags & LANDLOCK_CREATE_RULESET_VERSION ? 0 : RVAL_FD;
+
+ /* attr */
+ print_landlock_ruleset_attr(tcp, attr, size);
+ tprint_arg_next();
+
+ /* size */
+ PRINT_VAL_U(size);
+ tprint_arg_next();
+
+ /* flags */
+ printflags(landlock_create_ruleset_flags, flags,
+ "LANDLOCK_CREATE_RULESET_???");
+
+ return RVAL_DECODED | fd_flag;
+}
+
+static void
+print_landlock_path_beneath_attr(struct tcb *tcp, const kernel_ulong_t addr)
+{
+ struct {
+ uint64_t allowed_access;
+ int32_t parent_fd;
+ } ATTRIBUTE_PACKED attr;
+
+ if (umove_or_printaddr(tcp, addr, &attr))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_FLAGS(attr, allowed_access, landlock_ruleset_access_fs,
+ "LANDLOCK_ACCESS_FS_???");
+ tprint_struct_next();
+ PRINT_FIELD_FD(attr, parent_fd, tcp);
+ tprint_struct_end();
+}
+
+SYS_FUNC(landlock_add_rule)
+{
+ unsigned int rule_type = tcp->u_arg[1];
+
+ /* ruleset_fd */
+ printfd(tcp, tcp->u_arg[0]);
+ tprint_arg_next();
+
+ /* rule_type */
+ printxval(landlock_rule_types, rule_type, "LANDLOCK_RULE_???");
+ tprint_arg_next();
+
+ /* rule_attr */
+ switch (rule_type) {
+ case LANDLOCK_RULE_PATH_BENEATH:
+ print_landlock_path_beneath_attr(tcp, tcp->u_arg[2]);
+ break;
+
+ default:
+ printaddr(tcp->u_arg[2]);
+ }
+ tprint_arg_next();
+
+ /* flags */
+ PRINT_VAL_X((unsigned int) tcp->u_arg[3]);
+
+ return RVAL_DECODED;
+}
+
+SYS_FUNC(landlock_restrict_self)
+{
+ /* ruleset_fd */
+ printfd(tcp, tcp->u_arg[0]);
+ tprint_arg_next();
+
+ /* flags */
+ PRINT_VAL_X((unsigned int) tcp->u_arg[1]);
+
+ return RVAL_DECODED;
+}
diff --git a/src/linux/generic/syscallent-common.h b/src/linux/generic/syscallent-common.h
index 0cc3cf973..b46d418cb 100644
--- a/src/linux/generic/syscallent-common.h
+++ b/src/linux/generic/syscallent-common.h
@@ -27,3 +27,7 @@
[BASE_NR + 440] = { 5, TD, SEN(process_madvise), "process_madvise" },
[BASE_NR + 441] = { 6, TD, SEN(epoll_pwait2), "epoll_pwait2" },
[BASE_NR + 442] = { 5, TD|TF, SEN(mount_setattr), "mount_setattr" },
+/* 443 is reserved for quotactl_fd */
+[BASE_NR + 444] = { 3, TD, SEN(landlock_create_ruleset), "landlock_create_ruleset" },
+[BASE_NR + 445] = { 4, TD, SEN(landlock_add_rule), "landlock_add_rule" },
+[BASE_NR + 446] = { 2, TD, SEN(landlock_restrict_self), "landlock_restrict_self" },
diff --git a/src/pathtrace.c b/src/pathtrace.c
index 2c24ced8b..7f98dcbdb 100644
--- a/src/pathtrace.c
+++ b/src/pathtrace.c
@@ -372,6 +372,9 @@ pathtrace_match_set(struct tcb *tcp, struct path_set *set)
case SEN_io_uring_enter:
case SEN_io_uring_register:
case SEN_io_uring_setup:
+ case SEN_landlock_add_rule:
+ case SEN_landlock_create_ruleset:
+ case SEN_landlock_restrict_self:
case SEN_memfd_create:
case SEN_mq_getsetattr:
case SEN_mq_notify:
diff --git a/src/xlat/landlock_create_ruleset_flags.in b/src/xlat/landlock_create_ruleset_flags.in
new file mode 100644
index 000000000..2e7053c9a
--- /dev/null
+++ b/src/xlat/landlock_create_ruleset_flags.in
@@ -0,0 +1,2 @@
+#unconditional
+LANDLOCK_CREATE_RULESET_VERSION
diff --git a/src/xlat/landlock_rule_types.in b/src/xlat/landlock_rule_types.in
new file mode 100644
index 000000000..eaccb6de3
--- /dev/null
+++ b/src/xlat/landlock_rule_types.in
@@ -0,0 +1,3 @@
+#unconditional
+#value_indexed
+LANDLOCK_RULE_PATH_BENEATH
diff --git a/src/xlat/landlock_ruleset_access_fs.in b/src/xlat/landlock_ruleset_access_fs.in
new file mode 100644
index 000000000..c0251f416
--- /dev/null
+++ b/src/xlat/landlock_ruleset_access_fs.in
@@ -0,0 +1,14 @@
+#unconditional
+LANDLOCK_ACCESS_FS_EXECUTE
+LANDLOCK_ACCESS_FS_WRITE_FILE
+LANDLOCK_ACCESS_FS_READ_FILE
+LANDLOCK_ACCESS_FS_READ_DIR
+LANDLOCK_ACCESS_FS_REMOVE_DIR
+LANDLOCK_ACCESS_FS_REMOVE_FILE
+LANDLOCK_ACCESS_FS_MAKE_CHAR
+LANDLOCK_ACCESS_FS_MAKE_DIR
+LANDLOCK_ACCESS_FS_MAKE_REG
+LANDLOCK_ACCESS_FS_MAKE_SOCK
+LANDLOCK_ACCESS_FS_MAKE_FIFO
+LANDLOCK_ACCESS_FS_MAKE_BLOCK
+LANDLOCK_ACCESS_FS_MAKE_SYM
diff --git a/tests/.gitignore b/tests/.gitignore
index 8f2472b64..047b2d930 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -383,6 +383,14 @@ kill--pidns-translation
kill_child
ksysent
ksysent.h
+landlock_add_rule
+landlock_add_rule-y
+landlock_create_ruleset
+landlock_create_ruleset-success
+landlock_create_ruleset-success-y
+landlock_create_ruleset-y
+landlock_restrict_self
+landlock_restrict_self-y
lchown
lchown32
libtests.a
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 126e84361..5493f6223 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -205,6 +205,8 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
kill--pidns-translation \
kill_child \
ksysent \
+ landlock_create_ruleset-success \
+ landlock_create_ruleset-success-y \
list_sigaction_signum \
localtime \
looping_threads \
@@ -401,6 +403,7 @@ DECODER_TESTS = \
ioctl_evdev-success.test \
ipc_msgbuf.test \
kern_features-fault.test \
+ landlock_create_ruleset-success.test \
llseek.test \
lseek.test \
mmap.test \
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 747383368..017d33c70 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -370,6 +370,13 @@ keyctl-Xverbose -a41 -s10 -e trace=keyctl -Xverbose
kill -a12 -esignal=none
kill--pidns-translation test_pidns -a12 -e trace=kill -esignal=none
ksysent ../$NAME
+landlock_add_rule -a57
+landlock_add_rule-y -a57 -y -e trace=landlock_add_rule </dev/null 7>/dev/zero 8>/dev/full
+landlock_create_ruleset -a36
+landlock_create_ruleset-success-y +landlock_create_ruleset-success.test -y
+landlock_create_ruleset-y -a36 -y -e trace=landlock_create_ruleset
+landlock_restrict_self -a29
+landlock_restrict_self-y -a29 -y -e trace=landlock_restrict_self 7>/dev/full
lchown -a30
lchown32 -a32
link
diff --git a/tests/landlock_add_rule-y.c b/tests/landlock_add_rule-y.c
new file mode 100644
index 000000000..3f4f671f6
--- /dev/null
+++ b/tests/landlock_add_rule-y.c
@@ -0,0 +1,7 @@
+#define FD0_STR "</dev/null>"
+#define RULESET_FD 7
+#define RULESET_FD_STR "7</dev/zero>"
+#define PARENT_FD 8
+#define PARENT_FD_STR "8</dev/full>"
+
+#include "landlock_add_rule.c"
diff --git a/tests/landlock_add_rule.c b/tests/landlock_add_rule.c
new file mode 100644
index 000000000..d788929d8
--- /dev/null
+++ b/tests/landlock_add_rule.c
@@ -0,0 +1,132 @@
+/*
+ * Check decoding of landlock_add_rule syscall.
+ *
+ * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+#include "scno.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <linux/landlock.h>
+
+#ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+# define SKIP_IF_PROC_IS_UNAVAILABLE
+#endif
+
+#ifndef FD0_STR
+# define FD0_STR ""
+#endif
+#ifndef RULESET_FD
+# define RULESET_FD -1
+#endif
+#ifndef RULESET_FD_STR
+# define RULESET_FD_STR "-1"
+#endif
+#ifndef PARENT_FD
+# define PARENT_FD -1
+#endif
+#ifndef PARENT_FD_STR
+# define PARENT_FD_STR "-1"
+#endif
+
+static const char *errstr;
+
+static long
+sys_landlock_add_rule(int ruleset_fd, unsigned int rule_type, void *rule_attr,
+ unsigned int flags)
+{
+ static const kernel_ulong_t fill =
+ (kernel_ulong_t) 0xd1efaced00000000ULL;
+ kernel_ulong_t arg1 = fill | (unsigned int) ruleset_fd;
+ kernel_ulong_t arg2 = fill | rule_type;
+ kernel_ulong_t arg3 = (uintptr_t) rule_attr;
+ kernel_ulong_t arg4 = fill | flags;
+ kernel_ulong_t arg5 = fill | 0xdecaffed;
+ kernel_ulong_t arg6 = fill | 0xdeefaced;
+
+ long rc = syscall(__NR_landlock_add_rule,
+ arg1, arg2, arg3, arg4, arg5, arg6);
+ errstr = sprintrc(rc);
+ return rc;
+}
+
+int
+main(void)
+{
+ SKIP_IF_PROC_IS_UNAVAILABLE;
+
+ TAIL_ALLOC_OBJECT_VAR_PTR(struct landlock_path_beneath_attr, attr);
+
+ /* All zeroes */
+ sys_landlock_add_rule(0, 0, NULL, 0);
+ printf("landlock_add_rule(0" FD0_STR ", 0 /* LANDLOCK_RULE_??? */"
+ ", NULL, 0) = %s\n", errstr);
+
+ /* Bogus values */
+ sys_landlock_add_rule(0xdeadc0de, 0xfacebeef, attr + 1, 1);
+ printf("landlock_add_rule(-559038242"
+ ", 0xfacebeef /* LANDLOCK_RULE_??? */, %p, 0x1) = %s\n",
+ attr + 1, errstr);
+
+ sys_landlock_add_rule(1729, 2, attr + 1, 0xffffffff);
+ printf("landlock_add_rule(1729, 0x2 /* LANDLOCK_RULE_??? */, %p"
+ ", 0xffffffff) = %s\n",
+ attr + 1, errstr);
+
+ /* Invalid pointer */
+ sys_landlock_add_rule(RULESET_FD, LANDLOCK_RULE_PATH_BENEATH,
+ attr + 1, 0);
+ printf("landlock_add_rule(" RULESET_FD_STR
+ ", LANDLOCK_RULE_PATH_BENEATH, %p, 0) = %s\n",
+ attr + 1, errstr);
+
+ /* Short read */
+ sys_landlock_add_rule(RULESET_FD, LANDLOCK_RULE_PATH_BENEATH,
+ (char *) attr + 4, 0);
+ printf("landlock_add_rule(" RULESET_FD_STR
+ ", LANDLOCK_RULE_PATH_BENEATH, %p, 0) = %s\n",
+ (char *) attr + 4, errstr);
+
+ /* Valid attr ptr */
+ static const struct {
+ uint64_t val;
+ const char *str;
+ } attr_vals[] = {
+ { ARG_STR(LANDLOCK_ACCESS_FS_EXECUTE) },
+ { ARG_ULL_STR(LANDLOCK_ACCESS_FS_EXECUTE|LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR|LANDLOCK_ACCESS_FS_REMOVE_FILE|LANDLOCK_ACCESS_FS_MAKE_CHAR|LANDLOCK_ACCESS_FS_MAKE_DIR|LANDLOCK_ACCESS_FS_MAKE_SOCK|LANDLOCK_ACCESS_FS_MAKE_FIFO|LANDLOCK_ACCESS_FS_MAKE_BLOCK|LANDLOCK_ACCESS_FS_MAKE_SYM|0xdebeefeddecae000) },
+ { ARG_ULL_STR(0xdebeefeddecae000)
+ " /* LANDLOCK_ACCESS_FS_??? */" },
+ };
+ static const struct {
+ int val;
+ const char *str;
+ } parent_fd_vals[] = {
+ { ARG_STR(-1) },
+ { ARG_STR(11630) },
+ { PARENT_FD, PARENT_FD_STR },
+ };
+ for (size_t i = 0; i < ARRAY_SIZE(attr_vals); i++) {
+ for (size_t j = 0; j < ARRAY_SIZE(parent_fd_vals); j++) {
+ attr->allowed_access = attr_vals[i].val;
+ attr->parent_fd = parent_fd_vals[j].val;
+ sys_landlock_add_rule(RULESET_FD,
+ LANDLOCK_RULE_PATH_BENEATH,
+ attr, 0);
+ printf("landlock_add_rule(" RULESET_FD_STR
+ ", LANDLOCK_RULE_PATH_BENEATH"
+ ", {allowed_access=%s, parent_fd=%s}, 0) = %s\n",
+ attr_vals[i].str, parent_fd_vals[j].str, errstr);
+ }
+ }
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
diff --git a/tests/landlock_create_ruleset-success-y.c b/tests/landlock_create_ruleset-success-y.c
new file mode 100644
index 000000000..839155603
--- /dev/null
+++ b/tests/landlock_create_ruleset-success-y.c
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/null>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "landlock_create_ruleset-success.c"
diff --git a/tests/landlock_create_ruleset-success.c b/tests/landlock_create_ruleset-success.c
new file mode 100644
index 000000000..d9c471ba8
--- /dev/null
+++ b/tests/landlock_create_ruleset-success.c
@@ -0,0 +1,2 @@
+#define RETVAL_INJECTED 1
+#include "landlock_create_ruleset.c"
diff --git a/tests/landlock_create_ruleset-success.test b/tests/landlock_create_ruleset-success.test
new file mode 100755
index 000000000..a2e541212
--- /dev/null
+++ b/tests/landlock_create_ruleset-success.test
@@ -0,0 +1,13 @@
+#!/bin/sh -efu
+#
+# Copyright (c) 2019-2021 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/scno_tampering.sh"
+
+run_strace -a10 "$@" -e trace=landlock_create_ruleset \
+ -e inject=landlock_create_ruleset:retval=7 \
+ "../$NAME" > "$EXP" 7> /dev/null
+match_diff "$LOG" "$EXP"
diff --git a/tests/landlock_create_ruleset-y.c b/tests/landlock_create_ruleset-y.c
new file mode 100644
index 000000000..a30966b09
--- /dev/null
+++ b/tests/landlock_create_ruleset-y.c
@@ -0,0 +1,4 @@
+#define FD_PATH "<anon_inode:landlock-ruleset>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "landlock_create_ruleset.c"
diff --git a/tests/landlock_create_ruleset.c b/tests/landlock_create_ruleset.c
new file mode 100644
index 000000000..bc1bcc2cf
--- /dev/null
+++ b/tests/landlock_create_ruleset.c
@@ -0,0 +1,140 @@
+/*
+ * Check decoding of landlock_create_ruleset syscall.
+ *
+ * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+#include "scno.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <linux/landlock.h>
+
+#ifndef RETVAL_INJECTED
+# define RETVAL_INJECTED 0
+#endif
+
+#ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+# define SKIP_IF_PROC_IS_UNAVAILABLE
+#endif
+#ifndef FD_PATH
+# define FD_PATH ""
+#endif
+
+#if RETVAL_INJECTED
+# define INJ_STR " (INJECTED)\n"
+# define INJ_FD_STR FD_PATH " (INJECTED)\n"
+#else /* !RETVAL_INJECTED */
+# define INJ_STR "\n"
+# define INJ_FD_STR "\n"
+#endif /* RETVAL_INJECTED */
+
+static const char *errstr;
+
+static long
+sys_landlock_create_ruleset(struct landlock_ruleset_attr *attr,
+ kernel_ulong_t size, unsigned int flags)
+
+{
+ static const kernel_ulong_t fill =
+ (kernel_ulong_t) 0xd1efaced00000000ULL;
+ kernel_ulong_t arg1 = (uintptr_t) attr;
+ kernel_ulong_t arg2 = size;
+ kernel_ulong_t arg3 = fill | flags;
+ kernel_ulong_t arg4 = fill | 0xbadbeefd;
+ kernel_ulong_t arg5 = fill | 0xdecaffed;
+ kernel_ulong_t arg6 = fill | 0xdeefaced;
+
+ long rc = syscall(__NR_landlock_create_ruleset,
+ arg1, arg2, arg3, arg4, arg5, arg6);
+ errstr = sprintrc(rc);
+ return rc;
+}
+
+int
+main(void)
+{
+ static const kernel_ulong_t bogus_size =
+ (kernel_ulong_t) 0xbadfaceddecaffee;
+
+ SKIP_IF_PROC_IS_UNAVAILABLE;
+
+ TAIL_ALLOC_OBJECT_VAR_PTR(struct landlock_ruleset_attr, attr);
+ long rc;
+
+ /* All zeroes */
+ rc = sys_landlock_create_ruleset(NULL, 0, 0);
+ printf("landlock_create_ruleset(NULL, 0, 0) = %s" INJ_FD_STR,
+ errstr);
+
+ /* Get ABI version */
+ rc = sys_landlock_create_ruleset(NULL, 0, 1);
+ printf("landlock_create_ruleset(NULL, 0"
+ ", LANDLOCK_CREATE_RULESET_VERSION) = %s" INJ_STR, errstr);
+
+ /* ilp32 check */
+ rc = syscall(__NR_landlock_create_ruleset,
+ (kernel_ulong_t) 0xffFFffFF00000000,
+ (kernel_ulong_t) 0xdefeededdeadface,
+ (kernel_ulong_t) 0xbadc0dedbadfaced);
+ printf("landlock_create_ruleset("
+#if SIZEOF_KERNEL_LONG_T > 4
+ "%#llx"
+#else
+ "NULL"
+#endif
+ ", %llu, LANDLOCK_CREATE_RULESET_VERSION|%#x) = %s" INJ_STR,
+#if SIZEOF_KERNEL_LONG_T > 4
+ (unsigned long long) (kernel_ulong_t) 0xffFFffFF00000000,
+#endif
+ (unsigned long long) (kernel_ulong_t) 0xdefeededdeadface,
+ 0xbadfacec, sprintrc(rc));
+
+ /* Bogus addr, size, flags */
+ rc = sys_landlock_create_ruleset(attr + 1, bogus_size, 0xbadcaffe);
+ printf("landlock_create_ruleset(%p, %llu"
+ ", 0xbadcaffe /* LANDLOCK_CREATE_RULESET_??? */) = %s"
+ INJ_FD_STR,
+ attr + 1, (unsigned long long) bogus_size, errstr);
+
+ /* Size is too small */
+ for (size_t i = 0; i < 8; i++) {
+ rc = sys_landlock_create_ruleset(attr, i, 0);
+ printf("landlock_create_ruleset(%p, %zu, 0) = %s" INJ_FD_STR,
+ attr, i, errstr);
+ }
+
+ /* Perform syscalls with valid attr ptr */
+ static const struct {
+ uint64_t val;
+ const char *str;
+ } attr_vals[] = {
+ { ARG_STR(LANDLOCK_ACCESS_FS_EXECUTE) },
+ { ARG_ULL_STR(LANDLOCK_ACCESS_FS_EXECUTE|LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR|LANDLOCK_ACCESS_FS_REMOVE_FILE|LANDLOCK_ACCESS_FS_MAKE_CHAR|LANDLOCK_ACCESS_FS_MAKE_DIR|LANDLOCK_ACCESS_FS_MAKE_SOCK|LANDLOCK_ACCESS_FS_MAKE_FIFO|LANDLOCK_ACCESS_FS_MAKE_BLOCK|LANDLOCK_ACCESS_FS_MAKE_SYM|0xdebeefeddecae000) },
+ { ARG_ULL_STR(0xdebeefeddecae000)
+ " /* LANDLOCK_ACCESS_FS_??? */" },
+ };
+ static const kernel_ulong_t sizes[] = { 8, 12, 16 };
+ for (size_t i = 0; i < ARRAY_SIZE(attr_vals); i++) {
+ for (size_t j = 0; j < ARRAY_SIZE(sizes); j++) {
+ attr->handled_access_fs = attr_vals[i].val;
+ rc = sys_landlock_create_ruleset(attr, sizes[j], 0);
+ printf("landlock_create_ruleset({handled_access_fs=%s"
+ "%s}, %llu, 0) = %s%s" INJ_STR,
+ attr_vals[i].str,
+ sizes[j] > sizeof(*attr) ? ", ..." : "",
+ (unsigned long long) sizes[j],
+ errstr, rc > 0 ? FD_PATH : "");
+ }
+ }
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
diff --git a/tests/landlock_restrict_self-y.c b/tests/landlock_restrict_self-y.c
new file mode 100644
index 000000000..f28dd18b1
--- /dev/null
+++ b/tests/landlock_restrict_self-y.c
@@ -0,0 +1,4 @@
+#define RULESET_FD 7
+#define RULESET_FD_STR "7</dev/full>"
+
+#include "landlock_restrict_self.c"
diff --git a/tests/landlock_restrict_self.c b/tests/landlock_restrict_self.c
new file mode 100644
index 000000000..b4378eee5
--- /dev/null
+++ b/tests/landlock_restrict_self.c
@@ -0,0 +1,83 @@
+/*
+ * Check decoding of landlock_restrict_self syscall.
+ *
+ * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+#include "scno.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+# define SKIP_IF_PROC_IS_UNAVAILABLE
+#endif
+
+#ifndef RULESET_FD
+# define RULESET_FD 7
+#endif
+#ifndef RULESET_FD_STR
+# define RULESET_FD_STR "7"
+#endif
+
+static const char *errstr;
+
+static long
+sys_landlock_restrict_self(int ruleset_fd, unsigned int flags)
+{
+ static const kernel_ulong_t fill =
+ (kernel_ulong_t) 0xd1efaced00000000ULL;
+ kernel_ulong_t arg1 = fill | (unsigned int) ruleset_fd;
+ kernel_ulong_t arg2 = fill | flags;
+ kernel_ulong_t arg3 = fill | 0xcaffeedc;
+ kernel_ulong_t arg4 = fill | 0xbadceded;
+ kernel_ulong_t arg5 = fill | 0xdecaffed;
+ kernel_ulong_t arg6 = fill | 0xdeefaced;
+
+ long rc = syscall(__NR_landlock_restrict_self,
+ arg1, arg2, arg3, arg4, arg5, arg6);
+ errstr = sprintrc(rc);
+ return rc;
+}
+
+int
+main(void)
+{
+ SKIP_IF_PROC_IS_UNAVAILABLE;
+
+ /* Valid attr ptr */
+ static const struct {
+ uint64_t val;
+ const char *str;
+ } ruleset_fd_vals[] = {
+ { ARG_STR(-1) },
+ { ARG_STR(9409) },
+ { RULESET_FD, RULESET_FD_STR },
+ };
+ static const struct {
+ int val;
+ const char *str;
+ } flags_vals[] = {
+ { ARG_STR(0) },
+ { ARG_STR(0x1) },
+ { ARG_STR(0xffffffff) },
+ };
+ for (size_t i = 0; i < ARRAY_SIZE(ruleset_fd_vals); i++) {
+ for (size_t j = 0; j < ARRAY_SIZE(flags_vals); j++) {
+ sys_landlock_restrict_self(ruleset_fd_vals[i].val,
+ flags_vals[j].val);
+ printf("landlock_restrict_self(%s, %s) = %s\n",
+ ruleset_fd_vals[i].str, flags_vals[j].str,
+ errstr);
+ }
+ }
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index c59e11783..9a8248567 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -267,6 +267,12 @@ keyctl-Xabbrev
keyctl-Xraw
keyctl-Xverbose
kill
+landlock_add_rule
+landlock_add_rule-y
+landlock_create_ruleset
+landlock_create_ruleset-y
+landlock_restrict_self
+landlock_restrict_self-y
lchown
lchown32
link