1 /*
2  * Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved.
3  * Copyright (c) 2013 Fujitsu Ltd.
4  * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of version 2 of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it would be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program.
16  */
17 
18 #define _GNU_SOURCE
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <sched.h>
23 #include <sys/wait.h>
24 #include <linux/futex.h>
25 
26 #include "tst_test.h"
27 #include "clone_platform.h"
28 #include "lapi/syscalls.h"
29 
30 static pid_t ptid, ctid, tgid;
31 static void *child_stack;
32 
33 static void test_clone_parent(int t);
34 static int child_clone_parent(void *);
35 static pid_t parent_ppid;
36 
37 static void test_clone_tid(int t);
38 static int child_clone_child_settid(void *);
39 static int child_clone_parent_settid(void *);
40 
41 #ifdef CLONE_STOPPED
42 static void test_clone_stopped(int t);
43 static int child_clone_stopped(void *);
44 static int stopped_flag;
45 #endif
46 
47 static void test_clone_thread(int t);
48 static int child_clone_thread(void *);
49 
50 /*
51  * Children cloned with CLONE_VM should avoid using any functions that
52  * might require dl_runtime_resolve, because they share thread-local
53  * storage with parent. If both try to resolve symbols at same time you
54  * can crash, likely at _dl_x86_64_restore_sse().
55  * See this thread for relevant discussion:
56  * http://www.mail-archive.com/utrace-devel@redhat.com/msg01944.html
57  */
58 static struct test_case {
59 	char *name;
60 	int flags;
61 	void (*testfunc)(int);
62 	int (*do_child)(void *);
63 } test_cases[] = {
64 	{"CLONE_PARENT", CLONE_PARENT | SIGCHLD,
65 	 test_clone_parent, child_clone_parent},
66 	{"CLONE_CHILD_SETTID", CLONE_CHILD_SETTID | SIGCHLD,
67 	 test_clone_tid, child_clone_child_settid},
68 	{"CLONE_PARENT_SETTID", CLONE_PARENT_SETTID | CLONE_VM | SIGCHLD,
69 	 test_clone_tid, child_clone_parent_settid},
70 #ifdef CLONE_STOPPED
71 	{"CLONE_STOPPED", CLONE_STOPPED | CLONE_VM | SIGCHLD,
72 	 test_clone_stopped, child_clone_stopped},
73 #endif
74 	{"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM |
75 	 CLONE_CHILD_CLEARTID | SIGCHLD,
76 	 test_clone_thread, child_clone_thread},
77 };
78 
do_test(unsigned int i)79 static void do_test(unsigned int i)
80 {
81 	tst_res(TINFO, "running %s", test_cases[i].name);
82 	test_cases[i].testfunc(i);
83 }
84 
setup(void)85 static void setup(void)
86 {
87 	child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
88 }
89 
cleanup(void)90 static void cleanup(void)
91 {
92 	free(child_stack);
93 }
94 
clone_child(const struct test_case * t)95 static long clone_child(const struct test_case *t)
96 {
97 	TEST(ltp_clone7(t->flags, t->do_child, NULL, CHILD_STACK_SIZE,
98 		child_stack, &ptid, NULL, &ctid));
99 
100 	if (TEST_RETURN == -1 && TTERRNO == ENOSYS)
101 		tst_brk(TCONF, "clone does not support 7 args");
102 
103 	if (TEST_RETURN == -1)
104 		tst_brk(TBROK | TTERRNO, "%s clone() failed", t->name);
105 
106 	return TEST_RETURN;
107 }
108 
test_clone_parent(int t)109 static void test_clone_parent(int t)
110 {
111 	pid_t child;
112 
113 	child = SAFE_FORK();
114 	if (!child) {
115 		parent_ppid = getppid();
116 		clone_child(&test_cases[t]);
117 		_exit(0);
118 	}
119 	tst_reap_children();
120 }
121 
child_clone_parent(void * arg LTP_ATTRIBUTE_UNUSED)122 static int child_clone_parent(void *arg LTP_ATTRIBUTE_UNUSED)
123 {
124 	if (parent_ppid == getppid()) {
125 		tst_res(TPASS, "clone and forked child has the same parent");
126 	} else {
127 		tst_res(TFAIL, "getppid != parent_ppid (%d != %d)",
128 			parent_ppid, getppid());
129 	}
130 	tst_syscall(__NR_exit, 0);
131 	return 0;
132 }
133 
test_clone_tid(int t)134 static void test_clone_tid(int t)
135 {
136 	clone_child(&test_cases[t]);
137 	tst_reap_children();
138 }
139 
child_clone_child_settid(void * arg LTP_ATTRIBUTE_UNUSED)140 static int child_clone_child_settid(void *arg LTP_ATTRIBUTE_UNUSED)
141 {
142 	if (ctid == tst_syscall(__NR_getpid))
143 		tst_res(TPASS, "clone() correctly set ctid");
144 	else
145 		tst_res(TFAIL, "ctid != getpid() (%d != %d)", ctid, getpid());
146 	tst_syscall(__NR_exit, 0);
147 	return 0;
148 }
149 
child_clone_parent_settid(void * arg LTP_ATTRIBUTE_UNUSED)150 static int child_clone_parent_settid(void *arg LTP_ATTRIBUTE_UNUSED)
151 {
152 	if (ptid == tst_syscall(__NR_getpid))
153 		tst_res(TPASS, "clone() correctly set ptid");
154 	else
155 		tst_res(TFAIL, "ptid != getpid() (%d != %d)", ptid, getpid());
156 	tst_syscall(__NR_exit, 0);
157 	return 0;
158 }
159 
160 #ifdef CLONE_STOPPED
test_clone_stopped(int t)161 static void test_clone_stopped(int t)
162 {
163 	pid_t child;
164 
165 	if (tst_kvercmp(2, 6, 38) >= 0) {
166 		tst_res(TCONF, "CLONE_STOPPED skipped for kernels >= 2.6.38");
167 		return;
168 	}
169 
170 	child = clone_child(&test_cases[t]);
171 
172 	TST_PROCESS_STATE_WAIT(child, 'T');
173 
174 	stopped_flag = 0;
175 
176 	SAFE_KILL(child, SIGCONT);
177 
178 	tst_reap_children();
179 
180 	if (stopped_flag == 1)
181 		tst_res(TPASS, "clone stopped and resumed as expected");
182 	else
183 		tst_res(TFAIL, "clone not stopped, flag %d", stopped_flag);
184 }
185 
child_clone_stopped(void * arg LTP_ATTRIBUTE_UNUSED)186 static int child_clone_stopped(void *arg LTP_ATTRIBUTE_UNUSED)
187 {
188 	stopped_flag = 1;
189 	tst_syscall(__NR_exit, 0);
190 	return 0;
191 }
192 #endif
193 
test_clone_thread(int t)194 static void test_clone_thread(int t)
195 {
196 	pid_t child;
197 
198 	child = SAFE_FORK();
199 	if (!child) {
200 		struct timespec timeout = { 5 /* sec */, 0 };
201 
202 		tgid = tst_syscall(__NR_getpid);
203 		ctid = -1;
204 
205 		clone_child(&test_cases[t]);
206 
207 		if (syscall(SYS_futex, &ctid, FUTEX_WAIT, -1, &timeout)) {
208 			/*
209 			 * futex here is racing with clone() above.
210 			 * Which means we can get EWOULDBLOCK if
211 			 * ctid has been already changed by clone()
212 			 * before we make the call. As long as ctid
213 			 * changes we should not report error when
214 			 * futex returns EWOULDBLOCK.
215 			 */
216 			if (errno != EWOULDBLOCK || ctid == -1) {
217 				tst_res(TFAIL | TERRNO,
218 					"futex failed, ctid: %d", ctid);
219 				_exit(0);
220 			}
221 		}
222 		tst_res(TPASS, "futex exit on ctid change, ctid: %d", ctid);
223 		_exit(0);
224 	}
225 
226 	tst_reap_children();
227 }
228 
child_clone_thread(void * arg LTP_ATTRIBUTE_UNUSED)229 static int child_clone_thread(void *arg LTP_ATTRIBUTE_UNUSED)
230 {
231 	if (tgid == tst_syscall(__NR_getpid))
232 		tst_res(TPASS, "clone has the same thread id");
233 	else
234 		tst_res(TFAIL, "clone's thread id not equal parent's id");
235 	tst_syscall(__NR_exit, 0);
236 	return 0;
237 }
238 
239 static struct tst_test test = {
240 	.tcnt = ARRAY_SIZE(test_cases),
241 	.test = do_test,
242 	.setup = setup,
243 	.cleanup = cleanup,
244 	.forks_child = 1
245 };
246