• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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