From a518ea9ff1fe55c7bb5e4f391858a57d66b779d0 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sun, 16 Jul 2023 01:10:47 +0100 Subject: [PATCH 01/77] bus: add some minimal bounds check on signatures CID#1491292 CID#1491291 CID#1491290 CID#1491289 CID#1491284 CID#1491281 CID#1491280 CID#1491278 (cherry picked from commit d80cc39558ec7e596d594d1aadc4df81262611f8) --- src/busctl/busctl.c | 5 ++++- src/libsystemd/sd-bus/bus-message.c | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 72eed363351..c1a0479015c 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -1627,8 +1627,11 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, char p--; r = signature_element_length(signature, &k); - if (r < 0) + if (r < 0 || k < 2) { + if (r >= 0 && k < 2) + r = -ERANGE; return log_error_errno(r, "Invalid struct/dict entry signature: %m"); + } { char s[k-1]; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 3cf1419a14b..f1cf6a8cc47 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2027,6 +2027,8 @@ _public_ int sd_bus_message_appendv( r = signature_element_length(t, &k); if (r < 0) return r; + if (k < 2) + return -ERANGE; { char s[k - 1]; @@ -3470,6 +3472,8 @@ _public_ int sd_bus_message_readv( r = signature_element_length(t, &k); if (r < 0) return r; + if (k < 2) + return -ERANGE; { char s[k - 1]; @@ -3650,6 +3654,8 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) { r = signature_element_length(types, &k); if (r < 0) return r; + if (k < 2) + return -ERANGE; { char s[k-1]; From 7bd680bc62c3d071ae6b4b4a834f79b4eceff0d8 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Fri, 28 Jul 2023 12:24:32 +0200 Subject: [PATCH 02/77] core: free the strings in the set as well during unit cleanup Spotted while fuzzing #27890. ================================================================= ==908098==ERROR: LeakSanitizer: detected memory leaks Direct leak of 64 byte(s) in 1 object(s) allocated from: #0 0x7f4efe6d81f5 in __interceptor_realloc.part.0 (/lib64/libasan.so.8+0xd81f5) (BuildId: dc689b05ca2577037af24700212bb5cce1f91c8a) #1 0x7f4efb8e3ace in greedy_realloc ../src/basic/alloc-util.c:70 #2 0x7f4efb93b713 in extract_first_word ../src/basic/extract-word.c:62 #3 0x7f4efb970d50 in set_put_strsplit ../src/basic/hashmap.c:1902 #4 0x7f4efd76c27e in exec_context_deserialize ../src/core/execute-serialize.c:3341 #5 0x7f4efd778dcb in exec_deserialize ../src/core/execute-serialize.c:4122 #6 0x4032c0 in LLVMFuzzerTestOneInput ../src/core/fuzz-execute-serialize.c:60 #7 0x403c58 in main ../src/fuzz/fuzz-main.c:50 #8 0x7f4efecccb49 in __libc_start_call_main (/lib64/libc.so.6+0x27b49) (BuildId: 245240a31888ad5c11bbc55b18e02d87388f59a9) #9 0x7f4efecccc0a in __libc_start_main_alias_2 (/lib64/libc.so.6+0x27c0a) (BuildId: 245240a31888ad5c11bbc55b18e02d87388f59a9) #10 0x402344 in _start (/home/mrc0mmand/repos/@systemd/systemd/build-san/fuzz-execute-serialize+0x402344) (BuildId: 195f382cf1e39b9ba48d6dcf5a90f786d72837a8) SUMMARY: AddressSanitizer: 64 byte(s) leaked in 1 allocation(s). Aborted (core dumped) ==911550==ERROR: LeakSanitizer: detected memory leaks Direct leak of 17 byte(s) in 1 object(s) allocated from: #0 0x4df281 in strdup (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x4df281) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #1 0x7fe4ae2b38fc in _set_put_strndup_full /home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/../src/basic/hashmap.c:1868:21 #2 0x7fe4b0bad897 in exec_context_deserialize /home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/../src/core/execute-serialize.c:3914:29 #3 0x7fe4b0b80592 in exec_deserialize /home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/../src/core/execute-serialize.c:4109:13 #4 0x531d0f in LLVMFuzzerTestOneInput /home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/../src/core/fuzz-execute-serialize.c:59:16 #5 0x440594 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x440594) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #6 0x43f9b9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x43f9b9) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #7 0x440fd5 in fuzzer::Fuzzer::MutateAndTestOne() (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x440fd5) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #8 0x441955 in fuzzer::Fuzzer::Loop(std::vector>&) (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x441955) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #9 0x42e151 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x42e151) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #10 0x45a916 in main (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x45a916) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) #11 0x7fe4ac449b49 in __libc_start_call_main (/lib64/libc.so.6+0x27b49) (BuildId: 245240a31888ad5c11bbc55b18e02d87388f59a9) #12 0x7fe4ac449c0a in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x27c0a) (BuildId: 245240a31888ad5c11bbc55b18e02d87388f59a9) #13 0x422b74 in _start (/home/mrc0mmand/repos/@systemd/systemd/build-libfuzz/fuzz-execute-serialize+0x422b74) (BuildId: 4e58706e607b8be7972d83c421bc0b625d509ec6) SUMMARY: AddressSanitizer: 17 byte(s) leaked in 1 allocation(s). (cherry picked from commit 9b412709f21a4868e1bc0bb3252a4d26e862633b) --- src/core/cgroup.c | 2 +- src/core/execute.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 34643b242ce..2ccfcbad72e 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -287,7 +287,7 @@ void cgroup_context_done(CGroupContext *c) { while (c->bpf_foreign_programs) cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs); - c->restrict_network_interfaces = set_free(c->restrict_network_interfaces); + c->restrict_network_interfaces = set_free_free(c->restrict_network_interfaces); cpu_set_reset(&c->cpuset_cpus); cpu_set_reset(&c->startup_cpuset_cpus); diff --git a/src/core/execute.c b/src/core/execute.c index 9dafdffa08f..167657a0aee 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -6165,7 +6165,7 @@ void exec_context_done(ExecContext *c) { c->apparmor_profile = mfree(c->apparmor_profile); c->smack_process_label = mfree(c->smack_process_label); - c->restrict_filesystems = set_free(c->restrict_filesystems); + c->restrict_filesystems = set_free_free(c->restrict_filesystems); c->syscall_filter = hashmap_free(c->syscall_filter); c->syscall_archs = set_free(c->syscall_archs); @@ -6177,8 +6177,8 @@ void exec_context_done(ExecContext *c) { c->log_level_max = -1; exec_context_free_log_extra_fields(c); - c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns); - c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns); + c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); + c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); c->log_ratelimit_interval_usec = 0; c->log_ratelimit_burst = 0; @@ -6193,7 +6193,7 @@ void exec_context_done(ExecContext *c) { c->load_credentials = hashmap_free(c->load_credentials); c->set_credentials = hashmap_free(c->set_credentials); - c->import_credentials = set_free(c->import_credentials); + c->import_credentials = set_free_free(c->import_credentials); c->root_image_policy = image_policy_free(c->root_image_policy); c->mount_image_policy = image_policy_free(c->mount_image_policy); From ce856bb8c2f8d64504faababa8d046880bfa7165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 29 Jul 2023 14:07:07 +0200 Subject: [PATCH 03/77] configure: update meson invocation New meson says: WARNING: Running the setup command as `meson [options]` instead of `meson setup [options]` is ambiguous and deprecated. Inspired by https://github.com/systemd/systemd/issues/28482. (cherry picked from commit 4f3c90acfee4f5bbd128bdc72008fa2f79d52cfd) --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index e130c6cb142..5c1722db050 100755 --- a/configure +++ b/configure @@ -21,4 +21,4 @@ done export "${cflags?}" "${cxxflags?}" set -x -exec meson build "${args[@]}" +exec meson setup build "${args[@]}" From 7f9b0a978759b41c342629f6884ae519f5d0a1f0 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Sat, 29 Jul 2023 21:04:44 +0200 Subject: [PATCH 04/77] analyze: fix pcrs verb output without TPM support If we don't have TPM support then `alg` is NULL and passing this to table_new() means we'd get a table with only two columns instead of three, leading up to a very confusing output: $ build/systemd-analyze pcrs System lacks full TPM2 support, not showing PCR state. NR NAME 0 platform-code - 1 platform-config - 2 external-code - 3 external-config - 4 boot-loader-code - 5 boot-loader-config - 6 - - 7 ... Let's name the header in this case with a simple dash, as it's going to be hidden anyway, to make the table nice again: $ build/systemd-analyze pcrs System lacks full TPM2 support, not showing PCR state. NR NAME 0 platform-code 1 platform-config 2 external-code 3 external-config 4 boot-loader-code 5 boot-loader-config 6 - 7 secure-boot-policy ... (cherry picked from commit 9fe4e68cabaf79681388d025d86bd14f5ae944a6) --- src/analyze/analyze-pcrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyze/analyze-pcrs.c b/src/analyze/analyze-pcrs.c index 82f0f392880..c081ffef017 100644 --- a/src/analyze/analyze-pcrs.c +++ b/src/analyze/analyze-pcrs.c @@ -104,7 +104,7 @@ int verb_pcrs(int argc, char *argv[], void *userdata) { return r; } - table = table_new("nr", "name", alg); + table = table_new("nr", "name", alg ?: "-"); if (!table) return log_oom(); From b601dd459bbd45383ce7525cba89a18141d4c1b6 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 29 Jul 2023 20:00:55 +0800 Subject: [PATCH 05/77] fstab-util: add fstab_has_node (cherry picked from commit 24c0078a846c0e8dd7cc65f0a4a90ba05864434b) --- src/shared/fstab-util.c | 19 ++++++++++--------- src/shared/fstab-util.h | 3 +++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 4ffec25c754..67e718b6eaa 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -63,7 +63,7 @@ bool fstab_is_extrinsic(const char *mount, const char *opts) { return false; } -static int fstab_is_mount_point_of(const char *what_fstab, const char *path) { +static int fstab_is_same_node(const char *what_fstab, const char *path) { _cleanup_free_ char *node = NULL; assert(what_fstab); @@ -86,7 +86,7 @@ int fstab_is_mount_point_full(const char *where, const char *path) { _cleanup_endmntent_ FILE *f = NULL; int r; - assert(where); + assert(where || path); f = setmntent(fstab_path(), "re"); if (!f) @@ -100,14 +100,15 @@ int fstab_is_mount_point_full(const char *where, const char *path) { if (!me) return errno != 0 ? -errno : false; - if (path_equal(where, me->mnt_dir)) { - if (!path) - return true; + if (where && !path_equal(where, me->mnt_dir)) + continue; - r = fstab_is_mount_point_of(me->mnt_fsname, path); - if (r > 0 || (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))) - return r; - } + if (!path) + return true; + + r = fstab_is_same_node(me->mnt_fsname, path); + if (r > 0 || (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))) + return r; } return false; diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h index cb3686bee3f..a1c079fd417 100644 --- a/src/shared/fstab-util.h +++ b/src/shared/fstab-util.h @@ -13,6 +13,9 @@ int fstab_is_mount_point_full(const char *where, const char *path); static inline int fstab_is_mount_point(const char *where) { return fstab_is_mount_point_full(where, NULL); } +static inline int fstab_has_node(const char *path) { + return fstab_is_mount_point_full(NULL, path); +} int fstab_filter_options( const char *opts, From 15ff03b9882b75738b7a455ff956d1d9e073098f Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 29 Jul 2023 20:05:58 +0800 Subject: [PATCH 06/77] gpt-auto: don't mount ESP if there's an fstab entry for it Follow-up for #28511 Fixes #28550 (cherry picked from commit 7893a547ebcee007dbc6119373d3e5d809f221fe) --- src/gpt-auto-generator/gpt-auto-generator.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 840d3b6ed1d..ccf48b549b7 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -574,10 +574,17 @@ static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) { return 0; } + /* Check if there's an existing fstab entry for ESP. If so, we just skip the gpt-auto logic. */ + r = fstab_has_node(p->node); + if (r < 0) + return log_error_errno(r, + "Failed to check if fstab entry for device '%s' exists: %m", p->node); + if (r > 0) + return 0; + /* If /boot/ is present, unused, and empty, we'll take that. * Otherwise, if /efi/ is unused and empty (or missing), we'll take that. - * Otherwise, we do nothing. - */ + * Otherwise, we do nothing. */ if (!has_xbootldr && slash_boot_exists()) { r = slash_boot_in_fstab(); if (r < 0) @@ -590,16 +597,6 @@ static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) { esp_path = "/boot"; id = "boot"; } - } else { - /* Check if the fstab entry for /boot/ is already the ESP. If so, we don't need to - * check /efi/ or duplicate the mount there. */ - r = fstab_is_mount_point_full("/boot", p->node); - if (r < 0) - return log_error_errno(r, - "Failed to check if fstab entry for /boot uses the same device as '%s': %m", - p->node); - if (r > 0) - return 0; } } From 064be3eb48106faf45aa7e6ef481b58ad7c46e21 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sun, 30 Jul 2023 20:59:04 +0200 Subject: [PATCH 07/77] elf2efi: Fix header size calculation The PE header size calculation failed to take the PE magic and coff header size into account, which will lead to header truncation if we are writing only 5 sections. (cherry picked from commit ee91e06a5841c30bc7306260528ef407e0ebbab3) --- tools/elf2efi.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/elf2efi.py b/tools/elf2efi.py index e233c8e3aba..2e478940f5c 100755 --- a/tools/elf2efi.py +++ b/tools/elf2efi.py @@ -210,6 +210,7 @@ def __init__(self): # Nobody cares about DOS headers, so put the PE header right after. PE_OFFSET = 64 +PE_MAGIC = b"PE\0\0" def align_to(x: int, align: int) -> int: @@ -304,7 +305,10 @@ def copy_sections(elf: ELFFile, opt: PeOptionalHeader) -> typing.List[PeSection] def apply_elf_relative_relocation( - reloc: ElfRelocation, image_base: int, sections: typing.List[PeSection], addend_size: int + reloc: ElfRelocation, + image_base: int, + sections: typing.List[PeSection], + addend_size: int, ): # fmt: off [target] = [ @@ -439,7 +443,7 @@ def write_pe( file.seek(0x3C, io.SEEK_SET) file.write(PE_OFFSET.to_bytes(2, byteorder="little")) file.seek(PE_OFFSET, io.SEEK_SET) - file.write(b"PE\0\0") + file.write(PE_MAGIC) file.write(coff) file.write(opt) @@ -453,6 +457,8 @@ def write_pe( file.write(pe_s) offset = align_to(offset + len(pe_s.data), FILE_ALIGNMENT) + assert file.tell() <= opt.SizeOfHeaders + for pe_s in sections: file.seek(pe_s.PointerToRawData, io.SEEK_SET) file.write(pe_s.data) @@ -515,6 +521,8 @@ def elf2efi(args: argparse.Namespace): opt.SizeOfHeaders = align_to( PE_OFFSET + + len(PE_MAGIC) + + sizeof(PeCoffHeader) + coff.SizeOfOptionalHeader + sizeof(PeSection) * max(coff.NumberOfSections, args.minimum_sections), FILE_ALIGNMENT, From 83bf04f71a181a8c1325933b2f741852cef3c302 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sun, 30 Jul 2023 21:05:24 +0200 Subject: [PATCH 08/77] stub: Also reserve sections for EFI stub The stub image may not have enough sections to cause enough PE header space to be free for later expansion. Given that the stub is guaranteed to be expanded we should always reserve enough sections for it. This also bumps the reservation to 15. It doesn't add more space compared to current builds but it more closely reflects the amount of sections that a UKI could have in total if all optional sections are used. Fixes: #28593 (cherry picked from commit d0bbe3248551e6cb02ba62559e7ff87b0a27f789) --- src/boot/efi/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index 1c526296517..2773eaf2862 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -362,7 +362,7 @@ foreach efi_elf_binary : efi_elf_binaries name += name.startswith('systemd-boot') ? '.efi' : '.efi.stub' # For the addon, given it's empty, we need to explicitly reserve space in the header to account for # the sections that ukify will add. - minimum_sections = name.startswith('addon') ? '7' : '0' + minimum_sections = name.endswith('.stub') ? '15' : '0' exe = custom_target( name, output : name, From f42d35dd58b5f2b4695dedaa7e38c3731148639c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 20 Jul 2023 14:56:43 +0900 Subject: [PATCH 09/77] chase: reuse "done" to open fd of starting point For readability that 'done' and 'fd' are always consistent with each other. - dir_fd == AT_FDCWD: - path is absolute: - previous: fd = open("/") - current: fd = openat(AT_FDCWD, "/") - path is relative: - previous: fd = openat(AT_FDCWD, ".") - current: fd = openat(AT_FDCWD, ".") - dir_fd >= 0: - dir_fd points to "/": - previous: fd = openat(dir_fd, ".") - current: fd = openat(dir_fd, "/") - dir_fd does not point to "/": - previous: fd = openat(dir_fd, ".") - current: fd = openat(dir_fd, ".") Hence, this should not change any behavior. Just refactoring. (cherry picked from commit 00a050b395b6c38f6dea86fd660741bba00fadf0) --- src/basic/chase.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index a4d9edb4c97..2db0b412618 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -212,30 +212,27 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int return -ENOMEM; } - /* If we get AT_FDCWD, we always resolve symlinks relative to the host's root. Only if a positive - * directory file descriptor is provided we will look at CHASE_AT_RESOLVE_IN_ROOT to determine - * whether to resolve symlinks in it or not. */ - if (dir_fd >= 0 && FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) - root_fd = openat(dir_fd, ".", O_CLOEXEC|O_DIRECTORY|O_PATH); - else - root_fd = open("/", O_CLOEXEC|O_DIRECTORY|O_PATH); - if (root_fd < 0) - return -errno; - /* If a positive directory file descriptor is provided, always resolve the given path relative to it, * regardless of whether it is absolute or not. If we get AT_FDCWD, follow regular openat() * semantics, if the path is relative, resolve against the current working directory. Otherwise, * resolve against root. */ - if (dir_fd >= 0 || !path_is_absolute(path)) - fd = openat(dir_fd, ".", O_CLOEXEC|O_DIRECTORY|O_PATH); - else - fd = open("/", O_CLOEXEC|O_DIRECTORY|O_PATH); + fd = openat(dir_fd, done ?: ".", O_CLOEXEC|O_DIRECTORY|O_PATH); if (fd < 0) return -errno; if (fstat(fd, &st) < 0) return -errno; + /* If we get AT_FDCWD, we always resolve symlinks relative to the host's root. Only if a positive + * directory file descriptor is provided we will look at CHASE_AT_RESOLVE_IN_ROOT to determine + * whether to resolve symlinks in it or not. */ + if (dir_fd >= 0 && FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) + root_fd = openat(dir_fd, ".", O_CLOEXEC|O_DIRECTORY|O_PATH); + else + root_fd = open("/", O_CLOEXEC|O_DIRECTORY|O_PATH); + if (root_fd < 0) + return -errno; + if (FLAGS_SET(flags, CHASE_TRAIL_SLASH)) append_trail_slash = ENDSWITH_SET(buffer, "/", "/."); From 3700ecfc488be1a9c0576f5fb841fa615769e50c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 20 Jul 2023 15:04:01 +0900 Subject: [PATCH 10/77] chase: fix CHASE_STEP with ".." (cherry picked from commit 5f0bae7bffa8fe334dfef957d8eb48fc643e47ae) --- src/basic/chase.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index 2db0b412618..8f9c361a098 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -264,8 +264,11 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int /* If we already are at the top, then going up will not change anything. This is * in-line with how the kernel handles this. */ - if (empty_or_root(done) && FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) + if (empty_or_root(done) && FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) { + if (FLAGS_SET(flags, CHASE_STEP)) + goto chased_one; continue; + } fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH|O_DIRECTORY); if (fd_parent < 0) @@ -281,8 +284,11 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int r = dir_fd_is_root(fd); if (r < 0) return r; - if (r > 0) + if (r > 0) { + if (FLAGS_SET(flags, CHASE_STEP)) + goto chased_one; continue; + } } r = path_extract_directory(done, &parent); From 7b8b2c8b3a9fbe300d7f505e8ab4a09d1ca83824 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 20 Jul 2023 21:17:32 +0900 Subject: [PATCH 11/77] chase: drop CHASE_AT_RESOLVE_IN_ROOT earlier The flag will be anyway dropped in chaseat(), but let's shortcut. (cherry picked from commit b7e957d30f7ae5318bf6c294ef796bc75ca3fe20) --- src/basic/chase.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index 8f9c361a098..e66070b5d11 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -511,9 +511,14 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, return -EINVAL; /* A root directory of "/" or "" is identical to "/". */ - if (empty_or_root(root)) + if (empty_or_root(root)) { root = "/"; - else { + + /* When the root directory is "/", we will drop CHASE_AT_RESOLVE_IN_ROOT in chaseat(), + * hence below is not necessary, but let's shortcut. */ + flags &= ~CHASE_AT_RESOLVE_IN_ROOT; + + } else { r = path_make_absolute_cwd(root, &root_abs); if (r < 0) return r; From b775fc5930bac82cd6c65673107a9a4ef8afcf6d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 21 Jul 2023 11:07:01 +0900 Subject: [PATCH 12/77] chase: add two more assertions When 'need_absolute' is true, 'done' should always contain "/" at the beginning, and thus should not be NULL. (cherry picked from commit 1c13bdf34291dd2444439a4e30ad35a29d22a5d8) --- src/basic/chase.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/basic/chase.c b/src/basic/chase.c index e66070b5d11..4d883e18d8e 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -449,6 +449,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int } if (!done) { + assert(!need_absolute || FLAGS_SET(flags, CHASE_EXTRACT_FILENAME)); done = strdup(append_trail_slash ? "./" : "."); if (!done) return -ENOMEM; @@ -475,6 +476,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int const char *e; if (!done) { + assert(!need_absolute); done = strdup(append_trail_slash ? "./" : "."); if (!done) return -ENOMEM; From 80c6ed8dc05b6a3d9ee0e89eb16e6c16b916a85a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 20 Jul 2023 15:17:27 +0900 Subject: [PATCH 13/77] chase: carefully handle result of extracting parent directory Should not change any behavior. (cherry picked from commit 4de5b4e3751609e6a0fe5e3f5dfef22ccae56fad) --- src/basic/chase.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index 4d883e18d8e..b612a2fef61 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -292,9 +292,25 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int } r = path_extract_directory(done, &parent); - if (r >= 0 || r == -EDESTADDRREQ) + if (r >= 0) { + assert(!need_absolute || path_is_absolute(parent)); free_and_replace(done, parent); - else if (IN_SET(r, -EINVAL, -EADDRNOTAVAIL)) { + } else if (r == -EDESTADDRREQ) { + /* 'done' contains filename only (i.e. no slash). */ + assert(!need_absolute); + done = mfree(done); + } else if (r == -EADDRNOTAVAIL) { + /* 'done' is "/". This branch should be already handled in the above. */ + assert(!FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)); + assert_not_reached(); + } else if (r == -EINVAL) { + /* 'done' is an empty string, ends with '..', or an invalid path. */ + assert(!need_absolute); + assert(!FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)); + + if (!path_is_valid(done)) + return -EINVAL; + /* If we're at the top of "dir_fd", start appending ".." to "done". */ if (!path_extend(&done, "..")) return -ENOMEM; From 5e0187b0cf83e5e0b58818085865d6416e5b09af Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 21 Jul 2023 13:28:39 +0900 Subject: [PATCH 14/77] chase: check root path in more detail In chaseat() we call dir_fd_is_root() several places, and the final result depends on it. If the root path specified to `chase()` is not normalized but points to "/", e.g. "/../", assertions in `chaseat()` or `chase()` may be triggered. (cherry picked from commit 83c57d8cde7ac43e5d00e2ed247c831f4e241ba8) --- src/basic/chase.c | 36 +++++++++++++++++++++++++++++++++++- src/basic/fd-util.h | 3 +++ src/test/test-chase.c | 5 +++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index b612a2fef61..abb9b733841 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -518,6 +518,27 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int return 0; } +static int empty_or_root_to_null(const char **path) { + int r; + + assert(path); + + /* This nullifies the input path when the path is empty or points to "/". */ + + if (empty_or_root(*path)) { + *path = NULL; + return 0; + } + + r = path_is_root(*path); + if (r < 0) + return r; + if (r > 0) + *path = NULL; + + return 0; +} + int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, int *ret_fd) { _cleanup_free_ char *root_abs = NULL, *absolute = NULL, *p = NULL; _cleanup_close_ int fd = -EBADF, pfd = -EBADF; @@ -528,6 +549,10 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, if (isempty(path)) return -EINVAL; + r = empty_or_root_to_null(&root); + if (r < 0) + return r; + /* A root directory of "/" or "" is identical to "/". */ if (empty_or_root(root)) { root = "/"; @@ -624,8 +649,13 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) { if (!path_is_absolute(path)) { _cleanup_free_ char *root_abs = NULL; + r = empty_or_root_to_null(&root); + if (r < 0 && r != -ENOENT) + return r; + /* If the dir_fd points to the root directory, chaseat() always returns an absolute path. */ - assert(!empty_or_root(root)); + if (empty_or_root(root)) + return -EINVAL; r = path_make_absolute_cwd(root, &root_abs); if (r < 0) @@ -658,6 +688,10 @@ int chase_extract_filename(const char *path, const char *root, char **ret) { if (!path_is_absolute(path)) return -EINVAL; + r = empty_or_root_to_null(&root); + if (r < 0 && r != -ENOENT) + return r; + if (!empty_or_root(root)) { _cleanup_free_ char *root_abs = NULL; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index c870a1b8990..6aecb91fab3 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -102,6 +102,9 @@ int read_nr_open(void); int fd_get_diskseq(int fd, uint64_t *ret); int path_is_root_at(int dir_fd, const char *path); +static inline int path_is_root(const char *path) { + return path_is_root_at(AT_FDCWD, path); +} static inline int dir_fd_is_root(int dir_fd) { return path_is_root_at(dir_fd, NULL); } diff --git a/src/test/test-chase.c b/src/test/test-chase.c index 75c508970e1..d3399c11c6c 100644 --- a/src/test/test-chase.c +++ b/src/test/test-chase.c @@ -73,6 +73,11 @@ TEST(chase) { assert_se(path_equal(result, "/usr")); result = mfree(result); + r = chase(p, "/.//../../../", 0, &result, NULL); + assert_se(r > 0); + assert_se(path_equal(result, "/usr")); + result = mfree(result); + pslash = strjoina(p, "/"); r = chase(pslash, NULL, 0, &result, NULL); assert_se(r > 0); From 2bb47bcf916b2ea5c1ccd4cc737065dbef1fae4e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Jul 2023 10:07:05 +0900 Subject: [PATCH 15/77] chase: propagate error in dir_fd_is_root() Otherwise, if it fails, chaseat() may return unexpected result and triggers an assertion in chase(). (cherry picked from commit 4445242a1ea9e4988768c8ef36fa8ffe298ca925) --- src/basic/chase.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index abb9b733841..c3ecbbb3fee 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -72,6 +72,13 @@ static int log_prohibited_symlink(int fd, ChaseFlags flags) { strna(n1)); } +static int chaseat_needs_absolute(int dir_fd, const char *path) { + if (dir_fd < 0) + return path_is_absolute(path); + + return dir_fd_is_root(dir_fd); +} + int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int *ret_fd) { _cleanup_free_ char *buffer = NULL, *done = NULL; _cleanup_close_ int fd = -EBADF, root_fd = -EBADF; @@ -205,7 +212,11 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int /* If we receive an absolute path together with AT_FDCWD, we need to return an absolute path, because * a relative path would be interpreted relative to the current working directory. Also, let's make * the result absolute when the file descriptor of the root directory is specified. */ - bool need_absolute = (dir_fd == AT_FDCWD && path_is_absolute(path)) || (dir_fd >= 0 && dir_fd_is_root(dir_fd) > 0); + r = chaseat_needs_absolute(dir_fd, path); + if (r < 0) + return r; + + bool need_absolute = r; if (need_absolute) { done = strdup("/"); if (!done) From 44d235ac8f41f4e874a0abf62de19e0c705074c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 29 Jul 2023 19:29:33 +0200 Subject: [PATCH 16/77] systemd-battery-check: provide more debug logs The logs would give no hint about the answer to most interesting question: why we decided to return true or false from the program. If we find batteries that are low or uncertain, log at info level. (cherry picked from commit 02f7f8aa4f1d0b7a24ee3cd5685a791771d9ded5) --- src/shared/battery-util.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/shared/battery-util.c b/src/shared/battery-util.c index 71ee89a5498..8b7bdc704d2 100644 --- a/src/shared/battery-util.c +++ b/src/shared/battery-util.c @@ -254,19 +254,28 @@ int battery_is_discharging_and_low(void) { level = battery_read_capacity_percentage(dev); if (level < 0) { + log_device_debug_errno(dev, level, "Battery capacity is unreadable: %m"); unsure = true; continue; } - if (level > BATTERY_LOW_CAPACITY_LEVEL) /* Found a charged battery */ + if (level > BATTERY_LOW_CAPACITY_LEVEL) { /* Found a charged battery */ + log_device_full(dev, + found_low ? LOG_INFO : LOG_DEBUG, + "Found battery with capacity above threshold (%d%% > %d%%).", + level, BATTERY_LOW_CAPACITY_LEVEL); return false; + } + log_device_info(dev, + "Found battery with capacity below threshold (%d%% <= %d%%).", + level, BATTERY_LOW_CAPACITY_LEVEL); found_low = true; } /* If we found a battery whose state we couldn't read, don't assume we are in low battery state */ if (unsure) { - log_debug("Found battery with unreadable state, assuming not in low battery state."); + log_info("Found battery with unreadable state, assuming not in low battery state."); return false; } From 3d9be9aa3171d2096ab4922630f4db0a548e570d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 30 Jul 2023 12:11:33 +0200 Subject: [PATCH 17/77] man/systemd.service: advise Type=exec instead of Type=simple The descriptions of various options are reworked: first say what protocol actually is, i.e. describe what type of notification the manager waits for. Only after that describe various steps and things the service should do. Also, apply some paragraph breaks. Instead of recommending Type=simple, recommend Type=exec. Say explicitly that Type=simple, Type=forking are not recommended. Type=simple ignores failure in a way that doesn't make any sense except as a historical accident. We introduced 'exec' instead of changing 'simple' to keep backwards-compatiblity, but 'simple' is not very useful. 'forking' works, but is inefficient: correctly programming the interface requires a lot of work, and at runtime, the additional one or two forks are just a waste of CPU resources. Furthermore, we now understand that because of COW traps, they may also increase memory requirements. There is really no reason to use 'forking', except if it's already implemented and the code cannot be changed to use 'notify'. Also, remove the recommendations to use Type=simple to avoid delaying boot. In most cases, if the service can support notifications about startup, those should be done. Overall, for new services, "notify", "notify-reload", and "dbus" are the types that make sense. (cherry picked from commit 377d3a31e638c834ba66edefa4cabc90318420fc) --- man/systemd.service.xml | 135 ++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 6237d27f00c..b09cdd4ecf5 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -155,41 +155,52 @@ Type= - Configures the process start-up type for this service unit. One of , - , , , , - , or : + Configures the mechanism via which the service notifies the manager that the service start-up + has finished. One of , , , + , , , + , or : If set to (the default if ExecStart= is specified but neither Type= nor BusName= are), the service manager - will consider the unit started immediately after the main service process has been forked off. It is - expected that the process configured with ExecStart= is the main process of the - service. In this mode, if the process offers functionality to other processes on the system, its - communication channels should be installed before the service is started up (e.g. sockets set up by - systemd, via socket activation), as the service manager will immediately proceed starting follow-up units, - right after creating the main service process, and before executing the service's binary. Note that this - means systemctl start command lines for services will report - success even if the service's binary cannot be invoked successfully (for example because the selected - User= doesn't exist, or the service binary is missing). - - The type is similar to , but the service - manager will consider the unit started immediately after the main service binary has been executed. The service - manager will delay starting of follow-up units until that point. (Or in other words: - proceeds with further jobs right after fork() returns, while - will not proceed before both fork() and - execve() in the service process succeeded.) Note that this means systemctl - start command lines for services will report failure when the service's - binary cannot be invoked successfully (for example because the selected User= doesn't + will consider the unit started immediately after the main service process has been forked off. + The use of this type is discouraged, use instead. + + + It is expected that the process configured with ExecStart= is the main + process of the service. In this mode, if the process offers functionality to other processes on + the system, its communication channels should be installed before the service is started up + (e.g. sockets set up by systemd, via socket activation), as the service manager will immediately + proceed starting follow-up units, right after creating the main service process, and before + executing the service's binary. Note that this means systemctl start command + lines for services will report success even if the service's binary + cannot be invoked successfully (for example because the selected User= doesn't exist, or the service binary is missing). - If set to , it is expected that the process configured with - ExecStart= will call fork() as part of its start-up. The parent - process is expected to exit when start-up is complete and all communication channels are set up. The child - continues to run as the main service process, and the service manager will consider the unit started when - the parent process exits. This is the behavior of traditional UNIX services. If this setting is used, it is - recommended to also use the PIDFile= option, so that systemd can reliably identify the - main process of the service. systemd will proceed with starting follow-up units as soon as the parent - process exits. + The type is similar to , but the + service manager will consider the unit started immediately after the main service binary has been + executed. The service manager will delay starting of follow-up units until that point. (Or in + other words: proceeds with further jobs right after + fork() returns, while will not proceed before both + fork() and execve() in the service process succeeded.) + Note that this means systemctl start command lines for + services will report failure when the service's binary cannot be invoked successfully (for + example because the selected User= doesn't exist, or the service binary is + missing). + + If set to , the manager will consider the unit started + immediately after the binary that forked off by the manager exits. The use of this type + is discouraged, use , , or + instead. + + It is expected that the process configured with ExecStart= will call + fork() as part of its start-up. The parent process is expected to exit when + start-up is complete and all communication channels are set up. The child continues to run as the + main service process, and the service manager will consider the unit started when the parent + process exits. This is the behavior of traditional UNIX services. If this setting is used, it is + recommended to also use the PIDFile= option, so that systemd can reliably + identify the main process of the service. The manager will proceed with starting follow-up units + after the parent process exits. Behavior of is similar to ; however, the service manager will consider the unit up after the main process exits. It will then @@ -197,18 +208,19 @@ of service. Type= is the implied default if neither Type= nor ExecStart= are specified. Note that if this option is used without RemainAfterExit= the service will never enter - active unit state, but directly transition from activating - to deactivating or dead since no process is configured that - shall run continuously. In particular this means that after a service of this type ran (and which - has RemainAfterExit= not set) it will not show up as started afterwards, but - as dead. + active unit state, but will directly transition from + activating to deactivating or dead, + since no process is configured that shall run continuously. In particular this means that after a + service of this type ran (and which has RemainAfterExit= not set) it will not + show up as started afterwards, but as dead. Behavior of is similar to ; however, - it is expected that the service acquires a name on the D-Bus bus, as configured by - BusName=. systemd will proceed with starting follow-up units after the D-Bus - bus name has been acquired. Service units with this option configured implicitly gain - dependencies on the dbus.socket unit. This type is the default if - BusName= is specified. A service unit of this type is considered to be in the + units of this type must have the BusName= specified and the service manager + will consider the unit up when the specified bus name has been acquired. This type is the default + if BusName= is specified. + + Service units with this option configured implicitly gain dependencies on the + dbus.socket unit. A service unit of this type is considered to be in the activating state until the specified bus name is acquired. It is considered activated while the bus name is taken. Once the bus name is released the service is considered being no longer functional which has the effect that the service manager attempts to terminate any remaining @@ -223,15 +235,19 @@ units after this notification message has been sent. If this option is used, NotifyAccess= (see below) should be set to open access to the notification socket provided by systemd. If NotifyAccess= is missing or set to - , it will be forcibly set to . - - Behavior of is identical to - . However, it extends the logic in one way: the - SIGHUP UNIX process signal is sent to the service's main process when the - service is asked to reload. (The signal to send can be tweaked via - ReloadSignal=, see below.) When - initiating the reload process the service is then expected to reply with a notification message - via sd_notify3 + , it will be forcibly set to . + + If the service supports reloading, and uses the a signal to start the reload, using + instead is recommended. + + Behavior of is similar to , + with one difference: the SIGHUP UNIX process signal is sent to the service's + main process when the service is asked to reload and the manager will wait for a notification + about the reload being finished. + + When initiating the reload process the service is expected to reply with a notification + message via + sd_notify3 that contains the RELOADING=1 field in combination with MONOTONIC_USEC= set to the current monotonic time (i.e. CLOCK_MONOTONIC in @@ -239,7 +255,10 @@ in μs, formatted as decimal string. Once reloading is complete another notification message must be sent, containing READY=1. Using this service type and implementing this reload protocol is an efficient alternative to providing an ExecReload= - command for reloading of the service's configuration. + command for reloading of the service's configuration. + + The signal to send can be tweaked via ReloadSignal=, see below. + Behavior of is very similar to ; however, actual execution of the service program is delayed until all active jobs are dispatched. This may be used @@ -249,27 +268,25 @@ anyway. - It is generally recommended to use Type= for + It is generally recommended to use Type= for long-running services whenever possible, as it is the simplest and fastest option. However, as this service type won't propagate service start-up failures and doesn't allow ordering of other units against completion of initialization of the service (which for example is useful if clients need to connect to the service through some form of IPC, and the IPC channel is only established by the service itself — in contrast to doing this ahead of time through socket or bus activation or similar), it might not be sufficient for many cases. If so, , - or (the latter only in case the service + , or (the latter only in case the service provides a D-Bus interface) are the preferred options as they allow service program code to precisely schedule when to consider the service started up successfully and when to proceed with follow-up units. The / service types require explicit support in the service codebase (as sd_notify() or an equivalent API needs to be invoked by the service at the appropriate time) — if it's not supported, then - is an alternative: it supports the traditional UNIX service start-up - protocol. Finally, might be an option for cases where it is enough to ensure - the service binary is invoked, and where the service binary itself executes no or little - initialization on its own (and its initialization is unlikely to fail). Note that using any type - other than possibly delays the boot process, as the service manager needs - to wait for service initialization to complete. It is hence recommended not to needlessly use any - types other than . (Also note it is generally not recommended to use - or for long-running services.) + is an alternative: it supports the traditional heavy-weight UNIX service + start-up protocol. Note that using any type other than + / possibly delays the boot process, as the service + manager needs to wait for service initialization to complete. (Also note it is generally not + recommended to use or for long-running services.) + From 39abba501a6d2108f3e30b94d0ee9da7a5ef5348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 29 Jul 2023 19:28:55 +0200 Subject: [PATCH 18/77] NEWS: fix misstatement We don't have type 'ready'. (cherry picked from commit ffe7ddb9bcbae4059b2be9ad3c509cb3f3496f35) --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 2f538c69ee9..275bb9185f1 100644 --- a/NEWS +++ b/NEWS @@ -574,7 +574,7 @@ CHANGES WITH 254: specified command line after sending the requested messages. This is useful for sending out READY=1 first, and then continuing invocation without changing process ID, so that the tool can be nicely used - within an ExecStart= line of a unit file that uses Type=ready. + within an ExecStart= line of a unit file that uses Type=notify. sd-event + sd-bus APIs: @@ -722,7 +722,7 @@ CHANGES WITH 254: systemd.battery-check=0 through the kernel command line. * The 'passwdqc' library is now supported as an alternative to the - 'pwquality' library and it can be selected at build time. + 'pwquality' library and can be selected at build time. Contributions from: 김인수, 07416, Addison Snelling, Adrian Vovk, Aidan Dang, Alexander Krabler, Alfred Klomp, Anatoli Babenia, From 30b60a97f5323a5a3e0ff6f3e6812d825b152420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 31 Jul 2023 14:04:55 +0200 Subject: [PATCH 19/77] gpt-auto-generator: fix warnings about unused func when !ENABLE_EFI (cherry picked from commit 7f4b3dc043cfb2954d0b492693f105fd55e3c874) --- src/gpt-auto-generator/gpt-auto-generator.c | 54 ++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index ccf48b549b7..cc5fc3f8134 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -487,33 +487,6 @@ static int slash_boot_in_fstab(void) { return cache; } -static int slash_efi_in_fstab(void) { - static int cache = -1; - - if (cache >= 0) - return cache; - - cache = fstab_is_mount_point("/efi"); - if (cache < 0) - return log_error_errno(cache, "Failed to parse fstab: %m"); - return cache; -} - -static bool slash_boot_exists(void) { - static int cache = -1; - - if (cache >= 0) - return cache; - - if (access("/boot", F_OK) >= 0) - return (cache = true); - if (errno != ENOENT) - log_error_errno(errno, "Failed to determine whether /boot/ exists, assuming no: %m"); - else - log_debug_errno(errno, "/boot/: %m"); - return (cache = false); -} - static int add_partition_xbootldr(DissectedPartition *p) { _cleanup_free_ char *options = NULL; int r; @@ -562,6 +535,33 @@ static int add_partition_xbootldr(DissectedPartition *p) { } #if ENABLE_EFI +static int slash_efi_in_fstab(void) { + static int cache = -1; + + if (cache >= 0) + return cache; + + cache = fstab_is_mount_point("/efi"); + if (cache < 0) + return log_error_errno(cache, "Failed to parse fstab: %m"); + return cache; +} + +static bool slash_boot_exists(void) { + static int cache = -1; + + if (cache >= 0) + return cache; + + if (access("/boot", F_OK) >= 0) + return (cache = true); + if (errno != ENOENT) + log_error_errno(errno, "Failed to determine whether /boot/ exists, assuming no: %m"); + else + log_debug_errno(errno, "/boot/: %m"); + return (cache = false); +} + static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) { const char *esp_path = NULL, *id = NULL; _cleanup_free_ char *options = NULL; From 8d0a4feb6b2af6f9e00e6975483b3f96eb7d60cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 31 Jul 2023 14:12:36 +0200 Subject: [PATCH 20/77] tests: skip static asserts on old clang versions We declare clang >= 10 is supported. The workaround is easy enough, so let's just do that. Fixes #28598. With Debian clang version 11.0.1-2: [267/384] Compiling C object test-bitfield.p/src_test_test-bitfield.c.o FAILED: test-bitfield.p/src_test_test-bitfield.c.o clang -Itest-bitfield.p -I. -I.. -Isrc/basic -I../src/basic -Isrc/fundamental -I../src/fundamental -Isrc/systemd -I../src/systemd -I../src/libsystemd/sd-bus -I../src/libsystemd/sd-device -I../src/libsystemd/sd-event -I../src/libsystemd/sd-hwdb -I../src/libsystemd/sd-id128 -I../src/libsystemd/sd-journal -I../src/libsystemd/sd-netlink -I../src/libsystemd/sd-network -I../src/libsystemd/sd-resolve -Isrc/shared -I../src/shared -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O0 -g -Wno-missing-field-initializers -Wno-unused-parameter -Warray-bounds -Wdate-time -Wendif-labels -Werror=format=2 -Werror=implicit-function-declaration -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Werror=missing-declarations -Werror=missing-prototypes -Werror=overflow -Werror=override-init -Werror=return-type -Werror=shift-count-overflow -Werror=undef -Wfloat-equal -Winit-self -Wmissing-include-dirs -Wmissing-noreturn -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-aliasing=2 -Wstrict-prototypes -Wunused-function -Wwrite-strings '-Wno-error=#warnings' -Wno-string-plus-int -fdiagnostics-show-option -fno-common -fstack-protector -fstack-protector-strong --param=ssp-buffer-size=4 -Wno-typedef-redefinition -Wno-gnu-variable-sized-type-not-at-end -Werror=shadow -fno-strict-aliasing -fvisibility=hidden -fno-omit-frame-pointer -include config.h -DTEST_CODE=1 -MD -MQ test-bitfield.p/src_test_test-bitfield.c.o -MF test-bitfield.p/src_test_test-bitfield.c.o.d -o test-bitfield.p/src_test_test-bitfield.c.o -c ../src/test/test-bitfield.c ../src/test/test-bitfield.c:216:9: error: static_assert failed due to requirement '__builtin_constant_p(({ static_assert(sizeof(unsigned char) <= sizeof(unsigned long long), "sizeof(uint8_t) <= sizeof(unsigned long long)"); static_assert(__builtin_choose_expr(__builtin_constant_p(1), 1, 0) < (int)(sizeof(unsigned char) * 8), "__builtin_choose_expr(__builtin_constant_p(1), 1, 0) < (int)(sizeof(uint8_t) * 8)"); __builtin_choose_expr(__builtin_constant_p(1), ((unsigned char)1) << (1), ({ int __unique_prefix__i751 = (1); do { if ((__builtin_expect(!!(!(__unique_prefix__i751 < (int)sizeof(unsigned char) * 8)), 0))) log_assert_failed("UNIQ_T(_i, 751) < (int)sizeof(uint8_t) * 8", (&"../src/test/test-bitfield.c"[(sizeof ("..") - sizeof(const char)) + 1]), 216, __func__); } while (0); ((unsigned char)1) << __unique_prefix__i751; })); }))' "__builtin_constant_p(INDEX_TO_MASK(uint8_t, 1))" assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint8_t, 1))); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../src/fundamental/macro-fundamental.h:109:25: note: expanded from macro 'assert_cc' ^ ~~~~ /usr/include/assert.h:143:24: note: expanded from macro 'static_assert' ^ ... (cherry picked from commit 6425dec88b9dedf53d12a970339ab88f948c201a) --- src/test/test-bitfield.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/test-bitfield.c b/src/test/test-bitfield.c index 74ebd5cc48e..0f29c5d8bf5 100644 --- a/src/test/test-bitfield.c +++ b/src/test/test-bitfield.c @@ -213,6 +213,8 @@ TEST(bits) { assert_se(_u64 == u64); /* Verify these use cases are constant-folded. */ +#if !defined(__clang__) || (__clang_major__ >= 13) + /* Clang 11 doesn't grok those; skip them. */ assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint8_t, 1))); assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint16_t, 1))); assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint32_t, 1))); @@ -222,6 +224,7 @@ TEST(bits) { assert_cc(__builtin_constant_p(BIT_SET((uint16_t)2, 1))); assert_cc(__builtin_constant_p(BIT_SET((uint32_t)2, 1))); assert_cc(__builtin_constant_p(BIT_SET((uint64_t)2, 1))); +#endif } DEFINE_TEST_MAIN(LOG_INFO); From 4160b87d82b00960d3e6f906d5af2706552ac57e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 31 Jul 2023 23:41:12 +0900 Subject: [PATCH 21/77] test: update comment to make it consistent with the condition Follow-up for 6425dec88b9dedf53d12a970339ab88f948c201a. (cherry picked from commit 0bf67ba2d48c4e81b80e139959e6c3ec6e0970e9) --- src/test/test-bitfield.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/test-bitfield.c b/src/test/test-bitfield.c index 0f29c5d8bf5..f26b423940e 100644 --- a/src/test/test-bitfield.c +++ b/src/test/test-bitfield.c @@ -214,7 +214,7 @@ TEST(bits) { /* Verify these use cases are constant-folded. */ #if !defined(__clang__) || (__clang_major__ >= 13) - /* Clang 11 doesn't grok those; skip them. */ + /* Clang 11 and 12 (and possibly older) do not grok those; skip them. */ assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint8_t, 1))); assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint16_t, 1))); assert_cc(__builtin_constant_p(INDEX_TO_MASK(uint32_t, 1))); From 9087f924f9fec58e658aeb929a4d17b789c886ea Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 31 Jul 2023 18:04:14 +0900 Subject: [PATCH 22/77] network/address: make Label= accept an empty string We usually reset setting when an emptry string is specified. (cherry picked from commit b8e898a681a7d8a663b766f8e44469bc910d20cc) --- src/network/networkd-address.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 7fbe23e905a..746aec0bb47 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1808,6 +1808,12 @@ int config_parse_label( return 0; } + if (isempty(rvalue)) { + n->label = mfree(n->label); + TAKE_PTR(n); + return 0; + } + if (!address_label_valid(rvalue)) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue); From 148e2fa9a74d56b571deec4af7b7042f365f51bb Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 31 Jul 2023 20:56:14 +0200 Subject: [PATCH 23/77] kernel-install: Only bypass "add" and "remove" KERNEL_INSTALL_BYPASS should only bypass verbs that actually change the system, not harmless verbs such as "inspect". (cherry picked from commit b4afa94c5f99a5e3c6b5f50d528f480ad2106bc6) --- src/kernel-install/kernel-install.c | 35 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index c573228991e..7de62f3ba41 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -999,6 +999,19 @@ static int context_execute(Context *c) { return 0; } +static bool bypass(void) { + int r; + + r = getenv_bool("KERNEL_INSTALL_BYPASS"); + if (r < 0 && r != -ENXIO) + log_debug_errno(r, "Failed to parse $KERNEL_INSTALL_BYPASS, assuming no."); + if (r <= 0) + return false; + + log_debug("$KERNEL_INSTALL_BYPASS is enabled, skipping execution."); + return true; +} + static int verb_add(int argc, char *argv[], void *userdata) { Context *c = ASSERT_PTR(userdata); int r; @@ -1006,6 +1019,9 @@ static int verb_add(int argc, char *argv[], void *userdata) { assert(argc >= 3); assert(argv); + if (bypass()) + return 0; + c->action = ACTION_ADD; r = context_set_version(c, argv[1]); @@ -1048,6 +1064,9 @@ static int verb_remove(int argc, char *argv[], void *userdata) { log_debug("Too many arguments specified. 'kernel-install remove' takes only kernel version. " "Ignoring residual arguments."); + if (bypass()) + return 0; + c->action = ACTION_REMOVE; r = context_set_version(c, argv[1]); @@ -1098,19 +1117,6 @@ static int verb_inspect(int argc, char *argv[], void *userdata) { return 0; } -static bool bypass(void) { - int r; - - r = getenv_bool("KERNEL_INSTALL_BYPASS"); - if (r < 0 && r != -ENXIO) - log_debug_errno(r, "Failed to parse $KERNEL_INSTALL_BYPASS, assuming no."); - if (r <= 0) - return false; - - log_debug("$KERNEL_INSTALL_BYPASS is enabled, skipping execution."); - return true; -} - static int help(void) { _cleanup_free_ char *link = NULL; int r; @@ -1239,9 +1245,6 @@ static int run(int argc, char* argv[]) { log_setup(); - if (bypass()) - return 0; - r = parse_argv(argc, argv, &c); if (r <= 0) return r; From 9f3fd729a69723b3fc21a56cd8a78079c77d908d Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 31 Jul 2023 20:58:31 +0200 Subject: [PATCH 24/77] kernel-install: Make sure KERNEL_INSTALL_BYPASS is disabled in tests (cherry picked from commit 4435da1f1732e2078e42b0ee43ad56fde2b021a3) --- src/kernel-install/test-kernel-install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel-install/test-kernel-install.sh b/src/kernel-install/test-kernel-install.sh index aa0881a6e07..ad9462c7fb4 100755 --- a/src/kernel-install/test-kernel-install.sh +++ b/src/kernel-install/test-kernel-install.sh @@ -48,6 +48,7 @@ export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3' export KERNEL_INSTALL_UKIFY="$ukify" export KERNEL_INSTALL_BOOT_STUB="$boot_stub" export KERNEL_INSTALL_READ_MACHINE_INFO="no" +export KERNEL_INSTALL_BYPASS="no" # Test type#1 installation "$kernel_install" -v add 1.1.1 "$D/sources/linux" "$D/sources/initrd" From 5c47cc39296c26dfad69548f93e6e36c15551946 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Tue, 1 Aug 2023 10:44:06 +0200 Subject: [PATCH 25/77] core: free the strings in the set in other places too Follow-up for #28551. (cherry picked from commit 1a572fd08ff4a01f77d3b8c8465a559971c77466) --- src/core/dbus-cgroup.c | 2 +- src/core/dbus-execute.c | 8 ++++---- src/core/load-fragment.c | 10 +++++----- src/journal/journald-context.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 9ab806b22d7..5347525844e 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -2159,7 +2159,7 @@ int bus_cgroup_set_property( if (strv_isempty(l)) { c->restrict_network_interfaces_is_allow_list = false; - c->restrict_network_interfaces = set_free(c->restrict_network_interfaces); + c->restrict_network_interfaces = set_free_free(c->restrict_network_interfaces); unit_write_settingf(u, flags, name, "%s=", name); return 1; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index c3255398c6f..52964390ae8 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1915,8 +1915,8 @@ int bus_exec_context_set_transient_property( if (!UNIT_WRITE_FLAGS_NOOP(flags)) { if (strv_isempty(allow_list) && strv_isempty(deny_list)) { - c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns); - c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns); + c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); + c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); unit_write_settingf(u, flags, name, "%s=", name); } else { r = set_put_strdupv(&c->log_filter_allowed_patterns, allow_list); @@ -2124,7 +2124,7 @@ int bus_exec_context_set_transient_property( if (strv_isempty(l)) { c->restrict_filesystems_allow_list = false; - c->restrict_filesystems = set_free(c->restrict_filesystems); + c->restrict_filesystems = set_free_free(c->restrict_filesystems); unit_write_setting(u, flags, name, "RestrictFileSystems="); return 1; @@ -2374,7 +2374,7 @@ int bus_exec_context_set_transient_property( return r; if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) { - c->import_credentials = set_free(c->import_credentials); + c->import_credentials = set_free_free(c->import_credentials); (void) unit_write_settingf(u, flags, name, "%s=", name); } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index c69d47c2284..219a84a234d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3664,7 +3664,7 @@ int config_parse_restrict_filesystems( if (isempty(rvalue)) { /* Empty assignment resets the list */ - c->restrict_filesystems = set_free(c->restrict_filesystems); + c->restrict_filesystems = set_free_free(c->restrict_filesystems); c->restrict_filesystems_allow_list = false; return 0; } @@ -4977,7 +4977,7 @@ int config_parse_import_credential( if (isempty(rvalue)) { /* Empty assignment resets the list */ - *import_credentials = set_free(*import_credentials); + *import_credentials = set_free_free(*import_credentials); return 0; } @@ -6053,7 +6053,7 @@ int config_parse_restrict_network_interfaces( if (isempty(rvalue)) { /* Empty assignment resets the list */ - c->restrict_network_interfaces = set_free(c->restrict_network_interfaces); + c->restrict_network_interfaces = set_free_free(c->restrict_network_interfaces); return 0; } @@ -6647,8 +6647,8 @@ int config_parse_log_filter_patterns( if (isempty(pattern)) { /* Empty assignment resets the lists. */ - c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns); - c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns); + c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); + c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); return 0; } diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c index 9a09d544533..7274f5f3e93 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -182,8 +182,8 @@ static void client_context_reset(Server *s, ClientContext *c) { c->log_ratelimit_interval = s->ratelimit_interval; c->log_ratelimit_burst = s->ratelimit_burst; - c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns); - c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns); + c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); + c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); } static ClientContext* client_context_free(Server *s, ClientContext *c) { From 97673ddf369c3cdd5c4e8241ade335435051a805 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 17 Jul 2023 11:48:50 +0200 Subject: [PATCH 26/77] basic/memfd: drop test for F_SEAL_SEAL With `F_SEAL_SEAL` a memfd can disable further sealing operations, effectively sealing the set of seals. Testing for it ensures that no further seals can be added, it never prevents seals from being dropped, since seals cannot be dropped, ever. Now testing for `F_SEAL_SEAL` makes sense if you want to ensure that some seals are *not* set. That is, you either test for the entire set of seals to match a local set, or you verify that a specific seal is not set. Neither is what we are doing, so it feels wrong requiring it to be set. By dropping the requirement for `F_SEAL_SEAL`, the same FD can be shared with other entities while retaining the ability to further restrict the set of seals later on (e.g., being able to mark a region as executable later on, and then adding `F_SEAL_EXEC`). (cherry picked from commit d268b22b25f4a911067b3779f06dce8355af6868) --- src/basic/memfd-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 8e6946642b7..c4e36b0ad45 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -113,7 +113,7 @@ int memfd_get_sealed(int fd) { return -errno; /* We ignore F_SEAL_EXEC here to support older kernels. */ - return FLAGS_SET(r, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); + return FLAGS_SET(r, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); } int memfd_get_size(int fd, uint64_t *sz) { From 2ca3e3c261bd6fce45ada364cfaacc78255fb542 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 17 Jul 2023 12:01:18 +0200 Subject: [PATCH 27/77] basic/memfd: reduce default seals to historic set Rather than always setting all seals, make `memfd_set_seals()` employ the original set of seals, that is: SEAL+GROW+SHRINK+WRITE Historically, the memfd code was used with the out-of-tree memfd patches, which merely supported a single seal ("SEALED", which effectively was GROW+SHRINK+WRITE). When the code was adapted to the upstream memfd seals, it was extended to the full seal set. With more and more seals being added upstream, this because more problematic. In particular, it is unclear what the function really is meant to achieve. Instead of just adding all seals, the function is returned to its original purpose: seal the memfd so futher modifications to its content are prevented. (cherry picked from commit e1007a928a18baad7726113c9f473dd8b17cc0fe) --- src/basic/memfd-util.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index c4e36b0ad45..e21514fa9ea 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -92,15 +92,9 @@ int memfd_map(int fd, uint64_t offset, size_t size, void **p) { } int memfd_set_sealed(int fd) { - int r; - assert(fd >= 0); - r = RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_EXEC | F_SEAL_SEAL)); - if (r == -EINVAL) /* old kernel ? */ - r = RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL)); - - return r; + return RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)); } int memfd_get_sealed(int fd) { From 555b772185f8b315a3faee0e9886f2bdd618230c Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 17 Jul 2023 12:16:01 +0200 Subject: [PATCH 28/77] basic/memfd: add fcntl() wrappers Add wrappers around GET/ADD_SEALS to allow future use outside of the current `memfd_get/set_sealed()` helpers. (cherry picked from commit 4d903003715b160acf7bf4baeffee7829ff99f85) --- src/basic/memfd-util.c | 33 +++++++++++++++++++++++++-------- src/basic/memfd-util.h | 2 ++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index e21514fa9ea..a80d586ffa6 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -68,6 +68,26 @@ int memfd_new(const char *name) { return memfd_create_wrapper(name, MFD_ALLOW_SEALING | MFD_CLOEXEC | MFD_NOEXEC_SEAL); } +int memfd_add_seals(int fd, unsigned int seals) { + assert(fd >= 0); + + return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals)); +} + +int memfd_get_seals(int fd, unsigned int *ret_seals) { + int r; + + assert(fd >= 0); + + r = RET_NERRNO(fcntl(fd, F_GET_SEALS)); + if (r < 0) + return r; + + if (ret_seals) + *ret_seals = r; + return 0; +} + int memfd_map(int fd, uint64_t offset, size_t size, void **p) { void *q; int sealed; @@ -92,22 +112,19 @@ int memfd_map(int fd, uint64_t offset, size_t size, void **p) { } int memfd_set_sealed(int fd) { - assert(fd >= 0); - - return RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)); + return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); } int memfd_get_sealed(int fd) { + unsigned int seals; int r; - assert(fd >= 0); - - r = fcntl(fd, F_GET_SEALS); + r = memfd_get_seals(fd, &seals); if (r < 0) - return -errno; + return r; /* We ignore F_SEAL_EXEC here to support older kernels. */ - return FLAGS_SET(r, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); + return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); } int memfd_get_size(int fd, uint64_t *sz) { diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 0fe8e3a3c4d..9b2103e0ced 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -12,6 +12,8 @@ int memfd_new(const char *name); int memfd_new_and_map(const char *name, size_t sz, void **p); int memfd_new_and_seal(const char *name, const void *data, size_t sz); +int memfd_add_seals(int fd, unsigned int seals); +int memfd_get_seals(int fd, unsigned int *ret_seals); int memfd_map(int fd, uint64_t offset, size_t size, void **p); int memfd_set_sealed(int fd); From f81fb774e9301bad19a713c17fdd6bad8965df4f Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 17 Jul 2023 12:17:56 +0200 Subject: [PATCH 29/77] basic/memfd: fix memfd_map() seal test Private mappings are required when F_SEAL_WRITE is set on a memfd, because otherwise you could end up with writable mappings through mprotect() and other calls. This is a limitation of the kernel implementation, and might be lifted by future extensions. Regardless, the current code tests for the full `is_sealed()` before using MAP_PRIVATE. This might end up using MAP_SHARED for write-sealed memfds, which will be refused by the kernel. Fix this and make memfd_map() check for exactly `F_SEAL_WRITE`. (cherry picked from commit 69688410566aa9e2a00530abd91e7dfef0212c83) --- src/basic/memfd-util.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index a80d586ffa6..92b84f95a6a 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -89,18 +89,19 @@ int memfd_get_seals(int fd, unsigned int *ret_seals) { } int memfd_map(int fd, uint64_t offset, size_t size, void **p) { + unsigned int seals; void *q; - int sealed; + int r; assert(fd >= 0); assert(size > 0); assert(p); - sealed = memfd_get_sealed(fd); - if (sealed < 0) - return sealed; + r = memfd_get_seals(fd, &seals); + if (r < 0) + return r; - if (sealed) + if (seals & F_SEAL_WRITE) q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset); else q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); From a987b0f12133bcb5ab73000109468871bfbab3c2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 28 Sep 2022 18:09:29 +0900 Subject: [PATCH 30/77] udev-builtin-net_id: fix potential buffer overflow (cherry picked from commit 5660e68d651545b43e13a51b068e64022637a6c6) --- src/udev/udev-builtin-net_id.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 0028fb39f4f..01bfb7832e6 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -813,11 +813,11 @@ static int names_usb(sd_device *dev, NetNames *names) { /* append USB config number, suppress the common config == 1 */ if (!streq(config, "1")) - l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL); + l = strpcpyl(&s, l, "c", config, NULL); /* append USB interface number, suppress the interface == 0 */ if (!streq(interf, "0")) - l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL); + l = strpcpyl(&s, l, "i", interf, NULL); if (l == 0) return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENAMETOOLONG), "Generated USB name would be too long."); From f1df09a9fd4b22f09450465137e11e34104c8b2c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 2 Aug 2023 00:44:51 +0900 Subject: [PATCH 31/77] test: skip tests earlier when we do not have enough privileges Hopefully fixes #28624. (cherry picked from commit 46f0a4e7ac97b47c5718b718e3c6db4a8a8e78a0) --- src/test/test-bpf-devices.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/test-bpf-devices.c b/src/test/test-bpf-devices.c index 0e1287eac4e..438e49bb18f 100644 --- a/src/test/test-bpf-devices.c +++ b/src/test/test-bpf-devices.c @@ -272,9 +272,11 @@ int main(int argc, char *argv[]) { r = enter_cgroup_subroot(&cgroup); if (r == -ENOMEDIUM) return log_tests_skipped("cgroupfs not available"); + if (r < 0) + return log_tests_skipped_errno(r, "Failed to prepare cgroup subtree"); r = bpf_devices_supported(); - if (!r) + if (r == 0) return log_tests_skipped("BPF device filter not supported"); assert_se(r == 1); From 094c648078e93b4a020a869a611d64cbd189c83f Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 31 Jul 2023 21:35:02 +0200 Subject: [PATCH 32/77] ukify: Only run systemd-measure after adding all sections We were running systemd-measure before adding the sbat section, let's fix that. Also make sure we only pass --linux to systemd-measure once instead of twice. (cherry picked from commit d713104abef503708451a8efd88a7f5a78418f91) --- src/ukify/ukify.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index 3b4ee510fc2..5d9364c6a20 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -763,23 +763,29 @@ def make_uki(opts): for section in opts.sections: uki.add_section(section) - # PCR measurement and signing - - call_systemd_measure(uki, linux, opts=opts) - - # UKI or addon creation - addons don't use the stub so we add SBAT manually - if linux is not None: # Merge the .sbat sections from stub, kernel and parameter, so that revocation can be done on either. uki.add_section(Section.create('.sbat', merge_sbat([opts.stub, linux], opts.sbat), measure=True)) - uki.add_section(Section.create('.linux', linux, measure=True)) else: + # Addons don't use the stub so we add SBAT manually if not opts.sbat: opts.sbat = ["""sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md uki,1,UKI,uki,1,https://www.freedesktop.org/software/systemd/man/systemd-stub.html """] uki.add_section(Section.create('.sbat', merge_sbat([], opts.sbat), measure=False)) + # PCR measurement and signing + + # We pass in the contents for .linux separately because we need them to do the measurement but can't add + # the section yet because we want .linux to be the last section. Make sure any other sections are added + # before this function is called. + call_systemd_measure(uki, linux, opts=opts) + + # UKI creation + + if linux is not None: + uki.add_section(Section.create('.linux', linux, measure=True)) + if sign_args_present: unsigned = tempfile.NamedTemporaryFile(prefix='uki') output = unsigned.name From ca0c8adf9d6d348cd59e12282e1effab4a39c5f3 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Tue, 1 Aug 2023 19:38:13 +0200 Subject: [PATCH 33/77] test: console fonts are located in /usr/share on openSUSE (cherry picked from commit ba0ff9fc0fa657024edd7a4a0aab01aa95b39ff5) --- test/test-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-functions b/test/test-functions index 41e1a0d57df..f5d83697a9d 100644 --- a/test/test-functions +++ b/test/test-functions @@ -2259,8 +2259,8 @@ install_zoneinfo() { install_fonts() { dinfo "Install system fonts" for i in \ - /usr/lib/kbd/consolefonts/eurlatgr* \ - /usr/lib/kbd/consolefonts/latarcyrheb-sun16*; do + /usr/{lib,share}/kbd/consolefonts/eurlatgr* \ + /usr/{lib,share}/kbd/consolefonts/latarcyrheb-sun16*; do [[ -f "$i" ]] || continue inst "$i" done From 65d5b3561c2692e947327e9a77d3b1b4d932c828 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Tue, 1 Aug 2023 19:40:34 +0200 Subject: [PATCH 34/77] test: install systemd-homed for openSUSE This new sub-package has been recently introduced. (cherry picked from commit 33ce0a899258ed8dfb4a234a9f67e678127d41f9) --- test/test-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-functions b/test/test-functions index f5d83697a9d..2b26a49867b 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1289,6 +1289,7 @@ install_suse_systemd() { systemd-container systemd-coredump systemd-experimental + systemd-homed systemd-journal-remote # Since commit fb6f25d7b979134a, systemd-resolved, which is shipped by # systemd-network sub-package on openSUSE, has its own testsuite. From 7f1ee32108c51dc0a5e27b436d51934cf7897b00 Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Wed, 2 Aug 2023 18:52:41 +0100 Subject: [PATCH 35/77] NEWS: PrivateNetwork implies PrivateMounts This is clearly a change that can break existing units, and broke my system in at least two different ways. For this reason this should have been added to NEWS in #26458, specifically c2da3bf, but wasn't. (cherry picked from commit 6b2d576f2b38c0385bb056af328754ec8966f9fd) --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 275bb9185f1..b07d34bf9f5 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,9 @@ CHANGES WITH 254: trailing with escape as a non comment line. For details, see: https://github.com/systemd/systemd/issues/27975 + * PrivateNetwork=yes and NetworkNamespacePath= now imply + PrivateMounts=yes unless PrivateMounts=no is explicitly specified. + * Behaviour of sandboxing options for the per-user service manager units has changed. They now imply PrivateUsers=yes, which means user namespaces will be implicitly enabled when a sandboxing option is From c12373dc4416e545f221d5b05eef1387a8e53372 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 2 Aug 2023 10:33:48 -0700 Subject: [PATCH 36/77] include sys/file.h for LOCK_EX Fixes | ../git/src/basic/user-util.c:708:30: error: use of undeclared identifier 'LOCK_EX'; did you mean 'LOCK_BSD'? | 708 | r = unposix_lock(fd, LOCK_EX); | | ^~~~~~~ | | LOCK_BSD Signed-off-by: Khem Raj (cherry picked from commit 213ddf2d0525535533a8d758b50b99fcbd31c17b) --- src/basic/user-util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/basic/user-util.c b/src/basic/user-util.c index fe61a090055..5c39847733b 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include From d39bfd26d47793fc95aabfd9ff4f32e8d63d1021 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Aug 2023 02:12:10 +0900 Subject: [PATCH 37/77] network-generator: make network file generated from ip=dhcp matches only physical interfaces Otherwise, it also matches later created virtual devices, and that breaks networks generated and managed by container management services, like docker. Closes #28626. (cherry picked from commit c25aa6c8acc6d95eaacae7858a7057907d61a25e) --- src/network/generator/network-generator.c | 13 +++++++++---- src/network/generator/test-network-generator.c | 15 ++++++++++----- .../test-01-dhcp.expected/91-default.network | 3 ++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c index 823cd41f7ee..f1bcc325914 100644 --- a/src/network/generator/network-generator.c +++ b/src/network/generator/network-generator.c @@ -1108,10 +1108,15 @@ void network_dump(Network *network, FILE *f) { assert(network); assert(f); - fprintf(f, - "[Match]\n" - "Name=%s\n", - isempty(network->ifname) ? "*" : network->ifname); + fputs("[Match]\n", f); + + if (isempty(network->ifname)) + /* If the interface name is not specified, then let's make the .network file match the all + * physical interfaces. */ + fputs("Kind=!*\n" + "Type=!loopback\n", f); + else + fprintf(f, "Name=%s\n", network->ifname); fputs("\n[Link]\n", f); diff --git a/src/network/generator/test-network-generator.c b/src/network/generator/test-network-generator.c index bcd4b1d9e41..318b9e98c37 100644 --- a/src/network/generator/test-network-generator.c +++ b/src/network/generator/test-network-generator.c @@ -65,7 +65,8 @@ static void test_link_one(const char *filename, const char *key, const char *val int main(int argc, char *argv[]) { test_network_one("", "ip", "dhcp6", "[Match]\n" - "Name=*\n" + "Kind=!*\n" + "Type=!loopback\n" "\n[Link]\n" "\n[Network]\n" "DHCP=ipv6\n" @@ -228,7 +229,8 @@ int main(int argc, char *argv[]) { test_network_one("", "rd.route", "10.1.2.3/16:10.0.2.3", "[Match]\n" - "Name=*\n" + "Kind=!*\n" + "Type=!loopback\n" "\n[Link]\n" "\n[Network]\n" "\n[DHCP]\n" @@ -250,7 +252,8 @@ int main(int argc, char *argv[]) { test_network_one("", "nameserver", "10.1.2.3", "[Match]\n" - "Name=*\n" + "Kind=!*\n" + "Type=!loopback\n" "\n[Link]\n" "\n[Network]\n" "DNS=10.1.2.3\n" @@ -259,7 +262,8 @@ int main(int argc, char *argv[]) { test_network_one("", "rd.peerdns", "0", "[Match]\n" - "Name=*\n" + "Kind=!*\n" + "Type=!loopback\n" "\n[Link]\n" "\n[Network]\n" "\n[DHCP]\n" @@ -268,7 +272,8 @@ int main(int argc, char *argv[]) { test_network_one("", "rd.peerdns", "1", "[Match]\n" - "Name=*\n" + "Kind=!*\n" + "Type=!loopback\n" "\n[Link]\n" "\n[Network]\n" "\n[DHCP]\n" diff --git a/test/test-network-generator-conversion/test-01-dhcp.expected/91-default.network b/test/test-network-generator-conversion/test-01-dhcp.expected/91-default.network index e42ce1e311f..657cde79aed 100644 --- a/test/test-network-generator-conversion/test-01-dhcp.expected/91-default.network +++ b/test/test-network-generator-conversion/test-01-dhcp.expected/91-default.network @@ -1,7 +1,8 @@ # Automatically generated by systemd-network-generator [Match] -Name=* +Kind=!* +Type=!loopback [Link] From eebf48abfa06ad947a64d9fe5524f44a0ab1311f Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Wed, 2 Aug 2023 14:55:50 +0200 Subject: [PATCH 38/77] varlink: allocate the buffer for varlink FDs on the heap Since it's ~16K, which might cause issues in environments with limited stack space. Resolves: #28635 (cherry picked from commit b456f2266afd839f8817235475e57c38e9d76dc9) --- src/shared/varlink.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 343f8b4aaca..9bf9c4b5ac2 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -633,7 +633,7 @@ static int varlink_write(Varlink *v) { #define VARLINK_FDS_MAX (16U*1024U) static int varlink_read(Varlink *v) { - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * VARLINK_FDS_MAX)) control; + _cleanup_free_ struct cmsghdr *cmsg_fds = NULL; struct iovec iov; struct msghdr mh; size_t rs; @@ -690,9 +690,13 @@ static int varlink_read(Varlink *v) { mh = (struct msghdr) { .msg_iov = &iov, .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), }; + + mh.msg_controllen = CMSG_SPACE(sizeof(int) * VARLINK_FDS_MAX); + mh.msg_control = cmsg_fds = malloc(mh.msg_controllen); + if (!cmsg_fds) + return -ENOMEM; + n = recvmsg_safe(v->fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); } else { bool prefer_read = v->prefer_read_write; From 32a1b7aa0f01c82ec2aa42ec88f247200bef57df Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Aug 2023 00:53:48 +0900 Subject: [PATCH 39/77] journalctl: do not add io event source for stdout if it is a file Fixes a bug introduced by 713342d9b09d717e9942ed08bd620c9159a98fb8. Fixes #28636. Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2228089. (cherry picked from commit f882a986c271c3de1c622df0f1586946b4a09fef) --- src/journal/journalctl.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 000baae0dfe..3424819540a 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2310,6 +2310,7 @@ static int on_signal(sd_event_source *s, const struct signalfd_siginfo *si, void static int setup_event(Context *c, int fd, sd_event **ret) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; + struct stat st; int r; assert(arg_follow); @@ -2328,10 +2329,15 @@ static int setup_event(Context *c, int fd, sd_event **ret) { if (r < 0) return log_error_errno(r, "Failed to add io event source for journal: %m"); - /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */ - r = sd_event_add_io(e, NULL, STDOUT_FILENO, EPOLLHUP|EPOLLERR, NULL, INT_TO_PTR(-ECANCELED)); - if (r < 0) - return log_error_errno(r, "Failed to add io event source for stdout: %m"); + if (fstat(STDOUT_FILENO, &st) < 0) + return log_error_errno(r, "Failed to stat stdout: %m"); + + if (IN_SET(st.st_mode & S_IFMT, S_IFCHR, S_IFIFO, S_IFSOCK)) { + /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */ + r = sd_event_add_io(e, NULL, STDOUT_FILENO, EPOLLHUP|EPOLLERR, NULL, INT_TO_PTR(-ECANCELED)); + if (r < 0) + return log_error_errno(r, "Failed to add io event source for stdout: %m"); + } if (arg_lines != 0 || arg_since_set) { r = sd_event_add_defer(e, NULL, on_first_event, c); From ca38c7d81b909af2b615ef9a89251ce6ad25b977 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 2 Aug 2023 15:16:33 +0200 Subject: [PATCH 40/77] bless-boot: Actually return successfully $ journalctl -u systemd-bless-boot.service systemd[1]: Starting Mark the Current Boot Loader Entry as Good... systemd-bless-boot[536]: Marked boot as 'good'. (Boot attempt counter is at 2.) systemd-bless-boot[536]: Can't find boot counter source file for '/loader/entries/arch.conf': Device or resource busy systemd[1]: Finished Mark the Current Boot Loader Entry as Good. (cherry picked from commit 8f30a066ff48325c9197ae3b103cd446852b9f3d) --- src/boot/bless-boot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c index 59f02b761ac..0c0b4f23c77 100644 --- a/src/boot/bless-boot.c +++ b/src/boot/bless-boot.c @@ -483,6 +483,7 @@ static int verb_set(int argc, char *argv[], void *userdata) { log_debug_errno(errno, "Failed to synchronize $BOOT partition, ignoring: %m"); log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done); + return 0; } log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Can't find boot counter source file for '%s': %m", target); From b44bd7d7a88a1ca7a03aebbf5d791f3f99789fb9 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 2 Aug 2023 16:00:07 +0200 Subject: [PATCH 41/77] boot: Fix boot counting for XBOOTLDR entries We were passing the dir handle for the ESP to config_entry_bump_counters(), which will obviously fail if the entry actually resides on the XBOOTLDR partition. Fixes: #28637 (cherry picked from commit 66fd078ba89e90e8aeba6edac52d20456fc2cd5d) --- src/boot/efi/boot.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 1321658a01d..ccba953b412 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1346,7 +1346,7 @@ static void config_entry_parse_tries( suffix); } -static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) { +static EFI_STATUS config_entry_bump_counters(ConfigEntry *entry) { _cleanup_free_ char16_t* old_path = NULL, *new_path = NULL; _cleanup_(file_closep) EFI_FILE *handle = NULL; _cleanup_free_ EFI_FILE_INFO *file_info = NULL; @@ -1354,34 +1354,39 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) { EFI_STATUS err; assert(entry); - assert(root_dir); if (entry->tries_left < 0) - return; + return EFI_SUCCESS; if (!entry->path || !entry->current_name || !entry->next_name) - return; + return EFI_SUCCESS; + + _cleanup_(file_closep) EFI_FILE *root = NULL; + err = open_volume(entry->device, &root); + if (err != EFI_SUCCESS) + return log_error_status(err, "Error opening entry root path: %m"); old_path = xasprintf("%ls\\%ls", entry->path, entry->current_name); - err = root_dir->Open(root_dir, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL); + err = root->Open(root, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL); if (err != EFI_SUCCESS) - return; + return log_error_status(err, "Error opening boot entry: %m"); err = get_file_info(handle, &file_info, &file_info_size); if (err != EFI_SUCCESS) - return; + return log_error_status(err, "Error getting boot entry file info: %m"); /* And rename the file */ strcpy16(file_info->FileName, entry->next_name); err = handle->SetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), file_info_size, file_info); - if (err != EFI_SUCCESS) { - log_error_status(err, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path, entry->next_name); - return; - } + if (err != EFI_SUCCESS) + return log_error_status( + err, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path, entry->next_name); /* Flush everything to disk, just in case… */ - (void) handle->Flush(handle); + err = handle->Flush(handle); + if (err != EFI_SUCCESS) + return log_error_status(err, "Error flushing boot entry file info: %m"); /* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on * success */ @@ -1393,6 +1398,8 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) { free(entry->loader); entry->loader = TAKE_PTR(new_path); } + + return EFI_SUCCESS; } static void config_entry_add_type1( @@ -2714,7 +2721,7 @@ static EFI_STATUS run(EFI_HANDLE image) { continue; } - config_entry_bump_counters(entry, root_dir); + (void) config_entry_bump_counters(entry); save_selected_entry(&config, entry); /* Optionally, read a random seed off the ESP and pass it to the OS */ From 8fbfcbadf35425551c7247285535d3ae81a60240 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 2 Aug 2023 16:21:51 +0200 Subject: [PATCH 42/77] boot: Make file info size a constant (cherry picked from commit e80037b10fff052357ab0e1fd2169b1cae00f875) --- src/boot/efi/proto/file-io.h | 6 ++++++ src/boot/efi/util.c | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/boot/efi/proto/file-io.h b/src/boot/efi/proto/file-io.h index 106c267fdfb..57df9e111c1 100644 --- a/src/boot/efi/proto/file-io.h +++ b/src/boot/efi/proto/file-io.h @@ -31,6 +31,12 @@ typedef struct { char16_t FileName[]; } EFI_FILE_INFO; +/* Some broken firmware violates the EFI spec by still advancing the readdir + * position when returning EFI_BUFFER_TOO_SMALL, effectively skipping over any files when + * the buffer was too small. Therefore, we always start with a buffer that should handle FAT32 + * max file name length. */ +#define EFI_FILE_INFO_MIN_SIZE (sizeof(EFI_FILE_INFO) + 256 * sizeof(char16_t)) + typedef struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL { uint64_t Revision; diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index d2b8f882500..3beab238d4b 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -412,7 +412,7 @@ void sort_pointer_array( } EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size) { - size_t size = offsetof(EFI_FILE_INFO, FileName) + 256; + size_t size = EFI_FILE_INFO_MIN_SIZE; _cleanup_free_ EFI_FILE_INFO *fi = NULL; EFI_STATUS err; @@ -454,12 +454,7 @@ EFI_STATUS readdir( * the specified buffer needs to be freed by caller, after final use. */ if (!*buffer) { - /* Some broken firmware violates the EFI spec by still advancing the readdir - * position when returning EFI_BUFFER_TOO_SMALL, effectively skipping over any files when - * the buffer was too small. Therefore, start with a buffer that should handle FAT32 max - * file name length. - * As a side effect, most readdir() calls will now be slightly faster. */ - sz = sizeof(EFI_FILE_INFO) + 256 * sizeof(char16_t); + sz = EFI_FILE_INFO_MIN_SIZE; *buffer = xmalloc(sz); *buffer_size = sz; } else From de249cefe9878ed4b6dfe33628462b1f44e8d513 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 2 Aug 2023 12:14:56 -0700 Subject: [PATCH 43/77] test/test-sizeof: Include sys/timex.h for struct timex Fixes ../git/src/test/test-sizeof.c:64:41: error: incomplete definition of type 'struct timex' 64 | check(typeof(((struct timex *)0)->freq), SIZEOF_TIMEX_MEMBER); | ~~~~~~~~~~~~~~~~~~~^ (cherry picked from commit e6456caf7676329abe861e9381f1957794baeabc) --- src/test/test-sizeof.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c index 18378b04500..ea0c58770ec 100644 --- a/src/test/test-sizeof.c +++ b/src/test/test-sizeof.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #define __STDC_WANT_IEC_60559_TYPES_EXT__ From 6b03b53bcc140b36e0f0124946253ba9cda9a566 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 2 Aug 2023 12:18:24 -0700 Subject: [PATCH 44/77] include missing sys/file.h for LOCK_EX (cherry picked from commit ac8db36cbc26694ee94beecc8dca208ec4b5fd45) --- src/core/execute.c | 1 + src/shared/btrfs-util.c | 1 + src/shared/copy.c | 1 + src/test/test-btrfs.c | 1 + src/test/test-fs-util.c | 1 + src/test/test-lock-util.c | 1 + src/vconsole/vconsole-setup.c | 1 + 7 files changed, 7 insertions(+) diff --git a/src/core/execute.c b/src/core/execute.c index 167657a0aee..86d10b28ac4 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 5128b308abf..3ded95ea82e 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/shared/copy.c b/src/shared/copy.c index 241a2d112b7..7e47dc002c1 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index 95b7ef25d81..ba09563058e 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "btrfs-util.h" #include "fd-util.h" diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 1beba916a4d..5de1eea0d4d 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include "alloc-util.h" diff --git a/src/test/test-lock-util.c b/src/test/test-lock-util.c index a9a1b438ff0..28fc54a5d6e 100644 --- a/src/test/test-lock-util.c +++ b/src/test/test-lock-util.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include "fd-util.h" diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index d54764207e1..dd6e884335b 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include From 60046bf2a9f750a3ef17aab5948b9e5ba8734265 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Aug 2023 02:50:09 +0900 Subject: [PATCH 45/77] shutdown: disable recursive mount of /run/ on switching root Mounting /run/ recursively may be harmless, but not necessary on shutdown as the new root is /run/initramfs. Follow-up for b12d41a8bb7c99f7d7a1c7821a886d98b42d9ce0. (cherry picked from commit d709d1b20e2e15ee2ae1b44de94d493e17834235) --- src/shutdown/shutdown.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 8395bb429d8..97a4050ae91 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -167,11 +167,13 @@ static int switch_root_initramfs(void) { * * Disable sync() during switch-root, we after all sync'ed here plenty, and a dumb sync (as opposed * to the "smart" sync() we did here that looks at progress parameters) would defeat much of our - * efforts here. */ + * efforts here. As the new root will be /run/initramfs/, it is not necessary to mount /run/ + * recursively. */ return switch_root( /* new_root= */ "/run/initramfs", /* old_root_after= */ "/oldroot", - /* flags= */ SWITCH_ROOT_DONT_SYNC); + /* flags= */ SWITCH_ROOT_DONT_SYNC | + SWITCH_ROOT_SKIP_RECURSIVE_RUN); } /* Read the following fields from /proc/meminfo: From c75ca569500bf538058cc0e252ab29fe17131f41 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Aug 2023 04:19:14 +0900 Subject: [PATCH 46/77] shutdown: do not umount recursively before MS_MOVE Unmounting filesystem will be done gracefully by shutdown itself. Follow-up for f2c1d491a539035d6cc1fa53a7cef0cbc8d52902 and 268d1244e87a35ff8dff56c92ef375ebf69d462e. (cherry picked from commit 6b219b74de53729249956221a971047aab7c96e0) --- src/shared/switch-root.c | 3 ++- src/shared/switch-root.h | 8 +++++--- src/shutdown/shutdown.c | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index 37395e02ad4..99036c13647 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -166,7 +166,8 @@ int switch_root(const char *new_root, * MS_MOVE won't magically unmount anything below it. Once the chroot() succeeds the mounts * below would still be around but invisible to us, because not accessible via * /proc/self/mountinfo. Hence, let's clean everything up first, as long as we still can. */ - (void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root)); + if (!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT)) + (void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root)); if (mount(".", "/", NULL, MS_MOVE, NULL) < 0) return log_error_errno(errno, "Failed to move %s to /: %m", new_root); diff --git a/src/shared/switch-root.h b/src/shared/switch-root.h index 78d62f28e04..20561fcee8b 100644 --- a/src/shared/switch-root.h +++ b/src/shared/switch-root.h @@ -4,9 +4,11 @@ #include typedef enum SwitchRootFlags { - SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching – under the condition that it is backed by non-persistent tmpfs/ramfs/… */ - SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */ - SWITCH_ROOT_SKIP_RECURSIVE_RUN = 1 << 2, /* move /run without MS_REC */ + SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching – under the condition + * that it is backed by non-persistent tmpfs/ramfs/… */ + SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */ + SWITCH_ROOT_SKIP_RECURSIVE_RUN = 1 << 2, /* move /run without MS_REC */ + SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT = 1 << 3, /* do not umount recursively on move */ } SwitchRootFlags; int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags); diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 97a4050ae91..ed873c61f1a 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -168,12 +168,13 @@ static int switch_root_initramfs(void) { * Disable sync() during switch-root, we after all sync'ed here plenty, and a dumb sync (as opposed * to the "smart" sync() we did here that looks at progress parameters) would defeat much of our * efforts here. As the new root will be /run/initramfs/, it is not necessary to mount /run/ - * recursively. */ + * recursively. Also, do not umount filesystems before MS_MOVE, as that should be done by ourself. */ return switch_root( /* new_root= */ "/run/initramfs", /* old_root_after= */ "/oldroot", /* flags= */ SWITCH_ROOT_DONT_SYNC | - SWITCH_ROOT_SKIP_RECURSIVE_RUN); + SWITCH_ROOT_SKIP_RECURSIVE_RUN | + SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT); } /* Read the following fields from /proc/meminfo: From 6068122836726aadbb0a3ebae2290723774b8071 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 4 Aug 2023 04:03:29 +0900 Subject: [PATCH 47/77] switch-root: reopen target directory after it is mounted Fixes a bug introduced by f717d7a40a696b351415976f22a4f498c401de41. (cherry picked from commit 2159662608a00232f94302bd5942d07830c279b4) --- src/shared/switch-root.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index 99036c13647..9fb9a3e3768 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -76,6 +76,18 @@ int switch_root(const char *new_root, r = fd_make_mount_point(new_root_fd); if (r < 0) return log_error_errno(r, "Failed to make new root directory a mount point: %m"); + if (r > 0) { + int fd; + + /* When the path was not a mount point, then we need to reopen the path, otherwise, it still + * points to the underlying directory. */ + + fd = open(new_root, O_DIRECTORY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(errno, "Failed to reopen target directory '%s': %m", new_root); + + close_and_replace(new_root_fd, fd); + } if (FLAGS_SET(flags, SWITCH_ROOT_DESTROY_OLD_ROOT)) { istmp = fd_is_temporary_fs(old_root_fd); From 2bd3537dc32225c151bfcfd8e1f7dfe00faeb94b Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Thu, 3 Aug 2023 14:44:57 -0400 Subject: [PATCH 48/77] tpm2: use CreatePrimary() to create primary keys instead of Create() Older versions used CreatePrimary() to create a transient primary key to use when creating a sealed data object. That was changed in v254 to use Create() instead, which should result in the same transient key, but it seems some hardware TPMs refuse to allow using Create() to generate primary keys. This reverts to using CreatePrimary() to create primary key. Fixes: #28654 (cherry picked from commit aff853f8ea29f22b28e3b584807893c528227769) --- src/shared/tpm2-util.c | 102 +++++++++++++++++++++++++++++++---------- src/shared/tpm2-util.h | 4 ++ 2 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index ae8a8bc0733..bc4f7f3c90d 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -1149,8 +1149,6 @@ static int tpm2_get_srk( return 1; } -static int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private, Tpm2Handle **ret_handle); - /* Get the SRK, creating one if needed. Returns 0 on success, or < 0 on error. */ static int tpm2_get_or_create_srk( Tpm2Context *c, @@ -1169,20 +1167,18 @@ static int tpm2_get_or_create_srk( return 0; /* No SRK, create and persist one */ - TPMT_PUBLIC template; - r = tpm2_get_best_srk_template(c, &template); + TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), }; + r = tpm2_get_best_srk_template(c, &template.publicArea); if (r < 0) return log_error_errno(r, "Could not get best SRK template: %m"); _cleanup_(tpm2_handle_freep) Tpm2Handle *transient_handle = NULL; - r = tpm2_create_loaded( + r = tpm2_create_primary( c, - /* parent= */ NULL, session, &template, /* sensitive= */ NULL, /* ret_public= */ NULL, - /* ret_private= */ NULL, &transient_handle); if (r < 0) return r; @@ -1552,8 +1548,65 @@ static int tpm2_get_policy_digest( return 0; } -static int tpm2_create( +int tpm2_create_primary( Tpm2Context *c, + const Tpm2Handle *session, + const TPM2B_PUBLIC *template, + const TPM2B_SENSITIVE_CREATE *sensitive, + TPM2B_PUBLIC **ret_public, + Tpm2Handle **ret_handle) { + + usec_t ts; + TSS2_RC rc; + int r; + + assert(c); + assert(template); + + log_debug("Creating primary key on TPM."); + + ts = now(CLOCK_MONOTONIC); + + _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL; + r = tpm2_handle_new(c, &handle); + if (r < 0) + return r; + + _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; + rc = sym_Esys_CreatePrimary( + c->esys_context, + ESYS_TR_RH_OWNER, + session ? session->esys_handle : ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + sensitive ? sensitive : &(TPM2B_SENSITIVE_CREATE) {}, + template, + /* outsideInfo= */ NULL, + &(TPML_PCR_SELECTION) {}, + &handle->esys_handle, + &public, + /* creationData= */ NULL, + /* creationHash= */ NULL, + /* creationTicket= */ NULL); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to generate primary key in TPM: %s", + sym_Tss2_RC_Decode(rc)); + + log_debug("Successfully created primary key on TPM in %s.", + FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC)); + + if (ret_public) + *ret_public = TAKE_PTR(public); + if (ret_handle) + *ret_handle = TAKE_PTR(handle); + + return 0; +} + +/* Create a TPM object. Do not use this to create primary keys, because some HW TPMs refuse to allow that; + * instead use tpm2_create_primary(). */ +int tpm2_create(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, @@ -1565,6 +1618,7 @@ static int tpm2_create( TSS2_RC rc; assert(c); + assert(parent); assert(template); log_debug("Creating object on TPM."); @@ -1592,7 +1646,7 @@ static int tpm2_create( _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; rc = sym_Esys_Create( c->esys_context, - parent ? parent->esys_handle : ESYS_TR_RH_OWNER, + parent->esys_handle, session ? session->esys_handle : ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1726,6 +1780,7 @@ static int _tpm2_create_loaded( int r; assert(c); + assert(parent); assert(template); log_debug("Creating loaded object on TPM."); @@ -1767,7 +1822,7 @@ static int _tpm2_create_loaded( _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; rc = sym_Esys_CreateLoaded( c->esys_context, - parent ? parent->esys_handle : ESYS_TR_RH_OWNER, + parent->esys_handle, session ? session->esys_handle : ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1795,8 +1850,9 @@ static int _tpm2_create_loaded( } /* This calls TPM2_CreateLoaded() if the TPM supports it, otherwise it calls TPM2_Create() and TPM2_Load() - * separately. */ -static int tpm2_create_loaded( + * separately. Do not use this to create primary keys, because some HW TPMs refuse to allow that; instead use + * tpm2_create_primary(). */ +int tpm2_create_loaded( Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, @@ -3303,29 +3359,27 @@ int tpm2_seal(const char *device, return r; } else { /* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */ - TPMT_PUBLIC template; - r = tpm2_get_legacy_template(TPM2_ALG_ECC, &template); + TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), }; + r = tpm2_get_legacy_template(TPM2_ALG_ECC, &template.publicArea); if (r < 0) return log_error_errno(r, "Could not get legacy ECC template: %m"); - if (!tpm2_supports_tpmt_public(c, &template)) { - r = tpm2_get_legacy_template(TPM2_ALG_RSA, &template); + if (!tpm2_supports_tpmt_public(c, &template.publicArea)) { + r = tpm2_get_legacy_template(TPM2_ALG_RSA, &template.publicArea); if (r < 0) return log_error_errno(r, "Could not get legacy RSA template: %m"); - if (!tpm2_supports_tpmt_public(c, &template)) + if (!tpm2_supports_tpmt_public(c, &template.publicArea)) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM does not support either ECC or RSA legacy template."); } - r = tpm2_create_loaded( + r = tpm2_create_primary( c, - /* parent= */ NULL, /* session= */ NULL, &template, /* sensitive= */ NULL, &primary_public, - /* ret_private= */ NULL, &primary_handle); if (r < 0) return r; @@ -3509,19 +3563,17 @@ int tpm2_unseal(const char *device, return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to deserialize primary key: %s", sym_Tss2_RC_Decode(rc)); } else if (primary_alg != 0) { - TPMT_PUBLIC template; - r = tpm2_get_legacy_template(primary_alg, &template); + TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), }; + r = tpm2_get_legacy_template(primary_alg, &template.publicArea); if (r < 0) return log_error_errno(r, "Could not get legacy template: %m"); - r = tpm2_create_loaded( + r = tpm2_create_primary( c, - /* parent= */ NULL, /* session= */ NULL, &template, /* sensitive= */ NULL, /* ret_public= */ NULL, - /* ret_private= */ NULL, &primary_handle); if (r < 0) return r; diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index ad867b9d1d3..12f05b43f95 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -88,6 +88,10 @@ int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle); Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle); DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free); +int tpm2_create_primary(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_PUBLIC *template, const TPM2B_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, Tpm2Handle **ret_handle); +int tpm2_create(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private); +int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private, Tpm2Handle **ret_handle); + bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg); bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command); From 9c1b5911af27193bf92780dc231fe523cecf4c24 Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Fri, 4 Aug 2023 11:16:02 +0200 Subject: [PATCH 49/77] man/systemd-fsck@.service: clarify passno and noauto combination in /etc/fstab Fixes #28657 (cherry picked from commit 000680a68dbdb07d77807868df0b4f978180e4cd) --- man/systemd-fsck@.service.xml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml index 403286829e1..45104bb12ad 100644 --- a/man/systemd-fsck@.service.xml +++ b/man/systemd-fsck@.service.xml @@ -41,12 +41,11 @@ filesystem was not checked in the initrd. systemd-fsck@.service is used for all other file systems and for the root file system in the initrd. - These services are started at boot if - in /etc/fstab for the - file system is set to a value greater than zero. The file system - check for root is performed before the other file systems. Other - file systems may be checked in parallel, except when they are on - the same rotating disk. + These services are started at boot if in /etc/fstab + for the file system is set to a value greater than zero, but only if it is also configured to be + mounted at boot (i.e. without noauto option). The file system check for root is + performed before the other file systems. Other file systems may be checked in parallel, except when + they are on the same rotating disk. systemd-fsck does not know any details about specific filesystems, and simply executes file system From a5e5d6d64e7f9fb1fa245c5cabddd2d1dcccfcaf Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 4 Aug 2023 20:49:15 +0800 Subject: [PATCH 50/77] man/systemd.unit: DefaultTimeoutStartSec= -> DefaultDeviceTimeoutSec= for device unit job timeouts Follow-up for #24044 (cherry picked from commit 83d373d213cad0f67c85055bf342d36cef8ed8e6) --- man/systemd.unit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 94a5a30f929..915f5680ead 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1060,7 +1060,7 @@ specified, see systemd.time5. The default is infinity (job timeouts disabled), except for device units where - JobRunningTimeoutSec= defaults to DefaultTimeoutStartSec=. + JobRunningTimeoutSec= defaults to DefaultDeviceTimeoutSec=. Note: these timeouts are independent from any unit-specific timeouts (for example, the timeout From a1657264854aa43811200c400c1dc286d16119fb Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 4 Aug 2023 20:41:46 +0800 Subject: [PATCH 51/77] hibernate-resume-generator: escape device path passed to hibernate-resume Follow-up for #27330 Fixes #28668 (cherry picked from commit caf8d692ed98f557d9f5641bffaf383c8401711a) --- src/hibernate-resume/hibernate-resume-generator.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 23c1a0a3c8a..11bd417289e 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -11,6 +11,7 @@ #include "device-nodes.h" #include "dropin.h" #include "efivars.h" +#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fstab-util.h" @@ -196,7 +197,7 @@ static int parse_efi_hibernate_location(void) { } static int process_resume(void) { - _cleanup_free_ char *device_unit = NULL; + _cleanup_free_ char *device_unit = NULL, *device_escaped = NULL; _cleanup_fclose_ FILE *f = NULL; int r; @@ -214,6 +215,10 @@ static int process_resume(void) { if (r < 0) log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m"); + device_escaped = cescape(arg_resume_device); + if (!device_escaped) + return log_oom(); + r = generator_open_unit_file(arg_dest, NULL, SPECIAL_HIBERNATE_RESUME_SERVICE, &f); if (r < 0) return r; @@ -233,7 +238,7 @@ static int process_resume(void) { "Type=oneshot\n" "ExecStart=" ROOTLIBEXECDIR "/systemd-hibernate-resume %2$s %3$" PRIu64 "\n", device_unit, - arg_resume_device, + device_escaped, arg_resume_offset); r = fflush_and_check(f); From 0f27d7b9f9cda1aa4e0d56cabd517e9a95026cf2 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 4 Aug 2023 13:34:00 +0100 Subject: [PATCH 52/77] portablectl: fix regression when using --force without extension parameters c18f4eb9e96836a made it possible to use --force with various verbs, by going through the newer D-Bus methods. Except it didn't, as it regressed during PR review refactorings, and nobody noticed because there were no tests for it. Fix it, and add tests. Follow-up for c18f4eb9e96836a6a8285ec42fd8a34c8909f6d9 (cherry picked from commit bdfa3f3a5c6d16d56d432e7bc52be0c03a5ce6ad) --- src/portable/portablectl.c | 23 +++++++++++++---------- test/units/testsuite-29.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index e77ee50dab2..3a25624b088 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -91,12 +91,14 @@ static int determine_image(const char *image, bool permit_non_existing, char **r return 0; } -static int attach_extensions_to_message(sd_bus_message *m, char **extensions) { +static int attach_extensions_to_message(sd_bus_message *m, const char *method, char **extensions) { int r; assert(m); + assert(method); - if (strv_isempty(extensions)) + /* The new methods also have flags parameters that are independent of the extensions */ + if (strv_isempty(extensions) && !endswith(method, "WithExtensions")) return 0; r = sd_bus_message_open_container(m, 'a', "s"); @@ -263,7 +265,7 @@ static int get_image_metadata(sd_bus *bus, const char *image, char **matches, sd if (r < 0) return bus_log_create_error(r); - r = attach_extensions_to_message(m, arg_extension_images); + r = attach_extensions_to_message(m, method, arg_extension_images); if (r < 0) return r; @@ -271,7 +273,7 @@ static int get_image_metadata(sd_bus *bus, const char *image, char **matches, sd if (r < 0) return bus_log_create_error(r); - if (!strv_isempty(arg_extension_images)) { + if (streq(method, "GetImageMetadataWithExtensions")) { r = sd_bus_message_append(m, "t", flags); if (r < 0) return bus_log_create_error(r); @@ -774,8 +776,9 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) { if (r < 0) return bus_log_parse_error(r); - /* If we specified any extensions, we'll first an array of extension-release metadata. */ - if (!strv_isempty(arg_extension_images)) { + /* If we specified any extensions or --force (which makes the request go through the new + * WithExtensions calls), we'll first get an array of extension-release metadata. */ + if (!strv_isempty(arg_extension_images) || arg_force) { r = sd_bus_message_skip(reply, "a{say}"); if (r < 0) return bus_log_parse_error(r); @@ -855,7 +858,7 @@ static int attach_reattach_image(int argc, char *argv[], const char *method) { if (r < 0) return bus_log_create_error(r); - r = attach_extensions_to_message(m, arg_extension_images); + r = attach_extensions_to_message(m, method, arg_extension_images); if (r < 0) return r; @@ -933,11 +936,11 @@ static int detach_image(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_create_error(r); - r = attach_extensions_to_message(m, arg_extension_images); + r = attach_extensions_to_message(m, method, arg_extension_images); if (r < 0) return r; - if (strv_isempty(arg_extension_images)) + if (streq(method, "DetachImage")) r = sd_bus_message_append(m, "b", arg_runtime); else { uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_SYSEXT : 0); @@ -1145,7 +1148,7 @@ static int is_image_attached(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_create_error(r); - r = attach_extensions_to_message(m, arg_extension_images); + r = attach_extensions_to_message(m, method, arg_extension_images); if (r < 0) return r; diff --git a/test/units/testsuite-29.sh b/test/units/testsuite-29.sh index 18ec41727d0..36e5cdc1263 100755 --- a/test/units/testsuite-29.sh +++ b/test/units/testsuite-29.sh @@ -43,12 +43,16 @@ EOF portablectl "${ARGS[@]}" attach --now --runtime /usr/share/minimal_0.raw minimal-app0 +portablectl is-attached minimal-app0 +portablectl inspect /usr/share/minimal_0.raw minimal-app0.service systemctl is-active minimal-app0.service systemctl is-active minimal-app0-foo.service systemctl is-active minimal-app0-bar.service && exit 1 portablectl "${ARGS[@]}" reattach --now --runtime /usr/share/minimal_1.raw minimal-app0 +portablectl is-attached minimal-app0 +portablectl inspect /usr/share/minimal_0.raw minimal-app0.service systemctl is-active minimal-app0.service systemctl is-active minimal-app0-bar.service systemctl is-active minimal-app0-foo.service && exit 1 @@ -61,6 +65,32 @@ portablectl detach --now --runtime /usr/share/minimal_1.raw minimal-app0 portablectl list | grep -q -F "No images." busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1 +# Ensure we don't regress (again) when using --force + +portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0 + +portablectl is-attached --force minimal-app0 +portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service +systemctl is-active minimal-app0.service +systemctl is-active minimal-app0-foo.service +systemctl is-active minimal-app0-bar.service && exit 1 + +portablectl "${ARGS[@]}" reattach --force --now --runtime /usr/share/minimal_1.raw minimal-app0 + +portablectl is-attached --force minimal-app0 +portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service +systemctl is-active minimal-app0.service +systemctl is-active minimal-app0-bar.service +systemctl is-active minimal-app0-foo.service && exit 1 + +portablectl list | grep -q -F "minimal_1" +busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' + +portablectl detach --force --now --runtime /usr/share/minimal_1.raw minimal-app0 + +portablectl list | grep -q -F "No images." +busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1 + # portablectl also works with directory paths rather than images unsquashfs -dest /tmp/minimal_0 /usr/share/minimal_0.raw From faaa0ee5e94dc4121954f1e63e7affdc97eee7e0 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 4 Aug 2023 16:12:35 +0200 Subject: [PATCH 53/77] tmpfiles: Consider ENOPKG as information not available We already handle the case where /etc/machine-id is empty. Let's make sure we also handle the case where /etc/machine-id is "uninitialized". (cherry picked from commit 5dd814d7cd88b9d58c7c5bd79fb27ee2b22e82a3) --- src/tmpfiles/tmpfiles.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index a7de3c87fe4..1f25f889c4a 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -237,6 +237,7 @@ static inline bool ERRNO_IS_NOINFO(int r) { return IN_SET(abs(r), EUNATCH, /* os-release or machine-id missing */ ENOMEDIUM, /* machine-id or another file empty */ + ENOPKG, /* machine-id is uninitialized */ ENXIO); /* env var is unset */ } From 865f0d6e76bcfbf880986b4b08c54baf9354e8a6 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 4 Aug 2023 15:23:16 +0200 Subject: [PATCH 54/77] test-user-util: Drop tty check in gid_to_name() test The tty user is not guaranteed to exist, so let's remove the dependency from the test. (cherry picked from commit a1fedc613fe90b9f1f253fd02a7a6575351a27cc) --- src/test/test-user-util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 48d9b1e0fb9..66f3b38050a 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -47,7 +47,6 @@ static void test_gid_to_name_one(gid_t gid, const char *name) { TEST(gid_to_name) { test_gid_to_name_one(0, "root"); test_gid_to_name_one(GID_NOBODY, NOBODY_GROUP_NAME); - test_gid_to_name_one(TTY_GID, "tty"); test_gid_to_name_one(0xFFFF, "65535"); test_gid_to_name_one(0xFFFFFFFF, "4294967295"); } From 164c3935e4272941883eaa666ba99bf890754b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 2 Aug 2023 15:01:40 +0100 Subject: [PATCH 55/77] NEWS: expand list of new Startup* settings This way users can grep/search the NEWS file for when a given setting was added. (cherry picked from commit e9ae4187bb1c1f7718de2384a050b72158a2ca14) --- NEWS | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index b07d34bf9f5..a39eccda528 100644 --- a/NEWS +++ b/NEWS @@ -74,10 +74,12 @@ CHANGES WITH 254: Service Manager: - * "Startup" memory settings are now supported. Previously IO and CPU - settings were already supported via StartupCPUWeight= and similar. - The same logic has been added for the various per-unit memory - settings StartupMemoryMax= and related. + * Memory limits that apply while the unit is activating are now + supported. Previously IO and CPU settings were already supported via + StartupCPUWeight= and similar. The same logic has been added for the + various manager and unit memory settings (DefaultStartupMemoryLow=, + StartupMemoryLow=, StartupMemoryHigh=, StartupMemoryMax=, + StartupMemorySwapMax=, StartupMemoryZSwapMax=). * The service manager gained support for enqueuing POSIX signals to services that carry an additional integer value, exposing the From dc7d0eb3a6e6c74d3747b3830f1c626604067d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 2 Aug 2023 15:01:50 +0100 Subject: [PATCH 56/77] NEWS: adjust grammar (cherry picked from commit b77ff21ade31ddd79fcb4120874a9b62e6a9194b) --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a39eccda528..7b251210a73 100644 --- a/NEWS +++ b/NEWS @@ -663,8 +663,8 @@ CHANGES WITH 254: server-side environment variable expansion in specified command lines. Expansion defaults to enabled for all execution types except --scope, where it defaults to off (and prints a warning) for backward - compatibility reasons. --scope will be flipped to default enabled too - in a future release, so if you are using --scope and passing a '$' + compatibility reasons. --scope will be flipped to enabled by default + too in a future release. If you are using --scope and passing a '$' character in the payload you should start explicitly using --expand-environment=yes/no according to the use case. From e91f31e3728f8789cc3d6ba48632e2300f72bfc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 4 Aug 2023 18:08:43 +0100 Subject: [PATCH 57/77] journalctl: fix loggging invocation Fixup for f882a986c271c3de1c622df0f1586946b4a09fef. (cherry picked from commit 8cb0008977648ba67c35289d81aa2b5a086384f5) --- src/journal/journalctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 3424819540a..24b973a2049 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2330,7 +2330,7 @@ static int setup_event(Context *c, int fd, sd_event **ret) { return log_error_errno(r, "Failed to add io event source for journal: %m"); if (fstat(STDOUT_FILENO, &st) < 0) - return log_error_errno(r, "Failed to stat stdout: %m"); + return log_error_errno(errno, "Failed to stat stdout: %m"); if (IN_SET(st.st_mode & S_IFMT, S_IFCHR, S_IFIFO, S_IFSOCK)) { /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */ From 505504c02cc4fdc3a2e495c45d794c01e3c259ba Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Fri, 4 Aug 2023 16:12:05 -0400 Subject: [PATCH 58/77] tpm2: use ELEMENTSOF() instead of sizeof() for TPML_PCR_SELECTION pcrSelections field The count field indicates the number of elements in the pcrSelections field, and the size of each elements is greater than 1 byte, so using sizeof() is incorrect when verifying the count field is valid; instead ELEMENTSOF() should be used. Caught by coverity check: https://github.com/systemd/systemd/pull/26331#pullrequestreview-1556629586 (cherry picked from commit 9afd4dde22f852fa4643799b218bef268a76272c) --- src/shared/tpm2-util.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index bc4f7f3c90d..44d8b520b5d 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -1317,7 +1317,7 @@ size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s) { /* Remove the (0-based) index entry from 'l', shift all following entries, and update the count. */ static void tpm2_tpml_pcr_selection_remove_index(TPML_PCR_SELECTION *l, uint32_t index) { assert(l); - assert(l->count <= sizeof(l->pcrSelections)); + assert(l->count <= ELEMENTSOF(l->pcrSelections)); assert(index < l->count); size_t s = l->count - (index + 1); @@ -1333,6 +1333,7 @@ static TPMS_PCR_SELECTION *tpm2_tpml_pcr_selection_get_tpms_pcr_selection( TPMI_ALG_HASH hash_alg) { assert(l); + assert(l->count <= ELEMENTSOF(l->pcrSelections)); TPMS_PCR_SELECTION *selection = NULL; FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) @@ -1415,13 +1416,13 @@ void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const } /* It's already broken if the count is higher than the array has size for. */ - assert(!(l->count > sizeof(l->pcrSelections))); + assert(l->count <= ELEMENTSOF(l->pcrSelections)); /* If full, the cleanup should result in at least one available entry. */ - if (l->count == sizeof(l->pcrSelections)) + if (l->count == ELEMENTSOF(l->pcrSelections)) tpm2_tpml_pcr_selection_cleanup(l); - assert(l->count < sizeof(l->pcrSelections)); + assert(l->count < ELEMENTSOF(l->pcrSelections)); l->pcrSelections[l->count++] = *s; } @@ -1475,7 +1476,7 @@ char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l) { size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l) { assert(l); - assert(l->count <= sizeof(l->pcrSelections)); + assert(l->count <= ELEMENTSOF(l->pcrSelections)); size_t weight = 0; FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) { From 182b95cdc99a5f7e9bdcff8658423d3eeb877519 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 5 Aug 2023 12:35:17 +0800 Subject: [PATCH 59/77] man/systemd: avoid duplicate variable name (cherry picked from commit 804c6397bc39a95968366c031082e96e94ef218c) --- man/systemd.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/systemd.xml b/man/systemd.xml index 708bfa9f8c5..218ab7e6f30 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -697,7 +697,7 @@ $SYSTEMD_LOG_RATELIMIT_KMSG - + From e497d1b198c50bec1512a7d79497f9a5c8282e77 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Sat, 5 Aug 2023 16:35:09 +0200 Subject: [PATCH 60/77] ukify: don't panic when prepending to an undefined list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the case when all the arguments are passed in through a configuration file: $ cat ukify.conf [UKI] Linux = /boot/vmlinuz-linux Initrd = /boot/initramfs-linux.img Before: $ src/ukify/ukify.py --config ukify.conf build Traceback (most recent call last): File "/root/systemd/src/ukify/ukify.py", line 1604, in main() File "/root/systemd/src/ukify/ukify.py", line 1590, in main opts = parse_args() ^^^^^^^^^^^^ File "/root/systemd/src/ukify/ukify.py", line 1584, in parse_args apply_config(opts) File "/root/systemd/src/ukify/ukify.py", line 1431, in apply_config item.apply_config(namespace, section_name, group, key, value) File "/root/systemd/src/ukify/ukify.py", line 1123, in apply_config self.config_push(namespace, group, dest, value) File "/root/systemd/src/ukify/ukify.py", line 1019, in config_list_prepend setattr(namespace, dest, value + old) ~~~~~~^~~~~ TypeError: can only concatenate list (not "NoneType") to list After: $ src/ukify/ukify.py --config ukify.conf build Kernel version not specified, starting autodetection 😖. Found uname version: 6.4.7-arch1-3 Wrote unsigned vmlinuz-linux.unsigned.efi Resolves: #28688 (cherry picked from commit 0be1de7ffc4a608482e45890425b6fd90f6073f0) --- src/ukify/ukify.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index 5d9364c6a20..859b6380673 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -933,6 +933,8 @@ def config_list_prepend( assert not group old = getattr(namespace, dest, []) + if old is None: + old = [] setattr(namespace, dest, value + old) @staticmethod From 11dc2717e2a3aaf92681ab1798794780b828a1c5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 5 Aug 2023 22:31:24 +0800 Subject: [PATCH 61/77] shared/fstab-util: use is_device_path instead of is_device_node Follow-up for 99299d0d5a722812cedc0a23e4987f90a257c2d2 is_device_node() calls lstat(), causing device node symlinks under /dev/disk/ not being compared correctly using devnode_same(). Fixes #28585 (cherry picked from commit cc1e1bb03e49ccb90f36173a3d1ff10ab5676eb0) --- src/shared/fstab-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 67e718b6eaa..0ab37be41d8 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -76,7 +76,7 @@ static int fstab_is_same_node(const char *what_fstab, const char *path) { if (path_equal(node, path)) return true; - if (is_device_node(path) && is_device_node(node)) + if (is_device_path(path) && is_device_path(node)) return devnode_same(node, path); return false; From ec18b6015b5d09b011d4eec51f0813248acf6100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 28 Jul 2023 17:54:59 +0200 Subject: [PATCH 62/77] manager: fix reloading in reload-or-restart --marked bus_unit_queue_job_one has two callers: - bus_unit_queue_job which would do the appropriate transormations to turn JOB_TRY_RESTART into JOB_TRY_RELOAD, - and method_enqueue_marked_jobs which did not. In effect, method_enqueue_marked_jobs() would queue restart jobs for units which has Markers= needs-reload or needs-restart. When the chunk of code which does the transformations is moved from bus_unit_queue_job to bus_unit_queue_job_one, there is no change for bus_unit_queue_job, and method_enqueue_marked_jobs is fixed. The additional checks that are done seem reasonable to do from method_enqueue_marked_jobs: we shouldn't be restarting units which are configured to not allow that, or force unwanted start of dbus-broker. (cherry picked from commit 8ea8e23f4013dbc4f4a66c81eb786f0505434f2e) --- src/core/dbus-unit.c | 82 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 629f08ebcc6..1f673fe26d2 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1770,6 +1770,47 @@ int bus_unit_queue_job_one( Job *j, *a; int r; + if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) { + if (type == JOB_RESTART) + type = JOB_RELOAD_OR_START; + else if (type == JOB_TRY_RESTART) + type = JOB_TRY_RELOAD; + } + + if (type == JOB_STOP && + IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) && + unit_active_state(u) == UNIT_INACTIVE) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); + + if ((type == JOB_START && u->refuse_manual_start) || + (type == JOB_STOP && u->refuse_manual_stop) || + (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || + (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) + return sd_bus_error_setf(error, + BUS_ERROR_ONLY_BY_DEPENDENCY, + "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", + u->id); + + /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically + * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start + * job that pulls in dbus again would cause job type conflict. Let's avoid that by rejecting + * job enqueuing early. + * + * Note that unlike signal_activation_request(), we can't use unit_inactive_or_pending() + * here. StartUnit is a more generic interface, and thus users are allowed to use e.g. systemctl + * to start Type=dbus services even when dbus is inactive. */ + if (type == JOB_START && u->type == UNIT_SERVICE && SERVICE(u)->type == SERVICE_DBUS) + FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) { + Unit *dbus; + + dbus = manager_get_unit(u->manager, dbus_unit); + if (dbus && unit_stop_pending(dbus)) + return sd_bus_error_setf(error, + BUS_ERROR_SHUTTING_DOWN, + "Operation for unit %s refused, D-Bus is shutting down.", + u->id); + } + if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) { affected = set_new(NULL); if (!affected) @@ -1862,47 +1903,6 @@ int bus_unit_queue_job( if (r < 0) return r; - if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) { - if (type == JOB_RESTART) - type = JOB_RELOAD_OR_START; - else if (type == JOB_TRY_RESTART) - type = JOB_TRY_RELOAD; - } - - if (type == JOB_STOP && - IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) && - unit_active_state(u) == UNIT_INACTIVE) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); - - if ((type == JOB_START && u->refuse_manual_start) || - (type == JOB_STOP && u->refuse_manual_stop) || - (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || - (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) - return sd_bus_error_setf(error, - BUS_ERROR_ONLY_BY_DEPENDENCY, - "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", - u->id); - - /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically - * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start - * job that pulls in dbus again would cause job type conflict. Let's avoid that by rejecting - * job enqueuing early. - * - * Note that unlike signal_activation_request(), we can't use unit_inactive_or_pending() - * here. StartUnit is a more generic interface, and thus users are allowed to use e.g. systemctl - * to start Type=dbus services even when dbus is inactive. */ - if (type == JOB_START && u->type == UNIT_SERVICE && SERVICE(u)->type == SERVICE_DBUS) - FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) { - Unit *dbus; - - dbus = manager_get_unit(u->manager, dbus_unit); - if (dbus && unit_stop_pending(dbus)) - return sd_bus_error_setf(error, - BUS_ERROR_SHUTTING_DOWN, - "Operation for unit %s refused, D-Bus is shutting down.", - u->id); - } - r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; From 0ac89e3b3f2d47649ade717f453e7db3a1b34b01 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Aug 2023 15:36:39 +0200 Subject: [PATCH 63/77] varlink: don't allocate fd control buffer on each read() We'll need this on each read() again, hence let's just allocate this once and then reuse it for subsequent read()s. Follow-up for: #28639 (cherry picked from commit 3c8680585c698668c4d9774d3801d3446a194113) --- src/shared/varlink.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 9bf9c4b5ac2..97f50a5ed25 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -133,6 +133,9 @@ struct Varlink { size_t input_buffer_size; size_t input_buffer_unscanned; + void *input_control_buffer; + size_t input_control_buffer_size; + char *output_buffer; /* valid data starts at output_buffer_index, ends at output_buffer_index+output_buffer_size */ size_t output_buffer_index; size_t output_buffer_size; @@ -457,6 +460,9 @@ static void varlink_clear(Varlink *v) { v->input_buffer = mfree(v->input_buffer); v->output_buffer = v->output_buffer_sensitive ? erase_and_free(v->output_buffer) : mfree(v->output_buffer); + v->input_control_buffer = mfree(v->input_control_buffer); + v->input_control_buffer_size = 0; + varlink_clear_current(v); close_many(v->output_fds, v->n_output_fds); @@ -633,7 +639,6 @@ static int varlink_write(Varlink *v) { #define VARLINK_FDS_MAX (16U*1024U) static int varlink_read(Varlink *v) { - _cleanup_free_ struct cmsghdr *cmsg_fds = NULL; struct iovec iov; struct msghdr mh; size_t rs; @@ -687,16 +692,22 @@ static int varlink_read(Varlink *v) { if (v->allow_fd_passing_input) { iov = IOVEC_MAKE(p, rs); + + /* Allocate the fd buffer on the heap, since we need a lot of space potentially */ + if (!v->input_control_buffer) { + v->input_control_buffer_size = CMSG_SPACE(sizeof(int) * VARLINK_FDS_MAX); + v->input_control_buffer = malloc(v->input_control_buffer_size); + if (!v->input_control_buffer) + return -ENOMEM; + } + mh = (struct msghdr) { .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = v->input_control_buffer, + .msg_controllen = v->input_control_buffer_size, }; - mh.msg_controllen = CMSG_SPACE(sizeof(int) * VARLINK_FDS_MAX); - mh.msg_control = cmsg_fds = malloc(mh.msg_controllen); - if (!cmsg_fds) - return -ENOMEM; - n = recvmsg_safe(v->fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); } else { bool prefer_read = v->prefer_read_write; From 2ad138511035cd13de02815ea2a0c950a282480d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Aug 2023 16:36:26 +0200 Subject: [PATCH 64/77] shutdown: handle gracefully if MD_LEVEL udev propery is not set See: #28490 (cherry picked from commit ab9617a76624c43a26de7e94424088ae171ebfef) --- src/shutdown/detach-md.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c index 2dbb866902d..cf3130d4a70 100644 --- a/src/shutdown/detach-md.c +++ b/src/shutdown/detach-md.c @@ -75,20 +75,33 @@ static int md_list_get(RaidDevice **head) { RaidDevice *m; dev_t devnum; - if (sd_device_get_devnum(d, &devnum) < 0 || - sd_device_get_devname(d, &dn) < 0) + r = sd_device_get_devname(d, &dn); + if (r < 0) { + log_device_warning_errno(d, r, "Failed to get name of enumerated device, ignoring: %m"); continue; + } - r = sd_device_get_property_value(d, "MD_LEVEL", &md_level); + r = sd_device_get_devnum(d, &devnum); if (r < 0) { - log_warning_errno(r, "Failed to get MD_LEVEL property for %s, ignoring: %m", dn); + log_device_warning_errno(d, r, "Failed to get devno of enumerated device '%s', ignoring device: %m", dn); continue; } - /* MD "containers" are a special type of MD devices, used for external metadata. Since it - * doesn't provide RAID functionality in itself we don't need to stop it. */ - if (streq(md_level, "container")) + /* MD "containers" are a special type of MD devices, used for external metadata. Since they + * don't provide RAID functionality in themselves we don't need to stop them. Note that the + * MD_LEVEL udev property is set by mdadm in userspace, which is an optional package. Hence + * let's handle gracefully if the property is missing. */ + + r = sd_device_get_property_value(d, "MD_LEVEL", &md_level); + if (r < 0) + log_device_full_errno(d, + r == -ENOENT ? LOG_DEBUG : LOG_WARNING, + r, + "Failed to get MD_LEVEL property for %s, assuming regular MD device, not a container: %m", dn); + else if (streq(md_level, "container")) { + log_device_debug(d, "Skipping MD device '%s' because it is a container MD device.", dn); continue; + } p = strdup(dn); if (!p) From 1d8cb3c8a0af5b8809f67a94b7c156adc717286d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Aug 2023 11:24:22 +0900 Subject: [PATCH 65/77] busctl: fix showing array of dictionary in JSON format This partially reverts the commit 684bce3d54463b3222246f72adfe82ad5d176fea and fixes the issue introduced by it. Fixes #28711. (cherry picked from commit beddf8ba29152e8b7d8c04b8fc929ac33b693166) --- src/busctl/busctl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index c1a0479015c..f85db5fe142 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -1735,12 +1735,15 @@ static int json_transform_variant(sd_bus_message *m, const char *contents, JsonV } static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) { - _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; + JsonVariant **elements = NULL; + size_t n_elements = 0; int r; assert(m); assert(ret); + CLEANUP_ARRAY(elements, n_elements, json_variant_unref_many); + for (;;) { const char *contents; char type; @@ -1757,28 +1760,31 @@ static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) { assert(type == 'e'); + if (!GREEDY_REALLOC(elements, n_elements + 2)) + return log_oom(); + r = sd_bus_message_enter_container(m, type, contents); if (r < 0) return bus_log_parse_error(r); - r = json_transform_and_append(m, &array); + r = json_transform_one(m, elements + n_elements); if (r < 0) return r; - r = json_transform_and_append(m, &array); + n_elements++; + + r = json_transform_one(m, elements + n_elements); if (r < 0) return r; + n_elements++; + r = sd_bus_message_exit_container(m); if (r < 0) return bus_log_parse_error(r); } - if (!array) - return json_variant_new_array(ret, NULL, 0); - - *ret = TAKE_PTR(array); - return 0; + return json_variant_new_object(ret, elements, n_elements); } static int json_transform_one(sd_bus_message *m, JsonVariant **ret) { From 9f32329e855a6d1058d2b367297509c0cb13a56c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Aug 2023 14:54:05 +0900 Subject: [PATCH 66/77] udev: set ID_NAME and ID_SERIAL to MMC/memstick devices again Fixes a bug introduced by 998db5871fea331ec00b26a3a3f5271df040a905. Fixes #28671. (cherry picked from commit 074d90926fec26c305e23a7e9acb3e59c576c859) --- rules.d/60-persistent-storage.rules.in | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rules.d/60-persistent-storage.rules.in b/rules.d/60-persistent-storage.rules.in index f08fc0da2fc..0eba1f8764b 100644 --- a/rules.d/60-persistent-storage.rules.in +++ b/rules.d/60-persistent-storage.rules.in @@ -87,16 +87,18 @@ KERNEL=="pmem*", ATTRS{uuid}=="?*", SYMLINK+="disk/by-id/pmem-$attr{uuid}$env{.P KERNEL=="sd*|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}$env{.PART_SUFFIX}" # MMC -KERNEL!="mmcblk[0-9]|mmcblk[0-9]p[0-9]*", GOTO="mmc_end" -SUBSYSTEMS!="mmc", GOTO="mmc_end" +KERNEL=="mmcblk[0-9]|mmcblk[0-9]p[0-9]*", SUBSYSTEMS=="mmc", GOTO="mmc_start" +GOTO="mmc_end" +LABEL="mmc_start" ATTRS{name}=="?*", ENV{ID_NAME}="$attr{name}" ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}" ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}$env{.PART_SUFFIX}" LABEL="mmc_end" # Memstick -KERNEL!="msblk[0-9]|mspblk[0-9]|msblk[0-9]p[0-9]|mspblk[0-9]p[0-9]", GOTO="memstick_end" -SUBSYSTEMS!="memstick", GOTO="memstick_end" +KERNEL=="msblk[0-9]|mspblk[0-9]|msblk[0-9]p[0-9]|mspblk[0-9]p[0-9]", SUBSYSTEMS=="memstick", GOTO="memstick_start" +GOTO="memstick_end" +LABEL="memstick_start" ATTRS{name}=="?*", ENV{ID_NAME}="$attr{name}" ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}" ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}$env{.PART_SUFFIX}" From 9814972198a11591bbb10dfb99e9d50a4bed055b Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 7 Aug 2023 12:13:23 -0700 Subject: [PATCH 67/77] zsh: use sys_really_all_units for non-template names The systemctl invocations used for these completions match the ones used for the _sys_really_all_units parameter, so we should really just use the cached parameter rather than recomputing the result. (cherry picked from commit c8e2cd79c155151bcdb983eedd24a6a77082c41b) --- shell-completion/zsh/_systemctl.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 7ce7c4c0154..2314e1fa363 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -194,10 +194,10 @@ __systemctl() } (( $+functions[_systemctl_get_non_template_names] )) || - _systemctl_get_non_template_names() { echo -E - ${^${(R)${(f)"$( - __systemctl list-unit-files - __systemctl list-units --all - )"}:#*@.*}%%[[:space:]]*} } + _systemctl_get_non_template_names() { + _systemctl_really_all_units + print -r - ${_sys_really_all_units:#*@.*} + } (( $+functions[_systemctl_get_template_names] )) || _systemctl_get_template_names() { From dfc0445cb86e500732125da9f758092641a4c5a2 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Tue, 8 Aug 2023 01:30:28 -0700 Subject: [PATCH 68/77] zsh: reintroduce pattern argument to uncached verbs The systemctl completion previously made use of PREFIX as a pattern argument to list-unit-files and list-units. This had the problem of erroneously filtering the results that were stored in the cache, and erroneously filtering results that might have been requested according to the users configuration (e.g. _correct completer, certain matcher-lists or tag-orders, etc.). Unfortunately, the runtime of list-unit-files increases when no pattern argument is provided, and systemctl show, used to filter those units, can become unacceptably slow when provided with too many units to describe. Let's re-introduce the pattern argument to list-unit-files and list-units where necessary in order to alleviate these bottlenecks without poisining the cache. A 'use-pattern' style is introduced that may be used to disable this behavior if it is undesired. We can still expect that certain completions, like `systemctl start ` will be slow, like before. To fix this we will need systemd to learn a more efficient way of filtering the units than parsing systemctl show. (cherry picked from commit 2cbda74862049be2003496c7d432341d53a0fdf9) --- shell-completion/zsh/_systemctl.in | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 2314e1fa363..2306cbf6b02 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -206,23 +206,37 @@ __systemctl() } (( $+functions[_systemctl_active_units] )) || - _systemctl_active_units() {_sys_active_units=( ${${(f)"$(__systemctl list-units)"}%% *} )} + _systemctl_active_units() { + local pattern + if zstyle -T ":completion:$curcontext" use-pattern; then + pattern="$PREFIX*$SUFFIX" + fi + _sys_active_units=( ${${(f)"$(__systemctl list-units $pattern)"}%% *} ) + } (( $+functions[_systemctl_startable_units] )) || _systemctl_startable_units(){ + local pattern + if zstyle -T ":completion:$curcontext" use-pattern; then + pattern="$PREFIX*$SUFFIX" + fi _sys_startable_units=( $( _filter_units_by_property ActiveState inactive $( _filter_units_by_property CanStart yes ${${${(f)"$( - __systemctl list-unit-files --state enabled,enabled-runtime,linked,linked-runtime,static,indirect,disabled,generated,transient - __systemctl list-units --state inactive,failed + __systemctl list-unit-files --state enabled,enabled-runtime,linked,linked-runtime,static,indirect,disabled,generated,transient $pattern + __systemctl list-units --state inactive,failed $pattern )"}:#*@.*}%%[[:space:]]*} )) ) } (( $+functions[_systemctl_restartable_units] )) || _systemctl_restartable_units(){ + local pattern + if zstyle -T ":completion:$curcontext" use-pattern; then + pattern="$PREFIX*$SUFFIX" + fi _sys_restartable_units=( $( _filter_units_by_property CanStart yes ${${${(f)"$( - __systemctl list-unit-files --state enabled,disabled,static - __systemctl list-units + __systemctl list-unit-files --state enabled,disabled,static $pattern + __systemctl list-units $pattern )"}:#*@.*}%%[[:space:]]*} ) ) } @@ -232,8 +246,12 @@ __systemctl() (( $+functions[_systemctl_unit_state] )) || _systemctl_unit_state() { setopt localoptions extendedglob + local pattern + if zstyle -T ":completion:$curcontext" use-pattern; then + pattern="$PREFIX*$SUFFIX" + fi typeset -gA _sys_unit_state - _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files)"}%%[[:space:]]#}% *} ) + _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files $pattern)"}%%[[:space:]]#}% *} ) } local fun From 72da03631ae175dfa852c2cdedcdd8e9215c1d4f Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Tue, 8 Aug 2023 12:52:53 +0200 Subject: [PATCH 69/77] units/initrd-parse-etc.service: Conflict with emergency.target If emergency.target is started while initrd-parse-etc.service/start is queued, the initrd-parse-etc job did not get canceled. In parallel to the emergency units, it eventually runs the service, which starts initrd-cleanup.service, which in turn isolates initrd-switch-root.target. This stops the emergency units and effectively starts the initrd boot process again, which likely fails again like the initial attempt. The system is thus stuck in an endless loop, never really reaching emergency.target. With this conflict added, starting emergency.target automatically cancels initrd-parse-etc.service/start, avoiding the loop. (cherry picked from commit 327cd2d3db703555f8d572b4cd055fbe55e1068b) --- units/initrd-parse-etc.service.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/units/initrd-parse-etc.service.in b/units/initrd-parse-etc.service.in index fe0e860150c..b04e69f055f 100644 --- a/units/initrd-parse-etc.service.in +++ b/units/initrd-parse-etc.service.in @@ -15,6 +15,8 @@ DefaultDependencies=no Requires=initrd-root-fs.target After=initrd-root-fs.target +Conflicts=emergency.target + OnFailure=emergency.target OnFailureJobMode=replace-irreversibly From b4b4caf09f2826266fbe70d0de1c6276f2670bd7 Mon Sep 17 00:00:00 2001 From: mordner Date: Tue, 8 Aug 2023 21:57:41 +0200 Subject: [PATCH 70/77] man: fix typo in journalctl (cherry picked from commit 653c90ec0e6f4d68b68938a20bd8cff492e7a666) --- man/journalctl.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/journalctl.xml b/man/journalctl.xml index 671336e1509..70d8508cf0c 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -814,7 +814,7 @@ Similar to , but executes no operation if the root - file system and /var/lib/journal/ reside on the same mount point. This operation + file system and /var/log/journal/ reside on the same mount point. This operation is used during system shutdown in order to make the journal daemon stop writing data to /var/log/journal/ in case that directory is located on a mount point that needs to be unmounted. From 08c1aff48304eb2772c0cb2e6b9ad438608996eb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 9 Aug 2023 03:00:34 +0900 Subject: [PATCH 71/77] resolve: ignore nameserver= and domain= kernel command line options without value Otherwise, manager_parse_dns_server_string_and_warn() or manager_parse_search_domains_and_warn() will trigger assertion. (cherry picked from commit 91acee9906e973365109b1b1d5e880ced9aeae65) --- src/resolve/resolved-conf.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 3a67a4747e4..94a579275fd 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -518,6 +518,10 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data) * interpret, for example dracut and SUSE Linux. */ if (proc_cmdline_key_streq(key, "nameserver")) { + + if (proc_cmdline_value_missing(key, value)) + return 0; + if (!info->dns_server_unlinked) { /* The kernel command line overrides any prior configuration */ dns_server_unlink_all(manager_get_first_dns_server(info->manager, DNS_SERVER_SYSTEM)); @@ -532,6 +536,9 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data) } else if (proc_cmdline_key_streq(key, "domain")) { + if (proc_cmdline_value_missing(key, value)) + return 0; + if (!info->search_domain_unlinked) { dns_search_domain_unlink_all(info->manager->search_domains); info->search_domain_unlinked = true; From 7483f75fa6c6487281d0f39633258902c62e8856 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 9 Aug 2023 04:58:04 +0900 Subject: [PATCH 72/77] sd-dhcp-server: propagate error on parsing DHCP packet Otherwise, we silently ignore the received packet and that makes hard to debug issue. (cherry picked from commit 809da721f0167f88234e55a342e82023019e2341) --- src/libsystemd-network/sd-dhcp-server.c | 2 +- src/libsystemd-network/test-dhcp-server.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index df6812bb8a2..065d1af0561 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -1121,7 +1121,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz type = dhcp_option_parse(message, length, parse_request, req, &error_message); if (type < 0) - return 0; + return type; r = ensure_sane_request(server, req, message); if (r < 0) diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index c31a44e3770..a2b46b99627 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -146,7 +146,7 @@ static void test_message_handler(void) { test.option_type.code = 0; test.option_type.length = 0; test.option_type.type = 0; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == -ENOMSG); test.option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE; test.option_type.length = 1; test.option_type.type = DHCP_DISCOVER; From 4bb0d3cf566eed5b11745d8c44bd788e611bbfb4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 9 Aug 2023 03:40:14 +0900 Subject: [PATCH 73/77] veritysetup-generator: fix ordering of generated units Fixes a bug introduced by 08b04ec7e72b7327b4803809732b1b8fce8dd069 and 953006dcb0a37a57aed0e762ff6289700e8689e8. Fixes #28725. (cherry picked from commit 685e0dd1924cce44327040b08a8980af2192bf59) --- src/shared/generator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/generator.c b/src/shared/generator.c index 44ed3199222..274b799b634 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -829,7 +829,7 @@ int generator_write_veritysetup_unit_section( fprintf(f, "DefaultDependencies=no\n" "IgnoreOnIsolate=true\n" - "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n" + "After=veritysetup-pre.target systemd-udevd-kernel.socket\n" "Before=blockdev@dev-mapper-%%i.target\n" "Wants=blockdev@dev-mapper-%%i.target\n"); From 6ed278526d3fbadc95a4a75add126f0b5d3f3937 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 2 Aug 2023 23:33:14 +0900 Subject: [PATCH 74/77] udev: decrease devlink priority for encrypted partitions Decrease devlink priority for encrypted partitions, and make the priority for decrypted DM devices relatively higher. This is for the case that an encrypted partition and its decrypted DM device have the same label. (cherry picked from commit c4521fc17bb33d10bf5aca3f87f6a394dfecf423) --- rules.d/60-persistent-storage.rules.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rules.d/60-persistent-storage.rules.in b/rules.d/60-persistent-storage.rules.in index 0eba1f8764b..d5e0f5f705e 100644 --- a/rules.d/60-persistent-storage.rules.in +++ b/rules.d/60-persistent-storage.rules.in @@ -140,6 +140,11 @@ LABEL="persistent_storage_blkid_probe_end" # See issue #28468. ENV{ID_FS_TYPE}=="iso9660", ENV{DEVTYPE}=="disk", OPTIONS+="link_priority=-10" +# Decrease devlink priority for encrypted partitions, and make the priority for +# decrypted DM devices relatively higher. This is for the case that an encrypted +# partition and its decrypted DM device have the same label. +ENV{ID_FS_USAGE}=="crypto", OPTIONS+="link_priority=-10" + # by-label/by-uuid links (filesystem metadata) ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}" ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}" From 507c4c79685257857582b1cc9972d3b778f22dd3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 9 Aug 2023 01:25:42 +0900 Subject: [PATCH 75/77] Revert "Revert "tmpfiles.d: adjust /dev/vfio/vfio access mode"" This reverts commit 33b91308c26ca5d512e43b6b32d596a2c9237d04. The commit b42482af904ae0b94a6e4501ec595448f0ba1c06 dropped '--exclude-prefix=/dev' from systemd-tmpfiles-setup.service. So, the possibly later invocation of the service changes the permission set by udevd. As commmented in the head of this file, settings should be consistent with udev rules. Only missing entry here is vfio. Let's re-add the entry for the device. Addresses https://github.com/systemd/systemd/pull/28681#issuecomment-1666949888. (cherry picked from commit ca15b59f1f37cad54e82edb3042e8a035fc6ab18) --- tmpfiles.d/static-nodes-permissions.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/tmpfiles.d/static-nodes-permissions.conf.in b/tmpfiles.d/static-nodes-permissions.conf.in index f77312a71c7..df1fe2e3d5c 100644 --- a/tmpfiles.d/static-nodes-permissions.conf.in +++ b/tmpfiles.d/static-nodes-permissions.conf.in @@ -14,6 +14,7 @@ z /dev/snd/timer 0660 - audio - z /dev/loop-control 0660 - disk - z /dev/net/tun 0666 - - - z /dev/fuse 0666 - - - +z /dev/vfio/vfio 0666 - - - z /dev/kvm {{DEV_KVM_MODE}} - kvm - z /dev/vhost-net {{DEV_KVM_MODE}} - kvm - z /dev/vhost-vsock {{DEV_KVM_MODE}} - kvm - From 257c6f91b84869269145f26366c95d2d7e3c4ade Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 31 Jul 2023 22:11:51 +0900 Subject: [PATCH 76/77] resolve: initialize 'current' when SD_RESOLVED_NO_STALE is set Otherwise, the check below is always fail. ``` if (FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE) && j->until_valid < current) ``` Follow-up for 5ed91481abea382dc486507556e5cdf0f36b796f. (cherry picked from commit 6756b61626afc343f8b6824f41bef67bb442f1d7) --- src/resolve/resolved-dns-cache.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 9d2a2fa1acb..3805150d981 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -1030,9 +1030,10 @@ int dns_cache_lookup( goto miss; } - if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) { + if ((query_flags & (SD_RESOLVED_CLAMP_TTL | SD_RESOLVED_NO_STALE)) != 0) { /* 'current' is always passed to answer_add_clamp_ttl(), but is only used conditionally. - * We'll do the same assert there to make sure that it was initialized properly. */ + * We'll do the same assert there to make sure that it was initialized properly. + * 'current' is also used below when SD_RESOLVED_NO_STALE is set. */ current = now(CLOCK_BOOTTIME); assert(current > 0); } From 208a21833b6953a2517a6c3f8f4849c6664b01be Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Thu, 3 Aug 2023 17:40:15 +0300 Subject: [PATCH 77/77] hwdb: Mute SW rfkill keys on MSI Wind U100 Kernel patch [1] fixed bugs in rfkill handling on MSI Wind U100. Now that the HW rfkill reports the correct state, and the SW rfkill is controllable from userspace, it's necessary to mute KEY_WLAN and KEY_BLUETOOTH generated on HW rfkill state changes. Otherwise, the userspace will react to these keys and toggle the SW rfkill as well, which is not desired, because the user may end up with non-functional radios if HW and SW rfkills are out of sync. Blocking these keycodes doesn't impair user experience, because the desktop environment can still react to HW rfkill events and act accordingly (for example, show notifications). While at it, use "unknown" instead of "reserved" to mute keys, to avoid the "atkbd serio0: Unknown key pressed" flood in dmesg. [1]: https://lore.kernel.org/all/20230721145423.161057-1-maxtram95@gmail.com/ (cherry picked from commit fa8216e20605ff42054ee316201a13ac6cdd4cd1) --- hwdb.d/60-keyboard.hwdb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb index f3f40ef2ffb..87d592d2cd5 100644 --- a/hwdb.d/60-keyboard.hwdb +++ b/hwdb.d/60-keyboard.hwdb @@ -1438,9 +1438,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*PR200*:* KEYBOARD_KEY_f7=reserved KEYBOARD_KEY_f8=reserved -# MSI Wind U90/U100 generates separate touchpad on/off keycodes so ignore touchpad toggle keycode +# MSI Wind U90/U100 generates separate touchpad on/off keycodes so ignore touchpad toggle keycode. +# Also ignore Wi-Fi and Bluetooth keycodes, because they are generated when the HW rfkill state +# changes, but the userspace also toggles the SW rfkill upon receiving these keycodes. evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:* - KEYBOARD_KEY_e4=reserved + KEYBOARD_KEY_e4=unknown + KEYBOARD_KEY_e2=unknown + KEYBOARD_KEY_f6=unknown # Keymaps MSI Prestige And MSI Modern FnKeys and Special keys evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Prestige*:*