Repositories / jai.git
jai.git
Clone (read-only): git clone http://git.guha-anderson.com/git/jai.git
@@ -30,8 +30,11 @@ glob(std::string_view pattern, std::string_view target) std::string fdpath(int fd, bool must) { - if (fd < 0 || fd == AT_FDCWD) + if (fd < 0 || fd == AT_FDCWD) { + if (must) + err("fdpath invalid fd {}", fd); return "."; + } auto procfd = std::format("/proc/self/fd/{}", fd); std::error_code ec; auto res = std::filesystem::read_symlink(procfd, ec); @@ -42,24 +45,21 @@ fdpath(int fd, bool must) } res = std::format("fd {} [can't determine path]", fd, ec.message()); } + else if (must && !res.is_absolute() || !is_fd_at_path(fd, -1, res)) + err("{} not valid complete path for fd {}", res.string(), fd); return res; } std::string -fdpath(int fd, const path &file, bool must) +fdpath(int fd, const path &file) { if (fd < 0 || fd == AT_FDCWD || file.is_absolute()) return file.empty() ? "." : file.string(); auto procfd = std::format("/proc/self/fd/{}", fd); std::error_code ec; auto res = std::filesystem::read_symlink(procfd, ec); - if (ec) { - if (must) { - errno = ec.value(); - syserr("{}", procfd); - } - res = std::format("fd {} [can't determine path]", fd, ec.message()); - } + if (ec) + res = std::format("fd {} [can't determine path]: {}", fd, ec.message()); if (!file.empty()) res = res / file; return res;
@@ -68,7 +68,7 @@ subtree_rev(const is_one_of<PathSet, PathMultiset> auto &s, const path &root) return subtree(s, root) | std::views::reverse; } -std::string fdpath(int fd, const path &file, bool must = false); +std::string fdpath(int fd, const path &file); std::string fdpath(int fd, bool must = false); PathMultiset mountpoints(const path &mountinfo = "/proc/self/mountinfo");
@@ -255,10 +255,23 @@ Config::home_jai() int Config::storage() { + if (storage_fd_) + return *storage_fd_; + + auto restore = asuser(); + if (storagedir_.empty()) - return home_jai(); - if (!storage_fd_) + storage_fd_ = xdup(home_jai()); + else storage_fd_ = ensure_udir(AT_FDCWD, storagedir_); + + path fullpath = fdpath(*storage_fd_, true); + if (fullpath.is_relative()) + err("cannot find full pathname for {}", storagedir_.string()); + if (!is_fd_at_path(*storage_fd_, -1, fullpath)) + err("{} is no longer at {}", storagedir_.string(), fullpath.string()); + storagedir_ = fullpath; + return *storage_fd_; } @@ -573,6 +586,28 @@ Config::make_mnt_ns() xmnt_move(*src, *dst); } + xsetns(*newns, CLONE_NEWNS); + struct stat sb; + + if (!storagedir_.empty() && stat(storagedir_.c_str(), &sb) == 0 && + S_ISDIR(sb.st_mode)) { + // make sure storage directory not exposed + auto restore_root = asuser(); + Fd target = xopenat(AT_FDCWD, storagedir_.c_str(), O_DIRECTORY | O_RDONLY); + check_user(*target); + restore_root.reset(); + Fd empty = xopenat(-1, kRunRoot, O_RDONLY); + if (!is_dir_empty(*empty)) + err("{} should be empty in jail", kRunRoot); + Fd source = clone_tree(*empty); + xmnt_setattr(*source, mount_attr{ + .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | + MOUNT_ATTR_NODEV, + .propagation = MS_PRIVATE, + }); + xmnt_move(*source, *target); + } + return newns; }