Last active
March 7, 2020 04:13
-
-
Save iczero/b49a003234b6f11ef8bcdac567ca3734 to your computer and use it in GitHub Desktop.
crappy container (works on android)
This file contains 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
#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