From cfd0f7785c4033f7cb454c62087c91183443ddca Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 3 Jun 2022 18:12:00 +0200 Subject: [PATCH] New upstream version 251.2 --- man/homectl.xml | 9 +- man/loader.conf.xml | 4 +- man/sd_bus_error-example.c | 18 ++++ man/sd_bus_error.xml | 68 +++++++++----- man/shutdown.xml | 29 +++--- man/systemd-creds.xml | 2 + man/systemd.automount.xml | 28 +++--- src/basic/cgroup-util.c | 15 +++- src/core/bpf-firewall.c | 64 +++++++------ src/core/bpf-foreign.c | 22 ++--- src/core/bpf-lsm.c | 70 ++++++--------- src/core/bpf-socket-bind.c | 48 +++++----- src/core/bpf-util.c | 34 +++++++ src/core/bpf-util.h | 5 ++ src/core/device.c | 60 ++++++++++--- src/core/meson.build | 7 ++ src/core/restrict-ifaces.c | 47 +++++----- src/fundamental/sha256.c | 39 ++++---- src/kernel-install/kernel-install.in | 21 ++--- src/libsystemd/meson.build | 3 +- src/libsystemd/sd-bus/bus-message.c | 32 +++++-- src/libsystemd/sd-hwdb/hwdb-internal.h | 1 + src/login/logind-dbus.c | 4 +- src/login/logind-utmp.c | 26 ++++-- src/login/logind.h | 2 +- src/resolve/resolved-dns-stub.c | 14 ++- src/shared/bpf-dlopen.c | 28 +++++- src/shared/bpf-dlopen.h | 3 +- src/shared/find-esp.c | 6 +- src/shared/seccomp-util.c | 2 +- src/shared/utmp-wtmp.c | 11 ++- src/shared/utmp-wtmp.h | 2 +- src/test/meson.build | 10 ++- src/test/test-seccomp.c | 2 +- src/test/test-sha256.c | 50 +++++++++++ .../tty-ask-password-agent.c | 2 +- src/userdb/userwork.c | 2 +- src/volatile-root/volatile-root.c | 2 +- test/TEST-24-CRYPTSETUP/test.sh | 85 +++++++++++------- test/fuzz/fuzz-bus-message/issue-23486-case-1 | Bin 0 -> 32 bytes test/fuzz/fuzz-bus-message/issue-23486-case-2 | Bin 0 -> 16 bytes test/fuzz/fuzz-bus-message/issue-23486-case-3 | Bin 0 -> 16 bytes test/test-functions | 5 ++ test/test-shutdown.py | 2 +- 44 files changed, 574 insertions(+), 310 deletions(-) create mode 100644 man/sd_bus_error-example.c create mode 100644 src/core/bpf-util.c create mode 100644 src/core/bpf-util.h create mode 100644 src/test/test-sha256.c create mode 100644 test/fuzz/fuzz-bus-message/issue-23486-case-1 create mode 100644 test/fuzz/fuzz-bus-message/issue-23486-case-2 create mode 100644 test/fuzz/fuzz-bus-message/issue-23486-case-3 diff --git a/man/homectl.xml b/man/homectl.xml index dacbd17b1..6fd534037 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -686,7 +686,7 @@ CIPHER MODE - BITS + BYTES TYPE ALGORITHM SECONDS @@ -696,7 +696,12 @@ Configures various cryptographic parameters for the LUKS2 storage mechanism. See cryptsetup8 - for details on the specific attributes. + for details on the specific attributes. + + Note that homectl uses bytes for key size, like + /proc/crypto, but cryptsetup8 + uses bits. diff --git a/man/loader.conf.xml b/man/loader.conf.xml index d5abb1c04..509412ec9 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -121,7 +121,7 @@ will be stored as an EFI variable in that case, overriding this option. - If set to menu-hidden or 0 no menu + If set to menu-hidden or 0 (the default) no menu is shown and the default entry will be booted immediately. The menu can be shown by pressing and holding a key before systemd-boot is launched. Setting this to menu-force disables the timeout while always showing the menu. @@ -211,7 +211,7 @@ beep - Beep n times when the n-th entry in the boot menu is shown (default disabled). + Takes a boolean argument. If timeout enabled beep every second, otherwise beep n times when n-th entry in boot menu is selected (default disabled). Currently, only x86 is supported, where it uses the PC speaker. diff --git a/man/sd_bus_error-example.c b/man/sd_bus_error-example.c new file mode 100644 index 000000000..abea13ca4 --- /dev/null +++ b/man/sd_bus_error-example.c @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: CC0-1.0 */ + +#include +#include +#include +#include + +int writer_with_negative_errno_return(int fd, sd_bus_error *error) { + const char *message = "Hello, World!\n"; + + ssize_t n = write(fd, message, strlen(message)); + if (n >= 0) + return n; /* On success, return the number of bytes written, possibly 0. */ + + /* On error, initialize the error structure, and also propagate the errno + * value that write(2) set for us. */ + return sd_bus_error_set_errnof(error, errno, "Failed to write to fd %i: %m", fd); +} diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml index 5697ce732..f4d0fea2e 100644 --- a/man/sd_bus_error.xml +++ b/man/sd_bus_error.xml @@ -246,10 +246,15 @@ values in e, if e has been set with an error value before. Otherwise, it will return immediately. If the strings in e were set using sd_bus_error_set_const(), they will be shared. Otherwise, they will be - copied. Returns a converted errno-like, negative error code or 0. - Before this call, dst must be unset, i.e. either freshly initialized with + copied. Before this call, dst must be unset, i.e. either freshly initialized with NULL or reset using sd_bus_error_free(). + sd_bus_error_copy() generally returns 0 or a negative + errno-like value based on the input parameter e: + 0 if it was unset and a negative integer if it was set to some error, similarly to + sd_bus_error_set(). It may however also return an error generated internally, for + example -ENOMEM if a memory allocation fails. + sd_bus_error_move() is similar to sd_bus_error_copy(), but will move any error information from e into dst, resetting the former. This function cannot fail, as no new memory is allocated. Note that if @@ -286,6 +291,18 @@ to NULL. The structure may be reused afterwards. + + Reference ownership + + sd_bus_error is not reference-counted. Users should destroy resources held + by it by calling sd_bus_error_free(). Usually, error structures are allocated on the + stack or passed in as function parameters, but they may also be allocated dynamically, in which case it + is the duty of the caller to free3 the memory + held by the structure itself after freeing its contents with + sd_bus_error_free(). + + Return Value @@ -297,7 +314,8 @@ sd_bus_error_set_errnofv(), return 0 when the specified error value is 0, and a negative errno-like value corresponding to the error parameter otherwise. If an error occurs internally, one of the negative - error values listed below will be returned. + error values listed below will be returned. This allows those functions to be conveniently used in a + return statement, see the example below. sd_bus_error_get_errno() returns false when e is @@ -305,7 +323,9 @@ e->name otherwise. sd_bus_error_copy() and sd_bus_error_move() return a - negative error value converted from the source error, and zero if the error has not been set. + negative error value converted from the source error, and zero if the error has not been set. This + allows those functions to be conveniently used in a return statement, see the + example below. sd_bus_error_is_set() returns a non-zero value when e and the @@ -316,32 +336,18 @@ sd_bus_error_has_names_sentinel() return a non-zero value when e is non-NULL and the name field is equal to one of the given names, zero otherwise. - - - - Reference ownership - sd_bus_error is not reference - counted. Users should destroy resources held by it by calling - sd_bus_error_free(). Usually, error structures - are allocated on the stack or passed in as function parameters, - but they may also be allocated dynamically, in which case it is - the duty of the caller to free3 - the memory held by the structure itself after freeing its contents - with sd_bus_error_free(). Errors - Returned errors may indicate the following problems: + Return value may indicate the following problems in the invocation of the function itself: - -EINVAL - Error was already set in sd_bus_error structure when one - the error-setting functions was called. + Error was already set in the sd_bus_error structure when + one the error-setting functions was called. @@ -350,9 +356,29 @@ Memory allocation failed. + + On success, sd_bus_error_set(), sd_bus_error_setf(), + sd_bus_error_set_const(), sd_bus_error_set_errno(), + sd_bus_error_set_errnof(), sd_bus_error_set_errnofv(), + sd_bus_error_copy(), and sd_bus_error_move() will return a + negative converted errno-style value, or 0 if the error + parameter is NULL or unset. D-Bus errors are converted to the integral + errno-style value, and the mapping mechanism is extensible, see the discussion + above. This effectively means that almost any negative errno-style value can be + returned. + + Examples + + + Using the negative return value to propagate an error + + + + + diff --git a/man/shutdown.xml b/man/shutdown.xml index b07736ee6..97f33e802 100644 --- a/man/shutdown.xml +++ b/man/shutdown.xml @@ -18,7 +18,7 @@ shutdown - Halt, power-off or reboot the machine + Halt, power off or reboot the machine @@ -33,8 +33,7 @@ Description - shutdown may be used to halt, power-off - or reboot the machine. + shutdown may be used to halt, power off, or reboot the machine. The first argument may be a time string (which is usually now). Optionally, this may be followed by a @@ -81,47 +80,41 @@ - Power-off the machine (the - default). + Power the machine off (the default). - Reboot the - machine. + Reboot the machine. - Equivalent to , - unless is specified. + The same as , but does not override the action to take if + it is "halt". E.g. shutdown --reboot -h means "poweroff", but shutdown + --halt -h means "halt". - Do not halt, power-off, reboot, just write - wall message. + Do not halt, power off, or reboot, but just write the wall message. - Do not send wall - message before - halt, power-off, reboot. + Do not send wall message before halt, power off, or reboot. - Cancel a pending shutdown. This may be used - to cancel the effect of an invocation of - shutdown with a time argument that is not - +0 or + Cancel a pending shutdown. This may be used to cancel the effect of an invocation of + shutdown with a time argument that is not +0 or now. diff --git a/man/systemd-creds.xml b/man/systemd-creds.xml index 2ccbb223e..d803b5c12 100644 --- a/man/systemd-creds.xml +++ b/man/systemd-creds.xml @@ -25,6 +25,8 @@ systemd-creds OPTIONS + COMMAND + ARGS diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml index da35a7d26..c7c8b91e1 100644 --- a/man/systemd.automount.xml +++ b/man/systemd.automount.xml @@ -26,10 +26,9 @@ Description - A unit configuration file whose name ends in - .automount encodes information about a file - system automount point controlled and supervised by - systemd. + A unit configuration file whose name ends in .automount encodes information + about a file system automount point controlled and supervised by systemd. Automount units may be used to + implement on-demand mounting as well as parallelized mounting of file systems. This man page lists the configuration options specific to this unit type. See @@ -55,9 +54,6 @@ accesses /home/lennart the mount unit home-lennart.mount will be activated. - Automount units may be used to implement on-demand mounting - as well as parallelized mounting of file systems. - Note that automount units are separate from the mount itself, so you should not set After= or Requires= for mount dependencies here. For example, you should not set @@ -65,8 +61,11 @@ filesystems. Doing so may result in an ordering cycle. Note that automount support on Linux is privileged, automount units are hence only available in the - system service manager (and root's user service manager), but not in unprivileged user's service - manager. + system service manager (and root's user service manager), but not in unprivileged users' service + managers. + + Note that automount units should not be nested. (The establishment of the inner automount point + would unconditionally pin the outer mount point, defeating its purpose.) @@ -78,12 +77,12 @@ The following dependencies are implicitly added: - If an automount unit is beneath another mount unit in the - file system hierarchy, both a requirement and an ordering - dependency between both units are created automatically. + If an automount unit is beneath another mount unit in the file system hierarchy, a + requirement and ordering dependencies are created to the on the unit higher in the hierarchy. + - An implicit Before= dependency is created - between an automount unit and the mount unit it activates. + An implicit Before= dependency is created between an automount + unit and the mount unit it activates. @@ -161,6 +160,7 @@ creating these directories. Takes an access mode in octal notation. Defaults to 0755. + TimeoutIdleSec= Configures an idle timeout. Once the mount has been diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 95bf177a6..b03cc70e2 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -357,20 +357,29 @@ int cg_kill( Set *s, cg_kill_log_func_t log_kill, void *userdata) { - int r; + + int r, ret; r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.procs"); if (r < 0 || sig != SIGKILL) return r; + ret = r; + /* Only in case of killing with SIGKILL and when using cgroupsv2, kill remaining threads manually as a workaround for kernel bug. It was fixed in 5.2-rc5 (c03cd7738a83), backported to 4.19.66 (4340d175b898) and 4.14.138 (feb6b123b7dd). */ r = cg_unified_controller(controller); - if (r <= 0) + if (r < 0) + return r; + if (r == 0) + return ret; + + r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads"); + if (r < 0) return r; - return cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads"); + return r > 0 || ret > 0; } int cg_kill_kernel_sigkill(const char *controller, const char *path) { diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c index 258d09dd4..ce3b76c51 100644 --- a/src/core/bpf-firewall.c +++ b/src/core/bpf-firewall.c @@ -543,7 +543,7 @@ int bpf_firewall_compile(Unit *u) { return supported; if (supported == BPF_FIREWALL_UNSUPPORTED) return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), - "BPF firewalling not supported on this manager, proceeding without."); + "bpf-firewall: BPF firewalling not supported, proceeding without."); if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE) /* If BPF_F_ALLOW_MULTI is not supported we don't support any BPF magic on inner nodes (i.e. on slice * units), since that would mean leaf nodes couldn't do any BPF anymore at all. Under the assumption @@ -551,7 +551,7 @@ int bpf_firewall_compile(Unit *u) { * consistent with old systemd behaviour from before v238, where BPF wasn't supported in inner nodes at * all, either. */ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), - "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units."); + "bpf-firewall: BPF_F_ALLOW_MULTI is not supported, not doing BPF firewall on slice units."); /* If BPF_F_ALLOW_MULTI flag is supported program name is also supported (both were added to v4.15 * kernel). */ @@ -582,24 +582,24 @@ int bpf_firewall_compile(Unit *u) { r = bpf_firewall_prepare_access_maps(u, ACCESS_ALLOWED, &u->ipv4_allow_map_fd, &u->ipv6_allow_map_fd, &ip_allow_any); if (r < 0) - return log_unit_error_errno(u, r, "Preparation of eBPF allow maps failed: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF allow maps failed: %m"); r = bpf_firewall_prepare_access_maps(u, ACCESS_DENIED, &u->ipv4_deny_map_fd, &u->ipv6_deny_map_fd, &ip_deny_any); if (r < 0) - return log_unit_error_errno(u, r, "Preparation of eBPF deny maps failed: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF deny maps failed: %m"); } r = bpf_firewall_prepare_accounting_maps(u, cc->ip_accounting, &u->ip_accounting_ingress_map_fd, &u->ip_accounting_egress_map_fd); if (r < 0) - return log_unit_error_errno(u, r, "Preparation of eBPF accounting maps failed: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF accounting maps failed: %m"); r = bpf_firewall_compile_bpf(u, ingress_name, true, &u->ip_bpf_ingress, ip_allow_any, ip_deny_any); if (r < 0) - return log_unit_error_errno(u, r, "Compilation for ingress BPF program failed: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Compilation of ingress BPF program failed: %m"); r = bpf_firewall_compile_bpf(u, egress_name, false, &u->ip_bpf_egress, ip_allow_any, ip_deny_any); if (r < 0) - return log_unit_error_errno(u, r, "Compilation for egress BPF program failed: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Compilation of egress BPF program failed: %m"); return 0; } @@ -613,15 +613,15 @@ static int load_bpf_progs_from_fs_to_set(Unit *u, char **filter_paths, Set **set r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &prog); if (r < 0) - return log_unit_error_errno(u, r, "Can't allocate CGROUP SKB BPF program: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Allocation of SKB BPF program failed: %m"); r = bpf_program_load_from_bpf_fs(prog, *bpf_fs_path); if (r < 0) - return log_unit_error_errno(u, r, "Loading of ingress BPF program %s failed: %m", *bpf_fs_path); + return log_unit_error_errno(u, r, "bpf-firewall: Loading of ingress BPF program %s failed: %m", *bpf_fs_path); r = set_ensure_consume(set, &bpf_program_hash_ops, TAKE_PTR(prog)); if (r < 0) - return log_unit_error_errno(u, r, "Can't add program to BPF program set: %m"); + return log_oom(); } return 0; @@ -645,7 +645,8 @@ int bpf_firewall_load_custom(Unit *u) { return supported; if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI) - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs."); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs."); r = load_bpf_progs_from_fs_to_set(u, cc->ip_filters_ingress, &u->ip_bpf_custom_ingress); if (r < 0) @@ -671,7 +672,7 @@ static int attach_custom_bpf_progs(Unit *u, const char *path, int attach_type, S SET_FOREACH_MOVE(prog, *set_installed, *set) { r = bpf_program_cgroup_attach(prog, attach_type, path, BPF_F_ALLOW_MULTI); if (r < 0) - return log_unit_error_errno(u, r, "Attaching custom egress BPF program to cgroup %s failed: %m", path); + return log_unit_error_errno(u, r, "bpf-firewall: Attaching custom egress BPF program to cgroup %s failed: %m", path); } return 0; } @@ -697,16 +698,19 @@ int bpf_firewall_install(Unit *u) { if (supported < 0) return supported; if (supported == BPF_FIREWALL_UNSUPPORTED) - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF firewalling not supported on this manager, proceeding without."); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-firewall: BPF firewalling not supported, proceeding without."); if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE) - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units."); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-firewall: BPF_F_ALLOW_MULTI not supported, not doing BPF firewall on slice units."); if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && (!set_isempty(u->ip_bpf_custom_ingress) || !set_isempty(u->ip_bpf_custom_egress))) - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs."); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs."); r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &path); if (r < 0) - return log_unit_error_errno(u, r, "Failed to determine cgroup path: %m"); + return log_unit_error_errno(u, r, "bpf-firewall: Failed to determine cgroup path: %m"); flags = supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI ? BPF_F_ALLOW_MULTI : 0; @@ -728,7 +732,8 @@ int bpf_firewall_install(Unit *u) { if (u->ip_bpf_egress) { r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags); if (r < 0) - return log_unit_error_errno(u, r, "Attaching egress BPF program to cgroup %s failed: %m", path); + return log_unit_error_errno(u, r, + "bpf-firewall: Attaching egress BPF program to cgroup %s failed: %m", path); /* Remember that this BPF program is installed now. */ u->ip_bpf_egress_installed = TAKE_PTR(u->ip_bpf_egress); @@ -737,7 +742,8 @@ int bpf_firewall_install(Unit *u) { if (u->ip_bpf_ingress) { r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags); if (r < 0) - return log_unit_error_errno(u, r, "Attaching ingress BPF program to cgroup %s failed: %m", path); + return log_unit_error_errno(u, r, + "bpf-firewall: Attaching ingress BPF program to cgroup %s failed: %m", path); u->ip_bpf_ingress_installed = TAKE_PTR(u->ip_bpf_ingress); } @@ -824,11 +830,11 @@ int bpf_firewall_supported(void) { r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER); if (r < 0) - return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m"); + return log_error_errno(r, "bpf-firewall: Can't determine whether the unified hierarchy is used: %m"); if (r == 0) { bpf_firewall_unsupported_reason = log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), - "Not running with unified cgroups, BPF firewalling is not supported."); + "bpf-firewall: Not running with unified cgroup hierarchy, BPF firewalling is not supported."); return supported = BPF_FIREWALL_UNSUPPORTED; } @@ -836,21 +842,21 @@ int bpf_firewall_supported(void) { r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program); if (r < 0) { bpf_firewall_unsupported_reason = - log_debug_errno(r, "Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m"); + log_debug_errno(r, "bpf-firewall: Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m"); return supported = BPF_FIREWALL_UNSUPPORTED; } r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial)); if (r < 0) { bpf_firewall_unsupported_reason = - log_debug_errno(r, "Can't add trivial instructions to CGROUP SKB BPF program, BPF firewalling is not supported: %m"); + log_debug_errno(r, "bpf-firewall: Can't add trivial instructions to CGROUP SKB BPF program, BPF firewalling is not supported: %m"); return supported = BPF_FIREWALL_UNSUPPORTED; } r = bpf_program_load_kernel(program, NULL, 0); if (r < 0) { bpf_firewall_unsupported_reason = - log_debug_errno(r, "Can't load kernel CGROUP SKB BPF program, BPF firewalling is not supported: %m"); + log_debug_errno(r, "bpf-firewall: Can't load kernel CGROUP SKB BPF program, BPF firewalling is not supported: %m"); return supported = BPF_FIREWALL_UNSUPPORTED; } @@ -874,7 +880,7 @@ int bpf_firewall_supported(void) { if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) { if (errno != EBADF) { bpf_firewall_unsupported_reason = - log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m"); + log_debug_errno(errno, "bpf-firewall: Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m"); return supported = BPF_FIREWALL_UNSUPPORTED; } @@ -882,7 +888,7 @@ int bpf_firewall_supported(void) { } else { bpf_firewall_unsupported_reason = log_debug_errno(SYNTHETIC_ERRNO(EBADE), - "Wut? Kernel accepted our invalid BPF_PROG_DETACH call? " + "bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_DETACH call? " "Something is weird, assuming BPF firewalling is broken and hence not supported."); return supported = BPF_FIREWALL_UNSUPPORTED; } @@ -902,20 +908,20 @@ int bpf_firewall_supported(void) { if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) { if (errno == EBADF) { - log_debug_errno(errno, "Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!"); + log_debug_errno(errno, "bpf-firewall: Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!"); return supported = BPF_FIREWALL_SUPPORTED_WITH_MULTI; } if (errno == EINVAL) - log_debug_errno(errno, "Got EINVAL error when using BPF_F_ALLOW_MULTI, which indicates it's not supported."); + log_debug_errno(errno, "bpf-firewall: Got EINVAL error when using BPF_F_ALLOW_MULTI, which indicates it's not supported."); else - log_debug_errno(errno, "Got unexpected error when using BPF_F_ALLOW_MULTI, assuming it's not supported: %m"); + log_debug_errno(errno, "bpf-firewall: Got unexpected error when using BPF_F_ALLOW_MULTI, assuming it's not supported: %m"); return supported = BPF_FIREWALL_SUPPORTED; } else { bpf_firewall_unsupported_reason = log_debug_errno(SYNTHETIC_ERRNO(EBADE), - "Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? " + "bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? " "Something is weird, assuming BPF firewalling is broken and hence not supported."); return supported = BPF_FIREWALL_UNSUPPORTED; } diff --git a/src/core/bpf-foreign.c b/src/core/bpf-foreign.c index 7f50f5738..83c3bac87 100644 --- a/src/core/bpf-foreign.c +++ b/src/core/bpf-foreign.c @@ -63,7 +63,7 @@ static int attach_programs(Unit *u, const char *path, Hashmap* foreign_by_key, u HASHMAP_FOREACH_KEY(prog, key, foreign_by_key) { r = bpf_program_cgroup_attach(prog, key->attach_type, path, attach_flags); if (r < 0) - return log_unit_error_errno(u, r, "Attaching foreign BPF program to cgroup %s failed: %m", path); + return log_unit_error_errno(u, r, "bpf-foreign: Attaching foreign BPF program to cgroup %s failed: %m", path); } return 0; @@ -89,31 +89,31 @@ static int bpf_foreign_prepare( r = path_is_fs_type(bpffs_path, BPF_FS_MAGIC); if (r < 0) return log_unit_error_errno(u, r, - "Failed to determine filesystem type of %s: %m", bpffs_path); + "bpf-foreign: Failed to determine filesystem type of %s: %m", bpffs_path); if (r == 0) return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL), - "Path in BPF filesystem is expected."); + "bpf-foreign: Path in BPF filesystem is expected."); r = bpf_program_new_from_bpffs_path(bpffs_path, &prog); if (r < 0) - return log_unit_error_errno(u, r, "Failed to create foreign BPFProgram: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to create foreign BPF program: %m"); r = bpf_program_get_id_by_fd(prog->kernel_fd, &prog_id); if (r < 0) - return log_unit_error_errno(u, r, "Failed to get BPF program id by fd: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to get BPF program id from fd: %m"); r = bpf_foreign_key_new(prog_id, attach_type, &key); if (r < 0) return log_unit_error_errno(u, r, - "Failed to create foreign BPF program key from path '%s': %m", bpffs_path); + "bpf-foreign: Failed to create foreign BPF program key from path '%s': %m", bpffs_path); r = hashmap_ensure_put(&u->bpf_foreign_by_key, &bpf_foreign_by_key_hash_ops, key, prog); if (r == -EEXIST) { - log_unit_warning_errno(u, r, "Foreign BPF program already exists, ignoring: %m"); + log_unit_warning_errno(u, r, "bpf-foreign: Foreign BPF program already exists, ignoring: %m"); return 0; } if (r < 0) - return log_unit_error_errno(u, r, "Failed to put foreign BPFProgram into map: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to put foreign BPF program into map: %m"); TAKE_PTR(key); TAKE_PTR(prog); @@ -134,17 +134,17 @@ int bpf_foreign_install(Unit *u) { r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path); if (r < 0) - return log_unit_error_errno(u, r, "Failed to get cgroup path: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to get cgroup path: %m"); LIST_FOREACH(programs, p, cc->bpf_foreign_programs) { r = bpf_foreign_prepare(u, p->attach_type, p->bpffs_path); if (r < 0) - return log_unit_error_errno(u, r, "Failed to prepare foreign BPF hashmap: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to prepare foreign BPF hashmap: %m"); } r = attach_programs(u, cgroup_path, u->bpf_foreign_by_key, BPF_F_ALLOW_MULTI); if (r < 0) - return log_unit_error_errno(u, r, "Failed to install foreign BPF programs: %m"); + return log_unit_error_errno(u, r, "bpf-foreign: Failed to install foreign BPF programs: %m"); return 0; } diff --git a/src/core/bpf-lsm.c b/src/core/bpf-lsm.c index d3e92b98a..f3b933955 100644 --- a/src/core/bpf-lsm.c +++ b/src/core/bpf-lsm.c @@ -26,6 +26,7 @@ /* libbpf, clang and llc compile time dependencies are satisfied */ #include "bpf-dlopen.h" #include "bpf-link.h" +#include "bpf-util.h" #include "bpf/restrict_fs/restrict-fs-skel.h" #define CGROUP_HASH_SIZE_MAX 2048 @@ -61,29 +62,29 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) { obj = restrict_fs_bpf__open(); if (!obj) - return log_error_errno(errno, "Failed to open BPF object: %m"); + return log_error_errno(errno, "bpf-lsm: Failed to open BPF object: %m"); /* TODO Maybe choose a number based on runtime information? */ r = sym_bpf_map__resize(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX); assert(r <= 0); if (r < 0) - return log_error_errno(r, "Failed to resize BPF map '%s': %m", + return log_error_errno(r, "bpf-lsm: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.cgroup_hash)); /* Dummy map to satisfy the verifier */ inner_map_fd = sym_bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), 128, 0); if (inner_map_fd < 0) - return log_error_errno(errno, "Failed to create BPF map: %m"); + return log_error_errno(errno, "bpf-lsm: Failed to create BPF map: %m"); r = sym_bpf_map__set_inner_map_fd(obj->maps.cgroup_hash, inner_map_fd); assert(r <= 0); if (r < 0) - return log_error_errno(r, "Failed to set inner map fd: %m"); + return log_error_errno(r, "bpf-lsm: Failed to set inner map fd: %m"); r = restrict_fs_bpf__load(obj); assert(r <= 0); if (r < 0) - return log_error_errno(r, "Failed to load BPF object"); + return log_error_errno(r, "bpf-lsm: Failed to load BPF object: %m"); *ret_obj = TAKE_PTR(obj); @@ -103,7 +104,7 @@ static int mac_bpf_use(void) { r = read_one_line_file("/sys/kernel/security/lsm", &lsm_list); if (r < 0) { if (r != -ENOENT) - log_notice_errno(r, "Failed to read /sys/kernel/security/lsm, assuming bpf is unavailable: %m"); + log_notice_errno(r, "bpf-lsm: Failed to read /sys/kernel/security/lsm, assuming bpf is unavailable: %m"); return 0; } @@ -116,7 +117,7 @@ static int mac_bpf_use(void) { if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_notice_errno(r, "Failed to parse /sys/kernel/security/lsm, assuming bpf is unavailable: %m"); + log_notice_errno(r, "bpf-lsm: Failed to parse /sys/kernel/security/lsm, assuming bpf is unavailable: %m"); return 0; } @@ -135,33 +136,18 @@ bool lsm_bpf_supported(bool initialize) { if (!initialize) return false; - r = dlopen_bpf(); - if (r < 0) { - log_info_errno(r, "Failed to open libbpf, LSM BPF is not supported: %m"); + if (!cgroup_bpf_supported()) return (supported = false); - } - - r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER); - if (r < 0) { - log_warning_errno(r, "Can't determine whether the unified hierarchy is used: %m"); - return (supported = false); - } - - if (r == 0) { - log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "Not running with unified cgroup hierarchy, LSM BPF is not supported"); - return (supported = false); - } r = mac_bpf_use(); if (r < 0) { - log_warning_errno(r, "Can't determine whether the BPF LSM module is used: %m"); + log_warning_errno(r, "bpf-lsm: Can't determine whether the BPF LSM module is used: %m"); return (supported = false); } if (r == 0) { log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "BPF LSM hook not enabled in the kernel, LSM BPF not supported"); + "bpf-lsm: BPF LSM hook not enabled in the kernel, BPF LSM not supported"); return (supported = false); } @@ -171,7 +157,7 @@ bool lsm_bpf_supported(bool initialize) { if (!bpf_can_link_lsm_program(obj->progs.restrict_filesystems)) { log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "Failed to link BPF program. Assuming BPF is not available"); + "bpf-lsm: Failed to link program; assuming BPF LSM is not available"); return (supported = false); } @@ -192,10 +178,10 @@ int lsm_bpf_setup(Manager *m) { link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems); r = sym_libbpf_get_error(link); if (r != 0) - return log_error_errno(r, "Failed to link '%s' LSM BPF program: %m", + return log_error_errno(r, "bpf-lsm: Failed to link '%s' LSM BPF program: %m", sym_bpf_program__name(obj->progs.restrict_filesystems)); - log_info("LSM BPF program attached"); + log_info("bpf-lsm: LSM BPF program attached"); obj->links.restrict_filesystems = TAKE_PTR(link); m->restrict_fs = TAKE_PTR(obj); @@ -214,7 +200,7 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo if (!u->manager->restrict_fs) return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL), - "Restrict filesystems BPF object is not set, BPF LSM setup has failed?"); + "bpf-lsm: BPF LSM object is not installed, has setup failed?"); int inner_map_fd = sym_bpf_create_map( BPF_MAP_TYPE_HASH, @@ -223,39 +209,39 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo 128, /* Should be enough for all filesystem types */ 0); if (inner_map_fd < 0) - return log_unit_error_errno(u, errno, "Failed to create inner LSM map: %m"); + return log_unit_error_errno(u, errno, "bpf-lsm: Failed to create inner BPF map: %m"); int outer_map_fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash); if (outer_map_fd < 0) - return log_unit_error_errno(u, errno, "Failed to get BPF map fd: %m"); + return log_unit_error_errno(u, errno, "bpf-lsm: Failed to get BPF map fd: %m"); if (sym_bpf_map_update_elem(outer_map_fd, &u->cgroup_id, &inner_map_fd, BPF_ANY) != 0) - return log_unit_error_errno(u, errno, "Error populating LSM BPF map: %m"); + return log_unit_error_errno(u, errno, "bpf-lsm: Error populating BPF map: %m"); uint32_t allow = allow_list; /* Use key 0 to store whether this is an allow list or a deny list */ if (sym_bpf_map_update_elem(inner_map_fd, &zero, &allow, BPF_ANY) != 0) - return log_unit_error_errno(u, errno, "Error initializing BPF map: %m"); + return log_unit_error_errno(u, errno, "bpf-lsm: Error initializing map: %m"); SET_FOREACH(fs, filesystems) { r = fs_type_from_string(fs, &magic); if (r < 0) { - log_unit_warning(u, "Invalid filesystem name '%s', ignoring.", fs); + log_unit_warning(u, "bpf-lsm: Invalid filesystem name '%s', ignoring.", fs); continue; } - log_unit_debug(u, "Restricting filesystem access to '%s'", fs); + log_unit_debug(u, "bpf-lsm: Restricting filesystem access to '%s'", fs); for (int i = 0; i < FILESYSTEM_MAGIC_MAX; i++) { if (magic[i] == 0) break; if (sym_bpf_map_update_elem(inner_map_fd, &magic[i], &dummy_value, BPF_ANY) != 0) { - r = log_unit_error_errno(u, errno, "Failed to update BPF map: %m"); + r = log_unit_error_errno(u, errno, "bpf-lsm: Failed to update BPF map: %m"); if (sym_bpf_map_delete_elem(outer_map_fd, &u->cgroup_id) != 0) - log_unit_debug_errno(u, errno, "Failed to delete cgroup entry from LSM BPF map: %m"); + log_unit_debug_errno(u, errno, "bpf-lsm: Failed to delete cgroup entry from BPF map: %m"); return r; } @@ -278,10 +264,10 @@ int lsm_bpf_cleanup(const Unit *u) { int fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash); if (fd < 0) - return log_unit_error_errno(u, errno, "Failed to get BPF map fd: %m"); + return log_unit_error_errno(u, errno, "bpf-lsm: Failed to get BPF map fd: %m"); if (sym_bpf_map_delete_elem(fd, &u->cgroup_id) != 0) - return log_unit_debug_errno(u, errno, "Failed to delete cgroup entry from LSM BPF map: %m"); + return log_unit_debug_errno(u, errno, "bpf-lsm: Failed to delete cgroup entry from LSM BPF map: %m"); return 0; } @@ -305,11 +291,11 @@ bool lsm_bpf_supported(bool initialize) { } int lsm_bpf_setup(Manager *m) { - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set up LSM BPF: %m"); + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to set up LSM BPF: %m"); } int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, const bool allow_list) { - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to restrict filesystems using LSM BPF: %m"); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to restrict filesystems using LSM BPF: %m"); } int lsm_bpf_cleanup(const Unit *u) { @@ -344,7 +330,7 @@ int lsm_bpf_parse_filesystem( set = filesystem_set_find(name); if (!set) { log_syntax(unit, flags & FILESYSTEM_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0, - "Unknown filesystem group, ignoring: %s", name); + "bpf-lsm: Unknown filesystem group, ignoring: %s", name); return 0; } diff --git a/src/core/bpf-socket-bind.c b/src/core/bpf-socket-bind.c index 09f83dc66..3aa1bfa1f 100644 --- a/src/core/bpf-socket-bind.c +++ b/src/core/bpf-socket-bind.c @@ -11,8 +11,9 @@ /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ #include "bpf-dlopen.h" #include "bpf-link.h" -#include "bpf/socket_bind/socket-bind-skel.h" +#include "bpf-util.h" #include "bpf/socket_bind/socket-bind-api.bpf.h" +#include "bpf/socket_bind/socket-bind-skel.h" static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) { /* socket_bind_bpf__destroy handles object == NULL case */ @@ -68,27 +69,27 @@ static int prepare_socket_bind_bpf( if (allow_count > SOCKET_BIND_MAX_RULES) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL), - "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES); + "bpf-socket-bind: Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES); if (deny_count > SOCKET_BIND_MAX_RULES) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL), - "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES); + "bpf-socket-bind: Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES); obj = socket_bind_bpf__open(); if (!obj) - return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "Failed to open BPF object: %m"); + return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "bpf-socket-bind: Failed to open BPF object: %m"); if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno, - "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow)); + "bpf-socket-bind: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow)); if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno, - "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny)); + "bpf-socket-bind: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny)); if (socket_bind_bpf__load(obj) != 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, - "Failed to load BPF object: %m"); + "bpf-socket-bind: Failed to load BPF object: %m"); allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow); assert(allow_map_fd >= 0); @@ -96,7 +97,7 @@ static int prepare_socket_bind_bpf( r = update_rules_map(allow_map_fd, allow); if (r < 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r, - "Failed to put socket bind allow rules into BPF map '%s'", + "bpf-socket-bind: Failed to put socket bind allow rules into BPF map '%s'", sym_bpf_map__name(obj->maps.sd_bind_allow)); deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny); @@ -105,7 +106,7 @@ static int prepare_socket_bind_bpf( r = update_rules_map(deny_map_fd, deny); if (r < 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r, - "Failed to put socket bind deny rules into BPF map '%s'", + "bpf-socket-bind: Failed to put socket bind deny rules into BPF map '%s'", sym_bpf_map__name(obj->maps.sd_bind_deny)); *ret_obj = TAKE_PTR(obj); @@ -116,25 +117,17 @@ int bpf_socket_bind_supported(void) { _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL; int r; - r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER); - if (r < 0) - return log_debug_errno(r, "Can't determine whether the unified hierarchy is used: %m"); - if (r == 0) { - log_debug("Not running with unified cgroup hierarchy, BPF is not supported"); - return false; - } - - if (dlopen_bpf() < 0) + if (!cgroup_bpf_supported()) return false; if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) { - log_debug("BPF program type cgroup_sock_addr is not supported"); + log_debug("bpf-socket-bind: BPF program type cgroup_sock_addr is not supported"); return false; } r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj); if (r < 0) { - log_debug_errno(r, "BPF based socket_bind is not supported: %m"); + log_debug_errno(r, "bpf-socket-bind: socket bind filtering is not supported: %m"); return false; } @@ -154,7 +147,7 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) { r = fdset_put(u->initial_socket_bind_link_fds, fd); if (r < 0) - return log_unit_error_errno(u, r, "Failed to put socket-bind BPF link fd %d to initial fdset", fd); + return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to put BPF fd %d to initial fdset", fd); return 0; } @@ -175,29 +168,29 @@ static int socket_bind_install_impl(Unit *u) { r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path); if (r < 0) - return log_unit_error_errno(u, r, "Failed to get cgroup path: %m"); + return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to get cgroup path: %m"); if (!cc->socket_bind_allow && !cc->socket_bind_deny) return 0; r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj); if (r < 0) - return log_unit_error_errno(u, r, "Failed to load BPF object: %m"); + return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to load BPF object: %m"); cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC, 0); if (cgroup_fd < 0) - return log_unit_error_errno(u, errno, "Failed to open cgroup=%s for reading: %m", cgroup_path); + return log_unit_error_errno(u, errno, "bpf-socket-bind: Failed to open cgroup %s for reading: %m", cgroup_path); ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd); r = sym_libbpf_get_error(ipv4); if (r != 0) - return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m", + return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m", sym_bpf_program__name(obj->progs.sd_bind4)); ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd); r = sym_libbpf_get_error(ipv6); if (r != 0) - return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m", + return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m", sym_bpf_program__name(obj->progs.sd_bind6)); u->ipv4_socket_bind_link = TAKE_PTR(ipv4); @@ -241,7 +234,8 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) { } int bpf_socket_bind_install(Unit *u) { - return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to install socket bind: BPF framework is not supported"); + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-socket-bind: Failed to install; BPF framework is not supported"); } int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) { diff --git a/src/core/bpf-util.c b/src/core/bpf-util.c new file mode 100644 index 000000000..9130aa373 --- /dev/null +++ b/src/core/bpf-util.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "bpf-dlopen.h" +#include "bpf-util.h" +#include "cgroup-util.h" +#include "log.h" + +bool cgroup_bpf_supported(void) { + static int supported = -1; + int r; + + if (supported >= 0) + return supported; + + r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER); + if (r < 0) { + log_warning_errno(r, "Can't determine whether the unified hierarchy is used: %m"); + return (supported = false); + } + + if (r == 0) { + log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Not running with unified cgroup hierarchy, disabling cgroup BPF features."); + return (supported = false); + } + + r = dlopen_bpf(); + if (r < 0) { + log_info_errno(r, "Failed to open libbpf, cgroup BPF features disabled: %m"); + return (supported = false); + } + + return (supported = true); +} diff --git a/src/core/bpf-util.h b/src/core/bpf-util.h new file mode 100644 index 000000000..a6c55cd7e --- /dev/null +++ b/src/core/bpf-util.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +bool cgroup_bpf_supported(void); diff --git a/src/core/device.c b/src/core/device.c index 934676287..fcde8a420 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -163,14 +163,56 @@ static int device_coldplug(Unit *u) { assert(d->state == DEVICE_DEAD); /* First, let's put the deserialized state and found mask into effect, if we have it. */ - - if (d->deserialized_state < 0 || - (d->deserialized_state == d->state && - d->deserialized_found == d->found)) + if (d->deserialized_state < 0) return 0; - d->found = d->deserialized_found; - device_set_state(d, d->deserialized_state); + Manager *m = u->manager; + DeviceFound found = d->deserialized_found; + DeviceState state = d->deserialized_state; + + /* On initial boot, switch-root, reload, reexecute, the following happen: + * 1. MANAGER_IS_RUNNING() == false + * 2. enumerate devices: manager_enumerate() -> device_enumerate() + * Device.enumerated_found is set. + * 3. deserialize devices: manager_deserialize() -> device_deserialize() + * Device.deserialize_state and Device.deserialized_found are set. + * 4. coldplug devices: manager_coldplug() -> device_coldplug() + * deserialized properties are copied to the main properties. + * 5. MANAGER_IS_RUNNING() == true: manager_ready() + * 6. catchup devices: manager_catchup() -> device_catchup() + * Device.enumerated_found is applied to Device.found, and state is updated based on that. + * + * Notes: + * - On initial boot, no udev database exists. Hence, no devices are enumerated in the step 2. + * Also, there is no deserialized device. Device units are (a) generated based on dependencies of + * other units, or (b) generated when uevents are received. + * + * - On switch-root, the udev database may be cleared, except for devices with sticky bit, i.e. + * OPTIONS="db_persist". Hence, almost no devices are enumerated in the step 2. However, in general, + * we have several serialized devices. So, DEVICE_FOUND_UDEV bit in the deserialized_found must be + * ignored, as udev rules in initramfs and the main system are often different. If the deserialized + * state is DEVICE_PLUGGED, we need to downgrade it to DEVICE_TENTATIVE (or DEVICE_DEAD if nobody + * sees the device). Unlike the other starting mode, Manager.honor_device_enumeration == false + * (maybe, it is better to rename the flag) when device_coldplug() and device_catchup() are called. + * Hence, let's conditionalize the operations by using the flag. After switch-root, systemd-udevd + * will (re-)process all devices, and the Device.found and Device.state will be adjusted. + * + * - On reload or reexecute, we can trust enumerated_found, deserialized_found, and deserialized_state. + * Of course, deserialized parameters may be outdated, but the unit state can be adjusted later by + * device_catchup() or uevents. */ + + if (!m->honor_device_enumeration && !MANAGER_IS_USER(m) && + !FLAGS_SET(d->enumerated_found, DEVICE_FOUND_UDEV)) { + found &= ~DEVICE_FOUND_UDEV; /* ignore DEVICE_FOUND_UDEV bit */ + if (state == DEVICE_PLUGGED) + state = DEVICE_TENTATIVE; /* downgrade state */ + } + + if (d->found == found && d->state == state) + return 0; + + d->found = found; + device_set_state(d, state); return 0; } @@ -644,13 +686,9 @@ static void device_found_changed(Device *d, DeviceFound previous, DeviceFound no } static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) { - Manager *m; - assert(d); - m = UNIT(d)->manager; - - if (MANAGER_IS_RUNNING(m) && (m->honor_device_enumeration || MANAGER_IS_USER(m))) { + if (MANAGER_IS_RUNNING(UNIT(d)->manager)) { DeviceFound n, previous; /* When we are already running, then apply the new mask right-away, and trigger state changes diff --git a/src/core/meson.build b/src/core/meson.build index 1e8b6dc31..9efa542ac 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -135,6 +135,13 @@ libcore_sources = ''' unit.h '''.split() +if conf.get('BPF_FRAMEWORK') == 1 + libcore_sources += files( + 'bpf-util.c', + 'bpf-util.h', + ) +endif + subdir('bpf') subdir('bpf/socket_bind') diff --git a/src/core/restrict-ifaces.c b/src/core/restrict-ifaces.c index efa5c8d85..a0ecaff81 100644 --- a/src/core/restrict-ifaces.c +++ b/src/core/restrict-ifaces.c @@ -9,7 +9,7 @@ #include "bpf-dlopen.h" #include "bpf-link.h" - +#include "bpf-util.h" #include "bpf/restrict_ifaces/restrict-ifaces-skel.h" static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) { @@ -34,19 +34,19 @@ static int prepare_restrict_ifaces_bpf( obj = restrict_ifaces_bpf__open(); if (!obj) - return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "Failed to open BPF object: %m"); + return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "restrict-interfaces: Failed to open BPF object: %m"); r = sym_bpf_map__resize(obj->maps.sd_restrictif, MAX(set_size(restrict_network_interfaces), 1u)); if (r != 0) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r, - "Failed to resize BPF map '%s': %m", + "restrict-interfaces: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_restrictif)); obj->rodata->is_allow_list = is_allow_list; r = restrict_ifaces_bpf__load(obj); if (r != 0) - return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "Failed to load BPF object: %m"); + return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "restrict-interfaces: Failed to load BPF object: %m"); map_fd = sym_bpf_map__fd(obj->maps.sd_restrictif); @@ -56,13 +56,15 @@ static int prepare_restrict_ifaces_bpf( ifindex = rtnl_resolve_interface(&rtnl, iface); if (ifindex < 0) { - log_unit_warning_errno(u, ifindex, "Couldn't find index of network interface '%s', ignoring: %m", iface); + log_unit_warning_errno(u, ifindex, + "restrict-interfaces: Couldn't find index of network interface '%s', ignoring: %m", + iface); continue; } if (sym_bpf_map_update_elem(map_fd, &ifindex, &dummy, BPF_ANY)) return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno, - "Failed to update BPF map '%s' fd: %m", + "restrict-interfaces: Failed to update BPF map '%s' fd: %m", sym_bpf_map__name(obj->maps.sd_restrictif)); } @@ -78,29 +80,21 @@ int restrict_network_interfaces_supported(void) { if (supported >= 0) return supported; - r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER); - if (r < 0) - return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m"); - if (r == 0) { - log_debug("Not running with unified cgroup hierarchy, BPF is not supported"); - return supported = 0; - } - - if (dlopen_bpf() < 0) - return false; + if (!cgroup_bpf_supported()) + return (supported = false); if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*ifindex=*/0)) { - log_debug("BPF program type cgroup_skb is not supported"); - return supported = 0; + log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported"); + return (supported = false); } r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj); if (r < 0) { - log_debug_errno(r, "Failed to load BPF object: %m"); - return supported = 0; + log_debug_errno(r, "restrict-interfaces: Failed to load BPF object: %m"); + return (supported = false); } - return supported = bpf_can_link_program(obj->progs.sd_restrictif_i); + return (supported = bpf_can_link_program(obj->progs.sd_restrictif_i)); } static int restrict_network_interfaces_install_impl(Unit *u) { @@ -117,7 +111,7 @@ static int restrict_network_interfaces_install_impl(Unit *u) { r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path); if (r < 0) - return log_unit_error_errno(u, r, "Failed to get cgroup path: %m"); + return log_unit_error_errno(u, r, "restrict-interfaces: Failed to get cgroup path: %m"); if (!cc->restrict_network_interfaces) return 0; @@ -136,12 +130,12 @@ static int restrict_network_interfaces_install_impl(Unit *u) { ingress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_i, cgroup_fd); r = sym_libbpf_get_error(ingress_link); if (r != 0) - return log_unit_error_errno(u, r, "Failed to create ingress cgroup link: %m"); + return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create ingress cgroup link: %m"); egress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_e, cgroup_fd); r = sym_libbpf_get_error(egress_link); if (r != 0) - return log_unit_error_errno(u, r, "Failed to create egress cgroup link: %m"); + return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create egress cgroup link: %m"); u->restrict_ifaces_ingress_bpf_link = TAKE_PTR(ingress_link); u->restrict_ifaces_egress_bpf_link = TAKE_PTR(egress_link); @@ -180,7 +174,8 @@ int restrict_network_interfaces_add_initial_link_fd(Unit *u, int fd) { r = fdset_put(u->initial_restric_ifaces_link_fds, fd); if (r < 0) - return log_unit_error_errno(u, r, "Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd); + return log_unit_error_errno(u, r, + "restrict-interfaces: Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd); return 0; } @@ -192,7 +187,7 @@ int restrict_network_interfaces_supported(void) { int restrict_network_interfaces_install(Unit *u) { return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), - "Failed to install RestrictInterfaces: BPF programs built from source code are not supported: %m"); + "restrict-interfaces: Failed to install; BPF programs built from source code are not supported: %m"); } int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) { diff --git a/src/fundamental/sha256.c b/src/fundamental/sha256.c index 0577a2492..cd16aec4d 100644 --- a/src/fundamental/sha256.c +++ b/src/fundamental/sha256.c @@ -47,6 +47,20 @@ # define SWAP64(n) (n) #endif +/* The condition below is from glibc's string/string-inline.c. + * See definition of _STRING_INLINE_unaligned. */ +#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__) + +/* To check alignment gcc has an appropriate operator. Other compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((size_t) p) % __alignof__(uint32_t) != 0) +# else +# define UNALIGNED_P(p) (((size_t) p) % sizeof(uint32_t) != 0) +# endif +#else +# define UNALIGNED_P(p) false +#endif + /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (FIPS 180-2:5.1.1) */ static const uint8_t fillbuf[64] = { @@ -94,10 +108,7 @@ void sha256_init_ctx(struct sha256_ctx *ctx) { } /* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ + prolog according to the standard and write the result to RESBUF. */ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { /* Take yet unprocessed bytes into account. */ uint32_t bytes = ctx->buflen; @@ -122,7 +133,10 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { /* Put result from CTX in first 32 bytes following RESBUF. */ for (size_t i = 0; i < 8; ++i) - ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); + if (UNALIGNED_P(resbuf)) + memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t)); + else + ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); return resbuf; } @@ -156,17 +170,6 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx /* Process available complete blocks. */ if (len >= 64) { - -/* The condition below is from glibc's string/string-inline.c. - * See definition of _STRING_INLINE_unaligned. */ -#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__) - -/* To check alignment gcc has an appropriate operator. Other compilers don't. */ -# if __GNUC__ >= 2 -# define UNALIGNED_P(p) (((size_t) p) % __alignof__(uint32_t) != 0) -# else -# define UNALIGNED_P(p) (((size_t) p) % sizeof(uint32_t) != 0) -# endif if (UNALIGNED_P(buffer)) while (len > 64) { memcpy(ctx->buffer, buffer, 64); @@ -174,9 +177,7 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx buffer = (const char *) buffer + 64; len -= 64; } - else -#endif - { + else { sha256_process_block(buffer, len & ~63, ctx); buffer = (const char *) buffer + (len & ~63); len &= 63; diff --git a/src/kernel-install/kernel-install.in b/src/kernel-install/kernel-install.in index d1630937e..a41a56a3d 100755 --- a/src/kernel-install/kernel-install.in +++ b/src/kernel-install/kernel-install.in @@ -80,12 +80,13 @@ fi if [ "${0##*/}" = "installkernel" ]; then COMMAND=add - # make install doesn't pass any initrds - no_initrds=1 + # kernel's install.sh invokes us as + # /sbin/installkernel + # We ignore the last two arguments. + set -- "$1" else COMMAND="$1" [ $# -ge 1 ] && shift - no_initrds=0 fi if [ "$COMMAND" = "inspect" ]; then @@ -320,16 +321,8 @@ case "$COMMAND" in fi for f in $PLUGINS; do - if [ "$no_initrds" = 1 ]; then - # kernel's install.sh invokes us as - # /sbin/installkernel - # We ignore the last two arguments. - [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $1" - "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$1" - else - [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $*" - "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@" - fi + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS" "$@" + "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@" err=$? [ $err -eq $skip_remaining ] && break @@ -362,8 +355,8 @@ case "$COMMAND" in # Assert that ENTRY_DIR_ABS actually matches what we are printing here [ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; } - ;; + *) echo "Error: unknown command '$COMMAND'" >&2 exit 1 diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 8a03890d8..c3eef87b8 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -222,7 +222,8 @@ tests += [ libglib, libgobject, libgio, - libdbus]], + libdbus, + libm]], [files('sd-bus/test-bus-signature.c'), [], diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index b77372c3a..026ec101e 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -428,7 +428,7 @@ int bus_message_from_header( _cleanup_free_ sd_bus_message *m = NULL; struct bus_header *h; - size_t a, label_sz; + size_t a, label_sz = 0; /* avoid false maybe-uninitialized warning */ assert(bus); assert(header || header_accessible <= 0); @@ -506,7 +506,10 @@ int bus_message_from_header( m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size); m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size); - if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size) + assert(message_size >= sizeof(struct bus_header)); + if (m->fields_size > message_size - sizeof(struct bus_header) || + ALIGN8(m->fields_size) > message_size - sizeof(struct bus_header) || + m->body_size != message_size - sizeof(struct bus_header) - ALIGN8(m->fields_size)) return -EBADMSG; } @@ -3061,15 +3064,21 @@ void bus_body_part_unmap(struct bus_body_part *part) { return; } -static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) { +static int buffer_peek(const void *p, size_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) { size_t k, start, end; assert(rindex); assert(align > 0); - start = ALIGN_TO((size_t) *rindex, align); - end = start + nbytes; + start = ALIGN_TO(*rindex, align); + if (start > sz) + return -EBADMSG; + /* Avoid overflow below */ + if (nbytes > SIZE_MAX - start) + return -EBADMSG; + + end = start + nbytes; if (end > sz) return -EBADMSG; @@ -3272,10 +3281,17 @@ static int message_peek_body( assert(rindex); assert(align > 0); - start = ALIGN_TO((size_t) *rindex, align); - padding = start - *rindex; - end = start + nbytes; + start = ALIGN_TO(*rindex, align); + if (start > m->user_body_size) + return -EBADMSG; + padding = start - *rindex; + + /* Avoid overflow below */ + if (nbytes > SIZE_MAX - start) + return -EBADMSG; + + end = start + nbytes; if (end > m->user_body_size) return -EBADMSG; diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index 5ddc2211e..62d27f7b8 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include "def.h" #include "hashmap.h" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index f7cff5800..c40d8defa 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2342,8 +2342,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - reset_scheduled_shutdown(m); - if (m->enable_wall_messages) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; _cleanup_free_ char *username = NULL; @@ -2361,6 +2359,8 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd username, tty, logind_wall_tty_filter, m); } + reset_scheduled_shutdown(m); + return sd_bus_reply_method_return(message, "b", true); } diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 1db5050c3..7d761a0d6 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -42,20 +42,28 @@ _const_ static usec_t when_wall(usec_t n, usec_t elapse) { return left % USEC_PER_HOUR; } -bool logind_wall_tty_filter(const char *tty, void *userdata) { - Manager *m = userdata; - const char *p; +bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata) { + Manager *m = ASSERT_PTR(userdata); - assert(m); + assert(m->scheduled_shutdown_action); - if (!m->scheduled_shutdown_tty) - return true; - - p = path_startswith(tty, "/dev/"); + const char *p = path_startswith(tty, "/dev/"); if (!p) return true; - return !streq(p, m->scheduled_shutdown_tty); + /* Do not send information about events which do not destroy local sessions to local terminals. We + * can assume that if the system enters sleep or hibernation, this will be visible in an obvious way + * for any local user. And once the systems exits sleep or hibernation, the notication would be just + * noise, in particular for auto-suspend. */ + if (is_local && + IN_SET(m->scheduled_shutdown_action->handle, + HANDLE_SUSPEND, + HANDLE_HIBERNATE, + HANDLE_HYBRID_SLEEP, + HANDLE_SUSPEND_THEN_HIBERNATE)) + return false; + + return !streq_ptr(p, m->scheduled_shutdown_tty); } static int warn_wall(Manager *m, usec_t n) { diff --git a/src/login/logind.h b/src/login/logind.h index 2136486c6..27f9e9729 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -180,6 +180,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_n_autovts); CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size); int manager_setup_wall_message_timer(Manager *m); -bool logind_wall_tty_filter(const char *tty, void *userdata); +bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata); int manager_read_efi_boot_loader_entries(Manager *m); diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 9e34161eb..89d1f1cdf 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -528,18 +528,26 @@ static int dns_stub_send( if (s) r = dns_stream_write_packet(s, reply); else { - int fd; + int fd, ifindex; fd = find_socket_fd(m, l, p->family, &p->sender, SOCK_DGRAM); if (fd < 0) return fd; + if (address_is_proxy(p->family, &p->destination)) + /* Force loopback iface if this is the loopback proxy stub + * and ifindex was normalized to 0 by manager_recv(). */ + ifindex = p->ifindex ?: LOOPBACK_IFINDEX; + else + /* Force loopback iface if this is the main listener stub. */ + ifindex = l ? p->ifindex : LOOPBACK_IFINDEX; + /* Note that it is essential here that we explicitly choose the source IP address for this * packet. This is because otherwise the kernel will choose it automatically based on the - * routing table and will thus pick 127.0.0.1 rather than 127.0.0.53. */ + * routing table and will thus pick 127.0.0.1 rather than 127.0.0.53/54. */ r = manager_send(m, fd, - l || address_is_proxy(p->family, &p->destination) ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */ + ifindex, p->family, &p->sender, p->sender_port, &p->destination, reply); } diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c index 6f82002ff..d8e778794 100644 --- a/src/shared/bpf-dlopen.c +++ b/src/shared/bpf-dlopen.c @@ -9,7 +9,6 @@ static void *bpf_dl = NULL; struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int); struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *); -long (*sym_libbpf_get_error)(const void *); int (*sym_bpf_link__fd)(const struct bpf_link *); int (*sym_bpf_link__destroy)(struct bpf_link *); int (*sym_bpf_map__fd)(const struct bpf_map *); @@ -26,9 +25,27 @@ void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *); void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *); bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32); const char* (*sym_bpf_program__name)(const struct bpf_program *); +libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t); +long (*sym_libbpf_get_error)(const void *); + +_printf_(2,0) +static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) { +#if !LOG_TRACE + /* libbpf logs a lot of details at its debug level, which we don't need to see. */ + if (level == LIBBPF_DEBUG) + return 0; +#endif + /* All other levels are downgraded to LOG_DEBUG */ + + /* errno is used here, on the assumption that if the log message uses %m, errno will be set to + * something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */ + return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap); +} int dlopen_bpf(void) { - return dlopen_many_sym_or_warn( + int r; + + r = dlopen_many_sym_or_warn( &bpf_dl, "libbpf.so.0", LOG_DEBUG, DLSYM_ARG(bpf_link__destroy), DLSYM_ARG(bpf_link__fd), @@ -48,7 +65,14 @@ int dlopen_bpf(void) { DLSYM_ARG(bpf_program__attach_cgroup), DLSYM_ARG(bpf_program__attach_lsm), DLSYM_ARG(bpf_program__name), + DLSYM_ARG(libbpf_set_print), DLSYM_ARG(libbpf_get_error)); + if (r < 0) + return r; + + /* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */ + (void) sym_libbpf_set_print(bpf_print_func); + return r; } #else diff --git a/src/shared/bpf-dlopen.h b/src/shared/bpf-dlopen.h index 713c41c3f..f0d40325d 100644 --- a/src/shared/bpf-dlopen.h +++ b/src/shared/bpf-dlopen.h @@ -8,7 +8,6 @@ extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int); extern struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *); -extern long (*sym_libbpf_get_error)(const void *); extern int (*sym_bpf_link__fd)(const struct bpf_link *); extern int (*sym_bpf_link__destroy)(struct bpf_link *); extern int (*sym_bpf_map__fd)(const struct bpf_map *); @@ -27,6 +26,8 @@ extern void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *); extern void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *); extern bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32); extern const char* (*sym_bpf_program__name)(const struct bpf_program *); +extern libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t); +extern long (*sym_libbpf_get_error)(const void *); #endif diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index 75e639dd9..3b0c6d3fa 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -571,7 +571,11 @@ static int verify_xbootldr_udev( r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v); if (r < 0) return log_error_errno(r, "Failed to get device property: %m"); - if (id128_equal_string(v, GPT_XBOOTLDR)) + + r = id128_equal_string(v, GPT_XBOOTLDR); + if (r < 0) + return log_error_errno(r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v); + if (r == 0) return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" has wrong type for extended boot loader partition.", node); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 49044a45a..b76189d6b 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -1123,7 +1123,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter if (ERRNO_IS_SECCOMP_FATAL(r)) return r; if (r < 0) - log_debug_errno(r, "Failed to install systemc call filter for architecture %s, skipping: %m", + log_debug_errno(r, "Failed to install system call filter for architecture %s, skipping: %m", seccomp_arch_to_string(arch)); } diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index f2f53380a..c7e89ba6a 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -337,7 +337,7 @@ int utmp_wall( const char *message, const char *username, const char *origin_tty, - bool (*match_tty)(const char *tty, void *userdata), + bool (*match_tty)(const char *tty, bool is_local, void *userdata), void *userdata) { _unused_ _cleanup_(utxent_cleanup) bool utmpx = false; @@ -381,17 +381,20 @@ int utmp_wall( if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0) continue; - /* this access is fine, because STRLEN("/dev/") << 32 (UT_LINESIZE) */ + /* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */ if (path_startswith(u->ut_line, "/dev/")) path = u->ut_line; else { if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0) return -ENOMEM; - path = buf; } - if (!match_tty || match_tty(path, userdata)) { + /* It seems that the address field is always set for remote logins. + * For local logins and other local entries, we get [0,0,0,0]. */ + bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6)); + + if (!match_tty || match_tty(path, is_local, userdata)) { q = write_to_terminal(path, text); if (q < 0) r = q; diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h index 3e71f76b2..36e4203b4 100644 --- a/src/shared/utmp-wtmp.h +++ b/src/shared/utmp-wtmp.h @@ -23,7 +23,7 @@ int utmp_wall( const char *message, const char *username, const char *origin_tty, - bool (*match_tty)(const char *tty, void *userdata), + bool (*match_tty)(const char *tty, bool is_local, void *userdata), void *userdata); static inline bool utxent_start(void) { diff --git a/src/test/meson.build b/src/test/meson.build index 74da544a4..6a467ea56 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -211,7 +211,9 @@ tests += [ [files('test-mkdir.c')], - [files('test-json.c')], + [files('test-json.c'), + [], + [libm]], [files('test-modhex.c')], @@ -275,7 +277,9 @@ tests += [ [files('test-parse-helpers.c')], - [files('test-parse-util.c')], + [files('test-parse-util.c'), + [], + [libm]], [files('test-sysctl-util.c')], @@ -664,6 +668,8 @@ tests += [ [], [], [], 'ENABLE_NSCD', 'manual'], [files('test-hmac.c')], + + [files('test-sha256.c')], ] ############################################################ diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 7ccfeadbb..45fe8f7c5 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -655,7 +655,7 @@ TEST(memory_deny_write_execute_shmat) { log_notice("Seccomp not available, skipping %s", __func__); return; } - if (!have_seccomp_privs()) { + if (!have_seccomp_privs() || have_effective_cap(CAP_IPC_OWNER) <= 0) { log_notice("Not privileged, skipping %s", __func__); return; } diff --git a/src/test/test-sha256.c b/src/test/test-sha256.c new file mode 100644 index 000000000..f168e4c35 --- /dev/null +++ b/src/test/test-sha256.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "hexdecoct.h" +#include "sha256.h" +#include "string-util.h" +#include "tests.h" + +static void sha256_process_string(const char *key, struct sha256_ctx *ctx) { + sha256_process_bytes(key, strlen(key), ctx); +} + +static void test_sha256_one(const char *key, const char *expect) { + uint8_t result[SHA256_DIGEST_SIZE + 3]; + _cleanup_free_ char *str = NULL; + struct sha256_ctx ctx; + + log_debug("\"%s\" → %s", key, expect); + + assert_se(str = new(char, strlen(key) + 4)); + + /* This tests unaligned buffers. */ + + for (size_t i = 0; i < 4; i++) { + strcpy(str + i, key); + + for (size_t j = 0; j < 4; j++) { + _cleanup_free_ char *hex_result = NULL; + + sha256_init_ctx(&ctx); + sha256_process_string(str + i, &ctx); + sha256_finish_ctx(&ctx, result + j); + + hex_result = hexmem(result + j, SHA256_DIGEST_SIZE); + assert_se(streq_ptr(hex_result, expect)); + } + } +} + +TEST(sha256) { + /* Results compared with output of 'echo -n "" | sha256sum -' */ + + test_sha256_one("abcdefghijklmnopqrstuvwxyz", + "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); + test_sha256_one("ほげほげあっちょんぶりけ", + "ce7225683653be3b74861c5a4323b6baf3c3ceb361413ca99e3a5b52c04411bd"); + test_sha256_one("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", + "9cfe7faff7054298ca87557e15a10262de8d3eee77827417fbdfea1c41b9ec23"); +} + +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 7fc0ed7c8..13ade29b5 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -94,7 +94,7 @@ static int send_passwords(const char *socket_name, char **passwords) { return (int) n; } -static bool wall_tty_match(const char *path, void *userdata) { +static bool wall_tty_match(const char *path, bool is_local, void *userdata) { _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; struct stat st; diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index 18d58c308..490e42b01 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -556,7 +556,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parent already died?"); if (kill(parent, SIGUSR2) < 0) - return log_error_errno(errno, "Failed to kill our own parent."); + return log_error_errno(errno, "Failed to kill our own parent: %m"); } } diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index aa16582d9..e29d4df69 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -127,7 +127,7 @@ static int run(int argc, char *argv[]) { r = query_volatile_mode(&m); if (r < 0) - return log_error_errno(r, "Failed to determine volatile mode from kernel command line."); + return log_error_errno(r, "Failed to determine volatile mode from kernel command line: %m"); if (r == 0 && argc >= 2) { /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */ m = volatile_mode_from_string(argv[1]); diff --git a/test/TEST-24-CRYPTSETUP/test.sh b/test/TEST-24-CRYPTSETUP/test.sh index 96d255dd9..b81b81165 100755 --- a/test/TEST-24-CRYPTSETUP/test.sh +++ b/test/TEST-24-CRYPTSETUP/test.sh @@ -10,6 +10,11 @@ TEST_FORCE_NEWIMAGE=1 # shellcheck source=test/test-functions . "${TEST_BASE_DIR:?}/test-functions" +PART_UUID="deadbeef-dead-dead-beef-000000000000" +DM_NAME="test24_varcrypt" +KERNEL_APPEND+=" rd.luks=1 luks.name=$PART_UUID=$DM_NAME luks.key=$PART_UUID=/keyfile:LABEL=varcrypt_keydev" +QEMU_OPTIONS+=" -drive format=raw,cache=unsafe,file=${STATEDIR:?}/keydev.img" + check_result_qemu() { local ret=1 @@ -17,13 +22,13 @@ check_result_qemu() { [[ -e "${initdir:?}/testok" ]] && ret=0 [[ -f "$initdir/failed" ]] && cp -a "$initdir/failed" "${TESTDIR:?}" - cryptsetup luksOpen "${LOOPDEV:?}p2" varcrypt <"$TESTDIR/keyfile" - mount /dev/mapper/varcrypt "$initdir/var" + cryptsetup luksOpen "${LOOPDEV:?}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile" + mount "/dev/mapper/$DM_NAME" "$initdir/var" save_journal "$initdir/var/log/journal" check_coverage_reports "${initdir:?}" || ret=5 _umount_dir "$initdir/var" _umount_dir "$initdir" - cryptsetup luksClose /dev/mapper/varcrypt + cryptsetup luksClose "/dev/mapper/$DM_NAME" [[ -f "$TESTDIR/failed" ]] && cat "$TESTDIR/failed" echo "${JOURNAL_LIST:-No journals were saved}" @@ -36,45 +41,65 @@ test_create_image() { create_empty_image_rootdir echo -n test >"${TESTDIR:?}/keyfile" - cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile" - cryptsetup luksOpen "${LOOPDEV}p2" varcrypt <"$TESTDIR/keyfile" - mkfs.ext4 -L var /dev/mapper/varcrypt + cryptsetup -q luksFormat --uuid="$PART_UUID" --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile" + cryptsetup luksOpen "${LOOPDEV}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile" + mkfs.ext4 -L var "/dev/mapper/$DM_NAME" mkdir -p "${initdir:?}/var" - mount /dev/mapper/varcrypt "$initdir/var" + mount "/dev/mapper/$DM_NAME" "$initdir/var" - # Create what will eventually be our root filesystem onto an overlay - ( - LOG_LEVEL=5 - # shellcheck source=/dev/null - source <(udevadm info --export --query=env --name=/dev/mapper/varcrypt) - # shellcheck source=/dev/null - source <(udevadm info --export --query=env --name="${LOOPDEV}p2") + LOG_LEVEL=5 - setup_basic_environment - mask_supporting_services + setup_basic_environment + mask_supporting_services - install_dmevent - generate_module_dependencies - cat >"$initdir/etc/crypttab" <"$initdir/etc/varkey" - ddebug <"$initdir/etc/crypttab" + install_dmevent + generate_module_dependencies - cat >>"$initdir/etc/fstab" <"$STATEDIR/keydev/keyfile" + umount "$STATEDIR/keydev" + + cat >>"$initdir/etc/fstab" <> "$initdir/etc/systemd/journald.conf" - ) + # Forward journal messages to the console, so we have something + # to investigate even if we fail to mount the encrypted /var + echo ForwardToConsole=yes >> "$initdir/etc/systemd/journald.conf" + + # If $INITRD wasn't provided explicitly, generate a custom one with dm-crypt + # support + if [[ -z "$INITRD" ]]; then + INITRD="${TESTDIR:?}/initrd.img" + dinfo "Generating a custom initrd with dm-crypt support in '${INITRD:?}'" + + if command -v dracut >/dev/null; then + dracut --force --verbose --add crypt "$INITRD" + elif command -v mkinitcpio >/dev/null; then + mkinitcpio --addhooks sd-encrypt --generate "$INITRD" + elif command -v mkinitramfs >/dev/null; then + # The cryptroot hook is provided by the cryptsetup-initramfs package + if ! dpkg-query -s cryptsetup-initramfs; then + derror "Missing 'cryptsetup-initramfs' package for dm-crypt support in initrd" + return 1 + fi + + mkinitramfs -o "$INITRD" + else + dfatal "Unrecognized initrd generator, can't continue" + return 1 + fi + fi } cleanup_root_var() { ddebug "umount ${initdir:?}/var" mountpoint "$initdir/var" && umount "$initdir/var" - [[ -b /dev/mapper/varcrypt ]] && cryptsetup luksClose /dev/mapper/varcrypt + [[ -b "/dev/mapper/${DM_NAME:?}" ]] && cryptsetup luksClose "/dev/mapper/$DM_NAME" } test_cleanup() { diff --git a/test/fuzz/fuzz-bus-message/issue-23486-case-1 b/test/fuzz/fuzz-bus-message/issue-23486-case-1 new file mode 100644 index 0000000000000000000000000000000000000000..fe8338b42ba6af6c080aa92aa619e05a6e6e1cc8 GIT binary patch literal 32 gcmd1dVrFCj0xbpQd;uUW!