import systemd-252-46.el9_5.2

c9 imports/c9/systemd-252-46.el9_5.2
MSVSphere Packaging Team 1 month ago
parent ccf0d74ebf
commit 0e818eb40a
Signed by: sys_gitsync
GPG Key ID: B2B0B9F29E528FE8

@ -1,4 +1,4 @@
From 8e8f4d63f77fb9436d1e4caa2a4670dc3cf74657 Mon Sep 17 00:00:00 2001
From 7d3b9e98e22f92561c98f6bf838cc830324834e3 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 13 Dec 2022 10:50:01 +0000
Subject: [PATCH] execute: Pass AT_FDCWD instead of -1
@ -8,7 +8,7 @@ to avoid an assert() in read_full_file_full() if read_dfd is -1.
(cherry picked from commit 661e4251a5b157d1aee1df98fbd2f0c95285ebba)
Resolves: RHEL-32259
Resolves: RHEL-31783
---
src/core/execute.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

@ -0,0 +1,48 @@
From 06a6d5c5d5c6f3a9eb7ae55a7635d69158593181 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 11 Apr 2024 10:01:04 +0200
Subject: [PATCH] ci(src-git): update list of supported products
rhel-only
Related: RHEL-30372
---
.github/tracker-validator.yml | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
index f88cc0a572..31ef28f6ea 100644
--- a/.github/tracker-validator.yml
+++ b/.github/tracker-validator.yml
@@ -12,17 +12,17 @@ products:
- rhel-9.2.0.z
- rhel-9.3.0
- rhel-9.3.0.z
- - rhel-9.4.0
- - rhel-9.4.0.z
- - rhel-9.5.0
- - rhel-9.5.0.z
- - rhel-9.6.0
- - rhel-9.6.0.z
- - rhel-9.7.0
- - rhel-9.7.0.z
- - rhel-9.8.0
- - rhel-9.8.0.z
- - rhel-9.9.0
- - rhel-9.9.0.z
- - rhel-9.10.0
- - rhel-9.10.0.z
+ - rhel-9.4
+ - rhel-9.4.z
+ - rhel-9.5
+ - rhel-9.5.z
+ - rhel-9.6
+ - rhel-9.6.z
+ - rhel-9.7
+ - rhel-9.7.z
+ - rhel-9.8
+ - rhel-9.8.z
+ - rhel-9.9
+ - rhel-9.9.z
+ - rhel-9.10
+ - rhel-9.10.z

@ -0,0 +1,46 @@
From f387005b548bee7695c663167f9bd54e45636f6b Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 5 Apr 2024 15:56:58 +0200
Subject: [PATCH] coredump: by default process and store core files up to 1GiB
This is a major departure from our previous policy of soft core file
limit set to 0, i.e. core file processing and storage by
systemd-coredump was disabled. However, that policy made very difficult
for people to debug sporadic crashes with no known reproducer.
RHEL-only
Resolves: RHEL-15501
---
src/core/system.conf.in | 2 +-
src/coredump/coredump.conf | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 624746e512..5d1f6d24f0 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -61,7 +61,7 @@
#DefaultLimitFSIZE=
#DefaultLimitDATA=
#DefaultLimitSTACK=
-DefaultLimitCORE=0:infinity
+#DefaultLimitCORE=
#DefaultLimitRSS=
#DefaultLimitNOFILE=1024:{{HIGH_RLIMIT_NOFILE}}
#DefaultLimitAS=
diff --git a/src/coredump/coredump.conf b/src/coredump/coredump.conf
index 1f75d48d33..b934c2afb7 100644
--- a/src/coredump/coredump.conf
+++ b/src/coredump/coredump.conf
@@ -17,8 +17,8 @@
[Coredump]
#Storage=external
#Compress=yes
-#ProcessSizeMax=2G
-#ExternalSizeMax=2G
+ProcessSizeMax=1G
+ExternalSizeMax=1G
#JournalSizeMax=767M
#MaxUse=
#KeepFree=

@ -0,0 +1,35 @@
From e100e3855305a86367c690689833a460fa166428 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 5 Dec 2023 15:56:54 +0100
Subject: [PATCH] coredump: keep core files for two weeks
We have two mechanisms that remove old coredumps: systemd-coredump has
parameters based on disk use / remaining disk free, and systemd-tmpfiles does
cleanup based on time. The first mechanism should prevent us from using too much
disk space in case something is crashing continuously or there are very large
core files.
The limit of 3 days makes it likely that the core file will be gone by the time
the admin looks at the issue. E.g. if something crashes on Friday, the coredump
would likely be gone before people are back on Monday to look at it.
(cherry picked from commit f8d67130b8b492a1f2eedd07a3189051f98db648)
Related: RHEL-15501
---
tmpfiles.d/systemd.conf.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tmpfiles.d/systemd.conf.in b/tmpfiles.d/systemd.conf.in
index fa838d8d06..958935a04f 100644
--- a/tmpfiles.d/systemd.conf.in
+++ b/tmpfiles.d/systemd.conf.in
@@ -59,7 +59,7 @@ a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
{% endif %}
d /var/lib/systemd 0755 root root -
-d /var/lib/systemd/coredump 0755 root root 3d
+d /var/lib/systemd/coredump 0755 root root 2w
d /var/lib/private 0700 root root -
d /var/log/private 0700 root root -

@ -1,4 +1,4 @@
From 93759e2eedd282e57455735326d99b0dd3356a8a Mon Sep 17 00:00:00 2001
From af01ea4040e2d6fdd15641793db688d01f2da046 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Sat, 23 Dec 2023 12:20:03 +0100
Subject: [PATCH] ukify: make the test happy with the latest OpenSSL
@ -22,7 +22,7 @@ E AssertionError: assert 'Issuer: CN = SecureBoot signing key on host' in
(cherry picked from commit 338ed5bea4fcd0b5b1cdcfb96a789edf6251bbdd)
Resolves: RHEL-34061
Related: RHEL-30372
---
src/ukify/test/test_ukify.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

@ -0,0 +1,32 @@
From 1c4640a859937b84d3f31dd2fa054f7d744d65f4 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Sat, 3 Feb 2024 15:46:26 +0100
Subject: [PATCH] test_ukify: use raw string for the regex
To get rid of the "invalid escape sequence" warning:
=============================== warnings summary ===============================
../src/ukify/test/test_ukify.py:876
../src/ukify/test/test_ukify.py:876: SyntaxWarning: invalid escape sequence '\s'
assert re.search('Issuer: CN\s?=\s?SecureBoot signing key on host', out)
(cherry picked from commit a0485e07b38b3b1195a92ba86a173742f2bb867a)
Related: RHEL-30372
---
src/ukify/test/test_ukify.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py
index 31054eabea..f233e25cf7 100755
--- a/src/ukify/test/test_ukify.py
+++ b/src/ukify/test/test_ukify.py
@@ -850,7 +850,7 @@ def test_key_cert_generation(tmpdir):
'-noout',
], text = True)
assert 'Certificate' in out
- assert re.search('Issuer: CN\s?=\s?SecureBoot signing key on host', out)
+ assert re.search(r'Issuer: CN\s?=\s?SecureBoot signing key on host', out)
if __name__ == '__main__':
sys.exit(pytest.main(sys.argv))

@ -1,4 +1,4 @@
From 65989e9f8f66ef3d6a81d38b913616ce722bab2b Mon Sep 17 00:00:00 2001
From d0427b44ecb56cdbc40ca156af8e013b64cce74d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 18 Mar 2024 13:01:40 +0100
Subject: [PATCH] coredump: generate stacktraces also for processes running in
@ -9,7 +9,7 @@ setting SYSTEMD_COREDUMP_ALLOW_NAMESPACE_CHANGE environment variable.
RHEL-only
Resolves: RHEL-34061
Resolves: RHEL-29430
---
src/analyze/analyze-inspect-elf.c | 2 +-
src/basic/socket-util.c | 52 +++++++++++

@ -1,11 +1,11 @@
From ab1212eb3880ef8f9b59c2145efa1f289f02c8c4 Mon Sep 17 00:00:00 2001
From 6307dbb9cb25fd5a2131c043b89a52f032817178 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 21 Mar 2023 23:19:41 +0100
Subject: [PATCH] test: add a couple of tests for systemd-coredump
(cherry picked from commit aadbd81f7ffbc313d0541c15455211dddeedbfde)
Related: RHEL-34061
Related: RHEL-29430
---
test/units/testsuite-74.coredump.sh | 175 ++++++++++++++++++++++++++++
1 file changed, 175 insertions(+)

@ -1,4 +1,4 @@
From 67b33be5be12ea7500d54a78961acbe76126e8ed Mon Sep 17 00:00:00 2001
From 687c8da38e766fe35a2710b0539576710c345f34 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Sat, 25 Mar 2023 12:02:15 +0100
Subject: [PATCH] test: don't expand the subshell expression prematurely
@ -16,7 +16,7 @@ Follow-up to aadbd81f7f.
(cherry picked from commit 0b189ac84c432a085a1f10139260cec6b5032523)
Related: RHEL-34061
Related: RHEL-29430
---
test/units/testsuite-74.coredump.sh | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

@ -1,4 +1,4 @@
From 8eab546a3468dcb1ed714ec02c927ea2f5141645 Mon Sep 17 00:00:00 2001
From f46d65bba43c519d8d2ed8fab86ea765166c0e72 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Wed, 26 Apr 2023 14:18:04 +0100
Subject: [PATCH] coredump filter: fix stack overflow with =all
@ -16,7 +16,7 @@ Press ^] three times within 1s to disconnect TTY.
(cherry picked from commit 37232d55a7bcace37280e28b207c85f5ca9b3f6b)
Related: RHEL-34061
Related: RHEL-29430
---
src/basic/macro.h | 4 ++++
src/shared/coredump-util.c | 5 +++--

@ -1,4 +1,4 @@
From 88d675ef77a4cdebbb7f1367679fc349de487f75 Mon Sep 17 00:00:00 2001
From 8db17468f2c0dd07d5e9618e3b49fddda26724c6 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Wed, 26 Apr 2023 14:19:33 +0100
Subject: [PATCH] coredump filter: add mask for 'all' using UINT32_MAX, not
@ -10,7 +10,7 @@ be set.
(cherry picked from commit 7f3bb8f20dcccaceea8b1ee05f0560b81162037b)
Related: RHEL-34061
Related: RHEL-29430
---
src/shared/coredump-util.c | 2 +-
src/shared/coredump-util.h | 3 +++

@ -1,11 +1,11 @@
From 2d16eaf0c4151ecb308452375661960eab3ec3c8 Mon Sep 17 00:00:00 2001
From 27538bb6224cdcd2ee04284b496449e0d2755e7b Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Wed, 26 Apr 2023 14:32:04 +0100
Subject: [PATCH] test: add coverage for CoredumpFilter=all
(cherry picked from commit cf636aa59eb8c848ed04d5b08aac0acf3f6683d9)
Related: RHEL-34061
Related: RHEL-29430
---
test/units/testsuite-74.coredump.sh | 3 +++
1 file changed, 3 insertions(+)

@ -1,4 +1,4 @@
From 9bac78b7b359e063bfb43a2fb358195c0a6608e8 Mon Sep 17 00:00:00 2001
From cada47a50ea898f092c430508656ed717ab78dba Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 24 May 2023 10:31:41 +0900
Subject: [PATCH] test: rotate journal before storing coredumps
@ -31,7 +31,7 @@ https://jenkins-systemd.apps.ocp.cloud.ci.centos.org/job/upstream-vagrant-archli
(cherry picked from commit 5c4e96c28c4a2193ba0dd459ea3366614f9b262f)
Related: RHEL-34061
Related: RHEL-29430
---
test/units/testsuite-74.coredump.sh | 3 +++
1 file changed, 3 insertions(+)

@ -1,4 +1,4 @@
From 43c604a8ed7f436c9c123d4e53dc9b3d7192522d Mon Sep 17 00:00:00 2001
From 803900bb830163c13539a70ea56d82d27b06f52b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 2 Jun 2023 13:24:32 +0200
Subject: [PATCH] test: sync with the fake binary before killing it
@ -47,7 +47,7 @@ Fri 2023-06-02 10:42:13 CEST 593 0 0 SIGABRT missing /tmp/test-dump -
(cherry picked from commit 1326d2dd059132760b40acb7a715ecc9ff08bd35)
Related: RHEL-34061
Related: RHEL-29430
---
test/units/testsuite-74.coredump.sh | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

@ -1,4 +1,4 @@
From a8924006c47a680f038d9ff66fd3896ffbc37bc1 Mon Sep 17 00:00:00 2001
From 623e09d910fffd6824d77203b8d9b016c0dd6208 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Thu, 25 Apr 2024 19:50:10 +0200
Subject: [PATCH] test: check coredump handling in containers & namespaces
@ -9,7 +9,7 @@ coverage for RHEL-29430 (generating stack traces for processes in
containers without coredump fowarding).
rhel-only
Related: RHEL-34061
Related: RHEL-29430
---
test/test-functions | 2 +-
test/units/testsuite-74.coredump.sh | 64 ++++++++++++++++++++++++++++-

@ -0,0 +1,29 @@
From ddf2ccf36bb804d666da37ce12d00123550d85f1 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 25 Apr 2024 15:06:03 +0200
Subject: [PATCH] ci: update actions/upload-artifact to v4
`v3` will be deprecated soon, so update to `v4`.
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
rhel-only
Related: RHEL-30372
---
.github/workflows/gather-metadata.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/gather-metadata.yml b/.github/workflows/gather-metadata.yml
index 635708a71f..59659d9bc5 100644
--- a/.github/workflows/gather-metadata.yml
+++ b/.github/workflows/gather-metadata.yml
@@ -22,7 +22,7 @@ jobs:
uses: redhat-plumbers-in-action/gather-pull-request-metadata@v1
- name: Upload artifact with gathered metadata
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: pr-metadata
path: ${{ steps.Metadata.outputs.metadata-file }}

@ -0,0 +1,33 @@
From da0298596af24d1da92eb748b0a56065a9c041d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
Date: Fri, 11 Nov 2022 15:28:51 +0000
Subject: [PATCH] journal-remote: code is of type enum
MHD_RequestTerminationCode
Fixes gcc 13 -Wenum-int-mismatch which are enabled by default.
(cherry picked from commit aa70dd624bff6280ab6f2871f62d313bdb1e1bcc)
Related: RHEL-30372
---
src/journal-remote/microhttpd-util.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index 7e7d1b56b1..df18335469 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -64,11 +64,11 @@ void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0);
int mhd_respondf(struct MHD_Connection *connection,
int error,
- unsigned code,
+ enum MHD_RequestTerminationCode code,
const char *format, ...) _printf_(4,5);
int mhd_respond(struct MHD_Connection *connection,
- unsigned code,
+ enum MHD_RequestTerminationCode code,
const char *message);
int mhd_respond_oom(struct MHD_Connection *connection);

@ -0,0 +1,30 @@
From cc1a9f1a9a74dd8f5491a3a0fd9734fbca731378 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
Date: Fri, 11 Nov 2022 15:31:18 +0000
Subject: [PATCH] resolve: dns_server_feature_level_*_string type is
DnsServerFeatureLevel
gcc 13 -Wenum-int-mismatch reminds us that enum != int
(cherry picked from commit e14afe31c3e8380496dc85b57103b2f648bc7d43)
Related: RHEL-30372
---
src/resolve/resolved-dns-server.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index be9efb0a79..f939b534c3 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -44,8 +44,8 @@ typedef enum DnsServerFeatureLevel {
#define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO)
#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO)
-const char* dns_server_feature_level_to_string(int i) _const_;
-int dns_server_feature_level_from_string(const char *s) _pure_;
+const char* dns_server_feature_level_to_string(DnsServerFeatureLevel i) _const_;
+DnsServerFeatureLevel dns_server_feature_level_from_string(const char *s) _pure_;
struct DnsServer {
Manager *manager;

@ -0,0 +1,36 @@
From 9f0967eb61b1889c97da705abaf0b0e905d117f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
Date: Fri, 11 Nov 2022 15:34:32 +0000
Subject: [PATCH] shared|install: Use InstallChangeType consistently
gcc 13 -Wenum-int-mismatch, enabled by default, reminds us enum ! = int
(cherry picked from commit 9264db1a0ac6034ab5b40ef3f5914d8dc7d77aba)
Related: RHEL-30372
---
src/shared/install.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/shared/install.h b/src/shared/install.h
index 9bb412ba06..0abc73897e 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -197,7 +197,7 @@ int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *na
int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
Hashmap* unit_file_list_free(Hashmap *h);
-InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, int type, const char *path, const char *source);
+InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, InstallChangeType type, const char *path, const char *source);
void install_changes_free(InstallChange *changes, size_t n_changes);
void install_changes_dump(int r, const char *verb, const InstallChange *changes, size_t n_changes, bool quiet);
@@ -224,7 +224,7 @@ UnitFileState unit_file_state_from_string(const char *s) _pure_;
/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
const char *install_change_type_to_string(InstallChangeType t) _const_;
-int install_change_type_from_string(const char *s) _pure_;
+InstallChangeType install_change_type_from_string(const char *s) _pure_;
const char *unit_file_preset_mode_to_string(UnitFilePresetMode m) _const_;
UnitFilePresetMode unit_file_preset_mode_from_string(const char *s) _pure_;

@ -0,0 +1,78 @@
From 54c44b19c1018400c38da8f8be597536d14e7afa Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Thu, 18 Apr 2024 22:39:31 +0200
Subject: [PATCH] test: temporarily disable coredumps in testsuite-17.03.sh
Since f387005b54 we started generating coredumps by default (up to
certain size). This change has one unintentional effect on our test
suite - if a sanitized binary (udevd worker here) crashes and ASan is
instructed to allow core dumping (via disable_coredump=0 and
use_madv_dontdump=1), we try to dump a relatively big core file (~80
MiB), and since the test suite configures systemd-coredumpd to dump the
cores into the journal, we try to append it to the journal message about
the crash. However, journal complains that the message with the coredump
is too big so the crash report is not written, and we end up with
coredumpctl not showing the crash, which the test in this case uses to
monitor if the udevd worker's job timed out:
[ 17.873463] systemd-udevd[1617]: null: Worker [1625] processing SEQNUM=3588 is taking a long time
[ 17.876823] systemd-udevd[1625]: null: Spawned process '/bin/sleep 60' [1626] is taking longer than 3s to complete
...
[ 24.223459] systemd-udevd[1617]: null: Worker [1625] processing SEQNUM=3588 killed
[ 24.265141] systemd[1]: Created slice system-systemd\x2dcoredump.slice.
[ 24.284960] systemd[1]: Started systemd-coredump@0-1707-0.service.
[ 27.545120] systemd-journald[1225]: Failed to write entry to /var/log/journal/6da99a97048e4f08abd4ddabcf92bbdd/system.journal (51 items, 89252196 bytes) despite vacuuming, ignoring: Argument list too long
[ 27.551759] systemd-coredump[1709]: ==1709==LeakSanitizer has encountered a fatal error.
[ 27.551759] systemd-coredump[1709]: ==1709==HINT: For debugging, try setting environment variable LSAN_OPTIONS=verbosity=1:log_threads=1
[ 27.551759] systemd-coredump[1709]: ==1709==HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)
The upstream version of this test doesn't suffer from this because it
was recently-ish rewritten to not check for the crash event
(5592608bdcb, but we're missing some udevd prerequisites for that to
work in RHEL9), and we also started instructing ASan to allow coredumps
after that change, so the issue was never encountered there in the first
place.
Since we don't really care about the actual coredump in this case, let's
just temporarily override the core rlimit to 0 for the udevd process.
Related: RHEL-30372
rhel-only
---
test/units/testsuite-17.03.sh | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/test/units/testsuite-17.03.sh b/test/units/testsuite-17.03.sh
index 318afdcb5a..8fa58e2f08 100755
--- a/test/units/testsuite-17.03.sh
+++ b/test/units/testsuite-17.03.sh
@@ -17,9 +17,16 @@ event_timeout=10
timeout_signal=SIGABRT
EOF
+ mkdir -p /run/systemd/system/systemd-udevd.service.d/
+ cat >/run/systemd/system/systemd-udevd.service.d/99-disable-coredumps.conf <<EOF
+[Service]
+LimitCORE=0
+EOF
+ systemctl daemon-reload
systemctl restart systemd-udevd.service
}
+# shellcheck disable=SC2317
teardown() {
set +e
@@ -27,10 +34,11 @@ teardown() {
kill "$KILL_PID"
fi
- rm -rf "$TMPDIR"
+ rm -rf "$TMPDIR" /run/systemd/system/systemd-udevd.service.d
mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf
rm -f "$test_rule"
+ systemctl daemon-reload
systemctl restart systemd-udevd.service
}

@ -0,0 +1,80 @@
From 365a74eef2463a011fbe7413ab5479b4fbd60650 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 25 Apr 2024 15:46:35 +0200
Subject: [PATCH] ci: update manpage deployment workflow
rhel-only
Related: RHEL-30372
---
.github/workflows/deploy-man-pages.yml | 52 +-------------------------
1 file changed, 2 insertions(+), 50 deletions(-)
diff --git a/.github/workflows/deploy-man-pages.yml b/.github/workflows/deploy-man-pages.yml
index 08c3d6e322..9739228a87 100644
--- a/.github/workflows/deploy-man-pages.yml
+++ b/.github/workflows/deploy-man-pages.yml
@@ -37,61 +37,13 @@ jobs:
- name: Install dependencies
run: |
- RELEASE="$(lsb_release -cs)"
- sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
- sudo add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci
+ sudo add-apt-repository -y --no-update --enable-source
sudo apt-get -y update
sudo apt-get -y build-dep systemd
- sudo apt-get install -y \
- cryptsetup-bin \
- expect \
- fdisk \
- gettext \
- iputils-ping \
- isc-dhcp-client \
- itstool \
- kbd \
- libblkid-dev \
- libbpf-dev \
- libc6-dev-i386 \
- libcap-dev \
- libcurl4-gnutls-dev \
- libfdisk-dev \
- libfido2-dev \
- libgpg-error-dev \
- liblz4-dev \
- liblzma-dev \
- libmicrohttpd-dev \
- libmount-dev \
- libp11-kit-dev \
- libpwquality-dev \
- libqrencode-dev \
- libssl-dev \
- libtss2-dev \
- libxkbcommon-dev \
- libxtables-dev \
- libzstd-dev \
- meson \
- mold \
- mount \
- net-tools \
- ninja-build \
- perl \
- python3-evdev \
- python3-jinja2 \
- python3-lxml \
- python3-pip \
- python3-pyparsing \
- python3-setuptools \
- quota \
- strace \
- unifont \
- util-linux \
- zstd \
- name: Build HTML man pages
run: |
- meson build
+ meson setup build
ninja -C build man/html
- name: Setup Pages

@ -1,4 +1,4 @@
From ebb3f05ef5d2bf3543e61047a658103baa293ca0 Mon Sep 17 00:00:00 2001
From 41d2e7fbb87a99e80e9be1873775c79879f8b821 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 2 Dec 2022 14:30:22 +0900
Subject: [PATCH] bootspec: fix null-dereference-read
@ -8,7 +8,7 @@ Fixes #25450.
(cherry picked from commit 46dc071985ff487f5ccf20808531168a6add73d3)
Related: RHEL-40119
Resolves: RHEL-36284
---
src/shared/bootspec.c | 2 ++
...lusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120 | 1 +

@ -0,0 +1,40 @@
From 0947147008c9b2cb56b40616fccccf64a6534f07 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 17 Jan 2023 12:14:13 +0100
Subject: [PATCH] units: don't install pcrphase-related units without gnu-efi
since we don't have systemd-pcrphase built anyway, which breaks the tests:
...
I: Attempting to install /usr/lib/systemd/systemd-networkd-wait-online (based on unit file reference)
I: Attempting to install /usr/lib/systemd/systemd-network-generator (based on unit file reference)
I: Attempting to install /usr/lib/systemd/systemd-oomd (based on unit file reference)
I: Attempting to install /usr/lib/systemd/systemd-pcrphase (based on unit file reference)
W: Failed to install '/usr/lib/systemd/systemd-pcrphase'
make: *** [Makefile:4: setup] Error 1
make: Leaving directory '/root/systemd/test/TEST-01-BASIC'
Follow-up to 04959faa632272a8fc9cdac3121b2e4af721c1b6.
(cherry picked from commit 0eb635ef4bc11792cd4ef384ae252a2c7fd4122a)
Related: RHEL-33384
---
units/meson.build | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/units/meson.build b/units/meson.build
index cfc96a9111..39e6a9bb65 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -264,8 +264,8 @@ in_units = [
'sysinit.target.wants/'],
['systemd-pcrphase.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2',
'sysinit.target.wants/'],
- ['systemd-pcrfs-root.service', ''],
- ['systemd-pcrfs@.service', ''],
+ ['systemd-pcrfs-root.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2'],
+ ['systemd-pcrfs@.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2'],
['systemd-growfs-root.service', ''],
['systemd-growfs@.service', ''],
['systemd-pcrmachine.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2',

@ -1,4 +1,4 @@
From ba83f030dc2721a317f31f5b7a5884431349074f Mon Sep 17 00:00:00 2001
From 4ab2df57c79a923fba74b2cf48fd56c6a0756413 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 18 Mar 2024 17:04:22 +0100
Subject: [PATCH] kernel-install: fix uki-copy deinstall
@ -15,7 +15,7 @@ Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 3037616d8ed68f3263746e3c6399d4a05242068b)
Resolves: RHEL-35994
Resolves: RHEL-36505
---
src/kernel-install/90-uki-copy.install | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

@ -0,0 +1,27 @@
From 16eace42619860cbcfedca8c93e4ea20bfb0f98b Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 17 May 2024 14:02:07 +0200
Subject: [PATCH] ci(packit): explicitly clone `c9s` branch
Once default branch is changed to `c10s` the current configuration could stop working.
rhel-only
Related: RHEL-30372
---
.packit.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.packit.yml b/.packit.yml
index 35938f3586..9697a0df84 100644
--- a/.packit.yml
+++ b/.packit.yml
@@ -18,7 +18,7 @@ srpm_build_deps: []
actions:
post-upstream-clone:
# Use the CentOS Stream specfile
- - "git clone https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1"
+ - "git clone -b c9s https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1"
# Drop the "sources" file so rebase-helper doesn't think we're a dist-git
- "rm -fv .packit_rpm/sources"
# Drop all patches, since they're already included in the tarball

@ -0,0 +1,25 @@
From 43373d851c9f6222f4523b9db7006fbfe14c3d70 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 23 May 2024 18:07:45 +0200
Subject: [PATCH] ci(src-git): add RHEL-9.1 and RHEL-9.1.z to allowed versions
rhel-only
Related: RHEL-30372
---
.github/tracker-validator.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
index 31ef28f6ea..21cbedd8b0 100644
--- a/.github/tracker-validator.yml
+++ b/.github/tracker-validator.yml
@@ -8,6 +8,8 @@ products:
- CentOS Stream 9
- rhel-9.0.0
- rhel-9.0.0.z
+ - rhel-9.1.0
+ - rhel-9.1.0.z
- rhel-9.2.0
- rhel-9.2.0.z
- rhel-9.3.0

@ -0,0 +1,30 @@
From aa18f6b2b2cad6977f39e1e323705e2b11a7829c Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 23 May 2024 17:35:51 +0200
Subject: [PATCH] libsystemd: link with '-z nodelete'
We want to avoid reinitialization of our global variables with static
storage duration in case we get dlopened multiple times by the same
application. This will avoid potential resource leaks that could have
happened otherwise (e.g. leaking journal socket fd).
(cherry picked from commit 9d8533b7152daf792356c601516b57c6412d3e52)
Resolves: RHEL-6589
---
meson.build | 2 ++
1 file changed, 2 insertions(+)
diff --git a/meson.build b/meson.build
index 843d823e3e..274e43ba9e 100644
--- a/meson.build
+++ b/meson.build
@@ -2004,6 +2004,8 @@ libsystemd = shared_library(
version : libsystemd_version,
include_directories : libsystemd_includes,
link_args : ['-shared',
+ # Make sure our library is never deleted from memory, so that our open logging fds don't leak on dlopen/dlclose cycles.
+ '-z', 'nodelete',
'-Wl,--version-script=' + libsystemd_sym_path],
link_with : [libbasic,
libbasic_gcrypt,

@ -0,0 +1,54 @@
From d26e1ba4539a3a33224ca1019b9e6cf5590744f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 23 Jun 2023 11:10:42 -0600
Subject: [PATCH] basic/utf8: make utf8_encoded_to_unichar() return length of
the codepoint
(cherry picked from commit 9579e9a5308573c3c9c82f1978456cc71f68760c)
Related: RHEL-31219
---
src/basic/utf8.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 2532fcf81a..9d9e76904e 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -90,7 +90,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
switch (len) {
case 1:
*ret_unichar = (char32_t)str[0];
- return 0;
+ return 1;
case 2:
unichar = str[0] & 0x1f;
break;
@@ -119,15 +119,14 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
}
*ret_unichar = unichar;
-
- return 0;
+ return len;
}
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
assert(str);
for (const char *p = str; length > 0;) {
- int encoded_len, r;
+ int encoded_len;
char32_t val;
encoded_len = utf8_encoded_valid_unichar(p, length);
@@ -135,8 +134,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
return false;
assert(encoded_len > 0 && (size_t) encoded_len <= length);
- r = utf8_encoded_to_unichar(p, &val);
- if (r < 0 ||
+ if (utf8_encoded_to_unichar(p, &val) < 0 ||
unichar_is_control(val) ||
(!allow_newline && val == '\n'))
return false;

@ -0,0 +1,67 @@
From 0fc377b76f10eb283d4de76b8fe7c083b95f70b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 23 Jun 2023 17:24:11 -0600
Subject: [PATCH] test-gunicode: add new test to show that unichar_iswide() is
borked
I discovered this while looking at the tests with wide characters in the next
patch. It's something to fix, but not directly relevant to the issue of
skipping ANSI in ellipsization. We will generate output that is wider than
expected in some cases, but wide characters are used very rarely so this isn't
such a big problem.
(cherry picked from commit d9c72e54190db2a0845d1558b5beb734e9f629ff)
Related: RHEL-31219
---
src/test/meson.build | 2 ++
src/test/test-gunicode.c | 27 +++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 src/test/test-gunicode.c
diff --git a/src/test/meson.build b/src/test/meson.build
index 5430e72ab5..1d61dc343f 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -469,6 +469,8 @@ tests += [
[files('test-gpt.c')],
+ [files('test-gunicode.c')],
+
[files('test-log.c')],
[files('test-ipcrm.c'),
diff --git a/src/test/test-gunicode.c b/src/test/test-gunicode.c
new file mode 100644
index 0000000000..1836cdc04a
--- /dev/null
+++ b/src/test/test-gunicode.c
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "gunicode.h"
+#include "tests.h"
+#include "utf8.h"
+
+TEST(unichar_iswide) {
+ char32_t c;
+ int r;
+
+ /* FIXME: the cats are wide, but we get this wrong */
+ for (const char *narrow = "abX_…ąęµ!" "😼😿🙀😸😻"; *narrow; narrow += r) {
+ r = utf8_encoded_to_unichar(narrow, &c);
+ bool w = unichar_iswide(c);
+ assert_se(r > 0);
+ assert_se(!w);
+ }
+
+ for (const char *wide = "🐱/¥"; *wide; wide += r) {
+ r = utf8_encoded_to_unichar(wide, &c);
+ bool w = unichar_iswide(c);
+ assert_se(r > 0);
+ assert_se(w);
+ }
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);

@ -0,0 +1,320 @@
From cec4cc86486d3e212b5e919595feb39c6cee4c2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 23 Jun 2023 18:40:14 -0600
Subject: [PATCH] string-util: pass ANSI sequences through unchanged
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Cutting off in the middle may leave the terminal in a bad state, breaking
further output. But we don't know what a given ANSI sequence does, e.g.
ANSI_NORMAL should not be skipped. But it is also nice to keep various
sequences intact, so that if we had part of the string in blue, and we cut out
the beginning of the blue part, we still want to keep the remainder in color.
So let's just pass them through, stripping out the characters that take up
actual space.
Also, use memcpy_safe as we may end up copying zero bytes when ellipsizing at
the start/end of a string.
Fixes: #24502
This also fixes an ugliness where we would ellipsize string with ANSI
sequences too much, leading to output that was narrower on screen than the
requested length:
Starting AAAAAAAAAAAAAAAAAAAAA.service
Starting BBBBBBBBBBBBBBBBBBBBB.service
Starting LONG…ER.service
Co-authored-by: Jan Janssen <medhefgo@web.de>
(cherry picked from commit cb558ab222f0dbda3afd985c2190f35693963ffa)
Resolves: RHEL-31219
---
src/basic/string-util.c | 163 ++++++++++++++++++++++++++++++--------
src/test/test-ellipsize.c | 41 ++++++++++
2 files changed, 172 insertions(+), 32 deletions(-)
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 17d35fe1a4..fe6e9e94ad 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -288,6 +288,62 @@ static int write_ellipsis(char *buf, bool unicode) {
return 3;
}
+static size_t ansi_sequence_length(const char *s, size_t len) {
+ assert(s);
+
+ if (len < 2)
+ return 0;
+
+ if (s[0] != 0x1B) /* ASCII 27, aka ESC, aka Ctrl-[ */
+ return 0; /* Not the start of a sequence */
+
+ if (s[1] == 0x5B) { /* [, start of CSI sequence */
+ size_t i = 2;
+
+ if (i == len)
+ return 0;
+
+ while (s[i] >= 0x30 && s[i] <= 0x3F) /* Parameter bytes */
+ if (++i == len)
+ return 0;
+ while (s[i] >= 0x20 && s[i] <= 0x2F) /* Intermediate bytes */
+ if (++i == len)
+ return 0;
+ if (s[i] >= 0x40 && s[i] <= 0x7E) /* Final byte */
+ return i + 1;
+ return 0; /* Bad sequence */
+
+ } else if (s[1] >= 0x40 && s[1] <= 0x5F) /* other non-CSI Fe sequence */
+ return 2;
+
+ return 0; /* Bad escape? */
+}
+
+static bool string_has_ansi_sequence(const char *s, size_t len) {
+ const char *t = s;
+
+ while ((t = memchr(s, 0x1B, len - (t - s))))
+ if (ansi_sequence_length(t, len - (t - s)) > 0)
+ return true;
+ return false;
+}
+
+static size_t previous_ansi_sequence(const char *s, size_t length, const char **ret_where) {
+ /* Locate the previous ANSI sequence and save its start in *ret_where and return length. */
+
+ for (size_t i = length - 2; i > 0; i--) { /* -2 because at least two bytes are needed */
+ size_t slen = ansi_sequence_length(s + (i - 1), length - (i - 1));
+ if (slen == 0)
+ continue;
+
+ *ret_where = s + (i - 1);
+ return slen;
+ }
+
+ *ret_where = NULL;
+ return 0;
+}
+
static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
size_t x, need_space, suffix_len;
char *t;
@@ -347,7 +403,6 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
size_t x, k, len, len2;
const char *i, *j;
- char *e;
int r;
/* Note that 'old_length' refers to bytes in the string, while 'new_length' refers to character cells taken up
@@ -371,73 +426,117 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
if (new_length == 0)
return strdup("");
- /* If no multibyte characters use ascii_ellipsize_mem for speed */
- if (ascii_is_valid_n(s, old_length))
+ bool has_ansi_seq = string_has_ansi_sequence(s, old_length);
+
+ /* If no multibyte characters or ANSI sequences, use ascii_ellipsize_mem for speed */
+ if (!has_ansi_seq && ascii_is_valid_n(s, old_length))
return ascii_ellipsize_mem(s, old_length, new_length, percent);
- x = ((new_length - 1) * percent) / 100;
+ x = (new_length - 1) * percent / 100;
assert(x <= new_length - 1);
k = 0;
- for (i = s; i < s + old_length; i = utf8_next_char(i)) {
- char32_t c;
- int w;
+ for (i = s; i < s + old_length; ) {
+ size_t slen = has_ansi_seq ? ansi_sequence_length(i, old_length - (i - s)) : 0;
+ if (slen > 0) {
+ i += slen;
+ continue; /* ANSI sequences don't take up any space in output */
+ }
+ char32_t c;
r = utf8_encoded_to_unichar(i, &c);
if (r < 0)
return NULL;
- w = unichar_iswide(c) ? 2 : 1;
- if (k + w <= x)
- k += w;
- else
+ int w = unichar_iswide(c) ? 2 : 1;
+ if (k + w > x)
break;
+
+ k += w;
+ i += r;
}
- for (j = s + old_length; j > i; ) {
+ const char *ansi_start = s + old_length;
+ size_t ansi_len = 0;
+
+ for (const char *t = j = s + old_length; t > i && k < new_length; ) {
char32_t c;
int w;
- const char *jj;
+ const char *tt;
+
+ if (has_ansi_seq && ansi_start >= t)
+ /* Figure out the previous ANSI sequence, if any */
+ ansi_len = previous_ansi_sequence(s, t - s, &ansi_start);
- jj = utf8_prev_char(j);
- r = utf8_encoded_to_unichar(jj, &c);
+ /* If the sequence extends all the way to the current position, skip it. */
+ if (has_ansi_seq && ansi_len > 0 && ansi_start + ansi_len == t) {
+ t = ansi_start;
+ continue;
+ }
+
+ tt = utf8_prev_char(t);
+ r = utf8_encoded_to_unichar(tt, &c);
if (r < 0)
return NULL;
w = unichar_iswide(c) ? 2 : 1;
- if (k + w <= new_length) {
- k += w;
- j = jj;
- } else
+ if (k + w > new_length)
break;
+
+ k += w;
+ j = t = tt; /* j should always point to the first "real" character */
}
- assert(i <= j);
- /* we don't actually need to ellipsize */
- if (i == j)
+ /* We don't actually need to ellipsize */
+ if (i >= j)
return memdup_suffix0(s, old_length);
- /* make space for ellipsis, if possible */
- if (j < s + old_length)
- j = utf8_next_char(j);
- else if (i > s)
- i = utf8_prev_char(i);
+ if (k >= new_length) {
+ /* Make space for ellipsis, if required and possible. We know that the edge character is not
+ * part of an ANSI sequence (because then we'd skip it). If the last character we looked at
+ * was wide, we don't need to make space. */
+ if (j < s + old_length)
+ j = utf8_next_char(j);
+ else if (i > s)
+ i = utf8_prev_char(i);
+ }
len = i - s;
len2 = s + old_length - j;
- e = new(char, len + 3 + len2 + 1);
+
+ /* If we have ANSI, allow the same length as the source string + ellipsis. It'd be too involved to
+ * figure out what exact space is needed. Strings with ANSI sequences are most likely to be fairly
+ * short anyway. */
+ size_t alloc_len = has_ansi_seq ? old_length + 3 + 1 : len + 3 + len2 + 1;
+
+ char *e = new(char, alloc_len);
if (!e)
return NULL;
/*
- printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
+ printf("old_length=%zu new_length=%zu x=%zu len=%zu len2=%zu k=%zu\n",
old_length, new_length, x, len, len2, k);
*/
- memcpy(e, s, len);
+ memcpy_safe(e, s, len);
write_ellipsis(e + len, true);
- memcpy(e + len + 3, j, len2);
- *(e + len + 3 + len2) = '\0';
+
+ char *dst = e + len + 3;
+
+ if (has_ansi_seq)
+ /* Copy over any ANSI sequences in full */
+ for (const char *p = s + len; p < j; ) {
+ size_t slen = ansi_sequence_length(p, j - p);
+ if (slen > 0) {
+ memcpy(dst, p, slen);
+ dst += slen;
+ p += slen;
+ } else
+ p = utf8_next_char(p);
+ }
+
+ memcpy_safe(dst, j, len2);
+ dst[len2] = '\0';
return e;
}
diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c
index 7317193363..8f7e17bfe9 100644
--- a/src/test/test-ellipsize.c
+++ b/src/test/test-ellipsize.c
@@ -4,6 +4,7 @@
#include "alloc-util.h"
#include "def.h"
+#include "escape.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
@@ -116,4 +117,44 @@ TEST(ellipsize) {
test_ellipsize_one("shórt");
}
+TEST(ellipsize_ansi) {
+ const char *s = ANSI_HIGHLIGHT_YELLOW_UNDERLINE "yęllow"
+ ANSI_HIGHLIGHT_GREY_UNDERLINE "grěy"
+ ANSI_HIGHLIGHT_BLUE_UNDERLINE "blue"
+ ANSI_NORMAL "nórmął";
+ size_t len = strlen(s);
+
+ for (unsigned percent = 0; percent <= 100; percent += 15)
+ for (ssize_t x = 21; x >= 0; x--) {
+ _cleanup_free_ char *t = ellipsize_mem(s, len, x, percent);
+ printf("%02zd: \"%s\"\n", x, t);
+ assert_se(utf8_is_valid(t));
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *e = cescape(t);
+ printf(" : \"%s\"\n", e);
+ }
+ }
+}
+
+TEST(ellipsize_ansi_cats) {
+ _cleanup_free_ char *e, *f, *g, *h;
+
+ /* Make sure we don't cut off in the middle of an ANSI escape sequence. */
+
+ e = ellipsize("01" ANSI_NORMAL "23", 4, 0);
+ puts(e);
+ assert_se(streq(e, "01" ANSI_NORMAL "23"));
+ f = ellipsize("ab" ANSI_NORMAL "cd", 4, 90);
+ puts(f);
+ assert_se(streq(f, "ab" ANSI_NORMAL "cd"));
+
+ g = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 0);
+ puts(g);
+ assert_se(streq(g, "…" ANSI_NORMAL "🐱🐱" ANSI_NORMAL));
+ h = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 90);
+ puts(h);
+ assert_se(streq(h, "🐱…" ANSI_NORMAL "🐱" ANSI_NORMAL));
+}
+
DEFINE_TEST_MAIN(LOG_INFO);

@ -1,4 +1,4 @@
From 540f1d6b38dc6f2f72785ba7b44ad3cc65243982 Mon Sep 17 00:00:00 2001
From eac6ff660b32656d2a39bdc13d729e7eb0288596 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Wed, 15 Feb 2023 00:44:01 +0000
Subject: [PATCH] cryptsetup: do not assert when unsealing token without salt
@ -11,7 +11,7 @@ Assertion 'saltlen > 0' failed at src/shared/tpm2-util.c:2490, function tpm2_uti
(cherry picked from commit 504d0acf61c8472bc93c2a927e858074873b2eaf)
Resolves: RHEL-40119
Resolves: RHEL-38864
---
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 3 ++-
src/cryptsetup/cryptsetup-tpm2.c | 4 +++-

@ -1,4 +1,4 @@
From d22cd36758db25eb9144fbe47f741cd1547b7d0e Mon Sep 17 00:00:00 2001
From 661e3758451dc504eeb176194293c87f238d55dd Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 17 Feb 2023 08:24:54 +0900
Subject: [PATCH] cryptsetup: check the existence of salt by salt_size > 0
@ -9,7 +9,7 @@ The function may be called with non-NULL salt and salt_size == 0.
(cherry picked from commit 8c2264abb9c16bc2933f95be299f15ee66c21181)
Related: RHEL-40119
Related: RHEL-38864
---
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

@ -0,0 +1,83 @@
From 3e65e8111f7cc30ac38901dced3ed0defbd90206 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Sat, 17 Feb 2024 03:03:50 +0800
Subject: [PATCH] core/mount: if umount(8) fails but mount disappeared, assume
success
Fixes #31337
(cherry picked from commit 8e94bb62a5c1309c56c57e0a505aae13a2ac5f4f)
Resolves: RHEL-13159
---
src/core/mount.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index a46ac804d8..cfe3f40302 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1439,7 +1439,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
mount_set_reload_result(m, f);
- else if (m->result == MOUNT_SUCCESS)
+ else if (m->result == MOUNT_SUCCESS && !IN_SET(m->state, MOUNT_MOUNTING, MOUNT_UNMOUNTING))
+ /* MOUNT_MOUNTING and MOUNT_UNMOUNTING states need to be patched, see below. */
m->result = f;
if (m->control_command) {
@@ -1462,11 +1463,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
switch (m->state) {
case MOUNT_MOUNTING:
- /* Our mount point has not appeared in mountinfo. Something went wrong. */
+ /* Our mount point has not appeared in mountinfo. Something went wrong. */
if (f == MOUNT_SUCCESS) {
- /* Either /bin/mount has an unexpected definition of success,
- * or someone raced us and we lost. */
+ /* Either /bin/mount has an unexpected definition of success, or someone raced us
+ * and we lost. */
log_unit_warning(UNIT(m), "Mount process finished, but there is no mount.");
f = MOUNT_FAILURE_PROTOCOL;
}
@@ -1484,9 +1485,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case MOUNT_UNMOUNTING:
-
if (f == MOUNT_SUCCESS && m->from_proc_self_mountinfo) {
-
/* Still a mount point? If so, let's try again. Most likely there were multiple mount points
* stacked on top of each other. We might exceed the timeout specified by the user overall,
* but we will stop as soon as any one umount times out. */
@@ -1499,13 +1498,18 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
mount_enter_mounted(m, f);
}
+ } else if (f == MOUNT_FAILURE_EXIT_CODE && !m->from_proc_self_mountinfo) {
+ /* Hmm, umount process spawned by us failed, but the mount disappeared anyway?
+ * Maybe someone else is trying to unmount at the same time. */
+ log_unit_notice(u, "Mount disappeared even though umount process failed, continuing.");
+ mount_enter_dead(m, MOUNT_SUCCESS);
} else
mount_enter_dead_or_mounted(m, f);
break;
- case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
+ case MOUNT_UNMOUNTING_SIGKILL:
mount_enter_dead_or_mounted(m, f);
break;
@@ -2040,7 +2044,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
* then remove it because of an internal error. E.g., fuse.sshfs seems
* to do that when the connection fails. See #17617. To handle such the
* case, let's once set the state back to mounting. Then, the unit can
- * correctly enter the failed state later in mount_sigchld(). */
+ * correctly enter the failed state later in mount_sigchld_event(). */
mount_set_state(mount, MOUNT_MOUNTING);
break;

@ -0,0 +1,31 @@
From 82231e1834a5936216c666e3488bccb8b82de258 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 24 Apr 2023 20:55:15 +0200
Subject: [PATCH] Drop log level of header limits log message
Especially when using in-memory logging, these are too noisy so
let's drop them back to debug level.
(cherry picked from commit afc47ee2af456d12670df862457dcc7f6b864d79)
Related: RHEL-33890
---
src/journal/journald-server.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index cbcf1e9d9e..56f2ea8583 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -848,8 +848,9 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
if (!f)
return;
- if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_INFO)) {
- log_info("%s: Journal header limits reached or header out-of-date, rotating.", f->file->path);
+ if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
+ log_debug("%s: Journal header limits reached or header out-of-date, rotating.",
+ f->file->path);
rotate = true;
}
}

@ -0,0 +1,136 @@
From 6e5dce6e2f9cc43375eb481c2d533606d2a07e1b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Apr 2024 17:25:31 +0900
Subject: [PATCH] journal: do not rotate unrelated journal files when full or
corrupted
When we fail to add an entry to a journal file, typically when the file
is full or corrupted, it is not necessary to rotate other journal files.
Not only that's unnecessary, rotating all journal files allows
unprivileged users to wipe system or other user's journals by writing
many journal entries to their own user journal file.
Let's rotate all journal files only when
- it is really requested by a privileged user (e.g. by journalctl --rotate), or
- the system time jumps backwards.
And, otherwise rotate only the journal file we are currently writing.
(cherry picked from commit bd0ec61ae3bb7a5200b344bab46ba2d6b9406aac)
Resolves: RHEL-33890
---
src/journal/journald-server.c | 67 +++++++++++++++++++++++++----------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 56f2ea8583..0ff6a43e5b 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -667,6 +667,33 @@ void server_rotate(Server *s) {
server_process_deferred_closes(s);
}
+static void server_rotate_journal(Server *s, ManagedJournalFile *f, uid_t uid) {
+ int r;
+
+ assert(s);
+ assert(f);
+
+ /* This is similar to server_rotate(), but rotates only specified journal file.
+ *
+ * 💣💣💣 This invalidate 'f', and the caller cannot reuse the passed JournalFile object. 💣💣💣 */
+
+ if (f == s->system_journal)
+ (void) do_rotate(s, &s->system_journal, "system", s->seal, /* uid= */ 0);
+ else if (f == s->runtime_journal)
+ (void) do_rotate(s, &s->runtime_journal, "runtime", /* seal= */ false, /* uid= */ 0);
+ else {
+ assert(ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid)) == f);
+ r = do_rotate(s, &f, "user", s->seal, uid);
+ if (r >= 0)
+ ordered_hashmap_replace(s->user_journals, UID_TO_PTR(uid), f);
+ else if (!f)
+ /* Old file has been closed and deallocated */
+ ordered_hashmap_remove(s->user_journals, UID_TO_PTR(uid));
+ }
+
+ server_process_deferred_closes(s);
+}
+
void server_sync(Server *s) {
ManagedJournalFile *f;
int r;
@@ -819,7 +846,7 @@ static bool shall_try_append_again(JournalFile *f, int r) {
}
static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n, int priority) {
- bool vacuumed = false, rotate = false;
+ bool vacuumed = false;
struct dual_timestamp ts;
ManagedJournalFile *f;
int r;
@@ -841,23 +868,25 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
* bisection works correctly. */
log_info("Time jumped backwards, rotating.");
- rotate = true;
- } else {
+ server_rotate(s);
+ server_vacuum(s, /* verbose = */ false);
+ vacuumed = true;
+ }
- f = find_journal(s, uid);
- if (!f)
- return;
+ f = find_journal(s, uid);
+ if (!f)
+ return;
- if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
- log_debug("%s: Journal header limits reached or header out-of-date, rotating.",
- f->file->path);
- rotate = true;
+ if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
+ if (vacuumed) {
+ log_warning("Suppressing rotation, as we already rotated immediately before write attempt. Giving up.");
+ return;
}
- }
- if (rotate) {
- server_rotate(s);
- server_vacuum(s, false);
+ log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->file->path);
+
+ server_rotate_journal(s, TAKE_PTR(f), uid);
+ server_vacuum(s, /* verbose = */ false);
vacuumed = true;
f = find_journal(s, uid);
@@ -883,8 +912,8 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
else
log_ratelimit_full_errno(LOG_INFO, r, "Failed to write entry to %s (%zu items, %zu bytes), rotating before retrying: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
- server_rotate(s);
- server_vacuum(s, false);
+ server_rotate_journal(s, TAKE_PTR(f), uid);
+ server_vacuum(s, /* verbose = */ false);
f = find_journal(s, uid);
if (!f)
@@ -1211,10 +1240,10 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
log_info("Rotating system journal.");
- server_rotate(s);
- server_vacuum(s, false);
+ server_rotate_journal(s, s->system_journal, /* uid = */ 0);
+ server_vacuum(s, /* verbose = */ false);
- if (!s->system_journal) {
+ if (!s->system_journal->file) {
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
r = -EIO;
goto finish;

@ -0,0 +1,41 @@
From fd3e9815846aa1efe295e897faf1e57f38c6c165 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Jun 2023 14:54:34 +0200
Subject: [PATCH] man: suffix --unit with an equal sign, since it expects an
argument
As per our usual syntax in the docs.
(cherry picked from commit e754af353c494edfdd25412fae32876a2772a5cd)
Related: RHEL-31070
---
man/journalctl.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/man/journalctl.xml b/man/journalctl.xml
index 5bf895fce4..29d06aaef8 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -110,8 +110,8 @@
<option>--user</option>). If neither is specified, show all messages that the user can see.
</para>
- <para>The <option>--user</option> option affects how <option>--unit</option> arguments are
- treated. See <option>--unit</option>.</para></listitem>
+ <para>The <option>--user</option> option affects how <option>--unit=</option> arguments are
+ treated. See <option>--unit=</option>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -285,8 +285,8 @@
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>
unit, all logs of children of the slice will be shown.</para>
- <para>With <option>--user</option>, all <option>--unit</option> arguments will be converted to match
- user messages as if specified with <option>--user-unit</option>.</para>
+ <para>With <option>--user</option>, all <option>--unit=</option> arguments will be converted to match
+ user messages as if specified with <option>--user-unit=</option>.</para>
<para>This parameter can be specified multiple times.</para></listitem>
</varlistentry>

@ -0,0 +1,57 @@
From f69edd2042ebf1db72ad1a2c6cbfd8887231da25 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Jun 2023 15:15:42 +0200
Subject: [PATCH] =?UTF-8?q?shared:=20move=20uid-alloc-range.[ch]=20from=20?=
=?UTF-8?q?src/shared/=20=E2=86=92=20src/basic/?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This way we can use it in libsystemd
(cherry picked from commit 8a8b4a8784f48e941b6b460b4cb963929d1d6a8d)
Related: RHEL-31070
---
src/basic/meson.build | 2 ++
src/{shared => basic}/uid-alloc-range.c | 0
src/{shared => basic}/uid-alloc-range.h | 0
src/shared/meson.build | 2 --
4 files changed, 2 insertions(+), 2 deletions(-)
rename src/{shared => basic}/uid-alloc-range.c (100%)
rename src/{shared => basic}/uid-alloc-range.h (100%)
diff --git a/src/basic/meson.build b/src/basic/meson.build
index bfe52d5879..c0f0b07418 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -240,6 +240,8 @@ basic_sources = files(
'time-util.h',
'tmpfile-util.c',
'tmpfile-util.h',
+ 'uid-alloc-range.c',
+ 'uid-alloc-range.h',
'uid-range.c',
'uid-range.h',
'umask-util.h',
diff --git a/src/shared/uid-alloc-range.c b/src/basic/uid-alloc-range.c
similarity index 100%
rename from src/shared/uid-alloc-range.c
rename to src/basic/uid-alloc-range.c
diff --git a/src/shared/uid-alloc-range.h b/src/basic/uid-alloc-range.h
similarity index 100%
rename from src/shared/uid-alloc-range.h
rename to src/basic/uid-alloc-range.h
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 9e11e13934..766e4f9506 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -311,8 +311,6 @@ shared_sources = files(
'tpm2-util.h',
'udev-util.c',
'udev-util.h',
- 'uid-alloc-range.c',
- 'uid-alloc-range.h',
'user-record-nss.c',
'user-record-nss.h',
'user-record-show.c',

@ -0,0 +1,66 @@
From c499486907937a823a8a3fe003b4d8bcf232fec6 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Jun 2023 15:16:50 +0200
Subject: [PATCH] journald: move uid_for_system_journal() to uid-alloc-range.h
Let's move this helper call from journald specific code to src/basic/,
so that we can use it from sd-journal.
While we are at it, slightly extend it to also cover container uids,
which are also routed to the system journal now.
This places the call in uid-alloc-range.[ch] which contains similar
functions that match UID ranges for specific purposes.
(cherry picked from commit 115d5145a257c1a27330acf9f063b5f4d910ca4d)
Related: RHEL-31070
---
src/basic/uid-alloc-range.c | 7 +++++++
src/basic/uid-alloc-range.h | 2 ++
src/journal/journald-server.c | 7 -------
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/basic/uid-alloc-range.c b/src/basic/uid-alloc-range.c
index dcecdbe343..1b6d761a66 100644
--- a/src/basic/uid-alloc-range.c
+++ b/src/basic/uid-alloc-range.c
@@ -121,3 +121,10 @@ bool gid_is_system(gid_t gid) {
return gid <= defs->system_gid_max;
}
+
+bool uid_for_system_journal(uid_t uid) {
+
+ /* Returns true if the specified UID shall get its data stored in the system journal. */
+
+ return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY || uid_is_container(uid);
+}
diff --git a/src/basic/uid-alloc-range.h b/src/basic/uid-alloc-range.h
index d3bf077045..5badde148a 100644
--- a/src/basic/uid-alloc-range.h
+++ b/src/basic/uid-alloc-range.h
@@ -32,3 +32,5 @@ typedef struct UGIDAllocationRange {
int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root);
const UGIDAllocationRange *acquire_ugid_allocation_range(void);
+
+bool uid_for_system_journal(uid_t uid);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 0ff6a43e5b..6fa182a566 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -234,13 +234,6 @@ void server_space_usage_message(Server *s, JournalStorage *storage) {
NULL);
}
-static bool uid_for_system_journal(uid_t uid) {
-
- /* Returns true if the specified UID shall get its data stored in the system journal. */
-
- return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY;
-}
-
static void server_add_acls(ManagedJournalFile *f, uid_t uid) {
assert(f);

@ -0,0 +1,65 @@
From 8dfa6d7536994c1a75b5d8a2af009efa9135b395 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Jun 2023 15:19:25 +0200
Subject: [PATCH] sd-journal: when SD_JOURNAL_CURRENT_USER is set, and called
from system UID, imply SD_JOURNAL_SYSTEM
Fixes: #26742 #23679
(cherry picked from commit 97c621b72d8c5b5eb4bf7f177cd885bfc01518c9)
Resolves: RHEL-31070
---
src/libsystemd/sd-journal/sd-journal.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c
index 9ab31fbbc8..723beec0e8 100644
--- a/src/libsystemd/sd-journal/sd-journal.c
+++ b/src/libsystemd/sd-journal/sd-journal.c
@@ -41,6 +41,7 @@
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
+#include "uid-alloc-range.h"
#define JOURNAL_FILES_MAX 7168
@@ -1217,25 +1218,32 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
static bool file_type_wanted(int flags, const char *filename) {
assert(filename);
- if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
+ if (!ENDSWITH_SET(filename, ".journal", ".journal~"))
return false;
/* no flags set → every type is OK */
if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
return true;
- if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
- return true;
-
- if (flags & SD_JOURNAL_CURRENT_USER) {
+ if (FLAGS_SET(flags, SD_JOURNAL_CURRENT_USER)) {
char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
- xsprintf(prefix, "user-"UID_FMT, getuid());
+ xsprintf(prefix, "user-" UID_FMT, getuid());
if (file_has_type_prefix(prefix, filename))
return true;
+
+ /* If SD_JOURNAL_CURRENT_USER is specified and we are invoked under a system UID, then
+ * automatically enable SD_JOURNAL_SYSTEM too, because journald will actually put system user
+ * data into the system journal. */
+
+ if (uid_for_system_journal(getuid()))
+ flags |= SD_JOURNAL_SYSTEM;
}
+ if (FLAGS_SET(flags, SD_JOURNAL_SYSTEM) && file_has_type_prefix("system", filename))
+ return true;
+
return false;
}

@ -0,0 +1,46 @@
From 6cee9dd4b39082ec7d5afcb1f4c0b91832e294d9 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Jun 2023 16:23:45 +0200
Subject: [PATCH] man: document that journalctl --user requires
Storage=persistent
Fixes: #25061
(cherry picked from commit cad8fa471b9133f38fbd6ddb6ee143f361525e5d)
Related: RHEL-31070
---
man/journalctl.xml | 6 +++++-
man/journald.conf.xml | 3 +++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/man/journalctl.xml b/man/journalctl.xml
index 29d06aaef8..6be628caf8 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -111,7 +111,11 @@
</para>
<para>The <option>--user</option> option affects how <option>--unit=</option> arguments are
- treated. See <option>--unit=</option>.</para></listitem>
+ treated. See <option>--unit=</option>.</para>
+
+ <para>Note that <option>--user</option> only works if persistent logging is enabled, via the
+ <varname>Storage=</varname> setting in
+ <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/journald.conf.xml b/man/journald.conf.xml
index 24cee4c8b2..a7c3da6653 100644
--- a/man/journald.conf.xml
+++ b/man/journald.conf.xml
@@ -95,6 +95,9 @@
<filename>/var/log/journal/</filename>, as the <filename>systemd-journald@.service</filename> service
file by default carries <varname>LogsDirectory=</varname>. To turn that off, add a unit file drop-in
file that sets <varname>LogsDirectory=</varname> to an empty string.</para>
+
+ <para>Note that per-user journal files are not supported unless persistent storage is enabled, thus
+ making <command>journalctl --user</command> unavailable.</para>
</listitem>
</varlistentry>

@ -0,0 +1,35 @@
From ee2dd3cada129b39a2da5287f31e6d9e18a82764 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?=
=?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?=
<gdamjan@gmail.com>
Date: Fri, 1 Dec 2023 11:46:36 +0100
Subject: [PATCH] fix: prefix of dmesg pstore files
A change in the kernel[1] renamed the prefix of the pstore files from
`dmesg-efi-` to `dmesg-efi_pstore-`.
[1]
https://git.kernel.org/linus/893c5f1de620
(cherry picked from commit ef87c84e812cbdca4ef160fb0536d1f1bc6a2400)
Resolves: RHEL-20322
---
src/pstore/pstore.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 7fff6cee62..76657da536 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -233,7 +233,9 @@ static int process_dmesg_files(PStoreList *list) {
if (!startswith(pe->dirent.d_name, "dmesg-"))
continue;
- if ((p = startswith(pe->dirent.d_name, "dmesg-efi-"))) {
+ /* The linux kernel changed the prefix from dmesg-efi- to dmesg-efi_pstore-
+ * so now we have to handle both cases. */
+ if ((p = STARTSWITH_SET(pe->dirent.d_name, "dmesg-efi-", "dmesg-efi_pstore-"))) {
/* 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

File diff suppressed because it is too large Load Diff

@ -0,0 +1,335 @@
From 7b2bb541eba2795e0db1bfedd4b1fa64a6e28a55 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 19 Dec 2023 16:03:06 +0100
Subject: [PATCH] test: Skip various tests when /sys is not mounted
When running tests in a container, /sys might not be mounted, so
let's make sure we skip tests that depend on /sys in this case.
(cherry picked from commit a412a1b92ab234a57c646f6779471772b2c355ec)
Related: RHEL-27512
---
src/libsystemd/sd-bus/test-bus-creds.c | 2 +-
src/libsystemd/sd-device/test-sd-device-monitor.c | 4 ++++
src/libsystemd/sd-device/test-sd-device-thread.c | 3 +++
src/libsystemd/sd-device/test-sd-device.c | 10 +++++++++-
src/libsystemd/sd-login/test-login.c | 4 ++++
src/libudev/test-udev-device-thread.c | 7 ++++++-
src/shared/tests.c | 3 ++-
src/test/meson.build | 4 ++--
src/test/test-cgroup-util.c | 4 ++--
src/test/test-cgroup.c | 4 ++--
src/test/test-condition.c | 8 ++++----
src/test/test-mountpoint-util.c | 8 ++++----
src/test/test-udev-util.c | 4 ++++
src/test/test-watch-pid.c | 2 +-
src/udev/test-udev-event.c | 4 ++++
15 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index 13801becc9..d18ce88a25 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -12,7 +12,7 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
- if (cg_unified() == -ENOMEDIUM)
+ if (IN_SET(cg_unified(), -ENOMEDIUM, -ENOENT))
return log_tests_skipped("/sys/fs/cgroup/ not available");
r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
diff --git a/src/libsystemd/sd-device/test-sd-device-monitor.c b/src/libsystemd/sd-device/test-sd-device-monitor.c
index 9e64ba01c6..a9a002b5ae 100644
--- a/src/libsystemd/sd-device/test-sd-device-monitor.c
+++ b/src/libsystemd/sd-device/test-sd-device-monitor.c
@@ -10,6 +10,7 @@
#include "device-private.h"
#include "device-util.h"
#include "macro.h"
+#include "mountpoint-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "string-util.h"
@@ -302,6 +303,9 @@ int main(int argc, char *argv[]) {
if (getuid() != 0)
return log_tests_skipped("not root");
+ if (path_is_mount_point("/sys", NULL, 0) <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
if (path_is_read_only_fs("/sys") > 0)
return log_tests_skipped("Running in container");
diff --git a/src/libsystemd/sd-device/test-sd-device-thread.c b/src/libsystemd/sd-device/test-sd-device-thread.c
index 644f3c2aee..bf3cd5ce25 100644
--- a/src/libsystemd/sd-device/test-sd-device-thread.c
+++ b/src/libsystemd/sd-device/test-sd-device-thread.c
@@ -8,6 +8,7 @@
#include "sd-device.h"
#include "device-util.h"
+#include "tests.h"
#define handle_error_errno(error, msg) \
({ \
@@ -31,6 +32,8 @@ int main(int argc, char *argv[]) {
int r;
r = sd_device_new_from_syspath(&loopback, "/sys/class/net/lo");
+ if (r == -ENODEV)
+ return log_tests_skipped("Loopback device not found");
if (r < 0)
return handle_error_errno(r, "Failed to create loopback device object");
diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index a1bcf18059..237681eab8 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -11,6 +11,7 @@
#include "errno-util.h"
#include "fd-util.h"
#include "hashmap.h"
+#include "mountpoint-util.h"
#include "nulstr-util.h"
#include "path-util.h"
#include "rm-rf.h"
@@ -656,4 +657,11 @@ TEST(devname_from_devnum) {
}
}
-DEFINE_TEST_MAIN(LOG_INFO);
+static int intro(void) {
+ if (path_is_mount_point("/sys", NULL, 0) <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index f7cef6e304..84fcfab4a0 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -9,6 +9,7 @@
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
+#include "mountpoint-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
@@ -295,6 +296,9 @@ TEST(monitor) {
}
static int intro(void) {
+ if (IN_SET(cg_unified(), -ENOENT, -ENOMEDIUM))
+ return log_tests_skipped("cgroupfs is not mounted");
+
log_info("/* Information printed is from the live system */");
return EXIT_SUCCESS;
}
diff --git a/src/libudev/test-udev-device-thread.c b/src/libudev/test-udev-device-thread.c
index c082fdca46..fdf0818863 100644
--- a/src/libudev/test-udev-device-thread.c
+++ b/src/libudev/test-udev-device-thread.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include "libudev.h"
+#include "tests.h"
#define handle_error_errno(error, msg) \
({ \
@@ -29,8 +30,12 @@ int main(int argc, char *argv[]) {
int r;
loopback = udev_device_new_from_syspath(NULL, "/sys/class/net/lo");
- if (!loopback)
+ if (!loopback) {
+ if (errno == ENODEV)
+ return log_tests_skipped_errno(errno, "Loopback device not found");
+
return handle_error_errno(errno, "Failed to create loopback device object");
+ }
entry = udev_device_get_properties_list_entry(loopback);
udev_list_entry_foreach(e, entry)
diff --git a/src/shared/tests.c b/src/shared/tests.c
index a65080cbf4..a4deb7b0d5 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -28,6 +28,7 @@
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
+#include "mountpoint-util.h"
#include "namespace-util.h"
#include "path-util.h"
#include "process-util.h"
@@ -285,7 +286,7 @@ static int enter_cgroup(char **ret_cgroup, bool enter_subroot) {
log_warning_errno(r, "Couldn't allocate a scope unit for this test, proceeding without.");
r = cg_pid_get_path(NULL, 0, &cgroup_root);
- if (r == -ENOMEDIUM)
+ if (IN_SET(r, -ENOMEDIUM, -ENOENT))
return log_warning_errno(r, "cg_pid_get_path(NULL, 0, ...) failed: %m");
assert(r >= 0);
diff --git a/src/test/meson.build b/src/test/meson.build
index 1d61dc343f..5547271ee7 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -701,11 +701,11 @@ tests += [
libsystemd_static]],
[files('../libsystemd/sd-device/test-sd-device-thread.c'),
- [libsystemd],
+ [libbasic, libshared_static, libsystemd_static],
[threads]],
[files('../libudev/test-udev-device-thread.c'),
- [libudev],
+ [libbasic, libshared_static, libsystemd_static, libudev],
[threads]],
]
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 7113b07a95..c6439e2fbb 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -334,7 +334,7 @@ TEST(cg_tests) {
int all, hybrid, systemd, r;
r = cg_unified();
- if (r == -ENOMEDIUM) {
+ if (IN_SET(r, -ENOENT, -ENOMEDIUM)) {
log_tests_skipped("cgroup not mounted");
return;
}
@@ -367,7 +367,7 @@ TEST(cg_get_keyed_attribute) {
int i, r;
r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val);
- if (r == -ENOMEDIUM || ERRNO_IS_PRIVILEGE(r)) {
+ if (IN_SET(r, -ENOMEDIUM, -ENOENT) || ERRNO_IS_PRIVILEGE(r)) {
log_info_errno(r, "Skipping most of %s, /sys/fs/cgroup not accessible: %m", __func__);
return;
}
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 7341e5b022..a3d286a669 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -44,8 +44,8 @@ TEST(cg_create) {
int r;
r = cg_unified_cached(false);
- if (r == -ENOMEDIUM) {
- log_tests_skipped("cgroup not mounted");
+ if (IN_SET(r, -ENOMEDIUM, -ENOENT)) {
+ log_tests_skipped("cgroupfs is not mounted");
return;
}
assert_se(r >= 0);
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 4cd23d8e21..57e7d35119 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -138,8 +138,8 @@ TEST(condition_test_control_group_hierarchy) {
int r;
r = cg_unified();
- if (r == -ENOMEDIUM) {
- log_tests_skipped("cgroup not mounted");
+ if (IN_SET(r, -ENOMEDIUM, -ENOENT)) {
+ log_tests_skipped("cgroupfs is not mounted");
return;
}
assert_se(r >= 0);
@@ -162,8 +162,8 @@ TEST(condition_test_control_group_controller) {
int r;
r = cg_unified();
- if (r == -ENOMEDIUM) {
- log_tests_skipped("cgroup not mounted");
+ if (IN_SET(r, -ENOMEDIUM, -ENOENT)) {
+ log_tests_skipped("cgroupfs is not mounted");
return;
}
assert_se(r >= 0);
diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
index 391e1c97ba..8555c5a7db 100644
--- a/src/test/test-mountpoint-util.c
+++ b/src/test/test-mountpoint-util.c
@@ -138,10 +138,10 @@ TEST(path_is_mount_point) {
assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
- assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
- assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
+ assert_se(path_is_mount_point("/dev", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/dev", NULL, 0) > 0);
+ assert_se(path_is_mount_point("/dev/", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/dev/", NULL, 0) > 0);
/* we'll create a hierarchy of different kinds of dir/file/link
* layouts:
diff --git a/src/test/test-udev-util.c b/src/test/test-udev-util.c
index 1db2dad4ff..ee089939fd 100644
--- a/src/test/test-udev-util.c
+++ b/src/test/test-udev-util.c
@@ -4,6 +4,7 @@
#include <string.h>
#include "macro.h"
+#include "mountpoint-util.h"
#include "string-util.h"
#include "tests.h"
#include "udev-util.h"
@@ -137,6 +138,9 @@ static void test_udev_resolve_subsys_kernel_one(const char *str, bool read_value
}
TEST(udev_resolve_subsys_kernel) {
+ if (path_is_mount_point("/sys", NULL, 0) <= 0)
+ return (void) log_tests_skipped("/sys is not mounted");
+
test_udev_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL);
test_udev_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL);
test_udev_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL);
diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c
index 8c355c1d5f..34291fb539 100644
--- a/src/test/test-watch-pid.c
+++ b/src/test/test-watch-pid.c
@@ -17,7 +17,7 @@ int main(int argc, char *argv[]) {
if (getuid() != 0)
return log_tests_skipped("not root");
r = enter_cgroup_subroot(NULL);
- if (r == -ENOMEDIUM)
+ if (r < 0)
return log_tests_skipped("cgroupfs not available");
_cleanup_free_ char *unit_dir = NULL;
diff --git a/src/udev/test-udev-event.c b/src/udev/test-udev-event.c
index b6b2c91b2e..92cab2f354 100644
--- a/src/udev/test-udev-event.c
+++ b/src/udev/test-udev-event.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "mountpoint-util.h"
#include "path-util.h"
#include "signal-util.h"
#include "strv.h"
@@ -80,6 +81,9 @@ static void test2(void) {
int main(int argc, char *argv[]) {
_cleanup_free_ char *self = NULL;
+ if (path_is_mount_point("/sys", NULL, 0) <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
if (argc > 1) {
if (streq(argv[1], "test1"))
test1();

@ -0,0 +1,27 @@
From 2241ee9563bbcb8bf729547926133619d4baa0cd Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 14:13:47 +0900
Subject: [PATCH] string-util: introduce ascii_ishex()
(cherry picked from commit 0ce8870f19a839c7b09b4ef5b61c2d363050c7d9)
Related: RHEL-27512
---
src/fundamental/string-util-fundamental.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/fundamental/string-util-fundamental.h b/src/fundamental/string-util-fundamental.h
index 523c612a17..c35ce5b88f 100644
--- a/src/fundamental/string-util-fundamental.h
+++ b/src/fundamental/string-util-fundamental.h
@@ -110,6 +110,10 @@ static inline bool ascii_isdigit(sd_char a) {
return a >= '0' && a <= '9';
}
+static inline bool ascii_ishex(sd_char a) {
+ return ascii_isdigit(a) || (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F');
+}
+
static inline bool ascii_isalpha(sd_char a) {
/* A pure ASCII, locale independent version of isalpha() */
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');

@ -0,0 +1,207 @@
From 961b82ca7bd6a14fb564a63ae37c6c2af0d87d89 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 14:20:03 +0900
Subject: [PATCH] sd-id128: several cleanups
- use SD_ID128_STRING_MAX or friend,
- use sizeof(sd_id128_t),
- use newly introduced ascii_ishex().
(cherry picked from commit 28bf2de201e890193b57accbf736c7d3d82d813a)
Related: RHEL-27512
---
src/libsystemd/sd-id128/id128-util.c | 58 ++++++++++------------------
src/libsystemd/sd-id128/sd-id128.c | 21 +++++-----
2 files changed, 33 insertions(+), 46 deletions(-)
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index cef340f3bc..2ec77bb9f3 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -13,50 +13,35 @@
#include "sync-util.h"
bool id128_is_valid(const char *s) {
- size_t i, l;
+ size_t l;
assert(s);
l = strlen(s);
- if (l == 32) {
+ if (l == SD_ID128_STRING_MAX - 1)
/* Plain formatted 128bit hex string */
+ return in_charset(s, HEXDIGITS);
- for (i = 0; i < l; i++) {
- char c = s[i];
-
- if (!ascii_isdigit(c) &&
- !(c >= 'a' && c <= 'f') &&
- !(c >= 'A' && c <= 'F'))
- return false;
- }
-
- } else if (l == 36) {
-
+ if (l == SD_ID128_UUID_STRING_MAX - 1) {
/* Formatted UUID */
-
- for (i = 0; i < l; i++) {
+ for (size_t i = 0; i < l; i++) {
char c = s[i];
if (IN_SET(i, 8, 13, 18, 23)) {
if (c != '-')
return false;
- } else {
- if (!ascii_isdigit(c) &&
- !(c >= 'a' && c <= 'f') &&
- !(c >= 'A' && c <= 'F'))
- return false;
- }
+ } else if (!ascii_ishex(c))
+ return false;
}
+ return true;
+ }
- } else
- return false;
-
- return true;
+ return false;
}
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
- char buffer[36 + 2];
+ char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
ssize_t l;
assert(fd >= 0);
@@ -80,28 +65,28 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
/* Treat an "uninitialized" id file like an empty one */
return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
- case 33: /* plain UUID with trailing newline */
- if (buffer[32] != '\n')
+ case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
+ if (buffer[SD_ID128_STRING_MAX-1] != '\n')
return -EINVAL;
_fallthrough_;
- case 32: /* plain UUID without trailing newline */
+ case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
if (f == ID128_UUID)
return -EINVAL;
- buffer[32] = 0;
+ buffer[SD_ID128_STRING_MAX-1] = 0;
break;
- case 37: /* RFC UUID with trailing newline */
- if (buffer[36] != '\n')
+ case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
+ if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
return -EINVAL;
_fallthrough_;
- case 36: /* RFC UUID without trailing newline */
+ case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
return -EINVAL;
- buffer[36] = 0;
+ buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
break;
default:
@@ -122,7 +107,7 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
}
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
- char buffer[36 + 2];
+ char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
size_t sz;
int r;
@@ -131,14 +116,13 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
if (f != ID128_UUID) {
assert_se(sd_id128_to_string(id, buffer));
- buffer[SD_ID128_STRING_MAX - 1] = '\n';
sz = SD_ID128_STRING_MAX;
} else {
assert_se(sd_id128_to_uuid_string(id, buffer));
- buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
sz = SD_ID128_UUID_STRING_MAX;
}
+ buffer[sz - 1] = '\n';
r = loop_write(fd, buffer, sz, false);
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 709c8ffb57..07a13be2b2 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -19,14 +19,17 @@
#include "util.h"
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
+ size_t k = 0;
+
assert_return(s, NULL);
- for (size_t n = 0; n < 16; n++) {
- s[n*2] = hexchar(id.bytes[n] >> 4);
- s[n*2+1] = hexchar(id.bytes[n] & 0xF);
+ for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
+ s[k++] = hexchar(id.bytes[n] >> 4);
+ s[k++] = hexchar(id.bytes[n] & 0xF);
}
- s[SD_ID128_STRING_MAX-1] = 0;
+ assert(k == SD_ID128_STRING_MAX - 1);
+ s[k] = 0;
return s;
}
@@ -38,7 +41,7 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
- for (size_t n = 0; n < 16; n++) {
+ for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
@@ -53,14 +56,14 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
return s;
}
-_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
- unsigned n, i;
+_public_ int sd_id128_from_string(const char *s, sd_id128_t *ret) {
+ size_t n, i;
sd_id128_t t;
bool is_guid = false;
assert_return(s, -EINVAL);
- for (n = 0, i = 0; n < 16;) {
+ for (n = 0, i = 0; n < sizeof(sd_id128_t);) {
int a, b;
if (s[i] == '-') {
@@ -90,7 +93,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
t.bytes[n++] = (a << 4) | b;
}
- if (i != (is_guid ? 36 : 32))
+ if (i != (is_guid ? SD_ID128_UUID_STRING_MAX : SD_ID128_STRING_MAX) - 1)
return -EINVAL;
if (s[i] != 0)

@ -0,0 +1,468 @@
From 0cb518ec9b1860e553cf539304310a573494743a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 14:30:31 +0900
Subject: [PATCH] sd-id128: make id128_read() or friends return -ENOPKG when
the file contents is "uninitialized"
Then, this drops ID128_PLAIN_OR_UNINIT. Also, this renames
Id128Format -> Id128FormatFlag, and make it bitfield.
Fixes #25634.
(cherry picked from commit 057bf780e9d45480fbacdd3b060dbe37b37f9693)
Related: RHEL-27512
---
src/boot/bootctl.c | 2 +-
src/libsystemd/sd-id128/id128-util.c | 35 +++++++++++---------
src/libsystemd/sd-id128/id128-util.h | 27 ++++++---------
src/libsystemd/sd-id128/sd-id128.c | 4 +--
src/libsystemd/sd-journal/journal-file.c | 2 +-
src/machine-id-setup/machine-id-setup-main.c | 2 +-
src/nspawn/nspawn.c | 6 ++--
src/partition/repart.c | 4 +--
src/shared/discover-image.c | 2 +-
src/shared/machine-id-setup.c | 12 +++----
src/shared/specifier.c | 2 +-
src/test/test-condition.c | 2 +-
src/test/test-fs-util.c | 2 +-
src/test/test-id128.c | 26 +++++++--------
14 files changed, 63 insertions(+), 65 deletions(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 00e8eda992..dc4dc0d391 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -182,7 +182,7 @@ static int load_etc_machine_id(void) {
int r;
r = sd_id128_get_machine(&arg_machine_id);
- if (IN_SET(r, -ENOENT, -ENOMEDIUM)) /* Not set or empty */
+ if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG)) /* Not set or empty */
return 0;
if (r < 0)
return log_error_errno(r, "Failed to get machine-id: %m");
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index 2ec77bb9f3..9b0ad48e6b 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -40,17 +40,21 @@ bool id128_is_valid(const char *s) {
return false;
}
-int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
+int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
ssize_t l;
assert(fd >= 0);
- assert(f < _ID128_FORMAT_MAX);
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
- * accept". */
+ * accept".
+ *
+ * This returns the following:
+ * -ENOMEDIUM: an empty string,
+ * -ENOPKG: "uninitialized" or "uninitialized\n",
+ * -EINVAL: other invalid strings. */
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
if (l < 0)
@@ -60,10 +64,9 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
switch (l) {
- case 13:
- case 14:
- /* Treat an "uninitialized" id file like an empty one */
- return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
+ case STRLEN("uninitialized"):
+ case STRLEN("uninitialized\n"):
+ return strneq(buffer, "uninitialized\n", l) ? -ENOPKG : -EINVAL;
case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
if (buffer[SD_ID128_STRING_MAX-1] != '\n')
@@ -71,7 +74,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
_fallthrough_;
case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
- if (f == ID128_UUID)
+ if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
return -EINVAL;
buffer[SD_ID128_STRING_MAX-1] = 0;
@@ -83,7 +86,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
_fallthrough_;
case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
- if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
+ if (!FLAGS_SET(f, ID128_FORMAT_UUID))
return -EINVAL;
buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
@@ -96,7 +99,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
return sd_id128_from_string(buffer, ret);
}
-int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
+int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
_cleanup_close_ int fd = -1;
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -106,15 +109,15 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
return id128_read_fd(fd, f, ret);
}
-int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
size_t sz;
int r;
assert(fd >= 0);
- assert(f < _ID128_FORMAT_MAX);
+ assert(IN_SET((f & ID128_FORMAT_ANY), ID128_FORMAT_PLAIN, ID128_FORMAT_UUID));
- if (f != ID128_UUID) {
+ if (FLAGS_SET(f, ID128_FORMAT_PLAIN)) {
assert_se(sd_id128_to_string(id, buffer));
sz = SD_ID128_STRING_MAX;
} else {
@@ -136,7 +139,7 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
return 0;
}
-int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
_cleanup_close_ int fd = -1;
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
@@ -179,9 +182,9 @@ int id128_get_product(sd_id128_t *ret) {
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
- r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+ r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
if (r == -ENOENT)
- r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
+ r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index 9d8fe93641..d031c680f1 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -10,22 +10,17 @@
bool id128_is_valid(const char *s) _pure_;
-typedef enum Id128Format {
- ID128_ANY,
- ID128_PLAIN, /* formatted as 32 hex chars as-is */
- ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized"
- * value when reading from file (id128_read() and id128_read_fd()).
- *
- * This format should be used when reading a machine-id file. */
- ID128_UUID, /* formatted as 36 character uuid string */
- _ID128_FORMAT_MAX,
-} Id128Format;
-
-int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
-int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
-
-int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
-int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
+typedef enum Id128FormatFlag {
+ ID128_FORMAT_PLAIN = 1 << 0, /* formatted as 32 hex chars as-is */
+ ID128_FORMAT_UUID = 1 << 1, /* formatted as 36 character uuid string */
+ ID128_FORMAT_ANY = ID128_FORMAT_PLAIN | ID128_FORMAT_UUID,
+} Id128FormatFlag;
+
+int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret);
+int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret);
+
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync);
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 07a13be2b2..5e9ec2b5f6 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -127,7 +127,7 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_machine_id)) {
- r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
+ r = id128_read("/etc/machine-id", ID128_FORMAT_PLAIN, &saved_machine_id);
if (r < 0)
return r;
@@ -146,7 +146,7 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_boot_id)) {
- r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
+ r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
if (r < 0)
return r;
}
diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c
index 3c1385ddb0..2b66b3caed 100644
--- a/src/libsystemd/sd-journal/journal-file.c
+++ b/src/libsystemd/sd-journal/journal-file.c
@@ -421,7 +421,7 @@ static int journal_file_refresh_header(JournalFile *f) {
assert(f->header);
r = sd_id128_get_machine(&f->header->machine_id);
- if (IN_SET(r, -ENOENT, -ENOMEDIUM))
+ if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG))
/* We don't have a machine-id, let's continue without */
zero(f->header->machine_id);
else if (r < 0)
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 8a3b1efb4c..b595b2ab37 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -164,7 +164,7 @@ static int run(int argc, char *argv[]) {
return r;
etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
- r = id128_read(etc_machine_id, ID128_PLAIN, &id);
+ r = id128_read(etc_machine_id, ID128_FORMAT_PLAIN, &id);
if (r < 0)
return log_error_errno(r, "Failed to read machine ID back: %m");
} else {
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index df7b37ec4e..085f817dd3 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2195,7 +2195,7 @@ static int setup_boot_id(void) {
if (r < 0)
return log_error_errno(r, "Failed to generate random boot id: %m");
- r = id128_write(path, ID128_UUID, rnd, false);
+ r = id128_write(path, ID128_FORMAT_UUID, rnd, false);
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
@@ -2821,9 +2821,9 @@ static int setup_machine_id(const char *directory) {
etc_machine_id = prefix_roota(directory, "/etc/machine-id");
- r = id128_read(etc_machine_id, ID128_PLAIN_OR_UNINIT, &id);
+ r = id128_read(etc_machine_id, ID128_FORMAT_PLAIN, &id);
if (r < 0) {
- if (!IN_SET(r, -ENOENT, -ENOMEDIUM)) /* If the file is missing or empty, we don't mind */
+ if (!IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG)) /* If the file is missing, empty, or uninitialized, we don't mind */
return log_error_errno(r, "Failed to read machine ID from container image: %m");
if (sd_id128_is_null(arg_uuid)) {
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 2b3b384743..553d92e730 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -4515,8 +4515,8 @@ static int context_read_seed(Context *context, const char *root) {
else if (fd < 0)
return log_error_errno(fd, "Failed to determine machine ID of image: %m");
else {
- r = id128_read_fd(fd, ID128_PLAIN_OR_UNINIT, &context->seed);
- if (r == -ENOMEDIUM)
+ r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &context->seed);
+ if (IN_SET(r, -ENOMEDIUM, -ENOPKG))
log_info("No machine ID set, using randomized partition UUIDs.");
else if (r < 0)
return log_error_errno(r, "Failed to parse machine ID of image: %m");
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index 0488e215fd..75a42efe88 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -1153,7 +1153,7 @@ int image_read_metadata(Image *i) {
if (fd < 0)
log_debug_errno(errno, "Failed to open %s: %m", path);
else {
- r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
+ r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &machine_id);
if (r < 0)
log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
}
diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c
index df4ac419cb..787c0765d0 100644
--- a/src/shared/machine-id-setup.c
+++ b/src/shared/machine-id-setup.c
@@ -38,7 +38,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
- if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) {
+ if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0) {
log_info("Initializing machine ID from D-Bus machine ID.");
return 0;
}
@@ -123,7 +123,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
if (sd_id128_is_null(machine_id)) {
/* Try to read any existing machine ID */
- if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0)
+ if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0)
return 0;
/* Hmm, so, the id currently stored is not useful, then let's generate one */
@@ -152,7 +152,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
if (r < 0)
return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
} else {
- r = id128_write_fd(fd, ID128_PLAIN, machine_id, true);
+ r = id128_write_fd(fd, ID128_FORMAT_PLAIN, machine_id, true);
if (r < 0)
return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
else
@@ -168,7 +168,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0022)
- r = id128_write(run_machine_id, ID128_PLAIN, machine_id, false);
+ r = id128_write(run_machine_id, ID128_FORMAT_PLAIN, machine_id, false);
if (r < 0) {
(void) unlink(run_machine_id);
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
@@ -240,7 +240,7 @@ int machine_id_commit(const char *root) {
"%s is not on a temporary file system.",
etc_machine_id);
- r = id128_read_fd(fd, ID128_PLAIN, &id);
+ r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &id);
if (r < 0)
return log_error_errno(r, "We didn't find a valid machine ID in %s: %m", etc_machine_id);
@@ -261,7 +261,7 @@ int machine_id_commit(const char *root) {
return r;
/* Update a persistent version of etc_machine_id */
- r = id128_write(etc_machine_id, ID128_PLAIN, id, true);
+ r = id128_write(etc_machine_id, ID128_FORMAT_PLAIN, id, true);
if (r < 0)
return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index d54ab9f5a9..cd651768bd 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -195,7 +195,7 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con
/* Translate error for missing os-release file to EUNATCH. */
return fd == -ENOENT ? -EUNATCH : fd;
- r = id128_read_fd(fd, ID128_PLAIN, &id);
+ r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &id);
} else
r = sd_id128_get_machine(&id);
if (r < 0)
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 57e7d35119..b16e8047c6 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -250,7 +250,7 @@ TEST(condition_test_host) {
int r;
r = sd_id128_get_machine(&id);
- if (IN_SET(r, -ENOENT, -ENOMEDIUM))
+ if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG))
return (void) log_tests_skipped("/etc/machine-id missing");
assert_se(r >= 0);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 16f04d6889..0b1f11ebdf 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -302,7 +302,7 @@ TEST(chase_symlinks) {
assert_se(fd >= 0);
safe_close(pfd);
- assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &a) >= 0);
assert_se(sd_id128_get_machine(&b) >= 0);
assert_se(sd_id128_equal(a, b));
}
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 4b71c5c00b..4175ac7b60 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -86,17 +86,17 @@ TEST(id128) {
/* First, write as UUID */
assert_se(sd_id128_randomize(&id) >= 0);
- assert_se(id128_write_fd(fd, ID128_UUID, id, false) >= 0);
+ assert_se(id128_write_fd(fd, ID128_FORMAT_UUID, id, false) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
/* Second, write as plain */
@@ -104,17 +104,17 @@ TEST(id128) {
assert_se(ftruncate(fd, 0) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
- assert_se(id128_write_fd(fd, ID128_PLAIN, id, false) >= 0);
+ assert_se(id128_write_fd(fd, ID128_FORMAT_PLAIN, id, false) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
/* Third, write plain without trailing newline */
@@ -125,13 +125,13 @@ TEST(id128) {
assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
- /* Third, write UUID without trailing newline */
+ /* Fourth, write UUID without trailing newline */
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(ftruncate(fd, 0) >= 0);
@@ -139,10 +139,10 @@ TEST(id128) {
assert_se(write(fd, sd_id128_to_uuid_string(id, q), 36) == 36);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {

@ -0,0 +1,49 @@
From 845d23e9b10edfbd3ba28a81acf3871c4566c23b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 15:18:28 +0900
Subject: [PATCH] test: add tests for "uninitialized" string handling by
id128_read_fd()
(cherry picked from commit 66c7949e08a977a9d0c32dcfadef0bb843956b8d)
Related: RHEL-27512
---
src/test/test-id128.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 4175ac7b60..dccf3b7fb9 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -145,6 +145,31 @@ TEST(id128) {
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
+ /* Fifth, tests for "uninitialized" */
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(ftruncate(fd, 0) >= 0);
+ assert_se(write(fd, "uninitialized", STRLEN("uninitialized")) == STRLEN("uninitialized"));
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -ENOPKG);
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(ftruncate(fd, 0) >= 0);
+ assert_se(write(fd, "uninitialized\n", STRLEN("uninitialized\n")) == STRLEN("uninitialized\n"));
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -ENOPKG);
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(ftruncate(fd, 0) >= 0);
+ assert_se(write(fd, "uninitialized\nfoo", STRLEN("uninitialized\nfoo")) == STRLEN("uninitialized\nfoo"));
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(ftruncate(fd, 0) >= 0);
+ assert_se(write(fd, "uninit", STRLEN("uninit")) == STRLEN("uninit"));
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
+
if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0);
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0);

@ -0,0 +1,32 @@
From 1d0f2f8d806758a70e8fc81536e0cf54649f1bf5 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 15:43:26 +0900
Subject: [PATCH] man: mention sd_id128_get_machine() or friend may return
-ENOPKG
(cherry picked from commit a237c6e0b0b294cebc084891a84173a19eb69172)
Related: RHEL-27512
---
man/sd_id128_get_machine.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index a778f8a2b0..8bc76b686b 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -144,6 +144,14 @@
empty or all zeros.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>-ENOPKG</constant></term>
+
+ <listitem><para>Returned by <function>sd_id128_get_machine()</function> and
+ <function>sd_id128_get_machine_app_specific()</function> when the content of
+ <filename>/etc/machine-id</filename> is <literal>uninitialized</literal>.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><constant>-ENXIO</constant></term>

@ -0,0 +1,27 @@
From 5e97c9d10934b54dfb93a4d236dd3a9c92840f26 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 15:48:25 +0900
Subject: [PATCH] sd-id128: make sd_id128_get_boot() and friend return
-ENOMEDIUM
(cherry picked from commit 9be90c401e16cf04a9cea0b19fdefa7d0a47f056)
Related: RHEL-27512
---
src/libsystemd/sd-id128/sd-id128.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 5e9ec2b5f6..bff8074f19 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -149,6 +149,9 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
if (r < 0)
return r;
+
+ if (sd_id128_is_null(saved_boot_id))
+ return -ENOMEDIUM;
}
*ret = saved_boot_id;

@ -0,0 +1,34 @@
From 44d5561daff4ffa94e394e18c41001244bc170dc Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 12 Dec 2022 22:03:52 +0900
Subject: [PATCH] sd-id128: make sd_id128_get_boot() and friend return -ENOSYS
when /proc/ is not mounted
(cherry picked from commit e2720340e9fdf3aee2e8998dc72798de50be3630)
Related: RHEL-27512
---
src/libsystemd/sd-id128/sd-id128.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index bff8074f19..b3f4728988 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -15,6 +15,7 @@
#include "macro.h"
#include "missing_syscall.h"
#include "random-util.h"
+#include "stat-util.h"
#include "user-util.h"
#include "util.h"
@@ -147,6 +148,8 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
if (sd_id128_is_null(saved_boot_id)) {
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
+ if (r == -ENOENT && proc_mounted() == 0)
+ return -ENOSYS;
if (r < 0)
return r;

@ -0,0 +1,63 @@
From 66c103ed26f623a54318a6f4fa48f895fb6efab8 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 8 Dec 2022 15:49:02 +0900
Subject: [PATCH] man: mention that sd_id128_get_boot() and friend may return
-ENOSYS
And drop to mention sd_id128_get_boot_app_specific() may return -ENOENT
or -ENOMEDIUM. The function does not read /etc/machine-id. But reads a
file in the procfs, which is a kind of the kernel API. Hence the
failures are caused only when the system has wrong setup.
(cherry picked from commit c576920e673114529c5bfe5ea29891a24a443338)
Related: RHEL-27512
---
man/sd_id128_get_machine.xml | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 8bc76b686b..dbc6d4885d 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -129,19 +129,17 @@
<varlistentry>
<term><constant>-ENOENT</constant></term>
- <listitem><para>Returned by <function>sd_id128_get_machine()</function>,
- <function>sd_id128_get_machine_app_specific()</function>, and
- <function>sd_id128_get_boot_app_specific()</function> when <filename>/etc/machine-id</filename> is
- missing.</para></listitem>
+ <listitem><para>Returned by <function>sd_id128_get_machine()</function> and
+ <function>sd_id128_get_machine_app_specific()</function> when <filename>/etc/machine-id</filename>
+ is missing.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEDIUM</constant></term>
- <listitem><para>Returned by <function>sd_id128_get_machine()</function>,
- <function>sd_id128_get_machine_app_specific()</function>, and
- <function>sd_id128_get_boot_app_specific()</function> when <filename>/etc/machine-id</filename> is
- empty or all zeros.</para></listitem>
+ <listitem><para>Returned by <function>sd_id128_get_machine()</function> and
+ <function>sd_id128_get_machine_app_specific()</function> when <filename>/etc/machine-id</filename>
+ is empty or all zeros.</para></listitem>
</varlistentry>
<varlistentry>
@@ -152,6 +150,14 @@
<filename>/etc/machine-id</filename> is <literal>uninitialized</literal>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>-ENOSYS</constant></term>
+
+ <listitem><para>Returned by <function>sd_id128_get_boot()</function> and
+ <function>sd_id128_get_boot_app_specific()</function> when <filename>/proc/</filename> is not
+ mounted.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><constant>-ENXIO</constant></term>

@ -0,0 +1,143 @@
From 77085bae51bcfaaa0ef356bca93e9aa883a43a89 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 9 Dec 2022 05:37:12 +0900
Subject: [PATCH] sd-id128: fold do_sync flag into Id128FormatFlag
(cherry picked from commit b40c8ebdc86b61df03207865b5a75cd37900ea4c)
Related: RHEL-27512
---
src/libsystemd/sd-id128/id128-util.c | 8 ++++----
src/libsystemd/sd-id128/id128-util.h | 6 ++++--
src/nspawn/nspawn.c | 2 +-
src/shared/machine-id-setup.c | 6 +++---
src/test/test-id128.c | 4 ++--
5 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index 9b0ad48e6b..faacc55960 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -109,7 +109,7 @@ int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
return id128_read_fd(fd, f, ret);
}
-int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id) {
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
size_t sz;
int r;
@@ -130,7 +130,7 @@ int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
if (r < 0)
return r;
- if (do_sync) {
+ if (FLAGS_SET(f, ID128_SYNC_ON_WRITE)) {
r = fsync_full(fd);
if (r < 0)
return r;
@@ -139,14 +139,14 @@ int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
return 0;
}
-int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id) {
_cleanup_close_ int fd = -1;
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
if (fd < 0)
return -errno;
- return id128_write_fd(fd, f, id, do_sync);
+ return id128_write_fd(fd, f, id);
}
void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index d031c680f1..887f443d69 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -14,13 +14,15 @@ typedef enum Id128FormatFlag {
ID128_FORMAT_PLAIN = 1 << 0, /* formatted as 32 hex chars as-is */
ID128_FORMAT_UUID = 1 << 1, /* formatted as 36 character uuid string */
ID128_FORMAT_ANY = ID128_FORMAT_PLAIN | ID128_FORMAT_UUID,
+
+ ID128_SYNC_ON_WRITE = 1 << 2, /* Sync the file after write. Used only when writing an ID. */
} Id128FormatFlag;
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret);
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret);
-int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync);
-int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync);
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id);
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 085f817dd3..db45968cd3 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2195,7 +2195,7 @@ static int setup_boot_id(void) {
if (r < 0)
return log_error_errno(r, "Failed to generate random boot id: %m");
- r = id128_write(path, ID128_FORMAT_UUID, rnd, false);
+ r = id128_write(path, ID128_FORMAT_UUID, rnd);
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c
index 787c0765d0..f82a292ea3 100644
--- a/src/shared/machine-id-setup.c
+++ b/src/shared/machine-id-setup.c
@@ -152,7 +152,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
if (r < 0)
return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
} else {
- r = id128_write_fd(fd, ID128_FORMAT_PLAIN, machine_id, true);
+ r = id128_write_fd(fd, ID128_FORMAT_PLAIN | ID128_SYNC_ON_WRITE, machine_id);
if (r < 0)
return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
else
@@ -168,7 +168,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0022)
- r = id128_write(run_machine_id, ID128_FORMAT_PLAIN, machine_id, false);
+ r = id128_write(run_machine_id, ID128_FORMAT_PLAIN, machine_id);
if (r < 0) {
(void) unlink(run_machine_id);
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
@@ -261,7 +261,7 @@ int machine_id_commit(const char *root) {
return r;
/* Update a persistent version of etc_machine_id */
- r = id128_write(etc_machine_id, ID128_FORMAT_PLAIN, id, true);
+ r = id128_write(etc_machine_id, ID128_FORMAT_PLAIN | ID128_SYNC_ON_WRITE, id);
if (r < 0)
return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index dccf3b7fb9..6de0cec426 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -86,7 +86,7 @@ TEST(id128) {
/* First, write as UUID */
assert_se(sd_id128_randomize(&id) >= 0);
- assert_se(id128_write_fd(fd, ID128_FORMAT_UUID, id, false) >= 0);
+ assert_se(id128_write_fd(fd, ID128_FORMAT_UUID, id) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
@@ -104,7 +104,7 @@ TEST(id128) {
assert_se(ftruncate(fd, 0) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
- assert_se(id128_write_fd(fd, ID128_FORMAT_PLAIN, id, false) >= 0);
+ assert_se(id128_write_fd(fd, ID128_FORMAT_PLAIN, id) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);

@ -0,0 +1,229 @@
From db28b72d475c4e9bbd14286c9ca9366e339dfa28 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 14 Dec 2022 14:31:09 +0900
Subject: [PATCH] sd-id128: make sd_id128_get_machine() or friends return
-EUCLEAN when an ID is in an invalid format
EINVAL suggests that the caller passes an invalid argument. EIO is
for "input/output error", i.e. the error you'd get if the disk or
file system is borked, and this error code could be returned by the
underlying read/write functions.
Let's make the functions return an unambiguous error code.
(cherry picked from commit e8a6625422db9d5598b6d640a9f4eec68921ce3d)
Related: RHEL-27512
---
man/sd_id128_get_machine.xml | 2 +-
src/libsystemd/sd-id128/id128-util.c | 16 +++++++++-------
src/libsystemd/sd-id128/sd-id128.c | 18 ++++++++++--------
src/test/test-id128.c | 12 ++++++------
4 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index dbc6d4885d..4f6926fd7d 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -166,7 +166,7 @@
</varlistentry>
<varlistentry>
- <term><constant>-EIO</constant></term>
+ <term><constant>-EUCLEAN</constant></term>
<listitem><para>Returned by any of the functions described here when the configured value has
invalid format.</para></listitem>
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index faacc55960..364df6a9c8 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -43,6 +43,7 @@ bool id128_is_valid(const char *s) {
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
ssize_t l;
+ int r;
assert(fd >= 0);
@@ -54,7 +55,7 @@ int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
* This returns the following:
* -ENOMEDIUM: an empty string,
* -ENOPKG: "uninitialized" or "uninitialized\n",
- * -EINVAL: other invalid strings. */
+ * -EUCLEAN: other invalid strings. */
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
if (l < 0)
@@ -70,33 +71,34 @@ int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
if (buffer[SD_ID128_STRING_MAX-1] != '\n')
- return -EINVAL;
+ return -EUCLEAN;
_fallthrough_;
case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
- return -EINVAL;
+ return -EUCLEAN;
buffer[SD_ID128_STRING_MAX-1] = 0;
break;
case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
- return -EINVAL;
+ return -EUCLEAN;
_fallthrough_;
case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
if (!FLAGS_SET(f, ID128_FORMAT_UUID))
- return -EINVAL;
+ return -EUCLEAN;
buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
break;
default:
- return -EINVAL;
+ return -EUCLEAN;
}
- return sd_id128_from_string(buffer, ret);
+ r = sd_id128_from_string(buffer, ret);
+ return r == -EINVAL ? -EUCLEAN : r;
}
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index b3f4728988..b2f0438edf 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -207,22 +207,22 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Chop off the final description string */
d = strrchr(description, ';');
if (!d)
- return -EIO;
+ return -EUCLEAN;
*d = 0;
/* Look for the permissions */
p = strrchr(description, ';');
if (!p)
- return -EIO;
+ return -EUCLEAN;
errno = 0;
perms = strtoul(p + 1, &e, 16);
if (errno > 0)
return -errno;
if (e == p + 1) /* Read at least one character */
- return -EIO;
+ return -EUCLEAN;
if (e != d) /* Must reached the end */
- return -EIO;
+ return -EUCLEAN;
if ((perms & ~MAX_PERMS) != 0)
return -EPERM;
@@ -232,7 +232,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Look for the group ID */
g = strrchr(description, ';');
if (!g)
- return -EIO;
+ return -EUCLEAN;
r = parse_gid(g + 1, &gid);
if (r < 0)
return r;
@@ -243,7 +243,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Look for the user ID */
u = strrchr(description, ';');
if (!u)
- return -EIO;
+ return -EUCLEAN;
r = parse_uid(u + 1, &uid);
if (r < 0)
return r;
@@ -254,13 +254,14 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (c < 0)
return -errno;
if (c != sizeof(sd_id128_t))
- return -EIO;
+ return -EUCLEAN;
return 0;
}
static int get_invocation_from_environment(sd_id128_t *ret) {
const char *e;
+ int r;
assert(ret);
@@ -268,7 +269,8 @@ static int get_invocation_from_environment(sd_id128_t *ret) {
if (!e)
return -ENXIO;
- return sd_id128_from_string(e, ret);
+ r = sd_id128_from_string(e, ret);
+ return r == -EINVAL ? -EUCLEAN : r;
}
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 6de0cec426..b7a9b03403 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -89,7 +89,7 @@ TEST(id128) {
assert_se(id128_write_fd(fd, ID128_FORMAT_UUID, id) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EUCLEAN);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
@@ -107,7 +107,7 @@ TEST(id128) {
assert_se(id128_write_fd(fd, ID128_FORMAT_PLAIN, id) >= 0);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EUCLEAN);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
@@ -125,7 +125,7 @@ TEST(id128) {
assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EUCLEAN);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
@@ -139,7 +139,7 @@ TEST(id128) {
assert_se(write(fd, sd_id128_to_uuid_string(id, q), 36) == 36);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EUCLEAN);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
@@ -162,13 +162,13 @@ TEST(id128) {
assert_se(ftruncate(fd, 0) >= 0);
assert_se(write(fd, "uninitialized\nfoo", STRLEN("uninitialized\nfoo")) == STRLEN("uninitialized\nfoo"));
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EUCLEAN);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(ftruncate(fd, 0) >= 0);
assert_se(write(fd, "uninit", STRLEN("uninit")) == STRLEN("uninit"));
assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
+ assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EUCLEAN);
if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0);

@ -0,0 +1,90 @@
From 4af87f4d0643fa243aa1fd8e5c52cc5d4fbdd187 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 14 Dec 2022 13:34:15 +0900
Subject: [PATCH] sd-id128: allow sd_id128_get_machine() and friend to be
called with NULL
It may be useful to check if the machine ID or friends is set or not.
(cherry picked from commit 786b652c8989834f9218ec82b2d824d5b753fad3)
Related: RHEL-27512
---
src/libsystemd/sd-id128/sd-id128.c | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index b2f0438edf..dee0df2396 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -125,8 +125,6 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_machine_id)) {
r = id128_read("/etc/machine-id", ID128_FORMAT_PLAIN, &saved_machine_id);
if (r < 0)
@@ -136,7 +134,8 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
return -ENOMEDIUM;
}
- *ret = saved_machine_id;
+ if (ret)
+ *ret = saved_machine_id;
return 0;
}
@@ -144,8 +143,6 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_boot_id)) {
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
if (r == -ENOENT && proc_mounted() == 0)
@@ -157,7 +154,8 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
return -ENOMEDIUM;
}
- *ret = saved_boot_id;
+ if (ret)
+ *ret = saved_boot_id;
return 0;
}
@@ -277,26 +275,20 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
static thread_local sd_id128_t saved_invocation_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_invocation_id)) {
/* We first check the environment. The environment variable is primarily relevant for user
* services, and sufficiently safe as long as no privilege boundary is involved. */
r = get_invocation_from_environment(&saved_invocation_id);
- if (r >= 0) {
- *ret = saved_invocation_id;
- return 0;
- } else if (r != -ENXIO)
- return r;
-
- /* The kernel keyring is relevant for system services (as for user services we don't store
- * the invocation ID in the keyring, as there'd be no trust benefit in that). */
- r = get_invocation_from_keyring(&saved_invocation_id);
+ if (r == -ENXIO)
+ /* The kernel keyring is relevant for system services (as for user services we don't
+ * store the invocation ID in the keyring, as there'd be no trust benefit in that). */
+ r = get_invocation_from_keyring(&saved_invocation_id);
if (r < 0)
return r;
}
- *ret = saved_invocation_id;
+ if (ret)
+ *ret = saved_invocation_id;
return 0;
}

@ -0,0 +1,41 @@
From e9054375028335ef1e2946b80d9765f8e69cbb9c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 14 Dec 2022 13:40:42 +0900
Subject: [PATCH] sd-id128: also refuse an empty invocation ID
(cherry picked from commit 75fa1f25c08a4b5dc2180893718473be9e4f6bab)
Related: RHEL-27512
---
man/sd_id128_get_machine.xml | 3 ++-
src/libsystemd/sd-id128/sd-id128.c | 3 +++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 4f6926fd7d..075caffb2b 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -139,7 +139,8 @@
<listitem><para>Returned by <function>sd_id128_get_machine()</function> and
<function>sd_id128_get_machine_app_specific()</function> when <filename>/etc/machine-id</filename>
- is empty or all zeros.</para></listitem>
+ is empty or all zeros. Also returned by <function>sd_id128_get_invocation()</function> when the
+ invocation ID is all zeros.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index dee0df2396..ec53617fce 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -285,6 +285,9 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
r = get_invocation_from_keyring(&saved_invocation_id);
if (r < 0)
return r;
+
+ if (sd_id128_is_null(saved_invocation_id))
+ return -ENOMEDIUM;
}
if (ret)

@ -0,0 +1,41 @@
From 6715fc716fc843c3877160a8220af935c159e789 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 14 Dec 2022 14:29:25 +0900
Subject: [PATCH] man: update documents for sd_id128_get_invocation()
(cherry picked from commit f0d8358c245b4d0012d8db52dbf42bdebbe1b2bc)
Related: RHEL-27512
---
man/sd_id128_get_machine.xml | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 075caffb2b..cdab87ab63 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -94,10 +94,20 @@
has properties similar to the machine ID during that time.</para>
<para><function>sd_id128_get_invocation()</function> returns the invocation ID of the currently executed
- service. In its current implementation, this reads and parses the <varname>$INVOCATION_ID</varname> environment
- variable that the service manager sets when activating a service, see
- <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. The
- ID is cached internally. In future a different mechanism to determine the invocation ID may be added.</para>
+ service. In its current implementation, this tries to read and parse the following:
+ <itemizedlist>
+ <listitem>
+ <para>The <varname>$INVOCATION_ID</varname> environment variable that the service manager sets when
+ activating a service.</para>
+ </listitem>
+ <listitem>
+ <para>An entry in the kernel keyring that the system service manager sets when activating a service.
+ </para>
+ </listitem>
+ </itemizedlist>
+ See <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details. The ID is cached internally. In future a different mechanism to determine the invocation ID
+ may be added.</para>
<para>Note that <function>sd_id128_get_machine_app_specific()</function>,
<function>sd_id128_get_boot()</function>, <function>sd_id128_get_boot_app_specific()</function>, and

@ -0,0 +1,48 @@
From b54eb7dbdad4135fdcf846f6087ca29b6164b60b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 27 Feb 2024 16:03:10 +0100
Subject: [PATCH] test-id128: simplify machine-id check
This also ensures that the test is skipped when /etc/machine-id exists,
but is not initialized.
(cherry picked from commit 415eb50570744daf2257fc6fc96e2d5750532785)
Related: RHEL-27512
---
src/test/test-id128.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index b7a9b03403..afdbf1e4b9 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -38,7 +38,7 @@ TEST(id128) {
assert_se(!sd_id128_in_set(id, ID128_WALDI));
assert_se(!sd_id128_in_set(id, ID128_WALDI, ID128_WALDI));
- if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {
+ if (sd_booted() > 0 && sd_id128_get_machine(NULL) >= 0) {
assert_se(sd_id128_get_machine(&id) == 0);
printf("machine: %s\n", sd_id128_to_string(id, t));
@@ -170,7 +170,7 @@ TEST(id128) {
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EUCLEAN);
- if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {
+ if (sd_booted() > 0 && sd_id128_get_machine(NULL) >= 0) {
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0);
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
@@ -195,8 +195,8 @@ TEST(benchmark_sd_id128_get_machine_app_specific) {
unsigned iterations = slow_tests_enabled() ? 1000000 : 1000;
usec_t t, q;
- if (access("/etc/machine-id", F_OK) < 0 && errno == ENOENT)
- return (void) log_tests_skipped("/etc/machine-id does not exist");
+ if (sd_id128_get_machine(NULL) < 0)
+ return (void) log_tests_skipped("/etc/machine-id is not initialized");
log_info("/* %s (%u iterations) */", __func__, iterations);

@ -0,0 +1,30 @@
From 70754f42db910937021c74f85adba277c7db88a9 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Mon, 12 Dec 2022 14:37:52 -0500
Subject: [PATCH] test-fs-util: skip part of test_chase_symlinks if machine-id
is not initialized
The part of test_chase_symlink in test-fs-util that calls
sd_id128_get_machine will fail if /etc/machine-id is empty, so skip this
block if the machine-id is not initialized.
(cherry picked from commit 079fcdd04f57bfb1e333fea853e050c99eb16e02)
Related: RHEL-27512
---
src/test/test-fs-util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 0b1f11ebdf..ff248c1a9c 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -292,7 +292,7 @@ TEST(chase_symlinks) {
assert_se(symlink("/usr/../etc/./machine-id", p) >= 0);
r = chase_symlinks(p, NULL, 0, NULL, &pfd);
- if (r != -ENOENT) {
+ if (r != -ENOENT && sd_id128_get_machine(NULL) >= 0) {
_cleanup_close_ int fd = -1;
sd_id128_t a, b;

@ -0,0 +1,34 @@
From 1358081487650f718ad84b26313bcc16a3093e04 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Tue, 13 Dec 2022 12:22:37 -0500
Subject: [PATCH] test-unit-name: simplify machine-id check
(cherry picked from commit a635b6279cf35abad3abe169780ec899df9396df)
Related: RHEL-27512
---
src/test/test-unit-name.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index eec4831b4e..1e230ba5f9 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include "sd-id128.h"
+
#include "alloc-util.h"
#include "all-units.h"
#include "glob-util.h"
@@ -264,7 +266,7 @@ TEST_RET(unit_printf, .sd_booted = true) {
assert_se(short_hostname);
assert_se(specifier_pretty_hostname('q', NULL, NULL, NULL, &pretty_hostname) == 0);
assert_se(pretty_hostname);
- if (access("/etc/machine-id", F_OK) >= 0) {
+ if (sd_id128_get_machine(NULL) >= 0) {
assert_se(specifier_machine_id('m', NULL, NULL, NULL, &machine_id) >= 0);
assert_se(machine_id);
}

@ -0,0 +1,34 @@
From 5447ec5233b3079075dfac92ae3decf38f845e0e Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Tue, 13 Dec 2022 12:25:35 -0500
Subject: [PATCH] test-load-fragment: simplify machine-id check
(cherry picked from commit 2c6b738badf1404b3ceb7e322eeeb736b57f6162)
Related: RHEL-27512
---
src/test/test-load-fragment.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c
index 3cf704134c..997c2b2524 100644
--- a/src/test/test-load-fragment.c
+++ b/src/test/test-load-fragment.c
@@ -5,6 +5,8 @@
#include <stdio.h>
#include <unistd.h>
+#include "sd-id128.h"
+
#include "all-units.h"
#include "alloc-util.h"
#include "capability-util.h"
@@ -518,7 +520,7 @@ TEST(install_printf, .sd_booted = true) {
_cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL;
- if (access("/etc/machine-id", F_OK) >= 0)
+ if (sd_id128_get_machine(NULL) >= 0)
assert_se(specifier_machine_id('m', NULL, NULL, NULL, &mid) >= 0 && mid);
if (sd_booted() > 0)
assert_se(specifier_boot_id('b', NULL, NULL, NULL, &bid) >= 0 && bid);

@ -0,0 +1,75 @@
From 528e1178026b3f567139c994ce89992379618d2e Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Wed, 14 Dec 2022 10:07:40 -0500
Subject: [PATCH] journal: skip part of test-journal-interleaving if no
machine-id exists
When executed on a systemd with an empty /etc/machine-id,
test-journal-interleaving fails in test_sequence_numbers_one() when
re-opening the existing "two.journal". This is because opening the
existing journal file with managed_journal_file_open() causes
journal_file_verify_header() to be called. This function tries to
compare the current machine-id to the machine-id in the journal file
header, but does not handle the case where the machine-id is empty or
non-existent.
Check if we have an initialized machine-id before executing this portion
of the test.
(cherry picked from commit 3a9ca230363e6d1063a789492005d744723f5eed)
Related: RHEL-27512
---
src/journal/test-journal-interleaving.c | 27 +++++++++++++++----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index fb38cc7e82..e05eae034b 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -3,6 +3,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "sd-id128.h"
#include "sd-journal.h"
#include "alloc-util.h"
@@ -263,22 +264,26 @@ static void test_sequence_numbers_one(void) {
test_close(one);
- /* restart server */
- seqnum = 0;
+ /* If the machine-id is not initialized, the header file verification
+ * (which happens when re-opening a journal file) will fail. */
+ if (sd_id128_get_machine(NULL) >= 0) {
+ /* restart server */
+ seqnum = 0;
- assert_se(managed_journal_file_open(-1, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
- UINT64_MAX, NULL, m, NULL, NULL, &two) == 0);
+ assert_se(managed_journal_file_open(-1, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
+ UINT64_MAX, NULL, m, NULL, NULL, &two) == 0);
- assert_se(sd_id128_equal(two->file->header->seqnum_id, seqnum_id));
+ assert_se(sd_id128_equal(two->file->header->seqnum_id, seqnum_id));
- append_number(two, 7, &seqnum);
- printf("seqnum=%"PRIu64"\n", seqnum);
- assert_se(seqnum == 5);
+ append_number(two, 7, &seqnum);
+ printf("seqnum=%"PRIu64"\n", seqnum);
+ assert_se(seqnum == 5);
- /* So..., here we have the same seqnum in two files with the
- * same seqnum_id. */
+ /* So..., here we have the same seqnum in two files with the
+ * same seqnum_id. */
- test_close(two);
+ test_close(two);
+ }
log_info("Done...");

@ -0,0 +1,111 @@
From 80b1fd81ec483b57444572f957e38b5fea5b3db6 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 27 Feb 2024 16:10:37 +0100
Subject: [PATCH] test: skip journal tests without valid /etc/machine-id
The journal stuff in RHEL 9 can't handle existing but uninitialized
/etc/machine-id and backporting all the necessary changes would mean
pulling in another 50+ commits (I stopped after 50, so it's probably
much more). And to make matters worse, upstream renamed
chase_symlinks*() stuff to chase_*(), which makes the backports even
more painful (and risky).
Related PRs:
- https://github.com/systemd/systemd/pull/25734/commits
- https://github.com/systemd/systemd/pull/27137/commits
- https://github.com/systemd/systemd/pull/27122/commits
RHEL-only
Related: RHEL-27512
---
src/journal/test-journal-flush.c | 14 +++++++++++++-
src/journal/test-journal-interleaving.c | 2 +-
src/journal/test-journal-stream.c | 2 +-
src/journal/test-journal-verify.c | 4 ++++
src/journal/test-journal.c | 2 +-
5 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
index 2a5f7fad5e..4b52544e7f 100644
--- a/src/journal/test-journal-flush.c
+++ b/src/journal/test-journal-flush.c
@@ -16,6 +16,8 @@
#include "string-util.h"
#include "tests.h"
+static bool arg_keep = false;
+
static void test_journal_flush_one(int argc, char *argv[]) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
_cleanup_free_ char *fn = NULL;
@@ -117,4 +119,14 @@ TEST(journal_flush_compact) {
test_journal_flush_one(saved_argc, saved_argv);
}
-DEFINE_TEST_MAIN(LOG_INFO);
+static int intro(void) {
+ arg_keep = saved_argc > 1;
+
+ /* managed_journal_file_open requires a valid machine id */
+ if (sd_id128_get_machine(NULL) < 0)
+ return log_tests_skipped("/etc/machine-id not found");
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index e05eae034b..56b2489277 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -306,7 +306,7 @@ TEST(sequence_numbers) {
static int intro(void) {
/* managed_journal_file_open requires a valid machine id */
- if (access("/etc/machine-id", F_OK) != 0)
+ if (sd_id128_get_machine(NULL) < 0)
return log_tests_skipped("/etc/machine-id not found");
arg_keep = saved_argc > 1;
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index ac5b7f0005..fe4bc40eaa 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -179,7 +179,7 @@ static void run_test(void) {
int main(int argc, char *argv[]) {
/* managed_journal_file_open requires a valid machine id */
- if (access("/etc/machine-id", F_OK) != 0)
+ if (sd_id128_get_machine(NULL) < 0)
return log_tests_skipped("/etc/machine-id not found");
test_setup_logging(LOG_DEBUG);
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index e36ea8cae1..55be7f451b 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -143,6 +143,10 @@ static int run_test(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
+ /* managed_journal_file_open requires a valid machine id */
+ if (sd_id128_get_machine(NULL) < 0)
+ return log_tests_skipped("/etc/machine-id not found");
+
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
run_test(argc, argv);
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 889673cae7..99beb671c5 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -271,7 +271,7 @@ static int intro(void) {
arg_keep = saved_argc > 1;
/* managed_journal_file_open requires a valid machine id */
- if (access("/etc/machine-id", F_OK) != 0)
+ if (sd_id128_get_machine(NULL) < 0)
return log_tests_skipped("/etc/machine-id not found");
return EXIT_SUCCESS;

@ -0,0 +1,61 @@
From 36b71213e9f734fbf5ab3b032f61614c79737dac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 19 Oct 2023 16:46:56 +0200
Subject: [PATCH] test-recurse-dir: work around nftw() ignoring symlinks()
We have a test where we compare the results from nftw() and our own
resurce_dit_at(). nftw() skips a dangling symlink when running under mkosi and
the test fails. I don't understand why nftw() does that, but in our code we
don't need to test and care about the details of nftw(), which we don't use,
outside of the one test, so let's just skip symlinks in the test.
Closes #29603.
(cherry picked from commit 974959e6f6352b76355b76ab550c0e729b2a8c21)
Related: RHEL-27512
---
src/test/test-recurse-dir.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/test/test-recurse-dir.c b/src/test/test-recurse-dir.c
index 2c2120b136..c194896a1b 100644
--- a/src/test/test-recurse-dir.c
+++ b/src/test/test-recurse-dir.c
@@ -26,8 +26,7 @@ static int nftw_cb(
break;
case FTW_SL:
- log_debug("ftw found symlink %s", fpath);
- assert_se(strv_extendf(&list_nftw, "%s→", fpath) >= 0);
+ log_debug("ftw found symlink %s, ignoring.", fpath);
break;
case FTW_D:
@@ -71,11 +70,10 @@ static int recurse_dir_callback(
case RECURSE_DIR_ENTRY:
assert_se(!IN_SET(de->d_type, DT_UNKNOWN, DT_DIR));
- log_debug("found %s", path);
+ log_debug("found %s%s", path,
+ de->d_type == DT_LNK ? ", ignoring." : "");
- if (de->d_type == DT_LNK)
- assert_se(strv_extendf(l, "%s→", path) >= 0);
- else
+ if (de->d_type != DT_LNK)
assert_se(strv_extend(l, path) >= 0);
break;
@@ -131,7 +129,10 @@ int main(int argc, char *argv[]) {
else
p = "/usr/share/man"; /* something hopefully reasonably stable while we run (and limited in size) */
- /* Enumerate the specified dirs in full, once via nftw(), and once via recurse_dir(), and ensure the results are identical */
+ /* Enumerate the specified dirs in full, once via nftw(), and once via recurse_dir(), and ensure the
+ * results are identical. nftw() sometimes skips symlinks (see
+ * https://github.com/systemd/systemd/issues/29603), so ignore them to avoid bogus errors. */
+
t1 = now(CLOCK_MONOTONIC);
r = recurse_dir_at(AT_FDCWD, p, 0, UINT_MAX, RECURSE_DIR_SORT|RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_SAME_MOUNT, recurse_dir_callback, &list_recurse_dir);
t2 = now(CLOCK_MONOTONIC);

@ -0,0 +1,70 @@
From d4290244c49c6cc341225151cf0dfd5329dde943 Mon Sep 17 00:00:00 2001
From: Richard Maw <richard.maw@codethink.co.uk>
Date: Wed, 25 Oct 2023 18:12:58 +0100
Subject: [PATCH] test: Skip test-recurse-dir on overlayfs
(cherry picked from commit 31cfcf50088b69c973b9335a2383fa6502d90419)
Related: RHEL-27512
---
src/test/test-recurse-dir.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/test/test-recurse-dir.c b/src/test/test-recurse-dir.c
index c194896a1b..3e42526679 100644
--- a/src/test/test-recurse-dir.c
+++ b/src/test/test-recurse-dir.c
@@ -2,7 +2,9 @@
#include <ftw.h>
+#include "fd-util.h"
#include "log.h"
+#include "missing_magic.h"
#include "recurse-dir.h"
#include "strv.h"
#include "tests.h"
@@ -119,7 +121,7 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **list_recurse_dir = NULL;
const char *p;
usec_t t1, t2, t3, t4;
- int r;
+ _cleanup_close_ int fd = -EBADF;
log_show_color(true);
test_setup_logging(LOG_INFO);
@@ -129,18 +131,28 @@ int main(int argc, char *argv[]) {
else
p = "/usr/share/man"; /* something hopefully reasonably stable while we run (and limited in size) */
+ fd = open(p, O_DIRECTORY|O_CLOEXEC);
+ if (fd < 0 && errno == ENOENT) {
+ log_warning_errno(errno, "Couldn't open directory %s, ignoring: %m", p);
+ return EXIT_TEST_SKIP;
+ }
+ assert_se(fd >= 0);
+
+ /* If the test directory is on an overlayfs then files and their direcory may return different st_dev
+ * in stat results, which confuses nftw into thinking they're on different filesystems
+ * and won't return the result when the FTW_MOUNT flag is set. */
+ if (fd_is_fs_type(fd, OVERLAYFS_SUPER_MAGIC)) {
+ log_tests_skipped("nftw mountpoint detection produces false-positives on overlayfs");
+ return EXIT_TEST_SKIP;
+ }
+
/* Enumerate the specified dirs in full, once via nftw(), and once via recurse_dir(), and ensure the
* results are identical. nftw() sometimes skips symlinks (see
* https://github.com/systemd/systemd/issues/29603), so ignore them to avoid bogus errors. */
t1 = now(CLOCK_MONOTONIC);
- r = recurse_dir_at(AT_FDCWD, p, 0, UINT_MAX, RECURSE_DIR_SORT|RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_SAME_MOUNT, recurse_dir_callback, &list_recurse_dir);
+ assert_se(recurse_dir(fd, p, 0, UINT_MAX, RECURSE_DIR_SORT|RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_SAME_MOUNT, recurse_dir_callback, &list_recurse_dir) >= 0);
t2 = now(CLOCK_MONOTONIC);
- if (r == -ENOENT) {
- log_warning_errno(r, "Couldn't open directory %s, ignoring: %m", p);
- return EXIT_TEST_SKIP;
- }
- assert_se(r >= 0);
t3 = now(CLOCK_MONOTONIC);
assert_se(nftw(p, nftw_cb, 64, FTW_PHYS|FTW_MOUNT) >= 0);

@ -0,0 +1,28 @@
From 62cbc9f00697003069f1c263c0ab3361f0ea4b6a Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Sat, 6 May 2023 11:33:22 +0200
Subject: [PATCH] test-specifier: Ignore -ENOPKG from specifier_printf()
If /etc/machine-id contains "uninitialized", specifier_printf() with
%m will fail with ENOPKG, so ignore that error as well.
(cherry picked from commit 7429c8fe57bef84c3ff6ebd94b560356752af0bc)
Related: RHEL-27512
---
src/test/test-specifier.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c
index 4a8ff4bd10..d0adc1a87d 100644
--- a/src/test/test-specifier.c
+++ b/src/test/test-specifier.c
@@ -136,7 +136,7 @@ TEST(specifiers) {
xsprintf(spec, "%%%c", s->specifier);
r = specifier_printf(spec, SIZE_MAX, specifier_table, NULL, NULL, &resolved);
- if (s->specifier == 'm' && IN_SET(r, -ENOENT, -ENOMEDIUM)) /* machine-id might be missing in build chroots */
+ if (s->specifier == 'm' && IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG)) /* machine-id might be missing in build chroots */
continue;
assert_se(r >= 0);

@ -0,0 +1,29 @@
From db9c5f759c7c4163d9de1db398b72ef01abaec24 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Wed, 25 Jan 2023 09:39:13 +0100
Subject: [PATCH] test-execute: Skip when /sys is read-only
The test depends on /sys being writable, so let's skip it when /sys
is read-only.
(cherry picked from commit 34b5977015a557840988e825ac116a7f09d0be75)
Related: RHEL-27512
---
src/test/test-execute.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 0283caeca6..ce3489d708 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1228,6 +1228,9 @@ int main(int argc, char *argv[]) {
if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available");
+ if (path_is_read_only_fs("/sys") > 0)
+ return log_tests_skipped("/sys is mounted read-only");
+
_cleanup_free_ char *unit_dir = NULL, *unit_paths = NULL;
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());

@ -0,0 +1,25 @@
From bc68683e1ed1579718291a74edc7c6406ce078a0 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 31 Jul 2023 20:58:31 +0200
Subject: [PATCH] kernel-install: Make sure KERNEL_INSTALL_BYPASS is disabled
in tests
(cherry picked from commit 4435da1f1732e2078e42b0ee43ad56fde2b021a3)
Related: RHEL-27512
---
src/kernel-install/test-kernel-install.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/kernel-install/test-kernel-install.sh b/src/kernel-install/test-kernel-install.sh
index 2e44063668..3b9ff76e60 100755
--- a/src/kernel-install/test-kernel-install.sh
+++ b/src/kernel-install/test-kernel-install.sh
@@ -32,6 +32,7 @@ export KERNEL_INSTALL_CONF_ROOT="$D/sources"
export KERNEL_INSTALL_PLUGINS="$plugin"
export BOOT_ROOT="$D/boot"
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
+export KERNEL_INSTALL_BYPASS="no"
"$kernel_install" -v add 1.1.1 "$D/sources/linux" "$D/sources/initrd"

@ -0,0 +1,42 @@
From d2fcb75822d85a1516bca2fc2e87e1d94d7691c3 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 27 Feb 2024 16:59:23 +0100
Subject: [PATCH] tools: make sure $KERNEL_INSTALL_BYPASS is disabled when
checking help
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Upstream mkosi sets $KERNEL_INSTALL_BYPASS to 1 by default [0] which
then trip over check-help tests, as the message about
$KERNEL_INSTALL_BYPASS is not printed out to stderr. Upstream systemd
doesn't have this issue, since kernel-install there was rewritten in C,
so the code base is completely different.
1068/1073 systemd:dist-check / check-help-kernel-install FAIL 0.02s exit status 4
>>> MALLOC_PERTURB_=212 /work/src/tools/check-help.sh /work/build/kernel-install
――――――――――――――――――――――――――――――――――――― ✀ ―――――――――――――――――――――――――――――――――――――
kernel-install with an unknown parameter does not print to stderr
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
[0] https://github.com/systemd/mkosi/commit/deaaa831d4379ef400ffdc5f71bc0eabed072044
RHEL-only
Related: RHEL-27512
---
tools/check-help.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/check-help.sh b/tools/check-help.sh
index f97429364e..2f062a7515 100755
--- a/tools/check-help.sh
+++ b/tools/check-help.sh
@@ -9,6 +9,7 @@ set -o pipefail
BINARY="${1:?}"
export SYSTEMD_LOG_LEVEL=info
+export KERNEL_INSTALL_BYPASS="no"
if [[ ! -x "$BINARY" ]]; then
echo "$BINARY is not an executable"

@ -0,0 +1,888 @@
From bdde465ad1df52cb9b9fbaab37d5d7541601d774 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Feb 2023 12:28:31 +0900
Subject: [PATCH] test-execute: drop capabilities when testing with user
manager
Before this, tests are split into two categories, system and user, but
both are running in fully privileged environment. Hence, unprivileged
user scope was mostly not covered by the test.
Let's run all tests in both system and user scopes, and drop capabilities
when Manager is running in user scope.
This also makes the host environment protected more from the test run.
(cherry picked from commit 4e032f654b94c2544ccf937209303766dfa66c24)
Related: RHEL-27512
---
src/test/test-execute.c | 351 +++++++++++-------
...dynamicuser-statedir-migrate-step1.service | 16 +-
...dynamicuser-statedir-migrate-step2.service | 32 +-
.../exec-dynamicuser-statedir.service | 122 +++---
.../exec-privatenetwork-yes.service | 1 +
.../exec-specifier-system.service | 11 +
test/test-execute/exec-specifier-user.service | 11 +
test/test-execute/exec-specifier.service | 5 -
test/test-execute/exec-specifier@.service | 5 -
9 files changed, 333 insertions(+), 221 deletions(-)
create mode 100644 test/test-execute/exec-specifier-system.service
create mode 100644 test/test-execute/exec-specifier-user.service
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index ce3489d708..665ae8a833 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
+#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/types.h>
@@ -18,6 +19,7 @@
#include "manager.h"
#include "missing_prctl.h"
#include "mkdir.h"
+#include "mount-util.h"
#include "path-util.h"
#include "process-util.h"
#include "rm-rf.h"
@@ -35,6 +37,8 @@
#include "util.h"
#include "virt.h"
+#define PRIVATE_UNIT_DIR "/run/test-execute-unit-dir"
+
static char *user_runtime_unit_dir = NULL;
static bool can_unshare;
@@ -414,7 +418,7 @@ static void test_exec_privatedevices(Manager *m) {
test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
- test(m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+ test(m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_FAILURE : EXIT_GROUP, CLD_EXITED);
/* We use capsh to test if the capabilities are
* properly set, so be sure that it exists */
@@ -425,9 +429,9 @@ static void test_exec_privatedevices(Manager *m) {
}
test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
+ test(m, "exec-privatedevices-no-capability-mknod.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
+ test(m, "exec-privatedevices-no-capability-sys-rawio.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_protecthome(Manager *m) {
@@ -457,7 +461,7 @@ static void test_exec_protectkernelmodules(Manager *m) {
return;
}
- test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
+ test(m, "exec-protectkernelmodules-no-capabilities.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
@@ -778,7 +782,7 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
+ test(m, "exec-systemcallfilter-system-user.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -790,12 +794,12 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
#endif
}
static void test_exec_user(Manager *m) {
- test(m, "exec-user.service", 0, CLD_EXITED);
+ test(m, "exec-user.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -807,11 +811,11 @@ static void test_exec_user(Manager *m) {
return;
}
- test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(m, "exec-user-" NOBODY_USER_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_group(Manager *m) {
- test(m, "exec-group.service", 0, CLD_EXITED);
+ test(m, "exec-group.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -823,16 +827,17 @@ static void test_exec_group(Manager *m) {
return;
}
- test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+ test(m, "exec-group-" NOBODY_GROUP_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_supplementarygroups(Manager *m) {
- test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
+ int status = MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP;
+ test(m, "exec-supplementarygroups.service", status, CLD_EXITED);
+ test(m, "exec-supplementarygroups-single-group.service", status, CLD_EXITED);
+ test(m, "exec-supplementarygroups-single-group-user.service", status, CLD_EXITED);
+ test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", status, CLD_EXITED);
+ test(m, "exec-supplementarygroups-multiple-groups-withgid.service", status, CLD_EXITED);
+ test(m, "exec-supplementarygroups-multiple-groups-withuid.service", status, CLD_EXITED);
}
static char* private_directory_bad(Manager *m) {
@@ -864,14 +869,16 @@ static void test_exec_dynamicuser(Manager *m) {
return;
}
- test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ int status = can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NAMESPACE : EXIT_GROUP;
+
+ test(m, "exec-dynamicuser-fixeduser.service", status, CLD_EXITED);
if (check_user_has_group_with_same_name("adm"))
- test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-adm.service", status, CLD_EXITED);
if (check_user_has_group_with_same_name("games"))
- test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
- test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
- test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-games.service", status, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", status, CLD_EXITED);
+ test(m, "exec-dynamicuser-supplementarygroups.service", status, CLD_EXITED);
+ test(m, "exec-dynamicuser-statedir.service", status, CLD_EXITED);
(void) rm_rf("/var/lib/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -883,7 +890,7 @@ static void test_exec_dynamicuser(Manager *m) {
(void) rm_rf("/var/lib/private/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-statedir-migrate-step2.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -891,9 +898,9 @@ static void test_exec_dynamicuser(Manager *m) {
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
- test(m, "exec-dynamicuser-runtimedirectory1.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
- test(m, "exec-dynamicuser-runtimedirectory2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
- test(m, "exec-dynamicuser-runtimedirectory3.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-runtimedirectory1.service", status, CLD_EXITED);
+ test(m, "exec-dynamicuser-runtimedirectory2.service", status, CLD_EXITED);
+ test(m, "exec-dynamicuser-runtimedirectory3.service", status, CLD_EXITED);
}
static void test_exec_environment(Manager *m) {
@@ -959,9 +966,12 @@ static void test_exec_umask(Manager *m) {
}
static void test_exec_runtimedirectory(Manager *m) {
+ (void) rm_rf("/run/test-exec_runtimedirectory2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
+ (void) rm_rf("/run/test-exec_runtimedirectory2", REMOVE_ROOT|REMOVE_PHYSICAL);
+
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
- test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ test(m, "exec-runtimedirectory-owner.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -973,7 +983,7 @@ static void test_exec_runtimedirectory(Manager *m) {
return;
}
- test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+ test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_capabilityboundingset(Manager *m) {
@@ -1047,7 +1057,7 @@ static void test_exec_privatenetwork(Manager *m) {
return;
}
- test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
+ test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NETWORK : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_oomscoreadjust(Manager *m) {
@@ -1057,7 +1067,7 @@ static void test_exec_oomscoreadjust(Manager *m) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+ test(m, "exec-oomscoreadjust-negative.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
@@ -1069,7 +1079,7 @@ static void test_exec_ioschedulingclass(Manager *m) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-realtime.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_IOPRIO, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {
@@ -1078,9 +1088,13 @@ static void test_exec_unsetenvironment(Manager *m) {
static void test_exec_specifier(Manager *m) {
test(m, "exec-specifier.service", 0, CLD_EXITED);
+ if (MANAGER_IS_SYSTEM(m))
+ test(m, "exec-specifier-system.service", 0, CLD_EXITED);
+ else
+ test(m, "exec-specifier-user.service", 0, CLD_EXITED);
test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
- test(m, "exec-specifier-credentials-dir.service", 0, CLD_EXITED);
+ test(m, "exec-specifier-credentials-dir.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_CREDENTIALS, CLD_EXITED);
}
static void test_exec_standardinput(Manager *m) {
@@ -1113,7 +1127,7 @@ static void test_exec_umask_namespace(Manager *m) {
log_notice("Testing without inaccessible, skipping %s", __func__);
return;
}
- test(m, "exec-umask-namespace.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-umask-namespace.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NAMESPACE : EXIT_GROUP, CLD_EXITED);
}
typedef struct test_entry {
@@ -1123,40 +1137,27 @@ typedef struct test_entry {
#define entry(x) {x, #x}
-static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) {
+static void run_tests(LookupScope scope, char **patterns) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
+ _cleanup_free_ char *unit_paths = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
- assert_se(tests);
-
- r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
- m->default_std_output = EXEC_OUTPUT_NULL; /* don't rely on host journald */
- if (manager_errno_skip_test(r))
- return log_tests_skipped_errno(r, "manager_new");
- assert_se(r >= 0);
- assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
-
- for (const test_entry *test = tests; test->f; test++)
- if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
- test->f(m);
- else
- log_info("Skipping %s because it does not match any pattern.", test->name);
-
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
-
- static const test_entry user_tests[] = {
+ static const test_entry tests[] = {
entry(test_exec_basic),
entry(test_exec_ambientcapabilities),
entry(test_exec_bindpaths),
entry(test_exec_capabilityboundingset),
entry(test_exec_condition),
entry(test_exec_cpuaffinity),
+ entry(test_exec_dynamicuser),
entry(test_exec_environment),
entry(test_exec_environmentfile),
+ entry(test_exec_execsearchpath),
+ entry(test_exec_execsearchpath_environment),
+ entry(test_exec_execsearchpath_environment_files),
+ entry(test_exec_execsearchpath_passenvironment),
+ entry(test_exec_execsearchpath_specifier),
entry(test_exec_group),
entry(test_exec_ignoresigpipe),
entry(test_exec_inaccessiblepaths),
@@ -1175,6 +1176,7 @@ int main(int argc, char *argv[]) {
entry(test_exec_readwritepaths),
entry(test_exec_restrictnamespaces),
entry(test_exec_runtimedirectory),
+ entry(test_exec_specifier),
entry(test_exec_standardinput),
entry(test_exec_standardoutput),
entry(test_exec_standardoutput_append),
@@ -1182,35 +1184,15 @@ int main(int argc, char *argv[]) {
entry(test_exec_supplementarygroups),
entry(test_exec_systemcallerrornumber),
entry(test_exec_systemcallfilter),
+ entry(test_exec_systemcallfilter_system),
entry(test_exec_temporaryfilesystem),
entry(test_exec_umask),
+ entry(test_exec_umask_namespace),
entry(test_exec_unsetenvironment),
entry(test_exec_user),
entry(test_exec_workingdirectory),
- entry(test_exec_execsearchpath),
- entry(test_exec_execsearchpath_environment),
- entry(test_exec_execsearchpath_environment_files),
- entry(test_exec_execsearchpath_passenvironment),
- {},
- };
- static const test_entry system_tests[] = {
- entry(test_exec_dynamicuser),
- entry(test_exec_specifier),
- entry(test_exec_execsearchpath_specifier),
- entry(test_exec_systemcallfilter_system),
- entry(test_exec_umask_namespace),
{},
};
- int r;
-
- test_setup_logging(LOG_DEBUG);
-
-#if HAS_FEATURE_ADDRESS_SANITIZER
- if (strstr_ptr(ci_environment(), "travis") || strstr_ptr(ci_environment(), "github-actions")) {
- log_notice("Running on Travis CI/GH Actions under ASan, skipping, see https://github.com/systemd/systemd/issues/10696");
- return EXIT_TEST_SKIP;
- }
-#endif
assert_se(unsetenv("USER") == 0);
assert_se(unsetenv("LOGNAME") == 0);
@@ -1218,68 +1200,185 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("HOME") == 0);
assert_se(unsetenv("TMPDIR") == 0);
- can_unshare = have_namespaces();
-
- /* It is needed otherwise cgroup creation fails */
- if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0)
- return log_tests_skipped("not privileged");
-
- r = enter_cgroup_subroot(NULL);
- if (r == -ENOMEDIUM)
- return log_tests_skipped("cgroupfs not available");
-
- if (path_is_read_only_fs("/sys") > 0)
- return log_tests_skipped("/sys is mounted read-only");
+ /* Unset VARx, especially, VAR1, VAR2 and VAR3, which are used in the PassEnvironment test cases,
+ * otherwise (and if they are present in the environment), `manager_default_environment` will copy
+ * them into the default environment which is passed to each created job, which will make the tests
+ * that expect those not to be present to fail. */
+ assert_se(unsetenv("VAR1") == 0);
+ assert_se(unsetenv("VAR2") == 0);
+ assert_se(unsetenv("VAR3") == 0);
+ assert_se(unsetenv("VAR4") == 0);
+ assert_se(unsetenv("VAR5") == 0);
- _cleanup_free_ char *unit_dir = NULL, *unit_paths = NULL;
- assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
- assert_se(unit_paths = strjoin(unit_dir, ":", user_runtime_unit_dir));
+ assert_se(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
assert_se(set_unit_path(unit_paths) >= 0);
- /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
- * cases, otherwise (and if they are present in the environment),
- * `manager_default_environment` will copy them into the default
- * environment which is passed to each created job, which will make the
- * tests that expect those not to be present to fail.
- */
- assert_se(unsetenv("VAR1") == 0);
- assert_se(unsetenv("VAR2") == 0);
- assert_se(unsetenv("VAR3") == 0);
+ r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
+ if (manager_errno_skip_test(r))
+ return (void) log_tests_skipped_errno(r, "manager_new");
+ assert_se(r >= 0);
+
+ m->default_std_output = EXEC_OUTPUT_NULL; /* don't rely on host journald */
+ assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
+
+ /* Uncomment below if you want to make debugging logs stored to journal. */
+ //manager_override_log_target(m, LOG_TARGET_AUTO);
+ //manager_override_log_level(m, LOG_DEBUG);
+
+ for (const test_entry *test = tests; test->f; test++)
+ if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
+ test->f(m);
+ else
+ log_info("Skipping %s because it does not match any pattern.", test->name);
+}
+
+static int prepare_ns(const char *process_name) {
+ int r;
+
+ r = safe_fork(process_name,
+ FORK_RESET_SIGNALS |
+ FORK_CLOSE_ALL_FDS |
+ FORK_DEATHSIG |
+ FORK_WAIT |
+ FORK_REOPEN_LOG |
+ FORK_LOG |
+ FORK_NEW_MOUNTNS |
+ FORK_MOUNTNS_SLAVE,
+ NULL);
+ assert_se(r >= 0);
+ if (r == 0) {
+ _cleanup_free_ char *unit_dir = NULL;
+
+ /* Make "/" read-only. */
+ assert_se(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT, NULL) >= 0);
+
+ /* Creating a new user namespace in the above means all MS_SHARED mounts become MS_SLAVE.
+ * Let's put them back to MS_SHARED here, since that's what we want as defaults. (This will
+ * not reconnect propagation, but simply create new peer groups for all our mounts). */
+ assert_se(mount_follow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_SHARED|MS_REC, NULL) >= 0);
+
+ assert_se(mkdir_p(PRIVATE_UNIT_DIR, 0755) >= 0);
+
+ /* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
+ FOREACH_STRING(p, "/root", "/tmp", "/var/tmp", "/var/lib", PRIVATE_UNIT_DIR)
+ assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
- r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
- if (r != 0)
- return r;
+ /* Copy unit files to make them accessible even when unprivileged. */
+ assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
+ assert_se(copy_directory(unit_dir, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
- r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
- if (r != 0)
- return r;
+ /* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
+ FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
+ assert_se(mkdir_p(p, 0) >= 0);
+ assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, "mode=0000") >= 0);
+ }
+ }
+
+ return r;
+}
+
+TEST(run_tests_root) {
+ _cleanup_strv_free_ char **filters = NULL;
+
+ if (!have_namespaces())
+ return (void) log_tests_skipped("unshare() is disabled");
+
+ /* safe_fork() clears saved_argv in the child process. Let's copy it. */
+ assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
+
+ if (prepare_ns("(test-execute-root)") == 0) {
+ can_unshare = true;
+ run_tests(LOOKUP_SCOPE_SYSTEM, filters);
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+TEST(run_tests_without_unshare) {
+ if (!have_namespaces()) {
+ /* unshare() is already filtered. */
+ can_unshare = false;
+ run_tests(LOOKUP_SCOPE_SYSTEM, strv_skip(saved_argv, 1));
+ return;
+ }
#if HAVE_SECCOMP
+ _cleanup_strv_free_ char **filters = NULL;
+ int r;
+
/* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping unshare() filtered tests.");
- return 0;
- }
+ if (!is_seccomp_available())
+ return (void) log_tests_skipped("Seccomp not available, cannot run unshare() filtered tests");
+
+ /* safe_fork() clears saved_argv in the child process. Let's copy it. */
+ assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
- _cleanup_hashmap_free_ Hashmap *s = NULL;
- assert_se(s = hashmap_new(NULL));
- r = seccomp_syscall_resolve_name("unshare");
- assert_se(r != __NR_SCMP_ERROR);
- assert_se(hashmap_put(s, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
- assert_se(unshare(CLONE_NEWNS) < 0);
- assert_se(errno == EOPNOTSUPP);
+ if (prepare_ns("(test-execute-without-unshare)") == 0) {
+ _cleanup_hashmap_free_ Hashmap *s = NULL;
- can_unshare = false;
+ r = seccomp_syscall_resolve_name("unshare");
+ assert_se(r != __NR_SCMP_ERROR);
+ assert_se(hashmap_ensure_put(&s, NULL, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
- r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
- if (r != 0)
- return r;
+ /* Check unshare() is actually filtered. */
+ assert_se(unshare(CLONE_NEWNS) < 0);
+ assert_se(errno == EOPNOTSUPP);
- return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
+ can_unshare = false;
+ run_tests(LOOKUP_SCOPE_SYSTEM, filters);
+ _exit(EXIT_SUCCESS);
+ }
#else
- return 0;
+ log_tests_skipped("Built without seccomp support, cannot run unshare() filtered tests");
+#endif
+}
+
+TEST(run_tests_unprivileged) {
+ _cleanup_strv_free_ char **filters = NULL;
+
+ if (!have_namespaces())
+ return (void) log_tests_skipped("unshare() is disabled");
+
+ /* safe_fork() clears saved_argv in the child process. Let's copy it. */
+ assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
+
+ if (prepare_ns("(test-execute-unprivileged)") == 0) {
+ assert_se(capability_bounding_set_drop(0, /* right_now = */ true) >= 0);
+
+ can_unshare = false;
+ run_tests(LOOKUP_SCOPE_USER, filters);
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+static int intro(void) {
+#if HAS_FEATURE_ADDRESS_SANITIZER
+ if (strstr_ptr(ci_environment(), "travis") || strstr_ptr(ci_environment(), "github-actions"))
+ return log_tests_skipped("Running on Travis CI/GH Actions under ASan, see https://github.com/systemd/systemd/issues/10696");
#endif
+ /* It is needed otherwise cgroup creation fails */
+ if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0)
+ return log_tests_skipped("not privileged");
+
+ if (enter_cgroup_subroot(NULL) == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
+
+ if (path_is_read_only_fs("/sys") > 0)
+ return log_tests_skipped("/sys is mounted read-only");
+
+ /* Create dummy network interface for testing PrivateNetwork=yes */
+ (void) system("ip link add dummy-test-exec type dummy");
+
+ return EXIT_SUCCESS;
}
+
+static int outro(void) {
+ (void) system("ip link del dummy-test-exec");
+ (void) rmdir(PRIVATE_UNIT_DIR);
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_FULL(LOG_DEBUG, intro, outro);
diff --git a/test/test-execute/exec-dynamicuser-statedir-migrate-step1.service b/test/test-execute/exec-dynamicuser-statedir-migrate-step1.service
index 1c79e4f722..2a5a1e1ff3 100644
--- a/test/test-execute/exec-dynamicuser-statedir-migrate-step1.service
+++ b/test/test-execute/exec-dynamicuser-statedir-migrate-step1.service
@@ -3,14 +3,14 @@
Description=Test DynamicUser= migrate StateDirectory= (preparation)
[Service]
-ExecStart=test -w /var/lib/test-dynamicuser-migrate
-ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=test ! -L /var/lib/test-dynamicuser-migrate
-ExecStart=test ! -L /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=test -d /var/lib/test-dynamicuser-migrate
-ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
-ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=test -w %S/test-dynamicuser-migrate
+ExecStart=test -w %S/test-dynamicuser-migrate2/hoge
+ExecStart=test ! -L %S/test-dynamicuser-migrate
+ExecStart=test ! -L %S/test-dynamicuser-migrate2/hoge
+ExecStart=test -d %S/test-dynamicuser-migrate
+ExecStart=test -d %S/test-dynamicuser-migrate2/hoge
+ExecStart=touch %S/test-dynamicuser-migrate/yay
+ExecStart=touch %S/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot
diff --git a/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service b/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
index 015b74ce22..e89f0c5aae 100644
--- a/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
+++ b/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
@@ -3,22 +3,22 @@
Description=Test DynamicUser= migrate StateDirectory=
[Service]
-ExecStart=test -w /var/lib/test-dynamicuser-migrate
-ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=test -L /var/lib/test-dynamicuser-migrate
-ExecStart=test -L /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=test -d /var/lib/test-dynamicuser-migrate
-ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
-ExecStart=test -f /var/lib/test-dynamicuser-migrate/yay
-ExecStart=test -f /var/lib/test-dynamicuser-migrate2/hoge/yayyay
-ExecStart=test -d /var/lib/private/test-dynamicuser-migrate
-ExecStart=test -d /var/lib/private/test-dynamicuser-migrate2/hoge
-ExecStart=test -f /var/lib/private/test-dynamicuser-migrate/yay
-ExecStart=test -f /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
-ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
-ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
-ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
-ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=test -w %S/test-dynamicuser-migrate
+ExecStart=test -w %S/test-dynamicuser-migrate2/hoge
+ExecStart=test -L %S/test-dynamicuser-migrate
+ExecStart=test -L %S/test-dynamicuser-migrate2/hoge
+ExecStart=test -d %S/test-dynamicuser-migrate
+ExecStart=test -d %S/test-dynamicuser-migrate2/hoge
+ExecStart=test -f %S/test-dynamicuser-migrate/yay
+ExecStart=test -f %S/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=test -d %S/private/test-dynamicuser-migrate
+ExecStart=test -d %S/private/test-dynamicuser-migrate2/hoge
+ExecStart=test -f %S/private/test-dynamicuser-migrate/yay
+ExecStart=test -f %S/private/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=touch %S/test-dynamicuser-migrate/yay
+ExecStart=touch %S/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=touch %S/private/test-dynamicuser-migrate/yay
+ExecStart=touch %S/private/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot
diff --git a/test/test-execute/exec-dynamicuser-statedir.service b/test/test-execute/exec-dynamicuser-statedir.service
index b33b4da74a..b7e36f529e 100644
--- a/test/test-execute/exec-dynamicuser-statedir.service
+++ b/test/test-execute/exec-dynamicuser-statedir.service
@@ -3,71 +3,71 @@
Description=Test DynamicUser= with StateDirectory=
[Service]
-ExecStart=test -w /var/lib/waldo
-ExecStart=test -w /var/lib/quux/pief
-ExecStart=test -w /var/lib/aaa
-ExecStart=test -w /var/lib/aaa/bbb
-ExecStart=test -w /var/lib/aaa/ccc
-ExecStart=test -w /var/lib/xxx
-ExecStart=test -w /var/lib/xxx/yyy
-ExecStart=test -w /var/lib/xxx/zzz
-ExecStart=test -w /var/lib/aaa/111
-ExecStart=test -w /var/lib/aaa/222
-ExecStart=test -w /var/lib/aaa/333
+ExecStart=test -w %S/waldo
+ExecStart=test -w %S/quux/pief
+ExecStart=test -w %S/aaa
+ExecStart=test -w %S/aaa/bbb
+ExecStart=test -w %S/aaa/ccc
+ExecStart=test -w %S/xxx
+ExecStart=test -w %S/xxx/yyy
+ExecStart=test -w %S/xxx/zzz
+ExecStart=test -w %S/aaa/111
+ExecStart=test -w %S/aaa/222
+ExecStart=test -w %S/aaa/333
-ExecStart=test -d /var/lib/waldo
-ExecStart=test -d /var/lib/quux/pief
-ExecStart=test -d /var/lib/aaa
-ExecStart=test -d /var/lib/aaa/bbb
-ExecStart=test -d /var/lib/aaa/ccc
-ExecStart=test -d /var/lib/xxx
-ExecStart=test -d /var/lib/xxx/yyy
-ExecStart=test -d /var/lib/xxx/zzz
-ExecStart=test -L /var/lib/aaa/111
-ExecStart=test -L /var/lib/aaa/222
-ExecStart=test -L /var/lib/aaa/333
+ExecStart=test -d %S/waldo
+ExecStart=test -d %S/quux/pief
+ExecStart=test -d %S/aaa
+ExecStart=test -d %S/aaa/bbb
+ExecStart=test -d %S/aaa/ccc
+ExecStart=test -d %S/xxx
+ExecStart=test -d %S/xxx/yyy
+ExecStart=test -d %S/xxx/zzz
+ExecStart=test -L %S/aaa/111
+ExecStart=test -L %S/aaa/222
+ExecStart=test -L %S/aaa/333
-ExecStart=touch /var/lib/waldo/hoge
-ExecStart=touch /var/lib/quux/pief/hoge
-ExecStart=touch /var/lib/aaa/hoge
-ExecStart=touch /var/lib/aaa/bbb/hoge
-ExecStart=touch /var/lib/aaa/ccc/hoge
-ExecStart=touch /var/lib/xxx/hoge
-ExecStart=touch /var/lib/xxx/yyy/hoge
-ExecStart=touch /var/lib/xxx/zzz/hoge
-ExecStart=touch /var/lib/aaa/111/foo
-ExecStart=touch /var/lib/aaa/222/foo
-ExecStart=touch /var/lib/aaa/333/foo
+ExecStart=touch %S/waldo/hoge
+ExecStart=touch %S/quux/pief/hoge
+ExecStart=touch %S/aaa/hoge
+ExecStart=touch %S/aaa/bbb/hoge
+ExecStart=touch %S/aaa/ccc/hoge
+ExecStart=touch %S/xxx/hoge
+ExecStart=touch %S/xxx/yyy/hoge
+ExecStart=touch %S/xxx/zzz/hoge
+ExecStart=touch %S/aaa/111/foo
+ExecStart=touch %S/aaa/222/foo
+ExecStart=touch %S/aaa/333/foo
-ExecStart=test -f /var/lib/waldo/hoge
-ExecStart=test -f /var/lib/quux/pief/hoge
-ExecStart=test -f /var/lib/aaa/hoge
-ExecStart=test -f /var/lib/aaa/bbb/hoge
-ExecStart=test -f /var/lib/aaa/ccc/hoge
-ExecStart=test -f /var/lib/xxx/hoge
-ExecStart=test -f /var/lib/xxx/yyy/hoge
-ExecStart=test -f /var/lib/xxx/zzz/hoge
-ExecStart=test -f /var/lib/aaa/111/foo
-ExecStart=test -f /var/lib/aaa/222/foo
-ExecStart=test -f /var/lib/aaa/333/foo
-ExecStart=test -f /var/lib/xxx/foo
-ExecStart=test -f /var/lib/xxx/yyy/foo
-ExecStart=test -f /var/lib/xxx/zzz/foo
+ExecStart=test -f %S/waldo/hoge
+ExecStart=test -f %S/quux/pief/hoge
+ExecStart=test -f %S/aaa/hoge
+ExecStart=test -f %S/aaa/bbb/hoge
+ExecStart=test -f %S/aaa/ccc/hoge
+ExecStart=test -f %S/xxx/hoge
+ExecStart=test -f %S/xxx/yyy/hoge
+ExecStart=test -f %S/xxx/zzz/hoge
+ExecStart=test -f %S/aaa/111/foo
+ExecStart=test -f %S/aaa/222/foo
+ExecStart=test -f %S/aaa/333/foo
+ExecStart=test -f %S/xxx/foo
+ExecStart=test -f %S/xxx/yyy/foo
+ExecStart=test -f %S/xxx/zzz/foo
-ExecStart=test -f /var/lib/private/waldo/hoge
-ExecStart=test -f /var/lib/private/quux/pief/hoge
-ExecStart=test -f /var/lib/private/aaa/hoge
-ExecStart=test -f /var/lib/private/aaa/bbb/hoge
-ExecStart=test -f /var/lib/private/aaa/ccc/hoge
-ExecStart=test -f /var/lib/private/xxx/hoge
-ExecStart=test -f /var/lib/private/xxx/yyy/hoge
-ExecStart=test -f /var/lib/private/xxx/zzz/hoge
-ExecStart=test -f /var/lib/private/aaa/111/foo
-ExecStart=test -f /var/lib/private/aaa/222/foo
-ExecStart=test -f /var/lib/private/aaa/333/foo
-ExecStart=test -f /var/lib/private/xxx/foo
-ExecStart=test -f /var/lib/private/xxx/yyy/foo
-ExecStart=test -f /var/lib/private/xxx/zzz/foo
+ExecStart=test -f %S/private/waldo/hoge
+ExecStart=test -f %S/private/quux/pief/hoge
+ExecStart=test -f %S/private/aaa/hoge
+ExecStart=test -f %S/private/aaa/bbb/hoge
+ExecStart=test -f %S/private/aaa/ccc/hoge
+ExecStart=test -f %S/private/xxx/hoge
+ExecStart=test -f %S/private/xxx/yyy/hoge
+ExecStart=test -f %S/private/xxx/zzz/hoge
+ExecStart=test -f %S/private/aaa/111/foo
+ExecStart=test -f %S/private/aaa/222/foo
+ExecStart=test -f %S/private/aaa/333/foo
+ExecStart=test -f %S/private/xxx/foo
+ExecStart=test -f %S/private/xxx/yyy/foo
+ExecStart=test -f %S/private/xxx/zzz/foo
ExecStart=sh -x -c 'test "$$STATE_DIRECTORY" = "%S/aaa:%S/aaa/bbb:%S/aaa/ccc:%S/quux/pief:%S/waldo:%S/xxx:%S/xxx/yyy:%S/xxx/zzz"'
diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service
index 0fff048b94..360099d337 100644
--- a/test/test-execute/exec-privatenetwork-yes.service
+++ b/test/test-execute/exec-privatenetwork-yes.service
@@ -4,5 +4,6 @@ Description=Test for PrivateNetwork
[Service]
ExecStart=/bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -Ev ": (lo|(erspan|gre|gretap|ip_vti|ip6_vti|ip6gre|ip6tnl|sit|tunl)0@.*):"'
+ExecStart=/bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -F ": dummy-test-exec:"'
Type=oneshot
PrivateNetwork=yes
diff --git a/test/test-execute/exec-specifier-system.service b/test/test-execute/exec-specifier-system.service
new file mode 100644
index 0000000000..9e8ee567aa
--- /dev/null
+++ b/test/test-execute/exec-specifier-system.service
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Unit]
+Description=Test for specifiers (system)
+
+[Service]
+Type=oneshot
+ExecStart=test %t = /run
+ExecStart=test %S = /var/lib
+ExecStart=test %C = /var/cache
+ExecStart=test %L = /var/log
+ExecStart=test %E = /etc
diff --git a/test/test-execute/exec-specifier-user.service b/test/test-execute/exec-specifier-user.service
new file mode 100644
index 0000000000..ee0301a426
--- /dev/null
+++ b/test/test-execute/exec-specifier-user.service
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Unit]
+Description=Test for specifiers
+
+[Service]
+Type=oneshot
+ExecStart=sh -c 'test %t = $$XDG_RUNTIME_DIR'
+ExecStart=sh -c 'test %S = %h/.config'
+ExecStart=sh -c 'test %C = %h/.cache'
+ExecStart=sh -c 'test %L = %h/.config/log'
+ExecStart=sh -c 'test %E = %h/.config'
diff --git a/test/test-execute/exec-specifier.service b/test/test-execute/exec-specifier.service
index 2b487bae8c..512f786f83 100644
--- a/test/test-execute/exec-specifier.service
+++ b/test/test-execute/exec-specifier.service
@@ -13,11 +13,6 @@ ExecStart=test %I = ""
ExecStart=test %j = specifier
ExecStart=test %J = specifier
ExecStart=test %f = /exec/specifier
-ExecStart=test %t = /run
-ExecStart=test %S = /var/lib
-ExecStart=test %C = /var/cache
-ExecStart=test %L = /var/log
-ExecStart=test %E = /etc
ExecStart=test %T = /tmp
ExecStart=test %V = /var/tmp
ExecStart=test %d = %t/credentials/%n
diff --git a/test/test-execute/exec-specifier@.service b/test/test-execute/exec-specifier@.service
index 69e969f716..cb9d0a182a 100644
--- a/test/test-execute/exec-specifier@.service
+++ b/test/test-execute/exec-specifier@.service
@@ -13,11 +13,6 @@ ExecStart=test %I = foo/bar
ExecStart=test %j = specifier
ExecStart=test %J = specifier
ExecStart=test %f = /foo/bar
-ExecStart=test %t = /run
-ExecStart=test %S = /var/lib
-ExecStart=test %C = /var/cache
-ExecStart=test %L = /var/log
-ExecStart=test %E = /etc
ExecStart=sh -c 'test %u = $$(id -un)'
ExecStart=sh -c 'test %U = $$(id -u)'
ExecStart=sh -c 'test %g = $$(id -gn)'

@ -0,0 +1,96 @@
From 129f8896018377cfe9a64e2877517124b79ca87f Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 9 May 2023 13:45:16 +0200
Subject: [PATCH] tmpfiles: Add merge support for copy files action
If '+' is specified with 'C', let's merge the tree with any existing
tree.
(cherry picked from commit 1fd5ec5697680e2ec6277431bd74cabf48dbc94f)
Related: RHEL-27512
---
man/tmpfiles.d.xml | 22 +++++++++++-----------
src/tmpfiles/tmpfiles.c | 2 +-
test/units/testsuite-22.02.sh | 16 ++++++++++++++++
3 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index bd3bc33ab4..fe2a1dadab 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -58,10 +58,11 @@ c+ /dev/char-device-to-[re]create mode user group - major
b /dev/block-device-to-create mode user group - major:minor
b+ /dev/block-device-to-[re]create mode user group - major:minor
C /target/to/create - - - cleanup-age /source/to/copy
+C+ /target/to/create - - - cleanup-age /source/to/copy
x /path-or-glob/to/ignore/recursively - - - cleanup-age -
X /path-or-glob/to/ignore - - - cleanup-age -
-r /empty/dir/to/remove - - - - -
-R /dir/to/remove/recursively - - - - -
+r /path-or-glob/to/remove - - - - -
+R /path-or-glob/to/remove/recursively - - - - -
z /path-or-glob/to/adjust/mode mode user group - -
Z /path-or-glob/to/adjust/mode/recursively mode user group - -
t /path-or-glob/to/set/xattrs - - - - xattrs
@@ -325,15 +326,14 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<varlistentry>
<term><varname>C</varname></term>
- <listitem><para>Recursively copy a file or directory, if the
- destination files or directories do not exist yet or the
- destination directory is empty. Note that this command will not
- descend into subdirectories if the destination directory already
- exists and is not empty. Instead, the entire copy operation is
- skipped. If the argument is omitted, files from the source directory
- <filename>/usr/share/factory/</filename> with the same name
- are copied. Does not follow symlinks. Contents of the directories
- are subject to time based cleanup if the age argument is specified.
+ <term><varname>C+</varname></term>
+ <listitem><para>Recursively copy a file or directory, if the destination files or directories do
+ not exist yet or the destination directory is empty. Note that this command will not descend into
+ subdirectories if the destination directory already exists and is not empty, unless the action is
+ suffixed with <varname>+</varname>. Instead, the entire copy operation is skipped. If the argument
+ is omitted, files from the source directory <filename>/usr/share/factory/</filename> with the same
+ name are copied. Does not follow symlinks. Contents of the directories are subject to time-based
+ cleanup if the age argument is specified.
</para></listitem>
</varlistentry>
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 18bb75715b..ead5c49874 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1648,7 +1648,7 @@ static int copy_files(Item *i) {
dfd, bn,
i->uid_set ? i->uid : UID_INVALID,
i->gid_set ? i->gid : GID_INVALID,
- COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS);
+ COPY_REFLINK | ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS);
fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
if (fd < 0) {
diff --git a/test/units/testsuite-22.02.sh b/test/units/testsuite-22.02.sh
index 49c55f136b..f233be2499 100755
--- a/test/units/testsuite-22.02.sh
+++ b/test/units/testsuite-22.02.sh
@@ -121,3 +121,19 @@ EOF
test "$(stat -c %U:%G:%a /tmp/C/3/f1)" = "root:root:644"
test ! -e /tmp/C/4
+
+touch /tmp/C/3-origin/f{2,3,4}
+echo -n ABC > /tmp/C/3/f1
+
+systemd-tmpfiles --create - <<EOF
+C+ /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin
+EOF
+
+# Test that the trees got merged, even though /tmp/C/3 already exists.
+test -e /tmp/C/3/f1
+test -e /tmp/C/3/f2
+test -e /tmp/C/3/f3
+test -e /tmp/C/3/f4
+
+# Test that /tmp/C/3/f1 did not get overwritten.
+test "$(cat /tmp/C/3/f1)" = "ABC"

@ -0,0 +1,116 @@
From 1e4f0fdb8d684007fa0c9747181a8ca70da5eaae Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Mon, 10 Apr 2023 15:18:33 +0200
Subject: [PATCH] generator: add generator_open_unit_file_full to allow
creating temporary units
This function is like `generator_open_unit_file`, but if `ret_temp_path` is
passed, a temporary unit is created instead.
(cherry picked from commit 8a84e0d7960b7970c16a4efd4c5b0b26c810d22d)
Related: RHEL-27512
---
src/shared/generator.c | 46 ++++++++++++++++++++++++++++--------------
src/shared/generator.h | 10 ++++-----
2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 284e5fc580..29de8ada6b 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -20,42 +20,58 @@
#include "specifier.h"
#include "string-util.h"
#include "time-util.h"
+#include "tmpfile-util.h"
#include "unit-name.h"
#include "util.h"
-int generator_open_unit_file(
+int generator_open_unit_file_full(
const char *dir,
const char *source,
const char *fn,
- FILE **ret) {
+ FILE **ret_file,
+ char **ret_temp_path) {
_cleanup_free_ char *p = NULL;
FILE *f;
int r;
assert(dir);
- assert(fn);
- assert(ret);
+ assert(ret_file);
- p = path_join(dir, fn);
- if (!p)
- return log_oom();
+ /* If <ret_temp_path> is specified, it creates a temporary unit file and also returns its
+ * temporary path. */
- r = fopen_unlocked(p, "wxe", &f);
- if (r < 0) {
- if (source && r == -EEXIST)
- return log_error_errno(r,
- "Failed to create unit file '%s', as it already exists. Duplicate entry in '%s'?",
- p, source);
+ if (ret_temp_path) {
+ r = fopen_temporary(dir, &f, &p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create temporary unit file in '%s': %m", dir);
+
+ (void) fchmod(fileno(f), 0644);
- return log_error_errno(r, "Failed to create unit file '%s': %m", p);
+ *ret_temp_path = TAKE_PTR(p);
+ } else {
+ assert(fn);
+
+ p = path_join(dir, fn);
+ if (!p)
+ return log_oom();
+
+ r = fopen_unlocked(p, "wxe", &f);
+ if (r < 0) {
+ if (source && r == -EEXIST)
+ return log_error_errno(r,
+ "Failed to create unit file '%s', as it already exists. Duplicate entry in '%s'?",
+ p, source);
+
+ return log_error_errno(r, "Failed to create unit file '%s': %m", p);
+ }
}
fprintf(f,
"# Automatically generated by %s\n\n",
program_invocation_short_name);
- *ret = f;
+ *ret_file = f;
return 0;
}
diff --git a/src/shared/generator.h b/src/shared/generator.h
index 111900fd45..d97d6edc67 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -6,11 +6,11 @@
#include "macro.h"
#include "main-func.h"
-int generator_open_unit_file(
- const char *dest,
- const char *source,
- const char *name,
- FILE **file);
+int generator_open_unit_file_full(const char *dest, const char *source, const char *name, FILE **ret_file, char **ret_temp_path);
+
+static inline int generator_open_unit_file(const char *dest, const char *source, const char *name, FILE **ret_file) {
+ return generator_open_unit_file_full(dest, source, name, ret_file, NULL);
+}
int generator_add_symlink_full(const char *dir, const char *dst, const char *dep_type, const char *src, const char *instance);

@ -0,0 +1,142 @@
From 8d7665b3e327deb0868b97a159acfdb266a6a5e9 Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Mon, 10 Apr 2023 15:18:53 +0200
Subject: [PATCH] network-generator: rewrite unit if it already exists and its
content changed
When the `systemd-network-generator` is included in the initrd and runs from
there first, the next times it runs after switching to real root it
thinks there is a duplicate entry on the kernel command line.
This patch rewrites the unit file if the content has changed, instead of
displaying an error message.
(cherry picked from commit f3e4d04298bb73b836dd7ca90f7c7b09de1e776b)
Related: RHEL-27512
---
src/network/generator/main.c | 55 ++++++++++++++++++++++++++++--------
1 file changed, 43 insertions(+), 12 deletions(-)
diff --git a/src/network/generator/main.c b/src/network/generator/main.c
index a36fe98c86..2574bc1136 100644
--- a/src/network/generator/main.c
+++ b/src/network/generator/main.c
@@ -3,6 +3,7 @@
#include <getopt.h>
#include "fd-util.h"
+#include "fs-util.h"
#include "generator.h"
#include "macro.h"
#include "main-func.h"
@@ -16,67 +17,97 @@
static const char *arg_root = NULL;
static int network_save(Network *network, const char *dest_dir) {
- _cleanup_free_ char *filename = NULL;
+ _cleanup_free_ char *filename = NULL, *p = NULL;
+ _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(network);
+ r = generator_open_unit_file_full(dest_dir, NULL, NULL, &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ network_dump(network, f);
+
r = asprintf(&filename, "%s-%s.network",
isempty(network->ifname) ? "91" : "90",
isempty(network->ifname) ? "default" : network->ifname);
if (r < 0)
return log_oom();
- r = generator_open_unit_file(dest_dir, "kernel command line", filename, &f);
+ p = path_join(dest_dir, filename);
+ if (!p)
+ return log_oom();
+
+ r = conservative_rename(temp_path, p);
if (r < 0)
return r;
- network_dump(network, f);
-
+ temp_path = mfree(temp_path);
return 0;
}
static int netdev_save(NetDev *netdev, const char *dest_dir) {
- _cleanup_free_ char *filename = NULL;
+ _cleanup_free_ char *filename = NULL, *p = NULL;
+ _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(netdev);
+ r = generator_open_unit_file_full(dest_dir, NULL, NULL, &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ netdev_dump(netdev, f);
+
r = asprintf(&filename, "90-%s.netdev",
netdev->ifname);
if (r < 0)
return log_oom();
- r = generator_open_unit_file(dest_dir, "kernel command line", filename, &f);
+ p = path_join(dest_dir, filename);
+ if (!p)
+ return log_oom();
+
+ r = conservative_rename(temp_path, p);
if (r < 0)
return r;
- netdev_dump(netdev, f);
-
+ temp_path = mfree(temp_path);
return 0;
}
static int link_save(Link *link, const char *dest_dir) {
- _cleanup_free_ char *filename = NULL;
+ _cleanup_free_ char *filename = NULL, *p = NULL;
+ _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(link);
+ r = generator_open_unit_file_full(dest_dir, NULL, NULL, &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ link_dump(link, f);
+
filename = strjoin(!isempty(link->ifname) ? "90" :
!hw_addr_is_null(&link->mac) ? "91" : "92",
"-", link->filename, ".link");
if (!filename)
return log_oom();
- r = generator_open_unit_file(dest_dir, "kernel command line", filename, &f);
+ p = path_join(dest_dir, filename);
+ if (!p)
+ return log_oom();
+
+ r = conservative_rename(temp_path, p);
if (r < 0)
return r;
- link_dump(link, f);
-
+ temp_path = mfree(temp_path);
return 0;
}

@ -0,0 +1,38 @@
From 696206a798647adc73faab26ab5b7543df939372 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 17 Jul 2023 17:54:59 +0200
Subject: [PATCH] ci: drop super-linter's shellcheck
It's been a while since we introduced Differential ShellCheck and it
proved to be quite useful (and in some ways even better than the shellcheck
run by super-linter). So, to have only one linter scream at us for not
knowing how to write bash properly, let's drop the super-linter's one in
favor of Differential ShellCheck.
Follow-up for https://github.com/systemd/systemd/pull/24328#pullrequestreview-1074127504
(cherry picked from commit c4b167f857fe5c228da4d4950a3eae13f53c645c)
Related: RHEL-27512
---
.github/workflows/linter.yml | 8 --------
1 file changed, 8 deletions(-)
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index eddd350122..8dd3b075ad 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -32,13 +32,5 @@ jobs:
uses: github/super-linter/slim@01d3218744765b55c3b5ffbb27e50961e50c33c5
env:
DEFAULT_BRANCH: main
- MULTI_STATUS: false
- # Excludes:
- # - man/.* - all snippets in man pages (false positives due to
- # missing shebangs)
- # - .*\.(in|SKELETON) - all template/skeleton files
- # except kernel-install
- FILTER_REGEX_EXCLUDE: .*/(man/.*|([^k]|k(k|ek)*([^ek]|e[^kr]))*(k(k|ek)*e?)?\.(in|SKELETON))$
VALIDATE_ALL_CODEBASE: false
- VALIDATE_BASH: true
VALIDATE_GITHUB_ACTIONS: true

@ -0,0 +1,130 @@
From 57d14d938573b0670d3205bf27a416bcf18424d4 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 28 Feb 2024 12:15:44 +0100
Subject: [PATCH] mkosi: make sure we build & use RHEL 9 stuff
- drop Hyperscale SIG repos, so we don't pull in btrfs stuff
- use XFS for rootfs
- install gnu-efi headers, since RHEL 9 sd-boot still requires it
RHEL-only
Related: RHEL-27512
---
mkosi.conf | 2 +-
mkosi.conf.d/10-centos.conf | 2 +-
mkosi.images/base/mkosi.build.chroot | 8 ++++++++
.../base/mkosi.conf.d/10-centos-fedora.conf | 2 ++
.../usr/lib/systemd/system-preset/00-mkosi.preset | 13 ++++---------
.../system/mkosi.conf.d/10-centos-fedora.conf | 1 +
.../mkosi.extra/usr/lib/repart.d/20-root.conf | 3 +--
7 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/mkosi.conf b/mkosi.conf
index 9ec4faf122..d5cde391dd 100644
--- a/mkosi.conf
+++ b/mkosi.conf
@@ -23,7 +23,7 @@ KernelCommandLineExtra=systemd.crash_shell
systemd.log_level=debug
systemd.log_ratelimit_kmsg=0
systemd.journald.forward_to_console
- systemd.journald.max_level_console=warning
+ systemd.journald.max_level_console=info
# Disable the kernel's ratelimiting on userspace logging to kmsg.
printk.devkmsg=on
# Make sure /sysroot is mounted rw in the initrd.
diff --git a/mkosi.conf.d/10-centos.conf b/mkosi.conf.d/10-centos.conf
index ae2706c791..a740548d46 100644
--- a/mkosi.conf.d/10-centos.conf
+++ b/mkosi.conf.d/10-centos.conf
@@ -7,4 +7,4 @@ Distribution=centos
@Release=9
Repositories=epel
epel-next
- hyperscale-packages-main
+ crb
diff --git a/mkosi.images/base/mkosi.build.chroot b/mkosi.images/base/mkosi.build.chroot
index ba0c92eef2..3427d0e241 100755
--- a/mkosi.images/base/mkosi.build.chroot
+++ b/mkosi.images/base/mkosi.build.chroot
@@ -106,6 +106,14 @@ if [ ! -f "$BUILDDIR"/build.ninja ]; then
-D xenctrl="$([[ "$ID" =~ debian|ubuntu|fedora|opensuse ]] && echo true || echo false)"
-D libiptc="$([[ "$ID" =~ debian|ubuntu ]] && echo true || echo false)"
-D libcryptsetup-plugins="$([[ "$ID" = "centos" ]] && [[ "$VERSION" = "8" ]] && echo false || echo true)"
+ # Necessary on RHEL 9 to build sd-boot stuff
+ -D gnu-efi=true
+ # Disable stuff we don't build on RHEL
+ -D timesyncd=false
+ -D homed=false
+ -D userdb=false
+ -D portabled=false
+ -D networkd=false
)
# On debian-like systems the library directory is not /usr/lib64 but /usr/lib/<arch-triplet>/.
diff --git a/mkosi.images/base/mkosi.conf.d/10-centos-fedora.conf b/mkosi.images/base/mkosi.conf.d/10-centos-fedora.conf
index d7a135a5c0..b25b7b4185 100644
--- a/mkosi.images/base/mkosi.conf.d/10-centos-fedora.conf
+++ b/mkosi.images/base/mkosi.conf.d/10-centos-fedora.conf
@@ -29,6 +29,8 @@ BuildPackages=
bpftool
docbook-xsl
findutils
+ gnu-efi-compat # Necessary for sd-boot on RHEL 9
+ gnu-efi-devel # Necessary for sd-boot on RHEL 9
libgcrypt-devel # CentOS Stream 8 libgcrypt-devel doesn't ship a pkg-config file.
libxslt
pam-devel
diff --git a/mkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset b/mkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset
index 070af4c67a..42e5af3ec9 100644
--- a/mkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset
+++ b/mkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset
@@ -9,16 +9,9 @@ disable dnsmasq.service
disable isc-dhcp-server.service
disable isc-dhcp-server6.service
-# Pulled in via dracut-network by kexec-tools on Fedora.
-disable NetworkManager*
-
# Make sure dbus-broker is started by default on Debian/Ubuntu.
enable dbus-broker.service
-# systemd-networkd is disabled by default on Fedora so make sure it is enabled.
-enable systemd-networkd.service
-enable systemd-networkd-wait-online.service
-
# We install dnf in some images but it's only going to be used rarely,
# so let's not have dnf create its cache.
disable dnf-makecache.*
@@ -26,5 +19,7 @@ disable dnf-makecache.*
# We have journald to receive audit data so let's make sure we're not running auditd as well
disable auditd.service
-# systemd-timesyncd is not enabled by default in the default systemd preset so enable it here instead.
-enable systemd-timesyncd.service
+# We don't ship sd-networkd on RHEL 9, so replace it with NM
+disable systemd-networkd.service
+disable systemd-networkd-wait-online.service
+enable NetworkManager*
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos-fedora.conf b/mkosi.images/system/mkosi.conf.d/10-centos-fedora.conf
index 871186d5ca..23cfd4ecc0 100644
--- a/mkosi.images/system/mkosi.conf.d/10-centos-fedora.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-centos-fedora.conf
@@ -31,3 +31,4 @@ Packages=
python3dist(pytest)
quota
vim-common
+ vim
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/repart.d/20-root.conf b/mkosi.images/system/mkosi.extra/usr/lib/repart.d/20-root.conf
index 71eb9e38c4..31e8313263 100644
--- a/mkosi.images/system/mkosi.extra/usr/lib/repart.d/20-root.conf
+++ b/mkosi.images/system/mkosi.extra/usr/lib/repart.d/20-root.conf
@@ -2,7 +2,6 @@
[Partition]
Type=root
-Format=btrfs
+Format=xfs
SizeMinBytes=1G
-Subvolumes=/home /var
MakeDirectories=/home /var

@ -0,0 +1,217 @@
From 45bcebd103f23fb595d0ff1d5e02ea5edd25f12d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 27 Feb 2024 12:53:35 +0100
Subject: [PATCH] ci: backport mkosi CI configuration from upstream
Notes:
- on RHEL 9 we don't have vsock support in systemd, so we have to fall
back to some "older" checks (i.e. pre-6aca147f82).
- our systemd-repart doesn't automatically fall back to Format=swap
for Type=swap partitions, so we have to do that explicitely
- don't pull in sd-resolved and sd-networkd, since the former needs
some extra configuration to work alongsideNM, and we don't
build the latter at all on RHEL 9
RHEL-only
Related: RHEL-27512
---
.github/workflows/mkosi.yml | 139 ++++++++++++++++++
.../mkosi.extra/usr/lib/repart.d/15-swap.conf | 1 +
.../lib/systemd/mkosi-check-and-shutdown.sh | 3 +
.../system/mkosi-check-and-shutdown.service | 5 +-
4 files changed, 144 insertions(+), 4 deletions(-)
create mode 100644 .github/workflows/mkosi.yml
diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
new file mode 100644
index 0000000000..f9b6d9ba58
--- /dev/null
+++ b/.github/workflows/mkosi.yml
@@ -0,0 +1,139 @@
+---
+# vi: ts=2 sw=2 et:
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# Simple boot tests that build and boot the mkosi images generated by the mkosi config files in mkosi.conf.d/.
+name: mkosi
+
+on:
+ push:
+ branches:
+ - main
+ - v[0-9]+-stable
+ paths:
+ - '**'
+ - '!README*'
+ - '!LICENSE*'
+ - '!LICENSES/**'
+ - '!TODO'
+ - '!docs/**'
+ - '!man/**'
+ - '!catalog/**'
+ - '!shell-completion/**'
+ - '!po/**'
+ - '!.**'
+ - '.github/**'
+
+ pull_request:
+ branches:
+ - main
+ - v[0-9]+-stable
+ paths:
+ - '**'
+ - '!README*'
+ - '!LICENSE*'
+ - '!LICENSES/**'
+ - '!TODO'
+ - '!docs/**'
+ - '!man/**'
+ - '!catalog/**'
+ - '!shell-completion/**'
+ - '!po/**'
+ - '!.**'
+ - '.github/**'
+
+permissions:
+ contents: read
+
+jobs:
+ ci:
+ runs-on: ubuntu-22.04
+ concurrency:
+ group: ${{ github.workflow }}-${{ matrix.distro }}-${{ matrix.release }}-${{ github.ref }}
+ cancel-in-progress: true
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - distro: centos
+ release: "9"
+
+ env:
+ SYSTEMD_LOG_LEVEL: debug
+
+ steps:
+ - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+ - uses: systemd/mkosi@070528fec478fc93af7ec057a5d2fd0045123c99
+
+ - name: Configure
+ run: |
+ tee mkosi.local.conf <<EOF
+ [Distribution]
+ Distribution=${{ matrix.distro }}
+ Release=${{ matrix.release }}
+
+ [Output]
+ Format=disk
+
+ [Content]
+ Environment=CI_BUILD=1
+ SLOW_TESTS=true
+
+ [Host]
+ ToolsTree=default
+ ToolsTreeDistribution=fedora
+ # Sometimes we run on a host with /dev/kvm, but it is broken, so explicitly disable it
+ QemuKvm=no
+ EOF
+
+ # These should override the options from mkosi.conf so we put them in a dropin that's ordered later
+ # instead.
+ tee mkosi.conf.d/99-ci.conf <<EOF
+ [Host]
+ KernelCommandLineExtra=systemd.unit=mkosi-check-and-shutdown.service
+ systemd.journald.max_level_console=debug
+ # udev's debug log output is very verbose, so up it to info in CI.
+ udev.log_level=info
+ # Root device can take a long time to appear, so let's bump the timeout.
+ systemd.default_device_timeout_sec=180
+ EOF
+
+ # For erofs, we have to install linux-modules-extra-azure, but that doesn't match the running kernel
+ # version, so we can't load the erofs module. squashfs is a builtin module so we use that instead.
+
+ mkdir -p mkosi.images/system/mkosi.repart/10-usr.conf.d
+ tee mkosi.images/system/mkosi.repart/10-usr.conf.d/squashfs.conf <<EOF
+ [Partition]
+ Format=squashfs
+ EOF
+
+ # The emergency shell is not useful in the CI, as it just blocks for a long time before the job
+ # eventually times out. Override it to just shutdown immediately.
+ mkdir -p mkosi.images/initrd/mkosi.extra/usr/lib/systemd/system/emergency.service.d/
+ mkdir -p mkosi.images/system/mkosi.extra/usr/lib/systemd/system/emergency.service.d/
+ tee mkosi.images/initrd/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf <<EOF
+ [Unit]
+ FailureAction=exit
+ [Service]
+ ExecStartPre=
+ ExecStart=
+ ExecStart=false
+ EOF
+ cp mkosi.images/initrd/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf mkosi.images/system/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf
+
+ - name: Generate secure boot key
+ run: mkosi --debug genkey
+
+ - name: Show image summary
+ run: mkosi summary
+
+ - name: Build
+ run: mkosi --debug
+
+ - name: Boot systemd-nspawn
+ run: sudo mkosi --debug boot
+
+ - name: Boot QEMU
+ run: timeout -k 30 10m mkosi --debug qemu
+
+ - name: Check ${{ matrix.distro }} QEMU
+ run: sudo mkosi shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/repart.d/15-swap.conf b/mkosi.images/system/mkosi.extra/usr/lib/repart.d/15-swap.conf
index 3755278462..1cbd6c7c2f 100644
--- a/mkosi.images/system/mkosi.extra/usr/lib/repart.d/15-swap.conf
+++ b/mkosi.images/system/mkosi.extra/usr/lib/repart.d/15-swap.conf
@@ -2,5 +2,6 @@
[Partition]
Type=swap
+Format=swap
SizeMinBytes=100M
SizeMaxBytes=100M
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
index 9bb246263e..210fa78850 100755
--- a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
@@ -1,6 +1,8 @@
#!/bin/bash -eux
# SPDX-License-Identifier: LGPL-2.1-or-later
+rm -f /testok
+
# TODO: Figure out why this is failing
systemctl reset-failed systemd-vconsole-setup.service
@@ -17,3 +19,4 @@ fi
# Exit with non-zero EC if the /failed-services file is not empty (we have -e set)
[[ ! -s /failed-services ]]
+touch /testok
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service
index 7942cbfa77..4021ede274 100644
--- a/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service
@@ -3,12 +3,9 @@
Description=Check if any service failed and then shutdown the machine
After=multi-user.target network-online.target
Requires=multi-user.target
-Wants=systemd-resolved.service systemd-networkd.service network-online.target
+Wants=network-online.target
SuccessAction=exit
FailureAction=exit
-# On success, exit with 123 so that we can check that we receive the actual exit code from the script on the
-# host.
-SuccessActionExitStatus=123
[Service]
Type=oneshot

@ -0,0 +1,23 @@
From 78e911e288b51eff762c67bb3df2b7b59f8c6872 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 28 Feb 2024 19:51:17 +0100
Subject: [PATCH] mkosi: explicitly enroll SecureBoot keys
The automagic enrollment works only with systemd v253 onwards, on v252
we need to do this one extra step.
RHEL-only
Related: RHEL-27512
---
mkosi.images/system/mkosi.extra/efi/loader/loader.conf | 1 +
1 file changed, 1 insertion(+)
create mode 100644 mkosi.images/system/mkosi.extra/efi/loader/loader.conf
diff --git a/mkosi.images/system/mkosi.extra/efi/loader/loader.conf b/mkosi.images/system/mkosi.extra/efi/loader/loader.conf
new file mode 100644
index 0000000000..f7a9445d89
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/efi/loader/loader.conf
@@ -0,0 +1 @@
+secure-boot-enroll force

@ -0,0 +1,37 @@
From ad27f1973d24a051ddfc80efcd00446eddf4380d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 17 Feb 2023 10:21:58 +0900
Subject: [PATCH] test-execute: also mount tmpfs on /dev/shm
Otherwise, if /dev/shm has a directory that cannot be accessible by
unprivileged user, then we cannot pick a dynamic user, and test service
may fail with unexpected error code:
---
Failed to enter shared memory directory /dev/shm/systemd-watch-bind-BqAGlN: Permission denied
exec-dynamicuser-supplementarygroups.service: Failed to update dynamic user credentials: Device or resource busy
exec-dynamicuser-supplementarygroups.service: Failed at step USER spawning /bin/sh: Device or resource busy
src/test/test-execute.c:885:test_exec_dynamicuser: exec-dynamicuser-supplementarygroups.service: can_unshare=no: exit status 217, expected 216
---
Follow-up for 4e032f654b94c2544ccf937209303766dfa66c24.
(cherry picked from commit d51e31ac4197d971a468ff41f15593bb6fdb29f3)
Related: RHEL-27512
---
src/test/test-execute.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 665ae8a833..f37da945b6 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1262,7 +1262,7 @@ static int prepare_ns(const char *process_name) {
assert_se(mkdir_p(PRIVATE_UNIT_DIR, 0755) >= 0);
/* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
- FOREACH_STRING(p, "/root", "/tmp", "/var/tmp", "/var/lib", PRIVATE_UNIT_DIR)
+ FOREACH_STRING(p, "/dev/shm", "/root", "/tmp", "/var/tmp", "/var/lib", PRIVATE_UNIT_DIR)
assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
/* Copy unit files to make them accessible even when unprivileged. */

@ -0,0 +1,106 @@
From 8fd8b29eda64dd09ea01f1b87cc4c65950fb5e3a Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2024 11:49:30 +0100
Subject: [PATCH] mkosi: fix UKI addons test
The test hasn't been working for a while, since there's no /efi or /boot
in $DESTDIR.
(cherry picked from commit 374fa8e8533e4834337a22613c7bada205dc1853)
Related: RHEL-27512
---
mkosi.images/base/mkosi.build.chroot | 12 ------------
mkosi.images/system/mkosi.conf.d/10-arch.conf | 1 +
.../system/mkosi.conf.d/10-debian-ubuntu.conf | 1 +
mkosi.images/system/mkosi.conf.d/10-fedora.conf | 1 +
mkosi.images/system/mkosi.conf.d/10-opensuse.conf | 1 +
mkosi.images/system/mkosi.postinst.chroot | 11 ++++++++++-
6 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/mkosi.images/base/mkosi.build.chroot b/mkosi.images/base/mkosi.build.chroot
index 3427d0e241..c46d667a90 100755
--- a/mkosi.images/base/mkosi.build.chroot
+++ b/mkosi.images/base/mkosi.build.chroot
@@ -177,15 +177,3 @@ if [ "$WITH_TESTS" = 1 ]; then
fi
( set -x; meson install -C "$BUILDDIR" --quiet --no-rebuild --only-changed )
-
-# Ensure that side-loaded PE addons are loaded if signed, and ignored if not
-if [ -d "${DESTDIR}/boot/loader" ]; then
- addons_dir="${DESTDIR}/boot/loader/addons"
-elif [ -d "${DESTDIR}/efi/loader" ]; then
- addons_dir="${DESTDIR}/efi/loader/addons"
-fi
-if [ -n "${addons_dir}" ]; then
- mkdir -p "${addons_dir}"
- ukify --secureboot-private-key mkosi.secure-boot.key --secureboot-certificate mkosi.secure-boot.crt --cmdline this_should_be_here -o "${addons_dir}/good.addon.efi"
- ukify --cmdline this_should_not_be_here -o "${addons_dir}/bad.addon.efi"
-fi
diff --git a/mkosi.images/system/mkosi.conf.d/10-arch.conf b/mkosi.images/system/mkosi.conf.d/10-arch.conf
index e1a511c979..a3d008d10f 100644
--- a/mkosi.images/system/mkosi.conf.d/10-arch.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-arch.conf
@@ -23,5 +23,6 @@ Packages=
python-pytest
python3
quota-tools
+ sbsigntools
shadow
vim
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu.conf b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu.conf
index 348bdb2992..d6e3f20222 100644
--- a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu.conf
@@ -19,6 +19,7 @@ Packages=
netcat-openbsd
openssh-server
openssh-client
+ sbsigntool
passwd
policykit-1
procps
diff --git a/mkosi.images/system/mkosi.conf.d/10-fedora.conf b/mkosi.images/system/mkosi.conf.d/10-fedora.conf
index 5863f03b19..7554ad2dc3 100644
--- a/mkosi.images/system/mkosi.conf.d/10-fedora.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-fedora.conf
@@ -9,3 +9,4 @@ Packages=
compsize
f2fs-tools
glibc-langpack-en
+ sbsigntools
diff --git a/mkosi.images/system/mkosi.conf.d/10-opensuse.conf b/mkosi.images/system/mkosi.conf.d/10-opensuse.conf
index 71434b4560..ffcb664224 100644
--- a/mkosi.images/system/mkosi.conf.d/10-opensuse.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-opensuse.conf
@@ -20,5 +20,6 @@ Packages=
python3-psutil
python3-pytest
quota
+ sbsigntools
shadow
vim
diff --git a/mkosi.images/system/mkosi.postinst.chroot b/mkosi.images/system/mkosi.postinst.chroot
index 692242da38..330fa3b73e 100755
--- a/mkosi.images/system/mkosi.postinst.chroot
+++ b/mkosi.images/system/mkosi.postinst.chroot
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e
@@ -100,3 +100,12 @@ mkdir -p /usr/lib/tmpfiles.d
cat >/usr/lib/tmpfiles.d/testuser.conf <<EOF
q /home/testuser 0700 4711 4711
EOF
+
+# sbsign is not available on CentOS Stream
+if command -v sbsign &>/dev/null; then
+ # Ensure that side-loaded PE addons are loaded if signed, and ignored if not
+ addons_dir=/efi/loader/addons
+ mkdir -p "$addons_dir"
+ ukify build --secureboot-private-key mkosi.key --secureboot-certificate mkosi.crt --cmdline this_should_be_here -o "$addons_dir/good.addon.efi"
+ ukify build --cmdline this_should_not_be_here -o "$addons_dir/bad.addon.efi"
+fi

@ -0,0 +1,36 @@
From c77533f7cc265ce7fc4c933f8ebb3828c0c9ff57 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2024 11:51:52 +0100
Subject: [PATCH] Revert "mkosi: Disable cmdline addon test for now"
Let's see if this finally works.
This reverts commit e167a8283d5964ca0f903b3e362ab7e48a1ed2ab.
(cherry picked from commit d9c8cf40b5c920ae59a02fa2bab32e93dad33542)
Related: RHEL-27512
---
.../usr/lib/systemd/mkosi-check-and-shutdown.sh | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
index 210fa78850..076026d097 100755
--- a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
@@ -12,9 +12,12 @@ systemctl --failed --no-legend | tee /failed-services
if ! systemd-detect-virt --container; then
cmp /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\1')
cmp /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\0')
- # TODO: Figure out why this is failing
- # grep -q this_should_be_here /proc/cmdline
- # grep -q this_should_not_be_here /proc/cmdline && exit 1
+
+ if command -v sbsign &>/dev/null; then
+ cat /proc/cmdline
+ grep -q this_should_be_here /proc/cmdline
+ (! grep -q this_should_not_be_here /proc/cmdline)
+ fi
fi
# Exit with non-zero EC if the /failed-services file is not empty (we have -e set)

@ -0,0 +1,31 @@
From fd051e3de351860b52ff1bbe6cab1fa9c153be76 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2024 12:18:40 +0100
Subject: [PATCH] Revert "mkosi: Don't fail on systemd-vconsole-setup.service
failure for now"
This doesn't seem to fail anymore.
This reverts commit 84c7929cd461f6f1cc2c44c69877b9fd0676c794.
(cherry picked from commit 193fa9d7fe383801bf3ff53e5ee5a2c52107270f)
Related: RHEL-27512
---
.../mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh | 3 ---
1 file changed, 3 deletions(-)
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
index 076026d097..4011ab930b 100755
--- a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
@@ -3,9 +3,6 @@
rm -f /testok
-# TODO: Figure out why this is failing
-systemctl reset-failed systemd-vconsole-setup.service
-
systemctl --failed --no-legend | tee /failed-services
# Check that secure boot keys were properly enrolled.

@ -0,0 +1,25 @@
From f3646608832288bb08b705de9b54a04a618a1ce3 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2024 12:41:30 +0100
Subject: [PATCH] mkosi: make shellcheck happy
(cherry picked from commit e86b1a9b0f1d2fc150edde18ea6f748b9423df3c)
Related: RHEL-27512
---
mkosi.images/base/mkosi.build.chroot | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mkosi.images/base/mkosi.build.chroot b/mkosi.images/base/mkosi.build.chroot
index c46d667a90..69430c304d 100755
--- a/mkosi.images/base/mkosi.build.chroot
+++ b/mkosi.images/base/mkosi.build.chroot
@@ -8,7 +8,7 @@ set -e
# We don't want to install our build of systemd in the base image, but use it as an extra tree for the
# initrd and system images, so override DESTDIR to store it in the output directory so we can reference it as
# an extra tree in the initrd and system image builds.
-DESTDIR="$OUTPUTDIR/systemd"
+export DESTDIR="$OUTPUTDIR/systemd"
# If mkosi.builddir/ exists mkosi will set $BUILDDIR to it, let's then use it
# as out-of-tree build dir. Otherwise, let's make up our own builddir.

@ -0,0 +1,67 @@
From de81c5b27d15ffc61a2c586f8b9a6a7943c061c7 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2024 20:22:19 +0100
Subject: [PATCH] mkosi: use pesign for signing UKI addons
In C9S/RHEL9 we don't ship sbsign, so we have to use pesign instead.
Unfortunately, ukify doesn't support singing with pesign, so we have to
do that manually.
Related: RHEL-27512
RHEL-only
---
.../system/mkosi.conf.d/10-centos/mkosi.conf | 3 +++
.../usr/lib/systemd/mkosi-check-and-shutdown.sh | 2 +-
mkosi.images/system/mkosi.postinst.chroot | 13 ++++++++++---
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
index 146e03a895..c79ced5130 100644
--- a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
@@ -6,3 +6,6 @@ Distribution=centos
[Content]
Packages=
kernel-modules # For squashfs support
+ nss-tools
+ openssl
+ pesign
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
index 4011ab930b..f32128ead2 100755
--- a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
@@ -10,7 +10,7 @@ if ! systemd-detect-virt --container; then
cmp /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\1')
cmp /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\0')
- if command -v sbsign &>/dev/null; then
+ if command -v pesign &>/dev/null; then
cat /proc/cmdline
grep -q this_should_be_here /proc/cmdline
(! grep -q this_should_not_be_here /proc/cmdline)
diff --git a/mkosi.images/system/mkosi.postinst.chroot b/mkosi.images/system/mkosi.postinst.chroot
index 330fa3b73e..8d2c3d6a37 100755
--- a/mkosi.images/system/mkosi.postinst.chroot
+++ b/mkosi.images/system/mkosi.postinst.chroot
@@ -101,11 +101,18 @@ cat >/usr/lib/tmpfiles.d/testuser.conf <<EOF
q /home/testuser 0700 4711 4711
EOF
-# sbsign is not available on CentOS Stream
-if command -v sbsign &>/dev/null; then
+# RHEL 9 only: we don't ship sbsigntools in RHEL 9 so we have to use pesign
+# instead. Unfortunately, ATTOW ukify doesn't support signing with pesign, so we
+# have to do it manually :(
+if command -v pesign &>/dev/null; then
# Ensure that side-loaded PE addons are loaded if signed, and ignored if not
addons_dir=/efi/loader/addons
mkdir -p "$addons_dir"
- ukify build --secureboot-private-key mkosi.key --secureboot-certificate mkosi.crt --cmdline this_should_be_here -o "$addons_dir/good.addon.efi"
+ ukify build --cmdline this_should_be_here -o "good.addon.efi"
ukify build --cmdline this_should_not_be_here -o "$addons_dir/bad.addon.efi"
+
+ openssl pkcs12 -name "mkosi" -passin "pass:" -passout "pass:" -export -out mkosi.p12 -inkey mkosi.key -in mkosi.crt
+ pk12util -W "" -i mkosi.p12 -d /etc/pki/pesign
+ pesign -v -s -c "mkosi" -i "good.addon.efi" -o "$addons_dir/good.addon.efi"
+ pesign -S -i"$addons_dir/good.addon.efi"
fi

@ -0,0 +1,65 @@
From 59162dc947e9c9538f98f0a00ab9eeef9c7bae71 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 11 Jul 2023 21:03:22 +0200
Subject: [PATCH] test: copy out the necessary test data before we start
overmounting stuff
Otherwise the get_testdata_dir() call fails if the source tree is under
/root (which is usually the case in CIs).
I got bitten by this after leaving the source tree under /root but moving the
$BUILD_DIR elsewhere. This used to work by accident, as load_testdata_env()
would try to read $BUILD_DIR/systemd-runtest.env, but would fail if the
$BUILD_DIR is also under /root and fall back to SYSTEMD_TEST_DATA
(/lib/systemd/tests/testdata), which usually exist as we install the just built
revision. However, if the $BUILD_DIR is outside of /root we'd read
$BUILD_DIR/systemd-runtest.env which contains
SYSTEMD_TEST_DATA=/path/to/source/tree/test and that source tree is not visible
once we overmount /root with tmpfs making the test fail:
/* test_run_tests_unprivileged */
Successfully forked off '(test-execute-unprivileged)' as PID 10672.
Changing mount flags / (MS_REMOUNT|MS_BIND "")...
Changing mount propagation / (MS_REC|MS_SHARED "")
Mounting tmpfs (tmpfs) on /dev/shm (MS_NOSUID|MS_NODEV "")...
Mounting tmpfs (tmpfs) on /root (MS_NOSUID|MS_NODEV "")...
Mounting tmpfs (tmpfs) on /tmp (MS_NOSUID|MS_NODEV "")...
Mounting tmpfs (tmpfs) on /var/tmp (MS_NOSUID|MS_NODEV "")...
Mounting tmpfs (tmpfs) on /var/lib (MS_NOSUID|MS_NODEV "")...
Mounting tmpfs (tmpfs) on /run/test-execute-unit-dir (MS_NOSUID|MS_NODEV "")...
ERROR: $SYSTEMD_TEST_DATA directory [/root/systemd/test] not accessible: No such file or directory
Assertion 'get_testdata_dir("test-execute/", &unit_dir) >= 0' failed at src/test/test-execute.c:1306, function prepare_ns(). Aborting.
(test-execute-unprivileged) terminated by signal ABRT.
(cherry picked from commit c109cff9f998876c3b5abd62501132d0fb0f80a2)
Related: RHEL-27512
---
src/test/test-execute.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index f37da945b6..e6bd21b6b9 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1260,15 +1260,16 @@ static int prepare_ns(const char *process_name) {
assert_se(mount_follow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_SHARED|MS_REC, NULL) >= 0);
assert_se(mkdir_p(PRIVATE_UNIT_DIR, 0755) >= 0);
-
- /* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
- FOREACH_STRING(p, "/dev/shm", "/root", "/tmp", "/var/tmp", "/var/lib", PRIVATE_UNIT_DIR)
- assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
+ assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", PRIVATE_UNIT_DIR, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
/* Copy unit files to make them accessible even when unprivileged. */
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(copy_directory(unit_dir, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
+ /* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
+ FOREACH_STRING(p, "/dev/shm", "/root", "/tmp", "/var/tmp", "/var/lib")
+ assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
+
/* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
assert_se(mkdir_p(p, 0) >= 0);

@ -0,0 +1,39 @@
From 5bc5e4eccfccb2935ededa6976d3346b1b6fbdaf Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 6 Mar 2024 15:04:22 +0100
Subject: [PATCH] ci: make the build dir accessible when running w/o privileges
Otherwise the unprivileged part of test-execute gets silently skipped:
/* test_run_tests_unprivileged */
Successfully forked off '(test-execute-unprivileged)' as PID 20998.
...
pin_callout_binary: build dir binary: /home/runner/work/systemd/systemd/build/systemd-executor
pin_callout_binary: open(/home/runner/work/systemd/systemd/build/systemd-executor)=-13
Failed to pin executor binary: No such file or directory
(test-execute-unprivileged): manager_new, skipping tests: No such file or directory
(test-execute-unprivileged) succeeded.
(cherry picked from commit c538fecc617d7a5fe0048b1df49f69dead92353f)
Related: RHEL-27512
---
.github/workflows/unit_tests.sh | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
index 9a9fbb36ab..cb8ea332aa 100755
--- a/.github/workflows/unit_tests.sh
+++ b/.github/workflows/unit_tests.sh
@@ -52,6 +52,11 @@ for phase in "${PHASES[@]}"; do
apt-get -y build-dep systemd
apt-get -y install "${ADDITIONAL_DEPS[@]}"
pip3 install -r .github/workflows/requirements.txt --require-hashes
+
+ # Make sure the build dir is accessible even when drop privileges, otherwise the unprivileged
+ # part of test-execute gets skipped, since it can't run systemd-executor
+ chmod o+x /home/runner
+ capsh --drop=all -- -c "stat $PWD/meson.build"
;;
RUN|RUN_GCC|RUN_CLANG|RUN_CLANG_RELEASE)
if [[ "$phase" =~ ^RUN_CLANG ]]; then

@ -0,0 +1,74 @@
From 5a310f31d5d42bb7a556c274c3839c34c600e9f5 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 6 Mar 2024 15:21:10 +0100
Subject: [PATCH] ci: explicitly change oom-{score}-adj before running tests
For some reason root in GH actions is able to _decrease_ its oom score
even after dropping all capabilities (including CAP_SYS_RESOURCE), until
the oom score is changed explicitly after sudo:
$ systemd-detect-virt
microsoft
$ sudo su -
~# capsh --drop=all -- -c 'capsh --print; grep -H . /proc/self/oom*; choom -p $$ -n -101'
Current: =
Bounding set =
Ambient set =
Current IAB: !cap_chown,!cap_dac_override,!cap_dac_read_search,...,!cap_sys_resource,...,!cap_checkpoint_restore
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: UNCERTAIN (0)
/proc/self/oom_adj:8
/proc/self/oom_score:1000
/proc/self/oom_score_adj:500
pid 22180's OOM score adjust value changed from 500 to -101
~# choom -p $$ -n 500
pid 22027's OOM score adjust value changed from 500 to 500
~# capsh --drop=all -- -c 'capsh --print; grep -H . /proc/self/oom*; choom -p $$ -n -101'
Current: =
Bounding set =
Ambient set =
...
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: UNCERTAIN (0)
/proc/self/oom_adj:8
/proc/self/oom_score:1000
/proc/self/oom_score_adj:500
choom: failed to set score adjust value: Permission denied
I have no idea what's going on, but it breaks
exec-oomscoreadjust-negative.service from test-execute when running
unprivileged.
(cherry picked from commit 7161af9612d2d4f79cfbe8ed34ea7614d08901f7)
Related: RHEL-27512
---
.github/workflows/unit_tests.sh | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
index cb8ea332aa..6dcbc393fd 100755
--- a/.github/workflows/unit_tests.sh
+++ b/.github/workflows/unit_tests.sh
@@ -41,6 +41,12 @@ set -ex
MESON_ARGS=(-Dcryptolib=${CRYPTOLIB:-auto})
+# (Re)set the current oom-{score-}adj. For some reason root on GH actions is able to _decrease_
+# its oom-score even after dropping all capabilities (including CAP_SYS_RESOURCE), until the
+# score is explicitly changed after sudo. No idea what's going on, but it breaks
+# exec-oomscoreadjust-negative.service from test-execute when running unprivileged.
+choom -p $$ -n 0
+
for phase in "${PHASES[@]}"; do
case $phase in
SETUP)

@ -0,0 +1,49 @@
From 90c92458355a64d96f3167bcb510f690446bd76a Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Fri, 28 Apr 2023 13:10:23 +0100
Subject: [PATCH] ratelimit: add ratelimit_left helper
(cherry picked from commit 53d6987f9e46927bbc9ad683c091c070ebe06658)
Resolves: RHEL-35703
---
src/basic/ratelimit.c | 17 +++++++++++++++++
src/basic/ratelimit.h | 3 +++
2 files changed, 20 insertions(+)
diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c
index c16c8f7103..134ed7c2d8 100644
--- a/src/basic/ratelimit.c
+++ b/src/basic/ratelimit.c
@@ -43,3 +43,20 @@ unsigned ratelimit_num_dropped(RateLimit *r) {
return r->num > r->burst ? r->num - r->burst : 0;
}
+
+usec_t ratelimit_end(const RateLimit *rl) {
+ assert(rl);
+ if (rl->begin == 0)
+ return 0;
+
+ return usec_add(rl->begin, rl->interval);
+}
+
+usec_t ratelimit_left(const RateLimit *rl) {
+ assert(rl);
+
+ if (rl->begin == 0)
+ return 0;
+
+ return usec_sub_unsigned(ratelimit_end(rl), now(CLOCK_MONOTONIC));
+}
diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h
index 2236189851..bb7160a895 100644
--- a/src/basic/ratelimit.h
+++ b/src/basic/ratelimit.h
@@ -23,3 +23,6 @@ static inline bool ratelimit_configured(RateLimit *rl) {
bool ratelimit_below(RateLimit *r);
unsigned ratelimit_num_dropped(RateLimit *r);
+
+usec_t ratelimit_end(const RateLimit *rl);
+usec_t ratelimit_left(const RateLimit *rl);

@ -0,0 +1,264 @@
From 10e811e931efd55cab87b85eb75cbe73139cec43 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Thu, 27 Apr 2023 23:23:30 +0100
Subject: [PATCH] manager: restrict Dump*() to privileged callers or ratelimit
Dump*() methods can take quite some time due to the amount of data to
serialize, so they can potentially stall the manager. Make them
privileged, as they are debugging tools anyway. Use a new 'dump'
capability for polkit, and the 'reload' capability for SELinux, as
that's also non-destructive but slow.
If the caller is not privileged, allow it but rate limited to 10 calls
every 10 minutes.
(cherry picked from commit d936595672cf3ee7c1c547f8fd30512f82be8784)
Resolves: RHEL-35703
---
man/org.freedesktop.systemd1.xml | 7 +++--
man/systemd-analyze.xml | 2 +-
src/core/dbus-manager.c | 34 +++++++++++++++++++--
src/core/dbus.c | 3 ++
src/core/dbus.h | 1 +
src/core/manager-serialize.c | 23 ++++++++++++++
src/core/manager.c | 5 +++
src/core/manager.h | 3 ++
src/core/org.freedesktop.systemd1.policy.in | 10 ++++++
test/units/testsuite-65.sh | 15 +++++++++
10 files changed, 98 insertions(+), 5 deletions(-)
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index c18428a092..7ee649f6a7 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -1363,7 +1363,8 @@ node /org/freedesktop/systemd1 {
<function>DumpByFileDescriptor()</function>/<function>DumpUnitsMatchingPatternsByFileDescriptor()</function>
are usually the preferred interface, since it ensures the data can be passed reliably from the service
manager to the client. Note though that they cannot work when communicating with the service manager
- remotely, as file descriptors are strictly local to a system.</para>
+ remotely, as file descriptors are strictly local to a system. All the <function>Dump*()</function>
+ methods are rate limited for unprivileged users.</para>
<para><function>Reload()</function> may be invoked to reload all unit files.</para>
@@ -1726,7 +1727,9 @@ node /org/freedesktop/systemd1 {
<function>UnsetAndSetEnvironment()</function>) require
<interfacename>org.freedesktop.systemd1.set-environment</interfacename>. <function>Reload()</function>
and <function>Reexecute()</function> require
- <interfacename>org.freedesktop.systemd1.reload-daemon</interfacename>.
+ <interfacename>org.freedesktop.systemd1.reload-daemon</interfacename>. Operations which dump internal
+ state require <interfacename>org.freedesktop.systemd1.bypass-dump-ratelimit</interfacename> to avoid
+ rate limits.
</para>
</refsect2>
</refsect1>
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 5ba0d40fa0..ff5c84108d 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -249,7 +249,7 @@ multi-user.target @47.820s
<para>Without any parameter, this command outputs a (usually very long) human-readable serialization of
the complete service manager state. Optional glob pattern may be specified, causing the output to be
limited to units whose names match one of the patterns. The output format is subject to change without
- notice and should not be parsed by applications.</para>
+ notice and should not be parsed by applications. This command is rate limited for unprivileged users.</para>
<example>
<title>Show the internal state of user manager</title>
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 00380cc9c1..44b1027588 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1357,17 +1357,47 @@ static int dump_impl(
assert(message);
- /* Anyone can call this method */
-
+ /* 'status' access is the bare minimum always needed for this, as the policy might straight out
+ * forbid a client from querying any information from systemd, regardless of any rate limiting. */
r = mac_selinux_access_check(message, "status", error);
if (r < 0)
return r;
+ /* Rate limit reached? Check if the caller is privileged/allowed by policy to bypass this. We
+ * check the rate limit first to avoid the expensive roundtrip to polkit when not needed. */
+ if (!ratelimit_below(&m->dump_ratelimit)) {
+ /* We need a way for SELinux to constrain the operation when the rate limit is active, even
+ * if polkit would allow it, but we cannot easily add new named permissions, so we need to
+ * use an existing one. Reload/reexec are also slow but non-destructive/modifying
+ * operations, and can cause PID1 to stall. So it seems similar enough in terms of security
+ * considerations and impact, and thus use the same access check for dumps which, given the
+ * large amount of data to fetch, can stall PID1 for quite some time. */
+ r = mac_selinux_access_check(message, "reload", error);
+ if (r < 0)
+ goto ratelimited;
+
+ r = bus_verify_bypass_dump_ratelimit_async(m, message, error);
+ if (r < 0)
+ goto ratelimited;
+ if (r == 0)
+ /* No authorization for now, but the async polkit stuff will call us again when it
+ * has it */
+ return 1;
+ }
+
r = manager_get_dump_string(m, patterns, &dump);
if (r < 0)
return r;
return reply(message, dump);
+
+ratelimited:
+ log_warning("Dump request rejected due to rate limit on unprivileged callers, blocked for %s.",
+ FORMAT_TIMESPAN(ratelimit_left(&m->dump_ratelimit), USEC_PER_SEC));
+ return sd_bus_error_setf(error,
+ SD_BUS_ERROR_LIMITS_EXCEEDED,
+ "Dump request rejected due to rate limit on unprivileged callers, blocked for %s.",
+ FORMAT_TIMESPAN(ratelimit_left(&m->dump_ratelimit), USEC_PER_SEC));
}
static int reply_dump(sd_bus_message *message, char *dump) {
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 141c3ffe12..3cbe9c5cfd 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -1177,6 +1177,9 @@ int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_erro
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error);
}
+int bus_verify_bypass_dump_ratelimit_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
+ return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.bypass-dump-ratelimit", NULL, false, UID_INVALID, &m->polkit_registry, error);
+}
uint64_t manager_bus_n_queued_write(Manager *m) {
uint64_t c = 0;
diff --git a/src/core/dbus.h b/src/core/dbus.h
index 369d9f56a2..50e7bb400e 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -27,6 +27,7 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+int bus_verify_bypass_dump_ratelimit_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_forward_agent_released(Manager *m, const char *path);
diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c
index 27cb0925ae..f3b2d7ee16 100644
--- a/src/core/manager-serialize.c
+++ b/src/core/manager-serialize.c
@@ -164,6 +164,14 @@ int manager_serialize(
(void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
}
+ (void) serialize_item_format(f,
+ "dump-ratelimit",
+ USEC_FMT " " USEC_FMT " %u %u",
+ m->dump_ratelimit.begin,
+ m->dump_ratelimit.interval,
+ m->dump_ratelimit.num,
+ m->dump_ratelimit.burst);
+
bus_track_serialize(m->subscribed, f, "subscribed");
r = dynamic_user_serialize(m, f, fds);
@@ -549,6 +557,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
* remains set until all serialized contents are handled. */
if (deserialize_varlink_sockets)
(void) varlink_server_deserialize_one(m->varlink_server, val, fds);
+ } else if ((val = startswith(l, "dump-ratelimit="))) {
+ usec_t begin, interval;
+ unsigned num, burst;
+
+ if (sscanf(val, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4)
+ log_notice("Failed to parse dump ratelimit, ignoring: %s", val);
+ else {
+ /* If we changed the values across versions, flush the counter */
+ if (interval != m->dump_ratelimit.interval || burst != m->dump_ratelimit.burst)
+ m->dump_ratelimit.num = 0;
+ else
+ m->dump_ratelimit.num = num;
+ m->dump_ratelimit.begin = begin;
+ }
+
} else {
ManagerTimestamp q;
diff --git a/src/core/manager.c b/src/core/manager.c
index eeee395b90..b44c7785cf 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -866,6 +866,11 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager *
.test_run_flags = test_run_flags,
.default_oom_policy = OOM_STOP,
+
+ .dump_ratelimit = {
+ .interval = 10 * USEC_PER_MINUTE,
+ .burst = 10,
+ },
};
#if ENABLE_EFI
diff --git a/src/core/manager.h b/src/core/manager.h
index 87e63c3b68..86e7e40989 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -461,6 +461,9 @@ struct Manager {
struct restrict_fs_bpf *restrict_fs;
char *default_smack_process_label;
+
+ /* Dump*() are slow, so always rate limit them to 10 per 10 minutes */
+ RateLimit dump_ratelimit;
};
static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
diff --git a/src/core/org.freedesktop.systemd1.policy.in b/src/core/org.freedesktop.systemd1.policy.in
index 74adeadf38..9e9a20f66f 100644
--- a/src/core/org.freedesktop.systemd1.policy.in
+++ b/src/core/org.freedesktop.systemd1.policy.in
@@ -70,4 +70,14 @@
</defaults>
</action>
+ <action id="org.freedesktop.systemd1.bypass-dump-ratelimit">
+ <description gettext-domain="systemd">Dump the systemd state without rate limits</description>
+ <message gettext-domain="systemd">Authentication is required to dump the systemd state without rate limits.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>
diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh
index 7c34948f82..f416194922 100755
--- a/test/units/testsuite-65.sh
+++ b/test/units/testsuite-65.sh
@@ -51,6 +51,21 @@ systemd-analyze dot --require systemd-journald.service systemd-logind.service >/
systemd-analyze dot "systemd-*.service" >/dev/null
(! systemd-analyze dot systemd-journald.service systemd-logind.service "*" bbb ccc)
# dump
+# this should be rate limited to 10 calls in 10 minutes for unprivileged callers
+for _ in {1..10}; do
+ runas testuser systemd-analyze dump systemd-journald.service >/dev/null
+done
+(! runas testuser systemd-analyze dump >/dev/null)
+# still limited after a reload
+systemctl daemon-reload
+(! runas testuser systemd-analyze dump >/dev/null)
+# and a re-exec
+systemctl daemon-reexec
+(! runas testuser systemd-analyze dump >/dev/null)
+# privileged call, so should not be rate limited
+for _ in {1..10}; do
+ systemd-analyze dump systemd-journald.service >/dev/null
+done
systemd-analyze dump >/dev/null
systemd-analyze dump "*" >/dev/null
systemd-analyze dump "*.socket" >/dev/null

@ -0,0 +1,60 @@
From 3e5091146213b8b4abf0c5f5577a98b9da9c9f2c Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 11 Jun 2024 15:21:14 +0200
Subject: [PATCH] ci: define `runas` function inline
We don't have `test/units/util.sh`, which provides the definition of `runas` function in the RHEL9 codebase
Also partially backport https://github.com/systemd/systemd/commit/c7bf1959d7580e1b7e918b75f852b3bf3fb6eb3c
rhel-only
Related: RHEL-35703
---
test/test-functions | 5 +++--
test/units/testsuite-65.sh | 7 +++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/test/test-functions b/test/test-functions
index 947f8589c5..52eff07510 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -206,6 +206,7 @@ BASICTOOLS=(
seq
setfattr
setfont
+ setpriv
setsid
sfdisk
sh
@@ -2616,10 +2617,10 @@ inst_binary() {
# Same as above, but we need to wrap certain libraries unconditionally
#
# chown, getent, login, su, useradd, userdel - dlopen()s (not only) systemd's PAM modules
- # ls, stat - pulls in nss_systemd with certain options (like ls -l) when
+ # ls, setpriv, stat - pulls in nss_systemd with certain options (like ls -l) when
# nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
# tar - called by machinectl in TEST-25
- if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(chown|getent|login|id|ls|stat|su|tar|useradd|userdel)$ ]]; then
+ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(chown|getent|login|id|ls|setpriv|stat|su|tar|useradd|userdel)$ ]]; then
wrap_binary=1
fi
diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh
index f416194922..0fb143bde7 100755
--- a/test/units/testsuite-65.sh
+++ b/test/units/testsuite-65.sh
@@ -6,6 +6,13 @@ set -eux
# shellcheck source=test/units/assert.sh
. "$(dirname "$0")"/assert.sh
+# On RHEL9 we don't have the `util.sh` script, so we need to define the `runas` function here
+runas() {
+ local userid="${1:?}"
+ shift
+ XDG_RUNTIME_DIR=/run/user/"$(id -u "$userid")" setpriv --reuid="$userid" --init-groups "$@"
+}
+
systemctl log-level debug
export SYSTEMD_LOG_LEVEL=debug

@ -0,0 +1,31 @@
From f6fdbbe989e54480882b9eeda452d168eea804a2 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Thu, 21 Dec 2023 19:46:54 +0100
Subject: [PATCH] Drop /dev test in test-mountpoint-util
Even /dev isn't always guaranteed to be a mount point, so let's drop
this part of the test.
(cherry picked from commit bacad14f94a4e98c3e81d821c56dbe7e2e4726ff)
Related: RHEL-30372
---
src/test/test-mountpoint-util.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
index 8555c5a7db..d8e56c0365 100644
--- a/src/test/test-mountpoint-util.c
+++ b/src/test/test-mountpoint-util.c
@@ -138,11 +138,6 @@ TEST(path_is_mount_point) {
assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
- assert_se(path_is_mount_point("/dev", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/dev", NULL, 0) > 0);
- assert_se(path_is_mount_point("/dev/", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/dev/", NULL, 0) > 0);
-
/* we'll create a hierarchy of different kinds of dir/file/link
* layouts:
*

@ -0,0 +1,69 @@
From 7302d5d45efc1b157ddbfb04c387d83a87c8384f Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Mon, 8 May 2023 23:10:07 +0800
Subject: [PATCH] core/manager: export manager_dbus_is_running
(cherry picked from commit e8863150653931ae2ffc91757623f179ce763628)
Resolves: RHEL-40878
---
src/core/manager.c | 8 ++++----
src/core/manager.h | 5 +++++
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index b44c7785cf..fd6e711c65 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1680,7 +1680,7 @@ static void manager_distribute_fds(Manager *m, FDSet *fds) {
}
}
-static bool manager_dbus_is_running(Manager *m, bool deserialized) {
+bool manager_dbus_is_running_full(Manager *m, bool deserialized) {
Unit *u;
assert(m);
@@ -1722,7 +1722,7 @@ static void manager_setup_bus(Manager *m) {
(void) bus_init_system(m);
/* Let's connect to the bus now, but only if the unit is supposed to be up */
- if (manager_dbus_is_running(m, MANAGER_IS_RELOADING(m))) {
+ if (manager_dbus_is_running_full(m, MANAGER_IS_RELOADING(m))) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
@@ -2815,7 +2815,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGUSR1:
- if (manager_dbus_is_running(m, false)) {
+ if (manager_dbus_is_running(m)) {
log_info("Trying to reconnect to bus...");
(void) bus_init_api(m);
@@ -3930,7 +3930,7 @@ void manager_recheck_dbus(Manager *m) {
if (MANAGER_IS_RELOADING(m))
return; /* don't check while we are reloading… */
- if (manager_dbus_is_running(m, false)) {
+ if (manager_dbus_is_running(m)) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
diff --git a/src/core/manager.h b/src/core/manager.h
index 86e7e40989..1479813de4 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -491,6 +491,11 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *root);
+bool manager_dbus_is_running_full(Manager *m, bool deserialized);
+static inline bool manager_dbus_is_running(Manager *m) {
+ return manager_dbus_is_running_full(m, false);
+}
+
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);

@ -0,0 +1,61 @@
From 40f8600cfd866e4956fb09ca29bc5dc74e605450 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Tue, 9 May 2023 00:07:45 +0800
Subject: [PATCH] core: refuse dbus activation if dbus is not running
dbus-broker issues StartUnit directly for activation requests,
so let's add a check on bus state in bus_unit_queue_job to refuse
that if dbus is not running.
Replaces #27570
Closes #26799
(cherry picked from commit 53964fd26b4a01191609ffc064aa8ccccd28e377)
Resolves: RHEL-40878
---
src/core/dbus-unit.c | 7 +++++++
src/core/dbus.c | 5 ++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 19a71b6cb3..685d45fc23 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -21,6 +21,7 @@
#include "path-util.h"
#include "process-util.h"
#include "selinux-access.h"
+#include "service.h"
#include "signal-util.h"
#include "special.h"
#include "string-table.h"
@@ -1845,6 +1846,12 @@ int bus_unit_queue_job(
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
+ /* dbus-broker issues StartUnit for activation requests, so let's apply the same check
+ * used in signal_activation_request(). */
+ if (type == JOB_START && u->type == UNIT_SERVICE &&
+ SERVICE(u)->type == SERVICE_DBUS && !manager_dbus_is_running(u->manager))
+ return sd_bus_error_set(error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is not running.");
+
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 3cbe9c5cfd..b4564f79a2 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -160,9 +160,8 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
return 0;
}
- if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
- manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
- r = sd_bus_error_set(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
+ if (!manager_dbus_is_running(m)) {
+ r = sd_bus_error_set(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is not running.");
goto failed;
}

@ -0,0 +1,84 @@
From 6e61224e554decd747d6537a4d6839cff6b19909 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Wed, 10 May 2023 13:54:15 +0800
Subject: [PATCH] core: only refuse Type=dbus service enqueuing if dbus has
stop job
Follow-up for #27579
In #27579 we refused all StartUnit requests for Type=dbus units
if dbus is not running, which means if dbus is manually stopped,
user can't use systemctl to start Type=dbus units again, which
is incorrect.
The only culprit that leads to the cancellation of the whole
transaction mentioned in #26799 is job type conflict on dbus.
So let's relax the restriction and only refuse job enqueuing
if dbus has a stop job.
To summarize, the case we want to avoid is:
1. dbus has a stop job installed
2. StartUnit/ActivationRequest is received
3. Type=dbus service gets started, which has Requires=dbus.socket
4. dbus is pulled in again, resulting in job type conflict
What we can support is:
1. dbus is already stopped
2. StartUnit is received (possibly through systemctl, i.e. on private bus)
3. Type=dbus service gets started, which will wait for dbus to start
4. dbus is started again, thus the job for Type=dbus service
Replaces #27590
Fixes #27588
(cherry picked from commit bee6e755bb8e53a7a436e221b015ce0232ed87c0)
Resolves: RHEL-40878
---
src/core/dbus-unit.c | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 685d45fc23..49eacc977c 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -1844,13 +1844,30 @@ int bus_unit_queue_job(
(type == JOB_STOP && u->refuse_manual_stop) ||
(IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
- return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
-
- /* dbus-broker issues StartUnit for activation requests, so let's apply the same check
- * used in signal_activation_request(). */
- if (type == JOB_START && u->type == UNIT_SERVICE &&
- SERVICE(u)->type == SERVICE_DBUS && !manager_dbus_is_running(u->manager))
- return sd_bus_error_set(error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is not running.");
+ return sd_bus_error_setf(error,
+ BUS_ERROR_ONLY_BY_DEPENDENCY,
+ "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
+ u->id);
+
+ /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically
+ * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start
+ * job that pulls in dbus again would cause job type conflict. Let's avoid that by rejecting
+ * job enqueuing early.
+ *
+ * Note that unlike signal_activation_request(), we can't use unit_inactive_or_pending()
+ * here. StartUnit is a more generic interface, and thus users are allowed to use e.g. systemctl
+ * to start Type=dbus services even when dbus is inactive. */
+ if (type == JOB_START && u->type == UNIT_SERVICE && SERVICE(u)->type == SERVICE_DBUS)
+ FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) {
+ Unit *dbus;
+
+ dbus = manager_get_unit(u->manager, dbus_unit);
+ if (dbus && unit_stop_pending(dbus))
+ return sd_bus_error_setf(error,
+ BUS_ERROR_SHUTTING_DOWN,
+ "Operation for unit %s refused, D-Bus is shutting down.",
+ u->id);
+ }
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)

@ -0,0 +1,93 @@
From 07ec0810cf4dc638c138735eccda78e37ff42be7 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Thu, 11 May 2023 18:55:43 +0800
Subject: [PATCH] Revert "core/manager: export manager_dbus_is_running" and
partially "core: refuse dbus activation if dbus is not running"
This reverts commit e8863150653931ae2ffc91757623f179ce763628
and partially 53964fd26b4a01191609ffc064aa8ccccd28e377.
Specifically, changes to signal_activation_request()
is not desired.
(cherry picked from commit 2b680534c9667341551b39f4cc9735cd6e8c014e)
Resolves: RHEL-40878
---
src/core/dbus.c | 5 +++--
src/core/manager.c | 8 ++++----
src/core/manager.h | 5 -----
3 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index b4564f79a2..1431e079c2 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -160,8 +160,9 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
return 0;
}
- if (!manager_dbus_is_running(m)) {
- r = sd_bus_error_set(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is not running.");
+ if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET) ||
+ manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE)) {
+ r = sd_bus_error_set(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
goto failed;
}
diff --git a/src/core/manager.c b/src/core/manager.c
index fd6e711c65..b44c7785cf 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1680,7 +1680,7 @@ static void manager_distribute_fds(Manager *m, FDSet *fds) {
}
}
-bool manager_dbus_is_running_full(Manager *m, bool deserialized) {
+static bool manager_dbus_is_running(Manager *m, bool deserialized) {
Unit *u;
assert(m);
@@ -1722,7 +1722,7 @@ static void manager_setup_bus(Manager *m) {
(void) bus_init_system(m);
/* Let's connect to the bus now, but only if the unit is supposed to be up */
- if (manager_dbus_is_running_full(m, MANAGER_IS_RELOADING(m))) {
+ if (manager_dbus_is_running(m, MANAGER_IS_RELOADING(m))) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
@@ -2815,7 +2815,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGUSR1:
- if (manager_dbus_is_running(m)) {
+ if (manager_dbus_is_running(m, false)) {
log_info("Trying to reconnect to bus...");
(void) bus_init_api(m);
@@ -3930,7 +3930,7 @@ void manager_recheck_dbus(Manager *m) {
if (MANAGER_IS_RELOADING(m))
return; /* don't check while we are reloading… */
- if (manager_dbus_is_running(m)) {
+ if (manager_dbus_is_running(m, false)) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
diff --git a/src/core/manager.h b/src/core/manager.h
index 1479813de4..86e7e40989 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -491,11 +491,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *root);
-bool manager_dbus_is_running_full(Manager *m, bool deserialized);
-static inline bool manager_dbus_is_running(Manager *m) {
- return manager_dbus_is_running_full(m, false);
-}
-
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);

@ -0,0 +1,127 @@
From 758cd9ddac150342dbac49ed4c80c68531c169b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 28 Jul 2023 17:54:59 +0200
Subject: [PATCH] manager: fix reloading in reload-or-restart --marked
bus_unit_queue_job_one has two callers:
- bus_unit_queue_job which would do the appropriate transormations
to turn JOB_TRY_RESTART into JOB_TRY_RELOAD,
- and method_enqueue_marked_jobs which did not.
In effect, method_enqueue_marked_jobs() would queue restart jobs for
units which has Markers= needs-reload or needs-restart.
When the chunk of code which does the transformations is moved from
bus_unit_queue_job to bus_unit_queue_job_one, there is no change for
bus_unit_queue_job, and method_enqueue_marked_jobs is fixed.
The additional checks that are done seem reasonable to do from
method_enqueue_marked_jobs: we shouldn't be restarting units which are
configured to not allow that, or force unwanted start of dbus-broker.
(cherry picked from commit 8ea8e23f4013dbc4f4a66c81eb786f0505434f2e)
Resolves: RHEL-40878
---
src/core/dbus-unit.c | 82 ++++++++++++++++++++++----------------------
1 file changed, 41 insertions(+), 41 deletions(-)
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 49eacc977c..b45b3fdb53 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -1736,6 +1736,47 @@ int bus_unit_queue_job_one(
Job *j, *a;
int r;
+ if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
+ if (type == JOB_RESTART)
+ type = JOB_RELOAD_OR_START;
+ else if (type == JOB_TRY_RESTART)
+ type = JOB_TRY_RELOAD;
+ }
+
+ if (type == JOB_STOP &&
+ IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
+ unit_active_state(u) == UNIT_INACTIVE)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
+
+ if ((type == JOB_START && u->refuse_manual_start) ||
+ (type == JOB_STOP && u->refuse_manual_stop) ||
+ (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+ (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
+ return sd_bus_error_setf(error,
+ BUS_ERROR_ONLY_BY_DEPENDENCY,
+ "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
+ u->id);
+
+ /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically
+ * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start
+ * job that pulls in dbus again would cause job type conflict. Let's avoid that by rejecting
+ * job enqueuing early.
+ *
+ * Note that unlike signal_activation_request(), we can't use unit_inactive_or_pending()
+ * here. StartUnit is a more generic interface, and thus users are allowed to use e.g. systemctl
+ * to start Type=dbus services even when dbus is inactive. */
+ if (type == JOB_START && u->type == UNIT_SERVICE && SERVICE(u)->type == SERVICE_DBUS)
+ FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) {
+ Unit *dbus;
+
+ dbus = manager_get_unit(u->manager, dbus_unit);
+ if (dbus && unit_stop_pending(dbus))
+ return sd_bus_error_setf(error,
+ BUS_ERROR_SHUTTING_DOWN,
+ "Operation for unit %s refused, D-Bus is shutting down.",
+ u->id);
+ }
+
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
affected = set_new(NULL);
if (!affected)
@@ -1828,47 +1869,6 @@ int bus_unit_queue_job(
if (r < 0)
return r;
- if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
- if (type == JOB_RESTART)
- type = JOB_RELOAD_OR_START;
- else if (type == JOB_TRY_RESTART)
- type = JOB_TRY_RELOAD;
- }
-
- if (type == JOB_STOP &&
- IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
- unit_active_state(u) == UNIT_INACTIVE)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
-
- if ((type == JOB_START && u->refuse_manual_start) ||
- (type == JOB_STOP && u->refuse_manual_stop) ||
- (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
- (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
- return sd_bus_error_setf(error,
- BUS_ERROR_ONLY_BY_DEPENDENCY,
- "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
- u->id);
-
- /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically
- * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start
- * job that pulls in dbus again would cause job type conflict. Let's avoid that by rejecting
- * job enqueuing early.
- *
- * Note that unlike signal_activation_request(), we can't use unit_inactive_or_pending()
- * here. StartUnit is a more generic interface, and thus users are allowed to use e.g. systemctl
- * to start Type=dbus services even when dbus is inactive. */
- if (type == JOB_START && u->type == UNIT_SERVICE && SERVICE(u)->type == SERVICE_DBUS)
- FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) {
- Unit *dbus;
-
- dbus = manager_get_unit(u->manager, dbus_unit);
- if (dbus && unit_stop_pending(dbus))
- return sd_bus_error_setf(error,
- BUS_ERROR_SHUTTING_DOWN,
- "Operation for unit %s refused, D-Bus is shutting down.",
- u->id);
- }
-
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;

@ -0,0 +1,98 @@
From 8f9211463be196fee3acaba8d0d3aaff1dc166a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 26 Jul 2023 09:02:04 +0200
Subject: [PATCH] rpm: add `systemd_postun_with_reload` and
`systemd_user_postun_with_reload`
For some units, the package would like to issue a reload. The machinery was
already in place since c9615f73521986b3607b852c139036d58973043c:
systemctl reload-or-restart --marked
Enqueues restart jobs for all units that have the 'needs-restart'
mark, and reload jobs for units that have the 'needs-reload' mark.
When a unit marked for reload does not support reload, restart will
be queued.
The new macros allow a reload to be issued instead of a restart.
Based on the discussion on fedora-devel:
https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/message/IJSUGIEJNYZZRE53FF4YFUEBRHRAVIXR/
Tested using dummy package https://github.com/keszybz/rpm-test-reload.
(cherry picked from commit 631d2b05ec5195d1f8f8fbff8a2dfcbf23d0b7aa)
Resolves: RHEL-40878
---
src/rpm/macros.systemd.in | 16 ++++++++++++++++
src/rpm/systemd-update-helper.in | 22 ++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/src/rpm/macros.systemd.in b/src/rpm/macros.systemd.in
index 8880078b1b..fc607346e3 100644
--- a/src/rpm/macros.systemd.in
+++ b/src/rpm/macros.systemd.in
@@ -101,6 +101,22 @@ if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
fi \
%{nil}
+%systemd_postun_with_reload() \
+%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_reload}} \
+if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
+ # Package upgrade, not uninstall \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} mark-reload-system-units %{?*} || : \
+fi \
+%{nil}
+
+%systemd_user_postun_with_reload() \
+%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_user_postun_with_reload}} \
+if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
+ # Package upgrade, not uninstall \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} mark-reload-user-units %{?*} || : \
+fi \
+%{nil}
+
%udev_hwdb_update() %{nil}
%udev_rules_update() %{nil}
diff --git a/src/rpm/systemd-update-helper.in b/src/rpm/systemd-update-helper.in
index b35d952fab..1e00877de4 100755
--- a/src/rpm/systemd-update-helper.in
+++ b/src/rpm/systemd-update-helper.in
@@ -47,6 +47,15 @@ case "$command" in
wait
;;
+ mark-reload-system-units)
+ [ -d /run/systemd/system ] || exit 0
+
+ for unit in "$@"; do
+ systemctl set-property "$unit" Markers=+needs-reload &
+ done
+ wait
+ ;;
+
mark-restart-user-units)
[ -d /run/systemd/system ] || exit 0
@@ -60,6 +69,19 @@ case "$command" in
wait
;;
+ mark-reload-user-units)
+ [ -d /run/systemd/system ] || exit 0
+
+ users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
+ for user in $users; do
+ for unit in "$@"; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" set-property "$unit" Markers=+needs-reload &
+ done
+ done
+ wait
+ ;;
+
system-reload-restart|system-reload|system-restart)
if [ -n "$*" ]; then
echo "Unexpected arguments for '$command': $*"

@ -0,0 +1,38 @@
From 2400e5c6395459fa3629747168c36df8ef543811 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 28 Jul 2023 19:24:58 +0200
Subject: [PATCH] rpm: add `systemd_user_daemon_reexec`
This macros wraps the call to daemon-reexec in all user managers. It would be
called for example from systemd %post right after the call to systemctl
daemon-reexec.
This will be used in the Fedora systemd package to fix a long-standing FIXME.
Tested via building and reinstalling the systemd package with the patches.
(cherry picked from commit 9ff28e312bffe7567aa5d3f2c41303dd456f1691)
Resolves: RHEL-40878
---
src/rpm/macros.systemd.in | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/rpm/macros.systemd.in b/src/rpm/macros.systemd.in
index fc607346e3..8d5895eba1 100644
--- a/src/rpm/macros.systemd.in
+++ b/src/rpm/macros.systemd.in
@@ -117,6 +117,13 @@ if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
fi \
%{nil}
+%systemd_user_daemon_reexec() \
+if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
+ # Package upgrade, not uninstall \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} user-reexec || : \
+fi \
+%{nil}
+
%udev_hwdb_update() %{nil}
%udev_rules_update() %{nil}

@ -0,0 +1,25 @@
From d77bb7131a5c6946e78e8055e79ab7837189529c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Mar 2023 14:48:56 +0900
Subject: [PATCH] tools: fix the file name that "meson setup" generates
(cherry picked from commit 26ab5ea69d7b7804d0e9a7f4773443902c76c654)
Related: RHEL-30372
---
tools/meson-build.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/meson-build.sh b/tools/meson-build.sh
index ecd558f8d9..c8370a7e6a 100755
--- a/tools/meson-build.sh
+++ b/tools/meson-build.sh
@@ -10,7 +10,7 @@ CC="$5"
CXX="$6"
# shellcheck disable=SC2086
-[ -f "$dst/ninja.build" ] || CC="$CC" CXX="$CXX" meson "$src" "$dst" $options
+[ -f "$dst/build.ninja" ] || CC="$CC" CXX="$CXX" meson "$src" "$dst" $options
# Locate ninja binary, on CentOS 7 it is called ninja-build, so
# use that name if available.

@ -0,0 +1,41 @@
From d04257360c5b5cafbfdb67a3d1bcaf270f101465 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Mar 2023 20:06:09 +0900
Subject: [PATCH] tools: explicitly specify "setup" subcommand
As invoking meson without subcommand is deprecated since 0.64.0.
(cherry picked from commit e3b2f7c056551fa50ba6ed13703b8e63ba8303c7)
Related: RHEL-30372
---
tools/meson-build.sh | 2 +-
tools/oss-fuzz.sh | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/meson-build.sh b/tools/meson-build.sh
index c8370a7e6a..2ef60cfa8e 100755
--- a/tools/meson-build.sh
+++ b/tools/meson-build.sh
@@ -10,7 +10,7 @@ CC="$5"
CXX="$6"
# shellcheck disable=SC2086
-[ -f "$dst/build.ninja" ] || CC="$CC" CXX="$CXX" meson "$src" "$dst" $options
+[ -f "$dst/build.ninja" ] || CC="$CC" CXX="$CXX" meson setup "$src" "$dst" $options
# Locate ninja binary, on CentOS 7 it is called ninja-build, so
# use that name if available.
diff --git a/tools/oss-fuzz.sh b/tools/oss-fuzz.sh
index 7e9312b833..2e64475c6d 100755
--- a/tools/oss-fuzz.sh
+++ b/tools/oss-fuzz.sh
@@ -73,7 +73,7 @@ else
fi
fi
-if ! meson "$build" "-D$fuzzflag" -Db_lundef=false; then
+if ! meson setup "$build" "-D$fuzzflag" -Db_lundef=false; then
cat "$build/meson-logs/meson-log.txt"
exit 1
fi

@ -0,0 +1,86 @@
From cd2c39dd38fe4127a185e86798639c076dee58af Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 10 Nov 2023 16:38:01 +0100
Subject: [PATCH] fuzz: pass -Dc_args=/-Dcpp_args= to fuzzer targets
Prompted by #29972, because right now it's practically impossible to pass
-fno-sanitize=function to the fuzzer targets without some extensive
sed'ing.
This splits both c_args and cpp_args to separate arguments for
tools/meson-build.sh, because the other way would be to use `eval`, so
the space-separated but quoted strings passed to these options are not
split where they shouldn't, and I'd rather avoid using `eval` if
possible.
Also, this switches the positional arguments we pass to `meson setup`,
as they were in incorrect order (docs say it should be buildir followed
by sourcedir); meson is apparently clever enough to figure this out and
switch the arguments around if necessary, so it didn't complain.
(cherry picked from commit 17ee59c9c922553a8cb4d54cb8ae415706c4feff)
Related: RHEL-30372
---
test/fuzz/meson.build | 5 +++--
tools/meson-build.sh | 29 ++++++++++++++---------------
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build
index f7f0a6111c..813c2cfb8b 100644
--- a/test/fuzz/meson.build
+++ b/test/fuzz/meson.build
@@ -38,10 +38,11 @@ sanitize_address_undefined = custom_target(
project_source_root,
'@OUTPUT@',
'fuzzers',
- '-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@ -Dc_args=@2@ -Dcpp_args=@2@ -Dskip-deps=@3@'.format(
+ ' '.join(get_option('c_args') + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
+ ' '.join(get_option('cpp_args') + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
+ '-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@ -Dskip-deps=@2@'.format(
get_option('optimization'),
get_option('werror') ? '--werror' : '',
- '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION',
get_option('skip-deps')
),
' '.join(cc.cmd_array()),
diff --git a/tools/meson-build.sh b/tools/meson-build.sh
index 2ef60cfa8e..311b778f0a 100755
--- a/tools/meson-build.sh
+++ b/tools/meson-build.sh
@@ -2,21 +2,20 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
-src="$1"
-dst="$2"
-target="$3"
-options="$4"
-CC="$5"
-CXX="$6"
+sourcedir="${1:?}"
+builddir="${2:?}"
+target="${3:?}"
+c_args="${4:?}"
+cpp_args="${5:?}"
+options="${6:?}"
+CC="${7:?}"
+CXX="${8:?}"
-# shellcheck disable=SC2086
-[ -f "$dst/build.ninja" ] || CC="$CC" CXX="$CXX" meson setup "$src" "$dst" $options
-
-# Locate ninja binary, on CentOS 7 it is called ninja-build, so
-# use that name if available.
-ninja="ninja"
-if command -v ninja-build >/dev/null ; then
- ninja="ninja-build"
+if [ ! -f "$builddir/build.ninja" ]; then
+ # shellcheck disable=SC2086
+ CC="$CC" CXX="$CXX" meson setup -Dc_args="$c_args" -Dcpp_args="$cpp_args" "$builddir" "$sourcedir" $options
fi
-"$ninja" -C "$dst" "$target"
+# Locate ninja binary, on CentOS 7 it is called ninja-build, so use that name if available.
+command -v ninja-build >/dev/null && ninja="ninja-build" || ninja="ninja"
+"$ninja" -C "$builddir" "$target"

@ -0,0 +1,67 @@
From b327fbd6f262d2bbf2f20136d94a8edd28e43be8 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 15 Nov 2023 11:41:45 +0100
Subject: [PATCH] fuzz: don't panic without a C++ compiler
meson's `cpp_args` option is defined only if it detects a C++ compiler,
otherwise we get an error:
../test/fuzz/meson.build:56:28: ERROR: Tried to access unknown option 'cpp_args'.
[fsumsal]: make the RHS of the c_args/cpp_args expressions lists as
well, since it's a meson 0.60.0 feature (we ship 0.63.3 in RHEL 9 ATTOW,
but our baseline is 0.53.2, so meson rightfully complains about it;
bumping it would require several other commits to be pulled in as well
with lots of conflicts)
(cherry picked from commit a3d3bf559c9789c8abe96d931fc5d3f109886db9)
Related: RHEL-30372
---
test/fuzz/meson.build | 12 ++++++++++--
tools/meson-build.sh | 2 +-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build
index 813c2cfb8b..8637c66458 100644
--- a/test/fuzz/meson.build
+++ b/test/fuzz/meson.build
@@ -31,6 +31,14 @@ endforeach
############################################################
+
+fuzz_c_args = get_option('c_args')
+if cxx_cmd != ''
+ fuzz_cpp_args = get_option('cpp_args')
+else
+ fuzz_cpp_args = []
+endif
+
sanitize_address_undefined = custom_target(
'sanitize-address-undefined-fuzzers',
output : 'sanitize-address-undefined-fuzzers',
@@ -38,8 +46,8 @@ sanitize_address_undefined = custom_target(
project_source_root,
'@OUTPUT@',
'fuzzers',
- ' '.join(get_option('c_args') + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
- ' '.join(get_option('cpp_args') + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
+ ' '.join(fuzz_c_args + ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']),
+ ' '.join(fuzz_cpp_args + ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']),
'-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@ -Dskip-deps=@2@'.format(
get_option('optimization'),
get_option('werror') ? '--werror' : '',
diff --git a/tools/meson-build.sh b/tools/meson-build.sh
index 311b778f0a..2366df23f9 100755
--- a/tools/meson-build.sh
+++ b/tools/meson-build.sh
@@ -9,7 +9,7 @@ c_args="${4:?}"
cpp_args="${5:?}"
options="${6:?}"
CC="${7:?}"
-CXX="${8:?}"
+CXX="$8"
if [ ! -f "$builddir/build.ninja" ]; then
# shellcheck disable=SC2086

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save