• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4  *
5  * Basic clone3() test to check various failures.
6  */
7 #define _GNU_SOURCE
8 
9 #include <stdlib.h>
10 
11 #include "tst_test.h"
12 #include "lapi/clone.h"
13 
14 static struct clone_args *valid_args, *invalid_args;
15 unsigned long stack;
16 static int *invalid_address;
17 
18 static struct tcase {
19 	const char *name;
20 	struct clone_args **args;
21 	size_t size;
22 	uint64_t flags;
23 	int **pidfd;
24 	int **child_tid;
25 	int **parent_tid;
26 	int exit_signal;
27 	unsigned long stack;
28 	unsigned long stack_size;
29 	unsigned long tls;
30 	int exp_errno;
31 } tcases[] = {
32 	{"invalid args", &invalid_args, sizeof(*valid_args), 0, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EFAULT},
33 	{"zero size", &valid_args, 0, 0, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EINVAL},
34 	{"short size", &valid_args, sizeof(*valid_args) - 1, 0, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EINVAL},
35 	{"extra size", &valid_args, sizeof(*valid_args) + 1, 0, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EFAULT},
36 	{"sighand-no-VM", &valid_args, sizeof(*valid_args), CLONE_SIGHAND, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EINVAL},
37 	{"thread-no-sighand", &valid_args, sizeof(*valid_args), CLONE_THREAD, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EINVAL},
38 	{"fs-newns", &valid_args, sizeof(*valid_args), CLONE_FS | CLONE_NEWNS, NULL, NULL, NULL, SIGCHLD, 0, 0, 0, EINVAL},
39 	{"invalid pidfd", &valid_args, sizeof(*valid_args), CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, &invalid_address, NULL, NULL, SIGCHLD, 0, 0, 0, EFAULT},
40 	{"invalid childtid", &valid_args, sizeof(*valid_args), CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, NULL, &invalid_address, NULL, SIGCHLD, 0, 0, 0, EFAULT},
41 	{"invalid parenttid", &valid_args, sizeof(*valid_args), CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, NULL, NULL, &invalid_address, SIGCHLD, 0, 0, 0, EFAULT},
42 	{"invalid signal", &valid_args, sizeof(*valid_args), 0, NULL, NULL, NULL, CSIGNAL + 1, 0, 0, 0, EINVAL},
43 	{"zero-stack-size", &valid_args, sizeof(*valid_args), 0, NULL, NULL, NULL, SIGCHLD, (unsigned long)&stack, 0, 0, EINVAL},
44 	{"invalid-stack", &valid_args, sizeof(*valid_args), 0, NULL, NULL, NULL, SIGCHLD, 0, 4, 0, EINVAL},
45 };
46 
setup(void)47 static void setup(void)
48 {
49 	clone3_supported_by_kernel();
50 
51 	void *p = tst_get_bad_addr(NULL);
52 
53 	invalid_args = p;
54 	invalid_address = p;
55 }
56 
run(unsigned int n)57 static void run(unsigned int n)
58 {
59 	struct tcase *tc = &tcases[n];
60 	struct clone_args *args = *tc->args;
61 
62 	if (args == valid_args) {
63 		args->flags = tc->flags;
64 		if (tc->pidfd)
65 			args->pidfd = (uint64_t)(*tc->pidfd);
66 		if (tc->child_tid)
67 			args->child_tid = (uint64_t)(*tc->child_tid);
68 		if (tc->parent_tid)
69 			args->parent_tid = (uint64_t)(*tc->parent_tid);
70 		args->exit_signal = tc->exit_signal;
71 		args->stack = tc->stack;
72 		args->stack_size = tc->stack_size;
73 		args->tls = tc->tls;
74 	}
75 
76 	TEST(clone3(args, tc->size));
77 
78 	if (!TST_RET)
79 		exit(EXIT_SUCCESS);
80 
81 	if (TST_RET >= 0) {
82 		tst_res(TFAIL, "%s: clone3() passed unexpectedly", tc->name);
83 		return;
84 	}
85 
86 	if (tc->exp_errno != TST_ERR) {
87 		tst_res(TFAIL | TTERRNO, "%s: clone3() should fail with %s",
88 			tc->name, tst_strerrno(tc->exp_errno));
89 		return;
90 	}
91 
92 	tst_res(TPASS | TTERRNO, "%s: clone3() failed as expected", tc->name);
93 }
94 
95 static struct tst_test test = {
96 	.tcnt = ARRAY_SIZE(tcases),
97 	.test = run,
98 	.setup = setup,
99 	.needs_tmpdir = 1,
100 	.bufs = (struct tst_buffers []) {
101 		{&valid_args, .size = sizeof(*valid_args)},
102 		{},
103 	}
104 };
105