[CRIU] [PATCH 2/4] join-ns: perform join_namespace according to join-ns opts
Pavel Emelyanov
xemul at virtuozzo.com
Mon Apr 4 04:22:22 PDT 2016
On 04/04/2016 09:40 AM, Dengguangxing wrote:
>
> Signed-off-by: Deng Guangxing <dengguangxing at huawei.com>
> ---
> criu/cr-restore.c | 5 ++
> criu/include/namespaces.h | 1 +
> criu/namespaces.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 133 insertions(+)
>
> diff --git a/criu/cr-restore.c b/criu/cr-restore.c
> index 027232b..1ea9949 100644
> --- a/criu/cr-restore.c
> +++ b/criu/cr-restore.c
> @@ -1575,6 +1575,11 @@ static int restore_task_with_children(void *_arg)
>
> /* Restore root task */
> if (current->parent == NULL) {
> + if (join_namespaces()) {
> + pr_perror("Join namespaces failed");
> + goto err;
> + }
> +
> if (restore_finish_stage(CR_STATE_RESTORE_NS) < 0)
> goto err;
>
> diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
> index 73ac327..a810cf3 100644
> --- a/criu/include/namespaces.h
> +++ b/criu/include/namespaces.h
> @@ -122,6 +122,7 @@ extern gid_t userns_gid(gid_t gid);
> extern int dump_user_ns(pid_t pid, int ns_id);
> extern void free_userns_maps(void);
> extern int join_ns_add(const char *type, char *ns_file, char *extra_opts);
> +extern int join_namespaces();
> extern int check_namespace_opts();
>
> typedef int (*uns_call_t)(void *arg, int fd, pid_t pid);
> diff --git a/criu/namespaces.c b/criu/namespaces.c
> index 6994cf0..c7a5572 100644
> --- a/criu/namespaces.c
> +++ b/criu/namespaces.c
> @@ -1515,6 +1515,133 @@ static int prepare_userns_creds()
> return 0;
> }
>
> +static int get_join_ns_fd(struct join_ns *jn) {
{ on separate line
> + int pid, fd;
> + char nsf[32];
> + char *pnsf;
> +
> + if (jn->ns_file == NULL) {
This is impossible, so the whole if() is not needed.
> + pr_perror("join-ns file is NULL");
> + return -1;
> + }
> +
> + pid = atoi(jn->ns_file);
> + if (pid > 0) {
> + snprintf(nsf, sizeof(nsf), "/proc/%d/ns/%s", pid, jn->nd->str);
> + pnsf = nsf;
> + } else {
> + pnsf = jn->ns_file;
> + }
> +
> + fd = open(pnsf, O_RDONLY);
> + if (fd < 0) {
> + pr_perror("Can't open ns file: %s", pnsf);
> + return -1;
> + }
> + jn->ns_fd = fd;
> + return 0;
> +}
> +
> +static int switch_join_ns(struct join_ns *jn)
> +{
> + struct stat st, self_st;
> + char buf[32];
> +
> + if (jn->ns_fd < 0) {
This is impossible, so the whole if() is not needed.
> + pr_perror("Invalid ns fd in join-ns");
> + return -1;
> + }
> +
> + if (fstat(jn->ns_fd, &st) == -1) {
> + pr_perror("Can't get ns file %s stat", jn->ns_file);
> + return -1;
> + }
> +
> + snprintf(buf, sizeof(buf), "/proc/self/ns/%s", jn->nd->str);
> + if (stat(buf, &self_st) == -1) {
> + pr_perror("Can't get ns file %s stat", buf);
> + return -1;
> + }
> +
> + /* It is not permitted to use setns() to reenter the caller's current
> + * user namespace. This prevents a caller that has dropped capabilities
> + * from regaining those capabilities via a call to setns()
> + */
> + if (st.st_ino != self_st.st_ino) {
If this only makes sense for userns, then make this check (and stat-s) only happen
for user namespaces.
> + if (setns(jn->ns_fd, jn->nd->cflag)) {
> + pr_perror("Can't setns %s:%s",jn->nd->str, jn->ns_file);
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int switch_user_join_ns(struct join_ns *jn) {
{ on separate line
> + if (jn == NULL) {
> + return 0;
> + }
> +
> + uid_t uid;
> + gid_t gid;
Variables should go before code.
> +
> + if (switch_join_ns(jn))
> + return -1;
> +
> + if (jn->extra_opts.user_extra.uid == NULL)
> + uid = getuid();
> + else
> + uid = atoi(jn->extra_opts.user_extra.uid);
> +
> + if (jn->extra_opts.user_extra.gid == NULL)
> + gid = getgid();
> + else
> + gid = atoi(jn->extra_opts.user_extra.gid);
> +
> + /* FIXME:
> + * if err occurs in setuid/setgid, should we just alert or
> + * return an error
> + */
> + if (setuid(uid)) {
> + pr_perror("setuid failed while joining userns");
> + return -1;
> + }
> + if (setgid(gid)) {
> + pr_perror("setgid failed while joining userns");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int join_namespaces()
> +{
> + struct join_ns *jn, *user_jn = NULL;
> + int ret = -1;
> +
> + list_for_each_entry(jn, &opts.join_ns, list)
> + if (get_join_ns_fd(jn)) {
> + goto err_out;
> + }
> +
> + list_for_each_entry(jn, &opts.join_ns, list)
> + if (!strncmp(jn->nd->str, "user", 5)) {
Better to check jn->nd == &user_ns_desc
> + user_jn = jn;
> + } else {
> + if (switch_join_ns(jn))
> + goto err_out;
> + }
> +
> + if (switch_user_join_ns(user_jn))
> + goto err_out;
> +
> + ret = 0;
> +err_out:
> + list_for_each_entry(jn, &opts.join_ns, list)
> + close_safe(&jn->ns_fd);
> + return ret;
> +}
> +
> int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
> {
> pid_t pid = item->pid.virt;
>
More information about the CRIU
mailing list