make_console_stdio() forces KD_TEXT while reopening /dev/console. When
systemd-shutdown enters the exitrd, this can expose the text console over
a retained graphical shutdown splash.
Let callers choose whether to switch to text mode, and preserve the mode
for the exitrd handoff. Keep the existing text-mode behavior for manager
reexecution and the crash shell. Restore text mode if executing /shutdown
fails and before reporting a fatal error and freezing.
Add an unsafe, nonparallel virtual-console regression test requiring
explicit opt-in and an already-owned inactive VT in a disposable VM.
Check graphics preservation and text restoration through a private
/dev/console bind mount, retain stderr diagnostics, and restore the saved
mode in the parent even if the child fails.
(cherry picked from commit ef3e0ff7bb)
The test-18-options.fstab.input scenario was guarded by
"$(readlink /mnt)" != "/mnt", which is true on any normal system
since readlink prints nothing for a plain directory. This meant the
scenario was always skipped, and its fixtures were never actually
compared against generator output.
Fix the guard to check whether /mnt is a symlink directly, and repair
the pre-existing fixtures that had drifted while the scenario was
dead:
- mnt-wantedby-automount.mount had a stale Where= value and was
missing the escaping the generator emits for the hyphen in
/mnt/wantedby-automount.
- mnt-requires.mount had Requires=/After= in the wrong order.
Also extend the backslash-stripping workaround loop (used because the
.deb packager dislikes files named with a backslash) to cover
.automount units in addition to .mount/.swap, and fix an ordering bug
where -f was checked before -L, which could leave a dangling symlink
when both a unit and its drop-in symlink needed stripping.
(cherry picked from commit 9d27286214)
The default attestation key for the TPM2 report signer is currently
created with an empty policy but with the adminWithPolicy attribute set.
This makes it impossible to authorize use of the key for the ADMIN role,
which is required by TPM2_Certify.
This drops the adminWithPolicy attribute so that it can be authorized
using its (empty) authorization value. This is appropriate for local
style attestation keys ("LAKs"). I've been working on an interface for
managing attestation keys which will support creating an IAK, and this
will have both the adminWithPolicy attribute set and a policy defined as
specified in the TCG "TPM 2.0 Keys for Device Identity and Attestation"
spec.
(cherry picked from commit fc5875d137)
strv_rebreak_lines() was the last place left that decoded with the permissive
utf8_encoded_to_unichar() and then asked unichar_console_width() how wide the
result is, so it accepted and measured overlong encodings, surrogates,
noncharacters and the obsolete five and six byte forms that utf8_console_width()
now refuses.
That matters because callers mix the two within a single width computation.
sd-varlink-idl.c sizes its indent with utf8_console_width() and then breaks the
body with strv_rebreak_lines(); verbs.c does the same. One half of the sum
refused a sequence that the other half happily assigned a width to.
Use utf8_char_console_width(), which does the validation and the width in one
step, and advance with utf8_next_char() rather than the decoded length. The
function already refused invalid UTF-8, so the only change is which sequences
count as invalid; it now matches utf8_is_valid(), as everywhere else.
(cherry picked from commit 7cc0257ba8)
ellipsize_mem() and align_string_mem() open coded the width of a character as
unichar_iswide(c) ? 2 : 1, but unichar_console_width() counts a tab as eight
cells. The two disagreed, and format-table.c uses both: it decides a field is too
wide with utf8_console_width(), then asks ellipsize() to fit it into that many
columns, and ellipsize() believed a tab was one cell. The ellipsized cell then
still overflowed the column, measured by the very function that had just asked
for it to be truncated. A table pinned to table_set_width(20) emitted lines of
25, 44 and 39 columns. align_string_mem() undercounted the same way and so padded
already overlong cells further.
Use unichar_console_width(), split out for this purpose in 5c0d4b5061. While at
it, let align_string_mem() decode with utf8_char_console_width() as well, so that
the second pass shares both the width model and the validity check with the
measuring pass, instead of keeping a more permissive decoder of its own around
for the next caller to trip over. Its "count invalid chars as 1" fallback now
skips the whole rejected sequence rather than one byte, so that the continuation
bytes are not charged a cell each of their own; the branch should be unreachable
anyway, since our caller only gets there after utf8_console_width() succeeded on
the same string.
Note that unichar_console_width() charges a tab a flat eight cells, while a
terminal advances to the next multiple of eight, so this is deliberately an upper
bound: the two agree only when the tab itself starts on a multiple of eight. A
per character helper cannot do better, because a tab's width is a function of the
column it starts in, and neither ellipsize_mem() nor align_string_mem() is told
what column its string starts at. Overestimating is the safe direction: it can
leave a column padded short, but it cannot overflow one.
ascii_ellipsize_mem() equates bytes with character cells, which holds for ASCII
except for the tab, so keep tabs off that fast path. Like the ANSI sequence case
just above it, such strings now take the generic path, which means they get the
Unicode ellipsis and one reserved cell rather than "..." and three, even in a non
UTF-8 locale.
(cherry picked from commit 0834378fb9)
utf8_char_console_width() decoded with utf8_encoded_to_unichar(), which does not
check for overlong encodings, does not check unichar_is_valid(), and still
accepts the obsolete five and six byte forms. Those checks live in the wrapper
utf8_encoded_valid_unichar(), which is what utf8_is_valid() and ellipsize_mem()
use. Over all 4244897280 NUL free byte strings of length one to four, that is the
whole UTF-8 encoding space, the wrapper agrees with utf8_is_valid_n() everywhere,
while the bare decoder disagrees on 8835838 of them, always by accepting more.
So utf8_console_width() assigned a finite width to strings that utf8_is_valid()
refuses. format-table.c measures a cell with utf8_console_width() and, if it does
not fit, hands it to ellipsize(), which validates strictly, returns NULL, and is
reported as -ENOMEM. A surrogate, overlong, noncharacter or five byte sequence in
any cell therefore failed the whole table with a bogus out of memory error, and
only once the column happened to be narrow enough to require truncation, so
whether it happened at all depended on the width of the user's terminal. At other
widths the invalid sequence was printed to the terminal instead.
Decode with utf8_encoded_valid_unichar() so that how wide we think a string is
agrees with whether we consider it valid UTF-8 in the first place. Invalid cells
are now refused consistently with -EINVAL, the way the sequences that
utf8_encoded_to_unichar() already rejected always were.
Note that for tables this makes the refusal total rather than per field:
table_data_requested_width_height() turns a SIZE_MAX width into -EINVAL, which
table_format() propagates, so a cell in one of the newly rejected encodings now
fails the whole table at every width. systemd-dissect and repart --dry-run put
GPT partition names read straight off the image into cells without filtering
them, so a crafted partition name suppresses the whole listing where before it
cost one field, and only at some terminal widths. That is the intended trade:
the alternative is to keep emitting raw invalid bytes to the terminal at
whichever widths happen not to need truncation. Should degrading the cell rather
than the table turn out to be preferable, the place for it is where the text
enters the table, via utf8_escape_invalid() and friends, not in a helper whose
job is to say how wide a string is.
This also makes the assert(w >= 0) in utf8_escape_non_printable_full() hold by
construction rather than by the accident that its own validation was stricter
than the width helper's.
(cherry picked from commit cd51add717)
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
(cherry picked from commit 06c2dfa73c)
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).
(cherry picked from commit efa16c7f31)
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.