forked from mirrors/nixpkgs
chrootenv: bind-mount all dirs in /, symlink files, closes #32877
This commit is contained in:
parent
ef1accae91
commit
c03663a145
|
@ -10,6 +10,7 @@
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -43,33 +44,80 @@ char **env_build(char *names[], size_t len) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bind {
|
void bind(char *from, char *to) {
|
||||||
char *from;
|
if (mkdir(to, 0755) < 0)
|
||||||
char *to;
|
errorf(EX_IOERR, "mkdir");
|
||||||
};
|
|
||||||
|
|
||||||
struct bind binds[] = {{"/", "host"}, {"/proc", "proc"}, {"/sys", "sys"},
|
if (mount(from, to, "bind", MS_BIND | MS_REC, NULL) < 0)
|
||||||
{"/nix", "nix"}, {"/tmp", "tmp"}, {"/var", "var"},
|
errorf(EX_OSERR, "mount");
|
||||||
{"/run", "run"}, {"/dev", "dev"}, {"/home", "home"}};
|
}
|
||||||
|
|
||||||
void bind(struct bind *bind) {
|
char *strjoin(char *dir, char *name) {
|
||||||
DIR *src = opendir(bind->from);
|
char *path = malloc(strlen(dir) + strlen(name) + 1);
|
||||||
|
|
||||||
if (src) {
|
if (path == NULL)
|
||||||
if (closedir(src) < 0)
|
errorf(EX_OSERR, "malloc");
|
||||||
errorf(EX_IOERR, "closedir");
|
|
||||||
|
|
||||||
if (mkdir(bind->to, 0755) < 0)
|
if (strcpy(path, dir) < 0)
|
||||||
errorf(EX_IOERR, "mkdir");
|
errorf(EX_IOERR, "strcpy");
|
||||||
|
|
||||||
if (mount(bind->from, bind->to, "bind", MS_BIND | MS_REC, NULL) < 0)
|
if (strcat(path, name) < 0)
|
||||||
errorf(EX_OSERR, "mount");
|
errorf(EX_IOERR, "strcat");
|
||||||
|
|
||||||
} else {
|
return path;
|
||||||
// https://github.com/NixOS/nixpkgs/issues/31104
|
}
|
||||||
if (errno != ENOENT)
|
|
||||||
errorf(EX_OSERR, "opendir");
|
#define LEN(x) sizeof(x) / sizeof(*x)
|
||||||
|
|
||||||
|
char *bind_blacklist[] = {".", "..", "bin", "etc", "host", "usr"};
|
||||||
|
|
||||||
|
bool bind_blacklisted(char *name) {
|
||||||
|
for (size_t i = 0; i < LEN(bind_blacklist); i++) {
|
||||||
|
if (!strcmp(bind_blacklist[i], name))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isdir(char *path) {
|
||||||
|
struct stat buf;
|
||||||
|
stat(path, &buf);
|
||||||
|
return S_ISDIR(buf.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_to_cwd(char *prefix) {
|
||||||
|
DIR *prefix_dir = opendir(prefix);
|
||||||
|
|
||||||
|
if (prefix_dir == NULL)
|
||||||
|
errorf(EX_OSERR, "opendir");
|
||||||
|
|
||||||
|
struct dirent *prefix_dirent;
|
||||||
|
|
||||||
|
while (prefix_dirent = readdir(prefix_dir)) {
|
||||||
|
if (bind_blacklisted(prefix_dirent->d_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *prefix_dirent_path = strjoin(prefix, prefix_dirent->d_name);
|
||||||
|
|
||||||
|
if (isdir(prefix_dirent_path)) {
|
||||||
|
bind(prefix_dirent_path, prefix_dirent->d_name);
|
||||||
|
} else {
|
||||||
|
char *host_target = strjoin("host/", prefix_dirent->d_name);
|
||||||
|
|
||||||
|
if (symlink(host_target, prefix_dirent->d_name) < 0)
|
||||||
|
errorf(EX_IOERR, "symlink");
|
||||||
|
|
||||||
|
free(host_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(prefix_dirent_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(prefix, "host");
|
||||||
|
|
||||||
|
if (closedir(prefix_dir) < 0)
|
||||||
|
errorf(EX_IOERR, "closedir");
|
||||||
}
|
}
|
||||||
|
|
||||||
void spitf(char *path, char *fmt, ...) {
|
void spitf(char *path, char *fmt, ...) {
|
||||||
|
@ -96,8 +144,6 @@ int nftw_rm(const char *path, const struct stat *sb, int type,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LEN(x) sizeof(x) / sizeof(*x)
|
|
||||||
|
|
||||||
#define REQUIREMENTS "Linux version >= 3.19 built with CONFIG_USER_NS option"
|
#define REQUIREMENTS "Linux version >= 3.19 built with CONFIG_USER_NS option"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
@ -157,8 +203,7 @@ int main(int argc, char *argv[]) {
|
||||||
if (chdir(root) < 0)
|
if (chdir(root) < 0)
|
||||||
errorf(EX_IOERR, "chdir");
|
errorf(EX_IOERR, "chdir");
|
||||||
|
|
||||||
for (size_t i = 0; i < LEN(binds); i++)
|
bind_to_cwd("/");
|
||||||
bind(&binds[i]);
|
|
||||||
|
|
||||||
if (chroot(root) < 0)
|
if (chroot(root) < 0)
|
||||||
errorf(EX_OSERR, "chroot");
|
errorf(EX_OSERR, "chroot");
|
||||||
|
|
Loading…
Reference in a new issue