1 /*
2 * Check decoding of landlock_create_ruleset syscall.
3 *
4 * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2021-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include "scno.h"
13 #include "xmalloc.h"
14
15 #include <inttypes.h>
16 #include <stdio.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include <linux/landlock.h>
22
23 #ifndef RETVAL_INJECTED
24 # define RETVAL_INJECTED 0
25 #endif
26 #ifndef DECODE_FD
27 # define DECODE_FD 0
28 #endif
29
30 #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
31 # define SKIP_IF_PROC_IS_UNAVAILABLE
32 #endif
33 #ifndef FD_PATH
34 # define FD_PATH ""
35 #endif
36
37 #if RETVAL_INJECTED
38 # define INJ_STR " (INJECTED)\n"
39 # define INJ_FD_STR FD_PATH " (INJECTED)\n"
40 #else /* !RETVAL_INJECTED */
41 # define INJ_STR "\n"
42 # define INJ_FD_STR "\n"
43 #endif /* RETVAL_INJECTED */
44
45 static const char *errstr;
46
47 static long
48 sys_landlock_create_ruleset(struct landlock_ruleset_attr *attr,
49 kernel_ulong_t size, unsigned int flags)
50
51 {
52 static const kernel_ulong_t fill =
53 (kernel_ulong_t) 0xd1efaced00000000ULL;
54 kernel_ulong_t arg1 = (uintptr_t) attr;
55 kernel_ulong_t arg2 = size;
56 kernel_ulong_t arg3 = fill | flags;
57 kernel_ulong_t arg4 = fill | 0xbadbeefd;
58 kernel_ulong_t arg5 = fill | 0xdecaffed;
59 kernel_ulong_t arg6 = fill | 0xdeefaced;
60
61 long rc = syscall(__NR_landlock_create_ruleset,
62 arg1, arg2, arg3, arg4, arg5, arg6);
63 errstr = sprintrc(rc);
64 return rc;
65 }
66
67 int
68 main(void)
69 {
70 static const kernel_ulong_t bogus_size =
71 (kernel_ulong_t) 0xbadfaceddecaffee;
72
73 SKIP_IF_PROC_IS_UNAVAILABLE;
74
75 TAIL_ALLOC_OBJECT_VAR_PTR(struct landlock_ruleset_attr, attr);
76 long rc;
77
78 /* All zeroes */
79 rc = sys_landlock_create_ruleset(NULL, 0, 0);
80 printf("landlock_create_ruleset(NULL, 0, 0) = %s" INJ_FD_STR,
81 errstr);
82
83 /* Get ABI version */
84 rc = sys_landlock_create_ruleset(NULL, 0, 1);
85 printf("landlock_create_ruleset(NULL, 0"
86 ", LANDLOCK_CREATE_RULESET_VERSION) = %s" INJ_STR, errstr);
87
88 /* ilp32 check */
89 rc = syscall(__NR_landlock_create_ruleset,
90 (kernel_ulong_t) 0xffFFffFF00000000,
91 (kernel_ulong_t) 0xdefeededdeadface,
92 (kernel_ulong_t) 0xbadc0dedbadfaced);
93 printf("landlock_create_ruleset("
94 #if SIZEOF_KERNEL_LONG_T > 4
95 "%#llx"
96 #else
97 "NULL"
98 #endif
99 ", %llu, LANDLOCK_CREATE_RULESET_VERSION|%#x) = %s" INJ_STR,
100 #if SIZEOF_KERNEL_LONG_T > 4
101 (unsigned long long) (kernel_ulong_t) 0xffFFffFF00000000,
102 #endif
103 (unsigned long long) (kernel_ulong_t) 0xdefeededdeadface,
104 0xbadfacec, sprintrc(rc));
105
106 /* Bogus addr, size, flags */
107 rc = sys_landlock_create_ruleset(attr + 1, bogus_size, 0xbadcaffe);
108 printf("landlock_create_ruleset(%p, %llu"
109 ", 0xbadcaffe /* LANDLOCK_CREATE_RULESET_??? */) = %s"
110 INJ_FD_STR,
111 attr + 1, (unsigned long long) bogus_size, errstr);
112
113 /* Size is too small */
114 for (size_t i = 0; i < 8; i++) {
115 rc = sys_landlock_create_ruleset(attr, i, 0);
116 printf("landlock_create_ruleset(%p, %zu, 0) = %s" INJ_FD_STR,
117 attr, i, errstr);
118 }
119
120 /* Perform syscalls with valid attr ptr */
121 static const struct {
122 uint64_t val;
123 const char *str;
124 } attr_vals[] = {
125 { ARG_STR(LANDLOCK_ACCESS_FS_EXECUTE) },
126 { 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|LANDLOCK_ACCESS_FS_REFER|LANDLOCK_ACCESS_FS_TRUNCATE|0xdebeefeddeca8000) },
127 { ARG_ULL_STR(0xdebeefeddeca8000)
128 " /* LANDLOCK_ACCESS_FS_??? */" },
129 };
130 static const kernel_ulong_t sizes[] = { 8, 12, 16 };
131 for (size_t i = 0; i < ARRAY_SIZE(attr_vals); i++) {
132 for (size_t j = 0; j < ARRAY_SIZE(sizes); j++) {
133 const char *fd_str = FD_PATH;
134
135 attr->handled_access_fs = attr_vals[i].val;
136 rc = sys_landlock_create_ruleset(attr, sizes[j], 0);
137
138 #if DECODE_FD
139 /*
140 * The ABI has been broken in commit v5.18-rc1~88^2
141 * by adding brackets to the link value, hence, we can't
142 * rely on a specific name anymore and have to fetch it
143 * ourselves.
144 */
145 if (rc >= 0) {
146 static char buf[256];
147 char *path = xasprintf("/proc/self/fd/%ld", rc);
148 ssize_t ret = readlink(path, buf + 1,
149 sizeof(buf) - 3);
150 free(path);
151
152 if (ret >= 0) {
153 buf[0] = '<';
154 buf[ret + 1] = '>';
155 buf[ret + 2] = '\0';
156 fd_str = buf;
157 }
158 }
159 #endif
160
161 printf("landlock_create_ruleset({handled_access_fs=%s"
162 "%s}, %llu, 0) = %s%s" INJ_STR,
163 attr_vals[i].str,
164 sizes[j] > sizeof(*attr) ? ", ..." : "",
165 (unsigned long long) sizes[j],
166 errstr, rc >= 0 ? fd_str : "");
167 }
168 }
169
170 puts("+++ exited with 0 +++");
171 return 0;
172 }