1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

Prepare for FreeBSD sandboxing support

This is the utility changes from #9968, which were easier to rebase
first.

I (@Ericson2314) didn't write this code; I just rebased it.

Co-Authored-By: Artemis Tosini <me@artem.ist>
Co-Authored-By: Audrey Dutcher <audrey@rhelmot.io>
This commit is contained in:
John Ericson 2025-05-27 14:51:39 -04:00
parent 653a93ac0f
commit 625dce659a
19 changed files with 198 additions and 15 deletions

View file

@ -359,7 +359,7 @@
''^src/libutil/json-utils\.cc$''
''^src/libutil/include/nix/util/json-utils\.hh$''
''^src/libutil/linux/cgroup\.cc$''
''^src/libutil/linux/namespaces\.cc$''
''^src/libutil/linux/linux-namespaces\.cc$''
''^src/libutil/logging\.cc$''
''^src/libutil/include/nix/util/logging\.hh$''
''^src/libutil/memory-source-accessor\.cc$''

View file

@ -14,7 +14,7 @@
#endif
#ifdef __linux__
# include "nix/util/namespaces.hh"
# include "nix/util/linux-namespaces.hh"
#endif
#include <unistd.h>

View file

@ -85,7 +85,7 @@ Settings::Settings()
builders = concatStringsSep("\n", ss);
}
#if defined(__linux__) && defined(SANDBOX_SHELL)
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(SANDBOX_SHELL)
sandboxPaths = tokenizeString<StringSet>("/bin/sh=" SANDBOX_SHELL);
#endif

View file

@ -682,7 +682,9 @@ public:
description of the `size` option of `tmpfs` in mount(8). The default
is `50%`.
)"};
#endif
#if defined(__linux__) || defined(__FreeBSD__)
Setting<Path> sandboxBuildDir{this, "/build", "sandbox-build-dir",
R"(
*Linux only*

View file

@ -2,7 +2,7 @@
# include "nix/store/personality.hh"
# include "nix/util/cgroup.hh"
# include "nix/util/namespaces.hh"
# include "nix/util/linux-namespaces.hh"
# include "linux/fchmodat2-compat.hh"
# include <sys/ioctl.h>

View file

@ -197,7 +197,7 @@ bool useBuildUsers()
#ifdef __linux__
static bool b = (settings.buildUsersGroup != "" || settings.autoAllocateUids) && isRootUser();
return b;
#elif defined(__APPLE__)
#elif defined(__APPLE__) && defined(__FreeBSD__)
static bool b = settings.buildUsersGroup != "" && isRootUser();
return b;
#else

View file

@ -16,7 +16,12 @@
#ifdef __linux__
# include <mutex>
# include "nix/util/cgroup.hh"
# include "nix/util/namespaces.hh"
# include "nix/util/linux-namespaces.hh"
#endif
#ifdef __FreeBSD__
# include <sys/param.h>
# include <sys/sysctl.h>
#endif
namespace nix {
@ -115,6 +120,24 @@ std::optional<Path> getSelfExe()
return buf;
else
return std::nullopt;
#elif defined(__FreeBSD__)
int sysctlName[] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PATHNAME,
-1,
};
size_t pathLen = 0;
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), nullptr, &pathLen, nullptr, 0) < 0) {
return std::nullopt;
}
std::vector<char> path(pathLen);
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), path.data(), &pathLen, nullptr, 0) < 0) {
return std::nullopt;
}
return Path(path.begin(), path.end());
#else
return std::nullopt;
#endif

View file

@ -23,6 +23,11 @@
#include <boost/iostreams/device/mapped_file.hpp>
#ifdef __FreeBSD__
# include <sys/param.h>
# include <sys/mount.h>
#endif
#ifdef _WIN32
# include <io.h>
#endif
@ -364,6 +369,13 @@ void syncParent(const Path & path)
fd.fsync();
}
#ifdef __FreeBSD__
#define MOUNTEDPATHS_PARAM , std::set<Path> &mountedPaths
#define MOUNTEDPATHS_ARG , mountedPaths
#else
#define MOUNTEDPATHS_PARAM
#define MOUNTEDPATHS_ARG
#endif
void recursiveSync(const Path & path)
{
@ -410,11 +422,19 @@ void recursiveSync(const Path & path)
}
static void _deletePath(Descriptor parentfd, const std::filesystem::path & path, uint64_t & bytesFreed)
static void _deletePath(Descriptor parentfd, const std::filesystem::path & path, uint64_t & bytesFreed MOUNTEDPATHS_PARAM)
{
#ifndef _WIN32
checkInterrupt();
#ifdef __FreeBSD__
// In case of emergency (unmount fails for some reason) not recurse into mountpoints.
// This prevents us from tearing up the nullfs-mounted nix store.
if (mountedPaths.find(path) != mountedPaths.end()) {
return;
}
#endif
std::string name(baseNameOf(path.native()));
struct stat st;
@ -468,7 +488,7 @@ static void _deletePath(Descriptor parentfd, const std::filesystem::path & path,
checkInterrupt();
std::string childName = dirent->d_name;
if (childName == "." || childName == "..") continue;
_deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed);
_deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed MOUNTEDPATHS_ARG);
}
if (errno) throw SysError("reading directory %1%", path);
}
@ -484,7 +504,7 @@ static void _deletePath(Descriptor parentfd, const std::filesystem::path & path,
#endif
}
static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFreed MOUNTEDPATHS_PARAM)
{
Path dir = dirOf(path.string());
if (dir == "")
@ -496,7 +516,7 @@ static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFree
throw SysError("opening directory '%1%'", path);
}
_deletePath(dirfd.get(), path, bytesFreed);
_deletePath(dirfd.get(), path, bytesFreed MOUNTEDPATHS_ARG);
}
@ -529,8 +549,20 @@ void createDirs(const std::filesystem::path & path)
void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
{
//Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
#ifdef __FreeBSD__
std::set<Path> mountedPaths;
struct statfs *mntbuf;
int count;
if ((count = getmntinfo(&mntbuf, MNT_WAIT)) < 0) {
throw SysError("getmntinfo");
}
for (int i = 0; i < count; i++) {
mountedPaths.emplace(mntbuf[i].f_mntonname);
}
#endif
bytesFreed = 0;
_deletePath(path, bytesFreed);
_deletePath(path, bytesFreed MOUNTEDPATHS_ARG);
}
@ -572,6 +604,30 @@ void AutoDelete::reset(const std::filesystem::path & p, bool recursive) {
//////////////////////////////////////////////////////////////////////
#ifdef __FreeBSD__
AutoUnmount::AutoUnmount() : del{false} {}
AutoUnmount::AutoUnmount(Path &p) : path(p), del(true) {}
AutoUnmount::~AutoUnmount()
{
try {
if (del) {
if (unmount(path.c_str(), 0) < 0) {
throw SysError("Failed to unmount path %1%", path);
}
}
} catch (...) {
ignoreExceptionInDestructor();
}
}
void AutoUnmount::cancel()
{
del = false;
}
#endif
//////////////////////////////////////////////////////////////////////
std::string defaultTempDir() {

View file

@ -0,0 +1,52 @@
#ifdef __FreeBSD__
# include "nix/util/freebsd-jail.hh"
# include <sys/resource.h>
# include <sys/param.h>
# include <sys/jail.h>
# include <sys/mount.h>
# include "nix/util/error.hh"
# include "nix/util/util.hh"
namespace nix {
AutoRemoveJail::AutoRemoveJail()
: del{false}
{
}
AutoRemoveJail::AutoRemoveJail(int jid)
: jid(jid)
, del(true)
{
}
AutoRemoveJail::~AutoRemoveJail()
{
try {
if (del) {
if (jail_remove(jid) < 0) {
throw SysError("Failed to remove jail %1%", jid);
}
}
} catch (...) {
ignoreExceptionInDestructor();
}
}
void AutoRemoveJail::cancel()
{
del = false;
}
void AutoRemoveJail::reset(int j)
{
del = true;
jid = j;
}
//////////////////////////////////////////////////////////////////////
}
#endif

View file

@ -0,0 +1,20 @@
#pragma once
///@file
#include "nix/util/types.hh"
namespace nix {
class AutoRemoveJail
{
int jid;
bool del;
public:
AutoRemoveJail(int jid);
AutoRemoveJail();
~AutoRemoveJail();
void cancel();
void reset(int j);
};
}

View file

@ -0,0 +1,7 @@
# Public headers directory
include_dirs += include_directories('../..')
headers += files(
'freebsd-jail.hh',
)

View file

@ -0,0 +1,5 @@
sources += files(
'freebsd-jail.cc',
)
subdir('include/nix/util')

View file

@ -310,7 +310,7 @@ typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
/**
* Create a temporary directory.
*/
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
mode_t mode = 0755);
/**
@ -420,4 +420,17 @@ private:
std::filesystem::directory_iterator it_;
};
#ifdef __FreeBSD__
class AutoUnmount
{
Path path;
bool del;
public:
AutoUnmount(Path&);
AutoUnmount();
~AutoUnmount();
void cancel();
};
#endif
}

View file

@ -4,5 +4,5 @@ include_dirs += include_directories('../..')
headers += files(
'cgroup.hh',
'namespaces.hh',
'linux-namespaces.hh',
)

View file

@ -1,3 +1,4 @@
#include "nix/util/linux-namespaces.hh"
#include "nix/util/current-process.hh"
#include "nix/util/util.hh"
#include "nix/util/finally.hh"

View file

@ -1,6 +1,6 @@
sources += files(
'cgroup.cc',
'namespaces.cc',
'linux-namespaces.cc',
)
subdir('include/nix/util')

View file

@ -169,6 +169,10 @@ if host_machine.system() == 'linux'
subdir('linux')
endif
if host_machine.system() == 'freebsd'
subdir('freebsd')
endif
if host_machine.system() == 'windows'
subdir('windows')
else

View file

@ -38,7 +38,7 @@
#endif
#ifdef __linux__
# include "nix/util/namespaces.hh"
# include "nix/util/linux-namespaces.hh"
#endif
#ifndef _WIN32