From 22bbbfe74c412832689764da69670d42dbc00bdf Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 21 Jan 2020 18:33:31 -0500 Subject: [PATCH] import systemd-239-21.el8 --- ...201-sd-bus-deal-with-cookie-overruns.patch | 87 ++ ...o-not-request-Content-Length-if-Tran.patch | 77 ++ ...emove-multiple-spaces-after-identifi.patch | 79 ++ ...t-fallback-to-PLAIN-mapping-if-LUKS-.patch | 62 ++ ...p-call-crypt_load-for-LUKS-only-once.patch | 79 ++ ...6-cryptsetup-Add-LUKS2-token-support.patch | 45 + ...-incorrect-page-length-when-get-devi.patch | 30 + ...of-manager-triggered-restarts-to-JOB.patch | 55 ++ ...-completion-analyze-support-security.patch | 58 ++ ...urnal-does-not-validate-syslog-field.patch | 28 + ...1-rules-skip-memory-hotplug-on-ppc64.patch | 22 + ...simplify-proc-self-mountinfo-handler.patch | 86 ++ ...c-self-mountinfo-before-processing-w.patch | 90 ++ ...waps-before-processing-waitid-result.patch | 69 ++ ...urity-fix-potential-division-by-zero.patch | 25 + ...gate-reload-failure-to-service-resul.patch | 26 + ...an-document-systemd-analyze-security.patch | 59 ++ ...nd-add-examples-to-systemd-analyze-1.patch | 772 +++++++++++++++ ...ravis-move-to-CentOS-8-docker-images.patch | 132 +++ SOURCES/0220-travis-drop-SCL-remains.patch | 50 + ...ix-segfault-in-syslog_parse_priority.patch | 110 +++ ...0222-sd-bus-make-strict-asan-shut-up.patch | 45 + ...on-t-run-slow-tests-under-ASan-UBSan.patch | 43 + ...o-not-require-non-empty-kernel-cmdli.patch | 67 ++ ...vent-buffer-overrow-when-reading-fro.patch | 36 + ...en-dev-kmsg-again-right-after-mounti.patch | 37 + ...arbage-collect-sections-while-linkin.patch | 29 + .../0228-udev-introduce-CONST-key-name.patch | 186 ++++ ...o-know-size-of-supplementary-groups-.patch | 50 + ...0-Consider-smb3-as-remote-filesystem.patch | 30 + ...til-introduce-pid_is_my_child-helper.patch | 114 +++ ...number-of-stalled-PIDs-from-the-watc.patch | 323 ++++++ ...processes-when-it-s-really-necessary.patch | 55 ++ ...ement-per-unit-journal-rate-limiting.patch | 641 ++++++++++++ ...ng-path-specs-once-we-triggered-the-.patch | 35 + ...ssertion-failure-when-system-journal.patch | 28 + ...KDF2-instead-of-Argon2-in-cryptsetup.patch | 29 + ...st-mask-several-unnecessary-services.patch | 252 +++++ ...p-the-second-partition-s-size-to-50M.patch | 30 + ...fig-exclude-zram-devices-from-hibern.patch | 51 + ...g-SELINUX_INFO-and-SELINUX_WARNING-m.patch | 45 + ...-device-introduce-log_device_-macros.patch | 47 + ...ram-and-rule-for-FIDO-security-token.patch | 505 ++++++++++ ...drop-trusted-annotation-from-bus_ope.patch | 33 + ...d-bus-adjust-indentation-of-comments.patch | 50 + .../0246-resolved-do-not-run-loop-twice.patch | 46 + ...ccess-to-Set-Link-and-Revert-methods.patch | 347 +++++++ ...y-polkit-only-after-parsing-the-data.patch | 48 + ..._cleanup_free_-to-free-a-temporary-s.patch | 48 + ...c-user-util-allow-dots-in-user-names.patch | 90 ++ ...sd-bus-bump-message-queue-size-again.patch | 29 + ...ournald_processing_function-in-a-.c-.patch | 109 ++ ...sts-add-a-fuzzer-for-dev_kmsg_record.patch | 129 +++ ...move-an-assertion-from-cunescape_one.patch | 30 + ...-off-by-one-error-in-dev_kmsg_record.patch | 25 + ...oducer-for-a-memory-leak-fixed-in-30.patch | 25 + ...oducer-for-a-heap-buffer-overflow-fi.patch | 25 + ...-syslog_fd-in-fuzz-journald-kmsg-too.patch | 44 + ...dd-a-fuzzer-for-process_audit_string.patch | 99 ++ ...hether-sscanf-has-changed-the-value-.patch | 47 + ...dummy_server_init-and-use-it-in-all-.patch | 172 ++++ ...ts-add-a-fuzzer-for-journald-streams.patch | 148 +++ ...uzzer-for-server_process_native_file.patch | 96 ++ ...eam-avoid-assertion-failure-on-sampl.patch | 47 + ...ading-spaces-into-account-in-syslog_.patch | 45 + ...out-the-difference-in-permissions-be.patch | 43 + ...emove-one-redundant-comparison-check.patch | 32 + ...rship-mode-of-the-execution-director.patch | 88 ++ ...te-remove-unnecessary-initialization.patch | 25 + ...til-move-the-part-to-print-cpu-set-i.patch | 215 ++++ ...til-remove-now-unused-CPU_SIZE_TO_NU.patch | 29 + .../0272-Rework-cpu-affinity-parsing.patch | 932 ++++++++++++++++++ ...in_affinity_mask-to-cpu-set-util.-ch.patch | 125 +++ ...l-add-simple-test-for-cpus_in_affini.patch | 40 + ...l-add-a-smoke-test-for-test_parse_cp.patch | 63 ++ ...e-CPUAffinity-in-incremental-fashion.patch | 148 +++ ...-setting-from-proc-cmdline-upon-rest.patch | 86 ++ ...ing-configuration-forget-old-setting.patch | 208 ++++ .../0279-test-execute-use-CPUSet-too.patch | 114 +++ ...til-drop-now-unused-cleanup-function.patch | 26 + ...til-make-transfer-of-cpu_set_t-over-.patch | 126 +++ ...t-util-add-test-for-dbus-conversions.patch | 61 ++ ...-set-util-introduce-cpu_set_to_range.patch | 203 ++++ ...t-CPUAffinity-mask-as-a-list-of-CPU-.patch | 53 + ...til-only-force-range-printing-one-ti.patch | 77 ++ ...Affinity-as-a-range-string-instead-o.patch | 36 + ...-d-d-format-in-cpu_set_to_range_stri.patch | 95 ++ ...duce-NUMAPolicy-and-NUMAMask-options.patch | 779 +++++++++++++++ ...ore-disable-CPUAccounting-by-default.patch | 25 + SOURCES/0290-set-kptr_restrict-1.patch | 24 + ...e-the-chance-that-we-will-be-OOM-kil.patch | 34 + ...akage-of-ordering-dependencies-by-sy.patch | 136 +++ ...enable-custom-systemd.debug_shell-tt.patch | 149 +++ ...l-fix-comparison-for-allocation-size.patch | 118 +++ ...il-fix-allocation-size-check-on-i386.patch | 30 + SPECS/systemd.spec | 211 +++- 96 files changed, 10781 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0201-sd-bus-deal-with-cookie-overruns.patch create mode 100644 SOURCES/0202-journal-remote-do-not-request-Content-Length-if-Tran.patch create mode 100644 SOURCES/0203-journal-do-not-remove-multiple-spaces-after-identifi.patch create mode 100644 SOURCES/0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch create mode 100644 SOURCES/0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch create mode 100644 SOURCES/0206-cryptsetup-Add-LUKS2-token-support.patch create mode 100644 SOURCES/0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch create mode 100644 SOURCES/0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch create mode 100644 SOURCES/0209-bash-completion-analyze-support-security.patch create mode 100644 SOURCES/0210-man-note-that-journal-does-not-validate-syslog-field.patch create mode 100644 SOURCES/0211-rules-skip-memory-hotplug-on-ppc64.patch create mode 100644 SOURCES/0212-mount-simplify-proc-self-mountinfo-handler.patch create mode 100644 SOURCES/0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch create mode 100644 SOURCES/0214-swap-scan-proc-swaps-before-processing-waitid-result.patch create mode 100644 SOURCES/0215-analyze-security-fix-potential-division-by-zero.patch create mode 100644 SOURCES/0216-core-never-propagate-reload-failure-to-service-resul.patch create mode 100644 SOURCES/0217-man-document-systemd-analyze-security.patch create mode 100644 SOURCES/0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch create mode 100644 SOURCES/0219-travis-move-to-CentOS-8-docker-images.patch create mode 100644 SOURCES/0220-travis-drop-SCL-remains.patch create mode 100644 SOURCES/0221-syslog-fix-segfault-in-syslog_parse_priority.patch create mode 100644 SOURCES/0222-sd-bus-make-strict-asan-shut-up.patch create mode 100644 SOURCES/0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch create mode 100644 SOURCES/0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch create mode 100644 SOURCES/0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch create mode 100644 SOURCES/0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch create mode 100644 SOURCES/0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch create mode 100644 SOURCES/0228-udev-introduce-CONST-key-name.patch create mode 100644 SOURCES/0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch create mode 100644 SOURCES/0230-Consider-smb3-as-remote-filesystem.patch create mode 100644 SOURCES/0231-process-util-introduce-pid_is_my_child-helper.patch create mode 100644 SOURCES/0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch create mode 100644 SOURCES/0233-core-only-watch-processes-when-it-s-really-necessary.patch create mode 100644 SOURCES/0234-core-implement-per-unit-journal-rate-limiting.patch create mode 100644 SOURCES/0235-path-stop-watching-path-specs-once-we-triggered-the-.patch create mode 100644 SOURCES/0236-journald-fixed-assertion-failure-when-system-journal.patch create mode 100644 SOURCES/0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch create mode 100644 SOURCES/0238-test-mask-several-unnecessary-services.patch create mode 100644 SOURCES/0239-test-bump-the-second-partition-s-size-to-50M.patch create mode 100644 SOURCES/0240-shared-sleep-config-exclude-zram-devices-from-hibern.patch create mode 100644 SOURCES/0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch create mode 100644 SOURCES/0242-sd-device-introduce-log_device_-macros.patch create mode 100644 SOURCES/0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch create mode 100644 SOURCES/0244-shared-but-util-drop-trusted-annotation-from-bus_ope.patch create mode 100644 SOURCES/0245-sd-bus-adjust-indentation-of-comments.patch create mode 100644 SOURCES/0246-resolved-do-not-run-loop-twice.patch create mode 100644 SOURCES/0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch create mode 100644 SOURCES/0248-resolved-query-polkit-only-after-parsing-the-data.patch create mode 100644 SOURCES/0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch create mode 100644 SOURCES/0250-basic-user-util-allow-dots-in-user-names.patch create mode 100644 SOURCES/0251-sd-bus-bump-message-queue-size-again.patch create mode 100644 SOURCES/0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch create mode 100644 SOURCES/0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch create mode 100644 SOURCES/0254-basic-remove-an-assertion-from-cunescape_one.patch create mode 100644 SOURCES/0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch create mode 100644 SOURCES/0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch create mode 100644 SOURCES/0257-tests-add-a-reproducer-for-a-heap-buffer-overflow-fi.patch create mode 100644 SOURCES/0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch create mode 100644 SOURCES/0259-tests-add-a-fuzzer-for-process_audit_string.patch create mode 100644 SOURCES/0260-journald-check-whether-sscanf-has-changed-the-value-.patch create mode 100644 SOURCES/0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch create mode 100644 SOURCES/0262-tests-add-a-fuzzer-for-journald-streams.patch create mode 100644 SOURCES/0263-tests-add-a-fuzzer-for-server_process_native_file.patch create mode 100644 SOURCES/0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch create mode 100644 SOURCES/0265-journald-take-leading-spaces-into-account-in-syslog_.patch create mode 100644 SOURCES/0266-Add-a-warning-about-the-difference-in-permissions-be.patch create mode 100644 SOURCES/0267-execute-remove-one-redundant-comparison-check.patch create mode 100644 SOURCES/0268-core-change-ownership-mode-of-the-execution-director.patch create mode 100644 SOURCES/0269-core-dbus-execute-remove-unnecessary-initialization.patch create mode 100644 SOURCES/0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch create mode 100644 SOURCES/0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch create mode 100644 SOURCES/0272-Rework-cpu-affinity-parsing.patch create mode 100644 SOURCES/0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch create mode 100644 SOURCES/0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch create mode 100644 SOURCES/0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch create mode 100644 SOURCES/0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch create mode 100644 SOURCES/0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch create mode 100644 SOURCES/0278-pid1-when-reloading-configuration-forget-old-setting.patch create mode 100644 SOURCES/0279-test-execute-use-CPUSet-too.patch create mode 100644 SOURCES/0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch create mode 100644 SOURCES/0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch create mode 100644 SOURCES/0282-test-cpu-set-util-add-test-for-dbus-conversions.patch create mode 100644 SOURCES/0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch create mode 100644 SOURCES/0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch create mode 100644 SOURCES/0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch create mode 100644 SOURCES/0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch create mode 100644 SOURCES/0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch create mode 100644 SOURCES/0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch create mode 100644 SOURCES/0289-core-disable-CPUAccounting-by-default.patch create mode 100644 SOURCES/0290-set-kptr_restrict-1.patch create mode 100644 SOURCES/0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch create mode 100644 SOURCES/0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch create mode 100644 SOURCES/0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch create mode 100644 SOURCES/0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch create mode 100644 SOURCES/0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch diff --git a/SOURCES/0201-sd-bus-deal-with-cookie-overruns.patch b/SOURCES/0201-sd-bus-deal-with-cookie-overruns.patch new file mode 100644 index 0000000..bf61bb4 --- /dev/null +++ b/SOURCES/0201-sd-bus-deal-with-cookie-overruns.patch @@ -0,0 +1,87 @@ +From 980418c331293aeb8595fcc95cbc4a9e1a485eda Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Feb 2019 11:02:46 +0100 +Subject: [PATCH] sd-bus: deal with cookie overruns + +Apparently this happens IRL. Let's carefully deal with issues like this: +when we overrun, let's not go back to zero but instead leave the highest +cookie bit set. We use that as indication that we are in "overrun +territory", and then are particularly careful with checking cookies, +i.e. that they haven't been used for still outstanding replies yet. This +should retain the quick cookie generation behaviour we used to have, but +permits dealing with overruns. + +Replaces: #11804 +Fixes: #11809 +(cherry picked from commit 1f82f5bb4237ed5f015daf93f818e9db95e764b8) + +Resolves: #1694999 +--- + src/libsystemd/sd-bus/sd-bus.c | 47 +++++++++++++++++++++++++++++++++- + 1 file changed, 46 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index f53a98d6bf..3583e24e64 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -1597,6 +1597,47 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { + return 0; + } + ++#define COOKIE_CYCLED (UINT32_C(1) << 31) ++ ++static uint64_t cookie_inc(uint64_t cookie) { ++ ++ /* Stay within the 32bit range, since classic D-Bus can't deal with more */ ++ if (cookie >= UINT32_MAX) ++ return COOKIE_CYCLED; /* Don't go back to zero, but use the highest bit for checking ++ * whether we are looping. */ ++ ++ return cookie + 1; ++} ++ ++static int next_cookie(sd_bus *b) { ++ uint64_t new_cookie; ++ ++ assert(b); ++ ++ new_cookie = cookie_inc(b->cookie); ++ ++ /* Small optimization: don't bother with checking for cookie reuse until we overran cookiespace at ++ * least once, but then do it thorougly. */ ++ if (FLAGS_SET(new_cookie, COOKIE_CYCLED)) { ++ uint32_t i; ++ ++ /* Check if the cookie is currently in use. If so, pick the next one */ ++ for (i = 0; i < COOKIE_CYCLED; i++) { ++ if (!ordered_hashmap_contains(b->reply_callbacks, &new_cookie)) ++ goto good; ++ ++ new_cookie = cookie_inc(new_cookie); ++ } ++ ++ /* Can't fulfill request */ ++ return -EBUSY; ++ } ++ ++good: ++ b->cookie = new_cookie; ++ return 0; ++} ++ + static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { + int r; + +@@ -1620,7 +1661,11 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { + return r; + } + +- return sd_bus_message_seal(m, ++b->cookie, timeout); ++ r = next_cookie(b); ++ if (r < 0) ++ return r; ++ ++ return sd_bus_message_seal(m, b->cookie, timeout); + } + + static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) { diff --git a/SOURCES/0202-journal-remote-do-not-request-Content-Length-if-Tran.patch b/SOURCES/0202-journal-remote-do-not-request-Content-Length-if-Tran.patch new file mode 100644 index 0000000..431cdff --- /dev/null +++ b/SOURCES/0202-journal-remote-do-not-request-Content-Length-if-Tran.patch @@ -0,0 +1,77 @@ +From f551c05e4799386508e10f0f007251e426493a67 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 11 Mar 2019 12:27:18 +0900 +Subject: [PATCH] journal-remote: do not request Content-Length if + Transfer-Encoding is chunked + +This fixes a bug introduced by 7fdb237f5473cb8fc2129e57e8a0039526dcb4fd. + +Closes #11571. + +(cherry picked from commit a289dfd69b3ff4bccdde93e84b67c947bafa27e1) + +Resolves: #1708849 +--- + src/journal-remote/journal-remote-main.c | 41 ++++++++++++++++-------- + 1 file changed, 27 insertions(+), 14 deletions(-) + +diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c +index 5b0bbba310..47fe9d7433 100644 +--- a/src/journal-remote/journal-remote-main.c ++++ b/src/journal-remote/journal-remote-main.c +@@ -254,6 +254,7 @@ static int request_handler( + const char *header; + int r, code, fd; + _cleanup_free_ char *hostname = NULL; ++ bool chunked = false; + size_t len; + + assert(connection); +@@ -279,21 +280,33 @@ static int request_handler( + return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE, + "Content-Type: application/vnd.fdo.journal is required."); + ++ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding"); ++ if (header) { ++ if (!strcaseeq(header, "chunked")) ++ return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST, ++ "Unsupported Transfer-Encoding type: %s", header); ++ ++ chunked = true; ++ } ++ + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); +- if (!header) +- return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED, +- "Content-Length header is required."); +- r = safe_atozu(header, &len); +- if (r < 0) +- return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, +- "Content-Length: %s cannot be parsed: %m", header); +- +- if (len > ENTRY_SIZE_MAX) +- /* When serialized, an entry of maximum size might be slightly larger, +- * so this does not correspond exactly to the limit in journald. Oh well. +- */ +- return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, +- "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); ++ if (header) { ++ if (chunked) ++ return mhd_respond(connection, MHD_HTTP_BAD_REQUEST, ++ "Content-Length must not specified when Transfer-Encoding type is 'chuncked'"); ++ ++ r = safe_atozu(header, &len); ++ if (r < 0) ++ return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, ++ "Content-Length: %s cannot be parsed: %m", header); ++ ++ if (len > ENTRY_SIZE_MAX) ++ /* When serialized, an entry of maximum size might be slightly larger, ++ * so this does not correspond exactly to the limit in journald. Oh well. ++ */ ++ return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, ++ "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); ++ } + + { + const union MHD_ConnectionInfo *ci; diff --git a/SOURCES/0203-journal-do-not-remove-multiple-spaces-after-identifi.patch b/SOURCES/0203-journal-do-not-remove-multiple-spaces-after-identifi.patch new file mode 100644 index 0000000..3c7d150 --- /dev/null +++ b/SOURCES/0203-journal-do-not-remove-multiple-spaces-after-identifi.patch @@ -0,0 +1,79 @@ +From fffbf1f90be5236b310bc0b10034815b1051f0ac Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 10 Aug 2018 11:07:54 +0900 +Subject: [PATCH] journal: do not remove multiple spaces after identifier in + syslog message + +Single space is used as separator. +C.f. discussions in #156. + +Fixes #9839 introduced by a6aadf4ae0bae185dc4c414d492a4a781c80ffe5. + +(cherry picked from commit 8595102d3ddde6d25c282f965573a6de34ab4421) + +Resolves: #1691817 +--- + src/journal/journald-syslog.c | 4 +++- + src/journal/test-journal-syslog.c | 24 ++++++++++++++---------- + 2 files changed, 17 insertions(+), 11 deletions(-) + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 97711ac7a3..e0b55cc566 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -219,7 +219,9 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) + if (t) + *identifier = t; + +- e += strspn(p + e, WHITESPACE); ++ /* Single space is used as separator */ ++ if (p[e] != '\0' && strchr(WHITESPACE, p[e])) ++ e++; + + *buf = p + e; + return e; +diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c +index 05f759817e..7294cde032 100644 +--- a/src/journal/test-journal-syslog.c ++++ b/src/journal/test-journal-syslog.c +@@ -6,7 +6,7 @@ + #include "string-util.h" + + static void test_syslog_parse_identifier(const char *str, +- const char *ident, const char *pid, int ret) { ++ const char *ident, const char *pid, const char *rest, int ret) { + const char *buf = str; + _cleanup_free_ char *ident2 = NULL, *pid2 = NULL; + int ret2; +@@ -16,18 +16,22 @@ static void test_syslog_parse_identifier(const char *str, + assert_se(ret == ret2); + assert_se(ident == ident2 || streq_ptr(ident, ident2)); + assert_se(pid == pid2 || streq_ptr(pid, pid2)); ++ assert_se(streq(buf, rest)); + } + + int main(void) { +- test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", 11); +- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 6); +- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 7); +- test_syslog_parse_identifier("pidu xxx", NULL, NULL, 0); +- test_syslog_parse_identifier(":", "", NULL, 1); +- test_syslog_parse_identifier(": ", "", NULL, 3); +- test_syslog_parse_identifier("pidu:", "pidu", NULL, 5); +- test_syslog_parse_identifier("pidu: ", "pidu", NULL, 6); +- test_syslog_parse_identifier("pidu : ", NULL, NULL, 0); ++ test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11); ++ test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6); ++ test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, " xxx", 6); ++ test_syslog_parse_identifier("pidu xxx", NULL, NULL, "pidu xxx", 0); ++ test_syslog_parse_identifier(" pidu xxx", NULL, NULL, " pidu xxx", 0); ++ test_syslog_parse_identifier("", NULL, NULL, "", 0); ++ test_syslog_parse_identifier(" ", NULL, NULL, " ", 0); ++ test_syslog_parse_identifier(":", "", NULL, "", 1); ++ test_syslog_parse_identifier(": ", "", NULL, " ", 2); ++ test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5); ++ test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6); ++ test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0); + + return 0; + } diff --git a/SOURCES/0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch b/SOURCES/0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch new file mode 100644 index 0000000..eab6715 --- /dev/null +++ b/SOURCES/0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch @@ -0,0 +1,62 @@ +From 4f9d00380ea41f5a4eb1610ae5c354a8f749cc98 Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Mon, 27 May 2019 09:27:54 +0200 +Subject: [PATCH] cryptsetup: Do not fallback to PLAIN mapping if LUKS data + device set fails. + +If crypt_load() for LUKS succeeds, we know that it is a LUKS device. +Failure of data device setting should fail in this case; remapping +as a PLAIN device late could mean data corruption. + +(If a user wants to map PLAIN device over a device with LUKS header, +it should be said explicitly with "plain" argument type.) + +Also, if there is no explicit PLAIN type requested and crypt device +is already initialized (crypt_data_type() is set), do not run +the initialization again. + +(cherry picked from commit 2e4beb875bcb24e7d7d4339cc202b0b3f2953f71) + +Related: #1719153 +--- + src/cryptsetup/cryptsetup.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index abeba44ee8..5be1469d69 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -492,11 +492,14 @@ static int attach_luks_or_plain(struct crypt_device *cd, + return r; + } + +- if (data_device) ++ if (data_device) { + r = crypt_set_data_device(cd, data_device); ++ if (r < 0) ++ return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device); ++ } + } + +- if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) { ++ if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) { + struct crypt_params_plain params = { + .offset = arg_offset, + .skip = arg_skip, +@@ -543,14 +546,13 @@ static int attach_luks_or_plain(struct crypt_device *cd, + * parameters when used for plain + * mode. */ + r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, ¶ms); ++ if (r < 0) ++ return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); + + /* hash == NULL implies the user passed "plain" */ + pass_volume_key = (params.hash == NULL); + } + +- if (r < 0) +- return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); +- + log_info("Set cipher %s, mode %s, key size %i bits for device %s.", + crypt_get_cipher(cd), + crypt_get_cipher_mode(cd), diff --git a/SOURCES/0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch b/SOURCES/0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch new file mode 100644 index 0000000..543efeb --- /dev/null +++ b/SOURCES/0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch @@ -0,0 +1,79 @@ +From 788fb775f7deb8c456868362454e2a5f50c6068f Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Mon, 27 May 2019 09:43:03 +0200 +Subject: [PATCH] cryptsetup: call crypt_load() for LUKS only once + +The crypt_load() for LUKS2 can read a quite big area of disk +(metadata area size is configurable and can increase up to megabytes). + +This initialization is not needed to be repeated, just use the existing context. + +(This patch is also required for the following change.) + +(cherry picked from commit ea9a9d49e4af31c49e5c216e7e5e2f533e727579) + +Related: #1719153 +--- + src/cryptsetup/cryptsetup.c | 28 ++++++++++++---------------- + 1 file changed, 12 insertions(+), 16 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index 5be1469d69..a0bd80ea65 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -475,7 +475,6 @@ static int attach_tcrypt( + static int attach_luks_or_plain(struct crypt_device *cd, + const char *name, + const char *key_file, +- const char *data_device, + char **passwords, + uint32_t flags) { + int r = 0; +@@ -485,20 +484,6 @@ static int attach_luks_or_plain(struct crypt_device *cd, + assert(name); + assert(key_file || passwords); + +- if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) { +- r = crypt_load(cd, CRYPT_LUKS, NULL); +- if (r < 0) { +- log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd)); +- return r; +- } +- +- if (data_device) { +- r = crypt_set_data_device(cd, data_device); +- if (r < 0) +- return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device); +- } +- } +- + if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) { + struct crypt_params_plain params = { + .offset = arg_offset, +@@ -687,6 +672,18 @@ int main(int argc, char *argv[]) { + log_warning("Key file %s is world-readable. This is not a good idea!", key_file); + } + ++ if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) { ++ r = crypt_load(cd, CRYPT_LUKS, NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); ++ ++ if (arg_header) { ++ r = crypt_set_data_device(cd, argv[3]); ++ if (r < 0) ++ return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]); ++ } ++ } ++ + for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { + _cleanup_strv_free_erase_ char **passwords = NULL; + +@@ -704,7 +701,6 @@ int main(int argc, char *argv[]) { + r = attach_luks_or_plain(cd, + argv[2], + key_file, +- arg_header ? argv[3] : NULL, + passwords, + flags); + if (r >= 0) diff --git a/SOURCES/0206-cryptsetup-Add-LUKS2-token-support.patch b/SOURCES/0206-cryptsetup-Add-LUKS2-token-support.patch new file mode 100644 index 0000000..f818181 --- /dev/null +++ b/SOURCES/0206-cryptsetup-Add-LUKS2-token-support.patch @@ -0,0 +1,45 @@ +From 7a597a091de83a861d81166b0e863bf2977c829c Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Mon, 27 May 2019 09:44:14 +0200 +Subject: [PATCH] cryptsetup: Add LUKS2 token support. + +LUKS2 supports so-called tokens. The libcryptsetup internally +support keyring token (it tries to open device using specified +keyring entry). +Only if all token fails (or are not available), it uses a passphrase. + +This patch aligns the functionality with the cryptsetup utility +(cryptsetup luksOpen tries tokens first) but does not replace +the systemd native ask-password function (can be used the same in +combination with this patch). + +(cherry picked from commit 894bb3ca4c730cc9e9d46ef5004ba4ca5e201d8d) + +Resolves: #1719153 +--- + src/cryptsetup/cryptsetup.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index a0bd80ea65..4e1b3eff19 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -682,6 +682,18 @@ int main(int argc, char *argv[]) { + if (r < 0) + return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]); + } ++#ifdef CRYPT_ANY_TOKEN ++ /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */ ++ if (!key_file) { ++ r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags); ++ if (r >= 0) { ++ log_debug("Volume %s activated with LUKS token id %i.", argv[2], r); ++ return 0; ++ } ++ ++ log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd)); ++ } ++#endif + } + + for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { diff --git a/SOURCES/0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch b/SOURCES/0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch new file mode 100644 index 0000000..a884b4f --- /dev/null +++ b/SOURCES/0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch @@ -0,0 +1,30 @@ +From 7b3ef169e3142fb471c48f265881b371380d77e0 Mon Sep 17 00:00:00 2001 +From: Zhang Xianwei +Date: Mon, 13 May 2019 18:41:55 +0800 +Subject: [PATCH] udev/scsi_id: fix incorrect page length when get device + identification VPD page + +The length of device identification VPD page is filled with two bytes, +but scsi_id only gets the low byte. Fix it. + +Signed-off-by: Zhang Xianwei +(cherry picked from commit 1f7b6872dbe8ccae1f3bda9aa6aeb87c9b42e01e) + +Resolves: #1713227 +--- + src/udev/scsi_id/scsi_serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c +index fd91657a32..fb6055395d 100644 +--- a/src/udev/scsi_id/scsi_serial.c ++++ b/src/udev/scsi_id/scsi_serial.c +@@ -661,7 +661,7 @@ static int do_scsi_page83_inquiry(struct udev *udev, + * Examine each descriptor returned. There is normally only + * one or a small number of descriptors. + */ +- for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) { ++ for (j = 4; j <= ((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) { + retval = check_fill_0x83_id(udev, + dev_scsi, &page_83[j], + &id_search_list[id_ind], diff --git a/SOURCES/0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch b/SOURCES/0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch new file mode 100644 index 0000000..c40fd1c --- /dev/null +++ b/SOURCES/0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch @@ -0,0 +1,55 @@ +From d70e1c2eb596b8144197192e2324abbb45f547a6 Mon Sep 17 00:00:00 2001 +From: Jonathon Kowalski +Date: Thu, 17 Jan 2019 17:08:00 +0000 +Subject: [PATCH] Change job mode of manager triggered restarts to JOB_REPLACE + +Fixes: #11305 +Fixes: #3260 +Related: #11456 + +So, here's what happens in the described scenario in #11305. A unit goes +down, and that triggeres stop jobs for the other two units as they were +bound to it. Now, the timer for manager triggered restarts kicks in and +schedules a restart job with the JOB_FAIL job mode. This means there is +a stop job installed on those units, and now due to them being bound to +us they also get a restart job enqueued. This however is a conflicts, as +neither stop can merge into restart, nor restart into stop. However, +restart should be able to replace stop in any case. If the stop +procedure is ongoing, it can cancel the stop job, install itself, and +then after reaching dead finish and convert itself to a start job. +However, if we increase the timer, then it can always take those units +from inactive -> auto-restart. + +We change the job mode to JOB_REPLACE so the restart job cancels the +stop job and installs itself. + +Also, the original bug could be worked around by bumping RestartSec= to +avoid the conflicting. + +This doesn't seem to be something that is going to break uses. That is +because for those who already had it working, there must have never been +conflicting jobs, as that would result in a desctructive transaction by +virtue of the job mode used. + +After this change, the test case is able to work nicely without issues. + +(cherry picked from commit 03ff2dc71ecb09272d728d458498b44f7f132f51) + +Resolves: #1712524 +--- + src/core/service.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 3eab749362..8342c131c8 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2133,7 +2133,7 @@ static void service_enter_restart(Service *s) { + * restarted. We use JOB_RESTART (instead of the more obvious + * JOB_START) here so that those dependency jobs will be added + * as well. */ +- r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL); ++ r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL); + if (r < 0) + goto fail; + diff --git a/SOURCES/0209-bash-completion-analyze-support-security.patch b/SOURCES/0209-bash-completion-analyze-support-security.patch new file mode 100644 index 0000000..aec8a8d --- /dev/null +++ b/SOURCES/0209-bash-completion-analyze-support-security.patch @@ -0,0 +1,58 @@ +From 8d1a8f099dbf79d0e18e055721228192a637a759 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 6 Dec 2018 18:51:56 +0100 +Subject: [PATCH] bash-completion: analyze: support 'security' + +(cherry picked from commit 83da42c3bf86e8787cfec2c7fb6ca379dfec3632) + +Resolves: #1733395 +--- + shell-completion/bash/systemd-analyze | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze +index 21d0fcf1b8..b4fcfc6492 100644 +--- a/shell-completion/bash/systemd-analyze ++++ b/shell-completion/bash/systemd-analyze +@@ -31,8 +31,13 @@ __get_machines() { + machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; }; + } + ++__get_services() { ++ systemctl list-units --no-legend --no-pager -t service --all $1 | \ ++ { while read -r a b c; do [[ $b == "loaded" ]]; echo " $a"; done } ++} ++ + _systemd_analyze() { +- local i verb comps ++ local i verb comps mode + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + + local -A OPTS=( +@@ -51,6 +56,7 @@ _systemd_analyze() { + [SECCOMP_FILTER]='syscall-filter' + [SERVICE_WATCHDOGS]='service-watchdogs' + [CAT_CONFIG]='cat-config' ++ [SECURITY]='security' + ) + + local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf +@@ -149,6 +155,18 @@ _systemd_analyze() { + comps="$CONFIGS $( compgen -A file -- "$cur" )" + compopt -o filenames + fi ++ ++ elif __contains_word "$verb" ${VERBS[SECURITY]}; then ++ if [[ $cur = -* ]]; then ++ comps='--help --version --no-pager --system --user -H --host -M --machine' ++ else ++ if __contains_word "--user" ${COMP_WORDS[*]}; then ++ mode=--user ++ else ++ mode=--system ++ fi ++ comps=$( __get_services $mode ) ++ fi + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) diff --git a/SOURCES/0210-man-note-that-journal-does-not-validate-syslog-field.patch b/SOURCES/0210-man-note-that-journal-does-not-validate-syslog-field.patch new file mode 100644 index 0000000..3e9de97 --- /dev/null +++ b/SOURCES/0210-man-note-that-journal-does-not-validate-syslog-field.patch @@ -0,0 +1,28 @@ +From 705a67a53a8a1b836ef17f048366bbf33357afc1 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 14 May 2019 10:45:08 +0200 +Subject: [PATCH] man: note that journal does not validate syslog fields + +(cherry picked from commit 63ea8032f28052f7cda860e5324c0a83dee7ed23) + +Resolves: #1707175 +--- + man/systemd.journal-fields.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml +index c079274c32..0c95c4cd95 100644 +--- a/man/systemd.journal-fields.xml ++++ b/man/systemd.journal-fields.xml +@@ -111,6 +111,11 @@ + program_invocation_short_name variable, + see + program_invocation_short_name3.) ++ Note that the journal service does not validate the values of any structured ++ journal fields whose name is not prefixed with an underscore, and this includes any ++ syslog related fields such as these. Hence, applications that supply a facility, PID, ++ or log level are expected to do so properly formatted, i.e. as numeric integers formatted ++ as decimal strings. + + + diff --git a/SOURCES/0211-rules-skip-memory-hotplug-on-ppc64.patch b/SOURCES/0211-rules-skip-memory-hotplug-on-ppc64.patch new file mode 100644 index 0000000..3e311ee --- /dev/null +++ b/SOURCES/0211-rules-skip-memory-hotplug-on-ppc64.patch @@ -0,0 +1,22 @@ +From 72dd8d8cd1a7417805009050f859d502b1c6cf3e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 6 Jun 2019 09:35:27 +0200 +Subject: [PATCH] rules: skip memory hotplug on ppc64 + +Resolves (#1713159) +--- + rules/40-redhat.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 17b33682bd..fadc6e59f1 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -7,6 +7,7 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online} + SUBSYSTEM!="memory", GOTO="memory_hotplug_end" + ACTION!="add", GOTO="memory_hotplug_end" + PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end" ++PROGRAM="/bin/uname -p", RESULT=="ppc64*", GOTO="memory_hotplug_end" + + ENV{.state}="online" + PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable" diff --git a/SOURCES/0212-mount-simplify-proc-self-mountinfo-handler.patch b/SOURCES/0212-mount-simplify-proc-self-mountinfo-handler.patch new file mode 100644 index 0000000..316dda2 --- /dev/null +++ b/SOURCES/0212-mount-simplify-proc-self-mountinfo-handler.patch @@ -0,0 +1,86 @@ +From daf63a3c6c6cd241017bdf9a26c7b1caf744e69b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 17 Jul 2019 14:53:07 +0200 +Subject: [PATCH] mount: simplify /proc/self/mountinfo handler + +Our IO handler is only installed for one fd, hence there's no reason to +conditionalize on it again. + +Also, split out the draining into a helper function of its own. + +(cherry picked from commit fcd8e119c28be19ffbc5227089cf4d3b8ba60238) + +Conflicts: + src/core/mount.c + +Related: #1696178 +--- + src/core/mount.c | 48 ++++++++++++++++++++++++++---------------------- + 1 file changed, 26 insertions(+), 22 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 16229d4af1..85b07375e2 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1758,6 +1758,29 @@ fail: + mount_shutdown(m); + } + ++static int drain_libmount(Manager *m) { ++ bool rescan = false; ++ int r; ++ ++ assert(m); ++ ++ /* Drain all events and verify that the event is valid. ++ * ++ * Note that libmount also monitors /run/mount mkdir if the directory does not exist yet. The mkdir ++ * may generate event which is irrelevant for us. ++ * ++ * error: r < 0; valid: r == 0, false positive: r == 1 */ ++ do { ++ r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to drain libmount events: %m"); ++ if (r == 0) ++ rescan = true; ++ } while (r == 0); ++ ++ return rescan; ++} ++ + static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_set_free_ Set *around = NULL, *gone = NULL; + Manager *m = userdata; +@@ -1769,28 +1792,9 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + assert(m); + assert(revents & EPOLLIN); + +- if (fd == mnt_monitor_get_fd(m->mount_monitor)) { +- bool rescan = false; +- +- /* Drain all events and verify that the event is valid. +- * +- * Note that libmount also monitors /run/mount mkdir if the +- * directory does not exist yet. The mkdir may generate event +- * which is irrelevant for us. +- * +- * error: r < 0; valid: r == 0, false positive: rc == 1 */ +- do { +- r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL); +- if (r == 0) +- rescan = true; +- else if (r < 0) +- return log_error_errno(r, "Failed to drain libmount events"); +- } while (r == 0); +- +- log_debug("libmount event [rescan: %s]", yes_no(rescan)); +- if (!rescan) +- return 0; +- } ++ r = drain_libmount(m); ++ if (r <= 0) ++ return r; + + r = mount_load_proc_self_mountinfo(m, true); + if (r < 0) { diff --git a/SOURCES/0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch b/SOURCES/0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch new file mode 100644 index 0000000..032ea39 --- /dev/null +++ b/SOURCES/0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch @@ -0,0 +1,90 @@ +From 4bc21bbc61acd1ce114da381a9742f6bcd4ffde8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 17 Jul 2019 18:57:13 +0200 +Subject: [PATCH] mount: rescan /proc/self/mountinfo before processing waitid() + results + +(The interesting bits about the what and why are in a comment in the +patch, please have a look there instead of looking here in the commit +msg). + +Fixes: #10872 +(cherry picked from commit 350804867dbcc9b7ccabae1187d730d37e2d8a21) + +Conflicts: + src/core/mount.c + +Resolves: #1696178 +--- + src/core/mount.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 85b07375e2..2ac04e3874 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -53,6 +53,7 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { + + static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); ++static int mount_process_proc_self_mountinfo(Manager *m); + + static bool MOUNT_STATE_WITH_PROCESS(MountState state) { + return IN_SET(state, +@@ -1241,6 +1242,22 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { + if (pid != m->control_pid) + return; + ++ /* So here's the thing, we really want to know before /usr/bin/mount or /usr/bin/umount exit whether ++ * they established/remove a mount. This is important when mounting, but even more so when unmounting ++ * since we need to deal with nested mounts and otherwise cannot safely determine whether to repeat ++ * the unmounts. In theory, the kernel fires /proc/self/mountinfo changes off before returning from ++ * the mount() or umount() syscalls, and thus we should see the changes to the proc file before we ++ * process the waitid() for the /usr/bin/(u)mount processes. However, this is unfortunately racy: we ++ * have to waitid() for processes using P_ALL (since we need to reap unexpected children that got ++ * reparented to PID 1), but when using P_ALL we might end up reaping processes that terminated just ++ * instants ago, i.e. already after our last event loop iteration (i.e. after the last point we might ++ * have noticed /proc/self/mountinfo events via epoll). This means event loop priorities for ++ * processing SIGCHLD vs. /proc/self/mountinfo IO events are not as relevant as we want. To fix that ++ * race, let's explicitly scan /proc/self/mountinfo before we start processing /usr/bin/(u)mount ++ * dying. It's ugly, but it makes our ordering systematic again, and makes sure we always see ++ * /proc/self/mountinfo changes before our mount/umount exits. */ ++ (void) mount_process_proc_self_mountinfo(u->manager); ++ + m->control_pid = 0; + + if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL)) +@@ -1781,16 +1798,14 @@ static int drain_libmount(Manager *m) { + return rescan; + } + +-static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++static int mount_process_proc_self_mountinfo(Manager *m) { + _cleanup_set_free_ Set *around = NULL, *gone = NULL; +- Manager *m = userdata; + const char *what; + Iterator i; + Unit *u; + int r; + + assert(m); +- assert(revents & EPOLLIN); + + r = drain_libmount(m); + if (r <= 0) +@@ -1898,6 +1913,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + return 0; + } + ++static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ Manager *m = userdata; ++ ++ assert(m); ++ assert(revents & EPOLLIN); ++ ++ return mount_process_proc_self_mountinfo(m); ++} ++ + static void mount_reset_failed(Unit *u) { + Mount *m = MOUNT(u); + diff --git a/SOURCES/0214-swap-scan-proc-swaps-before-processing-waitid-result.patch b/SOURCES/0214-swap-scan-proc-swaps-before-processing-waitid-result.patch new file mode 100644 index 0000000..e872790 --- /dev/null +++ b/SOURCES/0214-swap-scan-proc-swaps-before-processing-waitid-result.patch @@ -0,0 +1,69 @@ +From a0c135f7771dbe3a6cd3da2aaa106900be0f4470 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 17 Jul 2019 18:58:44 +0200 +Subject: [PATCH] swap: scan /proc/swaps before processing waitid() results + +Similar to the previous commit, but for /proc/swaps, where the same +logic and rationale applies. + +(cherry picked from commit bcce581d65de68cca01c73e1c890e261e72d20af) + +Related: #1696178 +--- + src/core/swap.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index e01e61e56d..b644753a1c 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -40,6 +40,7 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { + + static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); ++static int swap_process_proc_swaps(Manager *m); + + static bool SWAP_STATE_WITH_PROCESS(SwapState state) { + return IN_SET(state, +@@ -990,6 +991,10 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { + if (pid != s->control_pid) + return; + ++ /* Let's scan /proc/swaps before we process SIGCHLD. For the reasoning see the similar code in ++ * mount.c */ ++ (void) swap_process_proc_swaps(u->manager); ++ + s->control_pid = 0; + + if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL)) +@@ -1125,13 +1130,11 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) { + return r; + } + +-static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { +- Manager *m = userdata; ++static int swap_process_proc_swaps(Manager *m) { + Unit *u; + int r; + + assert(m); +- assert(revents & EPOLLPRI); + + r = swap_load_proc_swaps(m, true); + if (r < 0) { +@@ -1205,6 +1208,15 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v + return 1; + } + ++static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ Manager *m = userdata; ++ ++ assert(m); ++ assert(revents & EPOLLPRI); ++ ++ return swap_process_proc_swaps(m); ++} ++ + static Unit *swap_following(Unit *u) { + Swap *s = SWAP(u); + Swap *other, *first = NULL; diff --git a/SOURCES/0215-analyze-security-fix-potential-division-by-zero.patch b/SOURCES/0215-analyze-security-fix-potential-division-by-zero.patch new file mode 100644 index 0000000..3e150b0 --- /dev/null +++ b/SOURCES/0215-analyze-security-fix-potential-division-by-zero.patch @@ -0,0 +1,25 @@ +From ebe93460ef5ae3744c4b627361f4dc5815cffc13 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 31 Jul 2019 09:13:41 +0200 +Subject: [PATCH] analyze-security: fix potential division by zero + +Upstream PR: https://github.com/systemd/systemd/pull/13238 + +Resolves: #1734400 +--- + src/analyze/analyze-security.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c +index 541fc0d97a..eec040d5c3 100644 +--- a/src/analyze/analyze-security.c ++++ b/src/analyze/analyze-security.c +@@ -1494,6 +1494,8 @@ static int assess(const struct security_info *info, Table *overview_table, Analy + } + } + ++ assert(weight_sum > 0); ++ + if (details_table) { + size_t row; + diff --git a/SOURCES/0216-core-never-propagate-reload-failure-to-service-resul.patch b/SOURCES/0216-core-never-propagate-reload-failure-to-service-resul.patch new file mode 100644 index 0000000..2d967cf --- /dev/null +++ b/SOURCES/0216-core-never-propagate-reload-failure-to-service-resul.patch @@ -0,0 +1,26 @@ +From cffe5d0e781f6fa7f2275b94d2dcc26e00859a78 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 17 Jul 2019 19:16:33 +0200 +Subject: [PATCH] core: never propagate reload failure to service result + +Fixes: #11238 +(cherry picked from commit d611cfa748aaf600832160132774074e808c82c7) + +Resolves: #1735787 +--- + src/core/service.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 8342c131c8..24f167572a 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -3310,7 +3310,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + "Control process exited, code=%s status=%i", + sigchld_code_to_string(code), status); + +- if (s->result == SERVICE_SUCCESS) ++ if (s->state != SERVICE_RELOAD && s->result == SERVICE_SUCCESS) + s->result = f; + + if (s->control_command && diff --git a/SOURCES/0217-man-document-systemd-analyze-security.patch b/SOURCES/0217-man-document-systemd-analyze-security.patch new file mode 100644 index 0000000..07ec674 --- /dev/null +++ b/SOURCES/0217-man-document-systemd-analyze-security.patch @@ -0,0 +1,59 @@ +From d11fdacaf3c804b60dfe8371062f34ac2b624ac9 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 13 Sep 2019 09:23:32 +0200 +Subject: [PATCH] man: document systemd-analyze security + +(cherry-picked from commit ee93c1e664a7bbc59f1578e285c871999507b14d) + +Resolves: #1750343 +--- + man/systemd-analyze.xml | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml +index 7aa10fc68e..f3b595880f 100644 +--- a/man/systemd-analyze.xml ++++ b/man/systemd-analyze.xml +@@ -106,6 +106,12 @@ + service-watchdogs + BOOL + ++ ++ systemd-analyze ++ OPTIONS ++ security ++ UNIT ++ + + + +@@ -253,6 +259,29 @@ NAutoVTs=8 + systemd.service5. + The hardware watchdog is not affected by this setting. + ++ systemd-analyze security analyzes the security and sandboxing settings of one or more ++ specified service units. If at least one unit name is specified the security settings of the specified service ++ units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded, ++ long-running service units are inspected and a terse table with results shown. The command checks for various ++ security-related service settings, assigning each a numeric "exposure level" value, depending on how important a ++ setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range ++ 0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied ++ sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only ++ analyzes the per-service security features systemd itself implements. This means that any additional security ++ mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should ++ not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the ++ service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels ++ do indicate however that most likely the service might benefit from additional settings applied to them. Please ++ note that many of the security and sandboxing settings individually can be circumvented — unless combined with ++ others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing ++ options can be undone by the service code itself. Due to that is essential that each service uses the most ++ comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these ++ combinations and relationships between the settings, but not all. Also note that the security and sandboxing ++ settings analyzed here only apply to the operations executed by the service code itself. If a service has access to ++ an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same ++ restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is ++ not validated too. ++ + If no command is passed, systemd-analyze + time is implied. + diff --git a/SOURCES/0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch b/SOURCES/0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch new file mode 100644 index 0000000..4cfc715 --- /dev/null +++ b/SOURCES/0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch @@ -0,0 +1,772 @@ +From a2e00522971897909db2a81b4daf10e5700f453e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 15 Mar 2019 10:13:55 +0100 +Subject: [PATCH] man: reorder and add examples to systemd-analyze(1) + +The number of verbs supported by systemd-analyze has grown quite a bit, and the +man page has become an unreadable wall of text. Let's put each verb in a +separate subsection, grouping similar verbs together, and add a lot of examples +to guide the user. + +(cherry picked from commit d323a99001c1f7625e8ac902e18deb514a4ca18d) + +Related: #1750343 +--- + man/systemd-analyze.xml | 678 +++++++++++++++++++++++++--------------- + 1 file changed, 429 insertions(+), 249 deletions(-) + +diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml +index f3b595880f..7c873cbdd1 100644 +--- a/man/systemd-analyze.xml ++++ b/man/systemd-analyze.xml +@@ -41,46 +41,50 @@ + critical-chain + UNIT + ++ + + systemd-analyze + OPTIONS +- plot +- > file.svg ++ log-level ++ LEVEL + + + systemd-analyze + OPTIONS +- dot +- PATTERN +- > file.dot ++ log-target ++ TARGET + + + systemd-analyze + OPTIONS +- dump ++ service-watchdogs ++ BOOL + ++ + + systemd-analyze + OPTIONS +- cat-config +- NAME|PATH ++ dump + ++ + + systemd-analyze + OPTIONS +- unit-paths ++ plot ++ >file.svg + + + systemd-analyze + OPTIONS +- log-level +- LEVEL ++ dot ++ PATTERN ++ >file.dot + ++ + + systemd-analyze + OPTIONS +- log-target +- TARGET ++ unit-paths + + + systemd-analyze +@@ -91,20 +95,20 @@ + + systemd-analyze + OPTIONS +- verify +- FILES ++ calendar ++ SPECS + + + systemd-analyze + OPTIONS +- calendar +- SPECS ++ timespan ++ SPAN + + + systemd-analyze + OPTIONS +- service-watchdogs +- BOOL ++ cat-config ++ NAME|PATH + + + systemd-analyze +@@ -123,73 +127,299 @@ + verify the correctness of unit files. It is also used to access + special functions useful for advanced system manager debugging. + +- systemd-analyze time prints the time +- spent in the kernel before userspace has been reached, the time +- spent in the initial RAM disk (initrd) before normal system +- userspace has been reached, and the time normal system userspace +- took to initialize. Note that these measurements simply measure +- the time passed up to the point where all system services have +- been spawned, but not necessarily until they fully finished +- initialization or the disk is idle. +- +- systemd-analyze blame prints a list of +- all running units, ordered by the time they took to initialize. +- This information may be used to optimize boot-up times. Note that +- the output might be misleading as the initialization of one +- service might be slow simply because it waits for the +- initialization of another service to complete. +- Also note: systemd-analyze blame doesn't display +- results for services with Type=simple, +- because systemd considers such services to be started immediately, +- hence no measurement of the initialization delays can be done. +- +- systemd-analyze critical-chain +- [UNIT…] prints a tree of +- the time-critical chain of units (for each of the specified +- UNITs or for the default target +- otherwise). The time after the unit is active or started is +- printed after the "@" character. The time the unit takes to start +- is printed after the "+" character. Note that the output might be +- misleading as the initialization of one service might depend on +- socket activation and because of the parallel execution of +- units. +- +- systemd-analyze plot prints an SVG +- graphic detailing which system services have been started at what +- time, highlighting the time they spent on initialization. +- +- systemd-analyze dot generates textual +- dependency graph description in dot format for further processing +- with the GraphViz +- dot1 +- tool. Use a command line like systemd-analyze dot | dot +- -Tsvg > systemd.svg to generate a graphical dependency +- tree. Unless or +- is passed, the generated graph will +- show both ordering and requirement dependencies. Optional pattern +- globbing style specifications (e.g. *.target) +- may be given at the end. A unit dependency is included in the +- graph if any of these patterns match either the origin or +- destination node. +- +- systemd-analyze dump outputs a (usually +- very long) human-readable serialization of the complete server +- state. Its format is subject to change without notice and should +- not be parsed by applications. +- +- systemd-analyze cat-config is similar +- to systemctl cat, but operates on config files. +- It will copy the contents of a config file and any drop-ins to standard +- output, using the usual systemd set of directories and rules for +- precedence. Each argument must be either an absolute path including +- the prefix (such as /etc/systemd/logind.conf or +- /usr/lib/systemd/logind.conf), or a name +- relative to the prefix (such as systemd/logind.conf). +- ++ If no command is passed, systemd-analyze ++ time is implied. ++ ++ ++ <command>systemd-analyze time</command> ++ ++ This command prints the time spent in the kernel before userspace has been reached, the time ++ spent in the initial RAM disk (initrd) before normal system userspace has been reached, and the time ++ normal system userspace took to initialize. Note that these measurements simply measure the time passed ++ up to the point where all system services have been spawned, but not necessarily until they fully ++ finished initialization or the disk is idle. ++ ++ ++ <command>Show how long the boot took</command> ++ ++ # in a container ++$ systemd-analyze time ++Startup finished in 296ms (userspace) ++multi-user.target reached after 275ms in userspace ++ ++# on a real machine ++$ systemd-analyze time ++Startup finished in 2.584s (kernel) + 19.176s (initrd) + 47.847s (userspace) = 1min 9.608s ++multi-user.target reached after 47.820s in userspace ++ ++ ++ ++ ++ ++ <command>systemd-analyze blame</command> ++ ++ This command prints a list of all running units, ordered by the time they took to initialize. ++ This information may be used to optimize boot-up times. Note that the output might be misleading as the ++ initialization of one service might be slow simply because it waits for the initialization of another ++ service to complete. Also note: systemd-analyze blame doesn't display results for ++ services with Type=simple, because systemd considers such services to be started ++ immediately, hence no measurement of the initialization delays can be done. ++ ++ ++ <command>Show which units took the most time during boot</command> ++ ++ $ systemd-analyze blame ++ 32.875s pmlogger.service ++ 20.905s systemd-networkd-wait-online.service ++ 13.299s dev-vda1.device ++ ... ++ 23ms sysroot.mount ++ 11ms initrd-udevadm-cleanup-db.service ++ 3ms sys-kernel-config.mount ++ ++ ++ ++ ++ ++ <command>systemd-analyze critical-chain <optional><replaceable>UNIT</replaceable>...</optional></command> ++ ++ This command prints a tree of the time-critical chain of units (for each of the specified ++ UNITs or for the default target otherwise). The time after the unit is ++ active or started is printed after the "@" character. The time the unit takes to start is printed after ++ the "+" character. Note that the output might be misleading as the initialization of services might ++ depend on socket activation and because of the parallel execution of units. ++ ++ ++ <command>systemd-analyze time</command> ++ ++ $ systemd-analyze critical-chain ++multi-user.target @47.820s ++└─pmie.service @35.968s +548ms ++ └─pmcd.service @33.715s +2.247s ++ └─network-online.target @33.712s ++ └─systemd-networkd-wait-online.service @12.804s +20.905s ++ └─systemd-networkd.service @11.109s +1.690s ++ └─systemd-udevd.service @9.201s +1.904s ++ └─systemd-tmpfiles-setup-dev.service @7.306s +1.776s ++ └─kmod-static-nodes.service @6.976s +177ms ++ └─systemd-journald.socket ++ └─system.slice ++ └─-.slice ++ ++ ++ ++ ++ ++ <command>systemd-analyze log-level [<replaceable>LEVEL</replaceable>]</command> ++ ++ systemd-analyze log-level prints the current log level of the ++ systemd daemon. If an optional argument LEVEL is ++ provided, then the command changes the current log level of the systemd daemon to ++ LEVEL (accepts the same values as described in ++ systemd1). ++ ++ ++ ++ <command>systemd-analyze log-target [<replaceable>TARGET</replaceable>]</command> ++ ++ systemd-analyze log-target prints the current log target of the ++ systemd daemon. If an optional argument TARGET is ++ provided, then the command changes the current log target of the systemd daemon to ++ TARGET (accepts the same values as , described ++ in systemd1). ++ ++ ++ ++ <command>systemd-analyze service-watchdogs [yes|no]</command> ++ ++ systemd-analyze service-watchdogs prints the current state of service runtime ++ watchdogs of the systemd daemon. If an optional boolean argument is provided, then ++ globally enables or disables the service runtime watchdogs () and ++ emergency actions (e.g. or ); see ++ systemd.service5. ++ The hardware watchdog is not affected by this setting. ++ ++ ++ ++ <command>systemd-analyze dump</command> ++ ++ This command outputs a (usually very long) human-readable serialization of the complete server ++ state. Its format is subject to change without notice and should not be parsed by applications. ++ ++ ++ Show the internal state of user manager ++ ++ $ systemd-analyze --user dump ++Timestamp userspace: Thu 2019-03-14 23:28:07 CET ++Timestamp finish: Thu 2019-03-14 23:28:07 CET ++Timestamp generators-start: Thu 2019-03-14 23:28:07 CET ++Timestamp generators-finish: Thu 2019-03-14 23:28:07 CET ++Timestamp units-load-start: Thu 2019-03-14 23:28:07 CET ++Timestamp units-load-finish: Thu 2019-03-14 23:28:07 CET ++-> Unit proc-timer_list.mount: ++ Description: /proc/timer_list ++ ... ++-> Unit default.target: ++ Description: Main user target ++... ++ ++ ++ ++ ++ ++ <command>systemd-analyze plot</command> ++ ++ This command prints an SVG graphic detailing which system services have been started at what ++ time, highlighting the time they spent on initialization. ++ ++ ++ <command>Plot a bootchart</command> ++ ++ $ systemd-analyze plot >bootup.svg ++$ eog bootup.svg& ++ ++ ++ ++ ++ ++ <command>systemd-analyze dot [<replaceable>pattern</replaceable>...]</command> ++ ++ This command generates textual dependency graph description in dot format for further processing ++ with the GraphViz ++ dot1 ++ tool. Use a command line like systemd-analyze dot | dot -Tsvg >systemd.svg to ++ generate a graphical dependency tree. Unless or is ++ passed, the generated graph will show both ordering and requirement dependencies. Optional pattern ++ globbing style specifications (e.g. *.target) may be given at the end. A unit ++ dependency is included in the graph if any of these patterns match either the origin or destination ++ node. ++ ++ ++ Plot all dependencies of any unit whose name starts with <literal>avahi-daemon</literal> ++ ++ ++ $ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg >avahi.svg ++$ eog avahi.svg ++ ++ ++ ++ Plot the dependencies between all known target units + +- +- Showing logind configuration +- $ systemd-analyze cat-config systemd/logind.conf ++ $ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' \ ++ | dot -Tsvg >targets.svg ++$ eog targets.svg ++ ++ ++ ++ ++ <command>systemd-analyze unit-paths</command> ++ ++ This command outputs a list of all directories from which unit files, .d ++ overrides, and .wants, .requires symlinks may be ++ loaded. Combine with to retrieve the list for the user manager instance, and ++ for the global configuration of user manager instances. ++ ++ ++ <command>Show all paths for generated units</command> ++ ++ $ systemd-analyze unit-paths | grep '^/run' ++/run/systemd/system.control ++/run/systemd/transient ++/run/systemd/generator.early ++/run/systemd/system ++/run/systemd/system.attached ++/run/systemd/generator ++/run/systemd/generator.late ++ ++ ++ ++ Note that this verb prints the list that is compiled into systemd-analyze ++ itself, and does not comunicate with the running manager. Use ++ systemctl [--user] [--global] show -p UnitPath --value ++ to retrieve the actual list that the manager uses, with any empty directories omitted. ++ ++ ++ ++ <command>systemd-analyze syscall-filter <optional><replaceable>SET</replaceable>...</optional></command> ++ ++ This command will list system calls contained in the specified system call set ++ SET, or all known sets if no sets are specified. Argument ++ SET must include the @ prefix. ++ ++ ++ ++ <command>systemd-analyze calendar <replaceable>EXPRESSION</replaceable>...</command> ++ ++ This command will parse and normalize repetitive calendar time events, and will calculate when ++ they elapse next. This takes the same input as the OnCalendar= setting in ++ systemd.timer5, ++ following the syntax described in ++ systemd.time7. By ++ default, only the next time the calendar expression will elapse is shown; use ++ to show the specified number of next times the expression ++ elapses. ++ ++ ++ Show leap days in the near future ++ ++ $ systemd-analyze calendar --iterations=5 '*-2-29 0:0:0' ++ Original form: *-2-29 0:0:0 ++Normalized form: *-02-29 00:00:00 ++ Next elapse: Sat 2020-02-29 00:00:00 UTC ++ From now: 11 months 15 days left ++ Iter. #2: Thu 2024-02-29 00:00:00 UTC ++ From now: 4 years 11 months left ++ Iter. #3: Tue 2028-02-29 00:00:00 UTC ++ From now: 8 years 11 months left ++ Iter. #4: Sun 2032-02-29 00:00:00 UTC ++ From now: 12 years 11 months left ++ Iter. #5: Fri 2036-02-29 00:00:00 UTC ++ From now: 16 years 11 months left ++ ++ ++ ++ ++ ++ <command>systemd-analyze timespan <replaceable>EXPRESSION</replaceable>...</command> ++ ++ This command parses a time span and outputs the normalized form and the equivalent value in ++ microseconds. The time span should adhere to the same syntax documented in ++ systemd.time7. ++ Values without associated magnitudes are parsed as seconds. ++ ++ ++ Show parsing of timespans ++ ++ $ systemd-analyze timespan 1s 300s '1year 0.000001s' ++Original: 1s ++ μs: 1000000 ++ Human: 1s ++ ++Original: 300s ++ μs: 300000000 ++ Human: 5min ++ ++Original: 1year 0.000001s ++ μs: 31557600000001 ++ Human: 1y 1us ++ ++ ++ ++ ++ ++ <command>systemd-analyze cat-config</command> ++ <replaceable>NAME</replaceable>|<replaceable>PATH</replaceable>... ++ ++ This command is similar to systemctl cat, but operates on config files. It ++ will copy the contents of a config file and any drop-ins to standard output, using the usual systemd ++ set of directories and rules for precedence. Each argument must be either an absolute path including ++ the prefix (such as /etc/systemd/logind.conf or ++ /usr/lib/systemd/logind.conf), or a name relative to the prefix (such as ++ systemd/logind.conf). ++ ++ ++ Showing logind configuration ++ $ systemd-analyze cat-config systemd/logind.conf + # /etc/systemd/logind.conf + ... + [Login] +@@ -201,90 +431,122 @@ NAutoVTs=8 + + # /etc/systemd/logind.conf.d/50-override.conf + ... some administrator override +- +- +- +- systemd-analyze unit-paths outputs a list of all +- directories from which unit files, .d overrides, and +- .wants, .requires symlinks may be +- loaded. Combine with to retrieve the list for the user +- manager instance, and for the global configuration of +- user manager instances. Note that this verb prints the list that is compiled into +- systemd-analyze itself, and does not comunicate with the +- running manager. Use +- systemctl [--user] [--global] show -p UnitPath --value +- to retrieve the actual list that the manager uses, with any empty directories +- omitted. +- +- systemd-analyze log-level +- prints the current log level of the systemd daemon. +- If an optional argument LEVEL is provided, then the command changes the current log +- level of the systemd daemon to LEVEL (accepts the same values as +- described in +- systemd1). +- +- systemd-analyze log-target +- prints the current log target of the systemd daemon. +- If an optional argument TARGET is provided, then the command changes the current log +- target of the systemd daemon to TARGET (accepts the same values as +- , described in +- systemd1). +- +- systemd-analyze syscall-filter SET… +- will list system calls contained in the specified system call set SET, +- or all known sets if no sets are specified. Argument SET must include +- the @ prefix. +- +- systemd-analyze verify will load unit files and print +- warnings if any errors are detected. Files specified on the command line will be +- loaded, but also any other units referenced by them. The full unit search path is +- formed by combining the directories for all command line arguments, and the usual unit +- load paths (variable $SYSTEMD_UNIT_PATH is supported, and may be +- used to replace or augment the compiled in set of unit load paths; see +- systemd.unit5). +- All units files present in the directories containing the command line arguments will +- be used in preference to the other paths. +- +- systemd-analyze calendar will parse and normalize repetitive calendar time events, and +- will calculate when they will elapse next. This takes the same input as the OnCalendar= setting +- in systemd.timer5, following the +- syntax described in +- systemd.time7. +- +- systemd-analyze service-watchdogs +- prints the current state of service runtime watchdogs of the systemd daemon. +- If an optional boolean argument is provided, then globally enables or disables the service +- runtime watchdogs () and emergency actions (e.g. +- or ); see +- systemd.service5. +- The hardware watchdog is not affected by this setting. +- +- systemd-analyze security analyzes the security and sandboxing settings of one or more +- specified service units. If at least one unit name is specified the security settings of the specified service +- units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded, +- long-running service units are inspected and a terse table with results shown. The command checks for various +- security-related service settings, assigning each a numeric "exposure level" value, depending on how important a +- setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range +- 0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied +- sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only +- analyzes the per-service security features systemd itself implements. This means that any additional security +- mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should +- not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the +- service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels +- do indicate however that most likely the service might benefit from additional settings applied to them. Please +- note that many of the security and sandboxing settings individually can be circumvented — unless combined with +- others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing +- options can be undone by the service code itself. Due to that is essential that each service uses the most +- comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these +- combinations and relationships between the settings, but not all. Also note that the security and sandboxing +- settings analyzed here only apply to the operations executed by the service code itself. If a service has access to +- an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same +- restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is +- not validated too. ++ ++ ++ + +- If no command is passed, systemd-analyze +- time is implied. ++ ++ <command>systemd-analyze verify <replaceable>FILE</replaceable>...</command> ++ ++ This command will load unit files and print warnings if any errors are detected. Files specified ++ on the command line will be loaded, but also any other units referenced by them. The full unit search ++ path is formed by combining the directories for all command line arguments, and the usual unit load ++ paths (variable $SYSTEMD_UNIT_PATH is supported, and may be used to replace or ++ augment the compiled in set of unit load paths; see ++ systemd.unit5). All ++ units files present in the directories containing the command line arguments will be used in preference ++ to the other paths. ++ ++ The following errors are currently detected: ++ ++ unknown sections and directives, ++ ++ missing dependencies which are required to start the given unit, ++ ++ man pages listed in Documentation= which are not found in the ++ system, ++ ++ commands listed in ExecStart= and similar which are not found in ++ the system or not executable. ++ + ++ ++ Misspelt directives ++ ++ $ cat ./user.slice ++[Unit] ++WhatIsThis=11 ++Documentation=man:nosuchfile(1) ++Requires=different.service ++ ++[Service] ++Description=x ++ ++$ systemd-analyze verify ./user.slice ++[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit' ++[./user.slice:13] Unknown section 'Service'. Ignoring. ++Error: org.freedesktop.systemd1.LoadFailed: ++ Unit different.service failed to load: ++ No such file or directory. ++Failed to create user.slice/start: Invalid argument ++user.slice: man nosuchfile(1) command failed with code 16 ++ ++ ++ ++ ++ Missing service units ++ ++ $ tail ./a.socket ./b.socket ++==> ./a.socket <== ++[Socket] ++ListenStream=100 ++ ++==> ./b.socket <== ++[Socket] ++ListenStream=100 ++Accept=yes ++ ++$ systemd-analyze verify ./a.socket ./b.socket ++Service a.service not loaded, a.socket cannot be started. ++Service b@0.service not loaded, b.socket cannot be started. ++ ++ ++ ++ ++ ++ <command>systemd-analyze security <optional><replaceable>UNIT</replaceable>...</optional></command> ++ ++ This command analyzes the security and sandboxing settings of one or more specified service ++ units. If at least one unit name is specified the security settings of the specified service units are ++ inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded, ++ long-running service units are inspected and a terse table with results shown. The command checks for ++ various security-related service settings, assigning each a numeric "exposure level" value, depending ++ on how important a setting is. It then calculates an overall exposure level for the whole unit, which ++ is an estimation in the range 0.0…10.0 indicating how exposed a service is security-wise. High exposure ++ levels indicate very little applied sandboxing. Low exposure levels indicate tight sandboxing and ++ strongest security restrictions. Note that this only analyzes the per-service security features systemd ++ itself implements. This means that any additional security mechanisms applied by the service code ++ itself are not accounted for. The exposure level determined this way should not be misunderstood: a ++ high exposure level neither means that there is no effective sandboxing applied by the service code ++ itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels do ++ indicate however that most likely the service might benefit from additional settings applied to ++ them. ++ ++ Please note that many of the security and sandboxing settings individually can be circumvented — ++ unless combined with others. For example, if a service retains the privilege to establish or undo mount ++ points many of the sandboxing options can be undone by the service code itself. Due to that is ++ essential that each service uses the most comprehensive and strict sandboxing and security settings ++ possible. The tool will take into account some of these combinations and relationships between the ++ settings, but not all. Also note that the security and sandboxing settings analyzed here only apply to ++ the operations executed by the service code itself. If a service has access to an IPC system (such as ++ D-Bus) it might request operations from other services that are not subject to the same ++ restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access ++ policy is not validated too. ++ ++ ++ Analyze <filename noindex="true">systemd-logind.service</filename> ++ ++ $ systemd-analyze security --no-pager systemd-logind.service ++ NAME DESCRIPTION EXPOSURE ++✗ PrivateNetwork= Service has access to the host's network 0.5 ++✗ User=/DynamicUser= Service runs as root user 0.4 ++✗ DeviceAllow= Service has no device ACL 0.2 ++✓ IPAddressDeny= Service blocks all IP address ranges ++... ++→ Overall exposure level for systemd-logind.service: 4.1 OK 🙂 ++ ++ ++ + + + +@@ -408,88 +670,6 @@ NAutoVTs=8 + otherwise. + + +- +- Examples for <command>dot</command> +- +- +- Plots all dependencies of any unit whose name starts with +- <literal>avahi-daemon</literal> +- +- $ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg > avahi.svg +-$ eog avahi.svg +- +- +- +- Plots the dependencies between all known target units +- +- $ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' | dot -Tsvg > targets.svg +-$ eog targets.svg +- +- +- +- +- Examples for <command>verify</command> +- +- The following errors are currently detected: +- +- unknown sections and directives, +- +- +- missing dependencies which are required to start +- the given unit, +- +- man pages listed in +- Documentation= which are not found in the +- system, +- +- commands listed in ExecStart= +- and similar which are not found in the system or not +- executable. +- +- +- +- Misspelt directives +- +- $ cat ./user.slice +-[Unit] +-WhatIsThis=11 +-Documentation=man:nosuchfile(1) +-Requires=different.service +- +-[Service] +-Description=x +- +-$ systemd-analyze verify ./user.slice +-[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit' +-[./user.slice:13] Unknown section 'Service'. Ignoring. +-Error: org.freedesktop.systemd1.LoadFailed: +- Unit different.service failed to load: +- No such file or directory. +-Failed to create user.slice/start: Invalid argument +-user.slice: man nosuchfile(1) command failed with code 16 +- +- +- +- +- Missing service units +- +- $ tail ./a.socket ./b.socket +-==> ./a.socket <== +-[Socket] +-ListenStream=100 +- +-==> ./b.socket <== +-[Socket] +-ListenStream=100 +-Accept=yes +- +-$ systemd-analyze verify ./a.socket ./b.socket +-Service a.service not loaded, a.socket cannot be started. +-Service b@0.service not loaded, b.socket cannot be started. +- +- +- +- + + + diff --git a/SOURCES/0219-travis-move-to-CentOS-8-docker-images.patch b/SOURCES/0219-travis-move-to-CentOS-8-docker-images.patch new file mode 100644 index 0000000..f5ba536 --- /dev/null +++ b/SOURCES/0219-travis-move-to-CentOS-8-docker-images.patch @@ -0,0 +1,132 @@ +From ac7db0c5b48f1090f77dbcfa0a1e0dc08d5c471e Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 14 Oct 2019 15:26:48 +0200 +Subject: [PATCH] travis: move to CentOS 8 docker images + +As the CentOS 8 Docker images is finally out, we can use it and drop the +plethora of workarounds we had to implement to compile RHEL8 systemd on +CentOS 7. + +Resolves: #1761519 +--- + .travis.yml | 22 ++++++++++------------ + ci/travis-centos-rhel8.sh | 32 +++++++++----------------------- + 2 files changed, 19 insertions(+), 35 deletions(-) + +diff --git a/.travis.yml b/.travis.yml +index 0010da5784..70c60cf24e 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -9,42 +9,40 @@ env: + + jobs: + include: +- - name: CentOS 7 ++ - name: CentOS 8 + language: bash + env: +- - CENTOS_RELEASE="centos7" ++ - CENTOS_RELEASE="centos8" + - CONT_NAME="systemd-centos-$CENTOS_RELEASE" + - DOCKER_EXEC="docker exec -ti $CONT_NAME" + before_install: + - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce + - docker --version + install: +- - if [ -f meson.build ]; then RHEL_VERSION=rhel8; else RHEL_VERSION=rhel7; fi +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh SETUP ++ - $CI_ROOT/travis-centos-rhel8.sh SETUP + script: + - set -e + # Build systemd +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh RUN ++ - $CI_ROOT/travis-centos-rhel8.sh RUN + - set +e + after_script: +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh CLEANUP ++ - $CI_ROOT/travis-centos-rhel8.sh CLEANUP + +- - name: CentOS 7 (ASan+UBSan) ++ - name: CentOS 8 (ASan+UBSan) + language: bash + env: +- - CENTOS_RELEASE="centos7" ++ - CENTOS_RELEASE="centos8" + - CONT_NAME="systemd-centos-$CENTOS_RELEASE" + - DOCKER_EXEC="docker exec -ti $CONT_NAME" + before_install: + - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce + - docker --version + install: +- - if [ -f meson.build ]; then RHEL_VERSION=rhel8; else RHEL_VERSION=rhel7; fi +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh SETUP ++ - $CI_ROOT/travis-centos-rhel8.sh SETUP + script: + - set -e + # Build systemd +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh RUN_ASAN ++ - $CI_ROOT/travis-centos-rhel8.sh RUN_ASAN + - set +e + after_script: +- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh CLEANUP ++ - $CI_ROOT/travis-centos-rhel8.sh CLEANUP +diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh +index c3d1018682..ade44a0413 100755 +--- a/ci/travis-centos-rhel8.sh ++++ b/ci/travis-centos-rhel8.sh +@@ -15,10 +15,7 @@ CONT_NAME="${CONT_NAME:-centos-$CENTOS_RELEASE-$RANDOM}" + DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}" + DOCKER_RUN="${DOCKER_RUN:-docker run}" + REPO_ROOT="${REPO_ROOT:-$PWD}" +-ADDITIONAL_DEPS=(systemd-ci-environment libidn2-devel python-lxml python36 ninja-build libasan net-tools strace nc busybox e2fsprogs quota dnsmasq) +-# Repo with additional depencencies to compile newer systemd on CentOS 7 +-COPR_REPO="https://copr.fedorainfracloud.org/coprs/mrc0mmand/systemd-centos-ci/repo/epel-7/mrc0mmand-systemd-centos-ci-epel-7.repo" +-COPR_REPO_PATH="/etc/yum.repos.d/${COPR_REPO##*/}" ++ADDITIONAL_DEPS=(libasan libubsan net-tools strace nc e2fsprogs quota dnsmasq) + # RHEL8 options + CONFIGURE_OPTS=( + -Dsysvinit-path=/etc/rc.d/init.d +@@ -95,18 +92,14 @@ for phase in "${PHASES[@]}"; do + -dit --net=host centos:$CENTOS_RELEASE /sbin/init + # Beautiful workaround for Fedora's version of Docker + sleep 1 +- $DOCKER_EXEC yum makecache +- $DOCKER_EXEC curl "$COPR_REPO" -o "$COPR_REPO_PATH" +- $DOCKER_EXEC yum -q -y install epel-release yum-utils +- $DOCKER_EXEC yum-config-manager -q --enable epel +- $DOCKER_EXEC yum -y upgrade +- # Install necessary build/test requirements +- $DOCKER_EXEC yum -y install "${ADDITIONAL_DEPS[@]}" +- $DOCKER_EXEC python3.6 -m ensurepip +- $DOCKER_EXEC python3.6 -m pip install meson +- # Create necessary symlinks +- $DOCKER_EXEC ln --force -s /usr/bin/python3.6 /usr/bin/python3 +- $DOCKER_EXEC ln --force -s /usr/bin/ninja-build /usr/bin/ninja ++ $DOCKER_EXEC dnf makecache ++ # Install and enable EPEL ++ $DOCKER_EXEC dnf -q -y install epel-release dnf-utils "${ADDITIONAL_DEPS[@]}" ++ $DOCKER_EXEC dnf config-manager -q --enable epel ++ # Upgrade the container to get the most recent environment ++ $DOCKER_EXEC dnf -y upgrade ++ # Install systemd's build dependencies ++ $DOCKER_EXEC dnf -q -y --enablerepo "PowerTools" builddep systemd + ;; + RUN) + info "Run phase" +@@ -117,16 +110,9 @@ for phase in "${PHASES[@]}"; do + # unexpected fails due to incompatibilities with older systemd + $DOCKER_EXEC ninja -C build install + docker restart $CONT_NAME +- # "Mask" the udev-test.pl, as it requires newer version of systemd-detect-virt +- # and it's pointless to run it on a VM in a Docker container... +- echo -ne "#!/usr/bin/perl\nexit(0);\n" > "test/udev-test.pl" + $DOCKER_EXEC ninja -C build test + ;; + RUN_ASAN|RUN_CLANG_ASAN) +- # Let's install newer gcc for proper ASan/UBSan support +- $DOCKER_EXEC yum -y install centos-release-scl +- $DOCKER_EXEC yum -y install devtoolset-8 devtoolset-8-libasan-devel libasan5 devtoolset-8-libubsan-devel libubsan1 +- $DOCKER_EXEC bash -c "echo 'source scl_source enable devtoolset-8' >> /root/.bashrc" + # Note to my future frustrated self: docker exec runs the given command + # as sh -c 'command' - which means both .bash_profile and .bashrc will + # be ignored. That's because .bash_profile is sourced for LOGIN shells (i.e. diff --git a/SOURCES/0220-travis-drop-SCL-remains.patch b/SOURCES/0220-travis-drop-SCL-remains.patch new file mode 100644 index 0000000..30d5378 --- /dev/null +++ b/SOURCES/0220-travis-drop-SCL-remains.patch @@ -0,0 +1,50 @@ +From 5b14988845b591f6fa2fc1e032618fe882827f4a Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 14 Oct 2019 16:22:51 +0200 +Subject: [PATCH] travis: drop SCL remains + +The `bash -ic` wrapper existed solely to make SCL work as expected + +Resolves: #1761519 +--- + ci/travis-centos-rhel8.sh | 16 +++------------- + 1 file changed, 3 insertions(+), 13 deletions(-) + +diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh +index ade44a0413..da131c726b 100755 +--- a/ci/travis-centos-rhel8.sh ++++ b/ci/travis-centos-rhel8.sh +@@ -113,22 +113,12 @@ for phase in "${PHASES[@]}"; do + $DOCKER_EXEC ninja -C build test + ;; + RUN_ASAN|RUN_CLANG_ASAN) +- # Note to my future frustrated self: docker exec runs the given command +- # as sh -c 'command' - which means both .bash_profile and .bashrc will +- # be ignored. That's because .bash_profile is sourced for LOGIN shells (i.e. +- # sh -l), whereas .bashrc is sourced for NON-LOGIN INTERACTIVE shells +- # (i.e. sh -i). +- # As the default docker exec command lacks either of those options, +- # we need to use a wrapper command which runs the wanted command +- # under an explicit bash -i, so the SCL source above works properly. +- docker exec -it $CONT_NAME bash -ic 'gcc --version' +- + if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then + ENV_VARS="-e CC=clang -e CXX=clang++" + MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764 + fi +- docker exec $ENV_VARS -it $CONT_NAME bash -ic "meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]}" +- docker exec -it $CONT_NAME bash -ic 'ninja -v -C build' ++ docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]} ++ docker exec -it $CONT_NAME ninja -v -C build + + # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb. + travis_wait docker exec --interactive=false \ +@@ -136,7 +126,7 @@ for phase in "${PHASES[@]}"; do + -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \ + -e "TRAVIS=$TRAVIS" \ + -t $CONT_NAME \ +- bash -ic 'meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs' ++ meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs + ;; + CLEANUP) + info "Cleanup phase" diff --git a/SOURCES/0221-syslog-fix-segfault-in-syslog_parse_priority.patch b/SOURCES/0221-syslog-fix-segfault-in-syslog_parse_priority.patch new file mode 100644 index 0000000..97f64e0 --- /dev/null +++ b/SOURCES/0221-syslog-fix-segfault-in-syslog_parse_priority.patch @@ -0,0 +1,110 @@ +From 8bd791fb3a8e85063e297204bdef8004aacd22b1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 8 Aug 2018 18:27:15 +0900 +Subject: [PATCH] syslog: fix segfault in syslog_parse_priority() + +(cherry picked from commit a5ee33b951cfa22db53d0274c9c6c0d9d4dae39d) + +Resolves: #1761519 +--- + src/basic/syslog-util.c | 20 +++++++++++--------- + src/journal/test-journal-syslog.c | 20 ++++++++++++++++++++ + 2 files changed, 31 insertions(+), 9 deletions(-) + +diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c +index 21461fa581..fe129482f3 100644 +--- a/src/basic/syslog-util.c ++++ b/src/basic/syslog-util.c +@@ -10,7 +10,8 @@ + + int syslog_parse_priority(const char **p, int *priority, bool with_facility) { + int a = 0, b = 0, c = 0; +- int k; ++ const char *end; ++ size_t k; + + assert(p); + assert(*p); +@@ -19,21 +20,22 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility) { + if ((*p)[0] != '<') + return 0; + +- if (!strchr(*p, '>')) ++ end = strchr(*p, '>'); ++ if (!end) + return 0; + +- if ((*p)[2] == '>') { ++ k = end - *p; ++ assert(k > 0); ++ ++ if (k == 2) + c = undecchar((*p)[1]); +- k = 3; +- } else if ((*p)[3] == '>') { ++ else if (k == 3) { + b = undecchar((*p)[1]); + c = undecchar((*p)[2]); +- k = 4; +- } else if ((*p)[4] == '>') { ++ } else if (k == 4) { + a = undecchar((*p)[1]); + b = undecchar((*p)[2]); + c = undecchar((*p)[3]); +- k = 5; + } else + return 0; + +@@ -46,7 +48,7 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility) { + else + *priority = (*priority & LOG_FACMASK) | c; + +- *p += k; ++ *p += k + 1; + return 1; + } + +diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c +index 7294cde032..120477cc9f 100644 +--- a/src/journal/test-journal-syslog.c ++++ b/src/journal/test-journal-syslog.c +@@ -4,6 +4,7 @@ + #include "journald-syslog.h" + #include "macro.h" + #include "string-util.h" ++#include "syslog-util.h" + + static void test_syslog_parse_identifier(const char *str, + const char *ident, const char *pid, const char *rest, int ret) { +@@ -19,6 +20,17 @@ static void test_syslog_parse_identifier(const char *str, + assert_se(streq(buf, rest)); + } + ++static void test_syslog_parse_priority(const char *str, int priority, int ret) { ++ const char *buf = str; ++ int priority2, ret2; ++ ++ ret2 = syslog_parse_priority(&buf, &priority2, false); ++ ++ assert_se(ret == ret2); ++ if (ret2 == 1) ++ assert_se(priority == priority2); ++} ++ + int main(void) { + test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11); + test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6); +@@ -33,5 +45,13 @@ int main(void) { + test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6); + test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0); + ++ test_syslog_parse_priority("<>", 0, 0); ++ test_syslog_parse_priority("<>aaa", 0, 0); ++ test_syslog_parse_priority("", 0, 0); ++ test_syslog_parse_priority("aaa", 0, 0); ++ test_syslog_parse_priority(" ", 0, 0); ++ test_syslog_parse_priority(" aaa", 0, 0); ++ /* TODO: add test cases of valid priorities */ ++ + return 0; + } diff --git a/SOURCES/0222-sd-bus-make-strict-asan-shut-up.patch b/SOURCES/0222-sd-bus-make-strict-asan-shut-up.patch new file mode 100644 index 0000000..bfe310a --- /dev/null +++ b/SOURCES/0222-sd-bus-make-strict-asan-shut-up.patch @@ -0,0 +1,45 @@ +From fbe5fa22f5b99d4e444db54aadb661e9c932eb6c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 16 Nov 2018 13:00:40 +0100 +Subject: [PATCH] sd-bus: make strict asan shut up + +asan doesn't like it if we use strndup() (i.e. a string function) on a +non-NULL terminated buffer (i.e. something that isn't really a string). + +Let's hence use memdup_suffix0() instead of strndup(), which is more +appropriate for binary data that is to become a string. + +Fixes: #10385 +(cherry picked from commit ac0a94f7438b49a0890d9806db1fa211a5bca10a) + +Resolves: #1761519 +--- + src/libsystemd/sd-bus/bus-message.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 53cbd675b7..19cb2b9a97 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -5101,6 +5101,7 @@ int bus_message_parse_fields(sd_bus_message *m) { + return -EBADMSG; + + if (*p == 0) { ++ char *k; + size_t l; + + /* We found the beginning of the signature +@@ -5114,9 +5115,11 @@ int bus_message_parse_fields(sd_bus_message *m) { + p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END) + return -EBADMSG; + +- if (free_and_strndup(&m->root_container.signature, +- p + 1 + 1, l - 2) < 0) ++ k = memdup_suffix0(p + 1 + 1, l - 2); ++ if (!k) + return -ENOMEM; ++ ++ free_and_replace(m->root_container.signature, k); + break; + } + diff --git a/SOURCES/0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch b/SOURCES/0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch new file mode 100644 index 0000000..d5df9f1 --- /dev/null +++ b/SOURCES/0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch @@ -0,0 +1,43 @@ +From 2f44943836b69455792a5422673f8a69bc9705ba Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 14 Oct 2019 17:14:35 +0200 +Subject: [PATCH] travis: don't run slow tests under ASan/UBSan + +Resolves: #1761519 +--- + ci/travis-centos-rhel8.sh | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh +index da131c726b..a1502e15ee 100755 +--- a/ci/travis-centos-rhel8.sh ++++ b/ci/travis-centos-rhel8.sh +@@ -65,10 +65,6 @@ CONFIGURE_OPTS=( + -Dnetworkd=false + -Dtimesyncd=false + -Ddefault-hierarchy=legacy +- # Custom options +- -Dslow-tests=true +- -Dtests=unsafe +- -Dinstall-tests=true + ) + + function info() { +@@ -104,7 +100,7 @@ for phase in "${PHASES[@]}"; do + RUN) + info "Run phase" + # Build systemd +- docker exec -it -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build "${CONFIGURE_OPTS[@]}" ++ docker exec -it -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build -Dtests=unsafe -Dslow-tests=true "${CONFIGURE_OPTS[@]}" + $DOCKER_EXEC ninja -v -C build + # Let's install the new systemd and "reboot" the container to avoid + # unexpected fails due to incompatibilities with older systemd +@@ -117,7 +113,7 @@ for phase in "${PHASES[@]}"; do + ENV_VARS="-e CC=clang -e CXX=clang++" + MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764 + fi +- docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]} ++ docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS "${CONFIGURE_OPTS[@]}" + docker exec -it $CONT_NAME ninja -v -C build + + # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb. diff --git a/SOURCES/0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch b/SOURCES/0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch new file mode 100644 index 0000000..b79434e --- /dev/null +++ b/SOURCES/0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch @@ -0,0 +1,67 @@ +From 6240d78097c6f828aa2ca3b50ac322b41dc41fd1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 23 Aug 2019 11:34:45 +0200 +Subject: [PATCH] kernel-install: do not require non-empty kernel cmdline + +When booting with Fedora-Server-dvd-x86_64-30-20190411.n.0.iso, +/proc/cmdline is empty (libvirt, qemu host with bios, not sure if that +matters), after installation to disk, anaconda would "crash" in kernel-core +%posttrans, after calling kernel-install, because dracut would fail +with + +> Could not determine the kernel command line parameters. +> Please specify the kernel command line in /etc/kernel/cmdline! + +I guess it's legitimate, even if unusual, to have no cmdline parameters. +Two changes are done in this patch: + +1. do not fail if the cmdline is empty. +2. if /usr/lib/kernel/cmdline or /etc/kernel/cmdline are present, but + empty, ignore /proc/cmdline. If there's explicit configuration to + have empty cmdline, don't ignore it. + +The same change was done in dracut: +https://github.com/dracutdevs/dracut/pull/561. + +(cherry picked from commit 88e1306af6380794842fb31108ba67895799fab4) + +Resolves: #1701454 +--- + src/kernel-install/90-loaderentry.install | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index a271cdb8a0..1619301536 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -43,13 +43,13 @@ if ! [[ $PRETTY_NAME ]]; then + PRETTY_NAME="Linux $KERNEL_VERSION" + fi + +-declare -a BOOT_OPTIONS +- + if [[ -f /etc/kernel/cmdline ]]; then + read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline +-fi ++elif [[ -f /usr/lib/kernel/cmdline ]]; then ++ read -r -d '' -a BOOT_OPTIONS < /usr/lib/kernel/cmdline ++else ++ declare -a BOOT_OPTIONS + +-if ! [[ ${BOOT_OPTIONS[*]} ]]; then + read -r -d '' -a line < /proc/cmdline + for i in "${line[@]}"; do + [[ "${i#initrd=*}" != "$i" ]] && continue +@@ -57,12 +57,6 @@ if ! [[ ${BOOT_OPTIONS[*]} ]]; then + done + fi + +-if ! [[ ${BOOT_OPTIONS[*]} ]]; then +- echo "Could not determine the kernel command line parameters." >&2 +- echo "Please specify the kernel command line in /etc/kernel/cmdline!" >&2 +- exit 1 +-fi +- + cp "$KERNEL_IMAGE" "$BOOT_DIR_ABS/linux" && + chown root:root "$BOOT_DIR_ABS/linux" && + chmod 0644 "$BOOT_DIR_ABS/linux" || { diff --git a/SOURCES/0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch b/SOURCES/0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch new file mode 100644 index 0000000..1a3af20 --- /dev/null +++ b/SOURCES/0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch @@ -0,0 +1,36 @@ +From c6c8e0d097d6ba12471c6112c3fd339ea40329d5 Mon Sep 17 00:00:00 2001 +From: Thadeu Lima de Souza Cascardo +Date: Mon, 13 May 2019 16:58:01 -0300 +Subject: [PATCH] ask-password: prevent buffer overrow when reading from + keyring + +When we read from keyring, a temporary buffer is allocated in order to +determine the size needed for the entire data. However, when zeroing that area, +we use the data size returned by the read instead of the lesser size allocate +for the buffer. + +That will cause memory corruption that causes systemd-cryptsetup to crash +either when a single large password is used or when multiple passwords have +already been pushed to the keyring. + +Signed-off-by: Thadeu Lima de Souza Cascardo +(cherry picked from commit 59c55e73eaee345e1ee67c23eace8895ed499693) + +Resolves: #1752050 +--- + src/shared/ask-password-api.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c +index 682dc754fc..764ebd08e1 100644 +--- a/src/shared/ask-password-api.c ++++ b/src/shared/ask-password-api.c +@@ -79,7 +79,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) { + if (n < m) + break; + +- explicit_bzero(p, n); ++ explicit_bzero(p, m); + free(p); + m *= 2; + } diff --git a/SOURCES/0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch b/SOURCES/0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch new file mode 100644 index 0000000..d568e76 --- /dev/null +++ b/SOURCES/0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch @@ -0,0 +1,37 @@ +From 985837dab9c892858a92ae50043843307f5e0714 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 19 Jul 2019 18:29:11 +0200 +Subject: [PATCH] core: try to reopen /dev/kmsg again right after mounting /dev + +I was debugging stuff during early boot, and was confused that I never +found the logs for it in kmsg. The reason for that was that /proc is +generally not mounted the first time we do log_open() and hence +log_set_target(LOG_TARGET_KMSG) we do when running as PID 1 had not +effect. A lot later during start-up we call log_open() again where this +is fixed (after the point where we close all remaining fds still open), +but in the meantime no logs every got written to kmsg. This patch fixes +that. + +(cherry picked from commit 0a2eef1ee1fef74be9d12f7dc4d0006b645b579c) + +Resolves: #1749212 +--- + src/core/main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/core/main.c b/src/core/main.c +index 44dd8348be..af7b26d6f1 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2215,6 +2215,11 @@ int main(int argc, char *argv[]) { + goto finish; + } + ++ /* Let's open the log backend a second time, in case the first time didn't ++ * work. Quite possibly we have mounted /dev just now, so /dev/kmsg became ++ * available, and it previously wasn't. */ ++ log_open(); ++ + r = initialize_security( + &loaded_policy, + &security_start_timestamp, diff --git a/SOURCES/0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch b/SOURCES/0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch new file mode 100644 index 0000000..d305484 --- /dev/null +++ b/SOURCES/0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch @@ -0,0 +1,29 @@ +From 9f259b46b760b2aa08ac1fe76fe61df514e2768f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 3 Sep 2019 10:05:42 +0200 +Subject: [PATCH] buildsys: don't garbage collect sections while linking + +gc-sections is actually very aggressive and garbage collects ELF +sections used by annobin gcc plugin and annocheck then reports gaps in +coverage. Let's drop that linker flag. + +RHEL-only + +Resolves: #1748258 +--- + meson.build | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/meson.build b/meson.build +index 04b461dcd4..613a5133b6 100644 +--- a/meson.build ++++ b/meson.build +@@ -357,8 +357,6 @@ if get_option('buildtype') != 'debug' + '-ffunction-sections', + '-fdata-sections', + ] +- +- possible_link_flags += '-Wl,--gc-sections' + endif + + add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c') diff --git a/SOURCES/0228-udev-introduce-CONST-key-name.patch b/SOURCES/0228-udev-introduce-CONST-key-name.patch new file mode 100644 index 0000000..127eea3 --- /dev/null +++ b/SOURCES/0228-udev-introduce-CONST-key-name.patch @@ -0,0 +1,186 @@ +From d6210c3d053d70175d72ed1d1719497eed76000b Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 17 Oct 2019 09:37:35 +0200 +Subject: [PATCH] udev: introduce CONST key name + +Currently, there is no way to match against system-wide constants, such +as architecture or virtualization type, without forking helper binaries. +That potentially results in a huge number of spawned processes which +output always the same answer. + +This patch introduces a special CONST keyword which takes a hard-coded +string as its key and returns a value assigned to that key. Currently +implemented are CONST{arch} and CONST{virt}, which can be used to match +against the system's architecture and virtualization type. + +(based on commit 4801d8afe2ff1c1c075c9f0bc5631612172e0bb7) + +Resolves: #1762679 +--- + man/udev.xml | 26 ++++++++++++++++++++++++++ + rules/40-redhat.rules | 6 +++--- + src/udev/udev-rules.c | 32 ++++++++++++++++++++++++++++++++ + test/rule-syntax-check.py | 2 +- + 4 files changed, 62 insertions(+), 4 deletions(-) + +diff --git a/man/udev.xml b/man/udev.xml +index bdf901a8f0..8c1eb41787 100644 +--- a/man/udev.xml ++++ b/man/udev.xml +@@ -236,6 +236,32 @@ + + + ++ ++ CONST{key} ++ ++ Match against a system-wide constant. Supported keys are: ++ ++ ++ arch ++ ++ System's architecture. See in ++ systemd.unit5 ++ for possible values. ++ ++ ++ ++ virt ++ ++ System's virtualization environment. See ++ systemd-detect-virt1 ++ for possible values. ++ ++ ++ ++ Unknown keys will never match. ++ ++ ++ + + TAG + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index fadc6e59f1..3c95cd2df0 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -6,11 +6,11 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online} + # Memory hotadd request + SUBSYSTEM!="memory", GOTO="memory_hotplug_end" + ACTION!="add", GOTO="memory_hotplug_end" +-PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end" +-PROGRAM="/bin/uname -p", RESULT=="ppc64*", GOTO="memory_hotplug_end" ++CONST{arch}=="s390*", GOTO="memory_hotplug_end" ++CONST{arch}=="ppc64*", GOTO="memory_hotplug_end" + + ENV{.state}="online" +-PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable" ++CONST{virt}=="none", ENV{.state}="online_movable" + ATTR{state}=="offline", ATTR{state}="$env{.state}" + + LABEL="memory_hotplug_end" +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 58af863f3d..a246cbe67e 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -17,6 +17,7 @@ + #include + + #include "alloc-util.h" ++#include "architecture.h" + #include "conf-files.h" + #include "dirent-util.h" + #include "escape.h" +@@ -34,6 +35,7 @@ + #include "udev.h" + #include "user-util.h" + #include "util.h" ++#include "virt.h" + + #define PREALLOC_TOKEN 2048 + +@@ -123,6 +125,7 @@ enum token_type { + TK_M_DEVLINK, /* val */ + TK_M_NAME, /* val */ + TK_M_ENV, /* val, attr */ ++ TK_M_CONST, /* val, attr */ + TK_M_TAG, /* val */ + TK_M_SUBSYSTEM, /* val */ + TK_M_DRIVER, /* val */ +@@ -259,6 +262,7 @@ static const char *token_str(enum token_type type) { + [TK_M_DEVLINK] = "M DEVLINK", + [TK_M_NAME] = "M NAME", + [TK_M_ENV] = "M ENV", ++ [TK_M_CONST] = "M CONST", + [TK_M_TAG] = "M TAG", + [TK_M_SUBSYSTEM] = "M SUBSYSTEM", + [TK_M_DRIVER] = "M DRIVER", +@@ -370,6 +374,7 @@ static void dump_token(struct udev_rules *rules, struct token *token) { + case TK_M_SYSCTL: + case TK_M_ATTRS: + case TK_M_ENV: ++ case TK_M_CONST: + case TK_A_ATTR: + case TK_A_SYSCTL: + case TK_A_ENV: +@@ -903,6 +908,7 @@ static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + token->key.builtin_cmd = *(enum udev_builtin_cmd *)data; + break; + case TK_M_ENV: ++ case TK_M_CONST: + case TK_M_ATTR: + case TK_M_SYSCTL: + case TK_M_ATTRS: +@@ -1226,6 +1232,17 @@ static void add_rule(struct udev_rules *rules, char *line, + rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); + } + ++ } else if (startswith(key, "CONST{")) { ++ attr = get_key_attribute(rules->udev, key + STRLEN("CONST")); ++ if (attr == NULL || !STR_IN_SET(attr, "arch", "virt")) ++ LOG_AND_RETURN("error parsing %s attribute", "CONST"); ++ ++ if (op == OP_REMOVE) ++ LOG_AND_RETURN("invalid %s operation", "CONST"); ++ ++ if (op < OP_MATCH_MAX) ++ rule_add_key(&rule_tmp, TK_M_CONST, op, value, attr); ++ + } else if (streq(key, "TAG")) { + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); +@@ -1855,6 +1872,21 @@ void udev_rules_apply_to_event(struct udev_rules *rules, + goto nomatch; + break; + } ++ case TK_M_CONST: { ++ const char *key_name = rules_str(rules, cur->key.attr_off); ++ const char *value = NULL; ++ ++ if (streq(key_name, "arch")) { ++ value = architecture_to_string(uname_architecture()); ++ } else if (streq(key_name, "virt")) { ++ value = virtualization_to_string(detect_virtualization()); ++ } else ++ assert_not_reached("Invalid CONST key"); ++ ++ if (match_key(rules, cur, value)) ++ goto nomatch; ++ break; ++ } + case TK_M_TAG: { + struct udev_list_entry *list_entry; + bool match = false; +diff --git a/test/rule-syntax-check.py b/test/rule-syntax-check.py +index c7c0a1a656..6e59f421f5 100755 +--- a/test/rule-syntax-check.py ++++ b/test/rule-syntax-check.py +@@ -19,7 +19,7 @@ quoted_string_re = r'"(?:[^\\"]|\\.)*"' + no_args_tests = re.compile(r'(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|PROGRAM|RESULT|TEST)\s*(?:=|!)=\s*' + quoted_string_re + '$') + # PROGRAM can also be specified as an assignment. + program_assign = re.compile(r'PROGRAM\s*=\s*' + quoted_string_re + '$') +-args_tests = re.compile(r'(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*' + quoted_string_re + '$') ++args_tests = re.compile(r'(ATTRS?|ENV|CONST|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*' + quoted_string_re + '$') + no_args_assign = re.compile(r'(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*' + quoted_string_re + '$') + args_assign = re.compile(r'(ATTR|ENV|IMPORT|RUN){([a-zA-Z0-9/_.*%-]+)}\s*(=|\+=)\s*' + quoted_string_re + '$') + # Find comma-separated groups, but allow commas that are inside quoted strings. diff --git a/SOURCES/0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch b/SOURCES/0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch new file mode 100644 index 0000000..655f32a --- /dev/null +++ b/SOURCES/0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch @@ -0,0 +1,50 @@ +From e1bd03e75860fb349a6de589bbb1274acc454aef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Fri, 13 Sep 2019 11:18:18 +0200 +Subject: [PATCH] Call getgroups() to know size of supplementary groups array + to allocate + +Resolves RHBZ #1743230 - journalctl dumps core when stack limit is reduced to 256 KB + +(cherry picked from commit f5e0b942af1e86993c21f4e5c84342bb10403dac) + +Resolves: #1743235 +--- + src/basic/user-util.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/src/basic/user-util.c b/src/basic/user-util.c +index a562a397c7..c533f67025 100644 +--- a/src/basic/user-util.c ++++ b/src/basic/user-util.c +@@ -358,9 +358,8 @@ char* gid_to_name(gid_t gid) { + } + + int in_gid(gid_t gid) { +- long ngroups_max; + gid_t *gids; +- int r, i; ++ int ngroups, r, i; + + if (getgid() == gid) + return 1; +@@ -371,12 +370,15 @@ int in_gid(gid_t gid) { + if (!gid_is_valid(gid)) + return -EINVAL; + +- ngroups_max = sysconf(_SC_NGROUPS_MAX); +- assert(ngroups_max > 0); ++ ngroups = getgroups(0, NULL); ++ if (ngroups < 0) ++ return -errno; ++ if (ngroups == 0) ++ return 0; + +- gids = newa(gid_t, ngroups_max); ++ gids = newa(gid_t, ngroups); + +- r = getgroups(ngroups_max, gids); ++ r = getgroups(ngroups, gids); + if (r < 0) + return -errno; + diff --git a/SOURCES/0230-Consider-smb3-as-remote-filesystem.patch b/SOURCES/0230-Consider-smb3-as-remote-filesystem.patch new file mode 100644 index 0000000..691f180 --- /dev/null +++ b/SOURCES/0230-Consider-smb3-as-remote-filesystem.patch @@ -0,0 +1,30 @@ +From 1bf923686a6842f222b1ef5f5174511340c75685 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 1 Oct 2019 08:45:08 +0200 +Subject: [PATCH] Consider smb3 as remote filesystem + +Currently systemd will treat smb3 as local filesystem and cause +can't boot failures. Add smb3 to the list of remote filesystems +to fix this issue. + +Signed-off-by: Kenneth D'souza + +(cherry picked from commit ff7d6a740b0c6fa3be63d3908a0858730a0837c5) + +Resolves: #1757257 +--- + src/basic/mount-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index 3670b7f591..5b04e21f34 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -603,6 +603,7 @@ bool fstype_is_network(const char *fstype) { + return STR_IN_SET(fstype, + "afs", + "cifs", ++ "smb3", + "smbfs", + "sshfs", + "ncpfs", diff --git a/SOURCES/0231-process-util-introduce-pid_is_my_child-helper.patch b/SOURCES/0231-process-util-introduce-pid_is_my_child-helper.patch new file mode 100644 index 0000000..5d740cf --- /dev/null +++ b/SOURCES/0231-process-util-introduce-pid_is_my_child-helper.patch @@ -0,0 +1,114 @@ +From f057aa6bb604845fa10ad569bca306e5e1e8fe0d Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Mon, 18 Mar 2019 11:48:34 +0100 +Subject: [PATCH] process-util: introduce pid_is_my_child() helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +No functional changes. + +Thanks Renaud Métrich for backporting this to RHEL. +Resolves: #1744972 +--- + src/basic/process-util.c | 14 ++++++++++++++ + src/basic/process-util.h | 1 + + src/core/cgroup.c | 7 ++----- + src/core/service.c | 8 ++------ + 4 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/src/basic/process-util.c b/src/basic/process-util.c +index aa3eff779a..6dbeee9dda 100644 +--- a/src/basic/process-util.c ++++ b/src/basic/process-util.c +@@ -903,6 +903,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { + return 0; + } + ++int pid_is_my_child(pid_t pid) { ++ pid_t ppid; ++ int r; ++ ++ if (pid <= 1) ++ return false; ++ ++ r = get_process_ppid(pid, &ppid); ++ if (r < 0) ++ return r; ++ ++ return ppid == getpid_cached(); ++} ++ + bool pid_is_unwaited(pid_t pid) { + /* Checks whether a PID is still valid at all, including a zombie */ + +diff --git a/src/basic/process-util.h b/src/basic/process-util.h +index a5bb072b25..a3bd2851b4 100644 +--- a/src/basic/process-util.h ++++ b/src/basic/process-util.h +@@ -68,6 +68,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value); + + bool pid_is_alive(pid_t pid); + bool pid_is_unwaited(pid_t pid); ++int pid_is_my_child(pid_t pid); + int pid_from_same_root_fs(pid_t pid); + + bool is_main_thread(void); +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 62ab41a288..b7ed07e65b 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -1876,7 +1876,7 @@ void unit_prune_cgroup(Unit *u) { + + int unit_search_main_pid(Unit *u, pid_t *ret) { + _cleanup_fclose_ FILE *f = NULL; +- pid_t pid = 0, npid, mypid; ++ pid_t pid = 0, npid; + int r; + + assert(u); +@@ -1889,15 +1889,12 @@ int unit_search_main_pid(Unit *u, pid_t *ret) { + if (r < 0) + return r; + +- mypid = getpid_cached(); + while (cg_read_pid(f, &npid) > 0) { +- pid_t ppid; + + if (npid == pid) + continue; + +- /* Ignore processes that aren't our kids */ +- if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid) ++ if (pid_is_my_child(npid) == 0) + continue; + + if (pid != 0) +diff --git a/src/core/service.c b/src/core/service.c +index 24f167572a..614ba05d89 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -139,8 +139,6 @@ static void service_unwatch_pid_file(Service *s) { + } + + static int service_set_main_pid(Service *s, pid_t pid) { +- pid_t ppid; +- + assert(s); + + if (pid <= 1) +@@ -159,12 +157,10 @@ static int service_set_main_pid(Service *s, pid_t pid) { + + s->main_pid = pid; + s->main_pid_known = true; ++ s->main_pid_alien = pid_is_my_child(pid) == 0; + +- if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid_cached()) { ++ if (s->main_pid_alien) + log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid); +- s->main_pid_alien = true; +- } else +- s->main_pid_alien = false; + + return 0; + } diff --git a/SOURCES/0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch b/SOURCES/0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch new file mode 100644 index 0000000..46cf59e --- /dev/null +++ b/SOURCES/0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch @@ -0,0 +1,323 @@ +From 79e9566ec0a61d887ab63f17192dbd71aae36ee0 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Mon, 18 Mar 2019 20:59:36 +0100 +Subject: [PATCH] core: reduce the number of stalled PIDs from the watched + processes list when possible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some PIDs can remain in the watched list even though their processes have +exited since a long time. It can easily happen if the main process of a forking +service manages to spawn a child before the control process exits for example. + +However when a pid is about to be mapped to a unit by calling unit_watch_pid(), +the caller usually knows if the pid should belong to this unit exclusively: if +we just forked() off a child, then we can be sure that its PID is otherwise +unused. In this case we take this opportunity to remove any stalled PIDs from +the watched process list. + +If we learnt about a PID in any other form (for example via PID file, via +searching, MAINPID= and so on), then we can't assume anything. + +Thanks Renaud Métrich for backporting this to RHEL. +Resolves: #1744972 +--- + src/core/cgroup.c | 2 +- + src/core/dbus-scope.c | 2 +- + src/core/manager.c | 10 ++++++++++ + src/core/manager.h | 2 ++ + src/core/mount.c | 5 ++--- + src/core/service.c | 16 ++++++++-------- + src/core/socket.c | 7 +++---- + src/core/swap.c | 5 ++--- + src/core/unit.c | 8 +++++++- + src/core/unit.h | 2 +- + src/test/test-watch-pid.c | 12 ++++++------ + 11 files changed, 43 insertions(+), 28 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index b7ed07e65b..76eafdc082 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -1926,7 +1926,7 @@ static int unit_watch_pids_in_path(Unit *u, const char *path) { + pid_t pid; + + while ((r = cg_read_pid(f, &pid)) > 0) { +- r = unit_watch_pid(u, pid); ++ r = unit_watch_pid(u, pid, false); + if (r < 0 && ret >= 0) + ret = r; + } +diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c +index 6725f62794..0bbf64fff1 100644 +--- a/src/core/dbus-scope.c ++++ b/src/core/dbus-scope.c +@@ -106,7 +106,7 @@ static int bus_scope_set_transient_property( + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, false); + if (r < 0 && r != -EEXIST) + return r; + } +diff --git a/src/core/manager.c b/src/core/manager.c +index c83e296cf3..0eae7d46fb 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2044,6 +2044,16 @@ void manager_clear_jobs(Manager *m) { + job_finish_and_invalidate(j, JOB_CANCELED, false, false); + } + ++void manager_unwatch_pid(Manager *m, pid_t pid) { ++ assert(m); ++ ++ /* First let's drop the unit keyed as "pid". */ ++ (void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid)); ++ ++ /* Then, let's also drop the array keyed by -pid. */ ++ free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid))); ++} ++ + static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { + Manager *m = userdata; + Job *j; +diff --git a/src/core/manager.h b/src/core/manager.h +index c7f4d66ecd..fa47952d24 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -406,6 +406,8 @@ int manager_get_dump_string(Manager *m, char **ret); + + void manager_clear_jobs(Manager *m); + ++void manager_unwatch_pid(Manager *m, pid_t pid); ++ + unsigned manager_dispatch_load_queue(Manager *m); + + int manager_environment_add(Manager *m, char **minus, char **plus); +diff --git a/src/core/mount.c b/src/core/mount.c +index 2ac04e3874..5878814b1b 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -677,7 +677,7 @@ static int mount_coldplug(Unit *u) { + pid_is_unwaited(m->control_pid) && + MOUNT_STATE_WITH_PROCESS(new_state)) { + +- r = unit_watch_pid(UNIT(m), m->control_pid); ++ r = unit_watch_pid(UNIT(m), m->control_pid, false); + if (r < 0) + return r; + +@@ -781,9 +781,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { + if (r < 0) + return r; + +- r = unit_watch_pid(UNIT(m), pid); ++ r = unit_watch_pid(UNIT(m), pid, true); + if (r < 0) +- /* FIXME: we need to do something here */ + return r; + + *_pid = pid; +diff --git a/src/core/service.c b/src/core/service.c +index 614ba05d89..310838a5f6 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -974,7 +974,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { + if (r < 0) + return r; + +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, false); + if (r < 0) /* FIXME: we need to do something here */ + return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid); + +@@ -1004,7 +1004,7 @@ static void service_search_main_pid(Service *s) { + if (service_set_main_pid(s, pid) < 0) + return; + +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, false); + if (r < 0) + /* FIXME: we need to do something here */ + log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid); +@@ -1135,7 +1135,7 @@ static int service_coldplug(Unit *u) { + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { +- r = unit_watch_pid(UNIT(s), s->main_pid); ++ r = unit_watch_pid(UNIT(s), s->main_pid, false); + if (r < 0) + return r; + } +@@ -1147,7 +1147,7 @@ static int service_coldplug(Unit *u) { + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { +- r = unit_watch_pid(UNIT(s), s->control_pid); ++ r = unit_watch_pid(UNIT(s), s->control_pid, false); + if (r < 0) + return r; + } +@@ -1545,8 +1545,8 @@ static int service_spawn( + s->exec_fd_event_source = TAKE_PTR(exec_fd_source); + s->exec_fd_hot = false; + +- r = unit_watch_pid(UNIT(s), pid); +- if (r < 0) /* FIXME: we need to do something here */ ++ r = unit_watch_pid(UNIT(s), pid, true); ++ if (r < 0) + return r; + + *_pid = pid; +@@ -3643,7 +3643,7 @@ static void service_notify_message( + } + if (r > 0) { + service_set_main_pid(s, new_main_pid); +- unit_watch_pid(UNIT(s), new_main_pid); ++ unit_watch_pid(UNIT(s), new_main_pid, false); + notify_dbus = true; + } + } +@@ -3858,7 +3858,7 @@ static void service_bus_name_owner_change( + log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, name, pid); + + service_set_main_pid(s, pid); +- unit_watch_pid(UNIT(s), pid); ++ unit_watch_pid(UNIT(s), pid, false); + } + } + } +diff --git a/src/core/socket.c b/src/core/socket.c +index d488c64e91..b034549634 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -1816,7 +1816,7 @@ static int socket_coldplug(Unit *u) { + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL)) { + +- r = unit_watch_pid(UNIT(s), s->control_pid); ++ r = unit_watch_pid(UNIT(s), s->control_pid, false); + if (r < 0) + return r; + +@@ -1902,9 +1902,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { + if (r < 0) + return r; + +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, true); + if (r < 0) +- /* FIXME: we need to do something here */ + return r; + + *_pid = pid; +@@ -1973,7 +1972,7 @@ static int socket_chown(Socket *s, pid_t *_pid) { + _exit(EXIT_SUCCESS); + } + +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, true); + if (r < 0) + goto fail; + +diff --git a/src/core/swap.c b/src/core/swap.c +index b644753a1c..e717dbb54a 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -531,7 +531,7 @@ static int swap_coldplug(Unit *u) { + pid_is_unwaited(s->control_pid) && + SWAP_STATE_WITH_PROCESS(new_state)) { + +- r = unit_watch_pid(UNIT(s), s->control_pid); ++ r = unit_watch_pid(UNIT(s), s->control_pid, false); + if (r < 0) + return r; + +@@ -636,9 +636,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { + if (r < 0) + goto fail; + +- r = unit_watch_pid(UNIT(s), pid); ++ r = unit_watch_pid(UNIT(s), pid, true); + if (r < 0) +- /* FIXME: we need to do something here */ + goto fail; + + *_pid = pid; +diff --git a/src/core/unit.c b/src/core/unit.c +index d298afb0d4..b0b1c77ef7 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2500,7 +2500,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag + unit_add_to_gc_queue(u); + } + +-int unit_watch_pid(Unit *u, pid_t pid) { ++int unit_watch_pid(Unit *u, pid_t pid, bool exclusive) { + int r; + + assert(u); +@@ -2508,6 +2508,12 @@ int unit_watch_pid(Unit *u, pid_t pid) { + + /* Watch a specific PID */ + ++ /* Caller might be sure that this PID belongs to this unit only. Let's take this ++ * opportunity to remove any stalled references to this PID as they can be created ++ * easily (when watching a process which is not our direct child). */ ++ if (exclusive) ++ manager_unwatch_pid(u->manager, pid); ++ + r = set_ensure_allocated(&u->pids, NULL); + if (r < 0) + return r; +diff --git a/src/core/unit.h b/src/core/unit.h +index e1a60da244..68cc1869e4 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -655,7 +655,7 @@ typedef enum UnitNotifyFlags { + + void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags); + +-int unit_watch_pid(Unit *u, pid_t pid); ++int unit_watch_pid(Unit *u, pid_t pid, bool exclusive); + void unit_unwatch_pid(Unit *u, pid_t pid); + void unit_unwatch_all_pids(Unit *u); + +diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c +index cb43b35bc5..8c70175aed 100644 +--- a/src/test/test-watch-pid.c ++++ b/src/test/test-watch-pid.c +@@ -49,25 +49,25 @@ int main(int argc, char *argv[]) { + assert_se(hashmap_isempty(m->watch_pids)); + assert_se(manager_get_unit_by_pid(m, 4711) == NULL); + +- assert_se(unit_watch_pid(a, 4711) >= 0); ++ assert_se(unit_watch_pid(a, 4711, false) >= 0); + assert_se(manager_get_unit_by_pid(m, 4711) == a); + +- assert_se(unit_watch_pid(a, 4711) >= 0); ++ assert_se(unit_watch_pid(a, 4711, false) >= 0); + assert_se(manager_get_unit_by_pid(m, 4711) == a); + +- assert_se(unit_watch_pid(b, 4711) >= 0); ++ assert_se(unit_watch_pid(b, 4711, false) >= 0); + u = manager_get_unit_by_pid(m, 4711); + assert_se(u == a || u == b); + +- assert_se(unit_watch_pid(b, 4711) >= 0); ++ assert_se(unit_watch_pid(b, 4711, false) >= 0); + u = manager_get_unit_by_pid(m, 4711); + assert_se(u == a || u == b); + +- assert_se(unit_watch_pid(c, 4711) >= 0); ++ assert_se(unit_watch_pid(c, 4711, false) >= 0); + u = manager_get_unit_by_pid(m, 4711); + assert_se(u == a || u == b || u == c); + +- assert_se(unit_watch_pid(c, 4711) >= 0); ++ assert_se(unit_watch_pid(c, 4711, false) >= 0); + u = manager_get_unit_by_pid(m, 4711); + assert_se(u == a || u == b || u == c); + diff --git a/SOURCES/0233-core-only-watch-processes-when-it-s-really-necessary.patch b/SOURCES/0233-core-only-watch-processes-when-it-s-really-necessary.patch new file mode 100644 index 0000000..058ff69 --- /dev/null +++ b/SOURCES/0233-core-only-watch-processes-when-it-s-really-necessary.patch @@ -0,0 +1,55 @@ +From 25b93538eba0275d35ef4b0792c2cd63d63d5e8d Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Tue, 19 Mar 2019 10:59:26 +0100 +Subject: [PATCH] core: only watch processes when it's really necessary +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If we know that main pid is our child then it's unnecessary to watch all +other processes of a unit since in this case we will get SIGCHLD when the main +process will exit and will act upon accordingly. + +So let's watch all processes only if the main process is not our child since in +this case we need to detect when the cgroup will become empty in order to +figure out when the service becomes dead. This is only needed by cgroupv1. + +Thanks Renaud Métrich for backporting this to RHEL. +Resolves: #1744972 +--- + src/core/service.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 310838a5f6..b1ec52d220 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -3410,8 +3410,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + if (main_pid_good(s) <= 0) + service_enter_stop_post(s, f); + +- /* If there is still a service +- * process around, wait until ++ /* If there is still a service process around, wait until + * that one quit, too */ + break; + +@@ -3433,10 +3432,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + if (notify_dbus) + unit_add_to_dbus_queue(u); + +- /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch, +- * under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched +- * was probably the parent of them, and they are hence now our children. */ +- (void) unit_enqueue_rewatch_pids(u); ++ /* We watch the main/control process otherwise we can't retrieve the unit they ++ * belong to with cgroupv1. But if they are not our direct child, we won't get a ++ * SIGCHLD for them. Therefore we need to look for others to watch so we can ++ * detect when the cgroup becomes empty. Note that the control process is always ++ * our child so it's pointless to watch all other processes. */ ++ if (!control_pid_good(s)) ++ if (!s->main_pid_known || s->main_pid_alien) ++ (void) unit_enqueue_rewatch_pids(u); + } + + static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { diff --git a/SOURCES/0234-core-implement-per-unit-journal-rate-limiting.patch b/SOURCES/0234-core-implement-per-unit-journal-rate-limiting.patch new file mode 100644 index 0000000..a503b82 --- /dev/null +++ b/SOURCES/0234-core-implement-per-unit-journal-rate-limiting.patch @@ -0,0 +1,641 @@ +From a26f2b2732733aa361fec0a3a8f0ba377f48e75c Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Sun, 7 Oct 2018 20:28:36 -0700 +Subject: [PATCH] core: implement per unit journal rate limiting + +Add LogRateLimitIntervalSec= and LogRateLimitBurst= options for +services. If provided, these values get passed to the journald +client context, and those values are used in the rate limiting +function in the journal over the the journald.conf values. + +Part of #10230 + +(cherry picked from commit 90fc172e191f44979005a524521112f2bd1ff21b) + +Resolves: #1719577 +--- + catalog/systemd.catalog.in | 3 +- + doc/TRANSIENT-SETTINGS.md | 2 + + man/journald.conf.xml | 8 +- + man/systemd.exec.xml | 16 ++++ + src/core/dbus-execute.c | 8 ++ + src/core/execute.c | 14 ++++ + src/core/execute.h | 3 + + src/core/load-fragment-gperf.gperf.m4 | 2 + + src/core/unit.c | 92 +++++++++++++++++++++ + src/core/unit.h | 2 + + src/journal/journald-context.c | 50 ++++++++++- + src/journal/journald-context.h | 3 + + src/journal/journald-rate-limit.c | 38 ++++----- + src/journal/journald-rate-limit.h | 4 +- + src/journal/journald-server.c | 4 +- + src/shared/bus-unit-util.c | 8 ++ + test/fuzz/fuzz-unit-file/directives.service | 2 + + 17 files changed, 231 insertions(+), 28 deletions(-) + +diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in +index f1bddc6f7d..8234e387cf 100644 +--- a/catalog/systemd.catalog.in ++++ b/catalog/systemd.catalog.in +@@ -52,7 +52,8 @@ dropped, other services' messages are unaffected. + + The limits controlling when messages are dropped may be configured + with RateLimitIntervalSec= and RateLimitBurst= in +-/etc/systemd/journald.conf. See journald.conf(5) for details. ++/etc/systemd/journald.conf or LogRateLimitIntervalSec= and LogRateLimitBurst= ++in the unit file. See journald.conf(5) and systemd.exec(5) for details. + + -- e9bf28e6e834481bb6f48f548ad13606 + Subject: Journal messages have been missed +diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md +index ca9e8387b7..0ea444b133 100644 +--- a/doc/TRANSIENT-SETTINGS.md ++++ b/doc/TRANSIENT-SETTINGS.md +@@ -135,6 +135,8 @@ All execution-related settings are available for transient units. + ✓ SyslogLevelPrefix= + ✓ LogLevelMax= + ✓ LogExtraFields= ++✓ LogRateLimitIntervalSec= ++✓ LogRateLimitBurst= + ✓ SecureBits= + ✓ CapabilityBoundingSet= + ✓ AmbientCapabilities= +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index ee8e8b7faf..b57a244b22 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -140,7 +140,13 @@ + following units: s, min, + h, ms, + us. To turn off any kind of rate limiting, +- set either value to 0. ++ set either value to 0. ++ ++ If a service provides rate limits for itself through ++ LogRateLimitIntervalSec= and/or LogRateLimitBurst= ++ in systemd.exec5, ++ those values will override the settings specified here. ++ + + + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 3bd790b485..737c52bcc4 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -1905,6 +1905,22 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy + matching. Assign an empty string to reset the list. + + ++ ++ LogRateLimitIntervalSec= ++ LogRateLimitBurst= ++ ++ Configures the rate limiting that is applied to messages generated by this unit. If, in the ++ time interval defined by LogRateLimitIntervalSec=, more messages than specified in ++ LogRateLimitBurst= are logged by a service, all further messages within the interval are ++ dropped until the interval is over. A message about the number of dropped messages is generated. The time ++ specification for LogRateLimitIntervalSec= may be specified in the following units: "s", ++ "min", "h", "ms", "us" (see ++ systemd.time7 for details). ++ The default settings are set by RateLimitIntervalSec= and RateLimitBurst= ++ configured in journald.conf5. ++ ++ ++ + + SyslogIdentifier= + +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index c44970c10c..33a91c012e 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -718,6 +718,8 @@ const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_rate_limit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_rate_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST), +@@ -1073,6 +1075,12 @@ int bus_exec_context_set_transient_property( + if (streq(name, "CPUSchedulingPriority")) + return bus_set_transient_sched_priority(u, name, &c->cpu_sched_priority, message, flags, error); + ++ if (streq(name, "LogRateLimitIntervalUSec")) ++ return bus_set_transient_usec(u, name, &c->log_rate_limit_interval_usec, message, flags, error); ++ ++ if (streq(name, "LogRateLimitBurst")) ++ return bus_set_transient_unsigned(u, name, &c->log_rate_limit_burst, message, flags, error); ++ + if (streq(name, "Personality")) + return bus_set_transient_personality(u, name, &c->personality, message, flags, error); + +diff --git a/src/core/execute.c b/src/core/execute.c +index c62f3cf849..8293c522bc 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -3693,6 +3693,9 @@ void exec_context_done(ExecContext *c) { + + exec_context_free_log_extra_fields(c); + ++ c->log_rate_limit_interval_usec = 0; ++ c->log_rate_limit_burst = 0; ++ + c->stdin_data = mfree(c->stdin_data); + c->stdin_data_size = 0; + } +@@ -4153,6 +4156,17 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t)); + } + ++ if (c->log_rate_limit_interval_usec > 0) { ++ char buf_timespan[FORMAT_TIMESPAN_MAX]; ++ ++ fprintf(f, ++ "%sLogRateLimitIntervalSec: %s\n", ++ prefix, format_timespan(buf_timespan, sizeof(buf_timespan), c->log_rate_limit_interval_usec, USEC_PER_SEC)); ++ } ++ ++ if (c->log_rate_limit_burst > 0) ++ fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_rate_limit_burst); ++ + if (c->n_log_extra_fields > 0) { + size_t j; + +diff --git a/src/core/execute.h b/src/core/execute.h +index bff1634b88..8c91636adc 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -216,6 +216,9 @@ struct ExecContext { + struct iovec* log_extra_fields; + size_t n_log_extra_fields; + ++ usec_t log_rate_limit_interval_usec; ++ unsigned log_rate_limit_burst; ++ + bool cpu_sched_reset_on_fork; + bool non_blocking; + bool private_tmp; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 15fb47838c..1066bcfb8f 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -57,6 +57,8 @@ $1.SyslogFacility, config_parse_log_facility, 0, + $1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority) + $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) + $1.LogLevelMax, config_parse_log_level, 0, offsetof($1, exec_context.log_level_max) ++$1.LogRateLimitIntervalSec, config_parse_sec, 0, offsetof($1, exec_context.log_rate_limit_interval_usec) ++$1.LogRateLimitBurst, config_parse_unsigned, 0, offsetof($1, exec_context.log_rate_limit_burst) + $1.LogExtraFields, config_parse_log_extra_fields, 0, offsetof($1, exec_context) + $1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context) + $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context.secure_bits) +diff --git a/src/core/unit.c b/src/core/unit.c +index b0b1c77ef7..115739f4c6 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3245,6 +3245,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { + unit_serialize_item(u, f, "exported-invocation-id", yes_no(u->exported_invocation_id)); + unit_serialize_item(u, f, "exported-log-level-max", yes_no(u->exported_log_level_max)); + unit_serialize_item(u, f, "exported-log-extra-fields", yes_no(u->exported_log_extra_fields)); ++ unit_serialize_item(u, f, "exported-log-rate-limit-interval", yes_no(u->exported_log_rate_limit_interval)); ++ unit_serialize_item(u, f, "exported-log-rate-limit-burst", yes_no(u->exported_log_rate_limit_burst)); + + unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); + if (u->cpu_usage_last != NSEC_INFINITY) +@@ -3508,6 +3510,26 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + + continue; + ++ } else if (streq(l, "exported-log-rate-limit-interval")) { ++ ++ r = parse_boolean(v); ++ if (r < 0) ++ log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v); ++ else ++ u->exported_log_rate_limit_interval = r; ++ ++ continue; ++ ++ } else if (streq(l, "exported-log-rate-limit-burst")) { ++ ++ r = parse_boolean(v); ++ if (r < 0) ++ log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v); ++ else ++ u->exported_log_rate_limit_burst = r; ++ ++ continue; ++ + } else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) { + + r = safe_atou64(v, &u->cpu_usage_base); +@@ -5241,6 +5263,60 @@ fail: + return r; + } + ++static int unit_export_log_rate_limit_interval(Unit *u, const ExecContext *c) { ++ _cleanup_free_ char *buf = NULL; ++ const char *p; ++ int r; ++ ++ assert(u); ++ assert(c); ++ ++ if (u->exported_log_rate_limit_interval) ++ return 0; ++ ++ if (c->log_rate_limit_interval_usec == 0) ++ return 0; ++ ++ p = strjoina("/run/systemd/units/log-rate-limit-interval:", u->id); ++ ++ if (asprintf(&buf, "%" PRIu64, c->log_rate_limit_interval_usec) < 0) ++ return log_oom(); ++ ++ r = symlink_atomic(buf, p); ++ if (r < 0) ++ return log_unit_debug_errno(u, r, "Failed to create log rate limit interval symlink %s: %m", p); ++ ++ u->exported_log_rate_limit_interval = true; ++ return 0; ++} ++ ++static int unit_export_log_rate_limit_burst(Unit *u, const ExecContext *c) { ++ _cleanup_free_ char *buf = NULL; ++ const char *p; ++ int r; ++ ++ assert(u); ++ assert(c); ++ ++ if (u->exported_log_rate_limit_burst) ++ return 0; ++ ++ if (c->log_rate_limit_burst == 0) ++ return 0; ++ ++ p = strjoina("/run/systemd/units/log-rate-limit-burst:", u->id); ++ ++ if (asprintf(&buf, "%u", c->log_rate_limit_burst) < 0) ++ return log_oom(); ++ ++ r = symlink_atomic(buf, p); ++ if (r < 0) ++ return log_unit_debug_errno(u, r, "Failed to create log rate limit burst symlink %s: %m", p); ++ ++ u->exported_log_rate_limit_burst = true; ++ return 0; ++} ++ + void unit_export_state_files(Unit *u) { + const ExecContext *c; + +@@ -5274,6 +5350,8 @@ void unit_export_state_files(Unit *u) { + if (c) { + (void) unit_export_log_level_max(u, c); + (void) unit_export_log_extra_fields(u, c); ++ (void) unit_export_log_rate_limit_interval(u, c); ++ (void) unit_export_log_rate_limit_burst(u, c); + } + } + +@@ -5310,6 +5388,20 @@ void unit_unlink_state_files(Unit *u) { + + u->exported_log_extra_fields = false; + } ++ ++ if (u->exported_log_rate_limit_interval) { ++ p = strjoina("/run/systemd/units/log-rate-limit-interval:", u->id); ++ (void) unlink(p); ++ ++ u->exported_log_rate_limit_interval = false; ++ } ++ ++ if (u->exported_log_rate_limit_burst) { ++ p = strjoina("/run/systemd/units/log-rate-limit-burst:", u->id); ++ (void) unlink(p); ++ ++ u->exported_log_rate_limit_burst = false; ++ } + } + + int unit_prepare_exec(Unit *u) { +diff --git a/src/core/unit.h b/src/core/unit.h +index 68cc1869e4..99755823eb 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -349,6 +349,8 @@ typedef struct Unit { + bool exported_invocation_id:1; + bool exported_log_level_max:1; + bool exported_log_extra_fields:1; ++ bool exported_log_rate_limit_interval:1; ++ bool exported_log_rate_limit_burst:1; + + /* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If + * == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */ +diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c +index dba3525ed8..c8e97e16de 100644 +--- a/src/journal/journald-context.c ++++ b/src/journal/journald-context.c +@@ -140,6 +140,8 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { + c->timestamp = USEC_INFINITY; + c->extra_fields_mtime = NSEC_INFINITY; + c->log_level_max = -1; ++ c->log_rate_limit_interval = s->rate_limit_interval; ++ c->log_rate_limit_burst = s->rate_limit_burst; + + r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); + if (r < 0) { +@@ -151,7 +153,8 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { + return 0; + } + +-static void client_context_reset(ClientContext *c) { ++static void client_context_reset(Server *s, ClientContext *c) { ++ assert(s); + assert(c); + + c->timestamp = USEC_INFINITY; +@@ -186,6 +189,9 @@ static void client_context_reset(ClientContext *c) { + c->extra_fields_mtime = NSEC_INFINITY; + + c->log_level_max = -1; ++ ++ c->log_rate_limit_interval = s->rate_limit_interval; ++ c->log_rate_limit_burst = s->rate_limit_burst; + } + + static ClientContext* client_context_free(Server *s, ClientContext *c) { +@@ -199,7 +205,7 @@ static ClientContext* client_context_free(Server *s, ClientContext *c) { + if (c->in_lru) + assert_se(prioq_remove(s->client_contexts_lru, c, &c->lru_index) >= 0); + +- client_context_reset(c); ++ client_context_reset(s, c); + + return mfree(c); + } +@@ -464,6 +470,42 @@ static int client_context_read_extra_fields( + return 0; + } + ++static int client_context_read_log_rate_limit_interval(ClientContext *c) { ++ _cleanup_free_ char *value = NULL; ++ const char *p; ++ int r; ++ ++ assert(c); ++ ++ if (!c->unit) ++ return 0; ++ ++ p = strjoina("/run/systemd/units/log-rate-limit-interval:", c->unit); ++ r = readlink_malloc(p, &value); ++ if (r < 0) ++ return r; ++ ++ return safe_atou64(value, &c->log_rate_limit_interval); ++} ++ ++static int client_context_read_log_rate_limit_burst(ClientContext *c) { ++ _cleanup_free_ char *value = NULL; ++ const char *p; ++ int r; ++ ++ assert(c); ++ ++ if (!c->unit) ++ return 0; ++ ++ p = strjoina("/run/systemd/units/log-rate-limit-burst:", c->unit); ++ r = readlink_malloc(p, &value); ++ if (r < 0) ++ return r; ++ ++ return safe_atou(value, &c->log_rate_limit_burst); ++} ++ + static void client_context_really_refresh( + Server *s, + ClientContext *c, +@@ -490,6 +532,8 @@ static void client_context_really_refresh( + (void) client_context_read_invocation_id(s, c); + (void) client_context_read_log_level_max(s, c); + (void) client_context_read_extra_fields(s, c); ++ (void) client_context_read_log_rate_limit_interval(c); ++ (void) client_context_read_log_rate_limit_burst(c); + + c->timestamp = timestamp; + +@@ -520,7 +564,7 @@ void client_context_maybe_refresh( + /* If the data isn't pinned and if the cashed data is older than the upper limit, we flush it out + * entirely. This follows the logic that as long as an entry is pinned the PID reuse is unlikely. */ + if (c->n_ref == 0 && c->timestamp + MAX_USEC < timestamp) { +- client_context_reset(c); ++ client_context_reset(s, c); + goto refresh; + } + +diff --git a/src/journal/journald-context.h b/src/journal/journald-context.h +index 9df3a38eff..5e19c71f14 100644 +--- a/src/journal/journald-context.h ++++ b/src/journal/journald-context.h +@@ -49,6 +49,9 @@ struct ClientContext { + size_t extra_fields_n_iovec; + void *extra_fields_data; + nsec_t extra_fields_mtime; ++ ++ usec_t log_rate_limit_interval; ++ unsigned log_rate_limit_burst; + }; + + int client_context_get( +diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c +index 6a8a36a736..539efb8669 100644 +--- a/src/journal/journald-rate-limit.c ++++ b/src/journal/journald-rate-limit.c +@@ -39,6 +39,10 @@ struct JournalRateLimitGroup { + JournalRateLimit *parent; + + char *id; ++ ++ /* Interval is stored to keep track of when the group expires */ ++ usec_t interval; ++ + JournalRateLimitPool pools[POOLS_MAX]; + uint64_t hash; + +@@ -47,8 +51,6 @@ struct JournalRateLimitGroup { + }; + + struct JournalRateLimit { +- usec_t interval; +- unsigned burst; + + JournalRateLimitGroup* buckets[BUCKETS_MAX]; + JournalRateLimitGroup *lru, *lru_tail; +@@ -58,18 +60,13 @@ struct JournalRateLimit { + uint8_t hash_key[16]; + }; + +-JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst) { ++JournalRateLimit *journal_rate_limit_new(void) { + JournalRateLimit *r; + +- assert(interval > 0 || burst == 0); +- + r = new0(JournalRateLimit, 1); + if (!r) + return NULL; + +- r->interval = interval; +- r->burst = burst; +- + random_bytes(r->hash_key, sizeof(r->hash_key)); + + return r; +@@ -109,7 +106,7 @@ _pure_ static bool journal_rate_limit_group_expired(JournalRateLimitGroup *g, us + assert(g); + + for (i = 0; i < POOLS_MAX; i++) +- if (g->pools[i].begin + g->parent->interval >= ts) ++ if (g->pools[i].begin + g->interval >= ts) + return false; + + return true; +@@ -126,7 +123,7 @@ static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) { + journal_rate_limit_group_free(r->lru_tail); + } + +-static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) { ++static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t interval, usec_t ts) { + JournalRateLimitGroup *g; + struct siphash state; + +@@ -145,6 +142,8 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, + string_hash_func(g->id, &state); + g->hash = siphash24_finalize(&state); + ++ g->interval = interval; ++ + journal_rate_limit_vacuum(r, ts); + + LIST_PREPEND(bucket, r->buckets[g->hash % BUCKETS_MAX], g); +@@ -189,7 +188,7 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) { + return burst; + } + +-int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) { ++int journal_rate_limit_test(JournalRateLimit *r, const char *id, usec_t rl_interval, unsigned rl_burst, int priority, uint64_t available) { + uint64_t h; + JournalRateLimitGroup *g; + JournalRateLimitPool *p; +@@ -209,11 +208,6 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u + if (!r) + return 1; + +- if (r->interval == 0 || r->burst == 0) +- return 1; +- +- burst = burst_modulate(r->burst, available); +- + ts = now(CLOCK_MONOTONIC); + + siphash24_init(&state, r->hash_key); +@@ -226,10 +220,16 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u + break; + + if (!g) { +- g = journal_rate_limit_group_new(r, id, ts); ++ g = journal_rate_limit_group_new(r, id, rl_interval, ts); + if (!g) + return -ENOMEM; +- } ++ } else ++ g->interval = rl_interval; ++ ++ if (rl_interval == 0 || rl_burst == 0) ++ return 1; ++ ++ burst = burst_modulate(rl_burst, available); + + p = &g->pools[priority_map[priority]]; + +@@ -240,7 +240,7 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u + return 1; + } + +- if (p->begin + r->interval < ts) { ++ if (p->begin + rl_interval < ts) { + unsigned s; + + s = p->suppressed; +diff --git a/src/journal/journald-rate-limit.h b/src/journal/journald-rate-limit.h +index 3a7f106de0..a2992800fe 100644 +--- a/src/journal/journald-rate-limit.h ++++ b/src/journal/journald-rate-limit.h +@@ -5,6 +5,6 @@ + + typedef struct JournalRateLimit JournalRateLimit; + +-JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst); ++JournalRateLimit *journal_rate_limit_new(void); + void journal_rate_limit_free(JournalRateLimit *r); +-int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available); ++int journal_rate_limit_test(JournalRateLimit *r, const char *id, usec_t rl_interval, unsigned rl_burst, int priority, uint64_t available); +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 8de45552f6..0c983e102a 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -943,7 +943,7 @@ void server_dispatch_message( + if (c && c->unit) { + (void) determine_space(s, &available, NULL); + +- rl = journal_rate_limit_test(s->rate_limit, c->unit, priority & LOG_PRIMASK, available); ++ rl = journal_rate_limit_test(s->rate_limit, c->unit, c->log_rate_limit_interval, c->log_rate_limit_burst, priority & LOG_PRIMASK, available); + if (rl == 0) + return; + +@@ -1852,7 +1852,7 @@ int server_init(Server *s) { + if (!s->udev) + return -ENOMEM; + +- s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst); ++ s->rate_limit = journal_rate_limit_new(); + if (!s->rate_limit) + return -ENOMEM; + +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index 3238b442c0..271cc054da 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -755,6 +755,14 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + + return bus_append_parse_nsec(m, field, eq); + ++ if (STR_IN_SET(field, "LogRateLimitIntervalSec")) ++ ++ return bus_append_parse_sec_rename(m, field, eq); ++ ++ if (streq(field, "LogRateLimitBurst")) ++ ++ return bus_append_safe_atou(m, field, eq); ++ + if (streq(field, "MountFlags")) + + return bus_append_mount_propagation_flags_from_string(m, field, eq); +diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service +index c2334d3b19..d8d1fc68b8 100644 +--- a/test/fuzz/fuzz-unit-file/directives.service ++++ b/test/fuzz/fuzz-unit-file/directives.service +@@ -792,6 +792,8 @@ LineMax= + LockPersonality= + LogExtraFields= + LogLevelMax= ++LogRateLimitIntervalSec= ++LogRateLimitBurst= + LogsDirectory= + LogsDirectoryMode= + MACVLAN= diff --git a/SOURCES/0235-path-stop-watching-path-specs-once-we-triggered-the-.patch b/SOURCES/0235-path-stop-watching-path-specs-once-we-triggered-the-.patch new file mode 100644 index 0000000..c538f50 --- /dev/null +++ b/SOURCES/0235-path-stop-watching-path-specs-once-we-triggered-the-.patch @@ -0,0 +1,35 @@ +From 55d9d6dfb731d2f1c8c940fb8a7ea0af6c498c4c Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 9 Sep 2019 14:38:35 +0200 +Subject: [PATCH] path: stop watching path specs once we triggered the target + unit + +We start watching them again once we get a notification that triggered +unit entered inactive or failed state. + +Fixes: #10503 +(cherry picked from commit 8fca6944c2ee20c63d62154c8badddc77170b176) + +Resolves: #1763161 +--- + src/core/path.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/core/path.c b/src/core/path.c +index 68b13b610a..5ef178a46b 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -478,11 +478,9 @@ static void path_enter_running(Path *p) { + + p->inotify_triggered = false; + +- r = path_watch(p); +- if (r < 0) +- goto fail; +- + path_set_state(p, PATH_RUNNING); ++ path_unwatch(p); ++ + return; + + fail: diff --git a/SOURCES/0236-journald-fixed-assertion-failure-when-system-journal.patch b/SOURCES/0236-journald-fixed-assertion-failure-when-system-journal.patch new file mode 100644 index 0000000..25c91dd --- /dev/null +++ b/SOURCES/0236-journald-fixed-assertion-failure-when-system-journal.patch @@ -0,0 +1,28 @@ +From 33aa231f5bf3335cdacfb38ffba757865019ce4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= + <1163635+rmetrich@users.noreply.github.com> +Date: Mon, 3 Sep 2018 05:42:39 +0200 +Subject: [PATCH] journald: fixed assertion failure when system journal + rotation fails (#9893) + +(cherry picked from commit fd790d6f09b10a87b007b71403cb018f18ff91c9) + +Resolves: #1763619 +--- + src/journal/journald-server.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 0c983e102a..6aecb67d6c 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1041,7 +1041,8 @@ int server_flush_to_var(Server *s, bool require_flag_file) { + r = 0; + + finish: +- journal_file_post_change(s->system_journal); ++ if (s->system_journal) ++ journal_file_post_change(s->system_journal); + + s->runtime_journal = journal_file_close(s->runtime_journal); + diff --git a/SOURCES/0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch b/SOURCES/0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch new file mode 100644 index 0000000..4599b60 --- /dev/null +++ b/SOURCES/0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch @@ -0,0 +1,29 @@ +From a7f18f9ef4abc7e0732d1710ead2a18a38c3ec6d Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 15 Mar 2019 10:05:33 +0100 +Subject: [PATCH] test: use PBKDF2 instead of Argon2 in cryptsetup... + +to reduce memory requirements for volume manipulation. Also, +to further improve the test performance, reduce number of PBKDF +iterations to 1000 (allowed minimum). + +(cherry picked from commit 5b69d297c153478f6f5e74ba66e1f4e5b6422baf) + +Related: #1761519 +--- + test/TEST-02-CRYPTSETUP/test.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh +index 545602e17a..c38e56f72e 100755 +--- a/test/TEST-02-CRYPTSETUP/test.sh ++++ b/test/TEST-02-CRYPTSETUP/test.sh +@@ -29,7 +29,7 @@ check_result_qemu() { + test_setup() { + create_empty_image + echo -n test >$TESTDIR/keyfile +- cryptsetup -q luksFormat ${LOOPDEV}p2 $TESTDIR/keyfile ++ cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 ${LOOPDEV}p2 $TESTDIR/keyfile + cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile + mkfs.ext4 -L var /dev/mapper/varcrypt + mkdir -p $TESTDIR/root diff --git a/SOURCES/0238-test-mask-several-unnecessary-services.patch b/SOURCES/0238-test-mask-several-unnecessary-services.patch new file mode 100644 index 0000000..6ff56e8 --- /dev/null +++ b/SOURCES/0238-test-mask-several-unnecessary-services.patch @@ -0,0 +1,252 @@ +From c748b95f5a00b6d9c46026c3d251c40437e6b64a Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 1 Nov 2018 17:26:36 +0900 +Subject: [PATCH] test: mask several unnecessary services + +This may make CIs run faster. + +(cherry picked from commit 056ae88152a722bdbea54ff33db815d585c8b9c6) + +Related: #1761519 +--- + test/TEST-02-CRYPTSETUP/test.sh | 8 ++++++++ + test/TEST-03-JOBS/test.sh | 8 ++++++++ + test/TEST-04-JOURNAL/test.sh | 8 ++++++++ + test/TEST-05-RLIMITS/test.sh | 8 ++++++++ + test/TEST-07-ISSUE-1981/test.sh | 8 ++++++++ + test/TEST-11-ISSUE-3166/test.sh | 8 ++++++++ + test/TEST-12-ISSUE-3171/test.sh | 8 ++++++++ + test/TEST-13-NSPAWN-SMOKE/test.sh | 8 ++++++++ + test/TEST-18-FAILUREACTION/test.sh | 7 +++++++ + test/TEST-19-DELEGATE/test.sh | 8 ++++++++ + test/TEST-20-MAINPIDGAMES/test.sh | 8 ++++++++ + test/TEST-23-TYPE-EXEC/test.sh | 8 ++++++++ + 12 files changed, 95 insertions(+) + +diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh +index c38e56f72e..97eb2f409e 100755 +--- a/test/TEST-02-CRYPTSETUP/test.sh ++++ b/test/TEST-02-CRYPTSETUP/test.sh +@@ -45,6 +45,14 @@ test_setup() { + + setup_basic_environment + ++ # mask some services that we do not want to run in these tests ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service ++ + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system.conf <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/testsuite.service < +Date: Mon, 21 Oct 2019 18:39:39 +0200 +Subject: [PATCH] test: bump the second partition's size to 50M + +The former size (10M) caused systemd-journald to crash with SIGABRT when +used on a LUKS2 partition, as the LUKS2 metadata consume a significant +part of the 10M partition, thus leaving no space for the journal file +itself (relevant for TEST-02-CRYPTSETUP). This change has been present +in upstream for a while anyway. + +Related: #1761519 +rhel-only +--- + test/test-functions | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/test-functions b/test/test-functions +index af9d16140f..fe25a501da 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -433,7 +433,7 @@ create_empty_image() { + [ -b "$LOOPDEV" ] || return 1 + echo "LOOPDEV=$LOOPDEV" >> $STATEFILE + sfdisk "$LOOPDEV" < +Date: Wed, 25 Jul 2018 08:06:57 -0700 +Subject: [PATCH] shared/sleep-config: exclude zram devices from hibernation + candidates + +On a host with sufficiently large zram but with no actual swap, logind will +respond to CanHibernate() with yes. With this patch, it will correctly respond +no, unless there are other swap devices to consider. + +(cherry picked from commit 411ae92b407bd7b4549b205ad754bcd0e3dfd81f) + +Resolves: #1763617 +--- + src/shared/sleep-config.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c +index 9e4ce183d3..a1523e3f21 100644 +--- a/src/shared/sleep-config.c ++++ b/src/shared/sleep-config.c +@@ -21,6 +21,7 @@ + #include "log.h" + #include "macro.h" + #include "parse-util.h" ++#include "path-util.h" + #include "sleep-config.h" + #include "string-util.h" + #include "strv.h" +@@ -201,9 +202,18 @@ int find_hibernate_location(char **device, char **type, size_t *size, size_t *us + continue; + } + +- if (streq(type_field, "partition") && endswith(dev_field, "\\040(deleted)")) { +- log_warning("Ignoring deleted swapfile '%s'.", dev_field); +- continue; ++ if (streq(type_field, "partition")) { ++ if (endswith(dev_field, "\\040(deleted)")) { ++ log_warning("Ignoring deleted swapfile '%s'.", dev_field); ++ continue; ++ } ++ ++ const char *fn; ++ fn = path_startswith(dev_field, "/dev/"); ++ if (fn && startswith(fn, "zram")) { ++ log_debug("Ignoring compressed ram swap device '%s'.", dev_field); ++ continue; ++ } + } + if (device) + *device = TAKE_PTR(dev_field); diff --git a/SOURCES/0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch b/SOURCES/0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch new file mode 100644 index 0000000..5845313 --- /dev/null +++ b/SOURCES/0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch @@ -0,0 +1,45 @@ +From cc3c020a5f4fc577dbd2da769c22b77e37ae4e30 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 26 Feb 2019 17:33:27 +0100 +Subject: [PATCH] selinux: don't log SELINUX_INFO and SELINUX_WARNING messages + to audit + +Previously we logged even info message from libselinux as USER_AVC's to +audit. For example, setting SELinux to permissive mode generated +following audit message, + +time->Tue Feb 26 11:29:29 2019 +type=USER_AVC msg=audit(1551198569.423:334): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='avc: received setenforce notice (enforcing=0) exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?' + +This is unnecessary and wrong at the same time. First, kernel already +records audit event that SELinux was switched to permissive mode, also +the type of the message really shouldn't be USER_AVC. + +Let's ignore SELINUX_WARNING and SELINUX_INFO and forward to audit only +USER_AVC's and errors as these two libselinux message types have clear +mapping to audit message types. + +(cherry picked from commit 6227fc14c48c4c17daed4b91f61cdd4aa375790a) + +Resolves: #1763612 +--- + src/core/selinux-access.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c +index 39e994afd7..ada4f8705c 100644 +--- a/src/core/selinux-access.c ++++ b/src/core/selinux-access.c +@@ -112,7 +112,11 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { + va_end(ap); + + if (r >= 0) { +- audit_log_user_avc_message(fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0); ++ if (type == SELINUX_AVC) ++ audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0); ++ else if (type == SELINUX_ERROR) ++ audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_SELINUX_ERR, buf, NULL, NULL, NULL, 0); ++ + return 0; + } + } diff --git a/SOURCES/0242-sd-device-introduce-log_device_-macros.patch b/SOURCES/0242-sd-device-introduce-log_device_-macros.patch new file mode 100644 index 0000000..6b13e77 --- /dev/null +++ b/SOURCES/0242-sd-device-introduce-log_device_-macros.patch @@ -0,0 +1,47 @@ +From 0160499e86642f159a972be0196bf7c8a1d19ea8 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Oct 2018 12:04:13 +0900 +Subject: [PATCH] sd-device: introduce log_device_*() macros + +(cherry picked from commit b0cba0ca526ed2d86e283a0fcfebdf0a4d4bea9b) + +Related: #1753369 +--- + src/libsystemd/sd-device/device-util.h | 27 ++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h +index 6dcd2645e6..448dfc63d7 100644 +--- a/src/libsystemd/sd-device/device-util.h ++++ b/src/libsystemd/sd-device/device-util.h +@@ -33,3 +33,30 @@ + for (device = sd_device_enumerator_get_subsystem_first(enumerator); \ + device; \ + device = sd_device_enumerator_get_subsystem_next(enumerator)) ++ ++#define log_device_full(device, level, error, ...) \ ++ ({ \ ++ const char *_sysname = NULL, *_subsystem = NULL; \ ++ sd_device *_d = (device); \ ++ int _level = (level), _error = (error); \ ++ \ ++ if (_d && _unlikely_(log_get_max_level() >= _level)) { \ ++ (void) sd_device_get_sysname(_d, &_sysname); \ ++ (void) sd_device_get_subsystem(_d, &_subsystem); \ ++ } \ ++ log_object_internal(_level, _error, __FILE__, __LINE__, __func__, \ ++ _sysname ? "DEVICE=" : NULL, _sysname, \ ++ _subsystem ? "SUBSYSTEM=" : NULL, _subsystem, ##__VA_ARGS__); \ ++ }) ++ ++#define log_device_debug(link, ...) log_device_full(link, LOG_DEBUG, 0, ##__VA_ARGS__) ++#define log_device_info(link, ...) log_device_full(link, LOG_INFO, 0, ##__VA_ARGS__) ++#define log_device_notice(link, ...) log_device_full(link, LOG_NOTICE, 0, ##__VA_ARGS__) ++#define log_device_warning(link, ...) log_device_full(link, LOG_WARNING, 0, ##__VA_ARGS__) ++#define log_device_error(link, ...) log_device_full(link, LOG_ERR, 0, ##__VA_ARGS__) ++ ++#define log_device_debug_errno(link, error, ...) log_device_full(link, LOG_DEBUG, error, ##__VA_ARGS__) ++#define log_device_info_errno(link, error, ...) log_device_full(link, LOG_INFO, error, ##__VA_ARGS__) ++#define log_device_notice_errno(link, error, ...) log_device_full(link, LOG_NOTICE, error, ##__VA_ARGS__) ++#define log_device_warning_errno(link, error, ...) log_device_full(link, LOG_WARNING, error, ##__VA_ARGS__) ++#define log_device_error_errno(link, error, ...) log_device_full(link, LOG_ERR, error, ##__VA_ARGS__) diff --git a/SOURCES/0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch b/SOURCES/0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch new file mode 100644 index 0000000..0d32c08 --- /dev/null +++ b/SOURCES/0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch @@ -0,0 +1,505 @@ +From 080d3b14470f6ac59f4cfb97a4200ed18df5c260 Mon Sep 17 00:00:00 2001 +From: Fabian Henneke +Date: Wed, 21 Aug 2019 11:17:59 +0200 +Subject: [PATCH] udev: Add id program and rule for FIDO security tokens + +Add a fido_id program meant to be run for devices in the hidraw +subsystem via an IMPORT directive. The program parses the HID report +descriptor and assigns the ID_SECURITY_TOKEN environment variable if a +declared usage matches the FIDO_CTAPHID_USAGE declared in the FIDO CTAP +specification. This replaces the previous approach of whitelisting all +known security token models manually. + +This commit is accompanied by a test suite and a fuzzer target for the +descriptor parsing routine. + +Fixes: #11996. +(cherry picked from commit d45ee2f31a8358db0accde2e7c81777cedadc3c2) + +Resolves: #1753369 +--- + rules/60-fido-id.rules | 7 ++ + rules/meson.build | 1 + + src/fuzz/fuzz-fido-id-desc.c | 23 +++++++ + src/fuzz/fuzz-fido-id-desc.dict | 6 ++ + src/fuzz/meson.build | 4 ++ + src/test/meson.build | 4 ++ + src/test/test-fido-id-desc.c | 85 +++++++++++++++++++++++ + src/udev/fido_id/fido_id.c | 103 ++++++++++++++++++++++++++++ + src/udev/fido_id/fido_id_desc.c | 92 +++++++++++++++++++++++++ + src/udev/fido_id/fido_id_desc.h | 8 +++ + src/udev/meson.build | 3 + + test/fuzz/fuzz-fido-id-desc/crash0 | 1 + + test/fuzz/fuzz-fido-id-desc/crash1 | 1 + + test/fuzz/fuzz-fido-id-desc/report0 | Bin 0 -> 71 bytes + test/fuzz/fuzz-fido-id-desc/report1 | Bin 0 -> 34 bytes + 15 files changed, 338 insertions(+) + create mode 100644 rules/60-fido-id.rules + create mode 100644 src/fuzz/fuzz-fido-id-desc.c + create mode 100644 src/fuzz/fuzz-fido-id-desc.dict + create mode 100644 src/test/test-fido-id-desc.c + create mode 100644 src/udev/fido_id/fido_id.c + create mode 100644 src/udev/fido_id/fido_id_desc.c + create mode 100644 src/udev/fido_id/fido_id_desc.h + create mode 100644 test/fuzz/fuzz-fido-id-desc/crash0 + create mode 100644 test/fuzz/fuzz-fido-id-desc/crash1 + create mode 100644 test/fuzz/fuzz-fido-id-desc/report0 + create mode 100644 test/fuzz/fuzz-fido-id-desc/report1 + +diff --git a/rules/60-fido-id.rules b/rules/60-fido-id.rules +new file mode 100644 +index 0000000000..fcf5079704 +--- /dev/null ++++ b/rules/60-fido-id.rules +@@ -0,0 +1,7 @@ ++# do not edit this file, it will be overwritten on update ++ ++ACTION=="remove", GOTO="fido_id_end" ++ ++SUBSYSTEM=="hidraw", IMPORT{program}="fido_id" ++ ++LABEL="fido_id_end" +diff --git a/rules/meson.build b/rules/meson.build +index b6aae596b6..6363f8bf2e 100644 +--- a/rules/meson.build ++++ b/rules/meson.build +@@ -7,6 +7,7 @@ rules = files(''' + 60-cdrom_id.rules + 60-drm.rules + 60-evdev.rules ++ 60-fido-id.rules + 60-input-id.rules + 60-persistent-alsa.rules + 60-persistent-input.rules +diff --git a/src/fuzz/fuzz-fido-id-desc.c b/src/fuzz/fuzz-fido-id-desc.c +new file mode 100644 +index 0000000000..cf98dee044 +--- /dev/null ++++ b/src/fuzz/fuzz-fido-id-desc.c +@@ -0,0 +1,23 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fido_id/fido_id_desc.h" ++#include "fuzz.h" ++#include "log.h" ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ++ /* We don't want to fill the logs with messages about parse errors. ++ * Disable most logging if not running standalone */ ++ if (!getenv("SYSTEMD_LOG_LEVEL")) ++ log_set_max_level(LOG_CRIT); ++ ++ if (size > HID_MAX_DESCRIPTOR_SIZE) ++ return 0; ++ (void) is_fido_security_token_desc(data, size); ++ ++ return 0; ++} +diff --git a/src/fuzz/fuzz-fido-id-desc.dict b/src/fuzz/fuzz-fido-id-desc.dict +new file mode 100644 +index 0000000000..d2d2679e18 +--- /dev/null ++++ b/src/fuzz/fuzz-fido-id-desc.dict +@@ -0,0 +1,6 @@ ++"\xfe" ++"\x00" ++"\x01" ++"\xf1" ++"\xd0" ++"\xf1\xd0\x00\x01" +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 1dbe28e57e..483a952421 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -47,4 +47,8 @@ fuzzers += [ + [libsystemd_journal_remote, + libshared], + []], ++ [['src/fuzz/fuzz-fido-id-desc.c', ++ 'src/udev/fido_id/fido_id_desc.c'], ++ [], ++ []] + ] +diff --git a/src/test/meson.build b/src/test/meson.build +index 0998f59897..4259421f98 100644 +--- a/src/test/meson.build ++++ b/src/test/meson.build +@@ -663,6 +663,10 @@ tests += [ + [['src/test/test-bus-util.c'], + [], + []], ++ [['src/test/test-fido-id-desc.c', ++ 'src/udev/fido_id/fido_id_desc.c'], ++ [], ++ []], + ] + + ############################################################ +diff --git a/src/test/test-fido-id-desc.c b/src/test/test-fido-id-desc.c +new file mode 100644 +index 0000000000..cf55dd3266 +--- /dev/null ++++ b/src/test/test-fido-id-desc.c +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include ++#include ++ ++#include "fido_id/fido_id_desc.h" ++#include "macro.h" ++ ++static void test_is_fido_security_token_desc__fido(void) { ++ static const uint8_t FIDO_HID_DESC_1[] = { ++ 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, ++ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, ++ 0x40, 0x91, 0x02, 0xc0, ++ }; ++ assert_se(is_fido_security_token_desc(FIDO_HID_DESC_1, sizeof(FIDO_HID_DESC_1)) > 0); ++ ++ static const uint8_t FIDO_HID_DESC_2[] = { ++ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, ++ 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, ++ 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, ++ 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65, ++ 0x81, 0x00, 0x09, 0x03, 0x75, 0x08, 0x95, 0x08, 0xb1, 0x02, 0xc0, ++ 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, ++ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, ++ 0x40, 0x91, 0x02, 0xc0, ++ }; ++ assert_se(is_fido_security_token_desc(FIDO_HID_DESC_2, sizeof(FIDO_HID_DESC_2)) > 0); ++} ++ ++static void test_is_fido_security_token_desc__non_fido(void) { ++ /* Wrong usage page */ ++ static const uint8_t NON_FIDO_HID_DESC_1[] = { ++ 0x06, 0xd0, 0xf0, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, ++ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, ++ 0x40, 0x91, 0x02, 0xc0, ++ }; ++ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_1, sizeof(NON_FIDO_HID_DESC_1)) == 0); ++ ++ /* Wrong usage */ ++ static const uint8_t NON_FIDO_HID_DESC_2[] = { ++ 0x06, 0xd0, 0xf1, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, ++ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, ++ 0x40, 0x91, 0x02, 0xc0, ++ }; ++ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_2, sizeof(NON_FIDO_HID_DESC_2)) == 0); ++ ++ static const uint8_t NON_FIDO_HID_DESC_3[] = { ++ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, ++ 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, ++ 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, ++ 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65, ++ 0x81, 0x00, 0x09, 0x03, 0x75, 0x08, 0x95, 0x08, 0xb1, 0x02, 0xc0, ++ }; ++ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_3, sizeof(NON_FIDO_HID_DESC_3)) == 0); ++} ++ ++static void test_is_fido_security_token_desc__invalid(void) { ++ /* Size coded on 1 byte, but no byte given */ ++ static const uint8_t INVALID_HID_DESC_1[] = { 0x01 }; ++ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_1, sizeof(INVALID_HID_DESC_1)) < 0); ++ ++ /* Size coded on 2 bytes, but only 1 byte given */ ++ static const uint8_t INVALID_HID_DESC_2[] = { 0x02, 0x01 }; ++ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_2, sizeof(INVALID_HID_DESC_2)) < 0); ++ ++ /* Size coded on 4 bytes, but only 3 bytes given */ ++ static const uint8_t INVALID_HID_DESC_3[] = { 0x03, 0x01, 0x02, 0x03 }; ++ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_3, sizeof(INVALID_HID_DESC_3)) < 0); ++ ++ /* Long item without a size byte */ ++ static const uint8_t INVALID_HID_DESC_4[] = { 0xfe }; ++ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_4, sizeof(INVALID_HID_DESC_4)) < 0); ++ ++ /* Usage pages are coded on at most 2 bytes */ ++ static const uint8_t INVALID_HID_DESC_5[] = { 0x07, 0x01, 0x02, 0x03, 0x04 }; ++ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_5, sizeof(INVALID_HID_DESC_5)) < 0); ++} ++ ++int main(int argc, char *argv[]) { ++ test_is_fido_security_token_desc__fido(); ++ test_is_fido_security_token_desc__non_fido(); ++ test_is_fido_security_token_desc__invalid(); ++ ++ return EXIT_SUCCESS; ++} +diff --git a/src/udev/fido_id/fido_id.c b/src/udev/fido_id/fido_id.c +new file mode 100644 +index 0000000000..7e1cc804f2 +--- /dev/null ++++ b/src/udev/fido_id/fido_id.c +@@ -0,0 +1,103 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++/* ++ * Identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on the usage declared in their report ++ * descriptor and outputs suitable environment variables. ++ * ++ * Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c' ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sd-device.h" ++ ++#include "device-internal.h" ++#include "device-private.h" ++#include "device-util.h" ++#include "fd-util.h" ++#include "fido_id_desc.h" ++#include "log.h" ++#include "macro.h" ++#include "path-util.h" ++#include "string-util.h" ++#include "udev-util.h" ++ ++static int run(int argc, char **argv) { ++ _cleanup_(sd_device_unrefp) struct sd_device *device = NULL; ++ _cleanup_free_ char *desc_path = NULL; ++ _cleanup_close_ int fd = -1; ++ ++ struct sd_device *hid_device; ++ const char *sys_path; ++ uint8_t desc[HID_MAX_DESCRIPTOR_SIZE]; ++ ssize_t desc_len; ++ ++ int r; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ udev_parse_config(); ++ log_parse_environment(); ++ log_open(); ++ ++ if (argc > 2) ++ return log_error_errno(EINVAL, "Usage: %s [SYSFS_PATH]", program_invocation_short_name); ++ ++ if (argc == 1) { ++ r = device_new_from_strv(&device, environ); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get current device from environment: %m"); ++ } else { ++ r = sd_device_new_from_syspath(&device, argv[1]); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get device from syspath: %m"); ++ } ++ ++ r = sd_device_get_parent(device, &hid_device); ++ if (r < 0) ++ return log_device_error_errno(device, r, "Failed to get parent HID device: %m"); ++ ++ r = sd_device_get_syspath(hid_device, &sys_path); ++ if (r < 0) ++ return log_device_error_errno(hid_device, r, "Failed to get syspath for HID device: %m"); ++ ++ desc_path = path_join(NULL, sys_path, "report_descriptor"); ++ if (!desc_path) ++ return log_oom(); ++ ++ fd = open(desc_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); ++ if (fd < 0) ++ return log_device_error_errno(hid_device, errno, ++ "Failed to open report descriptor at '%s': %m", desc_path); ++ ++ desc_len = read(fd, desc, sizeof(desc)); ++ if (desc_len < 0) ++ return log_device_error_errno(hid_device, errno, ++ "Failed to read report descriptor at '%s': %m", desc_path); ++ if (desc_len == 0) ++ return log_device_debug_errno(hid_device, EINVAL, ++ "Empty report descriptor at '%s'.", desc_path); ++ ++ r = is_fido_security_token_desc(desc, desc_len); ++ if (r < 0) ++ return log_device_debug_errno(hid_device, r, ++ "Failed to parse report descriptor at '%s'.", desc_path); ++ if (r > 0) { ++ printf("ID_FIDO_TOKEN=1\n"); ++ printf("ID_SECURITY_TOKEN=1\n"); ++ } ++ ++ return 0; ++} ++ ++int main(int argc, char *argv[]) { ++ int r; ++ ++ r = run(argc, argv); ++ ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} +diff --git a/src/udev/fido_id/fido_id_desc.c b/src/udev/fido_id/fido_id_desc.c +new file mode 100644 +index 0000000000..bbfcf93709 +--- /dev/null ++++ b/src/udev/fido_id/fido_id_desc.c +@@ -0,0 +1,92 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++/* Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c' */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fido_id_desc.h" ++ ++#define HID_RPTDESC_FIRST_BYTE_LONG_ITEM 0xfeu ++#define HID_RPTDESC_TYPE_GLOBAL 0x1u ++#define HID_RPTDESC_TYPE_LOCAL 0x2u ++#define HID_RPTDESC_TAG_USAGE_PAGE 0x0u ++#define HID_RPTDESC_TAG_USAGE 0x0u ++ ++/* ++ * HID usage for FIDO CTAP1 ("U2F") and CTAP2 security tokens. ++ * https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-u2f-u2f_hid.h-v1.0-ps-20141009.txt ++ * https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#usb-discovery ++ * https://www.usb.org/sites/default/files/hutrr48.pdf ++ */ ++#define FIDO_FULL_USAGE_CTAPHID 0xf1d00001u ++ ++/* ++ * Parses a HID report descriptor and identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on their ++ * declared usage. ++ * A positive return value indicates that the report descriptor belongs to a FIDO security token. ++ * https://www.usb.org/sites/default/files/documents/hid1_11.pdf (Section 6.2.2) ++ */ ++int is_fido_security_token_desc(const uint8_t *desc, size_t desc_len) { ++ uint32_t usage = 0; ++ ++ for (size_t pos = 0; pos < desc_len; ) { ++ uint8_t tag, type, size_code; ++ size_t size; ++ uint32_t value; ++ ++ /* Report descriptors consists of short items (1-5 bytes) and long items (3-258 bytes). */ ++ if (desc[pos] == HID_RPTDESC_FIRST_BYTE_LONG_ITEM) { ++ /* No long items are defined in the spec; skip them. ++ * The length of the data in a long item is contained in the byte after the long ++ * item tag. The header consists of three bytes: special long item tag, length, ++ * actual tag. */ ++ if (pos + 1 >= desc_len) ++ return -EINVAL; ++ pos += desc[pos + 1] + 3; ++ continue; ++ } ++ ++ /* The first byte of a short item encodes tag, type and size. */ ++ tag = desc[pos] >> 4; /* Bits 7 to 4 */ ++ type = (desc[pos] >> 2) & 0x3; /* Bits 3 and 2 */ ++ size_code = desc[pos] & 0x3; /* Bits 1 and 0 */ ++ /* Size is coded as follows: ++ * 0 -> 0 bytes, 1 -> 1 byte, 2 -> 2 bytes, 3 -> 4 bytes ++ */ ++ size = size_code < 3 ? size_code : 4; ++ /* Consume header byte. */ ++ pos++; ++ ++ /* Extract the item value coded on size bytes. */ ++ if (pos + size > desc_len) ++ return -EINVAL; ++ value = 0; ++ for (size_t i = 0; i < size; i++) ++ value |= (uint32_t) desc[pos + i] << (8 * i); ++ /* Consume value bytes. */ ++ pos += size; ++ ++ if (type == HID_RPTDESC_TYPE_GLOBAL && tag == HID_RPTDESC_TAG_USAGE_PAGE) { ++ /* A usage page is a 16 bit value coded on at most 16 bits. */ ++ if (size > 2) ++ return -EINVAL; ++ /* A usage page sets the upper 16 bits of a following usage. */ ++ usage = (value & 0x0000ffffu) << 16; ++ } ++ ++ if (type == HID_RPTDESC_TYPE_LOCAL && tag == HID_RPTDESC_TAG_USAGE) { ++ /* A usage is a 32 bit value, but is prepended with the current usage page if ++ * coded on less than 4 bytes (that is, at most 2 bytes). */ ++ if (size == 4) ++ usage = value; ++ else ++ usage = (usage & 0xffff0000u) | (value & 0x0000ffffu); ++ if (usage == FIDO_FULL_USAGE_CTAPHID) ++ return 1; ++ } ++ } ++ ++ return 0; ++} +diff --git a/src/udev/fido_id/fido_id_desc.h b/src/udev/fido_id/fido_id_desc.h +new file mode 100644 +index 0000000000..c813a3a454 +--- /dev/null ++++ b/src/udev/fido_id/fido_id_desc.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#pragma once ++ ++#include ++#include ++ ++int is_fido_security_token_desc(const uint8_t *desc, size_t desc_len); +diff --git a/src/udev/meson.build b/src/udev/meson.build +index 3bcd2bd3d7..5931a6da7d 100644 +--- a/src/udev/meson.build ++++ b/src/udev/meson.build +@@ -160,6 +160,9 @@ libudev_core = static_library( + foreach prog : [['ata_id/ata_id.c'], + ['cdrom_id/cdrom_id.c'], + ['collect/collect.c'], ++ ['fido_id/fido_id.c', ++ 'fido_id/fido_id_desc.c', ++ 'fido_id/fido_id_desc.h'], + ['scsi_id/scsi_id.c', + 'scsi_id/scsi_id.h', + 'scsi_id/scsi_serial.c', +diff --git a/test/fuzz/fuzz-fido-id-desc/crash0 b/test/fuzz/fuzz-fido-id-desc/crash0 +new file mode 100644 +index 0000000000..e066656502 +--- /dev/null ++++ b/test/fuzz/fuzz-fido-id-desc/crash0 +@@ -0,0 +1 @@ ++Ì +\ No newline at end of file +diff --git a/test/fuzz/fuzz-fido-id-desc/crash1 b/test/fuzz/fuzz-fido-id-desc/crash1 +new file mode 100644 +index 0000000000..aef3e18335 +--- /dev/null ++++ b/test/fuzz/fuzz-fido-id-desc/crash1 +@@ -0,0 +1 @@ ++øûøûûÜ +\ No newline at end of file +diff --git a/test/fuzz/fuzz-fido-id-desc/report0 b/test/fuzz/fuzz-fido-id-desc/report0 +new file mode 100644 +index 0000000000000000000000000000000000000000..48757cba682ffddd5a1ddd8988bb8bcdc7db0a7a +GIT binary patch +literal 71 +zcmZQ& +Date: Tue, 27 Aug 2019 19:00:34 +0200 +Subject: [PATCH] shared/but-util: drop trusted annotation from + bus_open_system_watch_bind_with_description() + +https://bugzilla.redhat.com/show_bug.cgi?id=1746057 + +This only affects systemd-resolved. bus_open_system_watch_bind_with_description() +is also used in timesyncd, but it has no methods, only read-only properties, and +in networkd, but it annotates all methods with SD_BUS_VTABLE_UNPRIVILEGED and does +polkit checks. + +Resolves: #1746857 +--- + src/shared/bus-util.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c +index a4f2deba31..302dbb4c2e 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -1699,10 +1699,6 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri + if (r < 0) + return r; + +- r = sd_bus_set_trusted(bus, true); +- if (r < 0) +- return r; +- + r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS); + if (r < 0) + return r; diff --git a/SOURCES/0245-sd-bus-adjust-indentation-of-comments.patch b/SOURCES/0245-sd-bus-adjust-indentation-of-comments.patch new file mode 100644 index 0000000..bdb144e --- /dev/null +++ b/SOURCES/0245-sd-bus-adjust-indentation-of-comments.patch @@ -0,0 +1,50 @@ +From 7e0f9a0cd4053fcc713a99ada3d0d50793b83564 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 27 Aug 2019 19:00:50 +0200 +Subject: [PATCH] sd-bus: adjust indentation of comments + +Related: #1746857 +--- + src/libsystemd/sd-bus/sd-bus.c | 3 +-- + src/shared/bus-util.c | 7 ++++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 3583e24e64..1c9e967ae0 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -1341,8 +1341,7 @@ _public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *descrip + b->bus_client = true; + b->is_user = true; + +- /* We don't do any per-method access control on the user +- * bus. */ ++ /* We don't do any per-method access control on the user bus. */ + b->trusted = true; + b->is_local = true; + +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c +index 302dbb4c2e..2d908eb45c 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -1675,7 +1675,8 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri + + assert(ret); + +- /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */ ++ /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal ++ * turned on. */ + + r = sd_bus_new(&bus); + if (r < 0) +@@ -1890,8 +1891,8 @@ int bus_reply_pair_array(sd_bus_message *m, char **l) { + + assert(m); + +- /* Reply to the specified message with a message containing a dictionary put together from the specified +- * strv */ ++ /* Reply to the specified message with a message containing a dictionary put together from the ++ * specified strv */ + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) diff --git a/SOURCES/0246-resolved-do-not-run-loop-twice.patch b/SOURCES/0246-resolved-do-not-run-loop-twice.patch new file mode 100644 index 0000000..70fdf78 --- /dev/null +++ b/SOURCES/0246-resolved-do-not-run-loop-twice.patch @@ -0,0 +1,46 @@ +From d95afbca80cf52f0bc84b2e1b4af6aadda007138 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 27 Aug 2019 19:02:53 +0200 +Subject: [PATCH] resolved: do not run loop twice + +This doesn't matter much, but let's just do the loop once and allocate +the populate the result set on the fly. If we find an error, it'll get +cleaned up automatically. + +Related: #1746857 +--- + src/resolve/resolved-link-bus.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c +index b1581740d8..46d2b11636 100644 +--- a/src/resolve/resolved-link-bus.c ++++ b/src/resolve/resolved-link-bus.c +@@ -492,6 +492,10 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v + if (r < 0) + return r; + ++ ns = set_new(&dns_name_hash_ops); ++ if (!ns) ++ return -ENOMEM; ++ + r = sd_bus_message_read_strv(message, &ntas); + if (r < 0) + return r; +@@ -501,14 +505,9 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v + if (r < 0) + return r; + if (r == 0) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i); +- } ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, ++ "Invalid negative trust anchor domain: %s", *i); + +- ns = set_new(&dns_name_hash_ops); +- if (!ns) +- return -ENOMEM; +- +- STRV_FOREACH(i, ntas) { + r = set_put_strdup(ns, *i); + if (r < 0) + return r; diff --git a/SOURCES/0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch b/SOURCES/0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch new file mode 100644 index 0000000..5e2b359 --- /dev/null +++ b/SOURCES/0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch @@ -0,0 +1,347 @@ +From ddd08e75b1e7fa1f6dfef3d30a0c1ef8c63e4d07 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 27 Aug 2019 19:25:05 +0200 +Subject: [PATCH] resolved: allow access to Set*Link and Revert methods through + polkit + +This matches what is done in networkd very closely. In fact even the +policy descriptions are all identical (with s/network/resolve), except +for the last one: +resolved has org.freedesktop.resolve1.revert while +networkd has org.freedesktop.network1.revert-ntp and +org.freedesktop.network1.revert-dns so the description is a bit different. + +Conflicts: + src/resolve/resolved-bus.c + src/resolve/resolved-link-bus.c + +Related: #1746857 +--- + src/resolve/org.freedesktop.resolve1.policy | 99 +++++++++++++++++++++ + src/resolve/resolved-bus.c | 22 ++--- + src/resolve/resolved-link-bus.c | 97 +++++++++++++++++--- + 3 files changed, 197 insertions(+), 21 deletions(-) + +diff --git a/src/resolve/org.freedesktop.resolve1.policy b/src/resolve/org.freedesktop.resolve1.policy +index b65ba3e56a..592c4eb8b0 100644 +--- a/src/resolve/org.freedesktop.resolve1.policy ++++ b/src/resolve/org.freedesktop.resolve1.policy +@@ -40,4 +40,103 @@ + unix-user:systemd-resolve + + ++ ++ Set DNS servers ++ Authentication is required to set DNS servers. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Set domains ++ Authentication is required to set domains. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Set default route ++ Authentication is required to set default route. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Enable/disable LLMNR ++ Authentication is required to enable or disable LLMNR. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Enable/disable multicast DNS ++ Authentication is required to enable or disable multicast DNS. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Enable/disable DNS over TLS ++ Authentication is required to enable or disable DNS over TLS. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Enable/disable DNSSEC ++ Authentication is required to enable or disable DNSSEC. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Set DNSSEC Negative Trust Anchors ++ Authentication is required to set DNSSEC Negative Trust Anchros. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ ++ ++ Revert name resolution settings ++ Authentication is required to revert name resolution settings. ++ ++ auth_admin ++ auth_admin ++ auth_admin_keep ++ ++ unix-user:systemd-resolve ++ ++ + +diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c +index da0a909dd6..4d6cc4fd48 100644 +--- a/src/resolve/resolved-bus.c ++++ b/src/resolve/resolved-bus.c +@@ -1848,18 +1848,18 @@ static const sd_bus_vtable resolve_vtable[] = { + SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), +- SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0), +- SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0), ++ SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), +- SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), +- SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0), +- SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0), +- SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, 0), +- SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0), +- SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0), +- SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0), ++ SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_METHOD("RegisterService", "sssqqqaa{say}", "o", bus_method_register_service, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("UnregisterService", "o", NULL, bus_method_unregister_service, SD_BUS_VTABLE_UNPRIVILEGED), +diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c +index 46d2b11636..bf3e42264e 100644 +--- a/src/resolve/resolved-link-bus.c ++++ b/src/resolve/resolved-link-bus.c +@@ -1,5 +1,9 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + ++#include ++#include ++#include ++ + #include "alloc-util.h" + #include "bus-common-errors.h" + #include "bus-util.h" +@@ -9,6 +13,7 @@ + #include "resolved-link-bus.h" + #include "resolved-resolv-conf.h" + #include "strv.h" ++#include "user-util.h" + + static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported); + static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string); +@@ -235,6 +240,15 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ + if (r < 0) + return r; + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-dns-servers", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + dns_server_mark_all(l->dns_servers); + + for (i = 0; i < n; i++) { +@@ -298,12 +312,21 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain"); + } + +- dns_search_domain_mark_all(l->search_domains); +- + r = sd_bus_message_rewind(message, false); + if (r < 0) + return r; + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-domains", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ ++ dns_search_domain_mark_all(l->search_domains); ++ + for (;;) { + DnsSearchDomain *d; + const char *name; +@@ -371,6 +394,15 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr); + } + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-llmnr", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + l->llmnr_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); +@@ -405,6 +437,15 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns); + } + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-mdns", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + l->mdns_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); +@@ -439,6 +480,15 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls); + } + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-dns-over-tls", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + link_set_dns_over_tls_mode(l, mode); + + (void) link_save_user(l); +@@ -471,6 +521,15 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec); + } + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-dnssec", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + link_set_dnssec_mode(l, mode); + + (void) link_save_user(l); +@@ -513,6 +572,15 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v + return r; + } + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.set-dnssec-negative-trust-anchors", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + set_free_free(l->dnssec_negative_trust_anchors); + l->dnssec_negative_trust_anchors = TAKE_PTR(ns); + +@@ -532,6 +600,15 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error + if (r < 0) + return r; + ++ r = bus_verify_polkit_async(message, CAP_NET_ADMIN, ++ "org.freedesktop.resolve1.revert", ++ NULL, true, UID_INVALID, ++ &l->manager->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + link_flush_settings(l); + link_allocate_scopes(l); + link_add_rrs(l, false); +@@ -556,14 +633,14 @@ const sd_bus_vtable link_vtable[] = { + SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0), + SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0), + +- SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0), +- SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0), +- SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0), +- SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0), +- SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, 0), +- SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0), +- SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0), +- SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0), ++ SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_VTABLE_END + }; diff --git a/SOURCES/0248-resolved-query-polkit-only-after-parsing-the-data.patch b/SOURCES/0248-resolved-query-polkit-only-after-parsing-the-data.patch new file mode 100644 index 0000000..eac8530 --- /dev/null +++ b/SOURCES/0248-resolved-query-polkit-only-after-parsing-the-data.patch @@ -0,0 +1,48 @@ +From 7b00cae817e54ee3398ad3b42ec69a3b63676562 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 27 Aug 2019 19:28:19 +0200 +Subject: [PATCH] resolved: query polkit only after parsing the data + +That's what we do everywhere else because it leads to nicer user experience. + +Related: #1746857 +--- + src/resolve/resolved-bus.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c +index 4d6cc4fd48..3f6a6f9e12 100644 +--- a/src/resolve/resolved-bus.c ++++ b/src/resolve/resolved-bus.c +@@ -1632,15 +1632,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata, + if (m->mdns_support != RESOLVE_SUPPORT_YES) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled"); + +- r = bus_verify_polkit_async(message, CAP_SYS_ADMIN, +- "org.freedesktop.resolve1.register-service", +- NULL, false, UID_INVALID, +- &m->polkit_registry, error); +- if (r < 0) +- return r; +- if (r == 0) +- return 1; /* Polkit will call us back */ +- + service = new0(DnssdService, 1); + if (!service) + return log_oom(); +@@ -1765,6 +1756,15 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata, + if (r < 0) + return r; + ++ r = bus_verify_polkit_async(message, CAP_SYS_ADMIN, ++ "org.freedesktop.resolve1.register-service", ++ NULL, false, UID_INVALID, ++ &m->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* Polkit will call us back */ ++ + r = hashmap_ensure_allocated(&m->dnssd_services, &string_hash_ops); + if (r < 0) + return r; diff --git a/SOURCES/0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch b/SOURCES/0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch new file mode 100644 index 0000000..932a2fc --- /dev/null +++ b/SOURCES/0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch @@ -0,0 +1,48 @@ +From 4d2145e3edd6ba6ac2e52a232fa5059ecdacaead Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 24 Dec 2018 00:29:56 +0100 +Subject: [PATCH] journal: rely on _cleanup_free_ to free a temporary string + used in client_context_read_cgroup + +Closes https://github.com/systemd/systemd/issues/11253. + +(cherry picked from commit ef30f7cac18a810814ada7e6a68a31d48cc9fccd) + +Resolves: #1764560 +--- + src/journal/journald-context.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c +index c8e97e16de..3a768094d9 100644 +--- a/src/journal/journald-context.c ++++ b/src/journal/journald-context.c +@@ -282,7 +282,7 @@ static int client_context_read_label( + } + + static int client_context_read_cgroup(Server *s, ClientContext *c, const char *unit_id) { +- char *t = NULL; ++ _cleanup_free_ char *t = NULL; + int r; + + assert(c); +@@ -290,7 +290,6 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u + /* Try to acquire the current cgroup path */ + r = cg_pid_get_path_shifted(c->pid, s->cgroup_root, &t); + if (r < 0 || empty_or_root(t)) { +- + /* We use the unit ID passed in as fallback if we have nothing cached yet and cg_pid_get_path_shifted() + * failed or process is running in a root cgroup. Zombie processes are automatically migrated to root cgroup + * on cgroupsv1 and we want to be able to map log messages from them too. */ +@@ -304,10 +303,8 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u + } + + /* Let's shortcut this if the cgroup path didn't change */ +- if (streq_ptr(c->cgroup, t)) { +- free(t); ++ if (streq_ptr(c->cgroup, t)) + return 0; +- } + + free_and_replace(c->cgroup, t); + diff --git a/SOURCES/0250-basic-user-util-allow-dots-in-user-names.patch b/SOURCES/0250-basic-user-util-allow-dots-in-user-names.patch new file mode 100644 index 0000000..4b03b91 --- /dev/null +++ b/SOURCES/0250-basic-user-util-allow-dots-in-user-names.patch @@ -0,0 +1,90 @@ +From 76176de0889c3e8b9b3a176da24e4f8dbbd380a3 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 2 Oct 2019 11:59:41 +0200 +Subject: [PATCH] basic/user-util: allow dots in user names + +(based on commit 1a29610f5fa1bcb2eeb37d2c6b79d8d1a6dbb865) + +Resolves: #1717603 +--- + src/basic/user-util.c | 9 ++++++--- + src/test/test-user-util.c | 8 ++++---- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/basic/user-util.c b/src/basic/user-util.c +index c533f67025..d92969c966 100644 +--- a/src/basic/user-util.c ++++ b/src/basic/user-util.c +@@ -575,11 +575,14 @@ bool valid_user_group_name(const char *u) { + /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, + * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules: + * +- * - We don't allow any dots (this would break chown syntax which permits dots as user/group name separator) + * - We require that names fit into the appropriate utmp field + * - We don't allow empty user names + * + * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters. ++ * ++ * jsynacek: We now allow dots in user names. The checks are not exhaustive as user names like "..." are allowed ++ * and valid according to POSIX, but can't be created using useradd. However, ".user" can be created. Let's not ++ * complicate the code by adding additional checks for weird corner cases like these, as they don't really matter here. + */ + + if (isempty(u)) +@@ -587,14 +590,14 @@ bool valid_user_group_name(const char *u) { + + if (!(u[0] >= 'a' && u[0] <= 'z') && + !(u[0] >= 'A' && u[0] <= 'Z') && +- u[0] != '_') ++ u[0] != '_' && u[0] != '.') + return false; + + for (i = u+1; *i; i++) { + if (!(*i >= 'a' && *i <= 'z') && + !(*i >= 'A' && *i <= 'Z') && + !(*i >= '0' && *i <= '9') && +- !IN_SET(*i, '_', '-')) ++ !IN_SET(*i, '_', '-', '.')) + return false; + } + +diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c +index c1428fab02..9114d30b8c 100644 +--- a/src/test/test-user-util.c ++++ b/src/test/test-user-util.c +@@ -71,8 +71,6 @@ static void test_valid_user_group_name(void) { + assert_se(!valid_user_group_name("-1")); + assert_se(!valid_user_group_name("-kkk")); + assert_se(!valid_user_group_name("rööt")); +- assert_se(!valid_user_group_name(".")); +- assert_se(!valid_user_group_name("eff.eff")); + assert_se(!valid_user_group_name("foo\nbar")); + assert_se(!valid_user_group_name("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id("aaa:bbb")); +@@ -83,6 +81,8 @@ static void test_valid_user_group_name(void) { + assert_se(valid_user_group_name("_kkk")); + assert_se(valid_user_group_name("kkk-")); + assert_se(valid_user_group_name("kk-k")); ++ assert_se(valid_user_group_name(".moo")); ++ assert_se(valid_user_group_name("eff.eff")); + + assert_se(valid_user_group_name("some5")); + assert_se(!valid_user_group_name("5some")); +@@ -102,8 +102,6 @@ static void test_valid_user_group_name_or_id(void) { + assert_se(!valid_user_group_name_or_id("-1")); + assert_se(!valid_user_group_name_or_id("-kkk")); + assert_se(!valid_user_group_name_or_id("rööt")); +- assert_se(!valid_user_group_name_or_id(".")); +- assert_se(!valid_user_group_name_or_id("eff.eff")); + assert_se(!valid_user_group_name_or_id("foo\nbar")); + assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id("aaa:bbb")); +@@ -114,6 +112,8 @@ static void test_valid_user_group_name_or_id(void) { + assert_se(valid_user_group_name_or_id("_kkk")); + assert_se(valid_user_group_name_or_id("kkk-")); + assert_se(valid_user_group_name_or_id("kk-k")); ++ assert_se(valid_user_group_name_or_id(".moo")); ++ assert_se(valid_user_group_name_or_id("eff.eff")); + + assert_se(valid_user_group_name_or_id("some5")); + assert_se(!valid_user_group_name_or_id("5some")); diff --git a/SOURCES/0251-sd-bus-bump-message-queue-size-again.patch b/SOURCES/0251-sd-bus-bump-message-queue-size-again.patch new file mode 100644 index 0000000..5fd7ade --- /dev/null +++ b/SOURCES/0251-sd-bus-bump-message-queue-size-again.patch @@ -0,0 +1,29 @@ +From 62623bafd9ce4842122ddeda83f9527e43b9a21f Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 8 Nov 2019 14:54:30 +0100 +Subject: [PATCH] sd-bus: bump message queue size again + +Simliarly to issue #4068, the current limit turns out to be too small for a +big storage setup that uses many small disks. Let's bump it further. + +(cherry picked from commit 83a32ea7b03d6707b8e5bb90a0b3a6eb868ef633) +Resolves: #1770189 +--- + src/libsystemd/sd-bus/bus-internal.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h +index 90e6028983..5d773b14c4 100644 +--- a/src/libsystemd/sd-bus/bus-internal.h ++++ b/src/libsystemd/sd-bus/bus-internal.h +@@ -328,8 +328,8 @@ struct sd_bus { + * with enough entropy yet and might delay the boot */ + #define BUS_AUTH_TIMEOUT ((usec_t) DEFAULT_TIMEOUT_USEC) + +-#define BUS_WQUEUE_MAX (192*1024) +-#define BUS_RQUEUE_MAX (192*1024) ++#define BUS_WQUEUE_MAX (384*1024) ++#define BUS_RQUEUE_MAX (384*1024) + + #define BUS_MESSAGE_SIZE_MAX (128*1024*1024) + #define BUS_AUTH_SIZE_MAX (64*1024) diff --git a/SOURCES/0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch b/SOURCES/0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch new file mode 100644 index 0000000..532dd60 --- /dev/null +++ b/SOURCES/0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch @@ -0,0 +1,109 @@ +From 18a45cf91dbdd075fb55d752f959e84d36f3ab3b Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 7 Sep 2018 06:13:17 +0000 +Subject: [PATCH] tests: put fuzz_journald_processing_function in a .c file + +(cherry picked from commit 231dca5579cfba6175d19eee5347d693893fb5aa) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald.c | 30 ++++++++++++++++++++++++++++++ + src/fuzz/fuzz-journald.h | 24 ++---------------------- + src/fuzz/meson.build | 6 ++++-- + 3 files changed, 36 insertions(+), 24 deletions(-) + create mode 100644 src/fuzz/fuzz-journald.c + +diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c +new file mode 100644 +index 0000000000..f271d7f2fe +--- /dev/null ++++ b/src/fuzz/fuzz-journald.c +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "alloc-util.h" ++#include "fuzz-journald.h" ++#include "journald-server.h" ++#include "sd-event.h" ++ ++void fuzz_journald_processing_function( ++ const uint8_t *data, ++ size_t size, ++ void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) ++ ) { ++ Server s = {}; ++ char *label = NULL; ++ size_t label_len = 0; ++ struct ucred *ucred = NULL; ++ struct timeval *tv = NULL; ++ ++ if (size == 0) ++ return; ++ ++ assert_se(sd_event_default(&s.event) >= 0); ++ s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1; ++ s.buffer = memdup_suffix0(data, size); ++ assert_se(s.buffer); ++ s.buffer_size = size + 1; ++ s.storage = STORAGE_NONE; ++ (*f)(&s, s.buffer, size, ucred, tv, label, label_len); ++ server_done(&s); ++} +diff --git a/src/fuzz/fuzz-journald.h b/src/fuzz/fuzz-journald.h +index e66ef54c9b..e9d32a74aa 100644 +--- a/src/fuzz/fuzz-journald.h ++++ b/src/fuzz/fuzz-journald.h +@@ -1,30 +1,10 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + #pragma once + +-#include "alloc-util.h" + #include "journald-server.h" +-#include "sd-event.h" + +-static void fuzz_journald_processing_function( ++void fuzz_journald_processing_function( + const uint8_t *data, + size_t size, + void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) +- ) { +- Server s = {}; +- char *label = NULL; +- size_t label_len = 0; +- struct ucred *ucred = NULL; +- struct timeval *tv = NULL; +- +- if (size == 0) +- return; +- +- assert_se(sd_event_default(&s.event) >= 0); +- s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1; +- s.buffer = memdup_suffix0(data, size); +- assert_se(s.buffer); +- s.buffer_size = size + 1; +- s.storage = STORAGE_NONE; +- (*f)(&s, s.buffer, size, ucred, tv, label, label_len); +- server_done(&s); +-} ++); +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 483a952421..1f8631bcc0 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -33,12 +33,14 @@ fuzzers += [ + libshared], + [libmount]], + +- [['src/fuzz/fuzz-journald-native.c'], ++ [['src/fuzz/fuzz-journald-native.c', ++ 'src/fuzz/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + +- [['src/fuzz/fuzz-journald-syslog.c'], ++ [['src/fuzz/fuzz-journald-syslog.c', ++ 'src/fuzz/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], diff --git a/SOURCES/0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch b/SOURCES/0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch new file mode 100644 index 0000000..6e01bbf --- /dev/null +++ b/SOURCES/0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch @@ -0,0 +1,129 @@ +From e7e70f575840cd021f6429f264911ae0cbff9741 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Thu, 15 Nov 2018 17:52:57 +0100 +Subject: [PATCH] tests: add a fuzzer for dev_kmsg_record + +(cherry picked from commit 8857fb9beb9dcb95a6ce1be14dc94c4dc4cd3ea3) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-kmsg.c | 29 +++++++++++++++++++ + src/fuzz/meson.build | 5 ++++ + src/journal/journald-kmsg.c | 2 +- + src/journal/journald-kmsg.h | 2 ++ + test/fuzz/fuzz-journald-kmsg/basic | 1 + + test/fuzz/fuzz-journald-kmsg/dev-null | 2 ++ + test/fuzz/fuzz-journald-kmsg/loopback | 2 ++ + .../fuzz-journald-kmsg/subsystem-loopback | 2 ++ + 8 files changed, 44 insertions(+), 1 deletion(-) + create mode 100644 src/fuzz/fuzz-journald-kmsg.c + create mode 100644 test/fuzz/fuzz-journald-kmsg/basic + create mode 100644 test/fuzz/fuzz-journald-kmsg/dev-null + create mode 100644 test/fuzz/fuzz-journald-kmsg/loopback + create mode 100644 test/fuzz/fuzz-journald-kmsg/subsystem-loopback + +diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c +new file mode 100644 +index 0000000000..5d99d244b5 +--- /dev/null ++++ b/src/fuzz/fuzz-journald-kmsg.c +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "fuzz.h" ++#include "journald-kmsg.h" ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ++ Server s = {}; ++ _cleanup_free_ char *buffer = NULL; ++ ++ if (size == 0) ++ return 0; ++ ++ s = (Server) { ++ .native_fd = -1, ++ .stdout_fd = -1, ++ .dev_kmsg_fd = -1, ++ .audit_fd = -1, ++ .hostname_fd = -1, ++ .notify_fd = -1, ++ .storage = STORAGE_NONE, ++ }; ++ assert_se(sd_event_default(&s.event) >= 0); ++ buffer = memdup(data, size); ++ assert_se(buffer); ++ dev_kmsg_record(&s, buffer, size); ++ server_done(&s); ++ ++ return 0; ++} +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 1f8631bcc0..0520e448a9 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -33,6 +33,11 @@ fuzzers += [ + libshared], + [libmount]], + ++ [['src/fuzz/fuzz-journald-kmsg.c'], ++ [libjournal_core, ++ libshared], ++ [libselinux]], ++ + [['src/fuzz/fuzz-journald-native.c', + 'src/fuzz/fuzz-journald.c'], + [libjournal_core, +diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c +index 7644bebfc8..0cdf1c4794 100644 +--- a/src/journal/journald-kmsg.c ++++ b/src/journal/journald-kmsg.c +@@ -93,7 +93,7 @@ static bool is_us(const char *identifier, const char *pid) { + streq(identifier, program_invocation_short_name); + } + +-static void dev_kmsg_record(Server *s, char *p, size_t l) { ++void dev_kmsg_record(Server *s, char *p, size_t l) { + + _cleanup_free_ char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL, *identifier = NULL, *pid = NULL; + struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS]; +diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h +index bff24ac310..2326bc8c93 100644 +--- a/src/journal/journald-kmsg.h ++++ b/src/journal/journald-kmsg.h +@@ -9,3 +9,5 @@ int server_flush_dev_kmsg(Server *s); + void server_forward_kmsg(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred); + + int server_open_kernel_seqnum(Server *s); ++ ++void dev_kmsg_record(Server *s, char *p, size_t l); +diff --git a/test/fuzz/fuzz-journald-kmsg/basic b/test/fuzz/fuzz-journald-kmsg/basic +new file mode 100644 +index 0000000000..1299cd0869 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-kmsg/basic +@@ -0,0 +1 @@ ++29,456,292891883,-;systemd[1]: Reexecuting. +diff --git a/test/fuzz/fuzz-journald-kmsg/dev-null b/test/fuzz/fuzz-journald-kmsg/dev-null +new file mode 100644 +index 0000000000..de039588b5 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-kmsg/dev-null +@@ -0,0 +1,2 @@ ++12,460,1322026586,-;hey ++ DEVICE=c1:3 +diff --git a/test/fuzz/fuzz-journald-kmsg/loopback b/test/fuzz/fuzz-journald-kmsg/loopback +new file mode 100644 +index 0000000000..ca320177b7 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-kmsg/loopback +@@ -0,0 +1,2 @@ ++12,460,1322026586,-;hey ++ DEVICE=n1 +diff --git a/test/fuzz/fuzz-journald-kmsg/subsystem-loopback b/test/fuzz/fuzz-journald-kmsg/subsystem-loopback +new file mode 100644 +index 0000000000..af9c0d91e5 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-kmsg/subsystem-loopback +@@ -0,0 +1,2 @@ ++12,460,1322026586,-;hey ++ DEVICE=+net:lo diff --git a/SOURCES/0254-basic-remove-an-assertion-from-cunescape_one.patch b/SOURCES/0254-basic-remove-an-assertion-from-cunescape_one.patch new file mode 100644 index 0000000..ec38ffc --- /dev/null +++ b/SOURCES/0254-basic-remove-an-assertion-from-cunescape_one.patch @@ -0,0 +1,30 @@ +From 43d72623fdfca8500c8c89a4b5023e35a3f0b259 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 07:05:29 +0100 +Subject: [PATCH] basic: remove an assertion from cunescape_one + +The function takes a pointer to a random block of memory and +the length of that block. It shouldn't crash every time it sees +a zero byte at the beginning there. + +This should help the dev-kmsg fuzzer to keep going. + +(cherry picked from commit 8dc4de966ce6d32470aaff30ed054f6a2688d6d7) + +Resolves: #1764560 +--- + src/basic/escape.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/basic/escape.c b/src/basic/escape.c +index 5004763d97..5f715156fb 100644 +--- a/src/basic/escape.c ++++ b/src/basic/escape.c +@@ -106,7 +106,6 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) + int r = 1; + + assert(p); +- assert(*p); + assert(ret); + + /* Unescapes C style. Returns the unescaped character in ret. diff --git a/SOURCES/0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch b/SOURCES/0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch new file mode 100644 index 0000000..28a0b3e --- /dev/null +++ b/SOURCES/0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch @@ -0,0 +1,25 @@ +From f00d221d5dc92a530e260db5f44fa57653f03e8b Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 07:11:06 +0100 +Subject: [PATCH] journal: fix an off-by-one error in dev_kmsg_record + +(cherry picked from commit 080d112caa0dc948555a69a008c1caf4d5d41ed6) + +Resolves: #1764560 +--- + src/journal/journald-kmsg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c +index 0cdf1c4794..726c006ce1 100644 +--- a/src/journal/journald-kmsg.c ++++ b/src/journal/journald-kmsg.c +@@ -239,7 +239,7 @@ void dev_kmsg_record(Server *s, char *p, size_t l) { + ll = udev_device_get_devlinks_list_entry(ud); + udev_list_entry_foreach(ll, ll) { + +- if (j > N_IOVEC_UDEV_FIELDS) ++ if (j >= N_IOVEC_UDEV_FIELDS) + break; + + g = udev_list_entry_get_name(ll); diff --git a/SOURCES/0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch b/SOURCES/0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch new file mode 100644 index 0000000..14c1223 --- /dev/null +++ b/SOURCES/0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch @@ -0,0 +1,25 @@ +From 4caa887ae8eabc087d6f9f2b233c96c220de8b02 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 07:20:44 +0100 +Subject: [PATCH] tests: add a reproducer for a memory leak fixed in + 30eddcd51b8a472e05d3b8d1 in August + +(cherry picked from commit 1dd485b700fe9ad94d7a780f14fcf18a4738ace4) + +Resolves: #1764560 +--- + ...leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 | Bin 0 -> 1847 bytes + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 + +diff --git a/test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 b/test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 +new file mode 100644 +index 0000000000000000000000000000000000000000..424ae5cb010aa519758e6af90cc981795b68d3fd +GIT binary patch +literal 1847 +zcmXps(lIeJ&@nVNGBPkSGqo_&(Y4MjX0aSiiycD2<{NiEaQE6vG)izFLb8I! +Date: Fri, 16 Nov 2018 07:33:02 +0100 +Subject: [PATCH] tests: add a reproducer for a heap-buffer-overflow fixed in + 937b1171378bc1000a + +(cherry picked from commit f7a6b40187a98751a9ab6867e8b52e4e6f1dad5c) + +Resolves: #1764560 +--- + ...crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 | Bin 0 -> 112 bytes + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 + +diff --git a/test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 b/test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 +new file mode 100644 +index 0000000000000000000000000000000000000000..19887a1fec9fc29b1f7da8a2d1c5ea5054f2bc02 +GIT binary patch +literal 112 +zcmXpq)Zrxx80r}680lCOP-~&{)k?wIfGehgOM!tQroxI#0Z63Aa4DF?03ibx03hxS +A82|tP + +literal 0 +HcmV?d00001 + diff --git a/SOURCES/0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch b/SOURCES/0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch new file mode 100644 index 0000000..3ffa913 --- /dev/null +++ b/SOURCES/0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch @@ -0,0 +1,44 @@ +From af471e7402a70b670cd50e45c6139a0ac50a74bd Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 09:23:53 +0100 +Subject: [PATCH] test: initialize syslog_fd in fuzz-journald-kmsg too + +This is a follow-up to 8857fb9beb9dcb that prevents the fuzzer from crashing with +``` +==220==ERROR: AddressSanitizer: ABRT on unknown address 0x0000000000dc (pc 0x7ff4953c8428 bp 0x7ffcf66ec290 sp 0x7ffcf66ec128 T0) +SCARINESS: 10 (signal) + #0 0x7ff4953c8427 in gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x35427) + #1 0x7ff4953ca029 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x37029) + #2 0x7ff49666503a in log_assert_failed_realm /work/build/../../src/systemd/src/basic/log.c:805:9 + #3 0x7ff496614ecf in safe_close /work/build/../../src/systemd/src/basic/fd-util.c:66:17 + #4 0x548806 in server_done /work/build/../../src/systemd/src/journal/journald-server.c:2064:9 + #5 0x5349fa in LLVMFuzzerTestOneInput /work/build/../../src/systemd/src/fuzz/fuzz-journald-kmsg.c:26:9 + #6 0x592755 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:571:15 + #7 0x590627 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/libfuzzer/FuzzerLoop.cpp:480:3 + #8 0x594432 in fuzzer::Fuzzer::MutateAndTestOne() /src/libfuzzer/FuzzerLoop.cpp:708:19 + #9 0x5973c6 in fuzzer::Fuzzer::Loop(std::__1::vector, std::__1::allocator >, fuzzer::fuzzer_allocator, std::__1::allocator > > > const&) /src/libfuzzer/FuzzerLoop.cpp:839:5 + #10 0x574541 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:764:6 + #11 0x5675fc in main /src/libfuzzer/FuzzerMain.cpp:20:10 + #12 0x7ff4953b382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) + #13 0x420f58 in _start (/out/fuzz-journald-kmsg+0x420f58) +``` + +(cherry picked from commit cc55ac0171a2493768c021faa356513642797e7f) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-kmsg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c +index 5d99d244b5..e2611c6d45 100644 +--- a/src/fuzz/fuzz-journald-kmsg.c ++++ b/src/fuzz/fuzz-journald-kmsg.c +@@ -11,6 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + return 0; + + s = (Server) { ++ .syslog_fd = -1, + .native_fd = -1, + .stdout_fd = -1, + .dev_kmsg_fd = -1, diff --git a/SOURCES/0259-tests-add-a-fuzzer-for-process_audit_string.patch b/SOURCES/0259-tests-add-a-fuzzer-for-process_audit_string.patch new file mode 100644 index 0000000..d6ea02d --- /dev/null +++ b/SOURCES/0259-tests-add-a-fuzzer-for-process_audit_string.patch @@ -0,0 +1,99 @@ +From f991a9c7644f3fb5155ff823600ba5a6ea403dc4 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 21:23:56 +0100 +Subject: [PATCH] tests: add a fuzzer for process_audit_string + +(cherry picked from commit 090a20cfaf3d5439fa39c5d8df473b0cfef181dd) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-audit.c | 27 +++++++++++++++++++++++++++ + src/fuzz/meson.build | 5 +++++ + src/journal/journald-audit.c | 2 +- + src/journal/journald-audit.h | 2 ++ + test/fuzz/fuzz-journald-audit/basic | 1 + + 5 files changed, 36 insertions(+), 1 deletion(-) + create mode 100644 src/fuzz/fuzz-journald-audit.c + create mode 100644 test/fuzz/fuzz-journald-audit/basic + +diff --git a/src/fuzz/fuzz-journald-audit.c b/src/fuzz/fuzz-journald-audit.c +new file mode 100644 +index 0000000000..fe401c0d98 +--- /dev/null ++++ b/src/fuzz/fuzz-journald-audit.c +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "fuzz.h" ++#include "journald-audit.h" ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ++ Server s; ++ _cleanup_free_ char *buffer = NULL; ++ ++ s = (Server) { ++ .syslog_fd = -1, ++ .native_fd = -1, ++ .stdout_fd = -1, ++ .dev_kmsg_fd = -1, ++ .audit_fd = -1, ++ .hostname_fd = -1, ++ .notify_fd = -1, ++ .storage = STORAGE_NONE, ++ }; ++ assert_se(sd_event_default(&s.event) >= 0); ++ buffer = memdup_suffix0(data, size); ++ assert_se(buffer); ++ process_audit_string(&s, 0, buffer, size); ++ server_done(&s); ++ ++ return 0; ++} +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 0520e448a9..5548da3822 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -33,6 +33,11 @@ fuzzers += [ + libshared], + [libmount]], + ++ [['src/fuzz/fuzz-journald-audit.c'], ++ [libjournal_core, ++ libshared], ++ [libselinux]], ++ + [['src/fuzz/fuzz-journald-kmsg.c'], + [libjournal_core, + libshared], +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index 87726684af..7810a0139a 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -313,7 +313,7 @@ static int map_all_fields( + } + } + +-static void process_audit_string(Server *s, int type, const char *data, size_t size) { ++void process_audit_string(Server *s, int type, const char *data, size_t size) { + size_t n_iov_allocated = 0, n_iov = 0, z; + _cleanup_free_ struct iovec *iov = NULL; + uint64_t seconds, msec, id; +diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h +index 57bb1711c9..7766618c98 100644 +--- a/src/journal/journald-audit.h ++++ b/src/journal/journald-audit.h +@@ -6,4 +6,6 @@ + + void server_process_audit_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const union sockaddr_union *sa, socklen_t salen); + ++void process_audit_string(Server *s, int type, const char *data, size_t size); ++ + int server_open_audit(Server*s); +diff --git a/test/fuzz/fuzz-journald-audit/basic b/test/fuzz/fuzz-journald-audit/basic +new file mode 100644 +index 0000000000..d1ce8cc5f0 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-audit/basic +@@ -0,0 +1 @@ ++audit(1542398162.211:744): pid=7376 uid=1000 auid=1000 ses=6 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="vagrant" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/1 res=success' +\ No newline at end of file diff --git a/SOURCES/0260-journald-check-whether-sscanf-has-changed-the-value-.patch b/SOURCES/0260-journald-check-whether-sscanf-has-changed-the-value-.patch new file mode 100644 index 0000000..29ce46f --- /dev/null +++ b/SOURCES/0260-journald-check-whether-sscanf-has-changed-the-value-.patch @@ -0,0 +1,47 @@ +From bef599d1a0e41afe4b6f1d6dfb6fbc86896ab8c5 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 16 Nov 2018 23:32:31 +0100 +Subject: [PATCH] journald: check whether sscanf has changed the value + corresponding to %n + +It's possible for sscanf to receive strings containing all three fields +and not matching the template at the same time. When this happens the +value of k doesn't change, which basically means that process_audit_string +tries to access memory randomly. Sometimes it works and sometimes it doesn't :-) + +See also https://bugzilla.redhat.com/show_bug.cgi?id=1059314. + +(cherry picked from commit 1dab14aba749b9c5ab8176c5730107b70834240b) + +Resolves: #1764560 +--- + src/journal/journald-audit.c | 3 ++- + test/fuzz/fuzz-journald-audit/crash | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + create mode 100644 test/fuzz/fuzz-journald-audit/crash + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index 7810a0139a..0fd6ab2a84 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -341,11 +341,12 @@ void process_audit_string(Server *s, int type, const char *data, size_t size) { + if (!p) + return; + ++ k = 0; + if (sscanf(p, "(%" PRIu64 ".%" PRIu64 ":%" PRIu64 "):%n", + &seconds, + &msec, + &id, +- &k) != 3) ++ &k) != 3 || k == 0) + return; + + p += k; +diff --git a/test/fuzz/fuzz-journald-audit/crash b/test/fuzz/fuzz-journald-audit/crash +new file mode 100644 +index 0000000000..91bd85ca6e +--- /dev/null ++++ b/test/fuzz/fuzz-journald-audit/crash +@@ -0,0 +1 @@ ++audit(1542398162.211:744) pid=7376 uid=1000 auid=1000 ses=6 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="vagrant" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/1 res=success' diff --git a/SOURCES/0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch b/SOURCES/0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch new file mode 100644 index 0000000..f4a5225 --- /dev/null +++ b/SOURCES/0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch @@ -0,0 +1,172 @@ +From b276c85200786add6c86b6c1fedc888c71ffe5db Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Sat, 17 Nov 2018 13:01:09 +0100 +Subject: [PATCH] tests: introduce dummy_server_init and use it in all journald + fuzzers + +(cherry picked from commit ed62712dc6fb236845c489a7f386c7aff0ec31d6) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-audit.c | 18 +++--------------- + src/fuzz/fuzz-journald-kmsg.c | 20 ++++---------------- + src/fuzz/fuzz-journald.c | 26 +++++++++++++++++++------- + src/fuzz/fuzz-journald.h | 2 ++ + src/fuzz/meson.build | 6 ++++-- + 5 files changed, 32 insertions(+), 40 deletions(-) + +diff --git a/src/fuzz/fuzz-journald-audit.c b/src/fuzz/fuzz-journald-audit.c +index fe401c0d98..3f3ce7e8ee 100644 +--- a/src/fuzz/fuzz-journald-audit.c ++++ b/src/fuzz/fuzz-journald-audit.c +@@ -1,26 +1,14 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "fuzz.h" ++#include "fuzz-journald.h" + #include "journald-audit.h" + + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + Server s; +- _cleanup_free_ char *buffer = NULL; + +- s = (Server) { +- .syslog_fd = -1, +- .native_fd = -1, +- .stdout_fd = -1, +- .dev_kmsg_fd = -1, +- .audit_fd = -1, +- .hostname_fd = -1, +- .notify_fd = -1, +- .storage = STORAGE_NONE, +- }; +- assert_se(sd_event_default(&s.event) >= 0); +- buffer = memdup_suffix0(data, size); +- assert_se(buffer); +- process_audit_string(&s, 0, buffer, size); ++ dummy_server_init(&s, data, size); ++ process_audit_string(&s, 0, s.buffer, size); + server_done(&s); + + return 0; +diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c +index e2611c6d45..f7426c8400 100644 +--- a/src/fuzz/fuzz-journald-kmsg.c ++++ b/src/fuzz/fuzz-journald-kmsg.c +@@ -1,29 +1,17 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "fuzz.h" ++#include "fuzz-journald.h" + #include "journald-kmsg.h" + + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { +- Server s = {}; +- _cleanup_free_ char *buffer = NULL; ++ Server s; + + if (size == 0) + return 0; + +- s = (Server) { +- .syslog_fd = -1, +- .native_fd = -1, +- .stdout_fd = -1, +- .dev_kmsg_fd = -1, +- .audit_fd = -1, +- .hostname_fd = -1, +- .notify_fd = -1, +- .storage = STORAGE_NONE, +- }; +- assert_se(sd_event_default(&s.event) >= 0); +- buffer = memdup(data, size); +- assert_se(buffer); +- dev_kmsg_record(&s, buffer, size); ++ dummy_server_init(&s, data, size); ++ dev_kmsg_record(&s, s.buffer, size); + server_done(&s); + + return 0; +diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c +index f271d7f2fe..0659b92ba3 100644 +--- a/src/fuzz/fuzz-journald.c ++++ b/src/fuzz/fuzz-journald.c +@@ -5,12 +5,29 @@ + #include "journald-server.h" + #include "sd-event.h" + ++void dummy_server_init(Server *s, const uint8_t *buffer, size_t size) { ++ *s = (Server) { ++ .syslog_fd = -1, ++ .native_fd = -1, ++ .stdout_fd = -1, ++ .dev_kmsg_fd = -1, ++ .audit_fd = -1, ++ .hostname_fd = -1, ++ .notify_fd = -1, ++ .storage = STORAGE_NONE, ++ }; ++ assert_se(sd_event_default(&s->event) >= 0); ++ s->buffer = memdup_suffix0(buffer, size); ++ assert_se(s->buffer); ++ s->buffer_size = size + 1; ++} ++ + void fuzz_journald_processing_function( + const uint8_t *data, + size_t size, + void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) + ) { +- Server s = {}; ++ Server s; + char *label = NULL; + size_t label_len = 0; + struct ucred *ucred = NULL; +@@ -19,12 +36,7 @@ void fuzz_journald_processing_function( + if (size == 0) + return; + +- assert_se(sd_event_default(&s.event) >= 0); +- s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1; +- s.buffer = memdup_suffix0(data, size); +- assert_se(s.buffer); +- s.buffer_size = size + 1; +- s.storage = STORAGE_NONE; ++ dummy_server_init(&s, data, size); + (*f)(&s, s.buffer, size, ucred, tv, label, label_len); + server_done(&s); + } +diff --git a/src/fuzz/fuzz-journald.h b/src/fuzz/fuzz-journald.h +index e9d32a74aa..77e3b0c064 100644 +--- a/src/fuzz/fuzz-journald.h ++++ b/src/fuzz/fuzz-journald.h +@@ -3,6 +3,8 @@ + + #include "journald-server.h" + ++void dummy_server_init(Server *s, const uint8_t *buffer, size_t size); ++ + void fuzz_journald_processing_function( + const uint8_t *data, + size_t size, +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 5548da3822..897c02e4ae 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -33,12 +33,14 @@ fuzzers += [ + libshared], + [libmount]], + +- [['src/fuzz/fuzz-journald-audit.c'], ++ [['src/fuzz/fuzz-journald-audit.c', ++ 'src/fuzz/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + +- [['src/fuzz/fuzz-journald-kmsg.c'], ++ [['src/fuzz/fuzz-journald-kmsg.c', ++ 'src/fuzz/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], diff --git a/SOURCES/0262-tests-add-a-fuzzer-for-journald-streams.patch b/SOURCES/0262-tests-add-a-fuzzer-for-journald-streams.patch new file mode 100644 index 0000000..03ff6e8 --- /dev/null +++ b/SOURCES/0262-tests-add-a-fuzzer-for-journald-streams.patch @@ -0,0 +1,148 @@ +From e7077e3a551a3faedfcc3d007de6a72fb5e1df62 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 20 Nov 2018 01:20:32 +0100 +Subject: [PATCH] tests: add a fuzzer for journald streams + +(cherry picked from commit 9541f5ff5c637bb1b3e3c69706cb73e68ff06813) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-stream.c | 35 ++++++++++++++++++++++++++++ + src/fuzz/fuzz-journald.c | 10 +++++--- + src/fuzz/meson.build | 6 +++++ + src/journal/journald-stream.c | 4 ++-- + src/journal/journald-stream.h | 2 ++ + test/fuzz/fuzz-journald-stream/basic | 8 +++++++ + 6 files changed, 60 insertions(+), 5 deletions(-) + create mode 100644 src/fuzz/fuzz-journald-stream.c + create mode 100644 test/fuzz/fuzz-journald-stream/basic + +diff --git a/src/fuzz/fuzz-journald-stream.c b/src/fuzz/fuzz-journald-stream.c +new file mode 100644 +index 0000000000..247c0889bc +--- /dev/null ++++ b/src/fuzz/fuzz-journald-stream.c +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include ++ ++#include "fd-util.h" ++#include "fuzz.h" ++#include "fuzz-journald.h" ++#include "journald-stream.h" ++ ++static int stream_fds[2] = { -1, -1 }; ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ++ Server s; ++ StdoutStream *stream; ++ int v; ++ ++ if (size == 0) ++ return 0; ++ ++ if (!getenv("SYSTEMD_LOG_LEVEL")) ++ log_set_max_level(LOG_CRIT); ++ ++ assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0, stream_fds) >= 0); ++ dummy_server_init(&s, NULL, 0); ++ assert_se(stdout_stream_install(&s, stream_fds[0], &stream) >= 0); ++ assert_se(write(stream_fds[1], data, size) == (ssize_t) size); ++ while (ioctl(stream_fds[0], SIOCINQ, &v) == 0 && v) ++ sd_event_run(s.event, (uint64_t) -1); ++ if (s.n_stdout_streams) ++ stdout_stream_destroy(stream); ++ server_done(&s); ++ stream_fds[1] = safe_close(stream_fds[1]); ++ ++ return 0; ++} +diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c +index 0659b92ba3..950e885cae 100644 +--- a/src/fuzz/fuzz-journald.c ++++ b/src/fuzz/fuzz-journald.c +@@ -15,11 +15,15 @@ void dummy_server_init(Server *s, const uint8_t *buffer, size_t size) { + .hostname_fd = -1, + .notify_fd = -1, + .storage = STORAGE_NONE, ++ .line_max = 64, + }; + assert_se(sd_event_default(&s->event) >= 0); +- s->buffer = memdup_suffix0(buffer, size); +- assert_se(s->buffer); +- s->buffer_size = size + 1; ++ ++ if (buffer) { ++ s->buffer = memdup_suffix0(buffer, size); ++ assert_se(s->buffer); ++ s->buffer_size = size + 1; ++ } + } + + void fuzz_journald_processing_function( +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index 897c02e4ae..eea9117360 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -51,6 +51,12 @@ fuzzers += [ + libshared], + [libselinux]], + ++ [['src/fuzz/fuzz-journald-stream.c', ++ 'src/fuzz/fuzz-journald.c'], ++ [libjournal_core, ++ libshared], ++ [libselinux]], ++ + [['src/fuzz/fuzz-journald-syslog.c', + 'src/fuzz/fuzz-journald.c'], + [libjournal_core, +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index dbf3503a82..6f8a4011ff 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -125,7 +125,7 @@ void stdout_stream_free(StdoutStream *s) { + + DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free); + +-static void stdout_stream_destroy(StdoutStream *s) { ++void stdout_stream_destroy(StdoutStream *s) { + if (!s) + return; + +@@ -534,7 +534,7 @@ terminate: + return 0; + } + +-static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { ++int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { + _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL; + sd_id128_t id; + int r; +diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h +index bc5622ab3b..487376e763 100644 +--- a/src/journal/journald-stream.h ++++ b/src/journal/journald-stream.h +@@ -10,4 +10,6 @@ int server_open_stdout_socket(Server *s); + int server_restore_streams(Server *s, FDSet *fds); + + void stdout_stream_free(StdoutStream *s); ++int stdout_stream_install(Server *s, int fd, StdoutStream **ret); ++void stdout_stream_destroy(StdoutStream *s); + void stdout_stream_send_notify(StdoutStream *s); +diff --git a/test/fuzz/fuzz-journald-stream/basic b/test/fuzz/fuzz-journald-stream/basic +new file mode 100644 +index 0000000000..a088f1a539 +--- /dev/null ++++ b/test/fuzz/fuzz-journald-stream/basic +@@ -0,0 +1,8 @@ ++ ++ ++6 ++1 ++0 ++0 ++0 ++hey +\ No newline at end of file diff --git a/SOURCES/0263-tests-add-a-fuzzer-for-server_process_native_file.patch b/SOURCES/0263-tests-add-a-fuzzer-for-server_process_native_file.patch new file mode 100644 index 0000000..500af37 --- /dev/null +++ b/SOURCES/0263-tests-add-a-fuzzer-for-server_process_native_file.patch @@ -0,0 +1,96 @@ +From 76e2fa8ed4bbee7c625e3b790f2e38a59fffd93d Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 23 Nov 2018 00:27:19 +0100 +Subject: [PATCH] tests: add a fuzzer for server_process_native_file + +(cherry picked from commit a4aa59bae206eebb4703b291147144def5d4bb3e) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-native-fd.c | 47 ++++++++++++++++++++++++ + src/fuzz/meson.build | 6 +++ + test/fuzz/fuzz-journald-native-fd/basic | Bin 0 -> 34 bytes + 3 files changed, 53 insertions(+) + create mode 100644 src/fuzz/fuzz-journald-native-fd.c + create mode 100644 test/fuzz/fuzz-journald-native-fd/basic + +diff --git a/src/fuzz/fuzz-journald-native-fd.c b/src/fuzz/fuzz-journald-native-fd.c +new file mode 100644 +index 0000000000..95415d9f85 +--- /dev/null ++++ b/src/fuzz/fuzz-journald-native-fd.c +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "fd-util.h" ++#include "fileio.h" ++#include "fs-util.h" ++#include "fuzz.h" ++#include "fuzz-journald.h" ++#include "journald-native.h" ++#include "memfd-util.h" ++#include "process-util.h" ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ++ Server s; ++ _cleanup_close_ int sealed_fd = -1, unsealed_fd = -1; ++ _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journald-native-fd.XXXXXX"; ++ char *label = NULL; ++ size_t label_len = 0; ++ struct ucred ucred; ++ struct timeval *tv = NULL; ++ ++ if (!getenv("SYSTEMD_LOG_LEVEL")) ++ log_set_max_level(LOG_CRIT); ++ ++ dummy_server_init(&s, NULL, 0); ++ ++ sealed_fd = memfd_new(NULL); ++ assert_se(sealed_fd >= 0); ++ assert_se(write(sealed_fd, data, size) == (ssize_t) size); ++ assert_se(memfd_set_sealed(sealed_fd) >= 0); ++ assert_se(lseek(sealed_fd, 0, SEEK_SET) == 0); ++ ucred = (struct ucred) { ++ .pid = getpid_cached(), ++ .uid = geteuid(), ++ .gid = getegid(), ++ }; ++ server_process_native_file(&s, sealed_fd, &ucred, tv, label, label_len); ++ ++ unsealed_fd = mkostemp_safe(name); ++ assert_se(unsealed_fd >= 0); ++ assert_se(write(unsealed_fd, data, size) == (ssize_t) size); ++ assert_se(lseek(unsealed_fd, 0, SEEK_SET) == 0); ++ server_process_native_file(&s, unsealed_fd, &ucred, tv, label, label_len); ++ ++ server_done(&s); ++ ++ return 0; ++} +diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build +index eea9117360..5315d2771c 100644 +--- a/src/fuzz/meson.build ++++ b/src/fuzz/meson.build +@@ -51,6 +51,12 @@ fuzzers += [ + libshared], + [libselinux]], + ++ [['src/fuzz/fuzz-journald-native-fd.c', ++ 'src/fuzz/fuzz-journald.c'], ++ [libjournal_core, ++ libshared], ++ [libselinux]], ++ + [['src/fuzz/fuzz-journald-stream.c', + 'src/fuzz/fuzz-journald.c'], + [libjournal_core, +diff --git a/test/fuzz/fuzz-journald-native-fd/basic b/test/fuzz/fuzz-journald-native-fd/basic +new file mode 100644 +index 0000000000000000000000000000000000000000..65f89705a655618851c0e446efaa5c633adf425f +GIT binary patch +literal 34 +kcmeZu4Gwm6cjaPXfB;7>M@KGyCofm$koW*k7h3}^0B8*cRR910 + +literal 0 +HcmV?d00001 + diff --git a/SOURCES/0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch b/SOURCES/0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch new file mode 100644 index 0000000..798aa6c --- /dev/null +++ b/SOURCES/0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch @@ -0,0 +1,47 @@ +From 2d197adc6d7109d5901401a90288530582f3f991 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 26 Feb 2019 13:00:35 +0100 +Subject: [PATCH] fuzz-journal-stream: avoid assertion failure on samples which + don't fit in pipe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11587. +We had a sample which was large enough that write(2) failed to push all the +data into the pipe, and an assert failed. The code could be changed to use +a loop, but then we'd need to interleave writes and sd_event_run (to process +the journal). I don't think the complexity is worth it — fuzzing works best +if the sample is not too huge anyway. So let's just reject samples above 64k, +and tell oss-fuzz about this limit. + +(cherry picked from commit eafadd069c4e30ed62173123326a7237448615d1) + +Resolves: #1764560 +--- + src/fuzz/fuzz-journald-stream.c | 2 +- + src/fuzz/fuzz-journald-stream.options | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + create mode 100644 src/fuzz/fuzz-journald-stream.options + +diff --git a/src/fuzz/fuzz-journald-stream.c b/src/fuzz/fuzz-journald-stream.c +index 247c0889bc..693b197d3a 100644 +--- a/src/fuzz/fuzz-journald-stream.c ++++ b/src/fuzz/fuzz-journald-stream.c +@@ -14,7 +14,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + StdoutStream *stream; + int v; + +- if (size == 0) ++ if (size == 0 || size > 65536) + return 0; + + if (!getenv("SYSTEMD_LOG_LEVEL")) +diff --git a/src/fuzz/fuzz-journald-stream.options b/src/fuzz/fuzz-journald-stream.options +new file mode 100644 +index 0000000000..678d526b1e +--- /dev/null ++++ b/src/fuzz/fuzz-journald-stream.options +@@ -0,0 +1,2 @@ ++[libfuzzer] ++max_len = 65536 diff --git a/SOURCES/0265-journald-take-leading-spaces-into-account-in-syslog_.patch b/SOURCES/0265-journald-take-leading-spaces-into-account-in-syslog_.patch new file mode 100644 index 0000000..25b1d95 --- /dev/null +++ b/SOURCES/0265-journald-take-leading-spaces-into-account-in-syslog_.patch @@ -0,0 +1,45 @@ +From 3521217c88b364e2c5b10a1e35d3c036b1ecba64 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 10 Aug 2018 12:55:09 +0000 +Subject: [PATCH] journald: take leading spaces into account in + syslog_parse_identifier + +This is a kind of follow-up to e88baee88fad8bc59d3 which should finally fix +the issue which that commit was supposed to fix. + +(cherry picked from commit 937b1171378bc1000a34fcdfe9534d898227e35f) + +Resolves: #1764560 +--- + src/journal/journald-syslog.c | 3 ++- + src/journal/test-journal-syslog.c | 2 ++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index e0b55cc566..ae966763a0 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -223,8 +223,9 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) + if (p[e] != '\0' && strchr(WHITESPACE, p[e])) + e++; + ++ l = (p - *buf) + e; + *buf = p + e; +- return e; ++ return l; + } + + static void syslog_skip_date(char **buf) { +diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c +index 120477cc9f..415b9d23ca 100644 +--- a/src/journal/test-journal-syslog.c ++++ b/src/journal/test-journal-syslog.c +@@ -41,6 +41,8 @@ int main(void) { + test_syslog_parse_identifier(" ", NULL, NULL, " ", 0); + test_syslog_parse_identifier(":", "", NULL, "", 1); + test_syslog_parse_identifier(": ", "", NULL, " ", 2); ++ test_syslog_parse_identifier(" :", "", NULL, "", 2); ++ test_syslog_parse_identifier(" pidu:", "pidu", NULL, "", 8); + test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5); + test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6); + test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0); diff --git a/SOURCES/0266-Add-a-warning-about-the-difference-in-permissions-be.patch b/SOURCES/0266-Add-a-warning-about-the-difference-in-permissions-be.patch new file mode 100644 index 0000000..8b0bd5c --- /dev/null +++ b/SOURCES/0266-Add-a-warning-about-the-difference-in-permissions-be.patch @@ -0,0 +1,43 @@ +From 5df63c2ddf93bab5e7f13e09dfb1f97a011b3451 Mon Sep 17 00:00:00 2001 +From: Taro Yamada +Date: Sun, 27 Jan 2019 13:50:04 +0900 +Subject: [PATCH] Add a warning about the difference in permissions between + existing directories and unit settings. + +To follows the intent of 30c81ce, this change does not execute chmod() and just add warnings. + +(cherry picked from commit 6cff72eb0a18d8547f005a481cd0622d3bc78483) + +Related: #1778384 +--- + src/core/execute.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 8293c522bc..9ddba00421 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2099,8 +2099,21 @@ static int setup_exec_directory( + r = mkdir_label(p, context->directories[type].mode); + if (r < 0 && r != -EEXIST) + goto fail; +- if (r == -EEXIST && !context->dynamic_user) +- continue; ++ if (r == -EEXIST) { ++ struct stat st; ++ ++ if (stat(p, &st) < 0) { ++ r = -errno; ++ goto fail; ++ } ++ if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) ++ log_warning("%s \'%s\' already exists but the mode is different. " ++ "(filesystem: %o %sMode: %o)", ++ exec_directory_type_to_string(type), *rt, ++ st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); ++ if (!context->dynamic_user) ++ continue; ++ } + } + + /* Don't change the owner of the configuration directory, as in the common case it is not written to by diff --git a/SOURCES/0267-execute-remove-one-redundant-comparison-check.patch b/SOURCES/0267-execute-remove-one-redundant-comparison-check.patch new file mode 100644 index 0000000..8101159 --- /dev/null +++ b/SOURCES/0267-execute-remove-one-redundant-comparison-check.patch @@ -0,0 +1,32 @@ +From 81ca39b7b38ef1d44cc146efe75bef412e7c4c97 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 14 Mar 2019 17:01:46 +0100 +Subject: [PATCH] execute: remove one redundant comparison check + +(cherry picked from commit d484580ca6f0e79abe6f3f5c677323a22d9e22d7) + +Related: #1778384 +--- + src/core/execute.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 9ddba00421..46aa733937 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2097,11 +2097,12 @@ static int setup_exec_directory( + } + } else { + r = mkdir_label(p, context->directories[type].mode); +- if (r < 0 && r != -EEXIST) +- goto fail; +- if (r == -EEXIST) { ++ if (r < 0) { + struct stat st; + ++ if (r != -EEXIST) ++ goto fail; ++ + if (stat(p, &st) < 0) { + r = -errno; + goto fail; diff --git a/SOURCES/0268-core-change-ownership-mode-of-the-execution-director.patch b/SOURCES/0268-core-change-ownership-mode-of-the-execution-director.patch new file mode 100644 index 0000000..faaef74 --- /dev/null +++ b/SOURCES/0268-core-change-ownership-mode-of-the-execution-director.patch @@ -0,0 +1,88 @@ +From 789806ac06bb13d1b579fef47dbb85f224b6dbb1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 14 Mar 2019 17:19:30 +0100 +Subject: [PATCH] core: change ownership/mode of the execution directories also + for static users + +It's probably unexpected if we do a recursive chown() when dynamic users +are used but not on static users. + +hence, let's tweak the logic slightly, and recursively chown in both +cases, except when operating on the configuration directory. + +Fixes: #11842 +(cherry picked from commit 206e9864de460dd79d9edd7bedb47dee168765e1) + +Resolves: #1778384 +--- + src/core/execute.c | 47 +++++++++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 21 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 46aa733937..c42300a41e 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2090,37 +2090,42 @@ static int setup_exec_directory( + if (r < 0) + goto fail; + +- /* Lock down the access mode */ +- if (chmod(pp, context->directories[type].mode) < 0) { +- r = -errno; +- goto fail; +- } + } else { + r = mkdir_label(p, context->directories[type].mode); + if (r < 0) { +- struct stat st; +- + if (r != -EEXIST) + goto fail; + +- if (stat(p, &st) < 0) { +- r = -errno; +- goto fail; +- } +- if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) +- log_warning("%s \'%s\' already exists but the mode is different. " +- "(filesystem: %o %sMode: %o)", +- exec_directory_type_to_string(type), *rt, +- st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); +- if (!context->dynamic_user) ++ if (type == EXEC_DIRECTORY_CONFIGURATION) { ++ struct stat st; ++ ++ /* Don't change the owner/access mode of the configuration directory, ++ * as in the common case it is not written to by a service, and shall ++ * not be writable. */ ++ ++ if (stat(p, &st) < 0) { ++ r = -errno; ++ goto fail; ++ } ++ ++ /* Still complain if the access mode doesn't match */ ++ if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) ++ log_warning("%s \'%s\' already exists but the mode is different. " ++ "(File system: %o %sMode: %o)", ++ exec_directory_type_to_string(type), *rt, ++ st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); ++ + continue; ++ } + } + } + +- /* Don't change the owner of the configuration directory, as in the common case it is not written to by +- * a service, and shall not be writable. */ +- if (type == EXEC_DIRECTORY_CONFIGURATION) +- continue; ++ /* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't ++ * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the ++ * current UID/GID ownership.) */ ++ r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID, GID_INVALID); ++ if (r < 0) ++ goto fail; + + /* Then, change the ownership of the whole tree, if necessary */ + r = path_chown_recursive(pp ?: p, uid, gid); diff --git a/SOURCES/0269-core-dbus-execute-remove-unnecessary-initialization.patch b/SOURCES/0269-core-dbus-execute-remove-unnecessary-initialization.patch new file mode 100644 index 0000000..e46f256 --- /dev/null +++ b/SOURCES/0269-core-dbus-execute-remove-unnecessary-initialization.patch @@ -0,0 +1,25 @@ +From 5d7e8cb0e12e4642a760cf00cbb6caf4c07b9cd9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 19 May 2019 16:05:02 +0200 +Subject: [PATCH] core/dbus-execute: remove unnecessary initialization + +(cherry picked from commit bd0abfaea1514bdd7cb60228d7a3f94c17ba916d) + +Related: #1734787 +--- + src/core/dbus-execute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index 33a91c012e..5379545d57 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -1552,7 +1552,7 @@ int bus_exec_context_set_transient_property( + #endif + if (streq(name, "CPUAffinity")) { + const void *a; +- size_t n = 0; ++ size_t n; + + r = sd_bus_message_read_array(message, 'y', &a, &n); + if (r < 0) diff --git a/SOURCES/0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch b/SOURCES/0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch new file mode 100644 index 0000000..5babb33 --- /dev/null +++ b/SOURCES/0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch @@ -0,0 +1,215 @@ +From 46b4d26c54a773f7da350e89562039ccc5157a8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 19 May 2019 18:02:38 +0200 +Subject: [PATCH] shared/cpu-set-util: move the part to print cpu-set into a + separate function + +Also avoid unnecessary asprintf() when we can write to the output area +directly. + +(cherry picked from commit a832893f9c4f0a0329768e90f67e2fa24bb0008e) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 21 +++++++++++++++++++++ + src/basic/cpu-set-util.h | 1 + + src/core/dbus-execute.c | 29 +++++------------------------ + src/test/test-cpu-set-util.c | 29 +++++++++++++++++++++++++++++ + 4 files changed, 56 insertions(+), 24 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index b1c927bcb8..8f24a2601a 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + + #include "alloc-util.h" +@@ -15,6 +16,26 @@ + #include "parse-util.h" + #include "string-util.h" + ++char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) { ++ _cleanup_free_ char *str = NULL; ++ size_t allocated = 0, len = 0; ++ int i, r; ++ ++ for (i = 0; (size_t) i < setsize * 8; i++) { ++ if (!CPU_ISSET_S(i, setsize, set)) ++ continue; ++ ++ if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int))) ++ return NULL; ++ ++ r = sprintf(str + len, len > 0 ? " %d" : "%d", i); ++ assert_se(r > 0); ++ len += r; ++ } ++ ++ return TAKE_PTR(str) ?: strdup(""); ++} ++ + cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + cpu_set_t *c; + unsigned n = 1024; +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 88470fe15a..3c546beb55 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -26,6 +26,7 @@ static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) { + + cpu_set_t* cpu_set_malloc(unsigned *ncpus); + ++char* cpu_set_to_string(const cpu_set_t *set, size_t setsize); + int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue); + + static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) { +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index 5379545d57..d9f4445745 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -1565,32 +1565,13 @@ int bus_exec_context_set_transient_property( + unit_write_settingf(u, flags, name, "%s=", name); + } else { + _cleanup_free_ char *str = NULL; +- size_t allocated = 0, len = 0, i, ncpus; ++ size_t ncpus; + +- ncpus = CPU_SIZE_TO_NUM(n); +- +- for (i = 0; i < ncpus; i++) { +- _cleanup_free_ char *p = NULL; +- size_t add; +- +- if (!CPU_ISSET_S(i, n, (cpu_set_t*) a)) +- continue; +- +- r = asprintf(&p, "%zu", i); +- if (r < 0) +- return -ENOMEM; +- +- add = strlen(p); +- +- if (!GREEDY_REALLOC(str, allocated, len + add + 2)) +- return -ENOMEM; +- +- strcpy(mempcpy(str + len, p, add), " "); +- len += add + 1; +- } ++ str = cpu_set_to_string(a, n); ++ if (!str) ++ return -ENOMEM; + +- if (len != 0) +- str[len - 1] = '\0'; ++ ncpus = CPU_SIZE_TO_NUM(n); + + if (!c->cpuset || c->cpuset_ncpus < ncpus) { + cpu_set_t *cpuset; +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index c9272459b4..ff5edb2a69 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -6,6 +6,7 @@ + + static void test_parse_cpu_set(void) { + cpu_set_t *c = NULL; ++ _cleanup_free_ char *str = NULL; + int ncpus; + int cpu; + +@@ -15,6 +16,10 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); ++ ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* A more interesting range */ +@@ -25,6 +30,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Quoted strings */ +@@ -33,6 +41,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Use commas as separators */ +@@ -43,6 +54,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Commas with spaces (and trailing comma, space) */ +@@ -51,6 +65,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Ranges */ +@@ -61,6 +78,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Ranges with trailing comma, space */ +@@ -71,6 +91,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Negative range (returns empty cpu_set) */ +@@ -85,6 +108,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Mix ranges and individual CPUs */ +@@ -95,6 +121,9 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); + c = cpu_set_mfree(c); + + /* Garbage */ diff --git a/SOURCES/0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch b/SOURCES/0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch new file mode 100644 index 0000000..8d393c5 --- /dev/null +++ b/SOURCES/0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch @@ -0,0 +1,29 @@ +From d6935e61de30967aa82b7722f36193ba782b75e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 19 May 2019 18:08:39 +0200 +Subject: [PATCH] shared/cpu-set-util: remove now-unused CPU_SIZE_TO_NUM() + +(cherry picked from commit b12ef7141648be40fd8c4b0209a742f2151736d9) + +Related: #1734787 +--- + src/basic/cpu-set-util.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 3c546beb55..20612a8876 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -9,12 +9,6 @@ + + #include "macro.h" + +-#ifdef __NCPUBITS +-#define CPU_SIZE_TO_NUM(n) ((n) * __NCPUBITS) +-#else +-#define CPU_SIZE_TO_NUM(n) ((n) * sizeof(cpu_set_t) * 8) +-#endif +- + DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); + #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + diff --git a/SOURCES/0272-Rework-cpu-affinity-parsing.patch b/SOURCES/0272-Rework-cpu-affinity-parsing.patch new file mode 100644 index 0000000..f6001e5 --- /dev/null +++ b/SOURCES/0272-Rework-cpu-affinity-parsing.patch @@ -0,0 +1,932 @@ +From 61e5aed87f1b82a51c6ea8ccde96805cb63e5b15 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 21 May 2019 08:45:19 +0200 +Subject: [PATCH] Rework cpu affinity parsing + +The CPU_SET_S api is pretty bad. In particular, it has a parameter for the size +of the array, but operations which take two (CPU_EQUAL_S) or even three arrays +(CPU_{AND,OR,XOR}_S) still take just one size. This means that all arrays must +be of the same size, or buffer overruns will occur. This is exactly what our +code would do, if it received an array of unexpected size over the network. +("Unexpected" here means anything different from what cpu_set_malloc() detects +as the "right" size.) + +Let's rework this, and store the size in bytes of the allocated storage area. + +The code will now parse any number up to 8191, independently of what the current +kernel supports. This matches the kernel maximum setting for any architecture, +to make things more portable. + +Fixes #12605. + +(cherry picked from commit 0985c7c4e22c8dbbea4398cf3453da45ebf63800) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 133 +++++++++++++++++++++----- + src/basic/cpu-set-util.h | 47 ++++++--- + src/core/dbus-execute.c | 35 ++----- + src/core/execute.c | 12 +-- + src/core/execute.h | 4 +- + src/core/load-fragment.c | 31 +----- + src/core/main.c | 14 +-- + src/nspawn/nspawn-settings.c | 33 +------ + src/nspawn/nspawn-settings.h | 4 +- + src/nspawn/nspawn.c | 29 +++--- + src/shared/bus-unit-util.c | 4 +- + src/test/test-cpu-set-util.c | 179 +++++++++++++++++++---------------- + src/test/test-sizeof.c | 3 + + 13 files changed, 286 insertions(+), 242 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index 8f24a2601a..fe440f6381 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -15,14 +15,15 @@ + #include "macro.h" + #include "parse-util.h" + #include "string-util.h" ++#include "util.h" + +-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) { ++char* cpu_set_to_string(const CPUSet *a) { + _cleanup_free_ char *str = NULL; + size_t allocated = 0, len = 0; + int i, r; + +- for (i = 0; (size_t) i < setsize * 8; i++) { +- if (!CPU_ISSET_S(i, setsize, set)) ++ for (i = 0; (size_t) i < a->allocated * 8; i++) { ++ if (!CPU_ISSET_S(i, a->allocated, a->set)) + continue; + + if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int))) +@@ -65,24 +66,74 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + } + } + +-int parse_cpu_set_internal( ++static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) { ++ size_t need; ++ ++ assert(cpu_set); ++ ++ need = CPU_ALLOC_SIZE(ncpus); ++ if (need > cpu_set->allocated) { ++ cpu_set_t *t; ++ ++ t = realloc(cpu_set->set, need); ++ if (!t) ++ return -ENOMEM; ++ ++ memzero((uint8_t*) t + cpu_set->allocated, need - cpu_set->allocated); ++ ++ cpu_set->set = t; ++ cpu_set->allocated = need; ++ } ++ ++ return 0; ++} ++ ++static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) { ++ int r; ++ ++ if (cpu >= 8192) ++ /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */ ++ return -ERANGE; ++ ++ r = cpu_set_realloc(cpu_set, cpu + 1); ++ if (r < 0) ++ return r; ++ ++ CPU_SET_S(cpu, cpu_set->allocated, cpu_set->set); ++ return 0; ++} ++ ++int cpu_set_add_all(CPUSet *a, const CPUSet *b) { ++ int r; ++ ++ /* Do this backwards, so if we fail, we fail before changing anything. */ ++ for (unsigned cpu_p1 = b->allocated * 8; cpu_p1 > 0; cpu_p1--) ++ if (CPU_ISSET_S(cpu_p1 - 1, b->allocated, b->set)) { ++ r = cpu_set_add(a, cpu_p1 - 1); ++ if (r < 0) ++ return r; ++ } ++ ++ return 0; ++} ++ ++int parse_cpu_set_full( + const char *rvalue, +- cpu_set_t **cpu_set, ++ CPUSet *cpu_set, + bool warn, + const char *unit, + const char *filename, + unsigned line, + const char *lvalue) { + +- _cleanup_cpu_free_ cpu_set_t *c = NULL; ++ _cleanup_(cpu_set_reset) CPUSet c = {}; + const char *p = rvalue; +- unsigned ncpus = 0; + +- assert(rvalue); ++ assert(p); + + for (;;) { + _cleanup_free_ char *word = NULL; +- unsigned cpu, cpu_lower, cpu_upper; ++ unsigned cpu_lower, cpu_upper; + int r; + + r = extract_first_word(&p, &word, WHITESPACE ",", EXTRACT_QUOTES); +@@ -93,31 +144,63 @@ int parse_cpu_set_internal( + if (r == 0) + break; + +- if (!c) { +- c = cpu_set_malloc(&ncpus); +- if (!c) +- return warn ? log_oom() : -ENOMEM; +- } +- + r = parse_range(word, &cpu_lower, &cpu_upper); + if (r < 0) + return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word) : r; +- if (cpu_lower >= ncpus || cpu_upper >= ncpus) +- return warn ? log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus) : -EINVAL; + + if (cpu_lower > cpu_upper) { + if (warn) +- log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring", word, cpu_lower, cpu_upper); +- continue; ++ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring.", ++ word, cpu_lower, cpu_upper); ++ ++ /* Make sure something is allocated, to distinguish this from the empty case */ ++ r = cpu_set_realloc(&c, 1); ++ if (r < 0) ++ return r; + } + +- for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) +- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); ++ for (unsigned cpu_p1 = MIN(cpu_upper, UINT_MAX-1) + 1; cpu_p1 > cpu_lower; cpu_p1--) { ++ r = cpu_set_add(&c, cpu_p1 - 1); ++ if (r < 0) ++ return warn ? log_syntax(unit, LOG_ERR, filename, line, r, ++ "Cannot add CPU %u to set: %m", cpu_p1 - 1) : r; ++ } + } + +- /* On success, sets *cpu_set and returns ncpus for the system. */ +- if (c) +- *cpu_set = TAKE_PTR(c); ++ /* On success, transfer ownership to the output variable */ ++ *cpu_set = c; ++ c = (CPUSet) {}; ++ ++ return 0; ++} ++ ++int parse_cpu_set_extend( ++ const char *rvalue, ++ CPUSet *old, ++ bool warn, ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *lvalue) { ++ ++ _cleanup_(cpu_set_reset) CPUSet cpuset = {}; ++ int r; ++ ++ r = parse_cpu_set_full(rvalue, &cpuset, true, unit, filename, line, lvalue); ++ if (r < 0) ++ return r; ++ ++ if (!cpuset.set) { ++ /* An empty assignment resets the CPU list */ ++ cpu_set_reset(old); ++ return 0; ++ } ++ ++ if (!old->set) { ++ *old = cpuset; ++ cpuset = (CPUSet) {}; ++ return 0; ++ } + +- return (int) ncpus; ++ return cpu_set_add_all(old, &cpuset); + } +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 20612a8876..eb31b362fe 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -12,23 +12,40 @@ + DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); + #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + +-static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) { +- if (p) +- CPU_FREE(p); +- return NULL; +-} +- + cpu_set_t* cpu_set_malloc(unsigned *ncpus); + +-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize); +-int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue); +- +-static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) { +- assert(lvalue); +- +- return parse_cpu_set_internal(rvalue, cpu_set, true, unit, filename, line, lvalue); ++/* This wraps the libc interface with a variable to keep the allocated size. */ ++typedef struct CPUSet { ++ cpu_set_t *set; ++ size_t allocated; /* in bytes */ ++} CPUSet; ++ ++static inline void cpu_set_reset(CPUSet *a) { ++ assert((a->allocated > 0) == !!a->set); ++ if (a->set) ++ CPU_FREE(a->set); ++ *a = (CPUSet) {}; + } + +-static inline int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set){ +- return parse_cpu_set_internal(rvalue, cpu_set, false, NULL, NULL, 0, NULL); ++int cpu_set_add_all(CPUSet *a, const CPUSet *b); ++ ++char* cpu_set_to_string(const CPUSet *a); ++int parse_cpu_set_full( ++ const char *rvalue, ++ CPUSet *cpu_set, ++ bool warn, ++ const char *unit, ++ const char *filename, unsigned line, ++ const char *lvalue); ++int parse_cpu_set_extend( ++ const char *rvalue, ++ CPUSet *old, ++ bool warn, ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *lvalue); ++ ++static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){ ++ return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL); + } +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index d9f4445745..08946627e3 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -220,7 +220,7 @@ static int property_get_cpu_affinity( + assert(reply); + assert(c); + +- return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus)); ++ return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated); + } + + static int property_get_timer_slack_nsec( +@@ -1560,37 +1560,22 @@ int bus_exec_context_set_transient_property( + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (n == 0) { +- c->cpuset = cpu_set_mfree(c->cpuset); +- c->cpuset_ncpus = 0; ++ cpu_set_reset(&c->cpu_set); + unit_write_settingf(u, flags, name, "%s=", name); + } else { + _cleanup_free_ char *str = NULL; +- size_t ncpus; ++ const CPUSet set = {(cpu_set_t*) a, n}; + +- str = cpu_set_to_string(a, n); ++ str = cpu_set_to_string(&set); + if (!str) + return -ENOMEM; + +- ncpus = CPU_SIZE_TO_NUM(n); +- +- if (!c->cpuset || c->cpuset_ncpus < ncpus) { +- cpu_set_t *cpuset; +- +- cpuset = CPU_ALLOC(ncpus); +- if (!cpuset) +- return -ENOMEM; +- +- CPU_ZERO_S(n, cpuset); +- if (c->cpuset) { +- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, (cpu_set_t*) a); +- CPU_FREE(c->cpuset); +- } else +- CPU_OR_S(n, cpuset, cpuset, (cpu_set_t*) a); +- +- c->cpuset = cpuset; +- c->cpuset_ncpus = ncpus; +- } else +- CPU_OR_S(n, c->cpuset, c->cpuset, (cpu_set_t*) a); ++ /* We forego any optimizations here, and always create the structure using ++ * cpu_set_add_all(), because we don't want to care if the existing size we ++ * got over dbus is appropriate. */ ++ r = cpu_set_add_all(&c->cpu_set, &set); ++ if (r < 0) ++ return r; + + unit_write_settingf(u, flags, name, "%s=%s", name, str); + } +diff --git a/src/core/execute.c b/src/core/execute.c +index c42300a41e..22e5825905 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2991,8 +2991,8 @@ static int exec_child( + } + } + +- if (context->cpuset) +- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) { ++ if (context->cpu_set.set) ++ if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) { + *exit_status = EXIT_CPUAFFINITY; + return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m"); + } +@@ -3694,7 +3694,7 @@ void exec_context_done(ExecContext *c) { + c->temporary_filesystems = NULL; + c->n_temporary_filesystems = 0; + +- c->cpuset = cpu_set_mfree(c->cpuset); ++ cpu_set_reset(&c->cpu_set); + + c->utmp_id = mfree(c->utmp_id); + c->selinux_context = mfree(c->selinux_context); +@@ -4097,10 +4097,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + prefix, yes_no(c->cpu_sched_reset_on_fork)); + } + +- if (c->cpuset) { ++ if (c->cpu_set.set) { + fprintf(f, "%sCPUAffinity:", prefix); +- for (i = 0; i < c->cpuset_ncpus; i++) +- if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset)) ++ for (i = 0; i < c->cpu_set.allocated * 8; i++) ++ if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set)) + fprintf(f, " %u", i); + fputs("\n", f); + } +diff --git a/src/core/execute.h b/src/core/execute.h +index 8c91636adc..e1e7a494cd 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -14,6 +14,7 @@ typedef struct Manager Manager; + #include + + #include "cgroup-util.h" ++#include "cpu-set-util.h" + #include "fdset.h" + #include "list.h" + #include "missing.h" +@@ -148,8 +149,7 @@ struct ExecContext { + int cpu_sched_policy; + int cpu_sched_priority; + +- cpu_set_t *cpuset; +- unsigned cpuset_ncpus; ++ CPUSet cpu_set; + + ExecInput std_input; + ExecOutput std_output; +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index d9a5094aa0..34ae834188 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1211,42 +1211,13 @@ int config_parse_exec_cpu_affinity(const char *unit, + void *userdata) { + + ExecContext *c = data; +- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; +- int ncpus; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + +- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); +- if (ncpus < 0) +- return ncpus; +- +- if (ncpus == 0) { +- /* An empty assignment resets the CPU list */ +- c->cpuset = cpu_set_mfree(c->cpuset); +- c->cpuset_ncpus = 0; +- return 0; +- } +- +- if (!c->cpuset) { +- c->cpuset = TAKE_PTR(cpuset); +- c->cpuset_ncpus = (unsigned) ncpus; +- return 0; +- } +- +- if (c->cpuset_ncpus < (unsigned) ncpus) { +- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset); +- CPU_FREE(c->cpuset); +- c->cpuset = TAKE_PTR(cpuset); +- c->cpuset_ncpus = (unsigned) ncpus; +- return 0; +- } +- +- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), c->cpuset, c->cpuset, cpuset); +- +- return 0; ++ return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue); + } + + int config_parse_capability_set( +diff --git a/src/core/main.c b/src/core/main.c +index af7b26d6f1..e62b2756ee 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -537,16 +537,18 @@ static int config_parse_cpu_affinity2( + void *data, + void *userdata) { + +- _cleanup_cpu_free_ cpu_set_t *c = NULL; +- int ncpus; ++ _cleanup_(cpu_set_reset) CPUSet c = {}; ++ int r; + +- ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); +- if (ncpus < 0) +- return ncpus; ++ r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue); ++ if (r < 0) ++ return r; + +- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) ++ if (sched_setaffinity(0, c.allocated, c.set) < 0) + log_warning_errno(errno, "Failed to set CPU affinity: %m"); + ++ // FIXME: parsing and execution should be seperated. ++ + return 0; + } + +diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c +index 62a3486952..21c24a1111 100644 +--- a/src/nspawn/nspawn-settings.c ++++ b/src/nspawn/nspawn-settings.c +@@ -85,7 +85,7 @@ Settings* settings_free(Settings *s) { + strv_free(s->syscall_blacklist); + rlimit_free_all(s->rlimit); + free(s->hostname); +- s->cpuset = cpu_set_mfree(s->cpuset); ++ cpu_set_reset(&s->cpu_set); + + strv_free(s->network_interfaces); + strv_free(s->network_macvlan); +@@ -687,41 +687,12 @@ int config_parse_cpu_affinity( + void *data, + void *userdata) { + +- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; + Settings *settings = data; +- int ncpus; + + assert(rvalue); + assert(settings); + +- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); +- if (ncpus < 0) +- return ncpus; +- +- if (ncpus == 0) { +- /* An empty assignment resets the CPU list */ +- settings->cpuset = cpu_set_mfree(settings->cpuset); +- settings->cpuset_ncpus = 0; +- return 0; +- } +- +- if (!settings->cpuset) { +- settings->cpuset = TAKE_PTR(cpuset); +- settings->cpuset_ncpus = (unsigned) ncpus; +- return 0; +- } +- +- if (settings->cpuset_ncpus < (unsigned) ncpus) { +- CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset); +- CPU_FREE(settings->cpuset); +- settings->cpuset = TAKE_PTR(cpuset); +- settings->cpuset_ncpus = (unsigned) ncpus; +- return 0; +- } +- +- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset); +- +- return 0; ++ return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue); + } + + DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode"); +diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h +index d522f3cb36..da863ef11c 100644 +--- a/src/nspawn/nspawn-settings.h ++++ b/src/nspawn/nspawn-settings.h +@@ -7,6 +7,7 @@ + #include "sd-id128.h" + + #include "conf-parser.h" ++#include "cpu-set-util.h" + #include "macro.h" + #include "nspawn-expose-ports.h" + #include "nspawn-mount.h" +@@ -123,8 +124,7 @@ typedef struct Settings { + int no_new_privileges; + int oom_score_adjust; + bool oom_score_adjust_set; +- cpu_set_t *cpuset; +- unsigned cpuset_ncpus; ++ CPUSet cpu_set; + ResolvConfMode resolv_conf; + LinkJournal link_journal; + bool link_journal_try; +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index b40411dcd0..08255b5724 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -199,8 +199,7 @@ static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {}; + static bool arg_no_new_privileges = false; + static int arg_oom_score_adjust = 0; + static bool arg_oom_score_adjust_set = false; +-static cpu_set_t *arg_cpuset = NULL; +-static unsigned arg_cpuset_ncpus = 0; ++static CPUSet arg_cpu_set = {}; + static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO; + static TimezoneMode arg_timezone = TIMEZONE_AUTO; + +@@ -1186,17 +1185,14 @@ static int parse_argv(int argc, char *argv[]) { + break; + + case ARG_CPU_AFFINITY: { +- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; ++ CPUSet cpuset; + + r = parse_cpu_set(optarg, &cpuset); + if (r < 0) +- return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg); ++ return log_error_errno(r, "Failed to parse CPU affinity mask %s: %m", optarg); + +- if (arg_cpuset) +- CPU_FREE(arg_cpuset); +- +- arg_cpuset = TAKE_PTR(cpuset); +- arg_cpuset_ncpus = r; ++ cpu_set_reset(&arg_cpu_set); ++ arg_cpu_set = cpuset; + arg_settings_mask |= SETTING_CPU_AFFINITY; + break; + } +@@ -2631,8 +2627,8 @@ static int inner_child( + return log_error_errno(r, "Failed to adjust OOM score: %m"); + } + +- if (arg_cpuset) +- if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0) ++ if (arg_cpu_set.set) ++ if (sched_setaffinity(0, arg_cpu_set.allocated, arg_cpu_set.set) < 0) + return log_error_errno(errno, "Failed to set CPU affinity: %m"); + + r = drop_capabilities(); +@@ -3494,15 +3490,14 @@ static int merge_settings(Settings *settings, const char *path) { + } + + if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 && +- settings->cpuset) { ++ settings->cpu_set.set) { + + if (!arg_settings_trusted) + log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path); + else { +- if (arg_cpuset) +- CPU_FREE(arg_cpuset); +- arg_cpuset = TAKE_PTR(settings->cpuset); +- arg_cpuset_ncpus = settings->cpuset_ncpus; ++ cpu_set_reset(&arg_cpu_set); ++ arg_cpu_set = settings->cpu_set; ++ settings->cpu_set = (CPUSet) {}; + } + } + +@@ -4600,7 +4595,7 @@ finish: + rlimit_free_all(arg_rlimit); + strv_free(arg_syscall_whitelist); + strv_free(arg_syscall_blacklist); +- arg_cpuset = cpu_set_mfree(arg_cpuset); ++ cpu_set_reset(&arg_cpu_set); + + return r < 0 ? EXIT_FAILURE : ret; + } +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index 271cc054da..75b4aace84 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -932,13 +932,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + } + + if (streq(field, "CPUAffinity")) { +- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; ++ _cleanup_(cpu_set_reset) CPUSet cpuset = {}; + + r = parse_cpu_set(eq, &cpuset); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + +- return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r)); ++ return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated); + } + + if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) { +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index ff5edb2a69..b9ec29af66 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -1,154 +1,171 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + ++#include ++ + #include "alloc-util.h" + #include "cpu-set-util.h" + #include "macro.h" + + static void test_parse_cpu_set(void) { +- cpu_set_t *c = NULL; ++ CPUSet c = {}; + _cleanup_free_ char *str = NULL; +- int ncpus; + int cpu; + + /* Simple range (from CPUAffinity example) */ +- ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); +- +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.set); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_ISSET_S(1, c.allocated, c.set)); ++ assert_se(CPU_ISSET_S(2, c.allocated, c.set)); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); ++ ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* A more interesting range */ +- ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + for (cpu = 8; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Quoted strings */ +- ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); ++ assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 4); + for (cpu = 8; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Use commas as separators */ +- ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + for (cpu = 8; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Commas with spaces (and trailing comma, space) */ +- ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 8; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Ranges */ +- ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + for (cpu = 8; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Ranges with trailing comma, space */ +- ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + for (cpu = 8; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Negative range (returns empty cpu_set) */ +- ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); +- c = cpu_set_mfree(c); ++ assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 0); ++ cpu_set_reset(&c); + + /* Overlapping ranges */ +- ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); ++ assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 12); + for (cpu = 0; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Mix ranges and individual CPUs */ +- ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus >= 1024); +- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); +- assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 10); ++ assert_se(CPU_ISSET_S(0, c.allocated, c.set)); ++ assert_se(CPU_ISSET_S(1, c.allocated, c.set)); + for (cpu = 4; cpu < 12; cpu++) +- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); +- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus))); ++ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); +- c = cpu_set_mfree(c); ++ cpu_set_reset(&c); + + /* Garbage */ +- ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus < 0); +- assert_se(!c); ++ assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); ++ assert_se(!c.set); ++ assert_se(c.allocated == 0); + + /* Range with garbage */ +- ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus < 0); +- assert_se(!c); ++ assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); ++ assert_se(!c.set); ++ assert_se(c.allocated == 0); + + /* Empty string */ +- c = NULL; +- ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus == 0); /* empty string returns 0 */ +- assert_se(!c); ++ assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(!c.set); /* empty string returns NULL */ ++ assert_se(c.allocated == 0); + + /* Runaway quoted string */ +- ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); +- assert_se(ncpus < 0); +- assert_se(!c); ++ assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); ++ assert_se(!c.set); ++ assert_se(c.allocated == 0); ++ ++ /* Maximum allocation */ ++ assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 192); ++ assert_se(str = cpu_set_to_string(&c)); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); ++ cpu_set_reset(&c); + } + + int main(int argc, char *argv[]) { ++ log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1)); ++ log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9)); ++ log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64)); ++ log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65)); ++ log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024)); ++ log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025)); ++ log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); ++ + test_parse_cpu_set(); + + return 0; +diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c +index 7a1e496ed2..396e68f35f 100644 +--- a/src/test/test-sizeof.c ++++ b/src/test/test-sizeof.c +@@ -1,5 +1,6 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + ++#include + #include + #include + +@@ -64,6 +65,8 @@ int main(void) { + info(uid_t); + info(gid_t); + ++ info(__cpu_mask); ++ + info(enum Enum); + info(enum BigEnum); + info(enum BigEnum2); diff --git a/SOURCES/0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch b/SOURCES/0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch new file mode 100644 index 0000000..43f5d04 --- /dev/null +++ b/SOURCES/0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch @@ -0,0 +1,125 @@ +From 42032749e61076b3d9e5004432073c2a5ea737ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 28 May 2019 21:28:31 +0200 +Subject: [PATCH] Move cpus_in_affinity_mask() to cpu-set-util.[ch] + +It just seems to fit better there and it's always better to have things +in shared/ rather than basic/. + +(cherry picked from commit f44b3035d4a698aa0ce08a552199b54d43de3d85) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 34 ++++++++++++++++++++++++++++++++++ + src/basic/cpu-set-util.h | 2 ++ + src/basic/process-util.c | 5 ++--- + src/shared/condition.c | 1 + + src/test/test-condition.c | 1 + + 5 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index fe440f6381..1803539ac6 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -204,3 +204,37 @@ int parse_cpu_set_extend( + + return cpu_set_add_all(old, &cpuset); + } ++ ++int cpus_in_affinity_mask(void) { ++ size_t n = 16; ++ int r; ++ ++ for (;;) { ++ cpu_set_t *c; ++ ++ c = CPU_ALLOC(n); ++ if (!c) ++ return -ENOMEM; ++ ++ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) { ++ int k; ++ ++ k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c); ++ CPU_FREE(c); ++ ++ if (k <= 0) ++ return -EINVAL; ++ ++ return k; ++ } ++ ++ r = -errno; ++ CPU_FREE(c); ++ ++ if (r != -EINVAL) ++ return r; ++ if (n > SIZE_MAX/2) ++ return -ENOMEM; ++ n *= 2; ++ } ++} +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index eb31b362fe..9b026aca09 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -49,3 +49,5 @@ int parse_cpu_set_extend( + static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){ + return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL); + } ++ ++int cpus_in_affinity_mask(void); +diff --git a/src/basic/process-util.c b/src/basic/process-util.c +index 6dbeee9dda..0a4a747ba4 100644 +--- a/src/basic/process-util.c ++++ b/src/basic/process-util.c +@@ -4,7 +4,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1474,7 +1473,7 @@ static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", +- [IOPRIO_CLASS_IDLE] = "idle" ++ [IOPRIO_CLASS_IDLE] = "idle", + }; + + DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES); +@@ -1495,7 +1494,7 @@ static const char* const sched_policy_table[] = { + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", +- [SCHED_RR] = "rr" ++ [SCHED_RR] = "rr", + }; + + DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 2969a89b4e..b829f0528c 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -21,6 +21,7 @@ + #include "cap-list.h" + #include "cgroup-util.h" + #include "condition.h" ++#include "cpu-set-util.h" + #include "efivars.h" + #include "extract-word.h" + #include "fd-util.h" +diff --git a/src/test/test-condition.c b/src/test/test-condition.c +index 7ce6ee80ea..24395dafc6 100644 +--- a/src/test/test-condition.c ++++ b/src/test/test-condition.c +@@ -13,6 +13,7 @@ + #include "audit-util.h" + #include "cgroup-util.h" + #include "condition.h" ++#include "cpu-set-util.h" + #include "efivars.h" + #include "hostname-util.h" + #include "id128-util.h" diff --git a/SOURCES/0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch b/SOURCES/0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch new file mode 100644 index 0000000..026cee1 --- /dev/null +++ b/SOURCES/0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch @@ -0,0 +1,40 @@ +From a1ed6bfc5a8c40377b9f1cab1acc3c67a9529427 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 21 May 2019 09:01:34 +0200 +Subject: [PATCH] test-cpu-set-util: add simple test for + cpus_in_affinity_mask() + +(cherry picked from commit 9d1345f0657c707df89b41b2738776efb40aec8e) + +Related: #1734787 +--- + src/test/test-cpu-set-util.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index b9ec29af66..e87e0ca6e6 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -157,6 +157,14 @@ static void test_parse_cpu_set(void) { + cpu_set_reset(&c); + } + ++static void test_cpus_in_affinity_mask(void) { ++ int r; ++ ++ r = cpus_in_affinity_mask(); ++ assert(r > 0); ++ log_info("cpus_in_affinity_mask: %d", r); ++} ++ + int main(int argc, char *argv[]) { + log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1)); + log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9)); +@@ -167,6 +175,7 @@ int main(int argc, char *argv[]) { + log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); + + test_parse_cpu_set(); ++ test_cpus_in_affinity_mask(); + + return 0; + } diff --git a/SOURCES/0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch b/SOURCES/0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch new file mode 100644 index 0000000..cce5c67 --- /dev/null +++ b/SOURCES/0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch @@ -0,0 +1,63 @@ +From 69541e93c45efb7ee15d7584c3aa70c3ff0b2200 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 24 May 2019 08:50:41 +0200 +Subject: [PATCH] test-cpu-set-util: add a smoke test for + test_parse_cpu_set_extend() + +(cherry picked from commit b54d7241f25b859c6c008e516c2131c39902e6e4) + +Related: #1734787 +--- + src/test/test-cpu-set-util.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index e87e0ca6e6..81f67647e8 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -11,6 +11,8 @@ static void test_parse_cpu_set(void) { + _cleanup_free_ char *str = NULL; + int cpu; + ++ log_info("/* %s */", __func__); ++ + /* Simple range (from CPUAffinity example) */ + assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); +@@ -157,6 +159,28 @@ static void test_parse_cpu_set(void) { + cpu_set_reset(&c); + } + ++static void test_parse_cpu_set_extend(void) { ++ CPUSet c = {}; ++ _cleanup_free_ char *s1 = NULL, *s2 = NULL; ++ ++ log_info("/* %s */", __func__); ++ ++ assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); ++ assert_se(s1 = cpu_set_to_string(&c)); ++ log_info("cpu_set_to_string: %s", s1); ++ ++ assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); ++ assert_se(s2 = cpu_set_to_string(&c)); ++ log_info("cpu_set_to_string: %s", s2); ++ ++ assert_se(parse_cpu_set_extend("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(!c.set); ++ assert_se(c.allocated == 0); ++ log_info("cpu_set_to_string: (null)"); ++} ++ + static void test_cpus_in_affinity_mask(void) { + int r; + +@@ -175,6 +199,7 @@ int main(int argc, char *argv[]) { + log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); + + test_parse_cpu_set(); ++ test_parse_cpu_set_extend(); + test_cpus_in_affinity_mask(); + + return 0; diff --git a/SOURCES/0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch b/SOURCES/0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch new file mode 100644 index 0000000..948c139 --- /dev/null +++ b/SOURCES/0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch @@ -0,0 +1,148 @@ +From 8bf8409c6e08f5aef35d1976e172b3f61b651c8d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 24 May 2019 08:35:51 +0200 +Subject: [PATCH] pid1: parse CPUAffinity= in incremental fashion + +This makes the handling of this option match what we do in unit files. I think +consistency is important here. (As it happens, it is the only option in +system.conf that is "non-atomic", i.e. where there's a list of things which can +be split over multiple assignments. All other options are single-valued, so +there's no issue of how to handle multiple assignments.) + +(cherry picked from commit 61fbbac1d517a0b3498a689c736c6ca918497904) + +Related: #1734787 +--- + man/systemd-system.conf.xml | 13 ++++++++----- + man/systemd.exec.xml | 2 +- + src/core/main.c | 36 ++++++++++++++++++++++++++---------- + 3 files changed, 35 insertions(+), 16 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 085086200a..ab23779ec0 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -99,11 +99,14 @@ + + CPUAffinity= + +- Configures the initial CPU affinity for the +- init process. Takes a list of CPU indices or ranges separated +- by either whitespace or commas. CPU ranges are specified by +- the lower and upper CPU indices separated by a +- dash. ++ Configures the CPU affinity for the service manager as well as the default CPU ++ affinity for all forked off processes. Takes a list of CPU indices or ranges separated by either ++ whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated by a ++ dash. This option may be specified more than once, in which case the specified CPU affinity masks are ++ merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have ++ no effect. Individual services may override the CPU affinity for their processes with the ++ CPUAffinity= setting in unit files, see ++ systemd.exec5. + + + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 737c52bcc4..342b8385bc 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -703,7 +703,7 @@ CapabilityBoundingSet=~CAP_B CAP_C + + Controls the CPU affinity of the executed processes. Takes a list of CPU indices or ranges + separated by either whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated +- by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are ++ by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are + merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no + effect. See + sched_setaffinity2 for +diff --git a/src/core/main.c b/src/core/main.c +index e62b2756ee..bc1db2af7b 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -127,6 +127,7 @@ static bool arg_default_tasks_accounting = true; + static uint64_t arg_default_tasks_max = UINT64_MAX; + static sd_id128_t arg_machine_id = {}; + static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; ++static CPUSet arg_cpu_affinity = {}; + + _noreturn_ static void freeze_or_reboot(void) { + +@@ -537,17 +538,11 @@ static int config_parse_cpu_affinity2( + void *data, + void *userdata) { + +- _cleanup_(cpu_set_reset) CPUSet c = {}; +- int r; +- +- r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue); +- if (r < 0) +- return r; ++ CPUSet *affinity = data; + +- if (sched_setaffinity(0, c.allocated, c.set) < 0) +- log_warning_errno(errno, "Failed to set CPU affinity: %m"); ++ assert(affinity); + +- // FIXME: parsing and execution should be seperated. ++ (void) parse_cpu_set_extend(rvalue, affinity, true, unit, filename, line, lvalue); + + return 0; + } +@@ -655,7 +650,7 @@ static int parse_config_file(void) { + { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, + { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, +- { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, ++ { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity }, + { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, + { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, + { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog }, +@@ -1483,6 +1478,21 @@ static void initialize_coredump(bool skip_setup) { + #endif + } + ++static void update_cpu_affinity(bool skip_setup) { ++ _cleanup_free_ char *mask = NULL; ++ ++ if (skip_setup || !arg_cpu_affinity.set) ++ return; ++ ++ assert(arg_cpu_affinity.allocated > 0); ++ ++ mask = cpu_set_to_string(&arg_cpu_affinity); ++ log_debug("Setting CPU affinity to %s.", strnull(mask)); ++ ++ if (sched_setaffinity(0, arg_cpu_affinity.allocated, arg_cpu_affinity.set) < 0) ++ log_warning_errno(errno, "Failed to set CPU affinity: %m"); ++} ++ + static void do_reexecute( + int argc, + char *argv[], +@@ -1655,6 +1665,8 @@ static int invoke_main_loop( + + set_manager_defaults(m); + ++ update_cpu_affinity(false); ++ + if (saved_log_level >= 0) + manager_override_log_level(m, saved_log_level); + if (saved_log_target >= 0) +@@ -1813,6 +1825,8 @@ static int initialize_runtime( + if (arg_action != ACTION_RUN) + return 0; + ++ update_cpu_affinity(skip_setup); ++ + if (arg_system) { + /* Make sure we leave a core dump without panicing the kernel. */ + install_crash_handler(); +@@ -1947,6 +1961,8 @@ static void free_arguments(void) { + arg_join_controllers = strv_free_free(arg_join_controllers); + arg_default_environment = strv_free(arg_default_environment); + arg_syscall_archs = set_free(arg_syscall_archs); ++ ++ cpu_set_reset(&arg_cpu_affinity); + } + + static int load_configuration(int argc, char **argv, const char **ret_error_message) { diff --git a/SOURCES/0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch b/SOURCES/0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch new file mode 100644 index 0000000..bb8d822 --- /dev/null +++ b/SOURCES/0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch @@ -0,0 +1,86 @@ +From f71f3271fa149d2b5f022830d43071d97b022b38 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 24 May 2019 08:59:23 +0200 +Subject: [PATCH] pid1: don't reset setting from /proc/cmdline upon restart + +We have settings which may be set on the kernel command line, and also +in /proc/cmdline (for pid1). The settings in /proc/cmdline have higher priority +of course. When a reload was done, we'd reload just the configuration file, +losing the overrides. + +So read /proc/cmdline again during reload. + +Also, when initially reading the configuration file when program starts, +don't treat any errors as fatal. The configuration done in there doesn't +seem important enough to refuse boot. + +(cherry picked from commit 470a5e6dcec4637439ae953002127af214d396ac) + +Related: #1734787 +--- + src/core/main.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index bc1db2af7b..9a9f145080 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -129,6 +129,8 @@ static sd_id128_t arg_machine_id = {}; + static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; + static CPUSet arg_cpu_affinity = {}; + ++static int parse_configuration(void); ++ + _noreturn_ static void freeze_or_reboot(void) { + + if (arg_crash_reboot) { +@@ -1659,9 +1661,7 @@ static int invoke_main_loop( + saved_log_level = m->log_level_overridden ? log_get_max_level() : -1; + saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID; + +- r = parse_config_file(); +- if (r < 0) +- log_warning_errno(r, "Failed to parse config file, ignoring: %m"); ++ (void) parse_configuration(); + + set_manager_defaults(m); + +@@ -1965,18 +1965,14 @@ static void free_arguments(void) { + cpu_set_reset(&arg_cpu_affinity); + } + +-static int load_configuration(int argc, char **argv, const char **ret_error_message) { ++static int parse_configuration(void) { + int r; + +- assert(ret_error_message); +- + arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U); + + r = parse_config_file(); +- if (r < 0) { +- *ret_error_message = "Failed to parse config file"; +- return r; +- } ++ if (r < 0) ++ log_warning_errno(r, "Failed to parse config file, ignoring: %m"); + + if (arg_system) { + r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); +@@ -1987,6 +1983,16 @@ static int load_configuration(int argc, char **argv, const char **ret_error_mess + /* Note that this also parses bits from the kernel command line, including "debug". */ + log_parse_environment(); + ++ return 0; ++} ++ ++static int load_configuration(int argc, char **argv, const char **ret_error_message) { ++ int r; ++ ++ assert(ret_error_message); ++ ++ (void) parse_configuration(); ++ + r = parse_argv(argc, argv); + if (r < 0) { + *ret_error_message = "Failed to parse commandline arguments"; diff --git a/SOURCES/0278-pid1-when-reloading-configuration-forget-old-setting.patch b/SOURCES/0278-pid1-when-reloading-configuration-forget-old-setting.patch new file mode 100644 index 0000000..1b941cc --- /dev/null +++ b/SOURCES/0278-pid1-when-reloading-configuration-forget-old-setting.patch @@ -0,0 +1,208 @@ +From 0387294ba41ceaf80c79621409aab9508732bda0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 24 May 2019 09:41:44 +0200 +Subject: [PATCH] pid1: when reloading configuration, forget old settings + +If we had a configuration setting from a configuration file, and it was +removed, we'd still remember the old value, because there's was no mechanism to +"reset" everything, just to assign new values. + +Note that the effect of this is limited. For settings that have an "ongoing" effect, +like systemd.confirm_spawn, the new value is simply used. But some settings can only +be set at start. + +In particular, CPUAffinity= will be updated if set to a new value, but if +CPUAffinity= is fully removed, it will not be reset, simply because we don't +know what to reset it to. We might have inherited a setting, or we might have +set it ourselves. In principle we could remember the "original" value that was +set when we were executed, but propagate this over reloads and reexecs, but +that would be a lot of work for little gain. So this corner case of removal of +CPUAffinity= is not handled fully, and a reboot is needed to execute the +change. As a work-around, a full mask of CPUAffinity=0-8191 can be specified. + +(cherry picked from commit fb39af4ce42d7ef9af63009f271f404038703704) + +Related: #1734787 +--- + src/core/main.c | 139 +++++++++++++++++++++++++++++++++--------------- + 1 file changed, 95 insertions(+), 44 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 9a9f145080..c74dc641c1 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -88,46 +88,52 @@ static enum { + ACTION_DUMP_CONFIGURATION_ITEMS, + ACTION_DUMP_BUS_PROPERTIES, + } arg_action = ACTION_RUN; +-static char *arg_default_unit = NULL; +-static bool arg_system = false; +-static bool arg_dump_core = true; +-static int arg_crash_chvt = -1; +-static bool arg_crash_shell = false; +-static bool arg_crash_reboot = false; +-static char *arg_confirm_spawn = NULL; +-static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; +-static bool arg_switched_root = false; +-static bool arg_no_pager = false; +-static bool arg_service_watchdogs = true; ++ ++/* Those variables are initalized to 0 automatically, so we avoid uninitialized memory access. ++ * Real defaults are assigned in reset_arguments() below. */ ++static char *arg_default_unit; ++static bool arg_system; ++static bool arg_dump_core; ++static int arg_crash_chvt; ++static bool arg_crash_shell; ++static bool arg_crash_reboot; ++static char *arg_confirm_spawn; ++static ShowStatus arg_show_status; ++static bool arg_switched_root; ++static bool arg_no_pager; ++static bool arg_service_watchdogs; + static char ***arg_join_controllers = NULL; +-static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; +-static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; +-static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC; +-static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC; +-static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC; +-static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL; +-static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST; +-static usec_t arg_runtime_watchdog = 0; +-static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; +-static char *arg_watchdog_device = NULL; +-static char **arg_default_environment = NULL; +-static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {}; +-static uint64_t arg_capability_bounding_set = CAP_ALL; +-static bool arg_no_new_privs = false; +-static nsec_t arg_timer_slack_nsec = NSEC_INFINITY; +-static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; +-static Set* arg_syscall_archs = NULL; +-static FILE* arg_serialization = NULL; +-static bool arg_default_cpu_accounting = false; +-static bool arg_default_io_accounting = false; +-static bool arg_default_ip_accounting = false; +-static bool arg_default_blockio_accounting = false; +-static bool arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT; +-static bool arg_default_tasks_accounting = true; +-static uint64_t arg_default_tasks_max = UINT64_MAX; +-static sd_id128_t arg_machine_id = {}; +-static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; +-static CPUSet arg_cpu_affinity = {}; ++static ExecOutput arg_default_std_output; ++static ExecOutput arg_default_std_error; ++static usec_t arg_default_restart_usec; ++static usec_t arg_default_timeout_start_usec; ++static usec_t arg_default_timeout_stop_usec; ++static usec_t arg_default_timeout_abort_usec; ++static bool arg_default_timeout_abort_set; ++static usec_t arg_default_start_limit_interval; ++static unsigned arg_default_start_limit_burst; ++static usec_t arg_runtime_watchdog; ++static usec_t arg_shutdown_watchdog; ++static char *arg_early_core_pattern; ++static char *arg_watchdog_device; ++static char **arg_default_environment; ++static struct rlimit *arg_default_rlimit[_RLIMIT_MAX]; ++static uint64_t arg_capability_bounding_set; ++static bool arg_no_new_privs; ++static nsec_t arg_timer_slack_nsec; ++static usec_t arg_default_timer_accuracy_usec; ++static Set* arg_syscall_archs; ++static FILE* arg_serialization; ++static int arg_default_cpu_accounting; ++static bool arg_default_io_accounting; ++static bool arg_default_ip_accounting; ++static bool arg_default_blockio_accounting; ++static bool arg_default_memory_accounting; ++static bool arg_default_tasks_accounting; ++static uint64_t arg_default_tasks_max; ++static sd_id128_t arg_machine_id; ++static EmergencyAction arg_cad_burst_action; ++static CPUSet arg_cpu_affinity; + + static int parse_configuration(void); + +@@ -1951,17 +1957,59 @@ static int do_queue_default_job( + return 0; + } + +-static void free_arguments(void) { +- +- /* Frees all arg_* variables, with the exception of arg_serialization */ +- rlimit_free_all(arg_default_rlimit); ++static void reset_arguments(void) { ++ /* Frees/resets arg_* variables, with a few exceptions commented below. */ + + arg_default_unit = mfree(arg_default_unit); ++ ++ /* arg_system — ignore */ ++ ++ arg_dump_core = true; ++ arg_crash_chvt = -1; ++ arg_crash_shell = false; ++ arg_crash_reboot = false; + arg_confirm_spawn = mfree(arg_confirm_spawn); + arg_join_controllers = strv_free_free(arg_join_controllers); ++ arg_show_status = _SHOW_STATUS_UNSET; ++ arg_switched_root = false; ++ arg_no_pager = false; ++ arg_service_watchdogs = true; ++ arg_default_std_output = EXEC_OUTPUT_JOURNAL; ++ arg_default_std_error = EXEC_OUTPUT_INHERIT; ++ arg_default_restart_usec = DEFAULT_RESTART_USEC; ++ arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC; ++ arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC; ++ arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC; ++ arg_default_timeout_abort_set = false; ++ arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL; ++ arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST; ++ arg_runtime_watchdog = 0; ++ arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; ++ arg_early_core_pattern = NULL; ++ arg_watchdog_device = NULL; ++ + arg_default_environment = strv_free(arg_default_environment); ++ rlimit_free_all(arg_default_rlimit); ++ ++ arg_capability_bounding_set = CAP_ALL; ++ arg_no_new_privs = false; ++ arg_timer_slack_nsec = NSEC_INFINITY; ++ arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; ++ + arg_syscall_archs = set_free(arg_syscall_archs); + ++ /* arg_serialization — ignore */ ++ ++ arg_default_cpu_accounting = -1; ++ arg_default_io_accounting = false; ++ arg_default_ip_accounting = false; ++ arg_default_blockio_accounting = false; ++ arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT; ++ arg_default_tasks_accounting = true; ++ arg_default_tasks_max = UINT64_MAX; ++ arg_machine_id = (sd_id128_t) {}; ++ arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; ++ + cpu_set_reset(&arg_cpu_affinity); + } + +@@ -1970,6 +2018,9 @@ static int parse_configuration(void) { + + arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U); + ++ /* Assign configuration defaults */ ++ reset_arguments(); ++ + r = parse_config_file(); + if (r < 0) + log_warning_errno(r, "Failed to parse config file, ignoring: %m"); +@@ -2460,7 +2511,7 @@ finish: + m = manager_free(m); + } + +- free_arguments(); ++ reset_arguments(); + mac_selinux_finish(); + + if (reexecute) diff --git a/SOURCES/0279-test-execute-use-CPUSet-too.patch b/SOURCES/0279-test-execute-use-CPUSet-too.patch new file mode 100644 index 0000000..2332226 --- /dev/null +++ b/SOURCES/0279-test-execute-use-CPUSet-too.patch @@ -0,0 +1,114 @@ +From 5e6b616ed2708391752ba8c45f183ceb38573d7d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 28 May 2019 21:38:41 +0200 +Subject: [PATCH] test-execute: use CPUSet too + +cpu_set_malloc() was the last user. It doesn't seem useful to keep +it just to save the allocation of a few hundred bytes in a test, so +it is dropped and a fixed maximum is allocated (1024 bytes). + +(cherry picked from commit 167a776dbe9d033523bd6881e5a695f2155dc321) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 31 +------------------------------ + src/basic/cpu-set-util.h | 3 +-- + src/test/test-execute.c | 13 ++++++------- + 3 files changed, 8 insertions(+), 39 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index 1803539ac6..c297eab032 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -37,36 +37,7 @@ char* cpu_set_to_string(const CPUSet *a) { + return TAKE_PTR(str) ?: strdup(""); + } + +-cpu_set_t* cpu_set_malloc(unsigned *ncpus) { +- cpu_set_t *c; +- unsigned n = 1024; +- +- /* Allocates the cpuset in the right size */ +- +- for (;;) { +- c = CPU_ALLOC(n); +- if (!c) +- return NULL; +- +- if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) { +- CPU_ZERO_S(CPU_ALLOC_SIZE(n), c); +- +- if (ncpus) +- *ncpus = n; +- +- return c; +- } +- +- CPU_FREE(c); +- +- if (errno != EINVAL) +- return NULL; +- +- n *= 2; +- } +-} +- +-static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) { ++int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) { + size_t need; + + assert(cpu_set); +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 9b026aca09..b54e737110 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -12,8 +12,6 @@ + DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); + #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + +-cpu_set_t* cpu_set_malloc(unsigned *ncpus); +- + /* This wraps the libc interface with a variable to keep the allocated size. */ + typedef struct CPUSet { + cpu_set_t *set; +@@ -30,6 +28,7 @@ static inline void cpu_set_reset(CPUSet *a) { + int cpu_set_add_all(CPUSet *a, const CPUSet *b); + + char* cpu_set_to_string(const CPUSet *a); ++int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus); + int parse_cpu_set_full( + const char *rvalue, + CPUSet *cpu_set, +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index fa8efdddd2..6c22995b1e 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -144,13 +144,12 @@ static void test_exec_bindpaths(Manager *m) { + } + + static void test_exec_cpuaffinity(Manager *m) { +- _cleanup_cpu_free_ cpu_set_t *c = NULL; +- unsigned n; ++ _cleanup_(cpu_set_reset) CPUSet c = {}; + +- assert_se(c = cpu_set_malloc(&n)); +- assert_se(sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0); ++ assert_se(cpu_set_realloc(&c, 8192) >= 0); /* just allocate the maximum possible size */ ++ assert_se(sched_getaffinity(0, c.allocated, c.set) >= 0); + +- if (CPU_ISSET_S(0, CPU_ALLOC_SIZE(n), c) == 0) { ++ if (!CPU_ISSET_S(0, c.allocated, c.set)) { + log_notice("Cannot use CPU 0, skipping %s", __func__); + return; + } +@@ -158,8 +157,8 @@ static void test_exec_cpuaffinity(Manager *m) { + test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED); + test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED); + +- if (CPU_ISSET_S(1, CPU_ALLOC_SIZE(n), c) == 0 || +- CPU_ISSET_S(2, CPU_ALLOC_SIZE(n), c) == 0) { ++ if (!CPU_ISSET_S(1, c.allocated, c.set) || ++ !CPU_ISSET_S(2, c.allocated, c.set)) { + log_notice("Cannot use CPU 1 or 2, skipping remaining tests in %s", __func__); + return; + } diff --git a/SOURCES/0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch b/SOURCES/0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch new file mode 100644 index 0000000..21bf12e --- /dev/null +++ b/SOURCES/0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch @@ -0,0 +1,26 @@ +From 7aa32093c3dfc4bf7298f02be553e95c40d7c211 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 28 May 2019 21:40:10 +0200 +Subject: [PATCH] shared/cpu-set-util: drop now-unused cleanup function + +(cherry picked from commit cb0d3acf55ef335001cac5dd9c335ec5e75e9b56) + +Related: #1734787 +--- + src/basic/cpu-set-util.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index b54e737110..68a73bf9f7 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -9,9 +9,6 @@ + + #include "macro.h" + +-DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); +-#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) +- + /* This wraps the libc interface with a variable to keep the allocated size. */ + typedef struct CPUSet { + cpu_set_t *set; diff --git a/SOURCES/0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch b/SOURCES/0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch new file mode 100644 index 0000000..d09f290 --- /dev/null +++ b/SOURCES/0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch @@ -0,0 +1,126 @@ +From daa0243fda679c8af723648b8b1e501fc55b0ada Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 22 May 2019 13:55:49 +0200 +Subject: [PATCH] shared/cpu-set-util: make transfer of cpu_set_t over bus + endian safe + +(cherry picked from commit c367f996f5f091a63f812f0140b304c649be77fc) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 38 ++++++++++++++++++++++++++++++++++++++ + src/basic/cpu-set-util.h | 3 +++ + src/core/dbus-execute.c | 6 +++++- + src/shared/bus-unit-util.c | 8 +++++++- + 4 files changed, 53 insertions(+), 2 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index c297eab032..74e35e57dd 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -209,3 +209,41 @@ int cpus_in_affinity_mask(void) { + n *= 2; + } + } ++ ++int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated) { ++ uint8_t *out; ++ ++ assert(set); ++ assert(ret); ++ ++ out = new0(uint8_t, set->allocated); ++ if (!out) ++ return -ENOMEM; ++ ++ for (unsigned cpu = 0; cpu < set->allocated * 8; cpu++) ++ if (CPU_ISSET_S(cpu, set->allocated, set->set)) ++ out[cpu / 8] |= 1u << (cpu % 8); ++ ++ *ret = out; ++ *allocated = set->allocated; ++ return 0; ++} ++ ++int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) { ++ _cleanup_(cpu_set_reset) CPUSet s = {}; ++ int r; ++ ++ assert(bits); ++ assert(set); ++ ++ for (unsigned cpu = size * 8; cpu > 0; cpu--) ++ if (bits[(cpu - 1) / 8] & (1u << ((cpu - 1) % 8))) { ++ r = cpu_set_add(&s, cpu - 1); ++ if (r < 0) ++ return r; ++ } ++ ++ *set = s; ++ s = (CPUSet) {}; ++ return 0; ++} +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 68a73bf9f7..415c6ca295 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -46,4 +46,7 @@ static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){ + return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL); + } + ++int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated); ++int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set); ++ + int cpus_in_affinity_mask(void); +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index 08946627e3..50ea71a281 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -1553,18 +1553,22 @@ int bus_exec_context_set_transient_property( + if (streq(name, "CPUAffinity")) { + const void *a; + size_t n; ++ _cleanup_(cpu_set_reset) CPUSet set = {}; + + r = sd_bus_message_read_array(message, 'y', &a, &n); + if (r < 0) + return r; + ++ r = cpu_set_from_dbus(a, n, &set); ++ if (r < 0) ++ return r; ++ + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (n == 0) { + cpu_set_reset(&c->cpu_set); + unit_write_settingf(u, flags, name, "%s=", name); + } else { + _cleanup_free_ char *str = NULL; +- const CPUSet set = {(cpu_set_t*) a, n}; + + str = cpu_set_to_string(&set); + if (!str) +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index 75b4aace84..ec8732c226 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -933,12 +933,18 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + + if (streq(field, "CPUAffinity")) { + _cleanup_(cpu_set_reset) CPUSet cpuset = {}; ++ _cleanup_free_ uint8_t *array = NULL; ++ size_t allocated; + + r = parse_cpu_set(eq, &cpuset); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + +- return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated); ++ r = cpu_set_to_dbus(&cpuset, &array, &allocated); ++ if (r < 0) ++ return log_error_errno(r, "Failed to serialize CPUAffinity: %m"); ++ ++ return bus_append_byte_array(m, field, array, allocated); + } + + if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) { diff --git a/SOURCES/0282-test-cpu-set-util-add-test-for-dbus-conversions.patch b/SOURCES/0282-test-cpu-set-util-add-test-for-dbus-conversions.patch new file mode 100644 index 0000000..f6e259a --- /dev/null +++ b/SOURCES/0282-test-cpu-set-util-add-test-for-dbus-conversions.patch @@ -0,0 +1,61 @@ +From fd65eadbbcc068171ee9164610fd1c2016b3bf59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 29 May 2019 09:44:16 +0200 +Subject: [PATCH] test-cpu-set-util: add test for dbus conversions + +(cherry picked from commit 1bf0d6c28f8c884e187c7dacc1a969c0763ff4e3) + +Related: #1734787 +--- + src/test/test-cpu-set-util.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index 81f67647e8..cae51ad7d9 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -181,6 +181,36 @@ static void test_parse_cpu_set_extend(void) { + log_info("cpu_set_to_string: (null)"); + } + ++static void test_cpu_set_to_from_dbus(void) { ++ _cleanup_(cpu_set_reset) CPUSet c = {}, c2 = {}; ++ _cleanup_free_ char *s = NULL; ++ ++ log_info("/* %s */", __func__); ++ ++ assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); ++ assert_se(s = cpu_set_to_string(&c)); ++ log_info("cpu_set_to_string: %s", s); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 104); ++ ++ _cleanup_free_ uint8_t *array = NULL; ++ size_t allocated; ++ static const char expected[32] = ++ "\x0A\x01\x00\x00\x00\x00\x00\x00\x00\x00" ++ "\x00\x00\xF0\xFF\xFF\xFF\xFF\xFF\xFF\xFF" ++ "\xFF\xFF\xFF\xFF\xFF\x01"; ++ ++ assert_se(cpu_set_to_dbus(&c, &array, &allocated) == 0); ++ assert_se(array); ++ assert_se(allocated == c.allocated); ++ ++ assert(memcmp(array, expected, sizeof expected) == 0); ++ ++ assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0); ++ assert_se(c2.set); ++ assert_se(c2.allocated == c.allocated); ++ assert_se(memcmp(c.set, c2.set, c.allocated) == 0); ++} ++ + static void test_cpus_in_affinity_mask(void) { + int r; + +@@ -201,6 +231,7 @@ int main(int argc, char *argv[]) { + test_parse_cpu_set(); + test_parse_cpu_set_extend(); + test_cpus_in_affinity_mask(); ++ test_cpu_set_to_from_dbus(); + + return 0; + } diff --git a/SOURCES/0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch b/SOURCES/0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch new file mode 100644 index 0000000..d49553f --- /dev/null +++ b/SOURCES/0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch @@ -0,0 +1,203 @@ +From 93777a6dd8c12d5cba094694bf7ed6e8c06c2d6d Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 23 May 2019 14:27:18 +0200 +Subject: [PATCH] shared/cpu-set-util: introduce cpu_set_to_range() + +(cherry picked from commit 71b28519b55b496237146f9bcb5a627455f15f7e) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 37 ++++++++++++++++++++++++++ + src/basic/cpu-set-util.h | 2 ++ + src/test/test-cpu-set-util.c | 50 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 89 insertions(+) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index 74e35e57dd..bff39ec143 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -37,6 +37,43 @@ char* cpu_set_to_string(const CPUSet *a) { + return TAKE_PTR(str) ?: strdup(""); + } + ++char *cpu_set_to_range_string(const CPUSet *set) { ++ unsigned range_start = 0, range_end; ++ _cleanup_free_ char *str = NULL; ++ size_t allocated = 0, len = 0; ++ bool in_range = false; ++ int r; ++ ++ for (unsigned i = 0; i < set->allocated * 8; i++) ++ if (CPU_ISSET_S(i, set->allocated, set->set)) { ++ if (in_range) ++ range_end++; ++ else { ++ range_start = range_end = i; ++ in_range = true; ++ } ++ } else if (in_range) { ++ in_range = false; ++ ++ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned))) ++ return NULL; ++ ++ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ assert_se(r > 0); ++ len += r; ++ } ++ ++ if (in_range) { ++ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int))) ++ return NULL; ++ ++ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ assert_se(r > 0); ++ } ++ ++ return TAKE_PTR(str) ?: strdup(""); ++} ++ + int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) { + size_t need; + +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index 415c6ca295..ec640b2ec9 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -25,7 +25,9 @@ static inline void cpu_set_reset(CPUSet *a) { + int cpu_set_add_all(CPUSet *a, const CPUSet *b); + + char* cpu_set_to_string(const CPUSet *a); ++char *cpu_set_to_range_string(const CPUSet *a); + int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus); ++ + int parse_cpu_set_full( + const char *rvalue, + CPUSet *cpu_set, +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index cae51ad7d9..0d2741cd43 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -4,6 +4,7 @@ + + #include "alloc-util.h" + #include "cpu-set-util.h" ++#include "string-util.h" + #include "macro.h" + + static void test_parse_cpu_set(void) { +@@ -13,6 +14,22 @@ static void test_parse_cpu_set(void) { + + log_info("/* %s */", __func__); + ++ /* Single value */ ++ assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(c.set); ++ assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(CPU_ISSET_S(0, c.allocated, c.set)); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 1); ++ ++ assert_se(str = cpu_set_to_string(&c)); ++ log_info("cpu_set_to_string: %s", str); ++ str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-0")); ++ str = mfree(str); ++ cpu_set_reset(&c); ++ + /* Simple range (from CPUAffinity example) */ + assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); +@@ -24,6 +41,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "1-2")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* A more interesting range */ +@@ -34,9 +55,14 @@ static void test_parse_cpu_set(void) { + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-3 8-11")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Quoted strings */ +@@ -48,6 +74,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "8-11")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Use commas as separators */ +@@ -72,6 +102,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-7")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Ranges */ +@@ -98,6 +132,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-3 8-11")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Negative range (returns empty cpu_set) */ +@@ -115,6 +153,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-11")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Mix ranges and individual CPUs */ +@@ -128,6 +170,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "0-1 4-11")); ++ str = mfree(str); + cpu_set_reset(&c); + + /* Garbage */ +@@ -156,6 +202,10 @@ static void test_parse_cpu_set(void) { + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); ++ assert_se(str = cpu_set_to_range_string(&c)); ++ log_info("cpu_set_to_range_string: %s", str); ++ assert_se(streq(str, "8000-8191")); ++ str = mfree(str); + cpu_set_reset(&c); + } + diff --git a/SOURCES/0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch b/SOURCES/0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch new file mode 100644 index 0000000..44d35dd --- /dev/null +++ b/SOURCES/0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch @@ -0,0 +1,53 @@ +From fb1244ef318e9f54628a7c13db9e2ffbc712dd38 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 22 May 2019 17:14:21 +0200 +Subject: [PATCH] systemctl: present CPUAffinity mask as a list of CPU index + ranges + +(cherry picked from commit a047f4f10ed2f922d6079c033d24a443b0e95f38) + +Related: #1734787 +--- + src/systemctl/systemctl.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index f072ad0c31..0154b300a3 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -30,6 +30,7 @@ + #include "cgroup-show.h" + #include "cgroup-util.h" + #include "copy.h" ++#include "cpu-set-util.h" + #include "dropin.h" + #include "efivars.h" + #include "env-util.h" +@@ -4876,6 +4877,27 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool + + print_prop(name, "%s", h); + ++ return 1; ++ } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "CPUAffinity")) { ++ _cleanup_free_ char *affinity = NULL; ++ _cleanup_(cpu_set_reset) CPUSet set = {}; ++ const void *a; ++ size_t n; ++ ++ r = sd_bus_message_read_array(m, 'y', &a, &n); ++ if (r < 0) ++ return bus_log_parse_error(r); ++ ++ r = cpu_set_from_dbus(a, n, &set); ++ if (r < 0) ++ return log_error_errno(r, "Failed to deserialize CPUAffinity: %m"); ++ ++ affinity = cpu_set_to_range_string(&set); ++ if (!affinity) ++ return log_oom(); ++ ++ print_prop(name, "%s", affinity); ++ + return 1; + } + diff --git a/SOURCES/0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch b/SOURCES/0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch new file mode 100644 index 0000000..5f34600 --- /dev/null +++ b/SOURCES/0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch @@ -0,0 +1,77 @@ +From cabd9055d0d745f7de9625dec6c623d363dd3aa6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 29 May 2019 10:17:43 +0200 +Subject: [PATCH] shared/cpu-set-util: only force range printing one time +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The idea is to have at least one range to make the new format clearly +distinguishable from the old. But it is enough to just do it once. +In particular, in case the affinity would be specified like 0, 2, 4, 6…, +this gives much shorter output. + +(cherry picked from commit 1f57a176af5152d05719bf43740e87a47e37af50) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 10 ++++++++-- + src/test/test-cpu-set-util.c | 7 ++++--- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index bff39ec143..5024290557 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -58,7 +58,10 @@ char *cpu_set_to_range_string(const CPUSet *set) { + if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned))) + return NULL; + +- r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ if (range_end > range_start || len == 0) ++ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ else ++ r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); + assert_se(r > 0); + len += r; + } +@@ -67,7 +70,10 @@ char *cpu_set_to_range_string(const CPUSet *set) { + if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int))) + return NULL; + +- r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ if (range_end > range_start || len == 0) ++ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); ++ else ++ r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); + assert_se(r > 0); + } + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index 0d2741cd43..995b981d25 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -31,19 +31,20 @@ static void test_parse_cpu_set(void) { + cpu_set_reset(&c); + + /* Simple range (from CPUAffinity example) */ +- assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); + assert_se(c.allocated >= sizeof(__cpu_mask) / 8); + assert_se(CPU_ISSET_S(1, c.allocated, c.set)); + assert_se(CPU_ISSET_S(2, c.allocated, c.set)); +- assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); ++ assert_se(CPU_ISSET_S(4, c.allocated, c.set)); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); + + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); +- assert_se(streq(str, "1-2")); ++ assert_se(streq(str, "1-2 4")); + str = mfree(str); + cpu_set_reset(&c); + diff --git a/SOURCES/0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch b/SOURCES/0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch new file mode 100644 index 0000000..050478a --- /dev/null +++ b/SOURCES/0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch @@ -0,0 +1,36 @@ +From b90f935f8d2268522480a7c12f7e2213a7a5e19d Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 31 May 2019 18:02:20 +0200 +Subject: [PATCH] execute: dump CPUAffinity as a range string instead of a list + of CPUs + +We do this already when printing the property in systemctl so be +consistent and do the same for systemd-analyze dump. + +(cherry picked from commit e7fca352ba43988682a927de6b1f629b3f10a415) + +Related: #1734787 +--- + src/core/execute.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 22e5825905..bc26aa66e7 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -4098,11 +4098,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + } + + if (c->cpu_set.set) { +- fprintf(f, "%sCPUAffinity:", prefix); +- for (i = 0; i < c->cpu_set.allocated * 8; i++) +- if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set)) +- fprintf(f, " %u", i); +- fputs("\n", f); ++ _cleanup_free_ char *affinity = NULL; ++ ++ affinity = cpu_set_to_range_string(&c->cpu_set); ++ fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity); + } + + if (c->timer_slack_nsec != NSEC_INFINITY) diff --git a/SOURCES/0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch b/SOURCES/0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch new file mode 100644 index 0000000..0b2bec0 --- /dev/null +++ b/SOURCES/0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch @@ -0,0 +1,95 @@ +From 35894625624f0e8c7d3ca2c200861005c7ad4435 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 3 Jun 2019 10:12:35 +0200 +Subject: [PATCH] cpu-set-util: use %d-%d format in cpu_set_to_range_string() + only for actual ranges + +(cherry picked from commit 71923237b18df35401626993d8a285cd998be78d) + +Related: #1734787 +--- + src/basic/cpu-set-util.c | 4 ++-- + src/test/test-cpu-set-util.c | 16 +++++++++------- + 2 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index 5024290557..103b9703b3 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -58,7 +58,7 @@ char *cpu_set_to_range_string(const CPUSet *set) { + if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned))) + return NULL; + +- if (range_end > range_start || len == 0) ++ if (range_end > range_start) + r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); + else + r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); +@@ -70,7 +70,7 @@ char *cpu_set_to_range_string(const CPUSet *set) { + if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int))) + return NULL; + +- if (range_end > range_start || len == 0) ++ if (range_end > range_start) + r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); + else + r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index 995b981d25..9522582891 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -26,7 +26,7 @@ static void test_parse_cpu_set(void) { + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); +- assert_se(streq(str, "0-0")); ++ assert_se(streq(str, "0")); + str = mfree(str); + cpu_set_reset(&c); + +@@ -95,17 +95,19 @@ static void test_parse_cpu_set(void) { + cpu_set_reset(&c); + + /* Commas with spaces (and trailing comma, space) */ +- assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= sizeof(__cpu_mask) / 8); +- assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); ++ assert_se(CPU_COUNT_S(c.allocated, c.set) == 9); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); ++ ++ assert_se(CPU_ISSET_S(63, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); +- assert_se(streq(str, "0-7")); ++ assert_se(streq(str, "0-7 63")); + str = mfree(str); + cpu_set_reset(&c); + +@@ -161,11 +163,11 @@ static void test_parse_cpu_set(void) { + cpu_set_reset(&c); + + /* Mix ranges and individual CPUs */ +- assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); ++ assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= sizeof(__cpu_mask) / 8); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 10); + assert_se(CPU_ISSET_S(0, c.allocated, c.set)); +- assert_se(CPU_ISSET_S(1, c.allocated, c.set)); ++ assert_se(CPU_ISSET_S(2, c.allocated, c.set)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); +@@ -173,7 +175,7 @@ static void test_parse_cpu_set(void) { + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); +- assert_se(streq(str, "0-1 4-11")); ++ assert_se(streq(str, "0 2 4-11")); + str = mfree(str); + cpu_set_reset(&c); + diff --git a/SOURCES/0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch b/SOURCES/0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch new file mode 100644 index 0000000..bcfd3a3 --- /dev/null +++ b/SOURCES/0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch @@ -0,0 +1,779 @@ +From a735699a8287c19e043b7d2fe9a387a3938e1e2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Mon, 18 Nov 2019 12:50:11 +0100 +Subject: [PATCH] core: introduce NUMAPolicy and NUMAMask options + +Make possible to set NUMA allocation policy for manager. Manager's +policy is by default inherited to all forked off processes. However, it +is possible to override the policy on per-service basis. Currently we +support, these policies: default, prefer, bind, interleave, local. +See man 2 set_mempolicy for details on each policy. + +Overall NUMA policy actually consists of two parts. Policy itself and +bitmask representing NUMA nodes where is policy effective. Node mask can +be specified using related option, NUMAMask. Default mask can be +overwritten on per-service level. + +(cherry-picked from commit fe9c54b2188e6cd23262a319f96b13215f2c5e9c) + +Resolves: #1734787 +--- + man/systemd-system.conf.xml | 19 ++++++ + man/systemd.exec.xml | 28 +++++++++ + meson.build | 4 ++ + src/basic/cpu-set-util.c | 91 +++++++++++++++++++++++++++ + src/basic/cpu-set-util.h | 28 +++++++++ + src/basic/exit-status.c | 3 + + src/basic/exit-status.h | 1 + + src/basic/missing_syscall.h | 43 +++++++++++++ + src/core/dbus-execute.c | 65 ++++++++++++++++++- + src/core/execute.c | 20 ++++++ + src/core/execute.h | 1 + + src/core/load-fragment-gperf.gperf.m4 | 2 + + src/core/load-fragment.c | 28 +++++++++ + src/core/load-fragment.h | 2 + + src/core/main.c | 27 ++++++++ + src/core/system.conf.in | 2 + + src/shared/bus-unit-util.c | 28 +++++++++ + src/systemctl/systemctl.c | 18 +++++- + 18 files changed, 405 insertions(+), 5 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index ab23779ec0..988c4e7665 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -132,6 +132,25 @@ + anymore. + + ++ ++ NUMAPolicy= ++ ++ Configures the NUMA memory policy for the service manager and the default NUMA memory policy ++ for all forked off processes. Individual services may override the default policy with the ++ NUMAPolicy= setting in unit files, see ++ systemd.exec5. ++ ++ ++ ++ NUMAMask= ++ ++ Configures the NUMA node mask that will be associated with the selected NUMA policy. Note that ++ and NUMA policies don't require explicit NUMA node mask and ++ value of the option can be empty. Similarly to NUMAPolicy=, value can be overriden ++ by individual services in unit files, see ++ systemd.exec5. ++ ++ + + RuntimeWatchdogSec= + ShutdownWatchdogSec= +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 342b8385bc..87fb8b34f4 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -710,6 +710,28 @@ CapabilityBoundingSet=~CAP_B CAP_C + details. + + ++ ++ NUMAPolicy= ++ ++ Controls the NUMA memory policy of the executed processes. Takes a policy type, one of: ++ , , , and ++ . A list of NUMA nodes that should be associated with the policy must be specified ++ in NUMAMask=. For more details on each policy please see, ++ set_mempolicy2. For overall ++ overview of NUMA support in Linux see, ++ numa7 ++ ++ ++ ++ ++ NUMAMask= ++ ++ Controls the NUMA node list which will be applied alongside with selected NUMA policy. ++ Takes a list of NUMA nodes and has the same syntax as a list of CPUs for CPUAffinity= ++ option. Note that the list of NUMA nodes is not required for and ++ policies and for policy we expect a single NUMA node. ++ ++ + + IOSchedulingClass= + +@@ -2709,6 +2731,12 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy + EXIT_CONFIGURATION_DIRECTORY + Failed to set up unit's configuration directory. See ConfigurationDirectory= above. + ++ ++ 242 ++ EXIT_NUMA_POLICY ++ Failed to set up unit's NUMA memory policy. See NUMAPolicy= and NUMAMask=above. ++ ++ + + + +diff --git a/meson.build b/meson.build +index 613a5133b6..fe82ca4ac2 100644 +--- a/meson.build ++++ b/meson.build +@@ -501,6 +501,10 @@ foreach ident : [ + #include '''], + ['explicit_bzero' , '''#include '''], + ['reallocarray', '''#include '''], ++ ['set_mempolicy', '''#include ++ #include '''], ++ ['get_mempolicy', '''#include ++ #include '''], + ] + + have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE') +diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c +index 103b9703b3..36cb017ae7 100644 +--- a/src/basic/cpu-set-util.c ++++ b/src/basic/cpu-set-util.c +@@ -10,11 +10,17 @@ + + #include "alloc-util.h" + #include "cpu-set-util.h" ++#include "dirent-util.h" + #include "extract-word.h" ++#include "fd-util.h" + #include "log.h" + #include "macro.h" ++#include "missing.h" + #include "parse-util.h" ++#include "stat-util.h" + #include "string-util.h" ++#include "string-table.h" ++#include "strv.h" + #include "util.h" + + char* cpu_set_to_string(const CPUSet *a) { +@@ -290,3 +296,88 @@ int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) { + s = (CPUSet) {}; + return 0; + } ++ ++bool numa_policy_is_valid(const NUMAPolicy *policy) { ++ assert(policy); ++ ++ if (!mpol_is_valid(numa_policy_get_type(policy))) ++ return false; ++ ++ if (!policy->nodes.set && ++ !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED)) ++ return false; ++ ++ if (policy->nodes.set && ++ numa_policy_get_type(policy) == MPOL_PREFERRED && ++ CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1) ++ return false; ++ ++ return true; ++} ++ ++static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) { ++ unsigned node, bits = 0, ulong_bits; ++ _cleanup_free_ unsigned long *out = NULL; ++ ++ assert(policy); ++ assert(ret_maxnode); ++ assert(ret_nodes); ++ ++ if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) || ++ (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) { ++ *ret_nodes = NULL; ++ *ret_maxnode = 0; ++ return 0; ++ } ++ ++ bits = policy->nodes.allocated * 8; ++ ulong_bits = sizeof(unsigned long) * 8; ++ ++ out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long))); ++ if (!out) ++ return -ENOMEM; ++ ++ /* We don't make any assumptions about internal type libc is using to store NUMA node mask. ++ Hence we need to convert the node mask to the representation expected by set_mempolicy() */ ++ for (node = 0; node < bits; node++) ++ if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set)) ++ out[node / ulong_bits] |= 1ul << (node % ulong_bits); ++ ++ *ret_nodes = TAKE_PTR(out); ++ *ret_maxnode = bits + 1; ++ return 0; ++} ++ ++int apply_numa_policy(const NUMAPolicy *policy) { ++ int r; ++ _cleanup_free_ unsigned long *nodes = NULL; ++ unsigned long maxnode; ++ ++ assert(policy); ++ ++ if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS) ++ return -EOPNOTSUPP; ++ ++ if (!numa_policy_is_valid(policy)) ++ return -EINVAL; ++ ++ r = numa_policy_to_mempolicy(policy, &maxnode, &nodes); ++ if (r < 0) ++ return r; ++ ++ r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode); ++ if (r < 0) ++ return -errno; ++ ++ return 0; ++} ++ ++static const char* const mpol_table[] = { ++ [MPOL_DEFAULT] = "default", ++ [MPOL_PREFERRED] = "preferred", ++ [MPOL_BIND] = "bind", ++ [MPOL_INTERLEAVE] = "interleave", ++ [MPOL_LOCAL] = "local", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(mpol, int); +diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h +index ec640b2ec9..295028cb54 100644 +--- a/src/basic/cpu-set-util.h ++++ b/src/basic/cpu-set-util.h +@@ -8,6 +8,7 @@ + #include + + #include "macro.h" ++#include "missing.h" + + /* This wraps the libc interface with a variable to keep the allocated size. */ + typedef struct CPUSet { +@@ -52,3 +53,30 @@ int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated); + int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set); + + int cpus_in_affinity_mask(void); ++ ++static inline bool mpol_is_valid(int t) { ++ return t >= MPOL_DEFAULT && t <= MPOL_LOCAL; ++} ++ ++typedef struct NUMAPolicy { ++ /* Always use numa_policy_get_type() to read the value */ ++ int type; ++ CPUSet nodes; ++} NUMAPolicy; ++ ++bool numa_policy_is_valid(const NUMAPolicy *p); ++ ++static inline int numa_policy_get_type(const NUMAPolicy *p) { ++ return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type; ++} ++ ++static inline void numa_policy_reset(NUMAPolicy *p) { ++ assert(p); ++ cpu_set_reset(&p->nodes); ++ p->type = -1; ++} ++ ++int apply_numa_policy(const NUMAPolicy *policy); ++ ++const char* mpol_to_string(int i) _const_; ++int mpol_from_string(const char *s) _pure_; +diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c +index 21af8c4c71..0a7a53b73d 100644 +--- a/src/basic/exit-status.c ++++ b/src/basic/exit-status.c +@@ -155,6 +155,9 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { + + case EXIT_CONFIGURATION_DIRECTORY: + return "CONFIGURATION_DIRECTORY"; ++ ++ case EXIT_NUMA_POLICY: ++ return "NUMA_POLICY"; + } + } + +diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h +index c41e8b82c3..dc284aacb1 100644 +--- a/src/basic/exit-status.h ++++ b/src/basic/exit-status.h +@@ -69,6 +69,7 @@ enum { + EXIT_CACHE_DIRECTORY, + EXIT_LOGS_DIRECTORY, /* 240 */ + EXIT_CONFIGURATION_DIRECTORY, ++ EXIT_NUMA_POLICY, + }; + + typedef enum ExitStatusLevel { +diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h +index 93c60458bf..014dd2b326 100644 +--- a/src/basic/missing_syscall.h ++++ b/src/basic/missing_syscall.h +@@ -428,3 +428,46 @@ static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flag + + # define statx missing_statx + #endif ++ ++#if !HAVE_SET_MEMPOLICY ++ ++enum { ++ MPOL_DEFAULT, ++ MPOL_PREFERRED, ++ MPOL_BIND, ++ MPOL_INTERLEAVE, ++ MPOL_LOCAL, ++}; ++ ++static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask, ++ unsigned long maxnode) { ++ long i; ++# ifdef __NR_set_mempolicy ++ i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode); ++# else ++ errno = ENOSYS; ++ i = -1; ++# endif ++ return i; ++} ++ ++# define set_mempolicy missing_set_mempolicy ++#endif ++ ++ ++#if !HAVE_GET_MEMPOLICY ++static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, ++ unsigned long maxnode, void *addr, ++ unsigned long flags) { ++ long i; ++# ifdef __NR_get_mempolicy ++ i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags); ++# else ++ errno = ENOSYS; ++ i = -1; ++# endif ++ return i; ++} ++ ++#define get_mempolicy missing_get_mempolicy ++#endif +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index 50ea71a281..198f149210 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -223,6 +223,48 @@ static int property_get_cpu_affinity( + return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated); + } + ++static int property_get_numa_mask( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ ExecContext *c = userdata; ++ _cleanup_free_ uint8_t *array = NULL; ++ size_t allocated; ++ ++ assert(bus); ++ assert(reply); ++ assert(c); ++ ++ (void) cpu_set_to_dbus(&c->numa_policy.nodes, &array, &allocated); ++ ++ return sd_bus_message_append_array(reply, 'y', array, allocated); ++} ++ ++static int property_get_numa_policy( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ExecContext *c = userdata; ++ int32_t policy; ++ ++ assert(bus); ++ assert(reply); ++ assert(c); ++ ++ policy = numa_policy_get_type(&c->numa_policy); ++ ++ return sd_bus_message_append_basic(reply, 'i', &policy); ++} ++ + static int property_get_timer_slack_nsec( + sd_bus *bus, + const char *path, +@@ -698,6 +740,8 @@ const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST), +@@ -1550,9 +1594,10 @@ int bus_exec_context_set_transient_property( + return 1; + } + #endif +- if (streq(name, "CPUAffinity")) { ++ if (STR_IN_SET(name, "CPUAffinity", "NUMAMask")) { + const void *a; + size_t n; ++ bool affinity = streq(name, "CPUAffinity"); + _cleanup_(cpu_set_reset) CPUSet set = {}; + + r = sd_bus_message_read_array(message, 'y', &a, &n); +@@ -1565,7 +1610,7 @@ int bus_exec_context_set_transient_property( + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (n == 0) { +- cpu_set_reset(&c->cpu_set); ++ cpu_set_reset(affinity ? &c->cpu_set : &c->numa_policy.nodes); + unit_write_settingf(u, flags, name, "%s=", name); + } else { + _cleanup_free_ char *str = NULL; +@@ -1577,7 +1622,7 @@ int bus_exec_context_set_transient_property( + /* We forego any optimizations here, and always create the structure using + * cpu_set_add_all(), because we don't want to care if the existing size we + * got over dbus is appropriate. */ +- r = cpu_set_add_all(&c->cpu_set, &set); ++ r = cpu_set_add_all(affinity ? &c->cpu_set : &c->numa_policy.nodes, &set); + if (r < 0) + return r; + +@@ -1587,6 +1632,20 @@ int bus_exec_context_set_transient_property( + + return 1; + ++ } else if (streq(name, "NUMAPolicy")) { ++ int32_t type; ++ ++ r = sd_bus_message_read(message, "i", &type); ++ if (r < 0) ++ return r; ++ ++ if (!mpol_is_valid(type)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NUMAPolicy value: %i", type); ++ ++ if (!UNIT_WRITE_FLAGS_NOOP(flags)) ++ c->numa_policy.type = type; ++ ++ return 1; + } else if (streq(name, "IOSchedulingClass")) { + int32_t q; + +diff --git a/src/core/execute.c b/src/core/execute.c +index bc26aa66e7..56aa89e1ec 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2997,6 +2997,16 @@ static int exec_child( + return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m"); + } + ++ if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) { ++ r = apply_numa_policy(&context->numa_policy); ++ if (r == -EOPNOTSUPP) ++ log_unit_debug_errno(unit, r, "NUMA support not available, ignoring."); ++ else if (r < 0) { ++ *exit_status = EXIT_NUMA_POLICY; ++ return log_unit_error_errno(unit, r, "Failed to set NUMA memory policy: %m"); ++ } ++ } ++ + if (context->ioprio_set) + if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { + *exit_status = EXIT_IOPRIO; +@@ -3651,6 +3661,7 @@ void exec_context_init(ExecContext *c) { + assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL); + c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL; + c->log_level_max = -1; ++ numa_policy_reset(&c->numa_policy); + } + + void exec_context_done(ExecContext *c) { +@@ -3695,6 +3706,7 @@ void exec_context_done(ExecContext *c) { + c->n_temporary_filesystems = 0; + + cpu_set_reset(&c->cpu_set); ++ numa_policy_reset(&c->numa_policy); + + c->utmp_id = mfree(c->utmp_id); + c->selinux_context = mfree(c->selinux_context); +@@ -4104,6 +4116,14 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity); + } + ++ if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) { ++ _cleanup_free_ char *nodes = NULL; ++ ++ nodes = cpu_set_to_range_string(&c->numa_policy.nodes); ++ fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy))); ++ fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes)); ++ } ++ + if (c->timer_slack_nsec != NSEC_INFINITY) + fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec); + +diff --git a/src/core/execute.h b/src/core/execute.h +index e1e7a494cd..b2eb55f8f5 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -150,6 +150,7 @@ struct ExecContext { + int cpu_sched_priority; + + CPUSet cpu_set; ++ NUMAPolicy numa_policy; + + ExecInput std_input; + ExecOutput std_output; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 1066bcfb8f..cdf4d14c4e 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -36,6 +36,8 @@ $1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, + $1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context) + $1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork) + $1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context) ++$1.NUMAPolicy, config_parse_numa_policy, 0, offsetof($1, exec_context.numa_policy.type) ++$1.NUMAMask, config_parse_numa_mask, 0, offsetof($1, exec_context.numa_policy) + $1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) + $1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment) + $1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 34ae834188..35dd595098 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -93,6 +93,7 @@ DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint + DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight"); + DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares"); + DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag"); ++DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type"); + + int config_parse_unit_deps( + const char *unit, +@@ -1159,6 +1160,33 @@ int config_parse_exec_cpu_sched_policy(const char *unit, + return 0; + } + ++int config_parse_numa_mask(const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ int r; ++ NUMAPolicy *p = data; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ return r; ++} ++ + int config_parse_exec_cpu_sched_prio(const char *unit, + const char *filename, + unsigned line, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index dad281ef72..f2ca1b8ee7 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -102,6 +102,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec); + CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec); + CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields); + CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode); ++CONFIG_PARSER_PROTOTYPE(config_parse_numa_policy); ++CONFIG_PARSER_PROTOTYPE(config_parse_numa_mask); + + /* gperf prototypes */ + const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length); +diff --git a/src/core/main.c b/src/core/main.c +index c74dc641c1..83f9dd5878 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -134,6 +134,7 @@ static uint64_t arg_default_tasks_max; + static sd_id128_t arg_machine_id; + static EmergencyAction arg_cad_burst_action; + static CPUSet arg_cpu_affinity; ++static NUMAPolicy arg_numa_policy; + + static int parse_configuration(void); + +@@ -660,6 +661,8 @@ static int parse_config_file(void) { + { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, + { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity }, + { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, ++ { "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type }, ++ { "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy }, + { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, + { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog }, + { "Manager", "WatchdogDevice", config_parse_path, 0, &arg_watchdog_device }, +@@ -1501,6 +1504,27 @@ static void update_cpu_affinity(bool skip_setup) { + log_warning_errno(errno, "Failed to set CPU affinity: %m"); + } + ++static void update_numa_policy(bool skip_setup) { ++ int r; ++ _cleanup_free_ char *nodes = NULL; ++ const char * policy = NULL; ++ ++ if (skip_setup || !mpol_is_valid(numa_policy_get_type(&arg_numa_policy))) ++ return; ++ ++ if (DEBUG_LOGGING) { ++ policy = mpol_to_string(numa_policy_get_type(&arg_numa_policy)); ++ nodes = cpu_set_to_range_string(&arg_numa_policy.nodes); ++ log_debug("Setting NUMA policy to %s, with nodes %s.", strnull(policy), strnull(nodes)); ++ } ++ ++ r = apply_numa_policy(&arg_numa_policy); ++ if (r == -EOPNOTSUPP) ++ log_debug_errno(r, "NUMA support not available, ignoring."); ++ else if (r < 0) ++ log_warning_errno(r, "Failed to set NUMA memory policy: %m"); ++} ++ + static void do_reexecute( + int argc, + char *argv[], +@@ -1672,6 +1696,7 @@ static int invoke_main_loop( + set_manager_defaults(m); + + update_cpu_affinity(false); ++ update_numa_policy(false); + + if (saved_log_level >= 0) + manager_override_log_level(m, saved_log_level); +@@ -1832,6 +1857,7 @@ static int initialize_runtime( + return 0; + + update_cpu_affinity(skip_setup); ++ update_numa_policy(skip_setup); + + if (arg_system) { + /* Make sure we leave a core dump without panicing the kernel. */ +@@ -2011,6 +2037,7 @@ static void reset_arguments(void) { + arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; + + cpu_set_reset(&arg_cpu_affinity); ++ numa_policy_reset(&arg_numa_policy); + } + + static int parse_configuration(void) { +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 653ec6b8c9..0d93fbf147 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -24,6 +24,8 @@ + #CtrlAltDelBurstAction=reboot-force + #CPUAffinity=1 2 + #JoinControllers=cpu,cpuacct net_cls,net_prio ++#NUMAPolicy=default ++#NUMAMask= + #RuntimeWatchdogSec=0 + #ShutdownWatchdogSec=10min + #CapabilityBoundingSet= +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index ec8732c226..055edd6e22 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -947,6 +947,34 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + return bus_append_byte_array(m, field, array, allocated); + } + ++ if (streq(field, "NUMAPolicy")) { ++ r = mpol_from_string(eq); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse %s value: %s", field, eq); ++ ++ r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r); ++ if (r < 0) ++ return bus_log_create_error(r); ++ ++ return 1; ++ } ++ ++ if (streq(field, "NUMAMask")) { ++ _cleanup_(cpu_set_reset) CPUSet nodes = {}; ++ _cleanup_free_ uint8_t *array = NULL; ++ size_t allocated; ++ ++ r = parse_cpu_set(eq, &nodes); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse %s value: %s", field, eq); ++ ++ r = cpu_set_to_dbus(&nodes, &array, &allocated); ++ if (r < 0) ++ return log_error_errno(r, "Failed to serialize NUMAMask: %m"); ++ ++ return bus_append_byte_array(m, field, array, allocated); ++ } ++ + if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) { + int whitelist = 1; + const char *p = eq; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 0154b300a3..7274921e6d 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4573,6 +4573,20 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool + + switch (bus_type) { + ++ case SD_BUS_TYPE_INT32: ++ if (streq(name, "NUMAPolicy")) { ++ int32_t i; ++ ++ r = sd_bus_message_read_basic(m, bus_type, &i); ++ if (r < 0) ++ return r; ++ ++ print_prop(name, "%s", strna(mpol_to_string(i))); ++ ++ return 1; ++ } ++ break; ++ + case SD_BUS_TYPE_STRUCT: + + if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) { +@@ -4878,7 +4892,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool + print_prop(name, "%s", h); + + return 1; +- } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "CPUAffinity")) { ++ } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask")) { + _cleanup_free_ char *affinity = NULL; + _cleanup_(cpu_set_reset) CPUSet set = {}; + const void *a; +@@ -4890,7 +4904,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool + + r = cpu_set_from_dbus(a, n, &set); + if (r < 0) +- return log_error_errno(r, "Failed to deserialize CPUAffinity: %m"); ++ return log_error_errno(r, "Failed to deserialize %s: %m", name); + + affinity = cpu_set_to_range_string(&set); + if (!affinity) diff --git a/SOURCES/0289-core-disable-CPUAccounting-by-default.patch b/SOURCES/0289-core-disable-CPUAccounting-by-default.patch new file mode 100644 index 0000000..d250c03 --- /dev/null +++ b/SOURCES/0289-core-disable-CPUAccounting-by-default.patch @@ -0,0 +1,25 @@ +From b47f26558e5234ec8cf2ecc3674c94a87f20ec69 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Thu, 28 Nov 2019 15:47:43 +0100 +Subject: [PATCH] core: disable CPUAccounting by default + +Related: #1734787 + +[RHEL-only] +--- + src/core/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 83f9dd5878..c83249a8dc 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2026,7 +2026,7 @@ static void reset_arguments(void) { + + /* arg_serialization — ignore */ + +- arg_default_cpu_accounting = -1; ++ arg_default_cpu_accounting = 0; + arg_default_io_accounting = false; + arg_default_ip_accounting = false; + arg_default_blockio_accounting = false; diff --git a/SOURCES/0290-set-kptr_restrict-1.patch b/SOURCES/0290-set-kptr_restrict-1.patch new file mode 100644 index 0000000..5005756 --- /dev/null +++ b/SOURCES/0290-set-kptr_restrict-1.patch @@ -0,0 +1,24 @@ +From cf1a9df1171273fc1ed3f977b5ec52aba27674bf Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Tue, 3 Dec 2019 14:04:00 +0100 +Subject: [PATCH] set kptr_restrict=1 + +Resolves: #1689346 +--- + sysctl.d/50-default.conf | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf +index e263cf0628..e0afc9c702 100644 +--- a/sysctl.d/50-default.conf ++++ b/sysctl.d/50-default.conf +@@ -21,6 +21,9 @@ kernel.sysrq = 16 + # Append the PID to the core filename + kernel.core_uses_pid = 1 + ++# https://bugzilla.redhat.com/show_bug.cgi?id=1689346 ++kernel.kptr_restrict = 1 ++ + # Source route verification + net.ipv4.conf.all.rp_filter = 1 + diff --git a/SOURCES/0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch b/SOURCES/0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch new file mode 100644 index 0000000..48f41cf --- /dev/null +++ b/SOURCES/0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch @@ -0,0 +1,34 @@ +From 40612e4e7690c613cba7ac87b9d782724e623a39 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Wed, 27 Nov 2019 14:27:58 +0100 +Subject: [PATCH] cryptsetup: reduce the chance that we will be OOM killed + +cryptsetup introduced optional locking scheme that should serialize +unlocking keyslots which use memory hard key derivation +function (argon2). Using the serialization should prevent OOM situation +in early boot while unlocking encrypted volumes. + +(cherry picked from commit 408c81f62454684dfbff1c95ce3210d06f256e58) + +Resolves: #1696602 +--- + src/cryptsetup/cryptsetup.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index 4e1b3eff19..9071126c2e 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -656,6 +656,12 @@ int main(int argc, char *argv[]) { + if (arg_discards) + flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + ++#ifdef CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF ++ /* Try to decrease the risk of OOM event if memory hard key derivation function is in use */ ++ /* https://gitlab.com/cryptsetup/cryptsetup/issues/446/ */ ++ flags |= CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF; ++#endif ++ + if (arg_timeout == USEC_INFINITY) + until = 0; + else diff --git a/SOURCES/0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch b/SOURCES/0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch new file mode 100644 index 0000000..4bfb5ef --- /dev/null +++ b/SOURCES/0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch @@ -0,0 +1,136 @@ +From cb084637ba1c8558f1538ce300c5520a6764dc76 Mon Sep 17 00:00:00 2001 +From: HATAYAMA Daisuke +Date: Mon, 28 Oct 2019 19:35:24 +0900 +Subject: [PATCH] core, job: fix breakage of ordering dependencies by systemctl + reload command + +Currently, systemctl reload command breaks ordering dependencies if it's +executed when its target service unit is in activating state. + +For example, prepare A.service, B.service and C.target as follows: + + # systemctl cat A.service B.service C.target + # /etc/systemd/system/A.service + [Unit] + Description=A + + [Service] + Type=oneshot + ExecStart=/usr/bin/echo A1 + ExecStart=/usr/bin/sleep 60 + ExecStart=/usr/bin/echo A2 + ExecReload=/usr/bin/echo A reloaded + RemainAfterExit=yes + + # /etc/systemd/system/B.service + [Unit] + Description=B + After=A.service + + [Service] + Type=oneshot + ExecStart=/usr/bin/echo B + RemainAfterExit=yes + + # /etc/systemd/system/C.target + [Unit] + Description=C + Wants=A.service B.service + +Start them. + + # systemctl daemon-reload + # systemctl start C.target + +Then, we have: + + # LANG=C journalctl --no-pager -u A.service -u B.service -u C.target -b + -- Logs begin at Mon 2019-09-09 00:25:06 EDT, end at Thu 2019-10-24 22:28:47 EDT. -- + Oct 24 22:27:47 localhost.localdomain systemd[1]: Starting A... + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Child 967 belongs to A.service. + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Running next main command for state start. + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Passing 0 fds to service + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: About to execute: /usr/bin/sleep 60 + Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Forked /usr/bin/sleep as 968 + Oct 24 22:27:47 localhost.localdomain systemd[968]: A.service: Executing: /usr/bin/sleep 60 + Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Trying to enqueue job A.service/reload/replace + Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Merged into running job, re-running: A.service/reload as 1288 + Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Enqueued job A.service/reload as 1288 + Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Unit cannot be reloaded because it is inactive. + Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Job 1288 A.service/reload finished, result=invalid + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Passing 0 fds to service + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: About to execute: /usr/bin/echo B + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Forked /usr/bin/echo as 970 + Oct 24 22:27:52 localhost.localdomain systemd[970]: B.service: Executing: /usr/bin/echo B + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Failed to send unit change signal for B.service: Connection reset by peer + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Changed dead -> start + Oct 24 22:27:52 localhost.localdomain systemd[1]: Starting B... + Oct 24 22:27:52 localhost.localdomain echo[970]: B + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Child 970 belongs to B.service. + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Main process exited, code=exited, status=0/SUCCESS + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Changed start -> exited + Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Job 1371 B.service/start finished, result=done + Oct 24 22:27:52 localhost.localdomain systemd[1]: Started B. + Oct 24 22:27:52 localhost.localdomain systemd[1]: C.target: Job 1287 C.target/start finished, result=done + Oct 24 22:27:52 localhost.localdomain systemd[1]: Reached target C. + Oct 24 22:27:52 localhost.localdomain systemd[1]: C.target: Failed to send unit change signal for C.target: Connection reset by peer + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Child 968 belongs to A.service. + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Running next main command for state start. + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Passing 0 fds to service + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: About to execute: /usr/bin/echo A2 + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Forked /usr/bin/echo as 972 + Oct 24 22:28:47 localhost.localdomain systemd[972]: A.service: Executing: /usr/bin/echo A2 + Oct 24 22:28:47 localhost.localdomain echo[972]: A2 + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Child 972 belongs to A.service. + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS + Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Changed start -> exited + +The issue occurs not only in reload command, i.e.: + + - reload + - try-restart + - reload-or-restart + - reload-or-try-restart commands + +The cause of this issue is that job_type_collapse() doesn't take care of the +activating state. + +Fixes: #10464 +(cherry picked from commit d1559793df555212271e490a4a72f55826caf5b4) + +Resolves: #1766417 +--- + src/core/job.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 8552ffb704..769ed6d603 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -403,21 +403,21 @@ JobType job_type_collapse(JobType t, Unit *u) { + + case JOB_TRY_RESTART: + s = unit_active_state(u); +- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) ++ if (!UNIT_IS_ACTIVE_OR_RELOADING(s)) + return JOB_NOP; + + return JOB_RESTART; + + case JOB_TRY_RELOAD: + s = unit_active_state(u); +- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) ++ if (!UNIT_IS_ACTIVE_OR_RELOADING(s)) + return JOB_NOP; + + return JOB_RELOAD; + + case JOB_RELOAD_OR_START: + s = unit_active_state(u); +- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) ++ if (!UNIT_IS_ACTIVE_OR_RELOADING(s)) + return JOB_START; + + return JOB_RELOAD; diff --git a/SOURCES/0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch b/SOURCES/0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch new file mode 100644 index 0000000..fb40563 --- /dev/null +++ b/SOURCES/0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch @@ -0,0 +1,149 @@ +From 613a02b7d67864af1860e9137e2ee101d603463e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 25 Apr 2019 12:19:16 +0200 +Subject: [PATCH] debug-generator: enable custom systemd.debug_shell tty + +(cherry picked from commit 93912e872fb14e9c372e090409e429084a6450f5) + +Resolves: #1723722 +--- + man/custom-entities.ent.in | 1 + + man/systemd-debug-generator.xml | 13 ++++++--- + meson.build | 1 + + src/debug-generator/debug-generator.c | 41 +++++++++++++++++++++------ + 4 files changed, 43 insertions(+), 13 deletions(-) + +diff --git a/man/custom-entities.ent.in b/man/custom-entities.ent.in +index e2bd44e5e7..85805777a0 100644 +--- a/man/custom-entities.ent.in ++++ b/man/custom-entities.ent.in +@@ -8,3 +8,4 @@ + + + ++ +diff --git a/man/systemd-debug-generator.xml b/man/systemd-debug-generator.xml +index fa88e8ac01..25d8b1a873 100644 +--- a/man/systemd-debug-generator.xml ++++ b/man/systemd-debug-generator.xml +@@ -1,6 +1,10 @@ + + +- ++ ++%entities; ++]> + +@@ -57,9 +61,10 @@ + option is + specified, the debug shell service + debug-shell.service is pulled into the boot +- transaction. It will spawn a debug shell on tty9 during early +- system startup. Note that the shell may also be turned on +- persistently by enabling it with ++ transaction and a debug shell will be spawned during early boot. ++ By default, &DEBUGTTY; is used, but a specific tty can also be set, ++ either with or without the /dev/ prefix. ++ Note that the shell may also be turned on persistently by enabling it with + systemctl1's + enable command. + is honored only by initial +diff --git a/meson.build b/meson.build +index fe82ca4ac2..70811c29cf 100644 +--- a/meson.build ++++ b/meson.build +@@ -768,6 +768,7 @@ conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) + + substs.set('SUSHELL', get_option('debug-shell')) + substs.set('DEBUGTTY', get_option('debug-tty')) ++conf.set_quoted('DEBUGTTY', get_option('debug-tty')) + + enable_debug_hashmap = false + enable_debug_mmap_cache = false +diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c +index 800d31cebe..ddef385833 100644 +--- a/src/debug-generator/debug-generator.c ++++ b/src/debug-generator/debug-generator.c +@@ -1,8 +1,11 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "alloc-util.h" ++#include "dropin.h" ++#include "generator.h" + #include "mkdir.h" + #include "parse-util.h" ++#include "path-util.h" + #include "proc-cmdline.h" + #include "special.h" + #include "string-util.h" +@@ -14,7 +17,7 @@ static char *arg_default_unit = NULL; + static const char *arg_dest = "/tmp"; + static char **arg_mask = NULL; + static char **arg_wants = NULL; +-static bool arg_debug_shell = false; ++static char *arg_debug_shell = NULL; + + static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { + int r; +@@ -50,15 +53,16 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat + return log_oom(); + + } else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) { ++ const char *t = NULL; + +- if (value) { +- r = parse_boolean(value); +- if (r < 0) +- log_error("Failed to parse systemd.debug_shell= argument '%s', ignoring.", value); +- else +- arg_debug_shell = r; +- } else +- arg_debug_shell = true; ++ r = value ? parse_boolean(value) : 1; ++ if (r < 0) ++ t = skip_dev_prefix(value); ++ else if (r > 0) ++ t = skip_dev_prefix(DEBUGTTY); ++ ++ if (free_and_strdup(&arg_debug_shell, t) < 0) ++ return log_oom(); + + } else if (streq(key, "systemd.unit")) { + +@@ -136,6 +140,23 @@ static int generate_wants_symlinks(void) { + return r; + } + ++static void install_debug_shell_dropin(const char *dir) { ++ int r; ++ ++ if (streq(arg_debug_shell, skip_dev_prefix(DEBUGTTY))) ++ return; ++ ++ r = write_drop_in_format(dir, "debug-shell.service", 50, "tty", ++ "[Unit]\n" ++ "Description=Early root shell on /dev/%s FOR DEBUGGING ONLY\n" ++ "ConditionPathExists=\n" ++ "[Service]\n" ++ "TTYPath=/dev/%s", ++ arg_debug_shell, arg_debug_shell); ++ if (r < 0) ++ log_warning_errno(r, "Failed to write drop-in for debug-shell.service, ignoring: %m"); ++} ++ + int main(int argc, char *argv[]) { + int r, q; + +@@ -164,6 +185,8 @@ int main(int argc, char *argv[]) { + r = log_oom(); + goto finish; + } ++ ++ install_debug_shell_dropin(arg_dest); + } + + r = generate_mask_symlinks(); diff --git a/SOURCES/0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch b/SOURCES/0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch new file mode 100644 index 0000000..490a14f --- /dev/null +++ b/SOURCES/0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch @@ -0,0 +1,118 @@ +From f4344bb4055cab8dc3bbe82a7f3d97fc6fabcb7e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 4 Jun 2019 09:19:04 +0200 +Subject: [PATCH] test-cpu-set-util: fix comparison for allocation size + +On i386, __cpu_mask is 4 bytes, so we'd check if c.allocated >= 0, and +gcc would warn about a bogus comparison. Let's round up. + +Fixes #12726. + +(cherry picked from commit a299ce058b41b21c87f36e77e2c563b0ddd1be0d) + +Related: #1734787 +--- + src/test/test-cpu-set-util.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index 9522582891..3456add989 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -17,7 +17,7 @@ static void test_parse_cpu_set(void) { + /* Single value */ + assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_ISSET_S(0, c.allocated, c.set)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 1); + +@@ -33,7 +33,7 @@ static void test_parse_cpu_set(void) { + /* Simple range (from CPUAffinity example) */ + assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_ISSET_S(1, c.allocated, c.set)); + assert_se(CPU_ISSET_S(2, c.allocated, c.set)); + assert_se(CPU_ISSET_S(4, c.allocated, c.set)); +@@ -50,7 +50,7 @@ static void test_parse_cpu_set(void) { + + /* A more interesting range */ + assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -68,7 +68,7 @@ static void test_parse_cpu_set(void) { + + /* Quoted strings */ + assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -83,7 +83,7 @@ static void test_parse_cpu_set(void) { + + /* Use commas as separators */ + assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -96,7 +96,7 @@ static void test_parse_cpu_set(void) { + + /* Commas with spaces (and trailing comma, space) */ + assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 9); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -113,7 +113,7 @@ static void test_parse_cpu_set(void) { + + /* Ranges */ + assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -126,7 +126,7 @@ static void test_parse_cpu_set(void) { + + /* Ranges with trailing comma, space */ + assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -143,13 +143,13 @@ static void test_parse_cpu_set(void) { + + /* Negative range (returns empty cpu_set) */ + assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 0); + cpu_set_reset(&c); + + /* Overlapping ranges */ + assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); +@@ -164,7 +164,7 @@ static void test_parse_cpu_set(void) { + + /* Mix ranges and individual CPUs */ + assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); +- assert_se(c.allocated >= sizeof(__cpu_mask) / 8); ++ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 10); + assert_se(CPU_ISSET_S(0, c.allocated, c.set)); + assert_se(CPU_ISSET_S(2, c.allocated, c.set)); diff --git a/SOURCES/0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch b/SOURCES/0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch new file mode 100644 index 0000000..cbb8483 --- /dev/null +++ b/SOURCES/0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch @@ -0,0 +1,30 @@ +From 3cf9361996b796eae0bda12aec8c92ddae1d5d48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 4 Jun 2019 09:40:38 +0200 +Subject: [PATCH] test-cpu-set-util: fix allocation size check on i386 + +We get just 28 bytes not 32 as on 64-bit architectures (__cpu_set_t is 4 bytes, +we need at least 26, so 28 satisfies the constraints). + +(cherry picked from commit 64412970ac0d4b6f5c4bbd8816edc9bff9eab2de) + +Related: #1734787 +--- + src/test/test-cpu-set-util.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c +index 3456add989..136eaca82d 100644 +--- a/src/test/test-cpu-set-util.c ++++ b/src/test/test-cpu-set-util.c +@@ -256,7 +256,9 @@ static void test_cpu_set_to_from_dbus(void) { + assert_se(array); + assert_se(allocated == c.allocated); + +- assert(memcmp(array, expected, sizeof expected) == 0); ++ assert_se(allocated <= sizeof expected); ++ assert_se(allocated >= DIV_ROUND_UP(201u, 8u)); /* We need at least 201 bits for our mask */ ++ assert(memcmp(array, expected, allocated) == 0); + + assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0); + assert_se(c2.set); diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 74a7533..e6a8d07 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 15%{?dist} +Release: 21%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -250,6 +250,101 @@ Patch0197: 0197-test-add-test-for-Type-exec.patch Patch0198: 0198-journal-gateway-explicitly-declare-local-variables.patch Patch0199: 0199-tools-drop-unused-variable.patch Patch0200: 0200-journal-gateway-use-localStorage-cursor-only-when-it.patch +Patch0201: 0201-sd-bus-deal-with-cookie-overruns.patch +Patch0202: 0202-journal-remote-do-not-request-Content-Length-if-Tran.patch +Patch0203: 0203-journal-do-not-remove-multiple-spaces-after-identifi.patch +Patch0204: 0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch +Patch0205: 0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch +Patch0206: 0206-cryptsetup-Add-LUKS2-token-support.patch +Patch0207: 0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch +Patch0208: 0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch +Patch0209: 0209-bash-completion-analyze-support-security.patch +Patch0210: 0210-man-note-that-journal-does-not-validate-syslog-field.patch +Patch0211: 0211-rules-skip-memory-hotplug-on-ppc64.patch +Patch0212: 0212-mount-simplify-proc-self-mountinfo-handler.patch +Patch0213: 0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch +Patch0214: 0214-swap-scan-proc-swaps-before-processing-waitid-result.patch +Patch0215: 0215-analyze-security-fix-potential-division-by-zero.patch +Patch0216: 0216-core-never-propagate-reload-failure-to-service-resul.patch +Patch0217: 0217-man-document-systemd-analyze-security.patch +Patch0218: 0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch +Patch0219: 0219-travis-move-to-CentOS-8-docker-images.patch +Patch0220: 0220-travis-drop-SCL-remains.patch +Patch0221: 0221-syslog-fix-segfault-in-syslog_parse_priority.patch +Patch0222: 0222-sd-bus-make-strict-asan-shut-up.patch +Patch0223: 0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch +Patch0224: 0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch +Patch0225: 0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch +Patch0226: 0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch +Patch0227: 0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch +Patch0228: 0228-udev-introduce-CONST-key-name.patch +Patch0229: 0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch +Patch0230: 0230-Consider-smb3-as-remote-filesystem.patch +Patch0231: 0231-process-util-introduce-pid_is_my_child-helper.patch +Patch0232: 0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch +Patch0233: 0233-core-only-watch-processes-when-it-s-really-necessary.patch +Patch0234: 0234-core-implement-per-unit-journal-rate-limiting.patch +Patch0235: 0235-path-stop-watching-path-specs-once-we-triggered-the-.patch +Patch0236: 0236-journald-fixed-assertion-failure-when-system-journal.patch +Patch0237: 0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch +Patch0238: 0238-test-mask-several-unnecessary-services.patch +Patch0239: 0239-test-bump-the-second-partition-s-size-to-50M.patch +Patch0240: 0240-shared-sleep-config-exclude-zram-devices-from-hibern.patch +Patch0241: 0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch +Patch0242: 0242-sd-device-introduce-log_device_-macros.patch +Patch0243: 0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch +Patch0244: 0244-shared-but-util-drop-trusted-annotation-from-bus_ope.patch +Patch0245: 0245-sd-bus-adjust-indentation-of-comments.patch +Patch0246: 0246-resolved-do-not-run-loop-twice.patch +Patch0247: 0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch +Patch0248: 0248-resolved-query-polkit-only-after-parsing-the-data.patch +Patch0249: 0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch +Patch0250: 0250-basic-user-util-allow-dots-in-user-names.patch +Patch0251: 0251-sd-bus-bump-message-queue-size-again.patch +Patch0252: 0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch +Patch0253: 0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch +Patch0254: 0254-basic-remove-an-assertion-from-cunescape_one.patch +Patch0255: 0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch +Patch0256: 0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch +Patch0257: 0257-tests-add-a-reproducer-for-a-heap-buffer-overflow-fi.patch +Patch0258: 0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch +Patch0259: 0259-tests-add-a-fuzzer-for-process_audit_string.patch +Patch0260: 0260-journald-check-whether-sscanf-has-changed-the-value-.patch +Patch0261: 0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch +Patch0262: 0262-tests-add-a-fuzzer-for-journald-streams.patch +Patch0263: 0263-tests-add-a-fuzzer-for-server_process_native_file.patch +Patch0264: 0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch +Patch0265: 0265-journald-take-leading-spaces-into-account-in-syslog_.patch +Patch0266: 0266-Add-a-warning-about-the-difference-in-permissions-be.patch +Patch0267: 0267-execute-remove-one-redundant-comparison-check.patch +Patch0268: 0268-core-change-ownership-mode-of-the-execution-director.patch +Patch0269: 0269-core-dbus-execute-remove-unnecessary-initialization.patch +Patch0270: 0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch +Patch0271: 0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch +Patch0272: 0272-Rework-cpu-affinity-parsing.patch +Patch0273: 0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch +Patch0274: 0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch +Patch0275: 0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch +Patch0276: 0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch +Patch0277: 0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch +Patch0278: 0278-pid1-when-reloading-configuration-forget-old-setting.patch +Patch0279: 0279-test-execute-use-CPUSet-too.patch +Patch0280: 0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch +Patch0281: 0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch +Patch0282: 0282-test-cpu-set-util-add-test-for-dbus-conversions.patch +Patch0283: 0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch +Patch0284: 0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch +Patch0285: 0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch +Patch0286: 0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch +Patch0287: 0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch +Patch0288: 0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch +Patch0289: 0289-core-disable-CPUAccounting-by-default.patch +Patch0290: 0290-set-kptr_restrict-1.patch +Patch0291: 0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch +Patch0292: 0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch +Patch0293: 0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch +Patch0294: 0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch +Patch0295: 0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch %ifarch %{ix86} x86_64 aarch64 @@ -869,6 +964,120 @@ fi %files tests -f .file-list-tests %changelog +* Mon Dec 09 2019 systemd maintenance team - 239-21 +- test-cpu-set-util: fix comparison for allocation size (#1734787) +- test-cpu-set-util: fix allocation size check on i386 (#1734787) + +* Mon Dec 09 2019 systemd maintenance team - 239-20 +- journal: rely on _cleanup_free_ to free a temporary string used in client_context_read_cgroup (#1764560) +- basic/user-util: allow dots in user names (#1717603) +- sd-bus: bump message queue size again (#1770189) +- tests: put fuzz_journald_processing_function in a .c file (#1764560) +- tests: add a fuzzer for dev_kmsg_record (#1764560) +- basic: remove an assertion from cunescape_one (#1764560) +- journal: fix an off-by-one error in dev_kmsg_record (#1764560) +- tests: add a reproducer for a memory leak fixed in 30eddcd51b8a472e05d3b8d1 in August (#1764560) +- tests: add a reproducer for a heap-buffer-overflow fixed in 937b1171378bc1000a (#1764560) +- test: initialize syslog_fd in fuzz-journald-kmsg too (#1764560) +- tests: add a fuzzer for process_audit_string (#1764560) +- journald: check whether sscanf has changed the value corresponding to %n (#1764560) +- tests: introduce dummy_server_init and use it in all journald fuzzers (#1764560) +- tests: add a fuzzer for journald streams (#1764560) +- tests: add a fuzzer for server_process_native_file (#1764560) +- fuzz-journal-stream: avoid assertion failure on samples which don't fit in pipe (#1764560) +- journald: take leading spaces into account in syslog_parse_identifier (#1764560) +- Add a warning about the difference in permissions between existing directories and unit settings. (#1778384) +- execute: remove one redundant comparison check (#1778384) +- core: change ownership/mode of the execution directories also for static users (#1778384) +- core/dbus-execute: remove unnecessary initialization (#1734787) +- shared/cpu-set-util: move the part to print cpu-set into a separate function (#1734787) +- shared/cpu-set-util: remove now-unused CPU_SIZE_TO_NUM() (#1734787) +- Rework cpu affinity parsing (#1734787) +- Move cpus_in_affinity_mask() to cpu-set-util.[ch] (#1734787) +- test-cpu-set-util: add simple test for cpus_in_affinity_mask() (#1734787) +- test-cpu-set-util: add a smoke test for test_parse_cpu_set_extend() (#1734787) +- pid1: parse CPUAffinity= in incremental fashion (#1734787) +- pid1: don't reset setting from /proc/cmdline upon restart (#1734787) +- pid1: when reloading configuration, forget old settings (#1734787) +- test-execute: use CPUSet too (#1734787) +- shared/cpu-set-util: drop now-unused cleanup function (#1734787) +- shared/cpu-set-util: make transfer of cpu_set_t over bus endian safe (#1734787) +- test-cpu-set-util: add test for dbus conversions (#1734787) +- shared/cpu-set-util: introduce cpu_set_to_range() (#1734787) +- systemctl: present CPUAffinity mask as a list of CPU index ranges (#1734787) +- shared/cpu-set-util: only force range printing one time (#1734787) +- execute: dump CPUAffinity as a range string instead of a list of CPUs (#1734787) +- cpu-set-util: use %d-%d format in cpu_set_to_range_string() only for actual ranges (#1734787) +- core: introduce NUMAPolicy and NUMAMask options (#1734787) +- core: disable CPUAccounting by default (#1734787) +- set kptr_restrict=1 (#1689346) +- cryptsetup: reduce the chance that we will be OOM killed (#1696602) +- core, job: fix breakage of ordering dependencies by systemctl reload command (#1766417) +- debug-generator: enable custom systemd.debug_shell tty (#1723722) + +* Thu Oct 24 2019 Lukas Nykryn - 239-19 +- core: never propagate reload failure to service result (#1735787) +- man: document systemd-analyze security (#1750343) +- man: reorder and add examples to systemd-analyze(1) (#1750343) +- travis: move to CentOS 8 docker images (#1761519) +- travis: drop SCL remains (#1761519) +- syslog: fix segfault in syslog_parse_priority() (#1761519) +- sd-bus: make strict asan shut up (#1761519) +- travis: don't run slow tests under ASan/UBSan (#1761519) +- kernel-install: do not require non-empty kernel cmdline (#1701454) +- ask-password: prevent buffer overrow when reading from keyring (#1752050) +- core: try to reopen /dev/kmsg again right after mounting /dev (#1749212) +- buildsys: don't garbage collect sections while linking (#1748258) +- udev: introduce CONST key name (#1762679) +- Call getgroups() to know size of supplementary groups array to allocate (#1743230256 KB +#1743235) +- Consider smb3 as remote filesystem (#1757257) +- process-util: introduce pid_is_my_child() helper (#1744972) +- core: reduce the number of stalled PIDs from the watched processes list when possible (#1744972) +- core: only watch processes when it's really necessary (#1744972) +- core: implement per unit journal rate limiting (#1719577) +- path: stop watching path specs once we triggered the target unit (#1763161) +- journald: fixed assertion failure when system journal rotation fails (#9893) (#1763619) +- test: use PBKDF2 instead of Argon2 in cryptsetup... (#1761519) +- test: mask several unnecessary services (#1761519) +- test: bump the second partition's size to 50M (#1761519) +- shared/sleep-config: exclude zram devices from hibernation candidates (#1763617) +- selinux: don't log SELINUX_INFO and SELINUX_WARNING messages to audit (#1763612) +- sd-device: introduce log_device_*() macros (#1753369) +- udev: Add id program and rule for FIDO security tokens (#1753369) +- shared/but-util: drop trusted annotation from bus_open_system_watch_bind_with_description() (#1746857) +- sd-bus: adjust indentation of comments (#1746857) +- resolved: do not run loop twice (#1746857) +- resolved: allow access to Set*Link and Revert methods through polkit (#1746857) +- resolved: query polkit only after parsing the data (#1746857) + +* Fri Aug 30 2019 Lukas Nykryn - 239-18 +- shared/but-util: drop trusted annotation from bus_open_system_watch_bind_with_description() (#1746857) +- sd-bus: adjust indentation of comments (#1746857) +- resolved: do not run loop twice (#1746857) +- resolved: allow access to Set*Link and Revert methods through polkit (#1746857) +- resolved: query polkit only after parsing the data (#1746857) + +* Wed Aug 07 2019 Lukas Nykryn - 239-17 +- mount: simplify /proc/self/mountinfo handler (#1696178) +- mount: rescan /proc/self/mountinfo before processing waitid() results (#1696178) +- swap: scan /proc/swaps before processing waitid() results (#1696178) +- analyze-security: fix potential division by zero (#1734400) + +* Fri Jul 26 2019 Lukas Nykryn - 239-16 +- sd-bus: deal with cookie overruns (#1694999) +- journal-remote: do not request Content-Length if Transfer-Encoding is chunked (#1708849) +- journal: do not remove multiple spaces after identifier in syslog message (#1691817) +- cryptsetup: Do not fallback to PLAIN mapping if LUKS data device set fails. (#1719153) +- cryptsetup: call crypt_load() for LUKS only once (#1719153) +- cryptsetup: Add LUKS2 token support. (#1719153) +- udev/scsi_id: fix incorrect page length when get device identification VPD page (#1713227) +- Change job mode of manager triggered restarts to JOB_REPLACE (#11456 +#1712524) +- bash-completion: analyze: support 'security' (#1733395) +- man: note that journal does not validate syslog fields (#1707175) +- rules: skip memory hotplug on ppc64 (#1713159) + * Thu May 23 2019 Lukas Nykryn - 239-15 - tree-wide: shorten error logging a bit (#1697893) - nspawn: simplify machine terminate bus call (#1697893)