Skip to content

Add sandboxed building for FreeBSD using jails#9968

Merged
Ericson2314 merged 2 commits intoNixOS:masterfrom
rhelmot:freebsd
Mar 7, 2026
Merged

Add sandboxed building for FreeBSD using jails#9968
Ericson2314 merged 2 commits intoNixOS:masterfrom
rhelmot:freebsd

Conversation

@rhelmot
Copy link
Copy Markdown
Contributor

@rhelmot rhelmot commented Feb 8, 2024

Motivation

Build isolation is good! In Linux, this is accomplished with namespaces (containers). The equivalent technology on FreeBSD is jails.

Context

This is part of my ongoing project to make FreeBSD a first class citizen in the nix world.

This was a fairly simple patch, just needed to add parallel implementations for all the sandboxed Linux build pieces.

The most fragile part of this implementation is the fact that there is a lot of global state that gets set up in order to construct the jail - the chroot dir in the nix store, the nullfs mounts (the FreeBSD equivalent of a bind mount), and the jail ID itself. Lots of steps have been taken to make sure these all get cleaned up, both at the end of the build and at the start of any rebuilds. It seems to be resilient to interruption.

This has been live-fire tested with my fork of nixpkgs for FreeBSD. It is able to build the stdenv without issue.

Please squash-merge this PR! It includes some changes that were later reverted, which don’t belong in this repository but instead in the FreeBSD ports repository.

Priorities and Process

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@Ericson2314

This comment was marked as resolved.

@rhelmot

This comment was marked as resolved.

@Ericson2314

This comment was marked as resolved.

@edolstra

This comment was marked as resolved.

@Ericson2314

This comment was marked as resolved.

@rhelmot

This comment was marked as resolved.

@github-actions github-actions bot added the with-tests Issues related to testing. PRs with tests have some priority label Feb 9, 2024
@rhelmot rhelmot mentioned this pull request Feb 10, 2024
13 tasks
@Ericson2314

This comment was marked as resolved.

@rhelmot

This comment was marked as resolved.

@nixos-discourse
Copy link
Copy Markdown

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2024-02-12-nix-team-meeting-minutes-123/39775/1

@L-as

This comment was marked as resolved.

@Ericson2314

This comment was marked as resolved.

@Ericson2314

This comment was marked as resolved.

Ericson2314 added a commit that referenced this pull request May 27, 2025
This is the utility changes from #9968, which were easier to rebase
first.
Ericson2314 added a commit that referenced this pull request May 27, 2025
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>
@Ericson2314 Ericson2314 force-pushed the freebsd branch 5 times, most recently from 6e711ce to d1a4478 Compare May 27, 2025 20:19
@rhelmot
Copy link
Copy Markdown
Contributor Author

rhelmot commented Mar 6, 2026

I have redone the rebase, fixed a couple of terrible bugs, added a few new features (made the chroot cleanup a lot more bulletproof, made ^C work).

Should be ready.

@rhelmot
Copy link
Copy Markdown
Contributor Author

rhelmot commented Mar 6, 2026

From dogfooding, this refactor seems to have introduced some issues related to the cleanup stuff.

rhelmot and others added 2 commits March 6, 2026 22:37
The <() process substitution syntax doesn't work for this one testcase
in bash for FreeBSD. The exact reason for this is unknown, possibly to
do with pipe vs file vs fifo EOF behavior. The prior behavior was this
test hanging forever, with no children of the bash process.

Change-Id: I71822a4b9dea6059b34300568256c5b7848109ac

(cherry picked from commit ae628d4)
New FreeBSD sandboxes are based on jails and chroots.
They provide fairly similar capabilities to sandboxes on
Linux and allow for pure builds of FreeBSD nixpkgs.
Although it would also be possble to use jails for Linux
emulation, that is not supported with this commit.

Change-Id: I619e1e34c56de7aaa64a38408210a410bb13adba

Co-Authored-By: Artemis Tosini <me@artem.ist>
Co-Authored-By: John Ericson <John.Ericson@Obsidian.Systems>
@rhelmot
Copy link
Copy Markdown
Contributor Author

rhelmot commented Mar 7, 2026

Just kiddinggggggggggggg I was dogfooding the wrong branch. This works for me now.

Copy link
Copy Markdown
Contributor

@xokdvium xokdvium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds wonderful. Excited for this! I do have some nitpicks, but I'll not block this - I can do a follow-up with minor cleanup after the merge (once I dogfood this a bit too).

Comment on lines +161 to +162
PathFmt(user.home),
PathFmt(user.shell)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this doesn't seem right since PathFmt is meant for debug messages and adds quotes around the path. This should probably be .native() to just give you a string instead.

Comment on lines +286 to +289
struct stat stat_buf;
if (stat(i.second.source.c_str(), &stat_buf) < 0) {
throw SysError("stat");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a nix::stat helper nowadays.

Comment on lines +286 to +297
struct stat stat_buf;
if (stat(i.second.source.c_str(), &stat_buf) < 0) {
throw SysError("stat");
}

// mount points must exist and be the right type
if (S_ISDIR(stat_buf.st_mode)) {
createDirs(path);
} else {
createDirs(path.parent_path());
writeFile(path, "");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to follow symlinks in stat? Shouldn't this be lstat at least? Or maybe open(..., O_NOFOLLOW | O_PATH) + fstat?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is getting the stat of files to be nullfs mounted into the build sandbox, so the only time we would ever see a symlink is... if there were a derivation which realized to just a symlink? Is that even possible? I don't think that nullfs can bind symlinks like that, so I would probably want to check if it's a symlink upfront and if so implement it with another symlink rather than a mount.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there were a derivation which realized to just a symlink? Is that even possible?

Yes, we do it all the time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following symlinks is actually very bad for security. Any derivation can build a store object pointing to /etc/verysecretblahblah and the priviledged daemon would resolve it and put in the build sandbox. Not good

Comment on lines +281 to +283
if (i.second.source == "/proc") {
continue; // backwards compatibility
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be yeeted right, since freebsd doesn't have procfs (I'm no freebsd guru though).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FreeBSD does in fact have a procfs, though it is deprecated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but this back-compat is for nix's config itself, which we don't need to carry over from the linux builder.

Comment on lines +161 to +162
PathFmt(user.home),
PathFmt(user.shell)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PathFmt(user.home),
PathFmt(user.shell)));
user.home.native(),
user.shell.native()));

Comment on lines +123 to +124
for (size_t i = 0; i < users.size(); i++) {
auto user = users[i];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also work:

Suggested change
for (size_t i = 0; i < users.size(); i++) {
auto user = users[i];
for (const auto& [i, user]: enumerate(users)) {

@Ericson2314 Ericson2314 added this pull request to the merge queue Mar 7, 2026
@Ericson2314
Copy link
Copy Markdown
Member

Ericson2314 commented Mar 7, 2026

Let's indeed fix it after because this is a two year old PR that I had held up for so many things :)

(I do agree with all those build comments, though)

Merged via the queue into NixOS:master with commit b4bd8d3 Mar 7, 2026
15 checks passed
@github-project-automation github-project-automation bot moved this from 🏁 Review to Done in Nix team Mar 7, 2026
@xokdvium
Copy link
Copy Markdown
Contributor

xokdvium commented Mar 7, 2026

@rhelmot anyway, I'm doing some cleanup here and will put up a PR shortly once I make sure that this stuff still works after all my changes.

brittonr pushed a commit to brittonr/nix that referenced this pull request Apr 1, 2026
Add sandboxed building for FreeBSD using jails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation new-cli Relating to the "nix" command with-tests Issues related to testing. PRs with tests have some priority

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

8 participants