make_policy() already retries unsealing the recovery PIN when the TPM
reports that PCR values changed, but the tpm2_policy_super_pcr() call
that builds the policy for that unseal attempt was not covered: a
concurrent PCR extension there aborted the whole operation on the first
try.
This is easy to hit when IMA is enabled (e.g. implicitly through secure
boot), as PCR 10 is extended for every kernel module that gets loaded.
Retry that step within the existing loop, and give the retry budget a
name while at it.
Signed-off-by: Alberto Planas <aplanas@suse.com>
tpm2_policy_pcr() returns -EUCLEAN when the TPM's global PCR update
counter moved while the policy was being submitted, not when the
recorded PCR values disagree with the current state. Logging "Either
the system has been tampered with or the provided policy is incorrect"
at error level is therefore wrong, and it is noisy too: the condition is
transient and callers are expected to restart the policy session.
Downgrade both occurrences to debug and describe what actually happened,
and document the contract at the declarations.
Signed-off-by: Alberto Planas <aplanas@suse.com>
tpm2_load_pcr_signature() propagates the JSON parser's errno, and the
parser reports a string that is not valid UTF-8 as -EUCLEAN. With
EUCLEAN now mapping to io.systemd.Credentials.PCRsKeptChanging, such a
file would be reported as if a PCR were being extended continuously.
Translate it where it originates, so that the errno stays single valued
for every caller of tpm2_load_pcr_signature() and not only for the creds
one: a signature file that cannot be parsed is -EBADMSG, whichever way
it is malformed. A syntax error used to come out as -EINVAL, which
matched nothing on the way out either.
Signed-off-by: Alberto Planas <aplanas@suse.com>
io.systemd.Credentials.UnexpectedPCRState used to be mapped to EUCLEAN,
which now means "a PCR kept being extended while unsealing" rather than
"the PCR state does not match the policy". Map it to EPERM instead,
which is one of the errnos ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR() covers,
and introduce a separate PCRsKeptChanging error for EUCLEAN.
Also report the condition explicitly in decrypt_credential_and_warn(),
like the other TPM2 unseal callers do.
Signed-off-by: Alberto Planas <aplanas@suse.com>
tpm2_unseal() returns -EUCLEAN specifically when a PCR kept being
extended while unsealing, but the unseal callers no longer catch it
via ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR() and would fall back to the
generic "Failed to unseal secret using TPM2" message.
Give it a message of its own instead, so that the log points at the
actual cause instead of suggesting the system was tampered with.
Signed-off-by: Alberto Planas <aplanas@suse.com>
So far tpm2_unseal() used -EUCLEAN together with the errors that
signal that the PCR state does not match the policy. That is
misleading: -EUCLEAN (and TPM2_RC_PCR_CHANGED) is only ever generated
when the TPM's global PCR update counter moves while we are building the
policy or unsealing, i.e. when something on the system extends a PCR
concurrentlyi (usually IMA extending PCR 10). It says nothing about
whether the policy itself matches.
Until now the retry loop only recognized those conditions while retries
were left (i > 0), and once the budget was exhausted the last iteration
fell through to the generic paths, reporting either an unrelated policy
error or -ENOTRECOVERABLE. Handle the last iteration explicitly instead,
and return -EUCLEAN with a message that names the actual problem.
Drop -EUCLEAN from ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(), it is not a "bad
PCR state" error.
Signed-off-by: Alberto Planas <aplanas@suse.com>
Adds EncryptAddToken=<type>[:<source>:<value>] to repart.d partition
files, registering one or more LUKS2 token objects in the partition
header after the keyslot is created. This allows custom token plugins
(e.g. a TDX KBS plugin) to be wired up at provisioning time without a
separate cryptsetup token import step.
The type name is always explicit and extra token fields can be supplied as
a JSON file (:file:/path) or base64-encoded JSON (:data:<base64>). The
type and keyslots fields are always injected by repart. The option is
repeatable; an empty value clears all tokens for the partition.
Supported with Encrypt=key-file, tpm2, and key-file+tpm2.
If KExecsCount > 0 then do not attempt to mark a UKI, as the stub (and also
any addon and the bootloader) will not have been exercised, so there's no
guaranteed a full reboot with the same image will actually work.
Fixes https://github.com/systemd/systemd/issues/43738
A triple backtick inside prose made the fence count odd, so a body with an
inline marker plus a valid suggestion block got cut at the block's closing
fence and left it open. Only fences at the start of a line delimit blocks,
so count and strip those alone.
Reviews keep hitting the 50 minute timeout. The coordinator agent that was
supposed to launch reviewers, watch the clock, stop stragglers, validate and
write the result does none of that reliably: reviewers get stopped and lose
their findings, foreground validators can't be stopped, deadlines get
overshot by minutes, and one leftover agent keeps the process alive until
the job fails. Piling more rules into its prompt hasn't helped.
Do the orchestration in the shell instead. Run one bounded claude invocation
per review lens in parallel under timeout(1), each returning its findings as
structured output, merge them with jq and run one bounded validator over the
candidates. A lens that times out is just reported as failed. The post job
builds the tracking comment from what it actually posted, so the model no
longer authors the summary or the review bookkeeping. Agents run from an
empty directory with all inputs outside it, so the sandbox keeps both the
checkout and the inputs read-only.
Let's make sure that we have wider regression coverage:
1. Verify duplicate, empty, binary, and repeated fields are stored and
enumerated correctly
2. Exercise reader position invalidation after seeking and changing
matches
3. Check cursor, data, unique-field, and field-enumeration lifetime
semantics
4. Test journal opening and following across invalid files, file
descriptor ownership, renames, unlinks, polling, immutable files, forked
readers, etc, etc
So far we didn't limit the number of jumps when decompressing a DNS
packet. This can lead to some extra work with specially crafted packets
that send a staircase of thousands of descending compression pointers,
which can then be amplified by referencing such staircase from thousands
of names.
Given that legitimate DNS packets need only a handful of jumps in the
compression chains, let's limit the number of jumps per a single name to
256 (the same limit as, for example, Unbound currently has).
Reported by opensec-intelligence (OpenSec).
namespace_enter() tried to become root after joining a user namespace
but ignored failures, so if root wasn't mapped we'd just carry on with
our original UID/GID. Let's make that an error instead.
Dropping supplementary groups stays best effort, as setgroups() might
be denied (e.g. by the nsresourced BPF LSM) even when root is mapped.
Some callers do need to enter namespaces without root, so add
NAMESPACE_ENTER_KEEP_UID_GID_IF_ROOT_UNMAPPED for those. It's used by
systemd-analyze unit-shell and by the credential refresh in the user
manager. Everything else enters containers or namespaces we allocated
ourselves, where root is always mapped.
Introspection is implemented for everything that has a command-line
parser, not only for select binaries.
Standarize on "rate-limit" as the spelling in docs.
Various other smaller tweaks and clarifications.
This is especially necessary since GCC 16.x.
=====
$ gcc --version
gcc (GCC) 16.2.1 20260819 (Red Hat 16.2.1-2)
Copyright (C) 2026 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
=====
Without this change, /usr/include/limits.h is not included, hence POSIX
constants are not defined:
=====
$ echo '#include <limits.h>' | gcc -E -H -isystem ~/git/systemd/src/include/musl - 2>&1 >/dev/null | grep '^\..*limit'
. /home/watanabe/git/systemd/src/include/musl/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
... /usr/lib/gcc/x86_64-redhat-linux/16/include/syslimits.h
=====
With this change, /usr/include/limits.h is included, thus POSIX
constants are defined:
=====
$ echo '#include <limits.h>' | gcc -E -H -isystem ~/git/systemd/src/include/musl - 2>&1 >/dev/null | grep '^\..*limit'
. /home/watanabe/git/systemd/src/include/musl/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
... /usr/include/limits.h
...... /usr/include/linux/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
=====
Replaces #43824.
The _const_ attribute can be only used for functions.
Fixes the following warnings on Fedora rawhide:
```
../src/core/namespace.h:260:75: warning: '__const__' attribute only applies to functions [-Wignored-attributes]
260 | char* bpf_delegate_to_string(uint64_t u, const char * (*parser)(uint64_t) _const_);
| ^
../src/basic/../fundamental/macro.h:80:32: note: expanded from macro '_const_'
80 | #define _const_ __attribute__((__const__))
| ^
In file included from ../src/core/unit.c:24:
../src/shared/condition.h:87:63: warning: '__const__' attribute only applies to functions [-Wignored-attributes]
87 | typedef const char* (*condition_to_string_t)(ConditionType t) _const_;
| ^
../src/basic/../fundamental/macro.h:80:32: note: expanded from macro '_const_'
80 | #define _const_ __attribute__((__const__))
| ^
```
Only PCI was treated as a "less specific" bus that should not be
assigned if USB was already assigned, so non-PCI USB controllers
(under platform/DT or ACPI) would have all their devices *not*
treated as USB at all, resulting in external peripherals being
treated as internal ones on DT platforms.
Clarify these assignments into specificity/nesting groups instead
of having some arbitrary "X must be before Y" comments.
Fixes a4381cae8b.
We generally want that the exposed strings for enum values and the
internal names for them stay in sync. Let's make sure this is the case
for the ConfidentialComputing enum.
This just changes the internal names, so that they match the external
ones. No user visible change, just some search and replace.
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
po: Translated using Weblate (Finnish)
Currently translated at 100.0% (286 of 286 strings)
Co-authored-by: Weblate Translation Memory <noreply-mt-weblate-translation-memory@weblate.org>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fi/
Translation: systemd/main
The Claude review workflow posted long, padded inline comments, and every
force push produced a fresh batch of new findings on code that had not
changed. Both make authors stop reading the reviews.
Add a comment style section to the prompt that limits each comment to the
problem and the obvious fix, and truncate anything over 1000 characters in
the post job. Track the number of completed reviews and the last reviewed
head in a hidden state line in the tracking comment. Each successful review
narrows the severities that may be posted: everything on the first review,
no nits on the second, and only must-fix findings from the third on. The
post job enforces the policy so it holds even if the model ignores the
prompt, and reviewers are told to range-diff against the previous head and
skip non-must-fix findings on unchanged code. Commenting "@claude review
full" resets the count for that run.
`TEST-23-UNIT-FILE.dbus-reconnect.sh` SIGKILLs `dbus.service` three
times. Nothing reconnects to the new broker, so logind keeps running
with `org.freedesktop.login1` unowned for the rest of the boot —
activation can't fix it either, as `dbus-org.freedesktop.login1.service`
is already active, so the job finishes at once and the name never
returns.
That leaks into the subtests after it. `statedir.sh`, the first to start
`user@0.service`, spends 2 × 25 s in user-runtime-dir on logind
properties, and where pam_systemd can't use Varlink (memory-max= & co.
in the PAM stack) it blocks in `CreateSession()` for 2 min, past
user@.service's 90 s TimeoutStartSec — failing, and pointing at a
subtest that has nothing to do with the bus.
Hit this in hyperscale v261.3 release test for centos9:
https://artifacts.dev.testing-farm.io/01c1c68b-da64-4b9e-b163-eb3459aabe79/work-upstreamjejyd7ep/log.txt
Killing the broker is destructive well beyond the units under test: nothing
reconnects to the new one, so logind for instance keeps running with
org.freedesktop.login1 unowned for the rest of the boot. As a subtest of
TEST-23-UNIT-FILE that leaked into everything running after it, and
statedir.sh, the first one to start user@0.service, then spent 25s per logind
property in user-runtime-dir and, where pam_systemd can't use Varlink, blocked
in CreateSession() past user@.service's 90s TimeoutStartSec and failed — with
the failure pointing at a subtest that has nothing to do with the bus.
In its own test the damage dies with the machine.
The flags to pass to symlinkat_atomic_full are defined in the
SymlinkFlags enum type. The previous code passed the result of a boolean
check operation directly instead of using flags.
Be explicit about the value to pass instead of relying on true
corresponding to the enum value for the SYMLINK_MAKE_RELATIVE flag.
Signed-off-by: Daniel Wagenknecht <dwagenknecht@emlix.com>
-ENODATA is returned when the message carries no (reply) cookie, but the
text stated the message "carries a reply cookie field". Say it does not
carry one.
- It does not accept NUL for type.
- ret_size is zero and ret_ptr is non-NULL when it returns positive.
- Fixed argument names: ptr -> ret_ptr, size -> ret_size.