@@ -95,6 +95,12 @@ struct nlconfig_t {
9595 size_t timensoffset_len ;
9696};
9797
98+ struct namespace_t {
99+ int fd ;
100+ char type [PATH_MAX ];
101+ char path [PATH_MAX ];
102+ };
103+
98104/*
99105 * List of netlink message types sent to us as part of bootstrapping the init.
100106 * These constants are defined in libcontainer/message_linux.go.
@@ -444,16 +450,11 @@ void nl_free(struct nlconfig_t *config)
444450 free (config -> data );
445451}
446452
447- void join_namespaces (char * nslist )
453+ struct namespace_t * init_namespaces (char * nslist , int * num )
448454{
449- int num = 0 , i ;
450455 char * saveptr = NULL ;
451456 char * namespace = strtok_r (nslist , "," , & saveptr );
452- struct namespace_t {
453- int fd ;
454- char type [PATH_MAX ];
455- char path [PATH_MAX ];
456- } * namespaces = NULL ;
457+ struct namespace_t * namespaces = NULL ;
457458
458459 if (!namespace || !strlen (namespace ) || !strlen (nslist ))
459460 bail ("ns paths are empty" );
@@ -469,10 +470,10 @@ void join_namespaces(char *nslist)
469470 struct namespace_t * ns ;
470471
471472 /* Resize the namespace array. */
472- namespaces = realloc (namespaces , ++ num * sizeof (struct namespace_t ));
473+ namespaces = realloc (namespaces , ++ * num * sizeof (struct namespace_t ));
473474 if (!namespaces )
474475 bail ("failed to reallocate namespace array" );
475- ns = & namespaces [num - 1 ];
476+ ns = & namespaces [* num - 1 ];
476477
477478 /* Split 'ns:path'. */
478479 path = strstr (namespace , ":" );
@@ -490,20 +491,41 @@ void join_namespaces(char *nslist)
490491 ns -> path [PATH_MAX - 1 ] = '\0' ;
491492 } while ((namespace = strtok_r (NULL , "," , & saveptr )) != NULL );
492493
493- /*
494- * The ordering in which we join namespaces is important. We should
495- * always join the user namespace *first*. This is all guaranteed
496- * from the container_linux.go side of this, so we're just going to
497- * follow the order given to us.
498- */
494+ return namespaces ;
495+ }
496+
497+ void join_namespaces ( struct namespace_t * namespaces , int num , bool ignoreError )
498+ {
499+ int i ;
499500
500501 for (i = 0 ; i < num ; i ++ ) {
501502 struct namespace_t * ns = & namespaces [i ];
502503 int flag = nsflag (ns -> type );
503504
505+ if (ns -> fd < 0 )
506+ continue ;
507+
508+ /*
509+ * The ordering in which we join namespaces is important. We should join
510+ * as many namespaces as possible *first* except the user namespace,
511+ * because there may be some ns paths are not owned by the user namespace
512+ * we want to join, then we can join remainning namespaces after we
513+ * join/unshare user ns. (#4390)
514+ *
515+ * When we join remaining namespaces or for rootless container, we should
516+ * always join the user namespace *first*. This is all guaranteed from the
517+ * container_linux.go side of this, so we're just going to follow the order
518+ * given to us.
519+ */
520+ if (ignoreError && flag == CLONE_NEWUSER )
521+ continue ;
522+
504523 write_log (DEBUG , "setns(%#x) into %s namespace (with path %s)" , flag , ns -> type , ns -> path );
505- if (setns (ns -> fd , flag ) < 0 )
506- bail ("failed to setns into %s namespace" , ns -> type );
524+ if (setns (ns -> fd , flag ) < 0 ) {
525+ if (!ignoreError )
526+ bail ("failed to setns into %s namespace" , ns -> type );
527+ continue ;
528+ }
507529
508530 /*
509531 * If we change user namespaces, make sure we switch to root in the
@@ -517,9 +539,8 @@ void join_namespaces(char *nslist)
517539 }
518540
519541 close (ns -> fd );
542+ ns -> fd = -1 ;
520543 }
521-
522- free (namespaces );
523544}
524545
525546static inline int sane_kill (pid_t pid , int signum )
@@ -840,6 +861,8 @@ void nsexec(void)
840861 case STAGE_CHILD :{
841862 pid_t stage2_pid = -1 ;
842863 enum sync_t s ;
864+ int nslen = 0 ;
865+ struct namespace_t * namespaces = NULL ;
843866
844867 /* For debugging. */
845868 current_stage = STAGE_CHILD ;
@@ -859,8 +882,11 @@ void nsexec(void)
859882 * [stage 2: STAGE_INIT]) would be meaningless). We could send it
860883 * using cmsg(3) but that's just annoying.
861884 */
862- if (config .namespaces )
863- join_namespaces (config .namespaces );
885+ if (config .namespaces ) {
886+ namespaces = init_namespaces (config .namespaces , & nslen );
887+ if (nslen > 0 )
888+ join_namespaces (namespaces , nslen , !config .is_rootless_euid );
889+ }
864890
865891 /*
866892 * Deal with user namespaces first. They are quite special, as they
@@ -923,6 +949,11 @@ void nsexec(void)
923949 if (setresuid (0 , 0 , 0 ) < 0 )
924950 bail ("failed to become root in user namespace" );
925951 }
952+ /* Join remainning namespaces after we join/unshare user ns. */
953+ if (nslen > 0 ) {
954+ join_namespaces (namespaces , nslen , false);
955+ free (namespaces );
956+ }
926957
927958 /*
928959 * Unshare all of the namespaces. Now, it should be noted that this
0 commit comments