<div dir="ltr">Here is the patch with the fixes you pointed out. I am still looking at the zdtm tests at the moment.<div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Aug 12, 2014 at 3:56 PM, Sophie Blee-Goldman <span dir="ltr"><<a href="mailto:ableegoldman@google.com" target="_blank">ableegoldman@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">Adds basic support for user namespaces by dumping and restoring<br>
the namespace itself and the uid/gid maps of the root process.<br>
<br>
Currently depends on a kernel patch to avoid failing on the prctl<br>
syscall by checking for CAP_SYS_RESOURCE in the user namespace<br>
instead of in the global one.<br>
<br>
Signed-off-by: Sophie Blee-Goldman <<a href="mailto:ableegoldman@google.com">ableegoldman@google.com</a>><br>
</div>---<br>
Makefile.crtools | 1 +<br>
cr-restore.c | 7 ++<br>
cr-show.c | 2 +<br>
image-desc.c | 1 +<br>
include/image-desc.h | 1 +<br>
include/magic.h | 1 +<br>
include/namespaces.h | 1 -<br>
include/protobuf-desc.h | 5 +-<br>
include/syscall-types.h | 6 +-<br>
include/user_ns.h | 9 ++<br>
namespaces.c | 27 +++++-<br>
protobuf-desc.c | 1 +<br>
protobuf/Makefile | 1 +<br>
protobuf/core.proto | 1 +<br>
protobuf/userns.proto | 9 ++<br>
pstree.c | 2 +<br>
user_ns.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++<br>
17 files changed, 296 insertions(+), 6 deletions(-)<br>
create mode 100644 include/user_ns.h<br>
create mode 100644 protobuf/userns.proto<br>
create mode 100644 user_ns.c<br>
<div class=""><br>
diff --git a/Makefile.crtools b/Makefile.crtools<br>
index 6033b2c..8e680d6 100644<br>
--- a/Makefile.crtools<br>
+++ b/Makefile.crtools<br>
@@ -34,6 +34,7 @@ obj-y += pipes.o<br>
obj-y += fifo.o<br>
obj-y += file-ids.o<br>
obj-y += namespaces.o<br>
+obj-y += user_ns.o<br>
obj-y += uts_ns.o<br>
obj-y += ipc_ns.o<br>
obj-y += netfilter.o<br>
diff --git a/cr-restore.c b/cr-restore.c<br>
</div>index 2bc98e8..a93fa74 100644<br>
<div class="">--- a/cr-restore.c<br>
+++ b/cr-restore.c<br>
@@ -52,6 +52,7 @@<br>
#include "restorer-blob.h"<br>
#include "crtools.h"<br>
#include "namespaces.h"<br>
+#include "user_ns.h"<br>
#include "mem.h"<br>
#include "mount.h"<br>
#include "fsnotify.h"<br>
</div>@@ -1612,6 +1613,12 @@ static int restore_root_task(struct pstree_item *init)<br>
<div class=""> if (ret)<br>
goto out;<br>
<br>
+ if (root_ns_mask & CLONE_NEWUSER) {<br>
+ ret = restore_user_ns(init->pid.real, init->ids->user_ns_id);<br>
+ if (ret < 0)<br>
+ goto out;<br>
+ }<br>
+<br>
ret = run_scripts("setup-namespaces");<br>
if (ret)<br>
goto out;<br>
diff --git a/cr-show.c b/cr-show.c<br>
</div>index 0e1a2c6..2b28746 100644<br>
<div class="">--- a/cr-show.c<br>
+++ b/cr-show.c<br>
@@ -21,6 +21,7 @@<br>
#include "util.h"<br>
#include "sockets.h"<br>
#include "image.h"<br>
+#include "user_ns.h"<br>
#include "uts_ns.h"<br>
#include "ipc_ns.h"<br>
#include "pstree.h"<br>
@@ -291,6 +292,7 @@ static struct show_image_info show_infos[] = {<br>
SHOW_VERT(CORE),<br>
SHOW_VERT(IDS),<br>
SHOW_VERT(CREDS),<br>
+ SHOW_VERT(USERNS),<br>
SHOW_VERT(UTSNS),<br>
SHOW_VERT(IPC_VAR),<br>
SHOW_VERT(FS),<br>
diff --git a/image-desc.c b/image-desc.c<br>
</div>index 49dc29d..814c3b2 100644<br>
<div class="">--- a/image-desc.c<br>
+++ b/image-desc.c<br>
@@ -52,6 +52,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {<br>
FD_ENTRY(POSIX_TIMERS, "posix-timers-%d"),<br>
FD_ENTRY(CREDS, "creds-%d"),<br>
FD_ENTRY(UTSNS, "utsns-%d"),<br>
+ FD_ENTRY(USERNS, "userns-%d"),<br>
FD_ENTRY(IPC_VAR, "ipcns-var-%d"),<br>
FD_ENTRY(IPCNS_SHM, "ipcns-shm-%d"),<br>
FD_ENTRY(IPCNS_MSG, "ipcns-msg-%d"),<br>
diff --git a/include/image-desc.h b/include/image-desc.h<br>
</div>index 93b3392..18535e1 100644<br>
--- a/include/image-desc.h<br>
+++ b/include/image-desc.h<br>
@@ -25,6 +25,7 @@ enum {<br>
<div><div class="h5"> /*<br>
* NS entries<br>
*/<br>
+ CR_FD_USERNS,<br>
CR_FD_UTSNS,<br>
CR_FD_MNTS,<br>
<br>
diff --git a/include/magic.h b/include/magic.h<br>
index 5192a60..06db3e3 100644<br>
--- a/include/magic.h<br>
+++ b/include/magic.h<br>
@@ -40,6 +40,7 @@<br>
#define ITIMERS_MAGIC 0x57464056 /* Kostroma */<br>
#define POSIX_TIMERS_MAGIC 0x52603957 /* Lipetsk */<br>
#define SK_QUEUES_MAGIC 0x56264026 /* Suzdal */<br>
+#define USERNS_MAGIC 0x55474908 /* Kazan */<br>
#define UTSNS_MAGIC 0x54473203 /* Smolensk */<br>
#define CREDS_MAGIC 0x54023547 /* Kozelsk */<br>
#define IPC_VAR_MAGIC 0x53115007 /* Samara */<br>
diff --git a/include/namespaces.h b/include/namespaces.h<br>
index 350b8b4..bc67519 100644<br>
--- a/include/namespaces.h<br>
+++ b/include/namespaces.h<br>
@@ -34,7 +34,6 @@ extern struct ns_id *ns_ids;<br>
extern bool check_ns_proc(struct fd_link *link);<br>
<br>
extern struct ns_desc pid_ns_desc;<br>
-extern struct ns_desc user_ns_desc;<br>
extern unsigned long root_ns_mask;<br>
<br>
extern const struct fdtype_ops nsfile_dump_ops;<br>
diff --git a/include/protobuf-desc.h b/include/protobuf-desc.h<br>
index 01c9f4c..1c8f9ce 100644<br>
--- a/include/protobuf-desc.h<br>
+++ b/include/protobuf-desc.h<br>
@@ -52,14 +52,15 @@ enum {<br>
PB_IRMAP_CACHE,<br>
PB_CGROUP,<br>
PB_TIMERFD,<br>
+ PB_USERNS,<br>
<br>
/* PB_AUTOGEN_STOP */<br>
<br>
PB_PAGEMAP_HEAD,<br>
PB_IDS,<br>
PB_SIGACT,<br>
- PB_NETDEV,<br>
- PB_REMAP_FPATH, /* 50 */<br>
+ PB_NETDEV, /* 50 */<br>
+ PB_REMAP_FPATH,<br>
PB_SK_QUEUES,<br>
PB_IPCNS_MSG,<br>
PB_IPCNS_MSG_ENT,<br>
diff --git a/include/syscall-types.h b/include/syscall-types.h<br>
index bab3dba..eb270b3 100644<br>
--- a/include/syscall-types.h<br>
+++ b/include/syscall-types.h<br>
@@ -57,7 +57,11 @@ struct itimerspec;<br>
#define CLONE_NEWNET 0x40000000<br>
#endif<br>
<br>
-#define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS)<br>
+#ifndef CLONE_NEWUSER<br>
+#define CLONE_NEWUSER 0x10000000<br>
+#endif<br>
+<br>
+#define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER)<br>
<br>
/* Nested namespaces are supported only for these types */<br>
#define CLONE_SUBNS (CLONE_NEWNS)<br>
diff --git a/include/user_ns.h b/include/user_ns.h<br>
new file mode 100644<br>
index 0000000..715b155<br>
--- /dev/null<br>
+++ b/include/user_ns.h<br>
@@ -0,0 +1,9 @@<br>
+#ifndef __CR_USER_NS_H__<br>
+#define __CR_USER_NS_H__<br>
+<br>
+extern int dump_user_ns(int ns_pid, int ns_id);<br>
+extern int restore_user_ns(int real_pid, int ns_id);<br>
+<br>
+extern struct ns_desc user_ns_desc;<br>
+<br>
+#endif /* __CR_USER_NS_H__ */<br>
diff --git a/namespaces.c b/namespaces.c<br>
index 6be030f..8c0d842 100644<br>
--- a/namespaces.c<br>
+++ b/namespaces.c<br>
@@ -9,6 +9,7 @@<br>
#include "uts_ns.h"<br>
#include "ipc_ns.h"<br>
#include "mount.h"<br>
+#include "user_ns.h"<br>
#include "pstree.h"<br>
#include "namespaces.h"<br>
#include "net.h"<br>
@@ -271,7 +272,7 @@ struct ns_file_info {<br>
static int open_ns_fd(struct file_desc *d)<br>
{<br>
struct ns_file_info *nfi = container_of(d, struct ns_file_info, d);<br>
- struct pstree_item *item, *t;<br>
+ struct pstree_item *item = NULL, *t;<br>
struct ns_desc *nd = NULL;<br>
char path[64];<br>
int fd;<br>
@@ -304,6 +305,10 @@ static int open_ns_fd(struct file_desc *d)<br>
item = t;<br>
nd = &mnt_ns_desc;<br>
break;<br>
+ } else if (ids->user_ns_id == nfi->nfe->ns_id) {<br>
+ item = t;<br>
+ nd = &user_ns_desc;<br>
+ break;<br>
}<br>
}<br>
<br>
@@ -391,6 +396,13 @@ int dump_task_ns_ids(struct pstree_item *item)<br>
return -1;<br>
}<br>
<br>
+ ids->has_user_ns_id = true;<br>
+ ids->user_ns_id = get_ns_id(pid, &user_ns_desc);<br>
+ if (!ids->user_ns_id) {<br>
+ pr_err("Can't make userns id\n");<br>
+ return -1;<br>
+ }<br>
+<br>
return 0;<br>
}<br>
<br>
@@ -446,6 +458,11 @@ static int do_dump_namespaces(struct ns_id *ns)<br>
ns->id, ns->pid);<br>
ret = dump_net_ns(ns->pid, ns->id);<br>
break;<br>
+ case CLONE_NEWUSER:<br>
+ pr_info("Dump USER namespace info %d via %d\n",<br>
+ ns->id, ns->pid);<br>
+ ret = dump_user_ns(ns->pid, ns->id);<br>
+ break;<br>
default:<br>
pr_err("Unknown namespace flag %x", ns->nd->cflag);<br>
break;<br>
@@ -604,9 +621,15 @@ int try_show_namespaces(int ns_pid)<br>
close(fd);<br>
}<br>
<br>
+ fd = open_image(CR_FD_USERNS, O_SHOW, ids->user_ns_id);<br>
+ if (fd > 0) {<br>
+ pr_msg("-------------------USERNS---------------------\n");<br>
+ cr_parse_fd(fd, fdset_template[CR_FD_USERNS].magic);<br>
+ close(fd);<br>
+ }<br>
+<br>
pr_msg("---[ end of %d namespaces ]---\n", ns_pid);<br>
return 0;<br>
}<br>
<br>
struct ns_desc pid_ns_desc = NS_DESC_ENTRY(CLONE_NEWPID, "pid");<br>
-struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, "user");<br>
diff --git a/protobuf-desc.c b/protobuf-desc.c<br>
index b97418b..9199b09 100644<br>
--- a/protobuf-desc.c<br>
+++ b/protobuf-desc.c<br>
@@ -38,6 +38,7 @@<br>
#include "protobuf/sk-packet.pb-c.h"<br>
#include "protobuf/creds.pb-c.h"<br>
#include "protobuf/timer.pb-c.h"<br>
+#include "protobuf/userns.pb-c.h"<br>
#include "protobuf/utsns.pb-c.h"<br>
#include "protobuf/ipc-var.pb-c.h"<br>
#include "protobuf/ipc-shm.pb-c.h"<br>
diff --git a/protobuf/Makefile b/protobuf/Makefile<br>
index 7f6485b..cd2b854 100644<br>
--- a/protobuf/Makefile<br>
+++ b/protobuf/Makefile<br>
@@ -50,6 +50,7 @@ proto-obj-y += ipc-shm.o<br>
proto-obj-y += ipc-msg.o<br>
proto-obj-y += ipc-sem.o<br>
proto-obj-y += utsns.o<br>
+proto-obj-y += userns.o<br>
proto-obj-y += creds.o<br>
proto-obj-y += vma.o<br>
proto-obj-y += netdev.o<br>
diff --git a/protobuf/core.proto b/protobuf/core.proto<br>
index d850e2e..8810376 100644<br>
--- a/protobuf/core.proto<br>
+++ b/protobuf/core.proto<br>
@@ -32,6 +32,7 @@ message task_kobj_ids_entry {<br>
optional uint32 ipc_ns_id = 7;<br>
optional uint32 uts_ns_id = 8;<br>
optional uint32 mnt_ns_id = 9;<br>
+ optional uint32 user_ns_id = 10;<br>
}<br>
<br>
message thread_sas_entry {<br>
diff --git a/protobuf/userns.proto b/protobuf/userns.proto<br>
new file mode 100644<br>
index 0000000..31d7718<br>
--- /dev/null<br>
+++ b/protobuf/userns.proto<br>
@@ -0,0 +1,9 @@<br>
+message userns_entry {<br>
+ message map_entry {<br>
+ required uint32 id_in = 1;<br>
+ required uint32 id_out = 2;<br>
+ required uint32 length = 3;<br>
+ }<br>
+ repeated map_entry uid_map = 1;<br>
+ repeated map_entry gid_map = 2;<br>
+}<br>
\ No newline at end of file<br>
diff --git a/pstree.c b/pstree.c<br>
index d005b64..c905317 100644<br>
--- a/pstree.c<br>
+++ b/pstree.c<br>
@@ -603,6 +603,8 @@ static unsigned long get_clone_mask(TaskKobjIdsEntry *i,<br>
mask |= CLONE_NEWUTS;<br>
if (i->mnt_ns_id != p->mnt_ns_id)<br>
mask |= CLONE_NEWNS;<br>
+ if (i->user_ns_id != p->user_ns_id)<br>
+ mask |= CLONE_NEWUSER;<br>
<br>
return mask;<br>
}<br>
diff --git a/user_ns.c b/user_ns.c<br>
new file mode 100644<br>
</div></div>index 0000000..e90f068<br>
--- /dev/null<br>
+++ b/user_ns.c<br>
@@ -0,0 +1,227 @@<br>
<div><div class="h5">+#include <unistd.h><br>
+<br>
+#include "namespaces.h"<br>
+#include "user_ns.h"<br>
+#include "list.h"<br>
+<br>
+#include "protobuf.h"<br>
+#include "protobuf/userns.pb-c.h"<br>
+<br>
+struct map_entry {<br>
+ UsernsEntry__MapEntry entry;<br>
+ struct list_head list;<br>
+};<br>
+<br>
+static void cleanup(int *fd, struct list_head *uid_list,<br>
+ struct list_head *gid_list)<br>
+{<br>
+ struct map_entry *pos, *tmp;<br>
+<br>
+ /* free uid entries */<br>
+ list_for_each_entry_safe(pos, tmp, uid_list, list) {<br>
+ list_del(&pos->list);<br>
+ xfree(pos);<br>
+ }<br>
+<br>
+ /* free gid entries */<br>
+ list_for_each_entry_safe(pos, tmp, gid_list, list) {<br>
+ list_del(&pos->list);<br>
+ xfree(pos);<br>
+ }<br>
+<br>
+ close_safe(fd);<br>
+}<br>
+<br>
+static void fill_map(int n_entries, UsernsEntry__MapEntry **map,<br>
+ struct list_head *head)<br>
+{<br>
+ struct map_entry *tmp;<br>
+<br>
+ list_for_each_entry(tmp, head, list) {<br>
+ map[--n_entries] = &(tmp->entry);<br>
+ }<br>
+}<br>
+<br>
+static int write_pb(int fd, int n_uid_entries, int n_gid_entries,<br>
+ struct list_head *uid_list, struct list_head *gid_list)<br>
+{<br>
+ UsernsEntry ue = USERNS_ENTRY__INIT;<br>
+<br>
+ UsernsEntry__MapEntry *uidmap[n_uid_entries];<br>
+ fill_map(n_uid_entries, uidmap, uid_list);<br>
+ ue.uid_map = uidmap;<br>
+ ue.n_uid_map = n_uid_entries;<br>
+<br>
+ UsernsEntry__MapEntry *gidmap[n_gid_entries];<br>
+ fill_map(n_gid_entries, gidmap, gid_list);<br>
+ ue.gid_map = gidmap;<br>
+ ue.n_gid_map = n_gid_entries;<br>
+<br>
+ return pb_write_one(fd, &ue, PB_USERNS);<br>
+}<br>
+<br>
</div></div>+static int read_map_entries(int pid, const char *id_map, struct list_head *head)<br>
<div class="">+{<br>
+ int n_read, n_entries = 0;<br>
+ FILE *fp;<br>
+ struct map_entry *tmp;<br>
+ UsernsEntry__MapEntry entry = USERNS_ENTRY__MAP_ENTRY__INIT;<br>
+<br>
</div>+ pr_debug("Reading entries from /proc/%d/%s\n", pid, id_map);<br>
+<br>
+ fp = fopen_proc(pid, "%s", id_map);<br>
+ if (!fp) {<br>
+ pr_perror("Error opening /proc/%d/%s\n", pid, id_map);<br>
<div class="">+ return -1;<br>
+ }<br>
+<br>
+ while ((n_read = fscanf(fp, "%u %u %u\n", &entry.id_in,<br>
+ &entry.id_out, &entry.length)) != EOF) {<br>
+ if (n_read != 3) {<br>
</div>+ pr_perror("Error reading /proc/%d/%s, fscanf returned %d",<br>
+ pid, id_map, n_read);<br>
<div class="">+ fclose(fp);<br>
+ return -1;<br>
+ }<br>
+<br>
+ tmp = (struct map_entry *)xmalloc(sizeof(struct map_entry));<br>
+ if (!tmp) {<br>
+ fclose(fp);<br>
+ return -1;<br>
+ }<br>
+<br>
+ memcpy(&tmp->entry, &entry, sizeof(UsernsEntry__MapEntry));<br>
+ list_add(&(tmp->list), head);<br>
+ n_entries++;<br>
+ }<br>
+<br>
+ if (fclose(fp) != 0) {<br>
</div>+ pr_perror("fclose(/proc/%d/%s) failed", pid, id_map);<br>
<div class="">+ return -1;<br>
+ }<br>
+<br>
+ return n_entries;<br>
+}<br>
+<br>
</div>+static int write_map_entries(int pid, const char *id_map,<br>
<div class="">+ UsernsEntry__MapEntry **map,<br>
+ size_t n_entries)<br>
+{<br>
</div>+ int i, fd, n_written, total = 0;<br>
+ char buf[PAGE_SIZE];<br>
+<br>
+ pr_debug("Writing entries to /proc/%d/%s, n_entries=%lu\n",<br>
+ pid, id_map, n_entries);<br>
+<br>
+ for (i = 0; i < n_entries; i++) {<br>
+ n_written = snprintf(buf + total, sizeof(buf) - total,<br>
+ "%u %u %u\n",<br>
<div class="">+ map[i]->id_in,<br>
+ map[i]->id_out,<br>
+ map[i]->length);<br>
</div>+ if (n_written < 0) {<br>
+ pr_err("snprintf failed for %s of pid: %d\n", id_map, pid);<br>
+ return -1;<br>
+ }<br>
+ total += n_written;<br>
+ }<br>
+<br>
+ /* id_maps can only be written to once */<br>
+ fd = open_proc_rw(pid, "%s", id_map);<br>
+ if (fd < 0) {<br>
+ pr_perror("Unable to open /proc/%d/%s\n", pid, id_map);<br>
<div class="">+ return -1;<br>
+ }<br>
+<br>
</div>+ if (write(fd, buf, total) != total) {<br>
+ pr_perror("Failed to write all %d bytes to /proc/%d/%s",<br>
+ total, pid, id_map);<br>
+ close_safe(&fd);<br>
<div class="">+ return -1;<br>
+ }<br>
+<br>
</div>+ close_safe(&fd);<br>
<div class="">+<br>
+ return 0;<br>
+}<br>
+<br>
+int dump_user_ns(int ns_pid, int ns_id)<br>
+{<br>
+ int fd, ret, n_uid_entries, n_gid_entries;<br>
+<br>
</div><div class="">+ LIST_HEAD(uid_list);<br>
+ LIST_HEAD(gid_list);<br>
+<br>
+ fd = open_image(CR_FD_USERNS, O_DUMP, ns_id);<br>
+ if (fd < 0) {<br>
+ pr_err("Error opening userns image");<br>
+ return -1;<br>
+ }<br>
+<br>
+ /* read uid map */<br>
</div>+ n_uid_entries = read_map_entries(ns_pid, "uid_map", &uid_list);<br>
<div class="">+ if (n_uid_entries < 0) {<br>
+ pr_err("Error reading uid_map\n");<br>
+ ret = -1;<br>
+ goto out;<br>
+ }<br>
+<br>
+ /* read gid map */<br>
</div>+ n_gid_entries = read_map_entries(ns_pid, "gid_map", &gid_list);<br>
<div class="">+ if (n_gid_entries < 0) {<br>
+ pr_err("Error reading gid_map\n");<br>
+ ret = -1;<br>
+ goto out;<br>
+ }<br>
+<br>
+ ret = write_pb(fd, n_uid_entries, n_gid_entries, &uid_list, &gid_list);<br>
+<br>
+out:<br>
+ cleanup(&fd, &uid_list, &gid_list);<br>
+ return ret;<br>
+}<br>
+<br>
+/*<br>
+ * Restore uid_map and gid_map file for the init process. Since this is called<br>
+ * from the parent, we access these files using the 'real_pid' of the process.<br>
+ */<br>
+int restore_user_ns(int real_pid, int ns_id)<br>
+{<br>
+ int fd, ret = 0;<br>
+ UsernsEntry *ue;<br>
+<br>
</div><div class="">+ pr_info("Restoring user namespace for real_pid:%d\n", real_pid);<br>
+<br>
+ fd = open_image(CR_FD_USERNS, O_RSTR, ns_id);<br>
+ if (fd < 0)<br>
+ return -1;<br>
+<br>
+ ret = pb_read_one(fd, &ue, PB_USERNS);<br>
+ if (ret < 0)<br>
+ return -1;<br>
+<br>
+ pr_info("userns restoring: n_uid_map:%lu ; n_gid_map:%lu\n",<br>
+ ue->n_uid_map, ue->n_gid_map);<br>
+<br>
+ /* restore uid_map */<br>
</div>+ ret = write_map_entries(real_pid, "uid_map", ue->uid_map, ue->n_uid_map);<br>
+ if (ret < 0) {<br>
+ pr_err("Failed to restore /proc/%d/uid_map\n", real_pid);<br>
<div class="">+ goto out;<br>
+ }<br>
+<br>
+ /* restore gid_map */<br>
</div>+ ret = write_map_entries(real_pid, "gid_map", ue->gid_map, ue->n_gid_map);<br>
+ if (ret < 0) {<br>
+ pr_err("Failed to restore /proc/%d/gid_map", real_pid);<br>
<div class="">+ goto out;<br>
+ }<br>
+<br>
+out:<br>
+ userns_entry__free_unpacked(ue, NULL);<br>
+<br>
+ close_safe(&fd);<br>
+ return ret;<br>
+}<br>
+<br>
+struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, "user");<br>
--<br>
</div>2.1.0.rc2.206.gedb03e5<br>
<br>
</blockquote></div><br></div></div>