summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorGiuseppe Scrivano <gscrivan@redhat.com>2020-02-25 17:46:48 +0100
committerGiuseppe Scrivano <gscrivan@redhat.com>2020-02-25 17:52:06 +0100
commitd400f0b5b2d68c4148a7c173e7fbbfd9b377a660 (patch)
tree0d5ef4c9abaad91e02db1aad85108896abbeaf87 /pkg
parent3d37dc639d87e4469a6457cf4592ff5b773d0777 (diff)
downloadpodman-d400f0b5b2d68c4148a7c173e7fbbfd9b377a660.tar.gz
podman-d400f0b5b2d68c4148a7c173e7fbbfd9b377a660.tar.bz2
podman-d400f0b5b2d68c4148a7c173e7fbbfd9b377a660.zip
rootless: fix segfault when open fd >= FD_SETSIZE
if there are more than FD_SETSIZE open fds passed down to the Podman process, the initialization code could crash as it attempts to store them into a fd_set. Use an array of fd_set structs, each of them holding only FD_SETSIZE file descriptors. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/rootless/rootless_linux.c51
1 files changed, 36 insertions, 15 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 83f4f3254..db898e706 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -58,7 +58,7 @@ static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
static int open_files_max_fd;
-fd_set open_files_set;
+static fd_set *open_files_set;
static uid_t rootless_uid_init;
static gid_t rootless_gid_init;
@@ -240,17 +240,39 @@ static void __attribute__((constructor)) init()
if (d)
{
struct dirent *ent;
+ size_t size = 0;
- FD_ZERO (&open_files_set);
for (ent = readdir (d); ent; ent = readdir (d))
{
- int fd = atoi (ent->d_name);
- if (fd != dirfd (d))
+ int fd;
+
+ if (ent->d_name[0] == '.')
+ continue;
+
+ fd = atoi (ent->d_name);
+ if (fd == dirfd (d))
+ continue;
+
+ if (fd >= size * FD_SETSIZE)
{
- if (fd > open_files_max_fd)
- open_files_max_fd = fd;
- FD_SET (fd, &open_files_set);
+ int i;
+ size_t new_size;
+
+ new_size = (fd / FD_SETSIZE) + 1;
+ open_files_set = realloc (open_files_set, new_size * sizeof (fd_set));
+ if (open_files_set == NULL)
+ _exit (EXIT_FAILURE);
+
+ for (i = size; i < new_size; i++)
+ FD_ZERO (&(open_files_set[i]));
+
+ size = new_size;
}
+
+ if (fd > open_files_max_fd)
+ open_files_max_fd = fd;
+
+ FD_SET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE]));
}
closedir (d);
}
@@ -553,10 +575,8 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
/* We passed down these fds, close them. */
int f;
for (f = 3; f < open_files_max_fd; f++)
- {
- if (FD_ISSET (f, &open_files_set))
- close (f);
- }
+ if (open_files_set == NULL || FD_ISSET (f % FD_SETSIZE, &(open_files_set[f / FD_SETSIZE])))
+ close (f);
return pid;
}
@@ -747,10 +767,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
num_fds = strtol (listen_fds, NULL, 10);
if (num_fds != LONG_MIN && num_fds != LONG_MAX)
{
- long i;
- for (i = 3; i < num_fds + 3; i++)
- if (FD_ISSET (i, &open_files_set))
- close (i);
+ int f;
+
+ for (f = 3; f < num_fds + 3; f++)
+ if (open_files_set == NULL || FD_ISSET (f % FD_SETSIZE, &(open_files_set[f / FD_SETSIZE])))
+ close (f);
}
unsetenv ("LISTEN_PID");
unsetenv ("LISTEN_FDS");