diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2020-02-25 17:46:48 +0100 |
---|---|---|
committer | Giuseppe Scrivano <gscrivan@redhat.com> | 2020-02-25 17:52:06 +0100 |
commit | d400f0b5b2d68c4148a7c173e7fbbfd9b377a660 (patch) | |
tree | 0d5ef4c9abaad91e02db1aad85108896abbeaf87 | |
parent | 3d37dc639d87e4469a6457cf4592ff5b773d0777 (diff) | |
download | podman-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>
-rw-r--r-- | pkg/rootless/rootless_linux.c | 51 |
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"); |