* 60fbc2d955 Update systemd to version 261.2 / rev 473 via SR 1368021
* c32d9727e6 Update systemd to version 261.1 / rev 472 via SR 1365923
* 74fd672013 Update systemd to version 260.3 / rev 471 via SR 1362701
* 769e1c4254 Update systemd to version 260.2 / rev 470 via SR 1361320
SUSE regularly builds packages into the future to track issues like the the
ones that might happen in 2038:
https://www.reddit.com/r/linux/comments/xjtf3q/in_the_year_2038/
Make sure that os_release_support_ended() doesn't fail in this case.
PS: on 32-bit systems time_t cannot represent dates past 2038, so use a safe
date there instead.
systemd-importd runs qcow2_detect()/qcow2_convert() over images it has just
downloaded (see pull-raw.c), so the header, the L1/L2 tables and every offset
and cluster descriptor in them are attacker controlled. There is a manual test
for the happy path, but nothing that feeds it a malformed image.
The corpus is two images, a plain data cluster and a zlib-compressed one (i.e.
decompress_zlib_raw()), at the 512 byte minimum cluster size and trimmed to the
last byte the converter reads, so 2K each. A zero cluster and a QCOW3 header are
a flipped descriptor bit and a bumped version field away from these, so they are
left to the fuzzer rather than carried in the tree.
fuzz-compress only ever feeds the decompressors their own output: it compresses
the fuzzer input and then decompresses the result, so the stream the decoders
see is well formed by construction. The blobs they get in reality come out of
journal files, systemd-journal-remote streams, coredumps and downloaded images,
i.e. from wherever the data was written, which is not necessarily somewhere we
trust.
So hand them the fuzzer input directly instead, across all four entrypoints:
decompress_blob(), decompress_startswith(), decompress_stream(), and the
decompressor_detect()/decompressor_push() pair that systemd-importd feeds from
the network. The latter is pushed in chunks, so that the decoders see the same
fragmentation a real download produces. The decompressed size is capped, as an
unbounded decode of a hostile blob measures the allocator rather than the
decoder.
The corpus carries the two truncated stream headers that used to send
decompress_startswith() allocating until OOM, fixed in the previous commit.
decompress_startswith() decodes just enough of a blob to compare its leading
bytes against a prefix, and grows the output buffer whenever a round of
decoding came back with less than prefix_len + 1 bytes decoded. That growth is
only the right answer while the decoder actually wants more output room. If it
instead ran out of input, i.e. the stream is truncated, then no amount of extra
room will help, and the gzip and bzip2 paths double their allocation on every
iteration until the process is out of memory.
Neither decoder lets us tell the two cases apart by return code alone:
inflate() reports the stalled stream as Z_BUF_ERROR, which we cannot simply
refuse since that is also how it asks for a bigger output buffer, and
BZ2_bzDecompress() does not distinguish them at all, it just keeps saying
BZ_OK. The output space left over does tell us, though: a decoder that stopped
without filling the buffer we gave it is waiting for input that is not coming,
so report the stream as corrupt instead of growing.
A 10 byte gzip header, or a 4 byte bzip2 header, with nothing behind it was
enough to reach a single 4 GiB allocation this way. The xz and zstd paths
already terminate, the former because liblzma turns a stalled stream into
LZMA_BUF_ERROR.
Note that no caller can reach this today: the only non-test caller is
decompress_startswith_journal(), and compression_supported_journal() admits
only NONE/XZ/LZ4/ZSTD. It is a trap for whoever wires up the other two, so
let's close it now.
When networkd starts or restarts, links are enumerated in ifindex
order. A slave enumerated before its master cannot register itself in
link_append_to_master(), as the master Link object does not exist yet.
The master then wrongly believes it has no slaves until the next
RTM_NEWLINK message for the slave arrives.
The stale slaves set affects operational state propagation
(degraded-carrier detection) and any code that inspects the slaves of
a master.
For instance, on restart, when networkd thinks that the master has no
slaves yet, we try to set the bond fail-over policy, which the kernel
then refuses because in reality the bond does have slaves.
To fix the issue, this updates the list of slaves after enumeration.
Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
Currently `RestrictFileSystemAccess` isn't trying hard enough to enforce
W^X and thus there are still places where an executable and writable
mapping can be created:
* `/proc/<pid>/mem` `FOLL_FORCE` writes
* `PTRACE_POKE{TEXT,DATA}` `FOLL_FORCE` writes
* `MAP_PRIVATE | MAP_EXECUTABLE` memory mappings
Let's block all of these mechanisms. Do note that
`RestrictFileSystemAccess` is still in very active development and also
cannot meaningfully be used on general purpose distros and systems.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Describe the system-wide W^X rule and the new proc_mem.force_override=never
and seccomp prerequisites, and drop the advice to block writable and
executable mappings by other means, which the policy now does itself.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
The kernel silently ignores command line options it doesn't know. So a
kernel without CONFIG_PROC_MEM_* would pass the command line check while
still allowing FOLL_FORCE memory overwrites. Write one byte through
/proc/self/mem into a private read-only anonymous page. That can only
succeed with FOLL_FORCE writes supported.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
In addition to PTRACE_POKE{TEXT,DATA} /proc/<pid>/mem can also be used
to FOLL_FORCE write into a trusted process's executable pages. Require
proc_mem.force_override=never.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
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.
Install a ptrace seccomp filter from PID 1 if RestrictFileSystemAccess=
is requested. Every process it spawns will inherit it.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
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>
Right now RestrictFileSystemAccess= checks that a file comes from a
trusted dm-verity device, but it doesn't guard against mapping that file
and making use of COW modifications. So a MAP_PRIVATE mapping of a
trusted binary can be made writable, modified, and executed, while the
vma still points to the trusted file and the pages are
attacker-controlled anonymous copies.
Enforce W^X: deny any mapping that is writable and executable at once,
and refuse to make a private file mapping executable once it has been
modified through copy-on-write.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Make sure the tests can tell the difference between an actual denial and
a probe that simply cannot be run.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
If dbus dies, it is then immediately reactivated by dbus.socket as soon
as a client reconnects. In that case pid1's own connection to the bus
drops and is reestablished by manager_recheck_dbus() (which comes from
the unit_notify() when dbus.services goes back to being running).
As part of bringing the bus back up, bus_setup_api() issues
GetNameOwner() for every name we watch on behalf of a BusName= unit.
For a Type=dbus service this is a problem. Consider this scenario:
1. spearmint.service is Type=dbus, owns com.example.Spearmint, and is
running.
2. The broker crashes and is re-activated through dbus.socket.
3. spearmint's client connection dropped too, so it is now reconnecting
to the new broker to grab its name again.
4. pid1 racily reconnects first given it is triggered the moment
dbus.service reaches SERVICE_RUNNING, whereas spearmint is an
ordinary client that must first notice its own disconnection and thus
when we do GetNameOwner() com.example.Spearmint is reported as having
no owner.
5. service_bus_name_owner_change() sets bus_name_good = false, and since
service_good() returns false for a Type=dbus service without its
name, service_enter_running() stops the (perfectly healthy, other
than dbus kicking the bucket temporarily) service.
In other words, a broker restart can tear down running Type=dbus
services that did nothing wrong, really.
So, to fix this, we can use the fact that a NameOwnerChanged signal is
definitive. That is, the name's owner changed while we were connected,
so a service that crashes or drops its name can still be stopped
immediately. By contrast a GetNameOwner() reply is less authoritative.
There is, importantly, no change to how losing the name on a live
connection works, we only give grace on reconnect.
For a Type=dbus service we sometimes want to keep treating it as running
while its bus name has briefly gone away (for example, due to a broker
restart).
SERVICE_RUNNING_REVALIDATING is active and keeps its main process like
SERVICE_RUNNING, but it's deliberately not part of the runtime timer
set, so RuntimeMaxSec= is paused while we sit in it.
Newly allocated new_res variable was left unreferenced if memory
allocation failed in ndisc_option_add_encrypted_dns_internal().
Co-authored-by: Siteshwar Vashisht <svashisht@redhat.com>
While keyring_describe() allocates a 64 byte buffer it still passes the
value of c as the buffer length. It's -1 on the first iteration. So
keyctl_describe_key() copies the whole description whenever buflen >=
its length. So any key whose description exceeding 64 bytes overflows.
Pass the actual buffer size.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[zjs: adjust comment]