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>
(cherry picked from commit 89d4940a3787ccc871c92950a79347efc0d5c58c)
This commit is contained in:
Giuseppe Scrivano
2020-04-29 11:01:56 +02:00
parent b3b889d8a2
commit efe956249e

View File

@ -535,32 +535,30 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
} }
} }
static void static int
join_namespace_or_die (int pid_to_join, const char *ns_file) open_namespace (int pid_to_join, const char *ns_file)
{ {
char ns_path[PATH_MAX]; char ns_path[PATH_MAX];
int ret; int ret;
int fd;
ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file); ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file);
if (ret == PATH_MAX) if (ret == PATH_MAX)
{ {
fprintf (stderr, "internal error: namespace path too long\n"); fprintf (stderr, "internal error: namespace path too long\n");
_exit (EXIT_FAILURE); return -1;
} }
fd = open (ns_path, O_CLOEXEC | O_RDONLY); return open (ns_path, O_CLOEXEC | O_RDONLY);
if (fd < 0) }
static void
join_namespace_or_die (const char *name, int ns_fd)
{
if (setns (ns_fd, 0) < 0)
{ {
fprintf (stderr, "cannot open: %s\n", ns_path); fprintf (stderr, "cannot set %s namespace\n", name);
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
if (setns (fd, 0) < 0)
{
fprintf (stderr, "cannot set namespace to %s: %s\n", ns_path, strerror (errno));
_exit (EXIT_FAILURE);
}
close (fd);
} }
int int
@ -570,6 +568,8 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
char gid[16]; char gid[16];
char **argv; char **argv;
int pid; int pid;
int mnt_ns = -1;
int user_ns = -1;
char *cwd = getcwd (NULL, 0); char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset; sigset_t sigset, oldsigset;
@ -589,14 +589,28 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE); _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 (); pid = fork ();
if (pid < 0) if (pid < 0)
fprintf (stderr, "cannot fork: %s\n", strerror (errno)); fprintf (stderr, "cannot fork: %s\n", strerror (errno));
if (pid) if (pid)
{ {
/* We passed down these fds, close them. */
int f; int f;
/* We passed down these fds, close them. */
close (user_ns);
close (mnt_ns);
for (f = 3; f < open_files_max_fd; f++) 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]))) if (open_files_set == NULL || FD_ISSET (f % FD_SETSIZE, &(open_files_set[f / FD_SETSIZE])))
close (f); close (f);
@ -634,8 +648,10 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
join_namespace_or_die (pid_to_join, "user"); join_namespace_or_die ("user", user_ns);
join_namespace_or_die (pid_to_join, "mnt"); join_namespace_or_die ("mnt", mnt_ns);
close (user_ns);
close (mnt_ns);
if (syscall_setresgid (0, 0, 0) < 0) if (syscall_setresgid (0, 0, 0) < 0)
{ {