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>
|
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"
|
|
|
|
|
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
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", pid, nd->str);
|
2012-01-26 15:27:00 +04:00
|
|
|
nsfd = open(buf, O_RDONLY);
|
|
|
|
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;
|
|
|
|
futex_set(&nsid->created, 0);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
static unsigned int lookup_ns_id(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)
|
|
|
|
return nsid->id;
|
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
unsigned int id;
|
|
|
|
struct ns_id *nsid;
|
|
|
|
|
|
|
|
id = lookup_ns_id(kid, nd);
|
|
|
|
if (id)
|
|
|
|
return id;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
return nsid->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int get_ns_id(int pid, struct ns_desc *nd)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
ret = readlinkat(proc_dir, ns_path, ns_id, sizeof(ns_id));
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't readlink ns link");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-18 04:00:05 +04:00
|
|
|
kid = parse_ns_link(ns_id, ret, nd);
|
|
|
|
BUG_ON(!kid);
|
|
|
|
|
2013-01-17 18:10:29 +04:00
|
|
|
return generate_ns_id(pid, kid, nd);
|
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;
|
|
|
|
unsigned int nsid;
|
|
|
|
|
|
|
|
nsid = lookup_ns_id(link->ns_kid, link->ns_d);
|
|
|
|
if (!nsid) {
|
|
|
|
pr_err("No NS ID with kid %u\n", link->ns_kid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfe.id = id;
|
|
|
|
nfe.ns_id = nsid;
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
ids->net_ns_id = get_ns_id(pid, &net_ns_desc);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-30 13:48:00 +04:00
|
|
|
static int gen_ns_ids(int pid)
|
|
|
|
{
|
2014-04-23 01:38:58 +04:00
|
|
|
/* needed for mntns_get_root_fd */
|
2014-01-30 13:48:00 +04:00
|
|
|
if (!get_ns_id(pid, &mnt_ns_desc))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We use ns_mask in various places to check whether
|
|
|
|
* the tasks we dump live in namespaces or not. The
|
|
|
|
* mask generation is tied with dumping inventory and
|
|
|
|
* tasks' images, which is not needed for pre-dump.
|
|
|
|
* This routine generates a mask for pre-dump.
|
|
|
|
*/
|
|
|
|
int gen_predump_ns_mask(void)
|
|
|
|
{
|
2014-04-21 18:23:22 +04:00
|
|
|
BUG_ON(root_ns_mask);
|
2014-01-30 13:48:00 +04:00
|
|
|
|
|
|
|
if (gen_ns_ids(getpid()))
|
|
|
|
return -1;
|
|
|
|
if (gen_ns_ids(root_item->pid.real))
|
|
|
|
return -1;
|
|
|
|
|
2014-04-21 18:23:22 +04:00
|
|
|
pr_info("NS mask generated: %lx\n", root_ns_mask);
|
2014-01-30 13:48:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
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-09-29 22:03:42 +04:00
|
|
|
int collect_namespaces(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = collect_mnt_namespaces();
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-09-29 22:03:55 +04:00
|
|
|
ret = collect_net_namespaces();
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-09-29 22:03:42 +04: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
|
|
|
|
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");
|