<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">&lt;<a href="mailto:ableegoldman@google.com" target="_blank">ableegoldman@google.com</a>&gt;</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 &lt;<a href="mailto:ableegoldman@google.com">ableegoldman@google.com</a>&gt;<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 &quot;restorer-blob.h&quot;<br>
 #include &quot;crtools.h&quot;<br>
 #include &quot;namespaces.h&quot;<br>
+#include &quot;user_ns.h&quot;<br>
 #include &quot;mem.h&quot;<br>
 #include &quot;mount.h&quot;<br>
 #include &quot;fsnotify.h&quot;<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 &amp; CLONE_NEWUSER) {<br>
+               ret = restore_user_ns(init-&gt;pid.real, init-&gt;ids-&gt;user_ns_id);<br>
+               if (ret &lt; 0)<br>
+                       goto out;<br>
+       }<br>
+<br>
        ret = run_scripts(&quot;setup-namespaces&quot;);<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 &quot;util.h&quot;<br>
 #include &quot;sockets.h&quot;<br>
 #include &quot;image.h&quot;<br>
+#include &quot;user_ns.h&quot;<br>
 #include &quot;uts_ns.h&quot;<br>
 #include &quot;ipc_ns.h&quot;<br>
 #include &quot;pstree.h&quot;<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,  &quot;posix-timers-%d&quot;),<br>
        FD_ENTRY(CREDS,         &quot;creds-%d&quot;),<br>
        FD_ENTRY(UTSNS,         &quot;utsns-%d&quot;),<br>
+       FD_ENTRY(USERNS,        &quot;userns-%d&quot;),<br>
        FD_ENTRY(IPC_VAR,       &quot;ipcns-var-%d&quot;),<br>
        FD_ENTRY(IPCNS_SHM,     &quot;ipcns-shm-%d&quot;),<br>
        FD_ENTRY(IPCNS_MSG,     &quot;ipcns-msg-%d&quot;),<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 &quot;uts_ns.h&quot;<br>
 #include &quot;ipc_ns.h&quot;<br>
 #include &quot;mount.h&quot;<br>
+#include &quot;user_ns.h&quot;<br>
 #include &quot;pstree.h&quot;<br>
 #include &quot;namespaces.h&quot;<br>
 #include &quot;net.h&quot;<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 = &amp;mnt_ns_desc;<br>
                        break;<br>
+               } else if (ids-&gt;user_ns_id == nfi-&gt;nfe-&gt;ns_id) {<br>
+                       item = t;<br>
+                       nd = &amp;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-&gt;has_user_ns_id = true;<br>
+       ids-&gt;user_ns_id = get_ns_id(pid, &amp;user_ns_desc);<br>
+       if (!ids-&gt;user_ns_id) {<br>
+               pr_err(&quot;Can&#39;t make userns id\n&quot;);<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-&gt;id, ns-&gt;pid);<br>
                ret = dump_net_ns(ns-&gt;pid, ns-&gt;id);<br>
                break;<br>
+       case CLONE_NEWUSER:<br>
+               pr_info(&quot;Dump USER namespace info %d via %d\n&quot;,<br>
+                               ns-&gt;id, ns-&gt;pid);<br>
+               ret = dump_user_ns(ns-&gt;pid, ns-&gt;id);<br>
+               break;<br>
        default:<br>
                pr_err(&quot;Unknown namespace flag %x&quot;, ns-&gt;nd-&gt;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-&gt;user_ns_id);<br>
+       if (fd &gt; 0) {<br>
+               pr_msg(&quot;-------------------USERNS---------------------\n&quot;);<br>
+               cr_parse_fd(fd, fdset_template[CR_FD_USERNS].magic);<br>
+               close(fd);<br>
+       }<br>
+<br>
        pr_msg(&quot;---[ end of %d namespaces ]---\n&quot;, ns_pid);<br>
        return 0;<br>
 }<br>
<br>
 struct ns_desc pid_ns_desc = NS_DESC_ENTRY(CLONE_NEWPID, &quot;pid&quot;);<br>
-struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, &quot;user&quot;);<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 &quot;protobuf/sk-packet.pb-c.h&quot;<br>
 #include &quot;protobuf/creds.pb-c.h&quot;<br>
 #include &quot;protobuf/timer.pb-c.h&quot;<br>
+#include &quot;protobuf/userns.pb-c.h&quot;<br>
 #include &quot;protobuf/utsns.pb-c.h&quot;<br>
 #include &quot;protobuf/ipc-var.pb-c.h&quot;<br>
 #include &quot;protobuf/ipc-shm.pb-c.h&quot;<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-&gt;mnt_ns_id != p-&gt;mnt_ns_id)<br>
                mask |= CLONE_NEWNS;<br>
+       if (i-&gt;user_ns_id != p-&gt;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 &lt;unistd.h&gt;<br>
+<br>
+#include &quot;namespaces.h&quot;<br>
+#include &quot;user_ns.h&quot;<br>
+#include &quot;list.h&quot;<br>
+<br>
+#include &quot;protobuf.h&quot;<br>
+#include &quot;protobuf/userns.pb-c.h&quot;<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(&amp;pos-&gt;list);<br>
+               xfree(pos);<br>
+       }<br>
+<br>
+       /* free gid entries */<br>
+       list_for_each_entry_safe(pos, tmp, gid_list, list) {<br>
+               list_del(&amp;pos-&gt;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] = &amp;(tmp-&gt;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, &amp;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(&quot;Reading entries from /proc/%d/%s\n&quot;, pid, id_map);<br>
+<br>
+       fp = fopen_proc(pid, &quot;%s&quot;, id_map);<br>
+       if (!fp) {<br>
+               pr_perror(&quot;Error opening /proc/%d/%s\n&quot;, pid, id_map);<br>
<div class="">+               return -1;<br>
+       }<br>
+<br>
+       while ((n_read = fscanf(fp, &quot;%u %u %u\n&quot;, &amp;entry.id_in,<br>
+                               &amp;entry.id_out, &amp;entry.length)) != EOF) {<br>
+               if (n_read != 3) {<br>
</div>+                       pr_perror(&quot;Error reading /proc/%d/%s, fscanf returned %d&quot;,<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(&amp;tmp-&gt;entry, &amp;entry, sizeof(UsernsEntry__MapEntry));<br>
+               list_add(&amp;(tmp-&gt;list), head);<br>
+               n_entries++;<br>
+       }<br>
+<br>
+       if (fclose(fp) != 0) {<br>
</div>+               pr_perror(&quot;fclose(/proc/%d/%s) failed&quot;, 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(&quot;Writing entries to /proc/%d/%s, n_entries=%lu\n&quot;,<br>
+                pid, id_map, n_entries);<br>
+<br>
+       for (i = 0; i &lt; n_entries; i++) {<br>
+               n_written = snprintf(buf + total, sizeof(buf) - total,<br>
+                                    &quot;%u %u %u\n&quot;,<br>
<div class="">+                                     map[i]-&gt;id_in,<br>
+                                     map[i]-&gt;id_out,<br>
+                                     map[i]-&gt;length);<br>
</div>+               if (n_written &lt; 0) {<br>
+                       pr_err(&quot;snprintf failed for %s of pid: %d\n&quot;, 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, &quot;%s&quot;, id_map);<br>
+       if (fd &lt; 0) {<br>
+               pr_perror(&quot;Unable to open /proc/%d/%s\n&quot;, pid, id_map);<br>
<div class="">+               return -1;<br>
+       }<br>
+<br>
</div>+       if (write(fd, buf, total) != total) {<br>
+               pr_perror(&quot;Failed to write all %d bytes to /proc/%d/%s&quot;,<br>
+                         total, pid, id_map);<br>
+               close_safe(&amp;fd);<br>
<div class="">+               return -1;<br>
+       }<br>
+<br>
</div>+       close_safe(&amp;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 &lt; 0) {<br>
+               pr_err(&quot;Error opening userns image&quot;);<br>
+               return -1;<br>
+       }<br>
+<br>
+       /* read uid map */<br>
</div>+       n_uid_entries = read_map_entries(ns_pid, &quot;uid_map&quot;, &amp;uid_list);<br>
<div class="">+       if (n_uid_entries &lt; 0) {<br>
+               pr_err(&quot;Error reading uid_map\n&quot;);<br>
+               ret = -1;<br>
+               goto out;<br>
+       }<br>
+<br>
+       /* read gid map */<br>
</div>+       n_gid_entries = read_map_entries(ns_pid, &quot;gid_map&quot;, &amp;gid_list);<br>
<div class="">+       if (n_gid_entries &lt; 0) {<br>
+               pr_err(&quot;Error reading gid_map\n&quot;);<br>
+               ret = -1;<br>
+               goto out;<br>
+       }<br>
+<br>
+       ret = write_pb(fd, n_uid_entries, n_gid_entries, &amp;uid_list, &amp;gid_list);<br>
+<br>
+out:<br>
+       cleanup(&amp;fd, &amp;uid_list, &amp;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 &#39;real_pid&#39; 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(&quot;Restoring user namespace for real_pid:%d\n&quot;, real_pid);<br>
+<br>
+       fd = open_image(CR_FD_USERNS, O_RSTR, ns_id);<br>
+       if (fd &lt; 0)<br>
+               return -1;<br>
+<br>
+       ret = pb_read_one(fd, &amp;ue, PB_USERNS);<br>
+       if (ret &lt; 0)<br>
+               return -1;<br>
+<br>
+       pr_info(&quot;userns restoring: n_uid_map:%lu ; n_gid_map:%lu\n&quot;,<br>
+               ue-&gt;n_uid_map, ue-&gt;n_gid_map);<br>
+<br>
+       /* restore uid_map */<br>
</div>+       ret = write_map_entries(real_pid, &quot;uid_map&quot;, ue-&gt;uid_map, ue-&gt;n_uid_map);<br>
+       if (ret &lt; 0) {<br>
+               pr_err(&quot;Failed to restore /proc/%d/uid_map\n&quot;, real_pid);<br>
<div class="">+               goto out;<br>
+       }<br>
+<br>
+       /* restore gid_map */<br>
</div>+       ret = write_map_entries(real_pid, &quot;gid_map&quot;, ue-&gt;gid_map, ue-&gt;n_gid_map);<br>
+       if (ret &lt; 0) {<br>
+               pr_err(&quot;Failed to restore /proc/%d/gid_map&quot;, real_pid);<br>
<div class="">+               goto out;<br>
+       }<br>
+<br>
+out:<br>
+       userns_entry__free_unpacked(ue, NULL);<br>
+<br>
+       close_safe(&amp;fd);<br>
+       return ret;<br>
+}<br>
+<br>
+struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, &quot;user&quot;);<br>
--<br>
</div>2.1.0.rc2.206.gedb03e5<br>
<br>
</blockquote></div><br></div></div>