1 /*
2  * Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #define _GNU_SOURCE
19 #include <sched.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 
23 #include "tst_test.h"
24 #include "clone_platform.h"
25 #include "lapi/syscalls.h"
26 #include "lapi/namespaces_constants.h"
27 
28 static void *child_stack;
29 static int sysctl_net = -1;
30 static int sysctl_net_new = -1;
31 static const char sysctl_path[] = "/proc/sys/net/ipv4/conf/lo/tag";
32 static const char sysctl_path_def[] = "/proc/sys/net/ipv4/conf/default/tag";
33 static int flags = CLONE_NEWNET | CLONE_VM | SIGCHLD;
34 
setup(void)35 static void setup(void)
36 {
37 	child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
38 }
39 
cleanup(void)40 static void cleanup(void)
41 {
42 	if (sysctl_net != -1)
43 		SAFE_FILE_PRINTF(sysctl_path, "%d", sysctl_net);
44 
45 	free(child_stack);
46 }
47 
newnet(void * arg LTP_ATTRIBUTE_UNUSED)48 static int newnet(void *arg LTP_ATTRIBUTE_UNUSED)
49 {
50 	SAFE_FILE_SCANF(sysctl_path, "%d", &sysctl_net_new);
51 	tst_syscall(__NR_exit, 0);
52 	return 0;
53 }
54 
clone_child(void)55 static long clone_child(void)
56 {
57 	TEST(ltp_clone(flags, newnet, NULL, CHILD_STACK_SIZE, child_stack));
58 
59 	if (TEST_RETURN == -1 && TEST_ERRNO == EINVAL)
60 		tst_brk(TCONF, "CONFIG_NET_NS was disabled");
61 
62 	if (TEST_RETURN == -1)
63 		tst_brk(TBROK | TTERRNO, "clone(CLONE_NEWNET) failed");
64 
65 	return TEST_RETURN;
66 }
67 
do_test(void)68 static void do_test(void)
69 {
70 	int def_val;
71 
72 	tst_res(TINFO, "create clone in a new netns with 'CLONE_NEWNET' flag");
73 
74 	SAFE_FILE_SCANF(sysctl_path, "%d", &sysctl_net);
75 	SAFE_FILE_PRINTF(sysctl_path, "%d", sysctl_net + 1);
76 
77 	clone_child();
78 	tst_reap_children();
79 
80 	if (sysctl_net_new == (sysctl_net + 1)) {
81 		tst_res(TFAIL, "sysctl params equal: %s=%d",
82 			sysctl_path, sysctl_net_new);
83 	}
84 
85 	SAFE_FILE_SCANF(sysctl_path_def, "%d", &def_val);
86 
87 	if (sysctl_net_new != def_val) {
88 		tst_res(TFAIL, "netns param init to non-default value %d",
89 			sysctl_net_new);
90 	}
91 
92 	/* restore previous value */
93 	SAFE_FILE_PRINTF(sysctl_path, "%d", sysctl_net);
94 
95 	tst_res(TPASS, "sysctl params differ in new netns");
96 }
97 
98 static struct tst_test test = {
99 	.test_all = do_test,
100 	.setup = setup,
101 	.cleanup = cleanup,
102 	.needs_root = 1,
103 	.min_kver = "2.6.24",
104 };
105