mirror of
https://github.com/containers/podman.git
synced 2025-10-20 20:54:45 +08:00
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:
@ -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)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user