diff --git a/SOURCES/0832-ci-lint-add-shell-linter-Differential-ShellCheck.patch b/SOURCES/0832-ci-lint-add-shell-linter-Differential-ShellCheck.patch new file mode 100644 index 0000000..d848bfa --- /dev/null +++ b/SOURCES/0832-ci-lint-add-shell-linter-Differential-ShellCheck.patch @@ -0,0 +1,59 @@ +From 5f69ba3919d32ed93c68bb6b8b70a516f2bb56a8 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Tue, 16 Aug 2022 14:34:49 +0200 +Subject: [PATCH] ci(lint): add shell linter - Differential ShellCheck + +It performs differential ShellCheck scans and report results directly in +pull request. + +documentation: +https://github.com/redhat-plumbers-in-action/differential-shellcheck + +(inspired by commit + https://github.com/systemd/systemd/commit/3f3c718e79abdac698ae90de5cd4c0560a0a75d4) + +RHEL-only + +Related: #2122499 +--- + .github/workflows/differential-shellcheck.yml | 31 +++++++++++++++++++ + 1 file changed, 31 insertions(+) + create mode 100644 .github/workflows/differential-shellcheck.yml + +diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml +new file mode 100644 +index 0000000000..fa94679b51 +--- /dev/null ++++ b/.github/workflows/differential-shellcheck.yml +@@ -0,0 +1,31 @@ ++--- ++# https://github.com/redhat-plumbers-in-action/differential-shellcheck#readme ++ ++name: Differential ShellCheck ++on: ++ pull_request: ++ branches: ++ - master ++ - rhel-8.*.0 ++ ++permissions: ++ contents: read ++ ++jobs: ++ lint: ++ runs-on: ubuntu-latest ++ ++ permissions: ++ security-events: write ++ pull-requests: write ++ ++ steps: ++ - name: Repository checkout ++ uses: actions/checkout@v3 ++ with: ++ fetch-depth: 0 ++ ++ - name: Differential ShellCheck ++ uses: redhat-plumbers-in-action/differential-shellcheck@v3 ++ with: ++ token: ${{ secrets.GITHUB_TOKEN }} diff --git a/SOURCES/0832-time-util-fix-buffer-over-run.patch b/SOURCES/0832-time-util-fix-buffer-over-run.patch deleted file mode 100644 index 7f587b4..0000000 --- a/SOURCES/0832-time-util-fix-buffer-over-run.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 3ec7e3ece5474475b9123a67636f1ba3eec1e3c4 Mon Sep 17 00:00:00 2001 -From: Yu Watanabe -Date: Thu, 7 Jul 2022 18:27:02 +0900 -Subject: [PATCH] time-util: fix buffer-over-run - -Fixes #23928. - -(cherry picked from commit 9102c625a673a3246d7e73d8737f3494446bad4e) - -Resolves: #2139390 ---- - src/basic/time-util.c | 2 +- - src/test/test-time-util.c | 5 +++++ - 2 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/basic/time-util.c b/src/basic/time-util.c -index c36e462193..d46d884be5 100644 ---- a/src/basic/time-util.c -+++ b/src/basic/time-util.c -@@ -515,7 +515,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { - t = b; - } - -- n = MIN((size_t) k, l); -+ n = MIN((size_t) k, l-1); - - l -= n; - p += n; -diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c -index 354a01dd1a..6ebde4153c 100644 ---- a/src/test/test-time-util.c -+++ b/src/test/test-time-util.c -@@ -187,6 +187,11 @@ static void test_format_timespan(usec_t accuracy) { - test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); - test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); - test_format_timespan_one(USEC_INFINITY, accuracy); -+ -+ /* See issue #23928. */ -+ _cleanup_free_ char *buf; -+ assert_se(buf = new(char, 5)); -+ assert_se(buf == format_timespan(buf, 5, 100005, 1000)); - } - - static void test_timezone_is_valid(void) { diff --git a/SOURCES/0833-core-move-reset_arguments-to-the-end-of-main-s-finis.patch b/SOURCES/0833-core-move-reset_arguments-to-the-end-of-main-s-finis.patch deleted file mode 100644 index d74b950..0000000 --- a/SOURCES/0833-core-move-reset_arguments-to-the-end-of-main-s-finis.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 944596e66a9cd947545c714c4682681fdbefc09f Mon Sep 17 00:00:00 2001 -From: Anita Zhang -Date: Thu, 17 Sep 2020 01:49:17 -0700 -Subject: [PATCH] core: move reset_arguments() to the end of main's finish - -Fixes #16991 - -fb39af4ce42d7ef9af63009f271f404038703704 replaced `free_arguments()` with -`reset_arguments()`, which frees arg_* variables as before, but also resets all -of them to the default values. `reset_arguments()` was positioned -in such a way that it overrode some arg_* values still in use at shutdown. - -To avoid further unintentional resets, I moved `reset_arguments()` -right before the return, when nothing else will be using the arg_* variables. - -(cherry picked from commit 7d9eea2bd3d4f83668c7a78754d201b226acbf1e) - -Resolves: #2127170 ---- - src/core/main.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/core/main.c b/src/core/main.c -index bfd4c531a7..cfa6fec930 100644 ---- a/src/core/main.c -+++ b/src/core/main.c -@@ -2631,7 +2631,6 @@ finish: - m = manager_free(m); - } - -- reset_arguments(); - mac_selinux_finish(); - - if (reexecute) -@@ -2656,6 +2655,7 @@ finish: - * in become_shutdown() so normally we cannot free them yet. */ - watchdog_free_device(); - arg_watchdog_device = mfree(arg_watchdog_device); -+ reset_arguments(); - return retval; - } - #endif -@@ -2677,5 +2677,6 @@ finish: - freeze_or_reboot(); - } - -+ reset_arguments(); - return retval; - } diff --git a/SOURCES/0833-meson-do-not-compare-objects-of-different-types.patch b/SOURCES/0833-meson-do-not-compare-objects-of-different-types.patch new file mode 100644 index 0000000..234e387 --- /dev/null +++ b/SOURCES/0833-meson-do-not-compare-objects-of-different-types.patch @@ -0,0 +1,34 @@ +From deb09b3bd826571149f6b018f3a3ff8a33cd104b Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 28 Jun 2018 16:09:04 +0900 +Subject: [PATCH] meson: do not compare objects of different types + +This fixes the following warning: +``` +meson.build:1140: WARNING: Trying to compare values of different types (DependencyHolder, list) using !=. +The result of this is undefined and will become a hard error in a future Meson release. +``` + +Follow-up for f02582f69fe1e7663a87ba80bd4f90d5d23ee75f(#9410). + +(cherry picked from commit 48f5da19b6e8f0d05f5217bc9856093d354ce5d0) + +Related: #2122499 +--- + meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 6729a9ea5e..af4cf331da 100644 +--- a/meson.build ++++ b/meson.build +@@ -1165,7 +1165,8 @@ substs.set('DEFAULT_DNSSEC_MODE', default_dnssec) + + dns_over_tls = get_option('dns-over-tls') + if dns_over_tls != 'false' +- have = libgnutls != [] and libgnutls.version().version_compare('>=3.5.3') ++ have = (conf.get('HAVE_GNUTLS') == 1 and ++ libgnutls.version().version_compare('>=3.5.3')) + if dns_over_tls == 'true' and not have + error('DNS-over-TLS support was requested, but dependencies are not available') + endif diff --git a/SOURCES/0834-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch b/SOURCES/0834-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch deleted file mode 100644 index 219d6cc..0000000 --- a/SOURCES/0834-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9274a3bec0d3b259a006574f6bfb559888b04533 Mon Sep 17 00:00:00 2001 -From: Michal Sekletar -Date: Fri, 18 Nov 2022 16:16:36 +0100 -Subject: [PATCH] basic: recognize pdfs filesystem as a network filesystem - -Fujitsu advises their users to always use _netdev mount option with pdfs -mounts. Hence it makes sense to simply consider pdfs mounts as network -filesystem mounts. - -https://software.fujitsu.com/jp/manual/manualfiles/m130027/j2ul1563/02enz200/j1563-02-06-02-02.html - -RHEL-only - -Resolves: #2143100 ---- - src/basic/mount-util.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c -index e7f9e514c2..983566b46b 100644 ---- a/src/basic/mount-util.c -+++ b/src/basic/mount-util.c -@@ -634,7 +634,8 @@ bool fstype_is_network(const char *fstype) { - "glusterfs", - "pvfs2", /* OrangeFS */ - "ocfs2", -- "lustre"); -+ "lustre", -+ "pdfs"); - } - - bool fstype_is_api_vfs(const char *fstype) { diff --git a/SOURCES/0834-journal-remote-use-MHD_HTTP_CONTENT_TOO_LARGE-as-MHD.patch b/SOURCES/0834-journal-remote-use-MHD_HTTP_CONTENT_TOO_LARGE-as-MHD.patch new file mode 100644 index 0000000..689ad06 --- /dev/null +++ b/SOURCES/0834-journal-remote-use-MHD_HTTP_CONTENT_TOO_LARGE-as-MHD.patch @@ -0,0 +1,48 @@ +From ea9b3a664f5e67d0ee6b0bf6ca362835ae11fedc Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 20 Dec 2021 20:48:32 +0900 +Subject: [PATCH] journal-remote: use MHD_HTTP_CONTENT_TOO_LARGE as + MHD_HTTP_PAYLOAD_TOO_LARGE is deprecated since 0.9.74 + +(cherry picked from commit 30df858f43b14a55c6650b43bea12cbf2cc0bc67) + +Related: #2122499 +--- + src/journal-remote/journal-remote-main.c | 2 +- + src/journal-remote/microhttpd-util.h | 10 +++++++--- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c +index 47fe9d7433..bcaa370099 100644 +--- a/src/journal-remote/journal-remote-main.c ++++ b/src/journal-remote/journal-remote-main.c +@@ -304,7 +304,7 @@ static int request_handler( + /* 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, ++ return mhd_respondf(connection, 0, MHD_HTTP_CONTENT_TOO_LARGE, + "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); + } + +diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h +index 26909082a1..dd0ca1d9bd 100644 +--- a/src/journal-remote/microhttpd-util.h ++++ b/src/journal-remote/microhttpd-util.h +@@ -38,9 +38,13 @@ + # define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE + #endif + +-/* Renamed in µhttpd 0.9.53 */ +-#ifndef MHD_HTTP_PAYLOAD_TOO_LARGE +-# define MHD_HTTP_PAYLOAD_TOO_LARGE MHD_HTTP_REQUEST_ENTITY_TOO_LARGE ++/* Renamed in µhttpd 0.9.74 (8c644fc1f4d498ea489add8d40a68f5d3e5899fa) */ ++#ifndef MHD_HTTP_CONTENT_TOO_LARGE ++# ifdef MHD_HTTP_PAYLOAD_TOO_LARGE ++# define MHD_HTTP_CONTENT_TOO_LARGE MHD_HTTP_PAYLOAD_TOO_LARGE /* 0.9.53 or newer */ ++# else ++# define MHD_HTTP_CONTENT_TOO_LARGE MHD_HTTP_REQUEST_ENTITY_TOO_LARGE ++# endif + #endif + + #if MHD_VERSION < 0x00094203 diff --git a/SOURCES/0835-Fix-build-with-httpd-0.9.71.patch b/SOURCES/0835-Fix-build-with-httpd-0.9.71.patch new file mode 100644 index 0000000..0f8ec58 --- /dev/null +++ b/SOURCES/0835-Fix-build-with-httpd-0.9.71.patch @@ -0,0 +1,71 @@ +From ca86de228e19cea268ec3eeabc9097d7c28fbf24 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 30 Jun 2020 09:56:10 +0200 +Subject: [PATCH] =?UTF-8?q?Fix=20build=20with=20=C2=B5httpd=200.9.71?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The return type of callbacks was changed from int to an enum. + +(cherry picked from commit d17eabb1052e7c8c432331a7a782845e36164f01) + +Related: #2122499 +--- + src/journal-remote/journal-gatewayd.c | 4 ++-- + src/journal-remote/journal-remote-main.c | 2 +- + src/journal-remote/microhttpd-util.h | 6 ++++++ + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c +index 54446ff7b5..3ff05a4d72 100644 +--- a/src/journal-remote/journal-gatewayd.c ++++ b/src/journal-remote/journal-gatewayd.c +@@ -338,7 +338,7 @@ static int request_parse_range( + return 0; + } + +-static int request_parse_arguments_iterator( ++static mhd_result request_parse_arguments_iterator( + void *cls, + enum MHD_ValueKind kind, + const char *key, +@@ -795,7 +795,7 @@ static int request_handler_machine( + return MHD_queue_response(connection, MHD_HTTP_OK, response); + } + +-static int request_handler( ++static mhd_result request_handler( + void *cls, + struct MHD_Connection *connection, + const char *url, +diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c +index bcaa370099..a1008db6eb 100644 +--- a/src/journal-remote/journal-remote-main.c ++++ b/src/journal-remote/journal-remote-main.c +@@ -241,7 +241,7 @@ static int process_http_upload( + return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK."); + }; + +-static int request_handler( ++static mhd_result request_handler( + void *cls, + struct MHD_Connection *connection, + const char *url, +diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h +index dd0ca1d9bd..792c07ac20 100644 +--- a/src/journal-remote/microhttpd-util.h ++++ b/src/journal-remote/microhttpd-util.h +@@ -51,6 +51,12 @@ + # define MHD_create_response_from_fd_at_offset64 MHD_create_response_from_fd_at_offset + #endif + ++#if MHD_VERSION >= 0x00097002 ++# define mhd_result enum MHD_Result ++#else ++# define mhd_result int ++#endif ++ + void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0); + + /* respond_oom() must be usable with return, hence this form. */ diff --git a/SOURCES/0835-core-bring-manager_startup-and-manager_reload-more-i.patch b/SOURCES/0835-core-bring-manager_startup-and-manager_reload-more-i.patch deleted file mode 100644 index e1c4d6c..0000000 --- a/SOURCES/0835-core-bring-manager_startup-and-manager_reload-more-i.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 2385f40cc80d723b105add1496de292c3241595c Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Tue, 9 Oct 2018 17:37:57 +0200 -Subject: [PATCH] core: bring manager_startup() and manager_reload() more - inline - -Both functions do partly the same, let's make sure they do it in the -same order, and that we don't miss some calls. - -This makes a number of changes: - -1. Moves exec_runtime_vacuum() two calls down in manager_startup(). This - should not have any effect but makes manager_startup() more like - manager_reload(). - -2. Calls manager_recheck_journal(), manager_recheck_dbus(), - manager_enqueue_sync_bus_names() in manager_startup() too. This is a - good idea since during reeexec we pass through manager_startup() and - hence can't assume dbus and journald weren't up yet, hence let's - check if they are ready to be connected to. - -3. Include manager_enumerate_perpetual() in manager_reload(), too. This - is not strictly necessary, since these units are included in the - serialization anyway, but it's still a nice thing, in particular as - theoretically the deserialization could fail. - -(cherry picked from commit 3ad2afb6a204513c7834c64ab864e40169874390) - -Resolves: #2164049 ---- - src/core/manager.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/src/core/manager.c b/src/core/manager.c -index f4611e6f8f..49d6d250ef 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -1660,12 +1660,12 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - /* Release any dynamic users no longer referenced */ - dynamic_user_vacuum(m, true); - -- exec_runtime_vacuum(m); -- - /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */ - manager_vacuum_uid_refs(m); - manager_vacuum_gid_refs(m); - -+ exec_runtime_vacuum(m); -+ - if (serialization) { - assert(m->n_reloading > 0); - m->n_reloading--; -@@ -1676,6 +1676,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - m->send_reloading_done = true; - } - -+ /* It might be safe to log to the journal now and connect to dbus */ -+ manager_recheck_journal(m); -+ manager_recheck_dbus(m); -+ -+ /* Sync current state of bus names with our set of listening units */ -+ (void) manager_enqueue_sync_bus_names(m); -+ - /* Let's finally catch up with any changes that took place while we were reloading/reexecing */ - manager_catchup(m); - -@@ -3500,7 +3507,8 @@ int manager_reload(Manager *m) { - lookup_paths_reduce(&m->lookup_paths); - manager_build_unit_path_cache(m); - -- /* First, enumerate what we can from all config files */ -+ /* First, enumerate what we can from kernel and suchlike */ -+ manager_enumerate_perpetual(m); - manager_enumerate(m); - - /* Second, deserialize our stored data */ diff --git a/SOURCES/0836-basic-add-STRERROR-wrapper-for-strerror_r.patch b/SOURCES/0836-basic-add-STRERROR-wrapper-for-strerror_r.patch deleted file mode 100644 index c1c53d8..0000000 --- a/SOURCES/0836-basic-add-STRERROR-wrapper-for-strerror_r.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 84a8245cf58fa7edea61eab5f1ebd86a3944c388 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Fri, 7 Oct 2022 12:28:31 +0200 -Subject: [PATCH] basic: add STRERROR() wrapper for strerror_r() - -(cherry picked from commit 2c5d05b3cd986568105d67891e4010b868dea24f) - -Related: #2155519 ---- - src/basic/util.h | 10 ++++++++++ - src/test/test-util.c | 40 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 50 insertions(+) - -diff --git a/src/basic/util.h b/src/basic/util.h -index 76b76d7e91..195f02cf5f 100644 ---- a/src/basic/util.h -+++ b/src/basic/util.h -@@ -153,6 +153,16 @@ static inline void _reset_errno_(int *saved_errno) { - errno = *saved_errno; - } - -+/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */ -+#define ERRNO_BUF_LEN 1024 -+ -+/* Note: the lifetime of the compound literal is the immediately surrounding block, -+ * see C11 §6.5.2.5, and -+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks -+ * -+ * Note that we use the GNU variant of strerror_r() here. */ -+#define STRERROR(errnum) strerror_r(abs(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) -+ - #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno - - #define UNPROTECT_ERRNO \ -diff --git a/src/test/test-util.c b/src/test/test-util.c -index df60d89115..c93eaf7fc6 100644 ---- a/src/test/test-util.c -+++ b/src/test/test-util.c -@@ -12,6 +12,7 @@ - #include "process-util.h" - #include "raw-clone.h" - #include "rm-rf.h" -+#include "stdio-util.h" - #include "string-util.h" - #include "util.h" - -@@ -321,6 +322,42 @@ static void test_system_tasks_max_scale(void) { - assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); - } - -+static void test_strerror_not_threadsafe(void) { -+ /* Just check that strerror really is not thread-safe. */ -+ log_info("strerror(%d) → %s", 200, strerror(200)); -+ log_info("strerror(%d) → %s", 201, strerror(201)); -+ log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX)); -+ -+ log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201)); -+ -+ /* This call is not allowed, because the first returned string becomes invalid when -+ * we call strerror the second time: -+ * -+ * log_info("strerror(%d), strerror(%d) → %s, %s", 200, 201, strerror(200), strerror(201)); -+ */ -+} -+ -+static void test_STRERROR(void) { -+ /* Just check that STRERROR really is thread-safe. */ -+ log_info("STRERROR(%d) → %s", 200, STRERROR(200)); -+ log_info("STRERROR(%d) → %s", 201, STRERROR(201)); -+ log_info("STRERROR(%d), STRERROR(%d) → %s, %s", 200, 201, STRERROR(200), STRERROR(201)); -+ -+ const char *a = STRERROR(200), *b = STRERROR(201); -+ assert_se(strstr(a, "200")); -+ assert_se(strstr(b, "201")); -+ -+ /* Check with negative values */ -+ assert_se(streq(a, STRERROR(-200))); -+ assert_se(streq(b, STRERROR(-201))); -+ -+ const char *c = STRERROR(INT_MAX); -+ char buf[DECIMAL_STR_MAX(int)]; -+ xsprintf(buf, "%d", INT_MAX); /* INT_MAX is hexadecimal, use printf to convert to decimal */ -+ log_info("STRERROR(%d) → %s", INT_MAX, c); -+ assert_se(strstr(c, buf)); -+} -+ - int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); -@@ -340,5 +377,8 @@ int main(int argc, char *argv[]) { - test_system_tasks_max(); - test_system_tasks_max_scale(); - -+ test_strerror_not_threadsafe(); -+ test_STRERROR(); -+ - return 0; - } diff --git a/SOURCES/0836-ci-replace-LGTM-with-CodeQL.patch b/SOURCES/0836-ci-replace-LGTM-with-CodeQL.patch new file mode 100644 index 0000000..b24cc6c --- /dev/null +++ b/SOURCES/0836-ci-replace-LGTM-with-CodeQL.patch @@ -0,0 +1,303 @@ +From 2b1dbcab1af1a22f3a46fa23aa551a7394673938 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Thu, 15 Sep 2022 15:29:23 +0200 +Subject: [PATCH] ci: replace LGTM with CodeQL + +As LGTM is going to be shut down by EOY, let's use CodeQL instead. + +This is loosely based on upstream's CodeQL configs with some minor +tweaks to avoid backporting tons of unrelated commits. + +rhel-only +Related: #2122499 +--- + .github/codeql-config.yml | 12 ++++ + .github/codeql-custom.qls | 44 ++++++++++++ + .../PotentiallyDangerousFunction.ql | 3 + + .../UninitializedVariableWithCleanup.ql | 16 ++--- + .github/codeql-queries/qlpack.yml | 11 +++ + .github/workflows/codeql.yml | 68 +++++++++++++++++++ + .lgtm.yml | 37 ---------- + 7 files changed, 146 insertions(+), 45 deletions(-) + create mode 100644 .github/codeql-config.yml + create mode 100644 .github/codeql-custom.qls + rename {.lgtm/cpp-queries => .github/codeql-queries}/PotentiallyDangerousFunction.ql (93%) + rename {.lgtm/cpp-queries => .github/codeql-queries}/UninitializedVariableWithCleanup.ql (86%) + create mode 100644 .github/codeql-queries/qlpack.yml + create mode 100644 .github/workflows/codeql.yml + delete mode 100644 .lgtm.yml + +diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml +new file mode 100644 +index 0000000000..7c01d32caa +--- /dev/null ++++ b/.github/codeql-config.yml +@@ -0,0 +1,12 @@ ++--- ++# vi: ts=2 sw=2 et: ++# SPDX-License-Identifier: LGPL-2.1-or-later ++name: "CodeQL config" ++ ++disable-default-queries: false ++ ++queries: ++ - name: Enable possibly useful queries which are disabled by default ++ uses: ./.github/codeql-custom.qls ++ - name: systemd-specific CodeQL queries ++ uses: ./.github/codeql-queries/ +diff --git a/.github/codeql-custom.qls b/.github/codeql-custom.qls +new file mode 100644 +index 0000000000..d35fbe3114 +--- /dev/null ++++ b/.github/codeql-custom.qls +@@ -0,0 +1,44 @@ ++--- ++# vi: ts=2 sw=2 et syntax=yaml: ++# SPDX-License-Identifier: LGPL-2.1-or-later ++# ++# Note: it is not recommended to directly reference the respective queries from ++# the github/codeql repository, so we have to "dance" around it using ++# a custom QL suite ++# See: ++# - https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#running-additional-queries ++# - https://github.com/github/codeql-action/issues/430#issuecomment-806092120 ++# - https://codeql.github.com/docs/codeql-cli/creating-codeql-query-suites/ ++ ++# Note: the codeql/-queries pack name can be found in the CodeQL repo[0] ++# in /ql/src/qlpack.yml. The respective codeql-suites are then ++# under /ql/src/codeql-suites/. ++# ++# [0] https://github.com/github/codeql ++- import: codeql-suites/cpp-lgtm.qls ++ from: codeql/cpp-queries ++- import: codeql-suites/python-lgtm.qls ++ from: codeql/python-queries ++- include: ++ id: ++ - cpp/bad-strncpy-size ++ - cpp/declaration-hides-variable ++ - cpp/include-non-header ++ - cpp/inconsistent-null-check ++ - cpp/mistyped-function-arguments ++ - cpp/nested-loops-with-same-variable ++ - cpp/sizeof-side-effect ++ - cpp/suspicious-pointer-scaling ++ - cpp/suspicious-pointer-scaling-void ++ - cpp/suspicious-sizeof ++ - cpp/unsafe-strcat ++ - cpp/unsafe-strncat ++ - cpp/unsigned-difference-expression-compared-zero ++ - cpp/unused-local-variable ++ tags: ++ - "security" ++ - "correctness" ++ severity: "error" ++- exclude: ++ id: ++ - cpp/fixme-comment +diff --git a/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql b/.github/codeql-queries/PotentiallyDangerousFunction.ql +similarity index 93% +rename from .lgtm/cpp-queries/PotentiallyDangerousFunction.ql +rename to .github/codeql-queries/PotentiallyDangerousFunction.ql +index 39e8dddd13..63fd14e75f 100644 +--- a/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql ++++ b/.github/codeql-queries/PotentiallyDangerousFunction.ql +@@ -46,6 +46,9 @@ predicate potentiallyDangerousFunction(Function f, string message) { + ) or ( + f.getQualifiedName() = "accept" and + message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead." ++ ) or ( ++ f.getQualifiedName() = "dirname" and ++ message = "Call dirname() is icky. Use path_extract_directory() instead." + ) + } + +diff --git a/.lgtm/cpp-queries/UninitializedVariableWithCleanup.ql b/.github/codeql-queries/UninitializedVariableWithCleanup.ql +similarity index 86% +rename from .lgtm/cpp-queries/UninitializedVariableWithCleanup.ql +rename to .github/codeql-queries/UninitializedVariableWithCleanup.ql +index 6b3b62f8bc..e514111f28 100644 +--- a/.lgtm/cpp-queries/UninitializedVariableWithCleanup.ql ++++ b/.github/codeql-queries/UninitializedVariableWithCleanup.ql +@@ -50,16 +50,16 @@ class UninitialisedLocalReachability extends StackVariableReachability { + * fun(&x); + * puts(x); + * +- * `useOfVarActual()` won't treat this an an uninitialized read even if the callee ++ * `useOfVarActual()` won't treat this as an uninitialized read even if the callee + * doesn't modify the argument, however, `useOfVar()` will + */ + override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVar(v, node) } + + override predicate isBarrier(ControlFlowNode node, StackVariable v) { +- // only report the _first_ possibly uninitialized use ++ /* only report the _first_ possibly uninitialized use */ + useOfVar(v, node) or + ( +- /* If there's an return statement somewhere between the variable declaration ++ /* If there's a return statement somewhere between the variable declaration + * and a possible definition, don't accept is as a valid initialization. + * + * E.g.: +@@ -71,7 +71,7 @@ class UninitialisedLocalReachability extends StackVariableReachability { + * x = malloc(...); + * + * is not a valid initialization, since we might return from the function +- * _before_ the actual iniitialization (emphasis on _might_, since we ++ * _before_ the actual initialization (emphasis on _might_, since we + * don't know if the return statement might ever evaluate to true). + */ + definitionBarrier(v, node) and +@@ -92,14 +92,14 @@ predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosing + * for this check to exclude them. + */ + VariableAccess commonException() { +- // If the uninitialized use we've found is in a macro expansion, it's +- // typically something like va_start(), and we don't want to complain. ++ /* If the uninitialized use we've found is in a macro expansion, it's ++ * typically something like va_start(), and we don't want to complain. */ + result.getParent().isInMacroExpansion() + or + result.getParent() instanceof BuiltInOperation + or +- // Finally, exclude functions that contain assembly blocks. It's +- // anyone's guess what happens in those. ++ /* Finally, exclude functions that contain assembly blocks. It's ++ * anyone's guess what happens in those. */ + containsInlineAssembly(result.getEnclosingFunction()) + } + +diff --git a/.github/codeql-queries/qlpack.yml b/.github/codeql-queries/qlpack.yml +new file mode 100644 +index 0000000000..a1a2dec6d6 +--- /dev/null ++++ b/.github/codeql-queries/qlpack.yml +@@ -0,0 +1,11 @@ ++--- ++# vi: ts=2 sw=2 et syntax=yaml: ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++library: false ++name: systemd/cpp-queries ++version: 0.0.1 ++dependencies: ++ codeql/cpp-all: "*" ++ codeql/suite-helpers: "*" ++extractor: cpp +diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml +new file mode 100644 +index 0000000000..c5426d5686 +--- /dev/null ++++ b/.github/workflows/codeql.yml +@@ -0,0 +1,68 @@ ++--- ++# vi: ts=2 sw=2 et: ++# SPDX-License-Identifier: LGPL-2.1-or-later ++# ++name: "CodeQL" ++ ++on: ++ pull_request: ++ branches: ++ - master ++ - rhel-* ++ paths: ++ - '**/meson.build' ++ - '.github/**/codeql*' ++ - 'src/**' ++ - 'test/**' ++ - 'tools/**' ++ push: ++ branches: ++ - master ++ - rhel-* ++ ++permissions: ++ contents: read ++ ++jobs: ++ analyze: ++ name: Analyze ++ runs-on: ubuntu-22.04 ++ concurrency: ++ group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }} ++ cancel-in-progress: true ++ permissions: ++ actions: read ++ security-events: write ++ ++ strategy: ++ fail-fast: false ++ matrix: ++ language: ['cpp', 'python'] ++ ++ steps: ++ - name: Checkout repository ++ uses: actions/checkout@v3 ++ ++ - name: Initialize CodeQL ++ uses: github/codeql-action/init@v2 ++ with: ++ languages: ${{ matrix.language }} ++ config-file: ./.github/codeql-config.yml ++ ++ - name: Install dependencies ++ if: matrix.language == 'cpp' ++ run: | ++ echo "deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list ++ sudo apt-get -y update ++ sudo apt-get -y build-dep systemd ++ sudo apt-get -y install libfdisk-dev libpwquality-dev libqrencode-dev libssl-dev libxkbcommon-dev libzstd-dev ++ ++ - name: Build ++ if: matrix.language == 'cpp' ++ run: | ++ # EL 8 systemd fails to build with newer gnu-efi (3.0.13 on Ubuntu Jammy ATTOW) ++ meson build -Dlibiptc=false -Dgnu-efi=false ++ ninja -C build -v ++ ++ - name: Perform CodeQL Analysis ++ uses: github/codeql-action/analyze@v2 +diff --git a/.lgtm.yml b/.lgtm.yml +deleted file mode 100644 +index fe93957b67..0000000000 +--- a/.lgtm.yml ++++ /dev/null +@@ -1,37 +0,0 @@ +---- +-# vi: ts=2 sw=2 et: +- +-# Explicitly enable certain checks which are hidden by default +-queries: +- - include: cpp/bad-strncpy-size +- - include: cpp/declaration-hides-variable +- - include: cpp/inconsistent-null-check +- - include: cpp/mistyped-function-arguments +- - include: cpp/nested-loops-with-same-variable +- - include: cpp/sizeof-side-effect +- - include: cpp/suspicious-pointer-scaling +- - include: cpp/suspicious-pointer-scaling-void +- - include: cpp/suspicious-sizeof +- - include: cpp/unsafe-strcat +- - include: cpp/unsafe-strncat +- - include: cpp/unsigned-difference-expression-compared-zero +- - include: cpp/unused-local-variable +- - include: +- tags: +- - "security" +- - "correctness" +- severity: "error" +- +-extraction: +- cpp: +- prepare: +- packages: +- - python3-pip +- - python3-setuptools +- - python3-wheel +- after_prepare: +- - pip3 install meson +- - export PATH="$HOME/.local/bin/:$PATH" +- python: +- python_setup: +- version: 3 diff --git a/SOURCES/0837-ci-mergify-Update-policy-Drop-LGTM-checks.patch b/SOURCES/0837-ci-mergify-Update-policy-Drop-LGTM-checks.patch new file mode 100644 index 0000000..b7603f0 --- /dev/null +++ b/SOURCES/0837-ci-mergify-Update-policy-Drop-LGTM-checks.patch @@ -0,0 +1,71 @@ +From 4c241b812ea79f3faa02c45f95834842c7847b76 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Wed, 21 Sep 2022 15:14:26 +0200 +Subject: [PATCH] ci(mergify): Update policy - Drop LGTM checks + +rhel-only + +Related: #2122499 +--- + .github/workflows/differential-shellcheck.yml | 1 + + .mergify.yml | 28 ++++++------------- + 2 files changed, 9 insertions(+), 20 deletions(-) + +diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml +index fa94679b51..4399f0bc64 100644 +--- a/.github/workflows/differential-shellcheck.yml ++++ b/.github/workflows/differential-shellcheck.yml +@@ -13,6 +13,7 @@ permissions: + + jobs: + lint: ++ name: Differential ShellCheck + runs-on: ubuntu-latest + + permissions: +diff --git a/.mergify.yml b/.mergify.yml +index 3afd04f18e..a5eed6a82a 100644 +--- a/.mergify.yml ++++ b/.mergify.yml +@@ -11,16 +11,10 @@ pull_request_rules: + - -check-success=build (stream8, GCC_ASAN) + # CentOS Stream CI + - -check-success=CentOS CI (CentOS Stream 8) +- # LGTM +- - and: +- - "-check-success=LGTM analysis: JavaScript" +- - "-check-neutral=LGTM analysis: JavaScript" +- - and: +- - "-check-success=LGTM analysis: Python" +- - "-check-neutral=LGTM analysis: Python" +- - and: +- - "-check-success=LGTM analysis: C/C++" +- - "-check-neutral=LGTM analysis: C/C++" ++ # CodeQL ++ - -check-success=CodeQL ++ # Other ++ - -check-success=Differential ShellCheck + actions: + label: + add: +@@ -36,16 +30,10 @@ pull_request_rules: + - check-success=build (stream8, GCC_ASAN) + # CentOS Stream CI + - check-success=CentOS CI (CentOS Stream 8) +- # LGTM +- - or: +- - "check-success=LGTM analysis: JavaScript" +- - "check-neutral=LGTM analysis: JavaScript" +- - or: +- - "check-success=LGTM analysis: Python" +- - "check-neutral=LGTM analysis: Python" +- - or: +- - "check-success=LGTM analysis: C/C++" +- - "check-neutral=LGTM analysis: C/C++" ++ # CodeQL ++ - check-success=CodeQL ++ # Other ++ - check-success=Differential ShellCheck + actions: + label: + remove: diff --git a/SOURCES/0837-coredump-put-context-array-into-a-struct.patch b/SOURCES/0837-coredump-put-context-array-into-a-struct.patch deleted file mode 100644 index 486092e..0000000 --- a/SOURCES/0837-coredump-put-context-array-into-a-struct.patch +++ /dev/null @@ -1,529 +0,0 @@ -From e256e03710abfd96e74d0b278c2b7186e3c8888b Mon Sep 17 00:00:00 2001 -From: David Tardon -Date: Thu, 12 Jan 2023 15:47:09 +0100 -Subject: [PATCH] coredump: put context array into a struct - -[dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 , -but does just the minimal change to introduce the Context struct that is -needed by the following commit.] - -Related: #2155519 ---- - src/coredump/coredump.c | 208 +++++++++++++++++++++------------------- - 1 file changed, 108 insertions(+), 100 deletions(-) - -diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c -index fb3a6ecfe9..ebc56d8342 100644 ---- a/src/coredump/coredump.c -+++ b/src/coredump/coredump.c -@@ -91,6 +91,10 @@ enum { - _CONTEXT_MAX - }; - -+typedef struct Context { -+ const char *meta[_CONTEXT_MAX]; -+} Context; -+ - typedef enum CoredumpStorage { - COREDUMP_STORAGE_NONE, - COREDUMP_STORAGE_EXTERNAL, -@@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) { - return 0; - } - --static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { -+static int fix_xattr(int fd, const Context *context) { - - static const char * const xattrs[_CONTEXT_MAX] = { - [CONTEXT_PID] = "user.coredump.pid", -@@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { - for (i = 0; i < _CONTEXT_MAX; i++) { - int k; - -- if (isempty(context[i]) || !xattrs[i]) -+ if (isempty(context->meta[i]) || !xattrs[i]) - continue; - -- k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE); -+ k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE); - if (k < 0 && r == 0) - r = -errno; - } -@@ -230,7 +234,7 @@ static int fix_permissions( - int fd, - const char *filename, - const char *target, -- const char *context[_CONTEXT_MAX], -+ const Context *context, - uid_t uid) { - - int r; -@@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) { - return 1; - } - --static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { -+static int make_filename(const Context *context, char **ret) { - _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; - sd_id128_t boot = {}; - int r; - - assert(context); - -- c = filename_escape(context[CONTEXT_COMM]); -+ c = filename_escape(context->meta[CONTEXT_COMM]); - if (!c) - return -ENOMEM; - -- u = filename_escape(context[CONTEXT_UID]); -+ u = filename_escape(context->meta[CONTEXT_UID]); - if (!u) - return -ENOMEM; - -@@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { - if (r < 0) - return r; - -- p = filename_escape(context[CONTEXT_PID]); -+ p = filename_escape(context->meta[CONTEXT_PID]); - if (!p) - return -ENOMEM; - -- t = filename_escape(context[CONTEXT_TIMESTAMP]); -+ t = filename_escape(context->meta[CONTEXT_TIMESTAMP]); - if (!t) - return -ENOMEM; - -@@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { - } - - static int save_external_coredump( -- const char *context[_CONTEXT_MAX], -+ const Context *context, - int input_fd, - char **ret_filename, - int *ret_node_fd, -@@ -334,19 +338,19 @@ static int save_external_coredump( - assert(ret_data_fd); - assert(ret_size); - -- r = parse_uid(context[CONTEXT_UID], &uid); -+ r = parse_uid(context->meta[CONTEXT_UID], &uid); - if (r < 0) - return log_error_errno(r, "Failed to parse UID: %m"); - -- r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit); -+ r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit); - if (r < 0) -- return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]); -+ return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]); - if (rlimit < page_size()) { - /* Is coredumping disabled? Then don't bother saving/processing the coredump. - * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses - * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */ - log_info("Resource limits disable core dumping for process %s (%s).", -- context[CONTEXT_PID], context[CONTEXT_COMM]); -+ context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); - return -EBADSLT; - } - -@@ -371,7 +375,7 @@ static int save_external_coredump( - - r = copy_bytes(input_fd, fd, max_size, 0); - if (r < 0) { -- log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); -+ log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); - goto fail; - } - *ret_truncated = r == 1; -@@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) { - return 1; - } - --static int change_uid_gid(const char *context[]) { -+static int change_uid_gid(const Context *context) { - uid_t uid; - gid_t gid; - int r; - -- r = parse_uid(context[CONTEXT_UID], &uid); -+ r = parse_uid(context->meta[CONTEXT_UID], &uid); - if (r < 0) - return r; - -@@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) { - uid = gid = 0; - } - } else { -- r = parse_gid(context[CONTEXT_GID], &gid); -+ r = parse_gid(context->meta[CONTEXT_GID], &gid); - if (r < 0) - return r; - } -@@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) { - return drop_privileges(uid, gid, 0); - } - --static bool is_journald_crash(const char *context[_CONTEXT_MAX]) { -+static bool is_journald_crash(const Context *context) { - assert(context); - -- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); -+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); - } - --static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) { -+static bool is_pid1_crash(const Context *context) { - assert(context); - -- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || -- streq_ptr(context[CONTEXT_PID], "1"); -+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || -+ streq_ptr(context->meta[CONTEXT_PID], "1"); - } - - #define SUBMIT_COREDUMP_FIELDS 4 - - static int submit_coredump( -- const char *context[_CONTEXT_MAX], -+ Context *context, - struct iovec *iovec, - size_t n_iovec_allocated, - size_t n_iovec, -@@ -760,11 +764,11 @@ static int submit_coredump( - if (coredump_size <= arg_process_size_max) { - _cleanup_free_ char *stacktrace = NULL; - -- r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace); -+ r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace); - if (r >= 0) -- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], -- " (", context[CONTEXT_COMM], ") of user ", -- context[CONTEXT_UID], " dumped core.", -+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], -+ " (", context->meta[CONTEXT_COMM], ") of user ", -+ context->meta[CONTEXT_UID], " dumped core.", - journald_crash ? "\nCoredump diverted to " : "", - journald_crash ? filename : "", - "\n\n", stacktrace); -@@ -779,9 +783,9 @@ static int submit_coredump( - if (!core_message) - #endif - log: -- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], -- " (", context[CONTEXT_COMM], ") of user ", -- context[CONTEXT_UID], " dumped core.", -+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], -+ " (", context->meta[CONTEXT_COMM], ") of user ", -+ context->meta[CONTEXT_UID], " dumped core.", - journald_crash && filename ? "\nCoredump diverted to " : NULL, - journald_crash && filename ? filename : NULL); - if (!core_message) -@@ -826,7 +830,7 @@ log: - return 0; - } - --static void map_context_fields(const struct iovec *iovec, const char* context[]) { -+static void map_context_fields(const struct iovec *iovec, Context *context) { - - static const char * const context_field_names[] = { - [CONTEXT_PID] = "COREDUMP_PID=", -@@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[]) - - /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the - * buffer, though not included in the iov_len count. (see below) */ -- context[i] = p; -+ context->meta[i] = p; - break; - } - } -@@ -866,7 +870,7 @@ static int process_socket(int fd) { - _cleanup_close_ int coredump_fd = -1; - struct iovec *iovec = NULL; - size_t n_iovec = 0, n_allocated = 0, i, k; -- const char *context[_CONTEXT_MAX] = {}; -+ Context context = {}; - int r; - - assert(fd >= 0); -@@ -950,7 +954,7 @@ static int process_socket(int fd) { - iovec[n_iovec].iov_len = (size_t) n; - - cmsg_close_all(&mh); -- map_context_fields(iovec + n_iovec, context); -+ map_context_fields(iovec + n_iovec, &context); - n_iovec++; - } - -@@ -960,24 +964,24 @@ static int process_socket(int fd) { - } - - /* Make sure we got all data we really need */ -- assert(context[CONTEXT_PID]); -- assert(context[CONTEXT_UID]); -- assert(context[CONTEXT_GID]); -- assert(context[CONTEXT_SIGNAL]); -- assert(context[CONTEXT_TIMESTAMP]); -- assert(context[CONTEXT_RLIMIT]); -- assert(context[CONTEXT_HOSTNAME]); -- assert(context[CONTEXT_COMM]); -+ assert(context.meta[CONTEXT_PID]); -+ assert(context.meta[CONTEXT_UID]); -+ assert(context.meta[CONTEXT_GID]); -+ assert(context.meta[CONTEXT_SIGNAL]); -+ assert(context.meta[CONTEXT_TIMESTAMP]); -+ assert(context.meta[CONTEXT_RLIMIT]); -+ assert(context.meta[CONTEXT_HOSTNAME]); -+ assert(context.meta[CONTEXT_COMM]); - assert(coredump_fd >= 0); - - /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s - * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we - * are reconstructing the original kernel context, we chop this off again, here. */ -- k = strlen(context[CONTEXT_TIMESTAMP]); -+ k = strlen(context.meta[CONTEXT_TIMESTAMP]); - if (k > 6) -- context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6); -+ context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6); - -- r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd); -+ r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd); - - finish: - for (i = 0; i < n_iovec; i++) -@@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch - } - - static int gather_pid_metadata( -- char* context[_CONTEXT_MAX], -+ Context *context, - char **comm_fallback, - struct iovec *iovec, size_t *n_iovec) { - -@@ -1077,65 +1081,69 @@ static int gather_pid_metadata( - const char *p; - int r, signo; - -- r = parse_pid(context[CONTEXT_PID], &pid); -+ r = parse_pid(context->meta[CONTEXT_PID], &pid); - if (r < 0) -- return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]); -+ return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]); - -- r = get_process_comm(pid, &context[CONTEXT_COMM]); -+ r = get_process_comm(pid, &t); - if (r < 0) { - log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m"); -- context[CONTEXT_COMM] = strv_join(comm_fallback, " "); -- if (!context[CONTEXT_COMM]) -+ context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " "); -+ if (!context->meta[CONTEXT_COMM]) - return log_oom(); -- } -+ } else -+ context->meta[CONTEXT_COMM] = t; - -- r = get_process_exe(pid, &context[CONTEXT_EXE]); -+ r = get_process_exe(pid, &t); - if (r < 0) - log_warning_errno(r, "Failed to get EXE, ignoring: %m"); -+ else -+ context->meta[CONTEXT_EXE] = t; - -- if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) { -- if (!is_journald_crash((const char**) context)) { -+ if (cg_pid_get_unit(pid, &t) >= 0) { -+ if (!is_journald_crash(context)) { - /* OK, now we know it's not the journal, hence we can make use of it now. */ - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_open(); - } - - /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */ -- if (is_pid1_crash((const char**) context)) { -+ if (is_pid1_crash(context)) { - log_notice("Due to PID 1 having crashed coredump collection will now be turned off."); - disable_coredumps(); - } - -- set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); -- } -+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]); -+ } else -+ context->meta[CONTEXT_UNIT] = t; - - if (cg_pid_get_user_unit(pid, &t) >= 0) - set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t); - - /* The next few are mandatory */ -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME])) - return log_oom(); - -- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) -+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM])) - return log_oom(); - -- if (context[CONTEXT_EXE] && -- !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) -+ if (context->meta[CONTEXT_EXE] && -+ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE])) - return log_oom(); - - if (sd_pid_get_session(pid, &t) >= 0) -@@ -1198,11 +1206,11 @@ static int gather_pid_metadata( - if (get_process_environ(pid, &t) >= 0) - set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t); - -- t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); -+ t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000"); - if (t) - iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t); - -- if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) -+ if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) - set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); - - return 0; /* we successfully acquired all metadata */ -@@ -1210,7 +1218,7 @@ static int gather_pid_metadata( - - static int process_kernel(int argc, char* argv[]) { - -- char* context[_CONTEXT_MAX] = {}; -+ Context context = {}; - struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS]; - size_t i, n_iovec, n_to_free = 0; - int r; -@@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) { - return -EINVAL; - } - -- context[CONTEXT_PID] = argv[1 + CONTEXT_PID]; -- context[CONTEXT_UID] = argv[1 + CONTEXT_UID]; -- context[CONTEXT_GID] = argv[1 + CONTEXT_GID]; -- context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; -- context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; -- context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; -- context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; -+ context.meta[CONTEXT_PID] = argv[1 + CONTEXT_PID]; -+ context.meta[CONTEXT_UID] = argv[1 + CONTEXT_UID]; -+ context.meta[CONTEXT_GID] = argv[1 + CONTEXT_GID]; -+ context.meta[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; -+ context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; -+ context.meta[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; -+ context.meta[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; - -- r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); -+ r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); - if (r < 0) - goto finish; - -@@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) { - - assert(n_iovec <= ELEMENTSOF(iovec)); - -- if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context)) -- r = submit_coredump((const char**) context, -+ if (is_journald_crash(&context) || is_pid1_crash(&context)) -+ r = submit_coredump(&context, - iovec, ELEMENTSOF(iovec), n_iovec, - STDIN_FILENO); - else -@@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) { - free(iovec[i].iov_base); - - /* Those fields are allocated by gather_pid_metadata */ -- free(context[CONTEXT_COMM]); -- free(context[CONTEXT_EXE]); -- free(context[CONTEXT_UNIT]); -+ free((char *) context.meta[CONTEXT_COMM]); -+ free((char *) context.meta[CONTEXT_EXE]); -+ free((char *) context.meta[CONTEXT_UNIT]); - - return r; - } - - static int process_backtrace(int argc, char *argv[]) { -- char *context[_CONTEXT_MAX] = {}; -+ Context context = {}; - _cleanup_free_ char *message = NULL; - _cleanup_free_ struct iovec *iovec = NULL; - size_t n_iovec, n_allocated, n_to_free = 0, i; -@@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) { - return -EINVAL; - } - -- context[CONTEXT_PID] = argv[2 + CONTEXT_PID]; -- context[CONTEXT_UID] = argv[2 + CONTEXT_UID]; -- context[CONTEXT_GID] = argv[2 + CONTEXT_GID]; -- context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; -- context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; -- context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; -- context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; -+ context.meta[CONTEXT_PID] = argv[2 + CONTEXT_PID]; -+ context.meta[CONTEXT_UID] = argv[2 + CONTEXT_UID]; -+ context.meta[CONTEXT_GID] = argv[2 + CONTEXT_GID]; -+ context.meta[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; -+ context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; -+ context.meta[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; -+ context.meta[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; - - n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL; - /* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */ -@@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) { - if (!iovec) - return log_oom(); - -- r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); -+ r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); - if (r < 0) - goto finish; - if (r > 0) { -@@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) { - if (journal_importer_eof(&importer)) { - log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter"); - -- message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], -- " (", context[CONTEXT_COMM], ")" -- " of user ", context[CONTEXT_UID], -- " failed with ", context[CONTEXT_SIGNAL]); -+ message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID], -+ " (", context.meta[CONTEXT_COMM], ")" -+ " of user ", context.meta[CONTEXT_UID], -+ " failed with ", context.meta[CONTEXT_SIGNAL]); - if (!message) { - r = log_oom(); - goto finish; -@@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) { - free(iovec[i].iov_base); - - /* Those fields are allocated by gather_pid_metadata */ -- free(context[CONTEXT_COMM]); -- free(context[CONTEXT_EXE]); -- free(context[CONTEXT_UNIT]); -+ free((char *) context.meta[CONTEXT_COMM]); -+ free((char *) context.meta[CONTEXT_EXE]); -+ free((char *) context.meta[CONTEXT_UNIT]); - - return r; - } diff --git a/SOURCES/0838-coredump-do-not-allow-user-to-access-coredumps-with-.patch b/SOURCES/0838-coredump-do-not-allow-user-to-access-coredumps-with-.patch deleted file mode 100644 index e251dd5..0000000 --- a/SOURCES/0838-coredump-do-not-allow-user-to-access-coredumps-with-.patch +++ /dev/null @@ -1,354 +0,0 @@ -From 9fa7f77c5a3d92fe03d6eec8384043555ea16dc6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Mon, 28 Nov 2022 12:12:55 +0100 -Subject: [PATCH] coredump: do not allow user to access coredumps with changed - uid/gid/capabilities - -When the user starts a program which elevates its permissions via setuid, -setgid, or capabilities set on the file, it may access additional information -which would then be visible in the coredump. We shouldn't make the the coredump -visible to the user in such cases. - -Reported-by: Matthias Gerstner - -This reads the /proc//auxv file and attaches it to the process metadata as -PROC_AUXV. Before the coredump is submitted, it is parsed and if either -at_secure was set (which the kernel will do for processes that are setuid, -setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file -is not made accessible to the user. If we can't access this data, we assume the -file should not be made accessible either. In principle we could also access -the auxv data from a note in the core file, but that is much more complex and -it seems better to use the stand-alone file that is provided by the kernel. - -Attaching auxv is both convient for this patch (because this way it's passed -between the stages along with other fields), but I think it makes sense to save -it in general. - -We use the information early in the core file to figure out if the program was -32-bit or 64-bit and its endianness. This way we don't need heuristics to guess -whether the format of the auxv structure. This test might reject some cases on -fringe architecutes. But the impact would be limited: we just won't grant the -user permissions to view the coredump file. If people report that we're missing -some cases, we can always enhance this to support more architectures. - -I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and -ppc64el, but not the whole coredump handling. - -(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03) - -Resolves: #2155519 ---- - src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 182 insertions(+), 8 deletions(-) - -diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c -index ebc56d8342..d8acd2d3a7 100644 ---- a/src/coredump/coredump.c -+++ b/src/coredump/coredump.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -88,11 +89,13 @@ enum { - CONTEXT_COMM, - CONTEXT_EXE, - CONTEXT_UNIT, -+ CONTEXT_PROC_AUXV, - _CONTEXT_MAX - }; - - typedef struct Context { - const char *meta[_CONTEXT_MAX]; -+ size_t meta_size[_CONTEXT_MAX]; - } Context; - - typedef enum CoredumpStorage { -@@ -148,8 +151,7 @@ static inline uint64_t storage_size_max(void) { - return 0; - } - --static int fix_acl(int fd, uid_t uid) { -- -+static int fix_acl(int fd, uid_t uid, bool allow_user) { - #if HAVE_ACL - _cleanup_(acl_freep) acl_t acl = NULL; - acl_entry_t entry; -@@ -157,6 +159,11 @@ static int fix_acl(int fd, uid_t uid) { - int r; - - assert(fd >= 0); -+ assert(uid_is_valid(uid)); -+ -+ /* We don't allow users to read coredumps if the uid or capabilities were changed. */ -+ if (!allow_user) -+ return 0; - - if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY) - return 0; -@@ -235,7 +242,8 @@ static int fix_permissions( - const char *filename, - const char *target, - const Context *context, -- uid_t uid) { -+ uid_t uid, -+ bool allow_user) { - - int r; - -@@ -245,7 +253,7 @@ static int fix_permissions( - - /* Ignore errors on these */ - (void) fchmod(fd, 0640); -- (void) fix_acl(fd, uid); -+ (void) fix_acl(fd, uid, allow_user); - (void) fix_xattr(fd, context); - - if (fsync(fd) < 0) -@@ -316,6 +324,154 @@ static int make_filename(const Context *context, char **ret) { - return 0; - } - -+static int parse_auxv64( -+ const uint64_t *auxv, -+ size_t size_bytes, -+ int *at_secure, -+ uid_t *uid, -+ uid_t *euid, -+ gid_t *gid, -+ gid_t *egid) { -+ -+ assert(auxv || size_bytes == 0); -+ -+ if (size_bytes % (2 * sizeof(uint64_t)) != 0) -+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes); -+ -+ size_t words = size_bytes / sizeof(uint64_t); -+ -+ /* Note that we set output variables even on error. */ -+ -+ for (size_t i = 0; i + 1 < words; i += 2) -+ switch (auxv[i]) { -+ case AT_SECURE: -+ *at_secure = auxv[i + 1] != 0; -+ break; -+ case AT_UID: -+ *uid = auxv[i + 1]; -+ break; -+ case AT_EUID: -+ *euid = auxv[i + 1]; -+ break; -+ case AT_GID: -+ *gid = auxv[i + 1]; -+ break; -+ case AT_EGID: -+ *egid = auxv[i + 1]; -+ break; -+ case AT_NULL: -+ if (auxv[i + 1] != 0) -+ goto error; -+ return 0; -+ } -+ error: -+ return log_warning_errno(-ENODATA, -+ "AT_NULL terminator not found, cannot parse auxv structure."); -+} -+ -+static int parse_auxv32( -+ const uint32_t *auxv, -+ size_t size_bytes, -+ int *at_secure, -+ uid_t *uid, -+ uid_t *euid, -+ gid_t *gid, -+ gid_t *egid) { -+ -+ assert(auxv || size_bytes == 0); -+ -+ size_t words = size_bytes / sizeof(uint32_t); -+ -+ if (size_bytes % (2 * sizeof(uint32_t)) != 0) -+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes); -+ -+ /* Note that we set output variables even on error. */ -+ -+ for (size_t i = 0; i + 1 < words; i += 2) -+ switch (auxv[i]) { -+ case AT_SECURE: -+ *at_secure = auxv[i + 1] != 0; -+ break; -+ case AT_UID: -+ *uid = auxv[i + 1]; -+ break; -+ case AT_EUID: -+ *euid = auxv[i + 1]; -+ break; -+ case AT_GID: -+ *gid = auxv[i + 1]; -+ break; -+ case AT_EGID: -+ *egid = auxv[i + 1]; -+ break; -+ case AT_NULL: -+ if (auxv[i + 1] != 0) -+ goto error; -+ return 0; -+ } -+ error: -+ return log_warning_errno(-ENODATA, -+ "AT_NULL terminator not found, cannot parse auxv structure."); -+} -+ -+static int grant_user_access(int core_fd, const Context *context) { -+ int at_secure = -1; -+ uid_t uid = UID_INVALID, euid = UID_INVALID; -+ uid_t gid = GID_INVALID, egid = GID_INVALID; -+ int r; -+ -+ assert(core_fd >= 0); -+ assert(context); -+ -+ if (!context->meta[CONTEXT_PROC_AUXV]) -+ return log_warning_errno(-ENODATA, "No auxv data, not adjusting permissions."); -+ -+ uint8_t elf[EI_NIDENT]; -+ errno = 0; -+ if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf)) -+ return log_warning_errno(errno > 0 ? -errno : -EIO, -+ "Failed to pread from coredump fd: %s", -+ errno > 0 ? STRERROR(errno) : "Unexpected EOF"); -+ -+ if (elf[EI_MAG0] != ELFMAG0 || -+ elf[EI_MAG1] != ELFMAG1 || -+ elf[EI_MAG2] != ELFMAG2 || -+ elf[EI_MAG3] != ELFMAG3 || -+ elf[EI_VERSION] != EV_CURRENT) -+ return log_info_errno(-EUCLEAN, -+ "Core file does not have ELF header, not adjusting permissions."); -+ if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) || -+ !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB)) -+ return log_info_errno(-EUCLEAN, -+ "Core file has strange ELF class, not adjusting permissions."); -+ -+ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN)) -+ return log_info_errno(-EUCLEAN, -+ "Core file has non-native endianness, not adjusting permissions."); -+ -+ if (elf[EI_CLASS] == ELFCLASS64) -+ r = parse_auxv64((const uint64_t*) context->meta[CONTEXT_PROC_AUXV], -+ context->meta_size[CONTEXT_PROC_AUXV], -+ &at_secure, &uid, &euid, &gid, &egid); -+ else -+ r = parse_auxv32((const uint32_t*) context->meta[CONTEXT_PROC_AUXV], -+ context->meta_size[CONTEXT_PROC_AUXV], -+ &at_secure, &uid, &euid, &gid, &egid); -+ if (r < 0) -+ return r; -+ -+ /* We allow access if we got all the data and at_secure is not set and -+ * the uid/gid matches euid/egid. */ -+ bool ret = -+ at_secure == 0 && -+ uid != UID_INVALID && euid != UID_INVALID && uid == euid && -+ gid != GID_INVALID && egid != GID_INVALID && gid == egid; -+ log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)", -+ ret ? "permit" : "restrict", -+ uid, euid, gid, egid, yes_no(at_secure)); -+ return ret; -+} -+ - static int save_external_coredump( - const Context *context, - int input_fd, -@@ -395,6 +551,8 @@ static int save_external_coredump( - goto fail; - } - -+ bool allow_user = grant_user_access(fd, context) > 0; -+ - #if HAVE_XZ || HAVE_LZ4 - /* If we will remove the coredump anyway, do not compress. */ - if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) { -@@ -420,7 +578,7 @@ static int save_external_coredump( - goto fail_compressed; - } - -- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid); -+ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user); - if (r < 0) - goto fail_compressed; - -@@ -443,7 +601,7 @@ static int save_external_coredump( - uncompressed: - #endif - -- r = fix_permissions(fd, tmp, fn, context, uid); -+ r = fix_permissions(fd, tmp, fn, context, uid, allow_user); - if (r < 0) - goto fail; - -@@ -842,6 +1000,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) { - [CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=", - [CONTEXT_COMM] = "COREDUMP_COMM=", - [CONTEXT_EXE] = "COREDUMP_EXE=", -+ [CONTEXT_PROC_AUXV] = "COREDUMP_PROC_AUXV=", - }; - - unsigned i; -@@ -862,6 +1021,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) { - /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the - * buffer, though not included in the iov_len count. (see below) */ - context->meta[i] = p; -+ context->meta_size[i] = iovec->iov_len - strlen(context_field_names[i]); - break; - } - } -@@ -1070,7 +1230,7 @@ static int gather_pid_metadata( - char **comm_fallback, - struct iovec *iovec, size_t *n_iovec) { - -- /* We need 27 empty slots in iovec! -+ /* We need 28 empty slots in iovec! - * - * Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid, - * with the first n_iovec fields initialized.) */ -@@ -1078,6 +1238,7 @@ static int gather_pid_metadata( - uid_t owner_uid; - pid_t pid; - char *t; -+ size_t size; - const char *p; - int r, signo; - -@@ -1187,6 +1348,19 @@ static int gather_pid_metadata( - if (read_full_file(p, &t, NULL) >=0) - set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t); - -+ /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */ -+ p = procfs_file_alloca(pid, "auxv"); -+ if (read_full_file(p, &t, &size) >= 0) { -+ char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1); -+ if (buf) { -+ /* Add a dummy terminator to make save_context() happy. */ -+ *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0'; -+ iovec[(*n_iovec)++] = IOVEC_MAKE(buf, size + strlen("COREDUMP_PROC_AUXV=")); -+ } -+ -+ free(t); -+ } -+ - if (get_process_cwd(pid, &t) >= 0) - set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t); - -@@ -1219,7 +1393,7 @@ static int gather_pid_metadata( - static int process_kernel(int argc, char* argv[]) { - - Context context = {}; -- struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS]; -+ struct iovec iovec[30 + SUBMIT_COREDUMP_FIELDS]; - size_t i, n_iovec, n_to_free = 0; - int r; - diff --git a/SOURCES/0838-time-util-fix-buffer-over-run.patch b/SOURCES/0838-time-util-fix-buffer-over-run.patch new file mode 100644 index 0000000..c63ae79 --- /dev/null +++ b/SOURCES/0838-time-util-fix-buffer-over-run.patch @@ -0,0 +1,44 @@ +From a521f942d5c304bca7c61bacb3c79e565853718e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 7 Jul 2022 18:27:02 +0900 +Subject: [PATCH] time-util: fix buffer-over-run + +Fixes #23928. + +(cherry picked from commit 9102c625a673a3246d7e73d8737f3494446bad4e) + +Resolves: #2139391 +--- + src/basic/time-util.c | 2 +- + src/test/test-time-util.c | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/basic/time-util.c b/src/basic/time-util.c +index c36e462193..d46d884be5 100644 +--- a/src/basic/time-util.c ++++ b/src/basic/time-util.c +@@ -515,7 +515,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { + t = b; + } + +- n = MIN((size_t) k, l); ++ n = MIN((size_t) k, l-1); + + l -= n; + p += n; +diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c +index 354a01dd1a..6ebde4153c 100644 +--- a/src/test/test-time-util.c ++++ b/src/test/test-time-util.c +@@ -187,6 +187,11 @@ static void test_format_timespan(usec_t accuracy) { + test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); + test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); + test_format_timespan_one(USEC_INFINITY, accuracy); ++ ++ /* See issue #23928. */ ++ _cleanup_free_ char *buf; ++ assert_se(buf = new(char, 5)); ++ assert_se(buf == format_timespan(buf, 5, 100005, 1000)); + } + + static void test_timezone_is_valid(void) { diff --git a/SOURCES/0839-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch b/SOURCES/0839-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch new file mode 100644 index 0000000..c7f889f --- /dev/null +++ b/SOURCES/0839-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch @@ -0,0 +1,32 @@ +From 2fe9fb3e844d7991105c40d4363eed9069a6837d Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 18 Nov 2022 16:16:36 +0100 +Subject: [PATCH] basic: recognize pdfs filesystem as a network filesystem + +Fujitsu advises their users to always use _netdev mount option with pdfs +mounts. Hence it makes sense to simply consider pdfs mounts as network +filesystem mounts. + +https://software.fujitsu.com/jp/manual/manualfiles/m130027/j2ul1563/02enz200/j1563-02-06-02-02.html + +RHEL-only + +Resolves: #2094661 +--- + src/basic/mount-util.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index e7f9e514c2..983566b46b 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -634,7 +634,8 @@ bool fstype_is_network(const char *fstype) { + "glusterfs", + "pvfs2", /* OrangeFS */ + "ocfs2", +- "lustre"); ++ "lustre", ++ "pdfs"); + } + + bool fstype_is_api_vfs(const char *fstype) { diff --git a/SOURCES/0840-core-move-reset_arguments-to-the-end-of-main-s-finis.patch b/SOURCES/0840-core-move-reset_arguments-to-the-end-of-main-s-finis.patch new file mode 100644 index 0000000..a2696f8 --- /dev/null +++ b/SOURCES/0840-core-move-reset_arguments-to-the-end-of-main-s-finis.patch @@ -0,0 +1,49 @@ +From 4bb425eea9f3037a583a23d99f15aa71562f2481 Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Thu, 17 Sep 2020 01:49:17 -0700 +Subject: [PATCH] core: move reset_arguments() to the end of main's finish + +Fixes #16991 + +fb39af4ce42d7ef9af63009f271f404038703704 replaced `free_arguments()` with +`reset_arguments()`, which frees arg_* variables as before, but also resets all +of them to the default values. `reset_arguments()` was positioned +in such a way that it overrode some arg_* values still in use at shutdown. + +To avoid further unintentional resets, I moved `reset_arguments()` +right before the return, when nothing else will be using the arg_* variables. + +(cherry picked from commit 7d9eea2bd3d4f83668c7a78754d201b226acbf1e) + +Resolves: #2127131 +--- + src/core/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/main.c b/src/core/main.c +index bfd4c531a7..cfa6fec930 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2631,7 +2631,6 @@ finish: + m = manager_free(m); + } + +- reset_arguments(); + mac_selinux_finish(); + + if (reexecute) +@@ -2656,6 +2655,7 @@ finish: + * in become_shutdown() so normally we cannot free them yet. */ + watchdog_free_device(); + arg_watchdog_device = mfree(arg_watchdog_device); ++ reset_arguments(); + return retval; + } + #endif +@@ -2677,5 +2677,6 @@ finish: + freeze_or_reboot(); + } + ++ reset_arguments(); + return retval; + } diff --git a/SOURCES/0841-manager-move-inc.-of-n_reloading-into-a-function.patch b/SOURCES/0841-manager-move-inc.-of-n_reloading-into-a-function.patch new file mode 100644 index 0000000..799bd04 --- /dev/null +++ b/SOURCES/0841-manager-move-inc.-of-n_reloading-into-a-function.patch @@ -0,0 +1,91 @@ +From 708c394b7ca35fe2328fa0760696ff95caab8ff8 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Tue, 29 Nov 2022 16:15:47 +0100 +Subject: [PATCH] manager: move inc. of n_reloading into a function + +[dtardon: This is inspired by commit d147e2b66b4d6b71db1bc59b62286b2eb9c3d29f , +but it does just the minimal change needed for the next commit.] + +Related: #2136869 +--- + src/core/main.c | 2 +- + src/core/manager.c | 12 ++++++++---- + src/core/manager.h | 1 + + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index cfa6fec930..c3e2ce8956 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1131,7 +1131,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching + return log_error_errno(r, "Failed to create serialization file: %m"); + + /* Make sure nothing is really destructed when we shut down */ +- m->n_reloading++; ++ manager_reloading_start(m); + bus_manager_send_reloading(m, true); + + fds = fdset_new(); +diff --git a/src/core/manager.c b/src/core/manager.c +index f4611e6f8f..f923cbce37 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1578,6 +1578,10 @@ static void manager_preset_all(Manager *m) { + log_info("Populated /etc with preset unit settings."); + } + ++void manager_reloading_start(Manager *m) { ++ m->n_reloading++; ++} ++ + int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + int r; + +@@ -1609,7 +1613,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + * this is already known, so we increase the counter here + * already */ + if (serialization) +- m->n_reloading++; ++ manager_reloading_start(m); + + /* First, enumerate what we can from all config files */ + dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START); +@@ -3093,7 +3097,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { + assert(f); + assert(fds); + +- m->n_reloading++; ++ manager_reloading_start(m); + + fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id); + fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs); +@@ -3211,7 +3215,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + + log_debug("Deserializing state..."); + +- m->n_reloading++; ++ manager_reloading_start(m); + + for (;;) { + _cleanup_free_ char *line = NULL; +@@ -3455,7 +3459,7 @@ int manager_reload(Manager *m) { + if (r < 0) + return r; + +- m->n_reloading++; ++ manager_reloading_start(m); + bus_manager_send_reloading(m, true); + + fds = fdset_new(); +diff --git a/src/core/manager.h b/src/core/manager.h +index 3f2cfc5e2e..adbbb518cb 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -386,6 +386,7 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **m); + Manager* manager_free(Manager *m); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); + ++void manager_reloading_start(Manager *m); + int manager_startup(Manager *m, FILE *serialization, FDSet *fds); + + Job *manager_get_job(Manager *m, uint32_t id); diff --git a/SOURCES/0842-core-Add-new-DBUS-properties-UnitsReloadStartTimesta.patch b/SOURCES/0842-core-Add-new-DBUS-properties-UnitsReloadStartTimesta.patch new file mode 100644 index 0000000..dd27bfa --- /dev/null +++ b/SOURCES/0842-core-Add-new-DBUS-properties-UnitsReloadStartTimesta.patch @@ -0,0 +1,59 @@ +From 22eb8fbdab14e5b1b11a4d84c83bef97317e1d2a Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Thu, 2 Sep 2021 16:37:13 +0200 +Subject: [PATCH] core: Add new DBUS properties UnitsReloadStartTimestamp and + UnitsLoadTimestampMontonic + +(cherry picked from commit 49fbe940a429c3d8807bacdfce03af834275257c) + +Related: #2136869 +--- + src/core/dbus-manager.c | 1 + + src/core/manager.c | 2 ++ + src/core/manager.h | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 5b1ed3646e..8a41eda4a6 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2486,6 +2486,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST), ++ BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0), + SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0), + SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0), +diff --git a/src/core/manager.c b/src/core/manager.c +index f923cbce37..8aa398cac8 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1580,6 +1580,7 @@ static void manager_preset_all(Manager *m) { + + void manager_reloading_start(Manager *m) { + m->n_reloading++; ++ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD); + } + + int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { +@@ -4622,6 +4623,7 @@ static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = { + [MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish", + [MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start", + [MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish", ++ [MANAGER_TIMESTAMP_UNITS_LOAD] = "units-load", + }; + + DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp); +diff --git a/src/core/manager.h b/src/core/manager.h +index adbbb518cb..98d381bc5b 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -67,6 +67,7 @@ typedef enum ManagerTimestamp { + MANAGER_TIMESTAMP_GENERATORS_FINISH, + MANAGER_TIMESTAMP_UNITS_LOAD_START, + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH, ++ MANAGER_TIMESTAMP_UNITS_LOAD, + _MANAGER_TIMESTAMP_MAX, + _MANAGER_TIMESTAMP_INVALID = -1, + } ManagerTimestamp; diff --git a/SOURCES/0843-core-Indicate-the-time-when-the-manager-started-load.patch b/SOURCES/0843-core-Indicate-the-time-when-the-manager-started-load.patch new file mode 100644 index 0000000..4a05d20 --- /dev/null +++ b/SOURCES/0843-core-Indicate-the-time-when-the-manager-started-load.patch @@ -0,0 +1,29 @@ +From f2de5398b0a1ebb3e6390506368c11329b843524 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Thu, 2 Sep 2021 16:50:50 +0200 +Subject: [PATCH] core: Indicate the time when the manager started loading + units the last time + +(cherry picked from commit 15b9243c0d7f6d1531fa65dbc01bd11e8e6c12ca) + +Resolves: #2136869 +--- + src/core/manager.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 8aa398cac8..a9cd51b624 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3554,6 +3554,11 @@ int manager_reload(Manager *m) { + /* Let's finally catch up with any changes that took place while we were reloading/reexecing */ + manager_catchup(m); + ++ /* Create a file which will indicate when the manager started loading units the last time. */ ++ (void) touch_file("/run/systemd/systemd-units-load", false, ++ m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME), ++ UID_INVALID, GID_INVALID, 0444); ++ + /* Sync current state of bus names with our set of listening units */ + q = manager_enqueue_sync_bus_names(m); + if (q < 0 && r >= 0) diff --git a/SOURCES/0844-core-do-not-touch-run-systemd-systemd-units-load-fro.patch b/SOURCES/0844-core-do-not-touch-run-systemd-systemd-units-load-fro.patch new file mode 100644 index 0000000..db62e35 --- /dev/null +++ b/SOURCES/0844-core-do-not-touch-run-systemd-systemd-units-load-fro.patch @@ -0,0 +1,34 @@ +From 3c2d2345814935cea8525e802e764fb2949eb3df Mon Sep 17 00:00:00 2001 +From: Luca Boccassi +Date: Mon, 27 Dec 2021 18:22:43 +0000 +Subject: [PATCH] core: do not touch /run/systemd/systemd-units-load from user + session instances + +Follow-up for: https://github.com/systemd/systemd/commit/15b9243c0d7f6d1531fa65dbc01bd11e8e6c12ca +Fixes: https://github.com/systemd/systemd/issues/21911 + +(cherry picked from commit 4b3ad81bfafcd97acb06db463495e348d159d8e6) + +Related: #2136869 +--- + src/core/manager.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index a9cd51b624..e083596e58 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3555,9 +3555,10 @@ int manager_reload(Manager *m) { + manager_catchup(m); + + /* Create a file which will indicate when the manager started loading units the last time. */ +- (void) touch_file("/run/systemd/systemd-units-load", false, +- m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME), +- UID_INVALID, GID_INVALID, 0444); ++ if (MANAGER_IS_SYSTEM(m)) ++ (void) touch_file("/run/systemd/systemd-units-load", false, ++ m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME), ++ UID_INVALID, GID_INVALID, 0444); + + /* Sync current state of bus names with our set of listening units */ + q = manager_enqueue_sync_bus_names(m); diff --git a/SOURCES/0845-sysctl-downgrade-message-when-we-have-no-permission.patch b/SOURCES/0845-sysctl-downgrade-message-when-we-have-no-permission.patch new file mode 100644 index 0000000..9e3d1e8 --- /dev/null +++ b/SOURCES/0845-sysctl-downgrade-message-when-we-have-no-permission.patch @@ -0,0 +1,49 @@ +From ffe4233155085b479c69abe844a34de212b8e5e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 16 Jan 2020 14:45:28 +0100 +Subject: [PATCH] sysctl: downgrade message when we have no permission + +We need to run sysctl also in containers, because the network +subtree is namespaces and may legitimately be writable. But logging +all "errors" at notice level creates unwanted noise. + +Also downgrade message about missing sysctls to log_info. This might also be +relatively common when configuration is targeted at different kernel +versions. With log_debug it'll still end up in the logs, but isn't really worth +of "notice" most of the time. + +https://bugzilla.redhat.com/show_bug.cgi?id=1609806 +(cherry picked from commit 32458cc9687c1b60ff0f22c0e71da93ce78b1534) + +Resolves: #2158160 +--- + src/sysctl/sysctl.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 4c85d6887f..dc14e1aaf1 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -82,13 +82,15 @@ static int apply_all(OrderedHashmap *sysctl_options) { + k = sysctl_write(option->key, option->value); + if (k < 0) { + /* If the sysctl is not available in the kernel or we are running with reduced +- * privileges and cannot write it, then log about the issue at LOG_NOTICE level, and +- * proceed without failing. (EROFS is treated as a permission problem here, since +- * that's how container managers usually protected their sysctls.) In all other cases +- * log an error and make the tool fail. */ +- +- if (IN_SET(k, -EPERM, -EACCES, -EROFS, -ENOENT) || option->ignore_failure) +- log_notice_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key); ++ * privileges and cannot write it, then log about the issue, and proceed without ++ * failing. (EROFS is treated as a permission problem here, since that's how ++ * container managers usually protected their sysctls.) In all other cases log an ++ * error and make the tool fail. */ ++ ++ if (option->ignore_failure || k == -EROFS || ERRNO_IS_PRIVILEGE(k)) ++ log_debug_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key); ++ else if (k == -ENOENT) ++ log_info_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key); + else { + log_error_errno(k, "Couldn't write '%s' to '%s': %m", option->value, option->key); + if (r == 0) diff --git a/SOURCES/0846-core-respect-SELinuxContext-for-socket-creation.patch b/SOURCES/0846-core-respect-SELinuxContext-for-socket-creation.patch new file mode 100644 index 0000000..dbdd058 --- /dev/null +++ b/SOURCES/0846-core-respect-SELinuxContext-for-socket-creation.patch @@ -0,0 +1,53 @@ +From 1f408c8d9739b1038012eeec7bf0f918c8095bc4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 23 Sep 2022 19:00:22 +0200 +Subject: [PATCH] core: respect SELinuxContext= for socket creation + +On socket creation respect the SELinuxContext= setting of the associated +service, such that the initial created socket has the same label as the +future process accepting the connection (since w.r.t SELinux sockets +normally have the same label as the owning process). + +Triggered by #24702 + +(cherry picked from commit 599b384924bbef9f8f7fa5700c6fa35a404d9a98) + +Related: #2136738 +--- + src/core/socket.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/core/socket.c b/src/core/socket.c +index 9d47ca2616..d1ca0a07c5 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -1427,6 +1427,7 @@ fail: + static int socket_determine_selinux_label(Socket *s, char **ret) { + Service *service; + ExecCommand *c; ++ const char *exec_context; + _cleanup_free_ char *path = NULL; + int r; + +@@ -1448,8 +1449,20 @@ static int socket_determine_selinux_label(Socket *s, char **ret) { + + if (!UNIT_ISSET(s->service)) + goto no_label; +- + service = SERVICE(UNIT_DEREF(s->service)); ++ ++ exec_context = service->exec_context.selinux_context; ++ if (exec_context) { ++ char *con; ++ ++ con = strdup(exec_context); ++ if (!con) ++ return -ENOMEM; ++ ++ *ret = TAKE_PTR(con); ++ return 0; ++ } ++ + c = service->exec_command[SERVICE_EXEC_START]; + if (!c) + goto no_label; diff --git a/SOURCES/0847-manager-use-target-process-context-to-set-socket-con.patch b/SOURCES/0847-manager-use-target-process-context-to-set-socket-con.patch new file mode 100644 index 0000000..d10bdca --- /dev/null +++ b/SOURCES/0847-manager-use-target-process-context-to-set-socket-con.patch @@ -0,0 +1,128 @@ +From 3f90090e70a5fa81bced17792fe08d9c46324da9 Mon Sep 17 00:00:00 2001 +From: "Ted X. Toth" +Date: Thu, 13 Oct 2022 12:58:26 -0700 +Subject: [PATCH] manager: use target process context to set socket context + +Use target process context to set socket context when using SELinuxContextFromNet +not systemd's context. Currently when using the SELinuxContextFromNet option for +a socket activated services, systemd calls getcon_raw which returns init_t and +uses the resulting context to compute the context to be passed to the +setsockcreatecon call. A socket of type init_t is created and listened on and +this means that SELinux policy cannot be written to control which processes +(SELinux types) can connect to the socket since the ref policy allows all +'types' to connect to sockets of the type init_t. When security accessors see +that any process can connect to a socket this raises serious concerns. I have +spoken with SELinux contributors in person and on the mailing list and the +consensus is that the best solution is to use the target executables context +when computing the sockets context in all cases. + +[zjs review/comment: + +This removes the branch that was added in 16115b0a7b7cdf08fb38084d857d572d8a9088dc. +16115b0a7b7cdf08fb38084d857d572d8a9088dc did two things: it had the branch here +in 'socket_determine_selinux_label()' and a code in 'exec_child()' to call +'label_get_child_mls_label(socket_fd, command->path, &label)'. + +Before this patch, the flow was: +''' +mac_selinux_get_child_mls_label: + peercon = getpeercon_raw(socket_fd); + if (!exec_label) + exec_label = getfilecon_raw(exe); + +socket_open_fds: + if (params->selinux_context_net) # + label = mac_selinux_get_our_label(); # this part is removed + else # + label = mac_selinux_get_create_label_from_exe(path); + socket_address_listen_in_cgroup(s, &p->address, label); + +exec_child(): + exec_context = mac_selinux_get_child_mls_label(fd, executable, context->selinux_context); + setexeccon(exec_context); +''' +] + +(cherry picked from commit 29dbc62d74f7b7881dc3136e68e03a03ea055b36) + +Resolves: #2136738 +--- + src/core/socket.c | 58 ++++++++++++++++++++--------------------------- + 1 file changed, 24 insertions(+), 34 deletions(-) + +diff --git a/src/core/socket.c b/src/core/socket.c +index d1ca0a07c5..8aa5463b25 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -1434,47 +1434,37 @@ static int socket_determine_selinux_label(Socket *s, char **ret) { + assert(s); + assert(ret); + +- if (s->selinux_context_from_net) { +- /* If this is requested, get label from the network label */ +- +- r = mac_selinux_get_our_label(ret); +- if (r == -EOPNOTSUPP) +- goto no_label; +- +- } else { +- /* Otherwise, get it from the executable we are about to start */ +- r = socket_instantiate_service(s); +- if (r < 0) +- return r; ++ r = socket_instantiate_service(s); ++ if (r < 0) ++ return r; + +- if (!UNIT_ISSET(s->service)) +- goto no_label; +- service = SERVICE(UNIT_DEREF(s->service)); ++ if (!UNIT_ISSET(s->service)) ++ goto no_label; ++ service = SERVICE(UNIT_DEREF(s->service)); + +- exec_context = service->exec_context.selinux_context; +- if (exec_context) { +- char *con; ++ exec_context = service->exec_context.selinux_context; ++ if (exec_context) { ++ char *con; + +- con = strdup(exec_context); +- if (!con) +- return -ENOMEM; ++ con = strdup(exec_context); ++ if (!con) ++ return -ENOMEM; + +- *ret = TAKE_PTR(con); +- return 0; +- } ++ *ret = TAKE_PTR(con); ++ return 0; ++ } + +- c = service->exec_command[SERVICE_EXEC_START]; +- if (!c) +- goto no_label; ++ c = service->exec_command[SERVICE_EXEC_START]; ++ if (!c) ++ goto no_label; + +- r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path); +- if (r < 0) +- goto no_label; ++ r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path); ++ if (r < 0) ++ goto no_label; + +- r = mac_selinux_get_create_label_from_exe(path, ret); +- if (IN_SET(r, -EPERM, -EOPNOTSUPP)) +- goto no_label; +- } ++ r = mac_selinux_get_create_label_from_exe(path, ret); ++ if (IN_SET(r, -EPERM, -EOPNOTSUPP)) ++ goto no_label; + + return r; + diff --git a/SOURCES/0848-virt-detect-Amazon-EC2-Nitro-instance.patch b/SOURCES/0848-virt-detect-Amazon-EC2-Nitro-instance.patch new file mode 100644 index 0000000..fc3d0bd --- /dev/null +++ b/SOURCES/0848-virt-detect-Amazon-EC2-Nitro-instance.patch @@ -0,0 +1,142 @@ +From 6ffd3de2ccc5901974f292c9694829e25441060d Mon Sep 17 00:00:00 2001 +From: Bertrand Jacquin +Date: Sun, 11 Oct 2020 21:25:00 +0100 +Subject: [PATCH] virt: detect Amazon EC2 Nitro instance + +Amazon EC2 Nitro hypervisor is technically based on KVM[1], which +systemd-detect-virt identify propely from CPUID. However the lack of +CPUID on aarch64 (A1, T4 instance type) prevents a correct +identification, impacting hostnamectl and systemd-random-seed. Instead +it's possible to identify virtualization from DMI vendor ID. + +Prior to this commit: + # hostnamectl + Static hostname: n/a + Transient hostname: ip-10-97-8-12 + Icon name: computer + Machine ID: 8e3772fbcfa3dd6f330a12ff5df5a63b + Boot ID: b7b7e2fe0079448db664839df59f9817 + Operating System: Gentoo/Linux + Kernel: Linux 5.4.69-longterm + Architecture: arm64 + +After this commit: + # hostnamectl + Static hostname: n/a + Transient hostname: ip-10-97-8-12 + Icon name: computer-vm + Chassis: vm + Machine ID: 8e3772fbcfa3dd6f330a12ff5df5a63b + Boot ID: bd04da57084e41078f20541101867113 + Virtualization: amazon + Operating System: Gentoo/Linux + Kernel: Linux 5.4.69-longterm + Architecture: arm64 + +[1] https://aws.amazon.com/ec2/faqs/ + +(cherry picked from commit b6eca3731dd92b009b182f188936e1c2544574da) + +Resolves: #2117948 +--- + man/systemd-detect-virt.xml | 7 ++++++- + man/systemd.unit.xml | 1 + + src/basic/virt.c | 8 +++++--- + src/basic/virt.h | 1 + + src/test/test-condition.c | 1 + + 5 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml +index 6beb2c2aa1..61c210e24d 100644 +--- a/man/systemd-detect-virt.xml ++++ b/man/systemd-detect-virt.xml +@@ -72,7 +72,12 @@ + + + kvm +- Linux KVM kernel virtual machine, with whatever software, except Oracle Virtualbox ++ Linux KVM kernel virtual machine, in combination with QEMU. Not used for other virtualizers using the KVM interfaces, such as Oracle VirtualBox or Amazon EC2 Nitro, see below. ++ ++ ++ ++ amazon ++ Amazon EC2 Nitro using Linux KVM + + + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 6f213ccd56..5207a5bb3c 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1068,6 +1068,7 @@ + virtualization solution, or one of + qemu, + kvm, ++ amazon, + zvm, + vmware, + microsoft, +diff --git a/src/basic/virt.c b/src/basic/virt.c +index 8d862b6d67..78c68d66e0 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -147,6 +147,7 @@ static int detect_vm_dmi(void) { + int id; + } dmi_vendor_table[] = { + { "KVM", VIRTUALIZATION_KVM }, ++ { "Amazon EC2", VIRTUALIZATION_AMAZON }, + { "QEMU", VIRTUALIZATION_QEMU }, + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + { "VMware", VIRTUALIZATION_VMWARE }, +@@ -339,8 +340,8 @@ int detect_vm(void) { + + /* We have to use the correct order here: + * +- * → First, try to detect Oracle Virtualbox, even if it uses KVM, as well as Xen even if it cloaks as Microsoft +- * Hyper-V. ++ * → First, try to detect Oracle Virtualbox and Amazon EC2 Nitro, even if they use KVM, as well as Xen even if ++ * it cloaks as Microsoft Hyper-V. + * + * → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is + * overwritten. +@@ -348,7 +349,7 @@ int detect_vm(void) { + * → Third, try to detect from DMI. */ + + dmi = detect_vm_dmi(); +- if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN)) { ++ if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN, VIRTUALIZATION_AMAZON)) { + r = dmi; + goto finish; + } +@@ -631,6 +632,7 @@ int running_in_chroot(void) { + static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { + [VIRTUALIZATION_NONE] = "none", + [VIRTUALIZATION_KVM] = "kvm", ++ [VIRTUALIZATION_AMAZON] = "amazon", + [VIRTUALIZATION_QEMU] = "qemu", + [VIRTUALIZATION_BOCHS] = "bochs", + [VIRTUALIZATION_XEN] = "xen", +diff --git a/src/basic/virt.h b/src/basic/virt.h +index 640b3ed779..ed4ff063e0 100644 +--- a/src/basic/virt.h ++++ b/src/basic/virt.h +@@ -10,6 +10,7 @@ enum { + + VIRTUALIZATION_VM_FIRST, + VIRTUALIZATION_KVM = VIRTUALIZATION_VM_FIRST, ++ VIRTUALIZATION_AMAZON, + VIRTUALIZATION_QEMU, + VIRTUALIZATION_BOCHS, + VIRTUALIZATION_XEN, +diff --git a/src/test/test-condition.c b/src/test/test-condition.c +index 24395dafc6..29ea63c4ff 100644 +--- a/src/test/test-condition.c ++++ b/src/test/test-condition.c +@@ -510,6 +510,7 @@ static void test_condition_test_virtualization(void) { + + NULSTR_FOREACH(virt, + "kvm\0" ++ "amazon\0" + "qemu\0" + "bochs\0" + "xen\0" diff --git a/SOURCES/0849-machine-id-setup-generate-machine-id-from-DMI-produc.patch b/SOURCES/0849-machine-id-setup-generate-machine-id-from-DMI-produc.patch new file mode 100644 index 0000000..12f1b77 --- /dev/null +++ b/SOURCES/0849-machine-id-setup-generate-machine-id-from-DMI-produc.patch @@ -0,0 +1,37 @@ +From e320f72150829228f10ec24f3fba34d5377c5120 Mon Sep 17 00:00:00 2001 +From: Bertrand Jacquin +Date: Sun, 11 Oct 2020 22:25:56 +0100 +Subject: [PATCH] machine-id-setup: generate machine-id from DMI product ID on + Amazon EC2 + +Amazon EC2 Nitro hypervisor is technically based on KVM[1]. + +[1] https://aws.amazon.com/ec2/faqs/ + +(cherry picked from commit 382a46d129899ca9027b07c325102cab173dd563) + +Related: #2117948 +--- + src/core/machine-id-setup.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c +index 11528f83c4..fe2abc4e68 100644 +--- a/src/core/machine-id-setup.c ++++ b/src/core/machine-id-setup.c +@@ -57,11 +57,11 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) { + return 0; + } + +- } else if (detect_vm() == VIRTUALIZATION_KVM) { ++ } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU)) { + +- /* If we are not running in a container, see if we are +- * running in qemu/kvm and a machine ID was passed in +- * via -uuid on the qemu/kvm command line */ ++ /* If we are not running in a container, see if we are running in a VM that provides ++ * a system UUID via the SMBIOS/DMI interfaces. Such environments include QEMU/KVM ++ * with the -uuid on the qemu command line or the Amazon EC2 Nitro hypervisor. */ + + if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) { + log_info("Initializing machine ID from KVM UUID."); diff --git a/SOURCES/0850-virt-use-string-table-to-detect-VM-or-container.patch b/SOURCES/0850-virt-use-string-table-to-detect-VM-or-container.patch new file mode 100644 index 0000000..f0990a6 --- /dev/null +++ b/SOURCES/0850-virt-use-string-table-to-detect-VM-or-container.patch @@ -0,0 +1,134 @@ +From efa2cdb699df3e5d5d7180e50f3ebfff74788c5c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 7 Jan 2020 11:49:39 +0900 +Subject: [PATCH] virt: use string table to detect VM or container + +(cherry picked from commit 735ea55f5cd87a82757a8911edd80fba799b46ee) + +Related: #2117948 +--- + src/basic/virt.c | 73 ++++++++++++++++++++++-------------------------- + 1 file changed, 33 insertions(+), 40 deletions(-) + +diff --git a/src/basic/virt.c b/src/basic/virt.c +index 78c68d66e0..6e4c702051 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -22,27 +22,26 @@ + #include "string-util.h" + #include "virt.h" + ++static const char *const vm_table[_VIRTUALIZATION_MAX] = { ++ [VIRTUALIZATION_XEN] = "XenVMMXenVMM", ++ [VIRTUALIZATION_KVM] = "KVMKVMKVM", ++ [VIRTUALIZATION_QEMU] = "TCGTCGTCGTCG", ++ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ ++ [VIRTUALIZATION_VMWARE] = "VMwareVMware", ++ /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */ ++ [VIRTUALIZATION_MICROSOFT] = "Microsoft Hv", ++ /* https://wiki.freebsd.org/bhyve */ ++ [VIRTUALIZATION_BHYVE] = "bhyve bhyve ", ++ [VIRTUALIZATION_QNX] = "QNXQVMBSQG", ++}; ++ ++DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(vm, int); ++ + static int detect_vm_cpuid(void) { + + /* CPUID is an x86 specific interface. */ + #if defined(__i386__) || defined(__x86_64__) + +- static const struct { +- const char *cpuid; +- int id; +- } cpuid_vendor_table[] = { +- { "XenVMMXenVMM", VIRTUALIZATION_XEN }, +- { "KVMKVMKVM", VIRTUALIZATION_KVM }, +- { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU }, +- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ +- { "VMwareVMware", VIRTUALIZATION_VMWARE }, +- /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */ +- { "Microsoft Hv", VIRTUALIZATION_MICROSOFT }, +- /* https://wiki.freebsd.org/bhyve */ +- { "bhyve bhyve ", VIRTUALIZATION_BHYVE }, +- { "QNXQVMBSQG", VIRTUALIZATION_QNX }, +- }; +- + uint32_t eax, ebx, ecx, edx; + bool hypervisor; + +@@ -59,7 +58,7 @@ static int detect_vm_cpuid(void) { + uint32_t sig32[3]; + char text[13]; + } sig = {}; +- unsigned j; ++ int v; + + /* There is a hypervisor, see what it is */ + __cpuid(0x40000000U, eax, ebx, ecx, edx); +@@ -70,11 +69,11 @@ static int detect_vm_cpuid(void) { + + log_debug("Virtualization found, CPUID=%s", sig.text); + +- for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++) +- if (streq(sig.text, cpuid_vendor_table[j].cpuid)) +- return cpuid_vendor_table[j].id; ++ v = vm_from_string(sig.text); ++ if (v < 0) ++ return VIRTUALIZATION_VM_OTHER; + +- return VIRTUALIZATION_VM_OTHER; ++ return v; + } + #endif + log_debug("No virtualization found in CPUID"); +@@ -434,22 +433,20 @@ finish: + return r; + } + +-int detect_container(void) { +- static const struct { +- const char *value; +- int id; +- } value_table[] = { +- { "lxc", VIRTUALIZATION_LXC }, +- { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT }, +- { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN }, +- { "docker", VIRTUALIZATION_DOCKER }, +- { "rkt", VIRTUALIZATION_RKT }, +- }; ++static const char *const container_table[_VIRTUALIZATION_MAX] = { ++ [VIRTUALIZATION_LXC] = "lxc", ++ [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt", ++ [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn", ++ [VIRTUALIZATION_DOCKER] = "docker", ++ [VIRTUALIZATION_RKT] = "rkt", ++}; ++ ++DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int); + ++int detect_container(void) { + static thread_local int cached_found = _VIRTUALIZATION_INVALID; + _cleanup_free_ char *m = NULL; + const char *e = NULL; +- unsigned j; + int r; + + if (cached_found >= 0) +@@ -522,13 +519,9 @@ int detect_container(void) { + goto finish; + + translate_name: +- for (j = 0; j < ELEMENTSOF(value_table); j++) +- if (streq(e, value_table[j].value)) { +- r = value_table[j].id; +- goto finish; +- } +- +- r = VIRTUALIZATION_CONTAINER_OTHER; ++ r = container_from_string(e); ++ if (r < 0) ++ r = VIRTUALIZATION_CONTAINER_OTHER; + + finish: + log_debug("Found container virtualization %s.", virtualization_to_string(r)); diff --git a/SOURCES/0851-fileio-introduce-read_full_virtual_file-for-reading-.patch b/SOURCES/0851-fileio-introduce-read_full_virtual_file-for-reading-.patch new file mode 100644 index 0000000..84b09c9 --- /dev/null +++ b/SOURCES/0851-fileio-introduce-read_full_virtual_file-for-reading-.patch @@ -0,0 +1,194 @@ +From 7a3843972ea290daf1bec5e1133db654749b8c02 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Tue, 22 Oct 2019 16:09:21 +0200 +Subject: [PATCH] fileio: introduce read_full_virtual_file() for reading + virtual files in sysfs, procfs + +Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work +with two sorts of virtual files. + +One sort uses "seq_file", and the results of the first read are buffered for +the second read. The other sort uses "raw" reads which always go direct to the +device. + +In the later case, the content of the virtual file must be retrieved with a +single read otherwise subsequent read might get the new value instead of +finding EOF immediately. That's the reason why the usage of fread(3) is +prohibited in this case as it always performs a second call to read(2) looking +for EOF which is subject to the race described previously. + +Fixes: #13585. +(cherry picked from commit 21b40f16622f171a9969dc334d74fb5eb2f575c2) + +Related: #2117948 +--- + src/basic/fileio.c | 115 ++++++++++++++++++++++++++- + src/basic/fileio.h | 1 + + src/libsystemd/sd-device/sd-device.c | 2 +- + 3 files changed, 113 insertions(+), 5 deletions(-) + +diff --git a/src/basic/fileio.c b/src/basic/fileio.c +index 6b0bad5b71..733fb42463 100644 +--- a/src/basic/fileio.c ++++ b/src/basic/fileio.c +@@ -276,6 +276,113 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { + return 1; + } + ++int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) { ++ _cleanup_free_ char *buf = NULL; ++ _cleanup_close_ int fd = -1; ++ struct stat st; ++ size_t n, size; ++ int n_retries; ++ char *p; ++ ++ assert(ret_contents); ++ ++ /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work ++ * with two sorts of virtual files. One sort uses "seq_file", and the results of ++ * the first read are buffered for the second read. The other sort uses "raw" ++ * reads which always go direct to the device. In the latter case, the content of ++ * the virtual file must be retrieved with a single read otherwise a second read ++ * might get the new value instead of finding EOF immediately. That's the reason ++ * why the usage of fread(3) is prohibited in this case as it always performs a ++ * second call to read(2) looking for EOF. See issue 13585. */ ++ ++ fd = open(filename, O_RDONLY|O_CLOEXEC); ++ if (fd < 0) ++ return -errno; ++ ++ /* Start size for files in /proc which usually report a file size of 0. */ ++ size = LINE_MAX / 2; ++ ++ /* Limit the number of attempts to read the number of bytes returned by fstat(). */ ++ n_retries = 3; ++ ++ for (;;) { ++ if (n_retries <= 0) ++ return -EIO; ++ ++ if (fstat(fd, &st) < 0) ++ return -errno; ++ ++ if (!S_ISREG(st.st_mode)) ++ return -EBADF; ++ ++ /* Be prepared for files from /proc which generally report a file size of 0. */ ++ if (st.st_size > 0) { ++ size = st.st_size; ++ n_retries--; ++ } else ++ size = size * 2; ++ ++ if (size > READ_FULL_BYTES_MAX) ++ return -E2BIG; ++ ++ p = realloc(buf, size + 1); ++ if (!p) ++ return -ENOMEM; ++ buf = TAKE_PTR(p); ++ ++ for (;;) { ++ ssize_t k; ++ ++ /* Read one more byte so we can detect whether the content of the ++ * file has already changed or the guessed size for files from /proc ++ * wasn't large enough . */ ++ k = read(fd, buf, size + 1); ++ if (k >= 0) { ++ n = k; ++ break; ++ } ++ ++ if (errno != -EINTR) ++ return -errno; ++ } ++ ++ /* Consider a short read as EOF */ ++ if (n <= size) ++ break; ++ ++ /* Hmm... either we read too few bytes from /proc or less likely the content ++ * of the file might have been changed (and is now bigger) while we were ++ * processing, let's try again either with a bigger guessed size or the new ++ * file size. */ ++ ++ if (lseek(fd, 0, SEEK_SET) < 0) ++ return -errno; ++ } ++ ++ if (n < size) { ++ p = realloc(buf, n + 1); ++ if (!p) ++ return -ENOMEM; ++ buf = TAKE_PTR(p); ++ } ++ ++ if (!ret_size) { ++ /* Safety check: if the caller doesn't want to know the size of what we ++ * just read it will rely on the trailing NUL byte. But if there's an ++ * embedded NUL byte, then we should refuse operation as otherwise ++ * there'd be ambiguity about what we just read. */ ++ ++ if (memchr(buf, 0, n)) ++ return -EBADMSG; ++ } else ++ *ret_size = n; ++ ++ buf[n] = 0; ++ *ret_contents = TAKE_PTR(buf); ++ ++ return 0; ++} ++ + int read_full_stream(FILE *f, char **contents, size_t *size) { + _cleanup_free_ char *buf = NULL; + struct stat st; +@@ -300,9 +407,9 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { + if (st.st_size > READ_FULL_BYTES_MAX) + return -E2BIG; + +- /* Start with the right file size, but be prepared for files from /proc which generally report a file +- * size of 0. Note that we increase the size to read here by one, so that the first read attempt +- * already makes us notice the EOF. */ ++ /* Start with the right file size. Note that we increase the size ++ * to read here by one, so that the first read attempt already ++ * makes us notice the EOF. */ + if (st.st_size > 0) + n = st.st_size + 1; + } +@@ -986,7 +1093,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin + assert(pattern); + assert(field); + +- r = read_full_file(filename, &status, NULL); ++ r = read_full_virtual_file(filename, &status, NULL); + if (r < 0) + return r; + +diff --git a/src/basic/fileio.h b/src/basic/fileio.h +index 77e6206e95..c6ad375b8d 100644 +--- a/src/basic/fileio.h ++++ b/src/basic/fileio.h +@@ -38,6 +38,7 @@ int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *f + int read_one_line_file(const char *fn, char **line); + int read_full_file(const char *fn, char **contents, size_t *size); + int read_full_stream(FILE *f, char **contents, size_t *size); ++int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size); + + int verify_file(const char *fn, const char *blob, bool accept_extra_nl); + +diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c +index be29053f8c..49750ba9d7 100644 +--- a/src/libsystemd/sd-device/sd-device.c ++++ b/src/libsystemd/sd-device/sd-device.c +@@ -1798,7 +1798,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, + size_t size; + + /* read attribute value */ +- r = read_full_file(path, &value, &size); ++ r = read_full_virtual_file(path, &value, &size); + if (r < 0) + return r; + diff --git a/SOURCES/0852-Use-BIOS-characteristics-to-distinguish-EC2-bare-met.patch b/SOURCES/0852-Use-BIOS-characteristics-to-distinguish-EC2-bare-met.patch new file mode 100644 index 0000000..bf84a18 --- /dev/null +++ b/SOURCES/0852-Use-BIOS-characteristics-to-distinguish-EC2-bare-met.patch @@ -0,0 +1,118 @@ +From 44cbd79562ed55a8b0f2e5b5dc708265568ed9f8 Mon Sep 17 00:00:00 2001 +From: Noah Meyerhans +Date: Fri, 30 Apr 2021 09:30:52 -0700 +Subject: [PATCH] Use BIOS characteristics to distinguish EC2 bare-metal from + VMs + +DMI vendor information fields do not provide enough information for us to +distinguish between Amazon EC2 virtual machines and bare-metal instances. +SMBIOS provides a BIOS Information +table (https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf +Ch. 7) that provides a field to indicate that the current machine is a virtual +machine. On EC2 virtual machine instances, this field is set, while bare-metal +instances leave this unset, so we inspect the field via the kernel's +/sys/firemware/dmi/entries interface. + +Fixes #18929 + +(cherry picked from commit ce35037928f4c4c931088256853f07804ec7d235) + +Related: #2117948 +--- + src/basic/virt.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 61 insertions(+), 4 deletions(-) + +diff --git a/src/basic/virt.c b/src/basic/virt.c +index 6e4c702051..00d1c894e6 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -22,6 +22,12 @@ + #include "string-util.h" + #include "virt.h" + ++enum { ++ SMBIOS_VM_BIT_SET, ++ SMBIOS_VM_BIT_UNSET, ++ SMBIOS_VM_BIT_UNKNOWN, ++}; ++ + static const char *const vm_table[_VIRTUALIZATION_MAX] = { + [VIRTUALIZATION_XEN] = "XenVMMXenVMM", + [VIRTUALIZATION_KVM] = "KVMKVMKVM", +@@ -131,9 +137,8 @@ static int detect_vm_device_tree(void) { + #endif + } + +-static int detect_vm_dmi(void) { + #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) +- ++static int detect_vm_dmi_vendor(void) { + static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */ + "/sys/class/dmi/id/sys_vendor", +@@ -179,11 +184,63 @@ static int detect_vm_dmi(void) { + return dmi_vendor_table[j].id; + } + } +-#endif ++ return VIRTUALIZATION_NONE; ++} ++ ++static int detect_vm_smbios(void) { ++ /* The SMBIOS BIOS Charateristics Extension Byte 2 (Section 2.1.2.2 of ++ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf), specifies that ++ * the 4th bit being set indicates a VM. The BIOS Characteristics table is exposed via the kernel in ++ * /sys/firmware/dmi/entries/0-0. Note that in the general case, this bit being unset should not ++ * imply that the system is running on bare-metal. For example, QEMU 3.1.0 (with or without KVM) ++ * with SeaBIOS does not set this bit. */ ++ _cleanup_free_ char *s = NULL; ++ size_t readsize; ++ int r; ++ ++ r = read_full_virtual_file("/sys/firmware/dmi/entries/0-0/raw", &s, &readsize); ++ if (r < 0) { ++ log_debug_errno(r, "Unable to read /sys/firmware/dmi/entries/0-0/raw, ignoring: %m"); ++ return SMBIOS_VM_BIT_UNKNOWN; ++ } ++ if (readsize < 20 || s[1] < 20) { ++ /* The spec indicates that byte 1 contains the size of the table, 0x12 + the number of ++ * extension bytes. The data we're interested in is in extension byte 2, which would be at ++ * 0x13. If we didn't read that much data, or if the BIOS indicates that we don't have that ++ * much data, we don't infer anything from the SMBIOS. */ ++ log_debug("Only read %zu bytes from /sys/firmware/dmi/entries/0-0/raw (expected 20)", readsize); ++ return SMBIOS_VM_BIT_UNKNOWN; ++ } + +- log_debug("No virtualization found in DMI"); ++ uint8_t byte = (uint8_t) s[19]; ++ if (byte & (1U<<4)) { ++ log_debug("DMI BIOS Extension table indicates virtualization"); ++ return SMBIOS_VM_BIT_SET; ++ } ++ log_debug("DMI BIOS Extension table does not indicate virtualization"); ++ return SMBIOS_VM_BIT_UNSET; ++} ++#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) */ ++ ++static int detect_vm_dmi(void) { ++#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) ++ ++ int r; ++ r = detect_vm_dmi_vendor(); + ++ /* The DMI vendor tables in /sys/class/dmi/id don't help us distinguish between Amazon EC2 ++ * virtual machines and bare-metal instances, so we need to look at SMBIOS. */ ++ if (r == VIRTUALIZATION_AMAZON && detect_vm_smbios() == SMBIOS_VM_BIT_UNSET) ++ return VIRTUALIZATION_NONE; ++ ++ /* If we haven't identified a VM, but the firmware indicates that there is one, indicate as much. We ++ * have no further information about what it is. */ ++ if (r == VIRTUALIZATION_NONE && detect_vm_smbios() == SMBIOS_VM_BIT_SET) ++ return VIRTUALIZATION_VM_OTHER; ++ return r; ++#else + return VIRTUALIZATION_NONE; ++#endif + } + + static int detect_vm_xen(void) { diff --git a/SOURCES/0853-device-drop-refuse_after.patch b/SOURCES/0853-device-drop-refuse_after.patch new file mode 100644 index 0000000..80e5c62 --- /dev/null +++ b/SOURCES/0853-device-drop-refuse_after.patch @@ -0,0 +1,37 @@ +From bb9d00035c00b8590c389e66b5d94334bbb7379d Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Mon, 30 Mar 2020 10:49:29 +0200 +Subject: [PATCH] device: drop refuse_after + +Scheduling devices after a given unit can be useful to start device *jobs* at a +specific time in the transaction, see commit 4195077ab4c823c. + +This (hidden) change was introduced by commit eef85c4a3f8054d2. + +(cherry picked from commit b862c25716520d9381d5a841dba0f0c14e9c970a) + +[dtardon: This picks just the minimal relevant change from +c80a9a33d04fb4381327a69ce929c94a9f1d0e6c and +b862c25716520d9381d5a841dba0f0c14e9c970a] + +Resolves: #2043524 +--- + src/core/unit.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index dfe0c243ef..9be2a0c326 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2841,8 +2841,9 @@ int unit_add_dependency( + return 0; + } + +- if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) || +- (d == UNIT_AFTER && u->type == UNIT_DEVICE)) { ++ /* Note that ordering a device unit after a unit is permitted since it ++ * allows to start its job running timeout at a specific time. */ ++ if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) { + log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id); + return 0; + } diff --git a/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch b/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch new file mode 100644 index 0000000..42ff3fa --- /dev/null +++ b/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch @@ -0,0 +1,44 @@ +From 004130ae74688eb321aadc05192bab69fe5cbcbf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 22 Jul 2022 11:45:12 +0200 +Subject: [PATCH] manager: limit access to private dbus socket + +For the system manager, /run/systemd/private is publicly accessible, because +/run/systemd is 0755, and /run/systemd/private is 0777. For the user manager, +/run/user/ is 0700, and /run/user//systemd/private is 0777. This +does not directly cause any security issue because we check the sender in +bus_check_peercred (ucred.uid != 0 && ucred.uid != geteuid()). + +But it makes sense to limit access to the socket to avoid wasting time in PID1. +Somebody could send messages there that'd we'd reject anyway. It also makes +things more explicit. + +(cherry picked from commit df1cbd1adf26071aab41d96e054452a3d66103a4) + +Resolves: #2119405 +--- + src/core/dbus.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 66d838cdb4..ec6c52cb85 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -42,6 +42,7 @@ + #include "string-util.h" + #include "strv.h" + #include "strxcpyx.h" ++#include "umask-util.h" + #include "user-util.h" + + #define CONNECTIONS_MAX 4096 +@@ -1019,7 +1020,8 @@ int bus_init_private(Manager *m) { + if (fd < 0) + return log_error_errno(errno, "Failed to allocate private socket: %m"); + +- r = bind(fd, &sa.sa, salen); ++ RUN_WITH_UMASK(0077) ++ r = bind(fd, &sa.sa, salen); + if (r < 0) + return log_error_errno(errno, "Failed to bind private socket: %m"); + diff --git a/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch b/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch new file mode 100644 index 0000000..d53c85d --- /dev/null +++ b/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch @@ -0,0 +1,35 @@ +From b0574acc0bddceb0af47f6cce327a87041ab4b52 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 11 Nov 2018 12:33:06 +0100 +Subject: [PATCH] journalctl: do not treat EINTR as an error when waiting for + events + +Fixup for 2a1e0f2228bbdfbc18635e959f47df7da50b62fe. Fixes #10724. + +Reproducer: start 'journalctl -f' in a terminal window, change window size. +(cherry picked from commit 8e143a123276a9636987b08f555603927ca9e186) + +Resolves: #2161683 +--- + src/journal/journalctl.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index fa83dce562..228cfe7e49 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2084,8 +2084,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) { + if (r < 0) + return log_error_errno(r, "Failed to determine journal waiting time: %m"); + +- if (ppoll(pollfds, ELEMENTSOF(pollfds), timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) ++ if (ppoll(pollfds, ELEMENTSOF(pollfds), ++ timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) { ++ if (errno == EINTR) ++ return 0; ++ + return log_error_errno(errno, "Couldn't wait for journal event: %m"); ++ } + + if (pollfds[1].revents & (POLLHUP|POLLERR)) { /* STDOUT has been closed? */ + log_debug("Standard output has been closed."); diff --git a/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch b/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch new file mode 100644 index 0000000..e785fdf --- /dev/null +++ b/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch @@ -0,0 +1,76 @@ +From b9dd7ee5f4d0f6d51899d7e14ac7ef2fd2840b8f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 9 Oct 2018 17:37:57 +0200 +Subject: [PATCH] core: bring manager_startup() and manager_reload() more + inline + +Both functions do partly the same, let's make sure they do it in the +same order, and that we don't miss some calls. + +This makes a number of changes: + +1. Moves exec_runtime_vacuum() two calls down in manager_startup(). This + should not have any effect but makes manager_startup() more like + manager_reload(). + +2. Calls manager_recheck_journal(), manager_recheck_dbus(), + manager_enqueue_sync_bus_names() in manager_startup() too. This is a + good idea since during reeexec we pass through manager_startup() and + hence can't assume dbus and journald weren't up yet, hence let's + check if they are ready to be connected to. + +3. Include manager_enumerate_perpetual() in manager_reload(), too. This + is not strictly necessary, since these units are included in the + serialization anyway, but it's still a nice thing, in particular as + theoretically the deserialization could fail. + +(cherry picked from commit 3ad2afb6a204513c7834c64ab864e40169874390) + +Resolves: #2059633 +--- + src/core/manager.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index e083596e58..4a9f9bfcf9 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1665,12 +1665,12 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + /* Release any dynamic users no longer referenced */ + dynamic_user_vacuum(m, true); + +- exec_runtime_vacuum(m); +- + /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */ + manager_vacuum_uid_refs(m); + manager_vacuum_gid_refs(m); + ++ exec_runtime_vacuum(m); ++ + if (serialization) { + assert(m->n_reloading > 0); + m->n_reloading--; +@@ -1681,6 +1681,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + m->send_reloading_done = true; + } + ++ /* It might be safe to log to the journal now and connect to dbus */ ++ manager_recheck_journal(m); ++ manager_recheck_dbus(m); ++ ++ /* Sync current state of bus names with our set of listening units */ ++ (void) manager_enqueue_sync_bus_names(m); ++ + /* Let's finally catch up with any changes that took place while we were reloading/reexecing */ + manager_catchup(m); + +@@ -3505,7 +3512,8 @@ int manager_reload(Manager *m) { + lookup_paths_reduce(&m->lookup_paths); + manager_build_unit_path_cache(m); + +- /* First, enumerate what we can from all config files */ ++ /* First, enumerate what we can from kernel and suchlike */ ++ manager_enumerate_perpetual(m); + manager_enumerate(m); + + /* Second, deserialize our stored data */ diff --git a/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch b/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch new file mode 100644 index 0000000..8825e9e --- /dev/null +++ b/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch @@ -0,0 +1,35 @@ +From b1b7aaf83414c5b0bed6e61d38aefe29a21fdbcf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 23 Nov 2022 16:09:56 +0100 +Subject: [PATCH] pam: add a call to pam_namespace + +A call to pam_namespace is required so that children of user@.service end up in +a namespace as expected. pam_namespace gets called as part of the stack that +creates a session (login, sshd, gdm, etc.) and those processes end up in a +namespace, but it also needs to be called from our stack which is parallel and +descends from pid1 itself. + +The call to pam_namespace is similar to the call to pam_keyinit that was added +in ab79099d1684457d040ee7c28b2012e8c1ea9a4f. The pam stack for user@.service +creates a new session which is disconnected from the parent environment. Both +calls are not suitable for inclusion in the shared part of the stack (e.g. +@system-auth on Fedora/RHEL systems), because for example su/sudo/runuser +should not include them. + +(cherry picked from commit 0ef48896d9f23b9fd547a532a4e6e6b8f8b12901) + +Resolves: #1861836 +--- + src/login/systemd-user.m4 | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4 +index 20c8999331..eb291beaed 100644 +--- a/src/login/systemd-user.m4 ++++ b/src/login/systemd-user.m4 +@@ -9,4 +9,5 @@ session required pam_selinux.so nottys open + )m4_dnl + session required pam_loginuid.so + session optional pam_keyinit.so force revoke ++session required pam_namespace.so + session optional pam_systemd.so diff --git a/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch b/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch new file mode 100644 index 0000000..8f71336 --- /dev/null +++ b/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch @@ -0,0 +1,31 @@ +From 4b573adbcc040fa50f1130cb8cf1bdb9559565cf Mon Sep 17 00:00:00 2001 +From: Boqun Feng +Date: Wed, 13 Oct 2021 11:32:09 +0800 +Subject: [PATCH] virt: Support detection for ARM64 Hyper-V guests + +The detection of Microsoft Hyper-V VMs is done by cpuid currently, +however there is no cpuid on ARM64. And since ARM64 is now a supported +architecture for Microsoft Hyper-V guests[1], then use DMI tables to +detect a Hyper-V guest, which is more generic and works for ARM64. + +[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7aff79e297ee1aa0126924921fd87a4ae59d2467 + +(cherry picked from commit 506bbc8569014253ea8614b680ccbc4fc2513a87) + +Resolves: #2158307 +--- + src/basic/virt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/basic/virt.c b/src/basic/virt.c +index 00d1c894e6..cc95097101 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -162,6 +162,7 @@ static int detect_vm_dmi_vendor(void) { + { "Parallels", VIRTUALIZATION_PARALLELS }, + /* https://wiki.freebsd.org/bhyve */ + { "BHYVE", VIRTUALIZATION_BHYVE }, ++ { "Microsoft", VIRTUALIZATION_MICROSOFT }, + }; + unsigned i; + int r; diff --git a/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch b/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch new file mode 100644 index 0000000..8a91e30 --- /dev/null +++ b/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch @@ -0,0 +1,41 @@ +From e732bc987f2f779e89f30193bf694e0456ab7ce0 Mon Sep 17 00:00:00 2001 +From: Boqun Feng +Date: Tue, 23 Nov 2021 15:09:26 +0800 +Subject: [PATCH] virt: Fix the detection for Hyper-V VMs + +Use product_version instead of product_name in DMI table and the string +"Hyper-V" to avoid misdetection. + +Fixes: #21468 + +Signed-off-by: Boqun Feng +(cherry picked from commit 76eec0649936d9ae2f9087769f463feaf0cf5cb4) + +Related: #2158307 +--- + src/basic/virt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/basic/virt.c b/src/basic/virt.c +index cc95097101..f750a0463f 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -143,7 +143,8 @@ static int detect_vm_dmi_vendor(void) { + "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */ + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", +- "/sys/class/dmi/id/bios_vendor" ++ "/sys/class/dmi/id/bios_vendor", ++ "/sys/class/dmi/id/product_version" /* For Hyper-V VMs test */ + }; + + static const struct { +@@ -162,7 +163,7 @@ static int detect_vm_dmi_vendor(void) { + { "Parallels", VIRTUALIZATION_PARALLELS }, + /* https://wiki.freebsd.org/bhyve */ + { "BHYVE", VIRTUALIZATION_BHYVE }, +- { "Microsoft", VIRTUALIZATION_MICROSOFT }, ++ { "Hyper-V", VIRTUALIZATION_MICROSOFT }, + }; + unsigned i; + int r; diff --git a/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch b/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch new file mode 100644 index 0000000..4d1c5e5 --- /dev/null +++ b/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch @@ -0,0 +1,98 @@ +From 9c95d8dda42de288a57638a44dd5ea967469063d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 7 Oct 2022 12:28:31 +0200 +Subject: [PATCH] basic: add STRERROR() wrapper for strerror_r() + +(cherry picked from commit 2c5d05b3cd986568105d67891e4010b868dea24f) + +Related: #2155520 +--- + src/basic/util.h | 10 ++++++++++ + src/test/test-util.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+) + +diff --git a/src/basic/util.h b/src/basic/util.h +index 76b76d7e91..195f02cf5f 100644 +--- a/src/basic/util.h ++++ b/src/basic/util.h +@@ -153,6 +153,16 @@ static inline void _reset_errno_(int *saved_errno) { + errno = *saved_errno; + } + ++/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */ ++#define ERRNO_BUF_LEN 1024 ++ ++/* Note: the lifetime of the compound literal is the immediately surrounding block, ++ * see C11 §6.5.2.5, and ++ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks ++ * ++ * Note that we use the GNU variant of strerror_r() here. */ ++#define STRERROR(errnum) strerror_r(abs(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) ++ + #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno + + #define UNPROTECT_ERRNO \ +diff --git a/src/test/test-util.c b/src/test/test-util.c +index df60d89115..c93eaf7fc6 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -12,6 +12,7 @@ + #include "process-util.h" + #include "raw-clone.h" + #include "rm-rf.h" ++#include "stdio-util.h" + #include "string-util.h" + #include "util.h" + +@@ -321,6 +322,42 @@ static void test_system_tasks_max_scale(void) { + assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); + } + ++static void test_strerror_not_threadsafe(void) { ++ /* Just check that strerror really is not thread-safe. */ ++ log_info("strerror(%d) → %s", 200, strerror(200)); ++ log_info("strerror(%d) → %s", 201, strerror(201)); ++ log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX)); ++ ++ log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201)); ++ ++ /* This call is not allowed, because the first returned string becomes invalid when ++ * we call strerror the second time: ++ * ++ * log_info("strerror(%d), strerror(%d) → %s, %s", 200, 201, strerror(200), strerror(201)); ++ */ ++} ++ ++static void test_STRERROR(void) { ++ /* Just check that STRERROR really is thread-safe. */ ++ log_info("STRERROR(%d) → %s", 200, STRERROR(200)); ++ log_info("STRERROR(%d) → %s", 201, STRERROR(201)); ++ log_info("STRERROR(%d), STRERROR(%d) → %s, %s", 200, 201, STRERROR(200), STRERROR(201)); ++ ++ const char *a = STRERROR(200), *b = STRERROR(201); ++ assert_se(strstr(a, "200")); ++ assert_se(strstr(b, "201")); ++ ++ /* Check with negative values */ ++ assert_se(streq(a, STRERROR(-200))); ++ assert_se(streq(b, STRERROR(-201))); ++ ++ const char *c = STRERROR(INT_MAX); ++ char buf[DECIMAL_STR_MAX(int)]; ++ xsprintf(buf, "%d", INT_MAX); /* INT_MAX is hexadecimal, use printf to convert to decimal */ ++ log_info("STRERROR(%d) → %s", INT_MAX, c); ++ assert_se(strstr(c, buf)); ++} ++ + int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); +@@ -340,5 +377,8 @@ int main(int argc, char *argv[]) { + test_system_tasks_max(); + test_system_tasks_max_scale(); + ++ test_strerror_not_threadsafe(); ++ test_STRERROR(); ++ + return 0; + } diff --git a/SOURCES/0861-coredump-put-context-array-into-a-struct.patch b/SOURCES/0861-coredump-put-context-array-into-a-struct.patch new file mode 100644 index 0000000..75029e7 --- /dev/null +++ b/SOURCES/0861-coredump-put-context-array-into-a-struct.patch @@ -0,0 +1,529 @@ +From f53c6620c55488e2a3bd92957b21b6b95a7a3d35 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Thu, 12 Jan 2023 15:47:09 +0100 +Subject: [PATCH] coredump: put context array into a struct + +[dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 , +but does just the minimal change to introduce the Context struct that is +needed by the following commit.] + +Related: #2155520 +--- + src/coredump/coredump.c | 208 +++++++++++++++++++++------------------- + 1 file changed, 108 insertions(+), 100 deletions(-) + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index fb3a6ecfe9..ebc56d8342 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -91,6 +91,10 @@ enum { + _CONTEXT_MAX + }; + ++typedef struct Context { ++ const char *meta[_CONTEXT_MAX]; ++} Context; ++ + typedef enum CoredumpStorage { + COREDUMP_STORAGE_NONE, + COREDUMP_STORAGE_EXTERNAL, +@@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) { + return 0; + } + +-static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { ++static int fix_xattr(int fd, const Context *context) { + + static const char * const xattrs[_CONTEXT_MAX] = { + [CONTEXT_PID] = "user.coredump.pid", +@@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { + for (i = 0; i < _CONTEXT_MAX; i++) { + int k; + +- if (isempty(context[i]) || !xattrs[i]) ++ if (isempty(context->meta[i]) || !xattrs[i]) + continue; + +- k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE); ++ k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE); + if (k < 0 && r == 0) + r = -errno; + } +@@ -230,7 +234,7 @@ static int fix_permissions( + int fd, + const char *filename, + const char *target, +- const char *context[_CONTEXT_MAX], ++ const Context *context, + uid_t uid) { + + int r; +@@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) { + return 1; + } + +-static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { ++static int make_filename(const Context *context, char **ret) { + _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; + sd_id128_t boot = {}; + int r; + + assert(context); + +- c = filename_escape(context[CONTEXT_COMM]); ++ c = filename_escape(context->meta[CONTEXT_COMM]); + if (!c) + return -ENOMEM; + +- u = filename_escape(context[CONTEXT_UID]); ++ u = filename_escape(context->meta[CONTEXT_UID]); + if (!u) + return -ENOMEM; + +@@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { + if (r < 0) + return r; + +- p = filename_escape(context[CONTEXT_PID]); ++ p = filename_escape(context->meta[CONTEXT_PID]); + if (!p) + return -ENOMEM; + +- t = filename_escape(context[CONTEXT_TIMESTAMP]); ++ t = filename_escape(context->meta[CONTEXT_TIMESTAMP]); + if (!t) + return -ENOMEM; + +@@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { + } + + static int save_external_coredump( +- const char *context[_CONTEXT_MAX], ++ const Context *context, + int input_fd, + char **ret_filename, + int *ret_node_fd, +@@ -334,19 +338,19 @@ static int save_external_coredump( + assert(ret_data_fd); + assert(ret_size); + +- r = parse_uid(context[CONTEXT_UID], &uid); ++ r = parse_uid(context->meta[CONTEXT_UID], &uid); + if (r < 0) + return log_error_errno(r, "Failed to parse UID: %m"); + +- r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit); ++ r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit); + if (r < 0) +- return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]); ++ return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]); + if (rlimit < page_size()) { + /* Is coredumping disabled? Then don't bother saving/processing the coredump. + * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses + * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */ + log_info("Resource limits disable core dumping for process %s (%s).", +- context[CONTEXT_PID], context[CONTEXT_COMM]); ++ context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); + return -EBADSLT; + } + +@@ -371,7 +375,7 @@ static int save_external_coredump( + + r = copy_bytes(input_fd, fd, max_size, 0); + if (r < 0) { +- log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); ++ log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); + goto fail; + } + *ret_truncated = r == 1; +@@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) { + return 1; + } + +-static int change_uid_gid(const char *context[]) { ++static int change_uid_gid(const Context *context) { + uid_t uid; + gid_t gid; + int r; + +- r = parse_uid(context[CONTEXT_UID], &uid); ++ r = parse_uid(context->meta[CONTEXT_UID], &uid); + if (r < 0) + return r; + +@@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) { + uid = gid = 0; + } + } else { +- r = parse_gid(context[CONTEXT_GID], &gid); ++ r = parse_gid(context->meta[CONTEXT_GID], &gid); + if (r < 0) + return r; + } +@@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) { + return drop_privileges(uid, gid, 0); + } + +-static bool is_journald_crash(const char *context[_CONTEXT_MAX]) { ++static bool is_journald_crash(const Context *context) { + assert(context); + +- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); ++ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); + } + +-static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) { ++static bool is_pid1_crash(const Context *context) { + assert(context); + +- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || +- streq_ptr(context[CONTEXT_PID], "1"); ++ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || ++ streq_ptr(context->meta[CONTEXT_PID], "1"); + } + + #define SUBMIT_COREDUMP_FIELDS 4 + + static int submit_coredump( +- const char *context[_CONTEXT_MAX], ++ Context *context, + struct iovec *iovec, + size_t n_iovec_allocated, + size_t n_iovec, +@@ -760,11 +764,11 @@ static int submit_coredump( + if (coredump_size <= arg_process_size_max) { + _cleanup_free_ char *stacktrace = NULL; + +- r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace); ++ r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace); + if (r >= 0) +- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], +- " (", context[CONTEXT_COMM], ") of user ", +- context[CONTEXT_UID], " dumped core.", ++ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], ++ " (", context->meta[CONTEXT_COMM], ") of user ", ++ context->meta[CONTEXT_UID], " dumped core.", + journald_crash ? "\nCoredump diverted to " : "", + journald_crash ? filename : "", + "\n\n", stacktrace); +@@ -779,9 +783,9 @@ static int submit_coredump( + if (!core_message) + #endif + log: +- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], +- " (", context[CONTEXT_COMM], ") of user ", +- context[CONTEXT_UID], " dumped core.", ++ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], ++ " (", context->meta[CONTEXT_COMM], ") of user ", ++ context->meta[CONTEXT_UID], " dumped core.", + journald_crash && filename ? "\nCoredump diverted to " : NULL, + journald_crash && filename ? filename : NULL); + if (!core_message) +@@ -826,7 +830,7 @@ log: + return 0; + } + +-static void map_context_fields(const struct iovec *iovec, const char* context[]) { ++static void map_context_fields(const struct iovec *iovec, Context *context) { + + static const char * const context_field_names[] = { + [CONTEXT_PID] = "COREDUMP_PID=", +@@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[]) + + /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the + * buffer, though not included in the iov_len count. (see below) */ +- context[i] = p; ++ context->meta[i] = p; + break; + } + } +@@ -866,7 +870,7 @@ static int process_socket(int fd) { + _cleanup_close_ int coredump_fd = -1; + struct iovec *iovec = NULL; + size_t n_iovec = 0, n_allocated = 0, i, k; +- const char *context[_CONTEXT_MAX] = {}; ++ Context context = {}; + int r; + + assert(fd >= 0); +@@ -950,7 +954,7 @@ static int process_socket(int fd) { + iovec[n_iovec].iov_len = (size_t) n; + + cmsg_close_all(&mh); +- map_context_fields(iovec + n_iovec, context); ++ map_context_fields(iovec + n_iovec, &context); + n_iovec++; + } + +@@ -960,24 +964,24 @@ static int process_socket(int fd) { + } + + /* Make sure we got all data we really need */ +- assert(context[CONTEXT_PID]); +- assert(context[CONTEXT_UID]); +- assert(context[CONTEXT_GID]); +- assert(context[CONTEXT_SIGNAL]); +- assert(context[CONTEXT_TIMESTAMP]); +- assert(context[CONTEXT_RLIMIT]); +- assert(context[CONTEXT_HOSTNAME]); +- assert(context[CONTEXT_COMM]); ++ assert(context.meta[CONTEXT_PID]); ++ assert(context.meta[CONTEXT_UID]); ++ assert(context.meta[CONTEXT_GID]); ++ assert(context.meta[CONTEXT_SIGNAL]); ++ assert(context.meta[CONTEXT_TIMESTAMP]); ++ assert(context.meta[CONTEXT_RLIMIT]); ++ assert(context.meta[CONTEXT_HOSTNAME]); ++ assert(context.meta[CONTEXT_COMM]); + assert(coredump_fd >= 0); + + /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s + * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we + * are reconstructing the original kernel context, we chop this off again, here. */ +- k = strlen(context[CONTEXT_TIMESTAMP]); ++ k = strlen(context.meta[CONTEXT_TIMESTAMP]); + if (k > 6) +- context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6); ++ context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6); + +- r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd); ++ r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd); + + finish: + for (i = 0; i < n_iovec; i++) +@@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch + } + + static int gather_pid_metadata( +- char* context[_CONTEXT_MAX], ++ Context *context, + char **comm_fallback, + struct iovec *iovec, size_t *n_iovec) { + +@@ -1077,65 +1081,69 @@ static int gather_pid_metadata( + const char *p; + int r, signo; + +- r = parse_pid(context[CONTEXT_PID], &pid); ++ r = parse_pid(context->meta[CONTEXT_PID], &pid); + if (r < 0) +- return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]); ++ return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]); + +- r = get_process_comm(pid, &context[CONTEXT_COMM]); ++ r = get_process_comm(pid, &t); + if (r < 0) { + log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m"); +- context[CONTEXT_COMM] = strv_join(comm_fallback, " "); +- if (!context[CONTEXT_COMM]) ++ context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " "); ++ if (!context->meta[CONTEXT_COMM]) + return log_oom(); +- } ++ } else ++ context->meta[CONTEXT_COMM] = t; + +- r = get_process_exe(pid, &context[CONTEXT_EXE]); ++ r = get_process_exe(pid, &t); + if (r < 0) + log_warning_errno(r, "Failed to get EXE, ignoring: %m"); ++ else ++ context->meta[CONTEXT_EXE] = t; + +- if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) { +- if (!is_journald_crash((const char**) context)) { ++ if (cg_pid_get_unit(pid, &t) >= 0) { ++ if (!is_journald_crash(context)) { + /* OK, now we know it's not the journal, hence we can make use of it now. */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + } + + /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */ +- if (is_pid1_crash((const char**) context)) { ++ if (is_pid1_crash(context)) { + log_notice("Due to PID 1 having crashed coredump collection will now be turned off."); + disable_coredumps(); + } + +- set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); +- } ++ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]); ++ } else ++ context->meta[CONTEXT_UNIT] = t; + + if (cg_pid_get_user_unit(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t); + + /* The next few are mandatory */ +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME])) + return log_oom(); + +- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) ++ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM])) + return log_oom(); + +- if (context[CONTEXT_EXE] && +- !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) ++ if (context->meta[CONTEXT_EXE] && ++ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE])) + return log_oom(); + + if (sd_pid_get_session(pid, &t) >= 0) +@@ -1198,11 +1206,11 @@ static int gather_pid_metadata( + if (get_process_environ(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t); + +- t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); ++ t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000"); + if (t) + iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t); + +- if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) ++ if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) + set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); + + return 0; /* we successfully acquired all metadata */ +@@ -1210,7 +1218,7 @@ static int gather_pid_metadata( + + static int process_kernel(int argc, char* argv[]) { + +- char* context[_CONTEXT_MAX] = {}; ++ Context context = {}; + struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS]; + size_t i, n_iovec, n_to_free = 0; + int r; +@@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) { + return -EINVAL; + } + +- context[CONTEXT_PID] = argv[1 + CONTEXT_PID]; +- context[CONTEXT_UID] = argv[1 + CONTEXT_UID]; +- context[CONTEXT_GID] = argv[1 + CONTEXT_GID]; +- context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; +- context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; +- context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; +- context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; ++ context.meta[CONTEXT_PID] = argv[1 + CONTEXT_PID]; ++ context.meta[CONTEXT_UID] = argv[1 + CONTEXT_UID]; ++ context.meta[CONTEXT_GID] = argv[1 + CONTEXT_GID]; ++ context.meta[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; ++ context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; ++ context.meta[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; ++ context.meta[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; + +- r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); ++ r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); + if (r < 0) + goto finish; + +@@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) { + + assert(n_iovec <= ELEMENTSOF(iovec)); + +- if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context)) +- r = submit_coredump((const char**) context, ++ if (is_journald_crash(&context) || is_pid1_crash(&context)) ++ r = submit_coredump(&context, + iovec, ELEMENTSOF(iovec), n_iovec, + STDIN_FILENO); + else +@@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) { + free(iovec[i].iov_base); + + /* Those fields are allocated by gather_pid_metadata */ +- free(context[CONTEXT_COMM]); +- free(context[CONTEXT_EXE]); +- free(context[CONTEXT_UNIT]); ++ free((char *) context.meta[CONTEXT_COMM]); ++ free((char *) context.meta[CONTEXT_EXE]); ++ free((char *) context.meta[CONTEXT_UNIT]); + + return r; + } + + static int process_backtrace(int argc, char *argv[]) { +- char *context[_CONTEXT_MAX] = {}; ++ Context context = {}; + _cleanup_free_ char *message = NULL; + _cleanup_free_ struct iovec *iovec = NULL; + size_t n_iovec, n_allocated, n_to_free = 0, i; +@@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) { + return -EINVAL; + } + +- context[CONTEXT_PID] = argv[2 + CONTEXT_PID]; +- context[CONTEXT_UID] = argv[2 + CONTEXT_UID]; +- context[CONTEXT_GID] = argv[2 + CONTEXT_GID]; +- context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; +- context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; +- context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; +- context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; ++ context.meta[CONTEXT_PID] = argv[2 + CONTEXT_PID]; ++ context.meta[CONTEXT_UID] = argv[2 + CONTEXT_UID]; ++ context.meta[CONTEXT_GID] = argv[2 + CONTEXT_GID]; ++ context.meta[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; ++ context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; ++ context.meta[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; ++ context.meta[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; + + n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL; + /* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */ +@@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) { + if (!iovec) + return log_oom(); + +- r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); ++ r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); + if (r < 0) + goto finish; + if (r > 0) { +@@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) { + if (journal_importer_eof(&importer)) { + log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter"); + +- message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], +- " (", context[CONTEXT_COMM], ")" +- " of user ", context[CONTEXT_UID], +- " failed with ", context[CONTEXT_SIGNAL]); ++ message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID], ++ " (", context.meta[CONTEXT_COMM], ")" ++ " of user ", context.meta[CONTEXT_UID], ++ " failed with ", context.meta[CONTEXT_SIGNAL]); + if (!message) { + r = log_oom(); + goto finish; +@@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) { + free(iovec[i].iov_base); + + /* Those fields are allocated by gather_pid_metadata */ +- free(context[CONTEXT_COMM]); +- free(context[CONTEXT_EXE]); +- free(context[CONTEXT_UNIT]); ++ free((char *) context.meta[CONTEXT_COMM]); ++ free((char *) context.meta[CONTEXT_EXE]); ++ free((char *) context.meta[CONTEXT_UNIT]); + + return r; + } diff --git a/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch b/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch new file mode 100644 index 0000000..707bdda --- /dev/null +++ b/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch @@ -0,0 +1,354 @@ +From d178865d3d9940423f4d99360e3dc2fcaf0b2c96 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 28 Nov 2022 12:12:55 +0100 +Subject: [PATCH] coredump: do not allow user to access coredumps with changed + uid/gid/capabilities + +When the user starts a program which elevates its permissions via setuid, +setgid, or capabilities set on the file, it may access additional information +which would then be visible in the coredump. We shouldn't make the the coredump +visible to the user in such cases. + +Reported-by: Matthias Gerstner + +This reads the /proc//auxv file and attaches it to the process metadata as +PROC_AUXV. Before the coredump is submitted, it is parsed and if either +at_secure was set (which the kernel will do for processes that are setuid, +setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file +is not made accessible to the user. If we can't access this data, we assume the +file should not be made accessible either. In principle we could also access +the auxv data from a note in the core file, but that is much more complex and +it seems better to use the stand-alone file that is provided by the kernel. + +Attaching auxv is both convient for this patch (because this way it's passed +between the stages along with other fields), but I think it makes sense to save +it in general. + +We use the information early in the core file to figure out if the program was +32-bit or 64-bit and its endianness. This way we don't need heuristics to guess +whether the format of the auxv structure. This test might reject some cases on +fringe architecutes. But the impact would be limited: we just won't grant the +user permissions to view the coredump file. If people report that we're missing +some cases, we can always enhance this to support more architectures. + +I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and +ppc64el, but not the whole coredump handling. + +(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03) + +Resolves: #2155520 +--- + src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 182 insertions(+), 8 deletions(-) + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index ebc56d8342..d8acd2d3a7 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -88,11 +89,13 @@ enum { + CONTEXT_COMM, + CONTEXT_EXE, + CONTEXT_UNIT, ++ CONTEXT_PROC_AUXV, + _CONTEXT_MAX + }; + + typedef struct Context { + const char *meta[_CONTEXT_MAX]; ++ size_t meta_size[_CONTEXT_MAX]; + } Context; + + typedef enum CoredumpStorage { +@@ -148,8 +151,7 @@ static inline uint64_t storage_size_max(void) { + return 0; + } + +-static int fix_acl(int fd, uid_t uid) { +- ++static int fix_acl(int fd, uid_t uid, bool allow_user) { + #if HAVE_ACL + _cleanup_(acl_freep) acl_t acl = NULL; + acl_entry_t entry; +@@ -157,6 +159,11 @@ static int fix_acl(int fd, uid_t uid) { + int r; + + assert(fd >= 0); ++ assert(uid_is_valid(uid)); ++ ++ /* We don't allow users to read coredumps if the uid or capabilities were changed. */ ++ if (!allow_user) ++ return 0; + + if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY) + return 0; +@@ -235,7 +242,8 @@ static int fix_permissions( + const char *filename, + const char *target, + const Context *context, +- uid_t uid) { ++ uid_t uid, ++ bool allow_user) { + + int r; + +@@ -245,7 +253,7 @@ static int fix_permissions( + + /* Ignore errors on these */ + (void) fchmod(fd, 0640); +- (void) fix_acl(fd, uid); ++ (void) fix_acl(fd, uid, allow_user); + (void) fix_xattr(fd, context); + + if (fsync(fd) < 0) +@@ -316,6 +324,154 @@ static int make_filename(const Context *context, char **ret) { + return 0; + } + ++static int parse_auxv64( ++ const uint64_t *auxv, ++ size_t size_bytes, ++ int *at_secure, ++ uid_t *uid, ++ uid_t *euid, ++ gid_t *gid, ++ gid_t *egid) { ++ ++ assert(auxv || size_bytes == 0); ++ ++ if (size_bytes % (2 * sizeof(uint64_t)) != 0) ++ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes); ++ ++ size_t words = size_bytes / sizeof(uint64_t); ++ ++ /* Note that we set output variables even on error. */ ++ ++ for (size_t i = 0; i + 1 < words; i += 2) ++ switch (auxv[i]) { ++ case AT_SECURE: ++ *at_secure = auxv[i + 1] != 0; ++ break; ++ case AT_UID: ++ *uid = auxv[i + 1]; ++ break; ++ case AT_EUID: ++ *euid = auxv[i + 1]; ++ break; ++ case AT_GID: ++ *gid = auxv[i + 1]; ++ break; ++ case AT_EGID: ++ *egid = auxv[i + 1]; ++ break; ++ case AT_NULL: ++ if (auxv[i + 1] != 0) ++ goto error; ++ return 0; ++ } ++ error: ++ return log_warning_errno(-ENODATA, ++ "AT_NULL terminator not found, cannot parse auxv structure."); ++} ++ ++static int parse_auxv32( ++ const uint32_t *auxv, ++ size_t size_bytes, ++ int *at_secure, ++ uid_t *uid, ++ uid_t *euid, ++ gid_t *gid, ++ gid_t *egid) { ++ ++ assert(auxv || size_bytes == 0); ++ ++ size_t words = size_bytes / sizeof(uint32_t); ++ ++ if (size_bytes % (2 * sizeof(uint32_t)) != 0) ++ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes); ++ ++ /* Note that we set output variables even on error. */ ++ ++ for (size_t i = 0; i + 1 < words; i += 2) ++ switch (auxv[i]) { ++ case AT_SECURE: ++ *at_secure = auxv[i + 1] != 0; ++ break; ++ case AT_UID: ++ *uid = auxv[i + 1]; ++ break; ++ case AT_EUID: ++ *euid = auxv[i + 1]; ++ break; ++ case AT_GID: ++ *gid = auxv[i + 1]; ++ break; ++ case AT_EGID: ++ *egid = auxv[i + 1]; ++ break; ++ case AT_NULL: ++ if (auxv[i + 1] != 0) ++ goto error; ++ return 0; ++ } ++ error: ++ return log_warning_errno(-ENODATA, ++ "AT_NULL terminator not found, cannot parse auxv structure."); ++} ++ ++static int grant_user_access(int core_fd, const Context *context) { ++ int at_secure = -1; ++ uid_t uid = UID_INVALID, euid = UID_INVALID; ++ uid_t gid = GID_INVALID, egid = GID_INVALID; ++ int r; ++ ++ assert(core_fd >= 0); ++ assert(context); ++ ++ if (!context->meta[CONTEXT_PROC_AUXV]) ++ return log_warning_errno(-ENODATA, "No auxv data, not adjusting permissions."); ++ ++ uint8_t elf[EI_NIDENT]; ++ errno = 0; ++ if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf)) ++ return log_warning_errno(errno > 0 ? -errno : -EIO, ++ "Failed to pread from coredump fd: %s", ++ errno > 0 ? STRERROR(errno) : "Unexpected EOF"); ++ ++ if (elf[EI_MAG0] != ELFMAG0 || ++ elf[EI_MAG1] != ELFMAG1 || ++ elf[EI_MAG2] != ELFMAG2 || ++ elf[EI_MAG3] != ELFMAG3 || ++ elf[EI_VERSION] != EV_CURRENT) ++ return log_info_errno(-EUCLEAN, ++ "Core file does not have ELF header, not adjusting permissions."); ++ if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) || ++ !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB)) ++ return log_info_errno(-EUCLEAN, ++ "Core file has strange ELF class, not adjusting permissions."); ++ ++ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN)) ++ return log_info_errno(-EUCLEAN, ++ "Core file has non-native endianness, not adjusting permissions."); ++ ++ if (elf[EI_CLASS] == ELFCLASS64) ++ r = parse_auxv64((const uint64_t*) context->meta[CONTEXT_PROC_AUXV], ++ context->meta_size[CONTEXT_PROC_AUXV], ++ &at_secure, &uid, &euid, &gid, &egid); ++ else ++ r = parse_auxv32((const uint32_t*) context->meta[CONTEXT_PROC_AUXV], ++ context->meta_size[CONTEXT_PROC_AUXV], ++ &at_secure, &uid, &euid, &gid, &egid); ++ if (r < 0) ++ return r; ++ ++ /* We allow access if we got all the data and at_secure is not set and ++ * the uid/gid matches euid/egid. */ ++ bool ret = ++ at_secure == 0 && ++ uid != UID_INVALID && euid != UID_INVALID && uid == euid && ++ gid != GID_INVALID && egid != GID_INVALID && gid == egid; ++ log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)", ++ ret ? "permit" : "restrict", ++ uid, euid, gid, egid, yes_no(at_secure)); ++ return ret; ++} ++ + static int save_external_coredump( + const Context *context, + int input_fd, +@@ -395,6 +551,8 @@ static int save_external_coredump( + goto fail; + } + ++ bool allow_user = grant_user_access(fd, context) > 0; ++ + #if HAVE_XZ || HAVE_LZ4 + /* If we will remove the coredump anyway, do not compress. */ + if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) { +@@ -420,7 +578,7 @@ static int save_external_coredump( + goto fail_compressed; + } + +- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid); ++ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user); + if (r < 0) + goto fail_compressed; + +@@ -443,7 +601,7 @@ static int save_external_coredump( + uncompressed: + #endif + +- r = fix_permissions(fd, tmp, fn, context, uid); ++ r = fix_permissions(fd, tmp, fn, context, uid, allow_user); + if (r < 0) + goto fail; + +@@ -842,6 +1000,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) { + [CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=", + [CONTEXT_COMM] = "COREDUMP_COMM=", + [CONTEXT_EXE] = "COREDUMP_EXE=", ++ [CONTEXT_PROC_AUXV] = "COREDUMP_PROC_AUXV=", + }; + + unsigned i; +@@ -862,6 +1021,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) { + /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the + * buffer, though not included in the iov_len count. (see below) */ + context->meta[i] = p; ++ context->meta_size[i] = iovec->iov_len - strlen(context_field_names[i]); + break; + } + } +@@ -1070,7 +1230,7 @@ static int gather_pid_metadata( + char **comm_fallback, + struct iovec *iovec, size_t *n_iovec) { + +- /* We need 27 empty slots in iovec! ++ /* We need 28 empty slots in iovec! + * + * Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid, + * with the first n_iovec fields initialized.) */ +@@ -1078,6 +1238,7 @@ static int gather_pid_metadata( + uid_t owner_uid; + pid_t pid; + char *t; ++ size_t size; + const char *p; + int r, signo; + +@@ -1187,6 +1348,19 @@ static int gather_pid_metadata( + if (read_full_file(p, &t, NULL) >=0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t); + ++ /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */ ++ p = procfs_file_alloca(pid, "auxv"); ++ if (read_full_file(p, &t, &size) >= 0) { ++ char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1); ++ if (buf) { ++ /* Add a dummy terminator to make save_context() happy. */ ++ *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0'; ++ iovec[(*n_iovec)++] = IOVEC_MAKE(buf, size + strlen("COREDUMP_PROC_AUXV=")); ++ } ++ ++ free(t); ++ } ++ + if (get_process_cwd(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t); + +@@ -1219,7 +1393,7 @@ static int gather_pid_metadata( + static int process_kernel(int argc, char* argv[]) { + + Context context = {}; +- struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS]; ++ struct iovec iovec[30 + SUBMIT_COREDUMP_FIELDS]; + size_t i, n_iovec, n_to_free = 0; + int r; + diff --git a/SOURCES/0863-logind-remember-our-idle-state-and-use-it-to-detect-.patch b/SOURCES/0863-logind-remember-our-idle-state-and-use-it-to-detect-.patch new file mode 100644 index 0000000..583749a --- /dev/null +++ b/SOURCES/0863-logind-remember-our-idle-state-and-use-it-to-detect-.patch @@ -0,0 +1,70 @@ +From a55bdb007ca24900a704f72359305b04125d9e05 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 20 Apr 2022 10:13:43 +0200 +Subject: [PATCH] logind: remember our idle state and use it to detect idle + level transitions + +Fixes #16391 + +(cherry picked from commit 4e2cfb778b9ed7f22ee98f48f28cf8678d25ad32) + +Resolved: #1866955 +--- + src/login/logind.c | 23 +++++++++++++++++++---- + src/login/logind.h | 1 + + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/src/login/logind.c b/src/login/logind.c +index 6b576dad0d..bb1d3f3523 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -1027,18 +1027,33 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us + n = now(CLOCK_MONOTONIC); + + r = manager_get_idle_hint(m, &since); +- if (r <= 0) ++ if (r <= 0) { + /* Not idle. Let's check if after a timeout it might be idle then. */ + elapse = n + m->idle_action_usec; +- else { ++ m->was_idle = false; ++ } else { ++ + /* Idle! Let's see if it's time to do something, or if + * we shall sleep for longer. */ + + if (n >= since.monotonic + m->idle_action_usec && + (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) { +- log_info("System idle. Taking action."); ++ bool is_edge = false; ++ ++ /* We weren't idle previously or some activity happened while we were sleeping, and now we are ++ * idle. Let's remember that for the next time and make this an edge transition. */ ++ if (!m->was_idle || since.monotonic >= m->idle_action_not_before_usec) { ++ is_edge = true; ++ m->was_idle = true; ++ } ++ ++ if (m->idle_action == HANDLE_LOCK && !is_edge) ++ /* We are idle and we were before so we are actually not taking any action. */ ++ log_debug("System idle."); ++ else ++ log_info("System idle. Doing %s operation.", handle_action_to_string(m->idle_action)); + +- manager_handle_action(m, 0, m->idle_action, false, false); ++ manager_handle_action(m, 0, m->idle_action, false, is_edge); + m->idle_action_not_before_usec = n; + } + +diff --git a/src/login/logind.h b/src/login/logind.h +index 606adf4fe6..b9b4a5113f 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -101,6 +101,7 @@ struct Manager { + usec_t idle_action_usec; + usec_t idle_action_not_before_usec; + HandleAction idle_action; ++ bool was_idle; + + usec_t stop_idle_session_usec; + diff --git a/SOURCES/0864-test-import-logind-test-from-debian-ubuntu-test-suit.patch b/SOURCES/0864-test-import-logind-test-from-debian-ubuntu-test-suit.patch new file mode 100644 index 0000000..6c058f8 --- /dev/null +++ b/SOURCES/0864-test-import-logind-test-from-debian-ubuntu-test-suit.patch @@ -0,0 +1,103 @@ +From 1925845dc10330e4b48fec68333fac6ef2b7bf5c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 1 Jun 2022 08:56:08 +0900 +Subject: [PATCH] test: import logind test from debian/ubuntu test suite + +[dtardon: Picked just the scaffolding, not the tests themselves.] + +(cherry picked from commit 9c94ab0f6ff22da4278a6e9a93ddc480607c55ac) + +Related: #1866955 +--- + test/TEST-35-LOGIN/Makefile | 1 + + test/TEST-35-LOGIN/test.sh | 55 +++++++++++++++++++++++++++++++++ + test/TEST-35-LOGIN/testsuite.sh | 9 ++++++ + 3 files changed, 65 insertions(+) + create mode 120000 test/TEST-35-LOGIN/Makefile + create mode 100755 test/TEST-35-LOGIN/test.sh + create mode 100755 test/TEST-35-LOGIN/testsuite.sh + +diff --git a/test/TEST-35-LOGIN/Makefile b/test/TEST-35-LOGIN/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-35-LOGIN/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh +new file mode 100755 +index 0000000000..32410c8149 +--- /dev/null ++++ b/test/TEST-35-LOGIN/test.sh +@@ -0,0 +1,55 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="LOGIN" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++test_setup() { ++ create_empty_image ++ mkdir -p "$TESTDIR"/root ++ mount "${LOOPDEV}p1" "$TESTDIR"/root ++ ++ ( ++ LOG_LEVEL=5 ++ eval $(udevadm info --export --query=env --name="${LOOPDEV}p2") ++ ++ setup_basic_environment ++ ++ inst_binary pkill ++ inst_binary useradd ++ inst_binary userdel ++ ++ # 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 </failed ++ ++touch /testok ++rm /failed diff --git a/SOURCES/0865-test-introduce-inst_recursive-helper-function.patch b/SOURCES/0865-test-introduce-inst_recursive-helper-function.patch new file mode 100644 index 0000000..cb98216 --- /dev/null +++ b/SOURCES/0865-test-introduce-inst_recursive-helper-function.patch @@ -0,0 +1,37 @@ +From 21c281585983fe2efc2b74d712d98ff7e6c013b1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:11:00 +0900 +Subject: [PATCH] test: introduce inst_recursive() helper function + +(cherry picked from commit da0465dc95388afc15598357452afef85035c639) + +Related: #1866955 +--- + test/test-functions | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/test/test-functions b/test/test-functions +index 19363be858..9606a1b085 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1224,6 +1224,20 @@ inst_any() { + return 1 + } + ++inst_recursive() { ++ local p item ++ ++ for p in "$@"; do ++ while read -r item; do ++ if [[ -d "$item" ]]; then ++ inst_dir "$item" ++ elif [[ -f "$item" ]]; then ++ inst_simple "$item" ++ fi ++ done < <(find "$p" 2>/dev/null) ++ done ++} ++ + # dracut_install [-o ] [ ... ] + # Install to the initramfs image + # -o optionally install the and don't fail, if it is not there diff --git a/SOURCES/0866-tests-verify-that-Lock-D-Bus-signal-is-sent-when-Idl.patch b/SOURCES/0866-tests-verify-that-Lock-D-Bus-signal-is-sent-when-Idl.patch new file mode 100644 index 0000000..f1fe13a --- /dev/null +++ b/SOURCES/0866-tests-verify-that-Lock-D-Bus-signal-is-sent-when-Idl.patch @@ -0,0 +1,148 @@ +From 638c2418e705410344e07e77f944530df0f4608f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 1 Jul 2022 12:59:57 +0200 +Subject: [PATCH] tests: verify that Lock D-Bus signal is sent when + IdleAction=lock + +(cherry picked from commit 181656fc0faa885d69bc34822b8e9b5de3fdf6bf) + +Related: #1866955 +--- + test/TEST-35-LOGIN/test.sh | 11 +++- + test/TEST-35-LOGIN/testsuite.sh | 93 +++++++++++++++++++++++++++++++++ + 2 files changed, 103 insertions(+), 1 deletion(-) + +diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh +index 32410c8149..f83afcff49 100755 +--- a/test/TEST-35-LOGIN/test.sh ++++ b/test/TEST-35-LOGIN/test.sh +@@ -14,14 +14,23 @@ test_setup() { + + ( + LOG_LEVEL=5 +- eval $(udevadm info --export --query=env --name="${LOOPDEV}p2") ++ eval "$(udevadm info --export --query=env --name="${LOOPDEV}p2")" + + setup_basic_environment + ++ inst_binary awk + inst_binary pkill + inst_binary useradd + inst_binary userdel + ++ if command -v expect >/dev/null && command -v tclsh >/dev/null ; then ++ # shellcheck disable=SC2016 ++ version="$(tclsh <<< 'puts $tcl_version')" ++ ++ dracut_install expect ++ inst_recursive /usr/lib64/tcl"$version" /usr/share/tcl"$version" ++ fi ++ + # 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 +diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh +index 9855b4bc80..e4d72beb74 100755 +--- a/test/TEST-35-LOGIN/testsuite.sh ++++ b/test/TEST-35-LOGIN/testsuite.sh +@@ -3,7 +3,100 @@ + set -eux + set -o pipefail + ++setup_idle_action_lock() { ++ useradd testuser ||: ++ ++ mkdir -p /run/systemd/logind.conf.d/ ++ cat >/run/systemd/logind.conf.d/idle-action-lock.conf </run/systemd/systemd-logind.service.d/debug.conf </dev/null ; then ++ echo >&2 "expect not installed, skiping test ${FUNCNAME[0]}" ++ return 0 ++ fi ++ ++ setup_idle_action_lock ++ trap teardown_idle_action_lock RETURN ++ ++ if loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -q testuser ; then ++ echo >&2 "Session of the \'testuser\' is already present." ++ return 1 ++ fi ++ ++ # IdleActionSec is set 1s but the accuracy of associated timer is 30s so we ++ # need to sleep in worst case for 31s to make sure timer elapsed. We sleep ++ # here for 35s to accomodate for any possible scheudling delays. ++ cat > /tmp/test.exp < dbus.log & ++ ++ expect /tmp/test.exp & ++ ++ # Sleep a bit to give expect time to spawn systemd-run before we check for ++ # the presence of resulting session. ++ sleep 2 ++ if [ "$(loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -c testuser)" != 1 ] ; then ++ echo >&2 "\'testuser\' is expected to have exactly one session running." ++ return 1 ++ fi ++ ++ wait %2 ++ sleep 20 ++ kill %1 ++ ++ # We slept for 35s , in that interval all sessions should have become idle ++ # and "Lock" signal should have been sent out. Then we wrote to tty to make ++ # session active again and next we slept for another 35s so sessions have ++ # become idle again. 'Lock' signal is sent out for each session, we have at ++ # least one session, so minimum of 2 "Lock" signals must have been sent. ++ if [ "$(grep -c Member=Lock dbus.log)" -lt 2 ]; then ++ echo >&2 "Too few 'Lock' D-Bus signal sent, expected at least 2." ++ return 1 ++ fi ++ ++ journalctl -b -u systemd-logind.service --since="$ts" > logind.log ++ if [ "$(grep -c 'System idle. Doing lock operation.' logind.log)" -lt 2 ]; then ++ echo >&2 "System haven't entered idle state at least 2 times." ++ return 1 ++ fi ++ ++ rm -f dbus.log logind.log ++} ++ + : >/failed + ++test_lock_idle_action ++ + touch /testok + rm /failed diff --git a/SOURCES/0867-systemctl-simplify-halt_main.patch b/SOURCES/0867-systemctl-simplify-halt_main.patch new file mode 100644 index 0000000..bd1d085 --- /dev/null +++ b/SOURCES/0867-systemctl-simplify-halt_main.patch @@ -0,0 +1,86 @@ +From 797b00e6a6f33d2b74beba02f678bf4d12e2146b Mon Sep 17 00:00:00 2001 +From: Ludwig Nussel +Date: Tue, 14 Dec 2021 17:27:05 +0100 +Subject: [PATCH] systemctl: simplify halt_main() + +The code at this point is not able to tell whether it was called as +halt/poweroff/reboot or shutdown with time "now". +The code also takes a shortcut to skip logind if called as root. +That however means asking shutdown for immediate action won't trigger a +wall message. +As per https://github.com/systemd/systemd/issues/8424#issuecomment-374677315 +all commands should trigger a wall message. +That simplifies the code as we can try logind first always. + +(cherry picked from commit adefc8789b63225662e50ceaa282f9553b5c64eb) + +Resolves: #2053273 +--- + src/systemctl/systemctl.c | 44 ++++++++++++++++----------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index b967550b97..4bedb52f2a 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -8658,34 +8658,23 @@ static int logind_schedule_shutdown(void) { + static int halt_main(void) { + int r; + +- r = logind_check_inhibitors(arg_action); +- if (r < 0) +- return r; +- ++ /* always try logind first */ + if (arg_when > 0) +- return logind_schedule_shutdown(); +- +- if (geteuid() != 0) { +- if (arg_dry_run || arg_force > 0) { +- (void) must_be_root(); +- return -EPERM; +- } ++ r = logind_schedule_shutdown(); ++ else { ++ r = logind_check_inhibitors(arg_action); ++ if (r < 0) ++ return r; + +- /* Try logind if we are a normal user and no special +- * mode applies. Maybe PolicyKit allows us to shutdown +- * the machine. */ +- if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) { +- r = logind_reboot(arg_action); +- if (r >= 0) +- return r; +- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) +- /* requested operation is not +- * supported on the local system or +- * already in progress */ +- return r; +- /* on all other errors, try low-level operation */ +- } ++ r = logind_reboot(arg_action); + } ++ if (r >= 0) ++ return r; ++ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) ++ /* Requested operation is not supported on the local system or already in ++ * progress */ ++ return r; ++ /* on all other errors, try low-level operation */ + + /* In order to minimize the difference between operation with and + * without logind, we explicitly enable non-blocking mode for this, +@@ -8695,7 +8684,10 @@ static int halt_main(void) { + if (!arg_dry_run && !arg_force) + return start_with_fallback(); + +- assert(geteuid() == 0); ++ if (geteuid() != 0) { ++ (void) must_be_root(); ++ return -EPERM; ++ } + + if (!arg_no_wtmp) { + if (sd_booted() > 0) diff --git a/SOURCES/0868-systemctl-shutdown-don-t-fallback-on-auth-fail.patch b/SOURCES/0868-systemctl-shutdown-don-t-fallback-on-auth-fail.patch new file mode 100644 index 0000000..dd7b2dd --- /dev/null +++ b/SOURCES/0868-systemctl-shutdown-don-t-fallback-on-auth-fail.patch @@ -0,0 +1,51 @@ +From 1d63577410cde215c04921d62f435259a6b258d7 Mon Sep 17 00:00:00 2001 +From: Ludwig Nussel +Date: Mon, 20 Dec 2021 18:05:50 +0100 +Subject: [PATCH] systemctl: shutdown don't fallback on auth fail + +For shutdowns don't fall back to starting the target directly if talking +to logind failed with auth failure. That would just lead to another +polkit auth attempt. + +(cherry picked from commit 38d55bf2641f345445cb4e6a5e5e808555591db2) + +Related: #2053273 +--- + src/systemctl/systemctl.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 4bedb52f2a..199f736f7f 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -3675,8 +3675,8 @@ static int start_special(int argc, char *argv[], void *userdata) { + r = logind_reboot(a); + if (r >= 0) + return r; +- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) +- /* requested operation is not supported or already in progress */ ++ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) ++ /* Requested operation requires auth, is not supported or already in progress */ + return r; + + /* On all other errors, try low-level operation. In order to minimize the difference between +@@ -8644,7 +8644,7 @@ static int logind_schedule_shutdown(void) { + action, + arg_when); + if (r < 0) +- return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r)); ++ return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r)); + + if (!arg_quiet) + log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when)); +@@ -8670,8 +8670,8 @@ static int halt_main(void) { + } + if (r >= 0) + return r; +- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) +- /* Requested operation is not supported on the local system or already in ++ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) ++ /* Requested operation requires auth, is not supported on the local system or already in + * progress */ + return r; + /* on all other errors, try low-level operation */ diff --git a/SOURCES/0869-systemctl-reintroduce-the-original-halt_main.patch b/SOURCES/0869-systemctl-reintroduce-the-original-halt_main.patch new file mode 100644 index 0000000..dce7359 --- /dev/null +++ b/SOURCES/0869-systemctl-reintroduce-the-original-halt_main.patch @@ -0,0 +1,82 @@ +From d36295d7c1b110d150b7af6e3354c28af4c4884d Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 30 Jan 2023 14:27:24 +0100 +Subject: [PATCH] systemctl: reintroduce the original halt_main() + +RHEL-only + +Related: #2053273 +--- + src/systemctl/systemctl.c | 59 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 199f736f7f..a26e4a913a 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -8655,6 +8655,65 @@ static int logind_schedule_shutdown(void) { + #endif + } + ++static int halt_main_old(void) { ++ int r; ++ ++ r = logind_check_inhibitors(arg_action); ++ if (r < 0) ++ return r; ++ ++ if (arg_when > 0) ++ return logind_schedule_shutdown(); ++ ++ if (geteuid() != 0) { ++ if (arg_dry_run || arg_force > 0) { ++ (void) must_be_root(); ++ return -EPERM; ++ } ++ ++ /* Try logind if we are a normal user and no special ++ * mode applies. Maybe PolicyKit allows us to shutdown ++ * the machine. */ ++ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) { ++ r = logind_reboot(arg_action); ++ if (r >= 0) ++ return r; ++ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) ++ /* requested operation is not ++ * supported on the local system or ++ * already in progress */ ++ return r; ++ /* on all other errors, try low-level operation */ ++ } ++ } ++ ++ /* In order to minimize the difference between operation with and ++ * without logind, we explicitly enable non-blocking mode for this, ++ * as logind's shutdown operations are always non-blocking. */ ++ arg_no_block = true; ++ ++ if (!arg_dry_run && !arg_force) ++ return start_with_fallback(); ++ ++ assert(geteuid() == 0); ++ ++ if (!arg_no_wtmp) { ++ if (sd_booted() > 0) ++ log_debug("Not writing utmp record, assuming that systemd-update-utmp is used."); ++ else { ++ r = utmp_put_shutdown(); ++ if (r < 0) ++ log_warning_errno(r, "Failed to write utmp record: %m"); ++ } ++ } ++ ++ if (arg_dry_run) ++ return 0; ++ ++ r = halt_now(arg_action); ++ return log_error_errno(r, "Failed to reboot: %m"); ++} ++ + static int halt_main(void) { + int r; + diff --git a/SOURCES/0870-systemctl-preserve-old-behavior-unless-requested.patch b/SOURCES/0870-systemctl-preserve-old-behavior-unless-requested.patch new file mode 100644 index 0000000..e652470 --- /dev/null +++ b/SOURCES/0870-systemctl-preserve-old-behavior-unless-requested.patch @@ -0,0 +1,44 @@ +From 74632586b46c7e88b09c57eec50f9c4aed254b98 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 30 Jan 2023 14:31:23 +0100 +Subject: [PATCH] systemctl: preserve old behavior unless requested + +Currently, the legacy shutdown commands ignore inhibitors and reboot +immediately if run by root. Let's preserve that behavior in RHEL-8 by +default. The new behavior can be turned on by those who want it by +exporting SYSTEMD_NEW_SHUTDOWN=1 . + +RHEL-only + +Related: #2053273 +--- + src/systemctl/systemctl.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index a26e4a913a..1546119ce5 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -8714,7 +8714,7 @@ static int halt_main_old(void) { + return log_error_errno(r, "Failed to reboot: %m"); + } + +-static int halt_main(void) { ++static int halt_main_new(void) { + int r; + + /* always try logind first */ +@@ -8765,6 +8765,13 @@ static int halt_main(void) { + return log_error_errno(r, "Failed to reboot: %m"); + } + ++static int halt_main(void) { ++ if (getenv_bool("SYSTEMD_NEW_SHUTDOWN") > 0) ++ return halt_main_new(); ++ else ++ return halt_main_old(); ++} ++ + static int runlevel_main(void) { + int r, runlevel, previous; + diff --git a/SOURCES/0871-pam_systemd-suppress-LOG_DEBUG-log-messages-if-debug.patch b/SOURCES/0871-pam_systemd-suppress-LOG_DEBUG-log-messages-if-debug.patch new file mode 100644 index 0000000..70e8f6f --- /dev/null +++ b/SOURCES/0871-pam_systemd-suppress-LOG_DEBUG-log-messages-if-debug.patch @@ -0,0 +1,43 @@ +From ea3910e561f043f5a131a846862955c77169da1b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 19 Nov 2018 11:39:45 +0100 +Subject: [PATCH] pam_systemd: suppress LOG_DEBUG log messages if debugging is + off + +In the PAM module we need to suppress LOG_DEBUG messages manually, if +debug logging is not on, as PAM won't do this for us. We did this +correctly for most log messages already, but two were missing. Let's fix +those too. + +Fixes: #10822 +(cherry picked from commit 2675747f3cdd6f1e6236bbb2f79abfa53fb307f1) + +Resolves: #2170084 +--- + src/login/pam_systemd.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 64e1b4d1bf..c87e980b18 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -476,7 +476,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( + } + + if (seat && !streq(seat, "seat0") && vtnr != 0) { +- pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat); ++ if (debug) ++ pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat); + vtnr = 0; + } + +@@ -577,7 +578,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { +- pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r)); ++ if (debug) ++ pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r)); + return PAM_SUCCESS; + } else { + pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); diff --git a/SOURCES/0872-udev-net_id-introduce-naming-scheme-for-RHEL-8.8.patch b/SOURCES/0872-udev-net_id-introduce-naming-scheme-for-RHEL-8.8.patch new file mode 100644 index 0000000..c83b140 --- /dev/null +++ b/SOURCES/0872-udev-net_id-introduce-naming-scheme-for-RHEL-8.8.patch @@ -0,0 +1,50 @@ +From 33351e103734188a4a30b88e7f2ea0613d628599 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Thu, 16 Feb 2023 15:56:52 +0100 +Subject: [PATCH] udev/net_id: introduce naming scheme for RHEL-8.8 + +RHEL-only + +Resolves: #2170499 +--- + man/systemd.net-naming-scheme.xml | 6 ++++++ + src/udev/udev-builtin-net_id.c | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml +index a567483995..3cc7719e99 100644 +--- a/man/systemd.net-naming-scheme.xml ++++ b/man/systemd.net-naming-scheme.xml +@@ -328,6 +328,12 @@ + for that, the limit is increased to now 65535. + + ++ ++ rhel-8.8 ++ ++ Same as naming scheme rhel-8.7. ++ ++ + Note that latest may be used to denote the latest scheme known to this + particular version of systemd. + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index df84acf27c..ef2bb1b08e 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -141,6 +141,7 @@ typedef enum NamingSchemeFlags { + NAMING_RHEL_8_5 = NAMING_RHEL_8_4, + NAMING_RHEL_8_6 = NAMING_RHEL_8_4, + NAMING_RHEL_8_7 = NAMING_RHEL_8_4|NAMING_SLOT_FUNCTION_ID|NAMING_16BIT_INDEX, ++ NAMING_RHEL_8_8 = NAMING_RHEL_8_7, + + _NAMING_SCHEME_FLAGS_INVALID = -1, + } NamingSchemeFlags; +@@ -161,6 +162,7 @@ static const NamingScheme naming_schemes[] = { + { "rhel-8.5", NAMING_RHEL_8_5 }, + { "rhel-8.6", NAMING_RHEL_8_6 }, + { "rhel-8.7", NAMING_RHEL_8_7 }, ++ { "rhel-8.8", NAMING_RHEL_8_8 }, + /* … add more schemes here, as the logic to name devices is updated … */ + }; + diff --git a/SOURCES/0873-journald-add-API-to-move-logging-from-var-to-run-aga.patch b/SOURCES/0873-journald-add-API-to-move-logging-from-var-to-run-aga.patch new file mode 100644 index 0000000..f44f50b --- /dev/null +++ b/SOURCES/0873-journald-add-API-to-move-logging-from-var-to-run-aga.patch @@ -0,0 +1,176 @@ +From 8f0a91b5192b72eb8b0f06e04ef3515d0397fcb8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 5 Apr 2019 18:20:25 +0200 +Subject: [PATCH] journald: add API to move logging from /var to /run again + +We now have this nice little Varlink API, let's beef it up a bit. + +[dtardon: This diverges from the upstream commit in two ways: One is +that the new action is bound to a signal, as varlink is not available. +The other is that this introduces a new "flag" file +/run/systemd/journal/relinquished, which is essentially the opposite of +/run/systemd/journal/flushed (hence at most one of them may exist at any +time).] + +(cherry picked from commit b4e26d1d8e582d78e67ed766177f10e8e194404c) + +Related: #1873540 +--- + src/journal/journald-server.c | 64 ++++++++++++++++++++++++++++------- + 1 file changed, 51 insertions(+), 13 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 7632e2d9d0..279a32768c 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -283,13 +283,14 @@ static bool flushed_flag_is_set(void) { + return access("/run/systemd/journal/flushed", F_OK) >= 0; + } + +-static int system_journal_open(Server *s, bool flush_requested) { ++static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) { + const char *fn; + int r = 0; + + if (!s->system_journal && + IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && +- (flush_requested || flushed_flag_is_set())) { ++ (flush_requested || flushed_flag_is_set()) && ++ !relinquish_requested) { + + /* If in auto mode: first try to create the machine + * path, but not the prefix. +@@ -331,7 +332,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + + fn = strjoina(s->runtime_storage.path, "/system.journal"); + +- if (s->system_journal) { ++ if (s->system_journal && !relinquish_requested) { + + /* Try to open the runtime journal, but only + * if it already exists, so that we can flush +@@ -386,7 +387,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { + * else that's left the journals as NULL). + * + * Fixes https://github.com/systemd/systemd/issues/3968 */ +- (void) system_journal_open(s, false); ++ (void) system_journal_open(s, false, false); + + /* We split up user logs only on /var, not on /run. If the + * runtime file is open, we write to it exclusively, in order +@@ -964,7 +965,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) { + char ts[FORMAT_TIMESPAN_MAX]; + usec_t start; + unsigned n = 0; +- int r; ++ int r, k; + + assert(s); + +@@ -977,7 +978,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) { + if (require_flag_file && !flushed_flag_is_set()) + return 0; + +- (void) system_journal_open(s, true); ++ (void) system_journal_open(s, true, false); + + if (!s->system_journal) + return 0; +@@ -1056,6 +1057,13 @@ finish: + n), + NULL); + ++ if (unlink("/run/systemd/journal/relinquished") < 0 && errno != ENOENT) ++ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/relinquished, ignoring: %m"); ++ ++ k = touch("/run/systemd/journal/flushed"); ++ if (k < 0) ++ log_warning_errno(k, "Failed to touch /run/systemd/journal/flushed, ignoring: %m"); ++ + return r; + } + +@@ -1180,7 +1188,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + + static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; +- int r; + + assert(s); + +@@ -1190,10 +1197,6 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * + server_sync(s); + server_vacuum(s, false); + +- r = touch("/run/systemd/journal/flushed"); +- if (r < 0) +- log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m"); +- + server_space_usage_message(s, NULL); + return 0; + } +@@ -1250,12 +1253,43 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo + return 0; + } + ++ ++static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { ++ Server *s = userdata; ++ int r; ++ ++ assert(s); ++ ++ if (s->storage == STORAGE_NONE) ++ return 0; ++ ++ if (s->runtime_journal && !s->system_journal) ++ return 0; ++ ++ log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid); ++ ++ (void) system_journal_open(s, false, true); ++ ++ s->system_journal = journal_file_close(s->system_journal); ++ ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close); ++ set_clear_with_destructor(s->deferred_closes, journal_file_close); ++ ++ if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT) ++ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m") ; ++ ++ r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC)); ++ if (r < 0) ++ log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m"); ++ ++ return 0; ++} ++ + static int setup_signals(Server *s) { + int r; + + assert(s); + +- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0); ++ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+2, -1) >= 0); + + r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); + if (r < 0) +@@ -1294,6 +1328,10 @@ static int setup_signals(Server *s) { + if (r < 0) + return r; + ++ r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+2, dispatch_sigrtmin2, s); ++ if (r < 0) ++ return r; ++ + r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15); + if (r < 0) + return r; +@@ -1876,7 +1914,7 @@ int server_init(Server *s) { + + (void) client_context_acquire_default(s); + +- return system_journal_open(s, false); ++ return system_journal_open(s, false, false); + } + + void server_maybe_append_tags(Server *s) { diff --git a/SOURCES/0874-journalctl-add-new-relinquish-and-smart-relinquish-o.patch b/SOURCES/0874-journalctl-add-new-relinquish-and-smart-relinquish-o.patch new file mode 100644 index 0000000..65b8ac3 --- /dev/null +++ b/SOURCES/0874-journalctl-add-new-relinquish-and-smart-relinquish-o.patch @@ -0,0 +1,242 @@ +From fa93a97bdf18906d9517f4183802456986490c89 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 5 Apr 2019 18:21:02 +0200 +Subject: [PATCH] journalctl: add new --relinquish and --smart-relinquish + options + +The latter is identical to the former, but becomes a NOP if +/var/log/journal is on the same mount as /, and thus during shutdown +unmounting /var is not necessary and hence we can keep logging until the +very end. + +[dtardon: The only divergence from the upstream commit is the impl. of +relinquish_var().] + +(cherry picked from commit c0dfcb318c28d87e1176a8ad87ac7cc4ecc50305) + +Related: #1873540 +--- + src/journal/journalctl.c | 161 +++++++++++++++++++++++++-------------- + 1 file changed, 103 insertions(+), 58 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 228cfe7e49..6928c79a06 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -47,6 +47,7 @@ + #include "log.h" + #include "logs-show.h" + #include "mkdir.h" ++#include "mount-util.h" + #include "pager.h" + #include "parse-util.h" + #include "path-util.h" +@@ -162,6 +163,7 @@ static enum { + ACTION_UPDATE_CATALOG, + ACTION_LIST_BOOTS, + ACTION_FLUSH, ++ ACTION_RELINQUISH_VAR, + ACTION_SYNC, + ACTION_ROTATE, + ACTION_VACUUM, +@@ -358,6 +360,8 @@ static void help(void) { + " --vacuum-time=TIME Remove journal files older than specified time\n" + " --verify Verify journal file consistency\n" + " --sync Synchronize unwritten journal messages to disk\n" ++ " --relinquish-var Stop logging to disk, log to temporary file system\n" ++ " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n" + " --flush Flush all journal data from /run into /var\n" + " --rotate Request immediate rotation of the journal files\n" + " --header Show journal header information\n" +@@ -402,6 +406,8 @@ static int parse_argv(int argc, char *argv[]) { + ARG_UTC, + ARG_SYNC, + ARG_FLUSH, ++ ARG_RELINQUISH_VAR, ++ ARG_SMART_RELINQUISH_VAR, + ARG_ROTATE, + ARG_VACUUM_SIZE, + ARG_VACUUM_FILES, +@@ -411,64 +417,66 @@ static int parse_argv(int argc, char *argv[]) { + }; + + static const struct option options[] = { +- { "help", no_argument, NULL, 'h' }, +- { "version" , no_argument, NULL, ARG_VERSION }, +- { "no-pager", no_argument, NULL, ARG_NO_PAGER }, +- { "pager-end", no_argument, NULL, 'e' }, +- { "follow", no_argument, NULL, 'f' }, +- { "force", no_argument, NULL, ARG_FORCE }, +- { "output", required_argument, NULL, 'o' }, +- { "all", no_argument, NULL, 'a' }, +- { "full", no_argument, NULL, 'l' }, +- { "no-full", no_argument, NULL, ARG_NO_FULL }, +- { "lines", optional_argument, NULL, 'n' }, +- { "no-tail", no_argument, NULL, ARG_NO_TAIL }, +- { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, +- { "quiet", no_argument, NULL, 'q' }, +- { "merge", no_argument, NULL, 'm' }, +- { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */ +- { "boot", optional_argument, NULL, 'b' }, +- { "list-boots", no_argument, NULL, ARG_LIST_BOOTS }, +- { "dmesg", no_argument, NULL, 'k' }, +- { "system", no_argument, NULL, ARG_SYSTEM }, +- { "user", no_argument, NULL, ARG_USER }, +- { "directory", required_argument, NULL, 'D' }, +- { "file", required_argument, NULL, ARG_FILE }, +- { "root", required_argument, NULL, ARG_ROOT }, +- { "header", no_argument, NULL, ARG_HEADER }, +- { "identifier", required_argument, NULL, 't' }, +- { "priority", required_argument, NULL, 'p' }, +- { "grep", required_argument, NULL, 'g' }, +- { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE }, +- { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, +- { "interval", required_argument, NULL, ARG_INTERVAL }, +- { "verify", no_argument, NULL, ARG_VERIFY }, +- { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, +- { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, +- { "cursor", required_argument, NULL, 'c' }, +- { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, +- { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, +- { "since", required_argument, NULL, 'S' }, +- { "until", required_argument, NULL, 'U' }, +- { "unit", required_argument, NULL, 'u' }, +- { "user-unit", required_argument, NULL, ARG_USER_UNIT }, +- { "field", required_argument, NULL, 'F' }, +- { "fields", no_argument, NULL, 'N' }, +- { "catalog", no_argument, NULL, 'x' }, +- { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, +- { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, +- { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG }, +- { "reverse", no_argument, NULL, 'r' }, +- { "machine", required_argument, NULL, 'M' }, +- { "utc", no_argument, NULL, ARG_UTC }, +- { "flush", no_argument, NULL, ARG_FLUSH }, +- { "sync", no_argument, NULL, ARG_SYNC }, +- { "rotate", no_argument, NULL, ARG_ROTATE }, +- { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, +- { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, +- { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, +- { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME }, +- { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS }, ++ { "help", no_argument, NULL, 'h' }, ++ { "version" , no_argument, NULL, ARG_VERSION }, ++ { "no-pager", no_argument, NULL, ARG_NO_PAGER }, ++ { "pager-end", no_argument, NULL, 'e' }, ++ { "follow", no_argument, NULL, 'f' }, ++ { "force", no_argument, NULL, ARG_FORCE }, ++ { "output", required_argument, NULL, 'o' }, ++ { "all", no_argument, NULL, 'a' }, ++ { "full", no_argument, NULL, 'l' }, ++ { "no-full", no_argument, NULL, ARG_NO_FULL }, ++ { "lines", optional_argument, NULL, 'n' }, ++ { "no-tail", no_argument, NULL, ARG_NO_TAIL }, ++ { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */ ++ { "quiet", no_argument, NULL, 'q' }, ++ { "merge", no_argument, NULL, 'm' }, ++ { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */ ++ { "boot", optional_argument, NULL, 'b' }, ++ { "list-boots", no_argument, NULL, ARG_LIST_BOOTS }, ++ { "dmesg", no_argument, NULL, 'k' }, ++ { "system", no_argument, NULL, ARG_SYSTEM }, ++ { "user", no_argument, NULL, ARG_USER }, ++ { "directory", required_argument, NULL, 'D' }, ++ { "file", required_argument, NULL, ARG_FILE }, ++ { "root", required_argument, NULL, ARG_ROOT }, ++ { "header", no_argument, NULL, ARG_HEADER }, ++ { "identifier", required_argument, NULL, 't' }, ++ { "priority", required_argument, NULL, 'p' }, ++ { "grep", required_argument, NULL, 'g' }, ++ { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE }, ++ { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, ++ { "interval", required_argument, NULL, ARG_INTERVAL }, ++ { "verify", no_argument, NULL, ARG_VERIFY }, ++ { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, ++ { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, ++ { "cursor", required_argument, NULL, 'c' }, ++ { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, ++ { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, ++ { "since", required_argument, NULL, 'S' }, ++ { "until", required_argument, NULL, 'U' }, ++ { "unit", required_argument, NULL, 'u' }, ++ { "user-unit", required_argument, NULL, ARG_USER_UNIT }, ++ { "field", required_argument, NULL, 'F' }, ++ { "fields", no_argument, NULL, 'N' }, ++ { "catalog", no_argument, NULL, 'x' }, ++ { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, ++ { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, ++ { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG }, ++ { "reverse", no_argument, NULL, 'r' }, ++ { "machine", required_argument, NULL, 'M' }, ++ { "utc", no_argument, NULL, ARG_UTC }, ++ { "flush", no_argument, NULL, ARG_FLUSH }, ++ { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR }, ++ { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR }, ++ { "sync", no_argument, NULL, ARG_SYNC }, ++ { "rotate", no_argument, NULL, ARG_ROTATE }, ++ { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, ++ { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, ++ { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, ++ { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME }, ++ { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS }, + {} + }; + +@@ -893,6 +901,35 @@ static int parse_argv(int argc, char *argv[]) { + arg_action = ACTION_FLUSH; + break; + ++ case ARG_SMART_RELINQUISH_VAR: { ++ int root_mnt_id, log_mnt_id; ++ ++ /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown: ++ * if it's on the same mount as the root file system there's no point in ++ * relinquishing access and we can leave journald write to it until the very last ++ * moment. */ ++ ++ r = path_get_mnt_id("/", &root_mnt_id); ++ if (r < 0) ++ log_debug_errno(r, "Failed to get root mount ID, ignoring: %m"); ++ else { ++ r = path_get_mnt_id("/var/log/journal/", &log_mnt_id); ++ if (r < 0) ++ log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m"); ++ else if (root_mnt_id == log_mnt_id) { ++ log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var."); ++ return 0; ++ } else ++ log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it."); ++ } ++ ++ _fallthrough_; ++ } ++ ++ case ARG_RELINQUISH_VAR: ++ arg_action = ACTION_RELINQUISH_VAR; ++ break; ++ + case ARG_ROTATE: + arg_action = ACTION_ROTATE; + break; +@@ -2056,6 +2093,10 @@ static int send_signal_and_wait(int sig, const char *watch_path) { + return 0; + } + ++static int relinquish_var(void) { ++ return send_signal_and_wait(SIGRTMIN+2, "/run/systemd/journal/relinquished"); ++} ++ + static int rotate(void) { + return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated"); + } +@@ -2171,6 +2212,10 @@ int main(int argc, char *argv[]) { + r = flush_to_var(); + goto finish; + ++ case ACTION_RELINQUISH_VAR: ++ r = relinquish_var(); ++ goto finish; ++ + case ACTION_SYNC: + r = sync_journal(); + goto finish; diff --git a/SOURCES/0875-units-automatically-revert-to-run-logging-on-shutdow.patch b/SOURCES/0875-units-automatically-revert-to-run-logging-on-shutdow.patch new file mode 100644 index 0000000..e5b3898 --- /dev/null +++ b/SOURCES/0875-units-automatically-revert-to-run-logging-on-shutdow.patch @@ -0,0 +1,26 @@ +From ce6531045b337c3f793d1d74f1e5641e658805bb Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 5 Apr 2019 18:22:31 +0200 +Subject: [PATCH] units: automatically revert to /run logging on shutdown if + necessary + +Fixes: #867 +(cherry picked from commit 1e187d2dd52cbb4f0bb30e4d96acf7f72a145b91) + +Resolves: #1873540 +--- + units/systemd-journal-flush.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in +index 439f5f3f76..653dcebe0e 100644 +--- a/units/systemd-journal-flush.service.in ++++ b/units/systemd-journal-flush.service.in +@@ -19,6 +19,7 @@ RequiresMountsFor=/var/log/journal + + [Service] + ExecStart=@rootbindir@/journalctl --flush ++ExecStop=@rootbindir@/journalctl --smart-relinquish-var + Type=oneshot + RemainAfterExit=yes + TimeoutSec=90s diff --git a/SOURCES/0876-pstore-Tool-to-archive-contents-of-pstore.patch b/SOURCES/0876-pstore-Tool-to-archive-contents-of-pstore.patch new file mode 100644 index 0000000..be1c25a --- /dev/null +++ b/SOURCES/0876-pstore-Tool-to-archive-contents-of-pstore.patch @@ -0,0 +1,929 @@ +From 2f75df5cd6dcd56775fec9e89fc79672e702d826 Mon Sep 17 00:00:00 2001 +From: Eric DeVolder +Date: Thu, 16 May 2019 08:59:01 -0500 +Subject: [PATCH] pstore: Tool to archive contents of pstore +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch introduces the systemd pstore service which will archive the +contents of the Linux persistent storage filesystem, pstore, to other storage, +thus preserving the existing information contained in the pstore, and clearing +pstore storage for future error events. + +Linux provides a persistent storage file system, pstore[1], that can store +error records when the kernel dies (or reboots or powers-off). These records in +turn can be referenced to debug kernel problems (currently the kernel stuffs +the tail of the dmesg, which also contains a stack backtrace, into pstore). + +The pstore file system supports a variety of backends that map onto persistent +storage, such as the ACPI ERST[2, Section 18.5 Error Serialization] and UEFI +variables[3 Appendix N Common Platform Error Record]. The pstore backends +typically offer a relatively small amount of persistent storage, e.g. 64KiB, +which can quickly fill up and thus prevent subsequent kernel crashes from +recording errors. Thus there is a need to monitor and extract the pstore +contents so that future kernel problems can also record information in the +pstore. + +The pstore service is independent of the kdump service. In cloud environments +specifically, host and guest filesystems are on remote filesystems (eg. iSCSI +or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation +of networking software *and* hardware *and* infrastructure. Thus it may not be +possible to capture a kernel coredump to a file since writes over the network +may not be possible. + +The pstore backend, on the other hand, is completely local and provides a path +to store error records which will survive a reboot and aid in post-mortem +debugging. + +Usage Notes: +This tool moves files from /sys/fs/pstore into /var/lib/systemd/pstore. + +To enable kernel recording of error records into pstore, one must either pass +crash_kexec_post_notifiers[4] to the kernel command line or enable via 'echo Y + > /sys/module/kernel/parameters/crash_kexec_post_notifiers'. This option +invokes the recording of errors into pstore *before* an attempt to kexec/kdump +on a kernel crash. + +Optionally, to record reboots and shutdowns in the pstore, one can either pass +the printk.always_kmsg_dump[4] to the kernel command line or enable via 'echo Y > +/sys/module/printk/parameters/always_kmsg_dump'. This option enables code on the +shutdown path to record information via pstore. + +This pstore service is a oneshot service. When run, the service invokes +systemd-pstore which is a tool that performs the following: + - reads the pstore.conf configuration file + - collects the lists of files in the pstore (eg. /sys/fs/pstore) + - for certain file types (eg. dmesg) a handler is invoked + - for all other files, the file is moved from pstore + + - In the case of dmesg handler, final processing occurs as such: + - files processed in reverse lexigraphical order to faciliate + reconstruction of original dmesg + - the filename is examined to determine which dmesg it is a part + - the file is appended to the reconstructed dmesg + +For example, the following pstore contents: + + root@vm356:~# ls -al /sys/fs/pstore + total 0 + drwxr-x--- 2 root root 0 May 9 09:50 . + drwxr-xr-x 7 root root 0 May 9 09:50 .. + -r--r--r-- 1 root root 1610 May 9 09:49 dmesg-efi-155741337601001 + -r--r--r-- 1 root root 1778 May 9 09:49 dmesg-efi-155741337602001 + -r--r--r-- 1 root root 1726 May 9 09:49 dmesg-efi-155741337603001 + -r--r--r-- 1 root root 1746 May 9 09:49 dmesg-efi-155741337604001 + -r--r--r-- 1 root root 1686 May 9 09:49 dmesg-efi-155741337605001 + -r--r--r-- 1 root root 1690 May 9 09:49 dmesg-efi-155741337606001 + -r--r--r-- 1 root root 1775 May 9 09:49 dmesg-efi-155741337607001 + -r--r--r-- 1 root root 1811 May 9 09:49 dmesg-efi-155741337608001 + -r--r--r-- 1 root root 1817 May 9 09:49 dmesg-efi-155741337609001 + -r--r--r-- 1 root root 1795 May 9 09:49 dmesg-efi-155741337710001 + -r--r--r-- 1 root root 1770 May 9 09:49 dmesg-efi-155741337711001 + -r--r--r-- 1 root root 1796 May 9 09:49 dmesg-efi-155741337712001 + -r--r--r-- 1 root root 1787 May 9 09:49 dmesg-efi-155741337713001 + -r--r--r-- 1 root root 1808 May 9 09:49 dmesg-efi-155741337714001 + -r--r--r-- 1 root root 1754 May 9 09:49 dmesg-efi-155741337715001 + +results in the following: + + root@vm356:~# ls -al /var/lib/systemd/pstore/155741337/ + total 92 + drwxr-xr-x 2 root root 4096 May 9 09:50 . + drwxr-xr-x 4 root root 40 May 9 09:50 .. + -rw-r--r-- 1 root root 1610 May 9 09:50 dmesg-efi-155741337601001 + -rw-r--r-- 1 root root 1778 May 9 09:50 dmesg-efi-155741337602001 + -rw-r--r-- 1 root root 1726 May 9 09:50 dmesg-efi-155741337603001 + -rw-r--r-- 1 root root 1746 May 9 09:50 dmesg-efi-155741337604001 + -rw-r--r-- 1 root root 1686 May 9 09:50 dmesg-efi-155741337605001 + -rw-r--r-- 1 root root 1690 May 9 09:50 dmesg-efi-155741337606001 + -rw-r--r-- 1 root root 1775 May 9 09:50 dmesg-efi-155741337607001 + -rw-r--r-- 1 root root 1811 May 9 09:50 dmesg-efi-155741337608001 + -rw-r--r-- 1 root root 1817 May 9 09:50 dmesg-efi-155741337609001 + -rw-r--r-- 1 root root 1795 May 9 09:50 dmesg-efi-155741337710001 + -rw-r--r-- 1 root root 1770 May 9 09:50 dmesg-efi-155741337711001 + -rw-r--r-- 1 root root 1796 May 9 09:50 dmesg-efi-155741337712001 + -rw-r--r-- 1 root root 1787 May 9 09:50 dmesg-efi-155741337713001 + -rw-r--r-- 1 root root 1808 May 9 09:50 dmesg-efi-155741337714001 + -rw-r--r-- 1 root root 1754 May 9 09:50 dmesg-efi-155741337715001 + -rw-r--r-- 1 root root 26754 May 9 09:50 dmesg.txt + +where dmesg.txt is reconstructed from the group of related +dmesg-efi-155741337* files. + +Configuration file: +The pstore.conf configuration file has four settings, described below. + - Storage : one of "none", "external", or "journal". With "none", this + tool leaves the contents of pstore untouched. With "external", the + contents of the pstore are moved into the /var/lib/systemd/pstore, + as well as logged into the journal. With "journal", the contents of + the pstore are recorded only in the systemd journal. The default is + "external". + - Unlink : is a boolean. When "true", the default, then files in the + pstore are removed once processed. When "false", processing of the + pstore occurs normally, but the pstore files remain. + +References: +[1] "Persistent storage for a kernel's dying breath", + March 23, 2011. + https://lwn.net/Articles/434821/ + +[2] "Advanced Configuration and Power Interface Specification", + version 6.2, May 2017. + https://www.uefi.org/sites/default/files/resources/ACPI_6_2.pdf + +[3] "Unified Extensible Firmware Interface Specification", + version 2.8, March 2019. + https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf + +[4] "The kernel’s command-line parameters", + https://static.lwn.net/kerneldoc/admin-guide/kernel-parameters.html + +(cherry picked from commit 9b4abc69b201e5d7295e1b0762883659f053e747) + +Resolves: #2158832 +--- + man/pstore.conf.xml | 89 +++++++ + man/rules/meson.build | 2 + + man/systemd-pstore.xml | 99 ++++++++ + meson.build | 20 ++ + meson_options.txt | 2 + + src/pstore/meson.build | 10 + + src/pstore/pstore.c | 395 ++++++++++++++++++++++++++++++++ + src/pstore/pstore.conf | 16 ++ + units/meson.build | 1 + + units/systemd-pstore.service.in | 24 ++ + 10 files changed, 658 insertions(+) + create mode 100644 man/pstore.conf.xml + create mode 100644 man/systemd-pstore.xml + create mode 100644 src/pstore/meson.build + create mode 100644 src/pstore/pstore.c + create mode 100644 src/pstore/pstore.conf + create mode 100644 units/systemd-pstore.service.in + +diff --git a/man/pstore.conf.xml b/man/pstore.conf.xml +new file mode 100644 +index 0000000000..b5cda47d02 +--- /dev/null ++++ b/man/pstore.conf.xml +@@ -0,0 +1,89 @@ ++ ++ ++ ++ ++ ++ ++ pstore.conf ++ systemd ++ ++ ++ ++ pstore.conf ++ 5 ++ ++ ++ ++ pstore.conf ++ pstore.conf.d ++ PStore configuration file ++ ++ ++ ++ ++ /etc/systemd/pstore.conf ++ /etc/systemd/pstore.conf.d/* ++ ++ ++ ++ ++ Description ++ ++ This file configures the behavior of ++ systemd-pstore8, ++ a tool for archiving the contents of the persistent storage filesystem, ++ pstore. ++ ++ ++ ++ ++ ++ ++ Options ++ ++ All options are configured in the ++ [PStore] section: ++ ++ ++ ++ ++ Storage= ++ ++ Controls where to archive (i.e. copy) files from the pstore filesystem. One of none, ++ external, and journal. When ++ none, the tool exits without processing files in the pstore filesystem. ++ When external (the default), files are archived into /var/lib/systemd/pstore/, ++ and logged into the journal. ++ When journal, pstore file contents are logged only in the journal. ++ ++ ++ ++ ++ ++ Unlink= ++ ++ Controls whether or not files are removed from pstore after processing. ++ Takes a boolean value. When true, a pstore file is removed from the pstore once it has been ++ archived (either to disk or into the journal). When false, processing of pstore files occurs ++ normally, but the files remain in the pstore. ++ The default is true in order to maintain the pstore in a nearly empty state, so that the pstore ++ has storage available for the next kernel error event. ++ ++ ++ ++ ++ The defaults for all values are listed as comments in the ++ template /etc/systemd/pstore.conf file that ++ is installed by default. ++ ++ ++ ++ See Also ++ ++ systemd-journald.service8, ++ ++ ++ ++ +diff --git a/man/rules/meson.build b/man/rules/meson.build +index e6c0a99bbd..6295330c5e 100644 +--- a/man/rules/meson.build ++++ b/man/rules/meson.build +@@ -44,6 +44,7 @@ manpages = [ + ['os-release', '5', [], ''], + ['pam_systemd', '8', [], 'HAVE_PAM'], + ['portablectl', '1', [], 'ENABLE_PORTABLED'], ++ ['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'], + ['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'], + ['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'], + ['runlevel', '8', [], 'ENABLE_UTMP'], +@@ -633,6 +634,7 @@ manpages = [ + ['systemd-nspawn', '1', [], ''], + ['systemd-path', '1', [], ''], + ['systemd-portabled.service', '8', ['systemd-portabled'], 'ENABLE_PORTABLED'], ++ ['systemd-pstore', '8', ['systemd-pstore.service'], 'ENABLE_PSTORE'], + ['systemd-quotacheck.service', + '8', + ['systemd-quotacheck'], +diff --git a/man/systemd-pstore.xml b/man/systemd-pstore.xml +new file mode 100644 +index 0000000000..dd1aa5e83b +--- /dev/null ++++ b/man/systemd-pstore.xml +@@ -0,0 +1,99 @@ ++ ++ ++ ++ ++ ++ ++ ++ systemd-pstore ++ systemd ++ ++ ++ ++ systemd-pstore ++ 8 ++ ++ ++ ++ systemd-pstore ++ systemd-pstore.service ++ Tool to archive contents of the persistent storage filesytem ++ ++ ++ ++ /usr/lib/systemd/systemd-pstore ++ systemd-pstore.service ++ ++ ++ ++ Description ++ systemd-pstore.service is a system service that archives the ++ contents of the Linux persistent storage filesystem, pstore, to other storage, ++ thus preserving the existing information contained in the pstore, and clearing ++ pstore storage for future error events. ++ ++ Linux provides a persistent storage file system, pstore, that can store ++ error records when the kernel dies (or reboots or powers-off). These records in ++ turn can be referenced to debug kernel problems (currently the kernel stuffs ++ the tail of the dmesg, which also contains a stack backtrace, into pstore). ++ ++ The pstore file system supports a variety of backends that map onto persistent ++ storage, such as the ACPI ERST and UEFI variables. The pstore backends ++ typically offer a relatively small amount of persistent storage, e.g. 64KiB, ++ which can quickly fill up and thus prevent subsequent kernel crashes from ++ recording errors. Thus there is a need to monitor and extract the pstore ++ contents so that future kernel problems can also record information in the ++ pstore. ++ ++ The pstore service is independent of the kdump service. In cloud environments ++ specifically, host and guest filesystems are on remote filesystems (eg. iSCSI ++ or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation ++ of networking software *and* hardware *and* infrastructure. Thus it may not be ++ possible to capture a kernel coredump to a file since writes over the network ++ may not be possible. ++ ++ The pstore backend, on the other hand, is completely local and provides a path ++ to store error records which will survive a reboot and aid in post-mortem ++ debugging. ++ ++ The systemd-pstore executable does the actual work. Upon starting, ++ the pstore.conf is read to obtain options, then the /sys/fs/pstore ++ directory contents are processed according to the options. Pstore files are written to the ++ journal, and optionally saved into /var/lib/systemd/pstore. ++ ++ ++ ++ Configuration ++ ++ The behavior of systemd-pstore is configured through the configuration file ++ /etc/systemd/pstore.conf and corresponding snippets ++ /etc/systemd/pstore.conf.d/*.conf, see ++ pstore.conf5. ++ ++ ++ ++ Disabling pstore processing ++ ++ To disable pstore processing by systemd-pstore, ++ set Storage=none in ++ pstore.conf5. ++ ++ ++ ++ ++ ++ Usage ++ Data stored in the journal can be viewed with ++ journalctl1 ++ as usual. ++ ++ ++ ++ See Also ++ ++ pstore.conf5 ++ ++ ++ +diff --git a/meson.build b/meson.build +index af4cf331da..972a8fb6f7 100644 +--- a/meson.build ++++ b/meson.build +@@ -1224,6 +1224,7 @@ foreach term : ['utmp', + 'environment-d', + 'binfmt', + 'coredump', ++ 'pstore', + 'resolve', + 'logind', + 'hostnamed', +@@ -1439,6 +1440,7 @@ subdir('src/network') + subdir('src/analyze') + subdir('src/journal-remote') + subdir('src/coredump') ++subdir('src/pstore') + subdir('src/hostname') + subdir('src/import') + subdir('src/kernel-install') +@@ -2151,6 +2153,23 @@ if conf.get('ENABLE_COREDUMP') == 1 + public_programs += [exe] + endif + ++if conf.get('ENABLE_PSTORE') == 1 ++ executable('systemd-pstore', ++ systemd_pstore_sources, ++ include_directories : includes, ++ link_with : [libshared], ++ dependencies : [threads, ++ libacl, ++ libdw, ++ libxz, ++ liblz4], ++ install_rpath : rootlibexecdir, ++ install : true, ++ install_dir : rootlibexecdir) ++ ++ public_programs += exe ++endif ++ + if conf.get('ENABLE_BINFMT') == 1 + exe = executable('systemd-binfmt', + 'src/binfmt/binfmt.c', +@@ -3014,6 +3033,7 @@ foreach tuple : [ + ['resolve'], + ['DNS-over-TLS'], + ['coredump'], ++ ['pstore'], + ['polkit'], + ['legacy pkla', install_polkit_pkla], + ['efi'], +diff --git a/meson_options.txt b/meson_options.txt +index 213079ac15..5624304bf4 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -76,6 +76,8 @@ option('binfmt', type : 'boolean', + description : 'support for custom binary formats') + option('coredump', type : 'boolean', + description : 'install the coredump handler') ++option('pstore', type : 'boolean', ++ description : 'install the pstore archival tool') + option('logind', type : 'boolean', + description : 'install the systemd-logind stack') + option('hostnamed', type : 'boolean', +diff --git a/src/pstore/meson.build b/src/pstore/meson.build +new file mode 100644 +index 0000000000..adbac24b54 +--- /dev/null ++++ b/src/pstore/meson.build +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1+ ++ ++systemd_pstore_sources = files(''' ++ pstore.c ++'''.split()) ++ ++if conf.get('ENABLE_PSTORE') == 1 ++ install_data('pstore.conf', ++ install_dir : pkgsysconfdir) ++endif +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +new file mode 100644 +index 0000000000..f95e016eb6 +--- /dev/null ++++ b/src/pstore/pstore.c +@@ -0,0 +1,395 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++/* Copyright © 2019 Oracle and/or its affiliates. */ ++ ++/* Generally speaking, the pstore contains a small number of files ++ * that in turn contain a small amount of data. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sd-daemon.h" ++#include "sd-journal.h" ++#include "sd-login.h" ++#include "sd-messages.h" ++ ++#include "acl-util.h" ++#include "alloc-util.h" ++#include "capability-util.h" ++#include "cgroup-util.h" ++#include "compress.h" ++#include "conf-parser.h" ++#include "copy.h" ++#include "dirent-util.h" ++#include "escape.h" ++#include "fd-util.h" ++#include "fileio.h" ++#include "fs-util.h" ++#include "io-util.h" ++#include "journal-importer.h" ++#include "log.h" ++#include "macro.h" ++#include "missing.h" ++#include "mkdir.h" ++#include "parse-util.h" ++#include "process-util.h" ++#include "signal-util.h" ++#include "socket-util.h" ++#include "special.h" ++#include "string-table.h" ++#include "string-util.h" ++#include "strv.h" ++#include "user-util.h" ++#include "util.h" ++ ++/* Command line argument handling */ ++typedef enum PStoreStorage { ++ PSTORE_STORAGE_NONE, ++ PSTORE_STORAGE_EXTERNAL, ++ PSTORE_STORAGE_JOURNAL, ++ _PSTORE_STORAGE_MAX, ++ _PSTORE_STORAGE_INVALID = -1 ++} PStoreStorage; ++ ++static const char* const pstore_storage_table[_PSTORE_STORAGE_MAX] = { ++ [PSTORE_STORAGE_NONE] = "none", ++ [PSTORE_STORAGE_EXTERNAL] = "external", ++ [PSTORE_STORAGE_JOURNAL] = "journal", ++}; ++ ++DEFINE_PRIVATE_STRING_TABLE_LOOKUP(pstore_storage, PStoreStorage); ++static DEFINE_CONFIG_PARSE_ENUM(config_parse_pstore_storage, pstore_storage, PStoreStorage, "Failed to parse storage setting"); ++ ++static PStoreStorage arg_storage = PSTORE_STORAGE_EXTERNAL; ++ ++static bool arg_unlink = true; ++static const char *arg_sourcedir = "/sys/fs/pstore"; ++static const char *arg_archivedir = "/var/lib/systemd/pstore"; ++ ++static int parse_config(void) { ++ static const ConfigTableItem items[] = { ++ { "PStore", "Unlink", config_parse_bool, 0, &arg_unlink }, ++ { "PStore", "Storage", config_parse_pstore_storage, 0, &arg_storage }, ++ {} ++ }; ++ ++ return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf", ++ CONF_PATHS_NULSTR("systemd/pstore.conf.d"), ++ "PStore\0", ++ config_item_table_lookup, items, ++ CONFIG_PARSE_WARN, NULL); ++} ++ ++/* File list handling - PStoreEntry is the struct and ++ * and PStoreEntry is the type that contains all info ++ * about a pstore entry. */ ++typedef struct PStoreEntry { ++ struct dirent dirent; ++ bool is_binary; ++ bool handled; ++ char *content; ++ size_t content_size; ++} PStoreEntry; ++ ++typedef struct PStoreList { ++ PStoreEntry *entries; ++ size_t n_entries; ++ size_t n_entries_allocated; ++} PStoreList; ++ ++static void pstore_entries_reset(PStoreList *list) { ++ for (size_t i = 0; i < list->n_entries; i++) ++ free(list->entries[i].content); ++ free(list->entries); ++ list->n_entries = 0; ++} ++ ++static int compare_pstore_entries(const void *_a, const void *_b) { ++ PStoreEntry *a = (PStoreEntry *)_a, *b = (PStoreEntry *)_b; ++ return strcmp(a->dirent.d_name, b->dirent.d_name); ++} ++ ++static int move_file(PStoreEntry *pe, const char *subdir) { ++ _cleanup_free_ char *ifd_path = NULL; ++ _cleanup_free_ char *ofd_path = NULL; ++ int r = 0; ++ struct iovec iovec[2] = {}; ++ int n_iovec = 0; ++ _cleanup_free_ void *field = NULL; ++ const char *suffix = NULL; ++ size_t field_size; ++ ++ if (pe->handled) ++ return 0; ++ ++ ifd_path = path_join(NULL, arg_sourcedir, pe->dirent.d_name); ++ if (!ifd_path) ++ return log_oom(); ++ ++ ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name); ++ if (!ofd_path) ++ return log_oom(); ++ ++ /* Always log to the journal */ ++ suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)"."; ++ field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix); ++ iovec[n_iovec++] = IOVEC_MAKE_STRING(field); ++ ++ field_size = strlen("FILE=") + pe->content_size; ++ field = malloc(field_size); ++ if (!field) ++ return log_oom(); ++ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size); ++ iovec[n_iovec++] = IOVEC_MAKE(field, field_size); ++ ++ r = sd_journal_sendv(iovec, n_iovec); ++ if (r < 0) ++ return log_error_errno(r, "Failed to log pstore entry: %m"); ++ ++ if (arg_storage == PSTORE_STORAGE_EXTERNAL) { ++ /* Move file from pstore to external storage */ ++ r = mkdir_parents(ofd_path, 0755); ++ if (r < 0) ++ return log_error_errno(r, "Failed to create directoy %s: %m", ofd_path); ++ r = copy_file_atomic(ifd_path, ofd_path, 0600, 0, COPY_REPLACE); ++ if (r < 0) ++ return log_error_errno(r, "Failed to copy_file_atomic: %s to %s", ifd_path, ofd_path); ++ } ++ ++ /* If file copied properly, remove it from pstore */ ++ if (arg_unlink) ++ (void) unlink(ifd_path); ++ ++ pe->handled = true; ++ ++ return 0; ++} ++ ++static int write_dmesg(const char *dmesg, size_t size, const char *id) { ++ _cleanup_(unlink_and_freep) char *ofd_path = NULL; ++ _cleanup_free_ char *tmp_path = NULL; ++ _cleanup_close_ int ofd = -1; ++ ssize_t wr; ++ int r; ++ ++ if (isempty(dmesg) || size == 0) ++ return 0; ++ ++ /* log_info("Record ID %s", id); */ ++ ++ ofd_path = path_join(arg_archivedir, id, "dmesg.txt"); ++ if (!ofd_path) ++ return log_oom(); ++ ++ ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path); ++ if (ofd < 0) ++ return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path); ++ wr = write(ofd, dmesg, size); ++ if (wr < 0) ++ return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path); ++ if (wr != (ssize_t)size) ++ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr); ++ r = link_tmpfile(ofd, tmp_path, ofd_path); ++ if (r < 0) ++ return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path); ++ ofd_path = mfree(ofd_path); ++ ++ return 0; ++} ++ ++static void process_dmesg_files(PStoreList *list) { ++ /* Move files, reconstruct dmesg.txt */ ++ PStoreEntry *pe; ++ _cleanup_free_ char *dmesg = NULL; ++ size_t dmesg_size = 0; ++ _cleanup_free_ char *dmesg_id = NULL; ++ ++ /* Handle each dmesg file: files processed in reverse ++ * order so as to properly reconstruct original dmesg */ ++ for (size_t n = list->n_entries; n > 0; n--) { ++ bool move_file_and_continue = false; ++ _cleanup_free_ char *pe_id = NULL; ++ char *p; ++ size_t plen; ++ ++ pe = &list->entries[n-1]; ++ ++ if (pe->handled) ++ continue; ++ if (!startswith(pe->dirent.d_name, "dmesg-")) ++ continue; ++ ++ if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */ ++ move_file_and_continue = true; ++ p = strrchr(pe->dirent.d_name, '-'); ++ if (!p) ++ move_file_and_continue = true; ++ ++ if (move_file_and_continue) { ++ /* A dmesg file on which we do NO additional processing */ ++ (void) move_file(pe, NULL); ++ continue; ++ } ++ ++ /* See if this file is one of a related group of files ++ * in order to reconstruct dmesg */ ++ ++ /* When dmesg is written into pstore, it is done so in ++ * small chunks, whatever the exchange buffer size is ++ * with the underlying pstore backend (ie. EFI may be ++ * ~2KiB), which means an example pstore with approximately ++ * 64KB of storage may have up to roughly 32 dmesg files ++ * that could be related, depending upon the size of the ++ * original dmesg. ++ * ++ * Here we look at the dmesg filename and try to discern ++ * if files are part of a related group, meaning the same ++ * original dmesg. ++ * ++ * The two known pstore backends are EFI and ERST. These ++ * backends store data in the Common Platform Error ++ * Record, CPER, format. The dmesg- filename contains the ++ * CPER record id, a 64bit number (in decimal notation). ++ * In Linux, the record id is encoded with two digits for ++ * the dmesg part (chunk) number and 3 digits for the ++ * count number. So allowing an additional digit to ++ * compensate for advancing time, this code ignores the ++ * last six digits of the filename in determining the ++ * record id. ++ * ++ * For the EFI backend, the record id encodes an id in the ++ * upper 32 bits, and a timestamp in the lower 32-bits. ++ * So ignoring the least significant 6 digits has proven ++ * to generally identify related dmesg entries. */ ++#define PSTORE_FILENAME_IGNORE 6 ++ ++ /* determine common portion of record id */ ++ ++p; /* move beyond dmesg- */ ++ plen = strlen(p); ++ if (plen > PSTORE_FILENAME_IGNORE) { ++ pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE); ++ if (!pe_id) { ++ log_oom(); ++ return; ++ } ++ } else ++ pe_id = mfree(pe_id); ++ ++ /* Now move file from pstore to archive storage */ ++ move_file(pe, pe_id); ++ ++ /* If the current record id is NOT the same as the ++ * previous record id, then start a new dmesg.txt file */ ++ if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) { ++ /* Encountered a new dmesg group, close out old one, open new one */ ++ if (dmesg) { ++ (void) write_dmesg(dmesg, dmesg_size, dmesg_id); ++ dmesg = mfree(dmesg); ++ dmesg_size = 0; ++ } ++ ++ /* now point dmesg_id to storage of pe_id */ ++ free_and_replace(dmesg_id, pe_id); ++ } ++ ++ /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */ ++ dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1); ++ if (dmesg) { ++ dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name); ++ if (pe->content) { ++ memcpy(&dmesg[dmesg_size], pe->content, pe->content_size); ++ dmesg_size += pe->content_size; ++ } ++ } ++ ++ pe_id = mfree(pe_id); ++ } ++ if (dmesg) ++ (void) write_dmesg(dmesg, dmesg_size, dmesg_id); ++} ++ ++static int list_files(PStoreList *list, const char *sourcepath) { ++ _cleanup_(closedirp) DIR *dirp = NULL; ++ struct dirent *de; ++ int r = 0; ++ ++ dirp = opendir(sourcepath); ++ if (!dirp) ++ return log_error_errno(errno, "Failed to opendir %s: %m", sourcepath); ++ ++ FOREACH_DIRENT(de, dirp, return log_error_errno(errno, "Failed to iterate through %s: %m", sourcepath)) { ++ _cleanup_free_ char *ifd_path = NULL; ++ ++ ifd_path = path_join(NULL, sourcepath, de->d_name); ++ if (!ifd_path) ++ return log_oom(); ++ ++ _cleanup_free_ char *buf = NULL; ++ size_t buf_size; ++ ++ /* Now read contents of pstore file */ ++ r = read_full_file(ifd_path, &buf, &buf_size); ++ if (r < 0) { ++ log_warning_errno(r, "Failed to read file %s: %m", ifd_path); ++ continue; ++ } ++ ++ if (!GREEDY_REALLOC(list->entries, list->n_entries_allocated, list->n_entries + 1)) ++ return log_oom(); ++ ++ list->entries[list->n_entries++] = (PStoreEntry) { ++ .dirent = *de, ++ .content = TAKE_PTR(buf), ++ .content_size = buf_size, ++ .is_binary = true, ++ .handled = false, ++ }; ++ } ++ ++ return r; ++} ++ ++static int run(int argc, char *argv[]) { ++ _cleanup_(pstore_entries_reset) PStoreList list = {}; ++ int r; ++ ++ log_open(); ++ ++ /* Ignore all parse errors */ ++ (void) parse_config(); ++ ++ log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage)); ++ log_debug("Selected Unlink '%d'.", arg_unlink); ++ ++ if (arg_storage == PSTORE_STORAGE_NONE) ++ /* Do nothing, intentionally, leaving pstore untouched */ ++ return 0; ++ ++ /* Obtain list of files in pstore */ ++ r = list_files(&list, arg_sourcedir); ++ if (r < 0) ++ return r; ++ ++ /* Handle each pstore file */ ++ /* Sort files lexigraphically ascending, generally needed by all */ ++ qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries); ++ ++ /* Process known file types */ ++ process_dmesg_files(&list); ++ ++ /* Move left over files out of pstore */ ++ for (size_t n = 0; n < list.n_entries; n++) ++ move_file(&list.entries[n], NULL); ++ ++ 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/pstore/pstore.conf b/src/pstore/pstore.conf +new file mode 100644 +index 0000000000..93a8b6707c +--- /dev/null ++++ b/src/pstore/pstore.conf +@@ -0,0 +1,16 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. ++# ++# See pstore.conf(5) for details. ++ ++[PStore] ++#Storage=external ++#Unlink=yes +diff --git a/units/meson.build b/units/meson.build +index a74fa95195..e8e64eb30a 100644 +--- a/units/meson.build ++++ b/units/meson.build +@@ -136,6 +136,7 @@ in_units = [ + ['systemd-binfmt.service', 'ENABLE_BINFMT', + 'sysinit.target.wants/'], + ['systemd-coredump@.service', 'ENABLE_COREDUMP'], ++ ['systemd-pstore.service', 'ENABLE_PSTORE'], + ['systemd-firstboot.service', 'ENABLE_FIRSTBOOT', + 'sysinit.target.wants/'], + ['systemd-fsck-root.service', ''], +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +new file mode 100644 +index 0000000000..fec2b1aebf +--- /dev/null ++++ b/units/systemd-pstore.service.in +@@ -0,0 +1,24 @@ ++# SPDX-License-Identifier: LGPL-2.1+ ++# ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=Platform Persistent Storage Archival ++Documentation=man:systemd-pstore(8) ++DefaultDependencies=no ++Wants=systemd-remount-fs.service ++After=systemd-remount-fs.service ++ ++[Service] ++Type=oneshot ++ExecStart=@rootlibexecdir@/systemd-pstore ++RemainAfterExit=yes ++StateDirectory=systemd/pstore ++ ++[Install] ++WantedBy=systemd-remount-fs.service diff --git a/SOURCES/0877-meson-drop-redundant-line.patch b/SOURCES/0877-meson-drop-redundant-line.patch new file mode 100644 index 0000000..ed13771 --- /dev/null +++ b/SOURCES/0877-meson-drop-redundant-line.patch @@ -0,0 +1,27 @@ +From c95ba53ab720dfbd7f692e0a87d7f5d4f89ea36b Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 10:46:53 +0900 +Subject: [PATCH] meson: drop redundant line + +Found by @mattiasb. + +(cherry picked from commit 3f708e7f6909faad307bdb60ed0f8d68e84f6584) + +Related: #2158832 +--- + meson.build | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/meson.build b/meson.build +index 972a8fb6f7..673800a1a7 100644 +--- a/meson.build ++++ b/meson.build +@@ -2166,8 +2166,6 @@ if conf.get('ENABLE_PSTORE') == 1 + install_rpath : rootlibexecdir, + install : true, + install_dir : rootlibexecdir) +- +- public_programs += exe + endif + + if conf.get('ENABLE_BINFMT') == 1 diff --git a/SOURCES/0878-pstore-drop-unnecessary-initializations.patch b/SOURCES/0878-pstore-drop-unnecessary-initializations.patch new file mode 100644 index 0000000..6bc6613 --- /dev/null +++ b/SOURCES/0878-pstore-drop-unnecessary-initializations.patch @@ -0,0 +1,48 @@ +From 7e4b7cc35af0e3b3afbf32fa0fd9961cd01ad9a9 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 10:52:12 +0900 +Subject: [PATCH] pstore: drop unnecessary initializations + +(cherry picked from commit 2e4effd129343d22bfed34e94810d3f87c8f0e85) + +Related: #2158832 +--- + src/pstore/pstore.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index f95e016eb6..e6a342fc50 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -113,14 +113,12 @@ static int compare_pstore_entries(const void *_a, const void *_b) { + } + + static int move_file(PStoreEntry *pe, const char *subdir) { +- _cleanup_free_ char *ifd_path = NULL; +- _cleanup_free_ char *ofd_path = NULL; +- int r = 0; +- struct iovec iovec[2] = {}; +- int n_iovec = 0; ++ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL; + _cleanup_free_ void *field = NULL; +- const char *suffix = NULL; ++ struct iovec iovec[2]; ++ const char *suffix; + size_t field_size; ++ int n_iovec = 0, r; + + if (pe->handled) + return 0; +@@ -202,10 +200,9 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) { + + static void process_dmesg_files(PStoreList *list) { + /* Move files, reconstruct dmesg.txt */ +- PStoreEntry *pe; +- _cleanup_free_ char *dmesg = NULL; ++ _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL; + size_t dmesg_size = 0; +- _cleanup_free_ char *dmesg_id = NULL; ++ PStoreEntry *pe; + + /* Handle each dmesg file: files processed in reverse + * order so as to properly reconstruct original dmesg */ diff --git a/SOURCES/0879-pstopre-fix-return-value-of-list_files.patch b/SOURCES/0879-pstopre-fix-return-value-of-list_files.patch new file mode 100644 index 0000000..72e8698 --- /dev/null +++ b/SOURCES/0879-pstopre-fix-return-value-of-list_files.patch @@ -0,0 +1,46 @@ +From a0485b96118d3d2ac439f510e404ffb3db03e23f Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 10:55:10 +0900 +Subject: [PATCH] pstopre: fix return value of list_files() + +Previously, the return value of the last read_full_file() is returned. +This makes the error in read_full_file() is always ignored. + +(cherry picked from commit 337874a45fff46a80e4974c681a5e651f3a0fac9) + +Related: #2158832 +--- + src/pstore/pstore.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index e6a342fc50..2fbef48543 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -311,7 +311,7 @@ static void process_dmesg_files(PStoreList *list) { + static int list_files(PStoreList *list, const char *sourcepath) { + _cleanup_(closedirp) DIR *dirp = NULL; + struct dirent *de; +- int r = 0; ++ int r; + + dirp = opendir(sourcepath); + if (!dirp) +@@ -330,7 +330,7 @@ static int list_files(PStoreList *list, const char *sourcepath) { + /* Now read contents of pstore file */ + r = read_full_file(ifd_path, &buf, &buf_size); + if (r < 0) { +- log_warning_errno(r, "Failed to read file %s: %m", ifd_path); ++ log_warning_errno(r, "Failed to read file %s, skipping: %m", ifd_path); + continue; + } + +@@ -346,7 +346,7 @@ static int list_files(PStoreList *list, const char *sourcepath) { + }; + } + +- return r; ++ return 0; + } + + static int run(int argc, char *argv[]) { diff --git a/SOURCES/0880-pstore-remove-temporary-file-on-failure.patch b/SOURCES/0880-pstore-remove-temporary-file-on-failure.patch new file mode 100644 index 0000000..33bf5a0 --- /dev/null +++ b/SOURCES/0880-pstore-remove-temporary-file-on-failure.patch @@ -0,0 +1,36 @@ +From 58000dc7dd93ff6e8357de64154b0849d3c17c5d Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 11:01:43 +0900 +Subject: [PATCH] pstore: remove temporary file on failure + +(cherry picked from commit 03c5f6cc02648eeff3179b2b762d46b9e1889bb1) + +Related: #2158832 +--- + src/pstore/pstore.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index 2fbef48543..ce8080ceed 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -167,8 +167,8 @@ static int move_file(PStoreEntry *pe, const char *subdir) { + } + + static int write_dmesg(const char *dmesg, size_t size, const char *id) { +- _cleanup_(unlink_and_freep) char *ofd_path = NULL; +- _cleanup_free_ char *tmp_path = NULL; ++ _cleanup_(unlink_and_freep) char *tmp_path = NULL; ++ _cleanup_free_ char *ofd_path = NULL; + _cleanup_close_ int ofd = -1; + ssize_t wr; + int r; +@@ -193,7 +193,7 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) { + r = link_tmpfile(ofd, tmp_path, ofd_path); + if (r < 0) + return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path); +- ofd_path = mfree(ofd_path); ++ tmp_path = mfree(tmp_path); + + return 0; + } diff --git a/SOURCES/0881-pstore-do-not-add-FILE-journal-entry-if-content_size.patch b/SOURCES/0881-pstore-do-not-add-FILE-journal-entry-if-content_size.patch new file mode 100644 index 0000000..400dae5 --- /dev/null +++ b/SOURCES/0881-pstore-do-not-add-FILE-journal-entry-if-content_size.patch @@ -0,0 +1,57 @@ +From 5006e4bd9aecea40ca3d907adc692c4c8001a6c1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 11:08:06 +0900 +Subject: [PATCH] pstore: do not add FILE= journal entry if content_size == 0 + +(cherry picked from commit 6bf18debddbe1b231f783617e054cc194bb36d1e) + +Related: #2158832 +--- + src/pstore/pstore.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index ce8080ceed..eb251d61c8 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -114,10 +114,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) { + + static int move_file(PStoreEntry *pe, const char *subdir) { + _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL; +- _cleanup_free_ void *field = NULL; ++ const char *suffix, *message; + struct iovec iovec[2]; +- const char *suffix; +- size_t field_size; + int n_iovec = 0, r; + + if (pe->handled) +@@ -133,15 +131,20 @@ static int move_file(PStoreEntry *pe, const char *subdir) { + + /* Always log to the journal */ + suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)"."; +- field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix); +- iovec[n_iovec++] = IOVEC_MAKE_STRING(field); ++ message = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix); ++ iovec[n_iovec++] = IOVEC_MAKE_STRING(message); + +- field_size = strlen("FILE=") + pe->content_size; +- field = malloc(field_size); +- if (!field) +- return log_oom(); +- memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size); +- iovec[n_iovec++] = IOVEC_MAKE(field, field_size); ++ if (pe->content_size > 0) { ++ _cleanup_free_ void *field = NULL; ++ size_t field_size; ++ ++ field_size = strlen("FILE=") + pe->content_size; ++ field = malloc(field_size); ++ if (!field) ++ return log_oom(); ++ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size); ++ iovec[n_iovec++] = IOVEC_MAKE(field, field_size); ++ } + + r = sd_journal_sendv(iovec, n_iovec); + if (r < 0) diff --git a/SOURCES/0882-pstore-run-only-when-sys-fs-pstore-is-not-empty.patch b/SOURCES/0882-pstore-run-only-when-sys-fs-pstore-is-not-empty.patch new file mode 100644 index 0000000..ea535a5 --- /dev/null +++ b/SOURCES/0882-pstore-run-only-when-sys-fs-pstore-is-not-empty.patch @@ -0,0 +1,24 @@ +From a7247899f156761934bcb4b380861b3d3ec5449f Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 22 Jul 2019 14:09:12 +0900 +Subject: [PATCH] pstore: run only when /sys/fs/pstore is not empty + +(cherry picked from commit 6d4f213b1f6afb2901f0d97cec0e28e20809b713) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index fec2b1aebf..dde21bc33e 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -10,6 +10,7 @@ + [Unit] + Description=Platform Persistent Storage Archival + Documentation=man:systemd-pstore(8) ++ConditionDirectoryNotEmpty=/sys/fs/pstore + DefaultDependencies=no + Wants=systemd-remount-fs.service + After=systemd-remount-fs.service diff --git a/SOURCES/0883-pstore-fix-use-after-free.patch b/SOURCES/0883-pstore-fix-use-after-free.patch new file mode 100644 index 0000000..3546fb3 --- /dev/null +++ b/SOURCES/0883-pstore-fix-use-after-free.patch @@ -0,0 +1,34 @@ +From 7f5bfbd5485e1cb779d7568cabb5783651fd9da3 Mon Sep 17 00:00:00 2001 +From: Michael Olbrich +Date: Fri, 6 Sep 2019 15:04:01 +0200 +Subject: [PATCH] pstore: fix use after free + +The memory is still needed in the sd_journal_sendv() after the 'if' block. + +(cherry picked from commit 1e19f5ac0d680a63eccae7ef1fc6ce225dca0bbf) + +Related: #2158832 +--- + src/pstore/pstore.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index eb251d61c8..cafb1804c6 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -114,6 +114,7 @@ static int compare_pstore_entries(const void *_a, const void *_b) { + + static int move_file(PStoreEntry *pe, const char *subdir) { + _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL; ++ _cleanup_free_ void *field = NULL; + const char *suffix, *message; + struct iovec iovec[2]; + int n_iovec = 0, r; +@@ -135,7 +136,6 @@ static int move_file(PStoreEntry *pe, const char *subdir) { + iovec[n_iovec++] = IOVEC_MAKE_STRING(message); + + if (pe->content_size > 0) { +- _cleanup_free_ void *field = NULL; + size_t field_size; + + field_size = strlen("FILE=") + pe->content_size; diff --git a/SOURCES/0884-pstore-refuse-to-run-if-arguments-are-specified.patch b/SOURCES/0884-pstore-refuse-to-run-if-arguments-are-specified.patch new file mode 100644 index 0000000..de27c4c --- /dev/null +++ b/SOURCES/0884-pstore-refuse-to-run-if-arguments-are-specified.patch @@ -0,0 +1,29 @@ +From a35a90322f8587f650aeb72bfbe1ebcc93e503aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Jul 2019 10:43:19 +0200 +Subject: [PATCH] pstore: refuse to run if arguments are specified + +(This is why the --help chech passed.) + +(cherry picked from commit 22d6bea8820612e6a1483d8b6cfd820f1417ae6b) + +Related: #2158832 +--- + src/pstore/pstore.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index cafb1804c6..b0b21dedd4 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -358,6 +358,10 @@ static int run(int argc, char *argv[]) { + + log_open(); + ++ if (argc > 1) ++ return log_error_errno(-EINVAL, ++ "This program takes no arguments."); ++ + /* Ignore all parse errors */ + (void) parse_config(); + diff --git a/SOURCES/0885-pstore-allow-specifying-src-and-dst-dirs-are-argumen.patch b/SOURCES/0885-pstore-allow-specifying-src-and-dst-dirs-are-argumen.patch new file mode 100644 index 0000000..00779b3 --- /dev/null +++ b/SOURCES/0885-pstore-allow-specifying-src-and-dst-dirs-are-argumen.patch @@ -0,0 +1,44 @@ +From 76fe0974f62f0a2beb2d3d8e224e80a57c0ebd09 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 4 Oct 2019 16:14:47 +0200 +Subject: [PATCH] pstore: allow specifying src and dst dirs are arguments + +This makes it much easier to debug the program as a normal user, since we +don't need to set up fake input under /sys/fs/pstore/. + +Also, let's make the debug output a bit nicer. + +(cherry picked from commit e05a72d7587ff916a983588f8393af624d330dd0) + +Related: #2158832 +--- + src/pstore/pstore.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index b0b21dedd4..7353e83a81 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -358,15 +358,18 @@ static int run(int argc, char *argv[]) { + + log_open(); + +- if (argc > 1) ++ if (argc == 3) { ++ arg_sourcedir = argv[1]; ++ arg_archivedir = argv[2]; ++ } else if (argc > 1) + return log_error_errno(-EINVAL, +- "This program takes no arguments."); ++ "This program takes zero or two arguments."); + + /* Ignore all parse errors */ + (void) parse_config(); + +- log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage)); +- log_debug("Selected Unlink '%d'.", arg_unlink); ++ log_debug("Selected storage: %s.", pstore_storage_to_string(arg_storage)); ++ log_debug("Selected unlink: %s.", yes_no(arg_unlink)); + + if (arg_storage == PSTORE_STORAGE_NONE) + /* Do nothing, intentionally, leaving pstore untouched */ diff --git a/SOURCES/0886-pstore-rework-memory-handling-for-dmesg.patch b/SOURCES/0886-pstore-rework-memory-handling-for-dmesg.patch new file mode 100644 index 0000000..8c0adda --- /dev/null +++ b/SOURCES/0886-pstore-rework-memory-handling-for-dmesg.patch @@ -0,0 +1,133 @@ +From a2ba34a79de3748f51d57541c54dbe22e1d03a9e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 4 Oct 2019 16:17:27 +0200 +Subject: [PATCH] pstore: rework memory handling for dmesg + +Semmle Security Reports report: +> The problem occurs on the way realloc is being used. When a size +> bigger than the chunk that wants to be reallocated is passed, realloc +> try to malloc a bigger size, however in the case that malloc fails +> (for example, by forcing a big allocation) realloc will return NULL. +> +> According to the man page: +> "The realloc() function returns a pointer to the newly allocated +> memory, which is suitably aligned for any built-in type and may be +> different from ptr, or NULL if the request fails. If size was +> equal to 0, either NULL or a pointer suitable to be passed to free() +> is returned. If realloc() fails, the original block is left +> untouched; it is not freed or moved." +> +> The problem occurs when the memory ptr passed to the first argument of +> realloc is the same as the one used for the result, for example in +> this case: +> +> dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + +> strlen(":\n") + pe->content_size + 1); +> +> https://lgtm.com/projects/g/systemd/systemd/snapshot/f8bcb81955f9e93a4787627e28f43fffb2a84836/files/src/pstore/pstore.c?sort=name&dir=A +> SC&mode=heatmap#L300 +> +> If the malloc inside that realloc fails, then the original memory +> chunk will never be free but since realloc will return NULL, the +> pointer to that memory chunk will be lost and a memory leak will +> occur. +> +> In case you are curious, this is the query we used to find this problem: +> https://lgtm.com/query/8650323308193591473/ + +Let's use a more standard pattern: allocate memory using greedy_realloc, and +instead of freeing it when we wrote out a chunk, let's just move the cursor +back to the beginning and reuse the memory we allocated previously. + +If we fail to allocate the memory for dmesg contents, don't write the dmesg +entry, but let's still process the files to move them out of pstore. + +(cherry picked from commit 8198c3e42b0614b6bd1db6f38813b842c8577304) + +Related: #2158832 +--- + src/pstore/pstore.c | 43 ++++++++++++++++++++++++++----------------- + 1 file changed, 26 insertions(+), 17 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index 7353e83a81..d70e142b4d 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -176,9 +176,11 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) { + ssize_t wr; + int r; + +- if (isempty(dmesg) || size == 0) ++ if (size == 0) + return 0; + ++ assert(dmesg); ++ + /* log_info("Record ID %s", id); */ + + ofd_path = path_join(arg_archivedir, id, "dmesg.txt"); +@@ -204,7 +206,8 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) { + static void process_dmesg_files(PStoreList *list) { + /* Move files, reconstruct dmesg.txt */ + _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL; +- size_t dmesg_size = 0; ++ size_t dmesg_size = 0, dmesg_allocated = 0; ++ bool dmesg_bad = false; + PStoreEntry *pe; + + /* Handle each dmesg file: files processed in reverse +@@ -281,33 +284,39 @@ static void process_dmesg_files(PStoreList *list) { + /* Now move file from pstore to archive storage */ + move_file(pe, pe_id); + ++ if (dmesg_bad) ++ continue; ++ + /* If the current record id is NOT the same as the + * previous record id, then start a new dmesg.txt file */ +- if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) { ++ if (!streq_ptr(pe_id, dmesg_id)) { + /* Encountered a new dmesg group, close out old one, open new one */ +- if (dmesg) { +- (void) write_dmesg(dmesg, dmesg_size, dmesg_id); +- dmesg = mfree(dmesg); +- dmesg_size = 0; +- } ++ (void) write_dmesg(dmesg, dmesg_size, dmesg_id); ++ dmesg_size = 0; + + /* now point dmesg_id to storage of pe_id */ + free_and_replace(dmesg_id, pe_id); + } + +- /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */ +- dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1); +- if (dmesg) { +- dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name); +- if (pe->content) { +- memcpy(&dmesg[dmesg_size], pe->content, pe->content_size); +- dmesg_size += pe->content_size; +- } ++ /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled ++ * output either. */ ++ size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1; ++ if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) { ++ log_warning_errno(ENOMEM, "Failed to write dmesg file: %m"); ++ dmesg_bad = true; ++ continue; ++ } ++ ++ dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name); ++ if (pe->content) { ++ memcpy(dmesg + dmesg_size, pe->content, pe->content_size); ++ dmesg_size += pe->content_size; + } + + pe_id = mfree(pe_id); + } +- if (dmesg) ++ ++ if (!dmesg_bad) + (void) write_dmesg(dmesg, dmesg_size, dmesg_id); + } + diff --git a/SOURCES/0887-pstore-fixes-for-dmesg.txt-reconstruction.patch b/SOURCES/0887-pstore-fixes-for-dmesg.txt-reconstruction.patch new file mode 100644 index 0000000..cbfb074 --- /dev/null +++ b/SOURCES/0887-pstore-fixes-for-dmesg.txt-reconstruction.patch @@ -0,0 +1,504 @@ +From 5ac15c7dc49476e7cd7cc3a4b507282c9f78d528 Mon Sep 17 00:00:00 2001 +From: Eric DeVolder +Date: Mon, 21 Nov 2022 11:27:27 -0500 +Subject: [PATCH] pstore: fixes for dmesg.txt reconstruction + +This patch fixes problems with the re-assembly of the dmesg +from the records stored in pstore. + +The current code simply ignores the last 6 characters of the +file name to form a base record id, which then groups any +pstore files with this base id into the reconstructed dmesg.txt. +This approach fails when the following oops generated the +following in pstore: + + -rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001 + -rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002 + -rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002 + -rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001 + -rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002 + -rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001 + -rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002 + -rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001 + -rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002 + -rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001 + -rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002 + -rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001 + -rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002 + -rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001 + -rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002 + -rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001 + -rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002 + -rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001 + -rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002 + -rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001 + -rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002 + -rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001 + -rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002 + -rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001 + -rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002 + -rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001 + -rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002 + -rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001 + -rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002 + -rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001 + -rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002 + -rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002 + -rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003 + -rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003 + -rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003 + -rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003 + -rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003 + -rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003 + -rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003 + -rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003 + -rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003 + -rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003 + -rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003 + -rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003 + -rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003 + -rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003 + -rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003 + +The "reconstructed" dmesg.txt that resulted from the above contained +the following (ignoring actual contents, just providing the Part info): + + Emergency#3 Part17 + Emergency#3 Part16 + Emergency#3 Part15 + Emergency#3 Part14 + Emergency#3 Part13 + Emergency#3 Part12 + Emergency#3 Part11 + Emergency#3 Part10 + Emergency#3 Part9 + Emergency#3 Part8 + Emergency#3 Part7 + Emergency#3 Part6 + Emergency#3 Part5 + Emergency#3 Part4 + Emergency#3 Part3 + Emergency#3 Part2 + Emergency#3 Part1 + Panic#2 Part17 + Panic#2 Part16 + Oops#1 Part16 + Panic#2 Part15 + Oops#1 Part15 + Panic#2 Part14 + Oops#1 Part14 + Panic#2 Part13 + Oops#1 Part13 + Panic#2 Part12 + Oops#1 Part12 + Panic#2 Part11 + Oops#1 Part11 + Panic#2 Part10 + Oops#1 Part10 + Panic#2 Part9 + Oops#1 Part9 + Panic#2 Part8 + Oops#1 Part8 + Panic#2 Part7 + Oops#1 Part7 + Panic#2 Part6 + Oops#1 Part6 + Panic#2 Part5 + Oops#1 Part5 + Panic#2 Part4 + Oops#1 Part4 + Panic#2 Part3 + Oops#1 Part3 + Panic#2 Part2 + Oops#1 Part2 + Panic#2 Part1 + Oops#1 Part1 + +The above is a interleaved mess of three dmesg dumps. + +This patch fixes the above problems, and simplifies the dmesg +reconstruction process. The code now distinguishes between +records on EFI vs ERST, which have differently formatted +record identifiers. Using knowledge of the format of the +record ids allows vastly improved reconstruction process. + +With this change in place, the above pstore records now +result in the following: + + # ls -alR /var/lib/systemd/pstore + 1666922861: + total 8 + drwxr-xr-x. 4 root root 28 Nov 18 14:58 . + drwxr-xr-x. 7 root root 144 Nov 18 14:58 .. + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 001 + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 002 + + 1666922861/001: + total 100 + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 . + drwxr-xr-x. 4 root root 28 Nov 18 14:58 .. + -rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001 + -rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001 + -rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001 + -rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001 + -rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001 + -rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001 + -rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001 + -rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001 + -rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001 + -rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001 + -rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001 + -rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001 + -rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001 + -rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001 + -rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001 + -rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001 + -rw-r-----. 1 root root 28677 Nov 18 14:58 dmesg.txt + + 1666922861/002: + total 104 + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 . + drwxr-xr-x. 4 root root 28 Nov 18 14:58 .. + -rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002 + -rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002 + -rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002 + -rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002 + -rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002 + -rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002 + -rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002 + -rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002 + -rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002 + -rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002 + -rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002 + -rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002 + -rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002 + -rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002 + -rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002 + -rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002 + -rw-r-----. 1 root root 30000 Nov 18 14:58 dmesg.txt + + 1666922867: + total 4 + drwxr-xr-x. 3 root root 17 Nov 18 14:58 . + drwxr-xr-x. 7 root root 144 Nov 18 14:58 .. + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 003 + + 1666922867/003: + total 104 + drwxr-xr-x. 2 root root 4096 Nov 18 14:58 . + drwxr-xr-x. 3 root root 17 Nov 18 14:58 .. + -rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003 + -rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003 + -rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003 + -rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003 + -rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003 + -rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003 + -rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003 + -rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003 + -rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003 + -rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003 + -rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003 + -rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003 + -rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003 + -rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003 + -rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003 + -rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003 + -rw-r-----. 1 root root 30111 Nov 18 14:58 dmesg.txt + +Furthemore, pstore records on ERST are now able to accurately +identify the change in timestamp sequence in order to start a +new dmesg.txt, as needed. + +(cherry picked from commit 5fbaa757077bde2db8d33b1c358518c41b990339) + +Related: #2158832 +--- + src/pstore/pstore.c | 216 +++++++++++++++++++------------------------- + 1 file changed, 92 insertions(+), 124 deletions(-) + +diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c +index d70e142b4d..9f61e8f7f8 100644 +--- a/src/pstore/pstore.c ++++ b/src/pstore/pstore.c +@@ -112,8 +112,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) { + return strcmp(a->dirent.d_name, b->dirent.d_name); + } + +-static int move_file(PStoreEntry *pe, const char *subdir) { +- _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL; ++static int move_file(PStoreEntry *pe, const char *subdir1, const char *subdir2) { ++ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL, *ofd_path_base = NULL; + _cleanup_free_ void *field = NULL; + const char *suffix, *message; + struct iovec iovec[2]; +@@ -126,7 +126,11 @@ static int move_file(PStoreEntry *pe, const char *subdir) { + if (!ifd_path) + return log_oom(); + +- ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name); ++ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2); ++ if (!ofd_path_base) ++ return log_oom(); ++ ++ ofd_path = path_join(NULL, ofd_path_base, pe->dirent.d_name); + if (!ofd_path) + return log_oom(); + +@@ -169,155 +173,119 @@ static int move_file(PStoreEntry *pe, const char *subdir) { + return 0; + } + +-static int write_dmesg(const char *dmesg, size_t size, const char *id) { +- _cleanup_(unlink_and_freep) char *tmp_path = NULL; +- _cleanup_free_ char *ofd_path = NULL; ++static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir2) { ++ /* Append dmesg chunk to end, create if needed */ ++ _cleanup_free_ char *ofd_path = NULL, *ofd_path_base = NULL; + _cleanup_close_ int ofd = -1; + ssize_t wr; +- int r; + +- if (size == 0) +- return 0; ++ assert(pe); + +- assert(dmesg); ++ if (pe->content_size == 0) ++ return 0; + +- /* log_info("Record ID %s", id); */ ++ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2); ++ if (!ofd_path_base) ++ return log_oom(); + +- ofd_path = path_join(arg_archivedir, id, "dmesg.txt"); ++ ofd_path = path_join(NULL, ofd_path_base, "dmesg.txt"); + if (!ofd_path) + return log_oom(); + +- ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path); ++ ofd = open(ofd_path, O_CREAT|O_NOFOLLOW|O_NOCTTY|O_CLOEXEC|O_APPEND|O_WRONLY, 0640); + if (ofd < 0) +- return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path); +- wr = write(ofd, dmesg, size); ++ return log_error_errno(ofd, "Failed to open file %s: %m", ofd_path); ++ wr = write(ofd, pe->content, pe->content_size); + if (wr < 0) + return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path); +- if (wr != (ssize_t)size) +- return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr); +- r = link_tmpfile(ofd, tmp_path, ofd_path); +- if (r < 0) +- return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path); +- tmp_path = mfree(tmp_path); ++ if ((size_t)wr != pe->content_size) ++ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, pe->content_size - wr); + + return 0; + } + +-static void process_dmesg_files(PStoreList *list) { ++static int process_dmesg_files(PStoreList *list) { + /* Move files, reconstruct dmesg.txt */ +- _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL; +- size_t dmesg_size = 0, dmesg_allocated = 0; +- bool dmesg_bad = false; +- PStoreEntry *pe; ++ _cleanup_free_ char *erst_subdir = NULL; ++ uint64_t last_record_id = 0; ++ ++ /* When dmesg is written into pstore, it is done so in small chunks, whatever the exchange buffer ++ * size is with the underlying pstore backend (ie. EFI may be ~2KiB), which means an example ++ * pstore with approximately 64KB of storage may have up to roughly 32 dmesg files, some likely ++ * related. ++ * ++ * Here we look at the dmesg filename and try to discern if files are part of a related group, ++ * meaning the same original dmesg. ++ * ++ * The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER, ++ * record id, a 64-bit number. ++ * ++ * Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.*/ + +- /* Handle each dmesg file: files processed in reverse +- * order so as to properly reconstruct original dmesg */ + for (size_t n = list->n_entries; n > 0; n--) { +- bool move_file_and_continue = false; +- _cleanup_free_ char *pe_id = NULL; ++ PStoreEntry *pe; + char *p; +- size_t plen; + + pe = &list->entries[n-1]; + + if (pe->handled) + continue; +- if (!startswith(pe->dirent.d_name, "dmesg-")) +- continue; +- + if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */ +- move_file_and_continue = true; +- p = strrchr(pe->dirent.d_name, '-'); +- if (!p) +- move_file_and_continue = true; +- +- if (move_file_and_continue) { +- /* A dmesg file on which we do NO additional processing */ +- (void) move_file(pe, NULL); + continue; +- } +- +- /* See if this file is one of a related group of files +- * in order to reconstruct dmesg */ +- +- /* When dmesg is written into pstore, it is done so in +- * small chunks, whatever the exchange buffer size is +- * with the underlying pstore backend (ie. EFI may be +- * ~2KiB), which means an example pstore with approximately +- * 64KB of storage may have up to roughly 32 dmesg files +- * that could be related, depending upon the size of the +- * original dmesg. +- * +- * Here we look at the dmesg filename and try to discern +- * if files are part of a related group, meaning the same +- * original dmesg. +- * +- * The two known pstore backends are EFI and ERST. These +- * backends store data in the Common Platform Error +- * Record, CPER, format. The dmesg- filename contains the +- * CPER record id, a 64bit number (in decimal notation). +- * In Linux, the record id is encoded with two digits for +- * the dmesg part (chunk) number and 3 digits for the +- * count number. So allowing an additional digit to +- * compensate for advancing time, this code ignores the +- * last six digits of the filename in determining the +- * record id. +- * +- * For the EFI backend, the record id encodes an id in the +- * upper 32 bits, and a timestamp in the lower 32-bits. +- * So ignoring the least significant 6 digits has proven +- * to generally identify related dmesg entries. */ +-#define PSTORE_FILENAME_IGNORE 6 +- +- /* determine common portion of record id */ +- ++p; /* move beyond dmesg- */ +- plen = strlen(p); +- if (plen > PSTORE_FILENAME_IGNORE) { +- pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE); +- if (!pe_id) { +- log_oom(); +- return; +- } +- } else +- pe_id = mfree(pe_id); +- +- /* Now move file from pstore to archive storage */ +- move_file(pe, pe_id); +- +- if (dmesg_bad) ++ if (!startswith(pe->dirent.d_name, "dmesg-")) + continue; + +- /* If the current record id is NOT the same as the +- * previous record id, then start a new dmesg.txt file */ +- if (!streq_ptr(pe_id, dmesg_id)) { +- /* Encountered a new dmesg group, close out old one, open new one */ +- (void) write_dmesg(dmesg, dmesg_size, dmesg_id); +- dmesg_size = 0; +- +- /* now point dmesg_id to storage of pe_id */ +- free_and_replace(dmesg_id, pe_id); +- } +- +- /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled +- * output either. */ +- size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1; +- if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) { +- log_warning_errno(ENOMEM, "Failed to write dmesg file: %m"); +- dmesg_bad = true; +- continue; +- } +- +- dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name); +- if (pe->content) { +- memcpy(dmesg + dmesg_size, pe->content, pe->content_size); +- dmesg_size += pe->content_size; +- } +- +- pe_id = mfree(pe_id); ++ if ((p = startswith(pe->dirent.d_name, "dmesg-efi-"))) { ++ /* For the EFI backend, the 3 least significant digits of record id encodes a ++ * "count" number, the next 2 least significant digits for the dmesg part ++ * (chunk) number, and the remaining digits as the timestamp. See ++ * linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write(). */ ++ _cleanup_free_ char *subdir1 = NULL, *subdir2 = NULL; ++ size_t plen = strlen(p); ++ ++ if (plen < 6) ++ continue; ++ ++ /* Extract base record id */ ++ subdir1 = strndup(p, plen - 5); ++ if (!subdir1) ++ return log_oom(); ++ /* Extract "count" field */ ++ subdir2 = strndup(p + plen - 3, 3); ++ if (!subdir2) ++ return log_oom(); ++ ++ /* Now move file from pstore to archive storage */ ++ (void) move_file(pe, subdir1, subdir2); ++ ++ /* Append to the dmesg */ ++ (void) append_dmesg(pe, subdir1, subdir2); ++ } else if ((p = startswith(pe->dirent.d_name, "dmesg-erst-"))) { ++ /* For the ERST backend, the record is a monotonically increasing number, seeded as ++ * a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer(). */ ++ uint64_t record_id; ++ ++ if (safe_atou64(p, &record_id) < 0) ++ continue; ++ if (last_record_id - 1 != record_id) ++ /* A discontinuity in the number has been detected, this current record id ++ * will become the directory name for all pieces of the dmesg in this ++ * series. */ ++ if (free_and_strdup(&erst_subdir, p) < 0) ++ return log_oom(); ++ ++ /* Now move file from pstore to archive storage */ ++ (void) move_file(pe, erst_subdir, NULL); ++ ++ /* Append to the dmesg */ ++ (void) append_dmesg(pe, erst_subdir, NULL); ++ ++ /* Update, but keep erst_subdir for next file */ ++ last_record_id = record_id; ++ } else ++ log_debug("Unknown backend, ignoring \"%s\".", pe->dirent.d_name); + } +- +- if (!dmesg_bad) +- (void) write_dmesg(dmesg, dmesg_size, dmesg_id); ++ return 0; + } + + static int list_files(PStoreList *list, const char *sourcepath) { +@@ -394,11 +362,11 @@ static int run(int argc, char *argv[]) { + qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries); + + /* Process known file types */ +- process_dmesg_files(&list); ++ (void) process_dmesg_files(&list); + + /* Move left over files out of pstore */ + for (size_t n = 0; n < list.n_entries; n++) +- move_file(&list.entries[n], NULL); ++ (void) move_file(&list.entries[n], NULL, NULL); + + return 0; + } diff --git a/SOURCES/0888-pstore-Don-t-start-systemd-pstore.service-in-contain.patch b/SOURCES/0888-pstore-Don-t-start-systemd-pstore.service-in-contain.patch new file mode 100644 index 0000000..10bb2fc --- /dev/null +++ b/SOURCES/0888-pstore-Don-t-start-systemd-pstore.service-in-contain.patch @@ -0,0 +1,27 @@ +From 653a635086cfeaf0af12da3a722b0ebe2029b927 Mon Sep 17 00:00:00 2001 +From: Balint Reczey +Date: Mon, 16 Dec 2019 19:03:19 +0100 +Subject: [PATCH] pstore: Don't start systemd-pstore.service in containers + +Usually it is not useful and can also fail making +boot-and-services autopkgtest fail. + +(cherry picked from commit 287f506c32f3f4a48ba020408f964cb0f964d752) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index dde21bc33e..89f34afe34 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -11,6 +11,7 @@ + Description=Platform Persistent Storage Archival + Documentation=man:systemd-pstore(8) + ConditionDirectoryNotEmpty=/sys/fs/pstore ++ConditionVirtualization=!container + DefaultDependencies=no + Wants=systemd-remount-fs.service + After=systemd-remount-fs.service diff --git a/SOURCES/0889-units-pull-in-systemd-pstore.service-from-sysinit.ta.patch b/SOURCES/0889-units-pull-in-systemd-pstore.service-from-sysinit.ta.patch new file mode 100644 index 0000000..3682e6f --- /dev/null +++ b/SOURCES/0889-units-pull-in-systemd-pstore.service-from-sysinit.ta.patch @@ -0,0 +1,36 @@ +From c7e65774a4ccc8a431f63c5a12ab776b24ee1190 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Apr 2020 16:12:00 +0200 +Subject: [PATCH] units: pull in systemd-pstore.service from sysinit.target + +sysinit.target is the target our early boot services are generally +pulled in from, make systemd-pstore.service not an exception of that. + +Effectively this doesn't mean much, either way our unit is part of the +initial transaction. + +(cherry picked from commit 167241912f51fbc0d7d0869b9af34c15b5ecc4b6) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index 89f34afe34..37fcf878f0 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -15,6 +15,7 @@ ConditionVirtualization=!container + DefaultDependencies=no + Wants=systemd-remount-fs.service + After=systemd-remount-fs.service ++Before=sysinit.target + + [Service] + Type=oneshot +@@ -23,4 +24,4 @@ RemainAfterExit=yes + StateDirectory=systemd/pstore + + [Install] +-WantedBy=systemd-remount-fs.service ++WantedBy=sysinit.target diff --git a/SOURCES/0890-units-drop-dependency-on-systemd-remount-fs.service-.patch b/SOURCES/0890-units-drop-dependency-on-systemd-remount-fs.service-.patch new file mode 100644 index 0000000..cb60e2b --- /dev/null +++ b/SOURCES/0890-units-drop-dependency-on-systemd-remount-fs.service-.patch @@ -0,0 +1,36 @@ +From bc6f273a0475a1fa7ab56bc1e498ee62c96aa660 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Apr 2020 16:10:38 +0200 +Subject: [PATCH] units: drop dependency on systemd-remount-fs.service from + systemd-pstore.service + +This dependency is now generated automatically given we use +StateDirectory=. Moreover the combination of Wants= and After= was too +strong anway, as whether remount-fs is pulled in or not should not be up +to systemd-pstore.service, and in fact is part of the initial +transaction anyway. + +[dtardon: This only removes Wants=, not After=, because I haven't +backported the auto-generation code the description talks about. The +code is simple, but it's just an optimisation allowing for slightly +shorter unit files, hence I don't think we really need it.] + +(cherry picked from commit 0c978faa16fa9ecf92f0bbb5c7cc709dc472d115) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index 37fcf878f0..9a86f3145c 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -13,7 +13,6 @@ Documentation=man:systemd-pstore(8) + ConditionDirectoryNotEmpty=/sys/fs/pstore + ConditionVirtualization=!container + DefaultDependencies=no +-Wants=systemd-remount-fs.service + After=systemd-remount-fs.service + Before=sysinit.target + diff --git a/SOURCES/0891-units-make-sure-systemd-pstore-stops-at-shutdown.patch b/SOURCES/0891-units-make-sure-systemd-pstore-stops-at-shutdown.patch new file mode 100644 index 0000000..6fdbf34 --- /dev/null +++ b/SOURCES/0891-units-make-sure-systemd-pstore-stops-at-shutdown.patch @@ -0,0 +1,29 @@ +From 818ddd1efd751ef50f9960920284465befe9d704 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Apr 2020 16:25:03 +0200 +Subject: [PATCH] units: make sure systemd-pstore stops at shutdown + +This doesn't matter too much given that the service doesn't do anything +on shutdown, but let's still stop it to make things cleaner. + +(cherry picked from commit b0c1a07654c80d3cbbbcc52f860d4206707c0b08) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index 9a86f3145c..8cbf264a99 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -14,7 +14,8 @@ ConditionDirectoryNotEmpty=/sys/fs/pstore + ConditionVirtualization=!container + DefaultDependencies=no + After=systemd-remount-fs.service +-Before=sysinit.target ++Conflicts=shutdown.target ++Before=sysinit.target shutdown.target + + [Service] + Type=oneshot diff --git a/SOURCES/0892-pstore-Run-after-modules-are-loaded.patch b/SOURCES/0892-pstore-Run-after-modules-are-loaded.patch new file mode 100644 index 0000000..491e363 --- /dev/null +++ b/SOURCES/0892-pstore-Run-after-modules-are-loaded.patch @@ -0,0 +1,45 @@ +From 9cc6ee46e0083bc36b53d19e14fb637f7a1542dd Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Thu, 9 Jun 2022 16:20:43 +0200 +Subject: [PATCH] pstore: Run after modules are loaded + +The systemd-pstore service takes pstore files on boot and transfers them +to disk. It only does it once on boot and only if it finds any. The typical +location of the pstore on modern systems is the UEFI variable store. + +Most distributions ship with CONFIG_EFI_VARS_PSTORE=m. That means, the +UEFI variable store is only available on boot after the respective module +is loaded. + +In most situations, the pstore service gets loaded before the UEFI pstore, +so we don't get to transfer logs. Instead, they accumulate, filling up the +pstore over time, potentially breaking the UEFI variable store. + +Let's add a service dependency on any kernel module that can provide a +pstore to ensure we only scan for pstate after we can actually see pstate. + +I have seen live occurences of systems breaking because we did not erase +the pstates and ran out of UEFI nvram space. + +Fixes https://github.com/systemd/systemd/issues/18540 + +(cherry picked from commit 70e74a5997ae2ce7ba72a74ac949c3b2dad1a1d6) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index 8cbf264a99..1983a9738f 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -16,6 +16,8 @@ DefaultDependencies=no + After=systemd-remount-fs.service + Conflicts=shutdown.target + Before=sysinit.target shutdown.target ++After=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service ++Wants=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service + + [Service] + Type=oneshot diff --git a/SOURCES/0893-pstore-do-not-try-to-load-all-known-pstore-modules.patch b/SOURCES/0893-pstore-do-not-try-to-load-all-known-pstore-modules.patch new file mode 100644 index 0000000..2108fd0 --- /dev/null +++ b/SOURCES/0893-pstore-do-not-try-to-load-all-known-pstore-modules.patch @@ -0,0 +1,48 @@ +From 6a6f108b59e47581d93cbc6bdc604ee84f1bb791 Mon Sep 17 00:00:00 2001 +From: Nick Rosbrook +Date: Wed, 7 Sep 2022 13:25:13 -0400 +Subject: [PATCH] pstore: do not try to load all known pstore modules + +Commit 70e74a5997 ("pstore: Run after modules are loaded") added After= +and Wants= entries for all known kernel modules providing a pstore. + +While adding these dependencies on systems where one of the modules is +not present, or not configured, should not have a real affect on the +system, it can produce annoying error messages in the kernel log. E.g. +"mtd device must be supplied (device name is empty)" when the mtdpstore +module is not configured correctly. + +Since dependencies cannot be removed with drop-ins, if a distro wants to +remove some of these modules from systemd-pstore.service, they need to +patch units/systemd-pstore.service.in. On the other hand, if they want +to append to the dependencies this can be done by shipping a drop-in. + +Since the original intent of the previous commit was to fix [1], which +only requires the efi_pstore module, remove all other kernel module +dependencies from systemd-pstore.service, and let distros ship drop-ins +to add dependencies if needed. + +[1] https://github.com/systemd/systemd/issues/18540 + +(cherry picked from commit 8b8bd621e1d16808678fc3afed257df1fa03a281) + +Related: #2158832 +--- + units/systemd-pstore.service.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in +index 1983a9738f..19ffa8d4e8 100644 +--- a/units/systemd-pstore.service.in ++++ b/units/systemd-pstore.service.in +@@ -16,8 +16,8 @@ DefaultDependencies=no + After=systemd-remount-fs.service + Conflicts=shutdown.target + Before=sysinit.target shutdown.target +-After=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service +-Wants=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service ++After=modprobe@efi_pstore.service ++Wants=modprobe@efi_pstore.service + + [Service] + Type=oneshot diff --git a/SOURCES/0894-logind-session-make-stopping-of-idle-session-visible.patch b/SOURCES/0894-logind-session-make-stopping-of-idle-session-visible.patch new file mode 100644 index 0000000..df27c3b --- /dev/null +++ b/SOURCES/0894-logind-session-make-stopping-of-idle-session-visible.patch @@ -0,0 +1,26 @@ +From b18e19f2262e7ed95c25d53268d12427fe77102d Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Tue, 21 Feb 2023 10:41:47 +0100 +Subject: [PATCH] logind-session: make stopping of idle session visible to + admins + +(cherry picked from commit 6269ffe7ee8a659df7336a2582054ecd9eecf4b1) + +Resolves: #2156780 +--- + src/login/logind-session.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 18a07efcdb..916202a65a 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -673,7 +673,7 @@ static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, vo + + idle = session_get_idle_hint(s, &ts); + if (idle) { +- log_debug("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name); ++ log_info("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name); + + return session_stop(s, /* force */ true); + } diff --git a/SOURCES/0895-journald-Increase-stdout-buffer-size-sooner-when-alm.patch b/SOURCES/0895-journald-Increase-stdout-buffer-size-sooner-when-alm.patch new file mode 100644 index 0000000..f03ea88 --- /dev/null +++ b/SOURCES/0895-journald-Increase-stdout-buffer-size-sooner-when-alm.patch @@ -0,0 +1,32 @@ +From a0b52398692f3e4bda18520db9e2397f7b2c80dd Mon Sep 17 00:00:00 2001 +From: Benjamin Robin +Date: Sun, 3 May 2020 18:37:21 +0200 +Subject: [PATCH] journald: Increase stdout buffer size sooner, when almost + full + +If the previous received buffer length is almost equal to the allocated +buffer size, before this change the next read can only receive a couple +of bytes (in the worst case only 1 byte), which is not efficient. + +(cherry picked from commit 034e9719ac1ba88a36b05da38c7aa98761d42c77) + +Related: #2029426 +--- + src/journal/journald-stream.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 302a82d3d7..c8de984335 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -507,8 +507,8 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + goto terminate; + } + +- /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */ +- if (s->length + 1 >= s->allocated) { ++ /* If the buffer is almost full, add room for another 1K */ ++ if (s->length + 512 >= s->allocated) { + if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) { + log_oom(); + goto terminate; diff --git a/SOURCES/0896-journald-rework-end-of-line-marker-handling-to-use-a.patch b/SOURCES/0896-journald-rework-end-of-line-marker-handling-to-use-a.patch new file mode 100644 index 0000000..a655502 --- /dev/null +++ b/SOURCES/0896-journald-rework-end-of-line-marker-handling-to-use-a.patch @@ -0,0 +1,77 @@ +From d8fabe7a6839eeb0d5d0504471f2d18b07545238 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 12 May 2020 18:53:35 +0200 +Subject: [PATCH] journald: rework end of line marker handling to use a field + table + +(cherry picked from commit 549b7379ba404c33fd448d2bca46a57f6529b00b) + +Related: #2029426 +--- + src/journal/journald-stream.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index c8de984335..58752a5a24 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -54,6 +54,8 @@ typedef enum LineBreak { + LINE_BREAK_NUL, + LINE_BREAK_LINE_MAX, + LINE_BREAK_EOF, ++ _LINE_BREAK_MAX, ++ _LINE_BREAK_INVALID = -1, + } LineBreak; + + struct StdoutStream { +@@ -233,7 +235,11 @@ fail: + return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file); + } + +-static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) { ++static int stdout_stream_log( ++ StdoutStream *s, ++ const char *p, ++ LineBreak line_break) { ++ + struct iovec *iovec; + int priority; + char syslog_priority[] = "PRIORITY=\0"; +@@ -245,6 +251,9 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea + assert(s); + assert(p); + ++ assert(line_break >= 0); ++ assert(line_break < _LINE_BREAK_MAX); ++ + if (s->context) + (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY); + else if (pid_is_valid(s->ucred.pid)) { +@@ -296,17 +305,19 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea + iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier); + } + +- if (line_break != LINE_BREAK_NEWLINE) { +- const char *c; ++ static const char * const line_break_field_table[_LINE_BREAK_MAX] = { ++ [LINE_BREAK_NEWLINE] = NULL, /* Do not add field if traditional newline */ ++ [LINE_BREAK_NUL] = "_LINE_BREAK=nul", ++ [LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max", ++ [LINE_BREAK_EOF] = "_LINE_BREAK=eof", ++ }; + +- /* If this log message was generated due to an uncommon line break then mention this in the log +- * entry */ ++ const char *c = line_break_field_table[line_break]; + +- c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" : +- line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" : +- "_LINE_BREAK=eof"; ++ /* If this log message was generated due to an uncommon line break then mention this in the log ++ * entry */ ++ if (c) + iovec[n++] = IOVEC_MAKE_STRING(c); +- } + + message = strappend("MESSAGE=", p); + if (message) diff --git a/SOURCES/0897-journald-use-the-fact-that-client_context_release-re.patch b/SOURCES/0897-journald-use-the-fact-that-client_context_release-re.patch new file mode 100644 index 0000000..7d4ab74 --- /dev/null +++ b/SOURCES/0897-journald-use-the-fact-that-client_context_release-re.patch @@ -0,0 +1,27 @@ +From cd85a657c932725ac7c1b506dc6dd4270d1dc068 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 12 May 2020 19:15:38 +0200 +Subject: [PATCH] journald: use the fact that client_context_release() returns + NULL + +(cherry picked from commit 020b4a023c2c6dda83afb9a82a62e640569c40c1) + +Related: #2029426 +--- + src/journal/journald-stream.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 58752a5a24..ab1a855943 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -570,8 +570,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + goto terminate; + + s->ucred = *ucred; +- client_context_release(s->server, s->context); +- s->context = NULL; ++ s->context = client_context_release(s->server, s->context); + } + + s->length += l; diff --git a/SOURCES/0898-journald-rework-pid-change-handling.patch b/SOURCES/0898-journald-rework-pid-change-handling.patch new file mode 100644 index 0000000..09fb251 --- /dev/null +++ b/SOURCES/0898-journald-rework-pid-change-handling.patch @@ -0,0 +1,219 @@ +From 538bd9b42dabf1145cf7ab77f32347d516b01e88 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 12 May 2020 18:56:34 +0200 +Subject: [PATCH] journald: rework pid change handling + +Let's introduce an explicit line ending marker for line endings due to +pid change. + +Let's also make sure we don't get confused with buffer management. + +Fixes: #15654 +(cherry picked from commit 45ba1ea5e9264d385fa565328fe957ef1d78caa1) + +Resolves: #2029426 +--- + src/journal/journald-stream.c | 99 +++++++++++++++++++++++------------ + 1 file changed, 66 insertions(+), 33 deletions(-) + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index ab1a855943..5be5b0939c 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -54,6 +54,7 @@ typedef enum LineBreak { + LINE_BREAK_NUL, + LINE_BREAK_LINE_MAX, + LINE_BREAK_EOF, ++ LINE_BREAK_PID_CHANGE, + _LINE_BREAK_MAX, + _LINE_BREAK_INVALID = -1, + } LineBreak; +@@ -310,6 +311,7 @@ static int stdout_stream_log( + [LINE_BREAK_NUL] = "_LINE_BREAK=nul", + [LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max", + [LINE_BREAK_EOF] = "_LINE_BREAK=eof", ++ [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change", + }; + + const char *c = line_break_field_table[line_break]; +@@ -431,21 +433,43 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { + assert_not_reached("Unknown stream state"); + } + +-static int stdout_stream_scan(StdoutStream *s, bool force_flush) { +- char *p; +- size_t remaining; ++static int stdout_stream_found( ++ StdoutStream *s, ++ char *p, ++ size_t l, ++ LineBreak line_break) { ++ ++ char saved; + int r; + + assert(s); ++ assert(p); ++ ++ /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */ ++ saved = p[l]; ++ p[l] = 0; ++ r = stdout_stream_line(s, p, line_break); ++ p[l] = saved; + +- p = s->buffer; +- remaining = s->length; ++ return r; ++} ++ ++static int stdout_stream_scan( ++ StdoutStream *s, ++ char *p, ++ size_t remaining, ++ LineBreak force_flush, ++ size_t *ret_consumed) { + +- /* XXX: This function does nothing if (s->length == 0) */ ++ size_t consumed = 0; ++ int r; ++ ++ assert(s); ++ assert(p); + + for (;;) { + LineBreak line_break; +- size_t skip; ++ size_t skip, found; + char *end1, *end2; + + end1 = memchr(p, '\n', remaining); +@@ -453,43 +477,40 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + + if (end2) { + /* We found a NUL terminator */ +- skip = end2 - p + 1; ++ found = end2 - p; ++ skip = found + 1; + line_break = LINE_BREAK_NUL; + } else if (end1) { + /* We found a \n terminator */ +- *end1 = 0; +- skip = end1 - p + 1; ++ found = end1 - p; ++ skip = found + 1; + line_break = LINE_BREAK_NEWLINE; + } else if (remaining >= s->server->line_max) { + /* Force a line break after the maximum line length */ +- *(p + s->server->line_max) = 0; +- skip = remaining; ++ found = skip = s->server->line_max; + line_break = LINE_BREAK_LINE_MAX; + } else + break; + +- r = stdout_stream_line(s, p, line_break); ++ r = stdout_stream_found(s, p, found, line_break); + if (r < 0) + return r; + +- remaining -= skip; + p += skip; ++ consumed += skip; ++ remaining -= skip; + } + +- if (force_flush && remaining > 0) { +- p[remaining] = 0; +- r = stdout_stream_line(s, p, LINE_BREAK_EOF); ++ if (force_flush >= 0 && remaining > 0) { ++ r = stdout_stream_found(s, p, remaining, force_flush); + if (r < 0) + return r; + +- p += remaining; +- remaining = 0; ++ consumed += remaining; + } + +- if (p > s->buffer) { +- memmove(s->buffer, p, remaining); +- s->length = remaining; +- } ++ if (ret_consumed) ++ *ret_consumed = consumed; + + return 0; + } +@@ -497,11 +518,12 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + StdoutStream *s = userdata; ++ size_t limit, consumed; + struct ucred *ucred = NULL; + struct cmsghdr *cmsg; + struct iovec iovec; +- size_t limit; + ssize_t l; ++ char *p; + int r; + + struct msghdr msghdr = { +@@ -529,7 +551,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also, + * always leave room for a terminating NUL we might need to add. */ + limit = MIN(s->allocated - 1, s->server->line_max); +- ++ assert(s->length <= limit); + iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length); + + l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); +@@ -543,7 +565,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + cmsg_close_all(&msghdr); + + if (l == 0) { +- stdout_stream_scan(s, true); ++ (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL); + goto terminate; + } + +@@ -562,22 +584,33 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + * in the meantime. + */ + if (ucred && ucred->pid != s->ucred.pid) { +- /* force out any previously half-written lines from a +- * different process, before we switch to the new ucred +- * structure for everything we just added */ +- r = stdout_stream_scan(s, true); ++ /* Force out any previously half-written lines from a different process, before we switch to ++ * the new ucred structure for everything we just added */ ++ r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL); + if (r < 0) + goto terminate; + +- s->ucred = *ucred; + s->context = client_context_release(s->server, s->context); ++ ++ p = s->buffer + s->length; ++ } else { ++ p = s->buffer; ++ l += s->length; + } + +- s->length += l; +- r = stdout_stream_scan(s, false); ++ /* Always copy in the new credentials */ ++ if (ucred) ++ s->ucred = *ucred; ++ ++ r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed); + if (r < 0) + goto terminate; + ++ /* Move what wasn't consumed to the front of the buffer */ ++ assert(consumed <= (size_t) l); ++ s->length = l - consumed; ++ memmove(s->buffer, p + consumed, s->length); ++ + return 1; + + terminate: diff --git a/SOURCES/0899-test-Add-a-test-case-for-15654.patch b/SOURCES/0899-test-Add-a-test-case-for-15654.patch new file mode 100644 index 0000000..24d7ee7 --- /dev/null +++ b/SOURCES/0899-test-Add-a-test-case-for-15654.patch @@ -0,0 +1,34 @@ +From e019afeefb396ea42d03f4c3f9713e262aff6450 Mon Sep 17 00:00:00 2001 +From: Benjamin Robin +Date: Wed, 6 May 2020 23:28:02 +0200 +Subject: [PATCH] test: Add a test case for #15654 + +(cherry picked from commit c11d8fd1dab3bc3f0abbc861ba5eb34518cec1da) + +Related: #2029426 +--- + test/TEST-04-JOURNAL/test-journal.sh | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh +index a3db1a7472..bdf137cd69 100755 +--- a/test/TEST-04-JOURNAL/test-journal.sh ++++ b/test/TEST-04-JOURNAL/test-journal.sh +@@ -76,6 +76,17 @@ journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output + grep -q "^_PID=$PID" /output + grep -vq "^_PID=$PID" /output + ++# https://github.com/systemd/systemd/issues/15654 ++ID=$(journalctl --new-id128 | sed -n 2p) ++printf "This will\nusually fail\nand be truncated\n">/expected ++systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usually fail";echo;env echo -n "and be truncated";echo;' ++journalctl --sync ++journalctl -b -o cat -t "$ID" >/output ++cmp /expected /output ++ ++# Add new tests before here, the journald restarts below ++# may make tests flappy. ++ + # Don't lose streams on restart + systemctl start forever-print-hola + sleep 3 diff --git a/SOURCES/0900-test-Stricter-test-case-for-15654-Add-more-checks.patch b/SOURCES/0900-test-Stricter-test-case-for-15654-Add-more-checks.patch new file mode 100644 index 0000000..8ebaec2 --- /dev/null +++ b/SOURCES/0900-test-Stricter-test-case-for-15654-Add-more-checks.patch @@ -0,0 +1,32 @@ +From afcfb65ce7514bf32e59e0b9d212ae18d023a4b5 Mon Sep 17 00:00:00 2001 +From: Benjamin Robin +Date: Sat, 9 May 2020 12:01:07 +0200 +Subject: [PATCH] test: Stricter test case for #15654 (Add more checks) + +Check: + - There is only 3 messages logged with type stdout + - Check all messages logged does not have new line: LINE_BREAK=eof + - Check that the 3 messages are logged from a different PID + - Check the 3 MESSAGE= content +(cherry picked from commit d38b3b74dbde2d65b23e5963354c3db96acd3420) + +Related: #2029426 +--- + test/TEST-04-JOURNAL/test-journal.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh +index bdf137cd69..641259ce24 100755 +--- a/test/TEST-04-JOURNAL/test-journal.sh ++++ b/test/TEST-04-JOURNAL/test-journal.sh +@@ -83,6 +83,10 @@ systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usual + journalctl --sync + journalctl -b -o cat -t "$ID" >/output + cmp /expected /output ++[[ $(journalctl -b -o export -t "$ID" --output-fields=_TRANSPORT | grep -Pc "^_TRANSPORT=stdout$") -eq 3 ]] ++[[ $(journalctl -b -o export -t "$ID" --output-fields=_LINE_BREAK | grep -Pc "^_LINE_BREAK=pid-change$") -eq 3 ]] ++[[ $(journalctl -b -o export -t "$ID" --output-fields=_PID | sort -u | grep -c "^_PID=.*$") -eq 3 ]] ++[[ $(journalctl -b -o export -t "$ID" --output-fields=MESSAGE | grep -Pc "^MESSAGE=(This will|usually fail|and be truncated)$") -eq 3 ]] + + # Add new tests before here, the journald restarts below + # may make tests flappy. diff --git a/SOURCES/0901-man-document-the-new-_LINE_BREAK-type.patch b/SOURCES/0901-man-document-the-new-_LINE_BREAK-type.patch new file mode 100644 index 0000000..75c0e85 --- /dev/null +++ b/SOURCES/0901-man-document-the-new-_LINE_BREAK-type.patch @@ -0,0 +1,42 @@ +From 2f55aeadef3dcdf65c61f24a41178148c3544ac3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 13 May 2020 00:09:43 +0200 +Subject: [PATCH] man: document the new _LINE_BREAK= type + +(cherry picked from commit a3d9aee14fa2f7df429dc401582877176206b7fd) + +Related: #2029426 +--- + man/systemd.journal-fields.xml | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml +index 0c95c4cd95..ad2b94dbd5 100644 +--- a/man/systemd.journal-fields.xml ++++ b/man/systemd.journal-fields.xml +@@ -326,15 +326,16 @@ + + _LINE_BREAK= + +- Only applies to _TRANSPORT=stdout records: indicates that the log message in the +- standard output/error stream was not terminated with a normal newline character (\n, +- i.e. ASCII 10). Specifically, when set this field is one of (in case the line was +- terminated by a NUL byte), (in case the maximum log line length was reached, as +- configured with LineMax= in +- journald.conf5) or +- (if this was the last log record of a stream and the stream ended without a final +- newline character). Note that this record is not generated when a normal newline character was used for +- marking the log line end. ++ Only applies to _TRANSPORT=stdout records: indicates that the log message ++ in the standard output/error stream was not terminated with a normal newline character ++ (\n, i.e. ASCII 10). Specifically, when set this field is one of ++ (in case the line was terminated by a NUL byte), (in ++ case the maximum log line length was reached, as configured with LineMax= in ++ journald.conf5), ++ (if this was the last log record of a stream and the stream ended without a ++ final newline character), or (if the process which generated the log ++ output changed in the middle of a line). Note that this record is not generated when a normal ++ newline character was used for marking the log line end. + + + diff --git a/SOURCES/0902-journald-server-always-create-state-file-in-signal-h.patch b/SOURCES/0902-journald-server-always-create-state-file-in-signal-h.patch new file mode 100644 index 0000000..b09df96 --- /dev/null +++ b/SOURCES/0902-journald-server-always-create-state-file-in-signal-h.patch @@ -0,0 +1,38 @@ +From 47cc8f7e1d153e576f146d309b4043739997a673 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 13 Mar 2023 14:22:28 +0100 +Subject: [PATCH] journald-server: always create state file in signal handler + +`journalctl --flush` waits on that file, so we must create if even if +nothing has really happened. + +RHEL-only + +Resolves: #2174645 +--- + src/journal/journald-server.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 279a32768c..c72cb68095 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1188,6 +1188,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + + static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; ++ int r; + + assert(s); + +@@ -1197,6 +1198,10 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * + server_sync(s); + server_vacuum(s, false); + ++ r = touch("/run/systemd/journal/flushed"); ++ if (r < 0) ++ log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m"); ++ + server_space_usage_message(s, NULL); + return 0; + } diff --git a/SOURCES/0903-journald-server-move-relinquish-code-into-function.patch b/SOURCES/0903-journald-server-move-relinquish-code-into-function.patch new file mode 100644 index 0000000..46f057d --- /dev/null +++ b/SOURCES/0903-journald-server-move-relinquish-code-into-function.patch @@ -0,0 +1,62 @@ +From 7a7b0c4ec7a5595a44d9c70d8270b0724a8b8c45 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 13 Mar 2023 14:31:38 +0100 +Subject: [PATCH] journald-server: move relinquish code into function + +No functional change, just refactoring. + +RHEL-only + +Related: #2174645 +--- + src/journal/journald-server.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index c72cb68095..aa70db95cc 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1258,20 +1258,16 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo + return 0; + } + +- +-static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { +- Server *s = userdata; ++static void relinquish_var(Server *s) { + int r; + + assert(s); + + if (s->storage == STORAGE_NONE) +- return 0; ++ return; + + if (s->runtime_journal && !s->system_journal) +- return 0; +- +- log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid); ++ return; + + (void) system_journal_open(s, false, true); + +@@ -1286,6 +1282,19 @@ static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo + if (r < 0) + log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m"); + ++ return; ++} ++ ++static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { ++ Server *s = userdata; ++ ++ assert(s); ++ assert(si); ++ ++ log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid); ++ ++ relinquish_var(s); ++ + return 0; + } + diff --git a/SOURCES/0904-journald-server-always-touch-state-file-in-signal-ha.patch b/SOURCES/0904-journald-server-always-touch-state-file-in-signal-ha.patch new file mode 100644 index 0000000..40267b7 --- /dev/null +++ b/SOURCES/0904-journald-server-always-touch-state-file-in-signal-ha.patch @@ -0,0 +1,58 @@ +From 980add7d84084a474c6c604c0670743c2d1e624c Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 13 Mar 2023 14:32:20 +0100 +Subject: [PATCH] journald-server: always touch state file in signal handler + +`journalctl --relinquish-var` waits on that file, so we must create if +even if nothing has really happened. + +RHEL-only + +Related: #2174645 +--- + src/journal/journald-server.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index aa70db95cc..4788ff78bb 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1259,8 +1259,6 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo + } + + static void relinquish_var(Server *s) { +- int r; +- + assert(s); + + if (s->storage == STORAGE_NONE) +@@ -1278,15 +1276,15 @@ static void relinquish_var(Server *s) { + if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT) + log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m") ; + +- r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC)); +- if (r < 0) +- log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m"); ++ /* NOTE: We don't create our own state file here, because dispatch_sigrtmin2() has to do it anyway. ++ * But if this function is ever called from another place, the creation must be done here too. */ + + return; + } + + static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; ++ int r; + + assert(s); + assert(si); +@@ -1295,6 +1293,10 @@ static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo + + relinquish_var(s); + ++ r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC)); ++ if (r < 0) ++ log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m"); ++ + return 0; + } + diff --git a/SOURCES/systemd-user b/SOURCES/systemd-user index 8607d4f..d1f64c1 100644 --- a/SOURCES/systemd-user +++ b/SOURCES/systemd-user @@ -8,4 +8,5 @@ account include system-auth session required pam_selinux.so close session required pam_selinux.so nottys open session required pam_loginuid.so +session required pam_namespace.so session include system-auth diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 1d067ef..da5b57f 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: 68%{?dist}.4 +Release: 74%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -881,13 +881,79 @@ Patch0828: 0828-core-load-fragment-move-config_parse_sec_fix_0-to-sr.patch Patch0829: 0829-sd-event-add-relative-timer-calls.patch Patch0830: 0830-logind-add-option-to-stop-idle-sessions-after-specif.patch Patch0831: 0831-logind-schedule-idle-check-full-interval-from-now-if.patch -Patch0832: 0832-time-util-fix-buffer-over-run.patch -Patch0833: 0833-core-move-reset_arguments-to-the-end-of-main-s-finis.patch -Patch0834: 0834-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch -Patch0835: 0835-core-bring-manager_startup-and-manager_reload-more-i.patch -Patch0836: 0836-basic-add-STRERROR-wrapper-for-strerror_r.patch -Patch0837: 0837-coredump-put-context-array-into-a-struct.patch -Patch0838: 0838-coredump-do-not-allow-user-to-access-coredumps-with-.patch +Patch0832: 0832-ci-lint-add-shell-linter-Differential-ShellCheck.patch +Patch0833: 0833-meson-do-not-compare-objects-of-different-types.patch +Patch0834: 0834-journal-remote-use-MHD_HTTP_CONTENT_TOO_LARGE-as-MHD.patch +Patch0835: 0835-Fix-build-with-httpd-0.9.71.patch +Patch0836: 0836-ci-replace-LGTM-with-CodeQL.patch +Patch0837: 0837-ci-mergify-Update-policy-Drop-LGTM-checks.patch +Patch0838: 0838-time-util-fix-buffer-over-run.patch +Patch0839: 0839-basic-recognize-pdfs-filesystem-as-a-network-filesys.patch +Patch0840: 0840-core-move-reset_arguments-to-the-end-of-main-s-finis.patch +Patch0841: 0841-manager-move-inc.-of-n_reloading-into-a-function.patch +Patch0842: 0842-core-Add-new-DBUS-properties-UnitsReloadStartTimesta.patch +Patch0843: 0843-core-Indicate-the-time-when-the-manager-started-load.patch +Patch0844: 0844-core-do-not-touch-run-systemd-systemd-units-load-fro.patch +Patch0845: 0845-sysctl-downgrade-message-when-we-have-no-permission.patch +Patch0846: 0846-core-respect-SELinuxContext-for-socket-creation.patch +Patch0847: 0847-manager-use-target-process-context-to-set-socket-con.patch +Patch0848: 0848-virt-detect-Amazon-EC2-Nitro-instance.patch +Patch0849: 0849-machine-id-setup-generate-machine-id-from-DMI-produc.patch +Patch0850: 0850-virt-use-string-table-to-detect-VM-or-container.patch +Patch0851: 0851-fileio-introduce-read_full_virtual_file-for-reading-.patch +Patch0852: 0852-Use-BIOS-characteristics-to-distinguish-EC2-bare-met.patch +Patch0853: 0853-device-drop-refuse_after.patch +Patch0854: 0854-manager-limit-access-to-private-dbus-socket.patch +Patch0855: 0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch +Patch0856: 0856-core-bring-manager_startup-and-manager_reload-more-i.patch +Patch0857: 0857-pam-add-a-call-to-pam_namespace.patch +Patch0858: 0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch +Patch0859: 0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch +Patch0860: 0860-basic-add-STRERROR-wrapper-for-strerror_r.patch +Patch0861: 0861-coredump-put-context-array-into-a-struct.patch +Patch0862: 0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch +Patch0863: 0863-logind-remember-our-idle-state-and-use-it-to-detect-.patch +Patch0864: 0864-test-import-logind-test-from-debian-ubuntu-test-suit.patch +Patch0865: 0865-test-introduce-inst_recursive-helper-function.patch +Patch0866: 0866-tests-verify-that-Lock-D-Bus-signal-is-sent-when-Idl.patch +Patch0867: 0867-systemctl-simplify-halt_main.patch +Patch0868: 0868-systemctl-shutdown-don-t-fallback-on-auth-fail.patch +Patch0869: 0869-systemctl-reintroduce-the-original-halt_main.patch +Patch0870: 0870-systemctl-preserve-old-behavior-unless-requested.patch +Patch0871: 0871-pam_systemd-suppress-LOG_DEBUG-log-messages-if-debug.patch +Patch0872: 0872-udev-net_id-introduce-naming-scheme-for-RHEL-8.8.patch +Patch0873: 0873-journald-add-API-to-move-logging-from-var-to-run-aga.patch +Patch0874: 0874-journalctl-add-new-relinquish-and-smart-relinquish-o.patch +Patch0875: 0875-units-automatically-revert-to-run-logging-on-shutdow.patch +Patch0876: 0876-pstore-Tool-to-archive-contents-of-pstore.patch +Patch0877: 0877-meson-drop-redundant-line.patch +Patch0878: 0878-pstore-drop-unnecessary-initializations.patch +Patch0879: 0879-pstopre-fix-return-value-of-list_files.patch +Patch0880: 0880-pstore-remove-temporary-file-on-failure.patch +Patch0881: 0881-pstore-do-not-add-FILE-journal-entry-if-content_size.patch +Patch0882: 0882-pstore-run-only-when-sys-fs-pstore-is-not-empty.patch +Patch0883: 0883-pstore-fix-use-after-free.patch +Patch0884: 0884-pstore-refuse-to-run-if-arguments-are-specified.patch +Patch0885: 0885-pstore-allow-specifying-src-and-dst-dirs-are-argumen.patch +Patch0886: 0886-pstore-rework-memory-handling-for-dmesg.patch +Patch0887: 0887-pstore-fixes-for-dmesg.txt-reconstruction.patch +Patch0888: 0888-pstore-Don-t-start-systemd-pstore.service-in-contain.patch +Patch0889: 0889-units-pull-in-systemd-pstore.service-from-sysinit.ta.patch +Patch0890: 0890-units-drop-dependency-on-systemd-remount-fs.service-.patch +Patch0891: 0891-units-make-sure-systemd-pstore-stops-at-shutdown.patch +Patch0892: 0892-pstore-Run-after-modules-are-loaded.patch +Patch0893: 0893-pstore-do-not-try-to-load-all-known-pstore-modules.patch +Patch0894: 0894-logind-session-make-stopping-of-idle-session-visible.patch +Patch0895: 0895-journald-Increase-stdout-buffer-size-sooner-when-alm.patch +Patch0896: 0896-journald-rework-end-of-line-marker-handling-to-use-a.patch +Patch0897: 0897-journald-use-the-fact-that-client_context_release-re.patch +Patch0898: 0898-journald-rework-pid-change-handling.patch +Patch0899: 0899-test-Add-a-test-case-for-15654.patch +Patch0900: 0900-test-Stricter-test-case-for-15654-Add-more-checks.patch +Patch0901: 0901-man-document-the-new-_LINE_BREAK-type.patch +Patch0902: 0902-journald-server-always-create-state-file-in-signal-h.patch +Patch0903: 0903-journald-server-move-relinquish-code-into-function.patch +Patch0904: 0904-journald-server-always-touch-state-file-in-signal-ha.patch %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 @@ -1305,7 +1371,8 @@ python3 %{SOURCE2} %buildroot < - 239-68.4 -- basic: add STRERROR() wrapper for strerror_r() (#2155519) -- coredump: put context array into a struct (#2155519) -- coredump: do not allow user to access coredumps with changed uid/gid/capabilities (#2155519) - -* Fri Jan 27 2023 systemd maintenance team - 239-68.3 -- core: bring manager_startup() and manager_reload() more inline (#2164049) - -* Mon Nov 21 2022 systemd maintenance team - 239-68.2 -- basic: recognize pdfs filesystem as a network filesystem (#2143100) - -* Mon Nov 07 2022 systemd maintenance team - 239-68.1 -- time-util: fix buffer-over-run (#2139390) -- core: move reset_arguments() to the end of main's finish (#2127170) - -* Tue Sep 27 2022 systemd maintenance team - 239-68 +* Tue Mar 14 2023 systemd maintenance team - 239-74 +- journald-server: always create state file in signal handler (#2174645) +- journald-server: move relinquish code into function (#2174645) +- journald-server: always touch state file in signal handler (#2174645) + +* Mon Feb 27 2023 systemd maintenance team - 239-73 +- journald: add API to move logging from /var to /run again (#1873540) +- journalctl: add new --relinquish and --smart-relinquish options (#1873540) +- units: automatically revert to /run logging on shutdown if necessary (#1873540) +- pstore: Tool to archive contents of pstore (#2158832) +- meson: drop redundant line (#2158832) +- pstore: drop unnecessary initializations (#2158832) +- pstopre: fix return value of list_files() (#2158832) +- pstore: remove temporary file on failure (#2158832) +- pstore: do not add FILE= journal entry if content_size == 0 (#2158832) +- pstore: run only when /sys/fs/pstore is not empty (#2158832) +- pstore: fix use after free (#2158832) +- pstore: refuse to run if arguments are specified (#2158832) +- pstore: allow specifying src and dst dirs are arguments (#2158832) +- pstore: rework memory handling for dmesg (#2158832) +- pstore: fixes for dmesg.txt reconstruction (#2158832) +- pstore: Don't start systemd-pstore.service in containers (#2158832) +- units: pull in systemd-pstore.service from sysinit.target (#2158832) +- units: drop dependency on systemd-remount-fs.service from systemd-pstore.service (#2158832) +- units: make sure systemd-pstore stops at shutdown (#2158832) +- pstore: Run after modules are loaded (#2158832) +- pstore: do not try to load all known pstore modules (#2158832) +- logind-session: make stopping of idle session visible to admins (#2156780) +- journald: Increase stdout buffer size sooner, when almost full (#2029426) +- journald: rework end of line marker handling to use a field table (#2029426) +- journald: use the fact that client_context_release() returns NULL (#2029426) +- journald: rework pid change handling (#2029426) +- test: Add a test case for #15654 (#2029426) +- test: Stricter test case for #15654 (Add more checks) (#2029426) +- man: document the new _LINE_BREAK= type (#2029426) + +* Fri Feb 17 2023 systemd maintenance team - 239-72 +- test: import logind test from debian/ubuntu test suite (#1866955) +- test: introduce inst_recursive() helper function (#1866955) +- tests: verify that Lock D-Bus signal is sent when IdleAction=lock (#1866955) +- systemctl: simplify halt_main() (#2053273) +- systemctl: shutdown don't fallback on auth fail (#2053273) +- systemctl: reintroduce the original halt_main() (#2053273) +- systemctl: preserve old behavior unless requested (#2053273) +- pam_systemd: suppress LOG_DEBUG log messages if debugging is off (#2170084) +- udev/net_id: introduce naming scheme for RHEL-8.8 (#2170499) +- pam: add a call to pam_namespace (#1861836) + +* Tue Jan 31 2023 systemd maintenance team - 239-71 +- manager: limit access to private dbus socket (#2119405) +- journalctl: do not treat EINTR as an error when waiting for events (#2161683) +- core: bring manager_startup() and manager_reload() more inline (#2059633) +- pam: add a call to pam_namespace (#1861836) +- virt: Support detection for ARM64 Hyper-V guests (#2158307) +- virt: Fix the detection for Hyper-V VMs (#2158307) +- basic: add STRERROR() wrapper for strerror_r() (#2155520) +- coredump: put context array into a struct (#2155520) +- coredump: do not allow user to access coredumps with changed uid/gid/capabilities (#2155520) + +* Mon Jan 16 2023 systemd maintenance team - 239-70 +- basic: recognize pdfs filesystem as a network filesystem (#2094661) +- core: move reset_arguments() to the end of main's finish (#2127131) +- manager: move inc. of n_reloading into a function (#2136869) +- core: Add new DBUS properties UnitsReloadStartTimestamp and UnitsLoadTimestampMontonic (#2136869) +- core: Indicate the time when the manager started loading units the last time (#2136869) +- core: do not touch /run/systemd/systemd-units-load from user session instances (#2136869) +- sysctl: downgrade message when we have no permission (#2158160) +- core: respect SELinuxContext= for socket creation (#2136738) +- manager: use target process context to set socket context (#2136738) +- virt: detect Amazon EC2 Nitro instance (#2117948) +- machine-id-setup: generate machine-id from DMI product ID on Amazon EC2 (#2117948) +- virt: use string table to detect VM or container (#2117948) +- fileio: introduce read_full_virtual_file() for reading virtual files in sysfs, procfs (#2117948) +- Use BIOS characteristics to distinguish EC2 bare-metal from VMs (#2117948) +- device: drop refuse_after (#2043524) + +* Tue Nov 08 2022 systemd maintenance team - 239-69 - logind: optionally watch utmp for login data (#2122288) - logind: add hashtable for finding session by leader PID (#2122288) - core/load-fragment: move config_parse_sec_fix_0 to src/shared (#2122288) - sd-event: add relative timer calls (#2122288) - logind: add option to stop idle sessions after specified timeout (#2122288) - logind: schedule idle check full interval from now if we couldn't figure out atime timestamp (#2122288) +- ci(lint): add shell linter - Differential ShellCheck (#2122499) +- meson: do not compare objects of different types (#2122499) +- journal-remote: use MHD_HTTP_CONTENT_TOO_LARGE as MHD_HTTP_PAYLOAD_TOO_LARGE is deprecated since 0.9.74 (#2122499) +- Fix build with µhttpd 0.9.71 (#2122499) +- ci: replace LGTM with CodeQL (#2122499) +- ci(mergify): Update policy - Drop LGTM checks (#2122499) +- time-util: fix buffer-over-run (#2139391) * Fri Aug 26 2022 systemd maintenance team - 239-67 - resolved: pin stream while calling callbacks for it (#2110549)