This time, various commands with non-trivial requirements are handled.
So the series is shorter, but has a pattern of feature additions and
then those new features being used. The way that --help output is
formatted is changed a bit in various places. Those changes are
described in individual commits.
22 'static int help()' functions left after this.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added.
Options are now in two groups: "Common options" and Mount options". In
--help, for systemd-mount, both groups are shown. For systemd-umount, only
the first. This changes the behaviour a bit: previously, both groups were
shown together as one list. I think the new behaviour is actually a bit
better, because it makes it easier for the user to figure out that the
commands share common options and one of the commands has its private
second group. But if people think that the previous behaviour should
be restored, we could add a display options to squish the groups back
together.
--help now goes through the pager, like other commands with --no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. --help now goes through the pager, like other
commands with --no-pager.
Also, previously, -h/--help/--version were listed in the "Commands"
section. This was cute, but recreating this in the new scheme would
be complicated. Also, it seems unnecessary. --help/--version and some
other commands terminate the program in all binaries, so they could
be considered "commands" in all cases. But we printed them together
with verbs only in a few cases. So I think it's fine to move them
back to the "Options" section. This makes the description of options
much more consistent between different programs.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The note about invocation as 'installkernel' is
kept as the footer. Verb and option column widths are kept separate, since
the verb table is very wide. --help now goes through the pager, like other
commands with --no-pager.
A separate COMMAND block is included for installkernel, but it is only
used for introspection data.
The custom halt_help() and shutdown_help() are replaced by COMMAND()
descriptions (one per command name, halt/poweroff/reboot sharing the
"halt" option namespace), and --introspect-cli is added to both parsers.
halt/poweroff/reboot now each reference their own man page name.
Create the file with open_tmpfile_linkable_at().
Write the recovery key and trailing newline to the temporary fd.
Set the final mode to 0600 before publishing it.
Link it into place with link_tmpfile_at(..., LINK_TMPFILE_SYNC).
As discussed in the PR, those fields can go down, so they cannot be advertised
as type COUNTER. But the type is shared for the whole family, so we need to
create a new family to keep the other ones as COUNTER and add the new ones
as GAUGE.
kernel/sched/cputime.c says above get_cpu_idle_time_us() and get_cpu_iowait_time_us():
> Note that this is partially broken due to the counter of iowait tasks that
> can be remotely updated without any synchronization. Therefore it is possible
> to observe backward values within two consecutive reads.
steal is apparently also unreliable because it is reported by the hyperviser.
So let's be cautious and report it as gauge too.
Extend the io.systemd.Basic metric families with host-level runtime
metrics: cumulative per-state CPU seconds, memory in use (MemTotal minus
MemAvailable), swap in use, the kernel's 10s pressure stall averages
(cpu/memory/io x some/full). Partitions and stacked devices are excluded
from the disk counters, since their traffic is already accounted for in
the parent device.
Also extend the TEST-74 report subtest with checks for the new metrics.
Network metrics are not added, because the service runs with
PrivateNetwork=yes, and it doesn't make sense to report stats for 'lo'.
After some back-and-forth, I settled on "CPUUsage". We use this scheme of
capitalization in other metric family names: "IPv4Public", "IPv6Public",
IPv4AddressState", "IPv6AddressState", "OSRelease" "SMBIOS" "BootID",
"CPUsOnline", "MachineID", "MachineInfo", "OSRelease",
"SMBIOS.SystemManufacturer", "TPM2.Manufacturer", "TPM2.VendorString",
"IOReadBytes", "IOReadOperations", "CGroup". The exception is
"io.systemd.cgroup.CpuUsage". I think we should treat that one as a
mistake and consider changing it to conform.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The generic help-verb check in the test is
filtered out, since systemctl's "help" verb shows unit manuals and fails
without arguments.
Arch rolling now ships Nmap 7.991, which contains Nmap commit
b408fc2, titled "Ignore stdin with recv-only"[1].
That change omits stdin from the Ncat descriptor list in recv-only
mode. For a Unix listener, the listening socket is then its sole
descriptor. Ncat enters its listen loop only when that list has more
than one descriptor or a connection already exists, so it exits
immediately after bind and leaves the socket pathname behind.
systemd-oomd sees that stale pathname, tries to invoke the hook, and
gets ECONNREFUSED. The notification output therefore remains empty
and the jq assertion fails. The problem is visible in trunk's CI
failures[2].
Use socat for these one-way Unix listeners. It remains in accept while
waiting for the hook and is already installed in integration images.
[1] https://github.com/nmap/nmap/commit/b408fc243ce26da7ca497595833c14ce36a5e1a4
[2] https://github.com/systemd/systemd/actions/runs/32622985037/job/97153925154
The DBus API already exposes the parsed machine-tags list via the Tags
property but varlink clients needed to parse the raw TAGS= line from
MachineInformationData (which also required implementing tag name
validation if the tags would later be used with SetTags, to avoid
spurious errors).
So, provide the same information that DBus gets (a list of pre-parsed
tags with bad tags gracefully removed) as a new MachineTags field
returned by Describe -- this does mean that the DBus API now exposes the
same data in two ways but making Describe() consistent is more important
and mirrors the OperatingSystem* class of properties.
image_rename() updated the Image object name and path before
computing the source paths for auxiliary files. As a result, the
auxiliary rename loop looked for files with the new image name,
while existing sidecars such as .roothash, .verity, and
.raw.tpmstate still used the old image name.
Delay updating the Image object until after renaming its settings
and auxiliary files. This lets image_auxiliary_path() resolve
existing sidecars from the old image name while
rename_auxiliary_file() assigns the new name.
Extend the import test raw image rename coverage to check
representative sidecars are renamed together with the image.
UnsetEnvironment= was applied to the environment block before the
command line was expanded. Since the expansion looks the variables up
in that same block, any variable listed in UnsetEnvironment= was
already gone when $VAR in ExecStart= and friends was expanded, and a
whole-word $VAR reference was dropped from the command line.
Let the expansion see the full environment block, and apply the
unsetting only to the environment block passed to the executed
process. This way UnsetEnvironment= can hide variables from the
executed process without breaking command lines that reference them.
Extend the exec-unsetenvironment test accordingly: the whole-word
$VAR6 argument must be expanded into a positional parameter for the
shell, while ${VAR6-X} must evaluate to X in the executed process.
Also document in both the UnsetEnvironment= description and the
"Environment Variables in Spawned Processes" section that the
unsetting happens after command line variable expansion.
Fixes: #43343
This adds an initial TPM2 implementation of the io.systemd.Report.Signer
interface, which returns a set of signed TPM attestations that also
includes the supplied report digest.
The returned report consists of multiple components:
- A signed PCR quote generated with TPM2_Quote.
- Signed NvPCR attestations generated with TPM2_NV_Certify.
- A signed audit session attestation generated with
TPM2_GetSessionAuditDigest.
Each signed report component includes the JSON encoded TPMS_ATTEST
attestation structure and corresponding signature, in both PEM encoded
form and as a JSON encoded TPMT_SIGNATURE structure.
NvPCR report components also include the readable name of the NvPCR, the
NV index public area as the JSON encoded TPMS_NV_PUBLIC structure, and some
additional authenticated data that is digested and supplied as the
qualifying data to the TPM2_NV_Certify command. This authenticated data
includes the NvPCR name and priority.
The report digest that is supplied via varlink is supplied as the
qualifying data to the audit session attestation.
The returned report also includes the event log which is retrieved from
pcrlock's varlink interface, and the public area of the signing key in
both PEM encoded form and as a JSON encoded TPMT_PUBLIC structure.
The audit session attestation is always the last component. The
preceding components are all executed with the audit session, and the
signer requires the audit session to remain exclusive whilst generating
the report. What this does is provide evidence to a verifier that the
overall report is a single, consistent snapshot of the system (ie, no
other TPM commands executed whilst generating the report) because the
audit session attestation contains a field that indicates that the
session was exclusive at the time it was attested.
The set of attested PCRs and NvPCRs are currently hardcoded. It includes
all firmware PCRs with the exception of PCR6, and all other PCRs with
the exception of the IMA one (which isn't useful on its own without the
IMA log). All defined NvPCRs are included.
A verifier can verify the signed attestation components individually by
verifying their signatures against the supplied attestation data, using
the supplied public key.
For the PCR report component, a verifier can replay the measurements in
the log in order to reconstruct the PCR values, and then use this and
the PCR selection from the attestation in order to calculate the PCR
digest, and then check that this matches the one in the attestation.
For the NvPCR report components, a verifier checks that the NV index
name in the attestation matches one that is anchored in PCR9 to be sure
that the attestation is for a valid NvPCR. A verifier can then replay
the measurements in the log to ensure that the resulting NvPCR value
matches the one supplied in the attestation. The authenticated data is a
JSON blob containing the NvPCR name and priority. A verifier can digest
this and ensure it matches the qualifying data in the attestation.
The audit session attestation includes the audit session digest and
whether the audit session was still exclusive when the attestation was
generated. A verifier should confirm exclusivity. The digest includes a
record of all TPM commands executed with the audit session, as each
command results in it being extended with the command parameter hash and
the result parameter hash. A verifier should replay the preceding report
components to compute an expected audit digest and make sure that this
digest matches the one in the attestation in order to be sure that the
overall report represents a single, consistent snapshot. The other
report components provide sufficient information for a verifier to
reconstruct the cpHash and rpHash.
When reconstructing the cpHash for the PCR and NvPCR components, the
signing scheme is the NULL scheme (they use the attestation key's
signing scheme). The required signing key public area is supplied in
the report. The supplied qualifying data is in the extra data field of
the attestation.
The PCR selection is also required to reconstruct the cpHash for the
PCR component. The PCR selection is available in the attestation.
The name of the NV index is also required to reconstruct the cpHash for
the NvPCR components. The name is available in the attestation.
The rpHash for each component can be reconstructed from the supplied
attestation blob and signature.
In the future, we might want to add more report component types. Eg, we
could add report components for ordinary NV indexes. Using the audit
session means that we could also add additional components that the TPM
can't attest directly, such as the values of interesting TPM properties
(as the TPM2_GetCapability calls will appear in the audit session digest).
The attestation signing key is stored as a JSON file in the report
signer's state directory. Different types of keys are supported:
- Ordinary keys that are protected by an existing persistent TPM key
such as the SRK or EK.
- Persistent TPM keys.
- Primary keys, which are recreated using a template on use.
When an ordinary or primary key is used, the report signer saves the
object context in its runtime directory. This context is used on future
invocations. This has the benefit that where a primary key is used, it
doesn't need to be recreated on each use. When an ordinary key is used,
we don't need to run TPM2_Load, which requires authorization with the
parent key, on each This authorization currently requires a policy
session for low-range EKs.
Regardless of the key type, it must be a restricted signing key. If no
key exists, an ordinary key is generated automatically.
The attestation key can also have an associated credential which is
attached to the signed report. The credential can be issued by a CA or
some other party during onboarding, and is presented to a verifier as
proof that the attestation key is authentic. It is considered an opaque
blob in order to not require it to be a specific format, such as a X.509
certificate. I've called this a "voucher" though because "cred" or
"credential" has other meanings in systemd.
As a follow-up to this, I plan to add a varlink interface for creating
attestation keys that can be used for report signing.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The referenced systemd-report-cgroup(8) man
page does not exist, so the reference is dropped.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The abstract gets a trailing period. There is
no man page for this helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this internal helper,
so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this internal helper,
so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this internal helper,
so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this internal helper,
so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The abstract is changed to the imperative.
There is no man page for this udev helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The abstract is changed to the imperative.
There is no man page for this udev helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this udev helper, so
none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. There is no man page for this udev helper, so
none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The help output had no abstract, so one is
added. There is no man page for this udev helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The help output had no abstract, so one is
added. There is no man page for this udev helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The help output had no abstract, so one is
added. There is no man page for this udev helper, so none is referenced.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The tool has no man page of its own, so
iocost.conf(5), which describes it, is referenced. The test now also looks
for commands in /usr/lib/udev, where the udev helpers are installed.
SetTimezone() and SetLocalRTC() updated the Context before writing
/etc/localtime or /etc/adjtime. If the write failed, D-Bus properties
showed the new value and a repeated request with the same value returned
success without retrying the file update.
Keep the write helpers Context-based, but save the old value before
installing the requested state. Restore the old Context value when the
backing file update fails.
Add TEST-45 coverage for failed alternate localtime and adjtime paths.
Follow-up for: f401e48c2d
Add a second COMMAND() for the mount.ddi helper namespace, like for
mount.storage and mount.mstack, so that it is exposed by --introspect-cli
too.
Fixes 1a54ce154c +
66246c98b5.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. An explicit "Lookup Keys" option group is added
so that the section heading stays the same.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. An explicit "Commands" option group is added
so that the section heading stays the same. The synopsis is now the same
as for systemd-sysusers, i.e. the "commands" are the options listed in the
Commands section. --help now goes through the pager, like other commands
with --no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. An explicit "Commands" option group is added
so that the section heading stays the same. The abstract is changed to the
imperative. --help now goes through the pager, like other commands with
--no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The odd "Verbs" option group marker is dropped,
so that all options are listed in one section after the verbs, with --help
and --version first. The synopsis now uses the generic "[OPTION…] COMMAND …"
form: a bare VERSION is not accepted as the first argument, and the man
page does not list it either. --help now goes through the pager, like
other commands with --no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The "Options" group marker after --help/--version
is dropped, so that all options are listed in one section after the verbs.
The synopsis now uses the generic "[OPTION…] COMMAND …" form: a bare
VERSION is not accepted as the first argument, and the man page does not
list it either. --help now goes through the pager, like other commands
with --no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. An explicit "Commands" option group is added
so that the section heading stays the same. The abstract is changed to the
imperative. --help now goes through the pager, like other commands with
--no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. --help now goes through the pager, like other
commands with --no-pager. The mount.storage helper interface is described
by a second COMMAND(), so that it is exposed by --introspect-cli too.
The custom help() and help_sudo_mode() are replaced by COMMAND()
descriptions for systemd-run and run0, and --introspect-cli is added to
both. run0 --help now goes through the pager, like systemd-run --help.