diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2019-05-08 13:49:46 +0200 |
---|---|---|
committer | Giuseppe Scrivano <gscrivan@redhat.com> | 2019-05-17 20:48:24 +0200 |
commit | 562357ebb26cacbe9a97c8c0a87c9524345158d0 (patch) | |
tree | f6f6e88343fd77a3aad233bae0d68e20e2ed857c /pkg/rootless | |
parent | 791d53a21421fba249156ea3a503e9e04a4912e4 (diff) | |
download | podman-562357ebb26cacbe9a97c8c0a87c9524345158d0.tar.gz podman-562357ebb26cacbe9a97c8c0a87c9524345158d0.tar.bz2 podman-562357ebb26cacbe9a97c8c0a87c9524345158d0.zip |
rootless: join namespace immediately when possible
add a shortcut for joining immediately the namespace so we don't need
to re-exec Podman.
With the pause process simplificaton, we can now attempt to join the
namespaces as soon as Podman starts (and before the Go runtime kicks
in), so that we don't need to re-exec and use just one process.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Diffstat (limited to 'pkg/rootless')
-rw-r--r-- | pkg/rootless/rootless_linux.c | 172 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 8 |
2 files changed, 170 insertions, 10 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index b87deb86e..a08cfd36a 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -39,6 +39,7 @@ static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivilege static int open_files_max_fd; fd_set open_files_set; +static uid_t rootless_uid_init; static int syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid) @@ -52,6 +53,12 @@ syscall_setresgid (gid_t rgid, gid_t egid, gid_t sgid) return (int) syscall (__NR_setresgid, rgid, egid, sgid); } +uid_t +rootless_uid () +{ + return rootless_uid_init; +} + static void do_pause () { @@ -72,7 +79,10 @@ get_cmd_line_args (pid_t pid) int i, argc = 0; char **argv; - sprintf (path, "/proc/%d/cmdline", pid); + if (pid) + sprintf (path, "/proc/%d/cmdline", pid); + else + strcpy (path, "/proc/self/cmdline"); fd = open (path, O_RDONLY); if (fd < 0) return NULL; @@ -87,7 +97,10 @@ get_cmd_line_args (pid_t pid) ret = read (fd, buffer + used, allocated - used); while (ret < 0 && errno == EINTR); if (ret < 0) - return NULL; + { + free (buffer); + return NULL; + } if (ret == 0) break; @@ -97,11 +110,12 @@ get_cmd_line_args (pid_t pid) { allocated += 512; char *tmp = realloc (buffer, allocated); - if (buffer == NULL) { - free(buffer); - return NULL; - } - buffer=tmp; + if (buffer == NULL) + { + free (buffer); + return NULL; + } + buffer = tmp; } } close (fd); @@ -110,11 +124,17 @@ get_cmd_line_args (pid_t pid) if (buffer[i] == '\0') argc++; if (argc == 0) - return NULL; + { + free (buffer); + return NULL; + } argv = malloc (sizeof (char *) * (argc + 1)); if (argv == NULL) - return NULL; + { + free (buffer); + return NULL; + } argc = 0; argv[argc++] = buffer; @@ -127,6 +147,40 @@ get_cmd_line_args (pid_t pid) return argv; } +static bool +can_use_shortcut () +{ + int argc; + char **argv; + bool ret = true; + +#ifdef DISABLE_JOIN_SHORTCUT + return false; +#endif + + argv = get_cmd_line_args (0); + if (argv == NULL) + return NULL; + + for (argc = 0; argv[argc]; argc++) + { + if (argc == 0 || argv[argc][0] == '-') + continue; + + if (strcmp (argv[argc], "mount") == 0 + || strcmp (argv[argc], "search") == 0 + || strcmp (argv[argc], "system") == 0) + { + ret = false; + break; + } + } + + free (argv[0]); + free (argv); + return ret; +} + static void __attribute__((constructor)) init() { const char *xdg_runtime_dir; @@ -159,6 +213,104 @@ static void __attribute__((constructor)) init() } closedir (d); } + + /* 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 ()) + { + int r; + int fd; + long pid; + char buf[12]; + uid_t uid; + char path[PATH_MAX]; + const char *const suffix = "/libpod/pause.pid"; + char *cwd = getcwd (NULL, 0); + + if (cwd == NULL) + { + fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (strlen (xdg_runtime_dir) >= PATH_MAX - strlen (suffix)) + { + fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %s", strerror (ENAMETOOLONG)); + exit (EXIT_FAILURE); + } + + sprintf (path, "%s%s", xdg_runtime_dir, suffix); + fd = open (path, O_RDONLY); + if (fd < 0) + { + free (cwd); + return; + } + + r = read (fd, buf, sizeof (buf)); + close (fd); + if (r < 0) + { + free (cwd); + return; + } + pid = strtol (buf, NULL, 10); + if (pid == LONG_MAX) + { + free (cwd); + return; + } + + uid = geteuid (); + + sprintf (path, "/proc/%d/ns/user", pid); + fd = open (path, O_RDONLY); + if (fd < 0 || setns (fd, 0) < 0) + { + free (cwd); + return; + } + close (fd); + + /* Errors here cannot be ignored as we already joined a ns. */ + sprintf (path, "/proc/%d/ns/mnt", pid); + fd = open (path, O_RDONLY); + if (fd < 0) + { + fprintf (stderr, "cannot open %s: %s", path, strerror (errno)); + exit (EXIT_FAILURE); + } + + r = setns (fd, 0); + if (r < 0) + { + fprintf (stderr, "cannot join mount namespace for %d: %s", pid, strerror (errno)); + exit (EXIT_FAILURE); + } + close (fd); + + if (syscall_setresgid (0, 0, 0) < 0) + { + fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (syscall_setresuid (0, 0, 0) < 0) + { + fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (chdir (cwd) < 0) + { + fprintf (stderr, "cannot chdir: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + + free (cwd); + rootless_uid_init = uid; + } } static int @@ -344,7 +496,7 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path) fprintf (stderr, "cannot setns: %s\n", strerror (errno)); _exit (EXIT_FAILURE); } - close (userns); + close (mountns); if (syscall_setresgid (0, 0, 0) < 0) { diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 0390bbb6a..ddf881368 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -22,7 +22,9 @@ import ( ) /* +#cgo remoteclient CFLAGS: -DDISABLE_JOIN_SHORTCUT #include <stdlib.h> +extern uid_t rootless_uid(); extern int reexec_in_user_namespace(int ready, char *pause_pid_file_path); extern int reexec_in_user_namespace_wait(int pid); extern int reexec_userns_join(int userns, int mountns, char *pause_pid_file_path); @@ -46,6 +48,12 @@ var ( // IsRootless tells us if we are running in rootless mode func IsRootless() bool { isRootlessOnce.Do(func() { + rootlessUIDInit := int(C.rootless_uid()) + if rootlessUIDInit != 0 { + // This happens if we joined the user+mount namespace as part of + os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done") + os.Setenv("_CONTAINERS_ROOTLESS_UID", fmt.Sprintf("%d", rootlessUIDInit)) + } isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" }) return isRootless |