password-cache= tracks both the cache mode and whether the option was
configured explicitly. The parser set arg_password_cache_set before
validating the value, so an invalid value was logged as ignored but
still blocked the PKCS#11 default no-cache policy.
Only mark password-cache= as configured after accepting read-only or a
valid boolean.
Repro:
build/systemd-cryptsetup attach sdscan /dev/null - \
pkcs11-uri=auto,password-cache=bogus
Before: warned ignored, then failed with the PKCS#11 cache error.
After: warned ignored, then continued to the device check.
Follow-up for: fd8ed7f26b
size= is specified in bits, but arg_key_size stores bytes after
parsing. The parser used arg_key_size as temporary storage before
validation. When the value was not divisible by 8, the warning said
the option was ignored, but the invalid bit count remained.
Parse into a local variable and update arg_key_size only after
validation.
Repro:
build/systemd-cryptsetup attach sdscan /tmp/plain.img /tmp/key \
plain,size=7
Before: warned ignored, then used key size 56 bits.
After: warned ignored, then kept the default key size 256 bits.
Follow-up for: 6131a78b4d
X entries inherit the cleanup age from the closest parent directory rule.
Inherit the age-by fields too, so parent rules such as m:1d keep their
full cleanup policy.
Reproducer:
mkdir -p /tmp/tmpfiles-ageby/parent/{child,other}
printf old >/tmp/tmpfiles-ageby/parent/child/file
printf old >/tmp/tmpfiles-ageby/parent/other/file
touch -d '3 days ago' /tmp/tmpfiles-ageby/parent/{child,other}/file
systemd-tmpfiles --clean - <<'EOT'
d /tmp/tmpfiles-ageby/parent - - - m:1d
X /tmp/tmpfiles-ageby/parent/child - - - -
EOT
Before:
child/file remained because X used the default age-by set.
other/file was removed by the parent m: rule.
Follow-up for 7f7a50dd15.
When --suppress-sync=yes was introduced in
4a4654e024 it filtered out openat2()
completely, as we can't check its "flags" argument because it's hidden
in an indirect struct. This was perfectly fine at that time, as
openat2() was quite new and software shipped with a fallback to
open()/openat() if the syscall wasn't present.
However, today the situation is different and an increasing number of
software is moving to openat2() without any fallback - tar [0] being the
most common one in the recent reports and workarounds, and attr recently
fixed a CVE by switching to openat2() [1] as well, to name a few.
Given that we already block all the sync-family syscalls and calling
openat2() with O_SYNC is relatively rare, let's just blanket-enable it
in the --suppress-sync=yes mode. This means that we might issue a
synchronous write when something calls openat2() with O_SYNC, but not
breaking the apps here feels like a reasonable trade-off, at least until
a better solution pops up.
Note that the same situation is in seccomp_restrict_sxid(), but allowing
the openat2() syscall there could actually have some security-related
implications under certain circumstances.
Resolves: #41868
[0] https://cgit.git.savannah.gnu.org/cgit/tar.git/commit/?id=75b03fdff48916bd0654677ed21379bdb0db016d
[1] https://cgit.git.savannah.gnu.org/cgit/attr.git/commit/?id=1cea2fc5e8b5c8a5f29abf1141399e01a57a3154
Resolve /etc/machine-id before checking the mount state and before
writing back, so symlinked targets are committed correctly.
Fixes: #43104
Follow-up for: efabf4e044
PrivateIPC= sets up a private mqueue mount for the service. When
CONFIG_POSIX_MQUEUE is disabled, mounting mqueue fails with ENODEV and
prevents the service from starting.
Treat ENODEV as an unavailable optional kernel feature while preserving
the private IPC namespace. Keep all other mount errors fatal.
Add coverage verifying that PrivateIPC= still creates a separate IPC
namespace when POSIX message queues are unavailable.
Fixes#42582
Previously, specifying multiple stacked netdevs of the same type required
repeating the corresponding setting, e.g.:
```
[Network]
VLAN=vlan_10
VLAN=vlan_20
VLAN=vlan_30
```
With this change, the same configuration can be written as:
```
[Network]
VLAN=vlan_10 vlan_20 vlan_30
```
Specifying an empty string now also clears all previously assigned stacked
netdevs.
Closes#43103.
af4c5730e5 tried to have meson stop
building all possible .standalone binaries in for tests. But it turns out
that those binaries are still built for meson-test-prereq, because they
are listed in executables_by_name, and we interate over
executables_by_name and add all exes found there as dependencies for two
tests: test-link-abi and libshared-unused-symbols. So we'd end up still
building all the .standalone binaries. To really fix this, define the
executables() for .standalone targets, but don't add them to this array.
A secondary change is to set build_by_default to true for .standalone
binaries if have_dlopen_tests is set. This means that we'll build more
binaries in the "build" phase, instead of only building them "on demand"
for tests. I think it is nicer to build everything that'll be used in one
step, and then only run the tests in the test target. For example, tests
may be run under root or in some special environment, and building thins
there is iffy.
The overall effect of this change should be that we stop building or
testing .standalone variants for binaries that we'll not later install,
unless -Ddlopen-tests=true is specified.
Also exclude .standalone binaries from check-help test. The test fails
for some binaries when the width is exceeded because of the ".standalone"
suffix in the name. The actual binary would be called without the
suffix, so the test is not testing a realistic scenario.
The option is generalized from a simple boolean switch that enables
a fixed list to a list-of-patterns.
The old value works, but is deprecated: -Dstandalone-binaries=true is translated
to -Dstandalone-binaries=repart,report,tmpfiles,sysusers,shutdown.
We could already build all normal executables as .standalone, but the
installation only supported a small fixes subset. This wasn't flexible
enough:
- packagers might want to provide additional standalone binaries then the
small subset that was already enabled
- but at the same time, whenever new binaries were added to this subset,
downstream packaging had to be adjusted in sync, at least in the case of
Fedora, because otherwise we'd get a complaint about unexpected .standalone
binaries in the temporary install root.
With the new option, downstreams can just specify the binaries that they
want to be installed in the .standalone variant.
As usual with this type of change, the build dir must be reprovisioned.
The user record loader currently uses a generic filename-or-path check
for shell and fallbackShell. This allows values that homectl rejects,
including relative names, control characters, colons, and trailing
slashes.
Use valid_shell() for all three record locations and cover the top-level,
matching per-machine, and status fallback fields at the loader boundary.
Fixes#43066
A calendar timer that is already waiting keeps the base timestamp it was
last armed from. When the wall clock is set backwards, that base can end
up in the future relative to the new realtime, and passing it to
calendar_spec_next_usec() schedules the next elapse relative to the old
future time instead of recalculating from now. systemctl list-timers
then keeps showing the stale pre-adjustment elapse (e.g. "3 years left"
after the clock moved back two years) and the timer never catches up.
Clamp the selected calendar base to the current realtime before asking
calendar_spec_next_usec() for the next occurrence. The clamp only kicks
in when the base is genuinely in the future, so Persistent=yes timers
whose last trigger is still in the past keep their catch-up behaviour and
we don't reintroduce the missed-run regression seen after suspend.
Fixes#6036.
1f76654f94 added support to build .standalone
variants of most binaries. test-dlopen-note.py is hooked in the test suite for
everything that can do .standalone, but this means that the .standalone
variants become a prerequisite for tests. This means that meson will build the
.standalone variants for all binaries before running tests, which takes quite a
bit of time in some situations. (Arguably, the dlopen test suite was excluded
by default, so maybe meson could be smart and figure out that those tests are
not enabled by default. But it doesn't seem to make this distinction.)
C lines copy symlinks as symlinks. The post-copy type check should
inspect the source symlink itself, not follow its target.
Reproducer:
src=/tmp/tmpfiles-src-link.$$
dst=/tmp/tmpfiles-dst-link.$$
conf=/tmp/tmpfiles-conf.$$
ln -s missing-target "$src"
printf 'C %s - - - - %s\n' "$dst" "$src" >"$conf"
systemd-tmpfiles --create "$conf"
Before:
Failed to stat($src): No such file or directory
status=73
$dst -> missing-target already existed
Follow-up for 8f6fb95cd0.
During early boot, interfaces may be renamed frequently, which can lead to
caching the driver name of a different interface. Invalidate the cached
driver whenever an interface rename is detected so it can be re-read using
the new name.
Follow-up for #42545.
Fixes#43099.
Plymouth encodes the password prompt length in a single byte.
Reject prompts whose length cannot be represented instead of
wrapping the encoded length while sending the complete message.
The scan pointer was advanced with utf8_next_char(), which blindly skips
utf8_skip_data[lead byte] bytes, so a line ending in a truncated multibyte
sequence like "foo\xF0" stepped over the NUL and the loop read past the end
of the string. Decode each character with utf8_encoded_to_unichar() and
propagate the error instead of measuring broken characters.
Fixes#43052.
Opening a shell script, Emacs notified me in the echo area:
sh-indentation is obsolete (since 26.1); use ‘sh-basic-offset’ instead
Commit 0c40aef7ef ("emacs: drop obsolete emacs property") got it backwards,
keeping sh-indentation rather than sh-basic-offset. The latter is an obsolete
alias for the former.
Opening the destination only proves that it exists. If copy_tree_at()
failed for any reason other than an existing destination, report that
copy error.
Reproducer:
name=tmpfiles-copy-bug.$$
src=/tmp/$name.src; dst=/tmp/$name.dst; conf=/tmp/$name.conf
mkdir "$src" "$dst"
printf payload >"$src/file"
chmod 500 "$dst"
printf 'C %s - - - - %s\n' "$dst" "$src" >"$conf"
systemd-tmpfiles --create "$conf"
Before:
exit=0
copied=no
Follow-up for 8f6fb95cd0.
Relative symlink targets are resolved from the directory containing the
link. Make the L? existence check use the same rule.
Reproducer:
tmp=$(mktemp -d /tmp/tmpfiles-link.XXXXXX)
conf=$(mktemp /tmp/tmpfiles-conf.XXXXXX)
printf data >"$tmp/target"
printf 'L? %s/link - - - - target\n' "$tmp" >"$conf"
systemd-tmpfiles --create --dry-run "$conf"
Before:
The target was checked root-relative, not beside the link.
Follow-up for b5dc805583.
I noticed that the use of sed in the `80-systemd-osc-context.sh` was
unnecessary, and upon writing a replacement in pure bash and testing it,
actually buggy. While in there, I also spotted some other minor things
that might be worth doing.
Getting rid of fork+exec for doing sed is probably the biggest win, but
there are still quite a few subshell invocations (that only do fork, not
exec). I haven't measured the overhead of those, but it seems that we
could get rid of those as well if we want.
Another thing I wonder about is whether we should emit an end= marker on
shell exit. There's no guaranteed way of doing it. Just as everything
else, we could get killed before getting a chance to do it. But also,
unlike PROMPT_COMMANDS, there's no "at_exit" array to hook into. Still,
we could ask if there is a 'trap exit' hook installed, and if not,
install one ourselves; if the user's bashrc subsequently overrides that,
so be it (though .bash_logout would be more appropriate).
%t and the other directory specifiers are parsed as normal paths.
They are prefixed by --root= later, so the specifier itself must stay
rootless.
Reproducer:
tmp=$(mktemp -d /tmp/tmpfiles-root.XXXXXX)
conf=$(mktemp /tmp/tmpfiles-conf.XXXXXX)
printf 'd %%t/tmpfiles-repro 0755 - - -\n' >"$conf"
systemd-tmpfiles --root="$tmp" --create --dry-run "$conf"
Before:
Would create directory $tmp/$tmp/run/tmpfiles-repro
Follow-up for de61a04b18.
Track which machine the cached address list belongs to and refresh it
when ResolveRecord() advances to another machine. This keeps A/AAAA
reuse for the same machine while avoiding mixed name/address records.
Reproducer: register two machines with private addresses 10.88.1.1
and 10.88.2.1, then call io.systemd.Resolve.Hook.ResolveRecord
with both A questions in one request.
Before: the answer for the second machine used its own name but
reused the first machine's address, e.g. resolve-bug-m2 returned
10.88.1.1 instead of 10.88.2.1.
Follow-up: 3cd929f837
KERNEL_INSTALL_CONF_ROOT overrides kernel-install config lookup. When it
was set and cmdline was absent, 60-ukify still fell back to
/proc/cmdline and embedded host boot options into the target UKI.
Return an empty base cmdline in that case, matching the adjacent
90-loaderentry behavior of not searching outside the override root.
Reproducer:
KERNEL_INSTALL_CONF_ROOT=$(mktemp -d) python3 -c '
import runpy
ns = runpy.run_path("src/kernel-install/60-ukify.install.in",
run_name="not_main")
print(ns["kernel_cmdline_base"]())'
Before:
The host /proc/cmdline was returned.
Follow-up for: 40c0c9d4bc
status with --static, --pretty, or --transient prints only the
selected hostname in regular output. JSON status output is built from
hostnamed's Describe data and remains a full status object.
Document this distinction so callers do not expect the name type
switches to turn JSON status into a single scalar value.
Follow-up for: ac8a4f6b78
Workers may return a newer embedded identity while processing
an owner update. Accept self-modifiable changes, but require
privileged changes to carry a trusted signature.
Follow-up for 70a5db5822
When a unit is stopped we try to destroy the credential mount point,
which might not exist. This logs at error level, which is noisy and
pointless. Downgrade to debug level on ENOENT.
systemd[1]: Failed to determine whether '/run/credentials/run-p119516-i119816.service' is the root file system: No such file or directory
Follow-up for 9dd2dab37e
The ExitType= documentation stated that ExitType=main "cannot be used
with Type=oneshot", which is incorrect: ExitType=main is the default
and works fine with Type=oneshot. The restriction actually enforced by
the code is that ExitType=cgroup is refused for Type=oneshot services
(see service_verify() in src/core/service.c).
Move the "cannot be used with Type=oneshot" note from the ExitType=main
bullet to the ExitType=cgroup bullet where it belongs.
Fixes#42327
Signed-off-by: Liu Zheng <liuzheng@uniontech.com>
A `\u` escape in `cunescape_one()` was accepted for any 16-bit value
except NUL. That range `0x0000`-`0xFFFF` includes the UTF-16 surrogates
`0xD800`-`0xDFFF`, which are not valid Unicode scalar values and cannot
be encoded as valid UTF-8.
The normal order of operations when iterating the GLib main loop is:
- prepare() -> sd_event_prepare()
- poll the file descriptors
- check() -> sd_event_wait()
- dispatch() -> sd_event_dispatch()
GLib does not guarantee that check() is always called between two
consecutive prepare() invocations. When another thread attaches or
removes a source with poll fds while the main thread is inside
poll(), g_main_context_check_unlocked() returns immediately without
calling any source's check() callback.
Since the sd_event GSource adapter maps prepare/check/dispatch to
sd_event_prepare/sd_event_wait/sd_event_dispatch, a skipped check()
leaves sd_event in ARMED state. The next prepare() then hits
assertion "e->state == SD_EVENT_INITIAL".
The following program reproduces the faulty scenario by creating a
thread that attaches a new fd during the poll phase:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <glib.h>
#include <systemd/sd-event.h>
#include <unistd.h>
/* from glib-event-glue.c */
extern GSource *g_sd_event_create_source(sd_event *event);
static gpointer thread_func(gpointer user_data) {
GSource *source;
GPollFD pollfd;
int fd;
g_usleep(G_USEC_PER_SEC / 10);
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0)
abort();
source = g_source_new(&(GSourceFuncs){0}, sizeof(GSource));
pollfd.fd = fd;
pollfd.events = G_IO_IN;
pollfd.revents = 0;
g_source_add_poll(source, &pollfd);
g_source_attach(source, NULL);
g_source_destroy(source);
g_source_unref(source);
close(fd);
return NULL;
}
int main(int argc, char *argv[]) {
sd_event *event = NULL;
GSource *source;
GThread *thread;
int i, r;
r = sd_event_default(&event);
if (r < 0)
return 1;
source = g_sd_event_create_source(event);
if (!source)
return 1;
g_source_attach(source, NULL);
for (i = 0; i < 50; i++) {
thread = g_thread_new("check-skip", thread_func, NULL);
g_main_context_iteration(NULL, TRUE);
g_thread_join(thread);
g_main_context_iteration(NULL, FALSE);
}
g_source_destroy(source);
g_source_unref(source);
sd_event_unref(event);
return 0;
}
When the program uses the current glue code, it crashes with:
Assertion 'e->state == SD_EVENT_INITIAL' failed at src/libsystemd/sd-event/sd-event.c:4560, function sd_event_prepare(). Aborting.
Fix the problem by skipping sd_event_prepare() if the event is
already ARMED: it was already prepared in a previous iteration and
it can be polled immediately.
Claude pointed out that while rather unlikely, it is possible for the USER and
HOSTNAME environment variables to contain problematic characters that require
escaping. Now that that escaping no longer involves the fork+exec overhead of
calling sed, let's ensure those fields do get put through the escape routine.
Refactor __systemd_osc_context_escape so that it not only takes the value and
prints that, but also the format specifier used for emitting the field. That
way, we avoid an extra subshell (i.e. fork+pipe and all that overhead), and
combined with the previous commit, we now only spawn one subshell instead of
two per start= sequence.
That could be reduced to zero, if the "callers" were rewritten to something
like
printf "\033]3008;start=%.64s;type=shell" "$systemd_osc_context_shell_id"
__systemd_osc_context_common
printf "\033\\"
but that will mean that the sequence is not emitted with a single write()
system call [which isn't really guaranteed currently either, just very likely],
so some background process could end up writing to the middle of the sequence,
thus losing that output and mangling the OSC3008 info. This in turn could be
overcome by building the whole sequence in a shell variable using 'printf -v'
and only printing at the end, but that would be a somewhat invasive change.
Now that the %s specifier used to embed the common fields in the output appears
immediately before the cwd= field, we can just emit that cwd= field as part of
the common fields.
Not because it is required by the specification, but it will make the following
patches simpler. Also, the fact that the spec explicitly does call out that
type= can appear at the end or in the middle suggests that people would
normally expect it to appear at the beginning.
There's really no point in having bash do arithmetic expansion on the
systemd_exitstatus variable, i.e. have it convert the string to a number, do no
actual arithmetic, then convert it back to a string to be used as the argument to
the printf, which will again convert it to a number for the %d specifier, and
finally emit it as a decimal. Also, it deviates for no obvious reason from how
it is passed to printf in the "probably died by signal" case just above.
The %.20d specifier was introduced in 2d738a0aee ("profile/systemd-osc-context:
Enforce length limits"). But, for numeric conversions, the precision is not an
upper bound, but rather a lower bound on the output width, padding as necessary
with 0 on the left. So as-is, this does not in fact limit the output to at most
20 characters.
Of course, in practice, pids on linux are never greater than 2^22, and
certainly never larger than what would fit in a 20-digit decimal. On the other
hand, that more or less guarantees that the pid= field is always emitted with
12+ leadings zeroes, which is a bit silly. Moreover, a leading 0 can cause a
parser to treat it as octal.
Since $$ does expand to the PID in decimal, just print that as a string, with the
enforced 20 character limit.
Bash is perfectly capable of performing the simple substitutions needed for
escaping according to the OSC 3008 spec, so there is no need for the fork+exec
and other overhead of calling sed.
In fact, when writing a test for ensuring that this is a drop-in replacement, I
found out that the current sed method is flawed: If $PWD contains newline
characters, they are passed through unchanged, because sed obviously is
line-oriented.
I do not know which bash version started supporting
${foo//pattern/replacement}, but I ran the below on all Debian images from docker
hub going back to Debian 6 (EOL 2016), carrying BASH_VERSION =
4.1.5(1)-release, and they all succeeded. Since the logic otherwise relies on
PROMPT_COMMAND being an array variable, which happened in 5.1, this should be
all good.
=== test.sh ===
#!/bin/bash
echo "BASH_VERSION = $BASH_VERSION"
ret=0
using_sed() {
echo "$1" | sed -e 's/\\/\\x5c/g' -e 's/;/\\x3b/g' -e 's/[[:cntrl:]]/⍰/g'
}
pure_bash() {
local str="$1"
str="${str//\\/\\x5c}"
str="${str//;/\\x3b}"
str="${str//[[:cntrl:]]/⍰}"
printf "%s" "${str}"
}
do_test() {
local r0="$1"
local r1="$(using_sed "$r0")"
local r2="$(pure_bash "$r0")"
local s0="$(printf '%s' "$r0" | od -A x -t x1z -w40 | head -n1)"
local s1="$(printf '%s' "$r1" | od -A x -t x1z -w40 | head -n1)"
local s2="$(printf '%s' "$r2" | od -A x -t x1z -w40 | head -n1)"
if [ "$r1" != "$r2" ] || [ "$s1" != "$s2" ] ; then
echo "Input: $s0"
echo "sed: $s1"
echo "bash: $s2"
ret=1
fi
}
do_test ''
do_test "one ; semicolon"
do_test "two ; semicolons ;"
do_test 'bs \ sc ; bs \ sc ;'
do_test $'\t'
do_test $'sc ; cntrl \x01 \x02 \x03 \x1f \t bs \\ bs \\ sc ; '
do_test $'sc ; tab \x09 del \x7f bs \\ ;'
# The last cases show that the existing function doesn't actually work in
# the case of $PWD containing a newline character, because sed is
# line-oriented, so a newline character will never be replaced.
if [ "$1" = "all" ] ; then
do_test $'embedded \n newline'
do_test $'ending in newline\n'
fi
exit "$ret"
=== test.sh ===
This partially reverts 13ce62caba.
Sometimes, the kernel passes non-safe characters in uevent files,
such as the UNIQ= property for USB serial devices.
Instead of rejecting the entire uevent file, let's only ignore the
specific key-value pairs that contain non-safe characters.
Fixes#43008.
The modern hwdb.bin format contains the filenames of the input data that
makes up the database. This is useful but in offline builds where --root
is used, the filenames are the full build paths including the specified
root. This introduces build paths and thus information leakage and
non-reproducible data.
Solve this by stripping the root prefix off the original path when
passing to import_file.