1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4 */
5
6 /*\
7 * [Description]
8 *
9 * This test verifies that landlock_add_rule syscall fails with the right
10 * error codes:
11 *
12 * - EINVAL flags is not 0, or the rule accesses are inconsistent
13 * - ENOMSG Empty accesses (i.e., rule_attr->allowed_access is 0)
14 * - EBADF ruleset_fd is not a file descriptor for the current thread,
15 * or a member of rule_attr is not a file descriptor as expected
16 * - EBADFD ruleset_fd is not a ruleset file descriptor, or a member of
17 * rule_attr is not the expected file descriptor type
18 * - EFAULT rule_attr was not a valid address
19 */
20
21 #include "landlock_common.h"
22
23 static struct tst_landlock_ruleset_attr_abi1 *attr_abi1;
24 static struct tst_landlock_ruleset_attr_abi4 *attr_abi4;
25 static struct landlock_path_beneath_attr *path_beneath_attr;
26 static struct landlock_path_beneath_attr *rule_null;
27 static struct landlock_net_port_attr *net_port_attr;
28 static int ruleset_fd;
29 static int invalid_fd = -1;
30 static int abi_current;
31
32 static struct tcase {
33 int *fd;
34 int rule_type;
35 struct landlock_path_beneath_attr **path_attr;
36 struct landlock_net_port_attr **net_attr;
37 int access;
38 int parent_fd;
39 int net_port;
40 uint32_t flags;
41 int exp_errno;
42 int abi_ver;
43 char *msg;
44 } tcases[] = {
45 {
46 .fd = &ruleset_fd,
47 .path_attr = &path_beneath_attr,
48 .access = LANDLOCK_ACCESS_FS_EXECUTE,
49 .flags = 1,
50 .exp_errno = EINVAL,
51 .abi_ver = 1,
52 .msg = "Invalid flags"
53 },
54 {
55 .fd = &ruleset_fd,
56 .path_attr = &path_beneath_attr,
57 .access = LANDLOCK_ACCESS_FS_EXECUTE,
58 .exp_errno = EINVAL,
59 .abi_ver = 1,
60 .msg = "Invalid rule type"
61 },
62 {
63 .fd = &ruleset_fd,
64 .rule_type = LANDLOCK_RULE_PATH_BENEATH,
65 .path_attr = &path_beneath_attr,
66 .exp_errno = ENOMSG,
67 .abi_ver = 1,
68 .msg = "Empty accesses"
69 },
70 {
71 .fd = &invalid_fd,
72 .path_attr = &path_beneath_attr,
73 .access = LANDLOCK_ACCESS_FS_EXECUTE,
74 .exp_errno = EBADF,
75 .abi_ver = 1,
76 .msg = "Invalid file descriptor"
77 },
78 {
79 .fd = &ruleset_fd,
80 .rule_type = LANDLOCK_RULE_PATH_BENEATH,
81 .path_attr = &path_beneath_attr,
82 .access = LANDLOCK_ACCESS_FS_EXECUTE,
83 .parent_fd = -1,
84 .exp_errno = EBADF,
85 .abi_ver = 1,
86 .msg = "Invalid parent fd"
87 },
88 {
89 .fd = &ruleset_fd,
90 .rule_type = LANDLOCK_RULE_PATH_BENEATH,
91 .path_attr = &rule_null,
92 .exp_errno = EFAULT,
93 .abi_ver = 1,
94 .msg = "Invalid rule attr"
95 },
96 {
97 .fd = &ruleset_fd,
98 .rule_type = LANDLOCK_RULE_NET_PORT,
99 .net_attr = &net_port_attr,
100 .access = LANDLOCK_ACCESS_FS_EXECUTE,
101 .net_port = 448,
102 .exp_errno = EINVAL,
103 .abi_ver = 4,
104 .msg = "Invalid access rule for network type"
105 },
106 {
107 .fd = &ruleset_fd,
108 .rule_type = LANDLOCK_RULE_NET_PORT,
109 .net_attr = &net_port_attr,
110 .access = LANDLOCK_ACCESS_NET_BIND_TCP,
111 .net_port = INT16_MAX + 1,
112 .exp_errno = EINVAL,
113 .abi_ver = 4,
114 .msg = "Socket port greater than 65535"
115 },
116 };
117
run(unsigned int n)118 static void run(unsigned int n)
119 {
120 struct tcase *tc = &tcases[n];
121 void *attr = NULL;
122
123 if (tc->abi_ver > abi_current) {
124 tst_res(TCONF, "Minimum ABI required: %d", tc->abi_ver);
125 return;
126 }
127
128 if (tc->path_attr && *tc->path_attr) {
129 (*tc->path_attr)->allowed_access = tc->access;
130 (*tc->path_attr)->parent_fd = tc->parent_fd;
131
132 attr = *tc->path_attr;
133 } else if (tc->net_attr && *tc->net_attr) {
134 (*tc->net_attr)->allowed_access = tc->access;
135 (*tc->net_attr)->port = tc->net_port;
136
137 attr = *tc->net_attr;
138 }
139
140 TST_EXP_FAIL(tst_syscall(__NR_landlock_add_rule,
141 *tc->fd, tc->rule_type, attr, tc->flags),
142 tc->exp_errno, "%s", tc->msg);
143 }
144
setup(void)145 static void setup(void)
146 {
147 abi_current = verify_landlock_is_enabled();
148
149 attr_abi1->handled_access_fs =
150 attr_abi4->handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE;
151
152 if (abi_current < 4) {
153 ruleset_fd = TST_EXP_FD_SILENT(tst_syscall(__NR_landlock_create_ruleset,
154 attr_abi1, sizeof(struct tst_landlock_ruleset_attr_abi1), 0));
155 } else {
156 ruleset_fd = TST_EXP_FD_SILENT(tst_syscall(__NR_landlock_create_ruleset,
157 attr_abi4, sizeof(struct tst_landlock_ruleset_attr_abi4), 0));
158 }
159 }
160
cleanup(void)161 static void cleanup(void)
162 {
163 if (ruleset_fd != -1)
164 SAFE_CLOSE(ruleset_fd);
165 }
166
167 static struct tst_test test = {
168 .test = run,
169 .tcnt = ARRAY_SIZE(tcases),
170 .setup = setup,
171 .cleanup = cleanup,
172 .needs_root = 1,
173 .bufs = (struct tst_buffers []) {
174 {&attr_abi1, .size = sizeof(struct tst_landlock_ruleset_attr_abi1)},
175 {&attr_abi4, .size = sizeof(struct tst_landlock_ruleset_attr_abi4)},
176 {&path_beneath_attr, .size = sizeof(struct landlock_path_beneath_attr)},
177 {&net_port_attr, .size = sizeof(struct landlock_net_port_attr)},
178 {},
179 },
180 .caps = (struct tst_cap []) {
181 TST_CAP(TST_CAP_REQ, CAP_SYS_ADMIN),
182 {}
183 },
184 };
185