]>
Commit | Line | Data |
---|---|---|
93f59100 LP |
1 | --- |
2 | title: Random Seeds | |
4cdca0af | 3 | category: Concepts |
b41a3f66 | 4 | layout: default |
93f59100 LP |
5 | --- |
6 | ||
7 | # Random Seeds | |
8 | ||
9 | systemd can help in a number of ways with providing reliable, high quality | |
10 | random numbers from early boot on. | |
11 | ||
12 | ## Linux Kernel Entropy Pool | |
13 | ||
14 | Today's computer systems require random number generators for numerous | |
15 | cryptographic and other purposes. On Linux systems, the kernel's entropy pool | |
16 | is typically used as high-quality source of random numbers. The kernel's | |
17 | entropy pool combines various entropy inputs together, mixes them and provides | |
18 | an API to userspace as well as to internal kernel subsystems to retrieve | |
19 | it. This entropy pool needs to be initialized with a minimal level of entropy | |
20 | before it can provide high quality, cryptographic random numbers to | |
21 | applications. Until the entropy pool is fully initialized application requests | |
22 | for high-quality random numbers cannot be fulfilled. | |
23 | ||
24 | The Linux kernel provides three relevant userspace APIs to request random data | |
25 | from the kernel's entropy pool: | |
26 | ||
27 | * The [`getrandom()`](http://man7.org/linux/man-pages/man2/getrandom.2.html) | |
28 | system call with its `flags` parameter set to 0. If invoked the calling | |
29 | program will synchronously block until the random pool is fully initialized | |
30 | and the requested bytes can be provided. | |
31 | ||
32 | * The `getrandom()` system call with its `flags` parameter set to | |
33 | `GRND_NONBLOCK`. If invoked the request for random bytes will fail if the | |
34 | pool is not initialized yet. | |
35 | ||
36 | * Reading from the | |
37 | [`/dev/urandom`](http://man7.org/linux/man-pages/man4/urandom.4.html) | |
38 | pseudo-device will always return random bytes immediately, even if the pool | |
39 | is not initialized. The provided random bytes will be of low quality in this | |
40 | case however. Moreover the kernel will log about all programs using this | |
41 | interface in this state, and which thus potentially rely on an uninitialized | |
42 | entropy pool. | |
43 | ||
44 | (Strictly speaking there are more APIs, for example `/dev/random`, but these | |
45 | should not be used by almost any application and hence aren't mentioned here.) | |
46 | ||
47 | Note that the time it takes to initialize the random pool may differ between | |
48 | systems. If local hardware random number generators are available, | |
49 | initialization is likely quick, but particularly in embedded and virtualized | |
50 | environments available entropy is small and thus random pool initialization | |
51 | might take a long time (up to tens of minutes!). | |
52 | ||
53 | Modern hardware tends to come with a number of hardware random number | |
54 | generators (hwrng), that may be used to relatively quickly fill up the entropy | |
55 | pool. Specifically: | |
56 | ||
57 | * All recent Intel and AMD CPUs provide the CPU opcode | |
58 | [RDRAND](https://en.wikipedia.org/wiki/RdRand) to acquire random bytes. Linux | |
59 | includes random bytes generated this way in its entropy pool, but didn't use | |
60 | to credit entropy for it (i.e. data from this source wasn't considered good | |
61 | enough to consider the entropy pool properly filled even though it was | |
62 | used). This has changed recently however, and most big distributions have | |
63 | turned on the `CONFIG_RANDOM_TRUST_CPU=y` kernel compile time option. This | |
64 | means systems with CPUs supporting this opcode will be able to very quickly | |
65 | reach the "pool filled" state. | |
66 | ||
67 | * The TPM security chip that is available on all modern desktop systems has a | |
68 | hwrng. It is also fed into the entropy pool, but generally not credited | |
69 | entropy. You may use `rng_core.default_quality=1000` on the kernel command | |
70 | line to change that, but note that this is a global setting affect all | |
71 | hwrngs. (Yeah, that's weird.) | |
72 | ||
73 | * Many Intel and AMD chipsets have hwrng chips. Their Linux drivers usually | |
74 | don't credit entropy. (But there's `rng_core.default_quality=1000`, see | |
75 | above.) | |
76 | ||
77 | * Various embedded boards have hwrng chips. Some drivers automatically credit | |
78 | entropy, others do not. Some WiFi chips appear to have hwrng sources too, and | |
79 | they usually do not credit entropy for them. | |
80 | ||
81 | * `virtio-rng` is used in virtualized environments and retrieves random data | |
82 | from the VM host. It credits full entropy. | |
83 | ||
84 | * The EFI firmware typically provides a RNG API. When transitioning from UEFI | |
85 | to kernel mode Linux will query some random data through it, and feed it into | |
86 | the pool, but not credit entropy to it. What kind of random source is behind | |
87 | the EFI RNG API is often not entirely clear, but it hopefully is some kind of | |
88 | hardware source. | |
89 | ||
90 | If neither of these are available (in fact, even if they are), Linux generates | |
91 | entropy from various non-hwrng sources in various subsystems, all of which | |
92 | ultimately are rooted in IRQ noise, a very "slow" source of entropy, in | |
93 | particular in virtualized environments. | |
94 | ||
95 | ## `systemd`'s Use of Random Numbers | |
96 | ||
97 | systemd is responsible for bringing up the OS. It generally runs as the first | |
98 | userspace process the kernel invokes. Because of that it runs at a time where | |
99 | the entropy pool is typically not yet initialized, and thus requests to acquire | |
100 | random bytes will either be delayed, will fail or result in a noisy kernel log | |
101 | message (see above). | |
102 | ||
103 | Various other components run during early boot that require random bytes. For | |
104 | example, initial RAM disks nowadays communicate with encrypted networks or | |
105 | access encrypted storage which might need random numbers. systemd itself | |
106 | requires random numbers as well, including for the following uses: | |
107 | ||
108 | * systemd assigns 'invocation' UUIDs to all services it invokes that uniquely | |
109 | identify each invocation. This is useful retain a global handle on a specific | |
110 | service invocation and relate it to other data. For example, log data | |
111 | collected by the journal usually includes the invocation UUID and thus the | |
112 | runtime context the service manager maintains can be neatly matched up with | |
113 | the log data a specific service invocation generated. systemd also | |
114 | initializes `/etc/machine-id` with a randomized UUID. (systemd also makes use | |
115 | of the randomized "boot id" the kernel exposes in | |
116 | `/proc/sys/kernel/random/boot_id`). These UUIDs are exclusively Type 4 UUIDs, | |
117 | i.e. randomly generated ones. | |
118 | ||
119 | * systemd maintains various hash tables internally. In order to harden them | |
120 | against [collision | |
21385e63 | 121 | attacks](https://www.cs.auckland.ac.nz/~mcw/Teaching/refs/misc/denial-of-service.pdf) |
93f59100 LP |
122 | they are seeded with random numbers. |
123 | ||
124 | * At various places systemd needs random bytes for temporary file name | |
125 | generation, UID allocation randomization, and similar. | |
126 | ||
127 | * systemd-resolved and systemd-networkd use random number generators to harden | |
128 | the protocols they implement against packet forgery. | |
129 | ||
130 | * systemd-udevd and systemd-nspawn can generate randomized MAC addresses for | |
131 | network devices. | |
132 | ||
133 | Note that these cases generally do not require a cryptographic-grade random | |
134 | number generator, as most of these utilize random numbers to minimize risk of | |
135 | collision and not to generate secret key material. However, they usually do | |
136 | require "medium-grade" random data. For example: systemd's hash-maps are | |
137 | reseeded if they grow beyond certain thresholds (and thus collisions are more | |
138 | likely). This means they are generally fine with low-quality (even constant) | |
139 | random numbers initially as long as they get better with time, so that | |
140 | collision attacks are eventually thwarted as better, non-guessable seeds are | |
141 | acquired. | |
142 | ||
143 | ## Keeping `systemd'`s Demand on the Kernel Entropy Pool Minimal | |
144 | ||
145 | Since most of systemd's own use of random numbers do not require | |
146 | cryptographic-grade RNGs, it tries to avoid reading entropy from the kernel | |
147 | entropy pool if possible. If it succeeds this has the benefit that there's no | |
148 | need to delay the early boot process until entropy is available, and noisy | |
149 | kernel log messages about early reading from `/dev/urandom` are avoided | |
150 | too. Specifically: | |
151 | ||
152 | 1. When generating [Type 4 | |
153 | UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_\(random\)), | |
154 | systemd tries to use Intel's and AMD's RDRAND CPU opcode directly, if | |
155 | available. While some doubt the quality and trustworthiness of the entropy | |
156 | provided by these opcodes, they should be good enough for generating UUIDs, | |
157 | if not key material (though, as mentioned, today's big distributions opted | |
158 | to trust it for that too, now, see above — but we are not going to make that | |
159 | decision for you, and for anything key material related will only use the | |
160 | kernel's entropy pool). If RDRAND is not available or doesn't work, it will | |
161 | use synchronous `getrandom()` as fallback, and `/dev/urandom` on old kernels | |
162 | where that system call doesn't exist yet. This means on non-Intel/AMD | |
163 | systems UUID generation will block on kernel entropy initialization. | |
164 | ||
165 | 2. For seeding hash tables, and all the other similar purposes systemd first | |
166 | tries RDRAND, and if that's not available will try to use asynchronous | |
167 | `getrandom()` (if the kernel doesn't support this system call, | |
168 | `/dev/urandom` is used). This may fail too in case the pool is not | |
169 | initialized yet, in which case it will fall back to glibc's internal rand() | |
170 | calls, i.e. weak pseudo-random numbers. This should make sure we use good | |
171 | random bytes if we can, but neither delay boot nor trigger noisy kernel log | |
172 | messages during early boot for these use-cases. | |
173 | ||
174 | ## `systemd`'s Support for Filling the Kernel Entropy Pool | |
175 | ||
176 | systemd has various provisions to ensure the kernel entropy is filled during | |
177 | boot, in order to ensure the entropy pool is filled up quickly. | |
178 | ||
179 | 1. When systemd's PID 1 detects it runs in a virtualized environment providing | |
180 | the `virtio-rng` interface it will load the necessary kernel modules to make | |
181 | use of it during earliest boot, if possible — much earlier than regular | |
182 | kernel module loading done by `systemd-udevd.service`. This should ensure | |
183 | that in VM environments the entropy pool is quickly filled, even before | |
184 | systemd invokes the first service process — as long as the VM environment | |
185 | provides virtualized RNG hardware (and VM environments really should!). | |
186 | ||
187 | 2. The | |
188 | [`systemd-random-seed.service`](https://www.freedesktop.org/software/systemd/man/systemd-random-seed.service.html) | |
189 | system service will load a random seed from `/var/lib/systemd/random-seed` | |
190 | into the kernel entropy pool. By default it does not credit entropy for it | |
191 | though, since the seed is — more often than not — not reset when 'golden' | |
192 | master images of an OS are created, and thus replicated into every | |
193 | installation. If OS image builders carefully reset the random seed file | |
194 | before generating the image it should be safe to credit entropy, which can | |
d35c7741 LP |
195 | be enabled by setting the `$SYSTEMD_RANDOM_SEED_CREDIT` environment variable |
196 | for the service to `1` (or even `force`, see man page). Note however, that | |
197 | this service typically runs relatively late during early boot: long after | |
198 | the initial RAM disk (`initrd`) completed, and after the `/var/` file system | |
199 | became writable. This is usually too late for many applications, it is hence | |
200 | not advised to rely exclusively on this functionality to seed the kernel's | |
93f59100 LP |
201 | entropy pool. Also note that this service synchronously waits until the |
202 | kernel's entropy pool is initialized before completing start-up. It may thus | |
203 | be used by other services as synchronization point to order against, if they | |
204 | require an initialized entropy pool to operate correctly. | |
205 | ||
206 | 3. The | |
207 | [`systemd-boot`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html) | |
208 | EFI boot loader included in systemd is able to maintain and provide a random | |
209 | seed stored in the EFI System Partition (ESP) to the booted OS, which allows | |
210 | booting up with a fully initialized entropy pool from earliest boot | |
211 | on. During installation of the boot loader (or when invoking [`bootctl | |
212 | random-seed`](https://www.freedesktop.org/software/systemd/man/bootctl.html#random-seed)) | |
213 | a seed file with an initial seed is placed in a file `/loader/random-seed` | |
214 | in the ESP. In addition, an identically sized randomized EFI variable called | |
37b22b3b ZJS |
215 | the 'system token' is set, which is written to the machine's firmware NVRAM. |
216 | During boot, when `systemd-boot` finds both the random seed file and the | |
217 | system token they are combined and hashed with SHA256 (in counter mode, to | |
218 | generate sufficient data), to generate a new random seed file to store in | |
93f59100 LP |
219 | the ESP as well as a random seed to pass to the OS kernel. The new random |
220 | seed file for the ESP is then written to the ESP, ensuring this is completed | |
221 | before the OS is invoked. Very early during initialization PID 1 will read | |
222 | the random seed provided in the EFI variable and credit it fully to the | |
223 | kernel's entropy pool. | |
224 | ||
225 | This mechanism is able to safely provide an initialized entropy pool already | |
226 | in the `initrd` and guarantees that different seeds are passed from the boot | |
227 | loader to the OS on every boot (in a way that does not allow regeneration of | |
228 | an old seed file from a new seed file). Moreover, when an OS image is | |
229 | replicated between multiple images and the random seed is not reset, this | |
230 | will still result in different random seeds being passed to the OS, as the | |
231 | per-machine 'system token' is specific to the physical host, and not | |
232 | included in OS disk images. If the 'system token' is properly initialized | |
233 | and kept sufficiently secret it should not be possible to regenerate the | |
234 | entropy pool of different machines, even if this seed is the only source of | |
235 | entropy. | |
236 | ||
237 | Note that the writes to the ESP needed to maintain the random seed should be | |
238 | minimal. The size of the random seed file is directly derived from the Linux | |
239 | kernel's entropy pool size, which defaults to 512 bytes. This means updating | |
240 | the random seed in the ESP should be doable safely with a single sector | |
241 | write (since hard-disk sectors typically happen to be 512 bytes long, too), | |
242 | which should be safe even with FAT file system drivers built into | |
243 | low-quality EFI firmwares. | |
244 | ||
245 | As a special restriction: in virtualized environments PID 1 will refrain | |
246 | from using this mechanism, for safety reasons. This is because on VM | |
247 | environments the EFI variable space and the disk space is generally not | |
248 | maintained physically separate (for example, `qemu` in EFI mode stores the | |
249 | variables in the ESP itself). The robustness towards sloppy OS image | |
250 | generation is the main purpose of maintaining the 'system token' however, | |
251 | and if the EFI variable storage is not kept physically separate from the OS | |
252 | image there's no point in it. That said, OS builders that know that they are | |
253 | not going to replicate the built image on multiple systems may opt to turn | |
254 | off the 'system token' concept by setting `random-seed-mode always` in the | |
255 | ESP's | |
256 | [`/loader/loader.conf`](https://www.freedesktop.org/software/systemd/man/loader.conf.html) | |
257 | file. If done, `systemd-boot` will use the random seed file even if no | |
258 | system token is found in EFI variables. | |
259 | ||
18d9cee0 LP |
260 | 4. A kernel command line option `systemd.random_seed=` may be used to pass in a |
261 | base64 encoded seed to initialize the kernel's entropy pool from during | |
262 | early service manager initialization. This option is only safe in testing | |
263 | environments, as the random seed passed this way is accessible to | |
264 | unprivileged programs via `/proc/cmdline`. Using this option outside of | |
265 | testing environments is a security problem since cryptographic key material | |
266 | derived from the entropy pool initialized with a seed accessible to | |
267 | unprivileged programs should not be considered secret. | |
268 | ||
269 | With the four mechanisms described above it should be possible to provide | |
93f59100 LP |
270 | early-boot entropy in most cases. Specifically: |
271 | ||
272 | 1. On EFI systems, `systemd-boot`'s random seed logic should make sure good | |
273 | entropy is available during earliest boot — as long as `systemd-boot` is | |
274 | used as boot loader, and outside of virtualized environments. | |
275 | ||
276 | 2. On virtualized systems, the early `virtio-rng` hookup should ensure entropy | |
277 | is available early on — as long as the VM environment provides virtualized | |
278 | RNG devices, which they really should all do in 2019. Complain to your | |
18d9cee0 LP |
279 | hosting provider if they don't. For VMs used in testing environments, |
280 | `systemd.random_seed=` may be used as an alternative to a virtualized RNG. | |
93f59100 LP |
281 | |
282 | 3. On Intel/AMD systems systemd's own reliance on the kernel entropy pool is | |
283 | minimal (as RDRAND is used on those for UUID generation). This only works if | |
284 | the CPU has RDRAND of course, which most physical CPUs do (but I hear many | |
285 | virtualized CPUs do not. Pity.) | |
286 | ||
287 | 4. In all other cases, `systemd-random-seed.service` will help a bit, but — as | |
288 | mentioned — is too late to help with early boot. | |
289 | ||
290 | This primarily leaves two kind of systems in the cold: | |
291 | ||
292 | 1. Some embedded systems. Many embedded chipsets have hwrng functionality these | |
293 | days. Consider using them while crediting | |
294 | entropy. (i.e. `rng_core.default_quality=1000` on the kernel command line is | |
295 | your friend). Or accept that the system might take a bit longer to | |
296 | boot. Alternatively, consider implementing a solution similar to | |
297 | systemd-boot's random seed concept in your platform's boot loader. | |
298 | ||
18d9cee0 LP |
299 | 2. Virtualized environments that lack both virtio-rng and RDRAND, outside of |
300 | test environments. Tough luck. Talk to your hosting provider, and ask them | |
301 | to fix this. | |
93f59100 LP |
302 | |
303 | 3. Also note: if you deploy an image without any random seed and/or without | |
304 | installing any 'system token' in an EFI variable, as described above, this | |
305 | means that on the first boot no seed can be passed to the OS | |
306 | either. However, as the boot completes (with entropy acquired elsewhere), | |
307 | systemd will automatically install both a random seed in the GPT and a | |
308 | 'system token' in the EFI variable space, so that any future boots will have | |
309 | entropy from earliest boot on — all provided `systemd-boot` is used. | |
310 | ||
311 | ## Frequently Asked Questions | |
312 | ||
313 | 1. *Why don't you just use getrandom()? That's all you need!* | |
314 | ||
315 | Did you read any of the above? getrandom() is hooked to the kernel entropy | |
316 | pool, and during early boot it's not going to be filled yet, very likely. We | |
317 | do use it in many cases, but not in all. Please read the above again! | |
318 | ||
319 | 2. *Why don't you use | |
320 | [getentropy()](http://man7.org/linux/man-pages/man3/getentropy.3.html)? That's | |
321 | all you need!* | |
322 | ||
323 | Same story. That call is just a different name for `getrandom()` with | |
324 | `flags` set to zero, and some additional limitations, and thus it also needs | |
325 | the kernel's entropy pool to be initialized, which is the whole problem we | |
326 | are trying to address here. | |
327 | ||
328 | 3. *Why don't you generate your UUIDs with | |
329 | [`uuidd`](http://man7.org/linux/man-pages/man8/uuidd.8.html)? That's all you | |
330 | need!* | |
331 | ||
332 | First of all, that's a system service, i.e. something that runs as "payload" | |
333 | of systemd, long after systemd is already up and hence can't provide us | |
334 | UUIDs during earliest boot yet. Don't forget: to assign the invocation UUID | |
335 | for the `uuidd.service` start we already need a UUID that the service is | |
336 | supposed to provide us. More importantly though, `uuidd` needs state/a random | |
337 | seed/a MAC address/host ID to operate, all of which are not available during | |
338 | early boot. | |
339 | ||
340 | 4. *Why don't you generate your UUIDs with `/proc/sys/kernel/random/uuid`? | |
341 | That's all you need!* | |
342 | ||
343 | This is just a different, more limited interface to `/dev/urandom`. It gains | |
344 | us nothing. | |
345 | ||
346 | 5. *Why don't you use [`rngd`](https://github.com/nhorman/rng-tools), | |
347 | [`haveged`](http://www.issihosts.com/haveged/), | |
348 | [`egd`](http://egd.sourceforge.net/)? That's all you need!* | |
349 | ||
350 | Like `uuidd` above these are system services, hence come too late for our | |
351 | use-case. In addition much of what `rngd` provides appears to be equivalent | |
352 | to `CONFIG_RANDOM_TRUST_CPU=y` or `rng_core.default_quality=1000`, except | |
353 | being more complex and involving userspace. These services partly measure | |
354 | system behavior (such as scheduling effects) which the kernel either | |
355 | already feeds into its pool anyway (and thus shouldn't be fed into it a | |
356 | second time, crediting entropy for it a second time) or is at least | |
357 | something the kernel could much better do on its own. Hence, if what these | |
358 | daemons do is still desirable today, this would be much better implemented | |
359 | in kernel (which would be very welcome of course, but wouldn't really help | |
360 | us here in our specific problem, see above). | |
361 | ||
362 | 6. *Why don't you use [`arc4random()`](https://man.openbsd.org/arc4random.3)? | |
363 | That's all you need!* | |
364 | ||
365 | This doesn't solve the issue, since it requires a nonce to start from, and | |
366 | it gets that from `getrandom()`, and thus we have to wait for random pool | |
367 | initialization the same way as calling `getrandom()` | |
368 | directly. `arc4random()` is nothing more than optimization, in fact it | |
369 | implements similar algorithms that the kernel entropy pool implements | |
370 | anyway, hence besides being able to provide random bytes with higher | |
371 | throughput there's little it gets us over just using `getrandom()`. Also, | |
372 | it's not supported by glibc. And as long as that's the case we are not keen | |
373 | on using it, as we'd have to maintain that on our own, and we don't want to | |
374 | maintain our own cryptographic primitives if we don't have to. Since | |
375 | systemd's uses are not performance relevant (besides the pool initialization | |
376 | delay, which this doesn't solve), there's hence little benefit for us to | |
377 | call these functions. That said, if glibc learns these APIs one day, we'll | |
378 | certainly make use of them where appropriate. | |
379 | ||
380 | 7. *This is boring: NetBSD had [boot loader entropy seed | |
381 | support](https://netbsd.gw.com/cgi-bin/man-cgi?boot+8) since ages!* | |
382 | ||
383 | Yes, NetBSD has that, and the above is inspired by that (note though: this | |
384 | article is about a lot more than that). NetBSD's support is not really safe, | |
385 | since it neither updates the random seed before using it, nor has any | |
386 | safeguards against replicating the same disk image with its random seed on | |
387 | multiple machines (which the 'system token' mentioned above is supposed to | |
388 | address). This means reuse of the same random seed by the boot loader is | |
389 | much more likely. | |
390 | ||
391 | 8. *Why does PID 1 upload the boot loader provided random seed into kernel | |
392 | instead of kernel doing that on its own?* | |
393 | ||
394 | That's a good question. Ideally the kernel would do that on its own, and we | |
395 | wouldn't have to involve userspace in this. | |
396 | ||
397 | 9. *What about non-EFI?* | |
398 | ||
399 | The boot loader random seed logic described above uses EFI variables to pass | |
400 | the seed from the boot loader to the OS. Other systems might have similar | |
401 | functionality though, and it shouldn't be too hard to implement something | |
402 | similar for them. Ideally, we'd have an official way to pass such a seed as | |
403 | part of the `struct boot_params` from the boot loader to the kernel, but | |
404 | this is currently not available. | |
405 | ||
406 | 10. *I use a different boot loader than `systemd-boot`, I'd like to use boot | |
407 | loader random seeds too!* | |
408 | ||
409 | Well, consider just switching to `systemd-boot`, it's worth it. See | |
410 | [systemd-boot(7)](https://www.freedesktop.org/software/systemd/man/systemd-boot.html) | |
411 | for an introduction why. That said, any boot loader can re-implement the | |
412 | logic described above, and can pass a random seed that systemd as PID 1 | |
413 | will then upload into the kernel's entropy pool. For details see the [Boot | |
414 | Loader Interface](https://systemd.io/BOOT_LOADER_INTERFACE) documentation. | |
415 | ||
416 | 11. *Why not pass the boot loader random seed via kernel command line instead | |
417 | of as EFI variable?* | |
418 | ||
419 | The kernel command line is accessible to unprivileged processes via | |
420 | `/proc/cmdline`. It's not desirable if unprivileged processes can use this | |
421 | information to possibly gain too much information about the current state | |
422 | of the kernel's entropy pool. | |
423 | ||
18d9cee0 LP |
424 | That said, we actually do implement this with the `systemd.random_seed=` |
425 | kernel command line option. Don't use this outside of testing environments, | |
426 | however, for the aforementioned reasons. | |
427 | ||
93f59100 LP |
428 | 12. *Why doesn't `systemd-boot` rewrite the 'system token' too each time |
429 | when updating the random seed file stored in the ESP?* | |
430 | ||
431 | The system token is stored as persistent EFI variable, i.e. in some form of | |
432 | NVRAM. These memory chips tend be of low quality in many machines, and | |
433 | hence we shouldn't write them too often. Writing them once during | |
434 | installation should generally be OK, but rewriting them on every single | |
435 | boot would probably wear the chip out too much, and we shouldn't risk that. |