Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <fcntl.h>
3 : : #include <sys/wait.h>
4 : : #include <stdlib.h>
5 : : #include "util.h"
6 : : #include "syscall.h"
7 : : #include "uts_ns.h"
8 : : #include "ipc_ns.h"
9 : : #include "mount.h"
10 : : #include "namespaces.h"
11 : : #include "net.h"
12 : :
13 : 386 : int switch_ns(int pid, int type, char *ns, int *rst)
14 : : {
15 : : char buf[32];
16 : : int nsfd;
17 : 386 : int ret = -1;
18 : :
19 : 386 : snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", pid, ns);
20 : 386 : nsfd = open(buf, O_RDONLY);
21 [ - + ]: 386 : if (nsfd < 0) {
22 : 0 : pr_perror("Can't open ipcns file");
23 : 0 : goto err_ns;
24 : : }
25 : :
26 [ + + ]: 386 : if (rst) {
27 : 152 : snprintf(buf, sizeof(buf), "/proc/self/ns/%s", ns);
28 : 152 : *rst = open(buf, O_RDONLY);
29 [ - + ]: 152 : if (*rst < 0) {
30 : 0 : pr_perror("Can't open ns file");
31 : 0 : goto err_rst;
32 : : }
33 : : }
34 : :
35 : 386 : ret = setns(nsfd, type);
36 [ - + ]: 386 : if (ret < 0) {
37 : 0 : pr_perror("Can't setns %d/%s", pid, ns);
38 : : goto err_set;
39 : : }
40 : :
41 : 386 : close(nsfd);
42 : : return 0;
43 : :
44 : : err_set:
45 [ # # ]: 0 : if (rst)
46 : 0 : close(*rst);
47 : : err_rst:
48 : 386 : close(nsfd);
49 : : err_ns:
50 : : return -1;
51 : : }
52 : :
53 : 152 : int restore_ns(int rst, int type)
54 : : {
55 : : int ret;
56 : :
57 : 152 : ret = setns(rst, type);
58 [ - + ]: 152 : if (ret < 0)
59 : 0 : pr_perror("Can't restore ns back");
60 : :
61 : 152 : return ret;
62 : : }
63 : :
64 : 83 : static int do_dump_namespaces(struct pid *ns_pid, unsigned int ns_flags)
65 : : {
66 : : struct cr_fdset *fdset;
67 : 83 : int ret = 0;
68 : :
69 : 83 : fdset = cr_ns_fdset_open(ns_pid->virt, O_DUMP);
70 [ + - ]: 83 : if (fdset == NULL)
71 : : return -1;
72 : :
73 [ + + ]: 83 : if (ns_flags & CLONE_NEWUTS) {
74 : 77 : pr_info("Dump UTS namespace\n");
75 : 77 : ret = dump_uts_ns(ns_pid->real, fdset);
76 [ + - ]: 77 : if (ret < 0)
77 : : goto err;
78 : : }
79 [ + + ]: 83 : if (ns_flags & CLONE_NEWIPC) {
80 : 81 : pr_info("Dump IPC namespace\n");
81 : 81 : ret = dump_ipc_ns(ns_pid->real, fdset);
82 [ + - ]: 81 : if (ret < 0)
83 : : goto err;
84 : : }
85 [ + + ]: 83 : if (ns_flags & CLONE_NEWNS) {
86 : 77 : pr_info("Dump MNT namespace (mountpoints)\n");
87 : 77 : ret = dump_mnt_ns(ns_pid->real, fdset);
88 [ + - ]: 77 : if (ret < 0)
89 : : goto err;
90 : : }
91 [ + + ]: 83 : if (ns_flags & CLONE_NEWNET) {
92 : 76 : pr_info("Dump NET namespace info\n");
93 : 76 : ret = dump_net_ns(ns_pid->real, fdset);
94 : : if (ret < 0)
95 : : goto err;
96 : : }
97 : : err:
98 : 83 : close_cr_fdset(&fdset);
99 : : return ret;
100 : :
101 : : }
102 : :
103 : 83 : int dump_namespaces(struct pid *ns_pid, unsigned int ns_flags)
104 : : {
105 : : int pid, status;
106 : 83 : int ret = 0;
107 : :
108 : : /*
109 : : * The setns syscall is cool, we can switch to the other
110 : : * namespace and then return back to our initial one, but
111 : : * for me it's much easier just to fork another task and
112 : : * let it do the job, all the more so it can be done in
113 : : * parallel with task dumping routine.
114 : : *
115 : : * However, the question how to dump sockets from the target
116 : : * net namesapce with this is still open
117 : : */
118 : :
119 : 83 : pr_info("Dumping %d(%d)'s namespaces\n", ns_pid->virt, ns_pid->real);
120 : :
121 [ - + ][ + + ]: 83 : if ((opts.namespaces_flags & CLONE_NEWPID) && ns_pid->virt != 1) {
122 : 0 : pr_err("Can't dump a pid namespace without the process init\n");
123 : : return -1;
124 : : }
125 : :
126 : 83 : pid = fork();
127 [ - + ]: 166 : if (pid < 0) {
128 : 0 : pr_perror("Can't fork ns dumper");
129 : : return -1;
130 : : }
131 : :
132 [ + + ]: 166 : if (pid == 0) {
133 : 83 : ret = do_dump_namespaces(ns_pid, ns_flags);
134 : 83 : exit(ret);
135 : : }
136 : :
137 : 83 : ret = waitpid(pid, &status, 0);
138 [ - + ]: 83 : if (ret != pid) {
139 : 0 : pr_perror("Can't wait ns dumper");
140 : : return -1;
141 : : }
142 : :
143 [ + - ][ - + ]: 83 : if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
144 : 0 : pr_err("Namespaces dumping finished with error %d\n", status);
145 : : return -1;
146 : : }
147 : :
148 : 83 : pr_info("Namespaces dump complete\n");
149 : : return 0;
150 : : }
151 : :
152 : 214 : int prepare_namespace(int pid, unsigned long clone_flags)
153 : : {
154 : 214 : pr_info("Restoring namespaces %d flags 0x%lx\n",
155 : : pid, clone_flags);
156 : :
157 : : /*
158 : : * On netns restore we launch an IP tool, thus we
159 : : * have to restore it _before_ altering the mount
160 : : * tree (i.e. -- mnt_ns restoring)
161 : : */
162 : :
163 [ + - ][ + + ]: 214 : if ((clone_flags & CLONE_NEWNET) && prepare_net_ns(pid))
164 : : return -1;
165 [ + + ][ + - ]: 355 : if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(pid))
166 : : return -1;
167 [ + + ][ + - ]: 355 : if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(pid))
168 : : return -1;
169 [ + + ][ + - ]: 355 : if ((clone_flags & CLONE_NEWNS) && prepare_mnt_ns(pid))
170 : : return -1;
171 : :
172 : : return 0;
173 : : }
174 : :
175 : 0 : int try_show_namespaces(int ns_pid, struct cr_options *o)
176 : : {
177 : : struct cr_fdset *fdset;
178 : : int i;
179 : :
180 : 0 : fdset = cr_ns_fdset_open(ns_pid, O_SHOW);
181 [ # # ]: 0 : if (!fdset)
182 : : return -1;
183 : :
184 [ # # ]: 0 : for (i = _CR_FD_NS_FROM + 1; i < _CR_FD_NS_TO; i++) {
185 : : int fd;
186 : :
187 [ # # ]: 0 : if (!fdset_template[i].show)
188 : 0 : continue;
189 : :
190 : 0 : fd = fdset_fd(fdset, i);
191 [ # # ]: 0 : if (fd == -1)
192 : 0 : continue;
193 : :
194 : 0 : fdset_template[i].show(fdset_fd(fdset, i), o);
195 : : }
196 : :
197 : 0 : close_cr_fdset(&fdset);
198 : : return 0;
199 : : }
|