Skip to content

Commit

Permalink
stage-2-init: fix false positives for RO Nix store mounts (#375257)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 authored Feb 2, 2025
2 parents b97dde9 + 2f3a80c commit b29c6f5
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
3 changes: 2 additions & 1 deletion nixos/modules/system/boot/stage-2-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ fi
chown -f 0:30000 /nix/store
chmod -f 1775 /nix/store
if [ -n "@readOnlyNixStore@" ]; then
if ! [[ "$(findmnt --noheadings --output OPTIONS /nix/store)" =~ ro(,|$) ]]; then
# #375257: Ensure that we pick the "top" (i.e. last) mount so we don't get a false positive for a lower mount.
if ! [[ "$(findmnt --direction backward --first-only --noheadings --output OPTIONS /nix/store)" =~ (^|,)ro(,|$) ]]; then
if [ -z "$container" ]; then
mount --bind /nix/store /nix/store
else
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ in {
boot = handleTestOn ["x86_64-linux" "aarch64-linux"] ./boot.nix {};
bootspec = handleTestOn ["x86_64-linux"] ./bootspec.nix {};
boot-stage1 = handleTest ./boot-stage1.nix {};
boot-stage2 = handleTest ./boot-stage2.nix {};
borgbackup = handleTest ./borgbackup.nix {};
borgmatic = handleTest ./borgmatic.nix {};
botamusique = handleTest ./botamusique.nix {};
Expand Down
73 changes: 73 additions & 0 deletions nixos/tests/boot-stage2.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "boot-stage2";

nodes.machine =
{
config,
pkgs,
lib,
...
}:
{
virtualisation = {
emptyDiskImages = [ 256 ];

# Mount an ext4 as the upper layer of the Nix store.
fileSystems = {
"/nix/store" = lib.mkForce {
device = "/dev/vdb"; # the above disk image
fsType = "ext4";

# data=journal always displays after errors=remount-ro; this is only needed because of the overlay
# and #375257 will trigger with `errors=remount-ro` on a non-overlaid store:
# see ordering in https://github.com/torvalds/linux/blob/v6.12/fs/ext4/super.c#L2974
options = [
"defaults"
"errors=remount-ro"
"data=journal"
];
};
};
};

boot = {
initrd = {
# Format the upper Nix store.
postDeviceCommands = ''
${pkgs.e2fsprogs}/bin/mkfs.ext4 /dev/vdb
'';

# Overlay the RO store onto it.
# Note that bug #375257 can be triggered without an overlay,
# using the errors=remount-ro option (or similar) or with an overlay where any of the
# paths ends in 'ro'. The offending mountpoint also has to be the last (top) one
# if an option ending in 'ro' is the last in the list, so test both cases here.
postMountCommands = ''
mkdir -p /mnt-root/nix/store/ro /mnt-root/nix/store/rw /mnt-root/nix/store/work
mount --bind /mnt-root/nix/.ro-store /mnt-root/nix/store/ro
mount -t overlay overlay \
-o lowerdir=/mnt-root/nix/store/ro,upperdir=/mnt-root/nix/store/rw,workdir=/mnt-root/nix/store/work \
/mnt-root/nix/store
'';

kernelModules = [ "overlay" ];
};

postBootCommands = ''
touch /etc/post-boot-ran
mount
'';
};
};

testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("test /etc/post-boot-ran")
machine.fail("touch /nix/store/should-not-work");
'';

meta.maintainers = with pkgs.lib.maintainers; [ numinit ];
}
)

0 comments on commit b29c6f5

Please sign in to comment.