/* Fucking with namespaces because bored.
* "Pegasus Epsilon" <pegasus@pimpninjas.org>
* (C) Apr 19 2023 - Educational Purposes
*/
#define _GNU_SOURCE
#include <stdarg.h> // va_*
#include <stdio.h> // vfprintf(), putc(), perror(), vsnprintf()
#include <stdlib.h> // exit(), malloc(), free(), setenv(), unsetenv(), getenv()
#include <fcntl.h> // open()
#include <unistd.h> // write(), close(), unlink(), execve()
#include <stdbool.h> // bool, true, false
#include <sched.h> // unshare()
#include <pwd.h> // getpwuid()
static void vperrorf (const char *const fmt, va_list *args) {
vfprintf(stderr, fmt, *args);
putc(':', stderr);
putc(' ', stderr);
perror(NULL);
}
static void perrorf (const char *const fmt, ...) {
va_list args;
va_start(args, fmt);
vperrorf(fmt, &args);
va_end(args);
}
__attribute__((noreturn))
static void fail (const int errlvl, const char *const fmt, ...) {
va_list args;
va_start(args, fmt);
vperrorf(fmt, &args);
va_end(args);
exit(errlvl);
}
static bool writefile (const char *const file, const char *const fmt, ...) {
int fd = open(file, O_WRONLY | O_CLOEXEC | O_CREAT);
if (0 > fd) { perror("open error"); return false; }
va_list args, copy;
va_start(args, fmt);
va_copy(copy, args);
int len = 1 + vsnprintf(NULL, 0, fmt, copy);
va_end(copy);
char *buf = malloc(len);
vsnprintf(buf, len, fmt, args);
va_end(args);
int wrote = write(fd, buf, len);
free(buf);
if (wrote != len) perrorf("error writing %s", file);
close(fd);
if (wrote == len) return true;
if (wrote) unlink(file);
return false;
}
int main (int argc, char **argv, char **envp) {
uid_t uid = getuid();
gid_t gid = getgid();
if (unshare(CLONE_NEWUSER)) fail(1, "unshare CLONE_NEWUSER");
if (unshare(CLONE_NEWNET)) fail(2, "unshare CLONE_NEWNET");
if (!writefile("/proc/self/setgroups", "deny")) return 3;
if (!writefile("/proc/self/uid_map", "0 %d 1\n", uid)) return 4;
if (!writefile("/proc/self/gid_map", "0 %d 1\n", gid)) return 5;
struct passwd *pwd = getpwuid(0);
setenv("HOME", pwd->pw_dir, true);
unsetenv("HISTFILE");
execve(getenv("SHELL"), argv, envp);
return 0;
}