From afdd737c95e9672997280860099fcef960ffa102 Mon Sep 17 00:00:00 2001 From: Will Fancher Date: Fri, 4 Apr 2025 18:15:12 -0400 Subject: [PATCH 1/3] nixos/tests: Fix systemd-shutdown Since 459ddaec261ae40149601e5bb487bd52936b4e50, stdout of PID 1 and children such as systemd generators and systemd-shutdown scripts goes to `tty0` instead of `ttyS0`. This is because systemd's stdout is `/dev/console`, which represents only one tty at a time, as explained here: https://docs.kernel.org/admin-guide/serial-console.html The reason PID 1's own output makes it to both consoles is because it uses kmsg as its log target both before journald has started and once the `systemd-shutdown` executable takes control. Unlike `/dev/console`, kmsg output makes it to one console *of each type*, i.e. one VT and one serial console. --- nixos/tests/systemd-shutdown.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/tests/systemd-shutdown.nix b/nixos/tests/systemd-shutdown.nix index 1f072086bdd1..602ead50639e 100644 --- a/nixos/tests/systemd-shutdown.nix +++ b/nixos/tests/systemd-shutdown.nix @@ -17,7 +17,7 @@ import ./make-test-python.nix ( imports = [ ../modules/profiles/minimal.nix ]; systemd.shutdownRamfs.contents."/etc/systemd/system-shutdown/shutdown-message".source = pkgs.writeShellScript "shutdown-message" '' - echo "${msg}" + echo "${msg}" > /dev/kmsg ''; boot.initrd.systemd.enable = systemdStage1; }; From 93b98639dd185d141c6710f4b118805e82033541 Mon Sep 17 00:00:00 2001 From: sudoBash418 Date: Sat, 29 Mar 2025 22:50:50 -0600 Subject: [PATCH 2/3] make-initrd-ng: Restore stripped file permissions Previously, all initrd ELFs would be made *world-writable*. This commit sets the write bit for the file owner exclusively, and removes it when done. It also sets the umask so that files don't implicitly become writable for other users by mistake. Fixes: https://github.com/NixOS/nixpkgs/security/advisories/GHSA-m7pq-h9p4-8rr4 Reported-By: sudoBash418 --- .../kernel/make-initrd-ng/Cargo.lock | 9 ++++++++- .../kernel/make-initrd-ng/Cargo.toml | 1 + .../kernel/make-initrd-ng/src/main.rs | 17 ++++++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock b/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock index ce5f5ef00971..67f72276575e 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock +++ b/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "eyre" @@ -35,6 +35,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + [[package]] name = "log" version = "0.4.21" @@ -47,6 +53,7 @@ version = "0.1.0" dependencies = [ "eyre", "goblin", + "libc", "serde", "serde_json", ] diff --git a/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml b/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml index 69081b94d892..bdcdffd80195 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml +++ b/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml @@ -9,5 +9,6 @@ edition = "2018" [dependencies] eyre = "0.6.8" goblin = "0.5.0" +libc = "0.2.171" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/pkgs/build-support/kernel/make-initrd-ng/src/main.rs b/pkgs/build-support/kernel/make-initrd-ng/src/main.rs index 934c2faebed8..64c114f2d9fa 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/src/main.rs +++ b/pkgs/build-support/kernel/make-initrd-ng/src/main.rs @@ -5,9 +5,12 @@ use std::fs; use std::hash::Hash; use std::iter::FromIterator; use std::os::unix; +use std::os::unix::fs::PermissionsExt; use std::path::{Component, Path, PathBuf}; use std::process::Command; +use libc::umask; + use eyre::Context; use goblin::{elf::Elf, Object}; use serde::Deserialize; @@ -191,9 +194,9 @@ fn copy_file< let mut permissions = fs::metadata(&target) .wrap_err_with(|| format!("failed to get metadata for {:?}", target))? .permissions(); - permissions.set_readonly(false); - fs::set_permissions(&target, permissions) - .wrap_err_with(|| format!("failed to set readonly flag to false for {:?}", target))?; + permissions.set_mode(permissions.mode() | 0o200); + fs::set_permissions(&target, permissions.clone()) + .wrap_err_with(|| format!("failed to set read-write permissions for {:?}", target))?; // Strip further than normal if let Ok(strip) = env::var("STRIP") { @@ -207,6 +210,11 @@ fn copy_file< println!("{:?} was not successfully stripped.", OsStr::new(&target)); } } + + // Remove writable permissions + permissions.set_mode(permissions.mode() ^ 0o222); + fs::set_permissions(&target, permissions) + .wrap_err_with(|| format!("failed to remove writable permissions for {:?}", target))?; }; Ok(()) @@ -335,6 +343,9 @@ fn main() -> eyre::Result<()> { let output = &args[2]; let out_path = Path::new(output); + // The files we create should not be writable. + unsafe { umask(0o022) }; + let mut queue = NonRepeatingQueue::::new(); for sp in input { From c9ea864d6fd086f174321cc96a414bdb92490588 Mon Sep 17 00:00:00 2001 From: Will Fancher Date: Wed, 2 Apr 2025 15:56:28 -0400 Subject: [PATCH 3/3] nixos/shutdown: Create /run/initramfs with mode 0700 --- nixos/modules/system/boot/systemd/shutdown.nix | 1 + nixos/tests/systemd-shutdown.nix | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/nixos/modules/system/boot/systemd/shutdown.nix b/nixos/modules/system/boot/systemd/shutdown.nix index 1e8b8c6f863c..242b47cc40b1 100644 --- a/nixos/modules/system/boot/systemd/shutdown.nix +++ b/nixos/modules/system/boot/systemd/shutdown.nix @@ -52,6 +52,7 @@ in what = "tmpfs"; where = "/run/initramfs"; type = "tmpfs"; + options = "mode=0700"; } ]; diff --git a/nixos/tests/systemd-shutdown.nix b/nixos/tests/systemd-shutdown.nix index 602ead50639e..fa0105cb90cf 100644 --- a/nixos/tests/systemd-shutdown.nix +++ b/nixos/tests/systemd-shutdown.nix @@ -23,6 +23,8 @@ import ./make-test-python.nix ( }; testScript = '' + # Check that 'generate-shutdown-ramfs.service' is started + # automatically and that 'systemd-shutdown' runs our script. machine.wait_for_unit("multi-user.target") # .shutdown() would wait for the machine to power off machine.succeed("systemctl poweroff") @@ -31,6 +33,12 @@ import ./make-test-python.nix ( machine.wait_for_console_text("${msg}") # Don't try to sync filesystems machine.wait_for_shutdown() + + # In a separate boot, start 'generate-shutdown-ramfs.service' + # manually in order to check the permissions on '/run/initramfs'. + machine.systemctl("start generate-shutdown-ramfs.service") + stat = machine.succeed("stat --printf=%a:%u:%g /run/initramfs") + assert stat == "700:0:0", f"Improper permissions on /run/initramfs: {stat}" ''; } )