Created
January 30, 2024 20:49
-
-
Save ig0rmin/e29694c640def5aef97ae26c83c4e7f3 to your computer and use it in GitHub Desktop.
Clone a process into a new mount namespace and pivot root to a given directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This example demonstrates creating mount namespace and using pivot_root() | |
// It doesn't create a user namespace, so to run it we need sudo | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sched.h> | |
#include <limits.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/mount.h> | |
#include <sys/stat.h> | |
#include <sys/syscall.h> | |
#include <sys/wait.h> | |
static void waitChild(pid_t pid) { | |
int status = 0; | |
pid_t res = waitpid(pid, &status, 0); | |
if (res == -1) { | |
printf("Waitpid returned error, errno: %d\n", errno); | |
return; | |
} | |
if (WIFEXITED(status)) { | |
printf("Child %d exited with exit status %d\n", pid, WEXITSTATUS(status)); | |
} else if (WIFSIGNALED(status)) { | |
printf("Child %d was killed by a signal %d (core dumped: %d)\n", | |
pid, WTERMSIG(status), __WCOREDUMP(status)); | |
} else { | |
printf("error: unexpected waitpid result\n"); | |
} | |
} | |
static int _clone(int flags) { | |
return syscall(SYS_clone, flags, NULL, NULL, NULL, NULL); | |
} | |
static int pivot_root(const char *new_root, const char *put_old) { | |
return syscall(SYS_pivot_root, new_root, put_old); | |
} | |
static void doPivotRoot(const char* newRoot) { | |
const char *oldRoot = "/old_root"; | |
// Recursively change mount propagation to "private" | |
mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL); | |
// Make sure that new new root is a mount point | |
mount(newRoot, newRoot, NULL, MS_BIND, NULL); | |
// Create directory to which old root will be pivoted | |
char path[PATH_MAX] = {0}; | |
snprintf(path, sizeof(path), "%s/%s", newRoot, oldRoot); | |
mkdir(path, 0777); | |
pivot_root(newRoot, path); | |
chdir("/"); | |
umount2(oldRoot, MNT_DETACH); | |
rmdir(oldRoot); | |
} | |
int main(int argc, char* argv[]) { | |
if (argc != 2) { | |
fprintf(stderr, "Usage: %s <new-root>\n", argv[0]); | |
return 1; | |
} | |
const char* newRoot = argv[1]; | |
fprintf(stdout, "New root: %s\n", newRoot); | |
int pid = _clone(SIGCHLD | CLONE_NEWNS); | |
if (pid == -1) { | |
// Error | |
fprintf(stderr, "clone returned -1\n"); | |
exit(EXIT_FAILURE); | |
} else if (pid == 0) { | |
// Child | |
printf("Child, PID: %d\n", getpid()); | |
doPivotRoot(newRoot); | |
// Execute a shell inside a container (we assume a new FS has it) | |
char* newExe = "/bin/sh"; | |
char* newArgs[] = {newExe, NULL}; | |
execv(newExe, newArgs); | |
fprintf(stderr, "execv failed\n"); | |
exit(EXIT_FAILURE); | |
} else { | |
printf("Parent, Child PID: %d\n", pid); | |
waitChild(pid); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment