Depending on the packaging of tzdata, /usr/share/zoneinfo/tzdata.zi may
reference zones or links that are not actually present on the system.
E.g. on Debian and Ubuntu, there is a tzdata-legacy package that
contains "legacy" zones and links, but they are still referenced in
/usr/share/zoneinfo/tzdata.zi shipped by the main tzdata package.
Right now, get_timezoes() does not validate timezones when building the
list, which makes the following possible:
$ timedatectl list-timezones | grep "US/Alaska"
US/Alaska
$ timedatectl set-timezone US/Alaska
Failed to set time zone: Invalid or not installed time zone 'US/Alaska'
which feels buggy. Hence, simply validate timezones in get_timezones()
to avoid listing timezones that are not installed.
This is what the symlinkat.2 man page uses.
The old naming with 'to' and 'from', where 'to' is the symlink name
and 'from' is the symlink target is very confusing.
Follow-up for 892838911b.
We pin the parent directory of the specified directory via CHASE_PARENT,
but if we do that we really should mask off CHASE_MUST_BE_REGULAR,
because a parent dir of course is a dir, nothing else. The
CHASE_MUST_BE_REGULAR after all should apply to the file created in that
dir, not to the parent.
In https://github.com/systemd/systemd/issues/38842 it is reported that
we're again having trouble accessing EFI variables:
```
[ 292.212415] H (udev-worker)[253]: Reading EFI variable /sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f.
...
[ 344.397961] H (udev-worker)[253]: Detected slow EFI variable read access on LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f: 52.185510s
```
We don't know what causes the slowdown, but it seems reasonable to avoid
unnecessary read() calls. We would read the 4-byte attr first, and then
the actual value later. But our code always reads the value (and
discards the attr in all cases except one, when _writing_ the variable),
so let's optimize for the case where we read the value and read the
whole contents in one read().
This should allow us to get rid of a bunch of "fail:" labels, because we
can clean up tmpfiles relative to some atfd this way.
This only ports over a small number of potential users, but there's more
work to be done.
path_is_root_at() is supposed to detect if the inode referenced by the
specified fd is the "root inode". For that it checks if the inode and
its parent are the same inode and the same mount. Traditionally this
check was correct. But these days we actually have detached mounts (i.e.
those returned by fsmount() and related calls), whose root inode also
behaves like that.
Our uses for path_is_root_at() use the function to detect if an absolute
path would be identical to a relative path based on the specified fd
(sepifically: chaseat()), which goes really wrong if used on a detached
mount.
hence, let's adjust the function a bit, and let's go by path to "/" to
check if the referenced inode is the actual root inode in our chroot.
This was added in c242a08279, and AFAICT, the
code was never exercised, not even in the tests. With this chunk gone, if
anyone ever calls the function without any output params, we'll do open + fstat
instead of access, which will work just fine too.
I also thought about converting efi_set_variable() to use writev, but we don't
have loop_writev. I'm not sure if the loop around write here is important.
Coinceivably, it could make a difference it we were writing a long value.
The loop was introduced in b7749eb517, without
much comment unfortunately. So it doesn't seem worth the risk of changing this
to not use a loop, and writing loop_writev just for this also seems overkill.
In https://github.com/systemd/systemd/issues/38842 it is reported that we're again
having trouble accessing EFI variables:
[ 292.212415] H (udev-worker)[253]: Reading EFI variable /sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f.
...
[ 344.397961] H (udev-worker)[253]: Detected slow EFI variable read access on LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f: 52.185510s
We don't know what causes the slowdown, but it seems reasonable to avoid
unnecessary read() calls. We would read the 4-byte attr first, and then the
actual value later. But our code always reads the value (and discards the attr
in all cases except one, when _writing_ the variable), so let's optimize for
the case where we read the value and read the whole contents in one readv().
When SYSTEMD_COLORS is invalid, parse_systemd_colors() logs about it.
Logging helpers then call into parse_systemd_colors() to pretty-print
the log message, which then fails, so it logs about the failure,
rinse and repeat until segfault.
Follow-up for c8210d98a4
This reverts commit b177095bfa.
The original issue (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=375275,
https://github.com/systemd/systemd/issues/22168) was about having a block
cursor instead of a box cursor after VM reset, which doesn't seem particularly
urgent. OTOH, the patch causes a minor regression, where the splash screen is
cleared immediately and replaced by a blinking cursor. With the patch, we are
trading one visual issue for another visual issue. The second is probably more
noticeable, since some poeple put in quite a lot of work to have pretty boots
where the firmware splash screen is displayed until the login prompt pops up.
Avoiding a regression is more important than fixing a minor long-standing
issue, so let's revert this.
Fixes https://github.com/systemd/systemd/issues/38752.
Since c5de7b14ae
file searching implies a new mount api syscall by default,
to trigger automounts.
But, this is not necessary in most cases, e.g. when chasing
syspath in sd-device (actually this causes regression in umockdev,
see https://github.com/martinpitt/umockdev/issues/271).
Another example is reading unit files, especially .network files,
as automount may trigger mounting network filesystems...
Also, when this is used in NSS plugins, programs that load the
plugins may fail because of spuriously configured seccomp. See #38565.
Let's not trigger automount by default, and do only when explicitly
requested.
This introduces CHASE_TRIGGER_AUTOFS, and use it in
- service manager,
- bootctl and finding ESP/xbootldr,
- sysupdate,
- mountfsd,
- systemd-mount.
There may be several more places we should trigger automount, but let's
do that later.
Follow-up for c5de7b14ae.
Fixes#38565.
Replaces #38569.
Co-authored-by: Luca Boccassi <luca.boccassi@gmail.com>
This reverts commit 490aa05ca1.
As commented https://github.com/systemd/systemd/pull/38569#discussion_r2284978273,
the commit makes autofs check bypassed. Before the commit, when
CHASE_NO_AUTOFS is set, we did not shortcut chasing paths, and refused
any autofs mount points in the path. However, with the commit, the flag
was swapped but even when CHASE_AUTOFS is unset, the autofs check may be
skipped.
To fix the issue, rather than swapping the flag, we should introduce
another flag, say CHASE_TRIGGER_AUTOFS. This revert the commit, and in a
later commit, the new flag will be introduced.
Since https://github.com/systemd/systemd/commit/c5de7b14ae2e08d267d8d75bc88934ac6aa7dcd6
file searching implies a new mount api syscall by default,
to trigger automounts.
This is problematic in NSS plugins, as they are dlopen'ed inside
processes by glibc, for two reasons.
First of all, potentially searching on a networked filesystem
automount could lead to nasty surprises, such as the process
responsible for setting up the network filesystem trying to
search on that same filesystem.
More importantly, the new mount api syscall was never part of
the filesystem seccomp filter that we provide by default, and
given mounting/remounting/bind mounting is one of the possible
ways to bypass sandboxing it is very likely not allowed when
custom filters are used in sandboxed processes, if they don't
need to do these operations otherwise.
The filesystem seccomp mask we provide has been updated, however
this only takes effect on the next restart of a service. When
systemd is upgraded via a package upgrade, the new nss plugin is
installed and will be immediately dlopen'ed by glibc when needed,
without waiting for the process to restart, which means the existing
seccomp filter applies, causing the filter to trigger.
Given it's not really possible for any arbitrary program to
predict which NSS modules glibc will load, given programs do not
configure that and instead nsswitch is set up by the sysadmin,
it's impossible to handle at each process level. It's also not
possible to know when it will be triggered, given the plugin
is not linked in each binary tools like need-restart cannot
even pre-emptively restart services that may be affected.
This means in practice, upgrading from systemd << v258 to >= v258
requires a reboot to avoid either subtle or catastrophic system
failures.
By avoiding to trigger automounts in nss-systemd we can avoid
both issues.
userdb drop-ins are searched for in:
/etc/userdb/
/run/userdb/
/run/host/userdb/
/usr/local/lib/userdb/
/usr/lib/userdb/
none of which are supported as automounts anyway.
Note that this happens only when the userdbd service is not running,
as otherwise nss-systemd will go through the varlink IPC, rather than
doing the searches in-process.
So invert CHASE_NO_AUTOFS to CHASE_AUTOFS and set it in the places where
we do want to trigger automounts, like looking for the ESP.
Follow-up for https://github.com/systemd/systemd/commit/c5de7b14ae2e08d267d8d75bc88934ac6aa7dcd6
Fixes https://github.com/systemd/systemd/issues/38565
path_is_root_at() is supposed to detect if the inode referenced by the
specified fd is the "root inode". For that it checks if the inode and
its parent are the same inode and the same mount. Traditionally this
check was correct. But these days we actually have detached mounts (i.e.
those returned by fsmount() and related calls), whose root inode also
behaves like that.
Our uses for path_is_root_at() use the function to detect if an absolute
path would be identical to a relative path based on the specified fd
(specifically: chaseat()), which goes really wrong if used on a detached
mount.
hence, let's adjust the function a bit, and let's go by path to "/" to
check if the referenced inode is the actual root inode in our chroot.
The payload of a file_handle structure is not 64bit aligned. So far used
_alignas_() to align it to 64bit as a whole, which by accident has the
side-effect that the payload ends up being aligned to 64bit too, but
this is ugly, because it's really just an accident...
Let's do this properly, and just use proper unaligned 64bit reads to
access the field, and do not assume aligning the structure as a whole
also aligns the payload part of it.
Follow-up for: fd51a7d8b5
BLOCK_SIGNALS() is also used in nss modules. If an application is
running with a too strict seccomp loads our nss modules, then the
assertion may be triggered.
Fixes#38582.
Then, also make nss modules parse $SYSTEMD_ASSERT_RETURN_IS_CRITICAL
environment variable.
This also moves nss-util.c and nss-util.h from src/basic/ to src/shared/,
as they are not used by libsystemd.
On 32bit the union won't be aligned automatically, needs to be enforced:
Assertion '((uintptr_t) _p) % alignof(uint64_t) == 0' failed at src/basic/pidfd-util.c:251, function pidfd_get_inode_id_impl(). Aborting.
Follow-up for 9c039ef5ff
From the previous changes, bare-metal support has been added by using
the `detect_vm_cpuid()` which works only for x86_64 and i386 architecture.
Do not use this change for other architectures to avoid wrong result of
the detect-virt tool.
Follow-up for fb71571d3a.
Fixes#38125.
When booting Linux with ACPI in QEMU, the device tree is not used and
the DT based detection will not work. DMI values are accurate though
and indicate QEMU.
While detect_vm_dmi_vendor() was enabled for RISC-V in a previous commit,
it missed detect_vm_dmi(), so it was never actually used. Fix that.
Signed-off-by: Fabian Vogt <fvogt@suse.de>
Fixes the following build warning:
```
In file included from ../../../home/runner/work/systemd/systemd/src/basic/assert-util.h:4,
from ../../../home/runner/work/systemd/systemd/src/basic/forward.h:17,
from ../../../home/runner/work/systemd/systemd/src/basic/filesystems.h:4,
from src/basic/filesystem-sets.c:2:
src/basic/filesystem-sets.c: In function ‘fs_in_group’:
../../../home/runner/work/systemd/systemd/src/fundamental/assert-fundamental.h:76:9: warning: array subscript 42 is above array bounds of ‘const char[28]’ [-Warray-bounds=]
76 | log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/basic/filesystem-sets.c:559:18: note: in expansion of macro ‘assert_not_reached’
559 | default: assert_not_reached();
| ^~~~~~~~~~~~~~~~~~
```
Follow-up for aca4353ab2.
Similar to fc4a9c9ce6.
We had errno_to_name() which works for "known" errnos, and returns NULL for
unknown ones, and then ERRNO_NAME which always returns an answer, possibly just
a number as a string, but requires a helper buffer.
It is possible for the kernel to add a new errno. We recently learned that some
architectures define custom errno names. Or for some function to unexpectedly
return a bogus errno value. In almost all cases it's better to print that value
rather than "n/a" or "(null)". So let's use ERRNO_NAME is most error handling
code. Noteably, our code wasn't very good in handling the potential NULL, so
in various places we could print "(null)". Since this is supposed to be used
most of the time, let's shorten the names to ERRNO_NAME/errno_name.
There are a few places where we don't want to use the fallback path, in
particular for D-Bus error names or when saving the error name. Let's rename
errno_to_name() to errno_name_no_fallback() to make the distinction clearer.
With the previous commit, now CHASE_MUST_BE_DIRECTORY can be set with
CHASE_NONEXISTENT. Let's unconditionally set the flag to chase the
directory part of the conf file.
Otherwise, if it is called with CHASE_NONEXISTENT, when we call
stat_verify_directory()/_regular() the struct stat is for one of the
parent directory, rather than for the result path.
With this change, we can safely specify CHASE_MUST_BE_DIRECTORY/REGULAR
with CHASE_NONEXISTENT.
More importantly, chaseat() internally sets CHASE_MUST_BE_DIRECTORY when
the input path ends with "/", "/,", "/..". Hence, without this change,
we cannot specify CHASE_NONEXISTENT safely.
Follow-up for 90b9f7a07e.
We want to check if the magic we got from statfs() is one of the magics listed
for one of the file systems in the given group. To do this, we'd iteratate over
the file system names, convert each name to an array of magics, and compare
those to the one we got. We were using gperf-generated lookup table for this,
so the string lookups were quick, but still this seems unnecessarily complex.
Let's just generate a simple lookup function, because we can:
$ src/basic/filesystem-sets.py fs-in-group
bool fs_in_group(const struct statfs *st, FilesystemGroups fs_group) {
switch (fs_group) {
case FILESYSTEM_SET_BASIC_API:
return F_TYPE_EQUAL(st->f_type, CGROUP2_SUPER_MAGIC)
|| F_TYPE_EQUAL(st->f_type, CGROUP_SUPER_MAGIC)
|| F_TYPE_EQUAL(st->f_type, DEVPTS_SUPER_MAGIC)
|| F_TYPE_EQUAL(st->f_type, MQUEUE_MAGIC)
|| F_TYPE_EQUAL(st->f_type, PROC_SUPER_MAGIC)
|| F_TYPE_EQUAL(st->f_type, SYSFS_MAGIC)
|| F_TYPE_EQUAL(st->f_type, TMPFS_MAGIC);
case FILESYSTEM_SET_ANONYMOUS:
return F_TYPE_EQUAL(st->f_type, ANON_INODE_FS_MAGIC)
|| F_TYPE_EQUAL(st->f_type, PIPEFS_MAGIC)
|| F_TYPE_EQUAL(st->f_type, SOCKFS_MAGIC);
...
We flatten the nested lookup of group=>fs=>magic into a single level.
The compiler can work its magic here to make the lookup quick.
Previously, the gperf table was the main "source of truth", and additional
information (e.g. which file system names are obsolete) was scattered in
various files. We would then parse the gperf file, using python, awk, grep, and
bash, and use the results in various ways. This is hard to understand and
maintain. Let's replace all of this with a single python script that generates
the requested outputs as appropriate.
$ diff -u <(git show @{u}:src/basic/filesystems-gperf.gperf) \
<(src/basic/filesystem-sets.py gperf)
shows that the outputs are the same except for comments.
Similarly, 'src/basic/filesystem-sets.py fs-type-to-string' and
'src/basic/filesystem-sets.py filesystem-sets' can be used to view
the generated code.
The check that the kernel doesn't define any new file system magics is
converted into a normal test. It doesn't seem necessary to fail the build
when that happens.
I was looking at strace for systemd-getty-generator and noticed the call to
faccessat2(3</sys>, "", W_OK, AT_EMPTY_PATH), even though we already did
fstatfs(3</sys>), which should give us all the necessary information. Let's
only do this additional check when it's likely to yield something useful, i.e.
for network fses and otherwise skip the syscall.
The call to statvfs is replaced by statfs because that gives us the .f_type
field and allows is_network_fs() to be called.
I'm a bit worried that the is_network_fs() is somewhat costly. This will be
improved in later commits.
Previously, ordered_set_put_strdupv() and friends returns the number of
pushed entries, but that is potentially larger than INT_MAX (of course,
realistically, OOM is triggered in that case).
No caller uses the number of the new entries. Let's return 1 when at
least one element is added.
Fixes CID#1611523.
The change in 4d2e61211d
broke armv7 where uintptr_t is 4 bytes:
/* test_id */
Assertion '((uintptr_t) _p) % alignof(uint64_t) == 0' failed at src/basic/cgroup-util.c:108, function cg_get_cgroupid_at(). Aborting.
(gdb) p (uintptr_t)fh.file_handle.f_handle % _Alignof(uint64_t)
$9 = 4
Enforce that the structure is aligned as expected
Follow-up for 4d2e61211d
We went back and forth between 'prog.sh', files('prog.sh'), and
find_program('prog.sh'). We want to use files() or find_program() so that we
get a good error message if the file is missing. Behaviour of meson changed
over time, and in the past not all forms could be used in all places. For
example 0f4c4f3824 added find_program() in many
places to avoid repeated messages. But it seems that all recent meson versions
work fine with files().
find_program prints silly messages:
Program tools/make-man-index.py found: YES
(/home/zbyszek/src/systemd/tools/make-man-index.py)
Program tools/meson-render-jinja2.py found: YES
(/home/zbyszek/src/systemd/tools/meson-render-jinja2.py)
...
We know that those files will be found, they are part of the git checkout.
With files() this is gone and the meson output is easier to read.