1 /*
2 * Copyright (c) International Business Machines Corp., 2007
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
11 * the GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 *
16 ***************************************************************************
17  * Copyright 2007 IBM
18  * Author: Serge Hallyn <serue@us.ibm.com>
19  *
20  * test1:
21 	P1: A=gethostname
22 	P2: B=gethostname
23 	Ensure(A==B)
24 
25  * test2:
26 	P1: sethostname(A);
27 	P2: (wait); B=gethostname
28 	Ensure (A==B)
29 
30  * test3:
31 	P1: A=gethostname; unshare(utsname); sethostname(newname); C=gethostname
32 	P2: B=gethostname; (wait); (wait); D=gethostname
33 	Ensure (A==B && A==D && C!=D)
34 
35  * test4:
36 	P1: A=gethostname; unshare(utsname); (wait); C=gethostname
37 	P2: B=gethostname; (wait); sethostname(newname); D=gethostname
38 	Ensure (A==B && A==C && C!=D)
39 
40  * test5:
41 	P1: drop_privs(); unshare(utsname); (wait); C=gethostname
42 	P2: (wait); sethostname(B); D=gethostname
43 	Ensure (B==C==D) and state is ok.
44  *
45  */
46 
47 #define _GNU_SOURCE 1
48 #include <sys/wait.h>
49 #include <assert.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <errno.h>
55 #include "libclone.h"
56 #include "test.h"
57 #include "safe_macros.h"
58 
59 char *TCID = "uts_namespace";
60 int TST_TOTAL = 1;
61 
dummy_child(void * v)62 static int dummy_child(void *v)
63 {
64 	(void) v;
65 	return 0;
66 }
67 
check_newuts(void)68 static void check_newuts(void)
69 {
70 	int pid, status;
71 
72 	if (tst_kvercmp(2, 6, 19) < 0)
73 		tst_brkm(TCONF, NULL, "CLONE_NEWUTS not supported");
74 
75 	pid = do_clone_unshare_test(T_CLONE, CLONE_NEWUTS, dummy_child, NULL);
76 	if (pid == -1)
77 		tst_brkm(TCONF | TERRNO, NULL, "CLONE_NEWUTS not supported");
78 
79 	SAFE_WAIT(NULL, &status);
80 }
81 
drop_root(void)82 int drop_root(void)
83 {
84 	int ret;
85 	ret = setresuid(1000, 1000, 1000);
86 	if (ret) {
87 		perror("setresuid");
88 		exit(4);
89 	}
90 	return 1;
91 }
92 
93 #define HLEN 100
94 #define NAME1 "serge1"
95 #define NAME2 "serge2"
96 
97 int p1fd[2], p2fd[2];
98 static char oldhost[HLEN];
99 pid_t cpid;
100 
picknewhostname(char * orig,char * new)101 void picknewhostname(char *orig, char *new)
102 {
103 	memset(new, 0, HLEN);
104 	if (strcmp(orig, NAME1) == 0)
105 		strcpy(new, NAME2);
106 	else
107 		strcpy(new, NAME1);
108 }
109 
zeroize(char * s)110 void zeroize(char *s)
111 {
112 	memset(s, 0, HLEN);
113 }
114 
115 char *tsttype;
P1(void * vtest)116 int P1(void *vtest)
117 {
118 	char hostname[HLEN], newhostname[HLEN], rhostname[HLEN];
119 	int err;
120 	int len;
121 	int testnum;
122 
123 	testnum = atoi((char *)vtest);
124 
125 	close(p1fd[1]);
126 	close(p2fd[0]);
127 
128 	switch (testnum) {
129 	case 1:
130 		gethostname(hostname, HLEN);
131 		zeroize(rhostname);
132 		len = read(p1fd[0], rhostname, HLEN);
133 		if (strcmp(hostname, rhostname) == 0) {
134 			tst_resm(TPASS, "test 1 (%s): success", tsttype);
135 			tst_exit();
136 		}
137 		tst_brkm(TFAIL, NULL,
138 			 "test 1 (%s): hostname 1 %s, hostname 2 %s",
139 			 tsttype, hostname, rhostname);
140 	case 2:
141 		gethostname(hostname, HLEN);
142 		picknewhostname(hostname, newhostname);
143 		err = sethostname(newhostname, strlen(newhostname));
144 		write(p2fd[1], "1", 1);
145 		if (err == -1) {
146 			tst_brkm(TFAIL, NULL,
147 				 "test 2 (%s): failed to sethostname",
148 				 tsttype);
149 		}
150 		zeroize(rhostname);
151 		len = read(p1fd[0], rhostname, HLEN);
152 		if (strcmp(newhostname, rhostname) == 0) {
153 			tst_resm(TPASS, "test 2 (%s): success", tsttype);
154 			tst_exit();
155 		}
156 		tst_brkm(TFAIL, NULL,
157 			 "test 2 (%s) hostname 1 %s, hostname 2 %s",
158 			 tsttype, newhostname, rhostname);
159 	case 3:
160 		gethostname(hostname, HLEN);
161 		picknewhostname(hostname, newhostname);
162 		err = sethostname(newhostname, strlen(newhostname));
163 		write(p2fd[1], "1", 1);
164 		if (err == -1) {
165 			tst_brkm(TFAIL, NULL,
166 				 "test 3 (%s): failed to sethostname",
167 				 tsttype);
168 		}
169 
170 		zeroize(rhostname);
171 		len = read(p1fd[0], rhostname, HLEN);
172 		if (strcmp(newhostname, rhostname) == 0) {
173 			tst_brkm(TFAIL,
174 				 NULL,
175 				 "test 3 (%s): hostname 1 %s, hostname 2 %s, these should have been different",
176 				 tsttype, newhostname, rhostname);
177 		}
178 		if (strcmp(hostname, rhostname) == 0) {
179 			tst_resm(TPASS, "test 3 (%s): success", tsttype);
180 			tst_exit();
181 		}
182 		tst_brkm(TFAIL,
183 			 NULL,
184 			 "test 3 (%s): hostname 1 %s, hostname 2 %s, should have been same",
185 			 tsttype, hostname, rhostname);
186 
187 	case 4:
188 		gethostname(hostname, HLEN);
189 		write(p2fd[1], "1", 1);	/* tell p2 to go ahead and sethostname */
190 		zeroize(rhostname);
191 		len = read(p1fd[0], rhostname, HLEN);
192 		gethostname(newhostname, HLEN);
193 		if (strcmp(hostname, newhostname) != 0) {
194 			tst_brkm(TFAIL,
195 				 NULL,
196 				 "test 4 (%s): hostname 1 %s, hostname 2 %s, should be same",
197 				 tsttype, hostname, newhostname);
198 		}
199 		if (strcmp(hostname, rhostname) == 0) {
200 			tst_brkm(TFAIL,
201 				 NULL,
202 				 "test 4 (%s): hostname 1 %s, hostname 2 %s, should be different",
203 				 tsttype, hostname, rhostname);
204 		}
205 		tst_resm(TPASS, "test 4 (%s): successful", tsttype);
206 		tst_exit();
207 	case 5:
208 		write(p2fd[1], "1", 1);	/* tell p2 to go ahead and sethostname */
209 		zeroize(rhostname);
210 		len = read(p1fd[0], rhostname, HLEN);
211 		gethostname(newhostname, HLEN);
212 		if (strcmp(rhostname, newhostname) != 0) {
213 			tst_brkm(TFAIL,
214 				 NULL,
215 				 "test 5 (%s): hostnames %s and %s should be same",
216 				 tsttype, rhostname, newhostname);
217 		}
218 		tst_resm(TPASS, "test 5 (%s): successful", tsttype);
219 		tst_exit();
220 	default:
221 		break;
222 	}
223 	tst_exit();
224 }
225 
P2(void * vtest)226 int P2(void *vtest)
227 {
228 	char hostname[HLEN], newhostname[HLEN];
229 	int len;
230 	int testnum;
231 
232 	testnum = atoi((char *)vtest);
233 
234 	close(p1fd[0]);
235 	close(p2fd[1]);
236 
237 	switch (testnum) {
238 	case 1:
239 		gethostname(hostname, HLEN);
240 		write(p1fd[1], hostname, strlen(hostname));
241 		break;
242 	case 2:
243 	case 3:
244 		len = 0;
245 		while (!len) {
246 			len = read(p2fd[0], hostname, 1);
247 		}
248 		gethostname(hostname, HLEN);
249 		write(p1fd[1], hostname, strlen(hostname));
250 		break;
251 	case 4:
252 	case 5:
253 		len = 0;
254 		while (!len) {
255 			len = read(p2fd[0], hostname, 1);
256 		}
257 		if (hostname[0] == '0') {
258 			tst_resm(TPASS, "P2: P1 claims error");
259 			return 0;
260 		}
261 		gethostname(hostname, HLEN);
262 		picknewhostname(hostname, newhostname);
263 		sethostname(newhostname, strlen(newhostname));
264 		write(p1fd[1], newhostname, strlen(newhostname));
265 		break;
266 	default:
267 		tst_resm(TFAIL, "undefined test: %d", testnum);
268 		break;
269 	}
270 	return 0;
271 }
272 
setup(void)273 static void setup(void)
274 {
275 	gethostname(oldhost, HLEN);
276 	tst_require_root();
277 	check_newuts();
278 }
279 
cleanup(void)280 static void cleanup(void)
281 {
282 	sethostname(oldhost, strlen(oldhost));
283 }
284 
285 #define UNSHARESTR "unshare"
286 #define CLONESTR "clone"
main(int argc,char * argv[])287 int main(int argc, char *argv[])
288 {
289 	int r, pid, use_clone = T_UNSHARE;
290 	int testnum;
291 	void *vtest;
292 
293 	setup();
294 	if (argc != 3) {
295 		tst_resm(TFAIL, "Usage: %s <clone|unshare> <testnum>",
296 			 argv[0]);
297 		tst_resm(TFAIL,
298 			 " where clone or unshare specifies unshare method,");
299 		tst_resm(TFAIL, " and testnum is between 1 and 5 inclusive");
300 		exit(2);
301 	}
302 	if (pipe(p1fd) == -1) {
303 		perror("pipe");
304 		exit(EXIT_FAILURE);
305 	}
306 	if (pipe(p2fd) == -1) {
307 		perror("pipe");
308 		exit(EXIT_FAILURE);
309 	}
310 
311 	tsttype = UNSHARESTR;
312 	if (strcmp(argv[1], "clone") == 0) {
313 		use_clone = T_CLONE;
314 		tsttype = CLONESTR;
315 	}
316 
317 	testnum = atoi(argv[2]);
318 
319 	vtest = (void *)argv[2];
320 	switch (testnum) {
321 	case 1:
322 	case 2:
323 		r = do_clone_unshare_tests(T_NONE, 0, P1, vtest, P2, vtest);
324 		break;
325 	case 3:
326 	case 4:
327 		r = do_clone_unshare_tests(use_clone, CLONE_NEWUTS,
328 					   P1, vtest, P2, vtest);
329 		break;
330 	case 5:
331 		pid = fork();
332 		if (pid == -1) {
333 			perror("fork");
334 			exit(2);
335 		}
336 		if (pid == 0) {
337 			if (!drop_root()) {
338 				tst_brkm(TFAIL, NULL, "failed to drop root.");
339 			}
340 			r = do_clone_unshare_test(use_clone, CLONE_NEWUTS,
341 						  P1, vtest);
342 			write(p2fd[1], "0", 1);	/* don't let p2 hang */
343 			exit(0);
344 		} else {
345 			P2(vtest);
346 		}
347 		break;
348 	default:
349 		tst_resm(TFAIL,
350 			 "testnum should be between 1 and 5 inclusive.");
351 		break;
352 	}
353 
354 	cleanup();
355 	tst_exit();
356 }
357