Merge pull request #305845 from abathur/resholve_0.10.5
[NixPkgs.git] / nixos / tests / boot-stage1.nix
blobf07802b8c31e3e436c5114ee8010b4682135b91f
1 import ./make-test-python.nix ({ pkgs, ... }: {
2   name = "boot-stage1";
4   nodes.machine = { config, pkgs, lib, ... }: {
5     boot.extraModulePackages = let
6       compileKernelModule = name: source: pkgs.runCommandCC name rec {
7         inherit source;
8         kdev = config.boot.kernelPackages.kernel.dev;
9         kver = config.boot.kernelPackages.kernel.modDirVersion;
10         ksrc = "${kdev}/lib/modules/${kver}/build";
11         hardeningDisable = [ "pic" ];
12         nativeBuildInputs = kdev.moduleBuildDependencies;
13       } ''
14         echo "obj-m += $name.o" > Makefile
15         echo "$source" > "$name.c"
16         make -C "$ksrc" M=$(pwd) modules
17         install -vD "$name.ko" "$out/lib/modules/$kver/$name.ko"
18       '';
20       # This spawns a kthread which just waits until it gets a signal and
21       # terminates if that is the case. We want to make sure that nothing during
22       # the boot process kills any kthread by accident, like what happened in
23       # issue #15226.
24       kcanary = compileKernelModule "kcanary" ''
25         #include <linux/version.h>
26         #include <linux/init.h>
27         #include <linux/module.h>
28         #include <linux/kernel.h>
29         #include <linux/kthread.h>
30         #include <linux/sched.h>
31         #include <linux/signal.h>
32         #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
33         #include <linux/sched/signal.h>
34         #endif
36         MODULE_LICENSE("GPL");
38         struct task_struct *canaryTask;
40         static int kcanary(void *nothing)
41         {
42           allow_signal(SIGINT);
43           allow_signal(SIGTERM);
44           allow_signal(SIGKILL);
45           while (!kthread_should_stop()) {
46             set_current_state(TASK_INTERRUPTIBLE);
47             schedule_timeout_interruptible(msecs_to_jiffies(100));
48             if (signal_pending(current)) break;
49           }
50           return 0;
51         }
53         static int kcanaryInit(void)
54         {
55           kthread_run(&kcanary, NULL, "kcanary");
56           return 0;
57         }
59         static void kcanaryExit(void)
60         {
61           kthread_stop(canaryTask);
62         }
64         module_init(kcanaryInit);
65         module_exit(kcanaryExit);
66       '';
68     in lib.singleton kcanary;
70     boot.initrd.kernelModules = [ "kcanary" ];
72     boot.initrd.extraUtilsCommands = let
73       compile = name: source: pkgs.runCommandCC name { inherit source; } ''
74         mkdir -p "$out/bin"
75         echo "$source" | gcc -Wall -o "$out/bin/$name" -xc -
76       '';
78       daemonize = name: source: compile name ''
79         #include <stdio.h>
80         #include <unistd.h>
82         void runSource(void) {
83         ${source}
84         }
86         int main(void) {
87           if (fork() > 0) return 0;
88           setsid();
89           runSource();
90           return 1;
91         }
92       '';
94       mkCmdlineCanary = { name, cmdline ? "", source ? "" }: (daemonize name ''
95         char *argv[] = {"${cmdline}", NULL};
96         execvp("${name}-child", argv);
97       '') // {
98         child = compile "${name}-child" ''
99           #include <stdio.h>
100           #include <unistd.h>
102           int main(void) {
103             ${source}
104             while (1) sleep(1);
105             return 1;
106           }
107         '';
108       };
110       copyCanaries = lib.concatMapStrings (canary: ''
111         ${lib.optionalString (canary ? child) ''
112           copy_bin_and_libs "${canary.child}/bin/${canary.child.name}"
113         ''}
114         copy_bin_and_libs "${canary}/bin/${canary.name}"
115       '');
117     in copyCanaries [
118       # Simple canary process which just sleeps forever and should be killed by
119       # stage 2.
120       (daemonize "canary1" "while (1) sleep(1);")
122       # We want this canary process to try mimicking a kthread using a cmdline
123       # with a zero length so we can make sure that the process is properly
124       # killed in stage 1.
125       (mkCmdlineCanary {
126         name = "canary2";
127         source = ''
128           FILE *f;
129           f = fopen("/run/canary2.pid", "w");
130           fprintf(f, "%d\n", getpid());
131           fclose(f);
132         '';
133       })
135       # This canary process mimics a storage daemon, which we do NOT want to be
136       # killed before going into stage 2. For more on root storage daemons, see:
137       # https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
138       (mkCmdlineCanary {
139         name = "canary3";
140         cmdline = "@canary3";
141       })
142     ];
144     boot.initrd.postMountCommands = ''
145       canary1
146       canary2
147       canary3
148       # Make sure the pidfile of canary 2 is created so that we still can get
149       # its former pid after the killing spree starts next within stage 1.
150       while [ ! -s /run/canary2.pid ]; do sleep 0.1; done
151     '';
152   };
154   testScript = ''
155     machine.wait_for_unit("multi-user.target")
156     machine.succeed("test -s /run/canary2.pid")
157     machine.fail("pgrep -a canary1")
158     machine.fail("kill -0 $(< /run/canary2.pid)")
159     machine.succeed('pgrep -a -f "^@canary3$"')
160     machine.succeed('pgrep -a -f "^kcanary$"')
161   '';
163   meta.maintainers = with pkgs.lib.maintainers; [ aszlig ];