summaryrefslogtreecommitdiff
path: root/pkg/rootless/rootless_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/rootless/rootless_linux.c')
-rw-r--r--pkg/rootless/rootless_linux.c172
1 files changed, 162 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)
{