diff options
-rw-r--r-- | .gitignore | 17 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rwxr-xr-x | bootstrap | 5 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | main.c | 58 | ||||
-rw-r--r-- | utils.c | 19 | ||||
-rw-r--r-- | utils.h | 17 |
7 files changed, 123 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0e9a62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.* +!.gitignore + +Makefile.in +aclocal.m4 +compile +configure +depcomp +install-sh +missing +Makefile +config.log +config.status +*.cache + +*.o +uroot diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..a451a6d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +bin_PROGRAMS = uroot +uroot_SOURCES = main.c utils.c diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..71f0ee2 --- /dev/null +++ b/bootstrap @@ -0,0 +1,5 @@ +#!/bin/sh +set -e +aclocal +automake --foreign --add-missing +autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..084b6bd --- /dev/null +++ b/configure.ac @@ -0,0 +1,5 @@ +AC_INIT([uroot], [0.1], [cynerd@email.cz]) +AM_INIT_AUTOMAKE([-Wall]) +AC_PROG_CC +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT @@ -0,0 +1,58 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <sys/types.h> +#include <sched.h> +#include <errno.h> +#include <assert.h> +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include "utils.h" + +void sigint_handler(int sig) { } + +int main(int argc, char **argv) { + pid_t ppid = getpid(); + + if (!fork()) { + system(aprintf("newuidmap %d 0 %d 1 1 65537 65536", ppid, getuid())); + system(aprintf("newgidmap %d 0 %d 1 1 65537 65536", ppid, getgid())); + kill(ppid, SIGINT); + return 0; + } + + unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID); + + signal(SIGINT, sigint_handler); + pause(); + errno = 0; // Just clear error from pause() + + pid_t chpid = fork(); + if (chpid) { + int stat; + waitpid(chpid, &stat, 0); + return stat; + } + + // mount /sys and /proc + mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL); + assert_perror(errno); + mount("none", "/proc", NULL, MS_REC | MS_PRIVATE, NULL); + assert_perror(errno); + mount("none", "/sys", NULL, MS_REC | MS_PRIVATE, NULL); + assert_perror(errno); + mount("proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL); + assert_perror(errno); + + // mount proc to root + // rbind mount dev and sys to root + + // TODO verify that all upper directories have +rx rights + // TODO chroot + execv("/bin/sh", NULL); +} @@ -0,0 +1,19 @@ +#include "utils.h" + +// Compute the size needed (including \0) to format given message +size_t printf_len(const char *msg, ...) { + va_list args; + va_start(args, msg); + size_t result = vsnprintf(NULL, 0, msg, args); + va_end(args); + return result + 1; +} + +// Like sprintf, but returs the string. Expects there's enough space. +char *printf_into(char *dst, const char *msg, ...) { + va_list args; + va_start(args, msg); + vsprintf(dst, msg, args); + va_end(args); + return dst; +} @@ -0,0 +1,17 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdarg.h> +#include <alloca.h> + +// Compute the size needed (including \0) to format given message +size_t printf_len(const char *msg, ...) __attribute__((format(printf, 1, 2))); +// Like sprintf, but returs the string. Expects there's enough space. +char *printf_into(char *dst, const char *msg, ...) __attribute__((format(printf, 2, 3))); +// Like printf, but allocates the data on the stack with alloca and returns. It +// uses the arguments multiple times, so beware of side effects. +#define aprintf(...) printf_into(alloca(printf_len(__VA_ARGS__)), __VA_ARGS__) + +#endif /* _UTILS_H_ */ |