bunpen: namespace: restore the working directory (if possible) after entering the mount namespace

This commit is contained in:
2024-08-27 18:06:47 +00:00
parent 469b9b9223
commit 99de056048

View File

@@ -40,6 +40,20 @@ export fn namespace_restrict(what: *resources) void = {
// mapped to non-ns ops by the same user, and vice-versa
write_uid_map(uid, gid);
let pwd = strings::dup(os::getcwd()); // dup because API uses a static buffer
defer(free(pwd));
isolate_paths(what.paths);
// try to change to the old working directory;
// this can fail if it's not within the sandbox.
rtext::swallow_error("namespace: restore $PWD", os::chdir(pwd));
// TODO: CLONE_NEWPID (might not work without forking to also become reaper)
};
// reconfigures all the mounts so that after this call the only paths accessible
// are those reachable from the provided `paths`.
// N.B.: this function does NOT preserve the current working directory
fn isolate_paths(paths: []path::buffer) void = {
// allow new mounts to propagate from the parent namespace into the child
// namespace, but not vice versa:
rtext::check_error("reconfigure / as MS_SLAVE", rtext::mount("/", "/", "", rtext::MS_SLAVE | rtext::MS_REC, null));
@@ -62,28 +76,22 @@ export fn namespace_restrict(what: *resources) void = {
rtext::check_error("mkdir new", rt::mkdir("new", 0o755));
rtext::check_error("mount -t tmpfs tmpfs new", rtext::mount("tmpfs", "new", "tmpfs", 0, null));
{
// bind all the user-requested paths from `old/$p` into `new/$p`.
// use the `dirfd` abstraction so that paths meant for `old` can't crawl out
// of that virtual fs.
let old_fd = rt::open("old", rt::O_RDONLY | rt::O_CLOEXEC, rt::RESOLVE_NO_SYMLINKS: uint)!;
let old_fs = os::dirfdopen(old_fd);
defer(free(old_fs));
let new_fd = rt::open("new", rt::O_RDONLY | rt::O_CLOEXEC, rt::RESOLVE_NO_SYMLINKS: uint)!;
let new_fs = os::dirfdopen(new_fd);
defer(free(new_fs));
// bind all the user-requested paths from `old/$p` into `new/$p`.
// use the `dirfd` abstraction so that paths meant for `old` can't crawl out
// of that virtual fs.
let old_fd = rt::open("old", rt::O_RDONLY | rt::O_CLOEXEC, rt::RESOLVE_NO_SYMLINKS: uint)!;
let old_fs = os::dirfdopen(old_fd);
defer(free(old_fs));
let new_fd = rt::open("new", rt::O_RDONLY | rt::O_CLOEXEC, rt::RESOLVE_NO_SYMLINKS: uint)!;
let new_fs = os::dirfdopen(new_fd);
defer(free(new_fs));
for (let path .. what.paths) {
bind_leaf(old_fs, new_fs, &path);
};
for (let path .. paths) {
bind_leaf(old_fs, new_fs, &path);
};
// pivot into the new rootfs
pivot_into("new");
// TODO: `chdir` back to the original dir we were executed from
// TODO: CLONE_NEWPID (might not work without forking to also become reaper)
};
// walk from root to `p`, creating any ancestors necessary and then binding the