diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2020-04-29 11:01:56 +0200 |
---|---|---|
committer | Giuseppe Scrivano <gscrivan@redhat.com> | 2020-04-29 11:44:24 +0200 |
commit | 89d4940a3787ccc871c92950a79347efc0d5c58c (patch) | |
tree | dbdb3c24f28188fd60659ec36363d50da5f4ac05 | |
parent | 4e21d09f98d3b6af37f2d6118cd8914674b56ab1 (diff) | |
download | podman-89d4940a3787ccc871c92950a79347efc0d5c58c.tar.gz podman-89d4940a3787ccc871c92950a79347efc0d5c58c.tar.bz2 podman-89d4940a3787ccc871c92950a79347efc0d5c58c.zip |
rootless: move ns open before fork
commit 788fdc685b00dee5ccb594bef845204250c4c123 introduced a race
where the target process dies before the child process opens the
namespace files. Move the open before the fork so if it fails the
parent process can attempt to join a different container instead of
failing.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
-rw-r--r-- | pkg/rootless/rootless_linux.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 72d461cdc..716db81dc 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -535,32 +535,30 @@ create_pause_process (const char *pause_pid_file_path, char **argv) } } -static void -join_namespace_or_die (int pid_to_join, const char *ns_file) +static int +open_namespace (int pid_to_join, const char *ns_file) { char ns_path[PATH_MAX]; int ret; - int fd; ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file); if (ret == PATH_MAX) { fprintf (stderr, "internal error: namespace path too long\n"); - _exit (EXIT_FAILURE); + return -1; } - fd = open (ns_path, O_CLOEXEC | O_RDONLY); - if (fd < 0) - { - fprintf (stderr, "cannot open: %s\n", ns_path); - _exit (EXIT_FAILURE); - } - if (setns (fd, 0) < 0) + return open (ns_path, O_CLOEXEC | O_RDONLY); +} + +static void +join_namespace_or_die (const char *name, int ns_fd) +{ + if (setns (ns_fd, 0) < 0) { - fprintf (stderr, "cannot set namespace to %s: %s\n", ns_path, strerror (errno)); + fprintf (stderr, "cannot set %s namespace\n", name); _exit (EXIT_FAILURE); } - close (fd); } int @@ -570,6 +568,8 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) char gid[16]; char **argv; int pid; + int mnt_ns = -1; + int user_ns = -1; char *cwd = getcwd (NULL, 0); sigset_t sigset, oldsigset; @@ -589,14 +589,28 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) _exit (EXIT_FAILURE); } + user_ns = open_namespace (pid_to_join, "user"); + if (user_ns < 0) + return user_ns; + mnt_ns = open_namespace (pid_to_join, "mnt"); + if (mnt_ns < 0) + { + close (user_ns); + return mnt_ns; + } + pid = fork (); if (pid < 0) fprintf (stderr, "cannot fork: %s\n", strerror (errno)); if (pid) { - /* We passed down these fds, close them. */ int f; + + /* We passed down these fds, close them. */ + close (user_ns); + close (mnt_ns); + for (f = 3; f < open_files_max_fd; f++) if (open_files_set == NULL || FD_ISSET (f % FD_SETSIZE, &(open_files_set[f / FD_SETSIZE]))) close (f); @@ -634,8 +648,10 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) _exit (EXIT_FAILURE); } - join_namespace_or_die (pid_to_join, "user"); - join_namespace_or_die (pid_to_join, "mnt"); + join_namespace_or_die ("user", user_ns); + join_namespace_or_die ("mnt", mnt_ns); + close (user_ns); + close (mnt_ns); if (syscall_setresgid (0, 0, 0) < 0) { |