1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*\
7f08c3bdfSopenharmony_ci * [Description]
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Basic clone3() test to check various failures.
10f08c3bdfSopenharmony_ci */
11f08c3bdfSopenharmony_ci
12f08c3bdfSopenharmony_ci#define _GNU_SOURCE
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci#include <stdlib.h>
15f08c3bdfSopenharmony_ci#include <assert.h>
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci#include "tst_test.h"
18f08c3bdfSopenharmony_ci#include "lapi/sched.h"
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_cistatic struct clone_args *valid_args, *invalid_args;
21f08c3bdfSopenharmony_ciunsigned long stack;
22f08c3bdfSopenharmony_cistatic int *invalid_address;
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic struct tcase {
25f08c3bdfSopenharmony_ci	const char *name;
26f08c3bdfSopenharmony_ci	struct clone_args **args;
27f08c3bdfSopenharmony_ci	size_t size;
28f08c3bdfSopenharmony_ci	uint64_t flags;
29f08c3bdfSopenharmony_ci	int **pidfd;
30f08c3bdfSopenharmony_ci	int exit_signal;
31f08c3bdfSopenharmony_ci	unsigned long stack;
32f08c3bdfSopenharmony_ci	unsigned long stack_size;
33f08c3bdfSopenharmony_ci	unsigned long tls;
34f08c3bdfSopenharmony_ci	int exp_errno;
35f08c3bdfSopenharmony_ci} tcases[] = {
36f08c3bdfSopenharmony_ci	{"invalid args", &invalid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, 0, 0, 0, EFAULT},
37f08c3bdfSopenharmony_ci	{"zero size", &valid_args, 0, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL},
38f08c3bdfSopenharmony_ci	{"short size", &valid_args, sizeof(struct clone_args_minimal) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL},
39f08c3bdfSopenharmony_ci	{"extra size", &valid_args, sizeof(*valid_args) + 1, 0, NULL, SIGCHLD, 0, 0, 0, EFAULT},
40f08c3bdfSopenharmony_ci	{"sighand-no-VM", &valid_args, sizeof(*valid_args), CLONE_SIGHAND, NULL, SIGCHLD, 0, 0, 0, EINVAL},
41f08c3bdfSopenharmony_ci	{"thread-no-sighand", &valid_args, sizeof(*valid_args), CLONE_THREAD, NULL, SIGCHLD, 0, 0, 0, EINVAL},
42f08c3bdfSopenharmony_ci	{"fs-newns", &valid_args, sizeof(*valid_args), CLONE_FS | CLONE_NEWNS, NULL, SIGCHLD, 0, 0, 0, EINVAL},
43f08c3bdfSopenharmony_ci	{"invalid pidfd", &valid_args, sizeof(*valid_args), CLONE_PIDFD, &invalid_address, SIGCHLD, 0, 0, 0, EFAULT},
44f08c3bdfSopenharmony_ci	{"invalid signal", &valid_args, sizeof(*valid_args), 0, NULL, CSIGNAL + 1, 0, 0, 0, EINVAL},
45f08c3bdfSopenharmony_ci	{"zero-stack-size", &valid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, (unsigned long)&stack, 0, 0, EINVAL},
46f08c3bdfSopenharmony_ci	{"invalid-stack", &valid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, 0, 4, 0, EINVAL},
47f08c3bdfSopenharmony_ci	/*
48f08c3bdfSopenharmony_ci	 * Don't test CLONE_CHILD_SETTID and CLONE_PARENT_SETTID:
49f08c3bdfSopenharmony_ci	 * When the parent tid is written to the memory location for
50f08c3bdfSopenharmony_ci	 * CLONE_PARENT_SETTID we're past the point of no return of process
51f08c3bdfSopenharmony_ci	 * creation, i.e. the return value from put_user() isn't checked and
52f08c3bdfSopenharmony_ci	 * can't be checked anymore so you'd never receive EFAULT for a bogus
53f08c3bdfSopenharmony_ci	 * parent_tid memory address.
54f08c3bdfSopenharmony_ci	 *
55f08c3bdfSopenharmony_ci	 * https://lore.kernel.org/linux-m68k/20200627122332.ki2otaiw3v7wndbl@wittgenstein/T/#u
56f08c3bdfSopenharmony_ci	 */
57f08c3bdfSopenharmony_ci};
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_cistatic void setup(void)
60f08c3bdfSopenharmony_ci{
61f08c3bdfSopenharmony_ci	clone3_supported_by_kernel();
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	TST_EXP_EQ_SZ(sizeof(struct clone_args_minimal), 64);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	void *p = tst_get_bad_addr(NULL);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	invalid_args = p;
68f08c3bdfSopenharmony_ci	invalid_address = p;
69f08c3bdfSopenharmony_ci}
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_cistatic void run(unsigned int n)
72f08c3bdfSopenharmony_ci{
73f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
74f08c3bdfSopenharmony_ci	struct clone_args *args = *tc->args;
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	if (args == valid_args) {
77f08c3bdfSopenharmony_ci		args->flags = tc->flags;
78f08c3bdfSopenharmony_ci		if (tc->pidfd)
79f08c3bdfSopenharmony_ci			args->pidfd = (uint64_t)(*tc->pidfd);
80f08c3bdfSopenharmony_ci		else
81f08c3bdfSopenharmony_ci			args->pidfd = 0;
82f08c3bdfSopenharmony_ci		args->exit_signal = tc->exit_signal;
83f08c3bdfSopenharmony_ci		args->stack = tc->stack;
84f08c3bdfSopenharmony_ci		args->stack_size = tc->stack_size;
85f08c3bdfSopenharmony_ci		args->tls = tc->tls;
86f08c3bdfSopenharmony_ci	}
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	TEST(clone3(args, tc->size));
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_ci	if (!TST_RET)
91f08c3bdfSopenharmony_ci		exit(EXIT_SUCCESS);
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	if (TST_RET >= 0) {
94f08c3bdfSopenharmony_ci		tst_res(TFAIL, "%s: clone3() passed unexpectedly", tc->name);
95f08c3bdfSopenharmony_ci		return;
96f08c3bdfSopenharmony_ci	}
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	if (tc->exp_errno != TST_ERR) {
99f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "%s: clone3() should fail with %s",
100f08c3bdfSopenharmony_ci			tc->name, tst_strerrno(tc->exp_errno));
101f08c3bdfSopenharmony_ci		return;
102f08c3bdfSopenharmony_ci	}
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	tst_res(TPASS | TTERRNO, "%s: clone3() failed as expected", tc->name);
105f08c3bdfSopenharmony_ci}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_cistatic struct tst_test test = {
108f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
109f08c3bdfSopenharmony_ci	.test = run,
110f08c3bdfSopenharmony_ci	.setup = setup,
111f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
112f08c3bdfSopenharmony_ci	.bufs = (struct tst_buffers []) {
113f08c3bdfSopenharmony_ci		{&valid_args, .size = sizeof(*valid_args)},
114f08c3bdfSopenharmony_ci		{},
115f08c3bdfSopenharmony_ci	}
116f08c3bdfSopenharmony_ci};
117