2012-01-26 15:27:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/wait.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <stdlib.h>
|
2014-11-07 17:23:17 +04:00
|
|
|
#include <sys/prctl.h>
|
2014-11-07 15:09:19 +03:00
|
|
|
#include <grp.h>
|
|
|
|
|
2013-11-06 14:34:33 +04:00
|
|
|
#include "cr-show.h"
|
2012-01-26 15:27:00 +04:00
|
|
|
#include "util.h"
|
2014-09-29 12:47:37 +04:00
|
|
|
#include "imgset.h"
|
2012-01-26 15:27:00 +04:00
|
|
|
#include "syscall.h"
|
2012-01-31 11:29:23 +03:00
|
|
|
#include "uts_ns.h"
|
2012-01-31 22:28:55 +04:00
|
|
|
#include "ipc_ns.h"
|
2012-05-12 03:30:10 +04:00
|
|
|
#include "mount.h"
|
2013-11-05 12:32:59 +04:00
|
|
|
#include "pstree.h"
|
2012-05-15 13:04:00 +04:00
|
|
|
#include "namespaces.h"
|
2012-08-02 08:06:29 +04:00
|
|
|
#include "net.h"
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/ns.pb-c.h"
|
2014-11-07 13:56:34 +03:00
|
|
|
#include "protobuf/userns.pb-c.h"
|
2013-05-18 04:00:05 +04:00
|
|
|
|
2013-08-24 15:30:39 +04:00
|
|
|
static struct ns_desc *ns_desc_array[] = {
|
2013-05-18 04:00:05 +04:00
|
|
|
&net_ns_desc,
|
|
|
|
&uts_ns_desc,
|
|
|
|
&ipc_ns_desc,
|
|
|
|
&pid_ns_desc,
|
|
|
|
&user_ns_desc,
|
|
|
|
&mnt_ns_desc,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int parse_ns_link(char *link, size_t len, struct ns_desc *d)
|
|
|
|
{
|
2014-04-09 14:46:12 +04:00
|
|
|
unsigned long kid = 0;
|
2013-05-18 04:00:05 +04:00
|
|
|
char *end;
|
|
|
|
|
|
|
|
if (len >= d->len + 2) {
|
|
|
|
if (link[d->len] == ':' && !memcmp(link, d->str, d->len)) {
|
|
|
|
kid = strtoul(&link[d->len + 2], &end, 10);
|
|
|
|
if (end && *end == ']')
|
|
|
|
BUG_ON(kid > UINT_MAX);
|
|
|
|
else
|
|
|
|
kid = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 14:46:12 +04:00
|
|
|
return (unsigned int)kid;
|
2013-05-18 04:00:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool check_ns_proc(struct fd_link *link)
|
|
|
|
{
|
|
|
|
unsigned int i, kid;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ns_desc_array); i++) {
|
|
|
|
kid = parse_ns_link(link->name + 1, link->len - 1, ns_desc_array[i]);
|
|
|
|
if (!kid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
link->ns_d = ns_desc_array[i];
|
|
|
|
link->ns_kid = kid;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
int switch_ns(int pid, struct ns_desc *nd, int *rst)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
|
|
|
char buf[32];
|
2012-02-01 15:58:30 +04:00
|
|
|
int nsfd;
|
|
|
|
int ret = -1;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2014-10-29 00:31:00 +04:00
|
|
|
nsfd = open_proc(pid, "ns/%s", nd->str);
|
2012-01-26 15:27:00 +04:00
|
|
|
if (nsfd < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't open ipcns file");
|
2012-08-02 07:55:05 +04:00
|
|
|
goto err_ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rst) {
|
2013-01-15 23:24:01 +04:00
|
|
|
snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
|
2012-08-02 07:55:05 +04:00
|
|
|
*rst = open(buf, O_RDONLY);
|
|
|
|
if (*rst < 0) {
|
|
|
|
pr_perror("Can't open ns file");
|
|
|
|
goto err_rst;
|
|
|
|
}
|
2012-01-26 15:27:00 +04:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
ret = setns(nsfd, nd->cflag);
|
2012-08-02 07:55:05 +04:00
|
|
|
if (ret < 0) {
|
2013-01-15 23:24:01 +04:00
|
|
|
pr_perror("Can't setns %d/%s", pid, nd->str);
|
2012-08-02 07:55:05 +04:00
|
|
|
goto err_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(nsfd);
|
|
|
|
return 0;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2012-08-02 07:55:05 +04:00
|
|
|
err_set:
|
|
|
|
if (rst)
|
|
|
|
close(*rst);
|
|
|
|
err_rst:
|
2012-01-26 15:27:00 +04:00
|
|
|
close(nsfd);
|
2012-08-02 07:55:05 +04:00
|
|
|
err_ns:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
int restore_ns(int rst, struct ns_desc *nd)
|
2012-08-02 07:55:05 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
ret = setns(rst, nd->cflag);
|
2012-08-02 07:55:05 +04:00
|
|
|
if (ret < 0)
|
|
|
|
pr_perror("Can't restore ns back");
|
|
|
|
|
2013-04-05 01:44:35 +04:00
|
|
|
close(rst);
|
|
|
|
|
2012-01-26 15:27:00 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-11 19:18:00 +04:00
|
|
|
struct ns_id *ns_ids = NULL;
|
2013-01-18 13:18:33 +04:00
|
|
|
static unsigned int ns_next_id = 1;
|
2014-04-21 18:23:22 +04:00
|
|
|
unsigned long root_ns_mask = 0;
|
2013-01-18 13:18:33 +04:00
|
|
|
|
2014-04-23 13:22:12 +04:00
|
|
|
struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
|
|
|
nsid = shmalloc(sizeof(*nsid));
|
|
|
|
if (nsid) {
|
|
|
|
nsid->nd = nd;
|
|
|
|
nsid->id = id;
|
|
|
|
nsid->pid = pid;
|
2014-11-07 20:25:05 +04:00
|
|
|
futex_set(&nsid->ns_created, 0);
|
2014-04-23 13:22:12 +04:00
|
|
|
|
|
|
|
nsid->next = ns_ids;
|
|
|
|
ns_ids = nsid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsid;
|
|
|
|
}
|
|
|
|
|
2014-04-21 18:23:14 +04:00
|
|
|
int rst_add_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
|
|
|
for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) {
|
|
|
|
if (nsid->id == id) {
|
|
|
|
if (pid_rst_prio(pid, nsid->pid))
|
|
|
|
nsid->pid = pid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-23 14:06:00 +04:00
|
|
|
nsid = rst_new_ns_id(id, pid, nd);
|
|
|
|
if (nsid == NULL)
|
2014-04-21 18:23:14 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
pr_info("Add namespace %d pid %d\n", nsid->id, nsid->pid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
static struct ns_id *lookup_ns_by_kid(unsigned int kid, struct ns_desc *nd)
|
2013-01-18 13:18:33 +04:00
|
|
|
{
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
|
|
|
for (nsid = ns_ids; nsid != NULL; nsid = nsid->next)
|
|
|
|
if (nsid->kid == kid && nsid->nd == nd)
|
2014-09-29 22:05:05 +04:00
|
|
|
return nsid;
|
2013-01-18 13:18:33 +04:00
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
return NULL;
|
2013-05-18 04:00:05 +04:00
|
|
|
}
|
|
|
|
|
2014-04-21 18:23:14 +04:00
|
|
|
struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
|
|
|
for (nsid = ns_ids; nsid != NULL; nsid = nsid->next)
|
|
|
|
if (nsid->id == id && nsid->nd == nd)
|
|
|
|
return nsid;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-10-09 17:42:40 +04:00
|
|
|
/*
|
|
|
|
* For all namespaces we support, there are two supported
|
|
|
|
* tasks-to-namespaces layout.
|
|
|
|
*
|
|
|
|
* If root task lives in the same namespace as criu does
|
|
|
|
* all other tasks should live in it too and we do NOT dump
|
|
|
|
* this namespace. On restore tasks inherit the respective
|
|
|
|
* namespace from criu.
|
|
|
|
*
|
|
|
|
* If root task lives in its own namespace, then all other
|
|
|
|
* tasks may live in it. Sometimes (CLONE_SUBNS) there can
|
|
|
|
* be more than one namespace of that type. For this case
|
|
|
|
* we dump all namespace's info and recreate them on restore.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int walk_namespaces(struct ns_desc *nd, int (*cb)(struct ns_id *, void *), void *oarg)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct ns_id *ns;
|
|
|
|
|
|
|
|
for (ns = ns_ids; ns != NULL; ns = ns->next) {
|
|
|
|
if (ns->nd != nd)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ns->pid == getpid()) {
|
|
|
|
if (root_ns_mask & nd->cflag)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = cb(ns, oarg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = cb(ns, oarg);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd,
|
|
|
|
struct ns_id **ns_ret)
|
2013-05-18 04:00:05 +04:00
|
|
|
{
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
nsid = lookup_ns_by_kid(kid, nd);
|
|
|
|
if (nsid)
|
|
|
|
goto found;
|
2013-05-18 04:00:05 +04:00
|
|
|
|
2013-01-17 18:10:29 +04:00
|
|
|
if (pid != getpid()) {
|
|
|
|
if (pid == root_item->pid.real) {
|
2014-04-21 18:23:22 +04:00
|
|
|
BUG_ON(root_ns_mask & nd->cflag);
|
2013-01-17 18:10:29 +04:00
|
|
|
pr_info("Will take %s namespace in the image\n", nd->str);
|
2014-04-21 18:23:22 +04:00
|
|
|
root_ns_mask |= nd->cflag;
|
2014-04-21 18:23:21 +04:00
|
|
|
} else if (nd->cflag & ~CLONE_SUBNS) {
|
2013-01-17 18:10:29 +04:00
|
|
|
pr_err("Can't dump nested %s namespace for %d\n",
|
|
|
|
nd->str, pid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-18 13:18:33 +04:00
|
|
|
nsid = xmalloc(sizeof(*nsid));
|
|
|
|
if (!nsid)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsid->id = ns_next_id++;
|
|
|
|
nsid->kid = kid;
|
|
|
|
nsid->nd = nd;
|
|
|
|
nsid->next = ns_ids;
|
2013-09-30 17:16:52 +04:00
|
|
|
nsid->pid = pid;
|
2013-01-18 13:18:33 +04:00
|
|
|
ns_ids = nsid;
|
|
|
|
|
|
|
|
pr_info("Collected %u.%s namespace\n", nsid->id, nd->str);
|
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
found:
|
|
|
|
if (ns_ret)
|
|
|
|
*ns_ret = nsid;
|
2013-01-18 13:18:33 +04:00
|
|
|
return nsid->id;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
static unsigned int __get_ns_id(int pid, struct ns_desc *nd, struct ns_id **ns)
|
2013-01-18 13:18:33 +04:00
|
|
|
{
|
|
|
|
int proc_dir, ret;
|
|
|
|
unsigned int kid;
|
2013-05-18 04:00:05 +04:00
|
|
|
char ns_path[10], ns_id[32];
|
2013-01-18 13:18:33 +04:00
|
|
|
|
|
|
|
proc_dir = open_pid_proc(pid);
|
|
|
|
if (proc_dir < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sprintf(ns_path, "ns/%s", nd->str);
|
2014-10-14 15:38:00 +04:00
|
|
|
ret = readlinkat(proc_dir, ns_path, ns_id, sizeof(ns_id) - 1);
|
2013-01-18 13:18:33 +04:00
|
|
|
if (ret < 0) {
|
2014-10-14 15:38:00 +04:00
|
|
|
if (errno == ENOENT) {
|
|
|
|
/* The namespace is unsupported */
|
|
|
|
kid = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-01-18 13:18:33 +04:00
|
|
|
pr_perror("Can't readlink ns link");
|
|
|
|
return 0;
|
|
|
|
}
|
2014-10-14 15:38:00 +04:00
|
|
|
ns_id[ret] = '\0';
|
2013-01-18 13:18:33 +04:00
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
kid = parse_ns_link(ns_id, ret, nd);
|
|
|
|
BUG_ON(!kid);
|
|
|
|
|
2014-10-14 15:38:00 +04:00
|
|
|
out:
|
2014-09-29 22:05:05 +04:00
|
|
|
return generate_ns_id(pid, kid, nd, ns);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int get_ns_id(int pid, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
return __get_ns_id(pid, nd, NULL);
|
2013-01-18 13:18:33 +04:00
|
|
|
}
|
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
int dump_one_ns_file(int lfd, u32 id, const struct fd_parms *p)
|
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img = img_from_set(glob_imgset, CR_FD_NS_FILES);
|
2013-05-18 04:00:05 +04:00
|
|
|
NsFileEntry nfe = NS_FILE_ENTRY__INIT;
|
|
|
|
struct fd_link *link = p->link;
|
2014-09-29 22:05:05 +04:00
|
|
|
struct ns_id *nsid;
|
2013-05-18 04:00:05 +04:00
|
|
|
|
2014-09-29 22:05:05 +04:00
|
|
|
nsid = lookup_ns_by_kid(link->ns_kid, link->ns_d);
|
2013-05-18 04:00:05 +04:00
|
|
|
if (!nsid) {
|
|
|
|
pr_err("No NS ID with kid %u\n", link->ns_kid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfe.id = id;
|
2014-09-29 22:05:05 +04:00
|
|
|
nfe.ns_id = nsid->id;
|
2013-05-18 04:00:05 +04:00
|
|
|
nfe.ns_cflag = link->ns_d->cflag;
|
|
|
|
nfe.flags = p->flags;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return pb_write_one(img, &nfe, PB_NS_FILE);
|
2013-05-18 04:00:05 +04:00
|
|
|
}
|
|
|
|
|
2013-06-14 00:11:08 +04:00
|
|
|
const struct fdtype_ops nsfile_dump_ops = {
|
2013-05-18 04:00:05 +04:00
|
|
|
.type = FD_TYPES__NS,
|
|
|
|
.dump = dump_one_ns_file,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ns_file_info {
|
|
|
|
struct file_desc d;
|
|
|
|
NsFileEntry *nfe;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int open_ns_fd(struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct ns_file_info *nfi = container_of(d, struct ns_file_info, d);
|
|
|
|
struct pstree_item *item, *t;
|
|
|
|
struct ns_desc *nd = NULL;
|
|
|
|
char path[64];
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find out who can open us.
|
|
|
|
*
|
|
|
|
* FIXME I need a hash or RBtree here.
|
|
|
|
*/
|
|
|
|
for_each_pstree_item(t) {
|
|
|
|
TaskKobjIdsEntry *ids = t->ids;
|
|
|
|
|
|
|
|
if (ids->pid_ns_id == nfi->nfe->ns_id) {
|
|
|
|
item = t;
|
|
|
|
nd = &pid_ns_desc;
|
|
|
|
break;
|
|
|
|
} else if (ids->net_ns_id == nfi->nfe->ns_id) {
|
|
|
|
item = t;
|
|
|
|
nd = &net_ns_desc;
|
|
|
|
break;
|
|
|
|
} else if (ids->ipc_ns_id == nfi->nfe->ns_id) {
|
|
|
|
item = t;
|
|
|
|
nd = &ipc_ns_desc;
|
|
|
|
break;
|
|
|
|
} else if (ids->uts_ns_id == nfi->nfe->ns_id) {
|
|
|
|
item = t;
|
|
|
|
nd = &uts_ns_desc;
|
|
|
|
break;
|
|
|
|
} else if (ids->mnt_ns_id == nfi->nfe->ns_id) {
|
|
|
|
item = t;
|
|
|
|
nd = &mnt_ns_desc;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nd || !item) {
|
|
|
|
pr_err("Can't find suitable NS ID for %#x\n", nfi->nfe->ns_id);
|
|
|
|
return -1;
|
2013-12-11 14:03:11 -08:00
|
|
|
}
|
2013-05-18 04:00:05 +04:00
|
|
|
|
|
|
|
if (nd->cflag != nfi->nfe->ns_cflag) {
|
|
|
|
pr_err("Clone flag mismatch for %#x\n", nfi->nfe->ns_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(path, sizeof(path) - 1, "/proc/%d/ns/%s", item->pid.virt, nd->str);
|
|
|
|
path[sizeof(path) - 1] = '\0';
|
|
|
|
|
|
|
|
fd = open(path, nfi->nfe->flags);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't open file %s on restore", path);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_desc_ops ns_desc_ops = {
|
|
|
|
.type = FD_TYPES__NS,
|
|
|
|
.open = open_ns_fd,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int collect_one_nsfile(void *o, ProtobufCMessage *base)
|
|
|
|
{
|
|
|
|
struct ns_file_info *nfi = o;
|
|
|
|
|
|
|
|
nfi->nfe = pb_msg(base, NsFileEntry);
|
|
|
|
pr_info("Collected ns file ID %#x NS-ID %#x\n", nfi->nfe->id, nfi->nfe->ns_id);
|
2013-08-21 01:06:58 +04:00
|
|
|
return file_desc_add(&nfi->d, nfi->nfe->id, &ns_desc_ops);
|
2013-05-18 04:00:05 +04:00
|
|
|
}
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
struct collect_image_info nsfile_cinfo = {
|
|
|
|
.fd_type = CR_FD_NS_FILES,
|
2013-08-23 21:47:31 +04:00
|
|
|
.pb_type = PB_NS_FILE,
|
2013-08-21 03:27:06 +04:00
|
|
|
.priv_size = sizeof(struct ns_file_info),
|
|
|
|
.collect = collect_one_nsfile,
|
|
|
|
.flags = COLLECT_OPTIONAL,
|
|
|
|
};
|
|
|
|
|
2014-10-01 16:15:00 +04:00
|
|
|
/*
|
|
|
|
* Same as dump_task_ns_ids(), but
|
|
|
|
* a) doesn't keep IDs (don't need them)
|
|
|
|
* b) generates them for mount and netns only
|
|
|
|
* mnt ones are needed for open_mount() in
|
|
|
|
* inotify pred-dump
|
|
|
|
* net ones are needed for parasite socket
|
|
|
|
*/
|
|
|
|
|
|
|
|
int predump_task_ns_ids(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
int pid = item->pid.real;
|
|
|
|
|
|
|
|
if (!__get_ns_id(pid, &net_ns_desc, &dmpi(item)->netns))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!get_ns_id(pid, &mnt_ns_desc))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-18 13:18:33 +04:00
|
|
|
int dump_task_ns_ids(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
int pid = item->pid.real;
|
|
|
|
TaskKobjIdsEntry *ids = item->ids;
|
|
|
|
|
|
|
|
ids->has_pid_ns_id = true;
|
|
|
|
ids->pid_ns_id = get_ns_id(pid, &pid_ns_desc);
|
|
|
|
if (!ids->pid_ns_id) {
|
|
|
|
pr_err("Can't make pidns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids->has_net_ns_id = true;
|
2014-09-29 22:05:17 +04:00
|
|
|
ids->net_ns_id = __get_ns_id(pid, &net_ns_desc, &dmpi(item)->netns);
|
2013-01-18 13:18:33 +04:00
|
|
|
if (!ids->net_ns_id) {
|
|
|
|
pr_err("Can't make netns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids->has_ipc_ns_id = true;
|
|
|
|
ids->ipc_ns_id = get_ns_id(pid, &ipc_ns_desc);
|
|
|
|
if (!ids->ipc_ns_id) {
|
|
|
|
pr_err("Can't make ipcns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids->has_uts_ns_id = true;
|
|
|
|
ids->uts_ns_id = get_ns_id(pid, &uts_ns_desc);
|
|
|
|
if (!ids->uts_ns_id) {
|
|
|
|
pr_err("Can't make utsns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids->has_mnt_ns_id = true;
|
|
|
|
ids->mnt_ns_id = get_ns_id(pid, &mnt_ns_desc);
|
|
|
|
if (!ids->mnt_ns_id) {
|
|
|
|
pr_err("Can't make mntns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-14 15:38:00 +04:00
|
|
|
ids->has_user_ns_id = true;
|
|
|
|
ids->user_ns_id = get_ns_id(pid, &user_ns_desc);
|
|
|
|
if (!ids->user_ns_id) {
|
|
|
|
pr_err("Can't make userns id\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-18 13:18:33 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
|
|
|
|
|
|
|
|
static int userns_id(int id, UidGidExtent **map, int n)
|
2014-10-31 12:14:27 +03:00
|
|
|
{
|
2014-11-07 13:56:34 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!(root_ns_mask & CLONE_NEWUSER))
|
|
|
|
return id;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (map[i]->lower_first <= id &&
|
|
|
|
map[i]->lower_first + map[i]->count > id)
|
|
|
|
return map[i]->first + (id - map[i]->lower_first);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2014-10-31 12:14:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int userns_uid(int uid)
|
|
|
|
{
|
2014-11-07 13:56:34 +03:00
|
|
|
UsernsEntry *e = &userns_entry;
|
|
|
|
return userns_id(uid, e->uid_map, e->n_uid_map);
|
2014-10-31 12:14:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int userns_gid(int gid)
|
|
|
|
{
|
2014-11-07 13:56:34 +03:00
|
|
|
UsernsEntry *e = &userns_entry;
|
|
|
|
return userns_id(gid, e->gid_map, e->n_gid_map);
|
2014-10-31 12:14:27 +03:00
|
|
|
}
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
static int parse_id_map(pid_t pid, char *name, UidGidExtent ***pb_exts)
|
2014-10-14 15:38:00 +04:00
|
|
|
{
|
2014-11-07 13:56:34 +03:00
|
|
|
UidGidExtent *extents = NULL;
|
|
|
|
int len = 0, size = 0, ret, i;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
f = fopen_proc(pid, "%s", name);
|
|
|
|
if (f == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = -1;
|
|
|
|
while (1) {
|
|
|
|
UidGidExtent *ext;
|
|
|
|
|
|
|
|
if (len == size) {
|
|
|
|
UidGidExtent *t;
|
|
|
|
|
|
|
|
size = size * 2 + 1;
|
|
|
|
t = xrealloc(extents, size * sizeof(UidGidExtent));
|
|
|
|
if (t == NULL)
|
|
|
|
break;
|
|
|
|
extents = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext = &extents[len];
|
|
|
|
|
|
|
|
uid_gid_extent__init(ext);
|
|
|
|
ret = fscanf(f, "%d %d %d", &ext->first,
|
|
|
|
&ext->lower_first, &ext->count);
|
|
|
|
if (ret != 3) {
|
|
|
|
if (errno != 0) {
|
|
|
|
pr_perror("Unable to parse extents");
|
|
|
|
ret = -1;
|
|
|
|
} else
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pr_info("id_map: %d %d %d\n", ext->first, ext->lower_first, ext->count);
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
*pb_exts = xmalloc(sizeof(UidGidExtent *) * len);
|
|
|
|
if (*pb_exts == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
(*pb_exts)[i] = &extents[i];
|
|
|
|
} else {
|
|
|
|
xfree(extents);
|
|
|
|
*pb_exts = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
err:
|
|
|
|
xfree(extents);
|
2014-10-14 15:38:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
int collect_user_ns(struct ns_id *ns, void *oarg)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* User namespace is dumped before files to get uid and gid
|
|
|
|
* mappings, which are used for convirting local id-s to
|
|
|
|
* userns id-s (userns_uid(), userns_gid())
|
|
|
|
*/
|
|
|
|
if (dump_user_ns(root_item->pid.real, root_item->ids->user_ns_id))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int collect_user_namespaces(bool for_dump)
|
|
|
|
{
|
|
|
|
if (!for_dump)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(root_ns_mask & CLONE_NEWUSER))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return walk_namespaces(&net_ns_desc, collect_user_ns, NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-31 13:14:00 +04:00
|
|
|
static int check_user_ns(int pid)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
pid_t chld;
|
|
|
|
|
|
|
|
chld = fork();
|
|
|
|
if (chld == -1) {
|
|
|
|
pr_perror("Unable to fork a process\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chld == 0) {
|
|
|
|
/*
|
|
|
|
* Check that we are able to enter into other namespaces
|
|
|
|
* from the target userns namespace. This signs that these
|
|
|
|
* namespaces were created from the target userns.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (switch_ns(pid, &user_ns_desc, NULL))
|
|
|
|
exit(-1);
|
|
|
|
|
|
|
|
if ((root_ns_mask & CLONE_NEWNET) &&
|
|
|
|
switch_ns(pid, &net_ns_desc, NULL))
|
|
|
|
exit(-1);
|
|
|
|
if ((root_ns_mask & CLONE_NEWUTS) &&
|
|
|
|
switch_ns(pid, &uts_ns_desc, NULL))
|
|
|
|
exit(-1);
|
|
|
|
if ((root_ns_mask & CLONE_NEWIPC) &&
|
|
|
|
switch_ns(pid, &ipc_ns_desc, NULL))
|
|
|
|
exit(-1);
|
|
|
|
if ((root_ns_mask & CLONE_NEWNS) &&
|
|
|
|
switch_ns(pid, &mnt_ns_desc, NULL))
|
|
|
|
exit(-1);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (waitpid(chld, &status, 0) != chld) {
|
|
|
|
pr_perror("Unable to wait the %d process", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
pr_err("One or more namespaces doesn't belong to the target user namespace\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
int dump_user_ns(pid_t pid, int ns_id)
|
|
|
|
{
|
|
|
|
int ret, exit_code = -1;
|
|
|
|
UsernsEntry *e = &userns_entry;
|
|
|
|
struct cr_img *img;
|
|
|
|
|
2014-10-31 13:14:00 +04:00
|
|
|
if (check_user_ns(pid))
|
|
|
|
return -1;
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
ret = parse_id_map(pid, "uid_map", &e->uid_map);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
e->n_uid_map = ret;
|
|
|
|
|
|
|
|
ret = parse_id_map(pid, "gid_map", &e->gid_map);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
e->n_gid_map = ret;
|
|
|
|
|
|
|
|
img = open_image(CR_FD_USERNS, O_DUMP, ns_id);
|
|
|
|
if (!img)
|
|
|
|
goto err;
|
|
|
|
ret = pb_write_one(img, e, PB_USERNS);
|
|
|
|
close_image(img);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
if (e->uid_map) {
|
|
|
|
xfree(e->uid_map[0]);
|
|
|
|
xfree(e->uid_map);
|
|
|
|
}
|
|
|
|
if (e->gid_map) {
|
|
|
|
xfree(e->gid_map[0]);
|
|
|
|
xfree(e->gid_map);
|
|
|
|
}
|
|
|
|
return exit_code;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_userns_maps()
|
|
|
|
{
|
|
|
|
if (userns_entry.n_uid_map > 0) {
|
|
|
|
xfree(userns_entry.uid_map[0]);
|
|
|
|
xfree(userns_entry.uid_map);
|
|
|
|
}
|
|
|
|
if (userns_entry.n_gid_map > 0) {
|
|
|
|
xfree(userns_entry.gid_map[0]);
|
|
|
|
xfree(userns_entry.gid_map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-30 17:16:53 +04:00
|
|
|
static int do_dump_namespaces(struct ns_id *ns)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2014-09-22 16:27:00 +04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = switch_ns(ns->pid, ns->nd, NULL);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2013-09-30 17:16:53 +04:00
|
|
|
switch (ns->nd->cflag) {
|
|
|
|
case CLONE_NEWUTS:
|
2013-09-28 05:32:52 +04:00
|
|
|
pr_info("Dump UTS namespace %d via %d\n",
|
|
|
|
ns->id, ns->pid);
|
2014-09-22 16:27:00 +04:00
|
|
|
ret = dump_uts_ns(ns->id);
|
2013-09-30 17:16:53 +04:00
|
|
|
break;
|
|
|
|
case CLONE_NEWIPC:
|
2013-09-28 05:32:52 +04:00
|
|
|
pr_info("Dump IPC namespace %d via %d\n",
|
|
|
|
ns->id, ns->pid);
|
2014-09-22 16:27:00 +04:00
|
|
|
ret = dump_ipc_ns(ns->id);
|
2013-09-30 17:16:53 +04:00
|
|
|
break;
|
|
|
|
case CLONE_NEWNET:
|
2013-09-28 05:32:52 +04:00
|
|
|
pr_info("Dump NET namespace info %d via %d\n",
|
|
|
|
ns->id, ns->pid);
|
2014-09-22 16:27:00 +04:00
|
|
|
ret = dump_net_ns(ns->id);
|
2013-09-30 17:16:53 +04:00
|
|
|
break;
|
2014-10-14 15:38:00 +04:00
|
|
|
case CLONE_NEWUSER:
|
2014-11-07 13:56:34 +03:00
|
|
|
/* userns is dumped before dumping tasks */
|
|
|
|
ret = 0;
|
2014-10-14 15:38:00 +04:00
|
|
|
break;
|
2013-09-30 17:16:53 +04:00
|
|
|
default:
|
|
|
|
pr_err("Unknown namespace flag %x", ns->nd->cflag);
|
|
|
|
break;
|
2012-08-02 08:06:29 +04:00
|
|
|
}
|
2013-09-30 17:16:53 +04:00
|
|
|
|
2012-01-26 15:28:00 +04:00
|
|
|
return ret;
|
|
|
|
|
2012-01-26 15:27:00 +04:00
|
|
|
}
|
|
|
|
|
2013-09-30 17:16:51 +04:00
|
|
|
int dump_namespaces(struct pstree_item *item, unsigned int ns_flags)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2013-09-30 17:16:51 +04:00
|
|
|
struct pid *ns_pid = &item->pid;
|
2013-09-30 17:16:53 +04:00
|
|
|
struct ns_id *ns;
|
2014-09-22 16:28:00 +04:00
|
|
|
int pid, nr = 0;
|
2012-02-01 15:58:30 +04:00
|
|
|
int ret = 0;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The setns syscall is cool, we can switch to the other
|
|
|
|
* namespace and then return back to our initial one, but
|
|
|
|
* for me it's much easier just to fork another task and
|
|
|
|
* let it do the job, all the more so it can be done in
|
|
|
|
* parallel with task dumping routine.
|
|
|
|
*
|
|
|
|
* However, the question how to dump sockets from the target
|
2013-04-12 13:00:06 -07:00
|
|
|
* net namespace with this is still open
|
2012-01-26 15:27:00 +04:00
|
|
|
*/
|
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
pr_info("Dumping %d(%d)'s namespaces\n", ns_pid->virt, ns_pid->real);
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if ((ns_flags & CLONE_NEWPID) && ns_pid->virt != 1) {
|
2012-06-22 00:38:00 +04:00
|
|
|
pr_err("Can't dump a pid namespace without the process init\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-04-18 18:42:51 +04:00
|
|
|
for (ns = ns_ids; ns; ns = ns->next) {
|
2013-09-30 17:16:53 +04:00
|
|
|
/* Skip current namespaces, which are in the list too */
|
2014-04-18 18:42:51 +04:00
|
|
|
if (ns->pid == getpid())
|
2013-09-30 17:16:53 +04:00
|
|
|
continue;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2014-09-22 16:27:00 +04:00
|
|
|
switch (ns->nd->cflag) {
|
|
|
|
/* No data for pid namespaces to dump */
|
|
|
|
case CLONE_NEWPID:
|
|
|
|
/* Dumped explicitly with dump_mnt_namespaces() */
|
|
|
|
case CLONE_NEWNS:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-09-30 17:16:53 +04:00
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
pr_perror("Can't fork ns dumper");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2013-09-30 17:16:53 +04:00
|
|
|
if (pid == 0) {
|
|
|
|
ret = do_dump_namespaces(ns);
|
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
|
2014-09-22 16:28:00 +04:00
|
|
|
nr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (nr > 0) {
|
|
|
|
int status;
|
|
|
|
|
|
|
|
ret = waitpid(-1, &status, 0);
|
|
|
|
if (ret < 0) {
|
2013-09-30 17:16:53 +04:00
|
|
|
pr_perror("Can't wait ns dumper");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
|
|
|
pr_err("Namespaces dumping finished with error %d\n", status);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-09-22 16:28:00 +04:00
|
|
|
|
|
|
|
nr--;
|
2012-01-26 15:27:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Namespaces dump complete\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 15:09:19 +03:00
|
|
|
static int write_id_map(pid_t pid, UidGidExtent **extents, int n, char *id_map)
|
|
|
|
{
|
|
|
|
char buf[PAGE_SIZE];
|
|
|
|
int off = 0, i;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can perform only a single write (that may contain multiple
|
|
|
|
* newline-delimited records) to a uid_map and a gid_map files.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
off += snprintf(buf + off, sizeof(buf) - off,
|
|
|
|
"%d %d %d\n", extents[i]->first,
|
|
|
|
extents[i]->lower_first,
|
|
|
|
extents[i]->count);
|
|
|
|
|
|
|
|
fd = open_proc_rw(pid, "%s", id_map);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
if (write(fd, buf, off) != off) {
|
|
|
|
pr_perror("Unable to write into %s\n", id_map);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prepare_userns(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
struct cr_img *img;
|
|
|
|
UsernsEntry *e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
img = open_image(CR_FD_USERNS, O_RSTR, item->ids->user_ns_id);
|
|
|
|
if (!img)
|
|
|
|
return -1;
|
|
|
|
ret = pb_read_one(img, &e, PB_USERNS);
|
|
|
|
close_image(img);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (write_id_map(item->pid.real, e->uid_map, e->n_uid_map, "uid_map"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (write_id_map(item->pid.real, e->gid_map, e->n_gid_map, "gid_map"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-01 16:15:00 +04:00
|
|
|
int collect_namespaces(bool for_dump)
|
2014-09-29 22:03:42 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-10-29 11:09:00 +04:00
|
|
|
ret = collect_mnt_namespaces(for_dump);
|
2014-09-29 22:03:42 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-10-01 16:15:00 +04:00
|
|
|
ret = collect_net_namespaces(for_dump);
|
2014-09-29 22:03:55 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-11-07 13:56:34 +03:00
|
|
|
ret = collect_user_namespaces(for_dump);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-09-29 22:03:42 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 15:09:19 +03:00
|
|
|
static int prepare_userns_creds()
|
|
|
|
{
|
|
|
|
/* UID and GID must be set after restoring /proc/PID/{uid,gid}_maps */
|
|
|
|
if (setuid(0) || setgid(0) || setgroups(0, NULL)) {
|
|
|
|
pr_perror("Unable to initialize id-s");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-31 12:14:30 +03:00
|
|
|
/*
|
|
|
|
* This flag is dropped after entering userns, but is
|
|
|
|
* required to access files in /proc, so put one here
|
|
|
|
* temoprarily. It will be set to proper value at the
|
|
|
|
* very end.
|
|
|
|
*/
|
|
|
|
if (prctl(PR_SET_DUMPABLE, 1, 0)) {
|
|
|
|
pr_perror("Unable to set PR_SET_DUMPABLE");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2014-11-07 15:09:19 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-30 17:16:51 +04:00
|
|
|
int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2013-09-30 17:16:51 +04:00
|
|
|
pid_t pid = item->pid.virt;
|
|
|
|
int id;
|
|
|
|
|
2012-04-13 19:44:00 +04:00
|
|
|
pr_info("Restoring namespaces %d flags 0x%lx\n",
|
2013-09-30 17:16:51 +04:00
|
|
|
item->pid.virt, clone_flags);
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2014-11-07 15:09:19 +03:00
|
|
|
if ((clone_flags & CLONE_NEWUSER) && prepare_userns_creds())
|
|
|
|
return -1;
|
|
|
|
|
2012-08-02 08:06:29 +04:00
|
|
|
/*
|
|
|
|
* On netns restore we launch an IP tool, thus we
|
|
|
|
* have to restore it _before_ altering the mount
|
|
|
|
* tree (i.e. -- mnt_ns restoring)
|
|
|
|
*/
|
|
|
|
|
2013-09-30 17:16:51 +04:00
|
|
|
id = ns_per_id ? item->ids->net_ns_id : pid;
|
|
|
|
if ((clone_flags & CLONE_NEWNET) && prepare_net_ns(id))
|
2012-09-28 14:09:58 +04:00
|
|
|
return -1;
|
2013-09-30 17:16:51 +04:00
|
|
|
id = ns_per_id ? item->ids->uts_ns_id : pid;
|
|
|
|
if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(id))
|
2012-09-28 14:09:58 +04:00
|
|
|
return -1;
|
2013-09-30 17:16:51 +04:00
|
|
|
id = ns_per_id ? item->ids->ipc_ns_id : pid;
|
|
|
|
if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id))
|
2012-09-28 14:09:58 +04:00
|
|
|
return -1;
|
2014-04-22 20:38:54 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This one is special -- there can be several mount
|
|
|
|
* namespaces and prepare_mnt_ns handles them itself.
|
|
|
|
*/
|
|
|
|
if (prepare_mnt_ns())
|
2012-09-28 14:09:58 +04:00
|
|
|
return -1;
|
2012-09-25 15:59:13 +04:00
|
|
|
|
2012-09-28 14:09:58 +04:00
|
|
|
return 0;
|
2012-01-26 15:27:00 +04:00
|
|
|
}
|
|
|
|
|
2013-05-28 21:11:13 +04:00
|
|
|
int try_show_namespaces(int ns_pid)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *imgset;
|
2014-09-29 12:48:53 +04:00
|
|
|
int i, ret;
|
|
|
|
struct cr_img *img;
|
2013-09-30 17:16:51 +04:00
|
|
|
TaskKobjIdsEntry *ids;
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2013-04-02 11:30:14 +04:00
|
|
|
pr_msg("Namespaces for %d:\n", ns_pid);
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_IDS, O_RSTR, ns_pid);
|
|
|
|
if (!img)
|
2013-09-30 17:16:51 +04:00
|
|
|
return -1;
|
2014-09-29 12:48:53 +04:00
|
|
|
ret = pb_read_one(img, &ids, PB_IDS);
|
|
|
|
close_image(img);
|
2013-09-30 17:16:51 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
imgset = cr_imgset_open(ids->net_ns_id, NETNS, O_SHOW);
|
|
|
|
if (imgset) {
|
2013-09-30 17:16:45 +04:00
|
|
|
pr_msg("-------------------NETNS---------------------\n");
|
|
|
|
for (i = _CR_FD_NETNS_FROM + 1; i < _CR_FD_NETNS_TO; i++) {
|
2014-09-29 12:48:53 +04:00
|
|
|
img = img_from_set(imgset, i);
|
|
|
|
if (!img)
|
2013-09-30 17:16:45 +04:00
|
|
|
continue;
|
2012-02-09 12:09:48 +03:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_parse_fd(img, imgset_template[i].magic);
|
2013-09-30 17:16:45 +04:00
|
|
|
}
|
2014-09-29 12:47:37 +04:00
|
|
|
close_cr_imgset(&imgset);
|
2013-09-30 17:16:45 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
imgset = cr_imgset_open(ids->ipc_ns_id, IPCNS, O_SHOW);
|
|
|
|
if (imgset) {
|
2013-09-30 17:16:45 +04:00
|
|
|
pr_msg("-------------------IPCNS---------------------\n");
|
|
|
|
for (i = _CR_FD_IPCNS_FROM + 1; i < _CR_FD_IPCNS_TO; i++) {
|
2014-09-29 12:48:53 +04:00
|
|
|
img = img_from_set(imgset, i);
|
|
|
|
if (!img)
|
2013-09-30 17:16:45 +04:00
|
|
|
continue;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_parse_fd(img, imgset_template[i].magic);
|
2013-09-30 17:16:45 +04:00
|
|
|
}
|
2014-09-29 12:47:37 +04:00
|
|
|
close_cr_imgset(&imgset);
|
2012-03-27 12:01:14 +04:00
|
|
|
}
|
2013-09-30 17:16:45 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_UTSNS, O_SHOW, ids->uts_ns_id);
|
|
|
|
if (img) {
|
2013-09-30 17:16:45 +04:00
|
|
|
pr_msg("-------------------UTSNS---------------------\n");
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_parse_fd(img, imgset_template[CR_FD_UTSNS].magic);
|
|
|
|
close_image(img);
|
2013-09-30 17:16:45 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_MNTS, O_SHOW, ids->mnt_ns_id);
|
|
|
|
if (img) {
|
2013-09-30 17:16:45 +04:00
|
|
|
pr_msg("-------------------MNTNS---------------------\n");
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_parse_fd(img, imgset_template[CR_FD_MNTS].magic);
|
|
|
|
close_image(img);
|
2013-09-30 17:16:45 +04:00
|
|
|
}
|
|
|
|
|
2013-04-02 11:30:14 +04:00
|
|
|
pr_msg("---[ end of %d namespaces ]---\n", ns_pid);
|
2012-01-26 15:27:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2013-01-15 23:24:01 +04:00
|
|
|
|
2013-05-20 13:30:17 +04:00
|
|
|
struct ns_desc pid_ns_desc = NS_DESC_ENTRY(CLONE_NEWPID, "pid");
|
|
|
|
struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, "user");
|