Commit Graph
88260 Commits
Author SHA1 Message Date
Daan De Meyer 466662c8bd qmp-client: eagerly enqueue qmp_capabilities on connect, drop the handshake state machine
QEMU's QMP greeting is an unsolicited, informational, server-initiated advertisement
— it doesn't gate commands. The server accepts (and pipelines) commands the instant
the socket is open. We were using it as a trigger to build qmp_capabilities and
blocking callers via qmp_client_ensure_running() until the reply came back.

Build qmp_capabilities inside qmp_client_connect_fd() instead and let the JsonStream
output queue preserve FIFO ordering between it and any user command a subsequent
invoke() enqueues. That satisfies QEMU's only ordering requirement (cap must precede
other commands) without any blocking in the send path.

Fallout:
  - Collapse QmpClientState to {RUNNING, DISCONNECTED}. The three HANDSHAKE_* states
    and the QMP_CLIENT_STATE_IS_HANDSHAKE() macro go away.
  - Drop qmp_client_dispatch_handshake(); fold greeting-drop into dispatch_reply as
    a one-line shape check.
  - Drop qmp_client_ensure_running() and its qmp_client_send() call site. send()
    now only refuses when state == DISCONNECTED.
  - The qmp_capabilities reply lands on an ordinary slot whose callback logs a
    protocol-level error and force-disconnects if cap negotiation failed, matching
    the old EPROTO behaviour at the same observable boundary.
  - qmp_client_phase() no longer special-cases the old handshake states; it maps
    directly to READING / AWAITING_REPLY based on whether slots are in flight.

Test updates:
  - qmp_client_first_invoke_with_fd → qmp_client_invoke_with_fd. The scenario it
    was pinned to (push_fd+invoke staging order) has been structurally impossible
    since the QmpClientArgs rework in 8ad4adcb6f; eager-cap removes it a second
    way. The test now covers end-to-end fd-passing on the first invoke, accepting
    either recv carrying the single SCM_RIGHTS fd (AF_UNIX absorbs non-scm skbs
    forward into the next scm-bearing skb's recv, so the fd may surface with cap
    or add-fd depending on kernel scheduling — QEMU's FIFO fd queue handles either).
  - qmp_client_invoke_failure_closes_fds restructured around the new invariant:
    invoke no longer blocks and no longer returns ENOTCONN for a dead peer, so
    the fd-leak assertion moves to "still open while the JsonStream queue owns it,
    closed on client teardown" and the nested block is flattened into an explicit
    qmp_client_unref().
2026-04-24 14:29:31 +02:00
Daan De Meyer 5f420abe1a json-stream: stop concatenating fd-bearing queue items with prior output-buffer bytes
json_stream_format_queue() drains queued output items into the output buffer and
stages their fds in n_output_fds, relying on the downstream sendmsg() to deliver
bytes-and-ancillary atomically as one SCM_RIGHTS message. If the output buffer
already holds bytes (from a prior fast-path enqueue that hasn't been sent yet or
from a partial write), concatenating a new fd-bearing item's JSON into it means
the next sendmsg() ships the combined bytes with those fds attached — violating
the per-message fd boundary on transports where that boundary is load-bearing.

Bail out of the drain loop when we would cross that boundary, so the next
write() first sends the buffered bytes with no ancillary, then pulls the
fd-bearing item into a clean buffer and ships it on its own sendmsg.

This only produces an observable difference for SOCK_SEQPACKET / SOCK_DGRAM
consumers: on those transports each sendmsg() is its own datagram with its own
SCM_RIGHTS cmsg, so whether we concatenate matters. On AF_UNIX SOCK_STREAM
(today's sole consumer shape, used by sd-varlink and the QMP client) the kernel
absorbs a preceding non-scm skb forward into the next scm-bearing skb's recv,
so per-sendmsg separation is invisible to the receiver anyway — the guard is
cheap defensive sender hygiene there, not a behaviour change. It becomes load-
bearing the moment a SEQPACKET/DGRAM consumer wires JsonStream up.
2026-04-24 14:29:31 +02:00
Daan De Meyer 54c124eb6c qmp-client: make QmpSlot a public, refcounted, cancellable handle
QmpSlot now stores a back-reference to its QmpClient (mirroring sd_bus_slot)
and is exposed as a public refcounted type via qmp_slot_ref/qmp_slot_unref.
qmp_client_invoke() gains an optional QmpSlot **ret_slot out-parameter
matching sd_bus_call_async(): passing non-NULL hands back a reference whose
unref cancels the pending call (the callback is deregistered; a late reply
is logged and discarded as unknown-id).

Internally slots come in two flavours, following sd_bus's model: floating
(owned by the client's pending set, used when ret_slot is NULL) and
non-floating (ref held by the caller, slot holds a ref on the client).
qmp_slot_disconnect() centralizes the teardown so the reply-dispatched,
explicit-cancel, and client-teardown paths all converge on the same
idempotent cleanup.

qmp_client_call()'s sync slot is now non-floating and observes completion
by watching slot->client go NULL instead of set_contains() on an id.
2026-04-24 14:29:31 +02:00
Daan De Meyer 89a4dba4a7 test-qmp-client: drive the mock QMP servers through JsonStream
The mock servers previously framed messages by hand: loop_write()+"\r\n" on
the way out, a single read(fd, buf, 4095)+sd_json_parse() on the way in,
and a custom recvmsg()+CMSG_FOREACH() for the fd-passing test. That only
works when each write-on-the-wire happens to be delivered in its own
recv(); the moment a test wants to issue back-to-back commands without
waiting for replies, the kernel coalesces them and sd_json_parse() chokes
on two concatenated objects.

Route the mock servers through the same JsonStream transport the client
uses: a tiny mock_qmp_init/recv/send/send_literal layer over json_stream
takes care of the CRLF delimiter, the output queue, and SCM_RIGHTS. The
recv helper loops parse→read→wait so coalesced inbound bytes get fed out
one complete message at a time.

Drop the bespoke mock_qmp_recv_command() and replace it with
json_stream_set_allow_fd_passing_input() +
json_stream_{get_n,take,close}_input_fds() in the fd-first test. EOF
signalling moves from an explicit safe_close() to the
_cleanup_(json_stream_done) on the JsonStream.
2026-04-24 14:29:31 +02:00
Daan De Meyer 317714dd49 A few more conversions to the option and verb macros (#41797) 2026-04-24 11:32:31 +02:00
Zbigniew Jędrzejewski-Szmek d0cda17c6f sysupdate: convert to the new option and verb parsers
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek 349bb00979 sysupdate: reorder verb functions and parse_argv cases to match --help
--transfer-source= is moved up to a better place.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek bd2b0e6514 ptyfwd: convert to the new option parser
--help is the same except for common option strings and indentation.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek 90a068ab5d socket-activate: convert to the new option parser
--help is identical except for whitespace and common option strings.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek ee287be0ad sysctl: convert to the new option parser
--help output is the same except for common strings and command
reordering.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek 5e6ce50068 sysctl: rename local Option struct to SysctlOption
Avoid collision with Option struct from options.h (option parser).

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek d6f0f3ebdf tty-ask-password-agent: convert to the new option parser
--help is identical except for whitespace.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek 3f575a7aef keyutil: use OPTION_COMMON macros in a few places
Somehow those slipped through.
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek b8a96ab34f storagetm: convert to the new option parser
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek bcbf53b858 journal-gatewayd: convert to the new option parser
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Zbigniew Jędrzejewski-Szmek ed6cf6bed8 inhibit: convert to the new option parser
--help is the same, except for common options and a rewording of
description of --what.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 09:25:27 +02:00
Yu Watanabe 188ee8baa2 sd-dhcp-client: several refactoring for state machine of the DHCP client (#41796) 2026-04-24 16:06:02 +09:00
Simon de Vlieger 1b15c70e0d shared: find-esp fsroot check skip
When running with `SYSTEMD_RELAX_ESP_CHECKS=1` the fsroot check is still
being ran; preventing (for example) `bootctl` from operating a on a tree
as it expects a filesystem to be mounted where it finds the ESP (or
XBOOTLDR).

Expand the enum with an additional option to skip the fsroot checks and
enable it by default when `SYSTEMD_RELAX_ESP_CHECKS=1`.

See these RFEs [1], [2] for rationale.

[1]: https://github.com/systemd/systemd/issues/29871
[2]: https://github.com/systemd/systemd/issues/41707

Signed-off-by: Simon de Vlieger <cmdr@supakeen.com>
2026-04-24 08:33:56 +02:00
Daan De Meyer 8c3f64e61f tree-wide: Load libcrypto and libssl via dlopen()
Until now OpenSSL was linked into every binary and library that needed
cryptography, pulling libcrypto (and, for resolved, libssl) into the
address space of services that never touch them at runtime. This commit
moves all OpenSSL usage behind the same dlopen helper pattern that we
already use for other optional libraries (libpam, libseccomp, libxz, …)
so libcrypto/libssl are only loaded on demand.

The bulk of the work lives in src/shared/crypto-util.{c,h} (libcrypto)
and src/shared/ssl-util.{c,h} (libssl), which replace the previous
src/shared/openssl-util.{c,h}:

 - crypto-util.{c,h} declares every libcrypto function we call via
   DLSYM_PROTOTYPE() and resolves them inside dlopen_libcrypto().

 - ssl-util.{c,h} holds the libssl-specific DLSYM_PROTOTYPEs,
   dlopen_libssl(), and the SSL_freep cleanup helper, so translation
   units that only need libcrypto do not pull in libssl declarations.

 - Callers refer to the symbols through sym_* aliases rather than the
   original names.

 - Convenience macros that used to be provided by the OpenSSL headers
   (OPENSSL_free, BN_num_bytes, the sk_TYPE_* helpers, …) are
   reimplemented as sym_* wrappers so no code path needs to fall back
   to the linker-resolved symbols.

 - All _cleanup_ helpers are redefined in terms of the sym_* variants
   (EVP_PKEY_freep, X509_freep, BIO_freep, …) so cleanup attributes
   keep working without pulling in libcrypto symbols at link time.

 - The public crypto-util.c entry points (openssl_pubkey_from_pem,
   openssl_digest_many, openssl_hmac_many, openssl_cipher_many,
   kdf_ss_derive, kdf_kb_hmac_derive, rsa_* / ecc_* helpers,
   pubkey_fingerprint, digest_and_sign, pkcs7_new, x509_fingerprint,
   openssl_extract_public_key, pkey_generate_volume_keys, the load_*
   helpers, …) now call dlopen_libcrypto() at entry before touching any
   sym_* pointer.

The call sites across the tree have been converted to call
dlopen_libcrypto()/dlopen_libssl() at the appropriate entry point
before their first sym_* use, and to use sym_* variants throughout:

 - bootctl, sbsign, measure, pcrlock, pcrextend, tpm2-setup, repart,
   cryptsetup, cryptenroll, homectl, homed, homework, keyutil,
   sysupdate, creds, import, dissect-image, pe-binary, pkcs11-util,
   pkcs7-util, tpm2-util, creds-util. resolved additionally dlopens
   libssl for DoT.

The meson build files are updated to depend on libopenssl_cflags (a
new partial dependency that exposes include paths and compile flags
only, not the linker flags) instead of libopenssl for every target that
previously linked against OpenSSL. Nothing links against libcrypto or
libssl directly anymore.

A new src/sbsign/authenticode.c hosts the Authenticode ASN.1 type
definitions that used to live inline in sbsign.c. The OpenSSL
ASN1_SEQUENCE / ASN1_CHOICE / IMPLEMENT_ASN1_FUNCTIONS macros expand to
code that references libcrypto symbols directly, so to keep this
translation unit unlinked from libcrypto we redirect ASN1_item_* to
the sym_* variants via #define and wrap the ASN1_*_it() getters (which
appear as constant function pointers in static initializers) in small
trampoline functions that forward to the sym_* pointers at runtime.

test-dlopen-so gains assertions for dlopen_libcrypto and dlopen_libssl
so the dlopen contract is exercised in CI, and the openssl-specific
test was renamed from test-openssl.c to test-crypto-util.c to match
the new header naming.
2026-04-24 06:32:42 +02:00
Yu Watanabe e06115cb8b sd-dhcp-client: add FIXME comment about the state callback
At least currently, it is a theoretical concern, as networkd does not
change the client state in the callback.
2026-04-24 07:40:08 +09:00
Yu Watanabe 6ee065ed99 sd-dhcp-client: rework discover/request_attempts counter
discover_attempts should be reset only when
- the client is stopped, to make the counter starts from zero on
  the next invocation.
- we acquire a bound lease, to make the counter starts from zero
  when the lease is expired.

request_attempts should be reset only when the client enter a new state
that sends DHCPREQUEST, that is, when enter one of the REBOOTING,
REQUESTING, RENEWING, and REBINDING state.

This moves resetting counter to client_set_state() as it should happen
only when the state transition.
2026-04-24 07:40:08 +09:00
Yu Watanabe 2dff63a31c sd-dhcp-client: notify SD_DHCP_CLIENT_EVENT_EXPIRED only when we already have a bound lease
Otherwise, if we emit the notification without a valid bound lease, networkd
may be confused (of course should not, but for safety).

Also, increment the delay before calling client_start_delayed().
Otherwise, the first reboot is done instantaneously.
2026-04-24 07:40:08 +09:00
Yu Watanabe b831cd00e6 sd-dhcp-client: propagate failure in setting timer and stop the client
If we fail to setup timer event sources about the lease lifetime or
T1/T2, then the lease will be never updated, and the user (networkd)
will not receive any notification about the expire. The situation is
terrible. Let's stop the client with error code earlier, and notify the
failure to networkd.
2026-04-24 07:40:08 +09:00
Yu Watanabe bb5b2f9e5a sd-dhcp-client: simplify the implementation of IPv6 Only mode support
This drop delay after ACK, as it has many problems. See comment in
sd_dhcp_client_is_waiting_for_ipv6_connectivity() for more details.
This way, the logic becomes much much simpler.

Also, do not restart the client if we lost IPv6 connectivity in
sd_dhcp_client side, but restart the client by networkd. As,
sd_dhcp_client does not know if we can start the client or not,
e.g., the interface may be currently down.
2026-04-24 07:40:08 +09:00
Yu Watanabe f0b9b679ff sd-dhcp-client: simply enter renewing/rebinding state send DHCPREQUEST on T1/T2
It is not necessary to enable another timer event source to send
DHCPREQUEST from the T1/T2 timer event source. Just call the callback
function for sending message.

Also, T1 hits only we have a bound lease. Drop spurious conditions.
2026-04-24 07:40:07 +09:00
Yu Watanabe ffc3d5f812 sd-dhcp-client: initialize event source and so on in client_start_delayed()
When we start the client, any previous state/configuration should be cleaned.
Let's effectively do the same thing as client_initialize() in that
function.

This also several assertions in client_start_delayed() to
sd_dhcp_client_start(). These kind of checks should be done earlier.
2026-04-24 07:40:07 +09:00
Yu Watanabe 0b3cbfd1bc sd-dhcp-client: enter the SELECTING state before sending DHCPDISCOVER
Similarly, enter the REBOOTING state before sending DHCPREQUEST on reboot.

Also, this makes DHCPREQUEST message is sent several times also in REBOOTING
state. Previously, we wait about 4 seconds after DHCPREQUEST on reboot, and
entered the init state if no response. Now we wait 1 second after the first
DHCPREQUEST, resend another DHCPREQUEST, wait 2 seconds, then enter the
init state if no response. So, even in the worst case, we have slight
speed up.
2026-04-24 07:40:07 +09:00
Yu Watanabe ffafefbcce sd-dhcp-client: replace max_request_attempts with constant macro 2026-04-24 07:40:07 +09:00
Yu Watanabe c32105081f sd-dhcp-client: introduce client_send_discover()
No functional change, just refactoring.
2026-04-24 07:40:07 +09:00
Yu Watanabe 16d08897bb sd-dhcp-client: open socket when necessary and close it when unnecessary
To make gracefully ignore unexpected messages from outside at unexpected timing.
This potentially reduces work load to handle such messages, and slightly
reduces attack surface by malicious DHCP messages.

This also makes the socket fd is owned by the relevant IO event source.

Except for the performance optimization and security hardening, this
should not change any behaviors. So, just refactoring.
2026-04-24 07:40:07 +09:00
Yu Watanabe 3817ab9e14 sd-dhcp-client: add one missing assertion
Found and suggested by Claude. Nice!
2026-04-24 07:40:07 +09:00
Yu Watanabe 6a3b0e8475 sd-dhcp-client: move the object definition to the header
Then, we can split the long sd-dhcp-client.c into small pieces later.

This also drops redundant typedef, which is also in sd-dhcp-client.h.
2026-04-24 07:40:07 +09:00
João Taveira Araújo bbadd35596 networkd: allow route table names for VRF.Table=
Allow `[VRF] Table=` to accept route table names in addition to
numeric table identifiers. These may be predefined route table names
or names configured with `networkd.conf` `RouteTable=`.

There was an earlier attempt to make `VRF.Table=` accept names in
f98dd1e707, but it wired the setting to
`config_parse_route_table()`. That parser was a `[Route]` section
parser, not a generic scalar parser for netdevs: it expected
network/route parser state and created a `Route` object. It was
therefore reverted by 40352cf0c1.

This commit replaces the uint32 parser with
`manager_get_route_table_from_string()`, the generic table parser
already used by route/rule, DHCP/RA `RouteTable=`, and WireGuard
`RouteTable=` in `.netdev` files. The VRF semantics stay
unchanged. The commit retains the existing behavior of the
deprecated `TableId=` field.

Co-developed-by: OpenAI Codex <codex@openai.com>
2026-04-23 22:06:12 +02:00
Zbigniew Jędrzejewski-Szmek 42506e6dd1 Add 'data' parameter to options and convert to programs where it is useful (#41786) 2026-04-23 21:13:32 +02:00
Daan De Meyer 4985c70162 qmp-client: add synchronous qmp_client_call()
Add a synchronous counterpart to qmp_client_invoke() that pumps the
client's own process()/wait() loop until the reply for the issued
command id arrives, mirroring sd_varlink_call()'s contract: *ret_result
and *ret_error_desc are borrowed pointers into c->current, valid until
the next qmp_client_call(), and a QMP error surfaces as -EIO when the
caller doesn't ask for the description.

Factor the command-build + slot-insert + enqueue sequence shared with
qmp_client_invoke() into qmp_client_send(). A NULL callback marks the
slot as synchronous: dispatch_reply still matches on id (so unknown
ids continue to be logged and discarded, preserving async-only
robustness), but skips the TAKE_PTR + callback invocation and leaves
c->current pinned for qmp_client_call() to read out.

Cover the three paths in test-qmp-client: successful reply, QMP error
with ret_error_desc, and QMP error returned as -EIO.
2026-04-23 21:10:20 +02:00
Yu Watanabe 7aa8eabc8e dhcp-protocol: introduce several constants, string table lookups, and so on (#41710) 2026-04-24 03:54:55 +09:00
Zbigniew Jędrzejewski-Szmek b476483639 various: use empty block not break after OPTION_GROUP
Use the same style everywhere.
2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek 5d806036f9 TODO: add one more entry
This is something that should be fixed for usability, but it's something
between a missing feature and a bug. Since nobody has complained about
this, it probably can wait.
2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek 6fdc0f96f7 measure: also measure forgotten .efifw section 2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek ed469ffc07 measure: convert to the new option and verb parsers
Previously, we had a nice third 'UKI PE Section' column with the section
names. This is now moved into the help strings, which means that the nice
alignment is lost. Previous behaviour could be restored by constructing
the table manually, but I'm not sure if this is worth the trouble.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek 69d1f600d0 measure: reorder verb functions to match --help 2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek aa7ebb1b62 repart: use parse_tristate_argument_with_auto in one more place 2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek 785c9301de Use the new verb+option macros in pcrlock (#41669)
There's a lot of code movement, but the actual changes are
straightforward. Previously, the program was not marked as public, so
the --help/--version interface wasn't tested.
2026-04-23 19:15:30 +02:00
Zbigniew Jędrzejewski-Szmek 82a95edc92 repart: convert to the new option parser
The metavars for a few options were changed to be shorter, so that the
automatic alignment works better. Overall, I think the new version is
as least as legible as the old one.

The synopsis for -S/-C/-P is fixed, they do not take an argument.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek 04ad6079bb sbsign: convert to the new option and verb parsers
The options --private-key, --private-key-source, --certificate,
--certificate-source are almost identical in sbsign, but are described
slightly differently. Add OPTION_COMMON_ macros that are parametrized
to keep the purpose of the --private-key and --certificate options
in the description.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek b7f2c23da9 test-libudev: convert to the new option parser
The program now has a proper --help output. (Not on purpose. It's just
easier to do same thing as everywhere else.)

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek 39c5bee7c1 network-generator: convert to the new option parser
--help is the same except for whitespace.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek 108f6045cc shutdown: convert to the new option parser
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek 663a831089 stdio-bridge: convert to the new option parser
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Zbigniew Jędrzejewski-Szmek f658387505 test-chase-manual: convert to the new option parser
--help now has help strings. --no_autofs is renamed to --no-autofs.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00