1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 10:41:16 +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/json-utils\.cc$''
''^src/libutil/include/nix/util/json-utils\.hh$'' ''^src/libutil/include/nix/util/json-utils\.hh$''
''^src/libutil/linux/cgroup\.cc$'' ''^src/libutil/linux/cgroup\.cc$''
''^src/libutil/linux/namespaces\.cc$'' ''^src/libutil/linux/linux-namespaces\.cc$''
''^src/libutil/logging\.cc$'' ''^src/libutil/logging\.cc$''
''^src/libutil/include/nix/util/logging\.hh$'' ''^src/libutil/include/nix/util/logging\.hh$''
''^src/libutil/memory-source-accessor\.cc$'' ''^src/libutil/memory-source-accessor\.cc$''

View file

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

View file

@ -85,7 +85,7 @@ Settings::Settings()
builders = concatStringsSep("\n", ss); 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); sandboxPaths = tokenizeString<StringSet>("/bin/sh=" SANDBOX_SHELL);
#endif #endif

View file

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

View file

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

View file

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

View file

@ -16,7 +16,12 @@
#ifdef __linux__ #ifdef __linux__
# include <mutex> # include <mutex>
# include "nix/util/cgroup.hh" # 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 #endif
namespace nix { namespace nix {
@ -115,6 +120,24 @@ std::optional<Path> getSelfExe()
return buf; return buf;
else else
return std::nullopt; 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 #else
return std::nullopt; return std::nullopt;
#endif #endif

View file

@ -23,6 +23,11 @@
#include <boost/iostreams/device/mapped_file.hpp> #include <boost/iostreams/device/mapped_file.hpp>
#ifdef __FreeBSD__
# include <sys/param.h>
# include <sys/mount.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
# include <io.h> # include <io.h>
#endif #endif
@ -364,6 +369,13 @@ void syncParent(const Path & path)
fd.fsync(); 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) 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 #ifndef _WIN32
checkInterrupt(); 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())); std::string name(baseNameOf(path.native()));
struct stat st; struct stat st;
@ -468,7 +488,7 @@ static void _deletePath(Descriptor parentfd, const std::filesystem::path & path,
checkInterrupt(); checkInterrupt();
std::string childName = dirent->d_name; std::string childName = dirent->d_name;
if (childName == "." || childName == "..") continue; 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); if (errno) throw SysError("reading directory %1%", path);
} }
@ -484,7 +504,7 @@ static void _deletePath(Descriptor parentfd, const std::filesystem::path & path,
#endif #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()); Path dir = dirOf(path.string());
if (dir == "") if (dir == "")
@ -496,7 +516,7 @@ static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFree
throw SysError("opening directory '%1%'", path); 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) void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
{ {
//Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path); //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; 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() { 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

@ -420,4 +420,17 @@ private:
std::filesystem::directory_iterator it_; 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( headers += files(
'cgroup.hh', '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/current-process.hh"
#include "nix/util/util.hh" #include "nix/util/util.hh"
#include "nix/util/finally.hh" #include "nix/util/finally.hh"

View file

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

View file

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

View file

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