From e1b02a48c19365a6508cc1d7de5beca3271dd33b Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 25 Sep 2012 15:59:13 +0400 Subject: [PATCH] cr-restore: block SIGCHLD for restoring namespaces Restore of namespaces requires executions of external tools (ip, tar, etc). We want to know return codes, so we should block a default sigchld handler. Before we did that for each command, I suggest to block SIGCHLD, then restore namespace and unblock SIGCHLD. The default sigchld handler is used for catching target processes, but all this processes (except a current one ) are started after restoring namespaces. Currently we forgot to block SIGCHLD before executing "ip", and this bug was caught. Reported-by: Stanislav Kinsbursky Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- mount.c | 28 +++------------------------- namespaces.c | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/mount.c b/mount.c index 80992b809..4534ff33a 100644 --- a/mount.c +++ b/mount.c @@ -309,26 +309,12 @@ static int tmpfs_dump(struct mount_info *pm) static int tmpfs_restore(struct mount_info *pm) { int ret, status = -1; - sigset_t mask, oldmask; pid_t pid; - ret = sigprocmask(SIG_SETMASK, NULL, &oldmask); - if (ret == -1) { - pr_perror("Can not get mask of blocked signals"); - return -1; - } - mask = oldmask; - sigaddset(&mask, SIGCHLD); - ret = sigprocmask(SIG_SETMASK, &mask, NULL); - if (ret == -1) { - pr_perror("Can not set mask of blocked signals"); - return -1; - } - pid = fork(); if (pid == -1) { pr_perror("fork() failed\n"); - goto out_unlock; + return -1; } else if (pid == 0) { int fd_img; @@ -352,20 +338,12 @@ static int tmpfs_restore(struct mount_info *pm) ret = waitpid(pid, &status, 0); if (ret == -1) { pr_perror("waitpid() failed"); - goto out_unlock; + return -1; } if (status) { pr_err("Can't restore tmpfs content\n"); - status = -1; - goto out_unlock; - } - -out_unlock: - ret = sigprocmask(SIG_SETMASK, &oldmask, NULL); - if (ret == -1) { - pr_perror("Can not set mask of blocked signals"); - BUG(); + return -1; } return status; diff --git a/namespaces.c b/namespaces.c index dc8e00896..55c022816 100644 --- a/namespaces.c +++ b/namespaces.c @@ -151,9 +151,19 @@ int dump_namespaces(struct pid *ns_pid, unsigned int ns_flags) int prepare_namespace(int pid, unsigned long clone_flags) { + sigset_t blockmask, oldmask; + int ret = -1; + pr_info("Restoring namespaces %d flags 0x%lx\n", pid, clone_flags); + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) { + pr_perror("Can not set mask of blocked signals"); + return -1; + } + /* * On netns restore we launch an IP tool, thus we * have to restore it _before_ altering the mount @@ -161,15 +171,22 @@ int prepare_namespace(int pid, unsigned long clone_flags) */ if ((clone_flags & CLONE_NEWNET) && prepare_net_ns(pid)) - return -1; + goto out; if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(pid)) - return -1; + goto out; if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(pid)) - return -1; + goto out; if ((clone_flags & CLONE_NEWNS) && prepare_mnt_ns(pid)) - return -1; + goto out; - return 0; + ret = 0; +out: + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) { + pr_perror("Can not set mask of blocked signals"); + BUG(); + } + + return ret; } int try_show_namespaces(int ns_pid, struct cr_options *o)