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.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
new file mode 100644
index 000000000..f107af7c7
--- /dev/null
+++ b/pkg/rootless/rootless_linux.c
@@ -0,0 +1,128 @@
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+static int
+syscall_clone (unsigned long flags, void *child_stack)
+{
+ return (int) syscall (__NR_clone, flags, child_stack);
+}
+
+static char **
+get_cmd_line_args (pid_t pid)
+{
+ int fd;
+ char path[PATH_MAX];
+ char *buffer;
+ size_t allocated;
+ size_t used = 0;
+ int ret;
+ int i, argc = 0;
+ char **argv;
+
+ sprintf (path, "/proc/%d/cmdline", pid);
+ fd = open (path, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ allocated = 512;
+ buffer = malloc (allocated);
+ if (buffer == NULL)
+ return NULL;
+ for (;;)
+ {
+ do
+ ret = read (fd, buffer + used, allocated - used);
+ while (ret < 0 && errno == EINTR);
+ if (ret < 0)
+ return NULL;
+
+ if (ret == 0)
+ break;
+
+ used += ret;
+ if (allocated == used)
+ {
+ allocated += 512;
+ buffer = realloc (buffer, allocated);
+ if (buffer == NULL)
+ return NULL;
+ }
+ }
+ close (fd);
+
+ for (i = 0; i < used; i++)
+ if (buffer[i] == '\0')
+ argc++;
+
+ argv = malloc (sizeof (char *) * (argc + 1));
+ argc = 0;
+
+ argv[argc++] = buffer;
+ for (i = 0; i < used - 1; i++)
+ if (buffer[i] == '\0')
+ argv[argc++] = buffer + i + 1;
+
+ argv[argc] = NULL;
+
+ return argv;
+}
+
+int
+reexec_in_user_namespace(int ready)
+{
+ int ret;
+ pid_t pid;
+ char b;
+ pid_t ppid = getpid ();
+ char **argv;
+
+ pid = syscall_clone (CLONE_NEWUSER|SIGCHLD, NULL);
+ if (pid)
+ return pid;
+
+ argv = get_cmd_line_args (ppid);
+
+ setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1);
+
+ do
+ ret = read (ready, &b, 1) < 0;
+ while (ret < 0 && errno == EINTR);
+ if (ret < 0)
+ _exit (1);
+ close (ready);
+
+ execv (argv[0], argv);
+
+ _exit (1);
+}
+
+int
+reexec_in_user_namespace_wait (int pid)
+{
+ pid_t p;
+ int status;
+
+ do
+ p = waitpid (pid, &status, 0);
+ while (p < 0 && errno == EINTR);
+
+ if (p < 0)
+ return -1;
+
+ if (WIFEXITED (status))
+ return WEXITSTATUS (status);
+ if (WIFSIGNALED (status))
+ return 128 + WTERMSIG (status);
+ return -1;
+}