diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index c1d819f32..6aed3817e 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -164,6 +164,8 @@ extern struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd); extern int collect_user_namespaces(bool for_dump); extern int prepare_userns(pid_t real_pid, UsernsEntry *e); +extern int __set_user_ns(struct ns_id *ns); +extern int set_user_ns(u32 id); extern int stop_usernsd(void); extern uid_t userns_uid(uid_t uid); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index b082e3586..5790943be 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -29,6 +29,7 @@ struct pstree_item { futex_t task_st; unsigned long task_st_le_bits; }; + struct ns_id *user_ns; }; static inline pid_t vpid(const struct pstree_item *i) diff --git a/criu/namespaces.c b/criu/namespaces.c index 85444155c..99411fddf 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -2277,5 +2277,50 @@ err_unds: return -1; } +int __set_user_ns(struct ns_id *ns) +{ + int fd; + + if (!(root_ns_mask & CLONE_NEWUSER)) + return 0; + + if (current->user_ns && current->user_ns->id == ns->id) + return 0; + + fd = fdstore_get(ns->user.nsfd_id); + if (fd < 0) { + pr_err("Can't get ns fd\n"); + return -1; + } + if (setns(fd, CLONE_NEWUSER) < 0) { + pr_perror("Can't setns"); + close(fd); + return -1; + } + current->user_ns = ns; + close(fd); + + if (prepare_userns_creds() < 0) { + pr_err("Can't set creds\n"); + return -1; + } + return 0; +} + +int set_user_ns(u32 id) +{ + struct ns_id *ns; + + if (current->user_ns && current->user_ns->id == id) + return 0; + + ns = lookup_ns_by_id(id, &user_ns_desc); + if (!ns) { + pr_err("Can't find user_ns %u\n", id); + return -1; + } + return __set_user_ns(ns); +} + struct ns_desc pid_ns_desc = NS_DESC_ENTRY(CLONE_NEWPID, "pid"); struct ns_desc user_ns_desc = NS_DESC_ENTRY(CLONE_NEWUSER, "user");