mirror of
https://github.com/containers/podman.git
synced 2025-05-30 15:15:20 +08:00

change the tests to use chroot to set a numeric UID/GID. Go syscall.Credential doesn't change the effective UID/GID of the process. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Closes: #1372 Approved by: mheon
177 lines
3.1 KiB
C
177 lines
3.1 KiB
C
#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++;
|
|
if (argc == 0)
|
|
return NULL;
|
|
|
|
argv = malloc (sizeof (char *) * (argc + 1));
|
|
if (argv == NULL)
|
|
return NULL;
|
|
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_userns_join (int userns)
|
|
{
|
|
pid_t ppid = getpid ();
|
|
char uid[16];
|
|
char **argv;
|
|
int pid;
|
|
|
|
sprintf (uid, "%d", geteuid ());
|
|
|
|
argv = get_cmd_line_args (ppid);
|
|
if (argv == NULL)
|
|
_exit (EXIT_FAILURE);
|
|
|
|
pid = fork ();
|
|
if (pid)
|
|
return pid;
|
|
|
|
setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1);
|
|
setenv ("_LIBPOD_ROOTLESS_UID", uid, 1);
|
|
|
|
if (setns (userns, 0) < 0)
|
|
_exit (EXIT_FAILURE);
|
|
close (userns);
|
|
|
|
if (setresgid (0, 0, 0) < 0 ||
|
|
setresuid (0, 0, 0) < 0)
|
|
_exit (EXIT_FAILURE);
|
|
|
|
execvp (argv[0], argv);
|
|
|
|
_exit (EXIT_FAILURE);
|
|
}
|
|
|
|
int
|
|
reexec_in_user_namespace (int ready)
|
|
{
|
|
int ret;
|
|
pid_t pid;
|
|
char b;
|
|
pid_t ppid = getpid ();
|
|
char **argv;
|
|
char uid[16];
|
|
|
|
sprintf (uid, "%d", geteuid ());
|
|
|
|
pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL);
|
|
if (pid)
|
|
return pid;
|
|
|
|
argv = get_cmd_line_args (ppid);
|
|
if (argv == NULL)
|
|
_exit (EXIT_FAILURE);
|
|
|
|
setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1);
|
|
setenv ("_LIBPOD_ROOTLESS_UID", uid, 1);
|
|
|
|
do
|
|
ret = read (ready, &b, 1) < 0;
|
|
while (ret < 0 && errno == EINTR);
|
|
if (ret < 0)
|
|
_exit (EXIT_FAILURE);
|
|
close (ready);
|
|
|
|
if (setresgid (0, 0, 0) < 0 ||
|
|
setresuid (0, 0, 0) < 0)
|
|
_exit (EXIT_FAILURE);
|
|
|
|
execvp (argv[0], argv);
|
|
|
|
_exit (EXIT_FAILURE);
|
|
}
|
|
|
|
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;
|
|
}
|