Commit Graph
61073 Commits
Author SHA1 Message Date
Luca Boccassi 4e67935b77 userdb: suppress userdb queries for backends indicating uid/gid/name range info via xattrs on entrypoint sockets (#42961)
Let's optimize userdb queries a bit: by encoding the covered UID/GID
ranges and user/group name patterns on the varlink entrypoint sockets
for userdb backends we can make them wake up less and reduce the work
triggered by queries.
2026-07-14 00:19:32 +01:00
Luca Boccassi 1fcd92a214 sysupdate: add "suggestion" concept to feature and component enablement (#42970) 2026-07-13 19:07:50 +01:00
Lennart Poettering 6ce0759d99 repart: allow empty EncryptedVolume= volume name (#42889)
Treat an empty volume name alongside other fields as unset instead of
rejecting it as invalid.

Example use case:
```
EncryptedVolume=:none:discard
```

In this case, the volume name is not specified so it can be generated as
luks-UUID.

From the docs:

> EncryptedVolume=
> Specifies how the encrypted partition should be set up. Takes at least
one and at most four fields separated with a colon (":"). The first
field specifies the encrypted volume name under /dev/mapper/. If not
specified, "luks-UUID" will be used where "UUID" is the LUKS UUID.
2026-07-13 18:47:09 +02:00
Luca Boccassi 4f397da505 process-util: introduce prctl_safe() and port everything over to it (#43006)
prctl() is an API full of pitfalls: it is variadic, and some interfaces
don't expect zero-initialization of excess arguments, and others do.
Moreover, the parameters are "long", and nonetheless we usually pass
"int" to them. If we are too dumb to call it properly, let's just not
call it directly anymore, but let's add a wrapper around it that makes
the function non-variadic and declares the right types. Then, let's port
over everything to it.

This is inspired by #42996, but we had issues with this many times,
before and looking at this PR one can see that we otherwise still are
having the issue at numerous other places.
2026-07-13 17:02:57 +01:00
Lennart Poettering c8cffba715 cryptsetup: add Argon2id-based PIN mode for TPM2 enrollment (#41859)
The current TPM2 PIN mode is flawed as a compromised TPM directly
exposes
the sealed secret which is the LUKS volume key itself
(https://github.com/systemd/systemd/pull/27502 and
https://github.com/systemd/systemd/issues/37386).

Goal: add Argon2id-based PIN hardening to TPM2 enrollment, making
the TPM a second factor rather than a single point of failure:

1. Password + salt → Argon2id → 512-bit key split into Key1 + Key2
2. Key2 (base64-encoded) is used as the PIN to seal a random secret
in the TPM
3. Key1 + unsealed secret → HKDF-SHA256 → final LUKS volume key

This implementation ensures that if the TPM is compromised, an attacker
still needs the password to derive Key1 and combine it with the unsealed
secret.

The --tpm2-with-pin= option now accepts three values:
- false (no PIN used)
- true (PIN hardened with Argon2id - default)
- "direct" (legacy PIN without Argon2id for backward compatibility)

Argon2id parameters are customizable via:

--tpm2-argon2id-memory=
--tpm2-argon2id-iterations=
--tpm2-argon2id-parallelism=
--tpm2-argon2id-iter-time=

These default to a function of available CPUs and physical memory, with
a benchmark that scales iterations to the target time (default: 2s) and
falls back to ARGON2ID_PARAMETERS_DEFAULT (64 MiB, 8 iter, 4 lanes) when
auto detection fails.
Also if the runtime OpenSSL lacks Argon2id support (< 3.2), the feature
silently falls back to direct PIN mode with a warning.

Added includes:
- src/cryptenroll/cryptenroll.c: cpu-set-util.h, limits-util.h,
time-util.h
for Argon2id benchmark auto-tuning (cpus_online, physical_memory_scale,
  now/usec_t)
- src/cryptenroll/cryptenroll-tpm2.c: crypto-util.h for
Argon2IdParameters
  struct in load_volume_key_tpm2()
- src/shared/tpm2-util.h: crypto-util.h for Argon2IdParameters in
  tpm2_make_luks2_json() API
- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c: crypto-util.h for
  kdf_argon2id_derive()/kdf_hkdf_sha256() on the token unlock path
2026-07-13 17:55:47 +02:00
Lennart Poettering 4481661a75 sysupdate: add support for --component-all + --feature-all + --feature-suggested to enable-feature verb
This adds similar concepts as we already have for enable-component:
let's add a way to enable all features or the suggeste dones, and
possibly on all components.

Or in other words, with this:

  systemd-sysupdate enable-component -S
  systemd-sysupdate enable-feature -A -s

We'll automatically enable all suggested components, and all features of
them.
2026-07-13 17:36:11 +02:00
Lennart Poettering 9f3b604d64 sysupdate: validate feature name syntax before using it
Let's tighten the rules on features, and enforce a sensible naming
policy.
2026-07-13 17:36:10 +02:00
Lennart Poettering f23224a7ca sysupdate: add feature select
Prepartion for the next commit: also allow selecting the all or
suggested features.
2026-07-13 17:36:10 +02:00
Lennart Poettering 52d9906a54 sysupdate: implement --component-all and --component-suggested for enable-component and disable-component
Let's now introduce "systemd-sysupdate enable-component
--component-suggested" and systemd-sysupdate enable-component
--component-all" for enabling all or all suggested components at once.
Similar, if used for disable-component will disable all components or
those not suggested.
2026-07-13 17:36:10 +02:00
Lennart Poettering 8f9a2f0c82 sysupdate: introduce --component-suggested similar to --component-all
While --component-all really picks all components --component-suggested
picks only the suggested ones.

Note that none of the verbs currently implement the concept, they will
all refuse the option. Hooking this up is going to be added next.
2026-07-13 17:36:10 +02:00
Lennart Poettering 40e727c93b sysupdate: add a "suggests" concept to features and components
Let's make it possible to "suggest" that certain features or components
are enabled under some conditions.

For this, both features and components gain two things:

1. A Suggested= field which takes a boolean. If true the
   feature/component will be suggested for installation, if false it
   will not.

2. A set of SuggestedOnXYZ= settings are modelled after ConditionXYZ= in
   unit files (and implement a subset of them), will suggest some
   component/feature under specific conditions.

The result of the condition is shown in the various output tools.
2026-07-13 17:36:10 +02:00
Frantisek Sumsal 5f2d15abf4 timer: avoid re-arming WakeSystem=yes timer after suspend
There's an edge case where a single-shot timer using WakeSystem=yes
could get re-armed after elapsing. For example, when a timer is created
using:

$ systemd-run --user --on-active="1m" --timer-property=WakeSystem=yes flatpak run io.bassi.Amberol

and the system is then suspended, following sequence of events may
happen:

Jul 08 06:57:25 systemd[2640]: run-p192456-i199160.timer: Installed new job run-p192456-i199160.timer/start as 7675
Jul 08 06:57:25 systemd[2640]: run-p192456-i199160.timer: Enqueued job run-p192456-i199160.timer/start as 7675
Jul 08 06:57:25 systemd[2640]: run-p192456-i199160.timer: Monotonic timer elapses in 59.999999s.
Jul 08 06:57:25 systemd[2640]: run-p192456-i199160.timer: Changed dead -> waiting
Jul 08 06:57:25 systemd[2640]: run-p192456-i199160.timer: Job 7675 run-p192456-i199160.timer/start finished, result=done
Jul 08 06:57:25 systemd[2640]: Started [systemd-run] /usr/bin/flatpak run io.bassi.Amberol.
Jul 08 06:58:13 systemd[2640]: run-p192456-i199160.timer: Time change, recalculating next elapse.
Jul 08 06:58:13 systemd[2640]: run-p192456-i199160.timer: Monotonic timer elapses in 12.785674s.
Jul 08 06:58:26 systemd[2640]: run-p192456-i199160.timer: Timer elapsed.
Jul 08 06:58:26 systemd[2640]: run-p192456-i199160.timer: Changed waiting -> running
Jul 08 06:58:29 systemd[2640]: run-p192456-i199160.timer: Got notified about unit deactivation.
Jul 08 06:58:29 systemd[2640]: run-p192456-i199160.timer: Monotonic timer elapses in 33.544681s.
Jul 08 06:58:29 systemd[2640]: run-p192456-i199160.timer: Changed running -> waiting
Jul 08 06:59:48 systemd[2640]: run-p192456-i199160.timer: Timer elapsed.

1) The timer is armed at 06:57:25. timer_enter_waiting()
   calculates following values:

   base = M0 (current CLOCK_MONOTONIC)
   usec_shift_clock(base, CLOCK_MONOTONIC, CLOCK_BOOTTIME_ALARM) = M0 (no delta yet)
   v->next_elapse = M0 + 60s

   The timer is on CLOCK_BOOTTIME_ALARM at M0 + 60s

2) System suspends. If the system ran for ~12s and was suspended for
   ~36s, at resume we'd get:

   CLOCK_MONOTONIC = M0 + 12s
   CLOCK_BOOTTIME = M0 + 12s + 36s = M0 + 48s

3) timer_time_change() fires and calls timer_enter_waiting(t, true)

   Because time_change=true, v->next_elapse is not recalculated and
   keeps the original M0 + 60s value. The timer then correctly computes
   the remaining time as ~12.8 seconds:

        Jul 08 06:58:13 ...: Monotonic timer elapses in 12.785674s.

4) Timer elapses at 06:58:26

        Jul 08 06:58:26 ...: Timer elapsed.

   timer_enter_running() sets last_trigger.monotonic to CLOCK_MONOTONIC
   (which equals to M0 + 12s before suspend + 13s after suspend, thus
   + 25s)

5) Unit deactivates at 06:58:29

   timer_trigger_notify() calls timer_enter_waiting(t, false) -
   time_change=false; that means that this time v->next_elapse gets
   recalculated:

   base = inactive_exit_timestamp.monotonic = M0 (i.e. when the timer was originally armed)
   usec_shift_clock(M0, CLOCK_MONOTONIC, CLOCK_BOOTTIME_ALARM)
        a = now(CLOCK_MONOTONIC) = M0 + 28s
        b = now(CLOCK_BOOTTIME_ALARM) = M0 + 64s
        result = b - (a - M0) = (M0 + 64s) - 28s = M0 + 36s => the time spent in suspend

   Hence v->next_elapse = (M0 + 36s) + 60s = M0 + 96s

   This then skips disabling of one-shot timers in the following check,
   because the expression

        v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t))

   is false, because the v->next_elapse (M0 + 96s) is not less than the
   current time (M0 + 64s), so the timer is re-armed again:

        Jul 08 06:58:29 ...: Monotonic timer elapses in 33.544681s

Let's mitigate this by skipping the next elapse timestamp recalculations
for one-shot timers for which we've already calculated the value in this
activation cycle.

Resolves: #42929
2026-07-13 16:23:59 +01:00
Lennart Poettering 3b38a4f240 tree-wide: port to prctl_safe() 2026-07-13 15:39:17 +02:00
Lennart Poettering 2d63905096 nsresource: port from PR_GET_NAME to pid_get_comm()
SImilar reasons as for the memfd change: let's normalize behaviour and
always use pid_get_comm().

This adds escaping here for the first time, which is a good thing.
2026-07-13 15:39:17 +02:00
Lennart Poettering b484f983fc memfd-util: port to pid_get_comm()
Let's the common function for querying the local thread name.

This changes the escaping rules when the therad name is not quite
kosher: previously we'd just escape invalid UTF-8 charcaters, now we do
what we usually do: also escape control characters and such, and limit
us to ASCII.

The description generated here is mostly for debug purposes, and process
names should normally not require this escaping anyway (it's mostly
paranoia), hence I think this change in behaviour should be fine, it's
not part of the API in any form.
2026-07-13 15:39:17 +02:00
Lennart Poettering 4d84f8fac3 process-util: introduce proc_get_timerslack() 2026-07-13 15:39:17 +02:00
Lennart Poettering 3ac3632e28 process-util: introduce trivial proc_set_nnp() helper 2026-07-13 15:39:16 +02:00
Lennart Poettering 0e077d3eea process-util: introduce proc_set_comm() helper
This operation is done at a bunch of places, let's add a type-safe
helper for it.
2026-07-13 15:39:16 +02:00
Lennart Poettering d3c0348c8b process-util: introduce prctl_safe() 2026-07-13 15:39:16 +02:00
Luca Boccassi 2e1c8bc3d7 udev: fix several option parsing edge cases (#42997)
Boundary tests were conducted on the udev subsystem, and some issues
were identified and resolved.
2026-07-13 13:42:27 +01:00
Luca Boccassi 061490432e repart: Some fixes for --copy-from= (#42976)
A bunch of things I noticed that aren't correct about `--copy-from` and
grain sizes + paddings.
2026-07-13 13:33:24 +01:00
Jonas Dreßler 71d20a990e repart: Don't copy trailing padding when using --copy-from=
Currently, --copy-from= copies the paddings in between the source partitions,
as well as the trailing padding that is at the end of the source partition table.
It doesn't copy the leading padding at the start of the source partition table
though.

This seems inconsistent, and likely it was an oversight that the trailing padding
is copied.

Fix that, and add a test to ensure we don't regress.
2026-07-13 12:23:20 +02:00
Jonas Dreßler 2b1be5d909 repart: Don't get old grain size from fdisk for --copy-from=
This is a little bit confusing, but grain size is not actually stored in the gpt
metadata. Rather, fdisk's `get_grain_size()` returns an autodiscovered "optimal io
size" value as grain size. This might not actually be the grain size that the
disk we're copying is using.

Since we're setting the padding of the copied partitions using that value from
fdisk, we're rounding the new paddings by fdisk's optimal grain size, which is
usually 1MiB (a lot more then the default 4KiB that we're using otherwise).

Set the grain size here to 1 byte instead, ensuring that the min/max padding set
is exactly the padding that was present before.

Also add a test to confirm the behavior is fixed: The test calls --copy-from= on
an existing disk with 4MiB grain size, and because we pass --grain-size=512, now
no rounding should happen and the paddings should be transferred to exactly the
same size.
2026-07-13 12:09:13 +02:00
Lennart Poettering 649ab380e1 nresourced: add user.userbd.* xattrs to nsresourced userdb socket 2026-07-13 09:53:15 +02:00
dongshengyuan 4106cf7439 udevadm-trigger: reject invalid wait-daemon timeout
Return from argument parsing when --wait-daemon= cannot be parsed.

This matches the other timeout options.

Reproducer:
  udevadm trigger --dry-run --wait-daemon=bad

Before:
  Failed to parse timeout value 'bad', ignoring: Invalid argument

Follow-up:
  2001622c58
2026-07-13 12:18:49 +08:00
dongshengyuan 20e1e2de67 udev-config: merge configured children max
Merge children_max from the per-source UdevConfig values before
defaulting it from system resources.

Reproducer:
  systemd-udevd --debug --children-max=1

Before:
  Set children_max to 32

Follow-up:
  04fa5c1580
2026-07-13 12:18:49 +08:00
dongshengyuan 778f932032 udevadm-settle: reject positional arguments
The settle command does not define positional arguments.

Reject them during argument parsing instead of silently ignoring
them.

Reproducer:
  udevadm settle /no/such/argument

Before:
  The command exits successfully and ignores the argument.

Follow-up:
  c71509028f
2026-07-13 12:18:49 +08:00
dongshengyuan 7bd6b8c587 udevadm-wait: let --removed override initialization
The documentation says --initialized= is ignored when --removed is
specified.

Track --removed separately so it wins regardless of option order.

Reproducer:
  udevadm wait --timeout=0 --removed --initialized=no /dev/no-such-test-device

Before:
  Timed out for waiting devices being added.

Follow-up:
  aa2b0d8d29
2026-07-13 12:18:49 +08:00
dongshengyuan c5a6425b81 udevadm-info: allow valueless attr filters
The --attr-match= and --attr-nomatch= filters are documented as
FILE[=VALUE], like the trigger filters.

Accept a bare attribute name for sysfs attribute presence matches.

Reproducer:
  udevadm info --export-db --attr-match=ifindex

Before:
  Expected <ATTR>=<value> instead of 'ifindex'

Follow-up:
  a6b4b2fa01
2026-07-13 12:18:48 +08:00
dongshengyuan 9725124635 udev: avoid reading before empty capability masks
When input_id prints a decoded capability bitmap, an all-zero
bitmap can decrement the index to zero.

Check the index before reading bitmask[val - 1].

Reproducer:
  udevadm test-builtin input_id with an all-zero capability mask

Follow-up:
  912541b024
2026-07-13 10:59:00 +08:00
fuldeka 41965b3568 tree-wide: add missing libopenssl_cflags to targets using tpm2-util.h
tpm2-util.h includes crypto-util.h, which requires OpenSSL compiler
flags when HAVE_OPENSSL is defined. Add libopenssl_cflags to every
build target that uses tpm2_cflags but was missing the transitive
OpenSSL dependency.
2026-07-12 23:31:29 +02:00
fuldeka f3fe668cdf cryptsetup: add Argon2id-based PIN mode for TPM2 enrollment
The current TPM2 PIN mode is flawed as a compromised TPM directly exposes
the sealed secret which is the LUKS volume key itself (#27502 and #37386).

Goal: add Argon2id-based PIN hardening to TPM2 enrollment, making
the TPM a second factor rather than a single point of failure:

1. Password + salt -> Argon2id -> 512-bit key split into Key1 + Key2
2. Key2 (base64-encoded) is used as the PIN to seal a random secret
in the TPM
3. Key1 + unsealed secret -> HKDF-SHA256 -> final LUKS volume key

This implementation ensures that if the TPM is compromised, an attacker
still needs the password to derive Key1 and combine it with the unsealed
secret.

The --tpm2-with-pin= option now accepts three values:
- false (no PIN used)
- true (PIN hardened with Argon2id - default)
- "direct" (legacy PIN without Argon2id for backward compatibility)

Argon2id parameters are customizable via:

--tpm2-argon2id-memory=
--tpm2-argon2id-iterations=
--tpm2-argon2id-parallelism=
--tpm2-argon2id-iter-time=

These default to a function of available CPUs and physical memory, with
a benchmark that scales iterations to the target time (default: 2s) and
falls back to ARGON2ID_PARAMETERS_DEFAULT (64 MiB, 8 iter, 4 lanes) when
auto detection fails.
Also if the runtime OpenSSL lacks Argon2id support (< 3.2), the feature
silently falls back to direct PIN mode with a warning.

Added includes:
- src/cryptenroll/cryptenroll.c: cpu-set-util.h, limits-util.h, time-util.h
  for Argon2id benchmark auto-tuning (cpus_online, physical_memory_scale,
  now/usec_t)
- src/cryptenroll/cryptenroll-tpm2.c: crypto-util.h for Argon2IdParameters
  struct in load_volume_key_tpm2()
- src/shared/tpm2-util.h: crypto-util.h for Argon2IdParameters in
  tpm2_make_luks2_json() API
- src/shared/tpm2-util.c: limits-util.h, tpm2-util.h for physical_memory() validation
  of Argon2id memory cost and function prototypes
- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c: crypto-util.h for
  kdf_argon2id_derive()/kdf_hkdf_sha256() on the token unlock path
2026-07-12 23:31:29 +02:00
Lennart Poettering 33b2db3c8f machined: set user.userdb.* xattrs on machined socket 2026-07-12 23:09:01 +02:00
Lennart Poettering e3876f7559 homed: set user.userdb xattrs on homed's userdb socket
We can't make a lot of restrictions here, since users are allowed to
basically freely pick their user names and UIDs too. But let's at least
exclude system UID ranges and those beyond the 16bit range.
2026-07-12 23:09:01 +02:00
Lennart Poettering 845786f60b core: tag dynamic user userdb provider with dynamic uid/gid ranges
Let's optimize lookups to PID 1's dynamic UID/GID range feature.
2026-07-12 23:09:01 +02:00
Lennart Poettering 00a7b1d2d8 userdb: suppress lookups outside of indicated ranges
When doing a userdb lookup we might end up issuing a lot of IPC calls in
parallel to backends and cause them all to do work, with us waiting for
it. Let's optimize this a bit, and indicate on the socket inodes via
xattrs hints which kind of records are provided by a backend. That way
we can suppress lookups to them and optimize runtime behaviour.

This only works on Linux 7.1 and newer where socket inodes gained
support for extended attributes.
2026-07-12 23:09:01 +02:00
Lennart Poettering 65796105a9 userdb: drop redundant check 2026-07-12 23:06:52 +02:00
Lennart Poettering 953d21846a sd-varlink: add sd_varlink_call_and_upgradeb() + sd_varlink_call_and_upgradebo()
This are to the existing sd_varlink_call_and_upgrade() what
sd_varlink_callb() and sd_varlink_callbo() are to sd_varlink_call():
they put together an object on the fly, via the usual JSON builder
logic.
2026-07-12 22:44:03 +02:00
Lennart Poettering 746d10d106 sd-varlink: add async server-side upgrade API 2026-07-12 22:44:03 +02:00
Lennart Poettering f194afa164 sd-varlink: move varlink_handle_upgrade_fds() before sd_varlink_process()
This is a simple move, in preparation for using this as part of the
sd_varlink_process() callchain.
2026-07-12 22:37:51 +02:00
Lennart Poettering 260fcf9763 sd-varlink: fold separate 'protocol_upgrade' flag into state machine 2026-07-12 22:37:48 +02:00
Lennart Poettering 755f1cff89 json-stream: add helper json_stream_has_buffered_output() 2026-07-12 22:32:40 +02:00
Luca Boccassi 2d85bba6b9 nss-myhostname: keep IPv6 probe result stable
Cache the IPv6 enabled state while sizing and filling NSS result
buffers, so a transient sysctl read result cannot change the tuple or
address layout after the scratch buffer size has been computed. Also
zero-initialize gaih_addrtuple records before filling IPv4 addresses.

Follow-up for e8a7a31539
2026-07-11 17:09:14 +01:00
Luca Boccassi 19c08f2dfa creds: tolerate TPM2 seal failure in auto mode
Automatic key modes tolerate a failed TPM2 sealing attempt and
fall back to a host or null key. Do not consume TPM2 blob output in
that case, tpm2_seal() leaves it empty on failure, so the fallback
path should continue without TPM2 metadata.

Follow-up for 9e4379945b
2026-07-11 17:09:13 +01:00
Luca Boccassi 8baed40298 ndisc: reject non-zero ICMPv6 codes in parsers
NDisc packets received through the socket path are filtered before
parser dispatch, but parser entry points should still reject malformed
packet bytes instead of asserting on them. Return EBADMSG for non-zero
ICMPv6 code values in RA, NA, and Redirect messages.

Follow-up for c34cb1d645
Follow-up for 696eb2b8de
Follow-up for 44e8cf303b
2026-07-11 17:07:53 +01:00
Luca Boccassi ad0996191d pull-oci: verify redirected manifest digest
An OCI index redirect already carries the digest of the selected
manifest. Store it in the expected checksum field so pull-job
verifies the downloaded manifest instead of overwriting the digest
with the computed checksum before comparison.

Follow-up for a9f6ba0496
2026-07-11 17:07:52 +01:00
Luca Boccassi 4309f68236 efivars: fix concurrent growth read accounting
efi_get_variable() allocates one byte for probing whether efivarfs
has grown since fstat(), then three more bytes for NUL termination.
Account for both sizes separately so a full readv() result is treated
as concurrent growth and retried before the terminators are written.

Follow-up for ab69a04600
2026-07-11 17:07:52 +01:00
Shihao Ren dbb59dab73 network: do not regenerate MAC address if already set by userspace
When MACAddress= is unspecified, a stable MAC is generated to seed a newly
created netdev. Since existing netdevs are reconfigured on reload/restart,
this seed got re-applied to an already existing interface, conflicting with
an explicit MACAddress= from the matching .network file and flipping MAC.

Now, when MACAddress= is unspecified, only generate a new address if
addr_assign_type is not NET_ADDR_SET (i.e. not already set by userspace). On
first creation the interface does not exist yet, so this is a no-op and the
address is generated as before. Mirrors src/udev/net/link-config.c.

Fixes: #42457
2026-07-12 00:00:01 +09:00
Popax21 70cfb11d4b creds-util: implement TPM2 SRK pinning
Stores the TPM2 SRK within the credential header, allowing for parameter decryption to be utilized when decrypting the credential.
A new dimension is added to the credential ID matrix to encode this capability.

This also allows for usage of TPM2-bound credentials when a TPM owner password is set since `Esys_CreatePrimary` is no longer used for sealing credentials.
2026-07-11 15:37:46 +01:00
Michael Vogt 8877f63ee1 creds: allow normal users to encrypt with--with-key=null
When encrypting with the `--with-key=null` option systemd-creds
is currently doing the encryption via IPC. This is not needed
for the null key, no privs are required so we can just do the
in-process operation. So instead simply check for the null-key and
if its requested use the in-process path.
2026-07-11 10:38:46 +01:00