Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active March 7, 2020 04:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/b49a003234b6f11ef8bcdac567ca3734 to your computer and use it in GitHub Desktop.
Save iczero/b49a003234b6f11ef8bcdac567ca3734 to your computer and use it in GitHub Desktop.
crappy container (works on android)
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#define PERSIST_PATH "mount.ns"
// usage: stuff <rootfs path> <container root> <pivot old> <program> [<args> ...]
// to umount the "container", simply run umount -R <container root>
int main(int argc, char **argv, char **envp) {
if (argc < 5) {
fprintf(stderr, "Not enough arguments\n");
return 5;
}
char *rootfs_path = argv[1];
char *mount_path = argv[2];
int rootfs_fd = open(rootfs_path, O_CLOEXEC | O_PATH | O_DIRECTORY);
if (rootfs_fd == -1) {
perror("open rootfs path");
return 1;
}
int ns_fd = -1;
int mount_fd = open(mount_path, O_CLOEXEC | O_PATH | O_DIRECTORY);
if (mount_fd == -1) {
if (errno != ENOENT) {
perror("open mount path");
return 1;
}
// mount path does not exist, create it
if (mkdir(mount_path, 0777)) {
perror("create mount path");
return 1;
}
mount_fd = open(mount_path, O_CLOEXEC | O_PATH | O_DIRECTORY);
if (mount_fd == -1) {
perror("open mount path");
return 1;
}
}
// laziness: check for mount/proc/self to determine if mount points exist
int temp_fd = openat(mount_fd, "proc/self", O_CLOEXEC | O_PATH | O_DIRECTORY);
if (temp_fd == -1) {
// bind mount rootfs
if (mount(rootfs_path, mount_path, NULL, MS_BIND, NULL)) {
perror("bind mount rootfs");
return 1;
}
// clear any unwanted flags (nosuid/nodev/noexec)
if (mount(rootfs_path, mount_path, NULL, MS_REMOUNT | MS_BIND, NULL)) {
perror("remount rootfs");
return 1;
}
// make mount private
if (mount(rootfs_path, mount_path, NULL, MS_PRIVATE, NULL)) {
perror("set rootfs mount private");
return 1;
}
char bind_target[PATH_MAX];
// mount /dev
snprintf(bind_target, sizeof(bind_target), "%s/dev", mount_path);
if (mount("/dev", bind_target, NULL, MS_BIND | MS_REC, NULL)) {
perror("mount /dev");
return 1;
}
// mount /proc
snprintf(bind_target, sizeof(bind_target), "%s/proc", mount_path);
if (mount("/proc", bind_target, NULL, MS_BIND | MS_REC, NULL)) {
perror("mount /proc");
return 1;
}
// mount /sys
snprintf(bind_target, sizeof(bind_target), "%s/sys", mount_path);
if (mount("/sys", bind_target, NULL, MS_BIND | MS_REC, NULL)) {
perror("mount /sys");
return 1;
}
} else {
close(temp_fd);
}
// reopen mount point
close(mount_fd);
mount_fd = open(mount_path, O_CLOEXEC | O_PATH | O_DIRECTORY);
if (mount_fd == -1) {
perror("open mount path");
return 1;
}
ns_fd = openat(mount_fd, PERSIST_PATH, O_CLOEXEC | O_CREAT | O_RDONLY, 0666);
if (ns_fd == -1) {
perror("create persistent namespace");
return 1;
}
if (setns(ns_fd, CLONE_NEWNS)) {
// namespace not available, create and persist
int pipefd[2];
if (pipe(pipefd)) {
perror("create pipe");
return 1;
}
pid_t parent_pid = getpid();
pid_t forked = fork();
if (forked == -1) {
perror("fork");
return 1;
} else if (forked == 0) {
char ns_path[64];
snprintf(ns_path, sizeof(ns_path), "/proc/%u/ns/mnt", (unsigned int) parent_pid);
char persist_path[PATH_MAX];
snprintf(persist_path, sizeof(persist_path), "%s/" PERSIST_PATH, mount_path);
// wait for signal from parent
char unused;
if (read(pipefd[0], &unused, 1) == -1) {
perror("waiting for parent");
return 1;
}
close(pipefd[0]);
// persist the namespace
if (mount(ns_path, persist_path, NULL, MS_BIND, NULL)) {
perror("persist namespace");
return 1;
}
return 0;
} else {
if (unshare(CLONE_NEWNS)) {
perror("unshare mount namespace");
return 1;
}
char unused = 1;
if (write(pipefd[1], &unused, 1) == -1) {
perror("signal child");
return 1;
}
close(pipefd[1]);
int wstatus;
if (waitpid(forked, &wstatus, 0) == -1) {
perror("waiting for child");
return 1;
}
if (!WIFEXITED(wstatus)) {
if (WIFSIGNALED(wstatus)) {
fprintf(stderr, "child terminated abnormally\n");
return WTERMSIG(wstatus);
} else {
fprintf(stderr, "no clue what just happened, please send help\n");
return 42;
}
} else {
int exit_status = WEXITSTATUS(wstatus);
if (exit_status) return exit_status;
}
char put_old[PATH_MAX];
snprintf(put_old, sizeof(put_old), "%s/%s", mount_path, argv[3]);
if (syscall(SYS_pivot_root, mount_path, put_old)) {
perror("pivot_root");
return 1;
}
}
}
chdir("/");
execve(argv[4], argv + 4, envp);
perror("exec program");
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment