diff options
Diffstat (limited to 'pkg/rootless/rootless_linux.c')
-rw-r--r-- | pkg/rootless/rootless_linux.c | 118 |
1 files changed, 75 insertions, 43 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 2356882e7..19b76f387 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -34,6 +34,15 @@ int renameat2 (int olddirfd, const char *oldpath, int newdirfd, const char *newp } #endif +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(expression) \ + (__extension__ \ + ({ long int __result; \ + do __result = (long int) (expression); \ + while (__result == -1L && errno == EINTR); \ + __result; })) +#endif + static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces"; static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone"; @@ -73,7 +82,7 @@ do_pause () struct sigaction act; int const sig[] = { - SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM, SIGPOLL, + SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGPOLL, SIGPROF, SIGVTALRM, SIGXCPU, SIGXFSZ, 0 }; @@ -113,9 +122,7 @@ get_cmd_line_args (pid_t pid) return NULL; for (;;) { - do - ret = read (fd, buffer + used, allocated - used); - while (ret < 0 && errno == EINTR); + ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used)); if (ret < 0) { free (buffer); @@ -180,7 +187,7 @@ can_use_shortcut () argv = get_cmd_line_args (0); if (argv == NULL) - return NULL; + return false; for (argc = 0; argv[argc]; argc++) { @@ -237,7 +244,7 @@ static void __attribute__((constructor)) init() /* Shortcut. If we are able to join the pause pid file, do it now so we don't need to re-exec. */ xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); - if (xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ()) + if (geteuid () != 0 && xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ()) { int r; int fd; @@ -269,13 +276,15 @@ static void __attribute__((constructor)) init() return; } - r = read (fd, buf, sizeof (buf)); + r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf))); close (fd); if (r < 0) { free (cwd); return; } + buf[r] = '\0'; + pid = strtol (buf, NULL, 10); if (pid == LONG_MAX) { @@ -286,7 +295,7 @@ static void __attribute__((constructor)) init() uid = geteuid (); gid = getegid (); - sprintf (path, "/proc/%d/ns/user", pid); + sprintf (path, "/proc/%ld/ns/user", pid); fd = open (path, O_RDONLY); if (fd < 0 || setns (fd, 0) < 0) { @@ -296,7 +305,7 @@ static void __attribute__((constructor)) init() close (fd); /* Errors here cannot be ignored as we already joined a ns. */ - sprintf (path, "/proc/%d/ns/mnt", pid); + sprintf (path, "/proc/%ld/ns/mnt", pid); fd = open (path, O_RDONLY); if (fd < 0) { @@ -307,7 +316,7 @@ static void __attribute__((constructor)) init() r = setns (fd, 0); if (r < 0) { - fprintf (stderr, "cannot join mount namespace for %d: %s", pid, strerror (errno)); + fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno)); exit (EXIT_FAILURE); } close (fd); @@ -352,10 +361,7 @@ reexec_in_user_namespace_wait (int pid, int options) pid_t p; int status; - do - p = waitpid (pid, &status, 0); - while (p < 0 && errno == EINTR); - + p = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); if (p < 0) return -1; @@ -384,12 +390,10 @@ create_pause_process (const char *pause_pid_file_path, char **argv) close (p[1]); /* Block until we write the pid file. */ - do - r = read (p[0], &b, 1); - while (r < 0 && errno == EINTR); + r = TEMP_FAILURE_RETRY (read (p[0], &b, 1)); close (p[0]); - reexec_in_user_namespace_wait(r, 0); + reexec_in_user_namespace_wait (r, 0); return r == 1 && b == '0' ? 0 : -1; } @@ -412,9 +416,16 @@ create_pause_process (const char *pause_pid_file_path, char **argv) sprintf (pid_str, "%d", pid); - asprintf (&tmp_file_path, "%s.XXXXXX", pause_pid_file_path); + if (asprintf (&tmp_file_path, "%s.XXXXXX", pause_pid_file_path) < 0) + { + fprintf (stderr, "unable to print to string\n"); + kill (pid, SIGKILL); + _exit (EXIT_FAILURE); + } + if (tmp_file_path == NULL) { + fprintf (stderr, "temporary file path is NULL\n"); kill (pid, SIGKILL); _exit (EXIT_FAILURE); } @@ -422,15 +433,15 @@ create_pause_process (const char *pause_pid_file_path, char **argv) fd = mkstemp (tmp_file_path); if (fd < 0) { + fprintf (stderr, "error creating temporary file: %s\n", strerror (errno)); kill (pid, SIGKILL); _exit (EXIT_FAILURE); } - do - r = write (fd, pid_str, strlen (pid_str)); - while (r < 0 && errno == EINTR); + r = TEMP_FAILURE_RETRY (write (fd, pid_str, strlen (pid_str))); if (r < 0) { + fprintf (stderr, "cannot write to file descriptor: %s\n", strerror (errno)); kill (pid, SIGKILL); _exit (EXIT_FAILURE); } @@ -445,9 +456,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv) _exit (EXIT_FAILURE); } - do - r = write (p[1], "0", 1); - while (r < 0 && errno == EINTR); + r = TEMP_FAILURE_RETRY (write (p[1], "0", 1)); close (p[1]); _exit (EXIT_SUCCESS); @@ -471,7 +480,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv) close (fd); setenv ("_PODMAN_PAUSE", "1", 1); - execlp (argv[0], NULL); + execlp (argv[0], argv[0], NULL); /* If the execve fails, then do the pause here. */ do_pause (); @@ -489,6 +498,7 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path) char **argv; int pid; char *cwd = getcwd (NULL, 0); + sigset_t sigset, oldsigset; if (cwd == NULL) { @@ -522,6 +532,27 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path) return pid; } + if (sigfillset (&sigset) < 0) + { + fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (sigdelset (&sigset, SIGCHLD) < 0) + { + fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (sigdelset (&sigset, SIGTERM) < 0) + { + fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0) + { + fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1); setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1); setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1); @@ -570,6 +601,11 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path) /* We ignore errors here as we didn't create the namespace anyway. */ create_pause_process (pause_pid_file_path, argv); } + if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) + { + fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } execvp (argv[0], argv); @@ -609,9 +645,7 @@ copy_file_to_fd (const char *file_to_read, int outfd) { ssize_t r, w, t = 0; - do - r = read (fd, buf, sizeof buf); - while (r < 0 && errno == EINTR); + r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf)); if (r < 0) { close (fd); @@ -623,9 +657,7 @@ copy_file_to_fd (const char *file_to_read, int outfd) while (t < r) { - do - w = write (outfd, &buf[t], r - t); - while (w < 0 && errno == EINTR); + w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t)); if (w < 0) { close (fd); @@ -675,7 +707,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); if (pid < 0) { - FILE *fp; fprintf (stderr, "cannot clone: %s\n", strerror (errno)); check_proc_sys_userns_file (_max_user_namespaces); check_proc_sys_userns_file (_unprivileged_user_namespaces); @@ -710,6 +741,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno)); _exit (EXIT_FAILURE); } + if (sigdelset (&sigset, SIGTERM) < 0) + { + fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0) { fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); @@ -734,9 +770,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1); setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1); - do - ret = read (ready, &b, 1) < 0; - while (ret < 0 && errno == EINTR); + ret = TEMP_FAILURE_RETRY (read (ready, &b, 1)); if (ret < 0) { fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno)); @@ -748,21 +782,21 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re if (syscall_setresgid (0, 0, 0) < 0) { fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); - write (ready, "1", 1); + TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } if (syscall_setresuid (0, 0, 0) < 0) { fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); - write (ready, "1", 1); + TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } if (chdir (cwd) < 0) { fprintf (stderr, "cannot chdir: %s\n", strerror (errno)); - write (ready, "1", 1); + TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } free (cwd); @@ -771,14 +805,12 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re { if (create_pause_process (pause_pid_file_path, argv) < 0) { - write (ready, "2", 1); + TEMP_FAILURE_RETRY (write (ready, "2", 1)); _exit (EXIT_FAILURE); } } - do - ret = write (ready, "0", 1) < 0; - while (ret < 0 && errno == EINTR); + ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); close (ready); if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) |