• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <linux/netlink.h>
7 #include <signal.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/prctl.h>
13 #include <sys/socket.h>
14 #include <sched.h>
15 #include <sys/eventfd.h>
16 #include <sys/stat.h>
17 #include <sys/syscall.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 
22 #include "../kselftest.h"
23 #include "../kselftest_harness.h"
24 
25 #define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
26 #define __UEVENT_BUFFER_SIZE (2048 * 2)
27 #define __UEVENT_HEADER "add@/devices/virtual/mem/full"
28 #define __UEVENT_HEADER_LEN sizeof("add@/devices/virtual/mem/full")
29 #define __UEVENT_LISTEN_ALL -1
30 
read_nointr(int fd,void * buf,size_t count)31 ssize_t read_nointr(int fd, void *buf, size_t count)
32 {
33 	ssize_t ret;
34 
35 again:
36 	ret = read(fd, buf, count);
37 	if (ret < 0 && errno == EINTR)
38 		goto again;
39 
40 	return ret;
41 }
42 
write_nointr(int fd,const void * buf,size_t count)43 ssize_t write_nointr(int fd, const void *buf, size_t count)
44 {
45 	ssize_t ret;
46 
47 again:
48 	ret = write(fd, buf, count);
49 	if (ret < 0 && errno == EINTR)
50 		goto again;
51 
52 	return ret;
53 }
54 
wait_for_pid(pid_t pid)55 int wait_for_pid(pid_t pid)
56 {
57 	int status, ret;
58 
59 again:
60 	ret = waitpid(pid, &status, 0);
61 	if (ret == -1) {
62 		if (errno == EINTR)
63 			goto again;
64 
65 		return -1;
66 	}
67 
68 	if (ret != pid)
69 		goto again;
70 
71 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
72 		return -1;
73 
74 	return 0;
75 }
76 
uevent_listener(unsigned long post_flags,bool expect_uevent,int sync_fd)77 static int uevent_listener(unsigned long post_flags, bool expect_uevent,
78 			   int sync_fd)
79 {
80 	int sk_fd, ret;
81 	socklen_t sk_addr_len;
82 	int fret = -1, rcv_buf_sz = __UEVENT_BUFFER_SIZE;
83 	uint64_t sync_add = 1;
84 	struct sockaddr_nl sk_addr = { 0 }, rcv_addr = { 0 };
85 	char buf[__UEVENT_BUFFER_SIZE] = { 0 };
86 	struct iovec iov = { buf, __UEVENT_BUFFER_SIZE };
87 	char control[CMSG_SPACE(sizeof(struct ucred))];
88 	struct msghdr hdr = {
89 		&rcv_addr, sizeof(rcv_addr), &iov, 1,
90 		control,   sizeof(control),  0,
91 	};
92 
93 	sk_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
94 		       NETLINK_KOBJECT_UEVENT);
95 	if (sk_fd < 0) {
96 		fprintf(stderr, "%s - Failed to open uevent socket\n", strerror(errno));
97 		return -1;
98 	}
99 
100 	ret = setsockopt(sk_fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_sz,
101 			 sizeof(rcv_buf_sz));
102 	if (ret < 0) {
103 		fprintf(stderr, "%s - Failed to set socket options\n", strerror(errno));
104 		goto on_error;
105 	}
106 
107 	sk_addr.nl_family = AF_NETLINK;
108 	sk_addr.nl_groups = __UEVENT_LISTEN_ALL;
109 
110 	sk_addr_len = sizeof(sk_addr);
111 	ret = bind(sk_fd, (struct sockaddr *)&sk_addr, sk_addr_len);
112 	if (ret < 0) {
113 		fprintf(stderr, "%s - Failed to bind socket\n", strerror(errno));
114 		goto on_error;
115 	}
116 
117 	ret = getsockname(sk_fd, (struct sockaddr *)&sk_addr, &sk_addr_len);
118 	if (ret < 0) {
119 		fprintf(stderr, "%s - Failed to retrieve socket name\n", strerror(errno));
120 		goto on_error;
121 	}
122 
123 	if ((size_t)sk_addr_len != sizeof(sk_addr)) {
124 		fprintf(stderr, "Invalid socket address size\n");
125 		goto on_error;
126 	}
127 
128 	if (post_flags & CLONE_NEWUSER) {
129 		ret = unshare(CLONE_NEWUSER);
130 		if (ret < 0) {
131 			fprintf(stderr,
132 				"%s - Failed to unshare user namespace\n",
133 				strerror(errno));
134 			goto on_error;
135 		}
136 	}
137 
138 	if (post_flags & CLONE_NEWNET) {
139 		ret = unshare(CLONE_NEWNET);
140 		if (ret < 0) {
141 			fprintf(stderr,
142 				"%s - Failed to unshare network namespace\n",
143 				strerror(errno));
144 			goto on_error;
145 		}
146 	}
147 
148 	ret = write_nointr(sync_fd, &sync_add, sizeof(sync_add));
149 	close(sync_fd);
150 	if (ret != sizeof(sync_add)) {
151 		fprintf(stderr, "Failed to synchronize with parent process\n");
152 		goto on_error;
153 	}
154 
155 	fret = 0;
156 	for (;;) {
157 		ssize_t r;
158 
159 		r = recvmsg(sk_fd, &hdr, 0);
160 		if (r <= 0) {
161 			fprintf(stderr, "%s - Failed to receive uevent\n", strerror(errno));
162 			ret = -1;
163 			break;
164 		}
165 
166 		/* ignore libudev messages */
167 		if (memcmp(buf, "libudev", 8) == 0)
168 			continue;
169 
170 		/* ignore uevents we didn't trigger */
171 		if (memcmp(buf, __UEVENT_HEADER, __UEVENT_HEADER_LEN) != 0)
172 			continue;
173 
174 		if (!expect_uevent) {
175 			fprintf(stderr, "Received unexpected uevent:\n");
176 			ret = -1;
177 		}
178 
179 		if (TH_LOG_ENABLED) {
180 			/* If logging is enabled dump the received uevent. */
181 			(void)write_nointr(STDERR_FILENO, buf, r);
182 			(void)write_nointr(STDERR_FILENO, "\n", 1);
183 		}
184 
185 		break;
186 	}
187 
188 on_error:
189 	close(sk_fd);
190 
191 	return fret;
192 }
193 
trigger_uevent(unsigned int times)194 int trigger_uevent(unsigned int times)
195 {
196 	int fd, ret;
197 	unsigned int i;
198 
199 	fd = open(__DEV_FULL, O_RDWR | O_CLOEXEC);
200 	if (fd < 0) {
201 		if (errno != ENOENT)
202 			return -EINVAL;
203 
204 		return -1;
205 	}
206 
207 	for (i = 0; i < times; i++) {
208 		ret = write_nointr(fd, "add\n", sizeof("add\n") - 1);
209 		if (ret < 0) {
210 			fprintf(stderr, "Failed to trigger uevent\n");
211 			break;
212 		}
213 	}
214 	close(fd);
215 
216 	return ret;
217 }
218 
set_death_signal(void)219 int set_death_signal(void)
220 {
221 	int ret;
222 	pid_t ppid;
223 
224 	ret = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
225 
226 	/* Check whether we have been orphaned. */
227 	ppid = getppid();
228 	if (ppid == 1) {
229 		pid_t self;
230 
231 		self = getpid();
232 		ret = kill(self, SIGKILL);
233 	}
234 
235 	if (ret < 0)
236 		return -1;
237 
238 	return 0;
239 }
240 
do_test(unsigned long pre_flags,unsigned long post_flags,bool expect_uevent,int sync_fd)241 static int do_test(unsigned long pre_flags, unsigned long post_flags,
242 		   bool expect_uevent, int sync_fd)
243 {
244 	int ret;
245 	uint64_t wait_val;
246 	pid_t pid;
247 	sigset_t mask;
248 	sigset_t orig_mask;
249 	struct timespec timeout;
250 
251 	sigemptyset(&mask);
252 	sigaddset(&mask, SIGCHLD);
253 
254 	ret = sigprocmask(SIG_BLOCK, &mask, &orig_mask);
255 	if (ret < 0) {
256 		fprintf(stderr, "%s- Failed to block SIGCHLD\n", strerror(errno));
257 		return -1;
258 	}
259 
260 	pid = fork();
261 	if (pid < 0) {
262 		fprintf(stderr, "%s - Failed to fork() new process\n", strerror(errno));
263 		return -1;
264 	}
265 
266 	if (pid == 0) {
267 		/* Make sure that we go away when our parent dies. */
268 		ret = set_death_signal();
269 		if (ret < 0) {
270 			fprintf(stderr, "Failed to set PR_SET_PDEATHSIG to SIGKILL\n");
271 			_exit(EXIT_FAILURE);
272 		}
273 
274 		if (pre_flags & CLONE_NEWUSER) {
275 			ret = unshare(CLONE_NEWUSER);
276 			if (ret < 0) {
277 				fprintf(stderr,
278 					"%s - Failed to unshare user namespace\n",
279 					strerror(errno));
280 				_exit(EXIT_FAILURE);
281 			}
282 		}
283 
284 		if (pre_flags & CLONE_NEWNET) {
285 			ret = unshare(CLONE_NEWNET);
286 			if (ret < 0) {
287 				fprintf(stderr,
288 					"%s - Failed to unshare network namespace\n",
289 					strerror(errno));
290 				_exit(EXIT_FAILURE);
291 			}
292 		}
293 
294 		if (uevent_listener(post_flags, expect_uevent, sync_fd) < 0)
295 			_exit(EXIT_FAILURE);
296 
297 		_exit(EXIT_SUCCESS);
298 	}
299 
300 	ret = read_nointr(sync_fd, &wait_val, sizeof(wait_val));
301 	if (ret != sizeof(wait_val)) {
302 		fprintf(stderr, "Failed to synchronize with child process\n");
303 		_exit(EXIT_FAILURE);
304 	}
305 
306 	/* Trigger 10 uevents to account for the case where the kernel might
307 	 * drop some.
308 	 */
309 	ret = trigger_uevent(10);
310 	if (ret < 0)
311 		fprintf(stderr, "Failed triggering uevents\n");
312 
313 	/* Wait for 2 seconds before considering this failed. This should be
314 	 * plenty of time for the kernel to deliver the uevent even under heavy
315 	 * load.
316 	 */
317 	timeout.tv_sec = 2;
318 	timeout.tv_nsec = 0;
319 
320 again:
321 	ret = sigtimedwait(&mask, NULL, &timeout);
322 	if (ret < 0) {
323 		if (errno == EINTR)
324 			goto again;
325 
326 		if (!expect_uevent)
327 			ret = kill(pid, SIGTERM); /* success */
328 		else
329 			ret = kill(pid, SIGUSR1); /* error */
330 		if (ret < 0)
331 			return -1;
332 	}
333 
334 	ret = wait_for_pid(pid);
335 	if (ret < 0)
336 		return -1;
337 
338 	return ret;
339 }
340 
signal_handler(int sig)341 static void signal_handler(int sig)
342 {
343 	if (sig == SIGTERM)
344 		_exit(EXIT_SUCCESS);
345 
346 	_exit(EXIT_FAILURE);
347 }
348 
TEST(uevent_filtering)349 TEST(uevent_filtering)
350 {
351 	int ret, sync_fd;
352 	struct sigaction act;
353 
354 	if (geteuid()) {
355 		TH_LOG("Uevent filtering tests require root privileges. Skipping test");
356 		_exit(KSFT_SKIP);
357 	}
358 
359 	ret = access(__DEV_FULL, F_OK);
360 	EXPECT_EQ(0, ret) {
361 		if (errno == ENOENT) {
362 			TH_LOG(__DEV_FULL " does not exist. Skipping test");
363 			_exit(KSFT_SKIP);
364 		}
365 
366 		_exit(KSFT_FAIL);
367 	}
368 
369 	act.sa_handler = signal_handler;
370 	act.sa_flags = 0;
371 	sigemptyset(&act.sa_mask);
372 
373 	ret = sigaction(SIGTERM, &act, NULL);
374 	ASSERT_EQ(0, ret);
375 
376 	sync_fd = eventfd(0, EFD_CLOEXEC);
377 	ASSERT_GE(sync_fd, 0);
378 
379 	/*
380 	 * Setup:
381 	 * - Open uevent listening socket in initial network namespace owned by
382 	 *   initial user namespace.
383 	 * - Trigger uevent in initial network namespace owned by initial user
384 	 *   namespace.
385 	 * Expected Result:
386 	 * - uevent listening socket receives uevent
387 	 */
388 	ret = do_test(0, 0, true, sync_fd);
389 	ASSERT_EQ(0, ret) {
390 		goto do_cleanup;
391 	}
392 
393 	/*
394 	 * Setup:
395 	 * - Open uevent listening socket in non-initial network namespace
396 	 *   owned by initial user namespace.
397 	 * - Trigger uevent in initial network namespace owned by initial user
398 	 *   namespace.
399 	 * Expected Result:
400 	 * - uevent listening socket receives uevent
401 	 */
402 	ret = do_test(CLONE_NEWNET, 0, true, sync_fd);
403 	ASSERT_EQ(0, ret) {
404 		goto do_cleanup;
405 	}
406 
407 	/*
408 	 * Setup:
409 	 * - unshare user namespace
410 	 * - Open uevent listening socket in initial network namespace
411 	 *   owned by initial user namespace.
412 	 * - Trigger uevent in initial network namespace owned by initial user
413 	 *   namespace.
414 	 * Expected Result:
415 	 * - uevent listening socket receives uevent
416 	 */
417 	ret = do_test(CLONE_NEWUSER, 0, true, sync_fd);
418 	ASSERT_EQ(0, ret) {
419 		goto do_cleanup;
420 	}
421 
422 	/*
423 	 * Setup:
424 	 * - Open uevent listening socket in non-initial network namespace
425 	 *   owned by non-initial user namespace.
426 	 * - Trigger uevent in initial network namespace owned by initial user
427 	 *   namespace.
428 	 * Expected Result:
429 	 * - uevent listening socket receives no uevent
430 	 */
431 	ret = do_test(CLONE_NEWUSER | CLONE_NEWNET, 0, false, sync_fd);
432 	ASSERT_EQ(0, ret) {
433 		goto do_cleanup;
434 	}
435 
436 	/*
437 	 * Setup:
438 	 * - Open uevent listening socket in initial network namespace
439 	 *   owned by initial user namespace.
440 	 * - unshare network namespace
441 	 * - Trigger uevent in initial network namespace owned by initial user
442 	 *   namespace.
443 	 * Expected Result:
444 	 * - uevent listening socket receives uevent
445 	 */
446 	ret = do_test(0, CLONE_NEWNET, true, sync_fd);
447 	ASSERT_EQ(0, ret) {
448 		goto do_cleanup;
449 	}
450 
451 	/*
452 	 * Setup:
453 	 * - Open uevent listening socket in initial network namespace
454 	 *   owned by initial user namespace.
455 	 * - unshare user namespace
456 	 * - Trigger uevent in initial network namespace owned by initial user
457 	 *   namespace.
458 	 * Expected Result:
459 	 * - uevent listening socket receives uevent
460 	 */
461 	ret = do_test(0, CLONE_NEWUSER, true, sync_fd);
462 	ASSERT_EQ(0, ret) {
463 		goto do_cleanup;
464 	}
465 
466 	/*
467 	 * Setup:
468 	 * - Open uevent listening socket in initial network namespace
469 	 *   owned by initial user namespace.
470 	 * - unshare user namespace
471 	 * - unshare network namespace
472 	 * - Trigger uevent in initial network namespace owned by initial user
473 	 *   namespace.
474 	 * Expected Result:
475 	 * - uevent listening socket receives uevent
476 	 */
477 	ret = do_test(0, CLONE_NEWUSER | CLONE_NEWNET, true, sync_fd);
478 	ASSERT_EQ(0, ret) {
479 		goto do_cleanup;
480 	}
481 
482 do_cleanup:
483 	close(sync_fd);
484 }
485 
486 TEST_HARNESS_MAIN
487