Skip to content

Conversation

andre4ik3
Copy link
Member

@andre4ik3 andre4ik3 commented Aug 11, 2025

Silences 2 warning messages that appear when using the systemd initrd:

  1. "System tainted (var-run-bad)": occurs because /var/run isn't a symlink to /run. Fixed by making /run and linking /var/run to it.

  2. "Failed to make /usr a mountpoint": occurs because ProtectSystem defaults to true in the initrd, which makes systemd try to remount /usr as read-only, which doesn't exist in the initrd. Fixed by linking /usr/bin and /usr/sbin to the initrd bin directories.

Also moves the /tmp creation from the initrd module to make-initrd-ng, to avoid making an unnecessary /tmp/.keep, saving a store path and a few bytes in the initrd image.

Things done

  • Built on platform:
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • Tested, as applicable:
  • Ran nixpkgs-review on this PR. See nixpkgs-review usage.
  • Tested basic functionality of all binary files, usually in ./result/bin/.
  • Nixpkgs Release Notes
    • Package update: when the change is major or breaking.
  • NixOS Release Notes
    • Module addition: when adding a new NixOS module.
    • Module update: when the change is significant.
  • Fits CONTRIBUTING.md, pkgs/README.md, maintainers/README.md and other READMEs.

Add a 👍 reaction to pull requests you find important.

@nixpkgs-ci nixpkgs-ci bot added 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 6.topic: systemd Software suite that provides an array of system components for Linux operating systems. labels Aug 11, 2025
@nix-owners nix-owners bot requested a review from philiptaron August 11, 2025 10:40
@nixpkgs-ci nixpkgs-ci bot added the 6.topic: kernel The Linux kernel label Aug 11, 2025
philiptaron
philiptaron previously approved these changes Aug 11, 2025
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

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

I like the solution to the first problem, but not the second.

Comment on lines 174 to 176
# Defaults to true in the initrd. Setting to false prevents systemd
# from attempting to remount a non-existent `/usr` as read-only.
ProtectSystem = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we do this instead of making an empty /usr?

Copy link
Member Author

Choose a reason for hiding this comment

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

My logic here was to prevent systemd from wasting time remounting it at all (since it would be empty anyway, it's not useful to remount it as read-only) instead of simply silencing it. But I'm happy to change it to create an empty /usr if that's better (or maybe do both?), since technically it's fewer characters of code.

Here is the relevant code in systemd, it doesn't check if /usr is empty and will always remount it, unless ProtectSystem disabled:

https://github.com/systemd/systemd/blob/5bd2538405660b10290bafdfa992a97970bffcc9/src/core/main.c#L1813-L1840

Copy link
Contributor

Choose a reason for hiding this comment

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

The main reason that I like making an empty /usr (and this is just me, the @NixOS/systemd team members might have a different opinion) is that ProtectSystem might gain other semantics beyond remounting usr as read-only. Making an empty /usr allows us to remain in the "default" zone with systemd settings.

Copy link
Member Author

Choose a reason for hiding this comment

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

After a few days thinking I will concede that making an empty /usr is better, like you said, to be more compatible with systemd defaults in the future. I updated it to do that instead.

@philiptaron philiptaron dismissed their stale review August 11, 2025 22:43

I meant to comment, not approve.

@nixpkgs-ci nixpkgs-ci bot added the 12.approvals: 1 This PR was reviewed and approved by one person. label Aug 15, 2025
Copy link
Contributor

@ElvishJerricco ElvishJerricco left a comment

Choose a reason for hiding this comment

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

Trying to build nixosTests.systemd-initrd-simple, it freezes immediately with systemd[1]: Freezing execution. Not sure why.

@andre4ik3
Copy link
Member Author

andre4ik3 commented Aug 15, 2025

Trying to build nixosTests.systemd-initrd-simple, it freezes immediately with systemd[1]: Freezing execution. Not sure why.

Interesting. I ran the test for ProtectSystem=false but not for making an empty /usr, since I assumed (wrongly) it would work. Perhaps making an empty /usr won't work after all. I'll revert it back to the previous approach.

The "Freezing execution" means systemd crashed. It looks like it does make /usr read-only successfully, so something later must behave differently when ProtectSystem takes effect which causes it to crash:

machine # [    2.532235] Run /init as init process
machine # [    2.653999] input: QEMU QEMU USB Keyboard as /devices/platform/4010000000.pcie/pci0000:00/0000:00:0a.0/usb1/1-1/1-1:1.0/0003:0627:0001.0001/input/input1
machine # [    2.661354] systemd[1]: Successfully made /usr/ read-only.
machine # [    2.671333] systemd[1]: systemd 257.6 running in system mode (+PAM +AUDIT -SELINUX +APPARMOR +IMA +IPE +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK -BTF -XKBCOMMON +UTMP -SYSVINIT +LIBARCHIVE)
machine # [    2.672085] systemd[1]: Detected virtualization qemu.
machine # [    2.672391] systemd[1]: Detected architecture arm64.
machine # [    2.672640] systemd[1]: Running in initrd.
machine # [    2.676972] systemd[1]: Freezing execution.

@ElvishJerricco
Copy link
Contributor

ElvishJerricco commented Aug 16, 2025

Found the issue. We set console=tty0 in the test framework, which means a lot of super early systemd messages get swallowed. In principle this is supposed to be ok because we redirect the journal to the serial console, but in this case the error is too early for the journal to have started. That error says:

[!!!!!!] Refusing to run in unsupported envi…ment where /usr/ is not populated.

So this fixes it.

diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index 394cbb487b..ffce5e7e0d 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -506,6 +506,8 @@
 
         "/bin".source = "${initrdBinEnv}/bin";
         "/sbin".source = "${initrdBinEnv}/sbin";
+        "/usr/bin".source = "${initrdBinEnv}/bin";
+        "/usr/sbin".source = "${initrdBinEnv}/sbin";
 
         "/etc/sysctl.d/nixos.conf".text = "kernel.modprobe = /sbin/modprobe";
         "/etc/modprobe.d/systemd.conf".source = "${cfg.package}/lib/modprobe.d/systemd.conf";
diff --git a/pkgs/build-support/kernel/make-initrd-ng.nix b/pkgs/build-support/kernel/make-initrd-ng.nix
index e0a415a09b..35fd66e89d 100644
--- a/pkgs/build-support/kernel/make-initrd-ng.nix
+++ b/pkgs/build-support/kernel/make-initrd-ng.nix
@@ -100,7 +100,7 @@
     ++ lib.optional makeUInitrd ubootTools;
   })
   ''
-    mkdir -p ./root/{run,tmp,usr,var/empty}
+    mkdir -p ./root/{run,tmp,var/empty}
     ln -s ../run ./root/var/run
     make-initrd-ng "$contentsPath" ./root
     mkdir "$out"

@andre4ik3
Copy link
Member Author

Interesting that an unpopulated /usr is explicitly unsupported but a nonexistent one isn't. Looking at the code, it seems it was done as a safeguard to ensure it's either mounted or on the same partition as the root.

Silences 2 warning messages that appear when using the systemd initrd:

1. "System tainted (var-run-bad)": occurs because `/var/run` isn't a
   symlink to `/run`. Fixed by making /run and linking /var/run to it.

2. "Failed to make /usr a mountpoint": occurs because ProtectSystem
   defaults to true in the initrd, which makes systemd try to remount
   `/usr` as read-only, which doesn't exist in the initrd. Fixed by
   linking `/usr/bin` and `/usr/sbin` to the initrd bin directories.

Also moves the `/tmp` creation from the initrd module to make-initrd-ng,
to avoid making an unnecessary `/tmp/.keep`, saving a store path and a
few bytes in the initrd image.
@nixpkgs-ci nixpkgs-ci bot added 12.approvals: 2 This PR was reviewed and approved by two persons. and removed 12.approvals: 1 This PR was reviewed and approved by one person. labels Aug 16, 2025
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

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

Thanks for figuring this out!

@philiptaron philiptaron merged commit 54a65ab into NixOS:master Aug 28, 2025
29 of 30 checks passed
@andre4ik3 andre4ik3 deleted the initrd-var-run branch August 29, 2025 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: kernel The Linux kernel 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 6.topic: systemd Software suite that provides an array of system components for Linux operating systems. 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 12.approvals: 2 This PR was reviewed and approved by two persons.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants