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).
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__))
| ^
```
Similar as the previous commit: the field was renamed by accident, and
we should revert to the old name to not break compat needlessly, and
because the old name actually made sense, given the underlying .transfer
file knob is AppStream=
The "isEnabled" name was changed from "enabled" post v261 by accident
(because a6f7ded859 replaced json
formatting via table formatter to a native json generator which was
introduced for varlink, which changed the names). THis was later made
official in #43603, but it should rather have changed things back to the
original name, in particular as the underling .feature file field
actually is called "Enabled=" and not "IsEnabled=".
We really should take care to generate the same names for Varlink JSON
data as for the data returned by the systemd-sysupdate cli.
a6f7ded859 ensured that, so that's great.
But at the same time I think the varlink names should be adjusted to the
old names, since varlink support for this was just added in this cycle.
Given that v262 is not tagged yet, let's now revert to the old name.
For re-use in systemd-gpt-auto-generator. This also makes it generic
across sysext/confext - no planned use for this, but to avoid confusion
later when someone tries to use it on a confext.
Encrypted credentials produced by systemd-creds are stored as Base64.
Decode them before decrypting in read_credential_with_decryption(), while
leaving plaintext credentials unchanged and retaining their precedence.
Bound the decoded encrypted input and report oversized credentials
explicitly. Match the plaintext reader's string semantics by rejecting
embedded NUL bytes when no size output is requested, while preserving
binary payloads for callers that request their size.
Add regression coverage for missing and malformed credentials, plaintext
precedence, decoded size boundaries, single-line and wrapped Base64,
empty strings, and binary data. Keep test outputs and host secrets scoped
to private fixtures.
Fixes#43621
The feature JSON payload switched to `id`, `isEnabled`, and `appstream`,
and made `documentation` an array of URLs.
`updatectl` still parsed legacy table-derived names and a single URL.
This broke feature JSON parsing and made output inconsistent.
Features without documentation could also cause a null dereference.
Align `updatectl` with the current schema and preserve all
documentation URLs across sysupdate, D-Bus, and Varlink payloads.
Propagate condition evaluation errors through `condition_test_list()`
and `feature_is_suggested()`, with consistent JSON error handling and
tests.
The `suggested` field is now optional and always a boolean when
present; it is omitted rather than set to an error string when
SuggestOn*= conditions cannot be evaluated.
Add `suggested` metadata and document the field transition.
Follow-up for 3e34ccf6df.
Follow-up for 75a247d4de.
Follow-up for 40e727c93b.
Fixes#43603
Make condition_test_list() return negative errno on condition
evaluation errors instead of coercing them to false. This allows
callers to distinguish between a condition that evaluated to false
and a condition that failed to evaluate.
Callers that only need a boolean result explicitly check for a
positive return value, preserving their current behavior.
Add comprehensive unit tests covering error propagation with trigger
and non-trigger conditions. Tests use uname_architecture() to get the
runtime architecture instead of native_architecture(), ensuring they
work correctly in environments where binaries run under architecture
emulation.
Standard Linux POSIX ACL tag values are 0x00, 0x01, 0x02, 0x04, 0x08,
0x10 and 0x20. ELEMENTSOF(tag_map) evaluates to 33, which is one past
the last valid index 32.
dns_packet_append_name() appends a name's labels and then the root byte
that terminates it. A failure on that last byte returned directly,
leaving both the labels on the packet and the compression entries this
call had added -- entries naming offsets the caller then truncates away.
Take the same rollback path as every other failure in the function.
Independent of the map invariant fixed before it: this is reachable
whether or not any offset exceeded the pointer range.
dns_packet_append_name() added every name it appends to the packet's
compression map, including names written at offsets >= 0x4000 that an
RFC 1035 compression pointer (14 bits) can never reference. Such
entries are not just useless -- when the same name occurs again, the
lookup finds it, the pointer cannot be emitted, the code falls through
to appending the labels again, and the re-insertion into the map then
fails the whole packet build with hashmap_ensure_put() returning
-EEXIST.
This is easily triggered with mDNS: an unsolicited DNS-SD announcement
covering a zone with a few hundred services exceeds 16KiB, and
dns_scope_announce() then fails with "Failed to build reply packet:
File exists".
This lifts the failure only: dns_scope_announce() still builds the whole
zone into one packet and hands it to the socket as a single datagram,
fragmented as the link requires. Splitting announcements across
MTU-sized packets, as RFC 6762 section 17 asks, is done separately.
Only insert a name into the map if its offset is pointer-expressible,
making "mapped implies referenceable" a map invariant. Re-occurrences of
out-of-range names are emitted as labels again -- the only encoding RFC
1035 section 4.1.4 permits in that case -- still compressed from the
first suffix that is mapped in range.
The lookup restates that range as control flow rather than asserting it.
Under -Db_ndebug=true, which CI builds, assert() is
__builtin_unreachable(), so an out-of-range entry would put 0xC000 | n
truncated to 14 bits on the wire -- a pointer to an arbitrary earlier
offset -- where falling through emits the labels instead. This layer is
shared with unicast DNS, DoT and LLMNR.
The pointer's tag bits and its offset bound are now named once, in
dns-def.h next to the other wire-format constants rather than in
dns-packet.h, since the format is RFC 1035's and not this packet
abstraction's -- dhcp-message.c open-codes the same two bits to parse
compressed names out of DHCP options. Compile-time checks pin that the
two partition the 16-bit field and that the tag is its top two bits,
which is what lets the reader take it from the first octet alone.
The offset's other bound becomes control flow along with it: it was an
assert(), which under -Db_ndebug=true is no check at all, for the bound
whose violation puts a pointer to the wrong bytes on the wire. It is
also tightened to the start of the name being appended rather than the
end of the packet, which is the "prior occurrence" RFC 1035 section
4.1.4 allows a pointer to address and what dns_packet_read_name()
enforces on the way in.
Add regression tests, including one through dns_packet_append_rr() --
the path the reported failure came from, where the name append is nested
inside the rdlength backpatch and two further rollbacks -- and one for
the reader's label-type dispatch, which the renamed constants touch.
machinectl clone --read-only ignored the requested read-only mode when
cloning a foreign-UID-owned directory because the unprivileged clone path
did not receive the read_only argument.
Pass the flag through and apply the immutable bit via the already-open
destination directory fd after copying. Keep this best-effort, matching
the ordinary directory clone fallback, so failure to set the attribute
does not turn a completed copy into a reported clone failure.
Add a regression test using foreign-0 rather than a fixed UID. Verify
the cloned image's ReadOnly property, copied contents and ownership, and
that the immutable directory rejects new entries. Run this subtest only
when file attributes and the existing rootless nspawn prerequisites are
available, leaving the other machined tests unchanged.
unprivileged_clone() returns success when mountfsd_make_directory() fails.
Consequently, callers can report a successful clone even though the
destination directory was never created.
Return the original error instead of zero so the failed clone is
reported to the caller.
Add a regression test that places a regular file without an image suffix
at the destination path. Such a file is ignored by image discovery but
prevents directory creation. Check that cloning reports failure without
changing the file, then succeeds after the conflicting file is removed.
The comment was wrong. The average word is about 6 characters, so in
64 iterations, the probability of never landing on a word boundary is
~(1 - 1/7)**64, about 0.01%.
hostname_pick_word() used to seek around in the wordlist file and read
individual lines with read_line()/read_stripped_line(). Instead, slurp the
whole file into memory use offset arithmetic. The wordlists are small, so
reading them entirely is faster and there is really no reason to do the
complicated thing. The new code is 15% faster (the slow parts are the
hashing and chaseat, they actually dominate over the reading of the data).
The "raced with truncation" case is gone, since the buffer is a consistent
snapshot of the file.
The random offsets derived from the machine ID are unchanged, so the
picked words stay the same.
This is useful to check if how fast the code is (painfully slow) and whether
worlds indeed are selected with a flat distribution probability (they are).
The code is slow because the hashing and because chaseat is exteremely
inefficient :(
PTRACE_POKETEXT and PTRACE_POKEDATA use FOLL_FORCE to forcibly write
into a tracee's memory. That includes executable read-only pages. If we
restrict execution to trusted binaries PID 1 must enforce that it's
impossible to abuse this to get untrusted code execution. Note, that
usermodehelpers are not subject to PID 1's seccomp filters.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
The man page udevadm(8) have explicitly documented that the option -V is
a short form of --version. Let's not hide the short form in the help
message.
This introduces OPTION_COMMON_VERSION_WITH_V then use it in udevadm,
udevd, and run0.
Alos, this moves print_version() to build.c, and renames it to
version_only(). Now the function is also used in udevd amd test-libudev.
With this change, the -V option is hidden only in dmi_memory_id and
scsi_id. So, this removes the OPTION_COMMON_VERSION_WITH_HIDDEN_V macro
and explicitly list the hidden option in their code.
Also add a note that the function does not support multiple groups. I
think that's fair, it doesn't make sense to generalize the functionality
when we're unlikely to ever use that. (Verb options are only used by
udevadm right now.)
Let's treat unset SYSTEMD_INVOKED_AS and SYSTEMD_INVOKED_AS='' the same.
I encountered this when testing various --help outputs. It is often
more convenient to override a variable with VAR= instead of removing it,
in particular on the commandline. But we'd then print help with the
program name missing. We look at the variable in two places, so adjust
both as in $subject.
All programs print their help through the COMMAND machinery now:
- the VERB_COMMON_HELP() and VERB_COMMON_HELP_HIDDEN() macros which
wired the help verb to a hand-written help() implementation are
unused — everything uses the VERB_COMMON_HELP_AUTO*() family,
- the verbs help table is only built internally, so the function
becomes static, as the TODO promised,
- help_abstract() and help_man_page_reference() are unused — the
generated help renders the abstract via print_wrapped() and the man
page links via print_man_links().
The hand-written help() functions were the only users of the
namespace+group help table builder, and they are all gone. The one
remaining caller in the verbs machinery is ported to
options_find_namespace() + options_get_help_table_group(), which
build the identical table.
Also drop OPTION_COMMON_INTROSPECT_CLI_ENTRY: it has no users, and
references the no-longer-existing _OPTION_ENTRY() macro, so it could
not even be used.
The variadic pair-wise variant was only used by the hand-written help()
functions to synchronize their verb and option tables. Those are all
gone, and the verbs machinery uses table_sync_all_column_widths().
The previous commit uses `parse_source_date_epoch()` for creating FAT
time stamps. Do the same in `mtools_exec()`, `mkfs.*`, and
`$E2FSPROGS_FAKE_TIME` instead of passing the raw environment variable.
That avoids these programs creating time stamps from a value we would
have rejected ourselves (unparsable, overflowing), read differently
(e.g. octal numbers), or from one that `secure_getenv()` declines to
look at under AT_SECURE.
Note: mtools derives file and directory timestamps from
$SOURCE_DATE_EPOCH since v4.0.20 (2018).
Add a `ts_clamp` argument to `copy_tree_at_full()` and
`copy_times_full()` that clamps copied inodes to a given time stamp.
This is the recommended `$SOURCE_DATE_EPOCH` semantics [1] for
reproducible builds. Their non-`_full` APIs keep existing behaviour by
clamping to `USEC_INFINITY`.
atime and mtime are clamped separately: a file that was merely read
after the epoch has to keep its mtime and still lose its atime. E.g. FAT
(EFI partition) stores an access date.
[1] https://reproducible-builds.org/specs/source-date-epoch/
Previously, verbs were skipped in --help automatically when their
.help field was nil. But this doesn't work in two ways:
- in introspection data we want to show the option, but marked as
deprecated
- in udevadm (and maybe other programs with verbs with own options in
the future), we need to show help for the verb.
So add an explicit flag to mark verbs as deprecated and skip them in
help even if .help is set. If there's a footer, print it highlighted
in red automatically.
A helper to print the help of a single verb, derived entirely from the
data in the SYSTEMD_VERBS and SYSTEMD_OPTIONS sections: the synopsis is
built from the verb name and argspec, the one-line verb help serves as
the abstract, the options come from the verb's option namespace, and the
man page links from the command the verb belongs to. A flag allows
suppressing the man page links for callers which append custom sections.
Like the command-level CommandDescription.argspec, a verb's argspec is now
a nulstr, so that a verb may declare multiple alternative usage lines. The
verbs help table renders one synopsis line per nulstr entry in the
synopsis cell.
All verb argument specifications must gain an explicit NUL suffix. This
is a lot of churn, but I think this needs to be done. For now, there'll
be only one user of the new functionality (i.e. a verb with more than
one argspec), but I think we'll eventually want to use this in other
places too.