Branch data Line data Source code
1 : : #include <sys/mman.h>
2 : : #include <unistd.h>
3 : : #include <stdlib.h>
4 : :
5 : : #include "cr_options.h"
6 : : #include "pstree.h"
7 : : #include "util.h"
8 : : #include "lock.h"
9 : : #include "namespaces.h"
10 : : #include "files.h"
11 : : #include "tty.h"
12 : : #include "mount.h"
13 : : #include "asm/dump.h"
14 : :
15 : : #include "protobuf.h"
16 : : #include "protobuf/pstree.pb-c.h"
17 : :
18 : : struct pstree_item *root_item;
19 : :
20 : 1903 : void core_entry_free(CoreEntry *core)
21 : : {
22 [ + + ][ - + ]: 1903 : if (core->tc && core->tc->timers)
23 [ # # ]: 0 : xfree(core->tc->timers->posix);
24 : 1903 : arch_free_thread_info(core);
25 [ + - ]: 1903 : xfree(core);
26 : 1903 : }
27 : :
28 : : #ifndef RLIM_NLIMITS
29 : : # define RLIM_NLIMITS 16
30 : : #endif
31 : :
32 : 5567 : CoreEntry *core_entry_alloc(int th, int tsk)
33 : : {
34 : : size_t sz;
35 : : CoreEntry *core = NULL;
36 : : void *m;
37 : :
38 : : sz = sizeof(CoreEntry);
39 [ + + ]: 5567 : if (tsk) {
40 : : sz += sizeof(TaskCoreEntry) + TASK_COMM_LEN;
41 [ + + ]: 3685 : if (th) {
42 : : sz += sizeof(TaskRlimitsEntry);
43 : : sz += RLIM_NLIMITS * sizeof(RlimitEntry *);
44 : : sz += RLIM_NLIMITS * sizeof(RlimitEntry);
45 : : sz += sizeof(TaskTimersEntry);
46 : : sz += 3 * sizeof(ItimerEntry); /* 3 for real, virt and prof */
47 : : }
48 : : }
49 [ + + ]: 5567 : if (th)
50 : 5546 : sz += sizeof(ThreadCoreEntry) + sizeof(ThreadSasEntry);
51 : :
52 [ - + ]: 5567 : m = xmalloc(sz);
53 [ + - ]: 5567 : if (m) {
54 : : core = xptr_pull(&m, CoreEntry);
55 : 5567 : core_entry__init(core);
56 : 5567 : core->mtype = CORE_ENTRY__MARCH;
57 : :
58 [ + + ]: 5567 : if (tsk) {
59 : 3685 : core->tc = xptr_pull(&m, TaskCoreEntry);
60 : 3685 : task_core_entry__init(core->tc);
61 : 7370 : core->tc->comm = xptr_pull_s(&m, TASK_COMM_LEN);
62 : 3685 : memzero(core->tc->comm, TASK_COMM_LEN);
63 : :
64 [ + + ]: 3685 : if (th) {
65 : : TaskRlimitsEntry *rls;
66 : : TaskTimersEntry *tte;
67 : : int i;
68 : :
69 : 3664 : rls = core->tc->rlimits = xptr_pull(&m, TaskRlimitsEntry);
70 : 3664 : task_rlimits_entry__init(rls);
71 : :
72 : 3664 : rls->n_rlimits = RLIM_NLIMITS;
73 : 3664 : rls->rlimits = xptr_pull_s(&m, sizeof(RlimitEntry *) * RLIM_NLIMITS);
74 : :
75 [ + + ]: 62288 : for (i = 0; i < RLIM_NLIMITS; i++) {
76 : 117248 : rls->rlimits[i] = xptr_pull(&m, RlimitEntry);
77 : 58624 : rlimit_entry__init(rls->rlimits[i]);
78 : : }
79 : :
80 : 3664 : tte = core->tc->timers = xptr_pull(&m, TaskTimersEntry);
81 : 3664 : task_timers_entry__init(tte);
82 : 3664 : tte->real = xptr_pull(&m, ItimerEntry);
83 : 3664 : itimer_entry__init(tte->real);
84 : 3664 : tte->virt = xptr_pull(&m, ItimerEntry);
85 : 3664 : itimer_entry__init(tte->virt);
86 : 3664 : tte->prof = xptr_pull(&m, ItimerEntry);
87 : 3664 : itimer_entry__init(tte->prof);
88 : : }
89 : : }
90 : :
91 [ + + ]: 5567 : if (th) {
92 : 5546 : core->thread_core = xptr_pull(&m, ThreadCoreEntry);
93 : 5546 : thread_core_entry__init(core->thread_core);
94 : 5546 : core->thread_core->sas = xptr_pull(&m, ThreadSasEntry);
95 : 5546 : thread_sas_entry__init(core->thread_core->sas);
96 : :
97 [ - + ]: 5546 : if (arch_alloc_thread_info(core)) {
98 [ # # ]: 0 : xfree(core);
99 : : core = NULL;
100 : : }
101 : : }
102 : : }
103 : :
104 : 5567 : return core;
105 : : }
106 : :
107 : 3664 : int pstree_alloc_cores(struct pstree_item *item)
108 : : {
109 : : unsigned int i;
110 : :
111 [ - + ]: 3664 : item->core = xzalloc(sizeof(*item->core) * item->nr_threads);
112 [ + - ]: 3664 : if (!item->core)
113 : : return -1;
114 : :
115 [ + + ]: 9210 : for (i = 0; i < item->nr_threads; i++) {
116 [ + + ]: 5546 : if (item->threads[i].real == item->pid.real)
117 : 3664 : item->core[i] = core_entry_alloc(1, 1);
118 : : else
119 : 1882 : item->core[i] = core_entry_alloc(1, 0);
120 : :
121 [ + - ]: 5546 : if (!item->core[i])
122 : : goto err;
123 : : }
124 : :
125 : : return 0;
126 : : err:
127 : 0 : pstree_free_cores(item);
128 : 0 : return -1;
129 : : }
130 : :
131 : 3764 : void pstree_free_cores(struct pstree_item *item)
132 : : {
133 : : unsigned int i;
134 : :
135 [ + + ]: 3764 : if (item->core) {
136 [ + + ]: 5546 : for (i = 1; i < item->nr_threads; i++)
137 : 1882 : core_entry_free(item->core[i]);
138 [ + - ]: 3664 : xfree(item->core);
139 : 3664 : item->core = NULL;
140 : : }
141 : 3764 : }
142 : :
143 : 1792 : void free_pstree(struct pstree_item *root_item)
144 : : {
145 : : struct pstree_item *item = root_item, *parent;
146 : :
147 [ + + ]: 7528 : while (item) {
148 [ + + ]: 5736 : if (!list_empty(&item->children)) {
149 : 1972 : item = list_first_entry(&item->children, struct pstree_item, sibling);
150 : 1972 : continue;
151 : : }
152 : :
153 : 3764 : parent = item->parent;
154 : : list_del(&item->sibling);
155 : 3764 : pstree_free_cores(item);
156 [ + - ]: 3764 : xfree(item->threads);
157 [ + - ]: 5736 : xfree(item);
158 : : item = parent;
159 : : }
160 : 1792 : }
161 : :
162 : 6313 : struct pstree_item *__alloc_pstree_item(bool rst)
163 : : {
164 : : struct pstree_item *item;
165 : :
166 [ + + ]: 6313 : if (!rst) {
167 [ - + ]: 3766 : item = xzalloc(sizeof(*item));
168 [ + - ]: 3766 : if (!item)
169 : : return NULL;
170 : : } else {
171 : 2547 : item = shmalloc(sizeof(*item) + sizeof(item->rst[0]));
172 [ + - ]: 2547 : if (!item)
173 : : return NULL;
174 : : memset(item, 0, sizeof(*item) + sizeof(item->rst[0]));
175 : : vm_area_list_init(&item->rst[0].vmas);
176 : : }
177 : :
178 : 6313 : INIT_LIST_HEAD(&item->children);
179 : 6313 : INIT_LIST_HEAD(&item->sibling);
180 : :
181 : 6313 : item->pid.virt = -1;
182 : 6313 : item->pid.real = -1;
183 : 6313 : item->born_sid = -1;
184 : :
185 : 6313 : return item;
186 : : }
187 : :
188 : : /* Deep first search on children */
189 : 12341 : struct pstree_item *pstree_item_next(struct pstree_item *item)
190 : : {
191 [ + + ][ + + ]: 58434 : if (!list_empty(&item->children))
[ + + ][ + + ]
[ + + ][ # # ]
[ # # ][ + + ]
[ + + ]
192 : 22165 : return list_first_entry(&item->children, struct pstree_item, sibling);
193 : :
194 [ + + ][ + + ]: 83020 : while (item->parent) {
[ + + ][ + + ]
[ + + ][ # # ]
[ # # ][ + + ]
[ + + ]
195 [ + + ][ + + ]: 31194 : if (item->sibling.next != &item->parent->children)
[ + + ][ + + ]
[ + + ][ # # ]
[ # # ][ + + ]
[ + + ]
196 : 42431 : return list_entry(item->sibling.next, struct pstree_item, sibling);
197 : : item = item->parent;
198 : : }
199 : :
200 : : return NULL;
201 : : }
202 : :
203 : 448 : int dump_pstree(struct pstree_item *root_item)
204 : : {
205 : : struct pstree_item *item = root_item;
206 : 448 : PstreeEntry e = PSTREE_ENTRY__INIT;
207 : : int ret = -1, i;
208 : : int pstree_fd;
209 : :
210 : 448 : pr_info("\n");
211 : 448 : pr_info("Dumping pstree (pid: %d)\n", root_item->pid.real);
212 : 448 : pr_info("----------------------------------------\n");
213 : :
214 : : /*
215 : : * Make sure we're dumping session leader, if not an
216 : : * appropriate option must be passed.
217 : : *
218 : : * Also note that if we're not a session leader we
219 : : * can't get the situation where the leader sits somewhere
220 : : * deeper in process tree, thus top-level checking for
221 : : * leader is enough.
222 : : */
223 [ - + ]: 448 : if (root_item->pid.virt != root_item->sid) {
224 [ # # ]: 0 : if (!opts.shell_job) {
225 : 0 : pr_err("The root process %d is not a session leader. "
226 : : "Consider using --" OPT_SHELL_JOB " option\n", item->pid.virt);
227 : 0 : return -1;
228 : : }
229 : : }
230 : :
231 : 448 : pstree_fd = open_image(CR_FD_PSTREE, O_DUMP);
232 [ + - ]: 448 : if (pstree_fd < 0)
233 : : return -1;
234 : :
235 [ + + ]: 1388 : for_each_pstree_item(item) {
236 : 940 : pr_info("Process: %d(%d)\n", item->pid.virt, item->pid.real);
237 : :
238 : 940 : e.pid = item->pid.virt;
239 [ + + ]: 940 : e.ppid = item->parent ? item->parent->pid.virt : 0;
240 : 940 : e.pgid = item->pgid;
241 : 940 : e.sid = item->sid;
242 : 940 : e.n_threads = item->nr_threads;
243 : :
244 [ - + ]: 940 : e.threads = xmalloc(sizeof(e.threads[0]) * e.n_threads);
245 [ + - ]: 940 : if (!e.threads)
246 : : goto err;
247 : :
248 [ + + ]: 2350 : for (i = 0; i < item->nr_threads; i++)
249 : 1410 : e.threads[i] = item->threads[i].virt;
250 : :
251 : 940 : ret = pb_write_one(pstree_fd, &e, PB_PSTREE);
252 [ + - ]: 940 : xfree(e.threads);
253 : :
254 [ + - ]: 940 : if (ret)
255 : : goto err;
256 : : }
257 : : ret = 0;
258 : :
259 : : err:
260 : 448 : pr_info("----------------------------------------\n");
261 : 448 : close(pstree_fd);
262 : 448 : return ret;
263 : : }
264 : :
265 : : static int max_pid = 0;
266 : :
267 : 1013 : static int prepare_pstree_for_shell_job(void)
268 : : {
269 : 1013 : pid_t current_sid = getsid(getpid());
270 : 1013 : pid_t current_gid = getpgid(getpid());
271 : :
272 : : struct pstree_item *pi;
273 : :
274 : : pid_t old_sid;
275 : : pid_t old_gid;
276 : :
277 [ - + ]: 1013 : if (!opts.shell_job)
278 : : return 0;
279 : :
280 [ # # ]: 0 : if (root_item->sid == root_item->pid.virt)
281 : : return 0;
282 : :
283 : : /*
284 : : * Migration of a root task group leader is a bit tricky.
285 : : * When a task yields SIGSTOP, the kernel notifies the parent
286 : : * with SIGCHLD. This means when task is running in a
287 : : * shell, the shell obtains SIGCHLD and sends a task to
288 : : * the background.
289 : : *
290 : : * The situation gets changed once we restore the
291 : : * program -- our tool become an additional stub between
292 : : * the restored program and the shell. So to be able to
293 : : * notify the shell with SIGCHLD from our restored
294 : : * program -- we make the root task to inherit the
295 : : * process group from us.
296 : : *
297 : : * Not that clever solution but at least it works.
298 : : */
299 : :
300 : : old_sid = root_item->sid;
301 : 0 : old_gid = root_item->pgid;
302 : :
303 : 0 : pr_info("Migrating process tree (GID %d->%d SID %d->%d)\n",
304 : : old_gid, current_gid, old_sid, current_sid);
305 : :
306 [ # # ]: 0 : for_each_pstree_item(pi) {
307 [ # # ]: 0 : if (pi->pgid == old_gid)
308 : 0 : pi->pgid = current_gid;
309 [ # # ]: 0 : if (pi->sid == old_sid)
310 : 0 : pi->sid = current_sid;
311 : : }
312 : :
313 : 0 : max_pid = max((int)current_sid, max_pid);
314 : 0 : max_pid = max((int)current_gid, max_pid);
315 : :
316 : 0 : return 0;
317 : : }
318 : :
319 : 1013 : static int read_pstree_image(void)
320 : : {
321 : : int ret = 0, i, ps_fd, fd;
322 : : struct pstree_item *pi, *parent = NULL;
323 : :
324 : 1013 : pr_info("Reading image tree\n");
325 : :
326 : 1013 : ps_fd = open_image(CR_FD_PSTREE, O_RSTR);
327 [ + - ]: 3540 : if (ps_fd < 0)
328 : : return ps_fd;
329 : :
330 : : while (1) {
331 : : PstreeEntry *e;
332 : :
333 : 3540 : ret = pb_read_one_eof(ps_fd, &e, PB_PSTREE);
334 [ + + ]: 3540 : if (ret <= 0)
335 : : break;
336 : :
337 : : ret = -1;
338 : 2527 : pi = alloc_pstree_item_with_rst();
339 [ + - ]: 2527 : if (pi == NULL)
340 : : break;
341 : :
342 : 2527 : pi->pid.virt = e->pid;
343 : 2527 : max_pid = max((int)e->pid, max_pid);
344 : :
345 : 2527 : pi->pgid = e->pgid;
346 : 2527 : max_pid = max((int)e->pgid, max_pid);
347 : :
348 : 2527 : pi->sid = e->sid;
349 : 2527 : max_pid = max((int)e->sid, max_pid);
350 : :
351 [ + + ]: 2527 : if (e->ppid == 0) {
352 [ - + ]: 1013 : if (root_item) {
353 : 0 : pr_err("Parent missed on non-root task "
354 : : "with pid %d, image corruption!\n", e->pid);
355 : 0 : goto err;
356 : : }
357 : 1013 : root_item = pi;
358 : 1013 : pi->parent = NULL;
359 : : } else {
360 : : /*
361 : : * Fast path -- if the pstree image is not edited, the
362 : : * parent of any item should have already being restored
363 : : * and sit among the last item's ancestors.
364 : : */
365 [ + - ]: 2197 : while (parent) {
366 [ + + ]: 2197 : if (parent->pid.virt == e->ppid)
367 : : break;
368 : 683 : parent = parent->parent;
369 : : }
370 : :
371 [ - + ]: 1514 : if (parent == NULL) {
372 [ # # ]: 0 : for_each_pstree_item(parent) {
373 [ # # ]: 0 : if (parent->pid.virt == e->ppid)
374 : : break;
375 : : }
376 : :
377 [ # # ]: 0 : if (parent == NULL) {
378 : 0 : pr_err("Can't find a parent for %d\n", pi->pid.virt);
379 : 0 : pstree_entry__free_unpacked(e, NULL);
380 [ # # ]: 0 : xfree(pi);
381 : : goto err;
382 : : }
383 : : }
384 : :
385 : 1514 : pi->parent = parent;
386 : 1514 : list_add(&pi->sibling, &parent->children);
387 : : }
388 : :
389 : : parent = pi;
390 : :
391 : 2527 : pi->nr_threads = e->n_threads;
392 [ - + ]: 2527 : pi->threads = xmalloc(e->n_threads * sizeof(struct pid));
393 [ + - ]: 2527 : if (!pi->threads)
394 : : break;
395 : :
396 [ + + ]: 6014 : for (i = 0; i < e->n_threads; i++) {
397 : 3487 : pi->threads[i].real = -1;
398 : 3487 : pi->threads[i].virt = e->threads[i];
399 : : }
400 : :
401 : 2527 : task_entries->nr_threads += e->n_threads;
402 : 2527 : task_entries->nr_tasks++;
403 : :
404 : 2527 : pstree_entry__free_unpacked(e, NULL);
405 : :
406 : 2527 : fd = open_image(CR_FD_IDS, O_RSTR, pi->pid.virt);
407 [ + + ]: 2527 : if (fd < 0) {
408 [ + - ]: 61 : if (errno == ENOENT)
409 : 61 : continue;
410 : : goto err;
411 : : }
412 : 2466 : ret = pb_read_one(fd, &pi->ids, PB_IDS);
413 : 2466 : close(fd);
414 [ + - ]: 2466 : if (ret != 1)
415 : : goto err;
416 : :
417 [ + - ]: 2466 : if (pi->ids->has_mnt_ns_id) {
418 [ + - ]: 3479 : if (rst_add_ns_id(pi->ids->mnt_ns_id, pi->pid.virt, &mnt_ns_desc))
419 : : goto err;
420 : : }
421 : : }
422 : : err:
423 : 1013 : close(ps_fd);
424 : 1013 : return ret;
425 : : }
426 : :
427 : 1013 : static int prepare_pstree_ids(void)
428 : : {
429 : : struct pstree_item *item, *child, *helper, *tmp;
430 : 1013 : LIST_HEAD(helpers);
431 : :
432 : 1013 : pid_t current_pgid = getpgid(getpid());
433 : :
434 : : /*
435 : : * Some task can be reparented to init. A helper task should be added
436 : : * for restoring sid of such tasks. The helper tasks will be exited
437 : : * immediately after forking children and all children will be
438 : : * reparented to init.
439 : : */
440 [ + + ]: 2191 : list_for_each_entry(item, &root_item->children, sibling) {
441 : :
442 : : /*
443 : : * If a child belongs to the root task's session or it's
444 : : * a session leader himself -- this is a simple case, we
445 : : * just proceed in a normal way.
446 : : */
447 [ + + ][ + + ]: 1178 : if (item->sid == root_item->sid || item->sid == item->pid.virt)
448 : 1162 : continue;
449 : :
450 : 16 : helper = alloc_pstree_item_with_rst();
451 [ + - ]: 16 : if (helper == NULL)
452 : : return -1;
453 : 16 : helper->sid = item->sid;
454 : 16 : helper->pgid = item->sid;
455 : 16 : helper->pid.virt = item->sid;
456 : 16 : helper->state = TASK_HELPER;
457 : 16 : helper->parent = root_item;
458 : 16 : list_add_tail(&helper->sibling, &helpers);
459 : 16 : task_entries->nr_helpers++;
460 : :
461 : 16 : pr_info("Add a helper %d for restoring SID %d\n",
462 : : helper->pid.virt, helper->sid);
463 : :
464 : 16 : child = list_entry(item->sibling.prev, struct pstree_item, sibling);
465 : : item = child;
466 : :
467 : : /*
468 : : * Stack on helper task all children with target sid.
469 : : */
470 [ + + ]: 40 : list_for_each_entry_safe_continue(child, tmp, &root_item->children, sibling) {
471 [ + + ]: 24 : if (child->sid != helper->sid)
472 : 8 : continue;
473 [ - + ]: 16 : if (child->sid == child->pid.virt)
474 : 0 : continue;
475 : :
476 : 16 : pr_info("Attach %d to the temporary task %d\n",
477 : : child->pid.virt, helper->pid.virt);
478 : :
479 : 16 : child->parent = helper;
480 : 16 : list_move(&child->sibling, &helper->children);
481 : : }
482 : : }
483 : :
484 : : /* Try to connect helpers to session leaders */
485 [ + + ]: 3540 : for_each_pstree_item(item) {
486 [ + + ]: 2527 : if (!item->parent) /* skip the root task */
487 : 1013 : continue;
488 : :
489 [ + + ]: 1514 : if (item->state == TASK_HELPER)
490 : 8 : continue;
491 : :
492 [ + + ]: 1506 : if (item->sid != item->pid.virt) {
493 : : struct pstree_item *parent;
494 : :
495 [ + + ]: 1002 : if (item->parent->sid == item->sid)
496 : 986 : continue;
497 : :
498 : : /* the task could fork a child before and after setsid() */
499 : : parent = item->parent;
500 [ + - ][ + + ]: 40 : while (parent && parent->pid.virt != item->sid) {
501 [ - + ][ # # ]: 24 : if (parent->born_sid != -1 && parent->born_sid != item->sid) {
502 : 0 : pr_err("Can't determinate with which sid (%d or %d)"
503 : : "the process %d was born\n",
504 : : parent->born_sid, item->sid, parent->pid.virt);
505 : 0 : return -1;
506 : : }
507 : 24 : parent->born_sid = item->sid;
508 : 24 : pr_info("%d was born with sid %d\n", parent->pid.virt, item->sid);
509 : 24 : parent = parent->parent;
510 : : }
511 : :
512 [ - + ]: 16 : if (parent == NULL) {
513 : 0 : pr_err("Can't find a session leader for %d\n", item->sid);
514 : 0 : return -1;
515 : : }
516 : :
517 : 16 : continue;
518 : : }
519 : :
520 : 504 : pr_info("Session leader %d\n", item->sid);
521 : :
522 : : /* Try to find helpers, who should be connected to the leader */
523 [ + + ]: 544 : list_for_each_entry(child, &helpers, sibling) {
524 [ - + ]: 48 : if (child->state != TASK_HELPER)
525 : 0 : continue;
526 : :
527 [ + + ]: 48 : if (child->sid != item->sid)
528 : 40 : continue;
529 : :
530 : 8 : child->pgid = item->pgid;
531 : 8 : child->pid.virt = ++max_pid;
532 : 8 : child->parent = item;
533 : 8 : list_move(&child->sibling, &item->children);
534 : :
535 : 8 : pr_info("Attach %d to the task %d\n",
536 : : child->pid.virt, item->pid.virt);
537 : :
538 : 8 : break;
539 : : }
540 : : }
541 : :
542 : : /* All other helpers are session leaders for own sessions */
543 : 1013 : list_splice(&helpers, &root_item->children);
544 : :
545 : : /* Add a process group leader if it is absent */
546 [ + + ]: 3560 : for_each_pstree_item(item) {
547 : : struct pstree_item *gleader;
548 : :
549 [ + - ][ + + ]: 2547 : if (!item->pgid || item->pid.virt == item->pgid)
550 : 1547 : continue;
551 : :
552 [ + + ]: 1464 : for_each_pstree_item(gleader) {
553 [ + + ]: 1460 : if (gleader->pid.virt == item->pgid)
554 : : break;
555 : : }
556 : :
557 [ + + ]: 1000 : if (gleader) {
558 : 996 : item->rst->pgrp_leader = gleader;
559 : 996 : continue;
560 : : }
561 : :
562 : : /*
563 : : * If the PGID is eq to current one -- this
564 : : * means we're inheriting group from the current
565 : : * task so we need to escape creating a helper here.
566 : : */
567 [ - + ]: 4 : if (current_pgid == item->pgid)
568 : 0 : continue;
569 : :
570 : 4 : helper = alloc_pstree_item_with_rst();
571 [ + - ]: 4 : if (helper == NULL)
572 : : return -1;
573 : 4 : helper->sid = item->sid;
574 : 4 : helper->pgid = item->pgid;
575 : 4 : helper->pid.virt = item->pgid;
576 : 4 : helper->state = TASK_HELPER;
577 : 4 : helper->parent = item;
578 : 4 : list_add(&helper->sibling, &item->children);
579 : 4 : task_entries->nr_helpers++;
580 : 4 : item->rst->pgrp_leader = helper;
581 : :
582 : 4 : pr_info("Add a helper %d for restoring PGID %d\n",
583 : : helper->pid.virt, helper->pgid);
584 : : }
585 : :
586 : : return 0;
587 : : }
588 : :
589 : 2466 : static unsigned long get_clone_mask(TaskKobjIdsEntry *i,
590 : : TaskKobjIdsEntry *p)
591 : : {
592 : : unsigned long mask = 0;
593 : :
594 [ + + ]: 2466 : if (i->files_id == p->files_id)
595 : : mask |= CLONE_FILES;
596 [ + + ]: 2466 : if (i->pid_ns_id != p->pid_ns_id)
597 : 420 : mask |= CLONE_NEWPID;
598 [ + + ]: 2466 : if (i->net_ns_id != p->net_ns_id)
599 : 428 : mask |= CLONE_NEWNET;
600 [ + + ]: 2466 : if (i->ipc_ns_id != p->ipc_ns_id)
601 : 446 : mask |= CLONE_NEWIPC;
602 [ + + ]: 2466 : if (i->uts_ns_id != p->uts_ns_id)
603 : 424 : mask |= CLONE_NEWUTS;
604 [ + + ]: 2466 : if (i->mnt_ns_id != p->mnt_ns_id)
605 : 420 : mask |= CLONE_NEWNS;
606 : :
607 : 2466 : return mask;
608 : : }
609 : :
610 : 1013 : static int prepare_pstree_kobj_ids(void)
611 : : {
612 : : struct pstree_item *item;
613 : :
614 : : /* Find a process with minimal pid for shared fd tables */
615 [ + + ]: 3540 : for_each_pstree_item(item) {
616 : 2527 : struct pstree_item *parent = item->parent;
617 : : TaskKobjIdsEntry *ids;
618 : : unsigned long cflags;
619 : :
620 [ + + ]: 2527 : if (!item->ids) {
621 [ - + ]: 61 : if (item == root_item) {
622 : 0 : cflags = opts.rst_namespaces_flags;
623 : 0 : goto set_mask;
624 : : }
625 : :
626 : 61 : continue;
627 : : }
628 : :
629 [ + + ]: 2466 : if (parent)
630 : 1453 : ids = parent->ids;
631 : : else
632 : 1013 : ids = root_ids;
633 : :
634 : : /*
635 : : * Add some sanity check on image data.
636 : : */
637 [ - + ]: 2466 : if (unlikely(!ids)) {
638 : 0 : pr_err("No kIDs provided, image corruption\n");
639 : 0 : return -1;
640 : : }
641 : :
642 : 2466 : cflags = get_clone_mask(item->ids, ids);
643 : :
644 [ + + ]: 2466 : if (cflags & CLONE_FILES) {
645 : : int ret;
646 : :
647 : : /*
648 : : * There might be a case when kIDs for
649 : : * root task are the same as in root_ids,
650 : : * thus it's image corruption and we should
651 : : * exit out.
652 : : */
653 [ - + ]: 45 : if (unlikely(!item->parent)) {
654 : 0 : pr_err("Image corruption on kIDs data\n");
655 : 0 : return -1;
656 : : }
657 : :
658 : 45 : ret = shared_fdt_prepare(item);
659 [ + - ]: 45 : if (ret)
660 : : return ret;
661 : : }
662 : :
663 : : set_mask:
664 : 2466 : item->rst->clone_flags = cflags;
665 : :
666 : 2466 : cflags &= CLONE_ALLNS;
667 : :
668 [ + + ]: 2466 : if (item == root_item) {
669 : 1013 : pr_info("Will restore in %lx namespaces\n", cflags);
670 : 1013 : root_ns_mask = cflags;
671 [ - + ]: 1453 : } else if (cflags & ~(root_ns_mask & CLONE_SUBNS)) {
672 : : /*
673 : : * Namespaces from CLONE_SUBNS can be nested, but in
674 : : * this case nobody can't share external namespaces of
675 : : * these types.
676 : : *
677 : : * Workaround for all other namespaces --
678 : : * all tasks should be in one namespace. And
679 : : * this namespace is either inherited from the
680 : : * criu or is created for the init task (only)
681 : : */
682 : 0 : pr_err("Can't restore sub-task in NS\n");
683 : 0 : return -1;
684 : : }
685 : : }
686 : :
687 : 1013 : pr_debug("NS mask to use %lx\n", root_ns_mask);
688 : 1013 : return 0;
689 : : }
690 : :
691 : 1013 : int prepare_pstree(void)
692 : : {
693 : : int ret;
694 : :
695 : 1013 : ret = read_pstree_image();
696 [ + - ]: 1013 : if (!ret)
697 : : /*
698 : : * Shell job may inherit sid/pgid from the current
699 : : * shell, not from image. Set things up for this.
700 : : */
701 : 1013 : ret = prepare_pstree_for_shell_job();
702 [ + - ]: 1013 : if (!ret)
703 : : /*
704 : : * Walk the collected tree and prepare for restoring
705 : : * of shared objects at clone time
706 : : */
707 : 1013 : ret = prepare_pstree_kobj_ids();
708 [ + - ]: 1013 : if (!ret)
709 : : /*
710 : : * Session/Group leaders might be dead. Need to fix
711 : : * pstree with properly injected helper tasks.
712 : : */
713 : 1013 : ret = prepare_pstree_ids();
714 : :
715 : 1013 : return ret;
716 : : }
717 : :
718 : 1092 : bool restore_before_setsid(struct pstree_item *child)
719 : : {
720 [ + - ]: 1092 : int csid = child->born_sid == -1 ? child->sid : child->born_sid;
721 : :
722 [ + - ]: 1092 : if (child->parent->born_sid == csid)
723 : : return true;
724 : :
725 : 1092 : return false;
726 : : }
727 : :
728 : 17738 : bool pid_in_pstree(pid_t pid)
729 : : {
730 : : struct pstree_item *item;
731 : :
732 [ + + ]: 54826 : for_each_pstree_item(item) {
733 [ + + ]: 37108 : if (item->pid.real == pid)
734 : : return true;
735 : : }
736 : :
737 : : return false;
738 : : }
|